frizz 0.13.3 → 0.13.6
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 +146 -27
- package/package.json +3 -2
package/dist/frizz.js
CHANGED
|
@@ -12493,7 +12493,7 @@ function requireEffortOutsideAcp(profile, ctx) {
|
|
|
12493
12493
|
function fallbackPort(base) {
|
|
12494
12494
|
return base + 1e4;
|
|
12495
12495
|
}
|
|
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,
|
|
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;
|
|
12497
12497
|
var init_src = __esm({
|
|
12498
12498
|
"packages/shared/src/index.ts"() {
|
|
12499
12499
|
"use strict";
|
|
@@ -12907,12 +12907,12 @@ var init_src = __esm({
|
|
|
12907
12907
|
" if anything is still owed, it is not done. Body: 1-3 sentences, then bullets, each opening with a",
|
|
12908
12908
|
" **bolded verb phrase**.",
|
|
12909
12909
|
"- `` ```awaiting `` \u2014 you are WAITING on work that is actually running. FRONTMATTER, THEN MARKDOWN:",
|
|
12910
|
-
" one
|
|
12910
|
+
" one YAML list per kind of thing you are waiting on, a REQUIRED `for:` duration, then a `---` line and",
|
|
12911
12911
|
" as much prose as you want. The prose is OPTIONAL; the lines above it are not.",
|
|
12912
12912
|
"",
|
|
12913
12913
|
" ```awaiting",
|
|
12914
|
-
"
|
|
12915
|
-
"
|
|
12914
|
+
" shells: [<the id your runtime gave you>]",
|
|
12915
|
+
" prs: [owner/repo#123]",
|
|
12916
12916
|
" for: 2h",
|
|
12917
12917
|
" ---",
|
|
12918
12918
|
" What you are waiting for, in your own words \u2014 this is what the human reads on your card.",
|
|
@@ -13230,6 +13230,17 @@ var init_src = __esm({
|
|
|
13230
13230
|
dismissed: external_exports.array(external_exports.string()),
|
|
13231
13231
|
open: external_exports.array(RegisteredQuestionView)
|
|
13232
13232
|
}).strict();
|
|
13233
|
+
SettledQuestionView = external_exports.object({
|
|
13234
|
+
id: external_exports.string(),
|
|
13235
|
+
spec: AskedQuestionSchema,
|
|
13236
|
+
askedAt: external_exports.string(),
|
|
13237
|
+
/** When the human sent the answer — what decides which rest the card stood at when it was answered. */
|
|
13238
|
+
settledAt: external_exports.string(),
|
|
13239
|
+
answer: QuestionAnswerSchema
|
|
13240
|
+
}).strict();
|
|
13241
|
+
ThreadSettledQuestionsResult = external_exports.object({
|
|
13242
|
+
questions: external_exports.array(SettledQuestionView)
|
|
13243
|
+
}).strict();
|
|
13233
13244
|
MarkOwnDoneInput = external_exports.object({
|
|
13234
13245
|
slug: ThreadSlug,
|
|
13235
13246
|
body: external_exports.string().trim().min(1).max(2e4)
|
|
@@ -13296,6 +13307,11 @@ var init_src = __esm({
|
|
|
13296
13307
|
UpsertOwnLinkResult = external_exports.object({ link: ThreadLinkView }).strict();
|
|
13297
13308
|
DropOwnLinkInput = external_exports.object({ slug: ThreadSlug, id: external_exports.string().min(1) }).strict();
|
|
13298
13309
|
DropOwnLinkResult = external_exports.object({ dropped: external_exports.boolean() }).strict();
|
|
13310
|
+
LiveTool = external_exports.object({
|
|
13311
|
+
name: external_exports.string(),
|
|
13312
|
+
desc: external_exports.string().optional(),
|
|
13313
|
+
detail: external_exports.string().optional()
|
|
13314
|
+
});
|
|
13299
13315
|
ThreadView = external_exports.object({
|
|
13300
13316
|
id: ThreadSlug,
|
|
13301
13317
|
// slug; filename is <slug>.md
|
|
@@ -13334,6 +13350,15 @@ var init_src = __esm({
|
|
|
13334
13350
|
// user hid the row from the nav; respawn/resume un-archives
|
|
13335
13351
|
lastAssistant: external_exports.string().optional(),
|
|
13336
13352
|
// trimmed preview of last assistant text
|
|
13353
|
+
// The FIRST non-empty line of that same text, markdown intact and newlines honoured (capped) — the
|
|
13354
|
+
// handoff's verdict line ("**Fixed** — …"), which `lastAssistant` cannot give back because its preview
|
|
13355
|
+
// collapses every newline to a space. The phone board's rested row reads it. Optional so old
|
|
13356
|
+
// snapshots parse.
|
|
13357
|
+
lastAssistantLine: external_exports.string().optional(),
|
|
13358
|
+
// The newest tool call the agent has issued and not yet had a result for (Claude session threads),
|
|
13359
|
+
// in the shape `toolActivityLabel` reads, so a list row can say "Running the focused tests" with the
|
|
13360
|
+
// gerund the chat's working indicator shows. Absent between calls, at rest, and for other backends.
|
|
13361
|
+
liveTool: LiveTool.optional(),
|
|
13337
13362
|
spawnedAt: external_exports.string().optional(),
|
|
13338
13363
|
// ISO8601
|
|
13339
13364
|
lastActivityAt: external_exports.string().optional(),
|
|
@@ -13392,6 +13417,11 @@ var init_src = __esm({
|
|
|
13392
13417
|
* same card and the swap is invisible. Absent whenever there is nothing in flight, which is almost
|
|
13393
13418
|
* always — it exists for the seconds between the human sending and the worker being handed it. */
|
|
13394
13419
|
answersInFlight: external_exports.string().optional(),
|
|
13420
|
+
/** The human's message — a follow-up or a registered answer — is on its way to the worker and the turn
|
|
13421
|
+
* has not started yet (board.deriveDeliveryInFlight). The queue has already let the thread go; this
|
|
13422
|
+
* tells the rail to draw it as working in every tab, not only the one that sent it (web
|
|
13423
|
+
* lib/steering.ts). Absent otherwise. */
|
|
13424
|
+
deliveryInFlight: external_exports.boolean().optional(),
|
|
13395
13425
|
// ISO8601 of the newest REAL user interaction (answer/steer/dispatch) — the chronological listing
|
|
13396
13426
|
// sort key. Optional; the listing falls back to spawnedAt when absent (a dispatch IS an interaction).
|
|
13397
13427
|
lastUserAt: external_exports.string().optional(),
|
|
@@ -13629,13 +13659,6 @@ var init_src = __esm({
|
|
|
13629
13659
|
activeThreads: external_exports.number().int().positive().optional(),
|
|
13630
13660
|
detail: external_exports.string().max(200).optional()
|
|
13631
13661
|
});
|
|
13632
|
-
AccountLoginStartInput = external_exports.object({ backend: AccountBackend }).strict();
|
|
13633
|
-
AccountLoginStartResult = external_exports.object({ attemptId: ThreadSlug });
|
|
13634
|
-
AccountLoginStatusInput = external_exports.object({ attemptId: ThreadSlug }).strict();
|
|
13635
|
-
AccountLoginStatusResult = external_exports.object({
|
|
13636
|
-
state: external_exports.enum(["running", "exited", "unknown"]),
|
|
13637
|
-
auth: ProviderAuth
|
|
13638
|
-
});
|
|
13639
13662
|
PermissionMode = external_exports.enum(["auto", "default", "acceptEdits", "plan", "bypassPermissions"]);
|
|
13640
13663
|
LocalFileOpener = external_exports.enum(["system", "cursor", "vscode", "finder", "copy"]);
|
|
13641
13664
|
Settings = external_exports.object({
|
|
@@ -13831,8 +13854,18 @@ var init_src = __esm({
|
|
|
13831
13854
|
// Broker-backed Claude only — that is every Claude thread dispatched since the broker cutover. On
|
|
13832
13855
|
// any other runtime the message is delivered normally and this is ignored, never refused: a send
|
|
13833
13856
|
// that arrives is always better than a send that errors.
|
|
13834
|
-
interrupt: external_exports.boolean().optional()
|
|
13857
|
+
interrupt: external_exports.boolean().optional(),
|
|
13858
|
+
// The deliveryId of a FAILED send this one re-sends — the failed bubble's Retry. The server drops that
|
|
13859
|
+
// failed entry in the same write that opens this send's own, so the retry replaces the failed bubble
|
|
13860
|
+
// rather than standing beside it. A new deliveryId, never the old one: the old send's failure may be
|
|
13861
|
+
// ambiguous, and only the operator decides to risk a second copy.
|
|
13862
|
+
supersedes: external_exports.string().min(1).max(200).optional()
|
|
13835
13863
|
});
|
|
13864
|
+
DismissFailedFollowUpInput = external_exports.object({
|
|
13865
|
+
slug: ThreadSlug,
|
|
13866
|
+
deliveryId: external_exports.string().min(1).max(200)
|
|
13867
|
+
}).strict();
|
|
13868
|
+
DismissFailedFollowUpResult = external_exports.object({ dismissed: external_exports.boolean() }).strict();
|
|
13836
13869
|
UnqueueFollowUpInput = external_exports.object({
|
|
13837
13870
|
slug: ThreadSlug,
|
|
13838
13871
|
// Same staleness guard as followUp: a stale tab must not unqueue against a re-dispatched session.
|
|
@@ -13852,6 +13885,11 @@ var init_src = __esm({
|
|
|
13852
13885
|
interrupted: external_exports.boolean(),
|
|
13853
13886
|
reason: external_exports.string().optional()
|
|
13854
13887
|
}).strict();
|
|
13888
|
+
CompactThreadInput = external_exports.object({
|
|
13889
|
+
slug: ThreadSlug,
|
|
13890
|
+
// Same staleness guard as followUp: a stale tab must not compact a re-dispatched session.
|
|
13891
|
+
sessionId: external_exports.string().min(1)
|
|
13892
|
+
}).strict();
|
|
13855
13893
|
SetThreadSnoozeInput = external_exports.object({
|
|
13856
13894
|
slug: ThreadSlug,
|
|
13857
13895
|
sessionId: external_exports.string().min(1),
|
|
@@ -14460,8 +14498,13 @@ ${DISPATCH_TASK_BANNER}
|
|
|
14460
14498
|
// yet — renders as an ordinary (un-grayed) user bubble. "unconfirmed": no evidence appeared within
|
|
14461
14499
|
// the timeout — the injection likely mutated/never landed; the client renders a quiet warning.
|
|
14462
14500
|
// Once the real transcript record lands the ledger drops the item and this field goes with it.
|
|
14463
|
-
//
|
|
14464
|
-
|
|
14501
|
+
// "sending": the server's WRITE-AHEAD entry, opened before any transport is touched, so the text is
|
|
14502
|
+
// the server's from the instant it arrives. "failed": the transport threw, or never answered — the
|
|
14503
|
+
// text is kept until the operator retries, edits or dismisses it, and nothing retries it on its own.
|
|
14504
|
+
// Additive + optional: an older client renders both as a plain bubble (gray for "sending").
|
|
14505
|
+
deliveryState: external_exports.enum(["sending", "pending", "enqueued", "delivered", "unconfirmed", "failed"]).optional(),
|
|
14506
|
+
// Why a "failed" send failed, verbatim from the transport. Set only alongside deliveryState "failed".
|
|
14507
|
+
deliveryError: external_exports.string().optional(),
|
|
14465
14508
|
// FRIZZ wrote this user turn, not the human: it is a scheduler wake delivery (isWakeDelivery). The
|
|
14466
14509
|
// client renders it as a first-party card rather than the human's off-white right-justified bubble,
|
|
14467
14510
|
// which was claiming the operator had typed a message the watcher composed. Additive + optional: an
|
|
@@ -14613,7 +14656,8 @@ ${DISPATCH_TASK_BANNER}
|
|
|
14613
14656
|
});
|
|
14614
14657
|
ProjectRailCounts = external_exports.object({
|
|
14615
14658
|
queued: external_exports.number().int().nonnegative(),
|
|
14616
|
-
running: external_exports.number().int().nonnegative()
|
|
14659
|
+
running: external_exports.number().int().nonnegative(),
|
|
14660
|
+
asks: external_exports.number().int().nonnegative()
|
|
14617
14661
|
});
|
|
14618
14662
|
PROJECT_ICON_MAX_BASE64_CHARS = 4 * 1024 * 1024;
|
|
14619
14663
|
DirectoryPickResult = external_exports.discriminatedUnion("kind", [
|
|
@@ -19955,13 +19999,6 @@ var init_project_registry = __esm({
|
|
|
19955
19999
|
}
|
|
19956
20000
|
});
|
|
19957
20001
|
|
|
19958
|
-
// packages/server/src/native-helper.ts
|
|
19959
|
-
var init_native_helper = __esm({
|
|
19960
|
-
"packages/server/src/native-helper.ts"() {
|
|
19961
|
-
"use strict";
|
|
19962
|
-
}
|
|
19963
|
-
});
|
|
19964
|
-
|
|
19965
20002
|
// src/production.ts
|
|
19966
20003
|
init_local_origin();
|
|
19967
20004
|
import { readFileSync as readFileSync15 } from "node:fs";
|
|
@@ -20561,6 +20598,29 @@ var AccessStore = class _AccessStore {
|
|
|
20561
20598
|
const id = _AccessStore.idOf(payload);
|
|
20562
20599
|
return !(id && this.sessions.isRevoked(id));
|
|
20563
20600
|
}
|
|
20601
|
+
/**
|
|
20602
|
+
* Sign out the device HOLDING this session — the "Sign out this device" row, not `--sign-out`.
|
|
20603
|
+
*
|
|
20604
|
+
* The id comes from the session itself, and only after its signature verifies, so the one thing this
|
|
20605
|
+
* can ever revoke is the credential the caller just proved it holds. There is deliberately no
|
|
20606
|
+
* parameter naming any other id: signing out SOMEONE ELSE stays loopback-only, because a stolen
|
|
20607
|
+
* session must not be able to evict the owner and keep the board.
|
|
20608
|
+
*
|
|
20609
|
+
* - `revoked`: the id is on the denylist now, so a surviving copy of this cookie is refused too.
|
|
20610
|
+
* - `legacy`: a session minted before ids existed verifies but has no id to revoke on its own. The
|
|
20611
|
+
* caller can still clear the cookie; rotating the key remains the way to kill a copy of it.
|
|
20612
|
+
* - `no-session`: nothing valid was presented — absent, forged, expired, or already signed out.
|
|
20613
|
+
*/
|
|
20614
|
+
signOutSession(session) {
|
|
20615
|
+
if (!session || !this.verifySession(session)) return { result: "no-session" };
|
|
20616
|
+
const id = _AccessStore.idOf(session.slice(0, session.lastIndexOf(".")));
|
|
20617
|
+
if (!id) return { result: "legacy" };
|
|
20618
|
+
if (!this.sessions.revoke(id)) {
|
|
20619
|
+
this.sessions.record({ id, label: "unknown device", createdAt: this.options.now() });
|
|
20620
|
+
this.sessions.revoke(id);
|
|
20621
|
+
}
|
|
20622
|
+
return this.sessions.isRevoked(id) ? { result: "revoked", id } : { result: "no-session" };
|
|
20623
|
+
}
|
|
20564
20624
|
/**
|
|
20565
20625
|
* Drop codes past their expiry so a long-lived board does not accumulate them forever.
|
|
20566
20626
|
*
|
|
@@ -22586,6 +22646,7 @@ var SUPERVISOR_UPDATE_RESTART_PATH = `${SUPERVISOR_CONTROL_PREFIX}/update-restar
|
|
|
22586
22646
|
var SUPERVISOR_STATUS_PATH = `${SUPERVISOR_CONTROL_PREFIX}/status`;
|
|
22587
22647
|
var SUPERVISOR_ACCESS_CODE_PATH = `${SUPERVISOR_CONTROL_PREFIX}/access-code`;
|
|
22588
22648
|
var SUPERVISOR_SESSIONS_PATH = `${SUPERVISOR_CONTROL_PREFIX}/sessions`;
|
|
22649
|
+
var SUPERVISOR_SIGN_OUT_PATH = `${SUPERVISOR_CONTROL_PREFIX}/sign-out`;
|
|
22589
22650
|
var SUPERVISOR_CONTROL_PROTOCOL = 1;
|
|
22590
22651
|
function responseJson(res, status, value) {
|
|
22591
22652
|
res.writeHead(status, { "content-type": "application/json; charset=utf-8", "cache-control": "no-store" });
|
|
@@ -22614,7 +22675,7 @@ function readCookie(header, name) {
|
|
|
22614
22675
|
}
|
|
22615
22676
|
function isControlRequest(req) {
|
|
22616
22677
|
const url = new URL(req.url ?? "/", "http://frizz.invalid");
|
|
22617
|
-
return url.pathname === SUPERVISOR_RESTART_PATH || url.pathname === SUPERVISOR_UPDATE_RESTART_PATH || url.pathname === SUPERVISOR_STATUS_PATH || url.pathname === SUPERVISOR_ACCESS_CODE_PATH || url.pathname === SUPERVISOR_SESSIONS_PATH;
|
|
22678
|
+
return url.pathname === SUPERVISOR_RESTART_PATH || url.pathname === SUPERVISOR_UPDATE_RESTART_PATH || url.pathname === SUPERVISOR_STATUS_PATH || url.pathname === SUPERVISOR_ACCESS_CODE_PATH || url.pathname === SUPERVISOR_SESSIONS_PATH || url.pathname === SUPERVISOR_SIGN_OUT_PATH;
|
|
22618
22679
|
}
|
|
22619
22680
|
function isLocalImageRequest(req) {
|
|
22620
22681
|
if (req.method !== "GET" && req.method !== "HEAD") return false;
|
|
@@ -22820,6 +22881,11 @@ var RestartSupervisorProxy = class {
|
|
|
22820
22881
|
}
|
|
22821
22882
|
async handleControl(req, res) {
|
|
22822
22883
|
const pathname = new URL(req.url ?? "/", "http://frizz.invalid").pathname;
|
|
22884
|
+
if (pathname !== SUPERVISOR_SIGN_OUT_PATH && this.arrivedPublicly(req) && !this.sessionAccepted(req)) {
|
|
22885
|
+
res.writeHead(401, { "cache-control": "no-store" });
|
|
22886
|
+
res.end();
|
|
22887
|
+
return;
|
|
22888
|
+
}
|
|
22823
22889
|
const sameOrigin = req.headers["sec-fetch-site"] === "same-origin" || this.vouchesSameOrigin(req);
|
|
22824
22890
|
const allowMissingOrigin = pathname === SUPERVISOR_STATUS_PATH && req.method === "GET" && sameOrigin;
|
|
22825
22891
|
if (!this.authorityAccepted(req, allowMissingOrigin)) {
|
|
@@ -22883,8 +22949,24 @@ var RestartSupervisorProxy = class {
|
|
|
22883
22949
|
responseJson(res, 200, { signedOut: 1 });
|
|
22884
22950
|
return;
|
|
22885
22951
|
}
|
|
22952
|
+
if (pathname === SUPERVISOR_SIGN_OUT_PATH) {
|
|
22953
|
+
if (req.method !== "POST") {
|
|
22954
|
+
res.writeHead(405, { allow: "POST" });
|
|
22955
|
+
res.end();
|
|
22956
|
+
return;
|
|
22957
|
+
}
|
|
22958
|
+
this.signOutThisDevice(req, res);
|
|
22959
|
+
return;
|
|
22960
|
+
}
|
|
22886
22961
|
if (pathname === SUPERVISOR_STATUS_PATH && req.method === "GET") {
|
|
22887
|
-
responseJson(res, 200, {
|
|
22962
|
+
responseJson(res, 200, {
|
|
22963
|
+
protocol: SUPERVISOR_CONTROL_PROTOCOL,
|
|
22964
|
+
...this.status(),
|
|
22965
|
+
// Sent ONLY when true, so a loopback tab's payload is byte-identical to what it was. The web
|
|
22966
|
+
// app cannot tell on its own: the session cookie is HttpOnly, and the page is the same bundle
|
|
22967
|
+
// whichever way it was reached. It is a fact about THIS request, never about the board.
|
|
22968
|
+
...this.carriesRemoteSession(req) ? { remoteSession: true } : {}
|
|
22969
|
+
});
|
|
22888
22970
|
return;
|
|
22889
22971
|
}
|
|
22890
22972
|
if (pathname !== SUPERVISOR_RESTART_PATH && pathname !== SUPERVISOR_UPDATE_RESTART_PATH || req.method !== "POST") {
|
|
@@ -22962,6 +23044,42 @@ var RestartSupervisorProxy = class {
|
|
|
22962
23044
|
if (!this.publicOrigin) return true;
|
|
22963
23045
|
return this.access.verifySession(readCookie(req.headers.cookie, SESSION_COOKIE));
|
|
22964
23046
|
}
|
|
23047
|
+
/** Did this request arrive through the public origin carrying a live session? Loopback never does. */
|
|
23048
|
+
carriesRemoteSession(req) {
|
|
23049
|
+
return this.arrivedPublicly(req) && this.access.verifySession(readCookie(req.headers.cookie, SESSION_COOKIE));
|
|
23050
|
+
}
|
|
23051
|
+
/**
|
|
23052
|
+
* End the session this request carries, and nothing else — see SUPERVISOR_SIGN_OUT_PATH in
|
|
23053
|
+
* handleControl for why that makes it safe to reach from the tunnel.
|
|
23054
|
+
*
|
|
23055
|
+
* A loopback request is a no-op even if it somehow carries a cookie: the operator's own tab has no
|
|
23056
|
+
* remote session to end, and loopback is the place `--sign-out` already covers.
|
|
23057
|
+
*/
|
|
23058
|
+
signOutThisDevice(req, res) {
|
|
23059
|
+
const reply = (status, body, clearCookie) => {
|
|
23060
|
+
res.writeHead(status, {
|
|
23061
|
+
"content-type": "application/json; charset=utf-8",
|
|
23062
|
+
"cache-control": "no-store",
|
|
23063
|
+
// Same attributes the exchange set, so the browser matches and drops that exact cookie.
|
|
23064
|
+
...clearCookie ? { "set-cookie": `${SESSION_COOKIE}=; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=0` } : {}
|
|
23065
|
+
});
|
|
23066
|
+
res.end(JSON.stringify(body));
|
|
23067
|
+
};
|
|
23068
|
+
if (!this.arrivedPublicly(req)) {
|
|
23069
|
+
reply(200, { protocol: SUPERVISOR_CONTROL_PROTOCOL, result: "no-remote-session" }, false);
|
|
23070
|
+
return;
|
|
23071
|
+
}
|
|
23072
|
+
const outcome = this.access.signOutSession(readCookie(req.headers.cookie, SESSION_COOKIE));
|
|
23073
|
+
if (outcome.result === "revoked") {
|
|
23074
|
+
reply(200, { protocol: SUPERVISOR_CONTROL_PROTOCOL, result: "signed-out", id: outcome.id }, true);
|
|
23075
|
+
return;
|
|
23076
|
+
}
|
|
23077
|
+
if (outcome.result === "legacy") {
|
|
23078
|
+
reply(200, { protocol: SUPERVISOR_CONTROL_PROTOCOL, result: "cookie-cleared" }, true);
|
|
23079
|
+
return;
|
|
23080
|
+
}
|
|
23081
|
+
reply(401, { protocol: SUPERVISOR_CONTROL_PROTOCOL, result: "no-remote-session" }, true);
|
|
23082
|
+
}
|
|
22965
23083
|
/**
|
|
22966
23084
|
* Trade `?frizz_code=…` for a cookie, then bounce to the same URL
|
|
22967
23085
|
* without the secret, so it never lands in history, a Referer header, or a screenshot.
|
|
@@ -26464,7 +26582,8 @@ function createNpmRegistryReleaseAdapter(options2 = {}) {
|
|
|
26464
26582
|
return reject(new Error(`could not check npm for ${packageName}: ${why}`));
|
|
26465
26583
|
}
|
|
26466
26584
|
try {
|
|
26467
|
-
const
|
|
26585
|
+
const answer = JSON.parse(stdout);
|
|
26586
|
+
const parsed = Array.isArray(answer) && answer.length === 1 ? answer[0] : answer;
|
|
26468
26587
|
resolveVersion(typeof parsed === "string" ? parsed : String(parsed));
|
|
26469
26588
|
} catch {
|
|
26470
26589
|
resolveVersion(stdout.trim().replaceAll('"', ""));
|
|
@@ -26669,7 +26788,8 @@ function npmServerPackageInstaller(env = process.env) {
|
|
|
26669
26788
|
},
|
|
26670
26789
|
async latestVersion(packageName) {
|
|
26671
26790
|
if (!PACKAGE.test(packageName)) throw new Error("invalid Frizz server package name");
|
|
26672
|
-
const
|
|
26791
|
+
const parsed = JSON.parse(await run3(["view", `${packageName}@latest`, "version", "--json"]));
|
|
26792
|
+
const version = Array.isArray(parsed) && parsed.length === 1 ? parsed[0] : parsed;
|
|
26673
26793
|
if (typeof version !== "string" || !VERSION.test(version)) throw new Error("npm returned an invalid Frizz server version");
|
|
26674
26794
|
return version;
|
|
26675
26795
|
}
|
|
@@ -26897,7 +27017,6 @@ function releaseHeldLease(lease) {
|
|
|
26897
27017
|
}
|
|
26898
27018
|
|
|
26899
27019
|
// src/preflight.ts
|
|
26900
|
-
init_native_helper();
|
|
26901
27020
|
import { spawnSync } from "node:child_process";
|
|
26902
27021
|
var SUPPORTED_NODE_LINES = [
|
|
26903
27022
|
{ major: 22, minor: 13 },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frizz",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A local web UI for running many coding agents at once",
|
|
6
6
|
"keywords": [
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"@types/ws": "^8.5",
|
|
50
50
|
"esbuild": "^0.25.0",
|
|
51
51
|
"jsqr": "^1.4.0",
|
|
52
|
+
"node-pty": "1.2.0-beta.15",
|
|
52
53
|
"puppeteer": "^25.3.0",
|
|
53
54
|
"typescript": "^5.7",
|
|
54
55
|
"ws": "^8.18"
|
|
@@ -65,7 +66,7 @@
|
|
|
65
66
|
},
|
|
66
67
|
"frizzServer": {
|
|
67
68
|
"package": "frizz-server",
|
|
68
|
-
"version": "0.15.
|
|
69
|
+
"version": "0.15.7",
|
|
69
70
|
"protocol": 1,
|
|
70
71
|
"dataEpoch": 1
|
|
71
72
|
}
|