frizz 0.12.3 → 0.12.5

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 (90) hide show
  1. package/dist/dev-child.js +378 -158
  2. package/dist/frizz.js +10 -1
  3. package/package.json +1 -1
  4. package/web-dist/assets/{TerminalPane-D5Tx2hu9.js → TerminalPane-PMq5oyOr.js} +1 -1
  5. package/web-dist/assets/{abnfDiagram-VRR7QNED-BO0tgRMu.js → abnfDiagram-VRR7QNED-Buzu9wC_.js} +1 -1
  6. package/web-dist/assets/architecture-TIHT7OUA-BA7zvXi9.js +1 -0
  7. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-TCJFLj-i.js → architectureDiagram-ZJ3FMSHR-D02SYSuj.js} +1 -1
  8. package/web-dist/assets/{blockDiagram-677ZJIJ3-BRd9xJTz.js → blockDiagram-677ZJIJ3-BrvpZDHp.js} +1 -1
  9. package/web-dist/assets/{c4Diagram-LMCZKHZV-BxlNYwY8.js → c4Diagram-LMCZKHZV-B-0cp5_F.js} +1 -1
  10. package/web-dist/assets/channel-DpG-J81n.js +1 -0
  11. package/web-dist/assets/{chunk-32BRIVSS-o0wtC3P5.js → chunk-32BRIVSS-DIhtnTI3.js} +1 -1
  12. package/web-dist/assets/{chunk-52WLFC77-C_bt24w7.js → chunk-52WLFC77-BDsrIC5O.js} +1 -1
  13. package/web-dist/assets/{chunk-C7G6YPKG-DlsBv-nI.js → chunk-C7G6YPKG-Dvi27VdS.js} +1 -1
  14. package/web-dist/assets/{chunk-EX3LRPZG-Y_Debiw-.js → chunk-EX3LRPZG-D5l4eCPE.js} +1 -1
  15. package/web-dist/assets/{chunk-FWX5IMBZ-D_9nCJ43.js → chunk-FWX5IMBZ-NQ92LXeo.js} +2 -2
  16. package/web-dist/assets/{chunk-HOUHSVGY-Bzhu2UoJ.js → chunk-HOUHSVGY-nsgiwhWv.js} +1 -1
  17. package/web-dist/assets/{chunk-ICXQ74PX-CwJVbXqL.js → chunk-ICXQ74PX-DE0wby7_.js} +1 -1
  18. package/web-dist/assets/{chunk-MOJQB5TN-DPm_X7tz.js → chunk-MOJQB5TN-BX7BpiS0.js} +1 -1
  19. package/web-dist/assets/{chunk-OGEWGWER-1m3zk2ed.js → chunk-OGEWGWER-Bv41bF82.js} +1 -1
  20. package/web-dist/assets/{chunk-PUDLZKDR-D2Bnu5zc.js → chunk-PUDLZKDR-B60KaMhk.js} +1 -1
  21. package/web-dist/assets/{chunk-Q4XR5HBZ-DJZtjVxI.js → chunk-Q4XR5HBZ-CV-8_gBi.js} +1 -1
  22. package/web-dist/assets/{chunk-V7JOEXUC-BQVKbxnn.js → chunk-V7JOEXUC-DP_fCRpB.js} +1 -1
  23. package/web-dist/assets/{chunk-VAUOI2AC-TwOgVbMm.js → chunk-VAUOI2AC-BG-Cmv38.js} +1 -1
  24. package/web-dist/assets/{chunk-VR4S4FIN-DlG1lzSj.js → chunk-VR4S4FIN-hvR8qINa.js} +1 -1
  25. package/web-dist/assets/{chunk-WYO6CB5R-Ckk8qoao.js → chunk-WYO6CB5R-Bcwb5mAM.js} +1 -1
  26. package/web-dist/assets/{chunk-ZGVPDNZ5-CZxmPZzT.js → chunk-ZGVPDNZ5-BotZNl6-.js} +1 -1
  27. package/web-dist/assets/classDiagram-OUVF2IWQ-BtWQH2f8.js +1 -0
  28. package/web-dist/assets/classDiagram-v2-EOCWNBFH-BtWQH2f8.js +1 -0
  29. package/web-dist/assets/{cynefin-VYW2F7L2-CioP0cgr.js → cynefin-VYW2F7L2-CyOxl50N.js} +1 -1
  30. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-BJZpJw_3.js → cynefinDiagram-TSTJHNR4-DkIgD3tV.js} +1 -1
  31. package/web-dist/assets/{dagre-VKFMJZFB-BGv33WEE.js → dagre-VKFMJZFB-Bft-Uqug.js} +1 -1
  32. package/web-dist/assets/{diagram-FQU43EPY-CvhxVWTl.js → diagram-FQU43EPY-CHOHuWxY.js} +1 -1
  33. package/web-dist/assets/{diagram-G47NLZAW-DnrPOeE0.js → diagram-G47NLZAW-Br6RKCjL.js} +1 -1
  34. package/web-dist/assets/{diagram-NH7WQ7WH-CazuXXkX.js → diagram-NH7WQ7WH-yB6WZ2Z_.js} +1 -1
  35. package/web-dist/assets/{diagram-OA4YK3LP-DfbFhbQs.js → diagram-OA4YK3LP-D5c8OQKK.js} +1 -1
  36. package/web-dist/assets/{diagram-WEI45ONY-BESpc3Oj.js → diagram-WEI45ONY-B2VsIZfh.js} +1 -1
  37. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-C6h37W51.js → ebnfDiagram-CCIWWBDH-zCELOOIj.js} +1 -1
  38. package/web-dist/assets/{erDiagram-Q63AITRT-vCxGREHo.js → erDiagram-Q63AITRT-PiVO0dn6.js} +1 -1
  39. package/web-dist/assets/eventmodeling-45OFAUF4-B5mW3Fg6.js +1 -0
  40. package/web-dist/assets/flowDiagram-23GEKE2U-DUzaEkcD.js +1 -0
  41. package/web-dist/assets/{ganttDiagram-NO4QXBWP-B5l9XyZe.js → ganttDiagram-NO4QXBWP-DV7ZZP3p.js} +1 -1
  42. package/web-dist/assets/{gitGraph-TEB2WS4Q-CQpssLnk.js → gitGraph-TEB2WS4Q-DFTA_fK1.js} +1 -1
  43. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-j95eUOjO.js → gitGraphDiagram-IHSO6WYX-OVJu-b5a.js} +1 -1
  44. package/web-dist/assets/{index-Dzq6GPUo.js → index-C2rIimvp.js} +92 -92
  45. package/web-dist/assets/{info-DKCQHKI2-CiW0hhEI.js → info-DKCQHKI2-C06Wjqu-.js} +1 -1
  46. package/web-dist/assets/{infoDiagram-FWYZ7A6U-BJwJPEq2.js → infoDiagram-FWYZ7A6U-DwqIxBIw.js} +1 -1
  47. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-Ck4D0hT_.js → ishikawaDiagram-FXEZZL3T-GLlaEA8x.js} +1 -1
  48. package/web-dist/assets/{journeyDiagram-5HDEW3XC-Bz8PK7lM.js → journeyDiagram-5HDEW3XC-BtPio3yW.js} +1 -1
  49. package/web-dist/assets/{kanban-definition-HUTT4EX6-Kqt3cah4.js → kanban-definition-HUTT4EX6-DplkqhKW.js} +1 -1
  50. package/web-dist/assets/{line-Dl7tIumR.js → line-kSkAw79f.js} +1 -1
  51. package/web-dist/assets/{mermaid-parser.core-C_aHybiE.js → mermaid-parser.core-Ds2HoE58.js} +3 -3
  52. package/web-dist/assets/{mermaid.core-Dv6lgZxU.js → mermaid.core-CuxdqC2S.js} +3 -3
  53. package/web-dist/assets/{mindmap-definition-LN4V7U3C-EkN_2bUd.js → mindmap-definition-LN4V7U3C-BDh65Pp4.js} +1 -1
  54. package/web-dist/assets/{packet-7NZHBO7P-LL-j9b42.js → packet-7NZHBO7P-CeKDY8cM.js} +1 -1
  55. package/web-dist/assets/{pegDiagram-2B236MQR-CrNUBIKh.js → pegDiagram-2B236MQR-Ynedj-CN.js} +1 -1
  56. package/web-dist/assets/{pie-RZYD4A2V-8wZ8AyeT.js → pie-RZYD4A2V-oPE5BxF3.js} +1 -1
  57. package/web-dist/assets/{pieDiagram-ENE6RG2P-BSUUt2Vt.js → pieDiagram-ENE6RG2P-BJdzHH98.js} +1 -1
  58. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-BmRRE-b9.js → quadrantDiagram-ABIIQ3AL-BGCH-Lqc.js} +1 -1
  59. package/web-dist/assets/{radar-I7S5WNFK-BZ8i3wPh.js → radar-I7S5WNFK-CIj2i3bC.js} +1 -1
  60. package/web-dist/assets/{railroad-3IZDKUUU-Bvq-p3jW.js → railroad-3IZDKUUU-sYkCdkuK.js} +1 -1
  61. package/web-dist/assets/railroad-abnf-AHOZXSZD-Doy_kNvp.js +1 -0
  62. package/web-dist/assets/railroad-ebnf-EBAXGLYW-BBq_aMtI.js +1 -0
  63. package/web-dist/assets/railroad-peg-LSFZ7HO6-DRmnTreC.js +1 -0
  64. package/web-dist/assets/{railroadDiagram-RFXS5EU6-CH0DOBjJ.js → railroadDiagram-RFXS5EU6-AhZXW611.js} +1 -1
  65. package/web-dist/assets/{requirementDiagram-TGXJPOKE-ytS-raWw.js → requirementDiagram-TGXJPOKE-prk9Slgr.js} +1 -1
  66. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-BU49ulmu.js → sankeyDiagram-HTMAVEWB-SCoBTH2A.js} +1 -1
  67. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-C1edCLps.js → sequenceDiagram-DBY2YBRQ-BrGw3SSP.js} +1 -1
  68. package/web-dist/assets/{stateDiagram-2N3HPSRC-C049S4Yj.js → stateDiagram-2N3HPSRC-CLd9B67a.js} +1 -1
  69. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-I87khM0f.js +1 -0
  70. package/web-dist/assets/{swimlanes-5IMT3BWC-KNWNnFDx.js → swimlanes-5IMT3BWC-CSj8B56G.js} +1 -1
  71. package/web-dist/assets/swimlanesDiagram-G3AALYLV-CTyGaVXS.js +8 -0
  72. package/web-dist/assets/{timeline-definition-FHXFAJF6-D8Z-Q8JO.js → timeline-definition-FHXFAJF6-Nwo-Ei0t.js} +1 -1
  73. package/web-dist/assets/{treeView-QDETBFTQ-CvyDkH5p.js → treeView-QDETBFTQ-DOdXAE02.js} +1 -1
  74. package/web-dist/assets/{treemap-6X3UGDF4-COwCP95k.js → treemap-6X3UGDF4-iLXYkTae.js} +1 -1
  75. package/web-dist/assets/{vennDiagram-L72KCM5P-DHKE_6N3.js → vennDiagram-L72KCM5P-DeaMbppe.js} +1 -1
  76. package/web-dist/assets/{wardley-OPB4EBWU-CYWcYdsx.js → wardley-OPB4EBWU-Dua8Pcgn.js} +1 -1
  77. package/web-dist/assets/{wardleyDiagram-EHGQE667-BS3OkOU_.js → wardleyDiagram-EHGQE667-DdoJgL5e.js} +1 -1
  78. package/web-dist/assets/{xychartDiagram-FW5EYKEG-Df4GdNEo.js → xychartDiagram-FW5EYKEG-BWpJEQki.js} +1 -1
  79. package/web-dist/index.html +1 -1
  80. package/web-dist/assets/architecture-TIHT7OUA-lCPPJORL.js +0 -1
  81. package/web-dist/assets/channel-tGE7Gbbs.js +0 -1
  82. package/web-dist/assets/classDiagram-OUVF2IWQ-CQo4x1hj.js +0 -1
  83. package/web-dist/assets/classDiagram-v2-EOCWNBFH-CQo4x1hj.js +0 -1
  84. package/web-dist/assets/eventmodeling-45OFAUF4-C517fJsQ.js +0 -1
  85. package/web-dist/assets/flowDiagram-23GEKE2U-IrjbjjxF.js +0 -1
  86. package/web-dist/assets/railroad-abnf-AHOZXSZD-DIZeZa-B.js +0 -1
  87. package/web-dist/assets/railroad-ebnf-EBAXGLYW-DVn3xHNX.js +0 -1
  88. package/web-dist/assets/railroad-peg-LSFZ7HO6-BvLcJu_d.js +0 -1
  89. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-D-Et-Cj1.js +0 -1
  90. package/web-dist/assets/swimlanesDiagram-G3AALYLV-DQNRnHXT.js +0 -8
