frizz 0.5.0 → 0.6.0

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 (102) hide show
  1. package/README.md +3 -3
  2. package/dist/claude-agent-broker.js +50 -7
  3. package/dist/dev-child.js +8820 -1420
  4. package/dist/frizz.js +7589 -240
  5. package/package.json +2 -1
  6. package/runtime/cc-worker/DECISIONS.md +2 -2
  7. package/runtime/cc-worker/bin/browser-mcp-tools.json +1192 -0
  8. package/runtime/cc-worker/bin/browser-mcp.mjs +730 -0
  9. package/runtime/cc-worker/bin/frizz-mcp.mjs +16 -5
  10. package/runtime/cc-worker/hooks/deny-ask.mjs +3 -3
  11. package/runtime/cc-worker/hooks/deny-plan.mjs +5 -4
  12. package/runtime/cc-worker/hooks/perm-policy.mjs +1 -1
  13. package/web-dist/assets/{TerminalPane-WcpgmCA-.js → TerminalPane-GfnCbZQ8.js} +1 -1
  14. package/web-dist/assets/{abnfDiagram-VRR7QNED-Caecklbz.js → abnfDiagram-VRR7QNED-By12QfQW.js} +1 -1
  15. package/web-dist/assets/architecture-TIHT7OUA-XOYod28l.js +1 -0
  16. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-BEk0fg8C.js → architectureDiagram-ZJ3FMSHR-CcXU45QO.js} +1 -1
  17. package/web-dist/assets/{blockDiagram-677ZJIJ3-B4yq3xiy.js → blockDiagram-677ZJIJ3-CmzyO2OF.js} +1 -1
  18. package/web-dist/assets/{c4Diagram-LMCZKHZV-DaA5NBkz.js → c4Diagram-LMCZKHZV-DFGSW_ZS.js} +1 -1
  19. package/web-dist/assets/channel-Bqn3pFKp.js +1 -0
  20. package/web-dist/assets/{chunk-32BRIVSS-2XsSs8F_.js → chunk-32BRIVSS-whgaFxPY.js} +1 -1
  21. package/web-dist/assets/{chunk-52WLFC77-DWJfECP3.js → chunk-52WLFC77-DCT0MLgl.js} +1 -1
  22. package/web-dist/assets/{chunk-C7G6YPKG-Bz07eaGt.js → chunk-C7G6YPKG-Br0OaxIX.js} +1 -1
  23. package/web-dist/assets/{chunk-EX3LRPZG-D78kZEMM.js → chunk-EX3LRPZG-CUnQkdEF.js} +1 -1
  24. package/web-dist/assets/{chunk-FWX5IMBZ-CeCa17CW.js → chunk-FWX5IMBZ-D1NqKRFr.js} +2 -2
  25. package/web-dist/assets/{chunk-HOUHSVGY-9H4GFuBa.js → chunk-HOUHSVGY-7ZL78OrO.js} +1 -1
  26. package/web-dist/assets/{chunk-ICXQ74PX--Aa17r4X.js → chunk-ICXQ74PX-QSgBAuYw.js} +1 -1
  27. package/web-dist/assets/{chunk-MOJQB5TN-C3vXhsPV.js → chunk-MOJQB5TN-DOI-0kaG.js} +1 -1
  28. package/web-dist/assets/{chunk-OGEWGWER-G4kZRBkX.js → chunk-OGEWGWER-CZ3ED-QB.js} +1 -1
  29. package/web-dist/assets/{chunk-PUDLZKDR-DWd5kvyM.js → chunk-PUDLZKDR-BQJElUFX.js} +1 -1
  30. package/web-dist/assets/{chunk-Q4XR5HBZ-u55p39Up.js → chunk-Q4XR5HBZ-5B6Qs7rQ.js} +1 -1
  31. package/web-dist/assets/{chunk-V7JOEXUC-BU4YBmV4.js → chunk-V7JOEXUC-DkMaAMFK.js} +1 -1
  32. package/web-dist/assets/{chunk-VAUOI2AC-VXcmT20q.js → chunk-VAUOI2AC-Bvq-8GYO.js} +1 -1
  33. package/web-dist/assets/{chunk-VR4S4FIN-CSjEXLOC.js → chunk-VR4S4FIN-DRVTU-HZ.js} +1 -1
  34. package/web-dist/assets/{chunk-WYO6CB5R-4WGk2dpL.js → chunk-WYO6CB5R-CRxI5d1E.js} +1 -1
  35. package/web-dist/assets/{chunk-ZGVPDNZ5-D5Xl8ZV6.js → chunk-ZGVPDNZ5-D_3ow6xU.js} +1 -1
  36. package/web-dist/assets/classDiagram-OUVF2IWQ-DEMCehy_.js +1 -0
  37. package/web-dist/assets/classDiagram-v2-EOCWNBFH-DEMCehy_.js +1 -0
  38. package/web-dist/assets/{cynefin-VYW2F7L2-O6wB49wK.js → cynefin-VYW2F7L2-Bexf41pD.js} +1 -1
  39. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-pd6ZogNC.js → cynefinDiagram-TSTJHNR4-9gbbl1EH.js} +1 -1
  40. package/web-dist/assets/{dagre-VKFMJZFB-D8W1S6fw.js → dagre-VKFMJZFB-B04shbL0.js} +1 -1
  41. package/web-dist/assets/{diagram-FQU43EPY-Bm1NOkHd.js → diagram-FQU43EPY-CGXlhEsB.js} +1 -1
  42. package/web-dist/assets/{diagram-G47NLZAW-CjwnXTIc.js → diagram-G47NLZAW-DmPCeTOa.js} +1 -1
  43. package/web-dist/assets/{diagram-NH7WQ7WH-DH1jZ_mu.js → diagram-NH7WQ7WH-D8Hthvi7.js} +1 -1
  44. package/web-dist/assets/{diagram-OA4YK3LP-B-s969Q_.js → diagram-OA4YK3LP-DbLR6tfL.js} +1 -1
  45. package/web-dist/assets/{diagram-WEI45ONY-BU3lv6cL.js → diagram-WEI45ONY-B6YWev_0.js} +1 -1
  46. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-FsAeyqcC.js → ebnfDiagram-CCIWWBDH-8G1uf683.js} +1 -1
  47. package/web-dist/assets/{erDiagram-Q63AITRT-BRvg5Y9d.js → erDiagram-Q63AITRT-U_VRdQHz.js} +1 -1
  48. package/web-dist/assets/eventmodeling-45OFAUF4-DIpO2jQx.js +1 -0
  49. package/web-dist/assets/flowDiagram-23GEKE2U-aERDdceE.js +1 -0
  50. package/web-dist/assets/{ganttDiagram-NO4QXBWP-eATKNh9U.js → ganttDiagram-NO4QXBWP-Cnsi9uVf.js} +1 -1
  51. package/web-dist/assets/{gitGraph-TEB2WS4Q-CNYqsua8.js → gitGraph-TEB2WS4Q-DYf7ka-G.js} +1 -1
  52. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-BUxgluf8.js → gitGraphDiagram-IHSO6WYX-Bvmr7dEH.js} +1 -1
  53. package/web-dist/assets/index-Czv3R-v0.js +486 -0
  54. package/web-dist/assets/index-D8iyWUZ0.css +1 -0
  55. package/web-dist/assets/{info-DKCQHKI2-HsVLwo1c.js → info-DKCQHKI2-CdP9Q9r0.js} +1 -1
  56. package/web-dist/assets/{infoDiagram-FWYZ7A6U-D7U65xDp.js → infoDiagram-FWYZ7A6U-RBcOH3Pi.js} +1 -1
  57. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-BsfIYXjX.js → ishikawaDiagram-FXEZZL3T-zS0gy3fS.js} +1 -1
  58. package/web-dist/assets/{journeyDiagram-5HDEW3XC-CpkREKol.js → journeyDiagram-5HDEW3XC-cOciJlFY.js} +1 -1
  59. package/web-dist/assets/{kanban-definition-HUTT4EX6-2M3KW6Gw.js → kanban-definition-HUTT4EX6-B-v0XClo.js} +1 -1
  60. package/web-dist/assets/{line-Cs7zWs24.js → line-z44YXdci.js} +1 -1
  61. package/web-dist/assets/{mermaid-parser.core-Dw-IECV5.js → mermaid-parser.core-0Bg1x4p0.js} +3 -3
  62. package/web-dist/assets/{mermaid.core-C1lrddjT.js → mermaid.core-ByFqgcIE.js} +3 -3
  63. package/web-dist/assets/{mindmap-definition-LN4V7U3C-gVS5On1g.js → mindmap-definition-LN4V7U3C-DiGaAQFh.js} +1 -1
  64. package/web-dist/assets/{packet-7NZHBO7P-Tti1-UWA.js → packet-7NZHBO7P-Bv8ILo_S.js} +1 -1
  65. package/web-dist/assets/{pegDiagram-2B236MQR-DE5in93G.js → pegDiagram-2B236MQR-CtOUW7n0.js} +1 -1
  66. package/web-dist/assets/{pie-RZYD4A2V-DfLNkvHl.js → pie-RZYD4A2V-Dz4Bm-Vx.js} +1 -1
  67. package/web-dist/assets/{pieDiagram-ENE6RG2P-DcqSqJqb.js → pieDiagram-ENE6RG2P-VMY_CK3i.js} +1 -1
  68. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-DR-nRPgN.js → quadrantDiagram-ABIIQ3AL-V7HZxM7j.js} +1 -1
  69. package/web-dist/assets/{radar-I7S5WNFK-DGLDBfPd.js → radar-I7S5WNFK-CWk6RruH.js} +1 -1
  70. package/web-dist/assets/{railroad-3IZDKUUU-BaiGEHlV.js → railroad-3IZDKUUU-m_8st_Ez.js} +1 -1
  71. package/web-dist/assets/railroad-abnf-AHOZXSZD-DIaRscxr.js +1 -0
  72. package/web-dist/assets/railroad-ebnf-EBAXGLYW-CeHpbK-W.js +1 -0
  73. package/web-dist/assets/railroad-peg-LSFZ7HO6-CbhVIbOj.js +1 -0
  74. package/web-dist/assets/{railroadDiagram-RFXS5EU6-82aEev5_.js → railroadDiagram-RFXS5EU6-Dz80V-7-.js} +1 -1
  75. package/web-dist/assets/{requirementDiagram-TGXJPOKE-Bs8opBRj.js → requirementDiagram-TGXJPOKE-DrDDgTwm.js} +1 -1
  76. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-gOb3FIr8.js → sankeyDiagram-HTMAVEWB-D4SeC-Bi.js} +1 -1
  77. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-6DvjtRHR.js → sequenceDiagram-DBY2YBRQ-CA-ZO_qp.js} +1 -1
  78. package/web-dist/assets/{stateDiagram-2N3HPSRC-Cg2LWdUf.js → stateDiagram-2N3HPSRC-C_ZYvV2s.js} +1 -1
  79. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BLevFa3H.js +1 -0
  80. package/web-dist/assets/{swimlanes-5IMT3BWC-BDpPdYEl.js → swimlanes-5IMT3BWC-DGMDseYx.js} +1 -1
  81. package/web-dist/assets/swimlanesDiagram-G3AALYLV-00mQRq57.js +8 -0
  82. package/web-dist/assets/{timeline-definition-FHXFAJF6-BSjfeutv.js → timeline-definition-FHXFAJF6-CEiMp3_j.js} +1 -1
  83. package/web-dist/assets/{treeView-QDETBFTQ-DwgPy6V3.js → treeView-QDETBFTQ-BSspY0US.js} +1 -1
  84. package/web-dist/assets/{treemap-6X3UGDF4-7eiifTKW.js → treemap-6X3UGDF4-DXNQxmQ7.js} +1 -1
  85. package/web-dist/assets/{vennDiagram-L72KCM5P-9u4AhcnV.js → vennDiagram-L72KCM5P-C-khqkdm.js} +1 -1
  86. package/web-dist/assets/{wardley-OPB4EBWU-DqNb5x9U.js → wardley-OPB4EBWU-B9QCQ_Tm.js} +1 -1
  87. package/web-dist/assets/{wardleyDiagram-EHGQE667-DlJ7h3vg.js → wardleyDiagram-EHGQE667-vhVpAUzh.js} +1 -1
  88. package/web-dist/assets/{xychartDiagram-FW5EYKEG-B_9ukg2S.js → xychartDiagram-FW5EYKEG-B8ev9zqs.js} +1 -1
  89. package/web-dist/index.html +2 -2
  90. package/web-dist/assets/architecture-TIHT7OUA-BTy2nvYL.js +0 -1
  91. package/web-dist/assets/channel-WghlT4VS.js +0 -1
  92. package/web-dist/assets/classDiagram-OUVF2IWQ-D21-Dy4r.js +0 -1
  93. package/web-dist/assets/classDiagram-v2-EOCWNBFH-D21-Dy4r.js +0 -1
  94. package/web-dist/assets/eventmodeling-45OFAUF4-RhX2WA7g.js +0 -1
  95. package/web-dist/assets/flowDiagram-23GEKE2U-C7N14tdV.js +0 -1
  96. package/web-dist/assets/index-BFuReKr0.js +0 -368
  97. package/web-dist/assets/index-BH9U3Zlg.css +0 -1
  98. package/web-dist/assets/railroad-abnf-AHOZXSZD-BCeoIOWA.js +0 -1
  99. package/web-dist/assets/railroad-ebnf-EBAXGLYW-lZpXJLD8.js +0 -1
  100. package/web-dist/assets/railroad-peg-LSFZ7HO6-CaUBrHTL.js +0 -1
  101. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-Digf9CWZ.js +0 -1
  102. package/web-dist/assets/swimlanesDiagram-G3AALYLV-DEZRDWHA.js +0 -8
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <p align="center">
2
2
  <h1 align="center"><img src="assets/logo-concepts/final/fff-tile.png" alt="" width="104" height="104"><br/>Frizz</h1>
