@songsid/agend 2.3.0-beta.7 → 2.3.0-beta.9

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 (88) hide show
  1. package/dist/agent-cli-instructions.md +2 -1
  2. package/dist/agent-cli.js +3 -0
  3. package/dist/agent-cli.js.map +1 -1
  4. package/dist/agent-whats-new.js +2 -0
  5. package/dist/agent-whats-new.js.map +1 -1
  6. package/dist/channel/mcp-tools.js +3 -3
  7. package/dist/channel/mcp-tools.js.map +1 -1
  8. package/dist/daemon.d.ts +2 -0
  9. package/dist/daemon.js +29 -9
  10. package/dist/daemon.js.map +1 -1
  11. package/dist/decision-list.d.ts +25 -0
  12. package/dist/decision-list.js +30 -0
  13. package/dist/decision-list.js.map +1 -0
  14. package/dist/fleet-manager.d.ts +9 -2
  15. package/dist/fleet-manager.js +44 -12
  16. package/dist/fleet-manager.js.map +1 -1
  17. package/dist/fleet-traffic.d.ts +36 -0
  18. package/dist/fleet-traffic.js +100 -0
  19. package/dist/fleet-traffic.js.map +1 -1
  20. package/dist/general-knowledge/skills/web-appearance/SKILL.md +17 -10
  21. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +32 -13
  22. package/dist/instance-config-impact.js +1 -0
  23. package/dist/instance-config-impact.js.map +1 -1
  24. package/dist/outbound-handlers.js +4 -1
  25. package/dist/outbound-handlers.js.map +1 -1
  26. package/dist/outbound-schemas.d.ts +6 -4
  27. package/dist/outbound-schemas.js +7 -3
  28. package/dist/outbound-schemas.js.map +1 -1
  29. package/dist/settings-api.js +4 -0
  30. package/dist/settings-api.js.map +1 -1
  31. package/dist/settings-change.js +4 -0
  32. package/dist/settings-change.js.map +1 -1
  33. package/dist/settings-effect.js +2 -0
  34. package/dist/settings-effect.js.map +1 -1
  35. package/dist/tool-permissions.js +9 -42
  36. package/dist/tool-permissions.js.map +1 -1
  37. package/dist/ui/app-effects.js +9 -5
  38. package/dist/ui/chat-ambient.js +8 -7
  39. package/dist/ui/chat-effect-posters.js +3 -2
  40. package/dist/ui/chat-effects.js +22 -15
  41. package/dist/ui/chat-render.js +5 -2
  42. package/dist/ui/chat-strings.js +6 -4
  43. package/dist/ui/chat-thread.js +134 -17
  44. package/dist/ui/effect-trial-controller.js +13 -8
  45. package/dist/ui/fleet-canvas.js +54 -18
  46. package/dist/ui/fleet-org.js +3 -3
  47. package/dist/ui/fleet-traffic.js +156 -37
  48. package/dist/ui/fleet-usage.js +401 -0
  49. package/dist/ui/panel-chat.js +101 -47
  50. package/dist/ui/panel-fleet.js +6 -5
  51. package/dist/ui/panel-settings.js +6 -1
  52. package/dist/ui/settings-owner-effects.js +1 -1
  53. package/dist/ui/settings-strings.js +2 -0
  54. package/dist/ui/shared/agend-auth.js +1 -1
  55. package/dist/ui/shared/app-route.js +1 -1
  56. package/dist/ui/shared/app-stream.js +3 -2
  57. package/dist/ui/shared/app.css +89 -9
  58. package/dist/ui/shared/effect-app-runtime.js +3 -3
  59. package/dist/ui/shared/effect-chat-runtime.js +1 -1
  60. package/dist/ui/shared/effect-policy.js +5 -6
  61. package/dist/ui/shared/effect-profiler.js +31 -9
  62. package/dist/ui/shared/effect-registry.js +23 -31
  63. package/dist/ui/shared/effect-stock-snapshot.js +9 -0
  64. package/dist/ui/shared/effect-stock-trust.js +37 -6
  65. package/dist/ui/shared/effect-trial-source.js +1 -1
  66. package/dist/ui/shared/effect-trial-stage.js +27 -21
  67. package/dist/ui/shared/effect-trial.css +1 -1
  68. package/dist/ui/shared/fx-motion.js +12 -3
  69. package/dist/ui/shared/tokens.css +9 -3
  70. package/dist/ui/shared/usage-dialog.js +8 -0
  71. package/dist/ui/shared/view-strings.js +4 -0
  72. package/dist/ui/web-terminal/terminal.css +4 -4
  73. package/dist/usage-report.d.ts +12 -1
  74. package/dist/usage-report.js +39 -8
  75. package/dist/usage-report.js.map +1 -1
  76. package/dist/web-ambient.js +9 -2
  77. package/dist/web-ambient.js.map +1 -1
  78. package/dist/web-api.d.ts +2 -0
  79. package/dist/web-api.js +8 -3
  80. package/dist/web-api.js.map +1 -1
  81. package/dist/web-settings-patch.d.ts +3 -1
  82. package/dist/web-settings-patch.js +4 -1
  83. package/dist/web-settings-patch.js.map +1 -1
  84. package/dist/web-shell-routes.d.ts +1 -1
  85. package/dist/web-shell-routes.js +1 -1
  86. package/dist/web-shell-routes.js.map +1 -1
  87. package/dist/workflow-templates/default.md +1 -1
  88. package/package.json +1 -1
