@songsid/agend 2.3.2-beta.15 → 2.3.2-beta.17

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 (92) hide show
  1. package/README.md +2 -0
  2. package/README.zh-TW.md +2 -0
  3. package/dist/backend/claude-code.js +23 -1
  4. package/dist/backend/claude-code.js.map +1 -1
  5. package/dist/backend/kiro.d.ts +2 -0
  6. package/dist/backend/kiro.js +7 -0
  7. package/dist/backend/kiro.js.map +1 -1
  8. package/dist/cache-service.d.ts +13 -1
  9. package/dist/cache-service.js +45 -2
  10. package/dist/cache-service.js.map +1 -1
  11. package/dist/channel/mcp-tools.js +4 -4
  12. package/dist/channel/mcp-tools.js.map +1 -1
  13. package/dist/config-validator.js +4 -1
  14. package/dist/config-validator.js.map +1 -1
  15. package/dist/fleet-manager.d.ts +14 -0
  16. package/dist/fleet-manager.js +36 -5
  17. package/dist/fleet-manager.js.map +1 -1
  18. package/dist/general-knowledge/skills/fleet-config/SKILL.md +5 -3
  19. package/dist/general-knowledge/skills/fleet-restart/SKILL.md +1 -1
  20. package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +24 -0
  21. package/dist/general-knowledge/skills/session-management/SKILL.md +1 -1
  22. package/dist/general-knowledge/skills/tui-effort/SKILL.md +1 -1
  23. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +3 -1
  24. package/dist/general-knowledge/skills/web-appearance/SKILL.md +3 -1
  25. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +27 -13
  26. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +27 -13
  27. package/dist/instance-config-impact.js +1 -0
  28. package/dist/instance-config-impact.js.map +1 -1
  29. package/dist/kiro-reconcile.js +11 -3
  30. package/dist/kiro-reconcile.js.map +1 -1
  31. package/dist/locale.js +4 -0
  32. package/dist/locale.js.map +1 -1
  33. package/dist/office-levels.d.ts +64 -0
  34. package/dist/office-levels.js +66 -0
  35. package/dist/office-levels.js.map +1 -0
  36. package/dist/office-share-page.js +1 -1
  37. package/dist/office-share-page.js.map +1 -1
  38. package/dist/office-share.d.ts +18 -2
  39. package/dist/office-share.js +22 -4
  40. package/dist/office-share.js.map +1 -1
  41. package/dist/public-web-gateway.js +1 -1
  42. package/dist/public-web-gateway.js.map +1 -1
  43. package/dist/scheduler/task-board.d.ts +28 -6
  44. package/dist/scheduler/task-board.js +66 -11
  45. package/dist/scheduler/task-board.js.map +1 -1
  46. package/dist/settings-api.js +4 -0
  47. package/dist/settings-api.js.map +1 -1
  48. package/dist/settings-change.js +2 -0
  49. package/dist/settings-change.js.map +1 -1
  50. package/dist/settings-effect.js +2 -0
  51. package/dist/settings-effect.js.map +1 -1
  52. package/dist/task-board-waker.js +7 -2
  53. package/dist/task-board-waker.js.map +1 -1
  54. package/dist/types.d.ts +5 -0
  55. package/dist/ui/fleet-office-card.js +114 -0
  56. package/dist/ui/fleet-office-editor.js +27 -7
  57. package/dist/ui/fleet-office-levels.js +105 -0
  58. package/dist/ui/fleet-office-model.js +9 -1
  59. package/dist/ui/fleet-office-pack.d.ts +2 -0
  60. package/dist/ui/fleet-office-pack.js +48 -2
  61. package/dist/ui/fleet-office-skin.js +39 -3
  62. package/dist/ui/fleet-office-store.js +13 -0
  63. package/dist/ui/fleet-office.js +172 -26
  64. package/dist/ui/fleet-org.js +2 -0
  65. package/dist/ui/fleet-task-card.js +2 -2
  66. package/dist/ui/fleet-task-common.js +30 -7
  67. package/dist/ui/fleet-task-work.js +2 -2
  68. package/dist/ui/fleet-tasks.js +10 -11
  69. package/dist/ui/office-share-page.js +1 -0
  70. package/dist/ui/panel-settings.js +7 -1
  71. package/dist/ui/settings-registry.js +1 -0
  72. package/dist/ui/settings-strings.js +2 -0
  73. package/dist/ui/shared/app.css +44 -0
  74. package/dist/usage-rollup.d.ts +34 -3
  75. package/dist/usage-rollup.js +56 -3
  76. package/dist/usage-rollup.js.map +1 -1
  77. package/dist/web-api.d.ts +5 -0
  78. package/dist/web-api.js +42 -10
  79. package/dist/web-api.js.map +1 -1
  80. package/dist/web-auth.js +1 -1
  81. package/dist/web-auth.js.map +1 -1
  82. package/dist/web-office-acts.d.ts +5 -2
  83. package/dist/web-office-acts.js +7 -2
  84. package/dist/web-office-acts.js.map +1 -1
  85. package/dist/web-office-store.d.ts +6 -1
  86. package/dist/web-office-store.js +5 -0
  87. package/dist/web-office-store.js.map +1 -1
  88. package/dist/web-settings-patch.d.ts +3 -1
  89. package/dist/web-settings-patch.js +4 -1
  90. package/dist/web-settings-patch.js.map +1 -1
  91. package/dist/workflow-templates/default.md +1 -1
  92. package/package.json +1 -1
@@ -15,7 +15,7 @@ import { Empty, ErrorState, Skeleton } from "/assets/ui-states.js";
15
15
  import { Icon } from "/assets/ui-icons.js";
16
16
  import { Menu } from "/assets/ui-menu.js";
17
17
  import { toast } from "/assets/ui-toast.js";
