@oar-sh/oar 0.9.1 → 0.9.3
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/.github/extensions/web-relay/extension.mjs +0 -3
- package/.github/extensions/web-relay/polling/heartbeat.mjs +2 -55
- package/.github/extensions/web-relay/polling/polling-loop.mjs +0 -1
- package/.github/extensions/web-relay/runtime/api-client.mjs +2 -34
- package/.github/extensions/web-relay/runtime/config-loader.mjs +2 -104
- package/.github/extensions/web-relay/runtime/send-and-wait-errors.mjs +2 -170
- package/.github/extensions/web-relay/runtime/session-io.mjs +1 -71
- package/.github/extensions/web-relay/runtime/worker-websocket-link.mjs +2 -325
- package/.github/extensions/web-relay/skills/prompt-context.mjs +2 -160
- package/CHANGELOG.md +269 -0
- package/README.md +407 -424
- package/bin/oar.js +142 -11
- package/package.json +8 -4
- package/server/README.md +59 -22
- package/server/claude-worker/claude-sdk-adapter.mjs +7 -2
- package/server/claude-worker/claude-session-process.mjs +1013 -45
- package/server/claude-worker/claude-session-worker.mjs +54 -9
- package/server/claude-worker/claude-turn-publisher.mjs +110 -19
- package/server/claude-worker/claude-worker-link-wiring.mjs +9 -0
- package/server/copilot-sdk-runtime.mjs +12 -3
- package/server/copilot-worker/copilot-ask-user-tool.mjs +89 -0
- package/server/copilot-worker/copilot-attachments.mjs +35 -2
- package/server/copilot-worker/copilot-continuation-signals.mjs +55 -0
- package/server/copilot-worker/copilot-model-switch.mjs +425 -0
- package/server/copilot-worker/copilot-prompt-context.mjs +20 -8
- package/server/copilot-worker/copilot-question-bridge.mjs +129 -16
- package/server/copilot-worker/copilot-sdk-adapter.mjs +59 -11
- package/server/copilot-worker/copilot-sdk-event-normalizer.mjs +136 -12
- package/server/copilot-worker/copilot-sdk-session-process.mjs +2753 -527
- package/server/copilot-worker/copilot-sdk-session-worker.mjs +94 -25
- package/server/cursor-worker/cursor-session-worker.mjs +5 -5
- package/server/cursor-worker/cursor-turn-runner.mjs +50 -4
- package/server/db-schema.mjs +61 -1
- package/server/features.mjs +155 -41
- package/server/grok-worker/grok-session-worker.mjs +5 -5
- package/server/grok-worker/grok-turn-runner.mjs +45 -4
- package/server/migrations/0004-steer-settle-markers.mjs +119 -0
- package/server/public/app/annotate-core.mjs +181 -0
- package/server/public/app/annotate-editor.js +617 -0
- package/server/public/app/api-client.js +86 -5
- package/server/public/app/ask-user-view.js +102 -13
- package/server/public/app/attachments-view.js +172 -3
- package/server/public/app/background-task-timeout-options.mjs +9 -0
- package/server/public/app/background-tasks-view.mjs +34 -19
- package/server/public/app/bootstrap.js +153 -69
- package/server/public/app/composer-control-state.mjs +52 -34
- package/server/public/app/context-tier-options.mjs +24 -4
- package/server/public/app/conversation-draft-sync.mjs +187 -0
- package/server/public/app/conversation-list-filter.mjs +86 -0
- package/server/public/app/conversation-preferences.mjs +47 -10
- package/server/public/app/conversation-provider-indicator.mjs +8 -0
- package/server/public/app/conversation-view.js +1032 -218
- package/server/public/app/emoji-view.js +2 -0
- package/server/public/app/font-scaling.js +4 -37
- package/server/public/app/journal-view.js +190 -24
- package/server/public/app/model-selector-options.mjs +185 -1
- package/server/public/app/new-conversation-model-choice.mjs +29 -9
- package/server/public/app/pwa-install.js +64 -136
- package/server/public/app/question-multi-select.mjs +52 -0
- package/server/public/app/reasoning-effort-labels.mjs +13 -3
- package/server/public/app/relay-prompt-sanitizer.mjs +26 -3
- package/server/public/app/router.js +120 -11
- package/server/public/app/settings-modal.js +225 -20
- package/server/public/app/settings-tabs.js +1 -1
- package/server/public/app/socket-handlers.js +47 -4
- package/server/public/app/steered-turn-merge.mjs +100 -0
- package/server/public/app/store.js +159 -16
- package/server/public/app/sync-outbox.mjs +16 -8
- package/server/public/app/tool-activity-emoji.mjs +36 -0
- package/server/public/app/transcript-viewport-anchor.mjs +210 -0
- package/server/public/app/update-ui.js +194 -0
- package/server/public/index.html +483 -24
- package/server/public/sw.js +7 -0
- package/server/relay-tools.md +2 -0
- package/server/relay.mjs +23 -21
- package/server/repositories/message-repository.mjs +78 -21
- package/server/repositories/question-repository.mjs +19 -1
- package/server/repositories/session-repository.mjs +7 -31
- package/server/routes/ask-user-routes.mjs +10 -0
- package/server/routes/messages-routes.mjs +689 -159
- package/server/routes/sessions-routes.mjs +574 -80
- package/server/server-runtime.mjs +393 -925
- package/server/services/claude-auth-service.mjs +7 -1
- package/server/services/cli-install-service.mjs +8 -27
- package/server/services/cli-process-runner.mjs +30 -0
- package/server/services/copilot-model-discovery-service.mjs +202 -0
- package/server/services/data-dir-resolution.mjs +47 -0
- package/server/services/grok-auth-service.mjs +9 -1
- package/server/services/live-turn-picker.mjs +47 -0
- package/server/services/model-variant-catalog-service.mjs +1183 -0
- package/server/services/oar-cli-helpers.mjs +6 -2
- package/server/services/relay-prompt-sanitizer.mjs +30 -3
- package/server/services/relay-question-context.mjs +46 -0
- package/server/services/sdk-session-import-service.mjs +144 -16
- package/server/services/sdk-session-sync-service.mjs +84 -27
- package/server/services/session-worker-registry-service.mjs +116 -3
- package/server/services/session-worker-supervisor-service.mjs +7 -1
- package/server/services/session-worker-websocket-service.mjs +119 -24
- package/server/services/status-event-service.mjs +8 -2
- package/server/services/steer-resend.mjs +45 -0
- package/server/services/update-check-service.mjs +220 -0
- package/server/services/update-install-service.mjs +279 -0
- package/server/services/windows-autostart-service.mjs +42 -6
- package/server/services/windows-boot-autostart-service.mjs +487 -0
- package/shared/ask-user-bridge.mjs +37 -5
- package/shared/background-task-timeout.mjs +12 -4
- package/shared/claude-model-catalog.mjs +49 -0
- package/shared/context-window-fallbacks.mjs +1 -0
- package/shared/control-poller.mjs +4 -1
- package/shared/copilot-model-order.mjs +182 -0
- package/shared/media-embed-instructions.mjs +35 -0
- package/shared/model-descriptors.mjs +181 -30
- package/shared/model-id.mjs +6 -0
- package/shared/pwa-app-name.mjs +44 -0
- package/shared/question-multi-select.mjs +16 -0
- package/shared/relay-stop-failure.mjs +15 -0
- package/shared/slash-command-guard.mjs +76 -0
- package/shared/steer-note.mjs +66 -0
- package/shared/steer-settle-failure.mjs +89 -0
- package/shared/steer-settle-markers.mjs +18 -0
- package/shared/update-semver.mjs +50 -0
- package/shared/worker-crash-guard.mjs +40 -14
- package/shared/worker-runtime/api-client.mjs +34 -0
- package/shared/worker-runtime/config-loader.mjs +104 -0
- package/shared/worker-runtime/heartbeat.mjs +109 -0
- package/shared/worker-runtime/prompt-context.mjs +160 -0
- package/shared/worker-runtime/runner-link-wiring.mjs +44 -0
- package/shared/worker-runtime/send-and-wait-errors.mjs +170 -0
- package/shared/worker-runtime/worker-websocket-link.mjs +436 -0
- package/server/claude-worker/claude-session-test-harness.mjs +0 -236
- package/server/claude-worker/fixtures/workflow-run-record.json +0 -1
- package/server/copilot-worker/copilot-sdk-test-harness.mjs +0 -329
- package/server/copilot-worker/fixtures/abort-turn.json +0 -588
- package/server/copilot-worker/fixtures/ask-user-turn.json +0 -1154
- package/server/copilot-worker/fixtures/background-timer-continuation.json +0 -445
- package/server/copilot-worker/fixtures/background-timer-turn.json +0 -497
- package/server/copilot-worker/fixtures/happy-turn.json +0 -566
- package/server/copilot-worker/fixtures/quota-turn.json +0 -647
- package/server/copilot-worker/fixtures/reasoning-turn.json +0 -625
- package/server/copilot-worker/fixtures/resume-turn.json +0 -700
- package/server/copilot-worker/fixtures/subagent-turn.json +0 -1378
- package/server/copilot-worker/fixtures/tool-permission-turn.json +0 -1293
- package/server/routes/messages-routes-test-harness.mjs +0 -111
- package/server/services/fixtures/claude-auth-stub.sh +0 -62
- package/server/services/fixtures/cli-install-stub.sh +0 -75
- package/server/services/fixtures/grok-stub.sh +0 -86
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
// `backgroundTasks` on reload; hidden whenever the set is empty.
|
|
6
6
|
|
|
7
7
|
import { apiFetch } from './api-client.js';
|
|
8
|
+
import { humanizeModelLabel } from './model-selector-options.mjs';
|
|
9
|
+
import { prefixToolActivityEmoji } from './tool-activity-emoji.mjs';
|
|
8
10
|
import {
|
|
9
11
|
getPreviewsForConversation,
|
|
10
12
|
renderPreviewRowsInto,
|
|
@@ -69,11 +71,26 @@ function taskKindLabel(task) {
|
|
|
69
71
|
return label === 'Subagent' && subagentType ? subagentType : label;
|
|
70
72
|
}
|
|
71
73
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
74
|
+
// "claude-opus-5-5" → "Opus 5.5". A bare alias ("opus") is what a spawn pin
|
|
75
|
+
// carries until the subagent's first answer names the real model.
|
|
76
|
+
export function formatTaskModelLabel(model) {
|
|
77
|
+
const value = String(model || '').trim();
|
|
78
|
+
if (!value) return '';
|
|
79
|
+
if (/^claude-/i.test(value)) return humanizeModelLabel(value);
|
|
80
|
+
if (/^[a-z]+(\[[^\]]+\])?$/i.test(value)) return value.charAt(0).toUpperCase() + value.slice(1);
|
|
81
|
+
return humanizeModelLabel(value);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Detail line: the live tool call when the worker saw one ("🪓 Tool
|
|
85
|
+
// (PowerShell): cd …", cropped to the row by CSS), else the SDK's progress
|
|
86
|
+
// summary, else the bare tool name.
|
|
87
|
+
export function taskActivityText(task) {
|
|
88
|
+
const toolCall = String(task?.lastToolCall || '').trim();
|
|
89
|
+
if (toolCall) return { text: prefixToolActivityEmoji(toolCall), toolCall: true };
|
|
90
|
+
const summary = String(task?.summary || '').trim();
|
|
91
|
+
if (summary) return { text: summary, toolCall: false };
|
|
92
|
+
const lastToolName = String(task?.lastToolName || '').trim();
|
|
93
|
+
return { text: lastToolName ? `using ${lastToolName}` : '', toolCall: false };
|
|
77
94
|
}
|
|
78
95
|
|
|
79
96
|
// Compact token counts: "812 tok", "62.2k tok", "1.2M tok". Exported for the
|
|
@@ -180,7 +197,7 @@ function buildWorkflowAgentRow(agent) {
|
|
|
180
197
|
const activityText = state === 'running' && lastToolName ? `— using ${lastToolName}` : '';
|
|
181
198
|
|
|
182
199
|
const meta = [];
|
|
183
|
-
const model =
|
|
200
|
+
const model = formatTaskModelLabel(agent.model);
|
|
184
201
|
if (model) meta.push(model);
|
|
185
202
|
const tokens = formatTaskTokens(agent.tokens);
|
|
186
203
|
if (tokens) meta.push(tokens);
|
|
@@ -364,16 +381,11 @@ function renderTaskRow(conversationId, task) {
|
|
|
364
381
|
const key = `${conversationId}:${task.taskId}`;
|
|
365
382
|
const stopping = stopsInFlight.has(key);
|
|
366
383
|
const elapsed = formatElapsed(task.startedAt);
|
|
367
|
-
//
|
|
368
|
-
//
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const
|
|
372
|
-
const lastToolName = String(task.lastToolName || '').trim();
|
|
373
|
-
const detail = [
|
|
374
|
-
summary || (lastToolName ? `using ${lastToolName}` : ''),
|
|
375
|
-
formatTaskModel(task),
|
|
376
|
-
].filter(Boolean).join(' · ');
|
|
384
|
+
// Token usage and the model render on the row's right side instead of
|
|
385
|
+
// riding the detail line, so a long tool call can never crowd them out.
|
|
386
|
+
const activity = taskActivityText(task);
|
|
387
|
+
const modelLabel = formatTaskModelLabel(task.model);
|
|
388
|
+
const modelTitle = task.modelInherited === true ? `${task.model} (inherited from the session)` : task.model;
|
|
377
389
|
const tokens = formatTaskTokens(task.totalTokens);
|
|
378
390
|
// Workflow rows with a digest get a fold chevron plus an (initially empty)
|
|
379
391
|
// tree container right below the row; renderBackgroundTasksPanel fills the
|
|
@@ -392,14 +404,17 @@ function renderTaskRow(conversationId, task) {
|
|
|
392
404
|
${foldButton}<span class="bg-task-icon" title="${escHtml(task.taskType || 'task')}">${taskIcon(task.taskType)}</span>
|
|
393
405
|
<span class="bg-task-main">
|
|
394
406
|
<span class="bg-task-desc">${escHtml(task.description || task.taskId)}</span>
|
|
395
|
-
${
|
|
407
|
+
${activity.text ? `<span class="bg-task-detail${activity.toolCall ? ' bg-task-toolcall' : ''}" title="${escHtml(activity.text)}">${escHtml(activity.text)}</span>` : ''}
|
|
396
408
|
</span>
|
|
397
409
|
<span class="bg-task-side">
|
|
398
|
-
<span class="bg-task-
|
|
410
|
+
<span class="bg-task-side-head">
|
|
411
|
+
${modelLabel ? `<span class="bg-task-model" title="${escHtml(modelTitle)}">${escHtml(modelLabel)}</span>` : ''}
|
|
412
|
+
<span class="bg-task-badge">${escHtml(taskKindLabel(task))}</span>
|
|
413
|
+
</span>
|
|
399
414
|
<span class="bg-task-side-status">
|
|
400
415
|
${tokens ? `<span class="bg-task-tokens">${escHtml(tokens)}</span>` : ''}
|
|
401
416
|
<span class="bg-task-elapsed">${escHtml(elapsed)}</span>
|
|
402
|
-
|
|
417
|
+
${task.stoppable === false ? '' : `<button type="button" class="bg-task-stop" data-task-id="${escHtml(task.taskId)}" ${stopping ? 'disabled' : ''}>${stopping ? 'Stopping…' : 'Stop'}</button>`}
|
|
403
418
|
</span>
|
|
404
419
|
</span>
|
|
405
420
|
</div>${treeHolder}`;
|
|
@@ -48,7 +48,10 @@ import {
|
|
|
48
48
|
SHARED_CONVERSATION_TOKEN,
|
|
49
49
|
getConversationWatcherCount,
|
|
50
50
|
generateId,
|
|
51
|
+
imageEditTarget,
|
|
52
|
+
hasPendingUserMessageForConversation,
|
|
51
53
|
} from './store.js';
|
|
54
|
+
import { createTranscriptResizeKeeper } from './transcript-viewport-anchor.mjs';
|
|
52
55
|
import {
|
|
53
56
|
verifyExistingSession,
|
|
54
57
|
verifyToken,
|
|
@@ -74,7 +77,7 @@ import {
|
|
|
74
77
|
reportSharedViewerPresence,
|
|
75
78
|
setNetworkRequestsEnabled,
|
|
76
79
|
} from './api-client.js';
|
|
77
|
-
import { loadConversations, refreshConversations, openConversation, renderConvList, applyLoadedConversationState, initConversationListLazyLoading } from './journal-view.js';
|
|
80
|
+
import { loadConversations, refreshConversations, openConversation, renderConvList, applyLoadedConversationState, initConversationListLazyLoading, initConversationFilter } from './journal-view.js';
|
|
78
81
|
import {
|
|
79
82
|
newConversation,
|
|
80
83
|
confirmNewConversationModel,
|
|
@@ -85,7 +88,7 @@ import {
|
|
|
85
88
|
loadRelayQuestions,
|
|
86
89
|
getPendingQuestionCountsByConversation,
|
|
87
90
|
} from './ask-user-view.js';
|
|
88
|
-
import { openPendingQuestionFromBanner, submitRelayQuestionChoice, submitRelayQuestionAnswer, submitRelayStructuredAnswer, onRelayQuestionDraftInput, handleRelayQuestionKey } from './ask-user-view.js';
|
|
91
|
+
import { openPendingQuestionFromBanner, submitRelayQuestionChoice, submitRelayQuestionAnswer, submitRelayQuestionMultiSelect, submitRelayStructuredAnswer, onRelayQuestionDraftInput, onRelayQuestionMultiSelectChange, setRelayQuestionMultiMode, handleRelayQuestionKey } from './ask-user-view.js';
|
|
89
92
|
import { loadRelayBoards, submitRelayBoardAction } from './relay-board-view.js';
|
|
90
93
|
import {
|
|
91
94
|
restoreInFlightThinking,
|
|
@@ -97,7 +100,10 @@ import {
|
|
|
97
100
|
updateComposerSlashMenu,
|
|
98
101
|
getConversationLoadedMessageCount,
|
|
99
102
|
loadOlderConversationMessages,
|
|
100
|
-
|
|
103
|
+
syncComposerButtonState,
|
|
104
|
+
syncCancellableSteerButtons,
|
|
105
|
+
syncComposerAfterUserEdit,
|
|
106
|
+
isConversationDraftHeldBySend,
|
|
101
107
|
persistComposerAttachments,
|
|
102
108
|
flushConversationDraft,
|
|
103
109
|
initConversationHistoryLazyLoading,
|
|
@@ -110,7 +116,7 @@ import {
|
|
|
110
116
|
} from './conversation-view.js';
|
|
111
117
|
import { bindChatSelectionGuard, chatSelectionGuard, isChatInteractionHeld } from './selection-guard.mjs';
|
|
112
118
|
import { loadRepoBrowserTree, openRepoBrowser, closeRepoBrowser, setRepoBrowserSessionInfo, resetWorkspaceRepoBrowserForRootChange } from './attachments-view.js';
|
|
113
|
-
import { handleAttachmentInput, retryAttachmentUpload, handleComposerPaste, handleComposerDrop, refreshComposerAttachmentWarning, removeAttachment, clearAttachments, openUploadedAttachmentViewer, setFilePreviewMode, toggleFilePreviewHtml, closeFilePreview, goBackFilePreview, openWorkspaceFilePreview, openWorkspaceFilePreviewFromRepo, setRepoBrowserRoot, setRepoBrowserViewMode, toggleRepoBrowserHidden, toggleRepoBrowserHeavy, refreshRepoBrowser, focusRepoTree, setRepoCurrentPath, confirmRepoBrowserCwdPick } from './attachments-view.js';
|
|
119
|
+
import { handleAttachmentInput, retryAttachmentUpload, openAnnotateEditorForPending, openAnnotateEditorForPreview, handleComposerPaste, handleComposerDrop, refreshComposerAttachmentWarning, removeAttachment, clearAttachments, openUploadedAttachmentViewer, setFilePreviewMode, toggleFilePreviewHtml, copyFilePreviewImage, closeFilePreview, goBackFilePreview, openWorkspaceFilePreview, openWorkspaceFilePreviewFromRepo, setRepoBrowserRoot, setRepoBrowserViewMode, toggleRepoBrowserHidden, toggleRepoBrowserHeavy, refreshRepoBrowser, focusRepoTree, setRepoCurrentPath, confirmRepoBrowserCwdPick } from './attachments-view.js';
|
|
114
120
|
import { initEmojiPicker, toggleEmojiPicker } from './emoji-view.js';
|
|
115
121
|
import { initSlashAutocomplete } from './slash-autocomplete.mjs';
|
|
116
122
|
import { dataTransferHasFiles } from './composer-paste.mjs';
|
|
@@ -122,8 +128,14 @@ import {
|
|
|
122
128
|
resolveConversationComposerSelection,
|
|
123
129
|
} from './conversation-preferences.mjs';
|
|
124
130
|
import {
|
|
131
|
+
buildCatalogModelOptions,
|
|
132
|
+
catalogModelLabel,
|
|
133
|
+
composerPlaceholderFor,
|
|
134
|
+
contextWindowSuffix,
|
|
135
|
+
humanizeModelLabel,
|
|
136
|
+
modelMetadataFor,
|
|
125
137
|
modelSelectorOptionsEqual,
|
|
126
|
-
|
|
138
|
+
splitModelVariantId,
|
|
127
139
|
} from './model-selector-options.mjs';
|
|
128
140
|
import {
|
|
129
141
|
buildContextTierOptions,
|
|
@@ -166,7 +178,7 @@ import {
|
|
|
166
178
|
initFullscreenButton,
|
|
167
179
|
promptInstallApp,
|
|
168
180
|
toggleFullscreen,
|
|
169
|
-
|
|
181
|
+
adoptLegacyPwaAppName,
|
|
170
182
|
registerPwaShell,
|
|
171
183
|
updatePwaAppName,
|
|
172
184
|
} from './pwa-install.js';
|
|
@@ -265,7 +277,7 @@ import {
|
|
|
265
277
|
toggleCursorProvider,
|
|
266
278
|
applyCursorSettingsState,
|
|
267
279
|
refreshCursorSettingsState,
|
|
268
|
-
|
|
280
|
+
updateWindowsAutostartMode,
|
|
269
281
|
previewTurnCeilingSetting,
|
|
270
282
|
updateTurnCeilingSetting,
|
|
271
283
|
previewBackgroundTaskTimeoutSetting,
|
|
@@ -311,6 +323,14 @@ import {
|
|
|
311
323
|
runCliInstall,
|
|
312
324
|
cancelCliInstallRun,
|
|
313
325
|
} from './cli-install-ui.js';
|
|
326
|
+
import {
|
|
327
|
+
updateAutoCheckSetting,
|
|
328
|
+
checkForUpdatesNow,
|
|
329
|
+
applyAvailableUpdate,
|
|
330
|
+
cancelRunningUpdate,
|
|
331
|
+
dismissAvailableUpdate,
|
|
332
|
+
dismissUpdateOutcome,
|
|
333
|
+
} from './update-ui.js';
|
|
314
334
|
|
|
315
335
|
const MODEL_STORAGE_KEY = 'copilot_selected_model';
|
|
316
336
|
// The New Chat modal used to keep its own model key, so a selection made there
|
|
@@ -413,6 +433,8 @@ let modelVariantCatalogState = {
|
|
|
413
433
|
variants: [],
|
|
414
434
|
enabledVariantIds: [],
|
|
415
435
|
reasoningByModel: {},
|
|
436
|
+
contextLimitsByModel: {},
|
|
437
|
+
modelMetadataByModel: {},
|
|
416
438
|
source: null,
|
|
417
439
|
refreshedAt: null,
|
|
418
440
|
warning: null,
|
|
@@ -1065,49 +1087,12 @@ function syncQueueStatusMenuEntry(payload = null) {
|
|
|
1065
1087
|
}
|
|
1066
1088
|
|
|
1067
1089
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
if (!value) return { baseModelId: '', reasoningEffort: null };
|
|
1071
|
-
const match = value.match(/^(.*)-(none|low|medium|high|xhigh|max)$/i);
|
|
1072
|
-
if (!match) return { baseModelId: value, reasoningEffort: null };
|
|
1073
|
-
return {
|
|
1074
|
-
baseModelId: String(match[1] || '').trim(),
|
|
1075
|
-
reasoningEffort: String(match[2] || '').trim().toLowerCase(),
|
|
1076
|
-
};
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
function humanizeModelLabel(modelId = '') {
|
|
1080
|
-
const text = String(modelId || '').trim();
|
|
1081
|
-
if (!text) return '';
|
|
1082
|
-
if (/^gpt-/i.test(text)) {
|
|
1083
|
-
return text
|
|
1084
|
-
.replace(/^gpt-/i, 'GPT-')
|
|
1085
|
-
.replace(/-codex$/i, ' Codex')
|
|
1086
|
-
.replace(/-mini$/i, ' Mini');
|
|
1087
|
-
}
|
|
1088
|
-
if (/^claude-/i.test(text)) {
|
|
1089
|
-
return text
|
|
1090
|
-
.replace(/^claude-/i, 'Claude ')
|
|
1091
|
-
.split('-')
|
|
1092
|
-
.map((part) => (/^\d+(\.\d+)?$/.test(part) ? part : (part.charAt(0).toUpperCase() + part.slice(1))))
|
|
1093
|
-
.join(' ');
|
|
1094
|
-
}
|
|
1095
|
-
if (/^gemini-/i.test(text)) {
|
|
1096
|
-
return text
|
|
1097
|
-
.replace(/^gemini-/i, 'Gemini ')
|
|
1098
|
-
.split('-')
|
|
1099
|
-
.map((part) => (/^\d+(\.\d+)?$/.test(part) ? part : (part.charAt(0).toUpperCase() + part.slice(1))))
|
|
1100
|
-
.join(' ');
|
|
1101
|
-
}
|
|
1102
|
-
return text;
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1090
|
+
// Bare label (no window suffix) for places outside the option list, such as
|
|
1091
|
+
// the runtime-lock pin.
|
|
1105
1092
|
function modelOptionLabel(modelVariantId = '') {
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
const baseLabel = humanizeModelLabel(baseModelId);
|
|
1110
|
-
return reasoningEffort ? `${baseLabel} (${reasoningEffort})` : baseLabel;
|
|
1093
|
+
return catalogModelLabel(modelVariantId, modelCatalogState.modelMetadataByModel, {
|
|
1094
|
+
autoValue: AUTO_MODEL_OPTION,
|
|
1095
|
+
});
|
|
1111
1096
|
}
|
|
1112
1097
|
|
|
1113
1098
|
function normalizeReasoningEffortList(efforts = []) {
|
|
@@ -1158,7 +1143,7 @@ function syncModelMetadataBlocker(message = '') {
|
|
|
1158
1143
|
reasoningSelect.disabled = blocked;
|
|
1159
1144
|
reasoningSelect.title = blocked ? 'Reasoning metadata unavailable' : 'Reasoning effort';
|
|
1160
1145
|
}
|
|
1161
|
-
window.
|
|
1146
|
+
window.syncComposerButtonState?.();
|
|
1162
1147
|
}
|
|
1163
1148
|
|
|
1164
1149
|
function currentConversationHasMessages() {
|
|
@@ -1314,6 +1299,9 @@ function clearModelMetadataHardFail() {
|
|
|
1314
1299
|
async function startAppWithErrorHandling() {
|
|
1315
1300
|
try {
|
|
1316
1301
|
await initApp();
|
|
1302
|
+
// Post-auth: move a legacy per-browser install app name to the relay so
|
|
1303
|
+
// manifest fetches (Android WebAPK checks included) stop reverting it.
|
|
1304
|
+
void adoptLegacyPwaAppName();
|
|
1317
1305
|
return true;
|
|
1318
1306
|
} catch (error) {
|
|
1319
1307
|
console.error('[bootstrap] initApp failed', error);
|
|
@@ -1332,6 +1320,25 @@ function activeComposerProviderType() {
|
|
|
1332
1320
|
).trim().toLowerCase();
|
|
1333
1321
|
}
|
|
1334
1322
|
|
|
1323
|
+
/**
|
|
1324
|
+
* Keeps "Message <who>…" in step with the current model selection. The two
|
|
1325
|
+
* standing overrides win: the shared read-only text owns the field for the
|
|
1326
|
+
* whole session, and an active image-edit target owns it until cleared
|
|
1327
|
+
* (clearImageEditTarget calls back in through the window global).
|
|
1328
|
+
*/
|
|
1329
|
+
function syncComposerPlaceholder() {
|
|
1330
|
+
const input = document.getElementById('msg-input');
|
|
1331
|
+
if (!input) return;
|
|
1332
|
+
if (isSharedReaderMode()) return;
|
|
1333
|
+
if (imageEditTarget) return;
|
|
1334
|
+
const rawValue = String(document.getElementById('model-select')?.value || '');
|
|
1335
|
+
const { baseModelId } = splitModelVariantId(rawValue);
|
|
1336
|
+
input.placeholder = composerPlaceholderFor({
|
|
1337
|
+
modelId: baseModelId || rawValue,
|
|
1338
|
+
providerType: normalizeModelSelectorProviderType(activeComposerProviderType()),
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1335
1342
|
function normalizeModelSelectorProviderType(providerType = '') {
|
|
1336
1343
|
const normalized = String(providerType || '').trim().toLowerCase();
|
|
1337
1344
|
if (normalized === 'openai' || normalized === 'openai-byok') return 'openai';
|
|
@@ -1379,10 +1386,19 @@ function modelVisibleForActiveProvider(modelId, activeProviderType, providersByM
|
|
|
1379
1386
|
return !((hasOpenAIByok || hasClaude || hasCursor || hasGrok) && !hasNonExclusiveProvider);
|
|
1380
1387
|
}
|
|
1381
1388
|
|
|
1382
|
-
|
|
1383
|
-
|
|
1389
|
+
// metadataByModel is a parameter because the catalog refresh builds the next
|
|
1390
|
+
// option list before it commits nextState; reading modelCatalogState there
|
|
1391
|
+
// would label the new models with the old metadata.
|
|
1392
|
+
function buildModelSelectorOptions(
|
|
1393
|
+
models = [],
|
|
1394
|
+
providersByModel = {},
|
|
1395
|
+
activeProviderType = '',
|
|
1396
|
+
metadataByModel = modelCatalogState.modelMetadataByModel,
|
|
1397
|
+
) {
|
|
1398
|
+
const normalizedOptions = buildCatalogModelOptions(models.length ? models : [FALLBACK_MODEL], {
|
|
1384
1399
|
autoValue: AUTO_MODEL_OPTION,
|
|
1385
|
-
|
|
1400
|
+
metadataByModel,
|
|
1401
|
+
annotateContextWindow: normalizeModelSelectorProviderType(activeProviderType) !== 'claude',
|
|
1386
1402
|
});
|
|
1387
1403
|
return normalizedOptions.filter((option) => modelVisibleForActiveProvider(
|
|
1388
1404
|
option.value,
|
|
@@ -1522,9 +1538,14 @@ function updateModelCatalogState(payload) {
|
|
|
1522
1538
|
: [];
|
|
1523
1539
|
const currentModel = String(payload?.currentModel || models[0] || '').trim();
|
|
1524
1540
|
const defaultModel = String(payload?.defaultModel || models[0] || '').trim();
|
|
1525
|
-
const
|
|
1541
|
+
const modelMetadataByModel = payload?.modelMetadataByModel && typeof payload.modelMetadataByModel === 'object'
|
|
1542
|
+
? payload.modelMetadataByModel
|
|
1543
|
+
: {};
|
|
1544
|
+
// Stored in catalog order so every consumer of modelCatalogState.models
|
|
1545
|
+
// (composer, provider rescope, auto fallback) walks the same sequence.
|
|
1546
|
+
const normalizedModelOptions = buildCatalogModelOptions(models.length ? models : [FALLBACK_MODEL], {
|
|
1526
1547
|
autoValue: AUTO_MODEL_OPTION,
|
|
1527
|
-
|
|
1548
|
+
metadataByModel: modelMetadataByModel,
|
|
1528
1549
|
});
|
|
1529
1550
|
const normalizedModels = normalizedModelOptions.map((option) => option.value);
|
|
1530
1551
|
|
|
@@ -1569,9 +1590,7 @@ function updateModelCatalogState(payload) {
|
|
|
1569
1590
|
]))
|
|
1570
1591
|
: {},
|
|
1571
1592
|
reasoningEfforts: normalizeReasoningEffortList(payload?.reasoningEfforts || []),
|
|
1572
|
-
modelMetadataByModel
|
|
1573
|
-
? payload.modelMetadataByModel
|
|
1574
|
-
: {},
|
|
1593
|
+
modelMetadataByModel,
|
|
1575
1594
|
claudeContextTiersByModel: payload?.claudeContextTiersByModel && typeof payload.claudeContextTiersByModel === 'object'
|
|
1576
1595
|
? Object.fromEntries(Object.entries(payload.claudeContextTiersByModel).map(([modelId, tiers]) => [
|
|
1577
1596
|
String(modelId || '').trim().toLowerCase(),
|
|
@@ -1590,6 +1609,7 @@ function updateModelCatalogState(payload) {
|
|
|
1590
1609
|
normalizedModels,
|
|
1591
1610
|
nextState.providersByModel,
|
|
1592
1611
|
activeProviderType,
|
|
1612
|
+
nextState.modelMetadataByModel,
|
|
1593
1613
|
);
|
|
1594
1614
|
const nextModels = nextOptions.map((option) => option.value);
|
|
1595
1615
|
const currentOptions = Array.from(select.options)
|
|
@@ -1670,6 +1690,10 @@ function updateModelCatalogState(payload) {
|
|
|
1670
1690
|
|
|
1671
1691
|
syncModelMetadataBlocker();
|
|
1672
1692
|
syncAutoModelAvailability();
|
|
1693
|
+
// After syncAutoModelAvailability: it can rewrite select.value (auto
|
|
1694
|
+
// fallback, runtime-lock pin) and the placeholder must describe the final
|
|
1695
|
+
// selection, not the transient one.
|
|
1696
|
+
syncComposerPlaceholder();
|
|
1673
1697
|
// The rebuilt catalog may now contain the conversation's preferred model for
|
|
1674
1698
|
// the first time (provider models arrive after the initial catalog load).
|
|
1675
1699
|
if (currentConvId) applyConversationPreferencesForConversation(currentConvId);
|
|
@@ -1703,7 +1727,7 @@ function updateContextTierSelector(modelId) {
|
|
|
1703
1727
|
const tierOptions = buildContextTierOptions({
|
|
1704
1728
|
modelId,
|
|
1705
1729
|
providerType: activeComposerProviderType(),
|
|
1706
|
-
metadata: modelCatalogState.modelMetadataByModel
|
|
1730
|
+
metadata: modelMetadataFor(modelId, modelCatalogState.modelMetadataByModel) || {},
|
|
1707
1731
|
claudeTiers: modelCatalogState.claudeContextTiersByModel,
|
|
1708
1732
|
});
|
|
1709
1733
|
const current = select.value;
|
|
@@ -1917,6 +1941,7 @@ function applyConversationPreferences({
|
|
|
1917
1941
|
String(preferredReasoningEffort || '').trim().toLowerCase(),
|
|
1918
1942
|
);
|
|
1919
1943
|
updateContextTierSelector(selection.model || modelSelect.value);
|
|
1944
|
+
syncComposerPlaceholder();
|
|
1920
1945
|
const tierSelect = document.getElementById('context-tier-select');
|
|
1921
1946
|
const desiredTier = String(preferredContextTier || 'default').trim().toLowerCase();
|
|
1922
1947
|
if (tierSelect && Array.from(tierSelect.options).some((option) => option.value === desiredTier)) {
|
|
@@ -1990,6 +2015,8 @@ function initModelSelector() {
|
|
|
1990
2015
|
if (suppressConversationPreferenceSync) return;
|
|
1991
2016
|
if (currentConversationHasMessages() && select.value.toLowerCase() === AUTO_MODEL_OPTION) {
|
|
1992
2017
|
syncAutoModelAvailability();
|
|
2018
|
+
// The revert rewrites select.value; keep the placeholder describing it.
|
|
2019
|
+
syncComposerPlaceholder();
|
|
1993
2020
|
setModelBanner('⚠️ Auto model selection is available only for a new conversation.');
|
|
1994
2021
|
return;
|
|
1995
2022
|
}
|
|
@@ -2003,6 +2030,7 @@ function initModelSelector() {
|
|
|
2003
2030
|
{ persist: true },
|
|
2004
2031
|
);
|
|
2005
2032
|
updateContextTierSelector(select.value);
|
|
2033
|
+
syncComposerPlaceholder();
|
|
2006
2034
|
syncSessionLockNote({ pinnedModel: currentRuntimeModelLock()?.model || '' });
|
|
2007
2035
|
refreshComposerAttachmentWarning();
|
|
2008
2036
|
void persistCurrentConversationPreferences().catch(() => {});
|
|
@@ -2145,6 +2173,10 @@ function applyModelVariantCatalogState(payload) {
|
|
|
2145
2173
|
selectable: entry?.selectable !== false,
|
|
2146
2174
|
enabled: !!entry?.enabled,
|
|
2147
2175
|
sortOrder: Number.isFinite(Number(entry?.sortOrder)) ? Math.max(0, Math.trunc(Number(entry.sortOrder))) : 0,
|
|
2176
|
+
contextLimitTokens: Number.isFinite(Number(entry?.contextLimitTokens)) && Number(entry.contextLimitTokens) > 0
|
|
2177
|
+
? Number(entry.contextLimitTokens)
|
|
2178
|
+
: null,
|
|
2179
|
+
pricing: entry?.pricing && typeof entry.pricing === 'object' ? entry.pricing : null,
|
|
2148
2180
|
})).filter((entry) => entry.variantId && entry.baseModelId)
|
|
2149
2181
|
: [];
|
|
2150
2182
|
const canonicalizeId = (value) => String(value || '').trim().toLowerCase();
|
|
@@ -2169,6 +2201,8 @@ function applyModelVariantCatalogState(payload) {
|
|
|
2169
2201
|
sortOrder: Math.min(existing.sortOrder, entry.sortOrder),
|
|
2170
2202
|
label: existing.label || entry.label,
|
|
2171
2203
|
provider: existing.provider || entry.provider,
|
|
2204
|
+
contextLimitTokens: existing.contextLimitTokens ?? entry.contextLimitTokens,
|
|
2205
|
+
pricing: existing.pricing || entry.pricing,
|
|
2172
2206
|
});
|
|
2173
2207
|
}
|
|
2174
2208
|
const variants = Array.from(dedupedVariantsMap.values());
|
|
@@ -2185,6 +2219,15 @@ function applyModelVariantCatalogState(payload) {
|
|
|
2185
2219
|
normalizeReasoningEffortList(efforts),
|
|
2186
2220
|
]))
|
|
2187
2221
|
: {},
|
|
2222
|
+
contextLimitsByModel: payload?.contextLimitsByModel && typeof payload.contextLimitsByModel === 'object'
|
|
2223
|
+
? Object.fromEntries(Object.entries(payload.contextLimitsByModel).map(([modelId, tokens]) => [
|
|
2224
|
+
String(modelId || '').trim().toLowerCase(),
|
|
2225
|
+
Number(tokens),
|
|
2226
|
+
]).filter(([modelId, tokens]) => modelId && Number.isFinite(tokens) && tokens > 0))
|
|
2227
|
+
: {},
|
|
2228
|
+
modelMetadataByModel: payload?.modelMetadataByModel && typeof payload.modelMetadataByModel === 'object'
|
|
2229
|
+
? payload.modelMetadataByModel
|
|
2230
|
+
: {},
|
|
2188
2231
|
source: String(payload?.source || '').trim() || null,
|
|
2189
2232
|
refreshedAt: payload?.refreshedAt || null,
|
|
2190
2233
|
warning: payload?.warning ? String(payload.warning) : null,
|
|
@@ -2514,6 +2557,13 @@ function renderModelVariantCatalogBody() {
|
|
|
2514
2557
|
? { ...fallbackMeta, efforts: new Set(providerEfforts) }
|
|
2515
2558
|
: fallbackMeta;
|
|
2516
2559
|
const label = meta.label || humanizeModelLabel(baseModelId) || baseModelId;
|
|
2560
|
+
const windowSuffix = contextWindowSuffix(
|
|
2561
|
+
baseModelId,
|
|
2562
|
+
modelVariantCatalogState.modelMetadataByModel || modelCatalogState.modelMetadataByModel,
|
|
2563
|
+
);
|
|
2564
|
+
const windowChip = windowSuffix
|
|
2565
|
+
? `<span class="model-reasoning-chip model-reasoning-chip-muted">${escHtml(windowSuffix.replace(/^ · /, ''))}</span>`
|
|
2566
|
+
: '';
|
|
2517
2567
|
const variantRowsHtml = variantRows.map((row) => {
|
|
2518
2568
|
const selectable = row.selectable !== false;
|
|
2519
2569
|
// SDK-provider rows (Claude/Cursor/Grok) carry their own enabled flag; only
|
|
@@ -2551,7 +2601,7 @@ function renderModelVariantCatalogBody() {
|
|
|
2551
2601
|
return `
|
|
2552
2602
|
<div class="model-base-group">
|
|
2553
2603
|
<div class="model-base-header">
|
|
2554
|
-
<div class="model-base-title">${escHtml(label)}</div>
|
|
2604
|
+
<div class="model-base-title">${escHtml(label)}${windowChip ? ` ${windowChip}` : ''}</div>
|
|
2555
2605
|
<div class="model-base-reasoning">
|
|
2556
2606
|
<span class="model-base-reasoning-label">Reasoning</span>
|
|
2557
2607
|
${renderReasoningEffortChipRow(meta.efforts)}
|
|
@@ -3194,6 +3244,10 @@ async function refreshSessionWorkerStatus() {
|
|
|
3194
3244
|
syncQueueStatusMenuEntry(status);
|
|
3195
3245
|
if (setSessionWorkerStatesFromStatusPayload(status.sessionWorker)) {
|
|
3196
3246
|
renderConvList();
|
|
3247
|
+
// A worker steering snapshot may have changed; the composer's Steer
|
|
3248
|
+
// button (gate, hold) and the pushed rows' Cancel controls derive from it.
|
|
3249
|
+
syncComposerButtonState();
|
|
3250
|
+
syncCancellableSteerButtons();
|
|
3197
3251
|
}
|
|
3198
3252
|
updateCliStatus();
|
|
3199
3253
|
const nextWorkerState = currentSdkSessionId ? getSessionWorkerState(currentSdkSessionId) : null;
|
|
@@ -3224,8 +3278,13 @@ async function pollAuthenticatedCurrentConversationLive() {
|
|
|
3224
3278
|
const currentId = String(currentConvId || '').trim();
|
|
3225
3279
|
if (!currentId) return;
|
|
3226
3280
|
const currentConversation = conversations[currentId] || null;
|
|
3281
|
+
// A locally-sent message still waiting in the queue must keep the poll
|
|
3282
|
+
// armed: while it waits, inFlight is null, so the poll itself tears the
|
|
3283
|
+
// bubble down — leaving neither localTurnStatus nor an indicator to revive
|
|
3284
|
+
// polling once a worker finally picks the message up.
|
|
3227
3285
|
const isProcessing = String(currentConversation?.localTurnStatus || '').trim().toLowerCase() === 'processing'
|
|
3228
|
-
|| !!document.getElementById('thinking-indicator')
|
|
3286
|
+
|| !!document.getElementById('thinking-indicator')
|
|
3287
|
+
|| hasPendingUserMessageForConversation(currentId);
|
|
3229
3288
|
if (!isProcessing) return;
|
|
3230
3289
|
// Refreshing while the user selects or drags in the chat would rebuild the
|
|
3231
3290
|
// DOM under the selection; the guard's release callback re-polls right away.
|
|
@@ -3260,9 +3319,18 @@ function startLiveConversationPolling() {
|
|
|
3260
3319
|
}, 900);
|
|
3261
3320
|
}
|
|
3262
3321
|
|
|
3322
|
+
const transcriptResizeKeeper = createTranscriptResizeKeeper({
|
|
3323
|
+
getElement: () => document.getElementById('messages'),
|
|
3324
|
+
});
|
|
3325
|
+
|
|
3263
3326
|
function setupViewportTracking() {
|
|
3264
3327
|
syncViewportMetrics();
|
|
3265
|
-
|
|
3328
|
+
// After the metrics: --app-height decides the transcript's height, and the
|
|
3329
|
+
// keeper's restore reads the post-resize layout.
|
|
3330
|
+
const update = () => {
|
|
3331
|
+
syncViewportMetrics();
|
|
3332
|
+
transcriptResizeKeeper.handleResize();
|
|
3333
|
+
};
|
|
3266
3334
|
window.addEventListener('resize', update, { passive: true });
|
|
3267
3335
|
window.addEventListener('orientationchange', update, { passive: true });
|
|
3268
3336
|
if (window.visualViewport) {
|
|
@@ -3301,7 +3369,7 @@ function setupViewportTracking() {
|
|
|
3301
3369
|
if (input && input.dataset.viewportBound !== '1') {
|
|
3302
3370
|
input.dataset.viewportBound = '1';
|
|
3303
3371
|
input.addEventListener('input', () => {
|
|
3304
|
-
|
|
3372
|
+
syncComposerAfterUserEdit();
|
|
3305
3373
|
}, { passive: true });
|
|
3306
3374
|
input.addEventListener('focus', () => {
|
|
3307
3375
|
document.body.classList.add('keyboard-open');
|
|
@@ -3376,6 +3444,7 @@ function initMessageScrollPersistence() {
|
|
|
3376
3444
|
if (!el || el.dataset.scrollPersistenceBound === '1') return;
|
|
3377
3445
|
el.dataset.scrollPersistenceBound = '1';
|
|
3378
3446
|
el.addEventListener('scroll', () => {
|
|
3447
|
+
transcriptResizeKeeper.recordScroll();
|
|
3379
3448
|
const convId = String(currentConvId || '').trim();
|
|
3380
3449
|
if (!convId) return;
|
|
3381
3450
|
saveConversationScrollTop(convId, el.scrollTop);
|
|
@@ -3893,7 +3962,11 @@ async function initApp() {
|
|
|
3893
3962
|
// The direct flush below can be killed mid-flight by the browser; the
|
|
3894
3963
|
// queued copy survives and is replayed by Background Sync. If the direct
|
|
3895
3964
|
// write wins, the replay hits a draft version conflict and is dropped.
|
|
3896
|
-
if (!appSharedMode)
|
|
3965
|
+
if (!appSharedMode) {
|
|
3966
|
+
void enqueueDraftFlushForBackgroundSync(currentConvId, {
|
|
3967
|
+
afterPendingSend: isConversationDraftHeldBySend(currentConvId),
|
|
3968
|
+
});
|
|
3969
|
+
}
|
|
3897
3970
|
void flushConversationDraft(currentConvId);
|
|
3898
3971
|
closeTmuxInspectorView();
|
|
3899
3972
|
});
|
|
@@ -4113,6 +4186,7 @@ async function initApp() {
|
|
|
4113
4186
|
initEmojiPicker();
|
|
4114
4187
|
initSlashAutocomplete();
|
|
4115
4188
|
initConversationListLazyLoading();
|
|
4189
|
+
initConversationFilter();
|
|
4116
4190
|
initConversationHistoryLazyLoading();
|
|
4117
4191
|
initBubbleActionHandlers();
|
|
4118
4192
|
initMessageScrollPersistence();
|
|
@@ -4164,9 +4238,6 @@ async function bootstrap() {
|
|
|
4164
4238
|
.then((registrations) => Promise.all(registrations.map((registration) => registration.unregister().catch(() => false))))
|
|
4165
4239
|
.catch(() => {});
|
|
4166
4240
|
}
|
|
4167
|
-
if (!sharedMode) {
|
|
4168
|
-
await applyPwaManifestFromSettings();
|
|
4169
|
-
}
|
|
4170
4241
|
if (!sharedMode) {
|
|
4171
4242
|
registerPwaShell();
|
|
4172
4243
|
initInstallButton();
|
|
@@ -4219,6 +4290,12 @@ window.confirmGrokLogout = confirmGrokLogout;
|
|
|
4219
4290
|
window.confirmCliInstall = confirmCliInstall;
|
|
4220
4291
|
window.runCliInstall = runCliInstall;
|
|
4221
4292
|
window.cancelCliInstallRun = cancelCliInstallRun;
|
|
4293
|
+
window.updateAutoCheckSetting = updateAutoCheckSetting;
|
|
4294
|
+
window.checkForUpdatesNow = checkForUpdatesNow;
|
|
4295
|
+
window.applyAvailableUpdate = applyAvailableUpdate;
|
|
4296
|
+
window.cancelRunningUpdate = cancelRunningUpdate;
|
|
4297
|
+
window.dismissAvailableUpdate = dismissAvailableUpdate;
|
|
4298
|
+
window.dismissUpdateOutcome = dismissUpdateOutcome;
|
|
4222
4299
|
window.saveGrokSettings = saveGrokSettings;
|
|
4223
4300
|
window.toggleGrokProvider = toggleGrokProvider;
|
|
4224
4301
|
window.saveCursorSettings = saveCursorSettings;
|
|
@@ -4231,7 +4308,7 @@ window.saveGrokAllowanceSettings = saveGrokAllowanceSettings;
|
|
|
4231
4308
|
window.resetGrokAllowanceAccounting = resetGrokAllowanceAccounting;
|
|
4232
4309
|
window.toggleCursorProvider = toggleCursorProvider;
|
|
4233
4310
|
window.updateShowSuspendHostSetting = updateShowSuspendHostSetting;
|
|
4234
|
-
window.
|
|
4311
|
+
window.updateWindowsAutostartMode = updateWindowsAutostartMode;
|
|
4235
4312
|
window.previewTurnCeilingSetting = previewTurnCeilingSetting;
|
|
4236
4313
|
window.updateTurnCeilingSetting = updateTurnCeilingSetting;
|
|
4237
4314
|
window.previewBackgroundTaskTimeoutSetting = previewBackgroundTaskTimeoutSetting;
|
|
@@ -4285,8 +4362,11 @@ window.retryAttachmentUpload = retryAttachmentUpload;
|
|
|
4285
4362
|
window.removeAttachment = removeAttachment;
|
|
4286
4363
|
window.clearAttachments = clearAttachments;
|
|
4287
4364
|
window.openUploadedAttachmentViewer = openUploadedAttachmentViewer;
|
|
4365
|
+
window.openAnnotateEditorForPending = openAnnotateEditorForPending;
|
|
4366
|
+
window.openAnnotateEditorForPreview = openAnnotateEditorForPreview;
|
|
4288
4367
|
window.setFilePreviewMode = setFilePreviewMode;
|
|
4289
4368
|
window.toggleFilePreviewHtml = toggleFilePreviewHtml;
|
|
4369
|
+
window.copyFilePreviewImage = copyFilePreviewImage;
|
|
4290
4370
|
window.closeFilePreview = closeFilePreview;
|
|
4291
4371
|
window.goBackFilePreview = goBackFilePreview;
|
|
4292
4372
|
window.openWorkspaceFilePreview = openWorkspaceFilePreview;
|
|
@@ -4301,14 +4381,18 @@ window.confirmRepoBrowserCwdPick = confirmRepoBrowserCwdPick;
|
|
|
4301
4381
|
window.toggleEmojiPicker = toggleEmojiPicker;
|
|
4302
4382
|
window.submitRelayQuestionChoice = submitRelayQuestionChoice;
|
|
4303
4383
|
window.submitRelayQuestionAnswer = submitRelayQuestionAnswer;
|
|
4384
|
+
window.submitRelayQuestionMultiSelect = submitRelayQuestionMultiSelect;
|
|
4304
4385
|
window.submitRelayStructuredAnswer = submitRelayStructuredAnswer;
|
|
4305
4386
|
window.onRelayQuestionDraftInput = onRelayQuestionDraftInput;
|
|
4387
|
+
window.onRelayQuestionMultiSelectChange = onRelayQuestionMultiSelectChange;
|
|
4388
|
+
window.setRelayQuestionMultiMode = setRelayQuestionMultiMode;
|
|
4306
4389
|
window.handleRelayQuestionKey = handleRelayQuestionKey;
|
|
4307
4390
|
window.openPendingQuestionFromBanner = openPendingQuestionFromBanner;
|
|
4308
4391
|
window.submitRelayBoardAction = submitRelayBoardAction;
|
|
4309
4392
|
window.compactCurrentConversation = compactCurrentConversation;
|
|
4310
4393
|
window.sendMessage = sendMessage;
|
|
4311
|
-
window.
|
|
4394
|
+
window.syncComposerButtonState = syncComposerButtonState;
|
|
4395
|
+
window.syncComposerPlaceholder = syncComposerPlaceholder;
|
|
4312
4396
|
window.persistComposerAttachments = persistComposerAttachments;
|
|
4313
4397
|
window.appendMessage = appendMessage;
|
|
4314
4398
|
window.loadOlderConversationMessages = loadOlderConversationMessages;
|