@@ -0,0 +1,25 @@
1
+ /**
2
+ * #2152: what `list_decisions` answers. The fleet's decisions are long (82 of them were 126 KB, ≈31k–42k tokens in one
3
+ * call) and every instance lists them after a restart, so by default it answers titles — id, title, scope, date, tags —
4
+ * and the full text is asked for: one decision by `id`, or all of them with `full: true`. One function for both entry
5
+ * paths (the MCP tool through the daemon, and the agent endpoint's `decision-*` ops).
6
+ */
7
+ import type { Decision } from "./scheduler/types.js";
8
+ export interface DecisionTitle {
9
+ id: string;
10
+ title: string;
11
+ scope: Decision["scope"];
12
+ /** The day it was last changed (YYYY-MM-DD). */
13
+ date: string;
14
+ tags?: string[];
15
+ status?: Decision["status"];
16
+ }
17
+ export declare const DECISION_TITLES_HINT = "Titles only. Call list_decisions with { id } for one decision's full text, or { full: true } for every one.";
18
+ /**
19
+ * The answer: `{ decision }` for an id, the full records for `full`, else the titles. `all` is the list as the store
20
+ * returns it (already filtered by scope, archive and tags).
21
+ */
22
+ export declare function decisionListAnswer(all: readonly Decision[], opts?: {
23
+ id?: unknown;
24
+ full?: unknown;
25
+ }): unknown;
@@ -0,0 +1,30 @@
1
+ export const DECISION_TITLES_HINT = "Titles only. Call list_decisions with { id } for one decision's full text, or { full: true } for every one.";
2
+ /** One decision by id (exact, or a unique prefix of at least 6 characters); null when none or more than one match. */
3
+ function byId(all, id) {
4
+ const exact = all.find(d => d.id === id);
5
+ if (exact)
6
+ return exact;
7
+ if (id.length < 6)
8
+ return null;
9
+ const hits = all.filter(d => d.id.startsWith(id));
10
+ return hits.length === 1 ? hits[0] : null;
11
+ }
12
+ /**
13
+ * The answer: `{ decision }` for an id, the full records for `full`, else the titles. `all` is the list as the store
14
+ * returns it (already filtered by scope, archive and tags).
15
+ */
16
+ export function decisionListAnswer(all, opts = {}) {
17
+ if (typeof opts.id === "string" && opts.id.trim()) {
18
+ const d = byId(all, opts.id.trim());
19
+ return d ? { decision: d } : { error: `No decision '${opts.id.trim()}' among these (an id, or a unique prefix of 6 or more characters).` };
20
+ }
21
+ if (opts.full === true)
22
+ return all;
23
+ const titles = all.map(d => ({
24
+ id: d.id, title: d.title, scope: d.scope, date: (d.updated_at || d.created_at || "").slice(0, 10),
25
+ ...(d.tags?.length ? { tags: d.tags } : {}),
26
+ ...(d.status && d.status !== "active" ? { status: d.status } : {}),
27
+ }));
28
+ return { decisions: titles, hint: DECISION_TITLES_HINT };
29
+ }
30
+ //# sourceMappingURL=decision-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision-list.js","sourceRoot":"","sources":["../src/decision-list.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,oBAAoB,GAAG,6GAA6G,CAAC;AAElJ,sHAAsH;AACtH,SAAS,IAAI,CAAC,GAAwB,EAAE,EAAU;IAChD,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACzC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;IAClD,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAwB,EAAE,OAAyC,EAAE;IACtG,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;QAClD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,gBAAgB,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,oEAAoE,EAAE,CAAC;IAC7I,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,GAAG,CAAC;IACnC,MAAM,MAAM,GAAoB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5C,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QACjG,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnE,CAAC,CAAC,CAAC;IACJ,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC;AAC3D,CAAC"}
@@ -75,7 +75,7 @@ import { ModStore } from "./web-mod-store.js";
75
75
  import { AgentMods } from "./web-mod-agent.js";
76
76
  import { type CachedImage } from "./web-images.js";
77
77
  import { WebSettingsTools } from "./web-settings-tools.js";
78
- import { type TrafficItem } from "./fleet-traffic.js";
78
+ import { type Delegation, type TrafficItem } from "./fleet-traffic.js";
79
79
  import { type RawConfigPatch } from "./settings-api.js";
80
80
  import { type AgentEndpointContext } from "./agent-endpoint.js";
81
81
  import { ClassicChannelManager } from "./classic-channel-manager.js";
@@ -705,8 +705,12 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
705
705
  private ensureDeliveryOutbox;
706
706
  /** #1918: cross-instance traffic, as the org canvas draws it (fleet-traffic.ts). */
707
707
  private readonly trafficLog;
708
+ private readonly delegations;
708
709
  private trafficMemo;
709
- /** One delivery row's traffic item, kept for the snapshot and sent to the open pages when it is news. */
710
+ /**
711
+ * One delivery row's traffic item, kept for the snapshot and sent to the open pages when it is news; and the
712
+ * delegation it opens or closes (a task and its report), sent as "delegation".
713
+ */
710
714
  private publishTraffic;
711
715
  /**
712
716
  * GET /ui/traffic: what is in flight now (the outbox's pending rows) and what finished in the last two minutes, at
@@ -716,6 +720,7 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
716
720
  trafficSnapshot(): {
717
721
  now: string;
718
722
  items: TrafficItem[];
723
+ delegations: Delegation[];
719
724
  };
720
725
  /** Synchronous SQLite admission; the caller may acknowledge only after this returns. */
