frizz-server 0.15.10 → 0.15.11

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 (100) hide show
  1. package/dist/claude-agent-broker.js +434 -13
  2. package/dist/dev-child.js +218 -72
  3. package/package.json +1 -1
  4. package/runtime/cc-worker/bin/frizz-mcp.mjs +22 -11
  5. package/web-dist/assets/{abnfDiagram-VRR7QNED-CPgDRCPL.js → abnfDiagram-VRR7QNED-NqOfYLl_.js} +1 -1
  6. package/web-dist/assets/{arc-BHLpLJBo.js → arc-D9UsqPOW.js} +1 -1
  7. package/web-dist/assets/architecture-TIHT7OUA-CYx5mu8e.js +1 -0
  8. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-D0qwvPWx.js → architectureDiagram-ZJ3FMSHR-CRU2_T_H.js} +1 -1
  9. package/web-dist/assets/{blockDiagram-677ZJIJ3-C3NPa6bJ.js → blockDiagram-677ZJIJ3-DZT8OjJK.js} +1 -1
  10. package/web-dist/assets/{c4Diagram-LMCZKHZV-BW9GHi19.js → c4Diagram-LMCZKHZV-k-Ft1ThH.js} +1 -1
  11. package/web-dist/assets/channel-CD-hjjIL.js +1 -0
  12. package/web-dist/assets/{chunk-32BRIVSS-DHkNUXJc.js → chunk-32BRIVSS-DDMMpuZb.js} +1 -1
  13. package/web-dist/assets/{chunk-52WLFC77-CD7yIcMj.js → chunk-52WLFC77-BW9KF5RJ.js} +1 -1
  14. package/web-dist/assets/{chunk-C7G6YPKG-DCNeb-B6.js → chunk-C7G6YPKG-B4caDIAT.js} +1 -1
  15. package/web-dist/assets/{chunk-EX3LRPZG-YD5FxMO3.js → chunk-EX3LRPZG-Dyz0PnIY.js} +1 -1
  16. package/web-dist/assets/{chunk-FWX5IMBZ-XPo-YcnN.js → chunk-FWX5IMBZ-Dxhqduv9.js} +2 -2
  17. package/web-dist/assets/{chunk-HOUHSVGY-D6MFIjXX.js → chunk-HOUHSVGY-Du7Ln4sO.js} +1 -1
  18. package/web-dist/assets/{chunk-ICXQ74PX-B4YNEdT-.js → chunk-ICXQ74PX-sNRNHZp6.js} +1 -1
  19. package/web-dist/assets/{chunk-MOJQB5TN-DmeXNe3e.js → chunk-MOJQB5TN-BsgPysrE.js} +1 -1
  20. package/web-dist/assets/{chunk-OGEWGWER-DOiD4wAh.js → chunk-OGEWGWER-DZ288hvO.js} +1 -1
  21. package/web-dist/assets/{chunk-PUDLZKDR-1SEr54_e.js → chunk-PUDLZKDR-DuU7e-Sm.js} +1 -1
  22. package/web-dist/assets/{chunk-Q4XR5HBZ-CyWVwYh2.js → chunk-Q4XR5HBZ-BO2aVRAy.js} +1 -1
  23. package/web-dist/assets/{chunk-RYQCIY6F-ClBJ_iGr.js → chunk-RYQCIY6F-pQoqlm5b.js} +1 -1
  24. package/web-dist/assets/{chunk-V7JOEXUC-Bz8VXwYP.js → chunk-V7JOEXUC-DkkQI0OQ.js} +1 -1
  25. package/web-dist/assets/{chunk-VAUOI2AC-DawR4suA.js → chunk-VAUOI2AC-D3_hzRfs.js} +1 -1
  26. package/web-dist/assets/{chunk-VR4S4FIN-B-_noBva.js → chunk-VR4S4FIN-BBnj_eoh.js} +1 -1
  27. package/web-dist/assets/{chunk-WYO6CB5R-DL1c5T7_.js → chunk-WYO6CB5R-BqxQ9C2U.js} +1 -1
  28. package/web-dist/assets/{chunk-XXDRQBXY-BtfDQurg.js → chunk-XXDRQBXY-i1ZlWoHe.js} +1 -1
  29. package/web-dist/assets/{chunk-ZGVPDNZ5-Du753kJ-.js → chunk-ZGVPDNZ5-CsZazrsC.js} +1 -1
  30. package/web-dist/assets/classDiagram-OUVF2IWQ-B-BSDhSx.js +1 -0
  31. package/web-dist/assets/classDiagram-v2-EOCWNBFH-B-BSDhSx.js +1 -0
  32. package/web-dist/assets/{cose-bilkent-JH36ORCC-B92GSF8h.js → cose-bilkent-JH36ORCC-BmEzvocR.js} +1 -1
  33. package/web-dist/assets/{cynefin-VYW2F7L2-K0fFe9n6.js → cynefin-VYW2F7L2-DZw7i9wG.js} +1 -1
  34. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-DPizF8tw.js → cynefinDiagram-TSTJHNR4-vngpN5Da.js} +1 -1
  35. package/web-dist/assets/{dagre-VKFMJZFB-CUyDVdiG.js → dagre-VKFMJZFB-DkIdWq34.js} +1 -1
  36. package/web-dist/assets/{diagram-FQU43EPY-B6T_JCaJ.js → diagram-FQU43EPY-BB6mK3b6.js} +1 -1
  37. package/web-dist/assets/{diagram-G47NLZAW-CoDvaB51.js → diagram-G47NLZAW-DNs0n26T.js} +1 -1
  38. package/web-dist/assets/{diagram-NH7WQ7WH-o5OSs1Ze.js → diagram-NH7WQ7WH-DOg3HmEF.js} +1 -1
  39. package/web-dist/assets/{diagram-OA4YK3LP-CZLlB0ak.js → diagram-OA4YK3LP-BVKuqpaY.js} +1 -1
  40. package/web-dist/assets/{diagram-WEI45ONY-2VF6u7pk.js → diagram-WEI45ONY-BVnqmqct.js} +1 -1
  41. package/web-dist/assets/{dist-C2Rccr_W.js → dist-DuviCA4e.js} +1 -1
  42. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-D9GSCcoU.js → ebnfDiagram-CCIWWBDH-BrqvjM1n.js} +1 -1
  43. package/web-dist/assets/{erDiagram-Q63AITRT-BLwWP_S8.js → erDiagram-Q63AITRT-Du1wclw9.js} +1 -1
  44. package/web-dist/assets/eventmodeling-45OFAUF4-BPCrKw7m.js +1 -0
  45. package/web-dist/assets/flowDiagram-23GEKE2U-AA0QqWn2.js +1 -0
  46. package/web-dist/assets/{ganttDiagram-NO4QXBWP-BDe4wbPG.js → ganttDiagram-NO4QXBWP-CSiHPJrQ.js} +1 -1
  47. package/web-dist/assets/{gitGraph-TEB2WS4Q-DtGgkTGs.js → gitGraph-TEB2WS4Q-7-fFcwxj.js} +1 -1
  48. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-Cz2LctIP.js → gitGraphDiagram-IHSO6WYX-CElQAu0f.js} +1 -1
  49. package/web-dist/assets/index-BWqGEWRg.js +330 -0
  50. package/web-dist/assets/index-W88ZnKOr.css +2 -0
  51. package/web-dist/assets/{info-DKCQHKI2-Crwk5sJH.js → info-DKCQHKI2-CXWr1yIe.js} +1 -1
  52. package/web-dist/assets/{infoDiagram-FWYZ7A6U-DkHHoxhz.js → infoDiagram-FWYZ7A6U-gN_v0GbL.js} +1 -1
  53. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-CXMQf65c.js → ishikawaDiagram-FXEZZL3T-je5d5eKU.js} +1 -1
  54. package/web-dist/assets/{journeyDiagram-5HDEW3XC-BMdDsuH7.js → journeyDiagram-5HDEW3XC-CybyC_OE.js} +1 -1
  55. package/web-dist/assets/{kanban-definition-HUTT4EX6-BLp4VuCG.js → kanban-definition-HUTT4EX6-DthSkUsp.js} +1 -1
  56. package/web-dist/assets/{line-DOl515UP.js → line-C6dQfGfT.js} +1 -1
  57. package/web-dist/assets/{linear-DXvWeSoC.js → linear-zrRCwmn0.js} +1 -1
  58. package/web-dist/assets/{mermaid-parser.core-CqGam-b6.js → mermaid-parser.core-DGsIiQR5.js} +3 -3
  59. package/web-dist/assets/{mermaid.core-DawC2x_0.js → mermaid.core-Dk0TeuEE.js} +3 -3
  60. package/web-dist/assets/{mindmap-definition-LN4V7U3C-DlsS0Y-V.js → mindmap-definition-LN4V7U3C-Wo-S6GUr.js} +1 -1
  61. package/web-dist/assets/{packet-7NZHBO7P-CmlVYVem.js → packet-7NZHBO7P-BjJcy3q1.js} +1 -1
  62. package/web-dist/assets/{pegDiagram-2B236MQR-Cx0g5nsx.js → pegDiagram-2B236MQR-BBD9ezK8.js} +1 -1
  63. package/web-dist/assets/{pie-RZYD4A2V-C0PsjAlT.js → pie-RZYD4A2V-B9UJsCc6.js} +1 -1
  64. package/web-dist/assets/{pieDiagram-ENE6RG2P-CSuFf6VT.js → pieDiagram-ENE6RG2P-DvLH3PU6.js} +1 -1
  65. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-CuQtvBia.js → quadrantDiagram-ABIIQ3AL-BwC1BKho.js} +1 -1
  66. package/web-dist/assets/{radar-I7S5WNFK-gk0WSCd9.js → radar-I7S5WNFK-BziFtIY8.js} +1 -1
  67. package/web-dist/assets/{railroad-3IZDKUUU-CovQLWaQ.js → railroad-3IZDKUUU-DPD8gyCw.js} +1 -1
  68. package/web-dist/assets/railroad-abnf-AHOZXSZD-C6wFrQk2.js +1 -0
  69. package/web-dist/assets/railroad-ebnf-EBAXGLYW-yv1OIO4r.js +1 -0
  70. package/web-dist/assets/railroad-peg-LSFZ7HO6-BNocqLQb.js +1 -0
  71. package/web-dist/assets/{railroadDiagram-RFXS5EU6-RU1nu6mz.js → railroadDiagram-RFXS5EU6-DkS_57bW.js} +1 -1
  72. package/web-dist/assets/{requirementDiagram-TGXJPOKE-VoYjpOAN.js → requirementDiagram-TGXJPOKE-DT4YnV0v.js} +1 -1
  73. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-DOVqKs1B.js → sankeyDiagram-HTMAVEWB-DMhUiLXu.js} +1 -1
  74. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-DWMCuKM1.js → sequenceDiagram-DBY2YBRQ-BzyFG5mU.js} +1 -1
  75. package/web-dist/assets/{src-T1UUKJjT.js → src-Bpw4w4N9.js} +1 -1
  76. package/web-dist/assets/{stateDiagram-2N3HPSRC-mvFnj-9X.js → stateDiagram-2N3HPSRC-DI7bXIvV.js} +1 -1
  77. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BnPQRodM.js +1 -0
  78. package/web-dist/assets/{swimlanes-5IMT3BWC-kRCjOJ75.js → swimlanes-5IMT3BWC-ocEwjrkf.js} +1 -1
  79. package/web-dist/assets/swimlanesDiagram-G3AALYLV-Cmi6u5Ox.js +8 -0
  80. package/web-dist/assets/{timeline-definition-FHXFAJF6-Z8oX_ic6.js → timeline-definition-FHXFAJF6-Cx606xig.js} +1 -1
  81. package/web-dist/assets/{treeView-QDETBFTQ-BNFv3tbG.js → treeView-QDETBFTQ-BBjaqvh7.js} +1 -1
  82. package/web-dist/assets/{treemap-6X3UGDF4-DFxnrL9n.js → treemap-6X3UGDF4-Bn8fQ4vt.js} +1 -1
  83. package/web-dist/assets/{vennDiagram-L72KCM5P-rBeP_pn_.js → vennDiagram-L72KCM5P-DaKXvRdc.js} +1 -1
  84. package/web-dist/assets/{wardley-OPB4EBWU-BovK6GPr.js → wardley-OPB4EBWU-CK6Oy13G.js} +1 -1
  85. package/web-dist/assets/{wardleyDiagram-EHGQE667-B1yRRFsz.js → wardleyDiagram-EHGQE667-esMnbbXF.js} +1 -1
  86. package/web-dist/assets/{xychartDiagram-FW5EYKEG-IShFUxtM.js → xychartDiagram-FW5EYKEG-D3DoqcNr.js} +1 -1
  87. package/web-dist/index.html +2 -2
  88. package/web-dist/assets/architecture-TIHT7OUA-BxHw4J0J.js +0 -1
  89. package/web-dist/assets/channel-CgUG0O7S.js +0 -1
  90. package/web-dist/assets/classDiagram-OUVF2IWQ-CpxiJqgs.js +0 -1
  91. package/web-dist/assets/classDiagram-v2-EOCWNBFH-CpxiJqgs.js +0 -1
  92. package/web-dist/assets/eventmodeling-45OFAUF4-C-XvAPEG.js +0 -1
  93. package/web-dist/assets/flowDiagram-23GEKE2U-DYBwekLd.js +0 -1
  94. package/web-dist/assets/index-B9jaLEKn.js +0 -330
  95. package/web-dist/assets/index-Dubos_kO.css +0 -2
  96. package/web-dist/assets/railroad-abnf-AHOZXSZD-DSq7zK8A.js +0 -1
  97. package/web-dist/assets/railroad-ebnf-EBAXGLYW-icFIsnio.js +0 -1
  98. package/web-dist/assets/railroad-peg-LSFZ7HO6-Csep5xwu.js +0 -1
  99. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BkzW7JgJ.js +0 -1
  100. package/web-dist/assets/swimlanesDiagram-G3AALYLV-mE9The3K.js +0 -8