3
- <p align="center">A local web UI for running many coding agents at once.
3
+ <p align="center">An opinionated agent console for extreme productivity.
4
4
  <br/>
5
5
  by <a href="https://x.com/colinhacks">@colinhacks</a>
6
6
  </p>
@@ -122,7 +122,7 @@ $ npx frizz --help
122
122
  Frizz production launcher
123
123
 
124
124
  Usage: npx frizz [options] [repository]
125
- npx frizz up serve this repo publicly, board + tunnel together
125
+ npx frizz up start the server plus its public tunnel
126
126
 
127
127
  Runs the npm-resolved immutable Frizz package, then opens it in your default browser. Use frizz-dev
128
128
  only for a source checkout.
@@ -196,7 +196,7 @@ trades the code for a session cookie, so the link itself stops working the momen
196
196
  <details>
197
197
  <summary><b>Can I run it on several repos at once?</b></summary>
198
198
 
199
- > Yes one server and one tab per repo, each fully isolated. There is deliberately no cross-repo board.
199
+ > Yes. One Frizz server serves every project on your machine — you don't start one per repo. Run `frizz` in any of them and switch projects from the board; each project's threads, settings and state stay separate.
200
200
 
201
201
  </details>
202
202
 
@@ -19832,6 +19832,18 @@ function claudeUltracodeSettings() {
19832
19832
  return { ultracode: true };
19833
19833
  }
