@songsid/agend 2.3.0-beta.1 → 2.3.0-beta.2

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 (85) hide show
  1. package/dist/agent-cli.js +5 -5
  2. package/dist/agent-cli.js.map +1 -1
  3. package/dist/agent-file-read.d.ts +11 -6
  4. package/dist/agent-file-read.js +32 -17
  5. package/dist/agent-file-read.js.map +1 -1
  6. package/dist/agent-whats-new.js +8 -13
  7. package/dist/agent-whats-new.js.map +1 -1
  8. package/dist/backend/claude-code.js +5 -1
  9. package/dist/backend/claude-code.js.map +1 -1
  10. package/dist/backend/types.d.ts +8 -0
  11. package/dist/backend/types.js +10 -0
  12. package/dist/backend/types.js.map +1 -1
  13. package/dist/cache-analysis.d.ts +47 -1
  14. package/dist/cache-analysis.js +68 -8
  15. package/dist/cache-analysis.js.map +1 -1
  16. package/dist/cache-report-tool.d.ts +17 -0
  17. package/dist/cache-report-tool.js +40 -0
  18. package/dist/cache-report-tool.js.map +1 -0
  19. package/dist/cache-service.d.ts +15 -0
  20. package/dist/cache-service.js +26 -1
  21. package/dist/cache-service.js.map +1 -1
  22. package/dist/channel/mcp-tools.js +5 -3
  23. package/dist/channel/mcp-tools.js.map +1 -1
  24. package/dist/cli.js +7 -3
  25. package/dist/cli.js.map +1 -1
  26. package/dist/config-validator.js +5 -1
  27. package/dist/config-validator.js.map +1 -1
  28. package/dist/daemon.js +5 -5
  29. package/dist/daemon.js.map +1 -1
  30. package/dist/fleet-manager.d.ts +3 -0
  31. package/dist/fleet-manager.js +9 -4
  32. package/dist/fleet-manager.js.map +1 -1
  33. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +7 -0
  34. package/dist/general-knowledge/skills/web-appearance/SKILL.md +112 -3
  35. package/dist/outbound-handlers.d.ts +2 -0
  36. package/dist/outbound-handlers.js +35 -1
  37. package/dist/outbound-handlers.js.map +1 -1
  38. package/dist/outbound-schemas.d.ts +10 -0
  39. package/dist/outbound-schemas.js +6 -0
  40. package/dist/outbound-schemas.js.map +1 -1
  41. package/dist/scheduler/scheduler.d.ts +12 -0
  42. package/dist/scheduler/scheduler.js +83 -10
  43. package/dist/scheduler/scheduler.js.map +1 -1
  44. package/dist/service-installer.d.ts +2 -1
  45. package/dist/service-installer.js +18 -3
  46. package/dist/service-installer.js.map +1 -1
  47. package/dist/tool-permissions.d.ts +5 -0
  48. package/dist/tool-permissions.js +11 -2
  49. package/dist/tool-permissions.js.map +1 -1
  50. package/dist/ui/chat-effects.js +2 -2
  51. package/dist/ui/fleet-cache.js +23 -1
  52. package/dist/ui/shared/app.css +11 -2
  53. package/dist/ui/shared/instance-nav.js +15 -5
  54. package/dist/ui/shared/usage-dialog.js +14 -2
  55. package/dist/ui/shared/view-strings.js +6 -2
  56. package/dist/ui/signin.html +1 -1
  57. package/dist/usage/providers.d.ts +3 -0
  58. package/dist/usage/providers.js +4 -3
  59. package/dist/usage/providers.js.map +1 -1
  60. package/dist/web-api.js +3 -1
  61. package/dist/web-api.js.map +1 -1
  62. package/dist/web-asset-parts.d.ts +3 -8
  63. package/dist/web-asset-parts.js.map +1 -1
  64. package/dist/web-effect-service.js +3 -1
  65. package/dist/web-effect-service.js.map +1 -1
  66. package/dist/web-effect-tools.js +4 -1
  67. package/dist/web-effect-tools.js.map +1 -1
  68. package/dist/web-effect-trials.d.ts +2 -2
  69. package/dist/web-effect-trials.js +3 -3
  70. package/dist/web-effect-trials.js.map +1 -1
  71. package/dist/web-effect-upload.d.ts +2 -4
  72. package/dist/web-effect-upload.js +3 -8
  73. package/dist/web-effect-upload.js.map +1 -1
  74. package/dist/web-effect.d.ts +14 -0
  75. package/dist/web-effect.js +21 -0
  76. package/dist/web-effect.js.map +1 -1
  77. package/dist/web-mod-agent.js +5 -3
  78. package/dist/web-mod-agent.js.map +1 -1
  79. package/dist/web-mod-bundle.d.ts +5 -0
  80. package/dist/web-mod-bundle.js +6 -0
  81. package/dist/web-mod-bundle.js.map +1 -1
  82. package/dist/web-mod-store.js +2 -1
  83. package/dist/web-mod-store.js.map +1 -1
  84. package/package.json +1 -1
  85. package/templates/systemd.service.ejs +8 -0
