frizz-server 0.14.1 → 0.14.3

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 (93) hide show
  1. package/dist/claude-agent-broker.js +96 -74
  2. package/dist/dev-child.js +79 -38
  3. package/package.json +1 -1
  4. package/web-dist/assets/{TerminalPane-C0ndNP2R.js → TerminalPane-DxjFpp3t.js} +2 -2
  5. package/web-dist/assets/{abnfDiagram-VRR7QNED-Cnsh1t8G.js → abnfDiagram-VRR7QNED-DQ_U9vYS.js} +1 -1
  6. package/web-dist/assets/architecture-TIHT7OUA-b9drsxEz.js +1 -0
  7. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-DnVeuKCI.js → architectureDiagram-ZJ3FMSHR-BDuNYFi2.js} +1 -1
  8. package/web-dist/assets/{blockDiagram-677ZJIJ3-DqKYXGJI.js → blockDiagram-677ZJIJ3-BQltzNja.js} +1 -1
  9. package/web-dist/assets/{c4Diagram-LMCZKHZV-DRNawTpl.js → c4Diagram-LMCZKHZV-DmNbZp__.js} +1 -1
  10. package/web-dist/assets/channel-BrXX7uN2.js +1 -0
  11. package/web-dist/assets/{chunk-32BRIVSS-BKqSe_nC.js → chunk-32BRIVSS-DvuSWQnf.js} +1 -1
  12. package/web-dist/assets/{chunk-52WLFC77-BCaLFglM.js → chunk-52WLFC77-4E2J-uvF.js} +1 -1
  13. package/web-dist/assets/{chunk-C7G6YPKG-vlAetigo.js → chunk-C7G6YPKG-HhvTLxPi.js} +1 -1
  14. package/web-dist/assets/{chunk-EX3LRPZG-C1O5APJY.js → chunk-EX3LRPZG-DU2vZbkt.js} +1 -1
  15. package/web-dist/assets/{chunk-FWX5IMBZ-DRBYKkzP.js → chunk-FWX5IMBZ-BG_FOvjT.js} +2 -2
  16. package/web-dist/assets/{chunk-HOUHSVGY-C7BVwG9_.js → chunk-HOUHSVGY-DoLv22O1.js} +1 -1
  17. package/web-dist/assets/{chunk-ICXQ74PX-DVwDQwtI.js → chunk-ICXQ74PX-CIS41K-3.js} +1 -1
  18. package/web-dist/assets/{chunk-MOJQB5TN-5DhQ9vKC.js → chunk-MOJQB5TN-CAVteDne.js} +1 -1
  19. package/web-dist/assets/{chunk-OGEWGWER-Bgg5ovNG.js → chunk-OGEWGWER-DXOz4_Hy.js} +1 -1
  20. package/web-dist/assets/{chunk-PUDLZKDR-B-hJsSaU.js → chunk-PUDLZKDR-p8-UchSj.js} +1 -1
  21. package/web-dist/assets/{chunk-Q4XR5HBZ-BRKTCm77.js → chunk-Q4XR5HBZ-ysaS6hzX.js} +1 -1
  22. package/web-dist/assets/{chunk-V7JOEXUC-DLg_AuLv.js → chunk-V7JOEXUC-BKPgk0Ma.js} +1 -1
  23. package/web-dist/assets/{chunk-VAUOI2AC-CRKn6Hdz.js → chunk-VAUOI2AC-C8XyTeg3.js} +1 -1
  24. package/web-dist/assets/{chunk-VR4S4FIN-C3tBNXjB.js → chunk-VR4S4FIN-DT3kI56L.js} +1 -1
  25. package/web-dist/assets/{chunk-WYO6CB5R-LRVUOcLK.js → chunk-WYO6CB5R-Chn5KyvG.js} +1 -1
  26. package/web-dist/assets/{chunk-ZGVPDNZ5-BbjZAQf3.js → chunk-ZGVPDNZ5-BnwuZm7Y.js} +1 -1
  27. package/web-dist/assets/classDiagram-OUVF2IWQ-4xAMAfr_.js +1 -0
  28. package/web-dist/assets/classDiagram-v2-EOCWNBFH-4xAMAfr_.js +1 -0
  29. package/web-dist/assets/{cynefin-VYW2F7L2-BiFACRL6.js → cynefin-VYW2F7L2-CfKJwszJ.js} +1 -1
  30. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-Ba2A7L8f.js → cynefinDiagram-TSTJHNR4-CTGSvPJC.js} +1 -1
  31. package/web-dist/assets/{dagre-VKFMJZFB-B1gwugR0.js → dagre-VKFMJZFB-IEAnnijO.js} +1 -1
  32. package/web-dist/assets/{diagram-FQU43EPY-D3yeDptD.js → diagram-FQU43EPY-DGrmY1mz.js} +1 -1
  33. package/web-dist/assets/{diagram-G47NLZAW-C3ckNGcW.js → diagram-G47NLZAW-BWbRa0Qp.js} +1 -1
  34. package/web-dist/assets/{diagram-NH7WQ7WH-Be2tn4YY.js → diagram-NH7WQ7WH-DieWMCK1.js} +1 -1
  35. package/web-dist/assets/{diagram-OA4YK3LP-Dwj1ohx-.js → diagram-OA4YK3LP-BABEK3QJ.js} +1 -1
  36. package/web-dist/assets/{diagram-WEI45ONY-Dt-jAW5B.js → diagram-WEI45ONY-Bn6HzRhS.js} +1 -1
  37. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-Bz3-UuRU.js → ebnfDiagram-CCIWWBDH-DAswFWeH.js} +1 -1
  38. package/web-dist/assets/{erDiagram-Q63AITRT-BaCr3-Qz.js → erDiagram-Q63AITRT-DnQ3OGS6.js} +1 -1
  39. package/web-dist/assets/eventmodeling-45OFAUF4-CiF_Cyk8.js +1 -0
  40. package/web-dist/assets/flowDiagram-23GEKE2U-C34OL8XH.js +1 -0
  41. package/web-dist/assets/{ganttDiagram-NO4QXBWP-BvCR51Ob.js → ganttDiagram-NO4QXBWP-h6IumNeF.js} +1 -1
  42. package/web-dist/assets/{gitGraph-TEB2WS4Q-ClGknGDf.js → gitGraph-TEB2WS4Q-D5miazSS.js} +1 -1
  43. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-D9a31pAE.js → gitGraphDiagram-IHSO6WYX-rCF_alGf.js} +1 -1
  44. package/web-dist/assets/index-Cs-YNEjh.css +1 -0
  45. package/web-dist/assets/index-fJYZO7Ai.js +319 -0
  46. package/web-dist/assets/{info-DKCQHKI2-BGPJKOjY.js → info-DKCQHKI2-Cd4hseAQ.js} +1 -1
  47. package/web-dist/assets/{infoDiagram-FWYZ7A6U-B9toNDZt.js → infoDiagram-FWYZ7A6U-CGfUtvIa.js} +1 -1
  48. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-COi6cP-a.js → ishikawaDiagram-FXEZZL3T-Z403Dptn.js} +1 -1
  49. package/web-dist/assets/{journeyDiagram-5HDEW3XC-jDqNUKQG.js → journeyDiagram-5HDEW3XC-BaQNBWFo.js} +1 -1
  50. package/web-dist/assets/{kanban-definition-HUTT4EX6-CtxeJlFi.js → kanban-definition-HUTT4EX6-BkbSHwml.js} +1 -1
  51. package/web-dist/assets/{line-uNWy2FRa.js → line-DGXofgeC.js} +1 -1
  52. package/web-dist/assets/{mermaid-parser.core-Cfuj8tio.js → mermaid-parser.core-CR7LZZEK.js} +3 -3
  53. package/web-dist/assets/{mermaid.core-BtNCexa9.js → mermaid.core-CpLYjKp0.js} +3 -3
  54. package/web-dist/assets/{mindmap-definition-LN4V7U3C-B2u_kZ9E.js → mindmap-definition-LN4V7U3C-BetUGJPe.js} +1 -1
  55. package/web-dist/assets/{packet-7NZHBO7P-DNfwFIg5.js → packet-7NZHBO7P-BRvBNpIE.js} +1 -1
  56. package/web-dist/assets/{pegDiagram-2B236MQR-Cm9NTz0P.js → pegDiagram-2B236MQR-BfucWsgY.js} +1 -1
  57. package/web-dist/assets/{pie-RZYD4A2V-CMjAC3_C.js → pie-RZYD4A2V-BciCzqSu.js} +1 -1
  58. package/web-dist/assets/{pieDiagram-ENE6RG2P-DZegJin2.js → pieDiagram-ENE6RG2P-B9gq73nN.js} +1 -1
  59. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-Cr1P0TiT.js → quadrantDiagram-ABIIQ3AL-BKQ8-4ms.js} +1 -1
  60. package/web-dist/assets/{radar-I7S5WNFK-D_BiHAza.js → radar-I7S5WNFK-CEZNpKLK.js} +1 -1
  61. package/web-dist/assets/{railroad-3IZDKUUU-Kx4om6Pi.js → railroad-3IZDKUUU-DLkLtNsX.js} +1 -1
  62. package/web-dist/assets/railroad-abnf-AHOZXSZD-DktOu4VY.js +1 -0
  63. package/web-dist/assets/railroad-ebnf-EBAXGLYW-v6GP9yGH.js +1 -0
  64. package/web-dist/assets/railroad-peg-LSFZ7HO6-Dp4G_TMl.js +1 -0
  65. package/web-dist/assets/{railroadDiagram-RFXS5EU6-CGiAkwN0.js → railroadDiagram-RFXS5EU6-CfcczTD0.js} +1 -1
  66. package/web-dist/assets/{requirementDiagram-TGXJPOKE-Uh5FVpIq.js → requirementDiagram-TGXJPOKE-DDi1_Sx6.js} +1 -1
  67. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-CMBZWUwb.js → sankeyDiagram-HTMAVEWB-B-sibOny.js} +1 -1
  68. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-CL7uvgun.js → sequenceDiagram-DBY2YBRQ-m4JoedCx.js} +1 -1
  69. package/web-dist/assets/{stateDiagram-2N3HPSRC-CSU2s89c.js → stateDiagram-2N3HPSRC-2c6_7vMb.js} +1 -1
  70. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-vQfHq4-m.js +1 -0
  71. package/web-dist/assets/{swimlanes-5IMT3BWC-sfLI2FY3.js → swimlanes-5IMT3BWC-CaR-KY52.js} +1 -1
  72. package/web-dist/assets/swimlanesDiagram-G3AALYLV-BBJrQt-B.js +8 -0
  73. package/web-dist/assets/{timeline-definition-FHXFAJF6-Dl3Dx33l.js → timeline-definition-FHXFAJF6-BTUJfN9E.js} +1 -1
  74. package/web-dist/assets/{treeView-QDETBFTQ-C6i-QhBd.js → treeView-QDETBFTQ-Dx4qSq4R.js} +1 -1
  75. package/web-dist/assets/{treemap-6X3UGDF4-kjzleK2t.js → treemap-6X3UGDF4-BQrP0aOT.js} +1 -1
  76. package/web-dist/assets/{vennDiagram-L72KCM5P-BVYuCdzD.js → vennDiagram-L72KCM5P-Cb6FiUn1.js} +1 -1
  77. package/web-dist/assets/{wardley-OPB4EBWU-Dd-gYK7z.js → wardley-OPB4EBWU-DxhyL1lM.js} +1 -1
  78. package/web-dist/assets/{wardleyDiagram-EHGQE667-BkLQ_w49.js → wardleyDiagram-EHGQE667-3EfJ9d7V.js} +1 -1
  79. package/web-dist/assets/{xychartDiagram-FW5EYKEG-Cm4pNjto.js → xychartDiagram-FW5EYKEG-COC-ChrZ.js} +1 -1
  80. package/web-dist/index.html +16 -10
  81. package/web-dist/assets/architecture-TIHT7OUA-BFTL2lQD.js +0 -1
  82. package/web-dist/assets/channel-Nm8jIZOi.js +0 -1
  83. package/web-dist/assets/classDiagram-OUVF2IWQ-C8nDRy2s.js +0 -1
  84. package/web-dist/assets/classDiagram-v2-EOCWNBFH-C8nDRy2s.js +0 -1
  85. package/web-dist/assets/eventmodeling-45OFAUF4-CD9TITDK.js +0 -1
  86. package/web-dist/assets/flowDiagram-23GEKE2U-Womg_Wqj.js +0 -1
  87. package/web-dist/assets/index-CTcjL-eO.js +0 -319
  88. package/web-dist/assets/index-CzN-tCOl.css +0 -1
  89. package/web-dist/assets/railroad-abnf-AHOZXSZD-pLt2-q5a.js +0 -1
  90. package/web-dist/assets/railroad-ebnf-EBAXGLYW-BvNkqSim.js +0 -1
  91. package/web-dist/assets/railroad-peg-LSFZ7HO6-g9R2pEue.js +0 -1
  92. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BjWfwAZ4.js +0 -1
  93. package/web-dist/assets/swimlanesDiagram-G3AALYLV-B5co78bI.js +0 -8
