frizz 0.7.8 → 0.8.1
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/README.md +5 -0
- package/dist/claude-agent-broker.js +65 -5
- package/dist/dev-child.js +457 -553
- package/dist/frizz.js +96 -9
- package/package.json +1 -1
- package/runtime/cc-worker/.claude-plugin/plugin.json +1 -1
- package/runtime/cc-worker/DECISIONS.md +29 -1
- package/runtime/cc-worker/agents/high.md +7 -0
- package/runtime/cc-worker/agents/low.md +7 -0
- package/runtime/cc-worker/agents/max.md +7 -0
- package/runtime/cc-worker/agents/medium.md +7 -0
- package/runtime/cc-worker/agents/xhigh.md +7 -0
- package/runtime/cc-worker/hooks/agent-dispatch.mjs +10 -9
- package/runtime/cc-worker/hooks/hooks.json +0 -2
- package/runtime/cc-worker/hooks/scratchpad.mjs +5 -3
- package/runtime/cc-worker/hooks/session-seed.mjs +17 -17
- package/runtime/cc-worker/skills/gh/SKILL.md +5 -19
- package/web-dist/assets/{TerminalPane-ubcEP7X3.js → TerminalPane-BM_laA_I.js} +1 -1
- package/web-dist/assets/{abnfDiagram-VRR7QNED-0brfnieb.js → abnfDiagram-VRR7QNED-C5FCLi1n.js} +1 -1
- package/web-dist/assets/architecture-TIHT7OUA-ngY1F0r2.js +1 -0
- package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-Dji-XBdF.js → architectureDiagram-ZJ3FMSHR-Dm7tUnwt.js} +1 -1
- package/web-dist/assets/{blockDiagram-677ZJIJ3-BQMyz3Q9.js → blockDiagram-677ZJIJ3-3EhpmwKM.js} +1 -1
- package/web-dist/assets/{c4Diagram-LMCZKHZV-BMNws0Oi.js → c4Diagram-LMCZKHZV-Ca-BjDxw.js} +1 -1
- package/web-dist/assets/channel-BpyNaJoi.js +1 -0
- package/web-dist/assets/{chunk-32BRIVSS-CVv1ae7n.js → chunk-32BRIVSS-xGbaUlTN.js} +1 -1
- package/web-dist/assets/{chunk-52WLFC77-BYhPlKCT.js → chunk-52WLFC77-YYhE3F1a.js} +1 -1
- package/web-dist/assets/{chunk-C7G6YPKG-Cn4HhNwb.js → chunk-C7G6YPKG-SYKXFtUg.js} +1 -1
- package/web-dist/assets/{chunk-EX3LRPZG-P3ZYFC1W.js → chunk-EX3LRPZG-cqjtdM_c.js} +1 -1
- package/web-dist/assets/{chunk-FWX5IMBZ-Ba3NpEQa.js → chunk-FWX5IMBZ-qyaTngKT.js} +2 -2
- package/web-dist/assets/{chunk-HOUHSVGY-BCWyMhwJ.js → chunk-HOUHSVGY-DBFt1HnE.js} +1 -1
- package/web-dist/assets/{chunk-ICXQ74PX-DWAAqHL7.js → chunk-ICXQ74PX-Bme_2_gm.js} +1 -1
- package/web-dist/assets/{chunk-MOJQB5TN-pc5VJ4Nq.js → chunk-MOJQB5TN-DupTmWhN.js} +1 -1
- package/web-dist/assets/{chunk-OGEWGWER-DUxmbiuX.js → chunk-OGEWGWER-DSqmbKCq.js} +1 -1
- package/web-dist/assets/{chunk-PUDLZKDR-DRdZWzxX.js → chunk-PUDLZKDR-DVnHUoFN.js} +1 -1
- package/web-dist/assets/{chunk-Q4XR5HBZ-Bafzu7s-.js → chunk-Q4XR5HBZ-BIZh_Yuh.js} +1 -1
- package/web-dist/assets/{chunk-V7JOEXUC-Bj0A8ftW.js → chunk-V7JOEXUC-e2G7UgOg.js} +1 -1
- package/web-dist/assets/{chunk-VAUOI2AC-DBgVQKIO.js → chunk-VAUOI2AC-uYgyYWPh.js} +1 -1
- package/web-dist/assets/{chunk-VR4S4FIN-DU-1KtuM.js → chunk-VR4S4FIN-BjGjcexQ.js} +1 -1
- package/web-dist/assets/{chunk-WYO6CB5R-DzVb3-Rj.js → chunk-WYO6CB5R-BKKd_W3B.js} +1 -1
- package/web-dist/assets/{chunk-ZGVPDNZ5-BPKQvduj.js → chunk-ZGVPDNZ5-D5_hsjnF.js} +1 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-DTEWwxt7.js +1 -0
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-DTEWwxt7.js +1 -0
- package/web-dist/assets/{cynefin-VYW2F7L2-lo8PqVCk.js → cynefin-VYW2F7L2-bkFv7EpV.js} +1 -1
- package/web-dist/assets/{cynefinDiagram-TSTJHNR4-BtQLaDV0.js → cynefinDiagram-TSTJHNR4-Du2-dyuZ.js} +1 -1
- package/web-dist/assets/{dagre-VKFMJZFB-BJ2-f-A0.js → dagre-VKFMJZFB-CU7w00Ul.js} +1 -1
- package/web-dist/assets/{diagram-FQU43EPY-CLM-8r74.js → diagram-FQU43EPY-BxvVgxWb.js} +1 -1
- package/web-dist/assets/{diagram-G47NLZAW-CfuoJGpN.js → diagram-G47NLZAW-D8VvetwQ.js} +1 -1
- package/web-dist/assets/{diagram-NH7WQ7WH-DfxxRwH8.js → diagram-NH7WQ7WH-CwsChkED.js} +1 -1
- package/web-dist/assets/{diagram-OA4YK3LP-D7knxZee.js → diagram-OA4YK3LP-BIPYbe6L.js} +1 -1
- package/web-dist/assets/{diagram-WEI45ONY-C2WfMXWl.js → diagram-WEI45ONY-BoyH4dKl.js} +1 -1
- package/web-dist/assets/{ebnfDiagram-CCIWWBDH-DRSZ24tF.js → ebnfDiagram-CCIWWBDH-9A3WRDfU.js} +1 -1
- package/web-dist/assets/{erDiagram-Q63AITRT-DXe0OrbY.js → erDiagram-Q63AITRT-D3Y9WA4H.js} +1 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-D7g9kDF0.js +1 -0
- package/web-dist/assets/flowDiagram-23GEKE2U-BqKnxVr3.js +1 -0
- package/web-dist/assets/{ganttDiagram-NO4QXBWP-wGqOgjvs.js → ganttDiagram-NO4QXBWP-Bk2-LClm.js} +1 -1
- package/web-dist/assets/{gitGraph-TEB2WS4Q-BygokG6y.js → gitGraph-TEB2WS4Q-CXvPrsio.js} +1 -1
- package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-CV1933_M.js → gitGraphDiagram-IHSO6WYX-BC9D72kT.js} +1 -1
- package/web-dist/assets/index-CCtNIGi6.js +491 -0
- package/web-dist/assets/index-Cq79m8AR.css +1 -0
- package/web-dist/assets/{info-DKCQHKI2-DLavbzui.js → info-DKCQHKI2-Beag76kE.js} +1 -1
- package/web-dist/assets/{infoDiagram-FWYZ7A6U-Biouxd9G.js → infoDiagram-FWYZ7A6U-DaqYXHYB.js} +1 -1
- package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-DJxwwS3R.js → ishikawaDiagram-FXEZZL3T-D-d4tmLU.js} +1 -1
- package/web-dist/assets/{journeyDiagram-5HDEW3XC-Clx_WkdW.js → journeyDiagram-5HDEW3XC-kkFYzNg1.js} +1 -1
- package/web-dist/assets/{kanban-definition-HUTT4EX6-Bf7bX_96.js → kanban-definition-HUTT4EX6-BYRPjbfv.js} +1 -1
- package/web-dist/assets/{line-CV2v49IN.js → line-C8l7y6rG.js} +1 -1
- package/web-dist/assets/{mermaid-parser.core-BPsFhEi6.js → mermaid-parser.core-BG3fgy77.js} +3 -3
- package/web-dist/assets/{mermaid.core-0EWDNL_R.js → mermaid.core-BCDzcbhr.js} +3 -3
- package/web-dist/assets/{mindmap-definition-LN4V7U3C-C1y4yy3Z.js → mindmap-definition-LN4V7U3C-CP_bgQm8.js} +1 -1
- package/web-dist/assets/{packet-7NZHBO7P-CpcpxruB.js → packet-7NZHBO7P-Dgd69pFS.js} +1 -1
- package/web-dist/assets/{pegDiagram-2B236MQR-CVlVP4cH.js → pegDiagram-2B236MQR-BJUb_DOD.js} +1 -1
- package/web-dist/assets/{pie-RZYD4A2V-BcVPOhTZ.js → pie-RZYD4A2V-DPbVRAuL.js} +1 -1
- package/web-dist/assets/{pieDiagram-ENE6RG2P-DZv4Tfae.js → pieDiagram-ENE6RG2P-DavUeOqM.js} +1 -1
- package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-DOzS_U_a.js → quadrantDiagram-ABIIQ3AL-BdvoSedu.js} +1 -1
- package/web-dist/assets/{radar-I7S5WNFK-8YADxkdT.js → radar-I7S5WNFK-C2TAta9K.js} +1 -1
- package/web-dist/assets/{railroad-3IZDKUUU-DzndPrRy.js → railroad-3IZDKUUU-DEMjzYqC.js} +1 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-_4FByoRI.js +1 -0
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-DKAvMIMu.js +1 -0
- package/web-dist/assets/railroad-peg-LSFZ7HO6-CkJl3c69.js +1 -0
- package/web-dist/assets/{railroadDiagram-RFXS5EU6-CPJAH-r7.js → railroadDiagram-RFXS5EU6-C4rERo6H.js} +1 -1
- package/web-dist/assets/{requirementDiagram-TGXJPOKE-BVFJZfwl.js → requirementDiagram-TGXJPOKE-DlIG9D0n.js} +1 -1
- package/web-dist/assets/{sankeyDiagram-HTMAVEWB-CUhvFPmE.js → sankeyDiagram-HTMAVEWB-DVMrG-qY.js} +1 -1
- package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-Cy9CGhNq.js → sequenceDiagram-DBY2YBRQ-DDcDM_-e.js} +1 -1
- package/web-dist/assets/{stateDiagram-2N3HPSRC-CqOnmPLp.js → stateDiagram-2N3HPSRC-DuCRKU5t.js} +1 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-90dqEQum.js +1 -0
- package/web-dist/assets/{swimlanes-5IMT3BWC-c_zBqkb9.js → swimlanes-5IMT3BWC-CY0fdvUm.js} +1 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-BETWueIt.js +8 -0
- package/web-dist/assets/{timeline-definition-FHXFAJF6-y_QM62SK.js → timeline-definition-FHXFAJF6-De0fDNdU.js} +1 -1
- package/web-dist/assets/{treeView-QDETBFTQ-T3y_1KXV.js → treeView-QDETBFTQ-AIoMhcen.js} +1 -1
- package/web-dist/assets/{treemap-6X3UGDF4-CzvqucqY.js → treemap-6X3UGDF4-CPZ1Ln05.js} +1 -1
- package/web-dist/assets/{vennDiagram-L72KCM5P-6-HNOpN0.js → vennDiagram-L72KCM5P-FrSO6pmh.js} +1 -1
- package/web-dist/assets/{wardley-OPB4EBWU-BrsaqsLL.js → wardley-OPB4EBWU-BbET6cjs.js} +1 -1
- package/web-dist/assets/{wardleyDiagram-EHGQE667-Cr_rCzwd.js → wardleyDiagram-EHGQE667-DqvcCBjr.js} +1 -1
- package/web-dist/assets/{xychartDiagram-FW5EYKEG-BnX6ccx4.js → xychartDiagram-FW5EYKEG-91xKEO07.js} +1 -1
- package/web-dist/index.html +2 -2
- package/runtime/cc-worker/agents/fable-high.md +0 -8
- package/runtime/cc-worker/agents/fable-low.md +0 -8
- package/runtime/cc-worker/agents/fable-max.md +0 -8
- package/runtime/cc-worker/agents/fable-medium.md +0 -8
- package/runtime/cc-worker/agents/fable-xhigh.md +0 -8
- package/runtime/cc-worker/agents/haiku.md +0 -7
- package/runtime/cc-worker/agents/opus-high.md +0 -8
- package/runtime/cc-worker/agents/opus-low.md +0 -8
- package/runtime/cc-worker/agents/opus-max.md +0 -8
- package/runtime/cc-worker/agents/opus-medium.md +0 -8
- package/runtime/cc-worker/agents/opus-xhigh.md +0 -8
- package/runtime/cc-worker/agents/sonnet-high.md +0 -8
- package/runtime/cc-worker/agents/sonnet-low.md +0 -8
- package/runtime/cc-worker/agents/sonnet-max.md +0 -8
- package/runtime/cc-worker/agents/sonnet-medium.md +0 -8
- package/runtime/cc-worker/agents/sonnet-xhigh.md +0 -8
- package/runtime/cc-worker/bin/browser-mcp-tools.json +0 -1192
- package/runtime/cc-worker/bin/browser-mcp.mjs +0 -730
- package/runtime/cc-worker/hooks/precompact-instructions.mjs +0 -133
- package/runtime/cc-worker/skills/waits/SKILL.md +0 -84
- package/web-dist/assets/architecture-TIHT7OUA-DksosNDW.js +0 -1
- package/web-dist/assets/channel-DqoPvfQz.js +0 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-DwUs74RB.js +0 -1
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-DwUs74RB.js +0 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-CUIjQ7kE.js +0 -1
- package/web-dist/assets/flowDiagram-23GEKE2U-Dka-3F3n.js +0 -1
- package/web-dist/assets/index-CmrDpsD8.css +0 -1
- package/web-dist/assets/index-DB1d3eMJ.js +0 -491
- package/web-dist/assets/railroad-abnf-AHOZXSZD-CCnWa6K9.js +0 -1
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-jtVdzv7e.js +0 -1
- package/web-dist/assets/railroad-peg-LSFZ7HO6-B8D6TyEe.js +0 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-DWKW-4qu.js +0 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-DZKoB7ae.js +0 -8
package/dist/frizz.js
CHANGED
|
@@ -12447,7 +12447,7 @@ var init_relay_protocol = __esm({
|
|
|
12447
12447
|
function fallbackPort(base) {
|
|
12448
12448
|
return base + 1e4;
|
|
12449
12449
|
}
|
|
12450
|
-
var import_yaml, ATTACHMENT_IMAGE_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, 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, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, 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, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketClientMsg, ProjectCard, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT;
|
|
12450
|
+
var import_yaml, ATTACHMENT_IMAGE_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, 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, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, 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, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketClientMsg, ProjectCard, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT;
|
|
12451
12451
|
var init_src = __esm({
|
|
12452
12452
|
"packages/shared/src/index.ts"() {
|
|
12453
12453
|
"use strict";
|
|
@@ -12703,7 +12703,7 @@ var init_src = __esm({
|
|
|
12703
12703
|
questions: external_exports.array(AskQuestion)
|
|
12704
12704
|
});
|
|
12705
12705
|
AwaitingHint = external_exports.object({
|
|
12706
|
-
kind: external_exports.enum(["shell", "agent", "timer", "pr", "for"]),
|
|
12706
|
+
kind: external_exports.enum(["shell", "agent", "timer", "pr", "for", "title"]),
|
|
12707
12707
|
value: external_exports.string()
|
|
12708
12708
|
});
|
|
12709
12709
|
RETIRED_AWAITING_KINDS = ["watch", "pr-watch", "human", "ci", "session", "shell", "agent", "timer", "pr", "reason"];
|
|
@@ -13280,6 +13280,14 @@ var init_src = __esm({
|
|
|
13280
13280
|
// Default action for a vetted non-image local path in agent markdown. Image clicks always use the
|
|
13281
13281
|
// OS default viewer so screenshots retain their expected behavior.
|
|
13282
13282
|
localFileOpener: LocalFileOpener.optional(),
|
|
13283
|
+
// The token count at which a NEW Claude worker auto-compacts its conversation. Frizz requests the
|
|
13284
|
+
// 1M context window on every dispatch (resolveClaudeLaunchModel), so without this a worker grows
|
|
13285
|
+
// toward 1M before it ever compacts — and every turn past 200K re-sends up to 5x the conversation a
|
|
13286
|
+
// 200K TUI session would, which is the single largest reason a Frizz thread spends quota faster than
|
|
13287
|
+
// the TUI (measured 2026-08-26). Reaches the worker as CLAUDE_CODE_AUTO_COMPACT_WINDOW, which Claude
|
|
13288
|
+
// Code caps to the model's real window. Optional so an old blob parses; defaultSettings pins 500_000
|
|
13289
|
+
// (maintainer 2026-08-26: "a default compaction window of 500k by default").
|
|
13290
|
+
autoCompactWindow: external_exports.number().int().positive().optional(),
|
|
13283
13291
|
// The GitHub batch-dispatch prompt template (the picker's per-item worker prompt). Optional: when
|
|
13284
13292
|
// unset OR blank the server falls back to its exported DEFAULT_GITHUB_PROMPT. Substitution tokens
|
|
13285
13293
|
// the server fills: {repo} {n} {title} {url} {labels} {body}. The leading `THREAD: <slug>` tag is
|
|
@@ -13545,9 +13553,11 @@ var init_src = __esm({
|
|
|
13545
13553
|
backend: Backend,
|
|
13546
13554
|
options: external_exports.array(ThreadProfileOption)
|
|
13547
13555
|
});
|
|
13556
|
+
ThreadSkillSource = external_exports.enum(["project", "user", "builtin", "plugin"]);
|
|
13548
13557
|
ThreadSkill = external_exports.object({
|
|
13549
13558
|
name: external_exports.string().min(1).max(512),
|
|
13550
|
-
description: external_exports.string().max(1024)
|
|
13559
|
+
description: external_exports.string().max(1024),
|
|
13560
|
+
source: ThreadSkillSource.optional()
|
|
13551
13561
|
}).strict();
|
|
13552
13562
|
ThreadSkillsInput = external_exports.object({ slug: ThreadSlug }).strict();
|
|
13553
13563
|
ThreadSkillsResult = external_exports.object({ skills: external_exports.array(ThreadSkill).max(1024) }).strict();
|
|
@@ -22797,6 +22807,7 @@ var b64url = (bytes) => {
|
|
|
22797
22807
|
for (const byte of view) binary += String.fromCharCode(byte);
|
|
22798
22808
|
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
22799
22809
|
};
|
|
22810
|
+
var SETTLED_MS = 1e4;
|
|
22800
22811
|
function defaultBackoff(attempt, random = Math.random) {
|
|
22801
22812
|
const base = Math.min(3e4, 500 * 2 ** Math.min(attempt, 6));
|
|
22802
22813
|
return Math.round(base / 2 + random() * (base / 2));
|
|
@@ -22846,8 +22857,11 @@ function connectRelay(options2) {
|
|
|
22846
22857
|
const url = `${options2.relayOrigin.replace(/^http/, "ws").replace(/\/$/, "")}/_relay/connect?h=${encoded}`;
|
|
22847
22858
|
const next = makeSocket(url);
|
|
22848
22859
|
socket = next;
|
|
22860
|
+
let settled;
|
|
22849
22861
|
next.addEventListener("open", () => {
|
|
22850
|
-
|
|
22862
|
+
settled = setTimer(() => {
|
|
22863
|
+
attempt = 0;
|
|
22864
|
+
}, SETTLED_MS);
|
|
22851
22865
|
options2.onStatus?.("connected");
|
|
22852
22866
|
});
|
|
22853
22867
|
next.addEventListener("message", (event) => {
|
|
@@ -22888,6 +22902,10 @@ function connectRelay(options2) {
|
|
|
22888
22902
|
});
|
|
22889
22903
|
const dropped = () => {
|
|
22890
22904
|
if (socket !== next) return;
|
|
22905
|
+
if (settled !== void 0) {
|
|
22906
|
+
clearTimer(settled);
|
|
22907
|
+
settled = void 0;
|
|
22908
|
+
}
|
|
22891
22909
|
socket = null;
|
|
22892
22910
|
for (const session of nested.values()) session.close();
|
|
22893
22911
|
nested.clear();
|
|
@@ -23343,6 +23361,7 @@ function createRemotePane(options2) {
|
|
|
23343
23361
|
...wrap(
|
|
23344
23362
|
"Claims <name>.frizz.sh for your GitHub account. The board dials out to frizz.sh \u2014 no port, no DNS record, no tunnel binary. One name per account; a name nobody runs for 30 days is released."
|
|
23345
23363
|
),
|
|
23364
|
+
...options2.sandbox ? ["", ...wrap("This is a sandbox, but a claim is real: it binds this machine's one name to your account, and your real board keeps it. Only the setup saved here is thrown away.")] : [],
|
|
23346
23365
|
"",
|
|
23347
23366
|
gh
|
|
23348
23367
|
];
|
|
@@ -23881,8 +23900,8 @@ init_src();
|
|
|
23881
23900
|
init_project_registry();
|
|
23882
23901
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
23883
23902
|
import { createServer as createServer2 } from "node:net";
|
|
23884
|
-
import { mkdirSync as mkdirSync10, readFileSync as readFileSync11, realpathSync as realpathSync5, writeFileSync as writeFileSync10 } from "node:fs";
|
|
23885
|
-
import { homedir as homedir10 } from "node:os";
|
|
23903
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync10, mkdtempSync, readdirSync as readdirSync3, readFileSync as readFileSync11, realpathSync as realpathSync5, rmSync as rmSync8, symlinkSync as symlinkSync2, writeFileSync as writeFileSync10 } from "node:fs";
|
|
23904
|
+
import { homedir as homedir10, tmpdir as tmpdir2 } from "node:os";
|
|
23886
23905
|
import { basename as basename5, join as join13, resolve as resolve3 } from "node:path";
|
|
23887
23906
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
23888
23907
|
var PORT_SCAN_COUNT = 100;
|
|
@@ -23946,6 +23965,7 @@ function parseCliArgs(argv) {
|
|
|
23946
23965
|
"--stop",
|
|
23947
23966
|
"--status",
|
|
23948
23967
|
"--link",
|
|
23968
|
+
"--sandbox",
|
|
23949
23969
|
"--sessions",
|
|
23950
23970
|
"--sign-out",
|
|
23951
23971
|
"--help",
|
|
@@ -23973,6 +23993,12 @@ function parseCliArgs(argv) {
|
|
|
23973
23993
|
throw new Error("--detach is no longer available; frizz-dev always runs in the foreground");
|
|
23974
23994
|
if (args2.has("--app") && args2.has("--no-app"))
|
|
23975
23995
|
throw new Error("choose either --app or --no-app");
|
|
23996
|
+
if (args2.has("--sandbox")) {
|
|
23997
|
+
for (const query of ["--stop", "--status", "--link", "--sessions", "--sign-out"]) {
|
|
23998
|
+
if (args2.has(query) || argv.some((arg) => arg.startsWith(`${query}=`)))
|
|
23999
|
+
throw new Error(`${query} asks the running board, and --sandbox starts a fresh disposable one \u2014 run ${query} without --sandbox`);
|
|
24000
|
+
}
|
|
24001
|
+
}
|
|
23976
24002
|
return {
|
|
23977
24003
|
noApp: args2.has("--no-app"),
|
|
23978
24004
|
appMode: args2.has("--app"),
|
|
@@ -23980,6 +24006,7 @@ function parseCliArgs(argv) {
|
|
|
23980
24006
|
foreground: true,
|
|
23981
24007
|
stop: args2.has("--stop"),
|
|
23982
24008
|
link: args2.has("--link"),
|
|
24009
|
+
sandbox: args2.has("--sandbox"),
|
|
23983
24010
|
sessions: args2.has("--sessions"),
|
|
23984
24011
|
...rawSignOut !== void 0 ? { signOut: rawSignOut } : {},
|
|
23985
24012
|
status: args2.has("--status"),
|
|
@@ -23992,6 +24019,57 @@ function parseCliArgs(argv) {
|
|
|
23992
24019
|
function boardAddress(url) {
|
|
23993
24020
|
return url.includes("?") || url.endsWith("/") ? url : `${url}/`;
|
|
23994
24021
|
}
|
|
24022
|
+
function prepareSandbox(env = process.env, realHome = homedir10()) {
|
|
24023
|
+
const home = mkdtempSync(join13(tmpdir2(), "frizz-sandbox-"));
|
|
24024
|
+
shareCredentials(realHome, home);
|
|
24025
|
+
env.HOME = home;
|
|
24026
|
+
env.USERPROFILE = home;
|
|
24027
|
+
const project = join13(home, "sandbox");
|
|
24028
|
+
mkdirSync10(project, { recursive: true });
|
|
24029
|
+
writeFileSync10(join13(project, "README.md"), "# frizz sandbox\n\nA throwaway project; everything here is deleted when the sandbox exits.\n");
|
|
24030
|
+
try {
|
|
24031
|
+
execFileSync3("git", ["init", "-q"], { cwd: project, stdio: "ignore" });
|
|
24032
|
+
} catch {
|
|
24033
|
+
throw new Error("--sandbox mints a throwaway git repository and git is not available \u2014 install git, or play in a repo of your own with a temp HOME");
|
|
24034
|
+
}
|
|
24035
|
+
process.chdir(project);
|
|
24036
|
+
return { home, project };
|
|
24037
|
+
}
|
|
24038
|
+
function shareCredentials(realHome, home) {
|
|
24039
|
+
const link = (from, to) => {
|
|
24040
|
+
try {
|
|
24041
|
+
symlinkSync2(from, to);
|
|
24042
|
+
} catch {
|
|
24043
|
+
}
|
|
24044
|
+
};
|
|
24045
|
+
mkdirSync10(join13(realHome, ".frizz"), { recursive: true });
|
|
24046
|
+
mkdirSync10(join13(home, ".frizz"), { recursive: true });
|
|
24047
|
+
link(join13(realHome, ".frizz", "identity.key"), join13(home, ".frizz", "identity.key"));
|
|
24048
|
+
if (existsSync5(join13(realHome, ".config", "gh"))) {
|
|
24049
|
+
mkdirSync10(join13(home, ".config"), { recursive: true });
|
|
24050
|
+
link(join13(realHome, ".config", "gh"), join13(home, ".config", "gh"));
|
|
24051
|
+
}
|
|
24052
|
+
const cloudflared = join13(realHome, ".cloudflared");
|
|
24053
|
+
if (existsSync5(cloudflared)) {
|
|
24054
|
+
mkdirSync10(join13(home, ".cloudflared"), { recursive: true });
|
|
24055
|
+
for (const entry of readdirSync3(cloudflared)) {
|
|
24056
|
+
if (entry === "cert.pem" || entry.endsWith(".json")) link(join13(cloudflared, entry), join13(home, ".cloudflared", entry));
|
|
24057
|
+
}
|
|
24058
|
+
}
|
|
24059
|
+
for (const entry of [".claude", ".claude.json", ".codex"]) {
|
|
24060
|
+
if (existsSync5(join13(realHome, entry))) link(join13(realHome, entry), join13(home, entry));
|
|
24061
|
+
}
|
|
24062
|
+
if (process.platform === "darwin" && existsSync5(join13(realHome, "Library", "Keychains"))) {
|
|
24063
|
+
mkdirSync10(join13(home, "Library"), { recursive: true });
|
|
24064
|
+
link(join13(realHome, "Library", "Keychains"), join13(home, "Library", "Keychains"));
|
|
24065
|
+
}
|
|
24066
|
+
}
|
|
24067
|
+
function cleanupSandbox(home) {
|
|
24068
|
+
try {
|
|
24069
|
+
rmSync8(home, { recursive: true, force: true });
|
|
24070
|
+
} catch {
|
|
24071
|
+
}
|
|
24072
|
+
}
|
|
23995
24073
|
function resolveLaunchIntent(cwd = process.cwd(), home = homedir10(), env = process.env) {
|
|
23996
24074
|
const candidate = realpathSync5(discoverProjectRoot(cwd, home));
|
|
23997
24075
|
const known = isExistingProjectRoot(candidate) || findByPath(candidate, home) !== void 0;
|
|
@@ -24246,7 +24324,7 @@ init_project_launch();
|
|
|
24246
24324
|
init_project_launch();
|
|
24247
24325
|
import { fork } from "node:child_process";
|
|
24248
24326
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
24249
|
-
import { existsSync as
|
|
24327
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync11, readFileSync as readFileSync12 } from "node:fs";
|
|
24250
24328
|
import { createServer as createNetServer } from "node:net";
|
|
24251
24329
|
import { basename as basename6, dirname as dirname10, extname as extname2, isAbsolute as isAbsolute3, relative, resolve as resolve4, sep as sep2 } from "node:path";
|
|
24252
24330
|
import { fileURLToPath } from "node:url";
|
|
@@ -24583,7 +24661,7 @@ var Supervisor = class {
|
|
|
24583
24661
|
await this.publicProxy.listen();
|
|
24584
24662
|
if (this.watchEnabled) {
|
|
24585
24663
|
const settled = await Promise.allSettled(
|
|
24586
|
-
this.roots.filter(
|
|
24664
|
+
this.roots.filter(existsSync6).map((root) => this.watchSubscribe(root, (err, events) => this.onWatch(err, events), {
|
|
24587
24665
|
ignore: DEV_WATCH_IGNORE
|
|
24588
24666
|
}))
|
|
24589
24667
|
);
|
|
@@ -25215,7 +25293,12 @@ for a source checkout.
|
|
|
25215
25293
|
Options:
|
|
25216
25294
|
--no-app print the URL without opening a browser
|
|
25217
25295
|
--port <port> request a fixed port for a new workspace server
|
|
25296
|
+
--sandbox a disposable Frizz to try things in: throwaway home and project, its
|
|
25297
|
+
own port, deleted when this terminal closes; credentials (gh,
|
|
25298
|
+
cloudflared, Claude, Codex, the machine's frizz.sh key) are shared
|
|
25218
25299
|
--link print a fresh single-use access link for the running board
|
|
25300
|
+
--sessions list the devices signed in to the running board
|
|
25301
|
+
--sign-out <id|all> sign one device out, or every one of them
|
|
25219
25302
|
--debug stream the full event feed to the terminal instead of the compact readout
|
|
25220
25303
|
-h, --help show this help
|
|
25221
25304
|
|
|
@@ -25228,6 +25311,8 @@ shows a single-use sign-in link as a QR; press L for a fresh one, or run --link
|
|
|
25228
25311
|
process.exit(0);
|
|
25229
25312
|
}
|
|
25230
25313
|
if (options.dev || rawArgs.includes("--prod")) fail("--dev and --prod are not available from the registry launcher");
|
|
25314
|
+
var sandbox = options.sandbox ? prepareSandbox() : null;
|
|
25315
|
+
if (sandbox) process.on("exit", () => cleanupSandbox(sandbox.home));
|
|
25231
25316
|
var remote = null;
|
|
25232
25317
|
var paneHost = null;
|
|
25233
25318
|
var accessPane = null;
|
|
@@ -25362,6 +25447,7 @@ async function openOrPrint(port, reused, path = "") {
|
|
|
25362
25447
|
}
|
|
25363
25448
|
const publicOrigin = reused ? void 0 : remote?.origin();
|
|
25364
25449
|
const warnings = [];
|
|
25450
|
+
if (sandbox) warnings.push(`Sandbox: everything here is throwaway (${sandbox.home}) and is deleted when this terminal closes.`);
|
|
25365
25451
|
if (!readout) {
|
|
25366
25452
|
console.log(`${reused ? "reusing" : "started"} Frizz ${PACKAGE_VERSION} for ${workspace.root}`);
|
|
25367
25453
|
console.log(url);
|
|
@@ -25490,7 +25576,8 @@ async function runSupervisor(port, token) {
|
|
|
25490
25576
|
claim: (name) => establishCloudConfig(name, port),
|
|
25491
25577
|
issueLink: () => supervisor.issueAccessLink(),
|
|
25492
25578
|
probes: { github: probeGithub, cloudflared: probeCloudflared, tailscale: probeTailscale },
|
|
25493
|
-
onChanged: (config) => logger.info("remote", config ? `reached at https://${config.hostname}` : "loopback only")
|
|
25579
|
+
onChanged: (config) => logger.info("remote", config ? `reached at https://${config.hostname}` : "loopback only"),
|
|
25580
|
+
sandbox: sandbox !== null
|
|
25494
25581
|
});
|
|
25495
25582
|
paneHost = installPaneHost({ bindings: { l: accessPane, L: accessPane, r: remotePane, R: remotePane } });
|
|
25496
25583
|
const stop = createSupervisorShutdownHandler({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frizz",
|
|
3
|
-
"description": "Worker-side frizz plugin for frizz-spawned sessions. Each session is a WORKER driving ONE effort (slug via env FRIZZ_THREAD): it SIGNALS through its final message (done, human/timer awaiting, question), keeps automatable waits active with Claude wait tools, and keeps its own free-form scratch directory (.frizz/threads/<session-id>/). Supplies the frizz:<
|
|
3
|
+
"description": "Worker-side frizz plugin for frizz-spawned sessions. Each session is a WORKER driving ONE effort (slug via env FRIZZ_THREAD): it SIGNALS through its final message (done, human/timer awaiting, question), keeps automatable waits active with Claude wait tools, and keeps its own free-form scratch directory (.frizz/threads/<session-id>/). Supplies the effort-only frizz:<effort> sub-agent profiles (frizz:low … frizz:max; the model rides the Agent tool's own parameter), the on-demand frizz:gh skill, and hooks that seed the worker contract, enforce background/name-stripped sub-agent dispatch, and deny the interactive question/plan prompts (deny-ask, deny-plan) that would hang a dashboard worker. Hooks are inert unless FRIZZ_THREAD is set.",
|
|
4
4
|
"version": "0.1.10",
|
|
5
5
|
"author": { "name": "Colin McDonnell" },
|
|
6
6
|
"homepage": "https://github.com/colinhacks/frizz",
|
|
@@ -1032,7 +1032,7 @@ Maintainer's call, verbatim: *"This is obviously something that should not be a
|
|
|
1032
1032
|
|
|
1033
1033
|
Three removals, one theme — Frizz's shipped worker contract states frizz MECHANICS, and everything else belongs to the repo or to the dispatch that starts the thread.
|
|
1034
1034
|
|
|
1035
|
-
- **`runtimeGate` (setting) + `RUNTIME_GATE` (prompt module) — gone.** The browser-QA loop (drive it in Chrome, screenshot into the handoff, escalate to an adversarial reviewer) was frizz's own engineering norm shipped to every worker Frizz dispatches anywhere. That is what `FRIZZ.md` / `CLAUDE.md` are for: `frizzConfigBlock` already injects a repo's own conventions into every spawn/adopt/resume, and this repo keeps its full browser-QA section there. What remains in the shipped contract is the repo-agnostic line that was already in the Quality bar — *"Verify behavior end-to-end before calling anything done."* `VISUAL_EVIDENCE` **stays**: it documents Frizz's guarded local-image proxy, a platform capability, not a QA policy. `chrome-devtools` also stays always-mounted — giving a worker a browser is a capability, not an opinion about when to use it.
|
|
1035
|
+
- **`runtimeGate` (setting) + `RUNTIME_GATE` (prompt module) — gone.** The browser-QA loop (drive it in Chrome, screenshot into the handoff, escalate to an adversarial reviewer) was frizz's own engineering norm shipped to every worker Frizz dispatches anywhere. That is what `FRIZZ.md` / `CLAUDE.md` are for: `frizzConfigBlock` already injects a repo's own conventions into every spawn/adopt/resume, and this repo keeps its full browser-QA section there. What remains in the shipped contract is the repo-agnostic line that was already in the Quality bar — *"Verify behavior end-to-end before calling anything done."* `VISUAL_EVIDENCE` **stays**: it documents Frizz's guarded local-image proxy, a platform capability, not a QA policy. `chrome-devtools` also stays always-mounted — giving a worker a browser is a capability, not an opinion about when to use it. **(Reversed 2026-08-26 — see the entry at the end of this file. The reasoning above survives one step further than it should have: mounting a browser is itself an opinion, and it was billed to every worker in tokens.)**
|
|
1036
1036
|
- **Model + Effort — removed from the settings drawer.** They are chosen per dispatch in the prompt box (`DispatchPreferences`, one profile per runtime); a second global copy only made it ambiguous which one applied. `Settings.model` / `Settings.effort` survive on the wire: `dispatch-preferences.ts` still seeds the composer's first-run profile from them and `dispatch.ts` still falls back to them for GitHub batch dispatch.
|
|
1037
1037
|
- **`autoResumeOnLimit` — gone; auto-resume is unconditional.** A thread cut off mid-turn by an exhausted subscription window always gets its own "continue" when the window rolls. `ThreadView.limitPause.autoResume` survives on the wire but is now purely a STALENESS verdict (`resolveLimitPause`): a fault old enough that the wake will never arrive stops promising one.
|
|
1038
1038
|
|
|
@@ -1112,3 +1112,31 @@ Maintainer: *"Changing the model and effort in a prompt box. That should be reme
|
|
|
1112
1112
|
- **The web cache treats `["dispatchPreferencesGet"]` as machine-wide** (`lib/queryKeyScope.ts`), so the composer's optimistic write on one project is what a client-side switch paints on the next, rather than that project's last-seen copy for the beat before a refetch.
|
|
1113
1113
|
|
|
1114
1114
|
Verified on a real two-project stack (launcher + tenant on one server): a profile chosen through the tenant's RPC is what the launcher reads, and back; a per-project `settingsSet` on the launcher stayed invisible to the tenant, which is the control that the two prefixes reach different projects.
|
|
1115
|
+
## 2026-08-26: Frizz mounts NO browser — a `chrome-devtools` server is the project's to bring
|
|
1116
|
+
|
|
1117
|
+
Maintainer: *"Is the Chrome DevTool stuff something that frizz automatically injects? Why not just let the user bring that themselves? That's very confusing to me. I feel like there's a level of opinionation here that we don't really want."*
|
|
1118
|
+
|
|
1119
|
+
This reverses the 2026-08-03 line above (*"`chrome-devtools` also stays always-mounted — giving a worker a browser is a capability, not an opinion"*). The capability argument stopped holding once the bill was measured: the server's 29 tool schemas sat in the prefix of **every** worker session at **~6,400 tokens**, and most workers never open a page. A capability nobody asked for, charged per turn, is an opinion.
|
|
1120
|
+
|
|
1121
|
+
- **Both backends stopped injecting it.** Claude's inline `--mcp-config` (`claudeMcpConfig`, `dispatch.ts`) and codex's `-c mcp_servers.chrome-devtools=…` app-server override (`codex-mcp.ts`) now mount the unified `frizz` server and nothing else. Parity was the point of the original pairing and it is the point of the removal.
|
|
1122
|
+
- **The lazy proxy went with it.** `cc-worker/bin/browser-mcp.mjs` and its committed schema snapshot `browser-mcp-tools.json` existed only to make the always-on mount affordable in MEMORY (159 MB → ~17 MB per worker, 2026-08-19). With no mount there is nothing to proxy, so they are deleted along with `chromeDevtoolsMcpSpec` / `chromeDevtoolsMcpMount` / `resolveBrowserMcpScript` / `CHROME_DEVTOOLS_MCP`, `scripts/harvest-browser-mcp-tools.mjs`, and the worker-plugin closure entries that required them. The memory win it bought is now the token win.
|
|
1123
|
+
- **Nothing about a browser is banned — it is just not Frizz's to decide.** A project adds a `.mcp.json` (plus `enabledMcpjsonServers` in `.claude/settings.json`, so a headless worker is never blocked on the approval prompt); an operator runs `claude mcp add --scope user`. Frizz's `--mcp-config` ADDS to whatever the CLI discovered rather than replacing it (frizz never passes `--strict-mcp-config`), so both paths reach a dispatched worker untouched.
|
|
1124
|
+
- **This repo does exactly that, and that is the whole demonstration.** Frizz's own skills drive Chrome headless, so the repo root carries the `.mcp.json` that used to be injected — pinned `chrome-devtools-mcp@1.7.0 --experimentalPageIdRouting --headless --isolated --no-usage-statistics`, the same argv the deleted spec rendered. Verified end-to-end on a disposable stack: a worker dispatched in a scratch project with no config reported `frizz` tools and no browser; a worker dispatched in this repo reported the full `mcp__chrome-devtools__*` set with no permission prompt.
|
|
1125
|
+
- **What deliberately stayed.** The orphan reaper still reaps `chrome-devtools-mcp` processes by name (a browser the USER brought leaks exactly the same way), and the transcript still renders a `take_screenshot` image result. Neither depends on who mounted the server.
|
|
1126
|
+
|
|
1127
|
+
## 2026-08-26: Sub-agent profiles are effort-only, and the dispatch epilogue carries mechanics, not a handoff format
|
|
1128
|
+
|
|
1129
|
+
Follow-on to the browser decision above, from the same audit of what Frizz registers into a worker that the worker did not ask for. The maintainer's frame — *"a level of opinionation here that we don't really want"* — applied to two more registrations, and the frizz Goal had this thread decide them itself.
|
|
1130
|
+
|
|
1131
|
+
- **16 `frizz:<model>-<effort>` profiles → 5 `frizz:<effort>` ones.** The model×effort grid existed because the Agent tool once had no way to pin either; today its own `model` parameter overrides a profile's model, so the only knob a profile still has to carry is `effort`. The grid cost ~1,340 tokens of agent descriptions on every session, and those descriptions doubled as a routing doctrine ("Opus matches Fable and costs less", "Haiku for scripted harvest only") that no project asked for. `low` … `max` carry no model and inherit the worker's; Haiku, which takes no effort setting, is dispatched with `model: "haiku"` and no profile. The worker contract's Sub-agents section now states the two knobs and nothing about which tier deserves which task.
|
|
1132
|
+
- **The dispatch-hook epilogue kept only what a helper cannot discover.** Its first paragraph prescribed the shape of a helper's final message (status, files, SHA, evidence, caveats, next action); that is a handoff format, and it is gone — one sentence remains saying the final message is what the dispatcher reads. The rest stayed because each line is a mechanic learned from a real failure: the `SendMessage({to: "main"})` upward channel, the own-file rule for the scratch directory, no fan-out of its own unless asked, and the symlinked-`.output` wait-loop trap.
|
|
1133
|
+
- **Verified** by the live harness (`_live_broker_workerenv.mts`, now dispatching `frizz:low`): a real broker worker through the real server dispatched the profile and it ran.
|
|
1134
|
+
|
|
1135
|
+
## 2026-08-26: three more worker registrations deleted — the waits skill, the pre-compaction brief, and the toon nudge
|
|
1136
|
+
|
|
1137
|
+
Third pass of the same audit that removed the browser mount and the model×effort profile grid above, and the same test: does Frizz register this into every worker because the worker needs it, or because Frizz has an opinion?
|
|
1138
|
+
|
|
1139
|
+
- **`skills/waits` is DELETED.** Maintainer: *"I feel like the waits skill is being replaced now. I don't think we need that. We have our own system now for registering watchers and whatnot as tools."* The skill's whole job was teaching a worker how to hold a wait open without falling out of the board's Active band, and the durable half of that is now TOOLS — `mcp__frizz__watch_pr`, `mcp__frizz__timer`, `mcp__frizz__recurring_prompt` — which carry their own descriptions and need no playbook. What remains (a sub-agent owns the wait, `run_in_background` does not hold a rest, never fake a wait with a foreground sleep) is already stated once in the system-prompt contract, which is where a mechanical rule belongs.
|
|
1140
|
+
- **The portable monitors STAYED.** `skills/gh/scripts/{ci-watch,github-watch,review-watch}.mjs` are generated byte-for-byte from `monitors/` and are load-bearing for two other readers: the codex worker prompt names their absolute directory (`monitorScriptsDir()`, `dispatch.ts`, pinned by `dispatch.test.ts`), and `skills/gh` documents them as its declared-tooling fallback. Only the skill went.
|
|
1141
|
+
- **`hooks/precompact-instructions.mjs` is DELETED**, with both its `PreCompact` registrations. Maintainer: *"the pre-compaction instructions are probably too opinionated, entirely too opinionated."* It handed the summarizer an editorial brief about WHAT to preserve — plan, alternatives rejected, rationale, at high fidelity — which is a prescription about how someone else's work should be remembered. `scratchpad.mjs --mode=precompact` keeps both matchers: it only says the worker's scratch files exist and names their paths, which is mechanics.
|
|
1142
|
+
- **The `toon` bullet is gone from the seed's `⟦gh available⟧` block and from `skills/gh`.** Maintainer: *"It seems pretty opinionated to tell it to pipe through toon, given that toon is probably not installed on most machines. That might be over the line."* The original reasoning (`plans/github-integration.md` §9: worker-side yes, server-side no) was measured against THIS machine's toolchain; a `command -v toon` guard makes the advice safe but not less opinionated, and it spent prompt tokens on every authed session to describe a binary almost no repo has. The one raw-API recipe that piped through it now uses `--jq`, which ships with `gh`.
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
// foreground agent blocks the worker's turn; a human interjection orphans it).
|
|
7
7
|
// 2) STRIP `name`/`team_name` — setting either strands a nested dispatch (its result routes
|
|
8
8
|
// wrong and never returns cleanly), so scrub both silently.
|
|
9
|
-
// 3) AUTO-APPEND a
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
9
|
+
// 3) AUTO-APPEND a short ORCHESTRATION EPILOGUE carrying only what a helper cannot discover on
|
|
10
|
+
// its own: that its final message is the return value, the `SendMessage({to: "main"})` upward
|
|
11
|
+
// channel, the own-file rule for the scratch directory, no fan-out of its own unless asked, and
|
|
12
|
+
// how a helper it DID dispatch is collected. It carries no handoff format and no build, test,
|
|
13
|
+
// git or process policy — the maintainer had the handoff-format doctrine cut on 2026-08-26.
|
|
13
14
|
//
|
|
14
15
|
// WHY NESTING IS DEFAULT-OFF (2026-08-04, maintainer's call): the epilogue used to speak about a
|
|
15
16
|
// helper's own helper only in the conditional ("if you dispatch a helper of your own…"), which reads
|
|
@@ -45,11 +46,11 @@ import { readFileSync } from 'node:fs';
|
|
|
45
46
|
const EPILOGUE = `
|
|
46
47
|
|
|
47
48
|
---
|
|
48
|
-
[ORCHESTRATION EPILOGUE — auto-appended by the frizz worker dispatch hook] You are a helper sub-agent for a frizz worker. Your final message is the handoff
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
Do the work yourself: do NOT dispatch sub-agents of your own unless your dispatch prompt explicitly tells you to. You are already one prong of someone else's fan-out
|
|
52
|
-
If your prompt DOES ask you to dispatch a helper, its completion is delivered to you automatically. Never hand-roll a wait loop over a helper's transcript or \`.output\` path
|
|
49
|
+
[ORCHESTRATION EPILOGUE — auto-appended by the frizz worker dispatch hook] You are a helper sub-agent for a frizz worker. Your final message is the handoff your dispatcher reads: what you did, what you verified, what remains.
|
|
50
|
+
If the worker names its scratch directory: Write your OWN file there — never edit or delete a file another agent wrote. That file is Frizz coordination state, not a project deliverable or source edit, so it stays allowed under limits such as "write only <path>" or "do not modify the repo"; never classify it as unauthorized or roll it back. Every other file is governed by your delegated authority; its location alone neither permits nor forbids editing. Do not edit other \`.frizz/\` state unless your prompt asks.
|
|
51
|
+
Upward channel: \`SendMessage({to: "main", summary: "<5-10 words>", message: "…"})\` reaches your dispatcher while you work (load it first with ToolSearch \`select:SendMessage\` if it is deferred). Use it only when the dispatcher acting before you finish would change the outcome — a blocker, a milestone another task needs, instructions that should change — not for progress updates.
|
|
52
|
+
Do the work yourself: do NOT dispatch sub-agents of your own unless your dispatch prompt explicitly tells you to. You are already one prong of someone else's fan-out; a slice that feels large is still yours to work through in your own turn.
|
|
53
|
+
If your prompt DOES ask you to dispatch a helper, its completion is delivered to you automatically. Never hand-roll a wait loop over a helper's transcript or \`.output\` path: that path is a SYMLINK (\`stat\` without \`-L\` reports the link's own ~150-byte size and frozen mtime) and the \`"type":"result"\` record is not reliably written, so a helper working hard reads as tiny, stale and dead, and you will discard live work and redo it. Judge a helper only by its completion notification or the text it returns, and give it a \`description\` naming its narrower slice.`;
|
|
53
54
|
|
|
54
55
|
/** @param {unknown} obj @returns {never} */
|
|
55
56
|
function emit(obj) {
|
|
@@ -58,14 +58,12 @@
|
|
|
58
58
|
{
|
|
59
59
|
"matcher": "auto",
|
|
60
60
|
"hooks": [
|
|
61
|
-
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/precompact-instructions.mjs\"" },
|
|
62
61
|
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scratchpad.mjs\" --mode=precompact" }
|
|
63
62
|
]
|
|
64
63
|
},
|
|
65
64
|
{
|
|
66
65
|
"matcher": "manual",
|
|
67
66
|
"hooks": [
|
|
68
|
-
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/precompact-instructions.mjs\"" },
|
|
69
67
|
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scratchpad.mjs\" --mode=precompact" }
|
|
70
68
|
]
|
|
71
69
|
}
|
|
@@ -280,9 +280,11 @@ if (mode === 'session-start') {
|
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
// ── mode: precompact ─────────────────────────────────────────────────────────────────────────────
|
|
283
|
-
// PLAIN STDOUT —
|
|
284
|
-
// `
|
|
285
|
-
//
|
|
283
|
+
// PLAIN STDOUT — handed to the summarizer as its `Additional Instructions:`. cc's usual
|
|
284
|
+
// `hookSpecificOutput` JSON would be read as literal instructions instead. Worded as an ordinary
|
|
285
|
+
// editorial note: a summarizer REFUSES instructions that read like prompt-hijacking (DECISIONS.md).
|
|
286
|
+
// This is the ONLY PreCompact hook the plugin registers — `precompact-instructions.mjs`, which also
|
|
287
|
+
// steered the summarizer, was deleted on 2026-08-26 as too opinionated.
|
|
286
288
|
if (mode === 'precompact') {
|
|
287
289
|
const files = listScratch();
|
|
288
290
|
if (files.length === 0) process.exit(0);
|
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
// frontmatter, no status field — a worker SIGNALS through its final message (fences), and anything that
|
|
9
9
|
// must outlive its context window is an arrangement it makes for itself. This hook injects, on every
|
|
10
10
|
// session start (startup/resume/clear/compact):
|
|
11
|
-
// 1. `core` — a runtime
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// signal-at-rest anchor + a pointer to the system-prompt contract.
|
|
11
|
+
// 1. `core` — a runtime POINTER, not a copy of the contract: the full worker contract lives ONCE in
|
|
12
|
+
// the system prompt (workerPrompt.ts) the server injects at spawn. This carries only what a
|
|
13
|
+
// static system prompt can't: the runtime scratch-directory PATH, and a one-line pointer.
|
|
15
14
|
// 2. the SCRATCH DIRECTORY — `.frizz/threads/<session_id>/`, a folder the worker may use as it likes.
|
|
16
15
|
// 3. on `compact` — a short re-grounding (compaction drops the deep model + this orientation).
|
|
17
16
|
//
|
|
@@ -57,21 +56,23 @@ const scratch = sid
|
|
|
57
56
|
? '.frizz/threads/' + sid + '/'
|
|
58
57
|
: '.frizz/threads/<session-id>/';
|
|
59
58
|
|
|
60
|
-
// A RUNTIME
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
59
|
+
// A RUNTIME pointer, NOT a copy of the contract. The full worker contract (signal fences,
|
|
60
|
+
// scratch-directory rules, sub-agent rules, the question handback, the stop criterion) lives ONCE in
|
|
61
|
+
// the system prompt frizz injects at spawn (workerPrompt.ts / loadWorkerPrompt) — re-applied on every
|
|
62
|
+
// resume, and it survives compaction. This hook adds only what a static system prompt CANNOT carry:
|
|
63
|
+
// the runtime-derived scratch-directory PATH, plus (below) the compaction re-read nudge and the
|
|
64
|
+
// auth-gated gh guidance.
|
|
65
|
+
//
|
|
66
|
+
// It used to restate the fence protocol, the stop criterion and the autonomy rule in full — ~4.4 KB
|
|
67
|
+
// (~1,100 tokens) on every startup, resume, clear AND compact, all of it already in the 42 KB system
|
|
68
|
+
// prompt. Trimmed 2026-08-26 (maintainer: "Definitely trim the session seed hook if it's fully
|
|
69
|
+
// repetitive") as part of cutting the per-session token overhead Frizz adds over a plain TUI session.
|
|
66
70
|
const core =
|
|
67
|
-
'⟦frizz worker contract⟧ You are a frizz WORKER driving EXACTLY ONE effort. Your FULL operating contract — the end-of-turn signal fences, scratch-directory rules, sub-agent rules,
|
|
68
|
-
'SCRATCH DIRECTORY (OPTIONAL): `' + scratch + '` — a folder kept FOR YOU
|
|
69
|
-
'DO NOT REST WHILE THE INSTRUCTION HAS PARTS LEFT — finish them in THIS turn; a milestone, a green test run and a long turn are none of them stopping points, and announcing the next step or writing it into a scratch file is not doing it.\n' +
|
|
70
|
-
'ALWAYS SIGN OFF WITH A FENCE, per the fence rules in your system prompt. A rest with NO fence is not a handoff — it is an item nobody can triage, and frizz will tell you so. ```done only when the effort\'s real work is COMPLETE (code LANDED on the mainline — an open PR is NOT done, park it on ```awaiting until it MERGES) and is a DISMISSAL (its card files the thread away where nobody looks again), so if the thread points at future work AT ALL — a pre-fix investigation, a live code-change discussion, follow-up work you DISCOVERED even when someone else will do it — ask a ```question instead, and uncertain is not done; a verdict that ends in something the HUMAN must now do (post this comment, merge or decline, pick one of these) is a ```question carrying your recommendation as option A, never a done card, because a draft you wrote but did not send is filed away with the thread; when your OWN mandate is complete and what is left is a separable effort, DO it first — dispatch a sub-agent, whose result comes BACK to you, so it lands on YOUR card — and ASK second; mcp__frizz__spawn_thread is the LAST resort, for work that genuinely cannot ride on your card, because a spawned thread reports only to the human and nothing it learns returns to you or its siblings; the ONE exception is a planning session whose plan file is fully written and persisted, because that artifact outlives the thread; ```awaiting parks your OWN background work — a shell, a sub-agent, an armed timer, a registered PR watcher — never CI/releases/merge progression (those stay ACTIVE), and never a person: waiting on a person is a ```question; ```question is the operator ask. Waiting on your own background shell? Your shells and sub-agents are watched AUTOMATICALLY — frizz wakes you when one finishes, fence or no fence. NAME it in the fence\'s YAML frontmatter anyway — plural keys taking lists (`shells: [<id>]`, `agents:`, `timers:`, `prs:`) plus a required `for:` duration, then `---` and your prose — and rest: that is what lets you stop without frizz asking you for a handoff, and what shows the human what you are waiting for. Frizz checks every name against what you actually have running. Keep the write-up SHORT: 1-3 sentences, then bullets starting with a **bolded verb phrase**. The fence and the prose above it are TWO SURFACES, not one message written twice — the card is the ledger of what shipped, the prose is only what a ledger cannot hold, and a sentence that would read the same in either belongs in exactly one. And a done message says what HAPPENED: delete every dangling "one thing to carry forward" or "a follow-up could" — do it, spawn it onto its own card, ask about it, or DROP it, and if it is not worth a card it is not worth a sentence.\n' +
|
|
71
|
-
'DECIDE rather than ask: anything derivable from the code, the conventions, or ordinary engineering judgment is YOURS to settle — asking permission to do the work you were dispatched to do is not a question, it is the job. Reserve the operator for the irreversible and the genuinely human-owned.';
|
|
71
|
+
'⟦frizz worker contract⟧ You are a frizz WORKER driving EXACTLY ONE effort. Your FULL operating contract — the end-of-turn signal fences (```done / ```awaiting / ```question), the scratch-directory rules, the sub-agent rules, the question handback and the stop criterion — lives in your SYSTEM PROMPT; follow it there. Always sign off with a fence.\n' +
|
|
72
|
+
'SCRATCH DIRECTORY (OPTIONAL): `' + scratch + '` — a folder kept FOR YOU, nothing in it read automatically, never a substitute for doing the work. Give each sub-agent its OWN file rather than a shared one.';
|
|
72
73
|
|
|
73
74
|
const grounding =
|
|
74
|
-
'⟦frizz worker re-grounding (post-compaction)⟧ Context was just compacted. You are still the frizz worker for effort `' + thread + '` — read whatever you left yourself in `' + scratch + '` NOW to recover your working state and to-do list before asserting anything, and re-read any code before claiming how it is structured.
|
|
75
|
+
'⟦frizz worker re-grounding (post-compaction)⟧ Context was just compacted. You are still the frizz worker for effort `' + thread + '` — read whatever you left yourself in `' + scratch + '` NOW to recover your working state and to-do list before asserting anything, and re-read any code before claiming how it is structured. Your system prompt still carries the full contract; sign off with a fence as it says.';
|
|
75
76
|
|
|
76
77
|
// AUTH-GATED gh guidance — teach the worker to use `gh` well, but ONLY when signed in.
|
|
77
78
|
// Shell `gh auth status --active`: exit 0 = an active gh account is authenticated. The whole gate is
|
|
@@ -84,7 +85,6 @@ const ghBlock =
|
|
|
84
85
|
'• READ freely: `gh issue view N -R OWNER/REPO --comments`, `gh pr view N`, `gh pr diff N`, `gh pr checks N`, `gh run list`/`gh run view`, `gh api repos/OWNER/REPO/…`. Prefer `--json <fields>` over scraping human text.\n' +
|
|
85
86
|
'• SEARCH across the repo (and GitHub) with `gh search issues`/`gh search prs` when hunting related work, duplicates, or prior art.\n' +
|
|
86
87
|
'• READ-ONLY BOUNDARY: never comment, label, assign, close, review, approve, or merge — no mutation of any kind — UNLESS the human explicitly asks in this session. Default to producing your findings/review as your final message, not as a GitHub post.\n' +
|
|
87
|
-
'• TOON: pipe LARGE, FLAT `gh … --json` output through `toon` when `command -v toon` finds it. Skip it when unavailable, for tiny payloads, or for deeply-nested output — the savings are noise and nesting defeats tabularization.\n' +
|
|
88
88
|
'Load the `frizz:gh` skill for the full playbook (recipes + explicit project-local monitor selection + native Monitor/background-Bash CI/PR watches).';
|
|
89
89
|
|
|
90
90
|
let ghAuthed = false;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gh
|
|
3
|
-
description: The gh-CLI playbook for a frizz worker signed into GitHub (invoke as frizz:gh). Load this whenever your effort touches GitHub — reading or triaging an issue or PR, reviewing a diff, checking CI/release status, or searching issues/PRs — to use `gh` eagerly and correctly: the read-vs-write boundary (never comment/label/close/merge unless the human asks),
|
|
4
|
-
version: 0.1.
|
|
3
|
+
description: The gh-CLI playbook for a frizz worker signed into GitHub (invoke as frizz:gh). Load this whenever your effort touches GitHub — reading or triaging an issue or PR, reviewing a diff, checking CI/release status, or searching issues/PRs — to use `gh` eagerly and correctly: the read-vs-write boundary (never comment/label/close/merge unless the human asks), concrete read recipes, and active Monitor/background-Bash CI/PR watches. Only meaningful when you are signed in (`gh auth status --active` exit 0); the session-seed hook injects a pointer here when you are.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
metadata:
|
|
6
6
|
internal: true
|
|
7
7
|
---
|
|
@@ -10,7 +10,7 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
You are a **frizz worker** and you are **signed into the `gh` CLI in a GitHub repo** (the session-seed hook confirmed `gh auth status --active` before pointing you here). `gh` is the fastest path to issue / PR / CI / release context — reach for it before guessing, and prefer it over scraping the web UI or reasoning from memory.
|
|
12
12
|
|
|
13
|
-
This skill is the full playbook the injected `⟦gh available⟧` block summarizes: the **read-vs-write boundary**,
|
|
13
|
+
This skill is the full playbook the injected `⟦gh available⟧` block summarizes: the **read-vs-write boundary**, concrete **read recipes**, and how to keep a **CI/PR watch** active until the next actionable event.
|
|
14
14
|
|
|
15
15
|
## The one hard rule — READ freely, WRITE only when asked
|
|
16
16
|
|
|
@@ -23,20 +23,6 @@ This skill is the full playbook the injected `⟦gh available⟧` block summariz
|
|
|
23
23
|
|
|
24
24
|
There is no server-side enforcement of this; the boundary is yours to hold.
|
|
25
25
|
|
|
26
|
-
## toon — pipe LARGE, FLAT gh JSON through the shim
|
|
27
|
-
|
|
28
|
-
`toon` (Token-Oriented Object Notation) losslessly re-encodes JSON ~30–40% smaller for LLM context. Use it only when a `gh … --json` result you're reading into YOUR context is **large and flat** (a list page: `gh issue list`, `gh pr list`, `gh search`, `gh api` list endpoints) and `command -v toon` succeeds. It is optional: do not install it or assume a home-directory-specific location.
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
if command -v toon >/dev/null 2>&1; then
|
|
32
|
-
gh issue list -R OWNER/REPO --json number,title,url,updatedAt --limit 50 | toon
|
|
33
|
-
else
|
|
34
|
-
gh issue list -R OWNER/REPO --json number,title,url,updatedAt --limit 50
|
|
35
|
-
fi
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
**Skip toon** for tiny payloads (a handful of fields, one item) and for **deeply-nested** JSON (`reactionGroups`, review threads, nested files) — nesting defeats tabularization, so the savings collapse to noise and you add a parse tax for yourself. A single `gh pr view N --json …` is small — read it raw.
|
|
39
|
-
|
|
40
26
|
## Read recipes
|
|
41
27
|
|
|
42
28
|
Always scope with `-R OWNER/REPO` so a command is dir-independent, and prefer `--json <fields>` (+ `-q <jq>`) so you pull exactly what you need.
|
|
@@ -52,7 +38,7 @@ gh issue list -R OWNER/REPO --search "sort:reactions-desc is:open" --json number
|
|
|
52
38
|
**PRs + diffs**
|
|
53
39
|
```bash
|
|
54
40
|
gh pr view N -R OWNER/REPO --json title,body,state,labels,files,additions,deletions,url
|
|
55
|
-
gh pr diff N -R OWNER/REPO # the unified diff
|
|
41
|
+
gh pr diff N -R OWNER/REPO # the unified diff
|
|
56
42
|
gh pr checks N -R OWNER/REPO # CI check rollup for the PR
|
|
57
43
|
gh pr view N -R OWNER/REPO --comments # review threads + conversation
|
|
58
44
|
```
|
|
@@ -97,7 +83,7 @@ Use search to find duplicates, related work, and prior art before you conclude s
|
|
|
97
83
|
**Raw API** for anything the porcelain doesn't cover:
|
|
98
84
|
```bash
|
|
99
85
|
gh api repos/OWNER/REPO/commits/SHA/check-runs --jq '.check_runs[] | {name, conclusion}'
|
|
100
|
-
gh api "repos/OWNER/REPO/issues?state=open&labels=bug&per_page=50" | {
|
|
86
|
+
gh api "repos/OWNER/REPO/issues?state=open&labels=bug&per_page=50" --jq '.[] | {number, title, html_url}'
|
|
101
87
|
```
|
|
102
88
|
|
|
103
89
|
## Keep GitHub automation active
|