@@ -189,6 +189,13 @@ A kiro profile that is configured but has never been logged in still gets a row,
189
189
  reading **Signed out — run `kiro-cli` to log in**. That is the reminder to go
190
190
  and log it in, so report it as such rather than as a missing subscription.
191
191
 
192
+ ## "Is the prompt cache costing us?"
193
+
194
+ `get_cache_report({ window?, instance?, top? })` is the dashboard's **Fleet → cache** report.
195
+ - **What a row has:** each instance's cache TTL as written and its 5m/1h write mix, the TTL it really behaves as (`effective_ttl`, with the gap-miss rate it is measured from), its expiry cost, and the keep-warm simulation and recommendation.
196
+ - **When to look:** when someone asks why costs rose, whether to keep caches warm, or whether to set `backend_options.claude-code.prompt_cache_ttl: "1h"`. A row recommending `switch_to_1h` is the answer to the last one.
197
+ - **What you can see:** as General you see every instance and the fleet summary.
198
+
192
199
  ## What to tell the user
193
200
 
194
201
  - Two agents with the same profile name share one login and one quota.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: web-appearance
3
- description: How you look on the AgEnD web dashboard — check it, change your own theme, identity card and widgets, preview the result, share it as a mod
3
+ description: How you look on the AgEnD web dashboard — check it, change your own theme, identity card, identity colour and widgets, play Canvas Worker effects in your chat (and offer a Try), preview the result, share it as a mod
4
4
  roles: [worker]
5
5
  ---
6
6
 
@@ -16,8 +16,10 @@ can shape how you look there — **only your own look, and only on the surfaces
16
16
  | Your chat | theme: colours, accent, bubbles, font, background picture, working label | `set_web_theme`, `set_web_theme_asset` |
17
17
  | Your face and ring | theme picture and accent | `set_web_theme`, `set_web_theme_asset` |
18
18
  | Your identity card | portrait, banner, tagline, bio | `set_web_theme` (`card.*`), `set_web_theme_asset` |
19
+ | Your identity colour | the colour people find you by in the sidebar, and where it shows (name, bar, ring) | `set_web_theme` (`identity`) |
19
20
  | Your chat header strip and Details page | widgets: small panels of facts the dashboard draws | `set_web_widget`, `remove_web_widget` |
20
21
  | A file of your look | a mod: export yours, or propose one for a person | `export_web_mod`, `propose_web_mod` |
22
+ | Effects in your chat | Canvas Worker animations, and Try cards a local admin may start | `upload_web_effect`, `apply_web_effect`, `preview_web_effect`, … (see Effects) |
21
23
 
22
24
  None of these tools takes a target: they always act on you. You can't change another instance, the dashboard's own
23
25
  chrome, a person's sidebar widget, or a person's custom CSS.
@@ -109,6 +111,25 @@ theme stops naming is deleted.
109
111
  `card.banner` (asset ids uploaded for those slots). Text is shown as text — never markup or links. A person may set
110
112
  their own version of any field; theirs is shown instead of yours.
111
113
 
114
+ The card goes **inside `set`**: `set_web_theme({ set: { card: { tagline, bio, portrait, banner } } })` (a top-level
115
+ `card` argument is refused).
116
+
117
+ ## Your identity colour
118
+
119
+ The colour people find you by in the sidebar, drawn on your name, a bar at your row's left edge and/or the ring around
120
+ your picture. Set yours with `set_web_theme({ set: { identity: { color, show } } })` (see Change your theme).
121
+
122
+ - **Which colour shows**, first match wins: a **person's** pick for you (⋯ → Colour… or View's Edit profile, also from a
123
+ temporary public link) > **yours** (`identity.color`, else your theme's `accent`; only for a viewer who shows agents'
124
+ themes) > your own bot's Discord **role** colour > an **automatic** soft colour chosen from your name (two instances
125
+ may share one).
126
+ - **Where it shows**: a person's choice for you > yours (`identity.show`; again only while themes are shown) > the
127
+ host's default (Settings → Web appearance; ring and bar unless changed).
128
+ - The host can **turn colours off** for everyone: nothing is drawn, and every pick, yours included, is kept for when
129
+ they come back.
130
+ - `get_web_appearance`'s `identity_color` shows what is in force: `color`, `source` (`person`, `agent`, `role`, `auto`),
131
+ `light` / `dark`, `show`, `show_source` (`person`, `agent`, `host`) and `off`.
132
+
112
133
  ## Widgets