19834
19834
 
19835
+ // packages/server/src/backend/claude-context-window.ts
19836
+ var WINDOW_SUFFIX = "[1m]";
19837
+ var CLAUDE_1M_MODELS = ["fable", "opus", "sonnet"];
19838
+ function resolveClaudeLaunchModel(model) {
19839
+ if (!model) return void 0;
19840
+ if (model.endsWith(WINDOW_SUFFIX)) {
19841
+ return { model, fallbackModel: model.slice(0, -WINDOW_SUFFIX.length) };
19842
+ }
19843
+ if (!CLAUDE_1M_MODELS.includes(model)) return { model };
19844
+ return { model: `${model}${WINDOW_SUFFIX}`, fallbackModel: model };
19845
+ }
19846
+
19835
19847
  // packages/server/src/backend/claude-agent-sdk-protocol.ts
19836
19848
  var CLAUDE_AGENT_SDK_PROTOCOL_VERSION = 1;
19837
19849
  var CLAUDE_AGENT_SDK_MAX_INPUT_BYTES = 64 * 1024;
@@ -19861,6 +19873,7 @@ var CLAUDE_BROKER_CAPABILITY_CANCEL_INPUT = "cancel-input-v1";
19861
19873
  var CLAUDE_BROKER_CAPABILITY_STOP_TASK = "stop-task-v1";