package/dist/dev-child.js CHANGED
@@ -13671,7 +13671,7 @@ function parseGithubWakeSteer(text2) {
13671
13671
  function frizzRoute(path3) {
13672
13672
  return `${FRIZZ_ROUTE_PREFIX}${path3.startsWith("/") ? path3 : `/${path3}`}`;
13673
13673
  }
13674
- 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, 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_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, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, PARK_CORRECTION_NAMES_LEAD, PARK_CORRECTION_RETIRED_LEAD, PARK_CORRECTION_QUESTION_LEAD, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, 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, AskQuestionKind, ASK_MAX_DEPTH, AskedOptionSchema, AskedQuestionSchema, AskInput, RegisteredQuestionView, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, BURIED_ANSWERS_HEADER, ANSWER_FOLLOW_UP_MARKER, DISMISSED_ANSWER, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountLogoutInput, AccountLogoutResult, AccountLoginStartInput, AccountLoginStartResult, AccountLoginStatusInput, AccountLoginStatusResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, 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, 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, PROJECT_ICON_EXTENSIONS, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT, threadIdentityName;
13674
+ 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, 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_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, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, PARK_CORRECTION_NAMES_LEAD, PARK_CORRECTION_RETIRED_LEAD, PARK_CORRECTION_QUESTION_LEAD, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, 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, AskQuestionKind, ASK_MAX_DEPTH, AskedOptionSchema, AskedQuestionSchema, AskInput, RegisteredQuestionView, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, BURIED_ANSWERS_HEADER, ANSWER_FOLLOW_UP_MARKER, DISMISSED_ANSWER, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ProviderError, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountLogoutInput, AccountLogoutResult, AccountLoginStartInput, AccountLoginStartResult, AccountLoginStatusInput, AccountLoginStatusResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, 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, 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, PROJECT_ICON_EXTENSIONS, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT, threadIdentityName;
13675
13675
  var init_src = __esm({
13676
13676
  "packages/shared/src/index.ts"() {
13677
13677
  "use strict";
@@ -14429,6 +14429,13 @@ var init_src = __esm({
14429
14429
  // setting is off, the instant is unresolvable, or the pause is too old to safely resume.
14430
14430
  autoResume: external_exports.boolean()
14431
14431
  });
14432
+ ProviderError = external_exports.object({
14433
+ message: external_exports.string(),
14434
+ code: external_exports.string().optional(),
14435
+ details: external_exports.string().optional(),
14436
+ retrying: external_exports.boolean().optional(),
14437
+ at: external_exports.string().optional()
14438
+ });
14432
14439
  ThreadView = external_exports.object({
14433
14440
  id: ThreadSlug,
14434
14441
  // slug; filename is <slug>.md
@@ -14539,6 +14546,7 @@ var init_src = __esm({
14539
14546
  // is to WAIT and continue — not to sign in. Same discipline as providerFault: only typed data
14540
14547
  // travels, never the provider's own error text. Optional so old snapshots/servers parse.
14541
14548
  limitPause: LimitPause.optional(),
14549
+ providerError: ProviderError.optional(),
14542
14550
  // ---- Session-first fields (ALL optional: absent ⇒ a legacy .frizz-file row / pre-restart server;
14543
14551
  // the client treats such rows as Legacy-shelf material). Deliberately not zod-defaulted so server
14544
14552
  // constructors that predate the model still typecheck and old snapshots parse unchanged. ----
@@ -15498,6 +15506,7 @@ ${DISPATCH_TASK_BANNER}
15498
15506
  // search, and transcript logic; shared chat surfaces use this compact form for generated prompts
15499
15507
  // whose machine-facing tail would otherwise dominate the first user bubble.
15500
15508
  displayText: external_exports.string().optional(),
15509
+ providerError: ProviderError.optional(),
15501
15510
  tools: external_exports.array(TranscriptToolCall),
15502
15511
  at: external_exports.string().optional(),
15503
15512
  // ISO8601
@@ -20752,6 +20761,180 @@ var init_dispatch_preferences = __esm({
20752
20761
  }
20753
20762
  });
20754
20763
 
20764
+ // packages/server/src/credential-redaction.ts
20765
+ function replacement(options, secretToken) {
20766
+ const configured = options.replacement ?? DEFAULT_REPLACEMENT;
20767
+ return typeof configured === "function" ? configured(secretToken) : configured;
20768
+ }
20769
+ function unquote(raw2) {
20770
+ return raw2.length >= 2 && (raw2[0] === '"' || raw2[0] === "'") && raw2.at(-1) === raw2[0] ? raw2.slice(1, -1) : raw2;
20771
+ }
20772
+ function userInfoParts(raw2) {
20773
+ const value = unquote(raw2);
20774
+ const literal = value.indexOf(":");
20775
+ const encodedMatch = /%3a/iu.exec(value);
20776
+ const encoded = encodedMatch?.index ?? -1;
20777
+ const index = literal === -1 ? encoded : encoded === -1 ? literal : Math.min(literal, encoded);
20778
+ if (index <= 0) return null;
20779
+ const delimiter2 = value.slice(index, index + (index === encoded ? 3 : 1));
20780
+ return { username: value.slice(0, index), delimiter: delimiter2, password: value.slice(index + delimiter2.length) };
20781
+ }
20782
+ function redactUserInfoToken(raw2, options) {
20783
+ const parts = userInfoParts(raw2);
20784
+ if (!parts) return null;
20785
+ return `${parts.username}${parts.delimiter}${replacement(options, parts.password)}`;
20786
+ }
20787
+ function hasCurlCommandContext(source, offset) {
20788
+ const bounded = source.slice(Math.max(0, offset - 1024), offset);
20789
+ const separator = Math.max(
20790
+ bounded.lastIndexOf("\n"),
20791
+ bounded.lastIndexOf("\r"),
20792
+ bounded.lastIndexOf(";"),
20793
+ bounded.lastIndexOf("&"),
20794
+ bounded.lastIndexOf("|")
20795
+ );
20796
+ const segment = bounded.slice(separator + 1);
20797
+ return segment.split(/[ \t]+/u).some((token) => CURL_EXECUTABLE_RE.test(unquote(token)));
20798
+ }
20799
+ function redactCredentialSyntax(raw2, options = {}) {
20800
+ let value = raw2;
20801
+ value = value.replace(
20802
+ URL_USERINFO_RE,
20803
+ (_whole, scheme, username, delimiter2, password) => `${scheme}${username}${delimiter2}${replacement(options, password)}@`
20804
+ );
20805
+ value = value.replace(
20806
+ URL_ENCODED_USERINFO_RE,
20807
+ (_whole, scheme, username, delimiter2, password) => `${scheme}${username}${delimiter2}${replacement(options, password)}@`
20808
+ );
20809
+ value = value.replace(
20810
+ USER_FLAG_RE,
20811
+ (whole, boundary, flag, separator, userInfo, offset, source) => {
20812
+ if (unquote(flag).toLowerCase() === "-u" && !hasCurlCommandContext(source, offset)) return whole;
20813
+ const safe = redactUserInfoToken(userInfo, options);
20814
+ return safe === null ? whole : `${boundary}${flag}${separator}${safe}`;
20815
+ }
20816
+ );
20817
+ value = value.replace(
20818
+ ATTACHED_USER_FLAG_RE,
20819
+ (whole, boundary, flag, userInfo, offset, source) => {
20820
+ if (!hasCurlCommandContext(source, offset)) return whole;
20821
+ const safe = redactUserInfoToken(userInfo, options);
20822
+ return safe === null ? whole : `${boundary}${flag}${safe}`;
20823
+ }
20824
+ );
20825
+ value = value.replace(
20826
+ LONG_FLAG_RE,
20827
+ (_whole, boundary, flag, separator, secret) => `${boundary}${flag}${separator}${replacement(options, secret)}`
20828
+ );
20829
+ return value;
20830
+ }
20831
+ function isCredentialFieldName(name) {
20832
+ const normalized = name.replace(new RegExp("([\\p{Ll}\\d])(\\p{Lu})", "gu"), "$1-$2");
20833
+ return EXACT_CREDENTIAL_NAME.test(normalized) || SUFFIX_CREDENTIAL_NAME.test(normalized);
20834
+ }
20835
+ function exactLongFlag(raw2) {
20836
+ return EXACT_LONG_FLAG_RE.test(unquote(raw2));
20837
+ }
20838
+ function redactArgv(argv, options) {
20839
+ const out = argv.map((part) => redactCredentialSyntax(part, options));
20840
+ for (let index = 0; index < argv.length; index++) {
20841
+ const flag = argv[index];
20842
+ if (exactLongFlag(flag) && index + 1 < argv.length) {
20843
+ out[index + 1] = replacement(options, argv[index + 1]);
20844
+ index++;
20845
+ continue;
20846
+ }
20847
+ const userFlag = unquote(flag).toLowerCase();
20848
+ const curlContext = argv.slice(0, index).some((part) => CURL_EXECUTABLE_RE.test(unquote(part)));
20849
+ if ((userFlag === "--user" || userFlag === "-u" && curlContext) && index + 1 < argv.length) {
20850
+ const safe = redactUserInfoToken(argv[index + 1], options);
20851
+ if (safe !== null) out[index + 1] = safe;
20852
+ index++;
20853
+ }
20854
+ }
20855
+ return out;
20856
+ }
20857
+ function redactCredentialStructure(input, options = {}) {
20858
+ const seen = /* @__PURE__ */ new WeakMap();
20859
+ const visit = (value, fieldName, credentialContext = false) => {
20860
+ const sensitive = credentialContext || fieldName !== void 0 && isCredentialFieldName(fieldName);
20861
+ if (typeof value === "string") {
20862
+ if (sensitive) return replacement(options, value);
20863
+ return redactCredentialSyntax(value, options);
20864
+ }
20865
+ if (!value || typeof value !== "object") return value;
20866
+ const prior = seen.get(value);
20867
+ if (prior) return prior;
20868
+ if (Array.isArray(value)) {
20869
+ const allStrings = value.every((entry) => typeof entry === "string");
20870
+ const target2 = [];
20871
+ seen.set(value, target2);
20872
+ const source = allStrings && (fieldName === void 0 || ARGV_FIELD_NAME.test(fieldName)) ? redactArgv(value, options) : value;
20873
+ for (const entry of source) target2.push(visit(entry, void 0, sensitive));
20874
+ return target2;
20875
+ }
20876
+ const target = {};
20877
+ seen.set(value, target);
20878
+ for (const [key, entry] of Object.entries(value)) target[key] = visit(entry, key, sensitive);
20879
+ return target;
20880
+ };
20881
+ return visit(input);
20882
+ }
20883
+ var DEFAULT_REPLACEMENT, FLAG_NAME, BOUNDARY, FLAG_TOKEN, FLAG_SEPARATOR, ESCAPED_SHELL_CHARACTER, QUOTED_OR_BARE_VALUE, LONG_FLAG_RE, USER_FLAG_RE, ATTACHED_USER_FLAG_RE, URL_USERINFO_RE, URL_ENCODED_USERINFO_RE, EXACT_CREDENTIAL_NAME, SUFFIX_CREDENTIAL_NAME, ARGV_FIELD_NAME, EXACT_LONG_FLAG_RE, CURL_EXECUTABLE_RE;
20884
+ var init_credential_redaction = __esm({
20885
+ "packages/server/src/credential-redaction.ts"() {
20886
+ "use strict";
20887
+ DEFAULT_REPLACEMENT = "[redacted]";
20888
+ FLAG_NAME = String.raw`(?:api[-_]?key|access[-_]?token|auth[-_]?token|client[-_]?secret|token|secret|password|passwd|credential|private[-_]?key)`;
20889
+ BOUNDARY = String.raw`(^|[\s;&|([{"'])`;
20890
+ FLAG_TOKEN = String.raw`(?:(?:"|')?--?${FLAG_NAME}(?:"|')?)`;
20891
+ FLAG_SEPARATOR = String.raw`(?:[ \t]*(?:=|:)[ \t]*|[ \t]*\\\r?\n[ \t]*|[ \t]+)`;
20892
+ ESCAPED_SHELL_CHARACTER = String.raw`\\(?:\r?\n|[^\r\n])`;
20893
+ QUOTED_OR_BARE_VALUE = String.raw`(?:"(?:${ESCAPED_SHELL_CHARACTER}|[^"\\]){0,4096}"|'[^']{0,4096}'|(?:${ESCAPED_SHELL_CHARACTER}|[^\\\s;&|"']){1,4096})`;
20894
+ LONG_FLAG_RE = new RegExp(`${BOUNDARY}(${FLAG_TOKEN})(${FLAG_SEPARATOR})(${QUOTED_OR_BARE_VALUE})`, "gimu");
20895
+ USER_FLAG_RE = new RegExp(
20896
+ `${BOUNDARY}((?:(?:"|')?(?:-u|--user)(?:"|')?))(${FLAG_SEPARATOR})(${QUOTED_OR_BARE_VALUE})`,
20897
+ "gimu"
20898
+ );
20899
+ ATTACHED_USER_FLAG_RE = new RegExp(`${BOUNDARY}(-u)(${QUOTED_OR_BARE_VALUE})`, "gimu");
20900
+ URL_USERINFO_RE = /\b([a-z][a-z0-9+.-]{0,31}:\/\/)([^\s/?#@"':]{1,512})(:)([^\s/?#@"']{0,4096})@/giu;
20901
+ URL_ENCODED_USERINFO_RE = /\b([a-z][a-z0-9+.-]{0,31}:\/\/)([^\s/?#@"']{1,512}?)(%3a)([^\s/?#@"']{0,4096})@/giu;
20902
+ EXACT_CREDENTIAL_NAME = /^(?:authorization|proxy[-_]?authorization|api[-_]?key|access[-_]?token|auth[-_]?token|client[-_]?secret|token|secret|password|passwd|credential|private[-_]?key|cookie)$/iu;
20903
+ SUFFIX_CREDENTIAL_NAME = /(?:^|[._-])(?:api[-_]?key|access[-_]?token|auth[-_]?token|client[-_]?secret|token|secret|password|passwd|credential|private[-_]?key)$/iu;
20904
+ ARGV_FIELD_NAME = /^(?:argv|args|arguments|command|cmd)$/iu;
20905
+ EXACT_LONG_FLAG_RE = new RegExp(`^--?${FLAG_NAME}$`, "iu");
20906
+ CURL_EXECUTABLE_RE = /(?:^|[\\/])curl(?:\.exe)?$/iu;
20907
+ }
20908
+ });
20909
+
20910
+ // packages/server/src/backend/codex-error.ts
20911
+ function errorText(text2) {
20912
+ const safe = redactCredentialSyntax(text2).replace(/\b((?:proxy-)?authorization\s*:\s*(?:bearer|basic)\s+)[^\s,;"']+/gi, "$1[redacted]").trim();
20913
+ return safe.length > 32e3 ? `${safe.slice(0, 32e3)}
20914
+ [truncated]` : safe;
20915
+ }
20916
+ function codexProviderError(raw2, at, retrying = false) {
20917
+ const error = raw2 && typeof raw2 === "object" ? raw2 : {};
20918
+ const info = error.codex_error_info ?? error.codexErrorInfo;
20919
+ const category = typeof info === "string" ? info : info && typeof info === "object" ? Object.keys(info)[0] : void 0;
20920
+ const code = category?.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase().slice(0, 128);
20921
+ const message = typeof raw2 === "string" ? raw2 : typeof error.message === "string" ? error.message : "";
20922
+ const details = error.additional_details ?? error.additionalDetails;
20923
+ return {
20924
+ message: errorText(message) || "Codex reported an error without a message.",
20925
+ ...code ? { code } : {},
20926
+ ...typeof details === "string" && details.trim() ? { details: errorText(details) } : {},
20927
+ ...retrying ? { retrying: true } : {},
20928
+ ...at ? { at } : {}
20929
+ };
20930
+ }
20931
+ var init_codex_error = __esm({
20932
+ "packages/server/src/backend/codex-error.ts"() {
20933
+ "use strict";
20934
+ init_credential_redaction();
20935
+ }
20936
+ });
20937
+
20755
20938
  // packages/server/src/discover.ts
20756
20939
  import { readdirSync as readdirSync3, statSync as statSync4, openSync as openSync7, readSync, closeSync as closeSync6 } from "node:fs";
20757
20940
  import { dirname as dirname7, join as join11 } from "node:path";
@@ -23754,6 +23937,18 @@ function applyFinalText(state, text2) {
23754
23937
  function applyEvent(state, ev) {
23755
23938
  if ("at" in ev && typeof ev.at === "string" && ev.kind !== "context-usage") state.lastActivityAt = ev.at;
23756
23939
  switch (ev.kind) {
23940
+ case "provider-error":
23941
+ state.sawRecords = true;
23942
+ if (ev.error.retrying) break;
23943
+ state.turn = "idle";
23944
+ state.apiFault = true;
23945
+ state.providerError = ev.error;
23946
+ state.lastAssistant = ev.error.message;
23947
+ state.lastFence = void 0;
23948
+ state.lastAssistantAllDone = false;
23949
+ state.lastAssistantHasQuestion = false;
23950
+ if (typeof ev.at === "string") state.lastAssistantAt = ev.at;
23951
+ break;
23757
23952
  case "turn-start":
23758
23953
  state.sawRecords = true;
23759
23954
  state.turn = "in-flight";
@@ -23762,10 +23957,16 @@ function applyEvent(state, ev) {
23762
23957
  state.sawRecords = true;
23763
23958
  state.turn = "idle";
23764
23959
  if (typeof ev.at === "string") state.lastAssistantAt = ev.at;
23960
+ if (ev.finalText !== void 0 || ev.successful) {
23961
+ state.apiFault = void 0;
23962
+ state.providerError = void 0;
23963
+ }
23765
23964
  if (ev.finalText !== void 0) applyFinalText(state, ev.finalText);
23766
23965
  break;
23767
23966
  case "assistant-text":
23768
23967
  state.sawRecords = true;
23968
+ state.apiFault = void 0;
23969
+ state.providerError = void 0;
23769
23970
  if (ev.final) {
23770
23971
  if (typeof ev.at === "string") state.lastAssistantAt = ev.at;
23771
23972
  applyFinalText(state, ev.text);
@@ -24762,8 +24963,44 @@ ${detail2}
24762
24963
  } catch {
24763
24964
  }
24764
24965
  }
24966
+ function relocatedTranscript(state) {
24967
+ const name = `${state.nativeSessionId}.jsonl`;
24968
+ const home = join18(logDir, name);
24969
+ const homeAt = home === state.path ? void 0 : mtimeOfNonEmpty(home);
24970
+ const dir = discoverTranscriptDir(logDir, state.nativeSessionId);
24971
+ const sibling = dir ? join18(dir, name) : void 0;
24972
+ const siblingAt = sibling && sibling !== state.path ? mtimeOfNonEmpty(sibling) : void 0;
24973
+ if (homeAt === void 0) return siblingAt === void 0 ? void 0 : sibling;
24974
+ if (siblingAt === void 0) return home;
24975
+ return siblingAt > homeAt ? sibling : home;
24976
+ }
24765
24977
  function resolveTranscript(state, row, nowMs) {
24766
- if (state.offset > 0) return true;
24978
+ if (state.offset > 0) {
24979
+ if (existsSync5(state.path)) {
24980
+ state.discoverMisses = 0;
24981
+ state.nextDiscoverMs = 0;
24982
+ return true;
24983
+ }
24984
+ if (nowMs < state.nextDiscoverMs) return true;
24985
+ const moved = relocatedTranscript(state);
24986
+ if (!moved) {
24987
+ state.discoverMisses++;
24988
+ state.nextDiscoverMs = nowMs + Math.min(
24989
+ DISCOVER_RETRY_MS * 2 ** (state.discoverMisses - 1),
24990
+ DISCOVER_RETRY_MAX_MS
24991
+ );
24992
+ return true;
24993
+ }
24994
+ state.path = moved;
24995
+ state.offset = 0;
24996
+ state.partial = "";
24997
+ state.primed = false;
24998
+ state.noTranscript = false;
24999
+ state.stallLogged = false;
25000
+ state.discoverMisses = 0;
25001
+ state.nextDiscoverMs = 0;
25002
+ return true;
25003
+ }
24767
25004
  let size = 0;
24768
25005
  try {
24769
25006
  size = statSync8(state.path).size;
@@ -24774,6 +25011,7 @@ ${detail2}
24774
25011
  state.noTranscript = false;
24775
25012
  state.stallLogged = false;
24776
25013
  state.discoverMisses = 0;
25014
+ state.nextDiscoverMs = 0;
24777
25015
  return true;
24778
25016
  }
24779
25017
  const spawnedMs = Date.parse(row.spawned_at);
@@ -24789,6 +25027,7 @@ ${detail2}
24789
25027
  state.noTranscript = false;
24790
25028
  state.stallLogged = false;
24791
25029
  state.discoverMisses = 0;
25030
+ state.nextDiscoverMs = 0;
24792
25031
  return true;
24793
25032
  }
24794
25033
  const found = discoverTranscriptId(logDir, row.session_id, { nowMs, exclude: claimedIds(row.slug) });
@@ -24812,6 +25051,7 @@ ${detail2}
24812
25051
  state.noTranscript = false;
24813
25052
  state.stallLogged = false;
24814
25053
  state.discoverMisses = 0;
25054
+ state.nextDiscoverMs = 0;
24815
25055
  return true;
24816
25056
  }
24817
25057
  state.discoverMisses++;
@@ -24893,6 +25133,7 @@ ${detail2}
24893
25133
  drainUnretiredOps(state, row);
24894
25134
  if (state.offset !== primeOffset) transcriptDirty.push(row.slug);
24895
25135
  state.turn = turnFor(row, state, nowMs);
25136
+ onPrimedAtRest(row, state);
24896
25137
  const pane2 = sniffPane(
24897
25138
  state,
24898
25139
  row,
@@ -25063,6 +25304,16 @@ ${detail2}
25063
25304
  body: state.lastAssistant
25064
25305
  });
25065
25306
  }
25307
+ function onPrimedAtRest(row, state) {
25308
+ if (state.turn !== "idle" || !state.sawRecords) return;
25309
+ const eventAt = state.lastAssistantAt;
25310
+ if (!eventAt) return;
25311
+ const at = Date.parse(eventAt);
25312
+ if (!Number.isFinite(at)) return;
25313
+ const stamped = row.rested_at ? Date.parse(row.rested_at) : NaN;
25314
+ if (Number.isFinite(stamped) && at <= stamped) return;
25315
+ deps.storage.setRestedAtIfCurrent(row.slug, row.session_id, row.runtime_generation ?? 0, eventAt);
25316
+ }
25066
25317
  function onPaneDeath(row) {
25067
25318
  const generation = row.runtime_generation ?? 0;
25068
25319
  const eventAt = new Date(now()).toISOString();
@@ -25153,7 +25404,7 @@ ${detail2}
25153
25404
  if (!s) return void 0;
25154
25405
  const pendingQuestion = s.lastAssistantHasQuestion;
25155
25406
  const nowMs = now();
25156
- return { turn: s.turn, permPrompt: s.permPrompt, permPolicy: s.permPolicy, permDenies: s.permDenies, model: s.model, effort: s.effort, profileAt: s.profileAt, profileRevision: s.profileRevision, permissionMode: s.permissionMode, permissionModeAt: s.permissionModeAt, permissionModeRevision: s.permissionModeRevision, lastActivityAt: s.lastActivityAt, lastAssistantAt: s.lastAssistantAt, lastAssistant: s.lastAssistant, aiTitle: s.aiTitle, customTitle: s.customTitle, customTitleRevision: s.customTitleRevision, subAgents: subAgentViews(s, nowMs), droppedReports: [...s.queuedReports.values()], bgShells: [...bgShellViews(s), ...codexBgShellViews(s)], retiredShells: retiredShellViews(s), pendingAsk: s.pendingAsk, pendingQuestion, lastAssistantAllDone: s.lastAssistantAllDone, lastUserAt: s.lastUserAt, lastUserText: s.lastUserText, firstUserText: s.firstUserText, lastFence: s.lastFence, noTranscript: s.noTranscript, authFault: s.authFault, apiFault: s.apiFault, limitFault: s.limitFault, contextTokens: s.contextTokens, contextWindow: s.contextWindow, lastCompactionAt: s.lastCompactionAt };
25407
+ return { turn: s.turn, permPrompt: s.permPrompt, permPolicy: s.permPolicy, permDenies: s.permDenies, model: s.model, effort: s.effort, profileAt: s.profileAt, profileRevision: s.profileRevision, permissionMode: s.permissionMode, permissionModeAt: s.permissionModeAt, permissionModeRevision: s.permissionModeRevision, lastActivityAt: s.lastActivityAt, lastAssistantAt: s.lastAssistantAt, lastAssistant: s.lastAssistant, aiTitle: s.aiTitle, customTitle: s.customTitle, customTitleRevision: s.customTitleRevision, subAgents: subAgentViews(s, nowMs), droppedReports: [...s.queuedReports.values()], bgShells: [...bgShellViews(s), ...codexBgShellViews(s)], retiredShells: retiredShellViews(s), pendingAsk: s.pendingAsk, pendingQuestion, lastAssistantAllDone: s.lastAssistantAllDone, lastUserAt: s.lastUserAt, lastUserText: s.lastUserText, firstUserText: s.firstUserText, lastFence: s.lastFence, noTranscript: s.noTranscript, authFault: s.authFault, apiFault: s.apiFault, providerError: s.providerError, limitFault: s.limitFault, contextTokens: s.contextTokens, contextWindow: s.contextWindow, lastCompactionAt: s.lastCompactionAt };
25157
25408
  },
25158
25409
  // The CURRENT fresh foreign session ids (mtime within FOREIGN_FRESH_MS, capped), mtime-desc. Kept
25159
25410
  // as the last scan's result — recomputed at most every FOREIGN_SCAN_EVERY ticks.
@@ -25486,8 +25737,15 @@ function parseCodexLine(line) {
25486
25737
  return [{ kind: "turn-start", at }];
25487
25738
  case "task_complete": {
25488
25739
  const finalText = typeof p.last_agent_message === "string" ? p.last_agent_message : void 0;
25489
- return [{ kind: "turn-end", at, finalText }];
25740
+ if (p.error != null) return [
25741
+ { kind: "provider-error", at, error: codexProviderError(p.error, at) },
25742
+ { kind: "turn-end", at }
25743
+ ];
25744
+ return [{ kind: "turn-end", at, finalText, ...p.error === null ? { successful: true } : {} }];
25490
25745
  }
25746
+ case "error":
25747
+ case "stream_error":
25748
+ return [{ kind: "provider-error", at, error: codexProviderError(p.error ?? p, at, pt === "stream_error" || p.will_retry === true || p.willRetry === true) }];
25491
25749
  // The OTHER closing bracket. An INTERRUPTED turn (`reason: "interrupted"` — what turn/interrupt
25492
25750
  // produces, now that stopping a Codex thread actually stops it) never reaches task_complete.
25493
25751
  // Without this the rollout's last word stays task_started, so the tailer holds the turn in-flight
@@ -25966,6 +26224,7 @@ var CODEX_FIRST_FINAL_TITLE_TRANSPORT, CODEX_FIRST_OUTPUT_TITLE_DEVELOPER_INSTRU
25966
26224
  var init_codex = __esm({
25967
26225
  "packages/server/src/backend/codex.ts"() {
25968
26226
  "use strict";
26227
+ init_codex_error();
25969
26228
  init_tailer();
25970
26229
  CODEX_FIRST_FINAL_TITLE_TRANSPORT = 'FRIZZ TITLE TRANSPORT (required): your very first assistant message must begin with one concise `<!-- frizz title="Concise thread title" -->` comment before any commentary, acknowledgement, or tool call. Frizz removes that comment from chat and uses only its quoted title as this thread\'s automatic title.';
25971
26230
  CODEX_FIRST_OUTPUT_TITLE_DEVELOPER_INSTRUCTIONS = 'FRIZZ UI metadata protocol (mandatory): the very first assistant message in this new session, before any commentary, acknowledgement, tool call, or other action, MUST begin on its first line with exactly one `<!-- frizz title="..." -->` HTML comment. Replace `...` with a concise human-readable 3-8 word title for the user\'s task. Put no text before the comment. You may continue the message normally after it. Emit this title comment exactly once. Do not explain the protocol. Frizz removes the comment before displaying the conversation.';
@@ -26004,152 +26263,6 @@ var init_worker_env = __esm({
26004
26263
  }
26005
26264
  });
26006
26265
 
26007
- // packages/server/src/credential-redaction.ts
26008
- function replacement(options, secretToken) {
26009
- const configured = options.replacement ?? DEFAULT_REPLACEMENT;
26010
- return typeof configured === "function" ? configured(secretToken) : configured;
26011
- }
26012
- function unquote(raw2) {
26013
- return raw2.length >= 2 && (raw2[0] === '"' || raw2[0] === "'") && raw2.at(-1) === raw2[0] ? raw2.slice(1, -1) : raw2;
26014
- }
26015
- function userInfoParts(raw2) {
26016
- const value = unquote(raw2);
26017
- const literal = value.indexOf(":");
26018
- const encodedMatch = /%3a/iu.exec(value);
26019
- const encoded = encodedMatch?.index ?? -1;
26020
- const index = literal === -1 ? encoded : encoded === -1 ? literal : Math.min(literal, encoded);
26021
- if (index <= 0) return null;
26022
- const delimiter2 = value.slice(index, index + (index === encoded ? 3 : 1));
26023
- return { username: value.slice(0, index), delimiter: delimiter2, password: value.slice(index + delimiter2.length) };
26024
- }
26025
- function redactUserInfoToken(raw2, options) {
26026
- const parts = userInfoParts(raw2);
26027
- if (!parts) return null;
26028
- return `${parts.username}${parts.delimiter}${replacement(options, parts.password)}`;
26029
- }
26030
- function hasCurlCommandContext(source, offset) {
26031
- const bounded = source.slice(Math.max(0, offset - 1024), offset);
26032
- const separator = Math.max(
26033
- bounded.lastIndexOf("\n"),
26034
- bounded.lastIndexOf("\r"),
26035
- bounded.lastIndexOf(";"),
26036
- bounded.lastIndexOf("&"),
26037
- bounded.lastIndexOf("|")
26038
- );
26039
- const segment = bounded.slice(separator + 1);
26040
- return segment.split(/[ \t]+/u).some((token) => CURL_EXECUTABLE_RE.test(unquote(token)));
26041
- }
26042
- function redactCredentialSyntax(raw2, options = {}) {
26043
- let value = raw2;
26044
- value = value.replace(
26045
- URL_USERINFO_RE,
26046
- (_whole, scheme, username, delimiter2, password) => `${scheme}${username}${delimiter2}${replacement(options, password)}@`
26047
- );
26048
- value = value.replace(
26049
- URL_ENCODED_USERINFO_RE,
26050
- (_whole, scheme, username, delimiter2, password) => `${scheme}${username}${delimiter2}${replacement(options, password)}@`
26051
- );
26052
- value = value.replace(
26053
- USER_FLAG_RE,
26054
- (whole, boundary, flag, separator, userInfo, offset, source) => {
26055
- if (unquote(flag).toLowerCase() === "-u" && !hasCurlCommandContext(source, offset)) return whole;
26056
- const safe = redactUserInfoToken(userInfo, options);
26057
- return safe === null ? whole : `${boundary}${flag}${separator}${safe}`;
26058
- }
26059
- );
26060
- value = value.replace(
26061
- ATTACHED_USER_FLAG_RE,
26062
- (whole, boundary, flag, userInfo, offset, source) => {
26063
- if (!hasCurlCommandContext(source, offset)) return whole;
26064
- const safe = redactUserInfoToken(userInfo, options);
26065
- return safe === null ? whole : `${boundary}${flag}${safe}`;
26066
- }
26067
- );
26068
- value = value.replace(
26069
- LONG_FLAG_RE,
26070
- (_whole, boundary, flag, separator, secret) => `${boundary}${flag}${separator}${replacement(options, secret)}`
26071
- );
26072
- return value;
26073
- }
26074
- function isCredentialFieldName(name) {
26075
- const normalized = name.replace(new RegExp("([\\p{Ll}\\d])(\\p{Lu})", "gu"), "$1-$2");
26076
- return EXACT_CREDENTIAL_NAME.test(normalized) || SUFFIX_CREDENTIAL_NAME.test(normalized);
26077
- }
26078
- function exactLongFlag(raw2) {
26079
- return EXACT_LONG_FLAG_RE.test(unquote(raw2));
26080
- }
26081
- function redactArgv(argv, options) {
26082
- const out = argv.map((part) => redactCredentialSyntax(part, options));
26083
- for (let index = 0; index < argv.length; index++) {
26084
- const flag = argv[index];
26085
- if (exactLongFlag(flag) && index + 1 < argv.length) {
26086
- out[index + 1] = replacement(options, argv[index + 1]);
26087
- index++;
26088
- continue;
26089
- }
26090
- const userFlag = unquote(flag).toLowerCase();
26091
- const curlContext = argv.slice(0, index).some((part) => CURL_EXECUTABLE_RE.test(unquote(part)));
26092
- if ((userFlag === "--user" || userFlag === "-u" && curlContext) && index + 1 < argv.length) {
26093
- const safe = redactUserInfoToken(argv[index + 1], options);
26094
- if (safe !== null) out[index + 1] = safe;
26095
- index++;
26096
- }
26097
- }
26098
- return out;
26099
- }
26100
- function redactCredentialStructure(input, options = {}) {
26101
- const seen = /* @__PURE__ */ new WeakMap();
26102
- const visit = (value, fieldName, credentialContext = false) => {
26103
- const sensitive = credentialContext || fieldName !== void 0 && isCredentialFieldName(fieldName);
26104
- if (typeof value === "string") {
26105
- if (sensitive) return replacement(options, value);
26106
- return redactCredentialSyntax(value, options);
26107
- }
26108
- if (!value || typeof value !== "object") return value;
26109
- const prior = seen.get(value);
26110
- if (prior) return prior;
26111
- if (Array.isArray(value)) {
26112
- const allStrings = value.every((entry) => typeof entry === "string");
26113
- const target2 = [];
26114
- seen.set(value, target2);
26115
- const source = allStrings && (fieldName === void 0 || ARGV_FIELD_NAME.test(fieldName)) ? redactArgv(value, options) : value;
26116
- for (const entry of source) target2.push(visit(entry, void 0, sensitive));
26117
- return target2;
26118
- }
26119
- const target = {};
26120
- seen.set(value, target);
26121
- for (const [key, entry] of Object.entries(value)) target[key] = visit(entry, key, sensitive);
26122
- return target;
26123
- };
26124
- return visit(input);
26125
- }
26126
- var DEFAULT_REPLACEMENT, FLAG_NAME, BOUNDARY, FLAG_TOKEN, FLAG_SEPARATOR, ESCAPED_SHELL_CHARACTER, QUOTED_OR_BARE_VALUE, LONG_FLAG_RE, USER_FLAG_RE, ATTACHED_USER_FLAG_RE, URL_USERINFO_RE, URL_ENCODED_USERINFO_RE, EXACT_CREDENTIAL_NAME, SUFFIX_CREDENTIAL_NAME, ARGV_FIELD_NAME, EXACT_LONG_FLAG_RE, CURL_EXECUTABLE_RE;
26127
- var init_credential_redaction = __esm({
26128
- "packages/server/src/credential-redaction.ts"() {
26129
- "use strict";
26130
- DEFAULT_REPLACEMENT = "[redacted]";
26131
- FLAG_NAME = String.raw`(?:api[-_]?key|access[-_]?token|auth[-_]?token|client[-_]?secret|token|secret|password|passwd|credential|private[-_]?key)`;
26132
- BOUNDARY = String.raw`(^|[\s;&|([{"'])`;
26133
- FLAG_TOKEN = String.raw`(?:(?:"|')?--?${FLAG_NAME}(?:"|')?)`;
26134
- FLAG_SEPARATOR = String.raw`(?:[ \t]*(?:=|:)[ \t]*|[ \t]*\\\r?\n[ \t]*|[ \t]+)`;
26135
- ESCAPED_SHELL_CHARACTER = String.raw`\\(?:\r?\n|[^\r\n])`;
26136
- QUOTED_OR_BARE_VALUE = String.raw`(?:"(?:${ESCAPED_SHELL_CHARACTER}|[^"\\]){0,4096}"|'[^']{0,4096}'|(?:${ESCAPED_SHELL_CHARACTER}|[^\\\s;&|"']){1,4096})`;
26137
- LONG_FLAG_RE = new RegExp(`${BOUNDARY}(${FLAG_TOKEN})(${FLAG_SEPARATOR})(${QUOTED_OR_BARE_VALUE})`, "gimu");
26138
- USER_FLAG_RE = new RegExp(
26139
- `${BOUNDARY}((?:(?:"|')?(?:-u|--user)(?:"|')?))(${FLAG_SEPARATOR})(${QUOTED_OR_BARE_VALUE})`,
26140
- "gimu"
26141
- );
26142
- ATTACHED_USER_FLAG_RE = new RegExp(`${BOUNDARY}(-u)(${QUOTED_OR_BARE_VALUE})`, "gimu");
26143
- URL_USERINFO_RE = /\b([a-z][a-z0-9+.-]{0,31}:\/\/)([^\s/?#@"':]{1,512})(:)([^\s/?#@"']{0,4096})@/giu;
26144
- URL_ENCODED_USERINFO_RE = /\b([a-z][a-z0-9+.-]{0,31}:\/\/)([^\s/?#@"']{1,512}?)(%3a)([^\s/?#@"']{0,4096})@/giu;
26145
- EXACT_CREDENTIAL_NAME = /^(?:authorization|proxy[-_]?authorization|api[-_]?key|access[-_]?token|auth[-_]?token|client[-_]?secret|token|secret|password|passwd|credential|private[-_]?key|cookie)$/iu;
26146
- SUFFIX_CREDENTIAL_NAME = /(?:^|[._-])(?:api[-_]?key|access[-_]?token|auth[-_]?token|client[-_]?secret|token|secret|password|passwd|credential|private[-_]?key)$/iu;
26147
- ARGV_FIELD_NAME = /^(?:argv|args|arguments|command|cmd)$/iu;
26148
- EXACT_LONG_FLAG_RE = new RegExp(`^--?${FLAG_NAME}$`, "iu");
26149
- CURL_EXECUTABLE_RE = /(?:^|[\\/])curl(?:\.exe)?$/iu;
26150
- }
26151
- });
26152
-
26153
26266
  // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/constants.js
26154
26267
  var require_constants = __commonJS({
26155
26268
  "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/constants.js"(exports, module) {
@@ -31817,7 +31930,7 @@ function createCodexAppServerBridge(options) {
31817
31930
  function codexAppServerBridgeEnabled() {
31818
31931
  return true;
31819
31932
  }
31820
- var CODEX_APP_SERVER_PROVIDER, CODEX_NATIVE_LISTEN_FLAG, CODEX_APP_SERVER_SUPPORTED_VERSION, CODEX_APP_SERVER_PROTOCOL_REVISION, aheadVersionWarned, PROTOCOL_FINGERPRINT, CLIENT_INFO, CLIENT_CAPABILITIES, CODEX_SANDBOX_MODES, CODEX_APPROVAL_POLICY, CODEX_DEFAULT_SANDBOX, SANDBOX_CONFIRM_TIMEOUT_MS, SANDBOX_NOOP_GRACE_MS, MAX_JSONL_BYTES, MAX_INBOUND_JSONL_BYTES, MAX_INBOUND_RECORDS, MAX_INBOUND_QUEUED_BYTES, MAX_OUTBOUND_REQUESTS, MAX_STDERR_BYTES, DEFAULT_REQUEST_TIMEOUT_MS, BRIDGE_DB_SCHEMA_VERSION, RpcIdSchema, Opaque, SafeTimestampMs, NullableString, CommandAction, NetworkApprovalContext, FileSystemSpecialPath, FileSystemPath, FileSystemSandboxEntry, NetworkPermissions, FileSystemPermissions, RequestedPermissions, NetworkPolicyAmendment, CommandApprovalParams, FileApprovalParams, PatchChangeKind, FileUpdateChange, FileChangeItem, CommandExecutionItem, ItemStartedNotification, ItemCompletedNotification, FileChangePatchUpdatedNotification, PermissionsApprovalParams, UserInputQuestion, UserInputParams, McpBase, McpElicitationParams, ResolvedNotification, RpcProtocolError, JsonlRpcConnection, BindingRowSchema, BridgeMetaRowSchema, DISPLAY_REDACTION, UNSAFE_DISPLAY_TEXT, SECRET_NAME, commandDecisionMap, InitializeResponse, ThreadResponse, TurnResponse, TurnSteerResponse, SkillsListResponse, ThreadResumeSandbox, ThreadResumeStatus, ThreadSettingsUpdated, TurnStarted, TurnCompleted, MAX_CORRELATED_FILE_ITEMS, CODEX_APP_SERVER_TABLES, CodexAppServerBridge;
31933
+ var CODEX_APP_SERVER_PROVIDER, CODEX_NATIVE_LISTEN_FLAG, CODEX_APP_SERVER_SUPPORTED_VERSION, CODEX_APP_SERVER_PROTOCOL_REVISION, aheadVersionWarned, PROTOCOL_FINGERPRINT, CLIENT_INFO, CLIENT_CAPABILITIES, CODEX_SANDBOX_MODES, CODEX_APPROVAL_POLICY, CODEX_DEFAULT_SANDBOX, SANDBOX_CONFIRM_TIMEOUT_MS, SANDBOX_NOOP_GRACE_MS, MAX_JSONL_BYTES, MAX_INBOUND_JSONL_BYTES, MAX_INBOUND_RECORDS, MAX_INBOUND_QUEUED_BYTES, MAX_OUTBOUND_REQUESTS, MAX_STDERR_BYTES, DEFAULT_REQUEST_TIMEOUT_MS, AUTH_REPLACEMENT_WAIT_MS, MAX_AUTH_REPLACEMENT_ATTEMPTS, BRIDGE_DB_SCHEMA_VERSION, RpcIdSchema, Opaque, SafeTimestampMs, NullableString, CommandAction, NetworkApprovalContext, FileSystemSpecialPath, FileSystemPath, FileSystemSandboxEntry, NetworkPermissions, FileSystemPermissions, RequestedPermissions, NetworkPolicyAmendment, CommandApprovalParams, FileApprovalParams, PatchChangeKind, FileUpdateChange, FileChangeItem, CommandExecutionItem, ItemStartedNotification, ItemCompletedNotification, FileChangePatchUpdatedNotification, PermissionsApprovalParams, UserInputQuestion, UserInputParams, McpBase, McpElicitationParams, ResolvedNotification, RpcProtocolError, JsonlRpcConnection, BindingRowSchema, BridgeMetaRowSchema, DISPLAY_REDACTION, UNSAFE_DISPLAY_TEXT, SECRET_NAME, commandDecisionMap, InitializeResponse, ThreadResponse, TurnResponse, TurnSteerResponse, SkillsListResponse, ThreadResumeSandbox, ThreadResumeStatus, ThreadSettingsUpdated, TurnStarted, TurnCompleted, MAX_CORRELATED_FILE_ITEMS, CODEX_APP_SERVER_TABLES, CodexAppServerBridge;
31821
31934
  var init_codex_app_server = __esm({
31822
31935
  "packages/server/src/backend/codex-app-server.ts"() {
31823
31936
  "use strict";
@@ -31831,6 +31944,7 @@ var init_codex_app_server = __esm({
31831
31944
  init_codex_app_server_native();
31832
31945
  init_auth_status();
31833
31946
  init_codex_mcp();
31947
+ init_codex_error();
31834
31948
  init_logging();
31835
31949
  CODEX_APP_SERVER_PROVIDER = "codex-app-server";
31836
31950
  CODEX_NATIVE_LISTEN_FLAG = "FRIZZ_CODEX_NATIVE_LISTEN";
@@ -31882,6 +31996,8 @@ var init_codex_app_server = __esm({
31882
31996
  MAX_OUTBOUND_REQUESTS = 128;
31883
31997
  MAX_STDERR_BYTES = 16 * 1024;
31884
31998
  DEFAULT_REQUEST_TIMEOUT_MS = 2e4;
31999
+ AUTH_REPLACEMENT_WAIT_MS = 2e4;
32000
+ MAX_AUTH_REPLACEMENT_ATTEMPTS = 3;
31885
32001
  BRIDGE_DB_SCHEMA_VERSION = 1;
31886
32002
  RpcIdSchema = external_exports.union([external_exports.string().min(1).max(256), external_exports.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER)]);
31887
32003
  Opaque = external_exports.string().min(1).max(256);
@@ -32401,6 +32517,7 @@ var init_codex_app_server = __esm({
32401
32517
  processAuthAccountId;
32402
32518
  /** Serializes account-driven replacement across concurrent session/turn starts. */
32403
32519
  authReplacement = null;
32520
+ authReplacementWaitMs;
32404
32521
  turnIdleWaiters = /* @__PURE__ */ new Set();
32405
32522
  /**
32406
32523
  * The handshake a FRESHLY FORKED daemon already gave us and we already rejected — i.e. what the
@@ -32436,6 +32553,9 @@ var init_codex_app_server = __esm({
32436
32553
  // durable, and it must not be — a processId belongs to one app-server process, so a stale one
32437
32554
  // surviving a restart would offer an × that addresses a PTY that no longer exists.
32438
32555
  liveExecs = /* @__PURE__ */ new Map();
32556
+ // Live notices fill the gap before task_complete reaches the durable rollout. Retry notices are
32557
+ // not retained by Codex at all. Session keys and current-turn checks prevent cross-thread leakage.
32558
+ providerErrors = /* @__PURE__ */ new Map();
32439
32559
  activeOperations = 0;
32440
32560
  operationWaiters = /* @__PURE__ */ new Set();
32441
32561
  shutdownPromise = null;
@@ -32445,6 +32565,7 @@ var init_codex_app_server = __esm({
32445
32565
  this.makeId = options.id ?? randomUUID11;
32446
32566
  this.codexBin = options.codexBin ?? "codex";
32447
32567
  this.timeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
32568
+ this.authReplacementWaitMs = options.authReplacementWaitMs ?? AUTH_REPLACEMENT_WAIT_MS;
32448
32569
  const hostKind = selectCodexHostKind(process.env[CODEX_NATIVE_LISTEN_FLAG], process.platform, Boolean(options.spawn));
32449
32570
  this.host = options.host ?? (hostKind === "direct" ? directChildHost(options.spawn) : hostKind === "native" ? nativeListenCodexAppServerHost : daemonCodexAppServerHost);
32450
32571
  this.db = options.db;
@@ -32632,7 +32753,9 @@ var init_codex_app_server = __esm({
32632
32753
  }
32633
32754
  if (binding.current_turn_id !== null) throw new Error("Codex app-server session already has an active turn");
32634
32755
  const pendingKey = turnKey(binding);
32756
+ this.providerErrors.delete(input.sessionId);
32635
32757
  this.pendingTurnStarts.add(pendingKey);
32758
+ this.options.onStatusChange?.();
32636
32759
  try {
32637
32760
  const response = TurnResponse.parse(await connection.request("turn/start", {
32638
32761
  threadId: binding.codex_thread_id,
@@ -32889,7 +33012,8 @@ var init_codex_app_server = __esm({
32889
33012
  const onThisConnection = row.state === "active" && row.connection_epoch === this.connectionEpoch;
32890
33013
  return {
32891
33014
  bridgeTurn: onThisConnection && (row.current_turn_id !== null || this.pendingTurnStarts.has(turnKey(row))),
32892
- ownedSince: row.updated_at
33015
+ ownedSince: row.updated_at,
33016
+ providerError: onThisConnection ? this.providerErrors.get(sessionId) : void 0
32893
33017
  };
32894
33018
  }
32895
33019
  /**
@@ -32931,6 +33055,7 @@ var init_codex_app_server = __esm({
32931
33055
  if (this.closed || this.dbReleased) return false;
32932
33056
  const row = this.bindingForScope(threadSlug, sessionId);
32933
33057
  if (!row) return false;
33058
+ this.providerErrors.delete(sessionId);
32934
33059
  const ownsCurrentProcess = row.connection_epoch === this.connectionEpoch || this.openingConnection !== null;
32935
33060
  try {
32936
33061
  this.forgetCorrelatedFileItems(row.codex_thread_id);
@@ -33089,12 +33214,27 @@ var init_codex_app_server = __esm({
33089
33214
  * keeps using the account it started with even after ccbroker atomically switches auth.json. Before
33090
33215
  * starting new model work, replace that stale process — but only after every turn already running
33091
33216
  * in the shared per-project process has reached its own completion event.
33217
+ *
33218
+ * THE WAIT IS BOUNDED, AND WHEN THE BOUND EXPIRES THE TURN GOES AHEAD ON THE ACCOUNT WE HAVE.
33219
+ * "Every turn in this project is idle" is a whole-PROJECT condition and the app-server is shared, so
33220
+ * on a board running several codex threads it can be a long time coming — and until it comes, this
33221
+ * used to hold the operator's own `turn/start` open with no timeout, no error and no way to tell.
33222
+ * Measured 2026-09-05: auth.json changed at 21:45Z, the thread's turn ended at 23:00Z, and every
33223
+ * follow-up typed into it from then on hung inside this wait until the project happened to go
33224
+ * quiet at 00:19Z — 1h 18m of an operator typing steers into a box that answered nothing (the
33225
+ * browser then queued each one behind the last, so not even a reload's worth of them ever left).
33226
+ *
33227
+ * Running one turn on the previous account is a visible, recoverable outcome; hanging the send is
33228
+ * neither. So the replacement stays armed and lands at the next real idle boundary, and every turn
33229
+ * started after it picks up the new account. A replacement that FAILS outright still throws — that
33230
+ * is a broken app-server, not a busy one.
33092
33231
  */
33093
33232
  async ensureCurrentAuth() {
33094
- for (; ; ) {
33233
+ for (let attempt = 0; ; attempt++) {
33095
33234
  const desiredAccountId = (this.options.codexAuthAccountId ?? readCodexAccountId)();
33096
33235
  const connection = await this.ensureConnected();
33097
33236
  if (!desiredAccountId || this.processAuthAccountId === desiredAccountId) return connection;
33237
+ if (attempt >= MAX_AUTH_REPLACEMENT_ATTEMPTS) return connection;
33098
33238
  if (!this.authReplacement) {
33099
33239
  const replacement2 = this.replaceAppServerForAuthChange();
33100
33240
  this.authReplacement = replacement2;
@@ -33102,7 +33242,23 @@ var init_codex_app_server = __esm({
33102
33242
  if (this.authReplacement === replacement2) this.authReplacement = null;
33103
33243
  }).catch(() => void 0);
33104
33244
  }
33105
- await this.authReplacement;
33245
+ if (!await this.awaitAuthReplacement(this.authReplacement)) return connection;
33246
+ }
33247
+ }
33248
+ /** Await an armed replacement for at most AUTH_REPLACEMENT_WAIT_MS. `false` = it is still waiting for
33249
+ * the project to go idle, so the caller should proceed rather than hang; a rejection propagates. */
33250
+ async awaitAuthReplacement(replacement2) {
33251
+ let timer;
33252
+ const expired = new Promise((resolve12) => {
33253
+ timer = setTimeout(() => resolve12(false), this.authReplacementWaitMs);
33254
+ timer.unref?.();
33255
+ });
33256
+ const settled = replacement2.then(() => true);
33257
+ try {
33258
+ return await Promise.race([settled, expired]);
33259
+ } finally {
33260
+ if (timer) clearTimeout(timer);
33261
+ void settled.catch(() => void 0);
33106
33262
  }
33107
33263
  }
33108
33264
  hasInFlightTurns() {
@@ -33264,6 +33420,7 @@ var init_codex_app_server = __esm({
33264
33420
  const epoch = this.connectionEpoch;
33265
33421
  this.connection = null;
33266
33422
  this.processAuthAccountId = void 0;
33423
+ this.providerErrors.clear();
33267
33424
  this.forgetCorrelatedFileItems();
33268
33425
  this.releaseSettingsWaiters();
33269
33426
  if (this.closed || this.dbReleased) return;
@@ -34006,9 +34163,20 @@ var init_codex_app_server = __esm({
34006
34163
  });
34007
34164
  }
34008
34165
  async handleNotification(connection, method, rawParams) {
34166
+ if (method === "error") {
34167
+ const parsed = external_exports.object({ threadId: Opaque, turnId: Opaque, error: external_exports.unknown(), willRetry: external_exports.boolean() }).passthrough().safeParse(rawParams);
34168
+ if (!parsed.success) return;
34169
+ const binding = this.bindingForCodexThread(parsed.data.threadId);
34170
+ if (!binding || binding.state !== "active" || binding.connection_epoch !== this.connectionEpoch || binding.current_turn_id !== parsed.data.turnId) return;
34171
+ this.providerErrors.set(binding.frizz_session_id, codexProviderError(parsed.data.error, this.now().toISOString(), parsed.data.willRetry));
34172
+ this.options.onStatusChange?.();
34173
+ return;
34174
+ }
34009
34175
  if (method === "item/started") {
34010
34176
  const envelope = ItemStartedNotification.safeParse(rawParams);
34011
34177
  if (!envelope.success) return;
34178
+ const binding = this.bindingForCodexThread(envelope.data.threadId);
34179
+ if (binding?.state === "active" && binding.connection_epoch === this.connectionEpoch && binding.current_turn_id === envelope.data.turnId && this.providerErrors.delete(binding.frizz_session_id)) this.options.onStatusChange?.();
34012
34180
  this.foldExecItem(envelope.data.threadId, envelope.data.item, envelope.data.startedAtMs);
34013
34181
  const item = FileChangeItem.safeParse(envelope.data.item);
34014
34182
  if (!item.success || item.data.status !== "inProgress") return;
@@ -34105,6 +34273,7 @@ var init_codex_app_server = __esm({
34105
34273
  return;
34106
34274
  }
34107
34275
  if (!this.pendingTurnStarts.has(turnKey(binding))) return;
34276
+ this.providerErrors.delete(binding.frizz_session_id);
34108
34277
  this.scope.prepare(`
34109
34278
  UPDATE codex_app_server_session SET current_turn_id = ?, updated_at = ?
34110
34279
  WHERE project_id = @project_id AND codex_thread_id = ? AND connection_epoch = ? AND current_turn_id IS NULL
@@ -34114,6 +34283,14 @@ var init_codex_app_server = __esm({
34114
34283
  if (method === "turn/completed") {
34115
34284
  const parsed = TurnCompleted.safeParse(rawParams);
34116
34285
  if (!parsed.success) return;
34286
+ const binding = this.bindingForCodexThread(parsed.data.threadId);
34287
+ if (binding?.state === "active" && binding.connection_epoch === this.connectionEpoch && binding.current_turn_id === parsed.data.turn.id) {
34288
+ if (parsed.data.turn.error != null || parsed.data.turn.status === "failed") {
34289
+ this.providerErrors.set(binding.frizz_session_id, codexProviderError(parsed.data.turn.error, this.now().toISOString()));
34290
+ } else {
34291
+ this.providerErrors.delete(binding.frizz_session_id);
34292
+ }
34293
+ }
34117
34294
  for (const item of [...this.correlatedFileItems.values()]) {
34118
34295
  if (item.threadId !== parsed.data.threadId || item.turnId !== parsed.data.turn.id) continue;
34119
34296
  const active = await this.invalidateCorrelatedFileApproval(
@@ -34130,6 +34307,7 @@ var init_codex_app_server = __esm({
34130
34307
  WHERE project_id = @project_id AND codex_thread_id = ? AND connection_epoch = ? AND current_turn_id = ?
34131
34308
  `).run(this.now().toISOString(), parsed.data.threadId, this.connectionEpoch, parsed.data.turn.id);
34132
34309
  this.notifyTurnIdleWaiters();
34310
+ this.options.onStatusChange?.();
34133
34311
  }
34134
34312
  }
34135
34313
  providerResponse(record, delivery2, input) {
@@ -37600,6 +37778,7 @@ function deriveNeedsYou(row, tele, runtime, hasActionableInteraction = false, no
37600
37778
  if (!atRest) return false;
37601
37779
  if (runtime === "exited" && tele?.turn === "in-flight") return true;
37602
37780
  if (hasFreshDelivery(row, deliveryProcessGone)) return false;
37781
+ if (tele?.providerError && !tele.providerError.retrying) return true;
37603
37782
  if (tele?.pendingQuestion) return true;
37604
37783
  if (openQuestions > 0) return true;
37605
37784
  if (limitPause) return true;
@@ -37613,7 +37792,7 @@ function deriveNeedsYou(row, tele, runtime, hasActionableInteraction = false, no
37613
37792
  }
37614
37793
  function deriveAwaitingBackground(row, tele, runtime, hasActionableInteraction = false, nowMs = Date.now(), limitPause = void 0, deliveryProcessGone = false, github = {}, registeredPrWatches = /* @__PURE__ */ new Set(), armedTimerIds = /* @__PURE__ */ new Set(), armedWatches = [], openQuestions = 0) {
37615
37794
  if (runtime !== "turn-idle" || !hasDeclaredWait(tele, nowMs, armedTimerIds, registeredPrWatches, armedWatches)) return false;
37616
- if (limitPause) return false;
37795
+ if (limitPause || tele?.providerError) return false;
37617
37796
  if (hasActionableInteraction || tele?.pendingAsk || tele?.pendingQuestion || openQuestions > 0) return false;
37618
37797
  if (tele?.lastFence?.kind === "done") return false;
37619
37798
  if (tele?.lastFence?.kind === "awaiting" && !hasParkedPrWatch(tele, registeredPrWatches) && !hasDeclaredBackgroundPark(tele, nowMs) && // A REGISTERED park is the same exception for the same reason. (A registration with no fence at all
@@ -37748,9 +37927,29 @@ function sessionThreadView(projectDir, storage, row, rawTele, registeredLegacyTe
37748
37927
  expiresAt: new Date(w.expires_at).toISOString()
37749
37928
  }));
37750
37929
  const supersededDone = questions.length > 0 || armedWatches.length > 0 || armedPrWatches.length > 0 || armedTimers.length > 0;
37751
- const done = supersededDone ? void 0 : registeredDoneFence(registries.done.get(row.slug), rawTele?.lastUserAt);
37752
- const tele = done && rawTele ? { ...rawTele, lastFence: done } : rawTele;
37753
- const headlessStalled = row.codex_runtime === "app-server" ? appServerTurnStalled(codexTurnLiveness(row.slug, row.session_id), tele?.lastActivityAt, nowMs) : isBrokerClaudeRow(row) ? !claudeBrokerDaemonAlive(row.session_id) : false;
37930
+ const codexLive = row.codex_runtime === "app-server" ? codexTurnLiveness(row.slug, row.session_id) : void 0;
37931
+ const nativeError = codexLive?.providerError;
37932
+ const nativeFailure = nativeError && !nativeError.retrying && !codexLive?.bridgeTurn && (!rawTele?.lastActivityAt || nativeError.at !== void 0 && nativeError.at >= rawTele.lastActivityAt);
37933
+ const sameError = rawTele?.providerError?.message === nativeError?.message && rawTele?.providerError?.code === nativeError?.code;
37934
+ const providerError = nativeError?.retrying ? nativeError : nativeFailure ? sameError ? rawTele?.providerError : nativeError : rawTele?.providerError;
37935
+ const failedTele = nativeFailure ? {
37936
+ subAgents: [],
37937
+ bgShells: [],
37938
+ ...rawTele,
37939
+ turn: "idle",
37940
+ permPrompt: false,
37941
+ pendingQuestion: false,
37942
+ pendingAsk: void 0,
37943
+ apiFault: true,
37944
+ providerError,
37945
+ lastAssistant: providerError?.message,
37946
+ lastAssistantAt: providerError?.at,
37947
+ lastFence: void 0,
37948
+ lastAssistantAllDone: false
37949
+ } : rawTele;
37950
+ const done = supersededDone || providerError ? void 0 : registeredDoneFence(registries.done.get(row.slug), rawTele?.lastUserAt);
37951
+ const tele = done && failedTele ? { ...failedTele, lastFence: done } : failedTele;
37952
+ const headlessStalled = row.codex_runtime === "app-server" ? !nativeFailure && appServerTurnStalled(codexLive, tele?.lastActivityAt, nowMs) : isBrokerClaudeRow(row) ? !claudeBrokerDaemonAlive(row.session_id) : false;
37754
37953
  const headlessLostWork = isBrokerClaudeRow(row) && headlessStalled && hasUnretiredOwnAgents(tele);
37755
37954
  const deliveryProcessGone = isBrokerClaudeRow(row) && headlessStalled;
37756
37955
  const runtime = degradeIfAwaitingAnswer(
@@ -37815,6 +38014,7 @@ function sessionThreadView(projectDir, storage, row, rawTele, registeredLegacyTe
37815
38014
  // Subscription window exhausted mid-turn — the credential is fine, so this is a WAIT, not a
37816
38015
  // sign-in. Drives the pause card and (while an auto-resume is promised) the queue excusal above.
37817
38016
  limitPause,
38017
+ providerError,
37818
38018
  kind: "session",
37819
38019
  foreign: false,
37820
38020
  lastFence: tele?.lastFence,
@@ -37929,6 +38129,7 @@ function foreignThreadView(sessionId, tele, backend) {
37929
38129
  questions: [],
37930
38130
  kind: "session",
37931
38131
  foreign: true,
38132
+ providerError: tele.providerError,
37932
38133
  needsYou: false,
37933
38134
  awaitingBackground: false,
37934
38135
  crashed: false,
@@ -39400,6 +39601,7 @@ function createScheduler(deps) {
39400
39601
  return tele.turn === "idle" ? "current-idle" : "current-busy";
39401
39602
  }
39402
39603
  if (isStopHookFenceId(item.fenceId)) {
39604
+ if (tele.authFault || tele.apiFault) return "superseded";
39403
39605
  const armed = armedRest(row);
39404
39606
  if (!armed || item.fenceId !== stopHookFenceId(armed.armedAt, tele.lastAssistantAt ?? "")) return "superseded";
39405
39607
  if (restMessageIsSignedOff(deps.storage, item.slug, tele, registeredPrWatchesOf(deps.storage, item.slug), armedTimerIdsOf(deps.storage, item.slug), armed.armedAt)) return "superseded";
@@ -39415,6 +39617,7 @@ function createScheduler(deps) {
39415
39617
  return tele.turn === "idle" ? "current-idle" : "current-busy";
39416
39618
  }
39417
39619
  if (isSignoffFenceId(item.fenceId)) {
39620
+ if (tele.authFault || tele.apiFault) return "superseded";
39418
39621
  if (item.fenceId !== signoffFenceId(tele.lastAssistantAt ?? "")) return "superseded";
39419
39622
  if (tele.lastFence || tele.pendingQuestion) return "superseded";
39420
39623
  return tele.turn === "idle" ? "current-idle" : "current-busy";
@@ -41857,6 +42060,7 @@ function createContextUnchecked(opts, resources) {
41857
42060
  // fact. Before this the diagnostic sink was unset and every death — the six-sub-agent loss
41858
42061
  // included — was an unattributable "the thread went quiet." See codex-app-server-diagnostics.ts.
41859
42062
  diagnostic: createCodexDiagnosticSink(project.stateDir, project.id),
42063
+ onStatusChange: () => board?.refresh(),
41860
42064
  // Never wake a thread the human has already put away: a restart-recovery nudge is only for a
41861
42065
  // thread that is still open and still theirs to come back to.
41862
42066
  shouldAutoResume: (slug) => {
@@ -46313,6 +46517,7 @@ function projectCodexTranscript(raw2, identityPrefix = "codex") {
46313
46517
  let sawFinalAnswer = false;
46314
46518
  let turnReasoning = null;
46315
46519
  let pendingCaption;
46520
+ let lastProviderError;
46316
46521
  let prevEventAt;
46317
46522
  let lastContextTokens;
46318
46523
  let openCompaction = null;
@@ -46333,6 +46538,20 @@ function projectCodexTranscript(raw2, identityPrefix = "codex") {
46333
46538
  for (const ev of parseCodexLine(line)) {
46334
46539
  const sourceId = `${identityPrefix}:${lineOffset}:${eventOrdinal++}`;
46335
46540
  switch (ev.kind) {
46541
+ case "provider-error": {
46542
+ const fingerprint = JSON.stringify({ ...ev.error, at: void 0 });
46543
+ if (fingerprint === lastProviderError?.fingerprint) {
46544
+ lastProviderError.message.providerError = ev.error;
46545
+ lastProviderError.message.at = ev.at;
46546
+ break;
46547
+ }
46548
+ cur = null;
46549
+ turnReasoning = null;
46550
+ const message = { sourceId, role: "assistant", kind: "event", text: ev.error.message, providerError: ev.error, tools: [], parts: [], at: ev.at };
46551
+ lastProviderError = { fingerprint, message };
46552
+ out.push(message);
46553
+ break;
46554
+ }
46336
46555
  case "assistant-text": {
46337
46556
  let text2 = extractCodexFrizzTitle(ev.text, ev.final).text;
46338
46557
  if (text2) {
@@ -46528,6 +46747,7 @@ ${text2}`;
46528
46747
  break;
46529
46748
  }
46530
46749
  case "turn-start":
46750
+ lastProviderError = void 0;
46531
46751
  sawFinalAnswer = false;
46532
46752
  turnReasoning = null;
46533
46753
  break;