@ai-ecoverse/slicc-agent 3.27.0 → 3.28.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.
Files changed (57) hide show
  1. package/README.md +46 -3
  2. package/dist/codemode/index.js +10 -4
  3. package/dist/codemode/index.js.map +2 -2
  4. package/dist/gelatiere/index.js +47 -9
  5. package/dist/gelatiere/index.js.map +2 -2
  6. package/dist/host.js +1 -0
  7. package/dist/host.js.map +2 -2
  8. package/dist/main.js +21 -2
  9. package/dist/main.js.map +2 -2
  10. package/dist/mcp/allow.js +39 -0
  11. package/dist/mcp/allow.js.map +7 -0
  12. package/dist/mcp/catalog.js +182 -0
  13. package/dist/mcp/catalog.js.map +7 -0
  14. package/dist/mcp/config.js +201 -0
  15. package/dist/mcp/config.js.map +7 -0
  16. package/dist/mcp/connection.js +296 -0
  17. package/dist/mcp/connection.js.map +7 -0
  18. package/dist/mcp/content.js +139 -0
  19. package/dist/mcp/content.js.map +7 -0
  20. package/dist/mcp/credentials.js +45 -0
  21. package/dist/mcp/credentials.js.map +7 -0
  22. package/dist/mcp/index.js +54 -0
  23. package/dist/mcp/index.js.map +7 -0
  24. package/dist/mcp/runtime.js +209 -0
  25. package/dist/mcp/runtime.js.map +7 -0
  26. package/dist/mcp/section.js +35 -0
  27. package/dist/mcp/section.js.map +7 -0
  28. package/dist/mcp/sse.js +112 -0
  29. package/dist/mcp/sse.js.map +7 -0
  30. package/dist/mcp/tools.js +413 -0
  31. package/dist/mcp/tools.js.map +7 -0
  32. package/dist/patches.js +2 -0
  33. package/dist/patches.js.map +2 -2
  34. package/dist/roles/roles.js +10 -1
  35. package/dist/roles/roles.js.map +2 -2
  36. package/dist/scoops/index.js +2 -1
  37. package/dist/scoops/index.js.map +2 -2
  38. package/dist/scoops/service.js +21 -6
  39. package/dist/scoops/service.js.map +2 -2
  40. package/dist/types/codemode/index.d.ts +8 -3
  41. package/dist/types/gelatiere/index.d.ts +3 -0
  42. package/dist/types/host.d.ts +2 -0
  43. package/dist/types/mcp/allow.d.ts +12 -0
  44. package/dist/types/mcp/catalog.d.ts +29 -0
  45. package/dist/types/mcp/config.d.ts +35 -0
  46. package/dist/types/mcp/connection.d.ts +57 -0
  47. package/dist/types/mcp/content.d.ts +27 -0
  48. package/dist/types/mcp/credentials.d.ts +15 -0
  49. package/dist/types/mcp/index.d.ts +16 -0
  50. package/dist/types/mcp/runtime.d.ts +42 -0
  51. package/dist/types/mcp/section.d.ts +7 -0
  52. package/dist/types/mcp/sse.d.ts +16 -0
  53. package/dist/types/mcp/tools.d.ts +44 -0
  54. package/dist/types/patches.d.ts +1 -0
  55. package/dist/types/scoops/index.d.ts +1 -0
  56. package/dist/types/scoops/service.d.ts +1 -0
  57. package/package.json +5 -4
package/README.md CHANGED
@@ -227,7 +227,8 @@ The model can write a short JavaScript program that calls its tools, with the `c
227
227
  - **Globals.** `text()`, `image()`, `console.*`, `return`, `exit()`, `ALL_TOOLS`, and `store()`/`load()`.
228
228
  - **The store** lives in the conversation document `slicc.codemode`, which is rewindable and forks as of the fork point, so each branch keeps its own values. Writes are kept only when the script succeeds.
229
229
  - **The result** starts with `Script completed` or `Script failed` and the wall time. Several text items each start with `==> text N/M <==`, and `console` lines come last in one `<console_output>` block. A failure adds `Script error:` with the error and the tool calls made before it, which aren't undone. Output past the budget keeps its start and end, and the full text goes to `/tmp/slicc-codemode-<call>.txt`.
230
- - **Not ported.** coding-agent's `models`, `searchTools`, `describeTool` and `describeNamespace`.
230
+ - **Discovery.** With MCP servers (below), `searchTools(query, { limit?, namespace? })`, `describeTool(name)` and `describeNamespace(name)` find the MCP tools that aren't listed.
231
+ - **Not ported.** coding-agent's `models`.
231
232
 
232
233
  **In the browser.** pi-codemode runs QuickJS (`quickjs-wasi`) in a worker of its own, so a spinning script never blocks the agent worker.
233
234
  - **The worker.** It starts through `node:worker_threads`, which slicc-bios provides as an `environment` stub (see Patched dependencies).
@@ -235,6 +236,46 @@ The model can write a short JavaScript program that calls its tools, with the `c
235
236
  - **Isolation.** Seven is cross-origin isolated, so pi-codemode's `SharedArrayBuffer` interrupt works.
236
237
  - **Overrides.** `runAgentWorker` takes `codemodeWasm` and `codemodeWorker` to override both, for bundled hosts.
237
238
 