18
- import { AskHost, COLUMNS, NO_PROJECT, ProgressBar, StatusPill, UNASSIGNED, Who, answerBlocked, boardApi, currentWork, dropNeighbours, errorText, followsSubs, moveCard, onPublicLink, projectKey, projectStats, readStored, recentlyDone, relTime, workersOf, wrapUpText, writeStored } from "./fleet-task-common.js";
18
+ import { AskHost, COLUMNS, NO_PROJECT, ProgressBar, StatusPill, UNASSIGNED, Who, answerBlocked, boardApi, currentWork, dropNeighbours, errorText, followsSubs, moveCard, onPublicLink, projectKey, projectStats, readStored, recentlyDone, relTime, reviewLabel, waitsForYou, workersOf, wrapUpText, writeStored } from "./fleet-task-common.js";
19
19
  import { CardDialog } from "./fleet-task-card.js";
20
20
  import { InstancesDrawer } from "./fleet-task-work.js";
21
21
 
@@ -188,16 +188,16 @@ function ProjectTile({ project, stats, onOpen, onDialog, reload }) {
188
188
  }
189
189
 
190
190
  /**
191
- * Cards waiting for the person: to confirm or send back, and blocked ones to answer. A card's buttons take one answer
192
- * at a time: claimed before the first await, so a double click sends one move.
191
+ * Cards waiting for the person: to confirm or send back, and blocked ones to answer — #2080: only those the person
192
+ * handed out (waitsForYou, Needs you's rule); an agent's card in review is its confirmer's, and a blocked one asks its
193
+ * dispatcher, not the person. A card's buttons take one answer at a time: claimed before the first await, so a double
194
+ * click sends one move.
193
195
  */