721
726
  admitDurableDelivery(input: {
@@ -2198,6 +2203,8 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
2198
2203
  private guildEmojiCache;
2199
2204
  private guildEmojiFetches;
2200
2205
  private webImageCaches;
2206
+ /** Server emoji whose picture fetch failure was already logged at warn (once each; bounded). */
2207
+ private readonly webEmojiFailures;
2201
2208
  private webImageCache;
2202
2209
  /**
2203
2210
  * The bots instances and ClassicBot rooms speak through, by connections configured now (a connection removed from
@@ -183,7 +183,7 @@ import { crossInstanceVisibility, runVisibilityCommand } from "./cross-instance-
183
183
  import { WebSettingsTools } from "./web-settings-tools.js";
184
184
  import { bindGuestRequest, guestRouteDecision } from "./web-guest-access.js";
185
185
  import { GUEST_ROOM_TICK_MS, GuestRoomMembership, guestGroupRooms } from "./web-guest-rooms.js";
186
- import { TrafficLog, trafficItem } from "./fleet-traffic.js";
186
+ import { Delegations, TrafficLog, trafficItem } from "./fleet-traffic.js";
187
187
  import { installedChannel, updateNoticeKey } from "./update-check.js";
188
188
  import { resolveInstalledAgend } from "./update-dispatch.js";
189
189
  import { resolveUpdateLaunch, openUpdateLog, updateLogPath, watchUpdateLaunch } from "./update-launch.js";
@@ -232,6 +232,7 @@ import { AuthorityStateStore } from "./authority/authority-state.js";
232
232
  import { SessionAuthorizations } from "./authority/session-authorizations.js";
233
233
  import { SessionAuthorizationRequests } from "./web-session-authorization.js";
234
234
  import { GuestLoginCodes, WebLoginCodes, LOGIN_CODE_TTL_MS } from "./web-login.js";
235
+ import { decisionListAnswer } from "./decision-list.js";
235
236
  import { CodeRequestLimiter, ReturningDevices } from "./web-returning-device.js";
236
237
  import { allowedHostNames, applyWebSecurityHeaders, hostnameOf, isHostAllowed, LOOPBACK_HOST_NAMES, WEB_HOST_REJECTED_MESSAGE } from "./web-host-guard.js";
237
238
  import { createPreviewListener, normalizeOrigin, previewAvailability, previewSettings } from "./web-preview.js";
@@ -1693,16 +1694,27 @@ export class FleetManager {
1693
1694
  }
1694
1695
  /** #1918: cross-instance traffic, as the org canvas draws it (fleet-traffic.ts). */
1695
1696
  trafficLog = new TrafficLog();
1697
+ delegations = new Delegations();
1696
1698
  trafficMemo = null;
1697
- /** One delivery row's traffic item, kept for the snapshot and sent to the open pages when it is news. */
1699
+ /**
1700
+ * One delivery row's traffic item, kept for the snapshot and sent to the open pages when it is news; and the
1701
+ * delegation it opens or closes (a task and its report), sent as "delegation".
1702
+ */
1698
1703
  publishTraffic(row, state) {
1699
1704
  try {
1700
1705
  const item = trafficItem(row, this.fleetConfig, new Date().toISOString(), state);
1701
1706
  const news = item ? this.trafficLog.note(item) : null;
1702
- if (news) {
1707
+ const work = news ? this.delegations.note(row, news) : [];
1708
+ if (news || work.length)
1703
1709
  this.trafficMemo = null;
1710
+ if (news)
1704
1711
  this.emitSseEvent("traffic", news);
1705
- }
1712
+ // Each delegation as its two instances are seen now: one that expires or is pushed out may be older than a change
1713
+ // to their visibility (the incoming row's own item was checked; these can be anyone's).
1714
+ const visible = (name) => crossInstanceVisibility(this.fleetConfig, name) !== "hidden";
1715
+ for (const d of work)
1716
+ if (visible(d.from) && visible(d.to))
1717
+ this.emitSseEvent("delegation", d);
1706
1718
  }
1707
1719
  catch (err) {
1708
1720
  this.logger.debug({ err }, "traffic: an item was not published");
@@ -1722,7 +1734,8 @@ export class FleetManager {
1722
1734
  .map((r) => trafficItem(r, this.fleetConfig, r.createdAt ?? now)).filter((i) => i !== null);
1723
1735
  const visible = (name) => crossInstanceVisibility(this.fleetConfig, name) !== "hidden";
1724
1736
  const items = this.trafficLog.snapshot(pending).filter((i) => visible(i.from) && visible(i.to));
1725
- this.trafficMemo = { atMs: nowMs, value: { now, items } };
1737
+ const delegations = this.delegations.snapshot().filter((d) => visible(d.from) && visible(d.to));
1738
+ this.trafficMemo = { atMs: nowMs, value: { now, items, delegations } };
1726
1739
  return this.trafficMemo.value;
1727
1740
  }
1728
1741
  /** Synchronous SQLite admission; the caller may acknowledge only after this returns. */
@@ -10163,10 +10176,11 @@ export class FleetManager {
10163
10176
  }
10164
10177
  case "fleet_decision_list":
10165
10178
  db.pruneExpiredDecisions();
10166
- result = db.listDecisions(projectRoot, {
10179
+ // #2152: titles by default; the full text by id, or all of it with full: true.
10180
+ result = decisionListAnswer(db.listDecisions(projectRoot, {
10167
10181
  includeArchived: payload.include_archived,
10168
10182
  tags: payload.tags,
10169
- });
10183
+ }), { id: payload.id, full: payload.full });
10170
10184
  break;
10171
10185
  case "fleet_decision_update": {
10172
10186
  const id = payload.id;
@@ -10359,10 +10373,16 @@ export class FleetManager {
10359
10373
  created_by: instance,
10360
10374
  });
10361
10375
  }
10362
- case "list": return db.listDecisions(projectRoot, {
10363
- includeArchived: args.includeArchived === true,
10364
- tags: asStrArr(args.tags),
10365
- });
10376
+ // #2152: titles by default (agend-agent decision-list); one decision's full text by id (decision-get <id>).
10377
+ // The CLI sends include_archived (snake case, as the MCP tool): both spellings are read.
10378
+ case "list":
10379
+ case "get":
10380
+ if (op === "get" && !asStr(args.id)?.trim())
10381
+ return { error: "id is required" };
10382
+ return decisionListAnswer(db.listDecisions(projectRoot, {
10383
+ includeArchived: args.includeArchived === true || args.include_archived === true,
10384
+ tags: asStrArr(args.tags),
10385
+ }), { id: op === "get" ? asStr(args.id) ?? "" : args.id, full: args.full });
10366
10386
  case "update": {
10367
10387
  const id = asStr(args.id);
10368
10388
  if (!id)
@@ -11398,11 +11418,23 @@ export class FleetManager {
11398
11418
  guildEmojiFetches = new Map();
11399
11419
  // ── #1630: what stands for an instance in the web app, and Discord server emoji in web chat ──
11400
11420
  webImageCaches = null;
11421
+ /** Server emoji whose picture fetch failure was already logged at warn (once each; bounded). */
11422
+ webEmojiFailures = new Set();
11401
11423
  webImageCache(kind) {
11402
11424
  const onError = (key, err) => this.logger.debug({ err: err?.message, key }, "web image fetch failed (kept what was cached)");
11425
+ // A server emoji's picture that cannot be fetched reads `:name:` in web chat (it used to be an empty box, the user's
11426
+ // "tofu"): say why once per emoji, where it can be seen, not on every render (its key is quiet for an hour anyway).
11427
+ const emojiError = (key, err) => {
11428
+ if (this.webEmojiFailures.has(key))
11429
+ return onError(key, err);
11430
+ this.webEmojiFailures.add(key);
11431
+ while (this.webEmojiFailures.size > 512)
11432
+ this.webEmojiFailures.delete(this.webEmojiFailures.values().next().value);
11433
+ this.logger.warn({ err: err?.message, key }, "Discord server emoji picture could not be fetched (web chat shows its :name:)");
11434
+ };
11403
11435
  this.webImageCaches ??= {
11404
11436
  avatars: new WebImageCache({ dir: join(this.dataDir, "cache", "avatars"), onError }),
11405
- emoji: new WebImageCache({ dir: join(this.dataDir, "cache", "emoji"), onError }),
11437
+ emoji: new WebImageCache({ dir: join(this.dataDir, "cache", "emoji"), onError: emojiError }),
11406
11438
  };
11407
11439
  return this.webImageCaches[kind];
11408
11440
  }