synabun 2.0.0 → 2.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +97 -0
- package/NOTICE +5 -0
- package/README.md +2 -1
- package/THIRD-PARTY-LICENSES.md +59 -0
- package/benchmarks/fixtures/browser/README.md +1 -1
- package/benchmarks/fixtures/desktop/README.md +1 -1
- package/docs/whatsapp.md +153 -18
- package/hooks/claude-code/pre-compact.mjs +11 -0
- package/hooks/claude-code/prompt-submit.mjs +60 -184
- package/hooks/claude-code/session-start.mjs +73 -16
- package/hooks/claude-code/shared.mjs +26 -3
- package/hooks/claude-code/stop.mjs +5 -5
- package/lib/child-path.js +303 -0
- package/lib/claude-hooks.js +2 -1
- package/lib/data-home-migration.js +2 -0
- package/lib/desktop-app.js +265 -0
- package/lib/external-tools.js +7 -3
- package/lib/log-redact.js +102 -0
- package/lib/packaged-runtime.js +138 -11
- package/lib/start-launcher.js +88 -1
- package/mcp-server/dist/http.d.ts +3 -1
- package/mcp-server/dist/http.d.ts.map +1 -1
- package/mcp-server/dist/http.js +15 -4
- package/mcp-server/dist/http.js.map +1 -1
- package/mcp-server/dist/index.d.ts.map +1 -1
- package/mcp-server/dist/index.js +9 -6
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts +108 -0
- package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -0
- package/mcp-server/dist/services/budget-judgments.js +153 -0
- package/mcp-server/dist/services/budget-judgments.js.map +1 -0
- package/mcp-server/dist/services/codex-config-heal.d.ts +5 -1
- package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.js +41 -4
- package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
- package/mcp-server/dist/services/identity.d.ts +11 -0
- package/mcp-server/dist/services/identity.d.ts.map +1 -1
- package/mcp-server/dist/services/identity.js +24 -0
- package/mcp-server/dist/services/identity.js.map +1 -1
- package/mcp-server/dist/services/neural-interface.d.ts +13 -0
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
- package/mcp-server/dist/services/neural-interface.js +34 -2
- package/mcp-server/dist/services/neural-interface.js.map +1 -1
- package/mcp-server/dist/services/typesafe-config.d.ts +1 -1
- package/mcp-server/dist/services/typesafe-config.d.ts.map +1 -1
- package/mcp-server/dist/services/typesafe-config.js +4 -1
- package/mcp-server/dist/services/typesafe-config.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +10 -7
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +34 -13
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/whatsapp-send-file.d.ts +17 -0
- package/mcp-server/dist/tools/whatsapp-send-file.d.ts.map +1 -0
- package/mcp-server/dist/tools/whatsapp-send-file.js +44 -0
- package/mcp-server/dist/tools/whatsapp-send-file.js.map +1 -0
- package/mcp-server/dist/tui.js +2 -1
- package/mcp-server/dist/tui.js.map +1 -1
- package/mcp-server/dist/version.d.ts +5 -0
- package/mcp-server/dist/version.d.ts.map +1 -0
- package/mcp-server/dist/version.js +21 -0
- package/mcp-server/dist/version.js.map +1 -0
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -3
- package/mcp-server/run.mjs +15 -9
- package/mcp-server/src/http.ts +18 -3
- package/mcp-server/src/index.ts +9 -6
- package/mcp-server/src/services/budget-judgments.ts +183 -0
- package/mcp-server/src/services/codex-config-heal.ts +35 -4
- package/mcp-server/src/services/identity.ts +27 -0
- package/mcp-server/src/services/neural-interface.ts +34 -2
- package/mcp-server/src/services/typesafe-config.ts +4 -1
- package/mcp-server/src/tools/agents.ts +33 -14
- package/mcp-server/src/tools/whatsapp-send-file.ts +51 -0
- package/mcp-server/src/tui.ts +2 -1
- package/mcp-server/src/version.ts +22 -0
- package/neural-interface/i18n/en.json +2126 -209
- package/neural-interface/i18n/pt-BR.json +2123 -207
- package/neural-interface/lib/account-usage.js +163 -0
- package/neural-interface/lib/assistant-api.js +316 -57
- package/neural-interface/lib/assistant-brains/claude.js +19 -2
- package/neural-interface/lib/assistant-brains/codex.js +3 -0
- package/neural-interface/lib/assistant-brains/opencode.js +17 -4
- package/neural-interface/lib/assistant-budget-planner.js +390 -0
- package/neural-interface/lib/assistant-budget-split.js +408 -0
- package/neural-interface/lib/assistant-budget.js +94 -95
- package/neural-interface/lib/assistant-catalog.js +179 -27
- package/neural-interface/lib/assistant-config.js +91 -14
- package/neural-interface/lib/assistant-dispatch.js +494 -138
- package/neural-interface/lib/assistant-hidden-models.js +393 -66
- package/neural-interface/lib/assistant-jev.js +26 -3
- package/neural-interface/lib/assistant-memory.js +24 -10
- package/neural-interface/lib/assistant-persona.js +73 -12
- package/neural-interface/lib/assistant-plan-permissions.js +8 -1
- package/neural-interface/lib/assistant-pricing.js +21 -6
- package/neural-interface/lib/assistant-route-accounts.js +14 -0
- package/neural-interface/lib/assistant-route-gate.js +19 -3
- package/neural-interface/lib/assistant-router.js +373 -42
- package/neural-interface/lib/assistant-runtime.js +488 -59
- package/neural-interface/lib/assistant-task-prompt.js +13 -3
- package/neural-interface/lib/assistant-test-density.js +142 -0
- package/neural-interface/lib/assistant-user-context-budgets.js +123 -0
- package/neural-interface/lib/assistant-user-context.js +908 -0
- package/neural-interface/lib/assistant-user-knowledge.js +328 -0
- package/neural-interface/lib/assistant-user-learn.js +404 -0
- package/neural-interface/lib/assistant-user-threads.js +226 -0
- package/neural-interface/lib/assistant-user-writer.js +183 -0
- package/neural-interface/lib/augmented-path.js +317 -53
- package/neural-interface/lib/browser-background-tab.js +134 -0
- package/neural-interface/lib/browser-screenshot.js +678 -61
- package/neural-interface/lib/claude-accounts.js +342 -31
- package/neural-interface/lib/claude-agent-bridge.js +123 -9
- package/neural-interface/lib/claude-executable.js +6 -1
- package/neural-interface/lib/claude-model-catalog.js +33 -5
- package/neural-interface/lib/claude-panel-auth.js +221 -0
- package/neural-interface/lib/claude-profile-api-key.js +62 -0
- package/neural-interface/lib/claude-temporary.js +46 -7
- package/neural-interface/lib/cli-install-api.js +137 -0
- package/neural-interface/lib/cli-install.js +797 -0
- package/neural-interface/lib/cli-path.js +130 -0
- package/neural-interface/lib/cli-resolver.js +744 -0
- package/neural-interface/lib/cli-update-planner.js +143 -7
- package/neural-interface/lib/cloudflared/install.js +533 -0
- package/neural-interface/lib/cloudflared/manager.js +545 -0
- package/neural-interface/lib/cloudflared/pins.js +115 -0
- package/neural-interface/lib/cloudflared/pins.json +63 -0
- package/neural-interface/lib/cloudflared/tunnel.js +265 -0
- package/neural-interface/lib/codex-account-auth.js +178 -0
- package/neural-interface/lib/codex-accounts.js +489 -0
- package/neural-interface/lib/codex-capabilities.js +2 -1
- package/neural-interface/lib/codex-compat-rpc.js +8 -2
- package/neural-interface/lib/codex-mcp-approvals.js +5 -1
- package/neural-interface/lib/codex-panel-auth.js +62 -0
- package/neural-interface/lib/codex-session-settings.js +1 -1
- package/neural-interface/lib/codex-settings-schema.js +120 -0
- package/neural-interface/lib/desktop/config.js +3 -0
- package/neural-interface/lib/editor-completion-endpoint.js +264 -0
- package/neural-interface/lib/editor-completion-opencode.js +436 -0
- package/neural-interface/lib/editor-completion.js +714 -0
- package/neural-interface/lib/editor-config.js +149 -0
- package/neural-interface/lib/editor-files-api.js +268 -0
- package/neural-interface/lib/editor-git-api.js +134 -0
- package/neural-interface/lib/file-explorer-api.js +1039 -0
- package/neural-interface/lib/file-explorer-system.js +355 -0
- package/neural-interface/lib/file-explorer-trash.ps1 +85 -0
- package/neural-interface/lib/file-explorer-watch.js +239 -0
- package/neural-interface/lib/git-bash/bzip2.js +339 -0
- package/neural-interface/lib/git-bash/claude-settings.js +73 -0
- package/neural-interface/lib/git-bash/extract-worker.js +34 -0
- package/neural-interface/lib/git-bash/install.js +529 -0
- package/neural-interface/lib/git-bash/licenses/COPYING +360 -0
- package/neural-interface/lib/git-bash/licenses/LGPL-2.1 +511 -0
- package/neural-interface/lib/git-bash/manager.js +268 -0
- package/neural-interface/lib/git-bash/pins.js +206 -0
- package/neural-interface/lib/git-bash/pins.json +34 -0
- package/neural-interface/lib/git-bash/resolver.js +194 -0
- package/neural-interface/lib/git-diff-api.js +103 -0
- package/neural-interface/lib/git-read.js +234 -0
- package/neural-interface/lib/greeting/api.js +89 -0
- package/neural-interface/lib/greeting/budgets.js +90 -0
- package/neural-interface/lib/greeting/engine.js +461 -0
- package/neural-interface/lib/greeting/facts.js +320 -0
- package/neural-interface/lib/greeting/sources.js +252 -0
- package/neural-interface/lib/greeting/writer.js +139 -0
- package/neural-interface/lib/http-guards.js +189 -13
- package/neural-interface/lib/install-details.js +145 -0
- package/neural-interface/lib/machine-names.js +88 -0
- package/neural-interface/lib/mcp-installer.js +14 -2
- package/neural-interface/lib/memory-api.js +31 -7
- package/neural-interface/lib/native-loop-providers.js +26 -8
- package/neural-interface/lib/native-loop-runtime.js +9 -4
- package/neural-interface/lib/os-path.js +319 -0
- package/neural-interface/lib/plugin-installer.js +4 -2
- package/neural-interface/lib/project-storage.js +5 -7
- package/neural-interface/lib/provider-panel-api-key-auth.js +92 -0
- package/neural-interface/lib/provider-panel-terminal-auth.js +95 -0
- package/neural-interface/lib/pty-host/core.js +2 -1
- package/neural-interface/lib/pty-host/manager.js +27 -2
- package/neural-interface/lib/remote-policy.js +20 -11
- package/neural-interface/lib/request-gate.js +589 -0
- package/neural-interface/lib/session-title-generator.js +4 -3
- package/neural-interface/lib/system-about.js +340 -0
- package/neural-interface/lib/system-activity.js +66 -0
- package/neural-interface/lib/terminal-env.js +11 -3
- package/neural-interface/lib/terminal-path.js +55 -0
- package/neural-interface/lib/ui-blob-api.js +108 -0
- package/neural-interface/lib/ui-blob-store.js +68 -0
- package/neural-interface/lib/virtual-socket.js +12 -1
- package/neural-interface/lib/whatsapp/baileys-adapter.js +165 -45
- package/neural-interface/lib/whatsapp/bridge.js +78 -34
- package/neural-interface/lib/whatsapp/commands.js +13 -14
- package/neural-interface/lib/whatsapp/config.js +134 -20
- package/neural-interface/lib/whatsapp/fake-baileys.js +99 -14
- package/neural-interface/lib/whatsapp/host-core.js +168 -35
- package/neural-interface/lib/whatsapp/inbound.js +5 -3
- package/neural-interface/lib/whatsapp/local-file.js +524 -0
- package/neural-interface/lib/whatsapp/manager.js +92 -32
- package/neural-interface/lib/whatsapp/paths.js +11 -1
- package/neural-interface/lib/whatsapp/protocol.js +65 -5
- package/neural-interface/lib/whatsapp/redact.js +63 -0
- package/neural-interface/lib/whatsapp/service.js +343 -91
- package/neural-interface/lib/whatsapp/transcription.js +463 -0
- package/neural-interface/package-lock.json +701 -2
- package/neural-interface/package.json +13 -2
- package/neural-interface/public/index.html +2 -0
- package/neural-interface/public/index2d.html +2 -0
- package/neural-interface/public/install-app.html +9 -6
- package/neural-interface/public/offline.html +19 -3
- package/neural-interface/public/onboarding.html +107 -2
- package/neural-interface/public/shared/account-i18n.js +7 -0
- package/neural-interface/public/shared/account-menu.js +539 -0
- package/neural-interface/public/shared/account-usage.js +19 -0
- package/neural-interface/public/shared/account-view.js +335 -0
- package/neural-interface/public/shared/agent-runtime-options.js +50 -14
- package/neural-interface/public/shared/assistant/asst-accounts.js +182 -184
- package/neural-interface/public/shared/assistant/asst-api.js +32 -2
- package/neural-interface/public/shared/assistant/asst-automation.js +286 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +430 -81
- package/neural-interface/public/shared/assistant/asst-budget.js +259 -303
- package/neural-interface/public/shared/assistant/asst-composer.js +11 -1
- package/neural-interface/public/shared/assistant/asst-mascot.js +140 -61
- package/neural-interface/public/shared/assistant/asst-menu.js +27 -11
- package/neural-interface/public/shared/assistant/asst-panel.js +198 -42
- package/neural-interface/public/shared/assistant/asst-render.js +197 -23
- package/neural-interface/public/shared/assistant/asst-route-models.js +108 -0
- package/neural-interface/public/shared/assistant/asst-route.js +95 -343
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +534 -0
- package/neural-interface/public/shared/assistant/asst-sanitize.js +8 -1
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +31 -9
- package/neural-interface/public/shared/assistant/asst-slash.js +1 -1
- package/neural-interface/public/shared/assistant/asst-state.js +186 -2
- package/neural-interface/public/shared/assistant/asst-styles.js +247 -11
- package/neural-interface/public/shared/blob-store.js +111 -22
- package/neural-interface/public/shared/cdx/cdx-commands.js +4 -1
- package/neural-interface/public/shared/cdx/cdx-features.js +22 -14
- package/neural-interface/public/shared/cdx/cdx-icons.js +2 -0
- package/neural-interface/public/shared/cdx/cdx-panel.js +80 -118
- package/neural-interface/public/shared/cdx/cdx-render.js +25 -89
- package/neural-interface/public/shared/cdx/cdx-settings.js +231 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +164 -107
- package/neural-interface/public/shared/cdx/cdx-tabs.js +348 -668
- package/neural-interface/public/shared/cdx/cdx-ws.js +2 -0
- package/neural-interface/public/shared/claude-account-view.js +3 -0
- package/neural-interface/public/shared/cli-install-view.js +392 -0
- package/neural-interface/public/shared/cli-status.js +282 -22
- package/neural-interface/public/shared/constants.js +6 -1
- package/neural-interface/public/shared/cp/cp-events.js +2 -1
- package/neural-interface/public/shared/cp/cp-rehydrate.js +2 -1
- package/neural-interface/public/shared/cp/cp-styles.js +61 -0
- package/neural-interface/public/shared/desktop-bridge.js +39 -0
- package/neural-interface/public/shared/desktop-titlebar-page.js +59 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +122 -0
- package/neural-interface/public/shared/desktop-titlebar.js +153 -0
- package/neural-interface/public/shared/desktop-update-view.js +462 -0
- package/neural-interface/public/shared/editor/editor-ai-logic.js +409 -0
- package/neural-interface/public/shared/editor/editor-ai.js +619 -0
- package/neural-interface/public/shared/editor/editor-commands.js +212 -0
- package/neural-interface/public/shared/editor/editor-compare.js +103 -0
- package/neural-interface/public/shared/editor/editor-completion-list.js +172 -0
- package/neural-interface/public/shared/editor/editor-doc.js +257 -0
- package/neural-interface/public/shared/editor/editor-git-logic.js +131 -0
- package/neural-interface/public/shared/editor/editor-git.js +95 -0
- package/neural-interface/public/shared/editor/editor-languages.js +156 -0
- package/neural-interface/public/shared/editor/editor-lint.js +229 -0
- package/neural-interface/public/shared/editor/editor-loader.js +51 -0
- package/neural-interface/public/shared/editor/editor-markdown.js +90 -0
- package/neural-interface/public/shared/editor/editor-menu.js +233 -0
- package/neural-interface/public/shared/editor/editor-minimap.js +371 -0
- package/neural-interface/public/shared/editor/editor-palette-logic.js +192 -0
- package/neural-interface/public/shared/editor/editor-palette.js +125 -0
- package/neural-interface/public/shared/editor/editor-panel-logic.js +288 -0
- package/neural-interface/public/shared/editor/editor-panel.js +2099 -0
- package/neural-interface/public/shared/editor/editor-prefs.js +224 -0
- package/neural-interface/public/shared/editor/editor-safety.js +500 -0
- package/neural-interface/public/shared/editor/editor-search.js +352 -0
- package/neural-interface/public/shared/editor/editor-statusbar.js +144 -0
- package/neural-interface/public/shared/editor/editor-tabs-logic.js +331 -0
- package/neural-interface/public/shared/editor/editor-tabs.js +233 -0
- package/neural-interface/public/shared/editor/editor-theme.js +244 -0
- package/neural-interface/public/shared/editor/editor-view.js +332 -0
- package/neural-interface/public/shared/explorer/fx-api.js +216 -0
- package/neural-interface/public/shared/explorer/fx-links.js +204 -0
- package/neural-interface/public/shared/explorer/fx-logic.js +537 -0
- package/neural-interface/public/shared/explorer/fx-main.js +865 -0
- package/neural-interface/public/shared/explorer/fx-names.js +87 -0
- package/neural-interface/public/shared/explorer/fx-ops.js +370 -0
- package/neural-interface/public/shared/explorer/fx-popups.js +490 -0
- package/neural-interface/public/shared/explorer/fx-tree.js +790 -0
- package/neural-interface/public/shared/file-links.js +339 -0
- package/neural-interface/public/shared/git-bash-view.js +145 -0
- package/neural-interface/public/shared/greeting/greeting-card.js +178 -0
- package/neural-interface/public/shared/greeting/greeting-view.js +148 -0
- package/neural-interface/public/shared/html-shell.js +161 -165
- package/neural-interface/public/shared/i18n.js +19 -1
- package/neural-interface/public/shared/install-details-view.js +86 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-greeting.js +47 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +131 -17
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +22 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +158 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +3 -2
- package/neural-interface/public/shared/pwa-install-page.js +32 -2
- package/neural-interface/public/shared/pwa-install.css +3 -3
- package/neural-interface/public/shared/pwa-install.js +100 -1
- package/neural-interface/public/shared/settings/settings-about-pane.js +271 -0
- package/neural-interface/public/shared/settings/settings-about.js +254 -0
- package/neural-interface/public/shared/settings/settings-code-editor-pane.js +412 -0
- package/neural-interface/public/shared/settings/settings-code-editor.js +328 -0
- package/neural-interface/public/shared/settings/settings-greeting.js +133 -0
- package/neural-interface/public/shared/settings/settings-ia.js +33 -4
- package/neural-interface/public/shared/settings/settings-user-context.js +154 -0
- package/neural-interface/public/shared/showcase-privacy.js +489 -0
- package/neural-interface/public/shared/start-bridge.js +238 -19
- package/neural-interface/public/shared/storage.js +30 -3
- package/neural-interface/public/shared/styles.css +1710 -770
- package/neural-interface/public/shared/synabun-mascot.js +68 -58
- package/neural-interface/public/shared/tunnel-view.js +167 -0
- package/neural-interface/public/shared/ui-claude-panel.js +369 -229
- package/neural-interface/public/shared/ui-cli-banner.js +355 -0
- package/neural-interface/public/shared/ui-detail.js +15 -0
- package/neural-interface/public/shared/ui-explorer.js +22 -0
- package/neural-interface/public/shared/ui-file-explorer.js +481 -2496
- package/neural-interface/public/shared/ui-file-links.js +103 -0
- package/neural-interface/public/shared/ui-git-bash.js +124 -0
- package/neural-interface/public/shared/ui-help.js +26 -0
- package/neural-interface/public/shared/ui-invite.js +126 -116
- package/neural-interface/public/shared/ui-judgments.js +10 -1
- package/neural-interface/public/shared/ui-keybinds.js +4 -0
- package/neural-interface/public/shared/ui-loading.js +187 -19
- package/neural-interface/public/shared/ui-menubar.js +25 -33
- package/neural-interface/public/shared/ui-native-loop-router-state.js +11 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +15 -2
- package/neural-interface/public/shared/ui-navbar.js +48 -22
- package/neural-interface/public/shared/ui-provider-auth.js +104 -0
- package/neural-interface/public/shared/ui-provider-terminal-auth.js +223 -0
- package/neural-interface/public/shared/ui-sessions.js +9 -3
- package/neural-interface/public/shared/ui-settings.js +509 -490
- package/neural-interface/public/shared/ui-sidepanel-runtime.js +2 -1
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -1
- package/neural-interface/public/shared/ui-sync.js +22 -0
- package/neural-interface/public/shared/ui-terminal.js +40 -5
- package/neural-interface/public/shared/ui-tool-updates.js +5 -0
- package/neural-interface/public/shared/ui-tunnel.js +130 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +6 -2
- package/neural-interface/public/shared/ui-update.js +594 -5
- package/neural-interface/public/shared/ui-whatsapp.js +21 -6
- package/neural-interface/public/shared/ui-whiteboard.js +12 -0
- package/neural-interface/public/shared/ui-worker-end.js +245 -0
- package/neural-interface/public/shared/ui-workspaces.js +41 -27
- package/neural-interface/public/shared/whatsapp/wa-view.js +51 -8
- package/neural-interface/public/shared/worker-end.js +253 -0
- package/neural-interface/public/sw.js +2 -2
- package/neural-interface/public/variant/2d/main.js +10 -1
- package/neural-interface/public/variant/3d/main.js +10 -1
- package/neural-interface/public/vendor/codemirror/chunks/apl-CSDKT72Z.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/asciiarmor-JYYPU5BM.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/asn1-NRWCZDA6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/asterisk-5OU6D4ZQ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/brainfuck-ID4N4SYC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-4RZWGCS2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-ACTJM3JR.js +11 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-S6BMAXLK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-TO2RDOHQ.js +3 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-US2GMZZQ.js +13 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-WYYO5ZAJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-XALZTDJC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-YRNUTRDV.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-Z3QOKH62.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/clike-OWQBSOGL.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/clojure-KV75UQWC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/cmake-GTEP5Y3C.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/cobol-WCZ7QEGJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/coffeescript-TGLBOT6B.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/commonlisp-WVVI432V.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/crystal-S6R6HLKQ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/css-PDA2RINP.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/cypher-HL5QPL4C.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/d-HHJH2HAJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/diff-MN3A35BY.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-25SQLBVS.js +3 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-27ZGGJJS.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-4E52OJIF.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-6FT73XDC.js +2 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-BE6YGRMW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-CJSGKW2O.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-CRPH2WLI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-CTG7JEQN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-I3FEVELX.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-IM5BBSWZ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-KERUKTIF.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-LXTMWZAM.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-MABASSET.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-MJVBUZLL.js +3 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-MNB3WZVU.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-QYWXOE3U.js +7 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-TEBOFWLZ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-UNXFROM3.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-XL2SLQO6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-XO42Y3AP.js +6 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-Y2WWDWJK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-YFEZKWMU.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-ZY7SWQO6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dockerfile-3Y4R4NCH.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dtd-5343GJ4P.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dylan-FI2CXSW2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ebnf-GNQ77YWA.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ecl-MRPUAE2L.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/eiffel-DZROES27.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/elm-4KICRFKQ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/erlang-3IHYC263.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/factor-C6D3E5UK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/fcl-VYTWUJMI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/forth-ZBO2EH5M.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/fortran-5NDCRWIK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/gas-SKRMOXFP.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/gherkin-L45YXZLW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/groovy-GLPTLN44.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/haskell-E7NF7P4Y.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/haxe-K2NVDOB6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/http-Q6DRQIJB.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/idl-MZYNJVLN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/javascript-6YRYK2HR.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/julia-HXEL2T5G.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/livescript-MV7CI2JZ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/lua-E36NHOOD.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mathematica-3XOZZCMC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mbox-ODYGFKS7.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mirc-WB43AWF5.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mllike-ZT6ET7ZH.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/modelica-LLMZPFGA.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mscgen-2OPNNYFH.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mumps-6P3HWJH6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/nginx-TCGKQTRW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/nsis-ATIGIXTJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ntriples-5PLBI5OV.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/octave-QF2S3NL6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/oz-JFIVFFH2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/pascal-JG6SW76V.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/perl-4B3IWVVO.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/pig-ABEBH4MI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/powershell-H32XE7TL.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/properties-NN644MMA.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/protobuf-YKWQK2J3.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/pug-RIYXEKFW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/puppet-JZQ5WPEV.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/python-EBCGGHAC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/q-5UMH2YQY.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/r-7XMGG453.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/rpm-IEV7TSLR.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ruby-T4SPFPNM.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sas-GEDX67ET.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/scheme-FTLOWKPC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/shell-HUFRKFSJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sieve-P5QUDVYO.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/smalltalk-2SORJNQI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/solr-M22TGAR5.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sparql-4M3KL752.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/spreadsheet-3K23LA4N.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sql-VHRFMUBI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/stex-QZDAQUY2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/stylus-7ZDKAKBD.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/swift-WCLCLGMR.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/tcl-JLMU6WOK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/textile-4CHDKZ4T.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/tiddlywiki-DKMCZZQ4.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/tiki-F4JIG36Q.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/toml-BHMHTIM2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/troff-YQ2KV5NT.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ttcn-ZHRCVFJY.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ttcn-cfg-KJOVTY4X.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/turtle-535P5N6I.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/vb-76UMQHOT.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/vbscript-CGNDTK6Z.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/velocity-VSJDO5T5.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/verilog-4T6ETXIP.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/vhdl-T7FNAXUN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/webidl-P6MJSJ6J.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/xquery-UOVILRGN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/yacas-CV2APROL.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/z80-3KFNVM4M.js +1 -0
- package/neural-interface/public/vendor/codemirror/codemirror-6.43.14-75f05e67.min.js +2 -0
- package/neural-interface/public/vendor/codemirror/manifest.json +60 -0
- package/neural-interface/scripts/build-vendor.mjs +78 -2
- package/neural-interface/scripts/vendor-codemirror-entry.js +121 -0
- package/neural-interface/server.js +2085 -1629
- package/neural-interface/templates/rulesets/README.md +1 -1
- package/package.json +5 -8
- package/setup.js +53 -15
- package/benchmarks/browser-live-results.json +0 -79
- package/benchmarks/browser-v2-results.json +0 -258
- package/neural-interface/lib/codex-capabilities.d.ts +0 -41
- package/neural-interface/public/category-logos/claude.svg +0 -1
- package/neural-interface/public/category-logos/gemini-color.svg +0 -1
- package/neural-interface/public/category-logos/openai.svg +0 -1
- package/neural-interface/public/category-logos/synabun.png +0 -0
- package/neural-interface/public/claude.svg +0 -1
- package/neural-interface/public/gallery.svg +0 -6
- package/neural-interface/public/leonardoai.svg +0 -1
- package/neural-interface/public/mcp.svg +0 -4
- package/neural-interface/public/opencode-logo-dark-square.svg +0 -1
- package/neural-interface/public/pin-svgrepo-com.svg +0 -25
- package/neural-interface/public/sessionicon.svg +0 -8
- package/neural-interface/public/toolbar-album.svg +0 -8
- package/neural-interface/public/toolbar-question.svg +0 -6
- package/neural-interface/public/toolbar-sessions.svg +0 -6
- package/neural-interface/scripts/codex-protocol-fixture.mjs +0 -83
- package/skills/synabun/synabunicon.png +0 -0
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import { mountMemoryMaintenance } from './ui-memory-maintenance.js';
|
|
2
2
|
import { buildJudgmentsTab, wireJudgmentsTab } from './ui-judgments.js';
|
|
3
3
|
import { buildWhatsAppTab, wireWhatsAppTab } from './ui-whatsapp.js';
|
|
4
|
+
import { buildCodeEditorTab, wireCodeEditorTab } from './settings/settings-code-editor-pane.js';
|
|
5
|
+
import { buildAboutTab, wireAboutTab } from './settings/settings-about-pane.js';
|
|
4
6
|
import { SETTINGS_GROUPS, SETTINGS_PAGES, DEFAULT_SETTINGS_PAGE, pageKeys, getSettingsPage, resolveSettingsTarget, homeOfControl } from './settings/settings-ia.js';
|
|
5
7
|
import * as kit from './settings/settings-kit.js';
|
|
6
8
|
import { RULES_HOST_LABELS, describeRulesHost, describeRulesInstall, describeRulesInstallAll } from './settings/settings-rules.js';
|
|
9
|
+
import { readUserContextResponse, describeUserContext, describeUserContextSaveFailure } from './settings/settings-user-context.js';
|
|
10
|
+
import { readGreetingStatus, describeGreeting, describeGreetingSaveFailure } from './settings/settings-greeting.js';
|
|
11
|
+
import { renderGreeting, clearGreeting } from './greeting/greeting-card.js';
|
|
12
|
+
import { createTunnelCard, drawInto, mcpKeyNeededText, readTunnel } from './ui-tunnel.js';
|
|
13
|
+
import { remoteMcpAddress } from './tunnel-view.js';
|
|
14
|
+
import { recheckCliStatus, getCliStatus, addCliToPath } from './cli-status.js';
|
|
15
|
+
import { cliInstallText, setCliInstallTranslator } from './cli-install-view.js';
|
|
16
|
+
setCliInstallTranslator((key, params) => kit.tx(`cliInstall.${key}`, params));
|
|
17
|
+
import { setGitBashTranslator } from './git-bash-view.js';
|
|
18
|
+
import { gitBashRowHtml, wireGitBashRow } from './ui-git-bash.js';
|
|
19
|
+
setGitBashTranslator((key, params) => kit.tx(`gitBash.${key}`, params));
|
|
7
20
|
import { initI18n, isReady as i18nReady, SUPPORTED_LOCALES, LOCALE_NAMES, SYSTEM_LOCALE, getLocale, getLocaleChoice, setLocaleChoice, getSystemLocale, englishTranslator, loadEnglishTranslator } from './i18n.js';
|
|
8
21
|
import { wireSettingsShell, wireSettingsSearch, collectSearchRows, revealSettingsTarget, followSettingsTarget, onSettingsTakeover, applyStoredSections, storeSectionState } from './settings/settings-shell.js';
|
|
9
22
|
import { buildSettingsSearchIndex } from './settings/settings-search.js';
|
|
@@ -12,7 +25,7 @@ import { buildSettingsSearchIndex } from './settings/settings-search.js';
|
|
|
12
25
|
// ═══════════════════════════════════════════
|
|
13
26
|
//
|
|
14
27
|
// The most complex shared UI module. Builds a floating settings panel with
|
|
15
|
-
//
|
|
28
|
+
// thirteen task pages in six groups (./settings/settings-ia.js). A page is a
|
|
16
29
|
// title, a one-line purpose and section cards (./settings/settings-kit.js);
|
|
17
30
|
// each builder below owns one pane of a page. Variant-registered tabs (the 2D
|
|
18
31
|
// Graphics tab) join the Appearance page. Old tab ids still open the right page.
|
|
@@ -62,6 +75,8 @@ const TAB_ICONS = {
|
|
|
62
75
|
discord: '<svg viewBox="0 0 24 24"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></svg>',
|
|
63
76
|
whatsapp: '<svg viewBox="0 0 24 24"><path d="M3.5 20.5l1.3-3.9A8.5 8.5 0 1 1 8 19.6z"/><path d="M9.5 8.5c.4 2.6 2.9 5.2 5.5 5.6l1-1.2 1.6.8c-.3 1-1.1 1.6-2.1 1.5-2.9-.3-5.8-3.2-6.1-6.1-.1-1 .5-1.8 1.5-2.1l.8 1.6z"/></svg>',
|
|
64
77
|
morelogin: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><path d="M12 11.5a1 1 0 0 0-1 1c0 1.8-.3 3.6-1.2 5.2"/><path d="M7.8 14.5a8 8 0 0 0-.6 4.3"/><path d="M12 7.5a4.5 4.5 0 0 1 4.5 4.5c0 .6 0 1.2-.1 1.8"/><path d="M5 9.2a7 7 0 0 1 11-1.9"/><path d="M15 13a3 3 0 0 1-3 3"/></svg>',
|
|
78
|
+
editor: '<svg viewBox="0 0 24 24"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/><line x1="13.5" y1="5" x2="10.5" y2="19"/></svg>',
|
|
79
|
+
about: '<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="11"/><line x1="12" y1="7.5" x2="12.01" y2="7.5"/></svg>',
|
|
65
80
|
};
|
|
66
81
|
|
|
67
82
|
// ── Shared icon constants ──
|
|
@@ -1098,6 +1113,7 @@ function buildTerminalTab(cliConfig) {
|
|
|
1098
1113
|
<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
|
1099
1114
|
${kit.L('CLI002')}
|
|
1100
1115
|
</button>
|
|
1116
|
+
${p.id === 'gemini' ? '' : `<button type="button" class="cli-detect-btn" data-cli-add-path="${p.id}" hidden>${escapeHtml(cliInstallText('addPath'))}</button>`}
|
|
1101
1117
|
<span class="cli-path-status${isDefault ? '' : ' custom'}" id="cli-status-${p.id}" ${kit.inv('CLI007')}>${kit.te(isDefault ? 'settings.redesign.terminal.cliStatus.default' : 'settings.redesign.terminal.cliStatus.custom')}</span>
|
|
1102
1118
|
</div>
|
|
1103
1119
|
<div class="stg-help" id="cli-path-${p.id}-help">${kit.H(p.inv)}</div>
|
|
@@ -1122,9 +1138,11 @@ function buildTerminalTab(cliConfig) {
|
|
|
1122
1138
|
<p class="stg-help">${kit.th('settings.redesign.terminal.pathsIntro', { code: '<code class="stg-code">wsl</code>' })}</p>
|
|
1123
1139
|
${kit.help('CLI002', { forId: 'cli-paths-detect' })}
|
|
1124
1140
|
${cliProfiles.map(pathRow).join('')}
|
|
1141
|
+
${gitBashRowHtml()}
|
|
1125
1142
|
<button type="button" class="stg-action-btn stg-save-btn" id="cli-paths-save" ${kit.inv('CLI006')} aria-describedby="cli-paths-save-help">
|
|
1126
1143
|
${kit.L('CLI006')}
|
|
1127
1144
|
</button>
|
|
1145
|
+
<button type="button" class="cli-detect-btn" id="cli-path-diagnostics">${escapeHtml(cliInstallText('copyPathDiagnostics'))}</button>
|
|
1128
1146
|
${kit.help('CLI006', { forId: 'cli-paths-save' })}
|
|
1129
1147
|
|
|
1130
1148
|
${kit.subhead(kit.te('settings.redesign.terminal.examples'))}
|
|
@@ -1721,7 +1739,163 @@ function buildPermissionsTab(toolCategories, toolPermissions) {
|
|
|
1721
1739
|
</div>`;
|
|
1722
1740
|
}
|
|
1723
1741
|
|
|
1724
|
-
|
|
1742
|
+
// ── Automation behavior: the Assistant's user context ──
|
|
1743
|
+
// settings/settings-user-context.js reads the server's answer and decides what is true; these draw it. The
|
|
1744
|
+
// same markup is built with the page and redrawn after a save, so a state never looks different the second time.
|
|
1745
|
+
|
|
1746
|
+
/** What GET /api/assistant/user-context answered, as a reading (never throws: no answer is a reading too). */
|
|
1747
|
+
// ── The greeting (Settings → Automations → Greeting) ──
|
|
1748
|
+
// settings/settings-greeting.js reads the server's answers and decides what is true; these ask and draw.
|
|
1749
|
+
async function loadGreetingReading() {
|
|
1750
|
+
try {
|
|
1751
|
+
const res = await fetch('/api/greeting');
|
|
1752
|
+
const body = await res.json().catch(() => null);
|
|
1753
|
+
return readGreetingStatus({ status: res.status, body });
|
|
1754
|
+
} catch (err) {
|
|
1755
|
+
return readGreetingStatus({ status: 0, error: err?.message });
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
/** What a new session would open with right now. `write`: ask the writer for the sentence now (one small call). */
|
|
1760
|
+
async function fetchGreetingPreview({ write = false } = {}) {
|
|
1761
|
+
try {
|
|
1762
|
+
const res = await fetch('/api/greeting/preview', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(write ? { write: true } : {}) });
|
|
1763
|
+
const body = await res.json().catch(() => null);
|
|
1764
|
+
if (res.ok && body?.ok === true && body.preview && typeof body.preview === 'object') return body.preview;
|
|
1765
|
+
return { failed: String(body?.reason || body?.error || `HTTP ${res.status}`) };
|
|
1766
|
+
} catch (err) {
|
|
1767
|
+
return { failed: err?.message || 'no answer' };
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
/** The section after an answer: the note, the switch, what stands in its way, and the preview (the card every panel shows). */
|
|
1772
|
+
function drawGreetingSection(overlay, view) {
|
|
1773
|
+
const q = (selector) => overlay.querySelector(selector);
|
|
1774
|
+
const note = q('#gr-status-note');
|
|
1775
|
+
if (note) { note.hidden = !view.note; note.textContent = view.note ? view.note.text : ''; note.dataset.grState = view.state; }
|
|
1776
|
+
const row = q('[data-gr-row]');
|
|
1777
|
+
if (row) { row.classList.toggle('enabled', view.on); row.classList.toggle('uc-disabled', view.disabled); }
|
|
1778
|
+
const toggle = q('[data-gr-toggle]');
|
|
1779
|
+
if (toggle) { toggle.classList.toggle('on', view.on); toggle.setAttribute('aria-pressed', view.on ? 'true' : 'false'); toggle.disabled = view.disabled; }
|
|
1780
|
+
const notes = q('#gr-notes');
|
|
1781
|
+
if (notes) notes.innerHTML = userContextNotesHTML(view.notes);
|
|
1782
|
+
const box = q('#gr-preview');
|
|
1783
|
+
if (!box) return;
|
|
1784
|
+
const preview = view.preview;
|
|
1785
|
+
box.hidden = !preview.shown;
|
|
1786
|
+
box.dataset.grPreviewState = preview.state;
|
|
1787
|
+
const project = q('#gr-preview-project');
|
|
1788
|
+
if (project) project.textContent = preview.project;
|
|
1789
|
+
const lead = q('#gr-preview-lead');
|
|
1790
|
+
if (lead) { lead.textContent = preview.lead || preview.empty; lead.hidden = !(preview.lead || preview.empty); }
|
|
1791
|
+
const card = q('#gr-preview-card');
|
|
1792
|
+
if (card) {
|
|
1793
|
+
if (preview.greeting) renderGreeting(card, preview.greeting, { t: kit.tx, onOpenMemory: (id) => { if (id) emit('memory:open', { id }); } });
|
|
1794
|
+
else clearGreeting(card);
|
|
1795
|
+
}
|
|
1796
|
+
const spend = q('#gr-preview-spend');
|
|
1797
|
+
if (spend) { spend.textContent = preview.spend; spend.hidden = !preview.spend; }
|
|
1798
|
+
const write = q('#gr-write');
|
|
1799
|
+
if (write) write.hidden = !preview.canWrite;
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
async function loadUserContextReading() {
|
|
1803
|
+
try {
|
|
1804
|
+
const res = await fetch('/api/assistant/user-context');
|
|
1805
|
+
const body = await res.json().catch(() => null);
|
|
1806
|
+
return readUserContextResponse({ status: res.status, body });
|
|
1807
|
+
} catch (err) {
|
|
1808
|
+
return readUserContextResponse({ status: 0, error: err?.message });
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
/** What stands in the way of a layer: one line each, with the Settings page that fixes it when there is one. */
|
|
1813
|
+
const userContextNotesHTML = (notes = []) => notes.map(note => `<div class="uc-layer-note" data-tone="${note.tone === 'warn' ? 'warn' : 'info'}">${kit.esc(note.text)}${
|
|
1814
|
+
note.link ? ` <button type="button" class="cc-copy-btn stg-text-btn uc-note-link" data-uc-goto="${kit.esc(JSON.stringify(note.link.target))}">${kit.esc(note.link.label)}</button>` : ''
|
|
1815
|
+
}</div>`).join('');
|
|
1816
|
+
|
|
1817
|
+
/** The digest's lines, or the one sentence that stands in for them (nothing known yet, the layer is off). */
|
|
1818
|
+
const userContextDigestHTML = (digest) => (digest.rows.length
|
|
1819
|
+
? digest.rows.map(row => `<button type="button" class="uc-digest-row" role="listitem" data-uc-memory="${kit.esc(row.id)}" title="${kit.te('settings.redesign.hooks.uc.openMemory')}"><span class="uc-digest-statement">${kit.esc(row.statement)}</span><span class="uc-digest-facet">${kit.esc(row.facet)}${row.seed ? ` · ${kit.te('settings.redesign.hooks.uc.seed')}` : ''}</span></button>`).join('')
|
|
1820
|
+
: `<div class="stg-help uc-digest-message" role="listitem" style="margin:0">${kit.esc(digest.message)}</div>`);
|
|
1821
|
+
|
|
1822
|
+
/** Put a view (describeUserContext) on the section: the note, each switch and its notes, the digest. */
|
|
1823
|
+
function drawUserContext(overlay, view) {
|
|
1824
|
+
const section = overlay.querySelector('#stg-sec-automation-behavior');
|
|
1825
|
+
if (!section) return;
|
|
1826
|
+
const note = section.querySelector('#uc-status-note');
|
|
1827
|
+
if (note) { note.hidden = !view.note; note.textContent = view.note?.text || ''; note.dataset.ucState = view.state; }
|
|
1828
|
+
const layers = section.querySelector('#uc-layers');
|
|
1829
|
+
if (layers) { layers.dataset.ucReady = view.ready ? '1' : '0'; layers.dataset.ucState = view.state; }
|
|
1830
|
+
for (const [key, row] of Object.entries(view.layers)) {
|
|
1831
|
+
const toggle = section.querySelector(`.cc-toggle[data-uc-layer="${key}"]`);
|
|
1832
|
+
if (!toggle) continue;
|
|
1833
|
+
toggle.classList.toggle('on', row.on);
|
|
1834
|
+
toggle.setAttribute('aria-pressed', row.on ? 'true' : 'false');
|
|
1835
|
+
toggle.disabled = row.disabled;
|
|
1836
|
+
toggle.setAttribute('aria-describedby', `uc-layer-${key}-help uc-layer-${key}-notes${view.note ? ' uc-status-note' : ''}`);
|
|
1837
|
+
const item = toggle.closest('.cc-integration-item');
|
|
1838
|
+
item?.classList.toggle('enabled', row.on);
|
|
1839
|
+
item?.classList.toggle('uc-disabled', row.disabled);
|
|
1840
|
+
const notes = section.querySelector(`#uc-layer-${key}-notes`);
|
|
1841
|
+
if (notes) notes.innerHTML = userContextNotesHTML(row.notes);
|
|
1842
|
+
}
|
|
1843
|
+
const applies = section.querySelector('#uc-applies');
|
|
1844
|
+
if (applies) { applies.hidden = !view.applies; applies.textContent = view.applies; }
|
|
1845
|
+
const digest = section.querySelector('#uc-digest');
|
|
1846
|
+
if (digest) {
|
|
1847
|
+
digest.hidden = !view.digest.shown;
|
|
1848
|
+
digest.dataset.ucDigestState = view.digest.state;
|
|
1849
|
+
const count = digest.querySelector('#uc-digest-count');
|
|
1850
|
+
if (count) count.textContent = view.digest.count;
|
|
1851
|
+
const rows = digest.querySelector('#uc-digest-rows');
|
|
1852
|
+
if (rows) rows.innerHTML = view.digest.shown ? userContextDigestHTML(view.digest) : '';
|
|
1853
|
+
const more = digest.querySelector('#uc-digest-more');
|
|
1854
|
+
if (more) { more.hidden = !view.digest.omitted; more.textContent = view.digest.omitted; }
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
/**
|
|
1859
|
+
* Does the server that answered refuse MCP from outside while no access key is set? One that brings its own
|
|
1860
|
+
* tunnel program does (lib/request-gate.js mcpWithoutKey); one started before that change, still running until
|
|
1861
|
+
* it is restarted, leaves the endpoint open to whoever has the address. Its tunnel status tells the two apart,
|
|
1862
|
+
* and the words about a missing key say what is true for the server that is running.
|
|
1863
|
+
*/
|
|
1864
|
+
function closesKeylessMcp(tunnelStatus) {
|
|
1865
|
+
return !!tunnelStatus?.cloudflared;
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
/**
|
|
1869
|
+
* Settings → Automations → Online access, the tunnel, for a reading of tunnel-view.js (the same reading the Share
|
|
1870
|
+
* menu draws). Two pieces, each drawn again by itself when the reading changes: the row (the state as a word
|
|
1871
|
+
* with its dot, the address while one is up, the switch), and what belongs under it (a download's progress; the
|
|
1872
|
+
* sentence about the state; after a failure its reason and a way to try again; for a running tunnel the remote
|
|
1873
|
+
* MCP address to copy, or what is missing for one, an access key, and which cloudflared runs).
|
|
1874
|
+
*/
|
|
1875
|
+
function tunnelRowHtml(view) {
|
|
1876
|
+
const tone = { ok: 'ok', busy: 'busy', err: 'err', warn: 'warn' }[view.tone] || '';
|
|
1877
|
+
return `
|
|
1878
|
+
<div class="cc-integration-info">
|
|
1879
|
+
<div class="cc-integration-label" id="cc-tunnel-label"><span class="stg-pill"${tone ? ` data-state="${tone}"` : ''} role="status">${escapeHtml(view.label)}${view.progress ? ` · ${escapeHtml(view.progress.text)}` : ''}</span></div>
|
|
1880
|
+
${view.kind === 'running' ? `<div class="cc-integration-path" id="cc-tunnel-url">${escapeHtml(view.url)}</div>` : ''}
|
|
1881
|
+
</div>
|
|
1882
|
+
${view.action ? `<button type="button" class="cc-toggle${view.on ? ' on' : ''}" id="cc-tunnel-toggle" role="switch" aria-checked="${view.on ? 'true' : 'false'}" ${kit.inv('AUT049')} aria-label="${kit.L('AUT049')}" title="${escapeHtml(view.actionLabel)}"></button>` : ''}`;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
function tunnelExtraHtml(view, mcpKeyInfo) {
|
|
1886
|
+
const running = view.kind === 'running';
|
|
1887
|
+
const address = running ? remoteMcpAddress(view.url, mcpKeyInfo?.key) : null;
|
|
1888
|
+
return [
|
|
1889
|
+
view.progress ? `<div class="stg-tunnel-progress" role="progressbar" aria-label="${escapeHtml(view.label)}" aria-valuemin="0" aria-valuemax="100" aria-valuenow="${view.progress.percent}"><span style="width:${view.progress.percent}%"></span></div>` : '',
|
|
1890
|
+
!running && view.detail ? `<div class="stg-help" id="cc-tunnel-detail"${view.kind === 'failed' ? ' role="alert"' : ''}>${escapeHtml(view.detail)}</div>` : '',
|
|
1891
|
+
view.kind === 'failed' ? `<button type="button" class="cc-copy-btn" id="cc-tunnel-retry">${escapeHtml(view.actionLabel)}</button>` : '',
|
|
1892
|
+
address ? `<button type="button" class="cc-copy-btn" id="cc-tunnel-copy-url" ${kit.inv('AUT050')} title="${kit.H('AUT050')}">${COPY_ICON} ${kit.te('settings.redesign.hooks.copyMcpUrl')}</button>` : '',
|
|
1893
|
+
running && !address ? `<div class="stg-help" id="cc-tunnel-key-needed">${escapeHtml(mcpKeyNeededText())}</div>` : '',
|
|
1894
|
+
running && view.copy ? `<div class="stg-help" id="cc-tunnel-copy">${escapeHtml(view.copy)}${view.copyNote ? ` ${escapeHtml(view.copyNote)}` : ''}</div>` : '',
|
|
1895
|
+
].filter(Boolean).join('');
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
function buildConnectionsTab(ccIntegrations, ccSkills, tunnelStatus, mcpKeyInfo, openclawBridge, greeting, toolPermissions, toolCategories, userContext = null) {
|
|
1725
1899
|
const gh = ccIntegrations.global.hooks || {};
|
|
1726
1900
|
const ssOn = !!gh.SessionStart;
|
|
1727
1901
|
const psOn = !!gh.UserPromptSubmit;
|
|
@@ -1733,7 +1907,6 @@ function buildConnectionsTab(ccIntegrations, ccSkills, tunnelStatus, mcpKeyInfo,
|
|
|
1733
1907
|
const subStopOn = !!gh.SubagentStop;
|
|
1734
1908
|
const hf = ccIntegrations.hookFeatures || {};
|
|
1735
1909
|
const cmOn = hf.conversationMemory !== false;
|
|
1736
|
-
const grOn = hf.greeting === true;
|
|
1737
1910
|
const ulOn = hf.userLearning !== false;
|
|
1738
1911
|
const ulThreshold = hf.userLearningThreshold || 8;
|
|
1739
1912
|
const ulMaxNudges = hf.userLearningMaxNudges || 3;
|
|
@@ -1766,7 +1939,7 @@ function buildConnectionsTab(ccIntegrations, ccSkills, tunnelStatus, mcpKeyInfo,
|
|
|
1766
1939
|
{ label: 'Gemini Web', on: false },
|
|
1767
1940
|
];
|
|
1768
1941
|
const openaiItems = [
|
|
1769
|
-
{ label: 'Codex CLI', on:
|
|
1942
|
+
{ label: 'Codex CLI', on: compat.codex !== false },
|
|
1770
1943
|
{ label: 'Cursor', on: false },
|
|
1771
1944
|
{ label: 'ChatGPT Web', on: false },
|
|
1772
1945
|
];
|
|
@@ -1797,91 +1970,35 @@ function buildConnectionsTab(ccIntegrations, ccSkills, tunnelStatus, mcpKeyInfo,
|
|
|
1797
1970
|
</div>`;
|
|
1798
1971
|
};
|
|
1799
1972
|
|
|
1800
|
-
//
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
<span class="cc-greeting-drag-handle" title="${h('dragToReorder')}">⋮⋮</span>
|
|
1814
|
-
<input class="cc-greeting-reminder-input label" placeholder="${h('label')}" aria-label="${h('label')}" value="${escapeHtml(reminder.label || '')}">
|
|
1815
|
-
<input class="cc-greeting-reminder-input cmd" placeholder="${h('command')}" aria-label="${h('command')}" value="${escapeHtml(reminder.command || '')}">
|
|
1816
|
-
<button type="button" class="cc-greeting-reminder-remove" title="${h('remove')}" aria-label="${h('remove')}">×</button>
|
|
1817
|
-
</div>`;
|
|
1818
|
-
const remindersHTML = (firstCfg.reminders || []).map(buildReminderRow).join('');
|
|
1819
|
-
const variable = (name, id) => `<tr><td><code>{${name}}</code></td><td id="${prefix}-cs-${id}"></td></tr>`;
|
|
1820
|
-
|
|
1821
|
-
return kit.card({
|
|
1822
|
-
id: `${prefix}-greeting-config`, level: 'h4', collapsible: true, collapsed: true,
|
|
1823
|
-
title: h(`greeting.title.${kind}`), purpose: h(`greeting.purpose.${kind}`),
|
|
1824
|
-
status: `<button type="button" class="cc-toggle${enabled ? ' on' : ''}" ${toggleAttrs} ${kit.inv(idToggle)} aria-label="${kit.L(idToggle)}" title="${kit.H(idToggle)}"></button>`,
|
|
1825
|
-
body: `
|
|
1826
|
-
<div id="${bodyId}" style="display:${enabled ? 'block' : 'none'}">
|
|
1827
|
-
<div class="stg-field" ${kit.inv(idProject)}>
|
|
1828
|
-
<label id="${prefix}-greeting-project-caption">${kit.L(idProject)}</label>
|
|
1829
|
-
<div class="cc-dropdown" id="${prefix}-greeting-project-dropdown" role="group" aria-labelledby="${prefix}-greeting-project-caption">
|
|
1830
|
-
<button class="cc-dropdown-trigger" type="button" aria-haspopup="listbox" aria-describedby="${prefix}-greeting-project-help">
|
|
1831
|
-
<span class="cc-dropdown-value" id="${prefix}-greeting-project-label">${projectLabel(firstKey)}</span>
|
|
1832
|
-
<svg class="cc-dropdown-arrow" viewBox="0 0 24 24" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>
|
|
1833
|
-
</button>
|
|
1834
|
-
<div class="cc-dropdown-menu" id="${prefix}-greeting-project-menu">
|
|
1835
|
-
${projectKeys.map((key) => `<div class="cc-dropdown-item${key === firstKey ? ' active' : ''}" data-value="${key}">${projectLabel(key)}</div>`).join('')}
|
|
1836
|
-
</div>
|
|
1837
|
-
<input type="hidden" id="${prefix}-greeting-project" value="${firstKey}">
|
|
1838
|
-
</div>
|
|
1839
|
-
<div class="stg-help" id="${prefix}-greeting-project-help">${kit.H(idProject)}</div>
|
|
1840
|
-
</div>
|
|
1841
|
-
<div class="cc-greeting-field stg-field" ${kit.inv(idTemplate)}>
|
|
1842
|
-
<label class="cc-greeting-label" for="${prefix}-greeting-template">${kit.L(idTemplate)}</label>
|
|
1843
|
-
<textarea class="cc-greeting-textarea" id="${prefix}-greeting-template" placeholder="${h('greeting.templatePlaceholder')}" aria-describedby="${prefix}-greeting-template-help">${escapeHtml(firstCfg.greetingTemplate || '')}</textarea>
|
|
1844
|
-
<div class="stg-help" id="${prefix}-greeting-template-help">${kit.H(idTemplate)}</div>
|
|
1845
|
-
<div class="cc-greeting-cheatsheet-toggle" id="${prefix}-greeting-cheatsheet-toggle" ${kit.inv('AUT047')} role="button" tabindex="0">
|
|
1846
|
-
<svg viewBox="0 0 24 24" aria-hidden="true" style="width:11px;height:11px;fill:none;stroke:currentColor;stroke-width:2;vertical-align:-1px"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
|
|
1847
|
-
${kit.L('AUT047')}
|
|
1848
|
-
</div>
|
|
1849
|
-
<div class="cc-greeting-cheatsheet" id="${prefix}-greeting-cheatsheet" style="display:none">
|
|
1850
|
-
<table class="cc-cheatsheet-table">
|
|
1851
|
-
<thead><tr><th>${h('greeting.placeholder')}</th><th>${h('greeting.showsAs')}</th></tr></thead>
|
|
1852
|
-
<tbody>
|
|
1853
|
-
${variable('time_greeting', 'time')}
|
|
1854
|
-
${variable('project_label', 'label')}
|
|
1855
|
-
${variable('project_name', 'name')}
|
|
1856
|
-
${variable('branch', 'branch')}
|
|
1857
|
-
${variable('date', 'date')}
|
|
1858
|
-
</tbody>
|
|
1859
|
-
</table>
|
|
1860
|
-
<div class="cc-cheatsheet-example">
|
|
1861
|
-
<div class="cc-greeting-label" style="margin-bottom:3px">${h('greeting.example')}</div>
|
|
1862
|
-
<div class="cc-cheatsheet-preview" id="${prefix}-cs-preview"></div>
|
|
1973
|
+
// The greeting (lib/greeting/): one switch for every agent, and what a new session would open with right now.
|
|
1974
|
+
// `greeting` is the view of what the server answered (describeGreeting). Without the engine (a server started
|
|
1975
|
+
// before it existed, one where it did not start, no answer) the switch shows off and disabled under a line
|
|
1976
|
+
// that says which of those it is. The preview is filled in once Settings is open (drawGreetingSection).
|
|
1977
|
+
const gr = greeting || describeGreeting(null, null, { tx: kit.tx });
|
|
1978
|
+
const greetingBlock = `
|
|
1979
|
+
<div class="stg-help uc-status-note" id="gr-status-note" role="status" data-gr-state="${gr.state}" data-stg-data${gr.note ? '' : ' hidden'}>${gr.note ? kit.esc(gr.note.text) : ''}</div>
|
|
1980
|
+
<div class="cc-hook-toggles" id="gr-switch" data-gr-ready="${gr.ready ? '1' : '0'}">
|
|
1981
|
+
<div class="cc-integration-item${gr.on ? ' enabled' : ''}${gr.disabled ? ' uc-disabled' : ''}" data-gr-row>
|
|
1982
|
+
<div class="cc-integration-info">
|
|
1983
|
+
<div class="cc-integration-label" id="gr-enabled-label">${kit.L('AUT058')}</div>
|
|
1984
|
+
<div class="cc-integration-path" id="gr-enabled-help">${kit.H('AUT058')}</div>
|
|
1985
|
+
<div class="uc-layer-notes" id="gr-notes" data-stg-data>${userContextNotesHTML(gr.notes)}</div>
|
|
1863
1986
|
</div>
|
|
1987
|
+
<button type="button" class="cc-toggle${gr.on ? ' on' : ''}" data-gr-toggle ${kit.inv('AUT058')} aria-pressed="${gr.on ? 'true' : 'false'}" aria-labelledby="gr-enabled-label" aria-describedby="gr-enabled-help gr-notes gr-status-note"${gr.disabled ? ' disabled' : ''}></button>
|
|
1864
1988
|
</div>
|
|
1989
|
+
</div>
|
|
1990
|
+
<div class="stg-help uc-save-status" id="gr-save-status" role="alert" data-stg-data hidden></div>
|
|
1991
|
+
<div class="uc-digest gr-preview" id="gr-preview" data-gr-preview-state="${gr.preview.state}" ${kit.inv('AUT059')}${gr.preview.shown ? '' : ' hidden'}>
|
|
1992
|
+
<div class="uc-digest-head">
|
|
1993
|
+
<span class="uc-digest-title" id="gr-preview-title">${kit.L('AUT059')}</span>
|
|
1994
|
+
<span class="uc-digest-count" id="gr-preview-project" data-stg-data>${kit.esc(gr.preview.project)}</span>
|
|
1865
1995
|
</div>
|
|
1866
|
-
<div class="
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
</div>
|
|
1870
|
-
<
|
|
1871
|
-
|
|
1872
|
-
<div class="cc-greeting-reminder-list" id="${prefix}-greeting-reminders" role="group" aria-labelledby="${prefix}-greeting-reminders-label">${remindersHTML}</div>
|
|
1873
|
-
<div class="stg-help">${h('greeting.remindersHelp')}</div>
|
|
1874
|
-
<button type="button" class="conn-add-btn" id="${prefix}-greeting-add-reminder" ${kit.inv(idAdd)} title="${kit.H(idAdd)}" style="margin-top:6px">
|
|
1875
|
-
<svg viewBox="0 0 24 24" aria-hidden="true"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
|
1876
|
-
${kit.L(idAdd)}
|
|
1877
|
-
</button>
|
|
1878
|
-
</div>
|
|
1879
|
-
<button type="button" class="conn-add-btn stg-save-btn" id="${prefix}-greeting-save" ${kit.inv(idSave)} title="${kit.H(idSave)}" style="width:100%;margin-top:4px;border-style:solid;background:rgba(79,195,247,0.08);border-color:rgba(79,195,247,0.25);color:rgba(79,195,247,0.9)">
|
|
1880
|
-
${kit.L(idSave)}
|
|
1881
|
-
</button>
|
|
1882
|
-
</div>`,
|
|
1883
|
-
});
|
|
1884
|
-
}
|
|
1996
|
+
<div class="stg-help gr-preview-help" style="margin:2px 0 0">${kit.H('AUT059')}</div>
|
|
1997
|
+
<div class="stg-help gr-preview-lead" id="gr-preview-lead" role="status" data-stg-data>${kit.esc(gr.preview.lead || gr.preview.empty)}</div>
|
|
1998
|
+
<div class="gr-preview-card" id="gr-preview-card" data-stg-data></div>
|
|
1999
|
+
<div class="stg-help gr-preview-spend" id="gr-preview-spend" data-stg-data${gr.preview.spend ? '' : ' hidden'}>${kit.esc(gr.preview.spend)}</div>
|
|
2000
|
+
<button type="button" class="conn-add-btn" id="gr-write" ${kit.inv('AUT060')} title="${kit.H('AUT060')}" style="margin:0;width:auto;padding:4px 10px;border-style:solid"${gr.preview.canWrite ? '' : ' hidden'}>${kit.L('AUT060')}</button>
|
|
2001
|
+
</div>`;
|
|
1885
2002
|
|
|
1886
2003
|
const feature = (invId, key, on, extra = '') => `
|
|
1887
2004
|
<div class="cc-integration-item${on ? ' enabled' : ''}" data-feature="${key}">
|
|
@@ -1892,26 +2009,65 @@ function buildConnectionsTab(ccIntegrations, ccSkills, tunnelStatus, mcpKeyInfo,
|
|
|
1892
2009
|
<button type="button" class="cc-toggle${on ? ' on' : ''}" data-cc-feature="${key}" ${kit.inv(invId)} aria-labelledby="cc-feature-${key}-label" aria-describedby="cc-feature-${key}-help"></button>
|
|
1893
2010
|
</div>`;
|
|
1894
2011
|
|
|
2012
|
+
// The Assistant's user context: three layers and the digest a new conversation starts with.
|
|
2013
|
+
// `userContext` is the view of what the server answered (describeUserContext). Without the engine (a server
|
|
2014
|
+
// started before it existed, one where it did not start, no answer) the rows show switched off and disabled
|
|
2015
|
+
// under a line that says which of those it is: public/ is served live, lib/ only after a restart.
|
|
2016
|
+
const uc = userContext || describeUserContext(null, { tx: kit.tx });
|
|
2017
|
+
const layer = (invId, key) => {
|
|
2018
|
+
const row = uc.layers[key];
|
|
2019
|
+
return `
|
|
2020
|
+
<div class="cc-integration-item${row.on ? ' enabled' : ''}${row.disabled ? ' uc-disabled' : ''}" data-uc-layer-row="${key}">
|
|
2021
|
+
<div class="cc-integration-info">
|
|
2022
|
+
<div class="cc-integration-label" id="uc-layer-${key}-label">${kit.L(invId)}</div>
|
|
2023
|
+
<div class="cc-integration-path" id="uc-layer-${key}-help">${kit.H(invId)}</div>
|
|
2024
|
+
<div class="uc-layer-notes" id="uc-layer-${key}-notes" data-stg-data>${userContextNotesHTML(row.notes)}</div>
|
|
2025
|
+
</div>
|
|
2026
|
+
<button type="button" class="cc-toggle${row.on ? ' on' : ''}" data-uc-layer="${key}" ${kit.inv(invId)} aria-pressed="${row.on ? 'true' : 'false'}" aria-labelledby="uc-layer-${key}-label" aria-describedby="uc-layer-${key}-help uc-layer-${key}-notes${uc.note ? ' uc-status-note' : ''}"${row.disabled ? ' disabled' : ''}></button>
|
|
2027
|
+
</div>`;
|
|
2028
|
+
};
|
|
2029
|
+
const userContextBlock = `
|
|
2030
|
+
<div class="stg-help uc-status-note" id="uc-status-note" role="status" data-uc-state="${uc.state}" data-stg-data${uc.note ? '' : ' hidden'}>${uc.note ? kit.esc(uc.note.text) : ''}</div>
|
|
2031
|
+
<div class="cc-hook-toggles" id="uc-layers" data-uc-ready="${uc.ready ? '1' : '0'}" data-uc-state="${uc.state}">
|
|
2032
|
+
${layer('AUT053', 'knowledge')}
|
|
2033
|
+
${layer('AUT054', 'nudges')}
|
|
2034
|
+
${layer('AUT055', 'trace')}
|
|
2035
|
+
</div>
|
|
2036
|
+
<div class="stg-help uc-save-status" id="uc-save-status" role="alert" data-stg-data hidden></div>
|
|
2037
|
+
<div class="stg-help uc-applies" id="uc-applies"${uc.applies ? '' : ' hidden'}>${kit.esc(uc.applies)}</div>
|
|
2038
|
+
<div class="uc-digest" id="uc-digest" data-uc-digest-state="${uc.digest.state}" ${kit.inv('AUT056')}${uc.digest.shown ? '' : ' hidden'}>
|
|
2039
|
+
<div class="uc-digest-head">
|
|
2040
|
+
<span class="uc-digest-title" id="uc-digest-title">${kit.L('AUT056')}</span>
|
|
2041
|
+
<span class="uc-digest-count" id="uc-digest-count" data-stg-data>${kit.esc(uc.digest.count)}</span>
|
|
2042
|
+
</div>
|
|
2043
|
+
<div class="stg-help uc-digest-help" style="margin:2px 0 0">${kit.H('AUT056')}</div>
|
|
2044
|
+
<div class="uc-digest-rows" id="uc-digest-rows" role="list" aria-labelledby="uc-digest-title" data-stg-data>${uc.digest.shown ? userContextDigestHTML(uc.digest) : ''}</div>
|
|
2045
|
+
<div class="stg-help" id="uc-digest-more" style="margin:0 0 8px"${uc.digest.omitted ? '' : ' hidden'}>${kit.esc(uc.digest.omitted)}</div>
|
|
2046
|
+
<button type="button" class="conn-add-btn" id="uc-digest-all" ${kit.inv('AUT057')} title="${kit.H('AUT057')}" style="margin:0;width:auto;padding:4px 10px;border-style:solid">${kit.L('AUT057')}</button>
|
|
2047
|
+
</div>`;
|
|
2048
|
+
|
|
1895
2049
|
return `
|
|
1896
2050
|
<div class="stg-pane" data-stg-pane="hooks">
|
|
1897
2051
|
|
|
1898
2052
|
${kit.card({
|
|
1899
2053
|
id: 'stg-sec-greetings', section: 'automations.greetings',
|
|
1900
2054
|
body: `
|
|
1901
|
-
${
|
|
1902
|
-
ids: ['AUT001', 'AUT002', 'AUT003', 'AUT004', 'AUT005', 'AUT009', 'AUT010'] })}
|
|
1903
|
-
${buildGreetingSection({ kind: 'codex', enabled: codexGreetingConfig?.enabled === true, config: codexGreetingConfig, prefix: 'codex', bodyId: 'codex-greeting-body', toggleAttrs: 'data-codex-greeting-toggle="enabled"',
|
|
1904
|
-
ids: ['AUT011', 'AUT012', 'AUT013', 'AUT014', 'AUT015', 'AUT016', 'AUT017'] })}
|
|
1905
|
-
${buildGreetingSection({ kind: 'opencode', enabled: opencodeGreetingConfig?.enabled === true, config: opencodeGreetingConfig, prefix: 'opencode', bodyId: 'opencode-greeting-body', toggleAttrs: 'data-opencode-greeting-toggle="enabled"',
|
|
1906
|
-
ids: ['AUT018', 'AUT019', 'AUT020', 'AUT021', 'AUT022', 'AUT026', 'AUT027'] })}`,
|
|
2055
|
+
${greetingBlock}`,
|
|
1907
2056
|
})}
|
|
1908
2057
|
|
|
1909
2058
|
${kit.card({
|
|
1910
2059
|
id: 'stg-sec-automation-behavior', section: 'automations.automation_behavior',
|
|
1911
|
-
status: providerBadge({ cli: true, vscode: true, web: false, cowork: false }),
|
|
1912
2060
|
body: `
|
|
1913
|
-
|
|
1914
|
-
|
|
2061
|
+
${userContextBlock}
|
|
2062
|
+
|
|
2063
|
+
${kit.card({
|
|
2064
|
+
id: 'stg-sec-hooks', level: 'h4', collapsible: true, collapsed: true, advanced: true, attrs: 'data-cc-target="global"',
|
|
2065
|
+
title: h('hooksTitle'), purpose: h('hooksPurpose'),
|
|
2066
|
+
// These hooks are Claude Code's own (~/.claude/settings.json, hooks/claude-code): no other assistant runs them.
|
|
2067
|
+
status: `<span class="cc-hooks-badge${allOn ? ' all-on' : ''}" id="cc-hooks-badge">${onCount}/${hookRows.length}</span>${providerBadge({ cli: true, vscode: true, web: false, cowork: false, codex: false })}`,
|
|
2068
|
+
body: `
|
|
2069
|
+
<div class="stg-help" style="margin:0 0 10px">${h('claudeOnly')}</div>
|
|
2070
|
+
<div class="cc-hook-toggles">
|
|
1915
2071
|
${feature('AUT036', 'conversationMemory', cmOn)}
|
|
1916
2072
|
${feature('AUT039', 'userLearning', ulOn, `
|
|
1917
2073
|
<div class="cc-ul-threshold" id="cc-ul-threshold" style="display:${ulOn ? 'flex' : 'none'};align-items:center;gap:6px;margin-top:5px;flex-wrap:wrap">
|
|
@@ -1924,14 +2080,8 @@ function buildConnectionsTab(ccIntegrations, ccSkills, tunnelStatus, mcpKeyInfo,
|
|
|
1924
2080
|
</div>`)}
|
|
1925
2081
|
${feature('AUT040', 'taskRecallGate', taskRecallOn)}
|
|
1926
2082
|
${feature('AUT041', 'subagentRemember', srOn)}
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
${kit.card({
|
|
1930
|
-
id: 'stg-sec-hooks', level: 'h4', collapsible: true, collapsed: true, advanced: true, attrs: 'data-cc-target="global"',
|
|
1931
|
-
title: h('hooksTitle'), purpose: h('hooksPurpose'),
|
|
1932
|
-
status: `<span class="cc-hooks-badge${allOn ? ' all-on' : ''}" id="cc-hooks-badge">${onCount}/${hookRows.length}</span>${providerBadge({ cli: true, vscode: true, web: false, cowork: false })}`,
|
|
1933
|
-
body: `
|
|
1934
|
-
<div class="cc-hook-toggles">
|
|
2083
|
+
</div>
|
|
2084
|
+
<div class="cc-hook-toggles" style="margin-top:10px">
|
|
1935
2085
|
${hookRows.map(r => `
|
|
1936
2086
|
<div class="cc-integration-item${r.on ? ' enabled' : ''}" data-hook="${r.key}">
|
|
1937
2087
|
<div class="cc-integration-info">
|
|
@@ -1949,20 +2099,14 @@ function buildConnectionsTab(ccIntegrations, ccSkills, tunnelStatus, mcpKeyInfo,
|
|
|
1949
2099
|
status: providerBadge({ cli: true, vscode: true, web: true, webNote: h('compat.viaAddress'), cowork: false }),
|
|
1950
2100
|
body: `
|
|
1951
2101
|
${kit.subhead(h('tunnel.title'))}
|
|
1952
|
-
<div class="cc-integration-item${tunnelStatus.
|
|
1953
|
-
|
|
1954
|
-
<div class="cc-integration-label" id="cc-tunnel-label">${tunnelStatus.running ? h('running') : tunnelStatus.available ? h('ready') : h('tunnel.notInstalled')}</div>
|
|
1955
|
-
<div class="cc-integration-path" id="cc-tunnel-url">${tunnelStatus.url ? escapeHtml(tunnelStatus.url) : (tunnelStatus.available ? h('exposeMcpToClaudeWebVia') : h('tunnel.install'))}</div>
|
|
1956
|
-
</div>
|
|
1957
|
-
${tunnelStatus.available ? `<button type="button" class="cc-toggle${tunnelStatus.running ? ' on' : ''}" id="cc-tunnel-toggle" ${kit.inv('AUT049')} aria-label="${kit.L('AUT049')}" title="${kit.H('AUT049')}"></button>` : ''}
|
|
1958
|
-
</div>
|
|
1959
|
-
${tunnelStatus.url ? `<button type="button" class="cc-copy-btn" id="cc-tunnel-copy-url" ${kit.inv('AUT050')} title="${kit.H('AUT050')}" style="margin-top:4px">${copyIcon} ${h('copyMcpUrl')}</button>` : ''}
|
|
2102
|
+
<div class="cc-integration-item${readTunnel(tunnelStatus).on ? ' enabled' : ''}" id="cc-tunnel-row" ${kit.inv('AUT048')}>${tunnelRowHtml(readTunnel(tunnelStatus))}</div>
|
|
2103
|
+
<div class="stg-tunnel-extra" id="cc-tunnel-extra">${tunnelExtraHtml(readTunnel(tunnelStatus), mcpKeyInfo)}</div>
|
|
1960
2104
|
|
|
1961
2105
|
<div style="margin-top:10px">
|
|
1962
2106
|
<div class="cc-integration-item${mcpKeyInfo.hasKey ? ' enabled' : ''}" id="cc-apikey-row">
|
|
1963
2107
|
<div class="cc-integration-info">
|
|
1964
2108
|
<div class="cc-integration-label">${h('apikey.title')}</div>
|
|
1965
|
-
<div class="cc-integration-path" id="cc-apikey-status">${mcpKeyInfo.hasKey ? escapeHtml(mcpKeyInfo.maskedKey) : h('apikey.none')}</div>
|
|
2109
|
+
<div class="cc-integration-path" id="cc-apikey-status">${mcpKeyInfo.hasKey ? escapeHtml(mcpKeyInfo.maskedKey) : h(closesKeylessMcp(tunnelStatus) ? 'apikey.noneClosed' : 'apikey.none')}</div>
|
|
1966
2110
|
</div>
|
|
1967
2111
|
<button type="button" class="conn-add-btn" id="cc-apikey-generate" ${kit.inv('AUT042')} title="${kit.H('AUT042')}" style="margin:0;padding:3px 8px;width:auto;border-style:solid;background:rgba(255,255,255,0.03)">${mcpKeyInfo.hasKey ? h('regenerate') : h('generateKey')}</button>
|
|
1968
2112
|
</div>
|
|
@@ -3044,12 +3188,11 @@ export async function openSettingsModal(options = {}) {
|
|
|
3044
3188
|
let connections = [];
|
|
3045
3189
|
let ccIntegrations = { global: { installed: false }, projects: [] };
|
|
3046
3190
|
let ccSkills = [];
|
|
3047
|
-
let tunnelStatus =
|
|
3191
|
+
let tunnelStatus = null; // GET /api/tunnel/status; null until it answered (tunnel-view.js reads either)
|
|
3048
3192
|
let mcpKeyInfo = { hasKey: false };
|
|
3049
3193
|
let _bridgeResult = null;
|
|
3050
|
-
|
|
3051
|
-
let
|
|
3052
|
-
let opencodeGreetingConfig = { enabled: false, defaults: {}, projects: {}, global: {} };
|
|
3194
|
+
// The greeting (lib/greeting/): what its endpoint answered, as a reading (no answer is a reading too).
|
|
3195
|
+
let greetingReading = readGreetingStatus({ status: 0 });
|
|
3053
3196
|
let setupStatus = { claude: {}, gemini: {}, codex: {}, opencode: {}, paths: {} };
|
|
3054
3197
|
let cliConfig = {};
|
|
3055
3198
|
let toolPermissions = {};
|
|
@@ -3059,9 +3202,12 @@ export async function openSettingsModal(options = {}) {
|
|
|
3059
3202
|
let customIconsData = { extensions: {}, filenames: {} };
|
|
3060
3203
|
let youtubeConfig = { secrets: {}, configured: {}, pipeline: {} };
|
|
3061
3204
|
let typesafeConfig = null;
|
|
3205
|
+
// The Assistant's user context (lib/assistant-user-context.js): what its endpoint answered, as a reading.
|
|
3206
|
+
// No answer is a reading too: the section says what is true instead of showing switches that do nothing.
|
|
3207
|
+
let userContextReading = readUserContextResponse({ status: 0 });
|
|
3062
3208
|
|
|
3063
3209
|
try {
|
|
3064
|
-
const [settingsRes, connRes, ccRes, skillsRes, tunnelRes, keyRes, bridgeRes, greetRes,
|
|
3210
|
+
const [settingsRes, connRes, ccRes, skillsRes, tunnelRes, keyRes, bridgeRes, greetRes, setupRes, cliRes, toolPermsRes, toolCatsRes, discordRes, skinsRes, iconsRes, youtubeRes, typesafeRes, userContextRes] = await Promise.allSettled([
|
|
3065
3211
|
fetch('/api/settings').then(r => r.json()),
|
|
3066
3212
|
fetch('/api/connections').then(r => r.json()),
|
|
3067
3213
|
fetch('/api/claude-code/integrations').then(r => r.json()),
|
|
@@ -3069,9 +3215,7 @@ export async function openSettingsModal(options = {}) {
|
|
|
3069
3215
|
fetch('/api/tunnel/status').then(r => r.json()),
|
|
3070
3216
|
fetch('/api/mcp-key').then(r => r.json()),
|
|
3071
3217
|
fetch('/api/bridges/openclaw').then(r => r.json()),
|
|
3072
|
-
|
|
3073
|
-
fetch('/api/codex-panel/greeting/config').then(r => r.json()),
|
|
3074
|
-
fetch('/api/opencode-panel/greeting/config').then(r => r.json()),
|
|
3218
|
+
loadGreetingReading(),
|
|
3075
3219
|
fetch('/api/setup/status').then(r => r.json()),
|
|
3076
3220
|
fetch('/api/cli/config').then(r => r.json()),
|
|
3077
3221
|
fetch('/api/claude-code/tool-permissions').then(r => r.json()),
|
|
@@ -3081,8 +3225,10 @@ export async function openSettingsModal(options = {}) {
|
|
|
3081
3225
|
fetch('/api/file-icons').then(r => r.json()),
|
|
3082
3226
|
fetch('/api/youtube/config').then(r => r.json()),
|
|
3083
3227
|
fetch('/api/typesafe/config').then(r => r.json()),
|
|
3228
|
+
loadUserContextReading(),
|
|
3084
3229
|
]);
|
|
3085
3230
|
if (typesafeRes.status === 'fulfilled' && typesafeRes.value.ok) typesafeConfig = typesafeRes.value;
|
|
3231
|
+
if (userContextRes.status === 'fulfilled') userContextReading = userContextRes.value;
|
|
3086
3232
|
if (settingsRes.status === 'fulfilled') settings = settingsRes.value;
|
|
3087
3233
|
if (connRes.status === 'fulfilled' && connRes.value.connections) connections = connRes.value.connections;
|
|
3088
3234
|
if (ccRes.status === 'fulfilled' && ccRes.value.ok) ccIntegrations = ccRes.value;
|
|
@@ -3090,9 +3236,7 @@ export async function openSettingsModal(options = {}) {
|
|
|
3090
3236
|
if (tunnelRes.status === 'fulfilled' && tunnelRes.value.ok) tunnelStatus = tunnelRes.value;
|
|
3091
3237
|
if (keyRes.status === 'fulfilled' && keyRes.value.ok) mcpKeyInfo = keyRes.value;
|
|
3092
3238
|
if (bridgeRes.status === 'fulfilled' && bridgeRes.value.ok) _bridgeResult = bridgeRes.value;
|
|
3093
|
-
if (greetRes.status === 'fulfilled'
|
|
3094
|
-
if (codexGreetRes.status === 'fulfilled' && codexGreetRes.value.ok) codexGreetingConfig = codexGreetRes.value.config;
|
|
3095
|
-
if (opencodeGreetRes.status === 'fulfilled' && opencodeGreetRes.value.ok) opencodeGreetingConfig = opencodeGreetRes.value.config;
|
|
3239
|
+
if (greetRes.status === 'fulfilled') greetingReading = greetRes.value;
|
|
3096
3240
|
if (setupRes.status === 'fulfilled' && setupRes.value.ok) setupStatus = setupRes.value;
|
|
3097
3241
|
if (cliRes.status === 'fulfilled' && cliRes.value.ok) cliConfig = cliRes.value.config;
|
|
3098
3242
|
if (toolPermsRes.status === 'fulfilled' && toolPermsRes.value.ok) toolPermissions = toolPermsRes.value.tools;
|
|
@@ -3153,7 +3297,7 @@ export async function openSettingsModal(options = {}) {
|
|
|
3153
3297
|
<div class="settings-content">
|
|
3154
3298
|
${buildPagesHTML({
|
|
3155
3299
|
server: buildServerTab(settings, connections),
|
|
3156
|
-
hooks: buildConnectionsTab(ccIntegrations, ccSkills, tunnelStatus, mcpKeyInfo, openclawBridge,
|
|
3300
|
+
hooks: buildConnectionsTab(ccIntegrations, ccSkills, tunnelStatus, mcpKeyInfo, openclawBridge, describeGreeting(greetingReading, null, { tx: kit.tx, t: kit.tx }), toolPermissions, toolCategories, describeUserContext(userContextReading, { tx: kit.tx })),
|
|
3157
3301
|
terminal: buildTerminalTab(cliConfig),
|
|
3158
3302
|
opencode: buildOpencodeTab(),
|
|
3159
3303
|
notifications: buildNotificationsTab(),
|
|
@@ -3169,12 +3313,14 @@ export async function openSettingsModal(options = {}) {
|
|
|
3169
3313
|
whatsapp: buildWhatsAppTab(),
|
|
3170
3314
|
morelogin: buildMoreLoginTab(),
|
|
3171
3315
|
permissions: buildPermissionsTab(toolCategories, toolPermissions),
|
|
3316
|
+
editor: buildCodeEditorTab(),
|
|
3172
3317
|
social: buildSocialTab(toolCategories, toolPermissions),
|
|
3173
3318
|
youtube: buildYoutubeTab(youtubeConfig),
|
|
3174
3319
|
language: buildLanguageTab(),
|
|
3175
3320
|
skins: buildSkinsTab(skinsData.skins, skinsData.active),
|
|
3176
3321
|
interface: buildInterfaceTab(),
|
|
3177
3322
|
icons: buildIconsTab(customIconsData),
|
|
3323
|
+
about: buildAboutTab(),
|
|
3178
3324
|
}, variantTabs, initialPage)}
|
|
3179
3325
|
</div>
|
|
3180
3326
|
</div>
|
|
@@ -4261,6 +4407,12 @@ export async function openSettingsModal(options = {}) {
|
|
|
4261
4407
|
// ── WhatsApp tab — self-loads its status (never part of the blocking fetch above) ──
|
|
4262
4408
|
wireWhatsAppTab(overlay, { toast: showCCToast });
|
|
4263
4409
|
|
|
4410
|
+
// ── Code editor: AI autocomplete (loads and saves itself) ──
|
|
4411
|
+
wireCodeEditorTab(overlay);
|
|
4412
|
+
|
|
4413
|
+
// ── About: version, links, system and dependencies (loads itself the first time its page is shown) ──
|
|
4414
|
+
wireAboutTab(overlay, { toast: showCCToast });
|
|
4415
|
+
|
|
4264
4416
|
// ── Discord tab handlers ──
|
|
4265
4417
|
{
|
|
4266
4418
|
// Token save
|
|
@@ -4402,6 +4554,36 @@ export async function openSettingsModal(options = {}) {
|
|
|
4402
4554
|
const cliDefaults = { 'claude-code': 'claude', 'codex': 'codex', 'gemini': 'gemini', 'opencode': 'opencode' };
|
|
4403
4555
|
const cliProfileIds = Object.keys(cliDefaults);
|
|
4404
4556
|
|
|
4557
|
+
const pathButtons = overlay.querySelectorAll('[data-cli-add-path]');
|
|
4558
|
+
const showPathAction = (tool, info) => {
|
|
4559
|
+
const button = overlay.querySelector(`[data-cli-add-path="${tool}"]`);
|
|
4560
|
+
if (button) button.hidden = !(info?.state === 'installed' && info.pathStatus?.canAdd === true);
|
|
4561
|
+
};
|
|
4562
|
+
pathButtons.forEach(button => {
|
|
4563
|
+
const tool = button.dataset.cliAddPath;
|
|
4564
|
+
getCliStatus(tool).then(info => showPathAction(tool, info)).catch(() => {});
|
|
4565
|
+
button.addEventListener('click', async () => {
|
|
4566
|
+
button.disabled = true; button.textContent = cliInstallText('addingPath');
|
|
4567
|
+
try {
|
|
4568
|
+
const result = await addCliToPath(tool);
|
|
4569
|
+
showCCToast(cliInstallText('doneAddedToPath', { dir: result.dir }) + (result.warning ? ` ${result.warning}` : ''));
|
|
4570
|
+
for (const pathButton of pathButtons) getCliStatus(pathButton.dataset.cliAddPath).then(info => showPathAction(pathButton.dataset.cliAddPath, info)).catch(() => {});
|
|
4571
|
+
} catch (error) { showCCToast(cliInstallText('pathFailed', { error: error.message })); }
|
|
4572
|
+
finally { button.disabled = false; button.textContent = cliInstallText('addPath'); }
|
|
4573
|
+
});
|
|
4574
|
+
});
|
|
4575
|
+
// Windows: the Git Bash every Claude Code SynaBun starts gets (ui-git-bash.js; hidden on macOS and Linux).
|
|
4576
|
+
wireGitBashRow(overlay.querySelector('#cli-git-bash'));
|
|
4577
|
+
overlay.querySelector('#cli-path-diagnostics')?.addEventListener('click', async () => {
|
|
4578
|
+
try {
|
|
4579
|
+
const response = await fetch('/api/cli/path');
|
|
4580
|
+
const diagnostics = await response.json();
|
|
4581
|
+
if (!response.ok) throw new Error(diagnostics.error || `HTTP ${response.status}`);
|
|
4582
|
+
await navigator.clipboard.writeText(JSON.stringify(diagnostics, null, 2));
|
|
4583
|
+
showCCToast(cliInstallText('copied'));
|
|
4584
|
+
} catch (error) { showCCToast(error.message); }
|
|
4585
|
+
});
|
|
4586
|
+
|
|
4405
4587
|
// Detect buttons
|
|
4406
4588
|
overlay.querySelectorAll('.cli-detect-btn[data-cli-detect]').forEach(btn => {
|
|
4407
4589
|
btn.addEventListener('click', async () => {
|
|
@@ -4415,9 +4597,13 @@ export async function openSettingsModal(options = {}) {
|
|
|
4415
4597
|
body: '{}',
|
|
4416
4598
|
});
|
|
4417
4599
|
const data = await res.json();
|
|
4418
|
-
|
|
4600
|
+
showPathAction(profileId, data);
|
|
4601
|
+
if (data.ok && data.found && data.path && data.state === 'broken') {
|
|
4602
|
+
// Found, but it does not start: not put in the field, so a broken path is never saved by accident.
|
|
4603
|
+
showCCToast(kit.tx('settings.redesign.terminal.detectionFailed', { message: data.error ? `${data.path}: ${data.error}` : data.path }));
|
|
4604
|
+
} else if (data.ok && data.found && data.path) {
|
|
4419
4605
|
input.value = data.path;
|
|
4420
|
-
showCCToast(kit.tx('settings.redesign.terminal.found', { path: data.path }));
|
|
4606
|
+
showCCToast(kit.tx('settings.redesign.terminal.found', { path: data.version ? `${data.path} (${data.version})` : data.path }));
|
|
4421
4607
|
} else {
|
|
4422
4608
|
showCCToast(kit.tx('settings.redesign.terminal.cliNotFoundInPath'));
|
|
4423
4609
|
}
|
|
@@ -4457,6 +4643,9 @@ export async function openSettingsModal(options = {}) {
|
|
|
4457
4643
|
}
|
|
4458
4644
|
});
|
|
4459
4645
|
showCCToast(kit.tx('settings.redesign.terminal.cliPathsSaved'));
|
|
4646
|
+
// The panels' CLI banners and the update badges follow the paths just saved (one forced
|
|
4647
|
+
// re-check answers for every CLI).
|
|
4648
|
+
recheckCliStatus('claude-code').catch(() => {});
|
|
4460
4649
|
} else {
|
|
4461
4650
|
alert(data.error || kit.tx('settings.redesign.terminal.failedToSave'));
|
|
4462
4651
|
}
|
|
@@ -4683,6 +4872,152 @@ export async function openSettingsModal(options = {}) {
|
|
|
4683
4872
|
toggle.addEventListener('click', () => { ccToggleHook('global', null, toggle, overlay.querySelector('.iface-section[data-cc-target="global"]'), toggle.dataset.ccHook); });
|
|
4684
4873
|
});
|
|
4685
4874
|
|
|
4875
|
+
// ── The Assistant's user context: layers and the digest preview ──
|
|
4876
|
+
const ucRowsEl = overlay.querySelector('#uc-digest-rows');
|
|
4877
|
+
const redrawUserContext = (reading = userContextReading) => drawUserContext(overlay, describeUserContext(reading, { tx: kit.tx }));
|
|
4878
|
+
// What could not be saved, said next to the switches (role="alert"); empty clears it.
|
|
4879
|
+
const setUserContextSaveStatus = (text = '') => {
|
|
4880
|
+
const status = overlay.querySelector('#uc-save-status');
|
|
4881
|
+
if (status) { status.hidden = !text; status.textContent = text; }
|
|
4882
|
+
};
|
|
4883
|
+
// A line of the digest opens its memory (the owner corrects line 1 there and the digest follows).
|
|
4884
|
+
ucRowsEl?.addEventListener('click', (e) => {
|
|
4885
|
+
const row = e.target.closest('[data-uc-memory]');
|
|
4886
|
+
if (!row) return;
|
|
4887
|
+
const id = row.dataset.ucMemory;
|
|
4888
|
+
close();
|
|
4889
|
+
emit('memory:open', { id });
|
|
4890
|
+
});
|
|
4891
|
+
overlay.querySelector('#uc-digest-all')?.addEventListener('click', () => {
|
|
4892
|
+
close();
|
|
4893
|
+
emit('explorer:show-category', { category: 'user-knowledge', fallback: 'communication-style' });
|
|
4894
|
+
});
|
|
4895
|
+
// A note that names another Settings page (learning needs AI decisions) goes there.
|
|
4896
|
+
overlay.querySelector('#uc-layers')?.addEventListener('click', (e) => {
|
|
4897
|
+
const link = e.target.closest('[data-uc-goto]');
|
|
4898
|
+
if (!link) return;
|
|
4899
|
+
try { applySettingsOpenOptions(overlay, JSON.parse(link.dataset.ucGoto)); } catch { /* a malformed target goes nowhere */ }
|
|
4900
|
+
});
|
|
4901
|
+
// The switch moves at once and follows the server's answer: the stored settings when the save went through,
|
|
4902
|
+
// back where it was (with the reason next to the switches) when it did not. Saves go one after the other, in
|
|
4903
|
+
// the order of the clicks, so a second click made before the first was answered is kept, not dropped.
|
|
4904
|
+
let userContextSaves = Promise.resolve();
|
|
4905
|
+
const userContextWanted = {}; // layer → what its last click asked for, until that save is answered
|
|
4906
|
+
const userContextWaiting = {}; // layer → saves not answered yet
|
|
4907
|
+
const userContextBusy = () => Object.values(userContextWaiting).some(count => count > 0);
|
|
4908
|
+
// What the page shows while saves are on their way: the stored settings with the clicks on top.
|
|
4909
|
+
const userContextShown = () => (userContextReading.state === 'ready'
|
|
4910
|
+
? { ...userContextReading, payload: { ...userContextReading.payload, settings: { ...userContextReading.payload.settings, ...userContextWanted } } }
|
|
4911
|
+
: userContextReading);
|
|
4912
|
+
const markUserContextWaiting = () => overlay.querySelectorAll('.cc-toggle[data-uc-layer]').forEach(other => { other.style.opacity = userContextWaiting[other.dataset.ucLayer] > 0 ? '0.4' : ''; });
|
|
4913
|
+
overlay.querySelectorAll('.cc-toggle[data-uc-layer]').forEach(toggle => {
|
|
4914
|
+
toggle.addEventListener('click', () => {
|
|
4915
|
+
if (toggle.disabled || userContextReading.state !== 'ready') return;
|
|
4916
|
+
const layerKey = toggle.dataset.ucLayer;
|
|
4917
|
+
const wanted = !toggle.classList.contains('on');
|
|
4918
|
+
const name = overlay.querySelector(`#uc-layer-${layerKey}-label`)?.textContent?.trim() || layerKey;
|
|
4919
|
+
userContextWanted[layerKey] = wanted;
|
|
4920
|
+
userContextWaiting[layerKey] = (userContextWaiting[layerKey] || 0) + 1;
|
|
4921
|
+
setUserContextSaveStatus('');
|
|
4922
|
+
redrawUserContext(userContextShown());
|
|
4923
|
+
markUserContextWaiting();
|
|
4924
|
+
userContextSaves = userContextSaves.then(async () => {
|
|
4925
|
+
let failure = null;
|
|
4926
|
+
try {
|
|
4927
|
+
const res = await fetch('/api/assistant/user-context', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ [layerKey]: wanted }) });
|
|
4928
|
+
const body = await res.json().catch(() => null);
|
|
4929
|
+
const reading = readUserContextResponse({ status: res.status, body });
|
|
4930
|
+
if (res.ok && reading.state === 'ready') userContextReading = reading;
|
|
4931
|
+
else failure = { status: res.status, body };
|
|
4932
|
+
} catch (err) {
|
|
4933
|
+
failure = { status: 0, error: err?.message };
|
|
4934
|
+
}
|
|
4935
|
+
userContextWaiting[layerKey] -= 1;
|
|
4936
|
+
// Every click on this switch was answered: it shows the stored value again (a later click still on its way keeps its wish).
|
|
4937
|
+
if (userContextWaiting[layerKey] <= 0) delete userContextWanted[layerKey];
|
|
4938
|
+
if (!overlay.isConnected) return;
|
|
4939
|
+
if (failure) setUserContextSaveStatus(describeUserContextSaveFailure({ name, wanted, ...failure }, { tx: kit.tx }));
|
|
4940
|
+
redrawUserContext(userContextShown());
|
|
4941
|
+
markUserContextWaiting();
|
|
4942
|
+
});
|
|
4943
|
+
});
|
|
4944
|
+
});
|
|
4945
|
+
// Switched in another window (or by a hand edit another Settings saved): this one follows.
|
|
4946
|
+
const offUserContextSync = on('sync:assistant:user-context-changed', async () => {
|
|
4947
|
+
if (userContextBusy() || userContextReading.state !== 'ready' || !overlay.isConnected) return;
|
|
4948
|
+
const reading = await loadUserContextReading();
|
|
4949
|
+
if (reading.state !== 'ready' || userContextBusy() || !overlay.isConnected) return;
|
|
4950
|
+
userContextReading = reading;
|
|
4951
|
+
redrawUserContext();
|
|
4952
|
+
});
|
|
4953
|
+
overlay.addEventListener('settings-close', () => offUserContextSync(), { once: true });
|
|
4954
|
+
|
|
4955
|
+
// ── Greeting (lib/greeting/): the one switch, and what a new session would open with right now ──
|
|
4956
|
+
// The switch moves at once and goes back, with the reason in the line under it, when the save fails;
|
|
4957
|
+
// quick clicks are saved in the order they were made. The preview is asked when Settings opens and
|
|
4958
|
+
// after every change; "Write it now" asks the writer for the sentence (one small call).
|
|
4959
|
+
let greetingPreview = null;
|
|
4960
|
+
let greetingSaves = Promise.resolve();
|
|
4961
|
+
let greetingClosed = false; // Settings was closed: an answer that arrives late draws nothing
|
|
4962
|
+
const drawGreeting = () => drawGreetingSection(overlay, describeGreeting(greetingReading, greetingPreview, { tx: kit.tx, t: kit.tx }));
|
|
4963
|
+
const refreshGreetingPreview = async ({ write = false } = {}) => {
|
|
4964
|
+
if (greetingReading.state !== 'ready') { drawGreeting(); return; }
|
|
4965
|
+
if (!greetingPreview) greetingPreview = { loading: true };
|
|
4966
|
+
drawGreeting();
|
|
4967
|
+
const answer = await fetchGreetingPreview({ write });
|
|
4968
|
+
if (greetingClosed) return;
|
|
4969
|
+
greetingPreview = answer;
|
|
4970
|
+
drawGreeting();
|
|
4971
|
+
};
|
|
4972
|
+
const greetingToggle = overlay.querySelector('[data-gr-toggle]');
|
|
4973
|
+
if (greetingToggle) {
|
|
4974
|
+
greetingToggle.addEventListener('click', () => {
|
|
4975
|
+
if (greetingToggle.disabled || greetingReading.state !== 'ready') return;
|
|
4976
|
+
const before = greetingReading;
|
|
4977
|
+
const wanted = before.payload.settings.enabled === false;
|
|
4978
|
+
greetingReading = { ...before, payload: { ...before.payload, settings: { ...before.payload.settings, enabled: wanted }, enabled: wanted && before.payload.killed !== true } };
|
|
4979
|
+
const status = overlay.querySelector('#gr-save-status');
|
|
4980
|
+
if (status) { status.hidden = true; status.textContent = ''; }
|
|
4981
|
+
drawGreeting();
|
|
4982
|
+
greetingSaves = greetingSaves.then(async () => {
|
|
4983
|
+
let res = null;
|
|
4984
|
+
let body = null;
|
|
4985
|
+
let error = null;
|
|
4986
|
+
try {
|
|
4987
|
+
res = await fetch('/api/greeting', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ enabled: wanted }) });
|
|
4988
|
+
body = await res.json().catch(() => null);
|
|
4989
|
+
} catch (err) { error = err?.message || String(err); }
|
|
4990
|
+
const next = readGreetingStatus({ status: res?.status || 0, body, error });
|
|
4991
|
+
if (next.state === 'ready') greetingReading = next;
|
|
4992
|
+
else {
|
|
4993
|
+
greetingReading = before;
|
|
4994
|
+
if (status) { status.textContent = describeGreetingSaveFailure({ status: res?.status || 0, body, error }, { tx: kit.tx }); status.hidden = false; }
|
|
4995
|
+
}
|
|
4996
|
+
drawGreeting();
|
|
4997
|
+
if (next.state === 'ready') await refreshGreetingPreview();
|
|
4998
|
+
});
|
|
4999
|
+
});
|
|
5000
|
+
}
|
|
5001
|
+
const greetingWrite = overlay.querySelector('#gr-write');
|
|
5002
|
+
if (greetingWrite) {
|
|
5003
|
+
greetingWrite.addEventListener('click', async () => {
|
|
5004
|
+
if (greetingWrite.disabled) return;
|
|
5005
|
+
const label = greetingWrite.textContent;
|
|
5006
|
+
greetingWrite.disabled = true;
|
|
5007
|
+
greetingWrite.textContent = kit.tx('settings.redesign.hooks.greet.preview.writing');
|
|
5008
|
+
try { await refreshGreetingPreview({ write: true }); }
|
|
5009
|
+
finally { greetingWrite.disabled = false; greetingWrite.textContent = label; }
|
|
5010
|
+
});
|
|
5011
|
+
}
|
|
5012
|
+
// Switched in another window: an open Settings follows.
|
|
5013
|
+
const offGreetingSync = on('sync:greeting:changed', async () => {
|
|
5014
|
+
greetingReading = await loadGreetingReading();
|
|
5015
|
+
if (greetingClosed) return;
|
|
5016
|
+
await refreshGreetingPreview();
|
|
5017
|
+
});
|
|
5018
|
+
overlay.addEventListener('settings-close', () => { greetingClosed = true; offGreetingSync(); }, { once: true });
|
|
5019
|
+
refreshGreetingPreview();
|
|
5020
|
+
|
|
4686
5021
|
// Feature toggles
|
|
4687
5022
|
overlay.querySelectorAll('.cc-toggle[data-cc-feature]').forEach(toggle => {
|
|
4688
5023
|
toggle.addEventListener('click', async () => {
|
|
@@ -4693,11 +5028,6 @@ export async function openSettingsModal(options = {}) {
|
|
|
4693
5028
|
const data = await res.json();
|
|
4694
5029
|
if (data.ok) {
|
|
4695
5030
|
toggle.classList.toggle('on'); const row = toggle.closest('.cc-integration-item'); if (row) row.classList.toggle('enabled', !isOn);
|
|
4696
|
-
// Show/hide greeting body when greeting feature is toggled
|
|
4697
|
-
if (feature === 'greeting') {
|
|
4698
|
-
const gcBody = overlay.querySelector('#cc-greeting-body');
|
|
4699
|
-
if (gcBody) gcBody.style.display = !isOn ? 'block' : 'none';
|
|
4700
|
-
}
|
|
4701
5031
|
// Show/hide user learning threshold when feature is toggled
|
|
4702
5032
|
if (feature === 'userLearning') {
|
|
4703
5033
|
const ulThreshold = overlay.querySelector('#cc-ul-threshold');
|
|
@@ -4710,64 +5040,6 @@ export async function openSettingsModal(options = {}) {
|
|
|
4710
5040
|
});
|
|
4711
5041
|
});
|
|
4712
5042
|
|
|
4713
|
-
overlay.querySelectorAll('.cc-toggle[data-codex-greeting-toggle]').forEach(toggle => {
|
|
4714
|
-
toggle.addEventListener('click', async () => {
|
|
4715
|
-
const isOn = toggle.classList.contains('on');
|
|
4716
|
-
try {
|
|
4717
|
-
toggle.style.opacity = '0.4';
|
|
4718
|
-
toggle.style.pointerEvents = 'none';
|
|
4719
|
-
const res = await fetch('/api/codex-panel/greeting/config', {
|
|
4720
|
-
method: 'PUT',
|
|
4721
|
-
headers: { 'Content-Type': 'application/json' },
|
|
4722
|
-
body: JSON.stringify({ enabled: !isOn }),
|
|
4723
|
-
});
|
|
4724
|
-
const data = await res.json();
|
|
4725
|
-
if (!data.ok) {
|
|
4726
|
-
alert(data.error || kit.tx('settings.redesign.hooks.failedToToggleCodexGreeting'));
|
|
4727
|
-
return;
|
|
4728
|
-
}
|
|
4729
|
-
codexGreetingConfig.enabled = !isOn;
|
|
4730
|
-
toggle.classList.toggle('on', !isOn);
|
|
4731
|
-
const body = overlay.querySelector('#codex-greeting-body');
|
|
4732
|
-
if (body) body.style.display = !isOn ? 'block' : 'none';
|
|
4733
|
-
} catch (err) {
|
|
4734
|
-
alert(kit.tx('settings.redesign.hooks.failed2', { message: err.message }));
|
|
4735
|
-
} finally {
|
|
4736
|
-
toggle.style.opacity = '';
|
|
4737
|
-
toggle.style.pointerEvents = '';
|
|
4738
|
-
}
|
|
4739
|
-
});
|
|
4740
|
-
});
|
|
4741
|
-
|
|
4742
|
-
overlay.querySelectorAll('.cc-toggle[data-opencode-greeting-toggle]').forEach(toggle => {
|
|
4743
|
-
toggle.addEventListener('click', async () => {
|
|
4744
|
-
const isOn = toggle.classList.contains('on');
|
|
4745
|
-
try {
|
|
4746
|
-
toggle.style.opacity = '0.4';
|
|
4747
|
-
toggle.style.pointerEvents = 'none';
|
|
4748
|
-
const res = await fetch('/api/opencode-panel/greeting/config', {
|
|
4749
|
-
method: 'PUT',
|
|
4750
|
-
headers: { 'Content-Type': 'application/json' },
|
|
4751
|
-
body: JSON.stringify({ enabled: !isOn }),
|
|
4752
|
-
});
|
|
4753
|
-
const data = await res.json();
|
|
4754
|
-
if (!data.ok) {
|
|
4755
|
-
alert(data.error || kit.tx('settings.redesign.hooks.failedToToggleOpencodeGreeting'));
|
|
4756
|
-
return;
|
|
4757
|
-
}
|
|
4758
|
-
opencodeGreetingConfig.enabled = !isOn;
|
|
4759
|
-
toggle.classList.toggle('on', !isOn);
|
|
4760
|
-
const body = overlay.querySelector('#opencode-greeting-body');
|
|
4761
|
-
if (body) body.style.display = !isOn ? 'block' : 'none';
|
|
4762
|
-
} catch (err) {
|
|
4763
|
-
alert(kit.tx('settings.redesign.hooks.failed2', { message: err.message }));
|
|
4764
|
-
} finally {
|
|
4765
|
-
toggle.style.opacity = '';
|
|
4766
|
-
toggle.style.pointerEvents = '';
|
|
4767
|
-
}
|
|
4768
|
-
});
|
|
4769
|
-
});
|
|
4770
|
-
|
|
4771
5043
|
// ── Tool Permission toggles ──
|
|
4772
5044
|
function updateToolBadges() {
|
|
4773
5045
|
// Update per-category counts across all tabs (Automations + Social)
|
|
@@ -4874,242 +5146,6 @@ export async function openSettingsModal(options = {}) {
|
|
|
4874
5146
|
}
|
|
4875
5147
|
}
|
|
4876
5148
|
|
|
4877
|
-
// ── Greeting editor handlers ──
|
|
4878
|
-
function wireGreetingEditor({ prefix, configRef, saveBaseUrl, onSave }) {
|
|
4879
|
-
const gcSelect = overlay.querySelector(`#${prefix}-greeting-project`);
|
|
4880
|
-
const gcTemplate = overlay.querySelector(`#${prefix}-greeting-template`);
|
|
4881
|
-
const gcShowReminders = overlay.querySelector(`#${prefix}-greeting-show-reminders`);
|
|
4882
|
-
const gcShowLastSession = overlay.querySelector(`#${prefix}-greeting-show-last-session`);
|
|
4883
|
-
const gcReminderList = overlay.querySelector(`#${prefix}-greeting-reminders`);
|
|
4884
|
-
const gcAddReminder = overlay.querySelector(`#${prefix}-greeting-add-reminder`);
|
|
4885
|
-
const gcSave = overlay.querySelector(`#${prefix}-greeting-save`);
|
|
4886
|
-
if (!gcSelect || !gcTemplate || !gcReminderList || !gcSave) return;
|
|
4887
|
-
|
|
4888
|
-
function getGreetingCfg(key) {
|
|
4889
|
-
const gc = configRef() || { defaults: {}, projects: {}, global: {} };
|
|
4890
|
-
if (key === 'global') return { ...gc.defaults, ...gc.global };
|
|
4891
|
-
return { ...gc.defaults, ...(gc.projects[key] || {}) };
|
|
4892
|
-
}
|
|
4893
|
-
|
|
4894
|
-
function reminderRowHTML(reminder) {
|
|
4895
|
-
return `<div class="cc-greeting-reminder-row">
|
|
4896
|
-
<span class="cc-greeting-drag-handle" title="${kit.te('settings.redesign.hooks.dragToReorder')}">⋮⋮</span>
|
|
4897
|
-
<input class="cc-greeting-reminder-input label" placeholder="${kit.te('settings.redesign.hooks.label')}" value="${escapeHtml(reminder.label || '')}">
|
|
4898
|
-
<input class="cc-greeting-reminder-input cmd" placeholder="${kit.te('settings.redesign.hooks.command')}" value="${escapeHtml(reminder.command || '')}">
|
|
4899
|
-
<button class="cc-greeting-reminder-remove" title="${kit.te('settings.redesign.hooks.remove')}">×</button>
|
|
4900
|
-
</div>`;
|
|
4901
|
-
}
|
|
4902
|
-
|
|
4903
|
-
function wireReminderRemoveButtons() {
|
|
4904
|
-
gcReminderList.querySelectorAll('.cc-greeting-reminder-remove').forEach((btn) => {
|
|
4905
|
-
btn.onclick = () => {
|
|
4906
|
-
const row = btn.closest('.cc-greeting-reminder-row');
|
|
4907
|
-
if (!row) return;
|
|
4908
|
-
row.style.opacity = '0';
|
|
4909
|
-
row.style.transition = 'opacity 0.15s';
|
|
4910
|
-
setTimeout(() => row.remove(), 150);
|
|
4911
|
-
};
|
|
4912
|
-
});
|
|
4913
|
-
}
|
|
4914
|
-
|
|
4915
|
-
function wireReminderDragHandles() {
|
|
4916
|
-
gcReminderList.querySelectorAll('.cc-greeting-drag-handle').forEach((handle) => {
|
|
4917
|
-
handle.onmousedown = (event) => {
|
|
4918
|
-
event.preventDefault();
|
|
4919
|
-
const row = handle.closest('.cc-greeting-reminder-row');
|
|
4920
|
-
if (!row) return;
|
|
4921
|
-
row.style.opacity = '0.5';
|
|
4922
|
-
const rows = [...gcReminderList.querySelectorAll('.cc-greeting-reminder-row')];
|
|
4923
|
-
const startY = event.clientY;
|
|
4924
|
-
const startIdx = rows.indexOf(row);
|
|
4925
|
-
const onMove = (moveEvent) => {
|
|
4926
|
-
const dy = moveEvent.clientY - startY;
|
|
4927
|
-
const rowH = row.offsetHeight + 4;
|
|
4928
|
-
const shift = Math.round(dy / rowH);
|
|
4929
|
-
const newIdx = Math.max(0, Math.min(rows.length - 1, startIdx + shift));
|
|
4930
|
-
if (newIdx !== rows.indexOf(row)) {
|
|
4931
|
-
const ref = gcReminderList.children[newIdx];
|
|
4932
|
-
if (newIdx > rows.indexOf(row)) gcReminderList.insertBefore(row, ref?.nextSibling || null);
|
|
4933
|
-
else gcReminderList.insertBefore(row, ref);
|
|
4934
|
-
}
|
|
4935
|
-
};
|
|
4936
|
-
const onUp = () => {
|
|
4937
|
-
row.style.opacity = '';
|
|
4938
|
-
document.removeEventListener('mousemove', onMove);
|
|
4939
|
-
document.removeEventListener('mouseup', onUp);
|
|
4940
|
-
};
|
|
4941
|
-
document.addEventListener('mousemove', onMove);
|
|
4942
|
-
document.addEventListener('mouseup', onUp);
|
|
4943
|
-
};
|
|
4944
|
-
});
|
|
4945
|
-
}
|
|
4946
|
-
|
|
4947
|
-
function populateGreetingFields(key) {
|
|
4948
|
-
const cfg = getGreetingCfg(key);
|
|
4949
|
-
gcTemplate.value = cfg.greetingTemplate || '';
|
|
4950
|
-
if (gcShowReminders) gcShowReminders.checked = !!cfg.showReminders;
|
|
4951
|
-
if (gcShowLastSession) gcShowLastSession.checked = !!cfg.showLastSession;
|
|
4952
|
-
gcReminderList.innerHTML = (cfg.reminders || []).map((reminder) => reminderRowHTML(reminder)).join('');
|
|
4953
|
-
wireReminderRemoveButtons();
|
|
4954
|
-
wireReminderDragHandles();
|
|
4955
|
-
}
|
|
4956
|
-
|
|
4957
|
-
const gcDropdown = overlay.querySelector(`#${prefix}-greeting-project-dropdown`);
|
|
4958
|
-
const gcDropdownLabel = overlay.querySelector(`#${prefix}-greeting-project-label`);
|
|
4959
|
-
const gcDropdownMenu = overlay.querySelector(`#${prefix}-greeting-project-menu`);
|
|
4960
|
-
if (gcDropdown && gcDropdownMenu) {
|
|
4961
|
-
gcDropdown.querySelector('.cc-dropdown-trigger')?.addEventListener('click', () => {
|
|
4962
|
-
gcDropdown.classList.toggle('open');
|
|
4963
|
-
});
|
|
4964
|
-
gcDropdownMenu.querySelectorAll('.cc-dropdown-item').forEach((item) => {
|
|
4965
|
-
item.addEventListener('click', () => {
|
|
4966
|
-
const val = item.dataset.value;
|
|
4967
|
-
gcSelect.value = val;
|
|
4968
|
-
gcSelect.dispatchEvent(new Event('change'));
|
|
4969
|
-
if (gcDropdownLabel) gcDropdownLabel.textContent = item.textContent;
|
|
4970
|
-
gcDropdownMenu.querySelectorAll('.cc-dropdown-item').forEach((entry) => entry.classList.remove('active'));
|
|
4971
|
-
item.classList.add('active');
|
|
4972
|
-
gcDropdown.classList.remove('open');
|
|
4973
|
-
populateGreetingFields(val);
|
|
4974
|
-
});
|
|
4975
|
-
});
|
|
4976
|
-
document.addEventListener('click', (event) => {
|
|
4977
|
-
if (!gcDropdown.contains(event.target)) gcDropdown.classList.remove('open');
|
|
4978
|
-
});
|
|
4979
|
-
}
|
|
4980
|
-
|
|
4981
|
-
gcAddReminder?.addEventListener('click', () => {
|
|
4982
|
-
const tmp = document.createElement('div');
|
|
4983
|
-
tmp.innerHTML = reminderRowHTML({ label: '', command: '' });
|
|
4984
|
-
const newRow = tmp.firstElementChild;
|
|
4985
|
-
gcReminderList.appendChild(newRow);
|
|
4986
|
-
wireReminderRemoveButtons();
|
|
4987
|
-
wireReminderDragHandles();
|
|
4988
|
-
newRow.querySelector('.label')?.focus();
|
|
4989
|
-
});
|
|
4990
|
-
|
|
4991
|
-
gcSave.addEventListener('click', async () => {
|
|
4992
|
-
const project = gcSelect.value || 'global';
|
|
4993
|
-
const reminders = [];
|
|
4994
|
-
gcReminderList.querySelectorAll('.cc-greeting-reminder-row').forEach((row) => {
|
|
4995
|
-
const label = row.querySelector('.label')?.value?.trim() || '';
|
|
4996
|
-
const command = row.querySelector('.cmd')?.value?.trim() || '';
|
|
4997
|
-
if (label || command) reminders.push({ label, command });
|
|
4998
|
-
});
|
|
4999
|
-
const body = {
|
|
5000
|
-
greetingTemplate: gcTemplate.value || '',
|
|
5001
|
-
showReminders: gcShowReminders?.checked ?? false,
|
|
5002
|
-
showLastSession: gcShowLastSession?.checked ?? false,
|
|
5003
|
-
reminders,
|
|
5004
|
-
};
|
|
5005
|
-
gcSave.style.opacity = '0.5';
|
|
5006
|
-
gcSave.style.pointerEvents = 'none';
|
|
5007
|
-
try {
|
|
5008
|
-
const res = await fetch(`${saveBaseUrl}/${encodeURIComponent(project)}`, {
|
|
5009
|
-
method: 'PUT',
|
|
5010
|
-
headers: { 'Content-Type': 'application/json' },
|
|
5011
|
-
body: JSON.stringify(body),
|
|
5012
|
-
});
|
|
5013
|
-
const data = await res.json();
|
|
5014
|
-
if (!data.ok) {
|
|
5015
|
-
alert(data.error || kit.tx('settings.redesign.hooks.failedToSave'));
|
|
5016
|
-
return;
|
|
5017
|
-
}
|
|
5018
|
-
onSave(project, body);
|
|
5019
|
-
showCCToast(kit.tx('settings.redesign.hooks.greetingConfigSaved'));
|
|
5020
|
-
} catch (err) {
|
|
5021
|
-
alert(kit.tx('settings.redesign.hooks.failed2', { message: err.message }));
|
|
5022
|
-
} finally {
|
|
5023
|
-
gcSave.style.opacity = '';
|
|
5024
|
-
gcSave.style.pointerEvents = '';
|
|
5025
|
-
}
|
|
5026
|
-
});
|
|
5027
|
-
|
|
5028
|
-
wireReminderRemoveButtons();
|
|
5029
|
-
wireReminderDragHandles();
|
|
5030
|
-
|
|
5031
|
-
const csToggle = overlay.querySelector(`#${prefix}-greeting-cheatsheet-toggle`);
|
|
5032
|
-
const csPanel = overlay.querySelector(`#${prefix}-greeting-cheatsheet`);
|
|
5033
|
-
if (csToggle && csPanel) {
|
|
5034
|
-
const updateCheatsheetPreview = () => {
|
|
5035
|
-
const hour = new Date().getHours();
|
|
5036
|
-
const timeGreeting = hour >= 5 && hour < 12 ? kit.tx('settings.redesign.hooks.goodMorning') : hour >= 12 && hour < 17 ? kit.tx('settings.redesign.hooks.goodAfternoon') : kit.tx('settings.redesign.hooks.goodEvening');
|
|
5037
|
-
const dateStr = new Date().toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
|
5038
|
-
const key = gcSelect.value || 'global';
|
|
5039
|
-
const gc = configRef() || {};
|
|
5040
|
-
const projCfg = key === 'global' ? gc.global : gc.projects?.[key];
|
|
5041
|
-
const label = projCfg?.label || key;
|
|
5042
|
-
const name = key === 'global' ? 'global' : key;
|
|
5043
|
-
|
|
5044
|
-
overlay.querySelector(`#${prefix}-cs-time`).textContent = timeGreeting;
|
|
5045
|
-
overlay.querySelector(`#${prefix}-cs-label`).textContent = label;
|
|
5046
|
-
overlay.querySelector(`#${prefix}-cs-name`).textContent = name;
|
|
5047
|
-
overlay.querySelector(`#${prefix}-cs-branch`).textContent = kit.tx('settings.redesign.hooks.dev');
|
|
5048
|
-
overlay.querySelector(`#${prefix}-cs-date`).textContent = dateStr;
|
|
5049
|
-
|
|
5050
|
-
const tpl = gcTemplate.value || '{time_greeting}! Working on **{project_label}** ({branch} branch). {date}.';
|
|
5051
|
-
const resolved = tpl
|
|
5052
|
-
.replace(/\{time_greeting\}/g, timeGreeting)
|
|
5053
|
-
.replace(/\{project_label\}/g, label)
|
|
5054
|
-
.replace(/\{project_name\}/g, name)
|
|
5055
|
-
.replace(/\{branch\}/g, 'dev')
|
|
5056
|
-
.replace(/\{date\}/g, dateStr)
|
|
5057
|
-
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
|
5058
|
-
.replace(/`(.+?)`/g, '<code>$1</code>');
|
|
5059
|
-
overlay.querySelector(`#${prefix}-cs-preview`).innerHTML = resolved;
|
|
5060
|
-
};
|
|
5061
|
-
|
|
5062
|
-
csToggle.addEventListener('click', () => {
|
|
5063
|
-
const open = csPanel.style.display !== 'none';
|
|
5064
|
-
csPanel.style.display = open ? 'none' : 'block';
|
|
5065
|
-
csToggle.classList.toggle('open', !open);
|
|
5066
|
-
if (!open) updateCheatsheetPreview();
|
|
5067
|
-
});
|
|
5068
|
-
gcSelect.addEventListener('change', () => {
|
|
5069
|
-
if (csPanel.style.display !== 'none') updateCheatsheetPreview();
|
|
5070
|
-
});
|
|
5071
|
-
gcTemplate.addEventListener('input', () => {
|
|
5072
|
-
if (csPanel.style.display !== 'none') updateCheatsheetPreview();
|
|
5073
|
-
});
|
|
5074
|
-
}
|
|
5075
|
-
}
|
|
5076
|
-
|
|
5077
|
-
wireGreetingEditor({
|
|
5078
|
-
prefix: 'cc',
|
|
5079
|
-
configRef: () => greetingConfig,
|
|
5080
|
-
saveBaseUrl: '/api/greeting/config',
|
|
5081
|
-
onSave: (project, body) => {
|
|
5082
|
-
const target = project === 'global'
|
|
5083
|
-
? (greetingConfig.global || (greetingConfig.global = {}))
|
|
5084
|
-
: (greetingConfig.projects[project] || (greetingConfig.projects[project] = {}));
|
|
5085
|
-
Object.assign(target, body);
|
|
5086
|
-
},
|
|
5087
|
-
});
|
|
5088
|
-
|
|
5089
|
-
wireGreetingEditor({
|
|
5090
|
-
prefix: 'codex',
|
|
5091
|
-
configRef: () => codexGreetingConfig,
|
|
5092
|
-
saveBaseUrl: '/api/codex-panel/greeting/config',
|
|
5093
|
-
onSave: (project, body) => {
|
|
5094
|
-
const target = project === 'global'
|
|
5095
|
-
? (codexGreetingConfig.global || (codexGreetingConfig.global = {}))
|
|
5096
|
-
: (codexGreetingConfig.projects[project] || (codexGreetingConfig.projects[project] = {}));
|
|
5097
|
-
Object.assign(target, body);
|
|
5098
|
-
},
|
|
5099
|
-
});
|
|
5100
|
-
|
|
5101
|
-
wireGreetingEditor({
|
|
5102
|
-
prefix: 'opencode',
|
|
5103
|
-
configRef: () => opencodeGreetingConfig,
|
|
5104
|
-
saveBaseUrl: '/api/opencode-panel/greeting/config',
|
|
5105
|
-
onSave: (project, body) => {
|
|
5106
|
-
const target = project === 'global'
|
|
5107
|
-
? (opencodeGreetingConfig.global || (opencodeGreetingConfig.global = {}))
|
|
5108
|
-
: (opencodeGreetingConfig.projects[project] || (opencodeGreetingConfig.projects[project] = {}));
|
|
5109
|
-
Object.assign(target, body);
|
|
5110
|
-
},
|
|
5111
|
-
});
|
|
5112
|
-
|
|
5113
5149
|
// Per-project toggles
|
|
5114
5150
|
overlay.querySelectorAll('.cc-enable-btn[data-cc-project-toggle]').forEach(btn => {
|
|
5115
5151
|
btn.addEventListener('click', () => { const idx = btn.dataset.ccProjectToggle; const panel = overlay.querySelector(`.cc-panel[data-cc-idx="${idx}"]`); const projectPath = panel?.dataset.ccPath; if (projectPath) ccToggleHook('project', projectPath, btn, panel); });
|
|
@@ -6442,69 +6478,48 @@ export async function openSettingsModal(options = {}) {
|
|
|
6442
6478
|
|
|
6443
6479
|
}
|
|
6444
6480
|
|
|
6445
|
-
// ──
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
} else if (attempts >= 30) { clearInterval(poll); if (label) label.textContent = kit.tx('settings.redesign.hooks.timeout'); if (urlEl) urlEl.textContent = kit.tx('settings.redesign.hooks.failedToGetTunnelUrlCheck'); }
|
|
6488
|
-
} catch {}
|
|
6489
|
-
}, 1000);
|
|
6490
|
-
}
|
|
6491
|
-
} else { alert(data.error || kit.tx('settings.redesign.hooks.failed')); }
|
|
6492
|
-
} catch (err) { alert(kit.tx('settings.redesign.hooks.failed2', { message: err.message })); }
|
|
6493
|
-
finally { tunnelToggle.style.opacity = ''; tunnelToggle.style.pointerEvents = ''; }
|
|
6494
|
-
});
|
|
6495
|
-
}
|
|
6496
|
-
|
|
6497
|
-
// Copy tunnel MCP URL
|
|
6498
|
-
const tunnelCopy = overlay.querySelector('#cc-tunnel-copy-url');
|
|
6499
|
-
if (tunnelCopy) {
|
|
6500
|
-
tunnelCopy.addEventListener('click', () => {
|
|
6501
|
-
const urlEl = overlay.querySelector('#cc-tunnel-url'); const baseUrl = urlEl?.textContent || '';
|
|
6502
|
-
if (!baseUrl) { alert(kit.tx('settings.redesign.hooks.tunnelUrlNotAvailable')); return; }
|
|
6503
|
-
const tunnelMcpUrl = mcpKeyInfo.key ? baseUrl + '/mcp/' + mcpKeyInfo.key : baseUrl + '/mcp';
|
|
6504
|
-
navigator.clipboard.writeText(tunnelMcpUrl);
|
|
6505
|
-
tunnelCopy.innerHTML = '<svg viewBox="0 0 24 24" style="width:12px;height:12px"><polyline points="20 6 9 17 4 12"/></svg> ' + kit.te('settings.redesign.hooks.copied') + '';
|
|
6506
|
-
setTimeout(() => { tunnelCopy.innerHTML = '<svg viewBox="0 0 24 24" style="width:12px;height:12px"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg> ' + kit.te('settings.redesign.hooks.copyMcpUrl') + ''; }, 2000);
|
|
6507
|
-
});
|
|
6481
|
+
// ── Public address (the Cloudflare tunnel) ──
|
|
6482
|
+
// One block, drawn again whenever the server says something new: ui-tunnel.js asks again by itself while the
|
|
6483
|
+
// tunnel program is being downloaded or a start waits for its address, for as long as this dialog is open.
|
|
6484
|
+
// A start on a machine that has no cloudflared fetches it and goes on by itself: one press.
|
|
6485
|
+
let redrawTunnelBox = () => {};
|
|
6486
|
+
let latestTunnelStatus = () => tunnelStatus;
|
|
6487
|
+
const tunnelRow = overlay.querySelector('#cc-tunnel-row');
|
|
6488
|
+
const tunnelExtra = overlay.querySelector('#cc-tunnel-extra');
|
|
6489
|
+
if (tunnelRow && tunnelExtra) {
|
|
6490
|
+
const drawTunnel = (view) => {
|
|
6491
|
+
tunnelRow.classList.toggle('enabled', view.on);
|
|
6492
|
+
drawInto(tunnelRow, tunnelRowHtml(view));
|
|
6493
|
+
drawInto(tunnelExtra, tunnelExtraHtml(view, mcpKeyInfo));
|
|
6494
|
+
};
|
|
6495
|
+
const tunnelCard = createTunnelCard({ alive: () => tunnelRow.isConnected, onChange: drawTunnel });
|
|
6496
|
+
latestTunnelStatus = () => tunnelCard.status() || tunnelStatus;
|
|
6497
|
+
redrawTunnelBox = () => drawTunnel(tunnelCard.view());
|
|
6498
|
+
tunnelCard.show(tunnelStatus);
|
|
6499
|
+
const onTunnelClick = async (event) => {
|
|
6500
|
+
const button = event.target.closest('button');
|
|
6501
|
+
if (!button || !(tunnelRow.contains(button) || tunnelExtra.contains(button))) return;
|
|
6502
|
+
if (button.id === 'cc-tunnel-toggle' || button.id === 'cc-tunnel-retry') {
|
|
6503
|
+
const action = tunnelCard.view().action;
|
|
6504
|
+
if (action === 'start' || action === 'retry') {
|
|
6505
|
+
// Shown at once; the server answers immediately too, and then says what it is doing.
|
|
6506
|
+
tunnelCard.show({ ...(tunnelCard.status() || {}), state: 'starting', starting: true, url: null, error: null });
|
|
6507
|
+
await tunnelCard.start();
|
|
6508
|
+
} else if (action === 'stop' || action === 'cancel') {
|
|
6509
|
+
await tunnelCard.stop();
|
|
6510
|
+
}
|
|
6511
|
+
} else if (button.id === 'cc-tunnel-copy-url') {
|
|
6512
|
+
// The remote MCP address is the public one with the access key in it: there is none without a key.
|
|
6513
|
+
const address = remoteMcpAddress(tunnelCard.view().url, mcpKeyInfo?.key);
|
|
6514
|
+
if (!address) { redrawTunnelBox(); return; }
|
|
6515
|
+
navigator.clipboard.writeText(address);
|
|
6516
|
+
const before = button.innerHTML;
|
|
6517
|
+
button.innerHTML = '<svg viewBox="0 0 24 24" style="width:12px;height:12px"><polyline points="20 6 9 17 4 12"/></svg> ' + kit.te('settings.redesign.hooks.copied') + '';
|
|
6518
|
+
setTimeout(() => { if (button.isConnected) button.innerHTML = before; }, 2000);
|
|
6519
|
+
}
|
|
6520
|
+
};
|
|
6521
|
+
tunnelRow.addEventListener('click', onTunnelClick);
|
|
6522
|
+
tunnelExtra.addEventListener('click', onTunnelClick);
|
|
6508
6523
|
}
|
|
6509
6524
|
|
|
6510
6525
|
// ── API key generate / copy / revoke ──
|
|
@@ -6589,6 +6604,7 @@ export async function openSettingsModal(options = {}) {
|
|
|
6589
6604
|
if (statusEl) statusEl.textContent = '***' + data.key.slice(-8);
|
|
6590
6605
|
if (row) row.classList.add('enabled');
|
|
6591
6606
|
apikeyGenBtn.textContent = kit.tx('settings.redesign.hooks.regenerate');
|
|
6607
|
+
redrawTunnelBox();
|
|
6592
6608
|
} else { alert(data.error || kit.tx('settings.redesign.hooks.failedToGenerateKey')); }
|
|
6593
6609
|
} catch (err) { alert(kit.tx('settings.redesign.hooks.failed2', { message: err.message })); }
|
|
6594
6610
|
finally { apikeyGenBtn.style.opacity = ''; apikeyGenBtn.style.pointerEvents = ''; }
|
|
@@ -6606,15 +6622,18 @@ export async function openSettingsModal(options = {}) {
|
|
|
6606
6622
|
const apikeyRevokeBtn = overlay.querySelector('#cc-apikey-revoke');
|
|
6607
6623
|
if (apikeyRevokeBtn) {
|
|
6608
6624
|
apikeyRevokeBtn.addEventListener('click', async () => {
|
|
6609
|
-
|
|
6625
|
+
// What a revoke leaves behind depends on the server that runs: see closesKeylessMcp.
|
|
6626
|
+
const closed = closesKeylessMcp(latestTunnelStatus());
|
|
6627
|
+
if (!confirm(kit.tx(closed ? 'settings.redesign.hooks.revokeKeyClosed' : 'settings.redesign.hooks.revokeThisApiKeyTheMcp'))) return;
|
|
6610
6628
|
try {
|
|
6611
6629
|
const res = await fetch('/api/mcp-key', { method: 'DELETE' }); const data = await res.json();
|
|
6612
6630
|
if (data.ok) {
|
|
6613
6631
|
mcpKeyInfo = { hasKey: false };
|
|
6614
6632
|
const reveal = overlay.querySelector('#cc-apikey-reveal'); if (reveal) reveal.style.display = 'none';
|
|
6615
|
-
const statusEl = overlay.querySelector('#cc-apikey-status'); if (statusEl) statusEl.textContent = kit.tx('settings.redesign.hooks.
|
|
6633
|
+
const statusEl = overlay.querySelector('#cc-apikey-status'); if (statusEl) statusEl.textContent = kit.tx(closed ? 'settings.redesign.hooks.apikey.noneClosed' : 'settings.redesign.hooks.apikey.none');
|
|
6616
6634
|
const row = overlay.querySelector('#cc-apikey-row'); if (row) row.classList.remove('enabled');
|
|
6617
6635
|
const genBtn = overlay.querySelector('#cc-apikey-generate'); if (genBtn) genBtn.textContent = kit.tx('settings.redesign.hooks.generateKey');
|
|
6636
|
+
redrawTunnelBox();
|
|
6618
6637
|
}
|
|
6619
6638
|
} catch (err) { alert(kit.tx('settings.redesign.hooks.failed2', { message: err.message })); }
|
|
6620
6639
|
});
|