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

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 (189) hide show
  1. package/dist/agent-whats-new.js +2 -0
  2. package/dist/agent-whats-new.js.map +1 -1
  3. package/dist/auth-api.d.ts +30 -1
  4. package/dist/auth-api.js +42 -12
  5. package/dist/auth-api.js.map +1 -1
  6. package/dist/backend/claude-code.d.ts +2 -2
  7. package/dist/backend/claude-code.js +5 -4
  8. package/dist/backend/claude-code.js.map +1 -1
  9. package/dist/backend/types.d.ts +6 -0
  10. package/dist/backend/types.js +15 -0
  11. package/dist/backend/types.js.map +1 -1
  12. package/dist/backend-availability.d.ts +120 -0
  13. package/dist/backend-availability.js +396 -0
  14. package/dist/backend-availability.js.map +1 -0
  15. package/dist/backend-command.d.ts +21 -3
  16. package/dist/backend-command.js +23 -4
  17. package/dist/backend-command.js.map +1 -1
  18. package/dist/channel/adapters/discord.d.ts +7 -0
  19. package/dist/channel/adapters/discord.js +35 -0
  20. package/dist/channel/adapters/discord.js.map +1 -1
  21. package/dist/channel/mcp-tools.js +8 -4
  22. package/dist/channel/mcp-tools.js.map +1 -1
  23. package/dist/channel/types.d.ts +6 -0
  24. package/dist/classic-channel-manager.d.ts +8 -3
  25. package/dist/classic-channel-manager.js +10 -3
  26. package/dist/classic-channel-manager.js.map +1 -1
  27. package/dist/config-validator.js +73 -2
  28. package/dist/config-validator.js.map +1 -1
  29. package/dist/delivery-outbox.js +5 -0
  30. package/dist/delivery-outbox.js.map +1 -1
  31. package/dist/fleet-context.d.ts +10 -0
  32. package/dist/fleet-manager.d.ts +238 -5
  33. package/dist/fleet-manager.js +878 -71
  34. package/dist/fleet-manager.js.map +1 -1
  35. package/dist/fleet-traffic.d.ts +38 -0
  36. package/dist/fleet-traffic.js +96 -0
  37. package/dist/fleet-traffic.js.map +1 -0
  38. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +13 -5
  39. package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
  40. package/dist/general-knowledge/skills/web-appearance/SKILL.md +56 -11
  41. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +398 -0
  42. package/dist/human-delivery-receipts.js +2 -1
  43. package/dist/human-delivery-receipts.js.map +1 -1
  44. package/dist/locale.js +48 -8
  45. package/dist/locale.js.map +1 -1
  46. package/dist/memory-hogs.d.ts +27 -0
  47. package/dist/memory-hogs.js +124 -0
  48. package/dist/memory-hogs.js.map +1 -0
  49. package/dist/outbound-handlers.d.ts +2 -0
  50. package/dist/outbound-handlers.js +40 -1
  51. package/dist/outbound-handlers.js.map +1 -1
  52. package/dist/outbound-schemas.d.ts +92 -0
  53. package/dist/outbound-schemas.js +55 -1
  54. package/dist/outbound-schemas.js.map +1 -1
  55. package/dist/public-web-gateway.js +1 -1
  56. package/dist/public-web-gateway.js.map +1 -1
  57. package/dist/public-web-link.d.ts +9 -0
  58. package/dist/public-web-link.js +8 -0
  59. package/dist/public-web-link.js.map +1 -1
  60. package/dist/quickstart-api.d.ts +10 -1
  61. package/dist/quickstart-api.js +12 -4
  62. package/dist/quickstart-api.js.map +1 -1
  63. package/dist/reply-buttons-controller.d.ts +2 -0
  64. package/dist/reply-buttons-controller.js +1 -1
  65. package/dist/reply-buttons-controller.js.map +1 -1
  66. package/dist/tmux-manager.d.ts +5 -0
  67. package/dist/tmux-manager.js +16 -0
  68. package/dist/tmux-manager.js.map +1 -1
  69. package/dist/tool-permissions.js +4 -0
  70. package/dist/tool-permissions.js.map +1 -1
  71. package/dist/topic-commands.d.ts +5 -0
  72. package/dist/topic-commands.js +16 -0
  73. package/dist/topic-commands.js.map +1 -1
  74. package/dist/types.d.ts +25 -1
  75. package/dist/ui/app-effects.js +33 -9
  76. package/dist/ui/chat-effects.js +62 -4
  77. package/dist/ui/chat-strings.js +40 -4
  78. package/dist/ui/chat-thread.js +17 -6
  79. package/dist/ui/effect-trial-panel.js +19 -16
  80. package/dist/ui/fleet-canvas-layout.js +111 -0
  81. package/dist/ui/fleet-canvas.js +489 -0
  82. package/dist/ui/fleet-org.js +27 -12
  83. package/dist/ui/fleet-traffic.js +224 -0
  84. package/dist/ui/panel-chat.js +12 -5
  85. package/dist/ui/panel-details.js +2 -1
  86. package/dist/ui/panel-fleet.js +32 -11
  87. package/dist/ui/panel-settings.js +6 -4
  88. package/dist/ui/preview.js +3 -2
  89. package/dist/ui/settings-appearance.js +34 -18
  90. package/dist/ui/settings-catalog.js +89 -0
  91. package/dist/ui/settings-dialogs.js +40 -12
  92. package/dist/ui/settings-effects.js +4 -3
  93. package/dist/ui/settings-learn.js +25 -0
  94. package/dist/ui/settings-model.js +6 -2
  95. package/dist/ui/settings-mods.js +4 -3
  96. package/dist/ui/settings-owner-effects.js +8 -8
  97. package/dist/ui/settings-strings.js +40 -38
  98. package/dist/ui/shared/app-i18n.js +2 -2
  99. package/dist/ui/shared/app-prefs.js +1 -1
  100. package/dist/ui/shared/app-shell.js +23 -1
  101. package/dist/ui/shared/app-store.js +12 -1
  102. package/dist/ui/shared/app-stream.js +2 -1
  103. package/dist/ui/shared/app.css +186 -11
  104. package/dist/ui/shared/card-strings.js +4 -0
  105. package/dist/ui/shared/effect-app-runtime.js +1 -1
  106. package/dist/ui/shared/effect-frame.js +10 -5
  107. package/dist/ui/shared/effect-geometry.js +24 -9
  108. package/dist/ui/shared/effect-policy.js +2 -1
  109. package/dist/ui/shared/effect-registry.js +71 -17
  110. package/dist/ui/shared/effect-stock-trust.js +23 -2
  111. package/dist/ui/shared/effect-trial-shadow.js +62 -0
  112. package/dist/ui/shared/effect-trial-stage.js +15 -9
  113. package/dist/ui/shared/effect-trial.css +40 -0
  114. package/dist/ui/shared/identity-card.js +75 -4
  115. package/dist/ui/shared/identity-color.js +3 -3
  116. package/dist/ui/shared/instance-nav.js +20 -4
  117. package/dist/ui/shared/panel-view.js +24 -4
  118. package/dist/ui/shared/view-strings.js +22 -0
  119. package/dist/view-api.d.ts +32 -0
  120. package/dist/view-api.js +55 -4
  121. package/dist/view-api.js.map +1 -1
  122. package/dist/web-api.d.ts +19 -4
  123. package/dist/web-api.js +178 -20
  124. package/dist/web-api.js.map +1 -1
  125. package/dist/web-appearance-policy.d.ts +4 -6
  126. package/dist/web-appearance-policy.js +5 -12
  127. package/dist/web-appearance-policy.js.map +1 -1
  128. package/dist/web-appearance-tools.js +5 -1
  129. package/dist/web-appearance-tools.js.map +1 -1
  130. package/dist/web-appearance-view.d.ts +14 -1
  131. package/dist/web-appearance-view.js +98 -10
  132. package/dist/web-appearance-view.js.map +1 -1
  133. package/dist/web-appearance.d.ts +2 -2
  134. package/dist/web-appearance.js +5 -6
  135. package/dist/web-appearance.js.map +1 -1
  136. package/dist/web-auth.js +1 -1
  137. package/dist/web-auth.js.map +1 -1
  138. package/dist/web-card.d.ts +14 -0
  139. package/dist/web-card.js +40 -6
  140. package/dist/web-card.js.map +1 -1
  141. package/dist/web-channel-echo.d.ts +7 -1
  142. package/dist/web-channel-echo.js +6 -2
  143. package/dist/web-channel-echo.js.map +1 -1
  144. package/dist/web-chat-history.d.ts +40 -0
  145. package/dist/web-chat-history.js +66 -3
  146. package/dist/web-chat-history.js.map +1 -1
  147. package/dist/web-commands.d.ts +1 -0
  148. package/dist/web-effect-tools.js +2 -3
  149. package/dist/web-effect-tools.js.map +1 -1
  150. package/dist/web-effect-trials.d.ts +2 -2
  151. package/dist/web-effect-trials.js +3 -3
  152. package/dist/web-effect-trials.js.map +1 -1
  153. package/dist/web-guest-access.d.ts +125 -0
  154. package/dist/web-guest-access.js +232 -0
  155. package/dist/web-guest-access.js.map +1 -0
  156. package/dist/web-guest-rooms.d.ts +82 -0
  157. package/dist/web-guest-rooms.js +135 -0
  158. package/dist/web-guest-rooms.js.map +1 -0
  159. package/dist/web-identity-palette.d.ts +1 -1
  160. package/dist/web-identity-palette.js +2 -2
  161. package/dist/web-identity-palette.js.map +1 -1
  162. package/dist/web-login.d.ts +47 -0
  163. package/dist/web-login.js +115 -0
  164. package/dist/web-login.js.map +1 -1
  165. package/dist/web-mod-agent.d.ts +1 -1
  166. package/dist/web-mod-agent.js +2 -4
  167. package/dist/web-mod-agent.js.map +1 -1
  168. package/dist/web-mod-store.d.ts +5 -0
  169. package/dist/web-mod-store.js +6 -0
  170. package/dist/web-mod-store.js.map +1 -1
  171. package/dist/web-prefs.d.ts +8 -0
  172. package/dist/web-prefs.js +9 -0
  173. package/dist/web-prefs.js.map +1 -1
  174. package/dist/web-preview.d.ts +6 -2
  175. package/dist/web-preview.js +4 -2
  176. package/dist/web-preview.js.map +1 -1
  177. package/dist/web-returning-device.d.ts +39 -0
  178. package/dist/web-returning-device.js +46 -5
  179. package/dist/web-returning-device.js.map +1 -1
  180. package/dist/web-session.d.ts +58 -10
  181. package/dist/web-session.js +104 -22
  182. package/dist/web-session.js.map +1 -1
  183. package/dist/web-settings-tools.d.ts +81 -0
  184. package/dist/web-settings-tools.js +257 -0
  185. package/dist/web-settings-tools.js.map +1 -0
  186. package/dist/web-theme.d.ts +2 -0
  187. package/dist/web-theme.js +10 -1
  188. package/dist/web-theme.js.map +1 -1
  189. package/package.json +1 -1
@@ -0,0 +1,38 @@
1
+ import type { FleetConfig } from "./types.js";
2
+ import type { OutboxDelivery, OutboxState } from "./delivery-outbox.js";
3
+ export type TrafficKind = "task" | "report" | "query" | "update" | "send" | "broadcast";
4
+ export type TrafficState = "queued" | "delivering" | "delivered" | "consumed" | "failed" | "uncertain" | "cancelled";
5
+ export interface TrafficItem {
6
+ id: string;
7
+ from: string;
8
+ to: string;
9
+ kind: TrafficKind;
10
+ state: TrafficState;
11
+ at: string;
12
+ op?: string;
13
+ }
14
+ /** Finished: the item stays a short while (it fades on the page), then leaves. */
15
+ export declare const TRAFFIC_FINISHED: ReadonlySet<TrafficState>;
16
+ /** How long a finished item stays in the snapshot, and how many items a snapshot holds at most. */
17
+ export declare const TRAFFIC_RECENT_MS = 120000;
18
+ export declare const TRAFFIC_SNAPSHOT_MAX = 200;
19
+ export declare const trafficId: (deliveryId: string) => string;
20
+ /** The item for a delivery row in `state` (default: the row's own), or null when it is not shown. */
21
+ export declare function trafficItem(row: OutboxDelivery, fleet: Pick<FleetConfig, "defaults" | "instances"> | null | undefined, at: string, state?: OutboxState | "consumed"): TrafficItem | null;
22
+ /**
23
+ * The traffic the fleet keeps in memory for a snapshot: each item's latest state, by id. Finished items are dropped
24
+ * TRAFFIC_RECENT_MS after they finished; at most TRAFFIC_SNAPSHOT_MAX are kept (the oldest go first).
25
+ */
26
+ export declare class TrafficLog {
27
+ private readonly monotonic;
28
+ private readonly items;
29
+ constructor(monotonic?: () => number);
30
+ /** Record an item; returns it when it is news (a new id, or a new state for one), else null. */
31
+ note(item: TrafficItem): TrafficItem | null;
32
+ /**
33
+ * In flight now and recently finished: the pending rows' items first (the outbox is the truth for what is still
34
+ * moving), then the recent finished ones; newest last, at most TRAFFIC_SNAPSHOT_MAX.
35
+ */
36
+ snapshot(pending: readonly TrafficItem[]): TrafficItem[];
37
+ private prune;
38
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * #1918: live cross-instance traffic for the org canvas — what the delivery outbox already records, as a small item the
3
+ * page can draw: who sends what kind of message to whom, and how far it got. No new probe: items are made where the
4
+ * outbox already changes a row (admission, its "state" events, a consumed mark), from the row the listener already has.
5
+ *
6
+ * - Only messages between instances: send_to_instance and what is built on it (delegate_task, report_result,
7
+ * request_information) and broadcast. Fleet-generated notices (system, reply-obligation, outcome) are not traffic.
8
+ * - Never a delivery id or any text: an opaque id (a hash of the delivery id) and the two instance names. A broadcast's
9
+ * items (one row per recipient) share an opaque `op`, so the page can draw them as one fan-out.
10
+ * - An instance whose cross_instance_visibility is "hidden" takes no part: a message to or from it is not shown.
11
+ */
12
+ import { createHash } from "node:crypto";
13
+ import { crossInstanceVisibility } from "./cross-instance-notice.js";
14
+ /** The row kinds that are messages between instances (outbound-handlers: send_to_instance's family, broadcast). */
15
+ const MESSAGE_KINDS = new Set(["fleet_inbound", "steer", "broadcast"]);
16
+ const REQUEST_KINDS = { task: "task", report: "report", query: "query", update: "update" };
17
+ const STATES = {
18
+ queued: "queued", retry_wait: "queued",
19
+ delivering: "delivering", submission_started: "delivering", reconciliation_pending: "delivering",
20
+ delivered: "delivered", consumed: "consumed",
21
+ failed: "failed", uncertain: "uncertain", cancelled: "cancelled",
22
+ };
23
+ /** Finished: the item stays a short while (it fades on the page), then leaves. */
24
+ export const TRAFFIC_FINISHED = new Set(["delivered", "consumed", "failed", "uncertain", "cancelled"]);
25
+ /** How long a finished item stays in the snapshot, and how many items a snapshot holds at most. */
26
+ export const TRAFFIC_RECENT_MS = 120_000;
27
+ export const TRAFFIC_SNAPSHOT_MAX = 200;
28
+ export const trafficId = (deliveryId) => createHash("sha256").update(deliveryId).digest("hex").slice(0, 16);
29
+ /** The item for a delivery row in `state` (default: the row's own), or null when it is not shown. */
30
+ export function trafficItem(row, fleet, at, state) {
31
+ if (!MESSAGE_KINDS.has(row.kind))
32
+ return null;
33
+ const from = row.sourceInstance, to = row.targetInstance;
34
+ if (!from || !to || from === to)
35
+ return null;
36
+ if (crossInstanceVisibility(fleet, from) === "hidden" || crossInstanceVisibility(fleet, to) === "hidden")
37
+ return null;
38
+ const mapped = STATES[state ?? (row.reconciliationPending ? "reconciliation_pending" : row.state)];
39
+ if (!mapped)
40
+ return null;
41
+ const meta = row.payload?.meta;
42
+ const kind = row.kind === "broadcast" ? "broadcast"
43
+ : typeof meta?.request_kind === "string" && Object.prototype.hasOwnProperty.call(REQUEST_KINDS, meta.request_kind) ? REQUEST_KINDS[meta.request_kind] : "send";
44
+ return { id: trafficId(row.deliveryId), from, to, kind, state: mapped, at, ...(kind === "broadcast" ? { op: trafficId(`op:${row.operationId}`) } : {}) };
45
+ }
46
+ /**
47
+ * The traffic the fleet keeps in memory for a snapshot: each item's latest state, by id. Finished items are dropped
48
+ * TRAFFIC_RECENT_MS after they finished; at most TRAFFIC_SNAPSHOT_MAX are kept (the oldest go first).
49
+ */
50
+ export class TrafficLog {
51
+ monotonic;
52
+ items = new Map();
53
+ constructor(monotonic = () => performance.now()) {
54
+ this.monotonic = monotonic;
55
+ }
56
+ /** Record an item; returns it when it is news (a new id, or a new state for one), else null. */
57
+ note(item) {
58
+ const prev = this.items.get(item.id);
59
+ if (prev && prev.item.state === item.state)
60
+ return null;
61
+ // A finished item never goes back to an earlier state (events can arrive out of order across listeners).
62
+ if (prev && TRAFFIC_FINISHED.has(prev.item.state) && !TRAFFIC_FINISHED.has(item.state))
63
+ return null;
64
+ if (prev && prev.item.state === "consumed")
65
+ return null;
66
+ this.items.delete(item.id);
67
+ this.items.set(item.id, { item, seenMs: this.monotonic() });
68
+ this.prune();
69
+ return item;
70
+ }
71
+ /**
72
+ * In flight now and recently finished: the pending rows' items first (the outbox is the truth for what is still
73
+ * moving), then the recent finished ones; newest last, at most TRAFFIC_SNAPSHOT_MAX.
74
+ */
75
+ snapshot(pending) {
76
+ this.prune();
77
+ const out = new Map();
78
+ for (const p of pending)
79
+ out.set(p.id, p);
80
+ for (const { item } of this.items.values())
81
+ if (TRAFFIC_FINISHED.has(item.state) && !out.has(item.id))
82
+ out.set(item.id, item);
83
+ const all = [...out.values()];
84
+ return all.slice(Math.max(0, all.length - TRAFFIC_SNAPSHOT_MAX));
85
+ }
86
+ prune() {
87
+ const now = this.monotonic();
88
+ for (const [id, e] of this.items) {
89
+ if (TRAFFIC_FINISHED.has(e.item.state) ? now - e.seenMs > TRAFFIC_RECENT_MS : now - e.seenMs > 24 * 3_600_000)
90
+ this.items.delete(id);
91
+ }
92
+ while (this.items.size > TRAFFIC_SNAPSHOT_MAX * 2)
93
+ this.items.delete(this.items.keys().next().value);
94
+ }
95
+ }
96
+ //# sourceMappingURL=fleet-traffic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fleet-traffic.js","sourceRoot":"","sources":["../src/fleet-traffic.ts"],"names":[],"mappings":"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"}
@@ -177,13 +177,21 @@ Say "the default login", not "no subscription".
177
177
  `get_usage` returns one row per subscription: `Kiro (work)` and
178
178
  `Kiro (personal)` rather than a single `Kiro`. Read them out separately — they
179
179
  are two quotas, and adding them together would give a number that is true of
180
- neither. An agent with no profile appears under the plain `Kiro` row. Codex works
181
- the same way: `Codex (<profile>)` rows next to the plain `Codex`.
180
+ neither. An agent with no profile appears under the plain `Kiro` row (shown only
181
+ while some instance still uses the default login). Codex works the same way:
182
+ `Codex (<profile>)` rows next to `Codex (default)`.
182
183
 
183
184
  Claude Code also has a row per profile: `Claude (work)`, `Claude (personal)`,
184
- next to the plain `Claude` for the default login. A profile reads quota from its
185
- own login; a profile that is configured but has never been signed in shows
186
- **Not logged in — run `/login claude-code <profile>` to sign in**.
185
+ next to the plain `Claude` for the default login (again only while some instance
186
+ uses it). A profile reads quota from its own login; a profile that is configured
187
+ but has never been signed in shows **Not logged in — sign in with
188
+ `/login claude-code <profile>`** (in chat, it adds the host command too).
189
+
190
+ On the web dashboard's usage card (#2014) the title line says just the
191
+ provider — "Claude", "Codex", "Kiro" — with the plan badge, and the profile
192
+ name sits on its own line under it; the full `Claude (work)` is the tooltip.
193
+ `get_usage` and the chat's `/usage` still call the row `Claude (work)`, so name
194
+ the profile the way the user sees it on the screen they are looking at.
187
195
 
188
196
  A kiro profile that is configured but has never been logged in still gets a row,
189
197
  reading **Signed out — run `kiro-cli` to log in**. That is the reminder to go
@@ -61,7 +61,7 @@ The `channel_id` field explicitly binds a general to an adapter. Without it, mat
61
61
 
62
62
  The dashboard's web chat is one more way in, not a `channels:` entry: its messages reach an instance as
63
63
  `[user:… via web, …]` and are answered with `reply` like any other. By default each is also copied to the
64
- instance's own topic (`web.echo_to_channel: false` turns that off; ClassicBot rooms only with `web_echo: true`).
64
+ instance's own topic (`web.echo_to_channel: false` turns that off; a ClassicBot room follows it unless its own `web_echo` is set — `false` keeps that room off).
65
65
 
66
66
  ## Single → Multi Migration
67
67
 
@@ -1,7 +1,7 @@
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, identity colour and widgets, play Canvas Worker effects in your chat (and offer a Try), preview the result, share it as a mod
4
- roles: [worker]
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; and, for General, changing Settings → Web appearance for the user
4
+ roles: [general, worker]
5
5
  ---
6
6
 
7
7
  ## What it is
@@ -24,6 +24,38 @@ can shape how you look there — **only your own look, and only on the surfaces
24
24
  None of these tools takes a target: they always act on you. You can't change another instance, the dashboard's own
25
25
  chrome, a person's sidebar widget, or a person's custom CSS.
26
26
 
27
+ ## For the user: Settings → Web appearance (General, coordinators, full)
28
+
29
+ If you are General (or a coordinator or full profile), you can change the user's **Settings → Web appearance** for
30
+ them, exactly as the page changes it: the same checks, the same refusals. Custom CSS keeps its safe rules: no remote
31
+ URLs, assets only as `url("asset:<id>")`, at most 64 KiB. Other instances can't; they shape only their own look (the rest
32
+ of this skill).
33
+
34
+ 1. **Read first:** `get_web_settings` returns a `summary` in plain words (tell the user from it), the values, and
35
+ `people`: the host operator and everyone who has signed in. Host settings are everyone's on this host. Custom CSS and
36
+ effect slots are one person's own: pass `person` as the entry whose id is the user's (`person:<adapter>:<their id>`),
37
+ else the host operator's are changed.
38
+ 2. **One change per call:** `set_web_settings({ person?, change })`, where `change.what` is one of:
39
+
40
+ | `what` | Changes | Example |
41
+ |---|---|---|
42
+ | `host` | `themes_shown`, `card_size` (s/m/l), `card_sizes` ({instance: s/m/l}), `colour_places` (name/bar/ring), `colours_off`, `sidebar_widget` ({spec, data}) — null puts one back to its default | `{ what: "host", set: { colour_places: ["name","ring"] } }` |
43
+ | `agent_colour` | one agent's colour (`preset:<name>` or `#rrggbb`) and places; null resets each | `{ what: "agent_colour", instance: "atlas", colour: "preset:teal" }` |
44
+ | `custom_css` | `save` (with `text`): goes **on trial** on their screens (it goes back by itself unless kept); `keep` (the trial), `revert` (the trial), `use` (with `version`: an earlier saved one, at once), `off` | `{ what: "custom_css", action: "save", text: "…" }`; ask how it looks, then `keep` only when they say so |
45
+ | `mod` | an agent's proposal: `review` (instance → `stage`, `plan`, `plan_hash`), then `install` (stage, plan_hash, `include`: the parts, `target`: the agent); `cancel`, `dismiss`, `uninstall` (id) | review, show the user the plan, install only what they asked for — never custom CSS unasked. A person has one review open at a time: while theirs is open (`mod_review_open`) ask them to finish it; a mod they imported from a file is theirs to install (`mod_not_from_an_agent`) |
46
+ | `effect` | `apply` (instance, id, params?) or `remove` (instance, id?) an effect on a chat | |
47
+ | `effect_slot` | a person's `sidebar` / `header` / `page` / `box` / `cursor` effect (an id, or null) | |
48
+ | `restore_defaults` | the host settings back to their defaults, and the person's custom CSS off | |
49
+
50
+ 3. **Say what changed** in the user's words (read again if unsure). A refusal says why: the same words the page would
51
+ show.
52
+
53
+ **Only the person can do these, on the page:**
54
+ - choose a file from their computer: import a mod file, upload an effect folder, add a CSS asset or a card picture;
55
+ - this browser's own switches: custom CSS off on this device, pausing effect playback;
56
+ - download an export;
57
+ - the card upload limits (fleet configuration; a raise waits for an admin's confirmation).
58
+
27
59
  ## Look first
28
60
 
29
61
  - `get_web_appearance` — how you appear **now**, resolved exactly as the dashboard resolves it: your face and where it
@@ -39,7 +71,7 @@ chrome, a person's sidebar widget, or a person's custom CSS.
39
71
  (`avatar.png`, `portrait.png`, …), and returns both lists of paths. Read the SVGs for exact colours, geometry and
40
72
  text, and the pictures as images. Only your own pictures are there.
41
73
  - `get_web_theme` — your stored theme, the token defaults it is drawn over, your uploaded pictures (`id`, `slot`), and
42
- `limits` (changes and uploads left, each picture slot's size limits, your picture quota).
74
+ `limits` (changes left, each picture slot's size limits, your picture quota).
43
75
 
44
76
  ## What wins over what
45
77
 
@@ -77,7 +109,7 @@ Typed values only; anything else is refused with `{ errors: [{ path, problem }]
77
109
  - `background`: `{ image: <asset id>, fit: "cover" | "contain", opacity: 0.05..1 }`.
78
110
  - `avatar`: an asset id — your face (below a person's upload).
79
111
  - `workingLabel`: 1..24 characters on one line, shown while you work instead of "is working…".
80
- - `card`: `{ portrait?, banner?, tagline?, bio? }` — see below.
112
+ - `card`: `{ portrait?, banner?, tagline?, bio?, bannerFocus? }` — see below.
81
113
 
82
114
  Example:
83
115
 
@@ -114,6 +146,13 @@ their own version of any field; theirs is shown instead of yours.
114
146
  The card goes **inside `set`**: `set_web_theme({ set: { card: { tagline, bio, portrait, banner } } })` (a top-level
115
147
  `card` argument is refused).
116
148
 
149
+ **Your banner is cropped: never drawn wider than 5 : 1** (on a wider screen it is centred over a blurred copy) **nor
150
+ narrower than 9 : 4** (which crops the sides). Make it **1600×600** (the default limit) and keep faces and text
151
+ inside the **safe area: the middle 84% of the width × 53% of the height — 1350×320** — which every card shows on every
152
+ screen and layout. `card.bannerFocus` (0 top … 100 bottom; default 50, the centre) moves that area up or down: put a face
153
+ near the top at `bannerFocus: 0`. A person's focus (Edit profile, or General's `set_web_settings { what: "banner_focus" }`)
154
+ wins over yours. `preview_web_appearance` draws the banner cropped at its focus, as the page does (an M card).
155
+
117
156
  ## Your identity colour
118
157
 
119
158
  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
@@ -189,7 +228,7 @@ everything in a mod and ticks what to apply.
189
228
  - `propose_web_mod { file }` sends a mod file from your working directory (at most 8 MiB) for a person to review. It
190
229
  is checked whole and answers with its problems if it isn't valid. **A mod carrying custom CSS is refused**
191
230
  (`owner_css_not_from_agent`). A muted line in your chat says it was proposed. Nothing changes until a person
192
- installs it. One proposal at a time: a new one replaces yours. It counts as an upload.
231
+ installs it. One proposal at a time: a new one replaces yours.
193
232
  - A widget a person placed from a mod is theirs: you may give it values (`set_web_widget` with `data`), but not replace
194
233
  or remove it (`person_placed`).
195
234
 
@@ -201,11 +240,14 @@ with the tools above, then `export_web_mod`.
201
240
 
202
241
  ## Limits
203
242
 
204
- - At least **30 s** between changes, at most **10 changes an hour**, at most **3 picture uploads an hour** — refused
205
- with `rate_limited` and `retry_after_s`. Only an accepted change counts; a refused or invalid one costs nothing.
243
+ - At least **30 s** between changes, at most **10 changes an hour** — refused with `rate_limited` and
244
+ `retry_after_s`. Only an accepted change counts; a refused or invalid one costs nothing.
245
+ - Uploads (pictures, effects, proposed mods) are not counted. Each picture slot's size limits, your picture quota and
246
+ each file's own caps still apply; using a picture in your theme is a change.
206
247
  - Widget values (`set_web_widget` with `data` only): at least **10 s** apart, at most **180 an hour**, apart from the
207
248
  above.
208
- - Effects: `apply_web_effect` and `remove_web_effect` are changes; `upload_web_effect` and `propose_web_mod` are uploads.
249
+ - Effects: `apply_web_effect` and `remove_web_effect` are changes; `upload_web_effect` and `propose_web_mod` are not
250
+ counted.
209
251
  At most 10 effects and 8 MiB of your own, at most two placed in your chat.
210
252
  - Plan the whole look, check it in one `set_web_theme`, then preview — don't iterate change by change.
211
253
 
@@ -266,9 +308,11 @@ smallest valid `effect.json`:
266
308
  at most 4096 px a side, and **8,388,608 pixels in total** across the assets, poster and cursor together. A cursor is
267
309
  a square PNG of at most 64 px and 32 KiB (after metadata is stripped).
268
310
 
311
+ **Reusable pointer example:** [`docs/examples/click-sparks`](https://github.com/songsid/AgEnD/blob/main/docs/examples/click-sparks.md) has a small two-file CW1 package: click for a burst, hold the primary button and move for a trail. Copy it into your working directory before uploading. Protected controls receive no pointer input; samples are coalesced (up to 60 Hz, 30 at reduced quality), so do not use it as a required click or drag control.
312
+
269
313
  **The tools:**
270
314
 
271
- - `upload_web_effect { dir }` → `{ id, warnings }`. It counts as an upload (3 an hour, shared with pictures and mods).
315
+ - `upload_web_effect { dir }` → `{ id, warnings }`. Uploads are not counted; the effect's own size caps apply.
272
316
  **Your own** copies are at most **10 effects and 8 MiB**; effects a person shared with you don't count.
273
317
  - `list_web_effects` — your own effects and those a person shared with you: `id`, `name`, `title`, `regions`, `layer`,
274
318
  `bytes`, `latest_profile`.
@@ -338,8 +382,9 @@ deferred to #1940; do not keep reapplying an agent front while custom CSS is on,
338
382
  `preview_web_effect({id})` posts a volatile Try card in your own web chat, using your current own/shared read rights. It starts nothing and changes no appearance. The sample is physically clipped inside its own host panel or sheet. Only an explicit
339
383
  click by a signed-in **local admin** may start it; never an agent, public link, header token or automatic action.
340
384
  The host owns a visible Trial label and Stop control. Closing the panel/sheet, navigating, window blur, or another
341
- menu/dialog stops it. Custom CSS must be off (on/loading/unknown denies), and the same caps, profiler and safety
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
385
+ menu/dialog stops it. The explicit Try click consents to this sample only; no global HTML-preview opt-in is needed or changed.
386
+ The host isolates the Trial controls and clipped stage in a closed Shadow DOM with fixed styles and reset typography.
387
+ Custom CSS stays active elsewhere. The same caps, profiler and safety 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
343
388
  rechecks the originating agent's current own/shared access, with the trial bound to the admin's session and epoch.
344
389
  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
345
390
  as permission to run or fetch an effect, and do not keep retrying an unavailable Try.