frizz 0.13.0 → 0.13.2
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 +225 -55
- package/package.json +3 -3
package/dist/frizz.js
CHANGED
|
@@ -180,10 +180,21 @@ var init_local_origin = __esm({
|
|
|
180
180
|
}
|
|
181
181
|
});
|
|
182
182
|
|
|
183
|
+
// packages/server/src/local-path.ts
|
|
184
|
+
function normalizeLocalPath(path, platform = process.platform) {
|
|
185
|
+
return platform === "win32" ? path.replace(/^\/([a-zA-Z]:[\\/])/, "$1") : path;
|
|
186
|
+
}
|
|
187
|
+
var init_local_path = __esm({
|
|
188
|
+
"packages/server/src/local-path.ts"() {
|
|
189
|
+
"use strict";
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
183
193
|
// packages/server/src/local-image.ts
|
|
184
194
|
import { readFileSync as readFileSync2, realpathSync, statSync } from "node:fs";
|
|
185
195
|
import { extname, isAbsolute } from "node:path";
|
|
186
196
|
function resolveLocalImage(rawPath) {
|
|
197
|
+
if (rawPath) rawPath = normalizeLocalPath(rawPath);
|
|
187
198
|
if (!rawPath || !isAbsolute(rawPath)) return { status: 400 };
|
|
188
199
|
const contentType = IMAGE_CONTENT_TYPE[extname(rawPath).toLowerCase()];
|
|
189
200
|
if (!contentType) return { status: 400 };
|
|
@@ -204,6 +215,7 @@ var IMAGE_CONTENT_TYPE;
|
|
|
204
215
|
var init_local_image = __esm({
|
|
205
216
|
"packages/server/src/local-image.ts"() {
|
|
206
217
|
"use strict";
|
|
218
|
+
init_local_path();
|
|
207
219
|
IMAGE_CONTENT_TYPE = {
|
|
208
220
|
".png": "image/png",
|
|
209
221
|
".jpg": "image/jpeg",
|
|
@@ -11775,7 +11787,7 @@ var init_interactions = __esm({
|
|
|
11775
11787
|
InteractionFieldId = external_exports.string().min(1).max(128).regex(/^[A-Za-z_][A-Za-z0-9_.:-]*$/).refine((value) => !["__proto__", "constructor", "prototype"].includes(value), "reserved field id");
|
|
11776
11788
|
InteractionDecisionId = external_exports.string().min(1).max(80).regex(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/);
|
|
11777
11789
|
InteractionProvider = external_exports.object({
|
|
11778
|
-
kind: external_exports.enum(["claude", "codex", "frizz"]),
|
|
11790
|
+
kind: external_exports.enum(["claude", "codex", "acp", "frizz"]),
|
|
11779
11791
|
name: InteractionLabel.optional(),
|
|
11780
11792
|
version: InteractionOpaqueId.optional()
|
|
11781
11793
|
}).strict();
|
|
@@ -12322,6 +12334,13 @@ var init_claim = __esm({
|
|
|
12322
12334
|
}
|
|
12323
12335
|
});
|
|
12324
12336
|
|
|
12337
|
+
// packages/shared/src/claude-editions.ts
|
|
12338
|
+
var init_claude_editions = __esm({
|
|
12339
|
+
"packages/shared/src/claude-editions.ts"() {
|
|
12340
|
+
"use strict";
|
|
12341
|
+
}
|
|
12342
|
+
});
|
|
12343
|
+
|
|
12325
12344
|
// packages/shared/src/code-fences.ts
|
|
12326
12345
|
var init_code_fences = __esm({
|
|
12327
12346
|
"packages/shared/src/code-fences.ts"() {
|
|
@@ -12466,10 +12485,15 @@ var init_shell_writes = __esm({
|
|
|
12466
12485
|
});
|
|
12467
12486
|
|
|
12468
12487
|
// packages/shared/src/index.ts
|
|
12488
|
+
function requireEffortOutsideAcp(profile, ctx) {
|
|
12489
|
+
if (profile.backend !== "acp" && profile.effort === void 0) {
|
|
12490
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["effort"], message: `effort is required for a ${profile.backend} profile` });
|
|
12491
|
+
}
|
|
12492
|
+
}
|
|
12469
12493
|
function fallbackPort(base) {
|
|
12470
12494
|
return base + 1e4;
|
|
12471
12495
|
}
|
|
12472
|
-
var import_yaml, ATTACHMENT_IMAGE_EXTENSIONS, ATTACHMENT_TEXT_EXTENSIONS, ATTACHMENT_OFFICE_EXTENSIONS, ATTACHMENT_DATA_EXTENSIONS, ATTACHMENT_ARCHIVE_EXTENSIONS, ATTACHMENT_DOC_EXTENSIONS, ATTACHMENT_EXTENSIONS, ATTACHMENT_MAX_BASE64_CHARS, ATTACHMENT_MAX_BYTES, ATTACHMENT_EXT_SET, ATTACHMENT_ACCEPT, FrizzStatus, BlockMechanism, RuntimeState, Backend, CodexModel, ThreadProfileOption, ThreadAgent, SubAgentView, BgShellView, CompletionHoldOp, CompletionHold, AskOption, AskQuestion, PendingAsk, AwaitingHint, RETIRED_AWAITING_KINDS, RETIRED_LINE_RE, AWAITING_FOR_MAX_MS, SnoozeUntil, SNOOZE_PROMPT_MAX, SnoozePrompt, RECURRING_PROMPT_MAX, RECURRING_MIN_INTERVAL_SECONDS, RECURRING_MAX_INTERVAL_SECONDS, RecurringPromptText, RecurringIntervalSeconds, ThreadRecurringPrompt, TIMER_PROMPT_MAX, TIMER_MAX_DELAY_SECONDS, TimerPromptText, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, ThreadWatchView, PR_WATCH_FOR_MAX_MS, PR_WATCH_DEFAULT_FOR_MS, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, OwnWatchKind, AddOwnWatchInput, OwnWatchView, AddOwnWatchResult, DropOwnWatchInput, DropOwnWatchResult, AskQuestionKind, AskedOptionSchema, AskedQuestionSchema, AskInput, RegisteredQuestionView, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ProviderError, ThreadLinkView, UpsertOwnLinkInput, UpsertOwnLinkResult, DropOwnLinkInput, DropOwnLinkResult, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountLogoutInput, AccountLogoutResult, AccountLoginStartInput, AccountLoginStartResult, AccountLoginStatusInput, AccountLoginStatusResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, SetThreadSnoozeInput, SetThreadPinnedInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetOwnThreadTitleInput, SetOwnThreadTitleResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkillSource, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, DISPATCH_TASK_BANNER, DISPATCH_TASK_BANNER_MARKER, HUMAN_GAP_FLOOR_MS, GithubWakeItem, GithubWakeSteer, WAKE_SCOPE, WAKE_REF, WAKE_SINGLE, WAKE_MULTI_HEAD, PR_WATCH_FINISHED, PR_WATCH_CI_PASSED, PR_WATCH_CI_GATED, PR_WATCH_STATE, PR_WATCH_CI_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, EditedFile, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketFilePath, SocketTranscriptClientMsg, SocketFileClientMsg, SocketClientMsg, ProjectCard, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT;
|
|
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, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ProviderError, ThreadLinkView, UpsertOwnLinkInput, UpsertOwnLinkResult, DropOwnLinkInput, DropOwnLinkResult, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountBackend, AccountLogoutInput, AccountLogoutResult, AccountLoginStartInput, AccountLoginStartResult, AccountLoginStatusInput, AccountLoginStatusResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshotShape, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, SetThreadSnoozeInput, SetThreadPinnedInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetOwnThreadTitleInput, SetOwnThreadTitleResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkillSource, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, 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;
|
|
12473
12497
|
var init_src = __esm({
|
|
12474
12498
|
"packages/shared/src/index.ts"() {
|
|
12475
12499
|
"use strict";
|
|
@@ -12478,6 +12502,7 @@ var init_src = __esm({
|
|
|
12478
12502
|
init_interactions();
|
|
12479
12503
|
init_thread_slug();
|
|
12480
12504
|
init_claim();
|
|
12505
|
+
init_claude_editions();
|
|
12481
12506
|
init_code_fences();
|
|
12482
12507
|
init_delta();
|
|
12483
12508
|
init_drainable_worker();
|
|
@@ -12588,7 +12613,7 @@ var init_src = __esm({
|
|
|
12588
12613
|
"exited"
|
|
12589
12614
|
// the worker process that owned this session is gone, or is no longer driving its turn
|
|
12590
12615
|
]);
|
|
12591
|
-
Backend = external_exports.enum(["claude", "codex"]);
|
|
12616
|
+
Backend = external_exports.enum(["claude", "codex", "acp"]);
|
|
12592
12617
|
CodexModel = external_exports.object({
|
|
12593
12618
|
slug: external_exports.string(),
|
|
12594
12619
|
displayName: external_exports.string(),
|
|
@@ -12602,9 +12627,36 @@ var init_src = __esm({
|
|
|
12602
12627
|
contextWindow: external_exports.number().int().positive().optional(),
|
|
12603
12628
|
maxContextWindow: external_exports.number().int().positive().optional()
|
|
12604
12629
|
});
|
|
12630
|
+
ClaudeModel = external_exports.object({
|
|
12631
|
+
alias: external_exports.string(),
|
|
12632
|
+
label: external_exports.string(),
|
|
12633
|
+
resolvedModel: external_exports.string().optional(),
|
|
12634
|
+
// The edition alone ("5.5") — the tail of `label`, which the picker sets dimmer than the family word.
|
|
12635
|
+
// Absent exactly when `resolvedModel` is.
|
|
12636
|
+
edition: external_exports.string().optional()
|
|
12637
|
+
});
|
|
12638
|
+
AcpAgent = external_exports.object({
|
|
12639
|
+
id: external_exports.string(),
|
|
12640
|
+
label: external_exports.string(),
|
|
12641
|
+
command: external_exports.string(),
|
|
12642
|
+
available: external_exports.boolean()
|
|
12643
|
+
});
|
|
12644
|
+
AcpAgentModel = external_exports.object({ id: external_exports.string(), name: external_exports.string() });
|
|
12645
|
+
AcpAgentModels = external_exports.object({
|
|
12646
|
+
agentId: external_exports.string(),
|
|
12647
|
+
models: external_exports.array(AcpAgentModel),
|
|
12648
|
+
/** The model the agent opens a session on when Frizz asks for none. */
|
|
12649
|
+
current: external_exports.string().optional(),
|
|
12650
|
+
/** Why the list is empty, when the probe could not open a session (not installed, not logged in…). */
|
|
12651
|
+
error: external_exports.string().optional(),
|
|
12652
|
+
probedAt: external_exports.string()
|
|
12653
|
+
});
|
|
12654
|
+
AcpAgentModelsInput = external_exports.object({ agentId: external_exports.string().min(1).max(100), refresh: external_exports.boolean().optional() }).strict();
|
|
12605
12655
|
ThreadProfileOption = external_exports.object({
|
|
12606
12656
|
model: external_exports.string().min(1),
|
|
12607
12657
|
label: external_exports.string().min(1),
|
|
12658
|
+
// The edition at the end of `label` ("5.5" of "Opus 5.5"), for a Claude row the pinned runtime resolved.
|
|
12659
|
+
edition: external_exports.string().optional(),
|
|
12608
12660
|
defaultEffort: external_exports.string().min(1),
|
|
12609
12661
|
efforts: external_exports.array(external_exports.string().min(1)).min(1)
|
|
12610
12662
|
});
|
|
@@ -12779,7 +12831,7 @@ var init_src = __esm({
|
|
|
12779
12831
|
questions: external_exports.array(AskQuestion)
|
|
12780
12832
|
});
|
|
12781
12833
|
AwaitingHint = external_exports.object({
|
|
12782
|
-
kind: external_exports.enum(["shell", "agent", "timer", "pr", "for", "title"]),
|
|
12834
|
+
kind: external_exports.enum(["shell", "agent", "timer", "pr", "issue", "for", "title"]),
|
|
12783
12835
|
value: external_exports.string()
|
|
12784
12836
|
});
|
|
12785
12837
|
RETIRED_AWAITING_KINDS = ["watch", "pr-watch", "human", "ci", "session", "shell", "agent", "timer", "pr", "reason"];
|
|
@@ -12929,6 +12981,20 @@ var init_src = __esm({
|
|
|
12929
12981
|
* must hear about. Empty when nothing is failing. */
|
|
12930
12982
|
failureSig: external_exports.string().optional()
|
|
12931
12983
|
}).strict();
|
|
12984
|
+
GithubIssueStatus = external_exports.object({
|
|
12985
|
+
/** OPEN | CLOSED, lowercased. A closed issue ends the wait outright. */
|
|
12986
|
+
state: external_exports.enum(["open", "closed"]),
|
|
12987
|
+
/** GitHub's own reason for a close — `completed`, `not_planned`, `duplicate` — lowercased, when it
|
|
12988
|
+
* gave one. Absent while open. */
|
|
12989
|
+
stateReason: external_exports.string().optional(),
|
|
12990
|
+
/** The issue's title, as of the last poll — the one fact a human needs to place a bare `owner/repo#N`
|
|
12991
|
+
* on the card. Capped, because a title is a headline and the card is not the place to read one. */
|
|
12992
|
+
title: external_exports.string().max(200).optional(),
|
|
12993
|
+
/** The conversation's size, so the card can say "14 comments" the way GitHub's list does. */
|
|
12994
|
+
comments: external_exports.number().int().nonnegative(),
|
|
12995
|
+
/** When frizz last heard from GitHub, for the same reason `GithubWatchStatus.polledAt` carries it. */
|
|
12996
|
+
polledAt: external_exports.string()
|
|
12997
|
+
}).strict();
|
|
12932
12998
|
ThreadWatchView = external_exports.object({
|
|
12933
12999
|
id: external_exports.string(),
|
|
12934
13000
|
kind: ThreadWatchKind,
|
|
@@ -12937,6 +13003,15 @@ var init_src = __esm({
|
|
|
12937
13003
|
createdAt: external_exports.string(),
|
|
12938
13004
|
/** `github` rows only, and absent until the first successful poll. */
|
|
12939
13005
|
github: GithubWatchStatus.optional(),
|
|
13006
|
+
/** `github` rows only: WHAT the row watches. A pull request and an issue share the kind — they are one
|
|
13007
|
+
* registry, one ref grammar (`owner/repo#N`) and one place on every surface that lists waits — and
|
|
13008
|
+
* differ in what the poll can read off them, which is what this field lets a card branch on.
|
|
13009
|
+
* Optional, and absent means a pull request — a row from a server that predates issues reads as the
|
|
13010
|
+
* PR it always was, and the non-github kinds never carry it. */
|
|
13011
|
+
subject: external_exports.enum(["pull", "issue"]).optional(),
|
|
13012
|
+
/** `github` rows watching an ISSUE only, and absent until the first successful poll — the twin of the
|
|
13013
|
+
* `github` half above, for the rows whose subject has no checks to report. */
|
|
13014
|
+
issue: GithubIssueStatus.optional(),
|
|
12940
13015
|
/** `timer` rows only: the armed timer's own registration, which is everything the row renders — the
|
|
12941
13016
|
* worker's prompt is the row's NAME (a `tmr_…` id names nothing to a human) and the fire instant is
|
|
12942
13017
|
* its status. Unlike `github` there is no polled half to be absent: a timer that exists is fully
|
|
@@ -12949,10 +13024,15 @@ var init_src = __esm({
|
|
|
12949
13024
|
id: external_exports.string(),
|
|
12950
13025
|
/** `owner/repo#N`, normalized — the same string the board's row and the status book are keyed by. */
|
|
12951
13026
|
target: external_exports.string(),
|
|
13027
|
+
/** A pull request or an issue. Both live in one registry (`pr_watch`) and answer to one drop verb;
|
|
13028
|
+
* `watch_pr` and `watch_issue` each list only their own. Defaulted for a row an older server sends. */
|
|
13029
|
+
kind: external_exports.enum(["pull", "issue"]).default("pull"),
|
|
12952
13030
|
state: external_exports.enum(["armed", "dropped", "settled"]),
|
|
12953
13031
|
createdAt: external_exports.string(),
|
|
12954
13032
|
/** The PR's checks/mergeability as the poller last saw it. Absent until the first successful poll. */
|
|
12955
|
-
github: GithubWatchStatus.optional()
|
|
13033
|
+
github: GithubWatchStatus.optional(),
|
|
13034
|
+
/** An ISSUE's state as the poller last saw it — `kind: "issue"` rows only, absent until polled. */
|
|
13035
|
+
issue: GithubIssueStatus.optional()
|
|
12956
13036
|
}).strict();
|
|
12957
13037
|
AddOwnPrWatchInput = external_exports.object({
|
|
12958
13038
|
slug: ThreadSlug,
|
|
@@ -12977,7 +13057,13 @@ var init_src = __esm({
|
|
|
12977
13057
|
* already running, with no recourse from inside those threads. Absent ⇒ PR_WATCH_DEFAULT_FOR, which
|
|
12978
13058
|
* still BOUNDS the poll; the point of the field is that a worker chooses, and one that cannot choose
|
|
12979
13059
|
* is better bounded than broken. */
|
|
12980
|
-
for: external_exports.string().trim().min(1).max(16).optional()
|
|
13060
|
+
for: external_exports.string().trim().min(1).max(16).optional(),
|
|
13061
|
+
/** What `target` names. `issue` (from `mcp__frizz__watch_issue`, 2026-09-14) registers a watcher on a
|
|
13062
|
+
* GitHub issue — same registry, same poll cadence, same drop verb, but a different probe (`gh issue
|
|
13063
|
+
* view`), a different GraphQL fragment and a report with no CI in it. ABSENT MEANS A PULL REQUEST,
|
|
13064
|
+
* for the same reason `for` is optional on the wire: every `watch_pr` binary dispatched before this
|
|
13065
|
+
* field existed sends nothing here and must go on meaning what it always did. */
|
|
13066
|
+
kind: external_exports.enum(["pull", "issue"]).optional()
|
|
12981
13067
|
}).strict();
|
|
12982
13068
|
AddOwnPrWatchResult = external_exports.object({
|
|
12983
13069
|
id: external_exports.string(),
|
|
@@ -13443,6 +13529,16 @@ var init_src = __esm({
|
|
|
13443
13529
|
// values forward-compatible; absent when neither durable source knows → the UI renders no guess.
|
|
13444
13530
|
model: external_exports.string().optional(),
|
|
13445
13531
|
effort: external_exports.string().optional(),
|
|
13532
|
+
// The Claude EDITION this thread's worker last ran ("Opus 5"), read off the model id on its own
|
|
13533
|
+
// transcript. It can be older than the edition the picker's row names ("Opus 5.5"): a worker keeps the
|
|
13534
|
+
// runtime it was started on, and a new pin only reaches the workers started after it. Emitted only when
|
|
13535
|
+
// that id belongs to the family `model` names, so a pending model switch never shows the old family's.
|
|
13536
|
+
runningModelLabel: external_exports.string().optional(),
|
|
13537
|
+
// Present when the pinned runtime now resolves this thread's family to a NEWER edition than it runs.
|
|
13538
|
+
// `staged`: no live worker holds the old edition, so the next turn starts on `label` with nothing
|
|
13539
|
+
// further to do; otherwise the composer offers the upgrade, and the first message after the thread's
|
|
13540
|
+
// next compaction takes it on its own.
|
|
13541
|
+
modelUpgrade: external_exports.object({ label: external_exports.string(), staged: external_exports.boolean() }).optional(),
|
|
13446
13542
|
// How full the session's context window is right now — the footer's fullness readout. BOTH halves
|
|
13447
13543
|
// are provider-measured and the field is emitted ONLY when both are present, so a client never has
|
|
13448
13544
|
// to decide what to do with half a fraction: absent ⇒ no reading, never a 0% dial. Codex reports
|
|
@@ -13525,14 +13621,15 @@ var init_src = __esm({
|
|
|
13525
13621
|
codex: ProviderAuth,
|
|
13526
13622
|
emails: AccountEmails
|
|
13527
13623
|
});
|
|
13528
|
-
|
|
13624
|
+
AccountBackend = external_exports.enum(["claude", "codex"]);
|
|
13625
|
+
AccountLogoutInput = external_exports.object({ backend: AccountBackend }).strict();
|
|
13529
13626
|
AccountLogoutResult = external_exports.object({
|
|
13530
13627
|
status: external_exports.enum(["done", "blocked", "failed"]),
|
|
13531
13628
|
auth: ProviderAuth,
|
|
13532
13629
|
activeThreads: external_exports.number().int().positive().optional(),
|
|
13533
13630
|
detail: external_exports.string().max(200).optional()
|
|
13534
13631
|
});
|
|
13535
|
-
AccountLoginStartInput = external_exports.object({ backend:
|
|
13632
|
+
AccountLoginStartInput = external_exports.object({ backend: AccountBackend }).strict();
|
|
13536
13633
|
AccountLoginStartResult = external_exports.object({ attemptId: ThreadSlug });
|
|
13537
13634
|
AccountLoginStatusInput = external_exports.object({ attemptId: ThreadSlug }).strict();
|
|
13538
13635
|
AccountLoginStatusResult = external_exports.object({
|
|
@@ -13574,13 +13671,13 @@ var init_src = __esm({
|
|
|
13574
13671
|
* to, not furniture you sit beside. Hidden, the way back is a breadcrumb in the status bar, which
|
|
13575
13672
|
* costs a click exactly when you meant to switch and nothing when you did not.
|
|
13576
13673
|
*
|
|
13577
|
-
* Machine-level
|
|
13674
|
+
* Machine-level: which chrome you want is a property of the person, not the repo.
|
|
13578
13675
|
*/
|
|
13579
13676
|
projectRail: external_exports.boolean(),
|
|
13580
|
-
//
|
|
13581
|
-
//
|
|
13582
|
-
//
|
|
13583
|
-
font
|
|
13677
|
+
// There is no `font` key any more. The interface rendered in one of two type families as a machine
|
|
13678
|
+
// setting until 2026-09-19 (maintainer: "let's drop monospace as an option"); every surface is sans
|
|
13679
|
+
// now, and index.html pins `data-font="sans"` on <html> directly. Settings is a non-strict object,
|
|
13680
|
+
// so a stored `font` is stripped the moment an old blob parses — no migration.
|
|
13584
13681
|
// Default action for a vetted non-image local path in agent markdown. Image clicks always use the
|
|
13585
13682
|
// OS default viewer so screenshots retain their expected behavior.
|
|
13586
13683
|
localFileOpener: LocalFileOpener.optional(),
|
|
@@ -13607,6 +13704,15 @@ var init_src = __esm({
|
|
|
13607
13704
|
// it (codex compacts at 90% of the resolved window). Unset ⇒ nothing is sent and the model's stock
|
|
13608
13705
|
// window applies. Optional so an old blob parses; defaultSettings leaves it unset.
|
|
13609
13706
|
codexContextWindow: external_exports.number().int().positive().optional(),
|
|
13707
|
+
// The operator's OWN Agent Client Protocol agents, merged over the built-in catalogue by id
|
|
13708
|
+
// (server/backend/acp-agents.ts). `command` is an executable name on PATH or an absolute path;
|
|
13709
|
+
// `args` is what puts it into ACP mode (`["acp"]`, `["--acp"]`). Optional so an old blob parses.
|
|
13710
|
+
acpAgents: external_exports.array(external_exports.object({
|
|
13711
|
+
id: external_exports.string().trim().min(1).max(64).regex(/^[a-z0-9][a-z0-9._-]*$/i),
|
|
13712
|
+
label: external_exports.string().trim().min(1).max(80),
|
|
13713
|
+
command: external_exports.string().trim().min(1).max(1024),
|
|
13714
|
+
args: external_exports.array(external_exports.string().max(1024)).max(32).optional()
|
|
13715
|
+
})).max(32).optional(),
|
|
13610
13716
|
// The GitHub batch-dispatch prompt template (the picker's per-item worker prompt). Optional: when
|
|
13611
13717
|
// unset OR blank the server falls back to its exported DEFAULT_GITHUB_PROMPT. Substitution tokens
|
|
13612
13718
|
// the server fills: {repo} {n} {title} {url} {labels} {body}. The leading `THREAD: <slug>` tag is
|
|
@@ -13633,28 +13739,38 @@ var init_src = __esm({
|
|
|
13633
13739
|
DispatchPreferences = external_exports.object({
|
|
13634
13740
|
backend: Backend,
|
|
13635
13741
|
claude: DispatchProviderPreferences,
|
|
13636
|
-
codex: DispatchProviderPreferences
|
|
13742
|
+
codex: DispatchProviderPreferences,
|
|
13743
|
+
// Optional because every record written before the ACP backend existed lacks it, and a required
|
|
13744
|
+
// key would fail those records' parse and silently reset the operator's saved profile.
|
|
13745
|
+
acp: DispatchProviderPreferences.optional()
|
|
13637
13746
|
});
|
|
13638
|
-
|
|
13747
|
+
DispatchProfileSnapshotShape = external_exports.object({
|
|
13639
13748
|
backend: Backend,
|
|
13640
13749
|
model: external_exports.string().trim().min(1).max(200),
|
|
13641
|
-
|
|
13750
|
+
// Required for Claude and Codex (the refinement below); absent for an ACP agent, which runs with
|
|
13751
|
+
// whatever model and effort its own CLI is configured for — Frizz has no effort axis to offer there.
|
|
13752
|
+
effort: Settings.shape.effort,
|
|
13642
13753
|
// IGNORED: dispatch permission is decided server-side (workerDispatchPermission) from the
|
|
13643
13754
|
// non-interactive floor plus the operator's Settings choice, never per dispatch. Optional so old
|
|
13644
13755
|
// clients that still send it parse.
|
|
13645
13756
|
permissionMode: PermissionMode.optional()
|
|
13646
13757
|
}).strict();
|
|
13758
|
+
DispatchProfileSnapshot = DispatchProfileSnapshotShape.superRefine(requireEffortOutsideAcp);
|
|
13647
13759
|
SetDispatchPreferenceInput = external_exports.discriminatedUnion("field", [
|
|
13648
13760
|
external_exports.object({ field: external_exports.literal("backend"), value: Backend }),
|
|
13649
13761
|
external_exports.object({
|
|
13650
13762
|
field: external_exports.literal("profile"),
|
|
13651
13763
|
backend: Backend,
|
|
13652
13764
|
model: external_exports.string().trim().min(1).max(200),
|
|
13653
|
-
|
|
13765
|
+
// Optional ONLY for an ACP profile (see DispatchProfileSnapshot); a Claude/Codex profile without
|
|
13766
|
+
// an effort is refused below rather than silently stored as "default".
|
|
13767
|
+
effort: Settings.shape.effort
|
|
13654
13768
|
}),
|
|
13655
13769
|
external_exports.object({ field: external_exports.literal("model"), backend: Backend, value: external_exports.string().trim().min(1).max(200) }),
|
|
13656
13770
|
external_exports.object({ field: external_exports.literal("effort"), backend: Backend, value: Settings.shape.effort.unwrap() })
|
|
13657
|
-
])
|
|
13771
|
+
]).superRefine((update, ctx) => {
|
|
13772
|
+
if (update.field === "profile") requireEffortOutsideAcp(update, ctx);
|
|
13773
|
+
});
|
|
13658
13774
|
DispatchInput = external_exports.object({
|
|
13659
13775
|
// Optional: when omitted, dispatch derives a fallback title from the prompt (Claude later renames
|
|
13660
13776
|
// the session via ai-title, which the UI prefers for display). The thread FILE always gets a
|
|
@@ -13702,8 +13818,9 @@ var init_src = __esm({
|
|
|
13702
13818
|
freshProcess: external_exports.boolean().optional(),
|
|
13703
13819
|
// PREEMPT the operation the worker is running right now, so this message is read at once instead of
|
|
13704
13820
|
// when that operation finishes. The operator's "Interrupt and send" verb, and opt-in for the same
|
|
13705
|
-
// reason `freshProcess` is: it costs the in-flight tool call's result
|
|
13706
|
-
// sub-agents
|
|
13821
|
+
// reason `freshProcess` is: it costs the in-flight tool call's result. (It no longer costs the
|
|
13822
|
+
// worker's sub-agents: since 2026-09-24 the broker's SDK query declares `perTaskStopAffordance`,
|
|
13823
|
+
// so the interrupt aborts only the turn and background agents run on.)
|
|
13707
13824
|
//
|
|
13708
13825
|
// It exists because delivery is ALREADY as fast as queueing can be. Measured over 14 days of this
|
|
13709
13826
|
// project's own transcripts, Claude Code drains its queue at the first sampling boundary that
|
|
@@ -13806,7 +13923,7 @@ var init_src = __esm({
|
|
|
13806
13923
|
timers: external_exports.array(ThreadTimerView)
|
|
13807
13924
|
}).strict();
|
|
13808
13925
|
ThreadActivityItem = external_exports.object({
|
|
13809
|
-
kind: external_exports.enum(["shell", "agent", "timer", "pr"]),
|
|
13926
|
+
kind: external_exports.enum(["shell", "agent", "timer", "pr", "issue"]),
|
|
13810
13927
|
/** The string a `<kind>:` fence line must carry. For a shell that is the runtime task id the worker
|
|
13811
13928
|
* was shown; for a PR, `owner/repo#N`; for a timer, its `tmr_…` row id. */
|
|
13812
13929
|
id: external_exports.string(),
|
|
@@ -13910,11 +14027,15 @@ var init_src = __esm({
|
|
|
13910
14027
|
SetThreadProfileInput = external_exports.object({
|
|
13911
14028
|
slug: ThreadSlug,
|
|
13912
14029
|
model: external_exports.string().trim().min(1).max(200),
|
|
13913
|
-
|
|
14030
|
+
// Absent ONLY for an ACP thread, whose model slug (`acp:<agent>@<model>`) carries no effort axis; the
|
|
14031
|
+
// router refuses a Claude/Codex profile without one rather than storing "".
|
|
14032
|
+
effort: external_exports.string().trim().min(1).max(100).optional()
|
|
13914
14033
|
}).strict();
|
|
13915
14034
|
SetThreadProfileResult = external_exports.object({
|
|
13916
14035
|
effect: external_exports.enum(["applied", "next-resume"])
|
|
13917
14036
|
});
|
|
14037
|
+
UpgradeThreadModelInput = external_exports.object({ slug: ThreadSlug, sessionId: external_exports.string().min(1) }).strict();
|
|
14038
|
+
UpgradeThreadModelResult = external_exports.object({ effect: external_exports.literal("next-turn"), label: external_exports.string() });
|
|
13918
14039
|
DISPATCH_TASK_BANNER = [
|
|
13919
14040
|
"===============================================================",
|
|
13920
14041
|
"====================== YOUR TASK ========================",
|
|
@@ -14044,9 +14165,9 @@ ${DISPATCH_TASK_BANNER}
|
|
|
14044
14165
|
page: external_exports.number().int().positive(),
|
|
14045
14166
|
pageCount: external_exports.number().int().positive()
|
|
14046
14167
|
});
|
|
14047
|
-
GithubBatchInput =
|
|
14168
|
+
GithubBatchInput = DispatchProfileSnapshotShape.extend({
|
|
14048
14169
|
items: external_exports.array(external_exports.object({ kind: external_exports.enum(["issue", "pr"]), number: external_exports.number().int().positive() })).min(1)
|
|
14049
|
-
}).strict();
|
|
14170
|
+
}).strict().superRefine(requireEffortOutsideAcp);
|
|
14050
14171
|
GithubBatchResult = external_exports.object({
|
|
14051
14172
|
dispatched: external_exports.array(external_exports.object({ number: external_exports.number(), kind: external_exports.string(), slug: ThreadSlug })),
|
|
14052
14173
|
failed: external_exports.array(external_exports.object({ number: external_exports.number(), kind: external_exports.string(), error: external_exports.string() }))
|
|
@@ -14490,6 +14611,10 @@ ${DISPATCH_TASK_BANNER}
|
|
|
14490
14611
|
/** An operator's uploaded icon, rather than one the scan found. Drives what the menu offers. */
|
|
14491
14612
|
iconIsCustom: external_exports.boolean().optional()
|
|
14492
14613
|
});
|
|
14614
|
+
ProjectRailCounts = external_exports.object({
|
|
14615
|
+
queued: external_exports.number().int().nonnegative(),
|
|
14616
|
+
running: external_exports.number().int().nonnegative()
|
|
14617
|
+
});
|
|
14493
14618
|
PROJECT_ICON_MAX_BASE64_CHARS = 4 * 1024 * 1024;
|
|
14494
14619
|
DirectoryPickResult = external_exports.discriminatedUnion("kind", [
|
|
14495
14620
|
external_exports.object({ kind: external_exports.literal("picked"), project: ProjectCard }),
|
|
@@ -19486,11 +19611,13 @@ function readBootProgress(stateDir) {
|
|
|
19486
19611
|
return null;
|
|
19487
19612
|
}
|
|
19488
19613
|
}
|
|
19489
|
-
var BOOT_PROGRESS_NAME;
|
|
19614
|
+
var BOOT_PROGRESS_NAME, BOOT_STALL_TIMEOUT_MS, BOOT_HARD_TIMEOUT_MS;
|
|
19490
19615
|
var init_boot_progress = __esm({
|
|
19491
19616
|
"packages/server/src/boot-progress.ts"() {
|
|
19492
19617
|
"use strict";
|
|
19493
19618
|
BOOT_PROGRESS_NAME = "boot.progress";
|
|
19619
|
+
BOOT_STALL_TIMEOUT_MS = 3e4;
|
|
19620
|
+
BOOT_HARD_TIMEOUT_MS = 10 * 6e4;
|
|
19494
19621
|
}
|
|
19495
19622
|
});
|
|
19496
19623
|
|
|
@@ -22146,12 +22273,12 @@ var qrcode_default = qrcode;
|
|
|
22146
22273
|
var stringToBytes = qrcode.stringToBytes;
|
|
22147
22274
|
|
|
22148
22275
|
// packages/server/src/qr.ts
|
|
22149
|
-
var LIGHT = "\x1B[38;5;15m";
|
|
22150
22276
|
var LIGHT_BG = "\x1B[48;5;15m";
|
|
22151
22277
|
var DARK = "\x1B[38;5;0m";
|
|
22152
22278
|
var DARK_BG = "\x1B[48;5;0m";
|
|
22153
22279
|
var RESET = "\x1B[0m";
|
|
22154
22280
|
var UPPER_HALF = "\u2580";
|
|
22281
|
+
var LOWER_HALF = "\u2584";
|
|
22155
22282
|
var QUIET_ZONE = 4;
|
|
22156
22283
|
function encode(value, errorCorrection) {
|
|
22157
22284
|
const code = qrcode_default(0, errorCorrection);
|
|
@@ -22182,7 +22309,8 @@ function renderQrLines(value, options2 = {}) {
|
|
|
22182
22309
|
line += top && bottom ? "#" : top ? "^" : bottom ? "v" : " ";
|
|
22183
22310
|
continue;
|
|
22184
22311
|
}
|
|
22185
|
-
line += `${top ?
|
|
22312
|
+
if (top === bottom) line += `${top ? DARK_BG : LIGHT_BG} `;
|
|
22313
|
+
else line += `${DARK}${LIGHT_BG}${top ? UPPER_HALF : LOWER_HALF}`;
|
|
22186
22314
|
}
|
|
22187
22315
|
lines.push(options2.plain ? line : `${line}${RESET}`);
|
|
22188
22316
|
}
|
|
@@ -22207,12 +22335,29 @@ var BASE_STYLE = `
|
|
|
22207
22335
|
:root{
|
|
22208
22336
|
color-scheme:dark;
|
|
22209
22337
|
--bg:#0d0e10;--panel:#131519;--panel-2:#181b20;
|
|
22210
|
-
--border:#26282d;--border-strong:#33363c;
|
|
22338
|
+
--border:#26282d;--border-strong:#33363c;--control-border:#26282d;--control-strong:#33363c;
|
|
22211
22339
|
--fg:#e6e7e9;--muted:#8b8f96;--accent:#e8b923;--danger:#fca5a5;
|
|
22340
|
+
--focus-border:color-mix(in srgb,var(--accent) 55%,transparent);--focus-ring:color-mix(in srgb,var(--accent) 22%,transparent);
|
|
22212
22341
|
--sans:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
|
|
22213
22342
|
--mono:ui-monospace,"JetBrains Mono","SF Mono","Cascadia Mono",Menlo,Consolas,monospace;
|
|
22214
22343
|
--ease:cubic-bezier(0,0,.2,1);
|
|
22215
22344
|
}
|
|
22345
|
+
:root[data-theme=light]{
|
|
22346
|
+
color-scheme:light;
|
|
22347
|
+
--bg:#f7f7f7;--panel:#fff;--panel-2:#fafafa;
|
|
22348
|
+
--border:#dedede;--border-strong:#cecece;--control-border:#858585;--control-strong:#7d7d7d;
|
|
22349
|
+
--fg:#292929;--muted:#606060;--accent:#416896;--danger:#cf222e;
|
|
22350
|
+
--focus-border:#416896;--focus-ring:#416896;
|
|
22351
|
+
}
|
|
22352
|
+
@media(prefers-color-scheme:light){
|
|
22353
|
+
:root:not([data-theme]){
|
|
22354
|
+
color-scheme:light;
|
|
22355
|
+
--bg:#f7f7f7;--panel:#fff;--panel-2:#fafafa;
|
|
22356
|
+
--border:#dedede;--border-strong:#cecece;--control-border:#858585;--control-strong:#7d7d7d;
|
|
22357
|
+
--fg:#292929;--muted:#606060;--accent:#416896;--danger:#cf222e;
|
|
22358
|
+
--focus-border:#416896;--focus-ring:#416896;
|
|
22359
|
+
}
|
|
22360
|
+
}
|
|
22216
22361
|
html,body{background:var(--bg)}
|
|
22217
22362
|
body{
|
|
22218
22363
|
margin:0;min-height:100vh;min-height:100dvh;
|
|
@@ -22220,7 +22365,6 @@ body{
|
|
|
22220
22365
|
color:var(--fg);font-family:var(--sans);font-size:12.5px;line-height:1.55;
|
|
22221
22366
|
-webkit-font-smoothing:antialiased;
|
|
22222
22367
|
}
|
|
22223
|
-
html[data-font=mono] body{font-family:var(--mono)}
|
|
22224
22368
|
main{width:100%;max-width:28rem;padding:18px;border:1px solid var(--border-strong);border-radius:12px;background:var(--panel-2)}
|
|
22225
22369
|
h1{margin:0;display:flex;align-items:baseline;gap:7px;font-size:14px;font-weight:600;letter-spacing:-.01em;line-height:1.4}
|
|
22226
22370
|
p{margin:0;text-wrap:pretty}
|
|
@@ -22234,13 +22378,13 @@ var RECOVERY_STYLE = `
|
|
|
22234
22378
|
/* ErrorBoundary's ACTION_CLASS, one size up for a page that is alone in a viewport. */
|
|
22235
22379
|
.btn{
|
|
22236
22380
|
appearance:none;display:inline-flex;align-items:center;
|
|
22237
|
-
border:1px solid var(--border);border-radius:6px;background:transparent;
|
|
22381
|
+
border:1px solid var(--control-border);border-radius:6px;background:transparent;
|
|
22238
22382
|
padding:5px 10px;font:inherit;font-size:11.5px;color:color-mix(in srgb,var(--fg) 90%,transparent);
|
|
22239
22383
|
cursor:pointer;text-decoration:none;
|
|
22240
22384
|
transition:background-color 120ms var(--ease),border-color 120ms var(--ease),color 120ms var(--ease);
|
|
22241
22385
|
}
|
|
22242
|
-
.btn:hover{background:var(--panel);border-color:var(--
|
|
22243
|
-
.btn:focus-visible{outline:none;border-color:
|
|
22386
|
+
.btn:hover{background:var(--panel);border-color:var(--control-strong);color:var(--fg)}
|
|
22387
|
+
.btn:focus-visible{outline:none;border-color:var(--focus-border);box-shadow:0 0 0 2px var(--focus-ring)}
|
|
22244
22388
|
.btn:disabled{opacity:.5;pointer-events:none}
|
|
22245
22389
|
/* min-height holds the slot open while it is LIVE, so a changing status line never nudges the card;
|
|
22246
22390
|
:empty collapses it when there is nothing live to say, so a halted card has no trailing gutter. */
|
|
@@ -22260,8 +22404,7 @@ var RECOVERY_STYLE = `
|
|
|
22260
22404
|
Alignment is an INK problem. A baseline-aligned flex item with no text of its own contributes its
|
|
22261
22405
|
BORDER-BOX BOTTOM as the baseline, so the dot's ink centre lands 3px above it while the cap band's
|
|
22262
22406
|
centre sits 0.5cap above it. \`cap\` is the resolved font's own cap height, so the correction holds
|
|
22263
|
-
|
|
22264
|
-
font setting flips. The em spelling is the fallback for a browser without the unit (.35em ~= 0.5 x a
|
|
22407
|
+
at any size, with nothing to re-measure when the type scale moves. The em spelling is the fallback for a browser without the unit (.35em ~= 0.5 x a
|
|
22265
22408
|
0.7em cap) and is overwritten wherever \`cap\` parses. */
|
|
22266
22409
|
.dot{
|
|
22267
22410
|
width:6px;height:6px;flex:0 0 auto;border-radius:9999px;background:var(--accent);
|
|
@@ -22292,7 +22435,7 @@ var RECOVERY_STYLE = `
|
|
|
22292
22435
|
.probe[data-live=yes]{animation:none;background:none;color:var(--muted)}
|
|
22293
22436
|
}
|
|
22294
22437
|
`.trim();
|
|
22295
|
-
var
|
|
22438
|
+
var THEME_SCRIPT = `var p;try{p=localStorage.getItem("frizz-theme")}catch{}var d=false;try{d=matchMedia&&matchMedia("(prefers-color-scheme: dark)").matches}catch{}var t=p==="dark"||p==="light"?p:d?"dark":"light";document.documentElement.dataset.theme=t;document.documentElement.style.colorScheme=t;document.querySelector('meta[name="theme-color"]').content=t==="dark"?"#0d0e10":"#f7f7f7"`;
|
|
22296
22439
|
var RECOVERY_SCRIPT = `
|
|
22297
22440
|
(function(){
|
|
22298
22441
|
var target=document.body.dataset.target||"/"
|
|
@@ -22391,8 +22534,8 @@ var RECOVERY_SCRIPT = `
|
|
|
22391
22534
|
})()
|
|
22392
22535
|
`.trim();
|
|
22393
22536
|
function documentShell(options2) {
|
|
22394
|
-
return `<!doctype html><html lang="en" data-font="sans"><head><meta charset="utf-8"><title>${options2.title}</title><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="dark"><meta name="theme-color" content="#0d0e10"><style>${options2.style ? `${BASE_STYLE}
|
|
22395
|
-
${options2.style}` : BASE_STYLE}</style>` + (options2.
|
|
22537
|
+
return `<!doctype html><html lang="en" data-font="sans"><head><meta charset="utf-8"><title>${options2.title}</title><meta name="viewport" content="width=device-width,initial-scale=1">` + (options2.appearance ? `<meta name="color-scheme" content="dark light"><meta name="theme-color" content="#0d0e10">` : `<meta name="color-scheme" content="dark light"><meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0d0e10"><meta name="theme-color" media="(prefers-color-scheme: light)" content="#f7f7f7">`) + `<style>${options2.style ? `${BASE_STYLE}
|
|
22538
|
+
${options2.style}` : BASE_STYLE}</style>` + (options2.appearance ? `<script>${THEME_SCRIPT}</script>` : "") + `</head><body${options2.bodyAttributes ? ` ${options2.bodyAttributes}` : ""}><main>${options2.body}</main>` + (options2.script ? `<script>${options2.script}</script>` : "") + `</body></html>`;
|
|
22396
22539
|
}
|
|
22397
22540
|
var RECOVERY_COPY = {
|
|
22398
22541
|
starting: {
|
|
@@ -22413,7 +22556,7 @@ function recoveryPage(url, variant = "starting") {
|
|
|
22413
22556
|
return documentShell({
|
|
22414
22557
|
title: copy.title,
|
|
22415
22558
|
style: RECOVERY_STYLE,
|
|
22416
|
-
|
|
22559
|
+
appearance: true,
|
|
22417
22560
|
bodyAttributes: `data-target="${target2}"`,
|
|
22418
22561
|
body: `<h1><span class="dot" id="dot" aria-hidden="true"></span><span id="heading">${copy.heading}</span></h1><p class="detail" id="detail">${copy.detail}</p><pre class="log" id="log" hidden></pre><p class="note">${THREADS_NOTE}</p><div class="actions"><a class="btn" href="${target2}">Try again</a><button class="btn" type="button" id="restart">Restart Frizz</button></div><p class="probe" id="probe" aria-live="polite"></p>`,
|
|
22419
22562
|
script: RECOVERY_SCRIPT
|
|
@@ -22430,7 +22573,7 @@ function unlistedHostPage(name) {
|
|
|
22430
22573
|
const shown = escapeHtml(name);
|
|
22431
22574
|
return documentShell({
|
|
22432
22575
|
title: "Not served by this name",
|
|
22433
|
-
|
|
22576
|
+
appearance: true,
|
|
22434
22577
|
body: `<h1>Not served by this name</h1><p class="detail">Frizz does not answer to <code>${shown}</code>. A name a browser has to resolve is how DNS rebinding makes another site's page count as this board, so an exposed board accepts only its own hostname and the names its operator lists.</p><p class="note">Open the board by its IP address, or relaunch with <code>--allowed-host ${shown}</code> (or <code>FRIZZ_ALLOWED_HOSTS=${shown}</code>) to accept this one.</p>`
|
|
22435
22578
|
});
|
|
22436
22579
|
}
|
|
@@ -23125,6 +23268,7 @@ function createAccessPane(options2) {
|
|
|
23125
23268
|
import { homedir as homedir5 } from "node:os";
|
|
23126
23269
|
|
|
23127
23270
|
// src/cloud.ts
|
|
23271
|
+
init_frizz_paths();
|
|
23128
23272
|
init_src();
|
|
23129
23273
|
import { spawn as spawn2 } from "node:child_process";
|
|
23130
23274
|
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3, rmSync } from "node:fs";
|
|
@@ -23138,8 +23282,8 @@ init_src();
|
|
|
23138
23282
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
23139
23283
|
import { homedir as homedir3 } from "node:os";
|
|
23140
23284
|
import { dirname as dirname3, join as join4 } from "node:path";
|
|
23141
|
-
function claimIdentityPath(home = homedir3()) {
|
|
23142
|
-
return join4(frizzPaths({ home }).state, "identity.key");
|
|
23285
|
+
function claimIdentityPath(home = homedir3(), env) {
|
|
23286
|
+
return join4(frizzPaths({ home, env }).state, "identity.key");
|
|
23143
23287
|
}
|
|
23144
23288
|
async function loadOrCreateClaimIdentity(home = homedir3()) {
|
|
23145
23289
|
const path = claimIdentityPath(home);
|
|
@@ -23684,7 +23828,7 @@ async function reconcileCloudConfig(config, port, home = homedir4(), onNotice, o
|
|
|
23684
23828
|
return establishCloudConfig(label, port, home, origin, github);
|
|
23685
23829
|
}
|
|
23686
23830
|
function cloudConfigPath(home = homedir4()) {
|
|
23687
|
-
return join5(home
|
|
23831
|
+
return join5(frizzPaths({ home }).data, "cloud.json");
|
|
23688
23832
|
}
|
|
23689
23833
|
function readCloudConfig(home = homedir4()) {
|
|
23690
23834
|
try {
|
|
@@ -23707,7 +23851,7 @@ function readCloudConfig(home = homedir4()) {
|
|
|
23707
23851
|
}
|
|
23708
23852
|
}
|
|
23709
23853
|
function tunnelTokenPath(home = homedir4()) {
|
|
23710
|
-
return join5(home
|
|
23854
|
+
return join5(frizzPaths({ home }).state, "tunnel-token");
|
|
23711
23855
|
}
|
|
23712
23856
|
function readTunnelToken(home = homedir4()) {
|
|
23713
23857
|
try {
|
|
@@ -24652,8 +24796,8 @@ init_logging();
|
|
|
24652
24796
|
init_src();
|
|
24653
24797
|
init_project_registry();
|
|
24654
24798
|
var PORT_SCAN_COUNT = 100;
|
|
24655
|
-
var LAUNCH_TIMEOUT_MS =
|
|
24656
|
-
var LAUNCH_HARD_TIMEOUT_MS =
|
|
24799
|
+
var LAUNCH_TIMEOUT_MS = BOOT_STALL_TIMEOUT_MS;
|
|
24800
|
+
var LAUNCH_HARD_TIMEOUT_MS = BOOT_HARD_TIMEOUT_MS;
|
|
24657
24801
|
var RETIRED_NETWORK_FLAGS = ["--host", "--allowed-host", "--public-origin", "--cloud"];
|
|
24658
24802
|
function retiredFlagMessage(flag) {
|
|
24659
24803
|
return `${flag} was retired \u2014 how a board is reached is set up from the running board now: press R in its terminal to pick a private or custom frizz.sh name, a Cloudflare Tunnel, Tailscale or a proxy of your own. The choice is remembered, so a plain launch serves it.`;
|
|
@@ -24766,11 +24910,14 @@ function parseCliArgs(argv) {
|
|
|
24766
24910
|
function boardAddress(url) {
|
|
24767
24911
|
return url.includes("?") || url.endsWith("/") ? url : `${url}/`;
|
|
24768
24912
|
}
|
|
24913
|
+
var SANDBOX_DROPPED_XDG_ROOTS = ["XDG_DATA_HOME", "XDG_STATE_HOME", "XDG_CACHE_HOME"];
|
|
24769
24914
|
function prepareSandbox(env = process.env, realHome = homedir10()) {
|
|
24770
24915
|
const home = mkdtempSync(join13(tmpdir2(), "frizz-sandbox-"));
|
|
24771
|
-
|
|
24916
|
+
const inherited = { ...env };
|
|
24772
24917
|
env.HOME = home;
|
|
24773
24918
|
env.USERPROFILE = home;
|
|
24919
|
+
for (const name of SANDBOX_DROPPED_XDG_ROOTS) delete env[name];
|
|
24920
|
+
shareCredentials(realHome, home, inherited, env);
|
|
24774
24921
|
const project = join13(home, "sandbox");
|
|
24775
24922
|
mkdirSync10(project, { recursive: true });
|
|
24776
24923
|
writeFileSync10(join13(project, "README.md"), "# frizz sandbox\n\nA throwaway project; everything here is deleted when the sandbox exits.\n");
|
|
@@ -24782,15 +24929,15 @@ function prepareSandbox(env = process.env, realHome = homedir10()) {
|
|
|
24782
24929
|
process.chdir(project);
|
|
24783
24930
|
return { home, project };
|
|
24784
24931
|
}
|
|
24785
|
-
function shareCredentials(realHome, home) {
|
|
24932
|
+
function shareCredentials(realHome, home, realEnv, sandboxEnv) {
|
|
24786
24933
|
const link = (from, to) => {
|
|
24787
24934
|
try {
|
|
24788
24935
|
symlinkSync2(from, to);
|
|
24789
24936
|
} catch {
|
|
24790
24937
|
}
|
|
24791
24938
|
};
|
|
24792
|
-
const realKey = claimIdentityPath(realHome);
|
|
24793
|
-
const sandboxKey = claimIdentityPath(home);
|
|
24939
|
+
const realKey = claimIdentityPath(realHome, realEnv);
|
|
24940
|
+
const sandboxKey = claimIdentityPath(home, sandboxEnv);
|
|
24794
24941
|
mkdirSync10(dirname10(realKey), { recursive: true });
|
|
24795
24942
|
mkdirSync10(dirname10(sandboxKey), { recursive: true });
|
|
24796
24943
|
link(realKey, sandboxKey);
|
|
@@ -25187,12 +25334,13 @@ import { basename as basename6, dirname as dirname11, extname as extname2, isAbs
|
|
|
25187
25334
|
import { fileURLToPath } from "node:url";
|
|
25188
25335
|
import watcher from "@parcel/watcher";
|
|
25189
25336
|
init_logging();
|
|
25337
|
+
init_boot_progress();
|
|
25190
25338
|
var DEV_RESTART_DEBOUNCE_MS = 180;
|
|
25191
25339
|
var DEV_CRASH_STABLE_MS = 5e3;
|
|
25192
25340
|
var DEV_CRASH_RETRY_BASE_MS = 500;
|
|
25193
25341
|
var DEV_CRASH_RETRY_MAX_MS = 1e4;
|
|
25194
25342
|
var CHILD_STOP_TIMEOUT_MS = 15e3;
|
|
25195
|
-
var STABLE_UPDATE_READY_TIMEOUT_MS =
|
|
25343
|
+
var STABLE_UPDATE_READY_TIMEOUT_MS = BOOT_STALL_TIMEOUT_MS;
|
|
25196
25344
|
var STABLE_UPDATE_STABILIZE_MS = 1e3;
|
|
25197
25345
|
var CHILD_KILL_GRACE_MS = 5e3;
|
|
25198
25346
|
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".mjs", ".cjs", ".json"]);
|
|
@@ -25444,6 +25592,7 @@ var Supervisor = class {
|
|
|
25444
25592
|
updateMode;
|
|
25445
25593
|
commitUpdate;
|
|
25446
25594
|
updateReadyTimeoutMs;
|
|
25595
|
+
updateHardTimeoutMs;
|
|
25447
25596
|
updateStabilizeMs;
|
|
25448
25597
|
rollbackUpdate;
|
|
25449
25598
|
durableReexec;
|
|
@@ -25488,6 +25637,7 @@ var Supervisor = class {
|
|
|
25488
25637
|
this.updateMode = opts.updateMode ?? "durableReexec";
|
|
25489
25638
|
this.commitUpdate = opts.commitUpdate;
|
|
25490
25639
|
this.updateReadyTimeoutMs = Math.max(1, opts.updateReadyTimeoutMs ?? STABLE_UPDATE_READY_TIMEOUT_MS);
|
|
25640
|
+
this.updateHardTimeoutMs = Math.max(1, opts.updateHardTimeoutMs ?? BOOT_HARD_TIMEOUT_MS);
|
|
25491
25641
|
this.updateStabilizeMs = Math.max(0, opts.updateStabilizeMs ?? STABLE_UPDATE_STABILIZE_MS);
|
|
25492
25642
|
this.rollbackUpdate = opts.rollbackUpdate;
|
|
25493
25643
|
this.durableReexec = opts.durableReexec;
|
|
@@ -25732,7 +25882,8 @@ var Supervisor = class {
|
|
|
25732
25882
|
if (this.closed) return this.failChildUpdate("Frizz supervisor stopped while starting the update", true);
|
|
25733
25883
|
const ready = await this.spawnChild({
|
|
25734
25884
|
updateCandidate: true,
|
|
25735
|
-
readinessTimeoutMs: this.updateReadyTimeoutMs
|
|
25885
|
+
readinessTimeoutMs: this.updateReadyTimeoutMs,
|
|
25886
|
+
hardTimeoutMs: this.updateHardTimeoutMs
|
|
25736
25887
|
});
|
|
25737
25888
|
const candidate = this.child;
|
|
25738
25889
|
if (!ready || !candidate) {
|
|
@@ -25912,9 +26063,28 @@ var Supervisor = class {
|
|
|
25912
26063
|
settled(ready);
|
|
25913
26064
|
};
|
|
25914
26065
|
if (options2.readinessTimeoutMs !== void 0) {
|
|
25915
|
-
|
|
26066
|
+
const stallMs = options2.readinessTimeoutMs;
|
|
26067
|
+
const hardMs = options2.hardTimeoutMs ?? BOOT_HARD_TIMEOUT_MS;
|
|
26068
|
+
const hardDeadline = Date.now() + hardMs;
|
|
26069
|
+
let stallDeadline = Date.now() + stallMs;
|
|
26070
|
+
let lastStep = -1;
|
|
26071
|
+
let lastPhase;
|
|
26072
|
+
const checkProgress = () => {
|
|
25916
26073
|
if (spawnSettled) return;
|
|
25917
|
-
const
|
|
26074
|
+
const now = Date.now();
|
|
26075
|
+
const progress = readBootProgress(this.launchTarget.stateDir);
|
|
26076
|
+
if (progress && progress.pid === child.pid && progress.step > lastStep) {
|
|
26077
|
+
lastStep = progress.step;
|
|
26078
|
+
lastPhase = progress.phase;
|
|
26079
|
+
stallDeadline = now + stallMs;
|
|
26080
|
+
}
|
|
26081
|
+
if (now < stallDeadline && now < hardDeadline) {
|
|
26082
|
+
readinessTimer = setTimeout(checkProgress, Math.min(250, stallDeadline - now, hardDeadline - now));
|
|
26083
|
+
readinessTimer.unref();
|
|
26084
|
+
return;
|
|
26085
|
+
}
|
|
26086
|
+
const reason = now >= hardDeadline ? `update candidate did not become ready within ${hardMs}ms` : `update candidate made no boot progress for ${stallMs}ms`;
|
|
26087
|
+
const message = lastPhase ? `${reason}; last boot step: ${lastPhase}` : reason;
|
|
25918
26088
|
this.lastRestartFailure = message;
|
|
25919
26089
|
this.errorLine(`[frizz] ${message}`);
|
|
25920
26090
|
this.writeStatus("failed", message, null);
|
|
@@ -25923,8 +26093,8 @@ var Supervisor = class {
|
|
|
25923
26093
|
} catch {
|
|
25924
26094
|
}
|
|
25925
26095
|
settleSpawn(false);
|
|
25926
|
-
}
|
|
25927
|
-
|
|
26096
|
+
};
|
|
26097
|
+
checkProgress();
|
|
25928
26098
|
}
|
|
25929
26099
|
child.on("message", (message) => {
|
|
25930
26100
|
if (stopOwnerMessage(message) && message.token === this.ownerToken) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frizz",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A local web UI for running many coding agents at once",
|
|
6
6
|
"keywords": [
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"frizz-dev:check": "nub scripts/install-global-cli.mjs --check",
|
|
36
36
|
"frizz-dev:uninstall": "nub scripts/install-global-cli.mjs --uninstall",
|
|
37
37
|
"install:global": "nub scripts/install-global-cli.mjs",
|
|
38
|
-
"typecheck": "tsc -b packages/shared packages/rpc packages/server packages/registrar packages/relay . packages/web",
|
|
38
|
+
"typecheck": "tsc -b packages/shared packages/rpc packages/claude-agent-sdk-runtime packages/server packages/registrar packages/relay . packages/web",
|
|
39
39
|
"test": "nub scripts/run-tests.mjs",
|
|
40
40
|
"test:e2e": "nub scripts/e2e-web.mjs",
|
|
41
41
|
"prepack": "node ./scripts/prepare-package.mjs --server && node ./scripts/build-package.mjs --server && node ./scripts/build-package.mjs --shell && node ./scripts/publish-manifest.mjs --strip",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
},
|
|
66
66
|
"frizzServer": {
|
|
67
67
|
"package": "frizz-server",
|
|
68
|
-
"version": "0.
|
|
68
|
+
"version": "0.15.0",
|
|
69
69
|
"protocol": 1,
|
|
70
70
|
"dataEpoch": 1
|
|
71
71
|
}
|