frizz 0.13.6 → 0.13.7
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/frizz.js +240 -103
- package/package.json +2 -2
package/dist/frizz.js
CHANGED
|
@@ -12485,6 +12485,106 @@ var init_shell_writes = __esm({
|
|
|
12485
12485
|
});
|
|
12486
12486
|
|
|
12487
12487
|
// packages/shared/src/index.ts
|
|
12488
|
+
function signoffNudgeAwaitingLines(needsInput) {
|
|
12489
|
+
if (!needsInput) {
|
|
12490
|
+
return [
|
|
12491
|
+
"- `` ```awaiting `` \u2014 you are WAITING on work that is actually running. FRONTMATTER, THEN MARKDOWN:",
|
|
12492
|
+
" one YAML list per kind of thing you are waiting on, a REQUIRED `for:` duration, then a `---` line and",
|
|
12493
|
+
" as much prose as you want. The prose is OPTIONAL; the lines above it are not.",
|
|
12494
|
+
"",
|
|
12495
|
+
" ```awaiting",
|
|
12496
|
+
" shells: [<the id your runtime gave you>]",
|
|
12497
|
+
" prs: [owner/repo#123]",
|
|
12498
|
+
" for: 2h",
|
|
12499
|
+
" ---",
|
|
12500
|
+
" What you are waiting for, in your own words \u2014 this is what the human reads on your card.",
|
|
12501
|
+
" ```"
|
|
12502
|
+
];
|
|
12503
|
+
}
|
|
12504
|
+
return [
|
|
12505
|
+
"- `` ```awaiting `` \u2014 you are WAITING on work that is actually running: a background shell, a",
|
|
12506
|
+
" sub-agent, a timer or a registered PR. FRONTMATTER, THEN MARKDOWN: one YAML list per kind of thing",
|
|
12507
|
+
" you are waiting on, a REQUIRED `for:` duration, a REQUIRED `needs_input:` answer, then optionally a",
|
|
12508
|
+
" `---` line and prose.",
|
|
12509
|
+
"",
|
|
12510
|
+
" ```awaiting",
|
|
12511
|
+
" agents: [<the id your runtime gave you>]",
|
|
12512
|
+
" needs_input: false",
|
|
12513
|
+
" for: 2h",
|
|
12514
|
+
" ```",
|
|
12515
|
+
"",
|
|
12516
|
+
" `needs_input: false` \u2014 nothing for the human yet. The thread stays out of their queue until the work",
|
|
12517
|
+
" wakes you, and you owe NO write-up: the fence alone is the whole message. `needs_input: true` \u2014 the",
|
|
12518
|
+
" human can read, try or act on something NOW while the work runs (a partial result, a file you wrote,",
|
|
12519
|
+
" a server to try), even if you need nothing back from them; the thread goes into their queue, and the",
|
|
12520
|
+
" prose under `---` says what to look at. If you wrote ANY words for the human at this rest, it is",
|
|
12521
|
+
" `true` \u2014 a `false` rest is never put in front of them. A rest on running work with NO fence is a",
|
|
12522
|
+
" bare rest, and it lands in the human's queue."
|
|
12523
|
+
];
|
|
12524
|
+
}
|
|
12525
|
+
function signoffNudgeText(needsInput) {
|
|
12526
|
+
return [
|
|
12527
|
+
`${SIGNOFF_NUDGE_MARKER} Nothing about your task has changed, and no new work is being asked of you.`,
|
|
12528
|
+
"",
|
|
12529
|
+
"You rested without a fence, so this thread cannot be triaged.",
|
|
12530
|
+
"",
|
|
12531
|
+
"**IF THE TASK STILL HAS PARTS LEFT, THE FENCE IS NOT WHAT YOU OWE \u2014 THE WORK IS.** If ANY part of the",
|
|
12532
|
+
"original task is unfinished, unverified, or deferred, resume it NOW, in THIS turn, and sign off once it",
|
|
12533
|
+
"is genuinely finished. A milestone, a green test run and a long turn are none of them endings, and",
|
|
12534
|
+
"neither is naming the next step or writing it into a scratch file.",
|
|
12535
|
+
"",
|
|
12536
|
+
"**AND THAT TASK IS ALSO THE CEILING \u2014 finish it, and nothing else.** Work you notice on the way is a",
|
|
12537
|
+
"FINDING TO REPORT in your sign-off, never work to take on: the bug beside the one you were sent for,",
|
|
12538
|
+
"the refactor the code obviously wants, the second issue the first one touches. Widening the job is not",
|
|
12539
|
+
"thoroughness \u2014 it is a different job nobody asked for, and it buries the answer they did ask for under",
|
|
12540
|
+
"changes they now have to review. If it should be done, name it in one line and let the human dispatch",
|
|
12541
|
+
"it.",
|
|
12542
|
+
"",
|
|
12543
|
+
"**IF WHAT YOU WERE ASKED FOR IS A DOCUMENT, THE DOCUMENT IS THE ENDING.** A triage, a review, an",
|
|
12544
|
+
"investigation, a recommendation, a plan \u2014 when that is the deliverable, the finished write-up IS the",
|
|
12545
|
+
"work. Implementing what it proposes is the NEXT job, and not yours unless you were asked. Sign off with",
|
|
12546
|
+
"the write-up.",
|
|
12547
|
+
"",
|
|
12548
|
+
"**DECIDE RATHER THAN ASK.** Stop only for a decision that is genuinely the human's AND that blocks you",
|
|
12549
|
+
"right now: register that one with `mcp__frizz__ask`. Every other open choice INSIDE the task \u2014 a name, a",
|
|
12550
|
+
"default, a reversible design call \u2014 is yours to make: decide it, say in one line which way you went and",
|
|
12551
|
+
"what would reverse it, and carry on. A choice that would ENLARGE the task is not one of those: an",
|
|
12552
|
+
"unanswered question is not permission to go build the answer.",
|
|
12553
|
+
"",
|
|
12554
|
+
"Otherwise, sign off \u2014 a registration, or a fence at the END of your next message:",
|
|
12555
|
+
"",
|
|
12556
|
+
"- `mcp__frizz__ask` \u2014 you need the human. NOT a fence: the ```question fence is retired, and a fence",
|
|
12557
|
+
" with a question in its body is plain prose. Register it (options with one-line trade-offs, the",
|
|
12558
|
+
" recommended one first), then rest normally \u2014 an open registered question is the sign-off.",
|
|
12559
|
+
"- `` ```done `` \u2014 genuinely FINISHED. A DISMISSAL: the card is filed away and nobody looks again, so",
|
|
12560
|
+
" if anything is still owed, it is not done. Body: 1-3 sentences, then bullets, each opening with a",
|
|
12561
|
+
" **bolded verb phrase**.",
|
|
12562
|
+
...signoffNudgeAwaitingLines(needsInput),
|
|
12563
|
+
"",
|
|
12564
|
+
" Frizz CHECKS every line: name something that is not running and you are bumped rather than parked.",
|
|
12565
|
+
" A fence that names NOTHING is not a park at all \u2014 if you are not waiting on anything, you are not",
|
|
12566
|
+
" awaiting, you are done. Register a PR with `mcp__frizz__watch_pr` and a timer with",
|
|
12567
|
+
" `mcp__frizz__timer`; `mcp__frizz__activity` reads back everything you have running, with its id.",
|
|
12568
|
+
"",
|
|
12569
|
+
"**STILL OWED counts things you are not going to do yourself.** A decision you are RECOMMENDING, a",
|
|
12570
|
+
"draft you wrote but did not send, follow-up work you discovered \u2014 all of it dies with the card, even",
|
|
12571
|
+
"the part that is someone else's to do. Each ends on a question with your recommendation as option A,",
|
|
12572
|
+
"or you DO it first \u2014 a sub-agent's result comes BACK to you, so it lands on your card; a new card via",
|
|
12573
|
+
"`mcp__frizz__spawn_thread` is the LAST resort, since nothing it learns returns to you or its siblings.",
|
|
12574
|
+
"None of them is a `done`. And what is not",
|
|
12575
|
+
'worth a card is not worth a SENTENCE: delete the dangling "one thing to carry forward", never park it',
|
|
12576
|
+
"in the handoff.",
|
|
12577
|
+
"",
|
|
12578
|
+
"**DO NOT REPEAT YOURSELF.** If the message you just wrote already stands on its own, reply with the",
|
|
12579
|
+
"fence ALONE \u2014 the human reads both together, so restating it costs them the second read for nothing.",
|
|
12580
|
+
"The same holds inside one message: the card is the ledger of what shipped, the prose is only what a",
|
|
12581
|
+
"ledger cannot hold, and a sentence that reads the same in either belongs in exactly one of them.",
|
|
12582
|
+
"",
|
|
12583
|
+
"Only if it does NOT stand alone, fix that first, briefly. It has to be readable cold: the human has",
|
|
12584
|
+
"seen nothing since their own last message \u2014 the Goal, this reminder, a watcher wake all came from",
|
|
12585
|
+
"frizz \u2014 so anything you assumed they had followed, they have not."
|
|
12586
|
+
].join("\n");
|
|
12587
|
+
}
|
|
12488
12588
|
function requireEffortOutsideAcp(profile, ctx) {
|
|
12489
12589
|
if (profile.backend !== "acp" && profile.effort === void 0) {
|
|
12490
12590
|
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["effort"], message: `effort is required for a ${profile.backend} profile` });
|
|
@@ -12493,7 +12593,7 @@ function requireEffortOutsideAcp(profile, ctx) {
|
|
|
12493
12593
|
function fallbackPort(base) {
|
|
12494
12594
|
return base + 1e4;
|
|
12495
12595
|
}
|
|
12496
|
-
var import_yaml, ATTACHMENT_IMAGE_EXTENSIONS, ATTACHMENT_TEXT_EXTENSIONS, ATTACHMENT_OFFICE_EXTENSIONS, ATTACHMENT_DATA_EXTENSIONS, ATTACHMENT_ARCHIVE_EXTENSIONS, ATTACHMENT_DOC_EXTENSIONS, ATTACHMENT_EXTENSIONS, ATTACHMENT_MAX_BASE64_CHARS, ATTACHMENT_MAX_BYTES, ATTACHMENT_EXT_SET, ATTACHMENT_ACCEPT, FrizzStatus, BlockMechanism, RuntimeState, Backend, CodexModel, ClaudeModel, AcpAgent, AcpAgentModel, AcpAgentModels, AcpAgentModelsInput, 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, GithubIssueStatus, 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, SettledQuestionView, ThreadSettledQuestionsResult, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ProviderError, ThreadLinkView, UpsertOwnLinkInput, UpsertOwnLinkResult, DropOwnLinkInput, DropOwnLinkResult, LiveTool, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountBackend, AccountLogoutInput, AccountLogoutResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshotShape, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, DismissFailedFollowUpInput, DismissFailedFollowUpResult, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, CompactThreadInput, SetThreadSnoozeInput, SetThreadPinnedInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetOwnThreadTitleInput, SetOwnThreadTitleResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkillSource, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, UpgradeThreadModelInput, UpgradeThreadModelResult, DISPATCH_TASK_BANNER, DISPATCH_TASK_BANNER_MARKER, 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_GATED, PR_WATCH_STATE, PR_WATCH_CI_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, EditedFile, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketFilePath, SocketTranscriptClientMsg, SocketFileClientMsg, SocketClientMsg, ProjectCard, ProjectRailCounts, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT;
|
|
12596
|
+
var import_yaml, ATTACHMENT_IMAGE_EXTENSIONS, ATTACHMENT_TEXT_EXTENSIONS, ATTACHMENT_OFFICE_EXTENSIONS, ATTACHMENT_DATA_EXTENSIONS, ATTACHMENT_ARCHIVE_EXTENSIONS, ATTACHMENT_DOC_EXTENSIONS, ATTACHMENT_EXTENSIONS, ATTACHMENT_MAX_BASE64_CHARS, ATTACHMENT_MAX_BYTES, ATTACHMENT_EXT_SET, ATTACHMENT_ACCEPT, FrizzStatus, BlockMechanism, RuntimeState, Backend, CodexModel, ClaudeModel, AcpAgent, AcpAgentModel, AcpAgentModels, AcpAgentModelsInput, 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, SIGNOFF_NUDGE_MESSAGE_NEEDS_INPUT, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, GithubIssueStatus, 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, SettledQuestionView, ThreadSettledQuestionsResult, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ProviderError, ThreadLinkView, UpsertOwnLinkInput, UpsertOwnLinkResult, DropOwnLinkInput, DropOwnLinkResult, LiveTool, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountBackend, AccountLogoutInput, AccountLogoutResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshotShape, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, DismissFailedFollowUpInput, DismissFailedFollowUpResult, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, CompactThreadInput, SetThreadSnoozeInput, SetThreadPinnedInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetOwnThreadTitleInput, SetOwnThreadTitleResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkillSource, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, UpgradeThreadModelInput, UpgradeThreadModelResult, DISPATCH_TASK_BANNER, DISPATCH_TASK_BANNER_MARKER, 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_GATED, PR_WATCH_STATE, PR_WATCH_CI_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, EditedFile, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketFilePath, SocketTranscriptClientMsg, SocketFileClientMsg, SocketClientMsg, ProjectCard, ProjectRailCounts, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT;
|
|
12497
12597
|
var init_src = __esm({
|
|
12498
12598
|
"packages/shared/src/index.ts"() {
|
|
12499
12599
|
"use strict";
|
|
@@ -12831,7 +12931,7 @@ var init_src = __esm({
|
|
|
12831
12931
|
questions: external_exports.array(AskQuestion)
|
|
12832
12932
|
});
|
|
12833
12933
|
AwaitingHint = external_exports.object({
|
|
12834
|
-
kind: external_exports.enum(["shell", "agent", "timer", "pr", "issue", "for", "title"]),
|
|
12934
|
+
kind: external_exports.enum(["shell", "agent", "timer", "pr", "issue", "for", "title", "needs_input"]),
|
|
12835
12935
|
value: external_exports.string()
|
|
12836
12936
|
});
|
|
12837
12937
|
RETIRED_AWAITING_KINDS = ["watch", "pr-watch", "human", "ci", "session", "shell", "agent", "timer", "pr", "reason"];
|
|
@@ -12870,77 +12970,8 @@ var init_src = __esm({
|
|
|
12870
12970
|
TIMER_MAX_DELAY_SECONDS = 30 * 24 * 60 * 60;
|
|
12871
12971
|
TimerPromptText = external_exports.string().trim().min(1).max(TIMER_PROMPT_MAX);
|
|
12872
12972
|
SIGNOFF_NUDGE_MARKER = "**This message is from frizz, not from the human.**";
|
|
12873
|
-
SIGNOFF_NUDGE_MESSAGE =
|
|
12874
|
-
|
|
12875
|
-
"",
|
|
12876
|
-
"You rested without a fence, so this thread cannot be triaged.",
|
|
12877
|
-
"",
|
|
12878
|
-
"**IF THE TASK STILL HAS PARTS LEFT, THE FENCE IS NOT WHAT YOU OWE \u2014 THE WORK IS.** If ANY part of the",
|
|
12879
|
-
"original task is unfinished, unverified, or deferred, resume it NOW, in THIS turn, and sign off once it",
|
|
12880
|
-
"is genuinely finished. A milestone, a green test run and a long turn are none of them endings, and",
|
|
12881
|
-
"neither is naming the next step or writing it into a scratch file.",
|
|
12882
|
-
"",
|
|
12883
|
-
"**AND THAT TASK IS ALSO THE CEILING \u2014 finish it, and nothing else.** Work you notice on the way is a",
|
|
12884
|
-
"FINDING TO REPORT in your sign-off, never work to take on: the bug beside the one you were sent for,",
|
|
12885
|
-
"the refactor the code obviously wants, the second issue the first one touches. Widening the job is not",
|
|
12886
|
-
"thoroughness \u2014 it is a different job nobody asked for, and it buries the answer they did ask for under",
|
|
12887
|
-
"changes they now have to review. If it should be done, name it in one line and let the human dispatch",
|
|
12888
|
-
"it.",
|
|
12889
|
-
"",
|
|
12890
|
-
"**IF WHAT YOU WERE ASKED FOR IS A DOCUMENT, THE DOCUMENT IS THE ENDING.** A triage, a review, an",
|
|
12891
|
-
"investigation, a recommendation, a plan \u2014 when that is the deliverable, the finished write-up IS the",
|
|
12892
|
-
"work. Implementing what it proposes is the NEXT job, and not yours unless you were asked. Sign off with",
|
|
12893
|
-
"the write-up.",
|
|
12894
|
-
"",
|
|
12895
|
-
"**DECIDE RATHER THAN ASK.** Stop only for a decision that is genuinely the human's AND that blocks you",
|
|
12896
|
-
"right now: register that one with `mcp__frizz__ask`. Every other open choice INSIDE the task \u2014 a name, a",
|
|
12897
|
-
"default, a reversible design call \u2014 is yours to make: decide it, say in one line which way you went and",
|
|
12898
|
-
"what would reverse it, and carry on. A choice that would ENLARGE the task is not one of those: an",
|
|
12899
|
-
"unanswered question is not permission to go build the answer.",
|
|
12900
|
-
"",
|
|
12901
|
-
"Otherwise, sign off \u2014 a registration, or a fence at the END of your next message:",
|
|
12902
|
-
"",
|
|
12903
|
-
"- `mcp__frizz__ask` \u2014 you need the human. NOT a fence: the ```question fence is retired, and a fence",
|
|
12904
|
-
" with a question in its body is plain prose. Register it (options with one-line trade-offs, the",
|
|
12905
|
-
" recommended one first), then rest normally \u2014 an open registered question is the sign-off.",
|
|
12906
|
-
"- `` ```done `` \u2014 genuinely FINISHED. A DISMISSAL: the card is filed away and nobody looks again, so",
|
|
12907
|
-
" if anything is still owed, it is not done. Body: 1-3 sentences, then bullets, each opening with a",
|
|
12908
|
-
" **bolded verb phrase**.",
|
|
12909
|
-
"- `` ```awaiting `` \u2014 you are WAITING on work that is actually running. FRONTMATTER, THEN MARKDOWN:",
|
|
12910
|
-
" one YAML list per kind of thing you are waiting on, a REQUIRED `for:` duration, then a `---` line and",
|
|
12911
|
-
" as much prose as you want. The prose is OPTIONAL; the lines above it are not.",
|
|
12912
|
-
"",
|
|
12913
|
-
" ```awaiting",
|
|
12914
|
-
" shells: [<the id your runtime gave you>]",
|
|
12915
|
-
" prs: [owner/repo#123]",
|
|
12916
|
-
" for: 2h",
|
|
12917
|
-
" ---",
|
|
12918
|
-
" What you are waiting for, in your own words \u2014 this is what the human reads on your card.",
|
|
12919
|
-
" ```",
|
|
12920
|
-
"",
|
|
12921
|
-
" Frizz CHECKS every line: name something that is not running and you are bumped rather than parked.",
|
|
12922
|
-
" A fence that names NOTHING is not a park at all \u2014 if you are not waiting on anything, you are not",
|
|
12923
|
-
" awaiting, you are done. Register a PR with `mcp__frizz__watch_pr` and a timer with",
|
|
12924
|
-
" `mcp__frizz__timer`; `mcp__frizz__activity` reads back everything you have running, with its id.",
|
|
12925
|
-
"",
|
|
12926
|
-
"**STILL OWED counts things you are not going to do yourself.** A decision you are RECOMMENDING, a",
|
|
12927
|
-
"draft you wrote but did not send, follow-up work you discovered \u2014 all of it dies with the card, even",
|
|
12928
|
-
"the part that is someone else's to do. Each ends on a question with your recommendation as option A,",
|
|
12929
|
-
"or you DO it first \u2014 a sub-agent's result comes BACK to you, so it lands on your card; a new card via",
|
|
12930
|
-
"`mcp__frizz__spawn_thread` is the LAST resort, since nothing it learns returns to you or its siblings.",
|
|
12931
|
-
"None of them is a `done`. And what is not",
|
|
12932
|
-
'worth a card is not worth a SENTENCE: delete the dangling "one thing to carry forward", never park it',
|
|
12933
|
-
"in the handoff.",
|
|
12934
|
-
"",
|
|
12935
|
-
"**DO NOT REPEAT YOURSELF.** If the message you just wrote already stands on its own, reply with the",
|
|
12936
|
-
"fence ALONE \u2014 the human reads both together, so restating it costs them the second read for nothing.",
|
|
12937
|
-
"The same holds inside one message: the card is the ledger of what shipped, the prose is only what a",
|
|
12938
|
-
"ledger cannot hold, and a sentence that reads the same in either belongs in exactly one of them.",
|
|
12939
|
-
"",
|
|
12940
|
-
"Only if it does NOT stand alone, fix that first, briefly. It has to be readable cold: the human has",
|
|
12941
|
-
"seen nothing since their own last message \u2014 the Goal, this reminder, a watcher wake all came from",
|
|
12942
|
-
"frizz \u2014 so anything you assumed they had followed, they have not."
|
|
12943
|
-
].join("\n");
|
|
12973
|
+
SIGNOFF_NUDGE_MESSAGE = signoffNudgeText(false);
|
|
12974
|
+
SIGNOFF_NUDGE_MESSAGE_NEEDS_INPUT = signoffNudgeText(true);
|
|
12944
12975
|
ThreadWatchKind = external_exports.enum(["shell", "github", "timer"]);
|
|
12945
12976
|
GithubChecksState = external_exports.enum(["none", "running", "passing", "failing"]);
|
|
12946
12977
|
GithubMergeState = external_exports.enum(["mergeable", "blocked", "conflicting", "unknown"]);
|
|
@@ -22333,13 +22364,26 @@ var qrcode_default = qrcode;
|
|
|
22333
22364
|
var stringToBytes = qrcode.stringToBytes;
|
|
22334
22365
|
|
|
22335
22366
|
// packages/server/src/qr.ts
|
|
22336
|
-
var
|
|
22337
|
-
var
|
|
22338
|
-
var
|
|
22367
|
+
var DARK = 232;
|
|
22368
|
+
var LIGHT = 231;
|
|
22369
|
+
var fg = (dark) => `\x1B[38;5;${dark ? DARK : LIGHT}m`;
|
|
22370
|
+
var bg = (dark) => `\x1B[48;5;${dark ? DARK : LIGHT}m`;
|
|
22339
22371
|
var RESET = "\x1B[0m";
|
|
22340
22372
|
var UPPER_HALF = "\u2580";
|
|
22341
22373
|
var LOWER_HALF = "\u2584";
|
|
22342
22374
|
var QUIET_ZONE = 4;
|
|
22375
|
+
var BLOCK_DRAWING_PROGRAMS = /* @__PURE__ */ new Set(["iTerm.app", "WezTerm", "ghostty", "WarpTerminal", "vscode"]);
|
|
22376
|
+
var BLOCK_DRAWING_TERMS = /* @__PURE__ */ new Set(["xterm-kitty", "xterm-ghostty", "alacritty", "wezterm"]);
|
|
22377
|
+
function drawsBlockElements(env = process.env) {
|
|
22378
|
+
const term = env.TERM ?? "";
|
|
22379
|
+
if (env.TMUX || env.STY || env.TERM_PROGRAM === "tmux" || term.startsWith("screen") || term.startsWith("tmux")) return false;
|
|
22380
|
+
if (BLOCK_DRAWING_PROGRAMS.has(env.TERM_PROGRAM ?? "")) return true;
|
|
22381
|
+
if (BLOCK_DRAWING_TERMS.has(term)) return true;
|
|
22382
|
+
if (env.LC_TERMINAL === "iTerm2") return true;
|
|
22383
|
+
return Boolean(
|
|
22384
|
+
env.KITTY_WINDOW_ID || env.ALACRITTY_WINDOW_ID || env.WEZTERM_PANE || env.GHOSTTY_RESOURCES_DIR || env.WT_SESSION || env.VTE_VERSION
|
|
22385
|
+
);
|
|
22386
|
+
}
|
|
22343
22387
|
function encode(value, errorCorrection) {
|
|
22344
22388
|
const code = qrcode_default(0, errorCorrection);
|
|
22345
22389
|
code.addData(value);
|
|
@@ -22356,26 +22400,70 @@ function encode(value, errorCorrection) {
|
|
|
22356
22400
|
}
|
|
22357
22401
|
};
|
|
22358
22402
|
}
|
|
22359
|
-
function
|
|
22360
|
-
|
|
22361
|
-
|
|
22403
|
+
function sizeOf(size, style) {
|
|
22404
|
+
return style === "paint" ? { columns: size * 2, rows: size } : { columns: size, rows: Math.ceil(size / 2) };
|
|
22405
|
+
}
|
|
22406
|
+
function qrSize(value, style = "half", errorCorrection = "M") {
|
|
22407
|
+
return sizeOf(encode(value, errorCorrection).size, style);
|
|
22408
|
+
}
|
|
22409
|
+
function qrStyleFor(value, options2 = {}) {
|
|
22410
|
+
const { area } = options2;
|
|
22411
|
+
if (!area || drawsBlockElements(options2.env)) return "half";
|
|
22412
|
+
const paint = qrSize(value, "paint", options2.errorCorrection);
|
|
22413
|
+
return paint.columns <= area.columns && paint.rows <= area.rows ? "paint" : "half";
|
|
22414
|
+
}
|
|
22415
|
+
function qrAreaOf(stream, frame) {
|
|
22416
|
+
if (!stream.columns || !stream.rows) return void 0;
|
|
22417
|
+
return { columns: stream.columns - frame.indent, rows: stream.rows - frame.rows };
|
|
22418
|
+
}
|
|
22419
|
+
function halfLines(size, at, plain) {
|
|
22362
22420
|
const lines = [];
|
|
22363
22421
|
for (let y = 0; y < size; y += 2) {
|
|
22364
22422
|
let line = "";
|
|
22365
22423
|
for (let x = 0; x < size; x++) {
|
|
22366
22424
|
const top = at(x, y);
|
|
22367
22425
|
const bottom = y + 1 < size ? at(x, y + 1) : false;
|
|
22368
|
-
if (
|
|
22426
|
+
if (plain) {
|
|
22369
22427
|
line += top && bottom ? "#" : top ? "^" : bottom ? "v" : " ";
|
|
22370
22428
|
continue;
|
|
22371
22429
|
}
|
|
22372
|
-
if (top === bottom)
|
|
22373
|
-
|
|
22430
|
+
if (top === bottom) {
|
|
22431
|
+
line += `${bg(top)} `;
|
|
22432
|
+
continue;
|
|
22433
|
+
}
|
|
22434
|
+
const above = y > 0 ? at(x, y - 1) : false;
|
|
22435
|
+
const below = y + 2 < size ? at(x, y + 2) : false;
|
|
22436
|
+
line += below === bottom && above !== top ? `${fg(top)}${bg(bottom)}${UPPER_HALF}` : `${fg(bottom)}${bg(top)}${LOWER_HALF}`;
|
|
22374
22437
|
}
|
|
22375
|
-
lines.push(
|
|
22438
|
+
lines.push(plain ? line : `${line}${RESET}`);
|
|
22376
22439
|
}
|
|
22377
22440
|
return lines;
|
|
22378
22441
|
}
|
|
22442
|
+
function paintLines(size, at, plain) {
|
|
22443
|
+
const lines = [];
|
|
22444
|
+
for (let y = 0; y < size; y++) {
|
|
22445
|
+
let line = "";
|
|
22446
|
+
let last;
|
|
22447
|
+
for (let x = 0; x < size; x++) {
|
|
22448
|
+
const dark = at(x, y);
|
|
22449
|
+
if (plain) line += dark ? "##" : " ";
|
|
22450
|
+
else {
|
|
22451
|
+
if (dark !== last) line += bg(dark);
|
|
22452
|
+
line += " ";
|
|
22453
|
+
}
|
|
22454
|
+
last = dark;
|
|
22455
|
+
}
|
|
22456
|
+
lines.push(plain ? line : `${line}${RESET}`);
|
|
22457
|
+
}
|
|
22458
|
+
return lines;
|
|
22459
|
+
}
|
|
22460
|
+
function renderQrLines(value, options2 = {}) {
|
|
22461
|
+
if (!value) throw new Error("renderQr requires a value");
|
|
22462
|
+
const errorCorrection = options2.errorCorrection ?? "M";
|
|
22463
|
+
const { size, at } = encode(value, errorCorrection);
|
|
22464
|
+
const style = options2.style ?? qrStyleFor(value, { area: options2.area, env: options2.env, errorCorrection });
|
|
22465
|
+
return style === "paint" ? paintLines(size, at, options2.plain ?? false) : halfLines(size, at, options2.plain ?? false);
|
|
22466
|
+
}
|
|
22379
22467
|
|
|
22380
22468
|
// packages/server/src/restart-supervisor.ts
|
|
22381
22469
|
import { request as requestHttp, createServer } from "node:http";
|
|
@@ -23298,12 +23386,20 @@ function installPaneHost(options2) {
|
|
|
23298
23386
|
input.pause();
|
|
23299
23387
|
process.off("exit", restore);
|
|
23300
23388
|
};
|
|
23389
|
+
const reclaim = () => {
|
|
23390
|
+
if (disposed) return;
|
|
23391
|
+
try {
|
|
23392
|
+
input.setRawMode(false);
|
|
23393
|
+
input.setRawMode(true);
|
|
23394
|
+
} catch {
|
|
23395
|
+
}
|
|
23396
|
+
};
|
|
23301
23397
|
input.setRawMode(true);
|
|
23302
23398
|
input.resume();
|
|
23303
23399
|
input.setEncoding("utf8");
|
|
23304
23400
|
input.on("data", onKey);
|
|
23305
23401
|
process.on("exit", restore);
|
|
23306
|
-
return { dispose: restore, isOpen: () => active !== null };
|
|
23402
|
+
return { dispose: restore, isOpen: () => active !== null, reclaim };
|
|
23307
23403
|
}
|
|
23308
23404
|
|
|
23309
23405
|
// src/access-pane.ts
|
|
@@ -23317,6 +23413,18 @@ var RESET2 = "\x1B[0m";
|
|
|
23317
23413
|
function secondsUntil(expiresAt, now) {
|
|
23318
23414
|
return Math.max(0, Math.ceil((expiresAt - now) / 1e3));
|
|
23319
23415
|
}
|
|
23416
|
+
function fitScreen(entries, rows, columns) {
|
|
23417
|
+
const width = columns ?? 80;
|
|
23418
|
+
const height = (text) => Math.max(1, Math.ceil([...text.replace(/\x1b\[[0-9;]*m/g, "")].length / width));
|
|
23419
|
+
const kept = entries.map((entry) => typeof entry === "string" ? { text: entry, drop: Infinity } : entry);
|
|
23420
|
+
const total = () => kept.reduce((sum, entry) => sum + height(entry.text), 0);
|
|
23421
|
+
while (rows && total() > rows) {
|
|
23422
|
+
const next = kept.reduce((lowest, entry, index) => entry.drop < (kept[lowest]?.drop ?? Infinity) ? index : lowest, -1);
|
|
23423
|
+
if (next < 0) break;
|
|
23424
|
+
kept.splice(next, 1);
|
|
23425
|
+
}
|
|
23426
|
+
return kept.map((entry) => entry.text).join("\n");
|
|
23427
|
+
}
|
|
23320
23428
|
function createAccessPane(options2) {
|
|
23321
23429
|
const output = options2.output ?? process.stdout;
|
|
23322
23430
|
const now = options2.now ?? Date.now;
|
|
@@ -23328,16 +23436,25 @@ function createAccessPane(options2) {
|
|
|
23328
23436
|
if (!shown) return;
|
|
23329
23437
|
const remaining = secondsUntil(shown.expiresAt, now());
|
|
23330
23438
|
const status = consumed ? "This link has been used. Press L for another." : remaining === 0 ? "This link has expired. Press L for another." : `Single use, expires in ${remaining}s.`;
|
|
23439
|
+
const footer = `${status} Press any other key to close.`;
|
|
23440
|
+
const width = output.columns ?? 80;
|
|
23441
|
+
const wrapped = (text) => Math.max(1, Math.ceil((text.length + 2) / width));
|
|
23442
|
+
const qr = renderQrLines(shown.url, { area: qrAreaOf(output, { indent: 2, rows: wrapped(shown.url) + wrapped(footer) + 1 }) });
|
|
23331
23443
|
output.write(CLEAR);
|
|
23332
|
-
output.write(
|
|
23333
|
-
|
|
23334
|
-
|
|
23335
|
-
|
|
23336
|
-
${
|
|
23337
|
-
|
|
23338
|
-
|
|
23339
|
-
|
|
23340
|
-
`
|
|
23444
|
+
output.write(
|
|
23445
|
+
fitScreen(
|
|
23446
|
+
[
|
|
23447
|
+
{ text: "", drop: 1 },
|
|
23448
|
+
...qr.map((row) => ` ${row}`),
|
|
23449
|
+
{ text: "", drop: 3 },
|
|
23450
|
+
` ${shown.url}`,
|
|
23451
|
+
{ text: "", drop: 2 },
|
|
23452
|
+
` ${DIM}${footer}${RESET2}`
|
|
23453
|
+
],
|
|
23454
|
+
output.rows,
|
|
23455
|
+
output.columns
|
|
23456
|
+
)
|
|
23457
|
+
);
|
|
23341
23458
|
};
|
|
23342
23459
|
return {
|
|
23343
23460
|
open() {
|
|
@@ -24284,9 +24401,8 @@ function createRemotePane(options2) {
|
|
|
24284
24401
|
const write = (lines) => {
|
|
24285
24402
|
if (!open) return;
|
|
24286
24403
|
output.write(CLEAR);
|
|
24287
|
-
|
|
24288
|
-
|
|
24289
|
-
`);
|
|
24404
|
+
const indented = lines.map((line) => typeof line === "string" ? ` ${line}` : { ...line, text: ` ${line.text}` });
|
|
24405
|
+
output.write(fitScreen([{ text: "", drop: 0 }, ...indented], output.rows, output.columns));
|
|
24290
24406
|
};
|
|
24291
24407
|
const check = (ok, text) => ok ? `${text} \u2713` : text;
|
|
24292
24408
|
const paint = () => {
|
|
@@ -24328,13 +24444,25 @@ function createRemotePane(options2) {
|
|
|
24328
24444
|
return;
|
|
24329
24445
|
}
|
|
24330
24446
|
if (s.name === "done") {
|
|
24331
|
-
|
|
24332
|
-
|
|
24333
|
-
|
|
24334
|
-
lines.push("", s.link.url, "", `${DIM}Scan to sign in on a phone. Single use, expires in 5 minutes. Press L later for another.${RESET2}`);
|
|
24447
|
+
if (!s.link) {
|
|
24448
|
+
write([s.message, "", `${DIM}press any key to return${RESET2}`]);
|
|
24449
|
+
return;
|
|
24335
24450
|
}
|
|
24336
|
-
|
|
24337
|
-
|
|
24451
|
+
const note = `${DIM}Scan to sign in on a phone. Single use, expires in 5 minutes. Press L later for another.${RESET2}`;
|
|
24452
|
+
const width = output.columns ?? 80;
|
|
24453
|
+
const wrapped = (text) => Math.max(1, Math.ceil((text.length + 2) / width));
|
|
24454
|
+
const qr = renderQrLines(s.link.url, { area: qrAreaOf(output, { indent: 2, rows: wrapped(s.message) + 1 + wrapped(s.link.url) + 1 }) });
|
|
24455
|
+
write([
|
|
24456
|
+
s.message,
|
|
24457
|
+
{ text: "", drop: 4 },
|
|
24458
|
+
...qr,
|
|
24459
|
+
{ text: "", drop: 6 },
|
|
24460
|
+
s.link.url,
|
|
24461
|
+
{ text: "", drop: 2 },
|
|
24462
|
+
{ text: note, drop: 5 },
|
|
24463
|
+
{ text: "", drop: 3 },
|
|
24464
|
+
`${DIM}press any key to return${RESET2}`
|
|
24465
|
+
]);
|
|
24338
24466
|
return;
|
|
24339
24467
|
}
|
|
24340
24468
|
write([`Could not apply that: ${s.message}`, "", `${DIM}press any key to go back${RESET2}`]);
|
|
@@ -25699,6 +25827,7 @@ var Supervisor = class {
|
|
|
25699
25827
|
logLine;
|
|
25700
25828
|
errorLine;
|
|
25701
25829
|
onActivity;
|
|
25830
|
+
onChildExit;
|
|
25702
25831
|
/** Suppresses activity beats until the first boot has settled; until then the readout owns the terminal. */
|
|
25703
25832
|
booted = false;
|
|
25704
25833
|
/** When the restart currently in flight began, so its "ready" beat can report a duration. */
|
|
@@ -25751,6 +25880,7 @@ var Supervisor = class {
|
|
|
25751
25880
|
this.logLine = opts.log ?? ((line) => log.info("supervisor", stripPrefix(line)));
|
|
25752
25881
|
this.errorLine = opts.error ?? ((line) => log.error("supervisor", stripPrefix(line)));
|
|
25753
25882
|
this.onActivity = opts.onActivity;
|
|
25883
|
+
this.onChildExit = opts.onChildExit;
|
|
25754
25884
|
this.updateRestart = opts.updateRestart;
|
|
25755
25885
|
this.updateMode = opts.updateMode ?? "durableReexec";
|
|
25756
25886
|
this.commitUpdate = opts.commitUpdate;
|
|
@@ -26249,6 +26379,10 @@ var Supervisor = class {
|
|
|
26249
26379
|
settleSpawn(false);
|
|
26250
26380
|
});
|
|
26251
26381
|
child.once("exit", (code, signal) => {
|
|
26382
|
+
try {
|
|
26383
|
+
this.onChildExit?.();
|
|
26384
|
+
} catch {
|
|
26385
|
+
}
|
|
26252
26386
|
if (this.child === child) {
|
|
26253
26387
|
this.child = null;
|
|
26254
26388
|
this.childPort = void 0;
|
|
@@ -27217,7 +27351,7 @@ if (options.link) {
|
|
|
27217
27351
|
process.exit(1);
|
|
27218
27352
|
}
|
|
27219
27353
|
const { url } = await response.json();
|
|
27220
|
-
if (process.stdout.isTTY) for (const row of renderQrLines(url)) console.log(` ${row}`);
|
|
27354
|
+
if (process.stdout.isTTY) for (const row of renderQrLines(url, { area: qrAreaOf(process.stdout, { indent: 2, rows: 3 }) })) console.log(` ${row}`);
|
|
27221
27355
|
console.log(process.stdout.isTTY ? `
|
|
27222
27356
|
${url}` : url);
|
|
27223
27357
|
process.exit(0);
|
|
@@ -27395,6 +27529,9 @@ async function runSupervisor(port, token, onPrepared = () => {
|
|
|
27395
27529
|
// here is triggered from a browser tab or by a crash, so without this the foreground process is
|
|
27396
27530
|
// the last place to learn what happened to it.
|
|
27397
27531
|
onActivity: (event) => renderSupervisorActivity(activityReadout, event),
|
|
27532
|
+
// Every child leaves the terminal as it found it at its own fork, and the first one was forked
|
|
27533
|
+
// before the keyboard went raw — so without this R stopped working after the first update.
|
|
27534
|
+
onChildExit: () => paneHost?.reclaim(),
|
|
27398
27535
|
updateRestart: async () => {
|
|
27399
27536
|
previous = active;
|
|
27400
27537
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frizz",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A local web UI for running many coding agents at once",
|
|
6
6
|
"keywords": [
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
},
|
|
67
67
|
"frizzServer": {
|
|
68
68
|
"package": "frizz-server",
|
|
69
|
-
"version": "0.15.
|
|
69
|
+
"version": "0.15.8",
|
|
70
70
|
"protocol": 1,
|
|
71
71
|
"dataEpoch": 1
|
|
72
72
|
}
|