194
196
  function Waiting({ cards, writable, onOpen, reload }) {
195
- const { instances } = useStore(appStore);
196
- const fleetNames = new Set(instances.map((i) => i.name));
197
197
  const pending = useRef(new Set());
198
198
  const [busy, setBusy] = useState(() => new Set());
199
- const review = cards.filter((c) => c.status === "review");
200
- const blocked = cards.filter((c) => c.status === "blocked");
199
+ const review = cards.filter((c) => c.status === "review" && waitsForYou(c));
200
+ const blocked = cards.filter((c) => c.status === "blocked" && waitsForYou(c));
201
201
  if (!review.length && !blocked.length) return null;
202
202
  const act = async (fn, done, card) => {
203
203
  if (pending.current.has(card.id)) return;
@@ -213,8 +213,6 @@ function Waiting({ cards, writable, onOpen, reload }) {
213
213
  <${StatusPill} status=${c.status} />
214
214
  <button type="button" class="tb-wait-title" onClick=${() => onOpen(c.id)}><span class="tb-code">${c.id}</span> ${c.title}
215
215
  ${c.status === "blocked" && c.blockedReason ? html`<span class="tb-wait-reason">${c.blockedReason}</span>` : null}
216
- ${c.status === "blocked" && c.dispatcher && c.dispatcher.kind === "instance" && c.dispatcher.name !== c.assignee && fleetNames.has(c.dispatcher.name)
217
- ? html`<span class="tb-wait-asked muted">${t("tasks.askedFirst", c.dispatcher.name)}</span>` : null}
218
216
  ${c.status === "review" && wrapUpText(c) ? html`<span class="tb-wait-reason wrapup">${t("tasks.wrapLine", wrapUpText(c))}</span>` : null}</button>
219
217
  </div>
220
218
  <div class="tb-wait-actions">
@@ -257,7 +255,7 @@ function SearchBox({ onOpen }) {
257
255
  ${results ? html`<ul class="tb-search-results" role="listbox">
258
256
  ${results.length ? results.map((r, i) => html`<li key=${r.card.id} role="option" aria-selected=${i === active ? "true" : "false"} class=${i === active ? "active" : ""}>
259
257
  <button type="button" onClick=${() => pick(r.card.id)}>
260
- <span class="tb-code">${r.card.id}</span><span class="tb-search-title">${r.card.title}</span><${StatusPill} status=${r.card.status} />
258
+ <span class="tb-code">${r.card.id}</span><span class="tb-search-title">${r.card.title}</span><${StatusPill} status=${r.card.status} card=${r.card} />
261
259
  <span class="tb-search-where muted">${[r.project, r.parentTitle].filter(Boolean).join(" › ")}${r.match ? ` · ${t("tasks.inField", t(`tasks.field${r.match.field}`))}: ${r.match.text}` : ""}</span>
262
260
  </button></li>`) : html`<li class="muted tb-search-none">${t("tasks.searchEmpty")}</li>`}
263
261
  </ul>` : null}
@@ -457,9 +455,10 @@ function Tile({ card, dragging, flash, subs = [], expanded, writable, onToggleSu
457
455
  ${now ? html`<div class="tb-tile-now" title=${now.cards.map((c) => `${c.id} ${c.title}`).join("\n")}>
458
456
  <span class=${`tb-now-label st-${now.tone}`}>${t(now.label)}</span><span class="tb-code">${now.cards[0].id}</span>
459
457
  <span class="tb-now-title">${now.cards[0].title}</span>${now.cards.length > 1 ? html`<span class="muted">${t("tasks.moreCards", now.cards.length - 1)}</span>` : null}</div>` : null}
458
+ ${card.status === "review" && !hasSubs ? html`<div class=${`tb-tile-waits${waitsForYou(card) ? " you" : ""}`}>${reviewLabel(card)}</div>` : null}
460
459
  <div class="tb-tile-foot">
461
460
  ${now ? html`<span class="tb-people">${workers.map((w) => html`<${Who} key=${w} name=${w} empty=${t("tasks.nobody")} title=${t("tasks.ownerTip", card.assignee || t("tasks.nobody"))} />`)}</span>`
462
- : hasSubs && card.status === "review" ? html`<span class="tb-who tb-now-label st-review" title=${t("tasks.ownerTip", card.assignee || t("tasks.nobody"))}>${t("tasks.review")}</span>`
461
+ : hasSubs && card.status === "review" ? html`<span class="tb-who tb-now-label st-review" title=${t("tasks.ownerTip", card.assignee || t("tasks.nobody"))}>${reviewLabel(card)}</span>`
463
462
  : html`<${Who} name=${card.assignee} empty=${t("tasks.nobody")} />`}
464
463
  <span class="tb-tile-stats">
465
464
  ${card.acceptance.length ? html`<span class=${accepted === card.acceptance.length ? "all" : ""} title=${t(card.kind === "main" ? "tasks.definition" : "tasks.acceptance")}><${Icon} name="check" size=${13} />${accepted}/${card.acceptance.length}</span>` : null}
@@ -30,6 +30,7 @@ export function shareUrl(base, path) {
30
30
  const p = String(path);
31
31
  if (p === "/ui/offices") return `${base}/offices`;
32
32
  if (p === "/ui/office-acts") return `${base}/office-acts`;
33
+ if (p === "/ui/office-levels") return `${base}/office-levels`;
33
34
  if (p === "/ui/office-skins" || p.startsWith("/ui/office-skins/") || p.startsWith("/ui/office-skins?")) return `${base}${p.slice(3)}`;
34
35
  return null;
35
36
  }
@@ -1198,13 +1198,14 @@ function WebSection({ ctx, staged, part = "all" }) {
1198
1198
  echo: web.echo_to_channel ?? true,
1199
1199
  log: web.log_tab === true, // #1218: off by default
1200
1200
  usagePub: web.usage_report_on_public_link === true, // #2122: off by default
1201
+ levels: web.office_levels !== false, // #2661: on by default
1201
1202
  pub: { allow_public: (web.public_link && web.public_link.allow_public) ?? true, ttl_minutes: (web.public_link && web.public_link.ttl_minutes) ?? 120, protocol: (web.public_link && web.public_link.protocol) ?? "http2", hostname: (web.public_link && web.public_link.hostname) ?? "", tunnel_token_env: (web.public_link && web.public_link.tunnel_token_env) ?? "", origin_port: (web.public_link && web.public_link.origin_port) ?? 19282, auto_open: (web.public_link && web.public_link.auto_open) ?? false },
1202
1203
  session: { absolute_hours: local.absolute_hours ?? null, idle_hours: local.idle_hours ?? null },
1203
1204
  terminal: { enabled: term.enabled ?? null, ttl_minutes: term.ttl_minutes ?? null },
1204
1205
  }), []);
1205
1206
  const text = (v) => (v === null || v === undefined ? "" : String(v));
1206
1207
  /** #2347: a field's row class: `s-dirty` while it differs from what is saved (the draft may come from before). */
1207
- const savedForm = useMemo(() => ({ notify: String(original.notify), echo: original.echo, log: original.log, usagePub: original.usagePub, pub: original.pub.allow_public,
1208
+ const savedForm = useMemo(() => ({ notify: String(original.notify), echo: original.echo, log: original.log, usagePub: original.usagePub, levels: original.levels, pub: original.pub.allow_public,
1208
1209
  ttl: String(original.pub.ttl_minutes), protocol: original.pub.protocol, hostname: original.pub.hostname, originPort: String(original.pub.origin_port),
1209
1210
  abs: text(original.session.absolute_hours), idle: text(original.session.idle_hours), termOn: original.terminal.enabled !== false,
1210
1211
  termTtl: text(original.terminal.ttl_minutes), autoOpen: original.pub.auto_open }), []);
@@ -1218,6 +1219,7 @@ function WebSection({ ctx, staged, part = "all" }) {
1218
1219
  return {
1219
1220
  notify: String(pick(pending, "notify_login", original.notify)),
1220
1221
  echo: pick(pending, "echo_to_channel", original.echo), log: pick(pending, "log_tab", original.log), usagePub: pick(pending, "usage_report_on_public_link", original.usagePub),
1222
+ levels: pick(pending, "office_levels", original.levels),
1221
1223
  pub: pick(pub, "allow_public", original.pub.allow_public), ttl: String(pick(pub, "ttl_minutes", original.pub.ttl_minutes)), protocol: pick(pub, "protocol", original.pub.protocol),
1222
1224
  hostname: pick(pub, "hostname", original.pub.hostname), originPort: String(pick(pub, "origin_port", original.pub.origin_port)), autoOpen: pick(pub, "auto_open", original.pub.auto_open),
1223
1225
  abs: text(pick(session, "absolute_hours", original.session.absolute_hours)), idle: text(pick(session, "idle_hours", original.session.idle_hours)),
@@ -1269,6 +1271,7 @@ function WebSection({ ctx, staged, part = "all" }) {
1269
1271
  ...(f.echo !== original.echo ? { echo_to_channel: f.echo } : {}),
1270
1272
  ...(f.log !== original.log ? { log_tab: f.log } : {}),
1271
1273
  ...(f.usagePub !== original.usagePub ? { usage_report_on_public_link: f.usagePub } : {}),
1274
+ ...(f.levels !== original.levels ? { office_levels: f.levels } : {}),
1272
1275
  ...(Object.keys(publicPatch).length ? { public_link: publicPatch } : {}),
1273
1276
  ...(Object.keys(sessionPatch).length ? { session: { local: sessionPatch } } : {}),
1274
1277
  ...(Object.keys(terminalPatch).length ? { web_terminal: terminalPatch } : {}),
@@ -1278,6 +1281,7 @@ function WebSection({ ctx, staged, part = "all" }) {
1278
1281
  ...(body.echo_to_channel !== undefined ? ["web.echo_to_channel"] : []),
1279
1282
  ...(body.log_tab !== undefined ? ["web.log_tab"] : []),
1280
1283
  ...(body.usage_report_on_public_link !== undefined ? ["web.usage_report_on_public_link"] : []),
1284
+ ...(body.office_levels !== undefined ? ["web.office_levels"] : []),
1281
1285
  ...Object.keys(publicPatch).map((k) => `web.public_link.${k}`),
1282
1286
  ...Object.keys(sessionPatch).map((k) => `web.session.local.${k}`),
1283
1287
  ...Object.keys(terminalPatch).map((k) => `web_terminal.${k}`),
@@ -1369,6 +1373,8 @@ function WebSection({ ctx, staged, part = "all" }) {
1369
1373
  <p class="note">${tn("webLogTabHint")}</p>
1370
1374
  <label class=${fc("check", "usagePub")}><input id="webUsagePublic" type="checkbox" checked=${f.usagePub} onChange=${(e) => set("usagePub")(e.target.checked)} /><span>${tn("webUsagePublic")}</span><${Impact} schema=${schema} field="web.usage_report_on_public_link" /></label>
1371
1375
  <p class="note">${tn("webUsagePublicHint")}</p>
1376
+ <label class=${fc("check", "levels")}><input id="webOfficeLevels" type="checkbox" checked=${f.levels} onChange=${(e) => set("levels")(e.target.checked)} /><span>${tn("webOfficeLevels")}</span><${Impact} schema=${schema} field="web.office_levels" /></label>
1377
+ <p class="note">${tn("webOfficeLevelsHint")}</p>
1372
1378
  </section>`) : null}
1373
1379
  ${has("readonly") ? html`<section class="card s-web-readonly"><h3>${tn("webReadOnlyTitle")}</h3>
1374
1380
  <p class="note">${tn("webReadOnlyLead")}</p>
@@ -66,6 +66,7 @@ const ROWS = [
66
66
  // Fleet · Web dashboard
67
67
  ["dash.log-tab", "web-dashboard", "#webLogTab", "settings.webLogTab", "web.log_tab", ["log tab", "steps", "log"], ["Log 分頁", "紀錄", "步驟"]],
68
68
  ["dash.usage-public", "web-dashboard", "#webUsagePublic", "settings.webUsagePublic", "web.usage_report_on_public_link", ["usage", "public link", "cost", "tokens"], ["用量", "公開連結", "費用"]],
69
+ ["dash.office-levels", "web-dashboard", "#webOfficeLevels", "settings.webOfficeLevels", "web.office_levels", ["office", "level", "badge", "profile card"], ["辦公室", "等級", "徽章", "名片"]],
69
70
  ["dash.app-icon", "web-dashboard", ".s-app-icon", "settings.appIconTitle", null, ["app icon", "favicon", "home screen", "icon"], ["App 圖示", "圖示", "主畫面"]],
70
71
  ["dash.card-limits", "web-dashboard", ".s-card-limits", "settings.cardLimitsTitle", "web.appearance", ["upload limits", "portrait", "banner", "card limits"], ["上傳限制", "身分卡上傳限制"]],
71
72
  ["dash.canvas-worker", "web-dashboard", ".s-experimental-effects", "experimentalEffects.title", "web.experimental.canvas_worker", ["canvas worker", "experimental", "effects"], ["Canvas Worker", "實驗功能", "特效"]],
@@ -39,6 +39,7 @@ register("settings", {
39
39
  namedTokenSaved: "Token change saved. Reopen the public link.",
40
40
  webEcho: "Web echo",
41
41
  webEchoHint: "Copies web messages to the bound Telegram or Discord topic. ClassicBot rooms follow it unless a room sets its own.",
42
+ webOfficeLevels: "Office levels", webOfficeLevelsHint: "Each agent's level from its lifetime work, on its name tag in the Office and on its profile card. Off removes the badges and the card's level rows. The token counts behind a level follow the usage report's rules. Applies at once.",
42
43
  webUsagePublic: "Usage report over the public link", webUsagePublicHint: "Fleet → Usage (up to 400 days of each agent's tokens, requests, messages and API-equivalent amounts) is offered over the temporary public link too. Off by default; guests never see it. Applies at once.",
43
44
  webLogTab: "Log tab: each agent's steps", webLogTabHint: "Shows each instance's prompts, replies, tool calls and results, and fleet events in its Log tab, read from its own transcript only while the tab is open. Secret values are masked. Also over the public link. Turning it on waits for a fleet admin's confirmation.",
44
45
  general: "General Settings",
@@ -719,6 +720,7 @@ register("settings", {
719
720
  namedTokenSaved: "Token 變更已儲存,請重新開啟公開連結。",
720
721
  webEcho: "Web 同步",
721
722
  webEchoHint: "將網頁訊息複製到綁定的 Telegram 或 Discord 主題。ClassicBot 聊天室也照這個設定,除非該聊天室另外設定。",
723
+ webOfficeLevels: "辦公室等級", webOfficeLevelsHint: "每個 agent 依終身工作量得到的等級,顯示在辦公室的名牌與名片上。關閉會移除徽章與名片上的等級列。等級背後的 token 數字依用量報告的規則顯示。變更立即生效。",
722
724
  webUsagePublic: "透過公開連結提供用量報告", webUsagePublicHint: "Fleet → 用量(最多 400 天、每個 agent 的 token、請求、訊息與依牌價換算的 API 等值)也會透過臨時公開連結提供。預設關閉;訪客一律看不到。變更立即生效。",
723
725
  webLogTab: "紀錄分頁:每個 agent 的步驟", webLogTabHint: "在每個 instance 的「紀錄」分頁顯示提示、回覆、工具呼叫與結果,以及 fleet 事件;只在分頁開著時從它自己的對話紀錄讀取。機密值會遮蔽。公開連結也看得到。開啟需 fleet admin 確認。",
724
726
  general: "一般設定",
@@ -1809,6 +1809,47 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1809
1809
  .oo-mini-dot.match { fill: var(--focus); }
1810
1810
  .oo-tip { position: absolute; left: 0; top: 0; z-index: 5; max-width: 240px; pointer-events: none; padding: 6px 10px; font-size: var(--fs-xs); line-height: 1.4;
1811
1811
  color: var(--text); background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md); box-shadow: var(--shadow-2); overflow-wrap: anywhere; }
1812
+ /* #2661: a person's profile card — a popover beside them (placed by the page: transform through the CSSOM), 320 px fixed;
1813
+ on a phone a bottom sheet. Tone over borders; the status tokens for the level's tier. */
1814
+ .oo-card { position: absolute; left: 0; top: 0; z-index: 8; width: 320px; box-sizing: border-box; padding: var(--s-3); font-size: var(--fs-sm); line-height: var(--lh-sm);
1815
+ color: var(--text); background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); box-shadow: var(--shadow-2); }
1816
+ .oo-card.sheet { position: fixed; left: 0; right: 0; top: auto; bottom: 0; width: auto; transform: none; z-index: 40; border-radius: var(--r-lg) var(--r-lg) 0 0;
1817
+ padding-bottom: calc(var(--s-3) + env(safe-area-inset-bottom, 0px)); touch-action: none; }
1818
+ /* On a phone the tab bar is fixed at the window's foot (z 35): the sheet sits above it. */
1819
+ @media (max-width: 899px) {
1820
+ .oo-card.sheet { bottom: calc(56px + env(safe-area-inset-bottom, 0px)); padding-bottom: var(--s-3); }
1821
+ .kb-open .oo-card.sheet { bottom: 0; }
1822
+ }
1823
+ .oo-card-grip { width: 36px; height: 4px; margin: 0 auto var(--s-2); border-radius: var(--r-full); background: var(--surface-2); }
1824
+ .oo-card-head { display: flex; gap: var(--s-3); align-items: flex-start; }
1825
+ .oo-card-avatar { position: relative; flex: none; width: 56px; height: 56px; border-radius: var(--r-md); background: var(--surface-2); }
1826
+ .oo-card-avatar canvas { width: 56px; height: 56px; image-rendering: pixelated; }
1827
+ .oo-card-avatar .oo-badge { position: absolute; left: -6px; top: -6px; }
1828
+ .oo-card-names { flex: 1; min-width: 0; }
1829
+ .oo-card-name { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1830
+ /* One line, cut; a fixed line height so a CJK fallback in the mono stack doesn't make it taller. */
1831
+ .oo-card-instance { height: 18px; line-height: 18px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-xs); color: var(--text-2); }
1832
+ .oo-card-state { color: var(--text-2); }
1833
+ .oo-card-close { flex: none; margin: -4px -4px 0 0; }
1834
+ .oo-card-xp { margin-top: var(--s-3); }
1835
+ .oo-card-bar { display: block; width: 100%; height: 6px; margin-top: var(--s-1); appearance: none; border: 0; border-radius: var(--r-full); background: var(--surface-2); overflow: hidden; }
1836
+ .oo-card-bar::-webkit-progress-bar { background: var(--surface-2); border-radius: var(--r-full); }
1837
+ .oo-card-bar::-webkit-progress-value { background: var(--accent); border-radius: var(--r-full); }
1838
+ .oo-card-bar::-moz-progress-bar { background: var(--accent); border-radius: var(--r-full); }
1839
+ .oo-card-rows { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-2) var(--s-3); margin: var(--s-3) 0 0; }
1840
+ .oo-card-rows > div { min-width: 0; }
1841
+ .oo-card-rows dt { font-size: var(--fs-xs); color: var(--text-3); }
1842
+ .oo-card-rows dd { margin: 0; overflow-wrap: anywhere; }
1843
+ .oo-card-now { margin-top: var(--s-3); overflow-wrap: anywhere; }
1844
+ .oo-card-actions { display: flex; justify-content: flex-end; gap: var(--s-2); margin-top: var(--s-3); }
1845
+ .oo-badge { display: inline-block; min-width: 18px; padding: 0 4px; box-sizing: border-box; font-size: 10px; font-weight: var(--fw-semibold); line-height: 16px; text-align: center;
1846
+ border-radius: var(--r-sm); border: 1px solid var(--border); background: var(--surface-2); color: var(--text-2); }
1847
+ .oo-badge.mark { min-width: 10px; width: 10px; height: 10px; padding: 0; transform: rotate(45deg); border-radius: 2px; }
1848
+ .oo-badge.tier-1 { background: var(--ok-bg); color: var(--ok); border-color: var(--ok); }
1849
+ .oo-badge.tier-2 { background: var(--accent-dim); color: var(--accent); border-color: var(--accent); }
1850
+ .oo-badge.tier-3 { background: var(--accent); color: var(--surface); border-color: var(--accent); }
1851
+ .oo-badge.tier-4 { background: var(--warn-bg); color: var(--warn); border-color: var(--warn); }
1852
+ .oo-badge.tier-5 { background: var(--danger-bg); color: var(--danger); border-color: var(--danger); }
1812
1853
  /* #2554: All offices — each tile's label (office name and head count) just above the tile, placed by the page (left, top,
1813
1854
  max-width through the CSSOM); a button that opens the office, the lobby's a plain chip. */
1814
1855
  .oo-tile-label { position: absolute; left: 0; top: 0; z-index: 3; transform: translateY(calc(-100% - 4px)); max-width: 240px; overflow: hidden; text-overflow: ellipsis;
@@ -2392,6 +2433,9 @@ html.oo-immersive .p-fleet > .panel-body { z-index: 50; }
2392
2433
  .tb-tile-note { display: flex; gap: var(--s-1); align-items: flex-start; font-size: var(--fs-xs); color: var(--text-2); overflow-wrap: anywhere; }
2393
2434
  /* A main task's sub task at work now (its worker in the foot), and what a card waiting for you still lacks. */
2394
2435
  .tb-tile-now { display: flex; align-items: baseline; gap: var(--s-1); min-width: 0; font-size: var(--fs-xs); color: var(--text-2); }
2436
+ /* #2080: whom a card in review waits for — the person (accented), or the agent that confirms it. */
2437
+ .tb-tile-waits { font-size: var(--fs-xs); color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2438
+ .tb-tile-waits.you { color: var(--text); font-weight: var(--fw-semibold); }
2395
2439
  .tb-now-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2396
2440
  .tb-now-label { flex-shrink: 0; font-size: 11px; font-weight: var(--fw-semibold); color: var(--text-2); }
2397
2441
  .tb-now-label.st-claimed { color: var(--accent); }
@@ -48,12 +48,43 @@ export declare function localDate(t: number, zone: string): string;
48
48
  * so a fold repeated after a crash adds nothing twice.
49
49
  */
50
50
  export declare function foldHours(days: UsageDays, ledger: Ledger, cutoff: number, zone: string): boolean;
51
- /** Drop day rows older than the rollup keeps (by date, against `now` in `zone`). */
52
- export declare function pruneDays(days: UsageDays, now: number, zone: string): boolean;
51
+ /**
52
+ * Drop day rows older than the rollup keeps (by date, against `now` in `zone`). #2661: `carriedThrough` (the lifetime
53
+ * file's `through` as it is on disk): only rows at or before it are dropped — one not carried yet stays until it is.
54
+ */
55
+ export declare function pruneDays(days: UsageDays, now: number, zone: string, carriedThrough: string | null): boolean;
56
+ /**
57
+ * #2661: what the days pruned past ROLLUP_KEEP_DAYS held, so an instance's lifetime work (its Office level,
58
+ * office-levels.ts) never shrinks as history ages out — `usage-lifetime.json` beside the rollup, a file no version
59
+ * before #2661 opens (one that rewrites usage-days.json cannot wipe it).
60
+ * - `by`: the carried rows' totals summed by backend; `first`: the earliest date among them; `through`: the latest
61
+ * date carried. A day row at or before `through` is in `by` already and is never added again.
62
+ * - Order: carryPruned adds the rows about to be pruned, the lifetime file is written (atomic rename), and only then
63
+ * does pruneDays drop them from the rollup. A crash between the two writes leaves those rows in both; the next pass
64
+ * skips them here (at or before `through`) and the prune finishes — never counted twice, never lost. A lifetime file
65
+ * that cannot be written prunes nothing that pass.
66
+ * - Rollback gap: an older version running meanwhile prunes days without carrying them; those days are missing from
67
+ * the lifetime total for good (nothing else is lost).
68
+ */
69
+ export interface UsageLifetime {
70
+ v: 1;
71
+ through: string | null;
72
+ first: string | null;
73
+ by: Record<string, HourTotals>;
74
+ }
75
+ export declare const emptyLifetime: () => UsageLifetime;
76
+ /** A lifetime file read back from disk; anything that is not one is empty. */
77
+ export declare function reviveLifetime(raw: unknown): UsageLifetime;
78
+ /**
79
+ * Carry the day rows pruneDays is about to drop (older than ROLLUP_KEEP_DAYS against `now` in `zone`) and not carried
80
+ * yet into `life`. Mutates `life`; returns whether anything was added.
81
+ */
82
+ export declare function carryPruned(life: UsageLifetime, days: UsageDays, now: number, zone: string): boolean;
83
+ export declare function readLifetime(path: string): Promise<UsageLifetime>;
53
84
  /** Record that the scanner has read [from, to]: merged into the intervals, at most COVERAGE_MAX of them. */
54
85
  export declare function addCoverage(days: UsageDays, from: number, to: number): void;
55
86
  /** Whether the scanner has read the hour starting at `h`. */
56
87
  export declare const covered: (days: UsageDays, h: number) => boolean;
57
88
  export declare function readDays(path: string): Promise<UsageDays>;
58
89
  /** Written whole and renamed into place (0600): a crash leaves the old file or the new one, never a mix. */
59
- export declare function writeDays(path: string, days: UsageDays): Promise<boolean>;
90
+ export declare function writeDays(path: string, days: UsageDays | UsageLifetime): Promise<boolean>;
@@ -129,16 +129,69 @@ export function foldHours(days, ledger, cutoff, zone) {
129
129
  days.checkpoint = hours[hours.length - 1];
130
130
  return true;
131
131
  }
132
- /** Drop day rows older than the rollup keeps (by date, against `now` in `zone`). */
133
- export function pruneDays(days, now, zone) {
132
+ /**
133
+ * Drop day rows older than the rollup keeps (by date, against `now` in `zone`). #2661: `carriedThrough` (the lifetime
134
+ * file's `through` as it is on disk): only rows at or before it are dropped — one not carried yet stays until it is.
135
+ */
136
+ export function pruneDays(days, now, zone, carriedThrough) {
134
137
  const oldest = localDate(now - ROLLUP_KEEP_DAYS * DAY, zone);
135
138
  const before = days.rows.length;
136
- days.rows = days.rows.filter(r => r.date >= oldest);
139
+ days.rows = days.rows.filter(r => r.date >= oldest || carriedThrough === null || r.date > carriedThrough);
137
140
  const cov = days.coverage.filter(([, to]) => to >= now - ROLLUP_KEEP_DAYS * DAY);
138
141
  const changed = days.rows.length !== before || cov.length !== days.coverage.length;
139
142
  days.coverage = cov;
140
143
  return changed;
141
144
  }
145
+ export const emptyLifetime = () => ({ v: 1, through: null, first: null, by: dict() });
146
+ const isDate = (v) => typeof v === "string" && /^\d{4}-\d{2}-\d{2}$/.test(v);
147
+ /** A lifetime file read back from disk; anything that is not one is empty. */
148
+ export function reviveLifetime(raw) {
149
+ const l = emptyLifetime();
150
+ if (!raw || typeof raw !== "object" || raw.v !== 1)
151
+ return l;
152
+ const r = raw;
153
+ if (isDate(r.through))
154
+ l.through = r.through;
155
+ if (isDate(r.first))
156
+ l.first = r.first;
157
+ for (const [be, t] of Object.entries((r.by && typeof r.by === "object" ? r.by : {}))) {
158
+ if (Array.isArray(t) && t.length === 7 && t.every(n => Number.isFinite(n)))
159
+ l.by[be] = t;
160
+ }
161
+ return l;
162
+ }
163
+ /**
164
+ * Carry the day rows pruneDays is about to drop (older than ROLLUP_KEEP_DAYS against `now` in `zone`) and not carried
165
+ * yet into `life`. Mutates `life`; returns whether anything was added.
166
+ */
167
+ export function carryPruned(life, days, now, zone) {
168
+ const oldest = localDate(now - ROLLUP_KEEP_DAYS * DAY, zone);
169
+ let changed = false;
170
+ for (const r of days.rows) {
171
+ if (r.date >= oldest || (life.through !== null && r.date <= life.through))
172
+ continue;
173
+ const into = life.by[r.be] ??= [0, 0, 0, 0, 0, 0, 0];
174
+ for (const t of Object.values(r.m))
175
+ add(into, t);
176
+ if (life.first === null || r.date < life.first)
177
+ life.first = r.date;
178
+ changed = true;
179
+ }
180
+ if (!changed)
181
+ return false;
182
+ // Every row before `oldest` is carried now: `through` is the latest of them.
183
+ const last = days.rows.filter(r => r.date < oldest).reduce((m, r) => (r.date > m ? r.date : m), life.through ?? "");
184
+ life.through = last;
185
+ return true;
186
+ }
187
+ export async function readLifetime(path) {
188
+ try {
189
+ return reviveLifetime(JSON.parse(await readFile(path, "utf8")));
190
+ }
191
+ catch {
192
+ return emptyLifetime();
193
+ }
194
+ }
142
195
  /** Record that the scanner has read [from, to]: merged into the intervals, at most COVERAGE_MAX of them. */
143
196
  export function addCoverage(days, from, to) {
144
197
  if (!(from <= to))
@@ -1 +1 @@
1
- {"version":3,"file":"usage-rollup.js","sourceRoot":"","sources":["../src/usage-rollup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"usage-rollup.js","sourceRoot":"","sources":["../src/usage-rollup.ts"],"names":[],"mappings":"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"}
package/dist/web-api.d.ts CHANGED
@@ -68,6 +68,7 @@ export interface WebApiContext {
68
68
  echo_to_channel?: boolean;
69
69
  usage_panel?: boolean;
70
70
  usage_report_on_public_link?: boolean;
71
+ office_levels?: boolean;
71
72
  upload_max_file_mb?: number;
72
73
  upload_max_total_mb?: number;
73
74
  search?: {
@@ -197,6 +198,8 @@ export interface WebApiContext {
197
198
  readonly themeStore?: ThemeStore;
198
199
  /** Fleet → Org chart → Office: the offices people made (web-offices.json); absent: /ui/offices is not offered. */
199
200
  readonly officeStore?: OfficeStore;
201
+ /** #2080: an instance dispatcher no longer in the fleet (its cards fall back to the person: Waiting for you). */
202
+ readonly dispatcherGone?: (name: string) => boolean;
200
203
  /** How often a person may save the offices (absent: no limit, as in a test without it). */
201
204
  readonly officeWrites?: OfficeWriteLimiter;
202
205
  /** #2578: the agents' live acts in the Office view (office_set); absent: /ui/office-acts is not offered. */
@@ -258,6 +261,8 @@ export interface WebApiContext {
258
261
  logSteps?(name: string, q: import("./log-service.js").LogQuery): Promise<unknown>;
259
262
  /** #1468: the prompt-cache expiry analysis for a window ("24h" | "7d" | "30d"); absent: not offered. */
260
263
  cacheReport?(window: string): Promise<unknown>;
264
+ /** #2661: every instance's Office level (office-levels.ts), reused for a minute; null: web.office_levels is off. Absent: not offered. */
265
+ officeLevels?(): Promise<Record<string, import("./office-levels.js").OfficeLevel> | null>;
261
266
  /** #2122: the usage report (Fleet → Usage); absent: not offered. */
262
267
  usageReport?(params: {
263
268
  range: import("./usage-report.js").UsageRange;
package/dist/web-api.js CHANGED
@@ -2565,6 +2565,37 @@ export function handleWebRequest(req, res, url, ctx) {
2565
2565
  json(res, 200, { acts: acts.live(), now: Date.now() }); // now: the host's clock, for the page's offset
2566
2566
  return true;
2567
2567
  }
2568
+ // #2661: GET /ui/office-levels { enabled, unit, detail, levels }: each instance's Office level, read as the offices
2569
+ // are (a guest's routes do not include it). The level for whoever may open the Office; the numbers behind it (work
2570
+ // tokens, today, first seen) only where the usage report would be served (`detail`): not with web.usage_panel off,
2571
+ // not over the public link unless web.usage_report_on_public_link. Off (web.office_levels false): no levels at all.
2572
+ if (method === "GET" && path === "/ui/office-levels") {
2573
+ if (!ctx.officeLevels) {
2574
+ json(res, 404, { error: "Office levels are not kept on this fleet" });
2575
+ return true;
2576
+ }
2577
+ const admitted = admissionOf(req, url, ctx);
2578
+ if (!admitted) {
2579
+ json(res, 401, { error: WEB_TOKEN_INVALID_MESSAGE });
2580
+ return true;
2581
+ }
2582
+ const detail = () => ctx.fleetConfig?.web?.usage_panel !== false
2583
+ && (!gatewayRequestContext(req) || ctx.fleetConfig?.web?.usage_report_on_public_link === true);
2584
+ void import("./office-levels.js").then(async ({ LEVEL, levelsFor }) => {
2585
+ const levels = await ctx.officeLevels();
2586
+ // Asked again before it is sent (it was awaited): a session signed out or a switch turned off meanwhile.
2587
+ if (admissionOf(req, url, ctx) !== admitted)
2588
+ return json(res, 401, { error: WEB_TOKEN_INVALID_MESSAGE });
2589
+ if (!levels || ctx.fleetConfig?.web?.office_levels === false)
2590
+ return json(res, 200, { enabled: false, unit: LEVEL.UNIT, detail: false, levels: {} });
2591
+ const d = detail();
2592
+ json(res, 200, { enabled: true, unit: LEVEL.UNIT, detail: d, levels: levelsFor(levels, d) });
2593
+ }).catch((err) => { ctx.logger.error({ err }, "office levels failed"); try {
2594
+ json(res, 500, { error: "Office levels failed" });
2595
+ }
2596
+ catch { /* already answered */ } });
2597
+ return true;
2598
+ }
2568
2599
  if (path === "/ui/office-skins" || path.startsWith("/ui/office-skins/"))
2569
2600
  return handleOfficeSkins(req, res, url, ctx, path, method);
2570
2601
  if (path === "/ui/office-pack-changes" || path.startsWith("/ui/office-pack-changes/"))
@@ -3389,7 +3420,8 @@ export function handleWebRequest(req, res, url, ctx) {
3389
3420
  // #2296: every open Tasks tab reads the board again after each change; on the dashboard they all get the same
3390
3421
  // board for a revision, so it is built once per (revision, done=all, minute) — the minute for the 14-day
3391
3422
  // window. The public link's reads are filtered per request (hidden instances) and are built each time.
3392
- const key = gateway ? null : `${rev}:${allDone ? 1 : 0}:${Math.floor(Date.now() / 60_000)}`;
3423
+ // #2757 review: and by the dispatchers gone (a deleted one makes its cards the person's, the revision unchanged).
3424
+ const key = gateway ? null : `${rev}:${allDone ? 1 : 0}:${Math.floor(Date.now() / 60_000)}:${board.goneDispatchers(ctx.dispatcherGone)}`;
3393
3425
  const kept = key ? boardBodies.get(board) : undefined;
3394
3426
  if (kept && kept.key === key) {
3395
3427
  jsonText(res, 200, kept.body);
@@ -3401,7 +3433,7 @@ export function handleWebRequest(req, res, url, ctx) {
3401
3433
  // #2355 review: the names a project's lead may be — the fleet's instances (a Classic-only room is not one); over the
3402
3434
  // public link, not a hidden one.
3403
3435
  const leads = Object.keys(ctx.fleetConfig?.instances ?? {}).filter((n) => !hiddenName(n)).sort();
3404
- const body = JSON.stringify({ rev, cards: board.views(cards, scope), projects, leads, stats: board.projectStats() });
3436
+ const body = JSON.stringify({ rev, cards: board.views(cards, scope, ctx.dispatcherGone), projects, leads, stats: board.projectStats(ctx.dispatcherGone) });
3405
3437
  if (key)
3406
3438
  boardBodies.set(board, { key, body });
3407
3439
  jsonText(res, 200, body);
@@ -3416,7 +3448,7 @@ export function handleWebRequest(req, res, url, ctx) {
3416
3448
  // by every open drawer (the public link's is filtered per request, as the board's).
3417
3449
  const only = url.searchParams.get("instance");
3418
3450
  const names = (only ? [only] : [...new Set([...Object.keys(ctx.fleetConfig?.instances ?? {}), ...board.liveAssignees()])]).filter((n) => !hiddenName(n));
3419
- const key = gateway ? null : `${board.revision()}:${only === null ? "*" : `=${only}`}:${names.join("\u0000")}`;
3451
+ const key = gateway ? null : `${board.revision()}:${only === null ? "*" : `=${only}`}:${names.join("\u0000")}:${board.goneDispatchers(ctx.dispatcherGone)}`;
3420
3452
  const kept = key ? workBodies.get(board) : undefined;
3421
3453
  if (kept && kept.key === key) {
3422
3454
  jsonText(res, 200, kept.body);
@@ -3429,7 +3461,7 @@ export function handleWebRequest(req, res, url, ctx) {
3429
3461
  for (const c of [...w.doing, ...w.blocked, ...w.review, ...w.ready, ...w.waiting.map((x) => x.card), ...w.mains.map((x) => x.card)])
3430
3462
  if (!hidden(c))
3431
3463
  all.set(c.uuid, c);
3432
- const viewOf = new Map(board.views([...all.values()], scope).map((v) => [v.uuid, v]));
3464
+ const viewOf = new Map(board.views([...all.values()], scope, ctx.dispatcherGone).map((v) => [v.uuid, v]));
3433
3465
  const drawn = (cards) => cards.flatMap((c) => (viewOf.has(c.uuid) ? [viewOf.get(c.uuid)] : []));
3434
3466
  const codes = (cards) => cards.filter((x) => all.has(x.card.uuid)).map((x) => x.card.code);
3435
3467
  const body = JSON.stringify({ instances: works.map(({ name, w }) => ({
@@ -3446,7 +3478,7 @@ export function handleWebRequest(req, res, url, ctx) {
3446
3478
  if (method === "GET" && path === "/ui/tasks/search") {
3447
3479
  const names = new Map(board.listProjects(true).map((p) => [p.id, p.name]));
3448
3480
  const hits = board.search(url.searchParams.get("q") ?? "", Number(url.searchParams.get("limit")) || 20, scope).filter((h) => !hidden(h.card));
3449
- const views = board.views(hits.map((h) => h.card), scope);
3481
+ const views = board.views(hits.map((h) => h.card), scope, ctx.dispatcherGone);
3450
3482
  const results = hits.map(({ card: c, match }, i) => ({
3451
3483
  card: views[i],
3452
3484
  match,
@@ -3462,13 +3494,13 @@ export function handleWebRequest(req, res, url, ctx) {
3462
3494
  json(res, 404, { error: "no such card", code: "not_found" });
3463
3495
  return true;
3464
3496
  }
3465
- json(res, 200, shown(board.detail(ref, scope)));
3497
+ json(res, 200, shown(board.detail(ref, scope, ctx.dispatcherGone)));
3466
3498
  return true;
3467
3499
  }
3468
3500
  if (method === "POST" && path === "/ui/tasks/cards") {
3469
3501
  boardWrite(req, res, url, ctx, board, CardCreateSchema, (spec, person) => {
3470
3502
  const { cards, said } = board.createCards(person, { cards: [spec] });
3471
- return { card: board.view(cards[0]), notes: said };
3503
+ return { card: board.view(cards[0], {}, ctx.dispatcherGone), notes: said };
3472
3504
  });
3473
3505
  return true;
3474
3506
  }
@@ -3476,16 +3508,16 @@ export function handleWebRequest(req, res, url, ctx) {
3476
3508
  if (card[2] === "move") {
3477
3509
  boardWrite(req, res, url, ctx, board, CardMoveSchema, ({ to, ...move }, person) => {
3478
3510
  const { card: moved, said } = board.moveCard(person, ref, to, move);
3479
- return { card: board.view(moved), notes: said };
3511
+ return { card: board.view(moved, {}, ctx.dispatcherGone), notes: said };
3480
3512
  });
3481
3513
  }
3482
3514
  else if (card[2] === "reorder") {
3483
- boardWrite(req, res, url, ctx, board, CardReorderSchema, ({ after, before }, person) => ({ card: board.view(board.reorder(person, ref, after ?? null, before ?? null)) }));
3515
+ boardWrite(req, res, url, ctx, board, CardReorderSchema, ({ after, before }, person) => ({ card: board.view(board.reorder(person, ref, after ?? null, before ?? null), {}, ctx.dispatcherGone) }));
3484
3516
  }
3485
3517
  else {
3486
3518
  boardWrite(req, res, url, ctx, board, CardPatchSchema, (patch, person) => {
3487
3519
  const { card: updated, said } = board.updateCard(person, ref, patch);
3488
- return { card: board.view(updated), notes: said };
3520
+ return { card: board.view(updated, {}, ctx.dispatcherGone), notes: said };
3489
3521
  });
3490
3522
  }
3491
3523
  return true;