113
134
 
114
135
  A widget is a small panel of facts the dashboard draws **with its own components**: you send what to show and the
@@ -184,6 +205,8 @@ with the tools above, then `export_web_mod`.
184
205
  with `rate_limited` and `retry_after_s`. Only an accepted change counts; a refused or invalid one costs nothing.
185
206
  - Widget values (`set_web_widget` with `data` only): at least **10 s** apart, at most **180 an hour**, apart from the
186
207
  above.
208
+ - Effects: `apply_web_effect` and `remove_web_effect` are changes; `upload_web_effect` and `propose_web_mod` are uploads.
209
+ At most 10 effects and 8 MiB of your own, at most two placed in your chat.
187
210
  - Plan the whole look, check it in one `set_web_theme`, then preview — don't iterate change by change.
188
211
 
189
212
  ## A good workflow
@@ -198,6 +221,92 @@ From a shell: `agend-agent theme get|set key=value…|set --json '<patch>'|clear
198
221
  `agend-agent widget set <slot> '<spec json>' ['<data json>']|data <slot> '<data json>'|remove [slot]`, and
199
222
  `agend-agent mod export <name> <version> [title]|propose <file>`.
200
223
 
224
+ ## Files in your working directory
225
+
226
+ Asset uploads, effect directories and mod proposals must be inside your working directory. This includes your own
227
+ AgEnD-managed workspace (`~/.agend/workspaces/<your-instance-name>`), used by ClassicBot and instances without a
228
+ project directory. `web-assets/` and `web-effects/` are convenient staging folders, not required names. Paths are
229
+ checked after resolving symlinks: for the supplied caller identity, another instance's workspace and all other AgEnD
230
+ state remain forbidden, including
231
+ `.env`, databases, `instances/`, `credential-profiles/` and `inbox/`. Symlinks cannot grant access outside your working
232
+ directory or into protected state; uploaded files themselves must not be symlinks. Generated appearance previews and
233
+ mod exports follow the same workspace boundary. The CLI takes its caller name from `AGEND_INSTANCE_NAME` and its
234
+ working directory from the shell; these local checks do not isolate shells running as the same OS user.
235
+
236
+ ## Effects
237
+
238
+ A Canvas Worker effect is a small animation drawn by code that runs in an isolated Worker: no page, no DOM, no
239
+ network. You place effects **only in your own chat**; a person can place them in the regions an effect's manifest
240
+ allows. None of these tools takes a target.
241
+
242
+ **The package** (CW1): a directory in your working directory with `effect.json` and `worker.js`, optionally
243
+ `poster.png`, `cursor.png` and `assets/*.png|jpg|jpeg|webp|gif`. No HTML or CSS, at most 20 files and 16 assets. The
244
+ smallest valid `effect.json`:
245
+
246
+ ```json
247
+ { "v": 1, "kind": "effect", "runtime": "canvas-worker-v1", "worker": "worker.js", "name": "spark", "title": "Spark", "regions": ["chat"], "layer": "behind", "wants": [] }
248
+ ```
249
+
250
+ - Optional fields: `description`, `poster` (`"poster.png"`), `box`, `cursor` (its `hotspot` inside the image) and
251
+ `params`.
252
+ - `name`: 1..32 characters, starting with a-z or 0-9, then a-z, 0-9 and -.
253
+ - `title` (1..40) and `description` (up to 200): one line each, counted in characters as people see them.
254
+ - `regions`: 1–5 of `chat`, `sidebar`, `header`, `page`, `box`. **Include `chat` to place it in a chat**: applying
255
+ one without it is refused (`effect_region`), and so is a mod placing it. The other regions are ones a person may
256
+ choose it for.
257
+ - `layer`: `behind` (under the content) or `front` (over it).
258
+ - `wants`: up to 5 of `pointer`, `state`, `reply`, `mention`, `theme`. **`mention` is reserved and never fires in
259
+ 2.3.0** (see Effect event availability).
260
+ - `params`: up to 16 typed parameters (`number`, `int`, `bool`, `enum`, `color`) a placement may set.
261
+ - `worker.js` (at most 1 MiB, a classic script: static `import` / `export` are refused) draws through the `agend` API:
262
+ `canvas`, `params`, `asset()`, `on()`, `frame()` and `ready()`. Call `ready()` within 10 s, or it is stopped. Network
263
+ and dynamic imports are blocked at run time; the upload may warn `network_or_import_api_unsupported`, but don't rely
264
+ on the warning to catch every use.
265
+ - Size: `effect.json` at most 64 KiB; the whole effect at most 8 MiB as uploaded and **1 MiB normalized**. Pictures:
266
+ at most 4096 px a side, and **8,388,608 pixels in total** across the assets, poster and cursor together. A cursor is
267
+ a square PNG of at most 64 px and 32 KiB (after metadata is stripped).
268
+
269
+ **The tools:**
270
+
271
+ - `upload_web_effect { dir }` → `{ id, warnings }`. It counts as an upload (3 an hour, shared with pictures and mods).
272
+ **Your own** copies are at most **10 effects and 8 MiB**; effects a person shared with you don't count.
273
+ - `list_web_effects` — your own effects and those a person shared with you: `id`, `name`, `title`, `regions`, `layer`,
274
+ `bytes`, `latest_profile`.
275
+ - `apply_web_effect { id, params? }` places one in your chat, **at most two at a time**, with the declared `params`
276
+ (unknown or out of range → `effect_params`; regions without `chat` → `effect_region`). `remove_web_effect { id? }`
277
+ takes one out, or all of them. Both are changes (30 s apart, 10 an hour), and are refused while a person has locked
278
+ your theme (`locked`) or when the fleet turned agent changes off (`theme_editing_off`).
279
+ - `delete_web_effect { id }` deletes your own copy once nothing uses it; a placement, mod, stage or Try offer gives
280
+ `effect_in_use`. Another's copy is never removed.
281
+ - `profile_web_effect { id }` — how it ran on viewers' pages, per device class: `unmeasured`, or `reported` with
282
+ records carrying a `verdict` (`ok`, `degraded`, `paused`, `off`) and a `reason` (`host_budget`, `hidden`,
283
+ `reduced_motion`, `save_data`, `viewer_off`, `clock_unavailable`, `gates_unknown`, or none).
284
+ `list_web_effects`' `latest_profile` has the latest one. These are best-effort reports of what happened, not live
285
+ notices. No measurement means unknown, never healthy.
286
+ - `preview_web_effect { id }` offers a Try card in your chat (see Try below).
287
+ - **Sharing is a person's act.** You can't share an effect. You may use one a person shared with you (list, apply,
288
+ Try, profile, put in a mod) while it is shared. When they unshare it, a placement already in your chat stays
289
+ eligible for playback (subject to the viewer's and the safety rules); applying, Try, listing, profiling or exporting
290
+ it again needs your own copy or another share, else `not_found`. A placement is never a grant to export it.
291
+
292
+ **On a viewer's page:**
293
+
294
+ - At most **3** effects play at once, at most **2** of them `front` (1 and 1 on a constrained device); the rest wait
295
+ (`frame_limit`, `front_limit`).
296
+ - Nothing plays in safe mode, over a temporary public link, with reduced motion or save-data, on a hidden page, while
297
+ the viewer has effects off, or before they consent to previews. A `poster.png` may then show behind the chat (see
298
+ Static Chat fallback). A visible menu or dialog stops `front` effects; these stops lift by themselves.
299
+ - **Safety pause** — it measures the page's responsiveness, not your Worker's CPU. The page's frame-rate floor is
300
+ 90% of what it measured before the effect started, capped at 55 fps (50 on a constrained device), so a 30 Hz screen
301
+ has a 27 fps floor. Where the browser reports them, long tasks may take at most 50 ms a second (25 ms constrained);
302
+ unknown timing doesn't count as free. Overlapping 2-second windows are judged at most once a second after a warm-up,
303
+ and three bad judgements in a row pause the effect (`host_budget`).
304
+ - Only a viewer's explicit **Resume** restarts a safety-paused effect, and it doesn't clear the history: three such
305
+ pauses within 24 hours turn the effect **off** for that viewer's browser and device class, across tabs and reloads,
306
+ and Resume then refuses. It doesn't come back by itself after 24 hours.
307
+ - **Your `front` effects are paused while the viewer's custom CSS is on, loading or unknown**; `behind` effects play
308
+ once the page's stock layout is proven. A person's placement is exempt. Don't keep re-applying (see below).
309
+
201
310
  ## Owner-level effect selections
202
311
 
203
312
  The five owner keys `fx.sidebar`, `fx.header`, `fx.page`, `fx.box` and `fx.cursor` are a signed-in person's web
@@ -214,7 +323,7 @@ placed there. A reference is not a sharing or export grant. Do not keep retrying
214
323
 
215
324
  Owner selectors are available in Settings → Web appearance. With effects and preview consent enabled, personal
216
325
  page/header/sidebar/box choices play across supported stock pages in the same pool as local signed-in Chat.
217
- Appearance offers slot Pause/Resume and unavailable/Clear controls. The personal cursor uses a static PNG on the host shell after the same consent: no Worker/code read or frame slot. It preserves explicit pointer/text/resize cursors, falls back while dragging or on failure, and has status/Clear rather than Worker Pause/Resume. Before revealing paint, the host must prove stock content
326
+ Web appearance offers slot Pause/Resume and unavailable/Clear controls. The personal cursor uses a static PNG on the host shell after the same consent: no Worker/code read or frame slot. It preserves explicit pointer/text/resize cursors, falls back while dragging or on failure, and has status/Clear rather than Worker Pause/Resume. Before revealing paint, the host must prove stock content
218
327
  ordering and trust paint coverage. Agent front effects must remain paused when custom CSS is active, loading or
219
328
  unknown; a person sees the reason and can open the causing setting. Human placements retain their exemption from
220
329
  that agent restriction, and behind effects still require proven ordering. Saving a placement alone is not proof of
@@ -230,7 +339,7 @@ deferred to #1940; do not keep reapplying an agent front while custom CSS is on,
230
339
  click by a signed-in **local admin** may start it; never an agent, public link, header token or automatic action.
231
340
  The host owns a visible Trial label and Stop control. Closing the panel/sheet, navigating, window blur, or another
232
341
  menu/dialog stops it. Custom CSS must be off (on/loading/unknown denies), and the same caps, profiler and safety
233
- stops apply. Ordinary foreground effects stay suppressed. A volatile offer lasts at most ten minutes; every read
342
+ stops apply. Ordinary foreground effects stay suppressed. A volatile offer lasts at most ten minutes (offering the same effect again keeps that offer and its expiry; a different effect replaces it); every read
234
343
  rechecks the originating agent's current own/shared access, with the trial bound to the admin's session and epoch.
235
344
  There is no saved placement, claim, share, export or new saved profile record. Cards are memory-only and become inert when expired; a restart never restores them. Try uses manifest defaults and the existing app pool, not a second runtime. Do not treat an offer id or ordinary reply button
236
345
  as permission to run or fetch an effect, and do not keep retrying an unavailable Try.
@@ -109,6 +109,8 @@ export interface OutboundContext {
109
109
  getInstanceExecutionState?(name: string): "idle" | "working" | "stuck" | "paused" | null;
110
110
  /** Subscription provider IDs used by running or paused fleet/Classic instances. */