package/dist/dev-child.js CHANGED
@@ -14086,7 +14086,7 @@ var init_src = __esm({
14086
14086
  };
14087
14087
  AWAITING_HINT_MAX = 8;
14088
14088
  AWAITING_HINT_VALUE_MAX = 200;
14089
- AWAITING_TITLE_MAX = 40;
14089
+ AWAITING_TITLE_MAX = 120;
14090
14090
  AWAITING_ITEM_KINDS = ["shell", "agent", "timer", "pr", "issue"];
14091
14091
  AWAITING_DURATION_RE = /^(\d{1,5})(s|m|h|d)$/;
14092
14092
  DURATION_UNIT_MS = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
@@ -14935,13 +14935,13 @@ var init_src = __esm({
14935
14935
  * to, not furniture you sit beside. Hidden, the way back is a breadcrumb in the status bar, which
14936
14936
  * costs a click exactly when you meant to switch and nothing when you did not.
14937
14937
  *
14938
- * Machine-level, like the font: which chrome you want is a property of the person, not the repo.
14938
+ * Machine-level: which chrome you want is a property of the person, not the repo.
14939
14939
  */
14940
14940
  projectRail: external_exports.boolean(),
14941
- // UI type family. `mono` (default) is the mono-forward system; `sans` swaps prose/UI chrome to a
14942
- // sans stack while code / tool lines / the terminal stay mono. Optional so an old settings blob
14943
- // parses; defaultSettings pins "mono".
14944
- font: external_exports.enum(["mono", "sans"]).optional(),
14941
+ // There is no `font` key any more. The interface rendered in one of two type families as a machine
14942
+ // setting until 2026-09-19 (maintainer: "let's drop monospace as an option"); every surface is sans
14943
+ // now, and index.html pins `data-font="sans"` on <html> directly. Settings is a non-strict object,
14944
+ // so a stored `font` is stripped the moment an old blob parses — no migration.
14945
14945
  // Default action for a vetted non-image local path in agent markdown. Image clicks always use the
14946
14946
  // OS default viewer so screenshots retain their expected behavior.
14947
14947
  localFileOpener: LocalFileOpener.optional(),
@@ -20911,12 +20911,12 @@ var init_settings = __esm({
20911
20911
  init_frizz_paths();
20912
20912
  init_machine_config();
20913
20913
  SETTINGS_KEY = "settings";
20914
- MACHINE_KEYS = ["font", "notifications", "localFileOpener", "projectRail"];
20914
+ MACHINE_KEYS = ["notifications", "localFileOpener", "projectRail"];
20915
20915
  MachineSettingsRecord = Settings.partial();
20916
20916
  defaultSettings = () => ({
20917
20917
  // `bypassPermissions` = claude's --dangerously-skip-permissions: a headless worker never stops on an
20918
- // approval card. Shipped default since 0.7.2 (maintainer 2026-08-24); the Settings "Permissions"
20919
- // (under Claude) control can lower it to `auto` — the CLI's classifier mode, where risky actions
20918
+ // approval card. Shipped default since 0.7.2 (maintainer 2026-08-24); the "Permissions" control
20919
+ // behind the Claude Code gear in the model picker can lower it to `auto` — the CLI's classifier mode, where risky actions
20920
20920
  // still surface an approval card in the thread. Those are the only two values a headless worker can
20921
20921
  // run in: the dispatch floor (WORKER_DISPATCH_PERMISSION) stays `auto`, and workerDispatchPermission
20922
20922
  // honors exactly one deviation from it, which is this one.
@@ -20924,7 +20924,6 @@ var init_settings = __esm({
20924
20924
  model: void 0,
20925
20925
  effort: void 0,
20926
20926
  notifications: true,
20927
- font: "sans",
20928
20927
  localFileOpener: "system",
20929
20928
  // 500K tokens: half the 1M window every Claude worker is dispatched with. See the schema for why a
20930
20929
  // worker left to compact at 1M is the biggest single reason a Frizz thread out-spends the TUI.
@@ -30508,14 +30507,18 @@ function tomlString(value) {
30508
30507
  function inlineTable(entries2) {
30509
30508
  return `{${entries2.map(([k, v]) => `${k}=${v}`).join(",")}}`;
30510
30509
  }
30511
- function serverTable(command, args, env) {
30510
+ function serverTable(command, args, cwd, env) {
30512
30511
  const entries2 = [
30513
30512
  ["command", tomlString(command)],
30514
- ["args", `[${args.map(tomlString).join(",")}]`]
30513
+ ["args", `[${args.map(tomlString).join(",")}]`],
30514
+ // Where the child RUNS, pinned so it never depends on the thread's own cwd — see
30515
+ // codexThreadMcpConfig for the rename that took a thread's tools with it.
30516
+ ["cwd", tomlString(cwd)]
30515
30517
  ];
30516
30518
  if (env && Object.keys(env).length > 0) {
30517
30519
  entries2.push(["env", inlineTable(Object.entries(env).map(([k, v]) => [k, tomlString(v)]))]);
30518
30520
  }
30521
+ entries2.push(["default_tools_approval_mode", tomlString("approve")]);
30519
30522
  return inlineTable(entries2);
30520
30523
  }
30521
30524
  function codexMcpConfigArgs(frizzMcp, nodeBin = process.execPath) {
@@ -30523,7 +30526,7 @@ function codexMcpConfigArgs(frizzMcp, nodeBin = process.execPath) {
30523
30526
  if (frizzMcp) {
30524
30527
  args.push(
30525
30528
  "-c",
30526
- `mcp_servers.${FRIZZ_MCP.name}=${serverTable(nodeBin, [frizzMcp.scriptPath], frizzMcpEnv(frizzMcp))}`
30529
+ `mcp_servers.${FRIZZ_MCP.name}=${serverTable(nodeBin, [frizzMcp.scriptPath], frizzMcp.stateDir, frizzMcpEnv(frizzMcp))}`
30527
30530
  );
30528
30531
  }
30529
30532
  args.push("-c", `default_tools_approval_mode=${tomlString("approve")}`);
@@ -30537,6 +30540,7 @@ function codexThreadMcpConfig(frizzMcp, slug, nodeBin = process.execPath) {
30537
30540
  // The ABSOLUTE node path, for the same reason the argv mount pins it — see codexMcpConfigArgs.
30538
30541
  command: nodeBin,
30539
30542
  args: [frizzMcp.scriptPath],
30543
+ cwd: frizzMcp.stateDir,
30540
30544
  env: frizzMcpEnv({ ...frizzMcp, slug }),
30541
30545
  default_tools_approval_mode: "approve"
30542
30546
  }
@@ -31247,6 +31251,11 @@ function parseClaudeUsage(body, planType) {
31247
31251
  if (windows.length === 0) return { status: "unavailable", windows: [], detail: "No usage windows reported" };
31248
31252
  return { status: "ok", planType, windows };
31249
31253
  }
31254
+ function retryAtFrom(res, now) {
31255
+ const seconds = Number(res.headers.get("retry-after"));
31256
+ const backoff = Number.isFinite(seconds) && seconds > 0 ? seconds * 1e3 : RATE_LIMIT_DEFAULT_BACKOFF_MS;
31257
+ return now + Math.min(backoff, RATE_LIMIT_MAX_BACKOFF_MS);
31258
+ }
31250
31259
  function cachePaths(cacheDir, configDir) {
31251
31260
  const profile = createHash9("sha256").update(configDir).digest("hex").slice(0, 12);
31252
31261
  return {
@@ -31335,10 +31344,10 @@ async function refreshQuota(claudeBin, deps, now) {
31335
31344
  const quota2 = parseClaudeUsage(body, planType);
31336
31345
  if (quota2.status === "ok") return quota2;
31337
31346
  } else if (res.status === 429 || res.status === 529) {
31338
- throw new Error(`Usage endpoint ${res.status}`);
31347
+ throw new UsageRateLimited(res.status, retryAtFrom(res, now));
31339
31348
  }
31340
31349
  } catch (err) {
31341
- if (err instanceof Error && /^Usage endpoint (429|529)$/.test(err.message)) throw err;
31350
+ if (err instanceof UsageRateLimited) throw err;
31342
31351
  }
31343
31352
  }
31344
31353
  const quota = parseClaudeUsageOutput(await (deps.execUsage ?? runClaudeUsage)(claudeBin), now);
@@ -31428,14 +31437,30 @@ async function tryAcquireLock2(path3) {
31428
31437
  }
31429
31438
  return void 0;
31430
31439
  }
31440
+ function rateLimited(shared, now) {
31441
+ return shared?.retryAt !== void 0 && now < shared.retryAt;
31442
+ }
31443
+ function serveRateLimited(shared, now) {
31444
+ if (shared.quota.status !== "ok" || now - shared.at >= STALE_MAX_AGE_MS) return UNAVAILABLE;
31445
+ const minutes = (ms, round) => Math.max(1, round(ms / 6e4));
31446
+ return {
31447
+ ...shared.quota,
31448
+ detail: `Next refresh in ${minutes(shared.retryAt - now, Math.ceil)}m \xB7 last updated ${minutes(now - shared.at, Math.round)}m ago`
31449
+ };
31450
+ }
31431
31451
  function refreshSharedInBackground(paths, claudeBin, deps, now) {
31432
31452
  if (backgroundRefreshes.has(paths.data)) return;
31433
31453
  const task = (async () => {
31454
+ if (rateLimited(await readShared(paths.data), now)) return;
31434
31455
  const release = await tryAcquireLock2(paths.lock);
31435
31456
  if (!release) return;
31436
31457
  try {
31437
31458
  const quota = await refreshQuota(claudeBin, deps, now);
31438
31459
  await writeShared(paths.data, { at: now, quota });
31460
+ } catch (err) {
31461
+ if (!(err instanceof UsageRateLimited)) throw err;
31462
+ const current = await readShared(paths.data);
31463
+ await writeShared(paths.data, { ...current ?? { at: now, quota: UNAVAILABLE }, retryAt: err.retryAt });
31439
31464
  } finally {
31440
31465
  await release().catch(() => {
31441
31466
  });
@@ -31453,7 +31478,10 @@ async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
31453
31478
  } catch {
31454
31479
  return;
31455
31480
  }
31456
- refreshSharedInBackground(cachePaths(cacheDir, configDir), claudeBin, deps, now);
31481
+ const paths = cachePaths(cacheDir, configDir);
31482
+ const current = await readShared(paths.data);
31483
+ if (current?.quota.status === "ok" && now - current.at < OK_TTL_MS) return;
31484
+ refreshSharedInBackground(paths, claudeBin, deps, now);
31457
31485
  }
31458
31486
  async function readClaudeQuota(claudeBin = "claude", deps = {}, options = {}) {
31459
31487
  const now = (deps.now ?? Date.now)();
@@ -31476,36 +31504,44 @@ async function readClaudeQuota(claudeBin = "claude", deps = {}, options = {}) {
31476
31504
  if (!options.force && initial?.quota.status === "ok" && now - initial.at < STALE_MAX_AGE_MS) {
31477
31505
  refreshSharedInBackground(paths, claudeBin, deps, now);
31478
31506
  const ageMs = now - initial.at;
31507
+ if (ageMs >= 10 * 6e4 && rateLimited(initial, now)) return serveRateLimited(initial, now);
31479
31508
  if (ageMs < 10 * 6e4) return initial.quota;
31480
31509
  return { ...initial.quota, detail: `Refreshing \xB7 last updated ${Math.round(ageMs / 6e4)}m ago` };
31481
31510
  }
31511
+ if (rateLimited(initial, now)) return serveRateLimited(initial, now);
31482
31512
  let release;
31483
31513
  try {
31484
31514
  release = await acquireLock(paths.lock);
31485
31515
  const afterLock = await readShared(paths.data);
31516
+ if (rateLimited(afterLock, now)) return serveRateLimited(afterLock, now);
31486
31517
  if (afterLock && afterLock.at !== initial?.at && now - afterLock.at < OK_TTL_MS) return afterLock.quota;
31487
31518
  const quota = await refreshQuota(claudeBin, deps, now);
31488
31519
  await writeShared(paths.data, { at: now, quota }).catch(() => {
31489
31520
  });
31490
31521
  return quota;
31491
- } catch {
31522
+ } catch (err) {
31492
31523
  const fallback = await readShared(paths.data);
31524
+ if (err instanceof UsageRateLimited) {
31525
+ const refused = { ...fallback ?? { at: now, quota: UNAVAILABLE }, retryAt: err.retryAt };
31526
+ await writeShared(paths.data, refused).catch(() => {
31527
+ });
31528
+ return serveRateLimited(refused, now);
31529
+ }
31493
31530
  if (fallback?.quota.status === "ok" && now - fallback.at < STALE_MAX_AGE_MS) {
31494
31531
  return {
31495
31532
  ...fallback.quota,
31496
31533
  detail: `Could not refresh \xB7 last updated ${Math.max(1, Math.round((now - fallback.at) / 6e4))}m ago`
31497
31534
  };
31498
31535
  }
31499
- const unavailable = { status: "unavailable", windows: [], detail: "Claude Code usage unavailable" };
31500
- await writeShared(paths.data, { at: now, quota: unavailable }).catch(() => {
31536
+ await writeShared(paths.data, { at: now, quota: UNAVAILABLE }).catch(() => {
31501
31537
  });
31502
- return unavailable;
31538
+ return UNAVAILABLE;
31503
31539
  } finally {
31504
31540
  await release?.().catch(() => {
31505
31541
  });
31506
31542
  }
31507
31543
  }
31508
- var execFileAsync2, USAGE_URL, OAUTH_BETA, USER_AGENT, ENDPOINT_TIMEOUT_MS, OK_TTL_MS, FAIL_TTL_MS, STALE_MAX_AGE_MS, CLI_TIMEOUT_MS, LOCK_STALE_MS, LOCK_WAIT_MS, LOCK_POLL_MS2, LINE_WINDOWS, MONTH_INDEX, backgroundRefreshes;
31544
+ var execFileAsync2, USAGE_URL, OAUTH_BETA, USER_AGENT, ENDPOINT_TIMEOUT_MS, OK_TTL_MS, FAIL_TTL_MS, STALE_MAX_AGE_MS, CLI_TIMEOUT_MS, LOCK_STALE_MS, LOCK_WAIT_MS, LOCK_POLL_MS2, RATE_LIMIT_DEFAULT_BACKOFF_MS, RATE_LIMIT_MAX_BACKOFF_MS, UsageRateLimited, LINE_WINDOWS, MONTH_INDEX, UNAVAILABLE, backgroundRefreshes;
31509
31545
  var init_claude_quota = __esm({
31510
31546
  "packages/server/src/backend/claude-quota.ts"() {
31511
31547
  "use strict";
@@ -31523,6 +31559,14 @@ var init_claude_quota = __esm({
31523
31559
  LOCK_STALE_MS = 4e4;
31524
31560
  LOCK_WAIT_MS = 15e3;
31525
31561
  LOCK_POLL_MS2 = 50;
31562
+ RATE_LIMIT_DEFAULT_BACKOFF_MS = 5 * 6e4;
31563
+ RATE_LIMIT_MAX_BACKOFF_MS = 60 * 6e4;
31564
+ UsageRateLimited = class extends Error {
31565
+ constructor(status, retryAt) {
31566
+ super(`Usage endpoint ${status}`);
31567
+ this.retryAt = retryAt;
31568
+ }
31569
+ };
31526
31570
  LINE_WINDOWS = [
31527
31571
  [/^Current session$/i, "5h", "5h"],
31528
31572
  [/^Current week \(all models\)$/i, "weekly", "Weekly"],
@@ -31543,6 +31587,7 @@ var init_claude_quota = __esm({
31543
31587
  nov: 10,
31544
31588
  dec: 11
31545
31589
  };
31590
+ UNAVAILABLE = { status: "unavailable", windows: [], detail: "Claude Code usage unavailable" };
31546
31591
  backgroundRefreshes = /* @__PURE__ */ new Map();
31547
31592
  }
31548
31593
  });
@@ -36040,9 +36085,11 @@ exactly ONE of them.
36040
36085
  until somebody notices. Long is free \u2014 real activity wakes you the moment it lands either way, and
36041
36086
  the human snoozes or archives the thread when they want it gone. Hours are for a PR you control and
36042
36087
  a check you expect to settle today.
36043
- - \`title:\` \u2014 OPTIONAL, the card's heading: **40 characters or fewer**, sentence case, naming THIS
36044
- wait ("Fork-CI approval", "Nightly bench, arm 3 of 3"); longer is trimmed on a word boundary.
36045
- Without it the card is headed "Awaiting", which is true of every park and specific to none.
36088
+ - \`title:\` \u2014 OPTIONAL, the card's heading: a short phrase in sentence case naming THIS wait
36089
+ ("Fork-CI approval", "Nightly bench, arm 3 of 3", "Spread ask and soundness issue on two TypeScript
36090
+ issues"). It wraps, so name the wait fully; a HEADING, though, not the handoff \u2014 past 120
36091
+ characters it is trimmed on a word boundary. Without it the card is headed "Awaiting", which is
36092
+ true of every park and specific to none.
36046
36093
  - **REGISTERING IS NOT PARKING, AND PARKING IS NOT REGISTERING.** Your shells, sub-agents, timers
36047
36094
  and PR watchers are watched AUTOMATICALLY, fence or no fence \u2014 frizz wakes you when one finishes,
36048
36095
  every time. The fence only declares that you have STOPPED, and names which of them you stopped
@@ -44881,7 +44928,7 @@ var init_context = __esm({
44881
44928
  init_logging();
44882
44929
  init_project_launch();
44883
44930
  CONTEXT_STARTUP_CLEANUP_TIMEOUT_MS = 4e3;
44884
- QUOTA_REFRESH_INTERVAL_MS = 2 * 6e4;
44931
+ QUOTA_REFRESH_INTERVAL_MS = 3e4;
44885
44932
  ContextStartupError = class extends Error {
44886
44933
  startupError;
44887
44934
  cleanupError;
@@ -53646,16 +53693,6 @@ Say which way you went and why in your write-up, so the human can course-correct
53646
53693
  output: Settings,
53647
53694
  handler: async ({ input }) => ctx.setSettings(input)
53648
53695
  }),
53649
- // Context controls live in the new-thread picker. Patch only the chosen field against the
53650
- // latest settings, synchronously, rather than replacing unrelated settings from a stale drawer.
53651
- contextWindowSet: mutation({
53652
- input: external_exports.object({ backend: external_exports.enum(["claude", "codex"]), tokens: external_exports.number().int().positive().nullable() }),
53653
- output: Settings,
53654
- handler: async ({ input }) => ctx.setSettings({
53655
- ...ctx.getSettings(),
53656
- [input.backend === "claude" ? "autoCompactWindow" : "codexContextWindow"]: input.tokens ?? void 0
53657
- })
53658
- }),
53659
53696
  // Clear the stored settings blob so defaults (incl. the shipped default preamble) apply again.
53660
53697
  settingsReset: mutation({
53661
53698
  input: external_exports.object({}),
@@ -54390,12 +54427,15 @@ a { color: inherit; }
54390
54427
  (() => {
54391
54428
  const notifyHeight = () => parent.postMessage({ type: "frizz-inline-vis-height", height: Math.ceil(document.documentElement.scrollHeight) }, "*");
54392
54429
  addEventListener("message", (event) => {
54393
- if (event.data?.type !== "frizz-inline-vis-theme" || !event.data.vars) return;
54430
+ if (event.source !== parent) return;
54431
+ if (event.data?.type !== "frizz-inline-vis-theme" || !event.data.vars || !Number.isSafeInteger(event.data.requestId)) return;
54394
54432
  for (const [name, value] of Object.entries(event.data.vars)) {
54395
54433
  if (/^--[a-z0-9-]+$/.test(name) && typeof value === "string") document.documentElement.style.setProperty(name, value);
54396
54434
  }
54397
54435
  document.documentElement.style.colorScheme = event.data.colorScheme === "light" ? "light" : "dark";
54398
54436
  requestAnimationFrame(notifyHeight);
54437
+ dispatchEvent(new CustomEvent("frizz-theme-change", { detail: { requestId: event.data.requestId, colorScheme: document.documentElement.style.colorScheme, vars: event.data.vars } }));
54438
+ parent.postMessage({ type: "frizz-inline-vis-applied", requestId: event.data.requestId }, "*");
54399
54439
  });
54400
54440
  window.openai = Object.freeze({
54401
54441
  sendFollowUpMessage: async () => { throw new Error("Follow-up actions are not supported in Frizz visualizations yet"); }
@@ -54403,6 +54443,7 @@ a { color: inherit; }
54403
54443
  addEventListener("DOMContentLoaded", () => {
54404
54444
  new ResizeObserver(notifyHeight).observe(document.body);
54405
54445
  notifyHeight();
54446
+ parent.postMessage({ type: "frizz-inline-vis-ready" }, "*");
54406
54447
  });
54407
54448
  })();
54408
54449
  </script>
@@ -56358,8 +56399,8 @@ var init_runtimes = __esm({
56358
56399
  init_codex_app_server();
56359
56400
  init_frizz_paths();
56360
56401
  init_runtime_lease();
56361
- CLAUDE_AGENT_SDK_VERSION = "0.3.277";
56362
- CLAUDE_CODE_VERSION = "2.1.277";
56402
+ CLAUDE_AGENT_SDK_VERSION = "0.3.278";
56403
+ CLAUDE_CODE_VERSION = "2.1.278";
56363
56404
  CODEX_VERSION = CODEX_APP_SERVER_SUPPORTED_VERSION;
56364
56405
  RUNTIMES_MODE_ENV = "FRIZZ_RUNTIMES";
56365
56406
  RUNTIMES_DIR_ENV = "FRIZZ_RUNTIMES_DIR";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frizz-server",
3
- "version": "0.14.1",
3
+ "version": "0.14.3",
4
4
  "private": false,
5
5
  "description": "Replaceable Frizz server runtime",
6
6
  "license": "MIT",