@aiworker/web 1.22.2 → 1.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +7 -0
- package/dist/assets/{CodeMirrorCommentWidgets-CSICpWQD.js → CodeMirrorCommentWidgets-teB3HmBT.js} +1 -1
- package/dist/assets/DiffView-DC9RX3MF.js +4 -0
- package/dist/assets/{DirtyBranchSwitchDialog-C22HdWj4.js → DirtyBranchSwitchDialog-DwPkzXsS.js} +1 -1
- package/dist/assets/FilesView-BFZkuu4O.js +13 -0
- package/dist/assets/{GitView-VQQkYuUw.js → GitView-B_x52MHY.js} +4 -4
- package/dist/assets/{JsonTreeView-6lrhwD3q.js → JsonTreeView-cmAzUTiw.js} +1 -1
- package/dist/assets/{LinearIssuesView-Ba6Q9569.js → LinearIssuesView-Dehh5afm.js} +1 -1
- package/dist/assets/MarkdownImageGallery-DgNOqqhE.js +1 -0
- package/dist/assets/MarkdownRendererImpl-DusmMZ_p.js +12 -0
- package/dist/assets/OnboardingScreen-B8fm1H4m.js +1 -0
- package/dist/assets/{PatchDiff-BzcZPlOq.js → PatchDiff-BVr7gJU0.js} +1 -1
- package/dist/assets/PierreDiffViewer-DzLt-nel.js +161 -0
- package/dist/assets/PlanView-BmQUYT_z.js +5 -0
- package/dist/assets/SettingsView-ChWmAcZT.js +28 -0
- package/dist/assets/{SettingsWindow-DDQYaKWQ.js → SettingsWindow-Dy3M6ZB9.js} +1 -1
- package/dist/assets/SymbolsNerdFontMono-Regular-aK5vsLov.woff2 +0 -0
- package/dist/assets/{ToolOutputDialog-iYF8Y2bz.js → ToolOutputDialog-cTl_eLIH.js} +5 -5
- package/dist/assets/{ToolPartDiffPreview-CdjbOVMM.js → ToolPartDiffPreview-C_3iYNJQ.js} +1 -1
- package/dist/assets/{VirtualizedFileDiff-fFFm2QgH.js → VirtualizedFileDiff-CAWthkoy.js} +4 -4
- package/dist/assets/WalkthroughView-C7AHOpCA.js +4 -0
- package/dist/assets/{computeVirtualFileMetrics-CzgLum_K.js → computeVirtualFileMetrics-BkiDSlTW.js} +2 -2
- package/dist/assets/contextPanelEmbeddedChat-BdA6bdky.js +1 -0
- package/dist/assets/de-DJsQr-p7.js +10 -0
- package/dist/assets/es-BuYMlA9g.js +16 -0
- package/dist/assets/fr-ePDay33C.js +14 -0
- package/dist/assets/ghostty-vt-DdA0Zryv.wasm +0 -0
- package/dist/assets/index-BD8ILbxF.js +40 -0
- package/dist/assets/{index-Bl3LSbjn.js → index-n6O3hklM.js} +1 -1
- package/dist/assets/index-zhgg-SDz.css +1 -0
- package/dist/assets/{isDiffPlainText-Dx-dB_8l.js → isDiffPlainText-GMdPz-71.js} +1 -1
- package/dist/assets/{isFilePlainText-CWFPwmnU.js → isFilePlainText-BVuH1zH9.js} +1 -1
- package/dist/assets/ja-BzR9xOY_.js +16 -0
- package/dist/assets/ko-BEjHAm14.js +16 -0
- package/dist/assets/main-BydQ1tr_.js +930 -0
- package/dist/assets/{main-DnBAoktx.js → main-D3ZDQglc.js} +2 -2
- package/dist/assets/markdownCore-Cb2MdZnV.js +5 -0
- package/dist/assets/{miniChat-BKyvLseN.js → miniChat-d01k801U.js} +2 -2
- package/dist/assets/{mobile-DKjeFgMN.js → mobile-D7VV-Ufz.js} +2 -2
- package/dist/assets/patchFileDiff-CdztVMz0.js +13 -0
- package/dist/assets/pl-rQmpxNIF.js +16 -0
- package/dist/assets/pt-BR-CorbsSW-.js +16 -0
- package/dist/assets/renderElectronMiniChatApp-BGG9UIlh.js +2 -0
- package/dist/assets/renderMobileApp-BRP3J1iv.js +25 -0
- package/dist/assets/runtimeEndpointReset-BhT_-c52.js +41 -0
- package/dist/assets/scheduledTasksApi-BEuUF_cj.js +1 -0
- package/dist/assets/{shikiHighlight-TEQCmzW8.js → shikiHighlight-BzXUjlby.js} +1 -1
- package/dist/assets/surface-COKb77Ua.js +1 -0
- package/dist/assets/tr-CoAMXPtI.js +7 -0
- package/dist/assets/uk-YlAX0rRU.js +16 -0
- package/dist/assets/{useAppFontEffects-D7sNpuL2.js → useAppFontEffects-Cwyhjfl5.js} +141 -140
- package/dist/assets/useGitComparison-BCZVefdE.js +1 -0
- package/dist/assets/useInlineCommentController-DDkpBEU8.js +2 -0
- package/dist/assets/useRootScrollLock-CwjoWuC4.js +1 -0
- package/dist/assets/{vendor-base-ui-BeMD8X_w.js → vendor-base-ui-BY_5qla_.js} +1 -1
- package/dist/assets/{vendor-codemirror-language-data-Dp3KMRQG.js → vendor-codemirror-language-data-Cb1YnICj.js} +2 -2
- package/dist/assets/vendor-legendapp-list-BuBPBC3R.js +1 -0
- package/dist/assets/vendor-zod-B6551dwG.js +39 -0
- package/dist/assets/{web-components-_mNEMjFY.js → web-components-LV3vjTxy.js} +1 -1
- package/dist/assets/zh-CN-DDYg0Jl7.js +16 -0
- package/dist/assets/zh-TW-CQKaCayr.js +16 -0
- package/dist/index.html +5 -43
- package/dist/mini-chat.html +4 -4
- package/dist/mobile.html +4 -4
- package/package.json +2 -3
- package/server/index.d.ts +15 -0
- package/server/index.js +48 -22
- package/server/lib/agent-memory/runtime.js +7 -2
- package/server/lib/agent-memory/runtime.test.js +22 -0
- package/server/lib/data-dir-migration.js +40 -0
- package/server/lib/data-dir-migration.test.js +59 -0
- package/server/lib/event-stream/DOCUMENTATION.md +3 -0
- package/server/lib/event-stream/global-hub.js +29 -4
- package/server/lib/event-stream/global-hub.test.js +22 -0
- package/server/lib/event-stream/global-ws-bridge.js +15 -18
- package/server/lib/event-stream/protocol.js +21 -7
- package/server/lib/event-stream/runtime.js +9 -6
- package/server/lib/event-stream/runtime.test.js +72 -12
- package/server/lib/fs/DOCUMENTATION.md +3 -0
- package/server/lib/fs/routes.js +31 -0
- package/server/lib/fs/routes.test.js +110 -1
- package/server/lib/git/DOCUMENTATION.md +39 -6
- package/server/lib/git/routes.js +45 -12
- package/server/lib/git/routes.test.js +78 -0
- package/server/lib/git/service.js +343 -202
- package/server/lib/git/service.test.js +496 -25
- package/server/lib/github/DOCUMENTATION.md +5 -0
- package/server/lib/github/routes.js +2 -2
- package/server/lib/inherited-env.js +16 -9
- package/server/lib/inherited-env.test.js +8 -9
- package/server/lib/message-queue/DOCUMENTATION.md +11 -1
- package/server/lib/message-queue/runtime.js +13 -0
- package/server/lib/message-queue/runtime.test.js +31 -1
- package/server/lib/network-defaults.js +23 -0
- package/server/lib/network-defaults.test.js +52 -0
- package/server/lib/notifications/DOCUMENTATION.md +1 -1
- package/server/lib/notifications/emitter-runtime.js +4 -3
- package/server/lib/opencode/DOCUMENTATION.md +35 -5
- package/server/lib/opencode/bootstrap-runtime.js +2 -0
- package/server/lib/opencode/env-runtime.js +5 -1
- package/server/lib/opencode/env-runtime.test.js +72 -0
- package/server/lib/opencode/feature-routes-runtime.js +17 -1
- package/server/lib/opencode/lifecycle.js +4 -3
- package/server/lib/opencode/lifecycle.test.js +29 -0
- package/server/lib/opencode/managed-plugin-config.js +1 -1
- package/server/lib/opencode/openchamber-routes.js +64 -4
- package/server/lib/opencode/openchamber-routes.test.js +128 -1
- package/server/lib/opencode/proxy.js +33 -0
- package/server/lib/opencode/routes.js +5 -3
- package/server/lib/opencode/settings-files.js +214 -0
- package/server/lib/opencode/settings-helpers.js +88 -41
- package/server/lib/opencode/settings-helpers.test.js +176 -1
- package/server/lib/opencode/settings-registry.json +750 -0
- package/server/lib/opencode/settings-runtime.js +175 -27
- package/server/lib/opencode/settings-runtime.test.js +321 -7
- package/server/lib/project-context/DOCUMENTATION.md +38 -4
- package/server/lib/project-context/routes.http.test.js +18 -0
- package/server/lib/project-context/routes.js +15 -0
- package/server/lib/project-context/runtime.js +256 -25
- package/server/lib/project-context/runtime.test.js +160 -3
- package/server/lib/projects/DOCUMENTATION.md +77 -0
- package/server/lib/projects/project-config.js +179 -17
- package/server/lib/projects/project-config.test.js +97 -0
- package/server/lib/projects/project-id.js +43 -0
- package/server/lib/projects/project-setup.js +409 -0
- package/server/lib/projects/project-setup.test.js +557 -0
- package/server/lib/projects/routes.js +59 -0
- package/server/lib/quota/DOCUMENTATION.md +31 -1
- package/server/lib/quota/providers/cline-pass.js +125 -0
- package/server/lib/quota/providers/cline-pass.test.js +103 -0
- package/server/lib/quota/providers/index.js +7 -0
- package/server/lib/quota/providers/neuralwatt.js +3 -6
- package/server/lib/quota/providers/neuralwatt.test.js +7 -7
- package/server/lib/quota/providers/ollama-cloud.js +31 -0
- package/server/lib/quota/providers/ollama-cloud.test.js +33 -1
- package/server/lib/quota/providers/opencode-go.js +1 -1
- package/server/lib/quota/providers/opencode-go.test.js +26 -1
- package/server/lib/quota/providers/openrouter.js +119 -24
- package/server/lib/quota/providers/openrouter.test.js +330 -0
- package/server/lib/relay/DOCUMENTATION.md +75 -0
- package/server/lib/relay/cross-compat.test.js +26 -0
- package/server/lib/relay/downstream-scheduler.js +154 -0
- package/server/lib/relay/downstream-scheduler.test.js +162 -0
- package/server/lib/relay/e2ee.js +10 -8
- package/server/lib/relay/flow-control.test.js +177 -0
- package/server/lib/relay/host-client.js +44 -8
- package/server/lib/relay/host-client.test.js +14 -0
- package/server/lib/relay/tunnel-codec.js +9 -0
- package/server/lib/relay/tunnel-host.js +66 -17
- package/server/lib/scheduled-tasks/DOCUMENTATION.md +9 -1
- package/server/lib/scheduled-tasks/issue-2710-double-execution.test.js +28 -0
- package/server/lib/scheduled-tasks/runtime.js +12 -2
- package/server/lib/scheduled-tasks/runtime.test.js +53 -0
- package/server/lib/session-assist/DOCUMENTATION.md +131 -66
- package/server/lib/session-assist/context.js +127 -0
- package/server/lib/session-assist/context.test.js +132 -0
- package/server/lib/session-assist/prompt.js +54 -0
- package/server/lib/session-assist/runtime.js +117 -267
- package/server/lib/session-assist/runtime.test.js +203 -0
- package/server/lib/session-goal/runtime.js +4 -9
- package/server/lib/small-model/DOCUMENTATION.md +3 -2
- package/server/lib/small-model/call.js +9 -4
- package/server/lib/small-model/call.test.js +29 -0
- package/server/lib/small-model/index.js +5 -10
- package/server/lib/small-model/runtime-providers.js +15 -7
- package/server/lib/small-model/runtime-providers.test.js +7 -1
- package/server/lib/terminal/DOCUMENTATION.md +4 -4
- package/server/lib/terminal/runtime.js +11 -6
- package/server/lib/terminal/runtime.test.js +20 -13
- package/server/lib/walkthrough/DOCUMENTATION.md +49 -20
- package/server/lib/walkthrough/model-settings.js +8 -12
- package/server/lib/walkthrough/pr-source.test.js +21 -0
- package/server/lib/walkthrough/prompt.js +3 -1
- package/server/lib/walkthrough/pull-request.js +7 -4
- package/server/lib/walkthrough/pull-request.test.js +16 -0
- package/server/lib/walkthrough/routes.js +19 -0
- package/server/lib/walkthrough/routes.test.js +26 -0
- package/server/lib/walkthrough/sources.js +36 -4
- package/server/opencode-worktree-readiness.test.js +130 -0
- package/dist/assets/DiffView-hDBKesA_.js +0 -4
- package/dist/assets/FilesView-CdWzeOp9.js +0 -17
- package/dist/assets/MarkdownImageGallery-Czv_mhvS.js +0 -1
- package/dist/assets/MarkdownRendererImpl-BrMcswiy.js +0 -12
- package/dist/assets/OnboardingScreen-ChxQoAkx.js +0 -1
- package/dist/assets/PierreDiffViewer-BchBtZlp.js +0 -157
- package/dist/assets/PlanView-DyDt_nZ_.js +0 -5
- package/dist/assets/SettingsView-BKf5xBsP.js +0 -28
- package/dist/assets/WalkthroughView-DOeCsMju.js +0 -4
- package/dist/assets/contextPanelEmbeddedChat-C0ZLAepL.js +0 -1
- package/dist/assets/de-B5JaA3SA.js +0 -10
- package/dist/assets/es-EPIH88ii.js +0 -16
- package/dist/assets/fr-CAMfxUdZ.js +0 -14
- package/dist/assets/index-DF5kMP-i.js +0 -39
- package/dist/assets/index-Dl3xbAB_.css +0 -1
- package/dist/assets/ja-CifOE1VN.js +0 -16
- package/dist/assets/ko-BBDyAyYQ.js +0 -16
- package/dist/assets/main-MhSaOZoB.js +0 -930
- package/dist/assets/markdownCore-BrBwOOMn.js +0 -3
- package/dist/assets/patchFileDiff-o8ms1me8.js +0 -10
- package/dist/assets/pl-DgEHYfFM.js +0 -16
- package/dist/assets/pt-BR-DuWHojUw.js +0 -16
- package/dist/assets/renderElectronMiniChatApp-CDgBwwCS.js +0 -2
- package/dist/assets/renderMobileApp-DJIKIK1r.js +0 -25
- package/dist/assets/runtimeEndpointReset-CYJ9O_xX.js +0 -17
- package/dist/assets/scheduledTasksApi-D8yamh1b.js +0 -1
- package/dist/assets/tr-D5m2yIWL.js +0 -7
- package/dist/assets/uk-D_q60oog.js +0 -16
- package/dist/assets/useInlineCommentController-Brz_cLcQ.js +0 -2
- package/dist/assets/useRootScrollLock-lXEnWlaU.js +0 -1
- package/dist/assets/vendor-ghostty-web-CrxinGGH.js +0 -13
- package/dist/assets/vendor-legendapp-list-gg7YLRW7.js +0 -1
- package/dist/assets/vendor-zod-CK21ihK-.js +0 -39
- package/dist/assets/zh-CN-D8QvsVeg.js +0 -16
- package/dist/assets/zh-TW-B9t7rQQO.js +0 -16
- package/server/lib/mcp-reconnect/DOCUMENTATION.md +0 -55
- package/server/lib/mcp-reconnect/runtime.js +0 -122
- package/server/lib/mcp-reconnect/runtime.test.js +0 -140
|
@@ -1,4 +1,32 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
|
|
1
3
|
import { isAgentMemoryFeatureAvailable } from '../agent-memory/feature-flag.js';
|
|
4
|
+
|
|
5
|
+
// Generated from packages/ui/src/lib/settings/registry.ts by
|
|
6
|
+
// `bun run settings-registry:generate`; `registry.test.ts` fails when stale.
|
|
7
|
+
// The server is plain ESM without a bundler, so the snapshot is read with
|
|
8
|
+
// `createRequire` (import attributes differ across the Node versions we run on).
|
|
9
|
+
const settingsRegistry = createRequire(import.meta.url)('./settings-registry.json');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Whether a client may persist this key through PUT /api/config/settings:
|
|
13
|
+
* it must be a registry key, not a server-computed flag, not a device field
|
|
14
|
+
* that only lives in the browser, and not one the desktop shell writes itself.
|
|
15
|
+
*/
|
|
16
|
+
const isPersistableSettingsKey = (key) => {
|
|
17
|
+
const field = settingsRegistry.fields[key];
|
|
18
|
+
if (!field) return false;
|
|
19
|
+
if (field.computed || field.local) return false;
|
|
20
|
+
if (field.owner === 'desktop-shell') return false;
|
|
21
|
+
return true;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** Keys accepted on write but never returned by a read. */
|
|
25
|
+
const SECRET_SETTINGS_KEYS = Object.freeze(
|
|
26
|
+
Object.entries(settingsRegistry.fields)
|
|
27
|
+
.filter(([, field]) => field.secret === true)
|
|
28
|
+
.map(([key]) => key),
|
|
29
|
+
);
|
|
2
30
|
import {
|
|
3
31
|
DEFAULT_INPUT_HISTORY_LIMIT,
|
|
4
32
|
DEFAULT_INPUT_HISTORY_SCOPE,
|
|
@@ -18,7 +46,6 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
18
46
|
normalizeManagedRemoteTunnelHostname,
|
|
19
47
|
normalizeManagedRemoteTunnelPresets,
|
|
20
48
|
normalizeManagedRemoteTunnelPresetTokens,
|
|
21
|
-
sanitizeTypographySizesPartial,
|
|
22
49
|
normalizeStringArray,
|
|
23
50
|
sanitizeModelRefs,
|
|
24
51
|
sanitizeSkillCatalogs,
|
|
@@ -203,6 +230,9 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
203
230
|
...new Set(candidate.workStatusHiddenSections.filter((entry) => typeof entry === 'string' && entry.length > 0)),
|
|
204
231
|
];
|
|
205
232
|
}
|
|
233
|
+
if (typeof candidate.workStatusHiddenSectionsExplicit === 'boolean') {
|
|
234
|
+
result.workStatusHiddenSectionsExplicit = candidate.workStatusHiddenSectionsExplicit;
|
|
235
|
+
}
|
|
206
236
|
if (typeof candidate.desktopLanAccessEnabled === 'boolean') {
|
|
207
237
|
result.desktopLanAccessEnabled = candidate.desktopLanAccessEnabled;
|
|
208
238
|
}
|
|
@@ -313,9 +343,6 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
313
343
|
if (typeof candidate.monoFont === 'string' && candidate.monoFont.length > 0) {
|
|
314
344
|
result.monoFont = candidate.monoFont;
|
|
315
345
|
}
|
|
316
|
-
if (typeof candidate.markdownDisplayMode === 'string' && candidate.markdownDisplayMode.length > 0) {
|
|
317
|
-
result.markdownDisplayMode = candidate.markdownDisplayMode;
|
|
318
|
-
}
|
|
319
346
|
if (typeof candidate.githubClientId === 'string') {
|
|
320
347
|
const trimmed = candidate.githubClientId.trim();
|
|
321
348
|
if (trimmed.length > 0) {
|
|
@@ -331,6 +358,45 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
331
358
|
if (typeof candidate.showReasoningTraces === 'boolean') {
|
|
332
359
|
result.showReasoningTraces = candidate.showReasoningTraces;
|
|
333
360
|
}
|
|
361
|
+
if (typeof candidate.streamingAutoFollowEnabled === 'boolean') {
|
|
362
|
+
result.streamingAutoFollowEnabled = candidate.streamingAutoFollowEnabled;
|
|
363
|
+
}
|
|
364
|
+
if (typeof candidate.codeBlockLineWrap === 'boolean') {
|
|
365
|
+
result.codeBlockLineWrap = candidate.codeBlockLineWrap;
|
|
366
|
+
}
|
|
367
|
+
if (typeof candidate.autoSaveEnabled === 'boolean') {
|
|
368
|
+
result.autoSaveEnabled = candidate.autoSaveEnabled;
|
|
369
|
+
}
|
|
370
|
+
if (typeof candidate.diffWrapLines === 'boolean') {
|
|
371
|
+
result.diffWrapLines = candidate.diffWrapLines;
|
|
372
|
+
}
|
|
373
|
+
if (typeof candidate.persistChatDraft === 'boolean') {
|
|
374
|
+
result.persistChatDraft = candidate.persistChatDraft;
|
|
375
|
+
}
|
|
376
|
+
if (typeof candidate.allowPromptingSubagentSessions === 'boolean') {
|
|
377
|
+
result.allowPromptingSubagentSessions = candidate.allowPromptingSubagentSessions;
|
|
378
|
+
}
|
|
379
|
+
if (typeof candidate.showOpenCodeRestartConfirm === 'boolean') {
|
|
380
|
+
result.showOpenCodeRestartConfirm = candidate.showOpenCodeRestartConfirm;
|
|
381
|
+
}
|
|
382
|
+
if (typeof candidate.sessionTabsEnabled === 'boolean') {
|
|
383
|
+
result.sessionTabsEnabled = candidate.sessionTabsEnabled;
|
|
384
|
+
}
|
|
385
|
+
if (typeof candidate.largeTextPasteBehavior === 'string') {
|
|
386
|
+
const mode = candidate.largeTextPasteBehavior.trim();
|
|
387
|
+
if (mode === 'ask' || mode === 'attach' || mode === 'inline') {
|
|
388
|
+
result.largeTextPasteBehavior = mode;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (typeof candidate.fileEditorKeymap === 'string') {
|
|
392
|
+
const mode = candidate.fileEditorKeymap.trim();
|
|
393
|
+
if (mode === 'default' || mode === 'vim') {
|
|
394
|
+
result.fileEditorKeymap = mode;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (Array.isArray(candidate.providerOrder)) {
|
|
398
|
+
result.providerOrder = normalizeStringArray(candidate.providerOrder);
|
|
399
|
+
}
|
|
334
400
|
if (typeof candidate.sessionRecapEnabled === 'boolean') {
|
|
335
401
|
result.sessionRecapEnabled = candidate.sessionRecapEnabled;
|
|
336
402
|
}
|
|
@@ -407,6 +473,9 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
407
473
|
if (candidate.sessionRetentionAction === 'archive' || candidate.sessionRetentionAction === 'delete') {
|
|
408
474
|
result.sessionRetentionAction = candidate.sessionRetentionAction;
|
|
409
475
|
}
|
|
476
|
+
if (typeof candidate.sessionRetentionOnlyArchived === 'boolean') {
|
|
477
|
+
result.sessionRetentionOnlyArchived = candidate.sessionRetentionOnlyArchived;
|
|
478
|
+
}
|
|
410
479
|
if (candidate.tunnelBootstrapTtlMs === null) {
|
|
411
480
|
result.tunnelBootstrapTtlMs = null;
|
|
412
481
|
} else if (typeof candidate.tunnelBootstrapTtlMs === 'number' && Number.isFinite(candidate.tunnelBootstrapTtlMs)) {
|
|
@@ -452,11 +521,6 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
452
521
|
result.managedRemoteTunnelSelectedPresetId = id || undefined;
|
|
453
522
|
}
|
|
454
523
|
|
|
455
|
-
const typography = sanitizeTypographySizesPartial(candidate.typographySizes);
|
|
456
|
-
if (typography) {
|
|
457
|
-
result.typographySizes = typography;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
524
|
if (typeof candidate.defaultModel === 'string') {
|
|
461
525
|
const trimmed = candidate.defaultModel.trim();
|
|
462
526
|
result.defaultModel = trimmed.length > 0 ? trimmed : undefined;
|
|
@@ -502,14 +566,6 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
502
566
|
const trimmed = candidate.zenModel.trim();
|
|
503
567
|
result.zenModel = trimmed.length > 0 ? trimmed : undefined;
|
|
504
568
|
}
|
|
505
|
-
if (typeof candidate.gitProviderId === 'string') {
|
|
506
|
-
const trimmed = candidate.gitProviderId.trim();
|
|
507
|
-
result.gitProviderId = trimmed.length > 0 ? trimmed : undefined;
|
|
508
|
-
}
|
|
509
|
-
if (typeof candidate.gitModelId === 'string') {
|
|
510
|
-
const trimmed = candidate.gitModelId.trim();
|
|
511
|
-
result.gitModelId = trimmed.length > 0 ? trimmed : undefined;
|
|
512
|
-
}
|
|
513
569
|
if (typeof candidate.pwaAppName === 'string') {
|
|
514
570
|
result.pwaAppName = normalizePwaAppName(candidate.pwaAppName, undefined);
|
|
515
571
|
}
|
|
@@ -522,12 +578,6 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
522
578
|
result.mobileKeyboardMode = mode;
|
|
523
579
|
}
|
|
524
580
|
}
|
|
525
|
-
if (typeof candidate.toolCallExpansion === 'string') {
|
|
526
|
-
const mode = candidate.toolCallExpansion.trim();
|
|
527
|
-
if (mode === 'collapsed' || mode === 'activity' || mode === 'detailed' || mode === 'changes') {
|
|
528
|
-
result.toolCallExpansion = mode;
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
581
|
if (typeof candidate.inputSpellcheckEnabled === 'boolean') {
|
|
532
582
|
result.inputSpellcheckEnabled = candidate.inputSpellcheckEnabled;
|
|
533
583
|
}
|
|
@@ -619,9 +669,6 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
619
669
|
if (typeof candidate.promptNavigatorEnabled === 'boolean') {
|
|
620
670
|
result.promptNavigatorEnabled = candidate.promptNavigatorEnabled;
|
|
621
671
|
}
|
|
622
|
-
if (typeof candidate.expandedEditorToolbar === 'boolean') {
|
|
623
|
-
result.expandedEditorToolbar = candidate.expandedEditorToolbar;
|
|
624
|
-
}
|
|
625
672
|
if (typeof candidate.wideChatLayoutEnabled === 'boolean') {
|
|
626
673
|
result.wideChatLayoutEnabled = candidate.wideChatLayoutEnabled;
|
|
627
674
|
}
|
|
@@ -724,11 +771,6 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
724
771
|
}
|
|
725
772
|
}
|
|
726
773
|
|
|
727
|
-
// Message limit — single setting for fetch / trim / Load More chunk
|
|
728
|
-
if (typeof candidate.messageLimit === 'number' && Number.isFinite(candidate.messageLimit)) {
|
|
729
|
-
result.messageLimit = Math.max(10, Math.min(500, Math.round(candidate.messageLimit)));
|
|
730
|
-
}
|
|
731
|
-
|
|
732
774
|
const skillCatalogs = sanitizeSkillCatalogs(candidate.skillCatalogs);
|
|
733
775
|
if (skillCatalogs) {
|
|
734
776
|
result.skillCatalogs = skillCatalogs;
|
|
@@ -912,6 +954,16 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
912
954
|
}
|
|
913
955
|
}
|
|
914
956
|
|
|
957
|
+
// The registry is the last word on what a client may persist: a key the
|
|
958
|
+
// code above still names but the registry no longer lists is dropped here,
|
|
959
|
+
// so the two cannot drift apart silently (settings-helpers.test.js checks
|
|
960
|
+
// the other direction).
|
|
961
|
+
for (const key of Object.keys(result)) {
|
|
962
|
+
if (!isPersistableSettingsKey(key)) {
|
|
963
|
+
delete result[key];
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
|
|
915
967
|
return result;
|
|
916
968
|
};
|
|
917
969
|
|
|
@@ -922,13 +974,6 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
922
974
|
? current.securityScopedBookmarks
|
|
923
975
|
: [];
|
|
924
976
|
|
|
925
|
-
const nextTypographySizes = changes.typographySizes
|
|
926
|
-
? {
|
|
927
|
-
...(current.typographySizes || {}),
|
|
928
|
-
...changes.typographySizes
|
|
929
|
-
}
|
|
930
|
-
: current.typographySizes;
|
|
931
|
-
|
|
932
977
|
const next = {
|
|
933
978
|
...current,
|
|
934
979
|
...changes,
|
|
@@ -937,7 +982,6 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
937
982
|
baseBookmarks.filter((entry) => typeof entry === 'string' && entry.length > 0)
|
|
938
983
|
)
|
|
939
984
|
),
|
|
940
|
-
typographySizes: nextTypographySizes
|
|
941
985
|
};
|
|
942
986
|
|
|
943
987
|
return next;
|
|
@@ -945,9 +989,12 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
945
989
|
|
|
946
990
|
const formatSettingsResponse = (settings) => {
|
|
947
991
|
const sanitized = sanitizeSettingsUpdate(settings);
|
|
948
|
-
|
|
992
|
+
for (const key of SECRET_SETTINGS_KEYS) {
|
|
993
|
+
delete sanitized[key];
|
|
994
|
+
}
|
|
949
995
|
const bookmarks = normalizeStringArray(settings.securityScopedBookmarks);
|
|
950
996
|
const hasManagedRemoteTunnelToken = typeof settings?.managedRemoteTunnelToken === 'string' && settings.managedRemoteTunnelToken.trim().length > 0;
|
|
997
|
+
const hasDesktopUiPassword = typeof settings?.desktopUiPassword === 'string' && settings.desktopUiPassword.trim().length > 0;
|
|
951
998
|
const pwaAppName = normalizePwaAppName(settings?.pwaAppName, '');
|
|
952
999
|
const pwaOrientation = normalizePwaOrientation(settings?.pwaOrientation, 'system');
|
|
953
1000
|
const mobileKeyboardMode = normalizeMobileKeyboardMode(settings?.mobileKeyboardMode, 'native');
|
|
@@ -957,6 +1004,7 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
957
1004
|
return {
|
|
958
1005
|
...sanitized,
|
|
959
1006
|
hasManagedRemoteTunnelToken,
|
|
1007
|
+
hasDesktopUiPassword,
|
|
960
1008
|
// Tells the client whether agent memory exists in this build at all, so
|
|
961
1009
|
// its settings row and panel tab can be absent rather than merely off.
|
|
962
1010
|
agentMemoryFeatureAvailable: isAgentMemoryFeatureAvailable(),
|
|
@@ -967,7 +1015,6 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
967
1015
|
inputHistoryLimit,
|
|
968
1016
|
securityScopedBookmarks: bookmarks,
|
|
969
1017
|
pinnedDirectories: normalizeStringArray(settings.pinnedDirectories),
|
|
970
|
-
typographySizes: sanitizeTypographySizesPartial(settings.typographySizes),
|
|
971
1018
|
...(process.env.AIWORKER_RUNTIME === 'desktop'
|
|
972
1019
|
? {
|
|
973
1020
|
desktopLanAccessActive: process.env.AIWORKER_DESKTOP_LAN_ACCESS_ACTIVE === 'true',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
|
-
import { mkdirSync, mkdtempSync, readdirSync, rmSync } from 'node:fs';
|
|
2
|
+
import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync } from 'node:fs';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { dirname, join } from 'node:path';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
@@ -69,6 +69,19 @@ const createTestHelpersWithRealSanitizers = () => {
|
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
describe('settings helpers', () => {
|
|
72
|
+
it('round-trips telemetry opt-in with the hidden list and preserves it across unrelated writes', () => {
|
|
73
|
+
const helpers = createTestHelpers();
|
|
74
|
+
const legacy = helpers.sanitizeSettingsUpdate({ workStatusHiddenSections: [] });
|
|
75
|
+
expect(legacy.workStatusHiddenSectionsExplicit).toBeUndefined();
|
|
76
|
+
const changes = helpers.sanitizeSettingsUpdate({ workStatusHiddenSections: [], workStatusHiddenSectionsExplicit: true });
|
|
77
|
+
const saved = helpers.mergePersistedSettings(legacy, changes);
|
|
78
|
+
const reloaded = helpers.formatSettingsResponse(JSON.parse(JSON.stringify(saved)));
|
|
79
|
+
expect(reloaded.workStatusHiddenSections).toEqual([]);
|
|
80
|
+
expect(reloaded.workStatusHiddenSectionsExplicit).toBe(true);
|
|
81
|
+
const next = helpers.mergePersistedSettings(reloaded, helpers.sanitizeSettingsUpdate({ workStatusPanelEnabled: false }));
|
|
82
|
+
expect(helpers.formatSettingsResponse(next).workStatusHiddenSectionsExplicit).toBe(true);
|
|
83
|
+
expect(helpers.sanitizeSettingsUpdate({ workStatusHiddenSectionsExplicit: 'true' }).workStatusHiddenSectionsExplicit).toBeUndefined();
|
|
84
|
+
});
|
|
72
85
|
it('imports from the packed @aiworker/web tarball without escaping the published package', async () => {
|
|
73
86
|
const tempRoot = mkdtempSync(join(tmpdir(), 'settings-helpers-pack-'));
|
|
74
87
|
const packDir = join(tempRoot, 'pack');
|
|
@@ -677,6 +690,14 @@ describe('settings helpers', () => {
|
|
|
677
690
|
});
|
|
678
691
|
|
|
679
692
|
describe('session retention settings persistence', () => {
|
|
693
|
+
it('round-trips archived-only retention and rejects non-boolean values', () => {
|
|
694
|
+
const helpers = createTestHelpersWithRealSanitizers();
|
|
695
|
+
for (const sessionRetentionOnlyArchived of [true, false]) {
|
|
696
|
+
expect(helpers.sanitizeSettingsUpdate({ sessionRetentionOnlyArchived })).toEqual({ sessionRetentionOnlyArchived });
|
|
697
|
+
}
|
|
698
|
+
expect(helpers.sanitizeSettingsUpdate({ sessionRetentionOnlyArchived: 'true' })).toEqual({});
|
|
699
|
+
expect(helpers.sanitizeSettingsUpdate({ sessionRetentionOnlyArchived: null })).toEqual({});
|
|
700
|
+
});
|
|
680
701
|
it('round-trips sessionRetentionAction archive and delete through the sanitizer', () => {
|
|
681
702
|
const helpers = createTestHelpersWithRealSanitizers();
|
|
682
703
|
|
|
@@ -701,6 +722,7 @@ describe('settings helpers', () => {
|
|
|
701
722
|
autoDeleteEnabled: true,
|
|
702
723
|
autoDeleteAfterDays: 60,
|
|
703
724
|
sessionRetentionAction: 'delete',
|
|
725
|
+
sessionRetentionOnlyArchived: true,
|
|
704
726
|
};
|
|
705
727
|
|
|
706
728
|
const sanitized = helpers.sanitizeSettingsUpdate(payload);
|
|
@@ -708,6 +730,159 @@ describe('settings helpers', () => {
|
|
|
708
730
|
expect(sanitized.autoDeleteEnabled).toBe(true);
|
|
709
731
|
expect(sanitized.autoDeleteAfterDays).toBe(60);
|
|
710
732
|
expect(sanitized.sessionRetentionAction).toBe('delete');
|
|
733
|
+
expect(sanitized.sessionRetentionOnlyArchived).toBe(true);
|
|
734
|
+
});
|
|
735
|
+
});
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
describe('settings registry gate', () => {
|
|
739
|
+
const registryPath = join(dirname(testFilePath), 'settings-registry.json');
|
|
740
|
+
const registry = JSON.parse(readFileSync(registryPath, 'utf8'));
|
|
741
|
+
const persistableKeys = Object.entries(registry.fields)
|
|
742
|
+
.filter(([, field]) => !field.computed && !field.local && field.owner !== 'desktop-shell')
|
|
743
|
+
.map(([key]) => key);
|
|
744
|
+
|
|
745
|
+
// One valid value per persistable registry key. The test below fails when a
|
|
746
|
+
// key is added to the registry without a line here, and when the sanitizer
|
|
747
|
+
// stops accepting a key the registry still lists — that is the drift the
|
|
748
|
+
// registry exists to end.
|
|
749
|
+
const validValues = {
|
|
750
|
+
themeId: 'openchamber-dark', useSystemTheme: true, themeVariant: 'dark', lightThemeId: 'openchamber-light', darkThemeId: 'openchamber-dark',
|
|
751
|
+
splashBgLight: '#fff', splashFgLight: '#000', splashBgDark: '#000', splashFgDark: '#fff',
|
|
752
|
+
lastDirectory: '/home/testuser/project', homeDirectory: '/home/testuser', opencodeBinary: '/usr/local/bin/opencode',
|
|
753
|
+
projects: [{ id: 'p', path: '/home/testuser/project' }], activeProjectId: 'p',
|
|
754
|
+
securityScopedBookmarks: ['bookmark'], pinnedDirectories: ['/home/testuser/project'],
|
|
755
|
+
desktopLanAccessEnabled: true, desktopKeepAwakeEnabled: true, desktopMinimizeToTrayEnabled: true, desktopMacMenuBarEnabled: true,
|
|
756
|
+
desktopUiPassword: 'secret', githubClientId: 'client', githubScopes: 'repo', skillCatalogs: [{ id: 'c', label: 'C', source: 'https://x' }],
|
|
757
|
+
defaultGitIdentityId: 'global', permissionAutoAccept: { sessions: { s: true }, revision: 1 },
|
|
758
|
+
agentControlToolEnabled: true, agentWebToolEnabled: true, agentMemoryToolEnabled: true, openCodeUpdateToastDismissedVersion: '1.0.0',
|
|
759
|
+
autoDeleteEnabled: true, autoDeleteAfterDays: 30, sessionRetentionOnlyArchived: false, sessionRetentionAction: 'archive', terminalShell: 'zsh', terminalLoginShells: ['zsh'],
|
|
760
|
+
openInAppId: 'vscode', dictationEnabled: true, sttProvider: 'local', sttServerUrl: 'http://localhost:8001/v1', sttModel: 'm', sttLocalModel: 'm', sttLanguage: 'en',
|
|
761
|
+
tunnelProvider: 'cloudflare', tunnelMode: 'quick', tunnelBootstrapTtlMs: 600000, tunnelSessionTtlMs: 86400000, managedLocalTunnelConfigPath: '/tmp/x',
|
|
762
|
+
managedRemoteTunnelHostname: 'x.example', managedRemoteTunnelToken: 'token', managedRemoteTunnelPresets: [{ id: 'a', name: 'A', hostname: 'a.example' }],
|
|
763
|
+
managedRemoteTunnelSelectedPresetId: 'a', managedRemoteTunnelPresetTokens: { a: 'token' },
|
|
764
|
+
sidebarProjectDisplayMode: 'all', sidebarSessionGroupingMode: 'flat', sidebarProjectSortOrder: 'manual', sidebarShowRecentSection: true,
|
|
765
|
+
workStatusPanelEnabled: true, workStatusHiddenSections: ['mcp'], workStatusHiddenSectionsExplicit: true,
|
|
766
|
+
showReasoningTraces: true, streamingAutoFollowEnabled: true, collapsibleThinkingBlocks: true, showTextJustificationActivity: true,
|
|
767
|
+
chatRenderMode: 'live', activityRenderMode: 'summary', mermaidRenderingMode: 'svg', userMessageRenderingMode: 'markdown', collapsibleUserMessages: true,
|
|
768
|
+
stickyUserHeader: true, promptNavigatorEnabled: true, wideChatLayoutEnabled: true, showSplitAssistantMessageActions: true, showToolFileIcons: true,
|
|
769
|
+
codeBlockLineWrap: true, showTurnChangedFiles: true, showExpandedBashTools: true, showExpandedEditTools: true, toolJsonViewMode: 'raw',
|
|
770
|
+
timeFormatPreference: '24h', weekStartPreference: 'monday', messageStreamTransport: 'ws', diffLayoutPreference: 'inline', diffWrapLines: true,
|
|
771
|
+
gitChangesViewMode: 'tree', gitmojiEnabled: true, defaultFileViewerPreview: true, directoryShowHidden: true, filesViewShowGitignored: true,
|
|
772
|
+
fileEditorKeymap: 'vim', autoSaveEnabled: true, autoCreateWorktree: true, sessionTabsEnabled: true, showOpenCodeRestartConfirm: true,
|
|
773
|
+
allowPromptingSubagentSessions: true, inputSpellcheckEnabled: true, enterToSend: true, enterToSendConfigured: true, persistChatDraft: true,
|
|
774
|
+
largeTextPasteBehavior: 'attach', followUpBehavior: 'steer', queueModeEnabled: true, inputHistoryScope: 'global', inputHistoryLimit: 40,
|
|
775
|
+
draftStarters: [{ type: 'command', name: 'plan-feature' }], draftStartersVisible: true, draftStartersCraftGoalAdded: true, draftStartersScheduleTaskAdded: true,
|
|
776
|
+
fontSize: 100, terminalFontSize: 14, editorFontSize: 14, uiFont: 'inter', monoFont: 'jetbrains-mono', padding: 100, cornerRadius: 8,
|
|
777
|
+
shortcutOverrides: { 'chat.send': 'mod+enter' },
|
|
778
|
+
defaultModel: 'anthropic/claude', defaultVariant: 'high', defaultAgent: 'build', smallModelUseDefault: false, smallModelOverride: 'anthropic/haiku',
|
|
779
|
+
walkthroughModelOverride: 'anthropic/claude', zenModel: 'zen/model',
|
|
780
|
+
favoriteModels: [{ providerID: 'anthropic', modelID: 'claude' }], hiddenModels: [{ providerID: 'openai', modelID: 'gpt' }], collapsedModelProviders: ['openai'],
|
|
781
|
+
recentModels: [{ providerID: 'anthropic', modelID: 'claude' }], recentAgents: ['build'], recentEfforts: { 'anthropic/claude': ['high'] }, providerOrder: ['anthropic'],
|
|
782
|
+
sessionRecapEnabled: true, sessionSuggestionEnabled: true, sessionGoalEnabled: true, sessionGoalDefaultBudgetEnabled: true, sessionGoalDefaultBudget: 5,
|
|
783
|
+
summarizeLastMessage: true, summaryThreshold: 100, summaryLength: 50, maxLastMessageLength: 200, showDeletionDialog: true,
|
|
784
|
+
nativeNotificationsEnabled: true, notificationMode: 'always', notifyOnSubtasks: true, notifyOnCompletion: true, notifyOnError: true, notifyOnQuestion: true,
|
|
785
|
+
notificationTemplates: { completion: { title: 't', message: 'm' } }, showOpenCodeUpdateNotifications: true, reportUsage: true,
|
|
786
|
+
usageDisplayMode: 'usage', usageDropdownProviders: ['anthropic'], usageSelectedModels: { anthropic: ['claude'] }, usageCollapsedFamilies: { anthropic: ['f'] },
|
|
787
|
+
usageExpandedFamilies: { anthropic: ['f'] }, usageModelGroups: { anthropic: { customGroups: [{ id: 'g', label: 'G', models: ['claude'], order: 0 }] } },
|
|
788
|
+
globalBehaviorPrompt: 'Be brief.', responseStyleEnabled: true, responseStylePreset: 'concise', responseStyleCustomInstructions: 'x', optimizeSystemPrompt: true,
|
|
789
|
+
pwaAppName: 'AiWorker', pwaOrientation: 'portrait', mobileKeyboardMode: 'native', desktopWindowControlsPosition: 'left', desktopWindowControlsStyle: 'classic',
|
|
790
|
+
inputBarOffset: 10,
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
it('accepts a valid value for every persistable registry key (no server-side drift)', () => {
|
|
794
|
+
// The shared test helpers stub the injected list sanitizers to `undefined`
|
|
795
|
+
// (they are covered by their own suites); here they must pass values through
|
|
796
|
+
// so a key is judged by the sanitizer's own branch, not by a stub.
|
|
797
|
+
const helpers = createSettingsHelpers({
|
|
798
|
+
normalizePathForPersistence: (value) => value,
|
|
799
|
+
normalizeDirectoryPath: (value) => value,
|
|
800
|
+
normalizeTunnelBootstrapTtlMs: (value) => value,
|
|
801
|
+
normalizeTunnelSessionTtlMs: (value) => value,
|
|
802
|
+
normalizeTunnelProvider: (value) => value,
|
|
803
|
+
normalizeTunnelMode: (value) => value,
|
|
804
|
+
normalizeOptionalPath: (value) => value,
|
|
805
|
+
normalizeManagedRemoteTunnelHostname: (value) => value,
|
|
806
|
+
normalizeManagedRemoteTunnelPresets: (value) => value,
|
|
807
|
+
normalizeManagedRemoteTunnelPresetTokens: (value) => value,
|
|
808
|
+
normalizeStringArray: (input) => input,
|
|
809
|
+
sanitizeModelRefs: (value) => value,
|
|
810
|
+
sanitizeSkillCatalogs: (value) => value,
|
|
811
|
+
sanitizeProjects: (value) => value,
|
|
812
|
+
});
|
|
813
|
+
const missingFixture = persistableKeys.filter((key) => !(key in validValues));
|
|
814
|
+
expect(missingFixture).toEqual([]);
|
|
815
|
+
|
|
816
|
+
const rejected = persistableKeys.filter((key) => {
|
|
817
|
+
const result = helpers.sanitizeSettingsUpdate({ [key]: validValues[key] });
|
|
818
|
+
// `queueModeEnabled` is absorbed into `followUpBehavior` on purpose.
|
|
819
|
+
const landedAs = key === 'queueModeEnabled' ? 'followUpBehavior' : key;
|
|
820
|
+
return result[landedAs] === undefined;
|
|
821
|
+
});
|
|
822
|
+
expect(rejected).toEqual([]);
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
it('drops keys the registry does not list, computed flags, and desktop-shell-owned keys', () => {
|
|
826
|
+
const helpers = createTestHelpers();
|
|
827
|
+
expect(helpers.sanitizeSettingsUpdate({
|
|
828
|
+
markdownDisplayMode: 'raw',
|
|
829
|
+
toolCallExpansion: 'collapsed',
|
|
830
|
+
expandedEditorToolbar: true,
|
|
831
|
+
typographySizes: { base: 14 },
|
|
832
|
+
gitProviderId: 'anthropic',
|
|
833
|
+
gitModelId: 'claude',
|
|
834
|
+
messageLimit: 200,
|
|
835
|
+
agentMemoryFeatureAvailable: true,
|
|
836
|
+
desktopHosts: [],
|
|
837
|
+
notARealKey: 1,
|
|
838
|
+
})).toEqual({});
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
it('never returns secret keys from a formatted response', () => {
|
|
842
|
+
const helpers = createTestHelpers();
|
|
843
|
+
const secretKeys = Object.entries(registry.fields).filter(([, field]) => field.secret).map(([key]) => key);
|
|
844
|
+
expect(secretKeys).toContain('managedRemoteTunnelToken');
|
|
845
|
+
expect(secretKeys).toContain('desktopUiPassword');
|
|
846
|
+
expect(secretKeys).toContain('managedRemoteTunnelPresetTokens');
|
|
847
|
+
const response = helpers.formatSettingsResponse({
|
|
848
|
+
managedRemoteTunnelToken: 'token',
|
|
849
|
+
desktopUiPassword: 'pw',
|
|
850
|
+
managedRemoteTunnelPresetTokens: { a: 'tok' },
|
|
851
|
+
themeId: 'x',
|
|
711
852
|
});
|
|
853
|
+
for (const key of secretKeys) {
|
|
854
|
+
expect(response).not.toHaveProperty(key);
|
|
855
|
+
}
|
|
856
|
+
expect(response.hasManagedRemoteTunnelToken).toBe(true);
|
|
857
|
+
expect(response.hasDesktopUiPassword).toBe(true);
|
|
858
|
+
expect(helpers.formatSettingsResponse({ desktopUiPassword: '' }).hasDesktopUiPassword).toBe(false);
|
|
859
|
+
});
|
|
860
|
+
|
|
861
|
+
it('accepts the newly shared profile fields', () => {
|
|
862
|
+
const helpers = createTestHelpersWithRealSanitizers();
|
|
863
|
+
expect(helpers.sanitizeSettingsUpdate({
|
|
864
|
+
providerOrder: ['b', 'a', 'a'],
|
|
865
|
+
diffWrapLines: true,
|
|
866
|
+
persistChatDraft: false,
|
|
867
|
+
largeTextPasteBehavior: 'inline',
|
|
868
|
+
fileEditorKeymap: 'vim',
|
|
869
|
+
allowPromptingSubagentSessions: true,
|
|
870
|
+
showOpenCodeRestartConfirm: false,
|
|
871
|
+
codeBlockLineWrap: true,
|
|
872
|
+
streamingAutoFollowEnabled: false,
|
|
873
|
+
autoSaveEnabled: false,
|
|
874
|
+
})).toEqual({
|
|
875
|
+
providerOrder: ['b', 'a'],
|
|
876
|
+
diffWrapLines: true,
|
|
877
|
+
persistChatDraft: false,
|
|
878
|
+
largeTextPasteBehavior: 'inline',
|
|
879
|
+
fileEditorKeymap: 'vim',
|
|
880
|
+
allowPromptingSubagentSessions: true,
|
|
881
|
+
showOpenCodeRestartConfirm: false,
|
|
882
|
+
codeBlockLineWrap: true,
|
|
883
|
+
streamingAutoFollowEnabled: false,
|
|
884
|
+
autoSaveEnabled: false,
|
|
885
|
+
});
|
|
886
|
+
expect(helpers.sanitizeSettingsUpdate({ largeTextPasteBehavior: 'maybe', fileEditorKeymap: 'emacs' })).toEqual({});
|
|
712
887
|
});
|
|
713
888
|
});
|