111
111
  getActiveUsageProviderIds?(): ReadonlySet<string>;
112
+ /** #2001: the cache report as last worked out (CacheService.published) — never a transcript read. */
113
+ cacheReportPublished?(window: string): Promise<import("./cache-service.js").CacheReport>;
112
114
  /** Effective process state used to annotate cross-instance delivery results. */
113
115
  getInstanceStatus?(name: string): "running" | "paused" | "stopped" | "crashed";
114
116
  /** #1808: whether `backend` takes this model name (the rule /backend applies too); `choices`: what it offers. */
@@ -15,7 +15,7 @@ import { CHAT_PROFILE_LOGIN_BACKENDS, credentialProfileLogin, credentialSwitchCa
15
15
  import { kiroEngineCandidates, kiroEngineStatus } from "./kiro-engine-status.js";
16
16
  import { noPlaceMarkers, placeRef, renderPlaceRefs, stripPlaceRefs, webRoute } from "./topic-link.js";
17
17
  import { formatCrossInstanceInboundMessage, MAX_ASSEMBLED_CROSS_INSTANCE_MESSAGE_BYTES, } from "./cross-instance-envelope.js";
18
- import { BroadcastArgs, CreateInstanceArgs, CreateTeamArgs, DelegateTaskArgs, DeleteInstanceArgs, DeleteTeamArgs, DeployTemplateArgs, DescribeInstanceArgs, ListDeploymentsArgs, ListInstancesArgs, ListTeamsArgs, ReplaceInstanceArgs, ReportResultArgs, DeliveryStatusArgs, RequestInformationArgs, RestartInstanceArgs, SendToInstanceArgs, PauseInstanceArgs, WakeInstanceArgs, StopInstanceArgs, GetInstanceLogsArgs, GetEffortArgs, ClosePollArgs, KiroEngineStatusArgs, GetUsageArgs, ListModelsArgs, GetFleetConfigArgs, UpdateInstanceConfigArgs, UpdateFleetDefaultsArgs, StartInstanceArgs, TeardownDeploymentArgs, UpdateTeamArgs, validateArgs, } from "./outbound-schemas.js";
18
+ import { BroadcastArgs, CreateInstanceArgs, CreateTeamArgs, DelegateTaskArgs, DeleteInstanceArgs, DeleteTeamArgs, DeployTemplateArgs, DescribeInstanceArgs, ListDeploymentsArgs, ListInstancesArgs, ListTeamsArgs, ReplaceInstanceArgs, ReportResultArgs, DeliveryStatusArgs, RequestInformationArgs, RestartInstanceArgs, SendToInstanceArgs, PauseInstanceArgs, WakeInstanceArgs, StopInstanceArgs, GetInstanceLogsArgs, GetEffortArgs, ClosePollArgs, KiroEngineStatusArgs, GetUsageArgs, GetCacheReportArgs, ListModelsArgs, GetFleetConfigArgs, UpdateInstanceConfigArgs, UpdateFleetDefaultsArgs, StartInstanceArgs, TeardownDeploymentArgs, UpdateTeamArgs, validateArgs, } from "./outbound-schemas.js";
19
19
  const HOME_DIR = homedir();
20
20
  function formatByteSize(bytes) {
21
21
  if (bytes < 1024)
@@ -871,6 +871,39 @@ const getUsage = async (ctx, rawArgs, respond) => {
871
871
  respond(null, `Usage fetch failed: ${err.message}`);
872
872
  }
873
873
  };
874
+ /**
875
+ * #2001: the prompt-cache report for an agent. From the last scan (cacheReportPublished: in-memory ledgers, reused
876
+ * for a minute) — no transcript read and no process on the fleet loop. Who sees what: cacheReportScope.
877
+ */
878
+ const getCacheReport = async (ctx, rawArgs, respond, meta) => {
879
+ const v = validateArgs(GetCacheReportArgs, rawArgs, "get_cache_report");
880
+ if (!v.ok) {
881
+ respond(null, v.error);
882
+ return;
883
+ }
884
+ const caller = meta?.instanceName;
885
+ if (!caller) {
886
+ respond(null, "get_cache_report: the calling instance is unknown");
887
+ return;
888
+ }
889
+ if (!ctx.cacheReportPublished) {
890
+ respond(null, "get_cache_report is unavailable on this fleet");
891
+ return;
892
+ }
893
+ const { resolveToolSet, cacheReportScope } = await import("./tool-permissions.js");
894
+ const { cacheReportForTool } = await import("./cache-report-tool.js");
895
+ const scope = cacheReportScope(resolveToolSet(ctx.fleetConfig?.instances[caller], caller));
896
+ try {
897
+ const out = cacheReportForTool(await ctx.cacheReportPublished(v.data.window ?? "7d"), { scope, caller, instance: v.data.instance, top: v.data.top });
898
+ if ("error" in out && typeof out.error === "string")
899
+ respond(null, out.error);
900
+ else
901
+ respond(out);
902
+ }
903
+ catch (err) {
904
+ respond(null, `get_cache_report failed: ${err.message}`);
905
+ }
906
+ };
874
907
  /**
875
908
  * Enumerate a backend's models. Read-only and best-effort by design: the
876
909
  * catalog is an aid for picking a name, and AgEnD passes model strings through
@@ -1993,6 +2026,7 @@ export const outboundHandlers = new Map([
1993
2026
  ["close_poll", closePoll],
1994
2027
  ["kiro_engine_status", kiroEngineStatusHandler],
1995
2028
  ["get_usage", getUsage],
2029
+ ["get_cache_report", getCacheReport],
1996
2030
  ["list_models", listModels],
1997
2031
  ["get_instance_logs", getInstanceLogs],
1998
2032
  ["get_fleet_config", getFleetConfig],