frizz 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/claude-agent-broker.js +141 -12
- package/dist/dev-child.js +869 -333
- package/dist/frizz.js +81 -19
- package/package.json +1 -1
- package/runtime/cc-worker/DECISIONS.md +11 -0
- package/runtime/cc-worker/bin/frizz-mcp.mjs +58 -24
- package/web-dist/assets/{TerminalPane-CNFymHXK.js → TerminalPane-XNji7D_c.js} +1 -1
- package/web-dist/assets/{abnfDiagram-VRR7QNED-DNBrcJfV.js → abnfDiagram-VRR7QNED-gPeb-B7g.js} +1 -1
- package/web-dist/assets/architecture-TIHT7OUA-BsgSgexh.js +1 -0
- package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-SXVydqly.js → architectureDiagram-ZJ3FMSHR-DV69ktbl.js} +1 -1
- package/web-dist/assets/{blockDiagram-677ZJIJ3-CgI1GSdx.js → blockDiagram-677ZJIJ3-D8vw5eim.js} +1 -1
- package/web-dist/assets/{c4Diagram-LMCZKHZV-KDmJm2tG.js → c4Diagram-LMCZKHZV--9PLGn-L.js} +1 -1
- package/web-dist/assets/channel-ClLnncxh.js +1 -0
- package/web-dist/assets/{chunk-32BRIVSS-j3eOjq4Z.js → chunk-32BRIVSS-D4BSk0FZ.js} +1 -1
- package/web-dist/assets/{chunk-52WLFC77-DZHfa78H.js → chunk-52WLFC77-WNcmTkcR.js} +1 -1
- package/web-dist/assets/{chunk-C7G6YPKG-CiB5uo24.js → chunk-C7G6YPKG-BDlcLa5W.js} +1 -1
- package/web-dist/assets/{chunk-EX3LRPZG-B35Inyjz.js → chunk-EX3LRPZG-CFnqFt7s.js} +1 -1
- package/web-dist/assets/{chunk-FWX5IMBZ-D2sRvM5U.js → chunk-FWX5IMBZ-Ci9LgOOg.js} +2 -2
- package/web-dist/assets/{chunk-HOUHSVGY-D247PDv6.js → chunk-HOUHSVGY-BTD_X5OP.js} +1 -1
- package/web-dist/assets/{chunk-ICXQ74PX-Bu3Tb6Ec.js → chunk-ICXQ74PX-D2Y3Ys5K.js} +1 -1
- package/web-dist/assets/{chunk-MOJQB5TN-C_lQy4on.js → chunk-MOJQB5TN-C-GDt7vC.js} +1 -1
- package/web-dist/assets/{chunk-OGEWGWER-DU5ZBedR.js → chunk-OGEWGWER-DvnPoUnz.js} +1 -1
- package/web-dist/assets/{chunk-PUDLZKDR-DWRT7ztS.js → chunk-PUDLZKDR-C3AymM-j.js} +1 -1
- package/web-dist/assets/{chunk-Q4XR5HBZ-CCX4AK_n.js → chunk-Q4XR5HBZ-DmyBNAl6.js} +1 -1
- package/web-dist/assets/{chunk-V7JOEXUC-VbixbkDG.js → chunk-V7JOEXUC-DTuPUeRa.js} +1 -1
- package/web-dist/assets/{chunk-VAUOI2AC-PJvChxMA.js → chunk-VAUOI2AC-CcW8PviB.js} +1 -1
- package/web-dist/assets/{chunk-VR4S4FIN-BjsMfxj8.js → chunk-VR4S4FIN-0tm6n83G.js} +1 -1
- package/web-dist/assets/{chunk-WYO6CB5R-Bcb97r3w.js → chunk-WYO6CB5R-CH3ADqeI.js} +1 -1
- package/web-dist/assets/{chunk-ZGVPDNZ5-CT2sZlhT.js → chunk-ZGVPDNZ5-BHFnlpXH.js} +1 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-CwLnPgud.js +1 -0
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-CwLnPgud.js +1 -0
- package/web-dist/assets/{cynefin-VYW2F7L2-dUpO4u0w.js → cynefin-VYW2F7L2-DtFCLOIN.js} +1 -1
- package/web-dist/assets/{cynefinDiagram-TSTJHNR4-BQZ3UIsx.js → cynefinDiagram-TSTJHNR4-llFTHp2q.js} +1 -1
- package/web-dist/assets/{dagre-VKFMJZFB-K-oO8w51.js → dagre-VKFMJZFB-CvBRVl_k.js} +1 -1
- package/web-dist/assets/{diagram-FQU43EPY-Cr47GJ_S.js → diagram-FQU43EPY-D1QXo6ri.js} +1 -1
- package/web-dist/assets/{diagram-G47NLZAW-BbWzSkoZ.js → diagram-G47NLZAW-2pZew-Bk.js} +1 -1
- package/web-dist/assets/{diagram-NH7WQ7WH-BGJJBgGM.js → diagram-NH7WQ7WH-Ch9JRwGN.js} +1 -1
- package/web-dist/assets/{diagram-OA4YK3LP-2W7aunEN.js → diagram-OA4YK3LP-BIbrLf02.js} +1 -1
- package/web-dist/assets/{diagram-WEI45ONY-D-4ITFI6.js → diagram-WEI45ONY-D3KtL2s-.js} +1 -1
- package/web-dist/assets/{ebnfDiagram-CCIWWBDH-CxUcx103.js → ebnfDiagram-CCIWWBDH-D829sKG_.js} +1 -1
- package/web-dist/assets/{erDiagram-Q63AITRT-Cf_5SWAE.js → erDiagram-Q63AITRT-Cj3Grovg.js} +1 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-CzZyv3HA.js +1 -0
- package/web-dist/assets/flowDiagram-23GEKE2U-rQ7PRoGL.js +1 -0
- package/web-dist/assets/{ganttDiagram-NO4QXBWP-CVZI8Ywa.js → ganttDiagram-NO4QXBWP-CGHaXF-g.js} +1 -1
- package/web-dist/assets/{gitGraph-TEB2WS4Q-BsiGpR9l.js → gitGraph-TEB2WS4Q-BbxeaotX.js} +1 -1
- package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-DVym_4l1.js → gitGraphDiagram-IHSO6WYX-C4WHE0cI.js} +1 -1
- package/web-dist/assets/index-BpCFdr7Z.css +1 -0
- package/web-dist/assets/index-CiaKj-0V.js +506 -0
- package/web-dist/assets/{info-DKCQHKI2-DYcsKFv-.js → info-DKCQHKI2-3fKpn7Qr.js} +1 -1
- package/web-dist/assets/{infoDiagram-FWYZ7A6U-hjVxlrTT.js → infoDiagram-FWYZ7A6U-CDQl4JMv.js} +1 -1
- package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-B0DKOPSS.js → ishikawaDiagram-FXEZZL3T-CDKjMW-u.js} +1 -1
- package/web-dist/assets/{journeyDiagram-5HDEW3XC-Cohibc5O.js → journeyDiagram-5HDEW3XC-BOsabu1Z.js} +1 -1
- package/web-dist/assets/{kanban-definition-HUTT4EX6-_6Zr31vM.js → kanban-definition-HUTT4EX6-KTuh-6eN.js} +1 -1
- package/web-dist/assets/{line-B14EZI6M.js → line-KaxbYSN3.js} +1 -1
- package/web-dist/assets/{mermaid-parser.core-DHkc6cqw.js → mermaid-parser.core-B53huyyd.js} +3 -3
- package/web-dist/assets/{mermaid.core-DuTvdsKf.js → mermaid.core-Bz6B5ouC.js} +3 -3
- package/web-dist/assets/{mindmap-definition-LN4V7U3C-DPRF9pW2.js → mindmap-definition-LN4V7U3C-Bb7T7B3a.js} +1 -1
- package/web-dist/assets/{packet-7NZHBO7P-Ci8oCcGM.js → packet-7NZHBO7P-w3lynC8r.js} +1 -1
- package/web-dist/assets/{pegDiagram-2B236MQR-Cr3ctC6e.js → pegDiagram-2B236MQR-nQ7c2Z03.js} +1 -1
- package/web-dist/assets/{pie-RZYD4A2V-EHgA307y.js → pie-RZYD4A2V-B3Yko5Wb.js} +1 -1
- package/web-dist/assets/{pieDiagram-ENE6RG2P-UW6Bmu6F.js → pieDiagram-ENE6RG2P-CN4Lp5HG.js} +1 -1
- package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-D6tAsRj9.js → quadrantDiagram-ABIIQ3AL-3QTB92dH.js} +1 -1
- package/web-dist/assets/{radar-I7S5WNFK-CAQqojcd.js → radar-I7S5WNFK-8ZsXt0FI.js} +1 -1
- package/web-dist/assets/{railroad-3IZDKUUU-BZsAOTrm.js → railroad-3IZDKUUU-C4IKxzEZ.js} +1 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-g2si5iUv.js +1 -0
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-BikkLG6y.js +1 -0
- package/web-dist/assets/railroad-peg-LSFZ7HO6-Dv4rDehz.js +1 -0
- package/web-dist/assets/{railroadDiagram-RFXS5EU6-bSpff55H.js → railroadDiagram-RFXS5EU6-DrGnmjpD.js} +1 -1
- package/web-dist/assets/{requirementDiagram-TGXJPOKE-DIAYvXoB.js → requirementDiagram-TGXJPOKE-Bh9XNuxa.js} +1 -1
- package/web-dist/assets/{sankeyDiagram-HTMAVEWB-DEnsSz3F.js → sankeyDiagram-HTMAVEWB-CXy3ra5-.js} +1 -1
- package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-DsG7eb9R.js → sequenceDiagram-DBY2YBRQ-B7ESCT52.js} +1 -1
- package/web-dist/assets/{stateDiagram-2N3HPSRC-DT3XNwjo.js → stateDiagram-2N3HPSRC-DFr9k5Xv.js} +1 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BQUd0MEa.js +1 -0
- package/web-dist/assets/{swimlanes-5IMT3BWC-B5hZwgRo.js → swimlanes-5IMT3BWC-B2RKoz1q.js} +1 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-GWn4zXxj.js +8 -0
- package/web-dist/assets/{timeline-definition-FHXFAJF6-BVTsjkfu.js → timeline-definition-FHXFAJF6-KpTqaG5g.js} +1 -1
- package/web-dist/assets/{treeView-QDETBFTQ-M6HmP4bB.js → treeView-QDETBFTQ-oB1a6ikv.js} +1 -1
- package/web-dist/assets/{treemap-6X3UGDF4-C60TppfC.js → treemap-6X3UGDF4-DO8OvvZg.js} +1 -1
- package/web-dist/assets/{vennDiagram-L72KCM5P-Dv1y3g4S.js → vennDiagram-L72KCM5P-BgTjK4_q.js} +1 -1
- package/web-dist/assets/{wardley-OPB4EBWU-D0lMJMWt.js → wardley-OPB4EBWU-CGyjn939.js} +1 -1
- package/web-dist/assets/{wardleyDiagram-EHGQE667-B1E5NtZY.js → wardleyDiagram-EHGQE667-CM_HxruS.js} +1 -1
- package/web-dist/assets/{xychartDiagram-FW5EYKEG-oA91YOvh.js → xychartDiagram-FW5EYKEG-vamHu0jN.js} +1 -1
- package/web-dist/index.html +2 -2
- package/web-dist/assets/architecture-TIHT7OUA-BSUDKbro.js +0 -1
- package/web-dist/assets/channel-DaCOnTxr.js +0 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-BlylbZXV.js +0 -1
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-BlylbZXV.js +0 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-DxKQnZNV.js +0 -1
- package/web-dist/assets/flowDiagram-23GEKE2U-Cdz9YM2Z.js +0 -1
- package/web-dist/assets/index-CYzJK7u0.js +0 -497
- package/web-dist/assets/index-CovJDCWc.css +0 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-_2rSHfPz.js +0 -1
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-xM3eAMFz.js +0 -1
- package/web-dist/assets/railroad-peg-LSFZ7HO6-cZlBUsED.js +0 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-C06v0Ltu.js +0 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-CXyN7ZyO.js +0 -8
package/dist/frizz.js
CHANGED
|
@@ -12462,7 +12462,7 @@ var init_relay_protocol = __esm({
|
|
|
12462
12462
|
function fallbackPort(base) {
|
|
12463
12463
|
return base + 1e4;
|
|
12464
12464
|
}
|
|
12465
|
-
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, AWAITING_FOR_MAX_MS, SnoozeUntil, SNOOZE_PROMPT_MAX, SnoozePrompt, RECURRING_PROMPT_MAX, RECURRING_MIN_INTERVAL_SECONDS, RECURRING_MAX_INTERVAL_SECONDS, RecurringPromptText, RecurringIntervalSeconds, ThreadRecurringPrompt, TIMER_PROMPT_MAX, TIMER_MAX_DELAY_SECONDS, TimerPromptText, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, ThreadWatchView, PR_WATCH_DEFAULT_FOR_MS, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, OwnWatchKind, AddOwnWatchInput, OwnWatchView, AddOwnWatchResult, DropOwnWatchInput, DropOwnWatchResult, AskQuestionKind,
|
|
12465
|
+
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, AWAITING_FOR_MAX_MS, SnoozeUntil, SNOOZE_PROMPT_MAX, SnoozePrompt, RECURRING_PROMPT_MAX, RECURRING_MIN_INTERVAL_SECONDS, RECURRING_MAX_INTERVAL_SECONDS, RecurringPromptText, RecurringIntervalSeconds, ThreadRecurringPrompt, TIMER_PROMPT_MAX, TIMER_MAX_DELAY_SECONDS, TimerPromptText, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, ThreadWatchView, PR_WATCH_FOR_MAX_MS, PR_WATCH_DEFAULT_FOR_MS, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, OwnWatchKind, AddOwnWatchInput, OwnWatchView, AddOwnWatchResult, DropOwnWatchInput, DropOwnWatchResult, AskQuestionKind, AskedOptionSchema, AskedQuestionSchema, AskInput, RegisteredQuestionView, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, 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, HUMAN_GAP_FLOOR_MS, GithubWakeItem, GithubWakeSteer, WAKE_SCOPE, WAKE_REF, WAKE_SINGLE, WAKE_MULTI_HEAD, PR_WATCH_FINISHED, PR_WATCH_CI_PASSED, 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_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT;
|
|
12466
12466
|
var init_src = __esm({
|
|
12467
12467
|
"packages/shared/src/index.ts"() {
|
|
12468
12468
|
"use strict";
|
|
@@ -12742,8 +12742,13 @@ var init_src = __esm({
|
|
|
12742
12742
|
subAgentCount: external_exports.number().default(0),
|
|
12743
12743
|
// total live sub-agents (≥ subAgents.length)
|
|
12744
12744
|
bgShells: external_exports.array(CompletionHoldOp).default([]),
|
|
12745
|
-
bgShellCount: external_exports.number().default(0)
|
|
12745
|
+
bgShellCount: external_exports.number().default(0),
|
|
12746
12746
|
// total live background shells (≥ bgShells.length)
|
|
12747
|
+
// The worker is DEAD and its recorded turn never ended — cut off by a reboot, a signal or a crash
|
|
12748
|
+
// mid-tool-call (router.cutOffHold). Nothing is running, so nothing will be killed; the hold exists
|
|
12749
|
+
// because the thread is not finished and Done would say it was. Optional rather than defaulted so it
|
|
12750
|
+
// is absent (⇒ false) on every hold that is not this one, and a pre-change client reads them unchanged.
|
|
12751
|
+
cutOff: external_exports.boolean().optional()
|
|
12747
12752
|
});
|
|
12748
12753
|
AskOption = external_exports.object({
|
|
12749
12754
|
label: external_exports.string(),
|
|
@@ -12908,7 +12913,8 @@ var init_src = __esm({
|
|
|
12908
12913
|
* known, so a timer row always carries this. */
|
|
12909
12914
|
timer: external_exports.object({ fireAt: external_exports.string(), prompt: external_exports.string() }).strict().optional()
|
|
12910
12915
|
}).strict();
|
|
12911
|
-
|
|
12916
|
+
PR_WATCH_FOR_MAX_MS = 365 * 24 * 60 * 60 * 1e3;
|
|
12917
|
+
PR_WATCH_DEFAULT_FOR_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
12912
12918
|
PrWatchView = external_exports.object({
|
|
12913
12919
|
id: external_exports.string(),
|
|
12914
12920
|
/** `owner/repo#N`, normalized — the same string the board's row and the status book are keyed by. */
|
|
@@ -12923,13 +12929,18 @@ var init_src = __esm({
|
|
|
12923
12929
|
/** `owner/repo#123` or a PR URL. Parsed server-side; an unparseable ref is refused rather than stored,
|
|
12924
12930
|
* because a watcher that can never fire is worse than none — the worker rests believing it is covered. */
|
|
12925
12931
|
target: external_exports.string().trim().min(1).max(200),
|
|
12926
|
-
/** How long to watch, as a DURATION (`
|
|
12932
|
+
/** How long to watch, as a DURATION (`2h`, `3d`, `180d` — parseAwaitingDurationRaw, capped at
|
|
12933
|
+
* PR_WATCH_FOR_MAX_MS).
|
|
12927
12934
|
*
|
|
12928
12935
|
* A PR nobody ever reviews would otherwise be polled forever, and a thread parked on it would wait
|
|
12929
12936
|
* forever with it — the same unbounded wait the awaiting fence's `for:` closes, one level down. A
|
|
12930
12937
|
* duration rather than an instant for the same reason it is one there: it cannot be written in the
|
|
12931
12938
|
* past (maintainer 2026-08-15, asking for it explicitly).
|
|
12932
12939
|
*
|
|
12940
|
+
* BOUNDED IS NOT THE SAME AS SHORT, and conflating them is what made this field a noise source. The
|
|
12941
|
+
* bound exists so a forgotten watcher stops polling eventually, which a year satisfies exactly as
|
|
12942
|
+
* well as a day — and a day spent it against every external PR, which does not move on that clock.
|
|
12943
|
+
*
|
|
12933
12944
|
* REQUIRED BY THE TOOL, OPTIONAL ON THE WIRE, and the asymmetry is deliberate. A worker's MCP server
|
|
12934
12945
|
* outlives every frizz restart, so a session dispatched before this existed still holds a binary that
|
|
12935
12946
|
* cannot send it — and making the RPC reject that would break `watch_pr` outright for every thread
|
|
@@ -12944,6 +12955,12 @@ var init_src = __esm({
|
|
|
12944
12955
|
/** True when this exact PR was ALREADY watched by this thread, so the call registered nothing new.
|
|
12945
12956
|
* Re-registering after a compaction is the common case, and a duplicate would double every wake. */
|
|
12946
12957
|
alreadyArmed: external_exports.boolean(),
|
|
12958
|
+
/** When this watcher runs out. Read back so the worker sees the duration it ACTUALLY got rather than
|
|
12959
|
+
* the one it asked for — on a re-registration that is the original expiry, which the call left alone. */
|
|
12960
|
+
expiresAt: external_exports.string(),
|
|
12961
|
+
/** The `for:` the worker wrote, present ONLY when it exceeded the ceiling and was capped. A clamp
|
|
12962
|
+
* nobody is told about is a worker resting on a year of coverage it does not have. */
|
|
12963
|
+
clampedFrom: external_exports.string().optional(),
|
|
12947
12964
|
watches: external_exports.array(PrWatchView)
|
|
12948
12965
|
}).strict();
|
|
12949
12966
|
DropOwnPrWatchInput = external_exports.object({
|
|
@@ -12970,7 +12987,11 @@ var init_src = __esm({
|
|
|
12970
12987
|
* that is both the stronger check and the one that catches the real mistake: naming a sub-agent under
|
|
12971
12988
|
* `kind: "shell"`, which is what put two sub-agents under a "Background shells" heading on 2026-08-26. */
|
|
12972
12989
|
target: external_exports.string().trim().min(1).max(200),
|
|
12973
|
-
/** REQUIRED, and a DURATION (`30m`, `2h`, `3d` —
|
|
12990
|
+
/** REQUIRED, and a DURATION (`30m`, `2h`, `3d` — parseAwaitingDurationRaw, capped at 24h).
|
|
12991
|
+
*
|
|
12992
|
+
* STILL A DAY, where a PR watcher now gets a year: this names a shell or a sub-agent, which lives
|
|
12993
|
+
* inside the session that launched it, so a wait standing longer than a day is one whose target is
|
|
12994
|
+
* almost certainly already gone.
|
|
12974
12995
|
*
|
|
12975
12996
|
* No default and no wire-level optionality, unlike `AddOwnPrWatchInput.for`: that field is optional
|
|
12976
12997
|
* only to keep working for sessions dispatched before it existed, and this RPC has no such sessions.
|
|
@@ -12995,6 +13016,10 @@ var init_src = __esm({
|
|
|
12995
13016
|
/** True when this exact (kind, target) was already watched, so the call registered nothing new and the
|
|
12996
13017
|
* existing expiry stands. Re-registering after a wake or a compaction is the common, correct case. */
|
|
12997
13018
|
alreadyArmed: external_exports.boolean(),
|
|
13019
|
+
/** The `for:` the worker wrote, present ONLY when it exceeded the ceiling and was capped — the twin of
|
|
13020
|
+
* `AddOwnPrWatchResult.clampedFrom`, for the same reason: a silent clamp is a worker resting on
|
|
13021
|
+
* coverage it does not have. */
|
|
13022
|
+
clampedFrom: external_exports.string().optional(),
|
|
12998
13023
|
watches: external_exports.array(OwnWatchView)
|
|
12999
13024
|
}).strict();
|
|
13000
13025
|
DropOwnWatchInput = external_exports.object({
|
|
@@ -13006,25 +13031,38 @@ var init_src = __esm({
|
|
|
13006
13031
|
watches: external_exports.array(OwnWatchView)
|
|
13007
13032
|
}).strict();
|
|
13008
13033
|
AskQuestionKind = external_exports.enum(["question", "multi"]);
|
|
13009
|
-
ASK_MAX_PER_CALL = 4;
|
|
13010
|
-
ASK_MAX_OPEN = 12;
|
|
13011
13034
|
AskedOptionSchema = external_exports.lazy(() => external_exports.object({
|
|
13012
|
-
|
|
13013
|
-
|
|
13035
|
+
// 400, not the 120 it launched with (2026-09-03): a label is a chip line, but "Post the drafted
|
|
13036
|
+
// comment as written" plus its qualifier runs long, and the fence has no cap at all. The answer's
|
|
13037
|
+
// `chosen` carries labels, so its per-item cap matches this one.
|
|
13038
|
+
label: external_exports.string().trim().min(1).max(400),
|
|
13039
|
+
// 20000, not the 4000 the retired `preview` had (2026-09-03): a description is allowed to BE the rich
|
|
13040
|
+
// body — a diff, a drafted comment, a table — and a real diff exceeds 4000.
|
|
13041
|
+
description: external_exports.string().trim().max(2e4).optional(),
|
|
13014
13042
|
recommended: external_exports.boolean().optional(),
|
|
13015
13043
|
preview: external_exports.string().max(4e3).optional(),
|
|
13016
|
-
|
|
13044
|
+
// No count cap, like `options` (2026-09-03); the tree is bounded by ASK_MAX_DEPTH instead.
|
|
13045
|
+
followUps: external_exports.array(AskedQuestionSchema).optional()
|
|
13017
13046
|
}).strict());
|
|
13018
13047
|
AskedQuestionSchema = external_exports.lazy(() => external_exports.object({
|
|
13019
|
-
|
|
13048
|
+
// 4000, not the 600 it launched with (2026-09-03): this field is the whole card context — everything
|
|
13049
|
+
// the human needs to answer cold — and a question that carries its own evidence needs the room. The
|
|
13050
|
+
// answer restates it, so QuestionAnswerSchema's cap matches.
|
|
13051
|
+
question: external_exports.string().trim().min(1).max(4e3),
|
|
13020
13052
|
header: external_exports.string().trim().max(24).optional(),
|
|
13021
13053
|
kind: AskQuestionKind,
|
|
13022
13054
|
danger: external_exports.boolean().optional(),
|
|
13023
|
-
|
|
13055
|
+
// UNBOUNDED, deliberately. This carried `.max(8)` from launch until 2026-09-03, when the maintainer
|
|
13056
|
+
// asked for the cap to go ("allow arbitrary numbers of options"): a `multi` over a long list — which
|
|
13057
|
+
// gates to run, which of twenty findings to act on — is a real shape, and the card letters past 26
|
|
13058
|
+
// (`AA.`) already. The count is the worker's to choose; the answer's `chosen` is unbounded to match.
|
|
13059
|
+
options: external_exports.array(AskedOptionSchema).optional()
|
|
13024
13060
|
}).strict());
|
|
13025
13061
|
AskInput = external_exports.object({
|
|
13026
13062
|
slug: ThreadSlug,
|
|
13027
|
-
|
|
13063
|
+
// No cap on the count (four until 2026-09-03): the tool's own text says "several at once is one
|
|
13064
|
+
// call — register them together", and a cap here told a worker with six to batch and then refused it.
|
|
13065
|
+
questions: external_exports.array(AskedQuestionSchema).min(1)
|
|
13028
13066
|
}).strict();
|
|
13029
13067
|
RegisteredQuestionView = external_exports.object({
|
|
13030
13068
|
/** Minted by frizz. The worker never chose it, which is why an answer RESTATES the question text —
|
|
@@ -13048,17 +13086,19 @@ var init_src = __esm({
|
|
|
13048
13086
|
}).strict();
|
|
13049
13087
|
QuestionAnswerSchema = external_exports.lazy(() => external_exports.object({
|
|
13050
13088
|
questionId: external_exports.string().min(1).max(64),
|
|
13051
|
-
question: external_exports.string().min(1).max(
|
|
13052
|
-
|
|
13089
|
+
question: external_exports.string().min(1).max(4e3),
|
|
13090
|
+
// No count cap: a `multi` may carry any number of options (see AskedQuestionSchema), and the human
|
|
13091
|
+
// may pick every one of them. The per-item cap is the option label's.
|
|
13092
|
+
chosen: external_exports.array(external_exports.string().max(400)),
|
|
13053
13093
|
text: external_exports.string().max(8e3).optional(),
|
|
13054
|
-
followUps: external_exports.array(QuestionAnswerSchema).
|
|
13094
|
+
followUps: external_exports.array(QuestionAnswerSchema).optional()
|
|
13055
13095
|
}).strict());
|
|
13056
13096
|
AnswerQuestionsInput = external_exports.object({
|
|
13057
13097
|
slug: ThreadSlug,
|
|
13058
13098
|
/** SUBMITTED AS A UNIT. The card sends whatever was answered in one call, because a per-question send
|
|
13059
13099
|
* would half-wake a turn: the worker would come back to a payload it cannot act on and would have to
|
|
13060
13100
|
* ask again for the rest. */
|
|
13061
|
-
answers: external_exports.array(QuestionAnswerSchema).min(1)
|
|
13101
|
+
answers: external_exports.array(QuestionAnswerSchema).min(1)
|
|
13062
13102
|
}).strict();
|
|
13063
13103
|
AnswerQuestionsResult = external_exports.object({
|
|
13064
13104
|
/** The ids that were open and are now answered. An id that was already settled is silently absent
|
|
@@ -13068,7 +13108,7 @@ var init_src = __esm({
|
|
|
13068
13108
|
}).strict();
|
|
13069
13109
|
DismissQuestionsInput = external_exports.object({
|
|
13070
13110
|
slug: ThreadSlug,
|
|
13071
|
-
ids: external_exports.array(external_exports.string().min(1).max(64)).min(1)
|
|
13111
|
+
ids: external_exports.array(external_exports.string().min(1).max(64)).min(1)
|
|
13072
13112
|
}).strict();
|
|
13073
13113
|
DismissQuestionsResult = external_exports.object({
|
|
13074
13114
|
dismissed: external_exports.array(external_exports.string()),
|
|
@@ -13248,6 +13288,11 @@ var init_src = __esm({
|
|
|
13248
13288
|
// AUTO-bump (the scheduler resumes the agent with exactly this text) rather than a reminder, which is
|
|
13249
13289
|
// the distinction the held row's tooltip renders. Absent ⇒ the card merely re-surfaces.
|
|
13250
13290
|
snoozePrompt: external_exports.string().optional(),
|
|
13291
|
+
// The instant the human PINNED this thread (absent = not pinned). A pinned thread leaves the rail's
|
|
13292
|
+
// band system entirely — Rested/Active/Snoozed/Done — and holds the pinned band at the very top, in
|
|
13293
|
+
// this instant's order. Lifecycle metadata like the snooze: written only by the pin/unpin verb, and
|
|
13294
|
+
// it outranks every derived state (a pinned thread that finishes stays pinned).
|
|
13295
|
+
pinnedAt: external_exports.string().optional(),
|
|
13251
13296
|
/** The EVENT snooze on the resting card is armed for this exact rest — the human has said "hide this
|
|
13252
13297
|
* until something reports". Distinct from `snoozedUntil`, which is a wall-clock park on the whole
|
|
13253
13298
|
* thread: this one has no deadline and clears itself when the thread comes to a NEW rest.
|
|
@@ -13493,6 +13538,12 @@ var init_src = __esm({
|
|
|
13493
13538
|
// Code caps to the model's real window. Optional so an old blob parses; defaultSettings pins 500_000
|
|
13494
13539
|
// (maintainer 2026-08-26: "a default compaction window of 500k by default").
|
|
13495
13540
|
autoCompactWindow: external_exports.number().int().positive().optional(),
|
|
13541
|
+
// The prompt-cache tier a NEW Claude worker writes to. "auto" leaves the CLI's own choice (1h on a
|
|
13542
|
+
// subscription); "5m" and "1h" reach the worker as CLAUDE_CODE_PROMPT_CACHE_TTL (and the sub-agent
|
|
13543
|
+
// twin). The 1h tier bills a cache write at 2x input against 1.25x for 5m; on 2026-09-03 cache
|
|
13544
|
+
// writes were 51% of a day's spend while the entries were invalidated every 15–30 minutes anyway
|
|
13545
|
+
// (see claudePromptCacheEnv). Optional so an old blob parses; defaultSettings pins "auto".
|
|
13546
|
+
promptCacheTtl: external_exports.enum(["auto", "5m", "1h"]).optional(),
|
|
13496
13547
|
// The GitHub batch-dispatch prompt template (the picker's per-item worker prompt). Optional: when
|
|
13497
13548
|
// unset OR blank the server falls back to its exported DEFAULT_GITHUB_PROMPT. Substitution tokens
|
|
13498
13549
|
// the server fills: {repo} {n} {title} {url} {labels} {body}. The leading `THREAD: <slug>` tag is
|
|
@@ -13631,6 +13682,11 @@ var init_src = __esm({
|
|
|
13631
13682
|
// can never leave an armed prompt behind.
|
|
13632
13683
|
prompt: SnoozePrompt.nullable().optional()
|
|
13633
13684
|
}).strict();
|
|
13685
|
+
SetThreadPinnedInput = external_exports.object({
|
|
13686
|
+
slug: ThreadSlug,
|
|
13687
|
+
sessionId: external_exports.string().min(1),
|
|
13688
|
+
pinned: external_exports.boolean()
|
|
13689
|
+
}).strict();
|
|
13634
13690
|
SetThreadRecurringPromptInput = external_exports.object({
|
|
13635
13691
|
slug: ThreadSlug,
|
|
13636
13692
|
sessionId: external_exports.string().min(1),
|
|
@@ -14311,10 +14367,16 @@ ${DISPATCH_TASK_BANNER}
|
|
|
14311
14367
|
cursor: TranscriptPageCursor
|
|
14312
14368
|
}).strict();
|
|
14313
14369
|
SocketTranscriptSlug = ThreadSlug;
|
|
14314
|
-
|
|
14370
|
+
SocketFilePath = external_exports.string().min(1).max(4096);
|
|
14371
|
+
SocketTranscriptClientMsg = external_exports.discriminatedUnion("t", [
|
|
14315
14372
|
external_exports.object({ t: external_exports.literal("sub"), topic: external_exports.literal("transcript"), slug: SocketTranscriptSlug }).strict(),
|
|
14316
14373
|
external_exports.object({ t: external_exports.literal("unsub"), topic: external_exports.literal("transcript"), slug: SocketTranscriptSlug }).strict()
|
|
14317
14374
|
]);
|
|
14375
|
+
SocketFileClientMsg = external_exports.discriminatedUnion("t", [
|
|
14376
|
+
external_exports.object({ t: external_exports.literal("sub"), topic: external_exports.literal("file"), path: SocketFilePath }).strict(),
|
|
14377
|
+
external_exports.object({ t: external_exports.literal("unsub"), topic: external_exports.literal("file"), path: SocketFilePath }).strict()
|
|
14378
|
+
]);
|
|
14379
|
+
SocketClientMsg = external_exports.union([SocketTranscriptClientMsg, SocketFileClientMsg]);
|
|
14318
14380
|
ProjectCard = external_exports.object({
|
|
14319
14381
|
id: external_exports.string(),
|
|
14320
14382
|
slug: external_exports.string(),
|
package/package.json
CHANGED
|
@@ -1147,3 +1147,14 @@ Two corrections from one maintainer thread, both about Frizz telling the worker
|
|
|
1147
1147
|
|
|
1148
1148
|
- **`recurring_prompt` is renamed `goal`.** The board panel, the footer mark and the delivered trailer have all said "Goal" since 2026-08-11; only the MCP tool still carried the mechanism's name. Maintainer: *"I don't think the tool is even called Recurring Prompt anymore, is it?"* — then *"Rename it."* Only the TOOL name and the worker-facing wording changed: the RPC procedures (`setOwnThreadRecurringPrompt`, `getOwnThreadRecurringPrompt`) and the `session.recurring_*` columns keep their names, because renaming the procedure is exactly what stranded every in-flight worker the last time (see the legacy aliases in `@frizz/shared`). No alias tool is listed for the old name — Claude Code rejects a tool name it has not listed, so an alias would have to be a visible second tool forever — and the new tool's description names its former name once, for a resumed worker whose summary still says `recurring_prompt`.
|
|
1149
1149
|
- **Every surface that mentions the scratch directory stopped prescribing the notes-plus-arming arrangement.** The 2026-08-06 entry above set the rule "every surface that mentions the directory also mentions `post_compaction: true`", and it produced the effect the maintainer noticed: workers armed the post-compaction goal constantly, 49 of the 65 armed prompts in the live db copying the contract's template sentence verbatim. Maintainer: *"this is a very opinionated thing, and I don't think we should be pushing it as the thing to do. We should just be saying that the scratch directory is available to it if it wants it. We can also be saying that it can set these goal hooks."* The contract's scratch sections, the dispatch preamble, `scratchpadOrientation`, the five `scratchpad.mjs` hook texts and the tool's own `post_compaction` wording now say the directory and the goal hooks EXIST and leave the choice to the worker. The literal `post_compaction: true` stays on each surface so the capability is still discoverable; the nudge hook keeps its ~60k-token cadence with the informational wording.
|
|
1150
|
+
|
|
1151
|
+
## 2026-09-03: a worker mounts ONLY what its project declares — `--strict-mcp-config`, with the project's `.mcp.json` carried inline
|
|
1152
|
+
|
|
1153
|
+
Maintainer, the evening of two memory crashes (a jetsam spiral into a watchdog panic at 19:50, a forced power-off at 20:52): *"Very weird that Frizz eagerly spawns Chrome DevTools."* It was not Frizz. It was the CLI's own discovery doing exactly what the 2026-08-26 entry above asked of it — in every worker at once.
|
|
1154
|
+
|
|
1155
|
+
Measured on the maintainer's machine 2026-09-02, nine live workers: the user-scope `chrome-real` (`claude mcp add --scope user`, an npx chrome-devtools-mcp) and each project's `chrome-devtools` (`.mcp.json`) both booted in EVERY worker — 18 browser servers, 36 processes, 4.2 GB, and 61 thirty-second MCP connection timeouts inside the crash window. The 2026-08-26 line *"Frizz's `--mcp-config` ADDS to whatever the CLI discovered rather than replacing it (frizz never passes `--strict-mcp-config`)"* was written so a project and an operator could each bring a browser. It also meant a fleet multiplied the operator's personal servers by N.
|
|
1156
|
+
|
|
1157
|
+
- **Every worker now launches under `--strict-mcp-config`** (`strictMcpConfig: true` on the SDK path, the flag on the argv path) and is handed its whole MCP surface inline, lowest precedence first: the operator's REMOTE user-scope servers (`type: http`/`sse` in `~/.claude.json` — a URL costs no process), the project's `.mcp.json` filtered by the same approval the CLI applies (`enableAllProjectMcpServers` / `enabledMcpjsonServers` / `disabledMcpjsonServers`, every layer unioned), then the `frizz` server, which wins a name collision. `packages/server/src/backend/project-mcp-servers.ts` is the rule and the reasons; the daemon reads it at every fork, so a `.mcp.json` edit reaches the next dispatch as it reaches the next plain `claude`.
|
|
1158
|
+
- **User-scope STDIO servers are the one thing a worker no longer inherits.** `claude mcp add --scope user` still reaches the operator's own sessions. A project that wants one in its fleet declares it in its `.mcp.json` — the scope that means "this repo's sessions".
|
|
1159
|
+
- **Nothing about settings changed.** `settingSources` stays `user,project,local` (the 2026-08-16 entry): auth, permissions, hooks, plugins and `CLAUDE.md` all still reach a worker. Only MCP discovery is replaced, and only with what discovery would have produced minus the operator's local processes.
|
|
1160
|
+
- **What this does not fix.** Twelve threads restarted at once are still ~9 processes and ~1 GB each before any of them runs a build; the crash was the aggregate, and this removes its largest avoidable term. A dispatch-time back-pressure check is the follow-up.
|
|
@@ -271,7 +271,13 @@ const WATCH_PR = {
|
|
|
271
271
|
"wait at all. This tool is the wait.\n\n" +
|
|
272
272
|
"THE ```awaiting FENCE IS STILL WORTH WRITING, and it is a different job: it is how you come to REST " +
|
|
273
273
|
"without frizz asking you for a handoff, and how the human sees what you are waiting for. Register " +
|
|
274
|
-
"the watcher with this tool, then name the same PR in your fence's `prs:` list
|
|
274
|
+
"the watcher with this tool, then name the same PR in your fence's `prs:` list — and give the fence " +
|
|
275
|
+
"the same long `for:` you gave the watcher, or the fence expires first and bumps you anyway.\n\n" +
|
|
276
|
+
"GIVE AN EXTERNAL PR A LONG `for` — MONTHS, up to a year. A pull request into a repo nobody here " +
|
|
277
|
+
"controls moves on its maintainers' clock, not yours, and a short watcher on one expires against a " +
|
|
278
|
+
"PR that has not changed: a wake with nothing in it, and a re-arm. Long costs nothing — real " +
|
|
279
|
+
"activity still wakes you the instant it lands, and the human snoozes or archives the thread if " +
|
|
280
|
+
"they want it off the board.\n\n" +
|
|
275
281
|
"REGISTERING IS IDEMPOTENT per pull request: asking twice returns the SAME id and tells you it was " +
|
|
276
282
|
"already armed, so re-registering after a compaction is safe and is the right instinct. Use `list` " +
|
|
277
283
|
"when you want to know what you are holding without changing anything — it answers with each PR's " +
|
|
@@ -299,10 +305,18 @@ const WATCH_PR = {
|
|
|
299
305
|
for: {
|
|
300
306
|
type: "string",
|
|
301
307
|
description:
|
|
302
|
-
"REQUIRED for `add`. How long to watch, as a DURATION — `
|
|
303
|
-
"instant, and there is no default.
|
|
304
|
-
"and
|
|
305
|
-
"and
|
|
308
|
+
"REQUIRED for `add`. How long to watch, as a DURATION — `2h`, `3d`, `180d` (max 365d). Never " +
|
|
309
|
+
"an instant, and there is no default. The watcher settles itself when this runs out and tells " +
|
|
310
|
+
"you, and you re-register if you still care.\n\n" +
|
|
311
|
+
"MATCH IT TO WHOSE PR IT IS, and the two cases are far apart. Your own PR, waiting on CI or on " +
|
|
312
|
+
"a review you expect today: hours. A PULL REQUEST IN A REPO NOBODY HERE CONTROLS — an upstream " +
|
|
313
|
+
"project, someone else's maintainers — takes as long as it takes, so give it MONTHS (`90d`, " +
|
|
314
|
+
"`180d`, `365d`). A short `for` on one of those does not make it get reviewed sooner; it just " +
|
|
315
|
+
"expires against a PR nothing has touched, wakes you for nothing, and costs a re-arm. That is " +
|
|
316
|
+
"not hypothetical — a watcher on an external PR re-armed at the old 24h ceiling four days " +
|
|
317
|
+
"running, with zero maintainer activity in between. Long is FREE here: real activity wakes you " +
|
|
318
|
+
"the moment it happens either way, and the human can snooze or archive the thread whenever " +
|
|
319
|
+
"they want it gone.",
|
|
306
320
|
},
|
|
307
321
|
id: {
|
|
308
322
|
type: "string",
|
|
@@ -368,7 +382,9 @@ const WATCH = {
|
|
|
368
382
|
"REQUIRED. How long to hold the wait, as a DURATION — `30m`, `2h`, `3d` (max 24h). Never an " +
|
|
369
383
|
"instant, and there is no default: choose it for THIS wait. When it elapses the row is " +
|
|
370
384
|
"cancelled and you are woken to re-decide, so an over-long guess costs a wait that outlives " +
|
|
371
|
-
"its reason and a too-short one costs one extra turn."
|
|
385
|
+
"its reason and a too-short one costs one extra turn. The ceiling is a DAY here, unlike " +
|
|
386
|
+
"`watch_pr`'s year: a shell or a sub-agent dies with this session, so a wait on one that has " +
|
|
387
|
+
"stood for a day is a wait on something already gone.",
|
|
372
388
|
},
|
|
373
389
|
},
|
|
374
390
|
required: ["kind", "target", "for"],
|
|
@@ -414,8 +430,12 @@ function questionSchema(depth) {
|
|
|
414
430
|
description: {
|
|
415
431
|
type: "string",
|
|
416
432
|
description:
|
|
417
|
-
"
|
|
418
|
-
"
|
|
433
|
+
"The trade-off, or the evidence — and it renders INSIDE the option, always visible, so this " +
|
|
434
|
+
"is where the human learns what they are choosing BEFORE they pick anything. One line for a " +
|
|
435
|
+
"simple fork. FULL MARKDOWN, over several lines, for one that deserves it: a list of " +
|
|
436
|
+
"consequences, a code block, the diff the option would produce, the exact message that would " +
|
|
437
|
+
"be posted. An option list with no trade-offs asks the human to reconstruct your reasoning " +
|
|
438
|
+
"before they can choose.",
|
|
419
439
|
},
|
|
420
440
|
recommended: {
|
|
421
441
|
type: "boolean",
|
|
@@ -425,18 +445,16 @@ function questionSchema(depth) {
|
|
|
425
445
|
"YOU ARE ASKING: you already know the answer, so implement it and say which way you went. " +
|
|
426
446
|
"This is for the fork you genuinely cannot take yourself.",
|
|
427
447
|
},
|
|
428
|
-
preview
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
"message that would be posted, the mockup. Use it when SEEING the outcome is what decides the " +
|
|
433
|
-
"question; skip it when the one-line trade-off already says everything.",
|
|
434
|
-
},
|
|
448
|
+
// `preview` (markdown revealed under the option once picked) is RETIRED from this schema
|
|
449
|
+
// (2026-09-01): detail that decides a choice must be visible before the choice, so it belongs in
|
|
450
|
+
// a rich `description` now. The server still ACCEPTS the field — an in-flight worker dispatched
|
|
451
|
+
// against the old schema keeps working, and the card folds it into the same always-visible body.
|
|
435
452
|
...(depth < ASK_MAX_DEPTH
|
|
436
453
|
? {
|
|
454
|
+
// No `maxItems` here either (four until 2026-09-03): the tree is bounded by its DEPTH, not
|
|
455
|
+
// by how many branches hang off one option.
|
|
437
456
|
followUps: {
|
|
438
457
|
type: "array",
|
|
439
|
-
maxItems: 4,
|
|
440
458
|
description:
|
|
441
459
|
"Questions that become live ONLY if the human picks this option — the conditional " +
|
|
442
460
|
"branch. A branch nobody takes is never asked and never answered, so this is how you " +
|
|
@@ -479,10 +497,13 @@ function questionSchema(depth) {
|
|
|
479
497
|
"x cannot dismiss it, because a generic close icon is not consent for something irreversible. " +
|
|
480
498
|
"Declining must therefore be one of your own options.",
|
|
481
499
|
},
|
|
500
|
+
// No `maxItems`: the count is the worker's to choose (maintainer 2026-09-03 — "allow arbitrary
|
|
501
|
+
// numbers of options"). A `multi` over a long list is a real shape, and the card letters past 26.
|
|
482
502
|
options: {
|
|
483
503
|
type: "array",
|
|
484
|
-
|
|
485
|
-
|
|
504
|
+
description:
|
|
505
|
+
"As many as the choice actually has — a fork of two, or a `multi` over twenty findings. " +
|
|
506
|
+
"Omit entirely for a free-text question.",
|
|
486
507
|
items: option,
|
|
487
508
|
},
|
|
488
509
|
},
|
|
@@ -530,10 +551,11 @@ const ASK = {
|
|
|
530
551
|
inputSchema: {
|
|
531
552
|
type: "object",
|
|
532
553
|
properties: {
|
|
554
|
+
// No `maxItems` (four until 2026-09-03): "several at once is one call" above, and a cap here told
|
|
555
|
+
// a worker with six to batch them and then refused the batch.
|
|
533
556
|
questions: {
|
|
534
557
|
type: "array",
|
|
535
558
|
minItems: 1,
|
|
536
|
-
maxItems: 4,
|
|
537
559
|
description: "The questions to register, together. Each becomes its own card and its own row.",
|
|
538
560
|
items: questionSchema(1),
|
|
539
561
|
},
|
|
@@ -1299,8 +1321,13 @@ async function watch(args) {
|
|
|
1299
1321
|
? `Already watching \`${target}\` as ${id} — nothing new was registered, and its original expiry stands.`
|
|
1300
1322
|
: `Watching \`${target}\` as ${id}. Your thread is held out of the queue until it finishes, and the ` +
|
|
1301
1323
|
"registration survives your turn ending, a compaction and a frizz restart."
|
|
1324
|
+
// A clamp is news here for the same reason it is on `watch_pr` — see that handler.
|
|
1325
|
+
const clamped = result?.clampedFrom
|
|
1326
|
+
? `\n\nYOUR \`for: ${result.clampedFrom}\` WAS CAPPED at the 24h ceiling for a shell or a sub-agent — ` +
|
|
1327
|
+
"the expiry listed below is what you actually hold."
|
|
1328
|
+
: ""
|
|
1302
1329
|
return (
|
|
1303
|
-
`${head}\n\nWHEN \`for\` RUNS OUT the row is CANCELLED and you are woken to re-decide — register ` +
|
|
1330
|
+
`${head}${clamped}\n\nWHEN \`for\` RUNS OUT the row is CANCELLED and you are woken to re-decide — register ` +
|
|
1304
1331
|
`again if you still mean it.\n\nDROP IT the moment it stops mattering (\`unwatch\`, id \`${id}\`); ` +
|
|
1305
1332
|
`you do NOT need to when the work simply finishes.\n\n${armedWatchList(result)}`
|
|
1306
1333
|
)
|
|
@@ -1436,12 +1463,19 @@ async function watchPr(args) {
|
|
|
1436
1463
|
const result = (await callRpc("addOwnPrWatch", { slug, target, for: typeof args.for === "string" ? args.for.trim() : "" }))?.result
|
|
1437
1464
|
const id = result?.id ?? "(unknown)"
|
|
1438
1465
|
const ref = result?.target ?? target
|
|
1466
|
+
const until = result?.expiresAt ? ` until ${result.expiresAt}` : ""
|
|
1439
1467
|
const head = result?.alreadyArmed
|
|
1440
|
-
? `Already watching ${ref} as ${id} — nothing new was registered, and you will be woken once per event.`
|
|
1441
|
-
: `Watching ${ref} as ${id}. Frizz wakes you when CI passes or fails and on every later
|
|
1442
|
-
"comment, and the registration survives your turn ending, a compaction and a frizz restart."
|
|
1468
|
+
? `Already watching ${ref} as ${id}${until} — nothing new was registered, its original expiry stands, and you will be woken once per event.`
|
|
1469
|
+
: `Watching ${ref} as ${id}${until}. Frizz wakes you when CI passes or fails and on every later ` +
|
|
1470
|
+
"review or comment, and the registration survives your turn ending, a compaction and a frizz restart."
|
|
1471
|
+
// A CLAMP IS NEWS. Silently handing back less coverage than was asked for is how a worker comes to
|
|
1472
|
+
// rest believing it is watched for a year when it is watched for one day.
|
|
1473
|
+
const clamped = result?.clampedFrom
|
|
1474
|
+
? `\n\nYOUR \`for: ${result.clampedFrom}\` WAS CAPPED at the ceiling — the expiry above is what you ` +
|
|
1475
|
+
"actually hold. Nothing else about the watcher changed."
|
|
1476
|
+
: ""
|
|
1443
1477
|
return (
|
|
1444
|
-
`${head}\n\nNAME IT IN YOUR \`\`\`awaiting FENCE TOO (\`prs: [${ref}]\`) — the watcher does the ` +
|
|
1478
|
+
`${head}${clamped}\n\nNAME IT IN YOUR \`\`\`awaiting FENCE TOO (\`prs: [${ref}]\`) — the watcher does the ` +
|
|
1445
1479
|
`waking, the fence is what lets you come to rest and shows the human what you are waiting for.\n\n` +
|
|
1446
1480
|
`DROP IT when it stops mattering (\`action: "drop", id: "${id}"\`).\n\n${armedPrWatchList(result)}`
|
|
1447
1481
|
)
|