19862
19874
  var CLAUDE_BROKER_CAPABILITY_RELOAD_PLUGINS = "reload-plugins-v1";
19863
19875
  var CLAUDE_BROKER_CAPABILITY_RENAME = "rename-v1";
19876
+ var CLAUDE_BROKER_CAPABILITY_LIST_SKILLS = "list-skills-v1";
19864
19877
  var CLAUDE_INPUT_DROP_DIAGNOSTIC_PREFIX = "input dropped, the agent never received it";
19865
19878
  var ClaudeAgentSdkProtocolError = class extends Error {
19866
19879
  constructor(message) {
@@ -20243,6 +20256,7 @@ var RealClaudeQueryHandle = class {
20243
20256
  closing = false;
20244
20257
  closed = false;
20245
20258
  initialized = false;
20259
+ initSkills = [];
20246
20260
  sdkQuery;
20247
20261
  input;
20248
20262
  diagnostic;
@@ -20352,6 +20366,21 @@ var RealClaudeQueryHandle = class {
20352
20366
  errorCount: Number.isFinite(result?.error_count) ? Number(result.error_count) : 0
20353
20367
  };
20354
20368
  }
20369
+ // The session's invocable skills: the initialize handshake already carries every slash entry WITH
20370
+ // its description (mapped and bounded above in mapControlInitialization — the same data the SDK's
20371
+ // `supportedCommands()` would re-serve from its cache), and the init frame's `skills` array is the
20372
+ // harness's own verdict on which of those are skills rather than built-in commands. The intersection
20373
+ // is exactly "what `/name` invokes a skill", with descriptions, and zero frizz-side discovery.
20374
+ async listSkills() {
20375
+ const initialization = await this.initializationResult();
20376
+ const skillNames = new Set(this.initSkills);
20377
+ const skills = [];
20378
+ for (const command of initialization.commands) {
20379
+ if (!command.name || !skillNames.has(command.name)) continue;
20380
+ skills.push({ name: command.name, description: command.description.slice(0, 1024) });
20381
+ }
20382
+ return skills;
20383
+ }
20355
20384
  // Unqueue a follow-up the operator has taken back.
20356
20385
  //
20357
20386
  // `cancelAsyncMessage` is present at runtime in @anthropic-ai/claude-agent-sdk 0.3.207 but absent
@@ -20449,6 +20478,7 @@ var RealClaudeQueryHandle = class {
20449
20478
  }
20450
20479
  if (event.kind === "init") {
20451
20480
  if (event.sessionId !== this.sessionId) throw new ClaudeAgentSdkProtocolError("Claude session ownership mismatch");
20481
+ this.initSkills = event.skills;
20452
20482
  if (this.initialized) {
20453
20483
  this.output.push(event);
20454
20484
  continue;
@@ -20612,6 +20642,7 @@ function startClaudeQuery(executablePath, options) {
20612
20642
  }
20613
20643
  } : void 0;
20614
20644
  const claudeEffort = resolveClaudeEffort(options.effort);
20645
+ const launchModel = resolveClaudeLaunchModel(options.model);
20615
20646
  const raw = uGe({
20616
20647
  prompt: input,
20617
20648
  options: {
@@ -20629,7 +20660,7 @@ function startClaudeQuery(executablePath, options) {
20629
20660
  // `AGENTS.md` and its `.claude/skills`. Measured differential in the frizz repo, one variable:
20630
20661
  // this factory answered `NO-CLAUDE-MD` where a plain `claude -p` in the same cwd answered
20631
20662
  // "# No pull requests — land on local `main`". That fix restored PROJECT + LOCAL and left USER
20632
- // out, which kept a second, quieter half of the same regression: the tmux transport ran plain
20663
+ // out, which kept a second, quieter half of the same regression: the retired transport ran plain
20633
20664
  // `claude` and got all three scopes, so a broker session was the only place the operator's
20634
20665
  // `~/.claude/settings.json` stopped applying. Measured 2026-08-16 against the maintainer's real
20635
20666
  // config, one variable: `--setting-sources=project,local` reported their `env` block UNSET where
@@ -20644,9 +20675,14 @@ function startClaudeQuery(executablePath, options) {
20644
20675
  ...options.disallowedTools?.length ? { disallowedTools: [...options.disallowedTools] } : {},
20645
20676
  persistSession: options.persistSession ?? false,
20646
20677
  // Keep Claude's default (preset) system prompt and APPEND the frizz worker contract, the SDK
20647
- // equivalent of the tmux path's --append-system-prompt-file.
20678
+ // equivalent of the argv path's --append-system-prompt-file.
20648
20679
  ...options.appendSystemPrompt ? { systemPrompt: { type: "preset", preset: "claude_code", append: options.appendSystemPrompt } } : {},
20649
- ...options.model ? { model: options.model } : {},
20680
+ // The 1M context window rides the MODEL value as a `[1m]` suffix, always paired with the bare
20681
+ // alias as `fallbackModel` — an unavailable long-context beta is a hard 400 that kills the
20682
+ // session, and the fallback is what makes asking for it safe on every subscription. See
20683
+ // claude-context-window.ts for the measurements.
20684
+ ...launchModel ? { model: launchModel.model } : {},
20685
+ ...launchModel?.fallbackModel ? { fallbackModel: launchModel.fallbackModel } : {},
20650
20686
  // "ultracode" is not an `effort` value — it resolves to xhigh plus a session setting, and the two
20651
20687
  // must travel TOGETHER or the setting is silently ignored (see resolveClaudeEffort). `settings` is
20652
20688
  // an additional highest-precedence settings source, layered over `settingSources` above.
@@ -21434,7 +21470,7 @@ function createClaudeBrokerExitWriter(path, meta, now = () => /* @__PURE__ */ ne
21434
21470
  }
21435
21471
 
21436
21472
  // packages/server/src/backend/claude-agent-broker.ts
21437
- var BROKER_CAPABILITIES = [CLAUDE_BROKER_CAPABILITY_SUBAGENT_STEER, CLAUDE_BROKER_CAPABILITY_CANCEL_INPUT, CLAUDE_BROKER_CAPABILITY_STOP_TASK, CLAUDE_BROKER_CAPABILITY_RELOAD_PLUGINS, CLAUDE_BROKER_CAPABILITY_RENAME];
21473
+ var BROKER_CAPABILITIES = [CLAUDE_BROKER_CAPABILITY_SUBAGENT_STEER, CLAUDE_BROKER_CAPABILITY_CANCEL_INPUT, CLAUDE_BROKER_CAPABILITY_STOP_TASK, CLAUDE_BROKER_CAPABILITY_RELOAD_PLUGINS, CLAUDE_BROKER_CAPABILITY_RENAME, CLAUDE_BROKER_CAPABILITY_LIST_SKILLS];
21438
21474
  var IDLE_EXIT_MS = 6 * 60 * 60 * 1e3;
21439
21475
  var REACHABILITY_CHECK_MS = 3e4;
21440
21476
  var REACHABILITY_STRIKES = 2;
@@ -21484,9 +21520,10 @@ function runClaudeBroker(config) {
21484
21520
  pluginDir: config.pluginDir,
21485
21521
  mcpServers: config.mcpServers,
21486
21522
  allowedTools: config.allowedTools,
21487
- // NO `disallowedTools` here, and the asymmetry with the tmux path (WORKER_DISALLOWED_TOOLS →
21488
- // `--disallowedTools=AskUserQuestion`) is DELIBERATE. That flag exists because a tmux worker's
21489
- // question has nowhere to go: it opens a TUI dialog in a pane nobody is looking at. On this path it
21523
+ // NO `disallowedTools` here, and the asymmetry with the argv path (WORKER_DISALLOWED_TOOLS →
21524
+ // `--disallowedTools=AskUserQuestion`) is DELIBERATE. That flag exists because a worker launched as
21525
+ // its own interactive `claude` process had nowhere to put the question: it opened a TUI dialog on a
21526
+ // terminal screen nobody was looking at. On this path it
21490
21527
  // has somewhere to go — canUseTool routes it to a real dashboard question card, the operator answers
21491
21528
  // it, and the chosen labels reach the model. A follow-up sent instead of an answer retires the card
21492
21529
  // and unwinds the tool call (see retirePendingFor in the bridge), so a parked turn is still steerable.
@@ -21621,6 +21658,12 @@ function runClaudeBroker(config) {
21621
21658
  (reloaded) => write(sock, { t: "reload-result", requestId, reloaded }),
21622
21659
  (error) => write(sock, { t: "reload-result", requestId, error: error instanceof Error ? error.message : String(error) })
21623
21660
  );
21661
+ } else if (msg.t === "list-skills") {
21662
+ const requestId = msg.requestId;
21663
+ void handle.listSkills().then(
21664
+ (skills) => write(sock, { t: "skills-result", requestId, skills }),
21665
+ (error) => write(sock, { t: "skills-result", requestId, error: error instanceof Error ? error.message : String(error) })
21666
+ );
21624
21667
  } else if (msg.t === "set-mode") void handle.setPermissionMode(msg.mode).catch(() => {
21625
21668
  });
21626
21669
  }