package/dist/dev-child.js CHANGED
@@ -13348,7 +13348,9 @@ function splitAwaitingFrontmatter(raw2) {
13348
13348
  const title = trimAwaitingTitle(titleLines.join(" "));
13349
13349
  if (title) parsed.hints.push({ kind: "title", value: title });
13350
13350
  const stepHints = steps.map((step) => step.trim()).filter(Boolean).slice(0, AWAITING_STEPS_MAX).map((step) => ({ kind: "step", value: step.slice(0, AWAITING_STEP_VALUE_MAX) }));
13351
- return { body: rest.join("\n").trim(), hints: [...parsed.hints.slice(0, AWAITING_HINT_MAX), ...stepHints] };
13351
+ const questionHints = parsed.hints.filter((h10) => h10.kind === "question").slice(0, AWAITING_QUESTIONS_MAX);
13352
+ const capped = parsed.hints.filter((h10) => h10.kind !== "question").slice(0, AWAITING_HINT_MAX);
13353
+ return { body: rest.join("\n").trim(), hints: [...capped, ...questionHints, ...stepHints] };
13352
13354
  }
13353
13355
  function inlineSteps(value) {
13354
13356
  const v3 = value.trim();
@@ -13364,6 +13366,12 @@ function inlineSteps(value) {
13364
13366
  function awaitingSteps(hints) {
13365
13367
  return (hints ?? []).filter((h10) => h10.kind === "step").map((h10) => h10.value);
13366
13368
  }
13369
+ function awaitingQuestions(hints) {
13370
+ return (hints ?? []).filter((h10) => h10.kind === "question").map((h10) => questionIdOf(h10.value));
13371
+ }
13372
+ function questionIdOf(value) {
13373
+ return (/qst_[a-z0-9]+/i.exec(value)?.[0] ?? value.trim()).toLowerCase();
13374
+ }
13367
13375
  function parseAwaitingYaml(text2) {
13368
13376
  if (!text2.trim()) return { ok: true, hints: [] };
13369
13377
  let doc;
@@ -13385,6 +13393,8 @@ function parseAwaitingYaml(text2) {
13385
13393
  const itemKind = AWAITING_SEQUENCE_KEYS[key];
13386
13394
  if (itemKind) {
13387
13395
  for (const entry of Array.isArray(raw2) ? raw2 : [raw2]) push(itemKind, entry);
13396
+ } else if (key === "questions") {
13397
+ for (const entry of Array.isArray(raw2) ? raw2 : [raw2]) push("question", entry);
13388
13398
  } else if (key === "for") {
13389
13399
  push("for", raw2);
13390
13400
  } else if (key === "needs_input" || key === "needs-input") {
@@ -13394,7 +13404,7 @@ function parseAwaitingYaml(text2) {
13394
13404
  return { ok: true, hints };
13395
13405
  }
13396
13406
  function awaitingNeedsInput(hints) {
13397
- if (awaitingSteps(hints).length > 0) return true;
13407
+ if (awaitingSteps(hints).length > 0 || awaitingQuestions(hints).length > 0) return true;
13398
13408
  let answer = null;
13399
13409
  for (const h10 of hints ?? []) {
13400
13410
  if (h10.kind !== "needs_input") continue;
@@ -13633,6 +13643,10 @@ function signoffNudgeText(needsInput) {
13633
13643
  " followed cold; frizz reads them verbatim. Steps name the HUMAN as the wait, so the fence needs no",
13634
13644
  " other name and no `for:`, and the thread goes into their queue. Their Done comes back to you as",
13635
13645
  " their reply; anything else they need to say comes as a message of their own.",
13646
+ "- `` ```awaiting `` with `questions:` \u2014 a question you registered at an EARLIER rest is still open and",
13647
+ " you still need its answer. Name every such question (`questions: [qst_\u2026]`) and withdraw the rest with",
13648
+ " `mcp__frizz__unask`: a fence that leaves an open question out is refused. A named card is drawn at",
13649
+ " this rest; an unnamed one stays where you asked it.",
13636
13650
  "",
13637
13651
  "**STILL OWED counts things you are not going to do yourself.** A decision you are RECOMMENDING, a",
13638
13652
  "draft you wrote but did not send, follow-up work you discovered \u2014 all of it dies with the card, even",
@@ -13653,6 +13667,27 @@ function signoffNudgeText(needsInput) {
13653
13667
  "frizz \u2014 so anything you assumed they had followed, they have not."
13654
13668
  ].join("\n");
13655
13669
  }
13670
+ function carriedQuestionsNudgeMessage(questions, ops, needsInput = false) {
13671
+ const one2 = questions.length === 1;
13672
+ const lines = [
13673
+ `${SIGNOFF_NUDGE_MARKER} Nothing about your task has changed, and no new work is being asked of you.`,
13674
+ "",
13675
+ `${one2 ? "A question you registered at an EARLIER rest is" : "Questions you registered at EARLIER rests are"} still open, and this rest neither names ${one2 ? "it" : "them"} nor withdraws ${one2 ? "it" : "them"}:`,
13676
+ "",
13677
+ ...questions.map((q10) => `- \`${q10.id}\` \u2014 ${q10.question}`),
13678
+ "",
13679
+ "Frizz does not draw an earlier rest's question under your newest handoff: its card stays where you",
13680
+ `asked it. So say where ${one2 ? "it stands" : "each one stands"}:`,
13681
+ "",
13682
+ "- STILL NEED THE ANSWER \u2192 end with an ```awaiting fence naming it, `questions: [qst_\u2026]`. A fence on",
13683
+ " questions needs no other name and no `for:`, and the thread stays in the human's queue. The card is",
13684
+ " drawn at this rest, under the reasoning you write below the `---` \u2014 what changed since you asked,",
13685
+ " if anything did.",
13686
+ "- NO LONGER NEED IT \u2192 withdraw it with `mcp__frizz__unask`, then sign off as you otherwise would.",
13687
+ ...liveOpsLines(ops, needsInput)
13688
+ ];
13689
+ return lines.join("\n");
13690
+ }
13656
13691
  function isParkCorrection(text2) {
13657
13692
  const t = text2.trimStart();
13658
13693
  return t.startsWith(PARK_CORRECTION_NAMES_LEAD) || t.startsWith(PARK_CORRECTION_RETIRED_LEAD) || t.startsWith(PARK_CORRECTION_QUESTION_LEAD) || t.startsWith(PARK_CORRECTION_NEEDS_INPUT_LEAD);
@@ -13986,7 +14021,7 @@ function parseGithubWakeSteer(text2) {
13986
14021
  function frizzRoute(path3) {
13987
14022
  return `${FRIZZ_ROUTE_PREFIX}${path3.startsWith("/") ? path3 : `/${path3}`}`;
13988
14023
  }
13989
- var import_yaml, ATTACHMENT_IMAGE_EXTENSIONS, ATTACHMENT_TEXT_EXTENSIONS, ATTACHMENT_OFFICE_EXTENSIONS, ATTACHMENT_DATA_EXTENSIONS, ATTACHMENT_ARCHIVE_EXTENSIONS, ATTACHMENT_DOC_EXTENSIONS, ATTACHMENT_EXTENSIONS, ATTACHMENT_MAX_BASE64_CHARS, ATTACHMENT_MAX_BYTES, ATTACHMENT_EXT_SET, ATTACHMENT_ACCEPT, FrizzStatus, BlockMechanism, RuntimeState, Backend, CodexModel, ClaudeModel, AcpAgent, ACP_MODEL_PREFIX, AcpAgentModel, AcpAgentModels, AcpAgentModelsInput, ThreadProfileOption, ThreadAgent, SubAgentView, BgShellView, CompletionHoldOp, CompletionHold, AskOption, AskQuestion, PendingAsk, AwaitingHint, RETIRED_AWAITING_KINDS, RETIRED_LINE_RE, RETIRED_AWAITING_REPLACEMENT, AWAITING_KEY_RE, AWAITING_YAML_KEYS, AWAITING_SEQUENCE_KEYS, AWAITING_HINT_MAX, AWAITING_HINT_VALUE_MAX, AWAITING_STEPS_MAX, AWAITING_STEP_VALUE_MAX, AWAITING_TITLE_MAX, AWAITING_ITEM_KINDS, AWAITING_DURATION_RE, DURATION_UNIT_MS, AWAITING_FOR_MAX_MS, SnoozeUntil, SNOOZE_PROMPT_MAX, SnoozePrompt, RECURRING_PROMPT_MAX, RECURRING_MIN_INTERVAL_SECONDS, RECURRING_MAX_INTERVAL_SECONDS, RecurringPromptText, RecurringIntervalSeconds, ThreadRecurringPrompt, INTERRUPT_MARKERS, ALLDONE_SENTINEL, OPT_OUT_NOTE, OVER_QUESTION_NOTE, TIMER_PROMPT_MAX, TIMER_MAX_DELAY_SECONDS, TIMER_MAX_ARMED, TimerPromptText, PR_WATCH_SPENT_TRAILER, PR_WATCH_ARMED_TRAILER, SHELL_DONE_TRAILER, ISSUE_WATCH_SPENT_TRAILER, ISSUE_WATCH_ARMED_TRAILER, INTERRUPT_ENDED_LEAD, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, SIGNOFF_NUDGE_MESSAGE_NEEDS_INPUT, PARK_CORRECTION_NAMES_LEAD, PARK_CORRECTION_RETIRED_LEAD, PARK_CORRECTION_QUESTION_LEAD, PARK_CORRECTION_NEEDS_INPUT_LEAD, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, GithubIssueStatus, ThreadWatchView, PR_WATCH_FOR_MAX_MS, PR_WATCH_DEFAULT_FOR_MS, PR_WATCH_MAX_ARMED, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, OwnWatchKind, AddOwnWatchInput, OwnWatchView, AddOwnWatchResult, DropOwnWatchInput, DropOwnWatchResult, OWN_WATCH_MAX_ARMED, QUESTION_FENCE_RETIRED_AT, NEEDS_INPUT_REQUIRED_AT, AskQuestionKind, ASK_MAX_DEPTH, AskedOptionSchema, AskedQuestionSchema, AskInput, RegisteredQuestionView, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, SettledQuestionView, ThreadSettledQuestionsResult, BURIED_ANSWERS_HEADER, ANSWER_FOLLOW_UP_MARKER, ANSWER_CONTINUATION_INDENT, indentAnswerContinuation, DISMISSED_ANSWER, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ProviderError, ThreadLinkView, UpsertOwnLinkInput, UpsertOwnLinkResult, DropOwnLinkInput, DropOwnLinkResult, LiveTool, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountBackend, AccountLogoutInput, AccountLogoutResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshotShape, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, DismissFailedFollowUpInput, DismissFailedFollowUpResult, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, CompactThreadInput, SetThreadSnoozeInput, SetThreadPinnedInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetOwnThreadTitleInput, SetOwnThreadTitleResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkillSource, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, UpgradeThreadModelInput, UpgradeThreadModelResult, DISPATCH_TASK_BANNER, DISPATCH_TASK_BANNER_MARKER, GITHUB_DISPATCH_UI_BOUNDARY, WAKE_TIME_HEADER_TAIL, WAKE_TRAILERS, HUMAN_GAP_FLOOR_MS, HUMAN_GAP_NOTE_TAIL, WAKE_DELIVERY_TOKEN_TAIL, WAKE_DELIVERY_TOKEN_LINE, NOISE_PREFIXES, AGENT_MESSAGE_WRAPPER, GithubWakeItem, GithubWakeSteer, WAKE_SCOPE, WAKE_REVIEW_LEAD, WAKE_BACKLOG_TAIL, WAKE_REF, WAKE_SINGLE, WAKE_MULTI_HEAD, WAKE_ITEM, WAKE_MORE, PR_WATCH_FINISHED, PR_WATCH_CI_PASSED, PR_WATCH_CI_GATED, PR_WATCH_STATE, PR_WATCH_CI_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, EditedFile, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketFilePath, SocketTranscriptClientMsg, SocketFileClientMsg, SocketClientMsg, ProjectCard, ProjectRailCounts, PROJECT_ICON_EXTENSIONS, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT, threadIdentityName;
14024
+ var import_yaml, ATTACHMENT_IMAGE_EXTENSIONS, ATTACHMENT_TEXT_EXTENSIONS, ATTACHMENT_OFFICE_EXTENSIONS, ATTACHMENT_DATA_EXTENSIONS, ATTACHMENT_ARCHIVE_EXTENSIONS, ATTACHMENT_DOC_EXTENSIONS, ATTACHMENT_EXTENSIONS, ATTACHMENT_MAX_BASE64_CHARS, ATTACHMENT_MAX_BYTES, ATTACHMENT_EXT_SET, ATTACHMENT_ACCEPT, FrizzStatus, BlockMechanism, RuntimeState, Backend, CodexModel, ClaudeModel, AcpAgent, ACP_MODEL_PREFIX, AcpAgentModel, AcpAgentModels, AcpAgentModelsInput, ThreadProfileOption, ThreadAgent, SubAgentView, BgShellView, CompletionHoldOp, CompletionHold, AskOption, AskQuestion, PendingAsk, AwaitingHint, RETIRED_AWAITING_KINDS, RETIRED_LINE_RE, RETIRED_AWAITING_REPLACEMENT, AWAITING_KEY_RE, AWAITING_YAML_KEYS, AWAITING_SEQUENCE_KEYS, AWAITING_HINT_MAX, AWAITING_HINT_VALUE_MAX, AWAITING_STEPS_MAX, AWAITING_STEP_VALUE_MAX, AWAITING_QUESTIONS_MAX, AWAITING_TITLE_MAX, AWAITING_ITEM_KINDS, AWAITING_DURATION_RE, DURATION_UNIT_MS, AWAITING_FOR_MAX_MS, SnoozeUntil, SNOOZE_PROMPT_MAX, SnoozePrompt, RECURRING_PROMPT_MAX, RECURRING_MIN_INTERVAL_SECONDS, RECURRING_MAX_INTERVAL_SECONDS, RecurringPromptText, RecurringIntervalSeconds, ThreadRecurringPrompt, INTERRUPT_MARKERS, ALLDONE_SENTINEL, OPT_OUT_NOTE, OVER_QUESTION_NOTE, TIMER_PROMPT_MAX, TIMER_MAX_DELAY_SECONDS, TIMER_MAX_ARMED, TimerPromptText, PR_WATCH_SPENT_TRAILER, PR_WATCH_ARMED_TRAILER, SHELL_DONE_TRAILER, ISSUE_WATCH_SPENT_TRAILER, ISSUE_WATCH_ARMED_TRAILER, INTERRUPT_ENDED_LEAD, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, SIGNOFF_NUDGE_MESSAGE_NEEDS_INPUT, PARK_CORRECTION_NAMES_LEAD, PARK_CORRECTION_RETIRED_LEAD, PARK_CORRECTION_QUESTION_LEAD, PARK_CORRECTION_NEEDS_INPUT_LEAD, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, GithubIssueStatus, ThreadWatchView, PR_WATCH_FOR_MAX_MS, PR_WATCH_DEFAULT_FOR_MS, PR_WATCH_MAX_ARMED, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, OwnWatchKind, AddOwnWatchInput, OwnWatchView, AddOwnWatchResult, DropOwnWatchInput, DropOwnWatchResult, OWN_WATCH_MAX_ARMED, QUESTION_FENCE_RETIRED_AT, NEEDS_INPUT_REQUIRED_AT, AskQuestionKind, ASK_MAX_DEPTH, AskedOptionSchema, AskedQuestionSchema, AskInput, RegisteredQuestionView, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, SettledQuestionView, ThreadSettledQuestionsResult, BURIED_ANSWERS_HEADER, ANSWER_FOLLOW_UP_MARKER, ANSWER_CONTINUATION_INDENT, indentAnswerContinuation, DISMISSED_ANSWER, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ProviderError, ThreadLinkView, UpsertOwnLinkInput, UpsertOwnLinkResult, DropOwnLinkInput, DropOwnLinkResult, LiveTool, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountBackend, AccountLogoutInput, AccountLogoutResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshotShape, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, DismissFailedFollowUpInput, DismissFailedFollowUpResult, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, CompactThreadInput, SetThreadSnoozeInput, SetThreadPinnedInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetOwnThreadTitleInput, SetOwnThreadTitleResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkillSource, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, UpgradeThreadModelInput, UpgradeThreadModelResult, DISPATCH_TASK_BANNER, DISPATCH_TASK_BANNER_MARKER, GITHUB_DISPATCH_UI_BOUNDARY, WAKE_TIME_HEADER_TAIL, WAKE_TRAILERS, HUMAN_GAP_FLOOR_MS, HUMAN_GAP_NOTE_TAIL, WAKE_DELIVERY_TOKEN_TAIL, WAKE_DELIVERY_TOKEN_LINE, NOISE_PREFIXES, AGENT_MESSAGE_WRAPPER, GithubWakeItem, GithubWakeSteer, WAKE_SCOPE, WAKE_REVIEW_LEAD, WAKE_BACKLOG_TAIL, WAKE_REF, WAKE_SINGLE, WAKE_MULTI_HEAD, WAKE_ITEM, WAKE_MORE, PR_WATCH_FINISHED, PR_WATCH_CI_PASSED, PR_WATCH_CI_GATED, PR_WATCH_STATE, PR_WATCH_CI_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, EditedFile, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketFilePath, SocketTranscriptClientMsg, SocketFileClientMsg, SocketClientMsg, ProjectCard, ProjectRailCounts, PROJECT_ICON_EXTENSIONS, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT, threadIdentityName;
13990
14025
  var init_src = __esm({
13991
14026
  "packages/shared/src/index.ts"() {
13992
14027
  "use strict";
@@ -14325,7 +14360,7 @@ var init_src = __esm({
14325
14360
  questions: external_exports.array(AskQuestion)
14326
14361
  });
14327
14362
  AwaitingHint = external_exports.object({
14328
- kind: external_exports.enum(["shell", "agent", "timer", "pr", "issue", "for", "title", "needs_input", "step"]),
14363
+ kind: external_exports.enum(["shell", "agent", "timer", "pr", "issue", "for", "title", "needs_input", "step", "question"]),
14329
14364
  value: external_exports.string()
14330
14365
  });
14331
14366
  RETIRED_AWAITING_KINDS = ["watch", "pr-watch", "human", "ci", "session", "shell", "agent", "timer", "pr", "reason"];
@@ -14347,7 +14382,7 @@ var init_src = __esm({
14347
14382
  "reason": "put it below the `---` as ordinary Markdown \u2014 the frontmatter is YAML now and takes no prose"
14348
14383
  };
14349
14384
  AWAITING_KEY_RE = /^([a-z][a-z_-]*):\s*(\S.*)?$/i;
14350
- AWAITING_YAML_KEYS = /* @__PURE__ */ new Set(["shells", "agents", "timers", "prs", "issues", "for", "title", "steps", "needs_input", "needs-input"]);
14385
+ AWAITING_YAML_KEYS = /* @__PURE__ */ new Set(["shells", "agents", "timers", "prs", "issues", "questions", "for", "title", "steps", "needs_input", "needs-input"]);
14351
14386
  AWAITING_SEQUENCE_KEYS = {
14352
14387
  shells: "shell",
14353
14388
  agents: "agent",
@@ -14362,6 +14397,7 @@ var init_src = __esm({
14362
14397
  AWAITING_HINT_VALUE_MAX = 200;
14363
14398
  AWAITING_STEPS_MAX = 12;
14364
14399
  AWAITING_STEP_VALUE_MAX = 500;
14400
+ AWAITING_QUESTIONS_MAX = 24;
14365
14401
  AWAITING_TITLE_MAX = 120;
14366
14402
  AWAITING_ITEM_KINDS = ["shell", "agent", "timer", "pr", "issue"];
14367
14403
  AWAITING_DURATION_RE = /^(\d{1,5})(s|m|h|d)$/;
@@ -24166,9 +24202,11 @@ function readTranscriptTail(path3, size, window) {
24166
24202
  }
24167
24203
  }
24168
24204
  }
24169
- async function probeShellsAlive(outputFiles, opts = {}) {
24205
+ async function probeShellsAlive(shells, opts = {}) {
24170
24206
  const platform3 = opts.platform ?? process.platform;
24171
24207
  const exec = opts.exec ?? execFileAsync;
24208
+ const launches = shells.map((s) => typeof s === "string" ? { outputFile: s } : s);
24209
+ const outputFiles = launches.map((l) => l.outputFile);
24172
24210
  const verdicts = /* @__PURE__ */ new Map();
24173
24211
  if (platform3 === "win32") {
24174
24212
  const present = outputFiles.filter((file) => {
@@ -24216,6 +24254,64 @@ async function probeShellsAlive(outputFiles, opts = {}) {
24216
24254
  const held = /* @__PURE__ */ new Set();
24217
24255
  for (const line of stdout.split("\n")) if (line.startsWith("n")) held.add(line.slice(1));
24218
24256
  for (const f of live) verdicts.set(f.requested, held.has(f.real));
24257
+ const unheld = launches.filter((l) => verdicts.get(l.outputFile) === false && l.sessionId && l.launchedAtMs !== void 0);
24258
+ if (unheld.length === 0) return verdicts;
24259
+ const running = await findShellProcesses(unheld, { exec, nowMs: opts.nowMs ?? Date.now(), env: opts.env });
24260
+ for (const [file, alive] of running) if (alive !== void 0) verdicts.set(file, alive);
24261
+ return verdicts;
24262
+ }
24263
+ async function findShellProcesses(shells, opts = {}) {
24264
+ const exec = opts.exec ?? execFileAsync;
24265
+ const nowMs = opts.nowMs ?? Date.now();
24266
+ const verdicts = /* @__PURE__ */ new Map();
24267
+ const env = { ...opts.env ?? process.env, LC_ALL: "C" };
24268
+ const run3 = async (args) => {
24269
+ try {
24270
+ return (await exec("ps", args, { encoding: "utf8", timeout: 8e3, maxBuffer: 16 * 1024 * 1024, env })).stdout;
24271
+ } catch (err) {
24272
+ const e14 = err;
24273
+ return typeof e14.code === "number" && !e14.killed && e14.stdout ? e14.stdout : void 0;
24274
+ }
24275
+ };
24276
+ const table = await run3(["-ax", "-o", "pid=,ppid=,lstart="]);
24277
+ if (table === void 0) {
24278
+ for (const s of shells) verdicts.set(s.outputFile, void 0);
24279
+ return verdicts;
24280
+ }
24281
+ const forks = [];
24282
+ for (const line of table.split("\n")) {
24283
+ const m = /^\s*(\d+)\s+(\d+)\s+(\S.*?)\s*$/.exec(line);
24284
+ const at2 = m ? Date.parse(m[3]) : NaN;
24285
+ if (m && Number.isFinite(at2)) forks.push({ pid: Number(m[1]), ppid: Number(m[2]), at: at2 });
24286
+ }
24287
+ if (forks.length === 0) {
24288
+ for (const s of shells) verdicts.set(s.outputFile, void 0);
24289
+ return verdicts;
24290
+ }
24291
+ const candidates = /* @__PURE__ */ new Map();
24292
+ for (const s of shells) {
24293
+ const from = Math.floor(s.launchedAtMs / 1e3) * 1e3 - 1e3;
24294
+ const to2 = (s.ackedAtMs ?? nowMs) + 1e3;
24295
+ candidates.set(s.outputFile, forks.filter((f) => f.at >= from && f.at <= to2));
24296
+ }
24297
+ const parents = [...new Set([...candidates.values()].flat().map((c) => c.ppid))];
24298
+ let argvOf = /* @__PURE__ */ new Map();
24299
+ if (parents.length > 0) {
24300
+ const listing = await run3(["-ww", "-o", "pid=,command=", "-p", parents.join(",")]);
24301
+ if (listing === void 0) {
24302
+ for (const s of shells) verdicts.set(s.outputFile, candidates.get(s.outputFile).length === 0 ? false : void 0);
24303
+ return verdicts;
24304
+ }
24305
+ argvOf = new Map(
24306
+ listing.split("\n").flatMap((line) => {
24307
+ const m = /^\s*(\d+)\s(.*)$/.exec(line);
24308
+ return m ? [[Number(m[1]), m[2]]] : [];
24309
+ })
24310
+ );
24311
+ }
24312
+ for (const s of shells) {
24313
+ verdicts.set(s.outputFile, candidates.get(s.outputFile).some((c) => argvOf.get(c.ppid)?.includes(s.sessionId) ?? false));
24314
+ }
24219
24315
  return verdicts;
24220
24316
  }
24221
24317
  function windowsShellHolderCommand(paths, env = process.env) {
@@ -24623,6 +24719,7 @@ function trackLaunchResults(state, rec) {
24623
24719
  }
24624
24720
  if (!entry.outputFile) entry.outputFile = launchOutputFile(state, text2);
24625
24721
  if (!entry.taskId) entry.taskId = launchTaskId(text2);
24722
+ if (entry.kind === "shell" && !entry.ackAt && typeof rec.timestamp === "string") entry.ackAt = rec.timestamp;
24626
24723
  if (LAUNCH_ACK_RE.test(text2)) continue;
24627
24724
  if (entry.kind === "shell") {
24628
24725
  state.subAgents.delete(id2);
@@ -25341,7 +25438,7 @@ function createTailer(deps) {
25341
25438
  for (const e14 of state.subAgents.values()) {
25342
25439
  if (e14.kind !== "shell") continue;
25343
25440
  const lastActivityAt = entryLastActivity(state, e14);
25344
- const shellState = shellIsGone(e14) ? "stale" : "running";
25441
+ const shellState = shellIsGone(e14, state.sessionId) ? "stale" : "running";
25345
25442
  out.push({ label: e14.label, startedAt: e14.startedAt, state: shellState, id: e14.toolUseId, ...e14.taskId ? { stoppable: true, taskId: e14.taskId } : {}, ...lastActivityAt ? { lastActivityAt } : {}, ...e14.monitor ? { outputUnavailable: true } : {} });
25346
25443
  }
25347
25444
  return out;
@@ -25588,7 +25685,7 @@ ${ask}`;
25588
25685
  return void 0;
25589
25686
  }
25590
25687
  const shellAliveCache = /* @__PURE__ */ new Map();
25591
- const shellProbeWanted = /* @__PURE__ */ new Set();
25688
+ const shellProbeWanted = /* @__PURE__ */ new Map();
25592
25689
  let shellProbeInFlight = false;
25593
25690
  let shellProbeArmed;
25594
25691
  function armShellProbeFlush() {
@@ -25601,7 +25698,7 @@ ${ask}`;
25601
25698
  }
25602
25699
  function flushShellProbes() {
25603
25700
  if (shellProbeInFlight || shellProbeWanted.size === 0) return;
25604
- const batch = [...shellProbeWanted];
25701
+ const batch = [...shellProbeWanted.values()];
25605
25702
  shellProbeWanted.clear();
25606
25703
  shellProbeInFlight = true;
25607
25704
  void probeShellsAlive(batch).then((verdicts) => {
@@ -25615,19 +25712,21 @@ ${ask}`;
25615
25712
  shellProbeInFlight = false;
25616
25713
  });
25617
25714
  }
25618
- function shellIsGone(e14) {
25715
+ function shellIsGone(e14, sessionId) {
25619
25716
  if (!e14.outputFile) return false;
25620
25717
  const started = Date.parse(e14.startedAt);
25621
25718
  if (!Number.isFinite(started) || now() - started < SHELL_PROBE_GRACE_MS) return false;
25622
25719
  const cached2 = shellAliveCache.get(e14.outputFile);
25623
25720
  if (cached2 && (cached2.alive === false || now() - cached2.at < SHELL_PROBE_TTL_MS)) return !cached2.alive;
25721
+ const acked = e14.ackAt ? Date.parse(e14.ackAt) : NaN;
25722
+ const launch = { outputFile: e14.outputFile, sessionId, launchedAtMs: started, ...Number.isFinite(acked) ? { ackedAtMs: acked } : {} };
25624
25723
  if (deps.shellAlive) {
25625
- const alive = deps.shellAlive(e14.outputFile);
25724
+ const alive = deps.shellAlive(e14.outputFile, launch);
25626
25725
  if (alive === void 0) return false;
25627
25726
  shellAliveCache.set(e14.outputFile, { at: now(), alive });
25628
25727
  return !alive;
25629
25728
  }
25630
- shellProbeWanted.add(e14.outputFile);
25729
+ shellProbeWanted.set(e14.outputFile, launch);
25631
25730
  armShellProbeFlush();
25632
25731
  return false;
25633
25732
  }
@@ -36533,7 +36632,7 @@ function readAwaitingPark(hints) {
36533
36632
  forMs = parseAwaitingDurationRaw(value);
36534
36633
  }
36535
36634
  }
36536
- return { items, forMs, steps: awaitingSteps(hints) };
36635
+ return { items, forMs, steps: awaitingSteps(hints), questions: awaitingQuestions(hints) };
36537
36636
  }
36538
36637
  function liveActivityOf(tele, registeredPrWatches, armedTimerIds, registeredIssueWatches = /* @__PURE__ */ new Set()) {
36539
36638
  const shells = /* @__PURE__ */ new Set();
@@ -36563,11 +36662,14 @@ function liveKey(i) {
36563
36662
  return i.value;
36564
36663
  }
36565
36664
  function parkIsHonoured(park, live) {
36566
- const onHuman = park.steps.length > 0;
36665
+ const onHuman = parkOnHuman(park);
36567
36666
  if (park.items.length === 0 && !onHuman) return false;
36568
36667
  if (park.forMs === null && !onHuman) return false;
36569
36668
  return unaccountedItems(park.items, live).length === 0;
36570
36669
  }
36670
+ function parkOnHuman(park) {
36671
+ return park.steps.length > 0 || park.questions.length > 0;
36672
+ }
36571
36673
  function needsInputParkHolds(hints, live, fenceAtMs, nowMs) {
36572
36674
  if (awaitingNeedsInput(hints) !== false) return false;
36573
36675
  const park = readAwaitingPark(hints);
@@ -36576,7 +36678,7 @@ function needsInputParkHolds(hints, live, fenceAtMs, nowMs) {
36576
36678
  return expiresAt !== null && nowMs < expiresAt;
36577
36679
  }
36578
36680
  function parkForMaxMs(park) {
36579
- if (park.items.length === 0) return park.steps.length > 0 ? PR_WATCH_FOR_MAX_MS : AWAITING_FOR_MAX_MS;
36681
+ if (park.items.length === 0) return parkOnHuman(park) ? PR_WATCH_FOR_MAX_MS : AWAITING_FOR_MAX_MS;
36580
36682
  return park.items.every((i) => i.kind === "pr" || i.kind === "issue") ? PR_WATCH_FOR_MAX_MS : AWAITING_FOR_MAX_MS;
36581
36683
  }
36582
36684
  function parkExpiresAt(park, fenceAtMs) {
@@ -36905,17 +37007,17 @@ bare rest, and it lands in the human's queue. **A QUESTION HAS NO FENCE ANY MORE
36905
37007
  2026-09-11): the only way to ask is \`mcp__frizz__ask\`, and a question written into a fence's body is
36906
37008
  plain prose \u2014 no card, no answer, and no sign-off.
36907
37009
 
36908
- **AN OPEN QUESTION IS A STANDING SIGN-OFF \u2014 REST NORMALLY.** Any unanswered question counts, not only
36909
- one you registered this turn, and frizz does not bump you for a missing fence while one is open. When
36910
- the work that does not depend on the answer runs out, write your handoff prose and STOP. Nothing you
36911
- write makes the card appear or hides it \u2014 frizz draws every open question at the rest it was asked,
36912
- until it is answered or withdrawn; your write-up carries the reasoning around the ask, never a copy of
36913
- it (see Questions for the human).
36914
- **And write no \` \`\`\`awaiting \` beside it.** A park cannot take while a question stands \u2014 the thread
36915
- sits in the queue on the question \u2014 so frizz REFUSES that fence and bumps you to rewrite the sign-off
36916
- without it. Name what is still running in the prose (frizz lists every live shell, sub-agent and
36917
- watcher under the prompt box whether or not a fence names it). A question you no longer need answered
36918
- is one you \`unask\`; only then can a park take.
37010
+ **A QUESTION YOU ASK IS THAT REST'S SIGN-OFF \u2014 REST NORMALLY.** Frizz does not bump you for a missing
37011
+ fence at the rest that asked. When the work that does not depend on the answer runs out, write your
37012
+ handoff prose and STOP. Nothing you write makes the card appear or hides it \u2014 frizz draws every open
37013
+ question at the rest it was asked, until it is answered or withdrawn; your write-up carries the
37014
+ reasoning around the ask, never a copy of it (see Questions for the human).
37015
+ **AT EVERY LATER REST, SAY WHERE EACH OLD QUESTION STANDS.** A question still open from an EARLIER rest
37016
+ is not your new rest's sign-off, and frizz does NOT redraw its card under your new handoff \u2014 it stays
37017
+ where you asked it. So a later rest either NAMES each one you still need under \`questions:\` in an
37018
+ \` \`\`\`awaiting \` fence \u2014 its card is then drawn at this rest, under your fence \u2014 or WITHDRAWS it with
37019
+ \`unask\`. A rest that does neither is bumped, and so is any \` \`\`\`awaiting \` fence that leaves an open
37020
+ question out, at whichever rest it lands.
36919
37021
 
36920
37022
  Use at most ONE fenced signal block, at the very END (a question's PLACEMENT marker is not a signal
36921
37023
  block \u2014 see Questions for the human). The fence language is the state; the body is the card the human
@@ -37045,7 +37147,7 @@ exactly ONE of them.
37045
37147
  or with anything but \`true\`/\`false\` \u2014 is not a park: the thread queues and frizz tells you which
37046
37148
  line is missing. And a \`false\` holds only while every name is live and \`for:\` has not run out, so a
37047
37149
  wrong \`false\` cannot hide the thread.
37048
- - **THE FRONTMATTER IS YAML. THE BODY IS MARKDOWN.** Four PLURAL keys taking LISTS (either list form;
37150
+ - **THE FRONTMATTER IS YAML. THE BODY IS MARKDOWN.** The PLURAL keys take LISTS (either list form;
37049
37151
  a single item may be written bare), plus the scalars \`for:\`, \`needs_input:\` and \`title:\`. **NO PROSE ABOVE THE
37050
37152
  \`---\`, EVER** \u2014 a colon or a \` #\` inside a sentence breaks the parse. (The \`title:\` and \`steps:\`
37051
37153
  values are the exceptions: frizz reads them verbatim, so code, \`#391\` and a colon are safe there.) There is no \`reason:\` key any more;
@@ -37102,6 +37204,12 @@ exactly ONE of them.
37102
37204
  \`Done\`, the same as anything they type; anything else they need to tell you \u2014 a step that failed,
37103
37205
  the account they used \u2014 comes as a message of their own. An act is not a decision: never ask
37104
37206
  WHETHER they will do it, and never call \`done\` while it is still owed.
37207
+ - \`questions:\` \u2014 your registered questions you are STILL waiting on, by id: \`questions: [qst_ab12cd34]\`.
37208
+ A fence beside open questions names EVERY one of them \u2014 withdraw any you no longer need with
37209
+ \`mcp__frizz__unask\` first \u2014 or frizz refuses the park and lists what it left out. Each named card is
37210
+ drawn at THIS rest, under your fence; to set it inside your prose instead, add its placement marker
37211
+ (see Questions for the human). Like \`steps:\`, questions name the human as the wait: no other name
37212
+ and no \`for:\` needed, and the thread stays in their queue.
37105
37213
  - **REGISTERING IS NOT PARKING, AND PARKING IS NOT REGISTERING.** Your shells, sub-agents, timers
37106
37214
  and PR watchers are watched AUTOMATICALLY, fence or no fence \u2014 frizz wakes you when one finishes,
37107
37215
  every time. The fence only declares that you have STOPPED, names which of them you stopped for,
@@ -37111,9 +37219,10 @@ exactly ONE of them.
37111
37219
  **A FENCE THAT NAMES NOTHING IS NOT A PARK** \u2014 \`for:\` describes a wait, it is not one \u2014 so
37112
37220
  "waiting on the checks" plus a duration just sits in the queue: REGISTER the PR and name it, and
37113
37221
  if nothing is actually running, end with \`\`\`done or register a question with \`mcp__frizz__ask\`.
37114
- (\`steps:\` count: they name the human.)
37115
- - **WAITING ON A PERSON TO DECIDE IS A REGISTERED QUESTION** \u2014 \`mcp__frizz__ask\`. **WAITING ON ONE
37116
- TO ACT IS \`steps:\`.** There is no human gate, no prose park, and no question fence.
37222
+ (\`steps:\` and \`questions:\` count: they name the human.)
37223
+ - **WAITING ON A PERSON TO DECIDE IS A REGISTERED QUESTION** \u2014 \`mcp__frizz__ask\`, and at each later
37224
+ rest \`questions:\` names the ones you still need. **WAITING ON ONE TO ACT IS \`steps:\`.** There is
37225
+ no human gate, no prose park, and no question fence.
37117
37226
  - **CI, RELEASES, DEPLOYS AND MERGE PROGRESSION ARE AUTOMATABLE \u2014 never \` \`\`\`awaiting \` them
37118
37227
  BLINDLY.** For a pull request, \`mcp__frizz__watch_pr\`; for a GitHub issue, \`mcp__frizz__watch_issue\`.
37119
37228
  For anything else stay ACTIVE: dispatch a sub-agent to own the wait (its return re-invokes you), or
@@ -37309,17 +37418,20 @@ paragraph that sets it up, before the one that says what happens either way:
37309
37418
  Frizz draws the registered card THERE instead of at the tail. Nothing goes in the body: the card comes
37310
37419
  from the ROW, so nothing about the question is ever guessed from prose, and a marker naming no open
37311
37420
  question of yours draws nothing. One marker per question. Placement is OPTIONAL \u2014 a question with no
37312
- marker renders at the tail of the rest, and a handoff that writes no marker loses nothing. Every answer
37313
- of the rest is sent together, with ONE Send button at the tail, wherever the cards sit. (Placement was
37314
- retired 2026-08-30 and restored 2026-09-11 with the free-form fence's retirement: the marker references
37315
- a row, which is exactly what a fence with a body never did.)
37421
+ marker renders at the tail of the rest, and a handoff that writes no marker loses nothing. A marker in
37422
+ a LATER handoff moves the card into it; name the question under \`questions:\` in that rest's fence too,
37423
+ since the marker only places it. Every answer is sent together, whichever card's Send the human
37424
+ presses. (Placement was retired 2026-08-30 and restored 2026-09-11 with the free-form fence's
37425
+ retirement: the marker references a row, which is exactly what a fence with a body never did.)
37316
37426
 
37317
37427
  A question you no longer want answered is not one you leave out of the write-up \u2014 it is one you
37318
37428
  \`unask\`, which is the difference between deciding something yourself and quietly hoping nobody
37319
37429
  answers. Questions asked in one \`ask\` call render together and send as one batch.
37320
37430
 
37321
- **AN OPEN REGISTERED QUESTION IS THE HANDBACK** \u2014 emit no \`done\`/\`awaiting\` fence beside it, and
37322
- write no question fence at all. The answer arrives as your next user message, as its own wake.`;
37431
+ **AN OPEN REGISTERED QUESTION IS THE HANDBACK** \u2014 at the rest that asks it, emit no \`done\` fence
37432
+ beside it and no question fence at all; an \`awaiting\` fence beside it is only for work that is ALSO
37433
+ running, and it names the question under \`questions:\`. The answer arrives as your next user message,
37434
+ as its own wake.`;
37323
37435
  STOP_CRITERION = `## The stop criterion
37324
37436
 
37325
37437
  **COMING TO REST IS A STOP, and it needs the same justification as a question.** The far more common
@@ -37497,8 +37609,9 @@ answering \`needs_input: false\` keeps a rested thread out of the queue \u2014 a
37497
37609
  \`mcp__frizz__watch_pr\`; for a GitHub issue, \`mcp__frizz__watch_issue\`; for anything else dispatch a
37498
37610
  SUB-AGENT to own the wait. It runs the watcher
37499
37611
  to completion in its own foreground and returns the verdict; you stay Active and its return
37500
- re-invokes you. Foreground Bash caps at ~10 min, so a longer wait loops until its terminal
37501
- condition. A helper must not hand back while its own watcher is still live.
37612
+ re-invokes you. A Bash call that names no \`timeout\` moves to the background after a minute, so the
37613
+ watcher names one sized to the wait (up to 24h) and loops until its terminal condition. A helper must
37614
+ not hand back while its own watcher is still live.
37502
37615
  - **Working alongside a process you launched** (dev server, log tail) \u2192 \`Bash\` with
37503
37616
  \`run_in_background: true\`. Never put shell job control (\`&\`, \`nohup \u2026 &\`, \`disown\`) inside the
37504
37617
  command to imitate the native flag: frizz's hook rejects an escaping job, because the process could
@@ -42275,7 +42388,10 @@ function createScheduler(deps) {
42275
42388
  if (tele.apiFault) continue;
42276
42389
  const needsInput = needsInputRequired(row.spawned_at);
42277
42390
  const questionRows = deps.storage.listThreadQuestions(row.slug);
42278
- if (tele.lastFence || tele.pendingQuestion || registeredDoneFence(deps.storage.getThreadDone(row.slug), tele.lastUserAt) !== void 0 || questionRows.some((q10) => q10.state === "open") || answersInFlight(questionRows, tele.lastUserAt, row.recurring_on_rest === 1 && Boolean(row.recurring_prompt?.trim())) !== void 0 || !needsInput && deps.storage.listThreadWatches(row.slug, { armedOnly: true }).length > 0) {
42391
+ const openRows = questionRows.filter((q10) => q10.state === "open");
42392
+ const restFrom = tele.lastUserAt ? Date.parse(tele.lastUserAt) : Number.NEGATIVE_INFINITY;
42393
+ const carried = openRows.filter((q10) => q10.asked_at <= restFrom);
42394
+ if (tele.lastFence || tele.pendingQuestion || registeredDoneFence(deps.storage.getThreadDone(row.slug), tele.lastUserAt) !== void 0 || openRows.length > 0 && carried.length === 0 || answersInFlight(questionRows, tele.lastUserAt, row.recurring_on_rest === 1 && Boolean(row.recurring_prompt?.trim())) !== void 0 || !needsInput && deps.storage.listThreadWatches(row.slug, { armedOnly: true }).length > 0) {
42279
42395
  if ((row.signoff_nudges ?? 0) > 0) deps.storage.resetSignoffNudges(row.slug);
42280
42396
  continue;
42281
42397
  }
@@ -42285,27 +42401,24 @@ function createScheduler(deps) {
42285
42401
  const fenceId = signoffFenceId(spokeAt);
42286
42402
  const deliveryId = wakeDeliveryId(row.slug, row.session_id, fenceId);
42287
42403
  if (outbox.get(deliveryId)) continue;
42404
+ const ops = {
42405
+ shells: (tele.bgShells ?? []).filter((sh2) => sh2.state === "running").map((sh2) => ({ id: sh2.taskId ?? sh2.id, label: sh2.label })),
42406
+ subAgents: (tele.subAgents ?? []).filter((a) => a.state === "running").map((a) => ({ id: a.taskId ?? a.id, label: a.label })),
42407
+ // The other two registries, so the nudge lists EVERY kind an awaiting fence can name rather
42408
+ // than the two the fold happens to know about — a worker told about half its work writes half
42409
+ // a fence, and the half it left out is not what gets it bumped.
42410
+ timers: deps.storage.listThreadTimers(row.slug, { armedOnly: true }).map((t) => ({ id: t.id, label: t.prompt.trim().replace(/\s+/g, " ").slice(0, 80) })),
42411
+ prs: deps.storage.listPrWatches(row.slug, { armedOnly: true }).filter((w) => w.kind !== "issue").map((w) => ({ id: `${w.owner}/${w.repo}#${w.number}`, label: `${w.owner}/${w.repo}#${w.number}` })),
42412
+ issues: deps.storage.listPrWatches(row.slug, { armedOnly: true }).filter((w) => w.kind === "issue").map((w) => ({ id: `${w.owner}/${w.repo}#${w.number}`, label: `${w.owner}/${w.repo}#${w.number}` }))
42413
+ };
42288
42414
  const item = outbox.enqueue({
42289
42415
  id: deliveryId,
42290
42416
  slug: row.slug,
42291
42417
  sessionId: row.session_id,
42292
42418
  fenceId,
42293
42419
  hintKey: SIGNOFF_HINT_KEY,
42294
- // The reminder plus THIS THREAD's live ops and their ids, so the agent can write a correct
42295
- // fence without going looking for an id it cannot see. Shells are named by `taskId` —
42296
- // the handle the runtime actually showed the worker — because that is the string it will
42297
- // naturally reach for, and the one the fence's own integrity check matches on.
42298
- message: withClock(signoffNudgeMessage({
42299
- shells: (tele.bgShells ?? []).filter((sh2) => sh2.state === "running").map((sh2) => ({ id: sh2.taskId ?? sh2.id, label: sh2.label })),
42300
- subAgents: (tele.subAgents ?? []).filter((a) => a.state === "running").map((a) => ({ id: a.taskId ?? a.id, label: a.label })),
42301
- // The other two registries, so the nudge lists EVERY kind an awaiting fence can name rather
42302
- // than the two the fold happens to know about — a worker told about half its work writes half
42303
- // a fence, and the half it left out is not what gets it bumped.
42304
- timers: deps.storage.listThreadTimers(row.slug, { armedOnly: true }).map((t) => ({ id: t.id, label: t.prompt.trim().replace(/\s+/g, " ").slice(0, 80) })),
42305
- prs: deps.storage.listPrWatches(row.slug, { armedOnly: true }).filter((w) => w.kind !== "issue").map((w) => ({ id: `${w.owner}/${w.repo}#${w.number}`, label: `${w.owner}/${w.repo}#${w.number}` })),
42306
- issues: deps.storage.listPrWatches(row.slug, { armedOnly: true }).filter((w) => w.kind === "issue").map((w) => ({ id: `${w.owner}/${w.repo}#${w.number}`, label: `${w.owner}/${w.repo}#${w.number}` }))
42307
- }, needsInput), spokeAt),
42308
- reason: "rested without signing off"
42420
+ message: withClock(carried.length > 0 ? carriedQuestionsNudgeMessage(carried.map((q10) => ({ id: q10.id, question: questionLine(q10.spec) })), ops, needsInput) : signoffNudgeMessage(ops, needsInput), spokeAt),
42421
+ reason: carried.length > 0 ? `rested with ${carried.length} earlier question(s) neither named nor withdrawn` : "rested without signing off"
42309
42422
  }, nowMs).delivery;
42310
42423
  log3(`waker: queued ${row.slug} \u2014 ${item.reason}`);
42311
42424
  checkpoint("after-enqueue", item);
@@ -42330,23 +42443,33 @@ ${wakeTimeHeader(now(), spokeAt)}`;
42330
42443
  if (!spokeAt) continue;
42331
42444
  if (tele.lastUserAt && Date.parse(tele.lastUserAt) >= Date.parse(spokeAt)) continue;
42332
42445
  if (tele.authFault || tele.apiFault) continue;
42333
- const openQuestions = deps.storage.listThreadQuestions(row.slug).filter((q10) => q10.state === "open");
42334
- if (openQuestions.length > 0) {
42446
+ const park = readAwaitingPark(tele.lastFence.hints);
42447
+ const questionRows = deps.storage.listThreadQuestions(row.slug);
42448
+ const openQuestions = questionRows.filter((q10) => q10.state === "open");
42449
+ const named = new Set(park.questions);
42450
+ const unnamed = openQuestions.filter((q10) => !named.has(q10.id.toLowerCase()));
42451
+ const spokeMs = Date.parse(spokeAt);
42452
+ const notOpen = park.questions.filter((id2) => {
42453
+ const q10 = questionRows.find((r) => r.id.toLowerCase() === id2);
42454
+ if (q10?.state === "open") return false;
42455
+ return !q10 || q10.settled_at === null || q10.settled_at <= spokeMs;
42456
+ });
42457
+ if (unnamed.length > 0 || notOpen.length > 0) {
42335
42458
  if ((row.park_bumps ?? 0) >= PARK_BUMP_MAX) continue;
42336
42459
  const fenceId2 = parkFenceId("question", spokeAt);
42337
42460
  const deliveryId2 = wakeDeliveryId(row.slug, row.session_id, fenceId2);
42338
42461
  if (outbox.get(deliveryId2)) continue;
42339
- const one2 = openQuestions.length === 1;
42462
+ const one2 = unnamed.length === 1;
42463
+ const head2 = unnamed.length > 0 ? `${one2 ? "a question of yours was" : `${unnamed.length} questions of yours were`} still OPEN and it does not name ${one2 ? "it" : "them"}, so frizz refused the park.` : `it names ${notOpen.length === 1 ? "a question that is" : "questions that are"} not open, so frizz refused the park.`;
42340
42464
  const message2 = [
42341
- `${PARK_CORRECTION_QUESTION_LEAD}${one2 ? "a question of yours was" : "questions of yours were"} still OPEN, so frizz refused the park \u2014 a question outranks a wait, and this thread sits in the human's queue on ${one2 ? "it" : "them"}.`,
42342
- "",
42343
- ...openQuestions.map((q10) => `- \`${q10.id}\` \u2014 ${questionLine(q10.spec)}`),
42465
+ `${PARK_CORRECTION_QUESTION_LEAD}${head2}`,
42466
+ ...unnamed.length > 0 ? ["", "Open, and not named under `questions:`:", ...unnamed.map((q10) => `- \`${q10.id}\` \u2014 ${questionLine(q10.spec)}`)] : [],
42467
+ ...notOpen.length > 0 ? ["", "Named, but not an open question of yours:", ...notOpen.map((id2) => `- \`${id2}\``)] : [],
42344
42468
  "",
42345
- "Never fence ```awaiting while a question stands. Rewrite your sign-off WITHOUT the fence: your",
42346
- "handoff prose \u2014 each open question draws its own card at that rest, so write the reasoning",
42347
- "around the ask, never the ask again. Your running work is watched and listed either way: a shell, a",
42348
- "sub-agent, a timer or a registered PR wakes you fence or no fence. A question you no longer need",
42349
- "answered is one you withdraw with `mcp__frizz__unask` \u2014 only then can a park take."
42469
+ "A fence beside open questions names EVERY one you still need answered \u2014 `questions: [qst_\u2026]` \u2014",
42470
+ "and you withdraw the rest with `mcp__frizz__unask`. A named question's card is drawn at this rest;",
42471
+ "an unnamed one stays where you asked it. Fix the list (or unask), re-send the fence, and the park",
42472
+ "takes. A fence on questions needs no other name and no `for:`."
42350
42473
  ].join("\n");
42351
42474
  const item2 = outbox.enqueue({
42352
42475
  id: deliveryId2,
@@ -42357,14 +42480,13 @@ ${wakeTimeHeader(now(), spokeAt)}`;
42357
42480
  message: `${message2}
42358
42481
 
42359
42482
  ${wakeTimeHeader(nowMs, spokeAt)}`,
42360
- reason: `awaiting fence beside ${openQuestions.length} open question(s)`
42483
+ reason: `awaiting fence leaves ${unnamed.length} open question(s) unnamed${notOpen.length ? `, names ${notOpen.length} that are not open` : ""}`
42361
42484
  }, nowMs).delivery;
42362
42485
  deps.storage.countParkBump(row.slug, fenceId2);
42363
42486
  log3(`waker: queued ${row.slug} \u2014 ${item2.reason}`);
42364
42487
  checkpoint("after-enqueue", item2);
42365
42488
  continue;
42366
42489
  }
42367
- const park = readAwaitingPark(tele.lastFence.hints);
42368
42490
  const live = liveActivityOf(
42369
42491
  tele,
42370
42492
  registeredPrWatchesOf(deps.storage, row.slug),
@@ -42374,7 +42496,7 @@ ${wakeTimeHeader(nowMs, spokeAt)}`,
42374
42496
  const dead = unaccountedItems(park.items, live);
42375
42497
  const expiresAt = parkExpiresAt(park, Date.parse(spokeAt));
42376
42498
  const expired = expiresAt !== null && nowMs >= expiresAt;
42377
- const nameless = park.items.length === 0 && park.steps.length === 0;
42499
+ const nameless = park.items.length === 0 && !parkOnHuman(park);
42378
42500
  const unanswered2 = needsInputRequired(row.spawned_at) && awaitingNeedsInput(tele.lastFence.hints) === null;
42379
42501
  if (parkIsHonoured(park, live) && !unanswered2 && (row.park_bumps ?? 0) > 0) deps.storage.resetParkBumps(row.slug);
42380
42502
  if (dead.length === 0 && !expired && !nameless) {
@@ -42420,18 +42542,26 @@ ${wakeTimeHeader(nowMs, spokeAt)}`,
42420
42542
  if (a.state !== "rested") continue;
42421
42543
  for (const h10 of [a.taskId, a.id, a.label]) if (h10) finishedHandles.add(h10);
42422
42544
  }
42545
+ const staleShellHandles = /* @__PURE__ */ new Set();
42546
+ for (const sh2 of tele.bgShells ?? []) {
42547
+ if (sh2.state !== "stale") continue;
42548
+ for (const h10 of [sh2.taskId, sh2.id, sh2.label]) if (h10) staleShellHandles.add(h10);
42549
+ }
42423
42550
  const firedTimers = new Set(
42424
42551
  deps.storage.listThreadTimers(row.slug).filter((t) => t.state === "fired").map((t) => t.id)
42425
42552
  );
42426
42553
  const finishedItem = (i) => finishedHandles.has(i.value) || i.kind === "timer" && firedTimers.has(i.value);
42427
42554
  const status = park.items.map((i) => {
42428
42555
  const gone = dead.some((d) => d.kind === i.kind && d.value === i.value);
42429
- const note = !gone ? "still running" : i.kind === "timer" && firedTimers.has(i.value) ? "already FIRED \u2014 its wake was delivered; there is nothing left to wait on" : finishedItem(i) ? "FINISHED \u2014 its result is waiting for you" : i.kind === "pr" ? "NOT REGISTERED \u2014 register it with `mcp__frizz__watch_pr` first, then name it here" : i.kind === "issue" ? "NOT REGISTERED \u2014 register it with `mcp__frizz__watch_issue` first, then name it here" : "NOT RUNNING (nothing by that name)";
42556
+ const note = !gone ? "still running" : i.kind === "timer" && firedTimers.has(i.value) ? "already FIRED \u2014 its wake was delivered; there is nothing left to wait on" : finishedItem(i) ? "FINISHED \u2014 its result is waiting for you" : i.kind === "shell" && staleShellHandles.has(i.value) ? "GONE WITHOUT A COMPLETION NOTICE \u2014 frizz knows this shell, but nothing holds its output file and no process it could be is still running; read its output to see how it ended" : i.kind === "pr" ? "NOT REGISTERED \u2014 register it with `mcp__frizz__watch_pr` first, then name it here" : i.kind === "issue" ? "NOT REGISTERED \u2014 register it with `mcp__frizz__watch_issue` first, then name it here" : "NOT RUNNING (nothing by that name)";
42430
42557
  return `- \`${AWAITING_KEY_OF[i.kind]}: [${i.value}]\` \u2014 ${note}`;
42431
42558
  });
42432
42559
  if (park.steps.length > 0) {
42433
42560
  status.push(`- \`steps:\` (${park.steps.length}) \u2014 the human has not replied; check whether they were done anyway before you post them again`);
42434
42561
  }
42562
+ if (park.questions.length > 0) {
42563
+ status.push(`- \`questions:\` (${park.questions.length}) \u2014 not answered yet; name the ones you still need in your next fence and withdraw the rest`);
42564
+ }
42435
42565
  const allFinished = dead.length > 0 && dead.every(finishedItem);
42436
42566
  const retired = retiredAwaitingKindsIn(tele.lastFence.body ?? "");
42437
42567
  const head = retired.length > 0 ? [
@@ -75367,6 +75497,16 @@ function claudeSidechainInstruction(text2) {
75367
75497
  if (wrapperStart < 0 || wrapperEnd < 0) return void 0;
75368
75498
  return parseAgentMessage(trimmed.slice(wrapperStart, wrapperEnd + "</agent-message>".length))?.body.trim() || void 0;
75369
75499
  }
75500
+ function blockedInCallSince(messages) {
75501
+ for (let i = messages.length - 1; i >= 0; i--) {
75502
+ const m = messages[i];
75503
+ if (m.queued || m.kind === "event") continue;
75504
+ if (m.role !== "assistant" || !m.tools.some((t) => t.status === "pending" && !t.backgroundState)) return void 0;
75505
+ const at2 = m.at === void 0 ? NaN : Date.parse(m.at);
75506
+ return Number.isFinite(at2) ? at2 : void 0;
75507
+ }
75508
+ return void 0;
75509
+ }
75370
75510
  function retireStaleQueuedBubbles(messages, nowMs = Date.now()) {
75371
75511
  let stale = false;
75372
75512
  for (const m of messages) {
@@ -75378,10 +75518,13 @@ function retireStaleQueuedBubbles(messages, nowMs = Date.now()) {
75378
75518
  }
75379
75519
  }
75380
75520
  if (!stale) return messages;
75521
+ const blockedSince = blockedInCallSince(messages);
75381
75522
  return messages.map((m) => {
75382
75523
  if (!m.queued) return m;
75383
75524
  const at2 = m.at === void 0 ? NaN : Date.parse(m.at);
75384
- return Number.isFinite(at2) && nowMs - at2 > QUEUED_STALE_MS ? { ...m, queued: false } : m;
75525
+ if (!(Number.isFinite(at2) && nowMs - at2 > QUEUED_STALE_MS)) return m;
75526
+ if (blockedSince !== void 0 && blockedSince <= at2 && nowMs - at2 <= QUEUED_BLOCKED_CEILING_MS) return m;
75527
+ return { ...m, queued: false };
75385
75528
  });
75386
75529
  }
75387
75530
  function createTranscriptFold(identityPrefix = "claude") {
@@ -77752,11 +77895,12 @@ function readTranscriptFile(absPath) {
77752
77895
  return [];
77753
77896
  }
77754
77897
  }
77755
- var MAX_MESSAGES, LATEST_WINDOW_ASK_REACH_ITEMS, LATEST_WINDOW_ASK_REACH_BYTES, LATEST_WINDOW_MAX_BYTES, REST_LABEL, LEGACY_TASK_MARKER, LEGACY_BANNER_PREAMBLE, COMMAND_NAME_RE, COMMAND_ARGS_RE, LOCAL_COMMAND_RECEIPT2, PEER_SESSION_PREAMBLE, CLAUDE_COORDINATOR_INSTRUCTION_PREFIX, CLAUDE_COORDINATOR_INSTRUCTION_SUFFIX, CLAUDE_PEER_INSTRUCTION_PREFIX, QUEUED_STALE_MS, EDIT_CAP, TRUNC_MARKER, AGENT_PROMPT_CAP, SEND_BODY_CAP, COMMAND_CAP, TOOL_INPUT_CAP, READ_LINE_CAP, READ_BYTE_CAP, IMAGE_MEDIA_EXT, SCREENSHOT_CACHE_DIR, SCREENSHOT_CACHE_MAX, SCREENSHOT_MAX_BASE64, screenshotTmpSeq, SENT_IMAGE_MAX_BYTES, SENT_FILES_MAX, TODO_ROWS_MAX, TODO_TEXT_CAP, TRANSCRIPT_CACHE_CAP, transcriptCache, PARSE_VERIFY_SAMPLE, TRANSCRIPT_DECODE_WINDOW, FOREIGN_SESSION_ID_RE, MAX_PINNED_BACKGROUND_OPERATIONS, CAPTION_MAX, _defaultCodexBackend, TRANSCRIPT_EARLIER_MAX_ITEMS, TRANSCRIPT_EARLIER_MAX_BYTES, fullDigestCache, FULL_DIGEST_CACHE_CAP, EMPTY_RETIRED_OPS;
77898
+ var MAX_MESSAGES, LATEST_WINDOW_ASK_REACH_ITEMS, LATEST_WINDOW_ASK_REACH_BYTES, LATEST_WINDOW_MAX_BYTES, REST_LABEL, LEGACY_TASK_MARKER, LEGACY_BANNER_PREAMBLE, COMMAND_NAME_RE, COMMAND_ARGS_RE, LOCAL_COMMAND_RECEIPT2, PEER_SESSION_PREAMBLE, CLAUDE_COORDINATOR_INSTRUCTION_PREFIX, CLAUDE_COORDINATOR_INSTRUCTION_SUFFIX, CLAUDE_PEER_INSTRUCTION_PREFIX, QUEUED_STALE_MS, QUEUED_BLOCKED_CEILING_MS, EDIT_CAP, TRUNC_MARKER, AGENT_PROMPT_CAP, SEND_BODY_CAP, COMMAND_CAP, TOOL_INPUT_CAP, READ_LINE_CAP, READ_BYTE_CAP, IMAGE_MEDIA_EXT, SCREENSHOT_CACHE_DIR, SCREENSHOT_CACHE_MAX, SCREENSHOT_MAX_BASE64, screenshotTmpSeq, SENT_IMAGE_MAX_BYTES, SENT_FILES_MAX, TODO_ROWS_MAX, TODO_TEXT_CAP, TRANSCRIPT_CACHE_CAP, transcriptCache, PARSE_VERIFY_SAMPLE, TRANSCRIPT_DECODE_WINDOW, FOREIGN_SESSION_ID_RE, MAX_PINNED_BACKGROUND_OPERATIONS, CAPTION_MAX, _defaultCodexBackend, TRANSCRIPT_EARLIER_MAX_ITEMS, TRANSCRIPT_EARLIER_MAX_BYTES, fullDigestCache, FULL_DIGEST_CACHE_CAP, EMPTY_RETIRED_OPS;
77756
77899
  var init_transcript = __esm({
77757
77900
  "packages/server/src/transcript.ts"() {
77758
77901
  "use strict";
77759
77902
  init_src();
77903
+ init_types2();
77760
77904
  init_delivery_ledger();
77761
77905
  init_edited_files();
77762
77906
  init_repo_files();
@@ -77785,6 +77929,7 @@ var init_transcript = __esm({
77785
77929
  CLAUDE_COORDINATOR_INSTRUCTION_SUFFIX = "\n\nAddress this before completing your current task.";
77786
77930
  CLAUDE_PEER_INSTRUCTION_PREFIX = "Another Claude session sent a message while you were working:\n";
77787
77931
  QUEUED_STALE_MS = 2 * 60 * 6e4;
77932
+ QUEUED_BLOCKED_CEILING_MS = Number(CLAUDE_WORKER_ENV.BASH_MAX_TIMEOUT_MS);
77788
77933
  EDIT_CAP = 4e3;
77789
77934
  TRUNC_MARKER = "\n\u2026 (truncated)";
77790
77935
  AGENT_PROMPT_CAP = 4e3;
@@ -79177,7 +79322,8 @@ function createRouter(ctx) {
79177
79322
  if (!info) return blocked(null);
79178
79323
  const shell = ctx.tailer.backgroundShell?.(slug, id2);
79179
79324
  const noun = shell ? "background shell" : "sub-agent";
79180
- if (!(shell ? shell.state === "running" : info.state === "running")) return blocked(null);
79325
+ const shellGone = shell !== void 0 && ctx.tailer.get(slug)?.bgShells?.find((s) => s.id === id2)?.state === "stale";
79326
+ if (!(shell ? shell.state === "running" && !shellGone : info.state === "running")) return blocked(null);
79181
79327
  const row = ctx.storage.getSession(slug);
79182
79328
  if (!row) return blocked(null);
79183
79329
  if (row.backend === "codex") {