239
+ ### MCP servers
240
+
241
+ MCP servers reachable over Streamable HTTP become native agent tools. The client is pi's [`@earendil-works/pi-mcp`](https://www.npmjs.com/package/@earendil-works/pi-mcp), and the rest is a port of coding-agent's built-in `mcp` extension (`docs/mcp.md`), which needs Node and can't load in the worker. stdio servers wait for slicc-kernel#68, and the `slicc-mcp` CLI is a separate project.
242
+
243
+ **The file** is `~/.pi/agent/mcp.json` in pi's format, so a pi or Claude Code `mcpServers` block can be pasted in:
244
+
245
+ ```json
246
+ {
247
+ "mcpServers": {
248
+ "docs": {
249
+ "url": "https://docs.example/mcp",
250
+ "headers": { "Authorization": "Bearer ${DOCS_TOKEN}" },
251
+ "description": "Search the product docs",
252
+ "toolExposure": { "search": "direct", "delete_*": "hidden" }
253
+ }
254
+ }
255
+ }
256
+ ```
257
+
258
+ - **Fields.** `url`, `type` (`http` or `streamable-http`), `headers`, `exposure`, `toolExposure`, `enabled`, `timeout` (seconds, default 60; progress resets it) and `description`.
259
+ - **Refused.** `command` (stdio), `type: "sse"`, `oauth`, `auth`, `!command` values, and literal secrets: a credential-like header (`Authorization`, `Cookie`, or a name with `token`, `key`, `secret`, `password` or `session`) or a URL with a password or a key in its query. The file is readable by every agent, so it holds only `${NAME}` placeholders.
260
+ - **Problems.** Each refused or broken entry is skipped and becomes one `warn` lick naming the server and the field; the other servers still connect.
261
+ - **Reconcile.** The worker watches the file. An unchanged server keeps its session, a changed one reconnects, and a removed one is closed and loses its tools. A server added later posts a "connected" lick naming its URL.
262
+
263
+ **Per agent.** Today every cone reads the one file in `/home` and gets every enabled server. A scoop doesn't read a file of its own: it inherits its cone's servers, and a role's `tools:` or `agent --tools` list narrows them. A list with no `mcp__` entry gets no MCP servers. A list with `mcp__docs__search` or `mcp__docs__*` keeps only those, and `codemode` is added so codemode tools stay reachable. The resource tools must be listed by name, and they reach only the servers the list names. A nested scoop without a list inherits its calling scoop's list. A `beforeTool` hook blocks the model's calls outside the list, and codemode scripts only get the tools on it. When kernel users give each cone its own home, each cone reads `~/.pi/agent/mcp.json` in that home, and scoops keep inheriting from their cone.
264
+
265
+ **Secrets.** `${NAME}` placeholders are filled from the agent's encrypted credential store, under `mcp:<server>|<hash of the URL>`, when the worker connects. A server whose secret is missing comes up as needing one, with a lick. Pointing a server at another URL leaves it without its secret. Header values never reach SQLite, the transcript, licks or `~/.pi/agent/mcp.log`, and stored secrets are scrubbed from error texts and server log lines. Adding the value in Settings › Accounts comes with the next release. Until then a server that needs a secret can't connect.
266
+
267
+ **Tools.** Tools are named `mcp__<server>__<tool>` (pi's names: everything but letters, digits and `_` becomes `_`, cut to 64 characters with a hash suffix on a collision). Their exposure follows pi:
268
+ - `codemode` (the default): callable from codemode scripts as `tools.mcp__docs__search(args)`, which resolves to the whole `CallToolResult`, but not declared to the model. The `mcp_servers` section lists these servers with their description or the first line of the server's instructions. It also says that MCP results are data from the server, not instructions.
269
+ - `direct`: declared to the model like a built-in tool, and callable from codemode too.
270
+ - `hidden`: unreachable.
271
+ - `deferred` counts as `codemode`, since `tool_search` isn't ported. With codemode turned off, `codemode` tools become `direct`.
272
+
273
+ A codemode script waits up to 10 s for servers still connecting. For the model, text results over 20 KB keep their start and end around a `…N chars truncated…` marker, and the full text goes to `/tmp/slicc-mcp-<call>.txt`. Images pass through, and binary resources are saved to `/tmp`. Servers with resources add pi's `list_mcp_resources`, `list_mcp_resource_templates` and `read_mcp_resource`, with the widest exposure among those servers. They skip servers whose exposure is `hidden`. MCP prompts, sampling and elicitation aren't supported, so a server can't call the model or ask the user anything.
274
+
275
+ **Network.** Requests go through the worker's transport fetch, as Bedrock's do. On the page's own fetch, a server must send CORS headers allowing `Authorization`, `Content-Type`, `Mcp-Session-Id`, `Mcp-Protocol-Version` and `Last-Event-ID`, and exposing `Mcp-Session-Id`. A server that doesn't gets a lick saying to run slicc-node, slicc-swift or the extension. Stop or a steer that aborts the turn cancels a running call (`notifications/cancelled`). Lists and reads are retried once after 408, 429 or 5xx, and tool calls never are. An interrupted call isn't rerun after a worker restart. Server log messages go to `~/.pi/agent/mcp.log`, which rolls over to `mcp.log.1` at 5 MB.
276
+
277
+ **Limiting a server** until approvals (PR 25): `"enabled": false`; `"exposure": "hidden"` with a `toolExposure` allow list; `toolExposure` deny patterns; role and `--tools` lists for scoops; and tokens or scopes that allow only what the server should do.
278
+
238
279
  ### Memory
239
280
 
240
281
  pi has no memory store or memory tool; its coding agent loads context files, and [pi-subagents](https://github.com/nicobailon/pi-subagents) gives a role a `MEMORY.md`. Both are ported here over `ExecutionEnv`.
@@ -254,6 +295,7 @@ The `memory` section, read before every request, holds the first 200 lines (at m
254
295
 
255
296
  **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.
256
297
  - `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 puts one crontab line `0 3 * * * gelatiere scoop:<handle> …` in `~/.slicc/crontab`, replacing an older one.
298
+ - **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.
257
299
  - 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:
258
300
  - kinds `skill`, `use-case`, `tip`, `skill-idea` and `issue`;
259
301
  - a `skill` with its name and its GitHub `repo` (`owner/repo`);
@@ -374,17 +416,18 @@ The built-in `sprinkles` skill teaches the files, the bridge and the command.
374
416
 
375
417
  ## The kernel
376
418
 
377
- `@ai-ecoverse/slicc-kernel` is a peer dependency (`>=1.26.3 <2`; older kernels have an IPv6-to-loopback security bug): 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 devDependency is the lowest certified kernel the range allows (1.26.3), and the unit and integration tests run on it. A second CI job reruns the integration tests on the newest certified kernel (`NEWEST_CERTIFIED_KERNEL` in `.github/workflows/ci.yml`). Today the floor is 1.26.3 and the newest certified kernel 1.40.1; the second job moves by hand to each newer certified kernel, so both ends of the range are tested. 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.
419
+ `@ai-ecoverse/slicc-kernel` is a peer dependency (`>=1.26.3 <2`; older kernels have an IPv6-to-loopback security bug): 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 devDependency is the lowest certified kernel the range allows (1.26.3), and the unit and integration tests run on it. A second CI job reruns the integration tests on the newest certified kernel (`NEWEST_CERTIFIED_KERNEL` in `.github/workflows/ci.yml`). Today the floor is 1.26.3 and the newest certified kernel 1.41.3; the second job moves by hand to each newer certified kernel, so both ends of the range are tested. 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.
378
420
 
379
421
  ## Patched dependencies
380
422
 
381
423
  Fixes to pi stay in this repository. [`patches/patches.json`](patches/patches.json) lists each one with its `kind`, `package`, `patchedVersion`, `reason`, `removeWhen` and `verify` command, and an optional `marker` (a file in the package and a string it must contain):
382
424
 
383
- - `monkeypatch`: code that runs in users' browsers is patched at runtime. `applyPatches()` in [`src/patches.ts`](src/patches.ts) applies them once before pi is used: `PortListener.start()` calls it, so `hostAgent` and a `PortListener` used directly with pi's `Server` both get them. Each one checks that the code it replaces still looks as expected and throws, naming its manifest entry, if not. Today there is one: pi-server's `Server.accept` calls `unref()` on its handshake timer, which browsers don't have, so the patch gives numeric timer ids a no-op `unref`.
425
+ - `monkeypatch`: code that runs in users' browsers is patched at runtime. pi-mcp parses SSE with Node's `Buffer.byteLength`, which browsers don't have. `patchSse()` in [`src/mcp/sse.ts`](src/mcp/sse.ts) replaces `StreamableHttpTransport.prototype.consumeSse` with the same parser measuring bytes with `TextEncoder`, before any server connects. `applyPatches()` in [`src/patches.ts`](src/patches.ts) applies them once before pi is used: `PortListener.start()` calls it, so `hostAgent` and a `PortListener` used directly with pi's `Server` both get them. Each one checks that the code it replaces still looks as expected and throws, naming its manifest entry, if not. Today there is one: pi-server's `Server.accept` calls `unref()` on its handshake timer, which browsers don't have, so the patch gives numeric timer ids a no-op `unref`.
384
426
  - `patch-package`: repository-only fixes go in `patches/<package>+<version>.patch`, applied by a `postinstall` that runs [patch-package](https://github.com/ds300/patch-package). There are none yet.
385
427
  - `environment`: something the host must provide.
386
428
  - pi-server imports `randomUUID` from `node:crypto`. slicc-bios serves a stub backed by `globalThis.crypto`, and the integration bundles alias it to `test/integration/shims/node-crypto.js`.
387
429
  - pi-codemode runs QuickJS in a `node:worker_threads` Worker. slicc-bios must serve a `node:worker_threads` stub that wraps a module Web Worker; inside the worker, the stub gives `parentPort` and `workerData` from the first message. `test/integration/shims/node-worker-threads.js` is that stub, and the integration bundles alias to it.
430
+ - pi-mcp's index re-exports its stdio transport, which imports `node:child_process`, `node:process` and the CommonJS `cross-spawn` at the top. SLICC never constructs it, so slicc-bios's `node:*` stubs and CommonJS wrapping only have to let them load; `cross-spawn`, `which` and `isexe` also read the free globals `process` and `global` when they load. The MCP runtime is imported lazily, so if it fails to load, the agent still starts, and a configured `mcp.json` gets a lick saying MCP servers can't start. The integration bundles alias all three to `test/integration/shims/node-only.js`.
388
431
  - `environment`, pruned from seven's install: slicc-bios's `/opt/agent` (its `src/packages/agent`) removes `@google/genai` and `esbuild` with pnpm overrides in `pnpm-workspace.yaml` (#22).
389
432
  - A real Bedrock turn loads 28 of 95 installed packages and never those two trees. Adobe's APIs reach only `@anthropic-ai/sdk`, `openai` and `partial-json`, so those stay.
390
433
  - The prune takes the install from 99 to 58 packages and `node_modules` from 143 to 92 MB.
@@ -33,6 +33,7 @@ const GLOBALS = [
33
33
  "- `store(key, value)` and `load(key)` keep JSON values across codemode calls in this conversation.",
34
34
  "- `ALL_TOOLS` lists every tool scripts can call."
35
35
  ].join("\n");
36
+ const DISCOVERY = "- `await searchTools(query, { limit?, namespace? })`, `await describeTool(name)`, `await describeNamespace(name)`: find unlisted tools, such as MCP tools.";
36
37
  const BASH_OUTPUT = {
37
38
  type: "object",
38
39
  properties: { output: { type: "string" }, exit_code: { type: "number" } },
@@ -46,9 +47,10 @@ function scriptTool(tool) {
46
47
  ...tool.name === "bash" ? { outputSchema: BASH_OUTPUT } : {}
47
48
  };
48
49
  }
49
- function codemodeDescription(declared) {
50
+ function codemodeDescription(declared, discovery = false) {
50
51
  const tools = declared.filter((tool) => tool.name !== CODEMODE).map((tool) => ({ ...scriptTool(tool), execute: () => void 0 }));
51
- const sections = [INTRO, GLOBALS];
52
+ const sections = [INTRO, discovery ? `${GLOBALS}
53
+ ${DISCOVERY}` : GLOBALS];
52
54
  if (tools.length) sections.push(`Nested tools:
53
55
  ${renderDeclarations({ tools })}`);
54
56
  return sections.join("\n\n");
@@ -171,7 +173,7 @@ async function saveStore(api, result, context) {
171
173
  function codemodeTool(options) {
172
174
  return defineTool({
173
175
  name: CODEMODE,
174
- description: codemodeDescription(options.declared),
176
+ description: codemodeDescription(options.declared, options.extra !== void 0),
175
177
  parameters: Type.Object({ code: Type.String({ description: "Raw JavaScript source." }) }),
176
178
  replay: "unsafe",
177
179
  async execute({ code }, api, context) {
@@ -184,9 +186,13 @@ function codemodeTool(options) {
184
186
  ...scriptTool(tool),
185
187
  execute: (args, { signal }) => callNested(tool, args, api, withAbortSignal(signal, context), `${api.callId}:${++count}`)
186
188
  }));
189
+ const extra = options.extra ? await options.extra(api, agent, context) : { tools: [], globals: [] };
190
+ const replaced = new Set(extra.tools.map((tool) => tool.name));
191
+ const scripted = [...tools.filter((tool) => !replaced.has(tool.name)), ...extra.tools];
187
192
  const saved = await api.snapshot(CodemodeDoc, api.conversationId, context);
188
193
  const sandbox = options.sandbox({
189
- tools,
194
+ tools: scripted,
195
+ ...extra.globals.length ? { globals: extra.globals } : {},
190
196
  timeoutMs: parsed.options.timeoutMs ?? Number.POSITIVE_INFINITY,
191
197
  memoryLimitBytes: MEMORY_LIMIT_BYTES
192
198
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/codemode/index.ts"],
4
- "sourcesContent": ["import type { Context, JsonValue } from '@earendil-works/chord';\nimport { withAbortSignal } from '@earendil-works/chord/context';\nimport { Type } from '@earendil-works/pi-ai';\nimport { validateToolArguments } from '@earendil-works/pi-ai/utils/validation';\nimport {\n type CodemodeError,\n type CodemodeJsonSchema,\n type CodemodeOutputItem,\n type CodemodeResult,\n CodemodeSandbox,\n type CodemodeSandboxOptions,\n type CodemodeTool,\n loadQuickJSWasm,\n parseCodemodeSource,\n renderDeclarations,\n} from '@earendil-works/pi-codemode';\nimport {\n defineDoc,\n defineExtension,\n defineTool,\n type Extension,\n type ToolExecutionApi,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\n\nexport const CODEMODE = 'codemode';\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 10_000;\nexport const MEMORY_LIMIT_BYTES = 256 * 1024 * 1024;\nconst CHARS_PER_TOKEN = 4;\n\nexport const CodemodeDoc = defineDoc<{ store: Record<string, JsonValue> }>({\n kind: 'slicc.codemode',\n version: 1,\n scope: 'conversation',\n history: 'rewindable',\n fork: 'asOf',\n initial: () => ({ store: {} }),\n});\n\nexport interface Sandbox {\n execute(\n code: string,\n options: { signal?: AbortSignal; store?: Record<string, unknown> }\n ): Promise<CodemodeResult>;\n close(): Promise<void>;\n}\n\nexport type SandboxFactory = (options: CodemodeSandboxOptions) => Sandbox;\n\nexport interface CodemodeOptions {\n sandbox: SandboxFactory;\n declared: readonly ToolRegistration[];\n}\n\nconst INTRO = `Run JavaScript that calls other tools. The input is raw JavaScript (not JSON, no code fence), run as an async function body in a QuickJS sandbox: top-level \\`await\\` and \\`return\\` work. No Node, file system, network, or timers.\n- \\`await tools.<name>({ ...args })\\` resolves to a string, or an object if the tool's declaration says so, and rejects with an Error on failure. Calls still running when the script ends are cancelled.\n- Optional first line: \\`// @options: {\"max_output_tokens\": 10000, \"timeout_ms\": 60000}\\``;\n\nconst GLOBALS = [\n 'Globals:',\n '- `text(value)`, `image(dataUrlOrImageBlock)`, `console.log(...)`, and top-level `return` add output; `exit()` ends the script. With several text items, each starts with a `==> text N/M <==` line, and `console` lines follow the other output in one `<console_output>` block.',\n '- `store(key, value)` and `load(key)` keep JSON values across codemode calls in this conversation.',\n '- `ALL_TOOLS` lists every tool scripts can call.',\n].join('\\n');\n\nconst BASH_OUTPUT: CodemodeJsonSchema = {\n type: 'object',\n properties: { output: { type: 'string' }, exit_code: { type: 'number' } },\n required: ['output', 'exit_code'],\n};\n\nfunction scriptTool(tool: ToolRegistration): Omit<CodemodeTool, 'execute'> {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.parameters as CodemodeJsonSchema,\n ...(tool.name === 'bash' ? { outputSchema: BASH_OUTPUT } : {}),\n };\n}\n\nexport function codemodeDescription(declared: readonly ToolRegistration[]): string {\n const tools = declared\n .filter((tool) => tool.name !== CODEMODE)\n .map((tool) => ({ ...scriptTool(tool), execute: () => undefined }));\n const sections = [INTRO, GLOBALS];\n if (tools.length) sections.push(`Nested tools:\\n${renderDeclarations({ tools })}`);\n return sections.join('\\n\\n');\n}\n\nfunction textOf(content: readonly { type: string; text?: string }[] | undefined): string {\n return (content ?? [])\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('\\n');\n}\n\nexport async function callNested(\n tool: ToolRegistration,\n args: unknown,\n api: ToolExecutionApi,\n context: Context,\n id: string\n): Promise<unknown> {\n const prepared = tool.prepareArguments ? tool.prepareArguments(args) : args;\n const valid = validateToolArguments(tool, {\n type: 'toolCall',\n id,\n name: tool.name,\n arguments: prepared as never,\n });\n const decoder = new TextDecoder();\n let output = '';\n const nested: ToolExecutionApi = {\n ...api,\n callId: id,\n outputWindow: undefined,\n output: (chunk) => {\n output += typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true });\n },\n diagnostic: () => undefined,\n details: async () => undefined,\n };\n const bash = tool.name === 'bash';\n try {\n const result = await tool.execute(valid, nested, context);\n const text = result.content ? textOf(result.content) : output;\n if (result.isError) throw new Error(text || `Tool \"${tool.name}\" failed`);\n return bash ? { output: text, exit_code: 0 } : text;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const exit = /exited with code (\\d+)/.exec(message);\n if (bash && exit) return { output, exit_code: Number(exit[1]) };\n throw new Error(message);\n }\n}\n\nfunction valueText(value: unknown): string {\n return typeof value === 'string' ? value : (JSON.stringify(value) ?? String(value));\n}\n\nexport function formatOutput(output: readonly CodemodeOutputItem[]): CodemodeOutputItem[] {\n const total = output.filter((item) => item.type === 'text' && !item.console).length;\n const items: CodemodeOutputItem[] = [];\n const lines: string[] = [];\n let index = 0;\n for (const item of output) {\n if (item.type === 'image') items.push(item);\n else if (item.console) lines.push(item.text);\n else {\n index++;\n items.push({\n type: 'text',\n text: total > 1 ? `==> text ${index}/${total} <==\\n${item.text}` : item.text,\n });\n }\n }\n if (lines.length)\n items.push({ type: 'text', text: `<console_output>\\n${lines.join('\\n')}\\n</console_output>` });\n return items;\n}\n\nexport function joinText(items: readonly CodemodeOutputItem[]): CodemodeOutputItem[] {\n const joined: CodemodeOutputItem[] = [];\n for (const item of items) {\n const last = joined.at(-1);\n if (item.type === 'text' && last?.type === 'text') {\n const separator = last.text === '' || last.text.endsWith('\\n') ? '' : '\\n';\n joined[joined.length - 1] = { type: 'text', text: `${last.text}${separator}${item.text}` };\n } else joined.push(item);\n }\n return joined;\n}\n\nexport function formatError(error: CodemodeError, calls: CodemodeResult['calls']): string {\n const heads: Record<string, string> = {\n timeout: `Script timed out: ${error.message}`,\n aborted: `Script aborted: ${error.message}`,\n sandbox: `Script sandbox failed: ${error.message}`,\n };\n const head =\n error.kind === 'script'\n ? (error.stack ?? `${error.name ?? 'Error'}: ${error.message}`)\n : heads[error.kind];\n const summary = calls.length\n ? `Tool calls made before the failure (they are not undone): ${calls.map((call) => `${call.name} (${call.status})`).join(', ')}`\n : 'No tool calls were made.';\n return `${head}\\n\\n${summary}`;\n}\n\nexport function truncate(\n items: readonly CodemodeOutputItem[],\n maxTokens: number\n): { items: CodemodeOutputItem[]; full: string | null } {\n const text = items\n .filter((item) => item.type === 'text')\n .map((item) => item.text)\n .join('\\n');\n const limit = maxTokens * CHARS_PER_TOKEN;\n if (text.length <= limit) return { items: [...items], full: null };\n const half = Math.floor(limit / 2);\n const kept = `${text.slice(0, half)}\\n\\n[\u2026 ${text.length - 2 * half} characters omitted \u2026]\\n\\n${text.slice(-half)}`;\n return {\n items: [{ type: 'text', text: kept }, ...items.filter((item) => item.type === 'image')],\n full: text,\n };\n}\n\nasync function spill(api: ToolExecutionApi, text: string, context: Context): Promise<string> {\n const path = `/tmp/slicc-codemode-${api.callId.replace(/[^\\w-]/g, '_')}.txt`;\n const written = await api.env?.writeFile(path, text, context);\n return written?.ok ? path : '';\n}\n\nasync function saveStore(\n api: ToolExecutionApi,\n result: CodemodeResult,\n context: Context\n): Promise<void> {\n if (!result.ok) return;\n const { set, delete: removed } = result.storeWrites;\n if (!Object.keys(set).length && !removed.length) return;\n await api.commit(async (tx) => {\n const doc = await tx.doc(CodemodeDoc, api.conversationId);\n for (const key of removed) delete doc.store[key];\n Object.assign(doc.store, set);\n }, context);\n}\n\nexport function codemodeTool(options: CodemodeOptions): ToolRegistration {\n return defineTool({\n name: CODEMODE,\n description: codemodeDescription(options.declared),\n parameters: Type.Object({ code: Type.String({ description: 'Raw JavaScript source.' }) }),\n replay: 'unsafe',\n async execute({ code }, api, context) {\n const started = performance.now();\n const parsed = parseCodemodeSource(code);\n const agent = await api.agent(context);\n const callable = agent.tools.filter((tool) => tool.name !== CODEMODE);\n let count = 0;\n const tools: CodemodeTool[] = callable.map((tool) => ({\n ...scriptTool(tool),\n execute: (args, { signal }) =>\n callNested(tool, args, api, withAbortSignal(signal, context), `${api.callId}:${++count}`),\n }));\n const saved = await api.snapshot(CodemodeDoc, api.conversationId, context);\n const sandbox = options.sandbox({\n tools,\n timeoutMs: parsed.options.timeoutMs ?? Number.POSITIVE_INFINITY,\n memoryLimitBytes: MEMORY_LIMIT_BYTES,\n });\n let result: CodemodeResult;\n try {\n result = await sandbox.execute(parsed.code, {\n signal: context.abortSignal as AbortSignal,\n store: { ...saved?.store },\n });\n } finally {\n await sandbox.close();\n }\n await saveStore(api, result, context);\n const output = [...result.output];\n if (result.ok && result.value !== undefined)\n output.push({ type: 'text', text: valueText(result.value) });\n const items = formatOutput(output);\n if (!result.ok)\n items.push({\n type: 'text',\n text: `Script error:\\n${formatError(result.error, result.calls)}`,\n });\n const cut = truncate(\n joinText(items),\n parsed.options.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS\n );\n const path = cut.full === null ? '' : await spill(api, cut.full, context);\n const note = path ? [{ type: 'text' as const, text: `Full output: ${path}` }] : [];\n const seconds = ((performance.now() - started) / 1000).toFixed(1);\n const header = `${result.ok ? 'Script completed' : 'Script failed'}\\nWall time ${seconds} seconds\\nOutput:\\n`;\n return {\n content: [{ type: 'text', text: header }, ...joinText([...cut.items, ...note])],\n ...(result.ok ? {} : { isError: true }),\n };\n },\n }) as ToolRegistration;\n}\n\nexport function codemodeExtension(tools: readonly ToolRegistration[]): Extension {\n return defineExtension({ name: 'slicc-codemode', tools });\n}\n\nexport function disabledBySettings(text: string | undefined): boolean {\n if (!text) return false;\n try {\n const settings = JSON.parse(text) as { defaultTools?: unknown };\n return Array.isArray(settings.defaultTools) && settings.defaultTools.includes(`-${CODEMODE}`);\n } catch {\n return false;\n }\n}\n\nexport type Fetcher = (url: string) => Promise<Response>;\n\nexport function wasmCandidates(from: URL): string[] {\n const out: string[] = [];\n let dir = new URL('.', from);\n for (;;) {\n out.push(new URL('node_modules/quickjs-wasi/quickjs.wasm', dir).href);\n if (dir.pathname === '/') return out;\n dir = new URL('..', dir);\n }\n}\n\nexport async function locateWasm(\n fetcher: Fetcher,\n from: URL\n): Promise<WebAssembly.Module | undefined> {\n for (const url of wasmCandidates(from)) {\n const response = await fetcher(url).catch(() => undefined);\n if (response?.ok) return WebAssembly.compile(await response.arrayBuffer());\n }\n return undefined;\n}\n\nexport function sandboxFactory(\n wasm: () => Promise<WebAssembly.Module | undefined>,\n workerUrl?: string | URL\n): SandboxFactory {\n let found: Promise<WebAssembly.Module | undefined> | undefined;\n return (options) => {\n found ??= wasm().catch(() => undefined);\n return new CodemodeSandbox({\n ...options,\n ...(workerUrl ? { workerUrl } : {}),\n wasm: found.then((module) => module ?? loadQuickJSWasm()),\n });\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Context, JsonValue } from '@earendil-works/chord';\nimport { withAbortSignal } from '@earendil-works/chord/context';\nimport { Type } from '@earendil-works/pi-ai';\nimport { validateToolArguments } from '@earendil-works/pi-ai/utils/validation';\nimport {\n type CodemodeError,\n type CodemodeJsonSchema,\n type CodemodeOutputItem,\n type CodemodeResult,\n CodemodeSandbox,\n type CodemodeSandboxOptions,\n type CodemodeTool,\n loadQuickJSWasm,\n parseCodemodeSource,\n renderDeclarations,\n} from '@earendil-works/pi-codemode';\nimport {\n type Agent,\n defineDoc,\n defineExtension,\n defineTool,\n type Extension,\n type ToolExecutionApi,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\n\nexport const CODEMODE = 'codemode';\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 10_000;\nexport const MEMORY_LIMIT_BYTES = 256 * 1024 * 1024;\nconst CHARS_PER_TOKEN = 4;\n\nexport const CodemodeDoc = defineDoc<{ store: Record<string, JsonValue> }>({\n kind: 'slicc.codemode',\n version: 1,\n scope: 'conversation',\n history: 'rewindable',\n fork: 'asOf',\n initial: () => ({ store: {} }),\n});\n\nexport interface Sandbox {\n execute(\n code: string,\n options: { signal?: AbortSignal; store?: Record<string, unknown> }\n ): Promise<CodemodeResult>;\n close(): Promise<void>;\n}\n\nexport type SandboxFactory = (options: CodemodeSandboxOptions) => Sandbox;\n\nexport interface CodemodeExtra {\n tools: CodemodeTool[];\n globals: CodemodeTool[];\n}\n\nexport interface CodemodeOptions {\n sandbox: SandboxFactory;\n declared: readonly ToolRegistration[];\n extra?: (api: ToolExecutionApi, agent: Agent, context: Context) => Promise<CodemodeExtra>;\n}\n\nconst INTRO = `Run JavaScript that calls other tools. The input is raw JavaScript (not JSON, no code fence), run as an async function body in a QuickJS sandbox: top-level \\`await\\` and \\`return\\` work. No Node, file system, network, or timers.\n- \\`await tools.<name>({ ...args })\\` resolves to a string, or an object if the tool's declaration says so, and rejects with an Error on failure. Calls still running when the script ends are cancelled.\n- Optional first line: \\`// @options: {\"max_output_tokens\": 10000, \"timeout_ms\": 60000}\\``;\n\nconst GLOBALS = [\n 'Globals:',\n '- `text(value)`, `image(dataUrlOrImageBlock)`, `console.log(...)`, and top-level `return` add output; `exit()` ends the script. With several text items, each starts with a `==> text N/M <==` line, and `console` lines follow the other output in one `<console_output>` block.',\n '- `store(key, value)` and `load(key)` keep JSON values across codemode calls in this conversation.',\n '- `ALL_TOOLS` lists every tool scripts can call.',\n].join('\\n');\n\nconst DISCOVERY =\n '- `await searchTools(query, { limit?, namespace? })`, `await describeTool(name)`, `await describeNamespace(name)`: find unlisted tools, such as MCP tools.';\n\nconst BASH_OUTPUT: CodemodeJsonSchema = {\n type: 'object',\n properties: { output: { type: 'string' }, exit_code: { type: 'number' } },\n required: ['output', 'exit_code'],\n};\n\nfunction scriptTool(tool: ToolRegistration): Omit<CodemodeTool, 'execute'> {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.parameters as CodemodeJsonSchema,\n ...(tool.name === 'bash' ? { outputSchema: BASH_OUTPUT } : {}),\n };\n}\n\nexport function codemodeDescription(\n declared: readonly ToolRegistration[],\n discovery = false\n): string {\n const tools = declared\n .filter((tool) => tool.name !== CODEMODE)\n .map((tool) => ({ ...scriptTool(tool), execute: () => undefined }));\n const sections = [INTRO, discovery ? `${GLOBALS}\\n${DISCOVERY}` : GLOBALS];\n if (tools.length) sections.push(`Nested tools:\\n${renderDeclarations({ tools })}`);\n return sections.join('\\n\\n');\n}\n\nfunction textOf(content: readonly { type: string; text?: string }[] | undefined): string {\n return (content ?? [])\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('\\n');\n}\n\nexport async function callNested(\n tool: ToolRegistration,\n args: unknown,\n api: ToolExecutionApi,\n context: Context,\n id: string\n): Promise<unknown> {\n const prepared = tool.prepareArguments ? tool.prepareArguments(args) : args;\n const valid = validateToolArguments(tool, {\n type: 'toolCall',\n id,\n name: tool.name,\n arguments: prepared as never,\n });\n const decoder = new TextDecoder();\n let output = '';\n const nested: ToolExecutionApi = {\n ...api,\n callId: id,\n outputWindow: undefined,\n output: (chunk) => {\n output += typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true });\n },\n diagnostic: () => undefined,\n details: async () => undefined,\n };\n const bash = tool.name === 'bash';\n try {\n const result = await tool.execute(valid, nested, context);\n const text = result.content ? textOf(result.content) : output;\n if (result.isError) throw new Error(text || `Tool \"${tool.name}\" failed`);\n return bash ? { output: text, exit_code: 0 } : text;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const exit = /exited with code (\\d+)/.exec(message);\n if (bash && exit) return { output, exit_code: Number(exit[1]) };\n throw new Error(message);\n }\n}\n\nfunction valueText(value: unknown): string {\n return typeof value === 'string' ? value : (JSON.stringify(value) ?? String(value));\n}\n\nexport function formatOutput(output: readonly CodemodeOutputItem[]): CodemodeOutputItem[] {\n const total = output.filter((item) => item.type === 'text' && !item.console).length;\n const items: CodemodeOutputItem[] = [];\n const lines: string[] = [];\n let index = 0;\n for (const item of output) {\n if (item.type === 'image') items.push(item);\n else if (item.console) lines.push(item.text);\n else {\n index++;\n items.push({\n type: 'text',\n text: total > 1 ? `==> text ${index}/${total} <==\\n${item.text}` : item.text,\n });\n }\n }\n if (lines.length)\n items.push({ type: 'text', text: `<console_output>\\n${lines.join('\\n')}\\n</console_output>` });\n return items;\n}\n\nexport function joinText(items: readonly CodemodeOutputItem[]): CodemodeOutputItem[] {\n const joined: CodemodeOutputItem[] = [];\n for (const item of items) {\n const last = joined.at(-1);\n if (item.type === 'text' && last?.type === 'text') {\n const separator = last.text === '' || last.text.endsWith('\\n') ? '' : '\\n';\n joined[joined.length - 1] = { type: 'text', text: `${last.text}${separator}${item.text}` };\n } else joined.push(item);\n }\n return joined;\n}\n\nexport function formatError(error: CodemodeError, calls: CodemodeResult['calls']): string {\n const heads: Record<string, string> = {\n timeout: `Script timed out: ${error.message}`,\n aborted: `Script aborted: ${error.message}`,\n sandbox: `Script sandbox failed: ${error.message}`,\n };\n const head =\n error.kind === 'script'\n ? (error.stack ?? `${error.name ?? 'Error'}: ${error.message}`)\n : heads[error.kind];\n const summary = calls.length\n ? `Tool calls made before the failure (they are not undone): ${calls.map((call) => `${call.name} (${call.status})`).join(', ')}`\n : 'No tool calls were made.';\n return `${head}\\n\\n${summary}`;\n}\n\nexport function truncate(\n items: readonly CodemodeOutputItem[],\n maxTokens: number\n): { items: CodemodeOutputItem[]; full: string | null } {\n const text = items\n .filter((item) => item.type === 'text')\n .map((item) => item.text)\n .join('\\n');\n const limit = maxTokens * CHARS_PER_TOKEN;\n if (text.length <= limit) return { items: [...items], full: null };\n const half = Math.floor(limit / 2);\n const kept = `${text.slice(0, half)}\\n\\n[\u2026 ${text.length - 2 * half} characters omitted \u2026]\\n\\n${text.slice(-half)}`;\n return {\n items: [{ type: 'text', text: kept }, ...items.filter((item) => item.type === 'image')],\n full: text,\n };\n}\n\nasync function spill(api: ToolExecutionApi, text: string, context: Context): Promise<string> {\n const path = `/tmp/slicc-codemode-${api.callId.replace(/[^\\w-]/g, '_')}.txt`;\n const written = await api.env?.writeFile(path, text, context);\n return written?.ok ? path : '';\n}\n\nasync function saveStore(\n api: ToolExecutionApi,\n result: CodemodeResult,\n context: Context\n): Promise<void> {\n if (!result.ok) return;\n const { set, delete: removed } = result.storeWrites;\n if (!Object.keys(set).length && !removed.length) return;\n await api.commit(async (tx) => {\n const doc = await tx.doc(CodemodeDoc, api.conversationId);\n for (const key of removed) delete doc.store[key];\n Object.assign(doc.store, set);\n }, context);\n}\n\nexport function codemodeTool(options: CodemodeOptions): ToolRegistration {\n return defineTool({\n name: CODEMODE,\n description: codemodeDescription(options.declared, options.extra !== undefined),\n parameters: Type.Object({ code: Type.String({ description: 'Raw JavaScript source.' }) }),\n replay: 'unsafe',\n async execute({ code }, api, context) {\n const started = performance.now();\n const parsed = parseCodemodeSource(code);\n const agent = await api.agent(context);\n const callable = agent.tools.filter((tool) => tool.name !== CODEMODE);\n let count = 0;\n const tools: CodemodeTool[] = callable.map((tool) => ({\n ...scriptTool(tool),\n execute: (args, { signal }) =>\n callNested(tool, args, api, withAbortSignal(signal, context), `${api.callId}:${++count}`),\n }));\n const extra = options.extra\n ? await options.extra(api, agent, context)\n : { tools: [], globals: [] };\n const replaced = new Set(extra.tools.map((tool) => tool.name));\n const scripted = [...tools.filter((tool) => !replaced.has(tool.name)), ...extra.tools];\n const saved = await api.snapshot(CodemodeDoc, api.conversationId, context);\n const sandbox = options.sandbox({\n tools: scripted,\n ...(extra.globals.length ? { globals: extra.globals } : {}),\n timeoutMs: parsed.options.timeoutMs ?? Number.POSITIVE_INFINITY,\n memoryLimitBytes: MEMORY_LIMIT_BYTES,\n });\n let result: CodemodeResult;\n try {\n result = await sandbox.execute(parsed.code, {\n signal: context.abortSignal as AbortSignal,\n store: { ...saved?.store },\n });\n } finally {\n await sandbox.close();\n }\n await saveStore(api, result, context);\n const output = [...result.output];\n if (result.ok && result.value !== undefined)\n output.push({ type: 'text', text: valueText(result.value) });\n const items = formatOutput(output);\n if (!result.ok)\n items.push({\n type: 'text',\n text: `Script error:\\n${formatError(result.error, result.calls)}`,\n });\n const cut = truncate(\n joinText(items),\n parsed.options.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS\n );\n const path = cut.full === null ? '' : await spill(api, cut.full, context);\n const note = path ? [{ type: 'text' as const, text: `Full output: ${path}` }] : [];\n const seconds = ((performance.now() - started) / 1000).toFixed(1);\n const header = `${result.ok ? 'Script completed' : 'Script failed'}\\nWall time ${seconds} seconds\\nOutput:\\n`;\n return {\n content: [{ type: 'text', text: header }, ...joinText([...cut.items, ...note])],\n ...(result.ok ? {} : { isError: true }),\n };\n },\n }) as ToolRegistration;\n}\n\nexport function codemodeExtension(tools: readonly ToolRegistration[]): Extension {\n return defineExtension({ name: 'slicc-codemode', tools });\n}\n\nexport function disabledBySettings(text: string | undefined): boolean {\n if (!text) return false;\n try {\n const settings = JSON.parse(text) as { defaultTools?: unknown };\n return Array.isArray(settings.defaultTools) && settings.defaultTools.includes(`-${CODEMODE}`);\n } catch {\n return false;\n }\n}\n\nexport type Fetcher = (url: string) => Promise<Response>;\n\nexport function wasmCandidates(from: URL): string[] {\n const out: string[] = [];\n let dir = new URL('.', from);\n for (;;) {\n out.push(new URL('node_modules/quickjs-wasi/quickjs.wasm', dir).href);\n if (dir.pathname === '/') return out;\n dir = new URL('..', dir);\n }\n}\n\nexport async function locateWasm(\n fetcher: Fetcher,\n from: URL\n): Promise<WebAssembly.Module | undefined> {\n for (const url of wasmCandidates(from)) {\n const response = await fetcher(url).catch(() => undefined);\n if (response?.ok) return WebAssembly.compile(await response.arrayBuffer());\n }\n return undefined;\n}\n\nexport function sandboxFactory(\n wasm: () => Promise<WebAssembly.Module | undefined>,\n workerUrl?: string | URL\n): SandboxFactory {\n let found: Promise<WebAssembly.Module | undefined> | undefined;\n return (options) => {\n found ??= wasm().catch(() => undefined);\n return new CodemodeSandbox({\n ...options,\n ...(workerUrl ? { workerUrl } : {}),\n wasm: found.then((module) => module ?? loadQuickJSWasm()),\n });\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,3 +1,4 @@
1
+ import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
1
2
  import { live } from "../agents.js";
2
3
  import { skillFromText } from "../skills/skills.js";
3
4
  import {
@@ -58,16 +59,44 @@ async function schedule(g, handle, context) {
58
59
  await env.writeFile(g.crontab, `${[...kept, line(handle)].join("\n")}
59
60
  `, context);
60
61
  }
61
- async function seed(g, context) {
62
+ const SHIPPED = [
63
+ "53bc19daa486dec24116d8cf0558a498d8476dc4e18874f8a3e9ccb9defb15bd",
64
+ "1c16654b93bc01179a71ec907919f45132b2e9f1a9ac331b213655c66387b4e5",
65
+ "3bdd8ae18831c37996413cb0277df7141fcd0dff2d056c7b7053c34f0a3beaac",
66
+ "23a063c8156fda9fb0ffdea20172a7f64c1576d1c009a28456c095e2866fc0e9"
67
+ ];
68
+ async function sha256(text) {
69
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
70
+ return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
71
+ }
72
+ async function seed(g, context, create) {
62
73
  const { env, assets } = g.options;
63
- const existing = await env.exists(g.procedure, context);
64
- if (existing.ok && existing.value || !assets) return;
65
- const text = await assets(PROCEDURE).catch(() => void 0);
66
- if (text !== void 0) await env.writeFile(g.procedure, text, context);
74
+ const text = assets ? await assets(PROCEDURE).catch(() => void 0) : void 0;
75
+ if (text === void 0) return "none";
76
+ const bundled = await sha256(text);
77
+ const marker = `${g.procedure}.sha256`;
78
+ const must = (result) => {
79
+ if (!result.ok) throw new Error(result.error?.message ?? "write failed");
80
+ };
81
+ const write = async (state) => {
82
+ must(await env.writeFile(g.procedure, text, context));
83
+ must(await env.writeFile(marker, `${bundled}
84
+ `, context));
85
+ must(await env.remove(g.pending, { force: true }, context));
86
+ return state;
87
+ };
88
+ const read = await env.readTextFile(g.procedure, context);
89
+ if (!read.ok) return create ? write("written") : "none";
90
+ const mine = await sha256(read.value);
91
+ if (mine === bundled) return write("current");
92
+ const last = await env.readTextFile(marker, context);
93
+ if (last.ok && last.value.trim() === mine || SHIPPED.includes(mine)) return write("updated");
94
+ must(await env.writeFile(g.pending, text, context));
95
+ return "kept";
67
96
  }
68
97
  async function init(g, context) {
69
98
  const { options } = g;
70
- await seed(g, context);
99
+ await seed(g, context, true);
71
100
  let handle = handleOf(options.agents);
72
101
  if (!handle) {
73
102
  const roles = await options.roles(context);
@@ -330,10 +359,14 @@ async function status(g, context) {
330
359
  const read = await env.readTextFile(g.crontab, context);
331
360
  const scheduled = (read.ok ? read.value : "").split("\n").map(scheduleOf).find(Boolean);
332
361
  const counts = store ? `${open(store).length} open, ${store.filter((item) => item.takenAt).length} taken, ${store.filter((item) => item.dismissedAt).length} dismissed` : "none yet";
362
+ const pending = await env.readTextFile(g.pending, context);
333
363
  const lines = [
334
364
  `scoop: ${handle ?? "none (gelatiere init)"}`,
335
365
  `schedule: ${scheduled ?? "none"}`,
336
- `store: ${counts}`
366
+ `store: ${counts}`,
367
+ ...pending.ok ? [
368
+ `procedure: ${g.procedure} has your edits, so it was kept; the new built-in one is ${g.pending}`
369
+ ] : []
337
370
  ];
338
371
  return { code: 0, out: `${lines.join("\n")}
339
372
  ` };
@@ -369,6 +402,7 @@ function attachGelatiere(options) {
369
402
  now,
370
403
  crontab: `${home}/.slicc/crontab`,
371
404
  procedure: `${home}/.pi/agent/GELATIERE.md`,
405
+ pending: `${home}/.pi/agent/GELATIERE.new.md`,
372
406
  load,
373
407
  mark: (id, field, context) => serial(async () => {
374
408
  const store = await load(context);
@@ -379,12 +413,15 @@ function attachGelatiere(options) {
379
413
  return true;
380
414
  })
381
415
  };
416
+ const seeded = seed(g, BACKGROUND_CONTEXT, false).catch(() => "none");
382
417
  return {
383
- command(argv, _caller, context) {
418
+ seeded,
419
+ async command(argv, _caller, context) {
384
420
  const verb = argv[0] ?? "help";
385
421
  const handler = VERBS[verb];
422
+ await seeded;
386
423
  if (handler) return handler(g, argv, context);
387
- return Promise.resolve({ code: verb === "help" || verb === "--help" ? 0 : 2, out: USAGE });
424
+ return { code: verb === "help" || verb === "--help" ? 0 : 2, out: USAGE };
388
425
  },
389
426
  async intercept(action, data, context) {
390
427
  const id = String(data?.id ?? "");
@@ -418,6 +455,7 @@ export {
418
455
  PROCEDURE,
419
456
  ROLE,
420
457
  SCHEDULE,
458
+ SHIPPED,
421
459
  SPRINKLE,
422
460
  USAGE,
423
461
  attachGelatiere,
@@ -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 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 { fold, open, readStore, STORE, type Suggestion, validate, writeStore } 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}\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}\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 load: (context: Context) => Promise<Suggestion[]>;\n mark: (id: string, field: 'dismissedAt' | 'takenAt', context: Context) => Promise<boolean>;\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 { env, home } = g.options;\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\nasync function seed(g: G, context: Context): Promise<void> {\n const { env, assets } = g.options;\n const existing = await env.exists(g.procedure, context);\n if ((existing.ok && existing.value) || !assets) return;\n const text = await assets(PROCEDURE).catch(() => undefined);\n if (text !== undefined) await env.writeFile(g.procedure, text, context);\n}\n\nasync function init(g: G, context: Context): Promise<Answer> {\n const { options } = g;\n await seed(g, context);\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 g.options.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);\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: 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);\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 } = g.options;\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(`${g.options.home}/${PROFILE}`, context);\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, home } = g.options;\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`, `${CATALOG_DIR}/catalog.json`, context),\n company\n ? sheet(options, `${base}${company}.json`, `${CATALOG_DIR}/company-${company}.json`, context)\n : undefined,\n sheet(options, `${base}use-cases.json`, `${CATALOG_DIR}/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(env, 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);\n const handle = handleOf(agents);\n const read = await env.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 lines = [\n `scoop: ${handle ?? 'none (gelatiere init)'}`,\n `schedule: ${scheduled ?? 'none'}`,\n `store: ${counts}`,\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 load = async (context: Context) => (await readStore(env, context)) ?? [];\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 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);\n return true;\n }),\n };\n return {\n command(argv, _caller, context) {\n const verb = argv[0] ?? 'help';\n const handler = VERBS[verb];\n if (handler) return handler(g, argv, context);\n return Promise.resolve({ 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 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 { fold, open, readStore, STORE, type Suggestion, validate, writeStore } 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}\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};\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 { env, home } = g.options;\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 { env, assets } = g.options;\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 g.options.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);\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: 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);\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 } = g.options;\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(`${g.options.home}/${PROFILE}`, context);\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, home } = g.options;\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`, `${CATALOG_DIR}/catalog.json`, context),\n company\n ? sheet(options, `${base}${company}.json`, `${CATALOG_DIR}/company-${company}.json`, context)\n : undefined,\n sheet(options, `${base}use-cases.json`, `${CATALOG_DIR}/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(env, 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);\n const handle = handleOf(agents);\n const read = await env.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 env.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 load = async (context: Context) => (await readStore(env, context)) ?? [];\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 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);\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, 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
  }
package/dist/host.js CHANGED
@@ -152,6 +152,7 @@ async function hostAgent(agent, options = {}) {
152
152
  await options.memory?.close(context);
153
153
  await options.sprinkles?.close(context);
154
154
  await options.skills?.close(context);
155
+ await options.mcp?.close(context);
155
156
  await options.scoops?.runtime.close(context);
156
157
  await options.licks?.sources.close(context);
157
158
  await agent.close();
package/dist/host.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/host.ts"],
4
- "sourcesContent": ["import {\n type Context,\n createRemoteServiceEndpoint,\n RemoteServiceProvider,\n replicatedState,\n} from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport {\n type RoutedServerServiceHost,\n type RoutedSessionAttachment,\n type RoutedSessionHandle,\n Server,\n type ServerHost,\n SessionNotFoundError,\n} from '@earendil-works/pi-server';\nimport type { Agent } from './agent.ts';\nimport type { ChangesView } from './changes/git.ts';\nimport type { ChangesRuntime } from './changes/index.ts';\nimport { createAgentControl, type HostLicks, type HostScoops } from './control.ts';\nimport { trackDeliveries } from './deliveries.ts';\nimport type { FreezerRuntime, FrozenCone } from './freezer/index.ts';\nimport { PortListener } from './listener.ts';\nimport type { MemoryEntry, MemoryScope } from './memory/format.ts';\nimport type { MemoryRuntime } from './memory/index.ts';\nimport {\n AGENT_SESSION,\n AgentControl,\n AgentSessions,\n AgentSettings,\n AgentTranscript,\n type Command,\n} from './services.ts';\nimport type { SkillsRuntime } from './skills/index.ts';\nimport type { SprinklesRuntime } from './sprinkles/index.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\nimport { agentViews } from './views.ts';\nimport type { PortEndpoint } from './wire.ts';\n\nexport interface AgentHost {\n readonly serverId: string;\n readonly agent: Agent;\n connect(endpoint: PortEndpoint): void;\n close(): Promise<void>;\n}\n\nfunction endpointFor(provider: RemoteServiceProvider): RoutedSessionAttachment {\n const endpoint = createRemoteServiceEndpoint(provider);\n return {\n invokeService: (call, publish, context) =>\n endpoint.invoke(call, (id, update) => publish(id, update, context), context),\n release: () => endpoint.dispose(),\n };\n}\n\nfunction sessionServices(provider: RemoteServiceProvider): RoutedSessionHandle {\n return {\n attachClient: () => endpointFor(provider),\n close: async () => {},\n };\n}\n\nfunction serverServices(): RoutedServerServiceHost {\n return {\n attachClient(presentation) {\n const provider = new RemoteServiceProvider([{ service: AgentSessions, mode: 'singleton' }]);\n provider.provide(AgentSessions, {\n attach: (sessionId, context) => presentation.attachSession(sessionId, context),\n detach: (context) => presentation.detachSession(context),\n });\n const attachment = endpointFor(provider);\n return {\n invokeService: attachment.invokeService,\n release(context) {\n attachment.release(context);\n provider.dispose();\n },\n };\n },\n };\n}\n\nconst noSettings: AgentSettings = {\n state: replicatedState({ models: [], accounts: [] }),\n connect: async () => {\n throw new Error('this agent has no accounts');\n },\n disconnect: async () => {},\n signIn: async () => null,\n};\n\nasync function follow(agent: Agent, context: Context) {\n let attached = await agent.cone().viewState(context);\n const state = replicatedState<ConversationView>(attached.value);\n const mirror = (value: ConversationView, from: Context) => state.replace(from, value);\n let off = attached.subscribe(mirror);\n const stop = agent.onCone(async (conversation) => {\n const next = await conversation.viewState(context);\n off();\n attached.dispose();\n attached = next;\n state.replace(context, next.value);\n off = next.subscribe(mirror);\n });\n return {\n state,\n dispose() {\n stop();\n off();\n attached.dispose();\n },\n };\n}\n\nexport async function hostAgent(\n agent: Agent,\n options: {\n serverId?: string;\n context?: Context;\n settings?: AgentSettings;\n licks?: HostLicks;\n scoops?: HostScoops;\n skills?: SkillsRuntime;\n sprinkles?: SprinklesRuntime;\n memory?: MemoryRuntime;\n freezer?: FreezerRuntime;\n changes?: ChangesRuntime;\n } = {}\n): Promise<AgentHost> {\n const context = options.context ?? BACKGROUND_CONTEXT;\n const serverId = options.serverId ?? crypto.randomUUID();\n const transcript = await follow(agent, context);\n const { state } = transcript;\n const mounted = await agentViews(agent, context);\n const touch = () => options.freezer?.touch();\n const untouch = [state.subscribe(touch), mounted.views.subscribe(touch)];\n const provider = new RemoteServiceProvider([\n { service: AgentControl, mode: 'singleton' },\n { service: AgentTranscript, mode: 'singleton' },\n { service: AgentSettings, mode: 'singleton' },\n ]);\n const deliveries = trackDeliveries(agent.harness, state, context);\n provider.provide(\n AgentControl,\n createAgentControl(\n agent.harness,\n agent,\n deliveries,\n options.licks,\n options.scoops,\n options.skills,\n options.sprinkles,\n options.memory,\n options.freezer,\n options.changes\n )\n );\n provider.provide(AgentTranscript, {\n state,\n deliveries: deliveries.state,\n agents: mounted.agents,\n views: mounted.views,\n commands: options.skills?.commands ?? replicatedState<Command[]>([]),\n sprinkles: options.sprinkles?.sprinkles ?? replicatedState<Sprinkle[]>([]),\n memories: options.memory?.memories ?? replicatedState<MemoryEntry[]>([]),\n memoryScopes: options.memory?.scopes ?? replicatedState<MemoryScope[]>([]),\n frozen: options.freezer?.frozen ?? replicatedState<FrozenCone[]>([]),\n changes:\n options.changes?.view ?? replicatedState<ChangesView>({ unavailable: null, changes: [] }),\n });\n provider.provide(AgentSettings, options.settings ?? noSettings);\n const host: ServerHost = {\n serverServices: serverServices(),\n async resolveSession(sessionId) {\n if (sessionId !== AGENT_SESSION)\n throw new SessionNotFoundError(`unknown session ${sessionId}`);\n return { id: sessionId };\n },\n openSession: async () => sessionServices(provider),\n };\n const listener = new PortListener(serverId);\n const server = await new Server(host, { serverId, listeners: [listener] }).start();\n return {\n serverId,\n agent,\n connect: (endpoint) => listener.connect(endpoint),\n async close() {\n await server.close();\n provider.dispose();\n deliveries.dispose();\n transcript.dispose();\n mounted.dispose();\n for (const off of untouch) off();\n options.freezer?.close();\n await options.changes?.close(context);\n await options.memory?.close(context);\n await options.sprinkles?.close(context);\n await options.skills?.close(context);\n await options.scoops?.runtime.close(context);\n await options.licks?.sources.close(context);\n await agent.close();\n },\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n type Context,\n createRemoteServiceEndpoint,\n RemoteServiceProvider,\n replicatedState,\n} from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport {\n type RoutedServerServiceHost,\n type RoutedSessionAttachment,\n type RoutedSessionHandle,\n Server,\n type ServerHost,\n SessionNotFoundError,\n} from '@earendil-works/pi-server';\nimport type { Agent } from './agent.ts';\nimport type { ChangesView } from './changes/git.ts';\nimport type { ChangesRuntime } from './changes/index.ts';\nimport { createAgentControl, type HostLicks, type HostScoops } from './control.ts';\nimport { trackDeliveries } from './deliveries.ts';\nimport type { FreezerRuntime, FrozenCone } from './freezer/index.ts';\nimport { PortListener } from './listener.ts';\nimport type { McpRuntime } from './mcp/index.ts';\nimport type { MemoryEntry, MemoryScope } from './memory/format.ts';\nimport type { MemoryRuntime } from './memory/index.ts';\nimport {\n AGENT_SESSION,\n AgentControl,\n AgentSessions,\n AgentSettings,\n AgentTranscript,\n type Command,\n} from './services.ts';\nimport type { SkillsRuntime } from './skills/index.ts';\nimport type { SprinklesRuntime } from './sprinkles/index.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\nimport { agentViews } from './views.ts';\nimport type { PortEndpoint } from './wire.ts';\n\nexport interface AgentHost {\n readonly serverId: string;\n readonly agent: Agent;\n connect(endpoint: PortEndpoint): void;\n close(): Promise<void>;\n}\n\nfunction endpointFor(provider: RemoteServiceProvider): RoutedSessionAttachment {\n const endpoint = createRemoteServiceEndpoint(provider);\n return {\n invokeService: (call, publish, context) =>\n endpoint.invoke(call, (id, update) => publish(id, update, context), context),\n release: () => endpoint.dispose(),\n };\n}\n\nfunction sessionServices(provider: RemoteServiceProvider): RoutedSessionHandle {\n return {\n attachClient: () => endpointFor(provider),\n close: async () => {},\n };\n}\n\nfunction serverServices(): RoutedServerServiceHost {\n return {\n attachClient(presentation) {\n const provider = new RemoteServiceProvider([{ service: AgentSessions, mode: 'singleton' }]);\n provider.provide(AgentSessions, {\n attach: (sessionId, context) => presentation.attachSession(sessionId, context),\n detach: (context) => presentation.detachSession(context),\n });\n const attachment = endpointFor(provider);\n return {\n invokeService: attachment.invokeService,\n release(context) {\n attachment.release(context);\n provider.dispose();\n },\n };\n },\n };\n}\n\nconst noSettings: AgentSettings = {\n state: replicatedState({ models: [], accounts: [] }),\n connect: async () => {\n throw new Error('this agent has no accounts');\n },\n disconnect: async () => {},\n signIn: async () => null,\n};\n\nasync function follow(agent: Agent, context: Context) {\n let attached = await agent.cone().viewState(context);\n const state = replicatedState<ConversationView>(attached.value);\n const mirror = (value: ConversationView, from: Context) => state.replace(from, value);\n let off = attached.subscribe(mirror);\n const stop = agent.onCone(async (conversation) => {\n const next = await conversation.viewState(context);\n off();\n attached.dispose();\n attached = next;\n state.replace(context, next.value);\n off = next.subscribe(mirror);\n });\n return {\n state,\n dispose() {\n stop();\n off();\n attached.dispose();\n },\n };\n}\n\nexport async function hostAgent(\n agent: Agent,\n options: {\n serverId?: string;\n context?: Context;\n settings?: AgentSettings;\n licks?: HostLicks;\n scoops?: HostScoops;\n skills?: SkillsRuntime;\n sprinkles?: SprinklesRuntime;\n memory?: MemoryRuntime;\n freezer?: FreezerRuntime;\n changes?: ChangesRuntime;\n mcp?: Pick<McpRuntime, 'close'>;\n } = {}\n): Promise<AgentHost> {\n const context = options.context ?? BACKGROUND_CONTEXT;\n const serverId = options.serverId ?? crypto.randomUUID();\n const transcript = await follow(agent, context);\n const { state } = transcript;\n const mounted = await agentViews(agent, context);\n const touch = () => options.freezer?.touch();\n const untouch = [state.subscribe(touch), mounted.views.subscribe(touch)];\n const provider = new RemoteServiceProvider([\n { service: AgentControl, mode: 'singleton' },\n { service: AgentTranscript, mode: 'singleton' },\n { service: AgentSettings, mode: 'singleton' },\n ]);\n const deliveries = trackDeliveries(agent.harness, state, context);\n provider.provide(\n AgentControl,\n createAgentControl(\n agent.harness,\n agent,\n deliveries,\n options.licks,\n options.scoops,\n options.skills,\n options.sprinkles,\n options.memory,\n options.freezer,\n options.changes\n )\n );\n provider.provide(AgentTranscript, {\n state,\n deliveries: deliveries.state,\n agents: mounted.agents,\n views: mounted.views,\n commands: options.skills?.commands ?? replicatedState<Command[]>([]),\n sprinkles: options.sprinkles?.sprinkles ?? replicatedState<Sprinkle[]>([]),\n memories: options.memory?.memories ?? replicatedState<MemoryEntry[]>([]),\n memoryScopes: options.memory?.scopes ?? replicatedState<MemoryScope[]>([]),\n frozen: options.freezer?.frozen ?? replicatedState<FrozenCone[]>([]),\n changes:\n options.changes?.view ?? replicatedState<ChangesView>({ unavailable: null, changes: [] }),\n });\n provider.provide(AgentSettings, options.settings ?? noSettings);\n const host: ServerHost = {\n serverServices: serverServices(),\n async resolveSession(sessionId) {\n if (sessionId !== AGENT_SESSION)\n throw new SessionNotFoundError(`unknown session ${sessionId}`);\n return { id: sessionId };\n },\n openSession: async () => sessionServices(provider),\n };\n const listener = new PortListener(serverId);\n const server = await new Server(host, { serverId, listeners: [listener] }).start();\n return {\n serverId,\n agent,\n connect: (endpoint) => listener.connect(endpoint),\n async close() {\n await server.close();\n provider.dispose();\n deliveries.dispose();\n transcript.dispose();\n mounted.dispose();\n for (const off of untouch) off();\n options.freezer?.close();\n await options.changes?.close(context);\n await options.memory?.close(context);\n await options.sprinkles?.close(context);\n await options.skills?.close(context);\n await options.mcp?.close(context);\n await options.scoops?.runtime.close(context);\n await options.licks?.sources.close(context);\n await agent.close();\n },\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }