synabun 2.0.5 → 2.0.9
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 +78 -0
- package/README.md +2 -1
- package/THIRD-PARTY-LICENSES.md +13 -0
- package/docs/whatsapp.md +151 -16
- package/hooks/claude-code/post-plan.mjs +6 -30
- package/hooks/claude-code/session-start.mjs +1 -4
- package/hooks/claude-code/shared.mjs +112 -75
- 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/package-processes.js +670 -0
- package/lib/packaged-runtime.js +138 -11
- package/lib/runtime-dependencies.js +225 -0
- 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/browser-bench.d.ts +1 -1
- package/mcp-server/dist/services/browser-bench.d.ts.map +1 -1
- package/mcp-server/dist/services/browser-bench.js +1 -1
- package/mcp-server/dist/services/browser-bench.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/categories.d.ts +35 -2
- package/mcp-server/dist/services/categories.d.ts.map +1 -1
- package/mcp-server/dist/services/categories.js +77 -33
- package/mcp-server/dist/services/categories.js.map +1 -1
- 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/desktop-bench.d.ts +7 -7
- package/mcp-server/dist/services/desktop-bench.d.ts.map +1 -1
- package/mcp-server/dist/services/desktop-bench.js +1 -1
- package/mcp-server/dist/services/desktop-bench.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 +11 -8
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +35 -14
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/bluesky.js +1 -1
- package/mcp-server/dist/tools/bluesky.js.map +1 -1
- package/mcp-server/dist/tools/browser-advanced.d.ts +1 -1
- package/mcp-server/dist/tools/browser-advanced.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-advanced.js +1 -1
- package/mcp-server/dist/tools/browser-advanced.js.map +1 -1
- package/mcp-server/dist/tools/browser-batch.d.ts +1 -1
- package/mcp-server/dist/tools/browser-batch.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-batch.js +1 -1
- package/mcp-server/dist/tools/browser-batch.js.map +1 -1
- package/mcp-server/dist/tools/browser-cheatsheet.d.ts +1 -1
- package/mcp-server/dist/tools/browser-cheatsheet.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-cheatsheet.js +1 -1
- package/mcp-server/dist/tools/browser-cheatsheet.js.map +1 -1
- package/mcp-server/dist/tools/browser-interact.d.ts +1 -1
- package/mcp-server/dist/tools/browser-interact.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-interact.js +1 -1
- package/mcp-server/dist/tools/browser-interact.js.map +1 -1
- package/mcp-server/dist/tools/browser-navigate.d.ts +1 -1
- package/mcp-server/dist/tools/browser-navigate.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-navigate.js +1 -1
- package/mcp-server/dist/tools/browser-navigate.js.map +1 -1
- package/mcp-server/dist/tools/browser-observe.d.ts +1 -1
- package/mcp-server/dist/tools/browser-observe.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-observe.js +1 -1
- package/mcp-server/dist/tools/browser-observe.js.map +1 -1
- package/mcp-server/dist/tools/card-tools.d.ts +1 -1
- package/mcp-server/dist/tools/card-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/card-tools.js +1 -1
- package/mcp-server/dist/tools/card-tools.js.map +1 -1
- package/mcp-server/dist/tools/category.d.ts +1 -1
- package/mcp-server/dist/tools/category.d.ts.map +1 -1
- package/mcp-server/dist/tools/category.js +5 -1
- package/mcp-server/dist/tools/category.js.map +1 -1
- package/mcp-server/dist/tools/choice.d.ts +1 -1
- package/mcp-server/dist/tools/choice.d.ts.map +1 -1
- package/mcp-server/dist/tools/choice.js +1 -1
- package/mcp-server/dist/tools/choice.js.map +1 -1
- package/mcp-server/dist/tools/computer.d.ts +1 -1
- package/mcp-server/dist/tools/computer.d.ts.map +1 -1
- package/mcp-server/dist/tools/computer.js +1 -1
- package/mcp-server/dist/tools/computer.js.map +1 -1
- package/mcp-server/dist/tools/discord-channel.d.ts +1 -1
- package/mcp-server/dist/tools/discord-channel.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-channel.js +1 -1
- package/mcp-server/dist/tools/discord-channel.js.map +1 -1
- package/mcp-server/dist/tools/discord-guild.d.ts +1 -1
- package/mcp-server/dist/tools/discord-guild.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-guild.js +1 -1
- package/mcp-server/dist/tools/discord-guild.js.map +1 -1
- package/mcp-server/dist/tools/discord-member.d.ts +1 -1
- package/mcp-server/dist/tools/discord-member.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-member.js +1 -1
- package/mcp-server/dist/tools/discord-member.js.map +1 -1
- package/mcp-server/dist/tools/discord-message.d.ts +1 -1
- package/mcp-server/dist/tools/discord-message.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-message.js +1 -1
- package/mcp-server/dist/tools/discord-message.js.map +1 -1
- package/mcp-server/dist/tools/discord-onboarding.d.ts +1 -1
- package/mcp-server/dist/tools/discord-onboarding.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-onboarding.js +1 -1
- package/mcp-server/dist/tools/discord-onboarding.js.map +1 -1
- package/mcp-server/dist/tools/discord-role.d.ts +1 -1
- package/mcp-server/dist/tools/discord-role.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-role.js +1 -1
- package/mcp-server/dist/tools/discord-role.js.map +1 -1
- package/mcp-server/dist/tools/discord-thread.d.ts +1 -1
- package/mcp-server/dist/tools/discord-thread.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-thread.js +1 -1
- package/mcp-server/dist/tools/discord-thread.js.map +1 -1
- package/mcp-server/dist/tools/discord-webhook.d.ts +1 -1
- package/mcp-server/dist/tools/discord-webhook.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-webhook.js +1 -1
- package/mcp-server/dist/tools/discord-webhook.js.map +1 -1
- package/mcp-server/dist/tools/fb-groups.d.ts +1 -1
- package/mcp-server/dist/tools/fb-groups.d.ts.map +1 -1
- package/mcp-server/dist/tools/fb-groups.js +1 -1
- package/mcp-server/dist/tools/fb-groups.js.map +1 -1
- package/mcp-server/dist/tools/forget.d.ts +1 -1
- package/mcp-server/dist/tools/forget.d.ts.map +1 -1
- package/mcp-server/dist/tools/forget.js +1 -1
- package/mcp-server/dist/tools/forget.js.map +1 -1
- package/mcp-server/dist/tools/git-tools.d.ts +1 -1
- package/mcp-server/dist/tools/git-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/git-tools.js +1 -1
- package/mcp-server/dist/tools/git-tools.js.map +1 -1
- package/mcp-server/dist/tools/gsc/experience.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/experience.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/experience.js +1 -1
- package/mcp-server/dist/tools/gsc/experience.js.map +1 -1
- package/mcp-server/dist/tools/gsc/indexing.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/indexing.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/indexing.js +1 -1
- package/mcp-server/dist/tools/gsc/indexing.js.map +1 -1
- package/mcp-server/dist/tools/gsc/inspect.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/inspect.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/inspect.js +1 -1
- package/mcp-server/dist/tools/gsc/inspect.js.map +1 -1
- package/mcp-server/dist/tools/gsc/navigate.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/navigate.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/navigate.js +1 -1
- package/mcp-server/dist/tools/gsc/navigate.js.map +1 -1
- package/mcp-server/dist/tools/gsc/performance.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/performance.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/performance.js +1 -1
- package/mcp-server/dist/tools/gsc/performance.js.map +1 -1
- package/mcp-server/dist/tools/gsc/settings.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/settings.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/settings.js +1 -1
- package/mcp-server/dist/tools/gsc/settings.js.map +1 -1
- package/mcp-server/dist/tools/image-tools.d.ts +1 -1
- package/mcp-server/dist/tools/image-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/image-tools.js +1 -1
- package/mcp-server/dist/tools/image-tools.js.map +1 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +1 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.js +1 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.js.map +1 -1
- package/mcp-server/dist/tools/loop.d.ts +1 -1
- package/mcp-server/dist/tools/loop.d.ts.map +1 -1
- package/mcp-server/dist/tools/loop.js +1 -1
- package/mcp-server/dist/tools/loop.js.map +1 -1
- package/mcp-server/dist/tools/memories.d.ts +1 -1
- package/mcp-server/dist/tools/memories.d.ts.map +1 -1
- package/mcp-server/dist/tools/memories.js +1 -1
- package/mcp-server/dist/tools/memories.js.map +1 -1
- package/mcp-server/dist/tools/morelogin.d.ts +1 -1
- package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
- package/mcp-server/dist/tools/morelogin.js +1 -1
- package/mcp-server/dist/tools/morelogin.js.map +1 -1
- package/mcp-server/dist/tools/profile.d.ts +1 -1
- package/mcp-server/dist/tools/profile.d.ts.map +1 -1
- package/mcp-server/dist/tools/profile.js +1 -1
- package/mcp-server/dist/tools/profile.js.map +1 -1
- package/mcp-server/dist/tools/recall.d.ts +1 -1
- package/mcp-server/dist/tools/recall.d.ts.map +1 -1
- package/mcp-server/dist/tools/recall.js +1 -1
- package/mcp-server/dist/tools/recall.js.map +1 -1
- package/mcp-server/dist/tools/reflect.d.ts +1 -1
- package/mcp-server/dist/tools/reflect.d.ts.map +1 -1
- package/mcp-server/dist/tools/reflect.js +1 -1
- package/mcp-server/dist/tools/reflect.js.map +1 -1
- package/mcp-server/dist/tools/remember.d.ts +1 -1
- package/mcp-server/dist/tools/remember.d.ts.map +1 -1
- package/mcp-server/dist/tools/remember.js +13 -11
- package/mcp-server/dist/tools/remember.js.map +1 -1
- package/mcp-server/dist/tools/restore.d.ts +1 -1
- package/mcp-server/dist/tools/restore.d.ts.map +1 -1
- package/mcp-server/dist/tools/restore.js +1 -1
- package/mcp-server/dist/tools/restore.js.map +1 -1
- package/mcp-server/dist/tools/style-guide-tools.d.ts +1 -1
- package/mcp-server/dist/tools/style-guide-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/style-guide-tools.js +1 -1
- package/mcp-server/dist/tools/style-guide-tools.js.map +1 -1
- package/mcp-server/dist/tools/sync.d.ts +1 -1
- package/mcp-server/dist/tools/sync.d.ts.map +1 -1
- package/mcp-server/dist/tools/sync.js +1 -1
- package/mcp-server/dist/tools/sync.js.map +1 -1
- package/mcp-server/dist/tools/tictactoe-tools.d.ts +1 -1
- package/mcp-server/dist/tools/tictactoe-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/tictactoe-tools.js +1 -1
- package/mcp-server/dist/tools/tictactoe-tools.js.map +1 -1
- package/mcp-server/dist/tools/utils.d.ts +1 -1
- package/mcp-server/dist/tools/utils.d.ts.map +1 -1
- package/mcp-server/dist/tools/utils.js +1 -1
- package/mcp-server/dist/tools/utils.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/tools/whiteboard-tools.d.ts +3 -3
- package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.js +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
- package/mcp-server/dist/tools/youtube/analytics.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/analytics.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/analytics.js +1 -1
- package/mcp-server/dist/tools/youtube/analytics.js.map +1 -1
- package/mcp-server/dist/tools/youtube/download.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/download.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/download.js +1 -1
- package/mcp-server/dist/tools/youtube/download.js.map +1 -1
- package/mcp-server/dist/tools/youtube/media.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/media.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/media.js +1 -1
- package/mcp-server/dist/tools/youtube/media.js.map +1 -1
- package/mcp-server/dist/tools/youtube/metadata.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/metadata.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/metadata.js +1 -1
- package/mcp-server/dist/tools/youtube/metadata.js.map +1 -1
- package/mcp-server/dist/tools/youtube/navigate.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/navigate.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/navigate.js +1 -1
- package/mcp-server/dist/tools/youtube/navigate.js.map +1 -1
- package/mcp-server/dist/tools/youtube/playlist.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/playlist.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/playlist.js +1 -1
- package/mcp-server/dist/tools/youtube/playlist.js.map +1 -1
- package/mcp-server/dist/tools/youtube/schedule.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/schedule.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/schedule.js +1 -1
- package/mcp-server/dist/tools/youtube/schedule.js.map +1 -1
- package/mcp-server/dist/tools/youtube/source.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/source.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/source.js +1 -1
- package/mcp-server/dist/tools/youtube/source.js.map +1 -1
- package/mcp-server/dist/tools/youtube/upload.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/upload.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/upload.js +4 -9
- package/mcp-server/dist/tools/youtube/upload.js.map +1 -1
- package/mcp-server/dist/tui.js +18 -5
- 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 +3 -3
- package/mcp-server/package.json +3 -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/browser-bench.ts +1 -1
- package/mcp-server/src/services/budget-judgments.ts +183 -0
- package/mcp-server/src/services/categories.ts +77 -32
- package/mcp-server/src/services/codex-config-heal.ts +35 -4
- package/mcp-server/src/services/desktop-bench.ts +1 -1
- 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 +34 -15
- package/mcp-server/src/tools/bluesky.ts +1 -1
- package/mcp-server/src/tools/browser-advanced.ts +1 -1
- package/mcp-server/src/tools/browser-batch.ts +1 -1
- package/mcp-server/src/tools/browser-cheatsheet.ts +1 -1
- package/mcp-server/src/tools/browser-interact.ts +1 -1
- package/mcp-server/src/tools/browser-navigate.ts +1 -1
- package/mcp-server/src/tools/browser-observe.ts +1 -1
- package/mcp-server/src/tools/card-tools.ts +1 -1
- package/mcp-server/src/tools/category.ts +6 -1
- package/mcp-server/src/tools/choice.ts +1 -1
- package/mcp-server/src/tools/computer.ts +1 -1
- package/mcp-server/src/tools/discord-channel.ts +1 -1
- package/mcp-server/src/tools/discord-guild.ts +1 -1
- package/mcp-server/src/tools/discord-member.ts +1 -1
- package/mcp-server/src/tools/discord-message.ts +1 -1
- package/mcp-server/src/tools/discord-onboarding.ts +1 -1
- package/mcp-server/src/tools/discord-role.ts +1 -1
- package/mcp-server/src/tools/discord-thread.ts +1 -1
- package/mcp-server/src/tools/discord-webhook.ts +1 -1
- package/mcp-server/src/tools/fb-groups.ts +1 -1
- package/mcp-server/src/tools/forget.ts +1 -1
- package/mcp-server/src/tools/git-tools.ts +1 -1
- package/mcp-server/src/tools/gsc/experience.ts +1 -1
- package/mcp-server/src/tools/gsc/indexing.ts +1 -1
- package/mcp-server/src/tools/gsc/inspect.ts +1 -1
- package/mcp-server/src/tools/gsc/navigate.ts +1 -1
- package/mcp-server/src/tools/gsc/performance.ts +1 -1
- package/mcp-server/src/tools/gsc/settings.ts +1 -1
- package/mcp-server/src/tools/image-tools.ts +1 -1
- package/mcp-server/src/tools/leonardo-browser-tools.ts +1 -1
- package/mcp-server/src/tools/loop.ts +1 -1
- package/mcp-server/src/tools/memories.ts +1 -1
- package/mcp-server/src/tools/morelogin.ts +1 -1
- package/mcp-server/src/tools/profile.ts +1 -1
- package/mcp-server/src/tools/recall.ts +1 -1
- package/mcp-server/src/tools/reflect.ts +1 -1
- package/mcp-server/src/tools/remember.ts +13 -12
- package/mcp-server/src/tools/restore.ts +1 -1
- package/mcp-server/src/tools/style-guide-tools.ts +1 -1
- package/mcp-server/src/tools/sync.ts +1 -1
- package/mcp-server/src/tools/tictactoe-tools.ts +1 -1
- package/mcp-server/src/tools/utils.ts +1 -1
- package/mcp-server/src/tools/whatsapp-send-file.ts +51 -0
- package/mcp-server/src/tools/whiteboard-tools.ts +1 -1
- package/mcp-server/src/tools/youtube/analytics.ts +1 -1
- package/mcp-server/src/tools/youtube/download.ts +1 -1
- package/mcp-server/src/tools/youtube/media.ts +1 -1
- package/mcp-server/src/tools/youtube/metadata.ts +1 -1
- package/mcp-server/src/tools/youtube/navigate.ts +1 -1
- package/mcp-server/src/tools/youtube/playlist.ts +1 -1
- package/mcp-server/src/tools/youtube/schedule.ts +1 -1
- package/mcp-server/src/tools/youtube/source.ts +1 -1
- package/mcp-server/src/tools/youtube/upload.ts +4 -12
- package/mcp-server/src/tui.ts +24 -10
- package/mcp-server/src/version.ts +22 -0
- package/neural-interface/i18n/en.json +645 -57
- package/neural-interface/i18n/pt-BR.json +644 -56
- package/neural-interface/lib/account-usage.js +163 -0
- package/neural-interface/lib/agent-sandbox-elevation.js +102 -0
- package/neural-interface/lib/agent-sandbox-setting.js +57 -0
- package/neural-interface/lib/assistant-api.js +274 -52
- package/neural-interface/lib/assistant-brains/claude.js +15 -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-config.js +62 -14
- package/neural-interface/lib/assistant-dispatch.js +432 -125
- package/neural-interface/lib/assistant-jev.js +26 -3
- package/neural-interface/lib/assistant-persona.js +68 -11
- package/neural-interface/lib/assistant-plan-permissions.js +8 -1
- package/neural-interface/lib/assistant-route-accounts.js +14 -0
- package/neural-interface/lib/assistant-route-gate-codex.js +3 -1
- 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 +312 -48
- package/neural-interface/lib/assistant-user-writer.js +4 -2
- package/neural-interface/lib/augmented-path.js +317 -53
- package/neural-interface/lib/claude-accounts.js +342 -31
- package/neural-interface/lib/claude-agent-bridge.js +90 -3
- package/neural-interface/lib/claude-executable.js +6 -1
- package/neural-interface/lib/claude-model-catalog.js +3 -3
- 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/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/codex-account-auth.js +180 -0
- package/neural-interface/lib/codex-accounts.js +502 -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 +122 -0
- package/neural-interface/lib/desktop/config.js +3 -0
- package/neural-interface/lib/exec-loop-command.js +3 -1
- 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-read.js +34 -2
- package/neural-interface/lib/install-details.js +163 -0
- package/neural-interface/lib/mcp-installer.js +14 -2
- package/neural-interface/lib/native-loop-providers.js +22 -4
- package/neural-interface/lib/native-loop-runtime.js +9 -4
- package/neural-interface/lib/os-path.js +319 -0
- package/neural-interface/lib/provider-panel-api-key-auth.js +92 -0
- package/neural-interface/lib/provider-panel-terminal-auth.js +96 -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/session-indexer.js +3 -1
- package/neural-interface/lib/session-title-generator.js +6 -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/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 +2 -2
- package/neural-interface/package.json +1 -1
- package/neural-interface/public/index.html +2 -0
- package/neural-interface/public/index2d.html +2 -0
- package/neural-interface/public/offline.html +16 -1
- package/neural-interface/public/onboarding.html +96 -2
- package/neural-interface/public/shared/account-i18n.js +7 -0
- package/neural-interface/public/shared/account-menu.js +542 -0
- package/neural-interface/public/shared/account-usage.js +79 -0
- package/neural-interface/public/shared/account-view.js +336 -0
- package/neural-interface/public/shared/agent-runtime-options.js +28 -8
- package/neural-interface/public/shared/assistant/asst-account-menu.js +298 -0
- package/neural-interface/public/shared/assistant/asst-accounts.js +182 -184
- package/neural-interface/public/shared/assistant/asst-api.js +39 -2
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +288 -32
- package/neural-interface/public/shared/assistant/asst-budget.js +259 -303
- package/neural-interface/public/shared/assistant/asst-mascot.js +126 -7
- package/neural-interface/public/shared/assistant/asst-menu.js +219 -80
- package/neural-interface/public/shared/assistant/asst-model-chip.js +135 -0
- package/neural-interface/public/shared/assistant/asst-panel.js +87 -16
- package/neural-interface/public/shared/assistant/asst-render.js +38 -7
- package/neural-interface/public/shared/assistant/asst-route.js +72 -14
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +45 -6
- package/neural-interface/public/shared/assistant/asst-slash.js +1 -1
- package/neural-interface/public/shared/assistant/asst-state.js +1 -1
- package/neural-interface/public/shared/assistant/asst-styles.js +160 -29
- 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 +49 -108
- package/neural-interface/public/shared/cdx/cdx-settings.js +231 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +172 -111
- package/neural-interface/public/shared/cdx/cdx-tabs.js +264 -664
- 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/cp/cp-events.js +2 -1
- package/neural-interface/public/shared/cp/cp-styles.js +46 -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-panel.js +1 -1
- package/neural-interface/public/shared/explorer/fx-main.js +1 -1
- package/neural-interface/public/shared/git-bash-view.js +145 -0
- package/neural-interface/public/shared/html-shell.js +1 -0
- 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 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +36 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +17 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +169 -2
- package/neural-interface/public/shared/pwa-install-page.js +3 -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-ia.js +15 -0
- package/neural-interface/public/shared/showcase-privacy.js +490 -0
- package/neural-interface/public/shared/storage.js +30 -3
- package/neural-interface/public/shared/styles.css +281 -32
- package/neural-interface/public/shared/synabun-mascot.js +48 -2
- package/neural-interface/public/shared/ui-claude-panel.js +262 -217
- package/neural-interface/public/shared/ui-cli-banner.js +355 -0
- package/neural-interface/public/shared/ui-explorer.js +2 -0
- package/neural-interface/public/shared/ui-git-bash.js +124 -0
- package/neural-interface/public/shared/ui-judgments.js +10 -1
- package/neural-interface/public/shared/ui-loading.js +30 -6
- package/neural-interface/public/shared/ui-menubar.js +13 -3
- package/neural-interface/public/shared/ui-navbar.js +3 -1
- 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 +55 -3
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -1
- package/neural-interface/public/shared/ui-sync.js +8 -0
- package/neural-interface/public/shared/ui-terminal.js +17 -0
- package/neural-interface/public/shared/ui-tool-updates.js +5 -0
- package/neural-interface/public/shared/ui-update.js +598 -7
- package/neural-interface/public/shared/ui-whatsapp.js +21 -6
- package/neural-interface/public/shared/whatsapp/wa-view.js +51 -8
- package/neural-interface/public/shared/worker-end.js +2 -0
- package/neural-interface/public/sw.js +1 -1
- package/neural-interface/public/variant/2d/main.js +10 -1
- package/neural-interface/public/variant/3d/main.js +10 -1
- package/neural-interface/scripts/rebuild-pty.js +14 -2
- package/neural-interface/server.js +1384 -679
- package/npm-shrinkwrap.json +4424 -0
- package/package.json +57 -2
- package/postinstall.js +61 -47
- package/preuninstall.js +8 -35
- package/setup.js +80 -47
- package/skills/synabun/modules/idea.md +1 -1
- package/skills/synabun/modules/schedule.md +1 -1
- package/updater.cmd +2 -2
- package/updater.mjs +97 -3
|
@@ -1,8 +1,17 @@
|
|
|
1
|
+
import { mountCodexSettings } from './cdx-settings.js';
|
|
2
|
+
import { t } from '../i18n.js';
|
|
3
|
+
import { getCliState, isCliInstalling } from '../cli-status.js';
|
|
4
|
+
import { cliInstallText } from '../cli-install-view.js';
|
|
1
5
|
// ═══════════════════════════════════════════
|
|
2
6
|
// SynaBun — Codex Panel: State, Tabs & Sessions
|
|
3
7
|
// ═══════════════════════════════════════════
|
|
4
8
|
|
|
5
9
|
import { storage } from '../storage.js';
|
|
10
|
+
import { providerAuthSnapshot } from '../ui-provider-auth.js';
|
|
11
|
+
import { mountProviderTerminalAuth, providerApiKeyRequest, startProviderTerminalLogin } from '../ui-provider-terminal-auth.js';
|
|
12
|
+
import { accountName, accountSummary, accountSwitchPlan, accountText, serverAccountId } from '../account-view.js';
|
|
13
|
+
import { mountAccountMenu } from '../account-menu.js';
|
|
14
|
+
import '../account-i18n.js';
|
|
6
15
|
import { restoreMcpAppCards, teardownMcpApps, retireMcpAppNode, stripMcpAppRuntime } from './cdx-mcp-app-host.js';
|
|
7
16
|
import { renderTurnDiff, completeTurnOutputs } from './cdx-render.js';
|
|
8
17
|
import { hydrateOutputControls } from './cdx-output.js';
|
|
@@ -29,14 +38,14 @@ import { fileLinkText } from '../ui-file-links.js';
|
|
|
29
38
|
import { WORKER_END_CLASS, backToAssistant, buildWorkerEndCard, endWorkerRunOnClose, forgetWorkerEnd } from '../ui-worker-end.js';
|
|
30
39
|
import {
|
|
31
40
|
CODEX_COMMANDS, CODEX_COMMAND_BY_NAME, parseCodexCommand, codexCommandHints,
|
|
32
|
-
capabilityAvailability, latestCompletedCodexText, configValue,
|
|
33
|
-
|
|
41
|
+
capabilityAvailability, latestCompletedCodexText, configValue,
|
|
42
|
+
SESSION_CONFIG_FIELDS, flattenNativeCatalog, fastServiceTier,
|
|
34
43
|
} from './cdx-commands.js';
|
|
35
44
|
import {
|
|
36
45
|
knownCodexCapabilities, storeCodexCapabilities, dropCodexCapabilities, invalidateCodexCapabilities,
|
|
37
46
|
currentCodexCapabilities, requestWithCodexCapability,
|
|
38
47
|
} from './cdx-capabilities.js';
|
|
39
|
-
import { openCodexCatalog, openCodexReview, openCodexGoal, openCodexFeedback, openCodexDiff, refreshCodexDiff, refreshCodexAttachments,
|
|
48
|
+
import { openCodexCatalog, openCodexReview, openCodexGoal, openCodexFeedback, openCodexDiff, refreshCodexDiff, refreshCodexAttachments, updateCodexGateway } from './cdx-features.js';
|
|
40
49
|
export { refreshCodexDiff } from './cdx-features.js';
|
|
41
50
|
import {
|
|
42
51
|
STOR, EFFORT_LEVELS, MAX_THREAD_SNAPSHOTS, MAX_THREAD_SNAPSHOT_CHARS,
|
|
@@ -412,6 +421,7 @@ function buildWsCallbacks(tab, options = {}) {
|
|
|
412
421
|
}
|
|
413
422
|
restoreMcpAppCards(_messagesEl, { tab: _boundTab, items: _items, request: requestSocketPayloadForTab, draft: setMcpAppDraft });
|
|
414
423
|
if (_boundTab) _boundTab.bootstrapped = true;
|
|
424
|
+
ensureCodexTerminalAuth(tab);
|
|
415
425
|
if (msg.mcpProfile && _boundTab) {
|
|
416
426
|
_boundTab.mcpProfile = msg.mcpProfile;
|
|
417
427
|
if (activeTab() === _boundTab) _onActiveTabChanged?.(_boundTab);
|
|
@@ -642,7 +652,8 @@ function buildWsCallbacks(tab, options = {}) {
|
|
|
642
652
|
return;
|
|
643
653
|
}
|
|
644
654
|
if (msg.type === 'codex_config_repaired') {
|
|
645
|
-
|
|
655
|
+
clearCodexConfigWarnings();
|
|
656
|
+
appendSystem(t('codexSettings.configRepaired'), 'muted');
|
|
646
657
|
return;
|
|
647
658
|
}
|
|
648
659
|
resolveGenericRequest(msg);
|
|
@@ -1253,6 +1264,7 @@ function writeThreadSnapshot(tab, { force = false } = {}) {
|
|
|
1253
1264
|
const snapshotNodes = [...messagesEl.children].filter((node) => (
|
|
1254
1265
|
!node.classList?.contains('cxp-empty') && !node.classList?.contains('cxp-thinking')
|
|
1255
1266
|
&& !node.classList?.contains(WORKER_END_CLASS)
|
|
1267
|
+
&& !node.hasAttribute('data-provider-auth-card')
|
|
1256
1268
|
));
|
|
1257
1269
|
const ownsEveryNode = codexTranscriptNodesHaveOwnership(snapshotNodes, { threadId, accountId });
|
|
1258
1270
|
if (!ownsEveryNode) {
|
|
@@ -1265,7 +1277,7 @@ function writeThreadSnapshot(tab, { force = false } = {}) {
|
|
|
1265
1277
|
stripMcpAppRuntime(snapshotEl);
|
|
1266
1278
|
// A worker's end card is drawn again from its run, never restored from markup.
|
|
1267
1279
|
snapshotEl.querySelectorAll(`.${WORKER_END_CLASS}`).forEach((node) => node.remove());
|
|
1268
|
-
const html = snapshotEl
|
|
1280
|
+
const html = providerAuthSnapshot(snapshotEl);
|
|
1269
1281
|
if (!html.trim()) return;
|
|
1270
1282
|
const ownedItemNodes = snapshotNodes.filter((node) => node.dataset?.itemId);
|
|
1271
1283
|
const itemCount = normalizeSnapshotItemCount(tab?.transcriptItemCount)
|
|
@@ -2044,6 +2056,8 @@ export function syncLegacyState() {
|
|
|
2044
2056
|
else storage.removeItem(STOR.project);
|
|
2045
2057
|
if (tab.threadId) storage.setItem(STOR.threadId, tab.threadId);
|
|
2046
2058
|
else storage.removeItem(STOR.threadId);
|
|
2059
|
+
if (tab.threadId) storage.setItem(STOR.threadAccount, tab.accountId || 'default');
|
|
2060
|
+
else storage.removeItem(STOR.threadAccount);
|
|
2047
2061
|
if (tab.threadId && tab.sessionLabel) storage.setItem(STOR.title, tab.sessionLabel);
|
|
2048
2062
|
else storage.removeItem(STOR.title);
|
|
2049
2063
|
}
|
|
@@ -2423,6 +2437,9 @@ export function setSessionLabel(label, { persist = true } = {}) {
|
|
|
2423
2437
|
if (isActiveTab(_boundTab)) {
|
|
2424
2438
|
const labelEl = panelEl('#cxp-session-label');
|
|
2425
2439
|
if (labelEl) labelEl.replaceChildren(document.createTextNode(_sessionLabel));
|
|
2440
|
+
// The whole name, for when the header shows only part of it.
|
|
2441
|
+
const sessionBtn = panelEl('#cxp-session-btn');
|
|
2442
|
+
if (sessionBtn) sessionBtn.title = _sessionLabel;
|
|
2426
2443
|
syncLegacyState();
|
|
2427
2444
|
}
|
|
2428
2445
|
updateTrayPillLabel();
|
|
@@ -2585,6 +2602,8 @@ function disposeDiscardedTab(tab) {
|
|
|
2585
2602
|
if (!tab) return;
|
|
2586
2603
|
flushThreadSnapshotSave(tab);
|
|
2587
2604
|
disconnectTab(tab);
|
|
2605
|
+
tab.authView?.dispose();
|
|
2606
|
+
tab.terminalAuthView?.dispose();
|
|
2588
2607
|
tab.closed = true;
|
|
2589
2608
|
if (tab.snapshotTimer) {
|
|
2590
2609
|
clearTimeout(tab.snapshotTimer);
|
|
@@ -3121,10 +3140,14 @@ export function restoreTabs() {
|
|
|
3121
3140
|
}
|
|
3122
3141
|
} catch {}
|
|
3123
3142
|
|
|
3143
|
+
// A window with no tabs of its own reopens the last thread, under the account it belongs to: its rollout
|
|
3144
|
+
// lives in that account's CODEX_HOME, never Default's.
|
|
3145
|
+
const lastThreadId = storage.getItem(STOR.threadId) || null;
|
|
3124
3146
|
createTab({
|
|
3125
3147
|
project: storage.getItem(STOR.project) || '',
|
|
3126
|
-
threadId:
|
|
3148
|
+
threadId: lastThreadId,
|
|
3127
3149
|
title: storage.getItem(STOR.title) || '',
|
|
3150
|
+
...(lastThreadId ? { accountId: storage.getItem(STOR.threadAccount) || 'default' } : {}),
|
|
3128
3151
|
}, { autoSwitch: false });
|
|
3129
3152
|
_activeTabIdx = 0;
|
|
3130
3153
|
updateActiveTabView();
|
|
@@ -3886,12 +3909,24 @@ export function cxpSessRebuildList(menu, listEl, tab) {
|
|
|
3886
3909
|
}
|
|
3887
3910
|
|
|
3888
3911
|
// ═══════════════════════════════════════════
|
|
3889
|
-
//
|
|
3912
|
+
// Codex accounts (per tab): the header account menu
|
|
3890
3913
|
// ═══════════════════════════════════════════
|
|
3914
|
+
// Every account and its state come from the server (lib/codex-accounts.js
|
|
3915
|
+
// describe(): its mode, whether it is signed in, its identity: an email or a
|
|
3916
|
+
// masked key, never a key); account-view.js decides the words, account-menu.js
|
|
3917
|
+
// draws the menu (the same component as the Claude panel's). /account, /login,
|
|
3918
|
+
// the sign-in screen's "Other accounts…" and the Context settings popover's
|
|
3919
|
+
// Account row open it. A conversation belongs to the account it started under
|
|
3920
|
+
// (its thread lives in that account's CODEX_HOME): a tab with one opens another
|
|
3921
|
+
// account in a new tab; before its first message the tab itself switches.
|
|
3922
|
+
|
|
3923
|
+
let _codexAccountsError = '';
|
|
3924
|
+
let _codexAccountsLoad = null;
|
|
3925
|
+
let _accountMenu = null;
|
|
3891
3926
|
|
|
3892
3927
|
function accountLabelFor(id) {
|
|
3893
3928
|
const acct = _codexAccounts.find((a) => a.id === id);
|
|
3894
|
-
return acct ? (acct
|
|
3929
|
+
return acct ? accountName(acct, 'codex') : (id === 'default' ? accountText('defaultName', {}, 'codex') : 'account');
|
|
3895
3930
|
}
|
|
3896
3931
|
|
|
3897
3932
|
// The tab's account as the Context settings popover names it: the label, and
|
|
@@ -3900,29 +3935,35 @@ function accountView(tab) {
|
|
|
3900
3935
|
const acctId = tab?.accountId || _accountId || 'default';
|
|
3901
3936
|
const acct = _codexAccounts.find((a) => a.id === acctId);
|
|
3902
3937
|
return {
|
|
3903
|
-
label: acct
|
|
3904
|
-
|
|
3905
|
-
: (acctId === 'default' ? 'Default' : 'Account'),
|
|
3906
|
-
tip: acct?.email
|
|
3907
|
-
? `Account: ${acct.email}${acct.planType ? ` (${acct.planType})` : ''} — click to switch`
|
|
3908
|
-
: 'Switch ChatGPT account for this tab',
|
|
3938
|
+
label: acct ? accountName(acct, 'codex') : accountLabelFor(acctId),
|
|
3939
|
+
tip: acct ? accountSummary(acct, 'codex') : accountText('menuTitle', {}, 'codex'),
|
|
3909
3940
|
};
|
|
3910
3941
|
}
|
|
3911
3942
|
|
|
3912
|
-
// The account is a row of the Context settings popover.
|
|
3943
|
+
// The account is a row of the Context settings popover and the header menu's trigger.
|
|
3913
3944
|
export function syncAccountChip() {
|
|
3914
3945
|
syncContextMenu();
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
}
|
|
3924
|
-
|
|
3925
|
-
|
|
3946
|
+
_accountMenu?.render();
|
|
3947
|
+
}
|
|
3948
|
+
|
|
3949
|
+
/** Read every account with its state (GET /api/codex/accounts); `refresh` asks Codex about each first. */
|
|
3950
|
+
export function refreshCodexAccounts({ refresh = false } = {}) {
|
|
3951
|
+
if (_codexAccountsLoad && !refresh) return _codexAccountsLoad;
|
|
3952
|
+
const load = fetch(`/api/codex/accounts${refresh ? '?refresh=true' : ''}`, { cache: 'no-store' })
|
|
3953
|
+
.then((response) => response.json().catch(() => ({})).then((data) => {
|
|
3954
|
+
if (!response.ok || !Array.isArray(data?.accounts)) throw new Error(data?.error || accountText('readFailed', {}, 'codex'));
|
|
3955
|
+
_codexAccounts = data.accounts;
|
|
3956
|
+
_codexAccountsError = '';
|
|
3957
|
+
return _codexAccounts;
|
|
3958
|
+
}))
|
|
3959
|
+
.catch((error) => { _codexAccountsError = accountText('readFailed', {}, 'codex'); throw error; })
|
|
3960
|
+
.finally(() => {
|
|
3961
|
+
if (_codexAccountsLoad === load) _codexAccountsLoad = null;
|
|
3962
|
+
syncAccountChip();
|
|
3963
|
+
});
|
|
3964
|
+
_codexAccountsLoad = load;
|
|
3965
|
+
load.catch(() => {});
|
|
3966
|
+
return load;
|
|
3926
3967
|
}
|
|
3927
3968
|
|
|
3928
3969
|
function resetViewForAccountChange(label) {
|
|
@@ -3948,29 +3989,33 @@ function resetViewForAccountChange(label) {
|
|
|
3948
3989
|
}
|
|
3949
3990
|
setSessionLabel('New session', { persist: false });
|
|
3950
3991
|
clearTranscript(freshThreadText());
|
|
3992
|
+
if (_boundTab) ensureCodexTerminalAuth(_boundTab);
|
|
3951
3993
|
if (label) setStatus(label, 'ready');
|
|
3952
3994
|
}
|
|
3953
3995
|
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
if (acct && info.email) {
|
|
3958
|
-
acct.email = info.email;
|
|
3959
|
-
acct.planType = info.planType || acct.planType;
|
|
3960
|
-
if (!acct.label || acct.label === 'New account') acct.label = info.email;
|
|
3961
|
-
}
|
|
3996
|
+
// What the server says an account holds, for the sign-in screen: { loggedIn } (true / false / unknown).
|
|
3997
|
+
function signInStateOf(row) {
|
|
3998
|
+
return row && typeof row.signedIn === 'boolean' ? { loggedIn: row.signedIn } : null;
|
|
3962
3999
|
}
|
|
3963
4000
|
|
|
3964
4001
|
function handleAccountMessage(msg) {
|
|
4002
|
+
const ownsAccount = (!msg.accountId || msg.accountId === _boundTab?.accountId)
|
|
4003
|
+
&& (!msg.state?.accountId || msg.state.accountId === _boundTab?.accountId);
|
|
3965
4004
|
if (Array.isArray(msg.accounts)) _codexAccounts = msg.accounts;
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
4005
|
+
// The server's reading of the account (accountState / account_state) is what every surface shows.
|
|
4006
|
+
const state = msg.type === 'account_state' ? msg.account : msg.accountState;
|
|
4007
|
+
if (state?.id) {
|
|
4008
|
+
const index = _codexAccounts.findIndex((a) => a.id === state.id);
|
|
4009
|
+
if (index >= 0) _codexAccounts[index] = state; else _codexAccounts.push(state);
|
|
4010
|
+
}
|
|
4011
|
+
if (ownsAccount && !msg.error) {
|
|
4012
|
+
const signIn = signInStateOf(state);
|
|
4013
|
+
if (signIn) _boundTab?.terminalAuthView?.update(signIn);
|
|
4014
|
+
if (msg.type === 'account_logged_out' && !state) _boundTab?.terminalAuthView?.update({ loggedIn: false });
|
|
4015
|
+
}
|
|
4016
|
+
if (msg.type === 'account_info' && !msg.error && (!msg.accountId || msg.accountId === _accountId)) refreshModelCatalog(_boundTab);
|
|
3970
4017
|
if (msg.type === 'account_logged_out' && !msg.error) refreshModelCatalog(_boundTab);
|
|
3971
|
-
if (msg.type === '
|
|
3972
|
-
applyAccountReadToCache(msg.accountId || _accountId || 'default', msg.account);
|
|
3973
|
-
}
|
|
4018
|
+
if (msg.type === 'account_state' && ownsAccount) { invalidateCodexFeatureCaches(_boundTab); refreshModelCatalog(_boundTab); }
|
|
3974
4019
|
if (msg.type === 'account_switched' && msg.accountId) {
|
|
3975
4020
|
_accountId = msg.accountId;
|
|
3976
4021
|
if (_boundTab) _boundTab.accountId = msg.accountId;
|
|
@@ -3978,139 +4023,118 @@ function handleAccountMessage(msg) {
|
|
|
3978
4023
|
resetViewForAccountChange(`Switched to ${accountLabelFor(msg.accountId)}`);
|
|
3979
4024
|
refreshModelCatalog(_boundTab);
|
|
3980
4025
|
}
|
|
3981
|
-
if (msg.type === 'account_add_started') {
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
saveTabs();
|
|
3986
|
-
}
|
|
4026
|
+
if (msg.type === 'account_add_started' && msg.accountId) {
|
|
4027
|
+
_accountId = msg.accountId;
|
|
4028
|
+
if (_boundTab) _boundTab.accountId = msg.accountId;
|
|
4029
|
+
saveTabs();
|
|
3987
4030
|
resetViewForAccountChange('');
|
|
3988
|
-
appendSystem('Opening ChatGPT login in your browser… complete sign-in, then return here. The account name updates automatically once you finish.', 'working');
|
|
3989
4031
|
}
|
|
3990
4032
|
syncAccountChip();
|
|
3991
|
-
const menu = panelEl('#cxp-account-menu');
|
|
3992
|
-
if (menu?.classList.contains('open')) renderAccountMenu();
|
|
3993
4033
|
}
|
|
3994
4034
|
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
if (!
|
|
3998
|
-
const
|
|
3999
|
-
|
|
4035
|
+
// The header account menu (mounted by cdx-panel.js into the header's actions).
|
|
4036
|
+
export function mountCodexAccountMenu(actionsEl, panelEl) {
|
|
4037
|
+
if (_accountMenu || !actionsEl) return _accountMenu;
|
|
4038
|
+
const path = (id) => `/api/codex/accounts/${encodeURIComponent(id)}`;
|
|
4039
|
+
_accountMenu = mountAccountMenu({
|
|
4040
|
+
provider: 'codex', container: actionsEl, before: actionsEl.firstChild, layer: () => panelEl,
|
|
4041
|
+
read: () => {
|
|
4042
|
+
const tab = activeTab();
|
|
4043
|
+
return {
|
|
4044
|
+
rows: _codexAccounts, currentId: tab?.accountId || 'default', hasConversation: !!tab?.threadId,
|
|
4045
|
+
available: !!tab && !tab.automationRunId, busy: !!(tab?.running || tab?.automationActive),
|
|
4046
|
+
loading: !_codexAccounts.length && !_codexAccountsError, error: _codexAccountsError,
|
|
4047
|
+
};
|
|
4048
|
+
},
|
|
4049
|
+
actions: {
|
|
4050
|
+
load: ({ refresh }) => refreshCodexAccounts({ refresh }),
|
|
4051
|
+
pick: (id) => { const tab = activeTab(); if (tab) pickCodexAccount(tab, id); },
|
|
4052
|
+
add: async () => (await codexAccountRequest('/api/codex/accounts', { method: 'POST', body: '{}' })).account,
|
|
4053
|
+
signIn: (id) => startProviderTerminalLogin('codex', id, `Codex sign-in · ${accountLabelFor(id)}`),
|
|
4054
|
+
saveKey: (id, key) => providerApiKeyRequest('codex', id, key),
|
|
4055
|
+
setMode: (id, mode) => codexAccountRequest(path(id), { method: 'PATCH', body: JSON.stringify({ mode }) }),
|
|
4056
|
+
signOut: (id, credential) => codexAccountRequest(`${path(id)}/auth/logout`, { method: 'POST', body: JSON.stringify({ credential }) }),
|
|
4057
|
+
rename: (id, label) => codexAccountRequest(path(id), { method: 'PATCH', body: JSON.stringify({ label }) }),
|
|
4058
|
+
remove: (id) => removeCodexAccount(id),
|
|
4059
|
+
},
|
|
4060
|
+
});
|
|
4061
|
+
refreshCodexAccounts().catch(() => {});
|
|
4062
|
+
return _accountMenu;
|
|
4000
4063
|
}
|
|
4001
4064
|
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
if (!
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
if (!_codexAccounts.length) {
|
|
4012
|
-
const empty = document.createElement('div');
|
|
4013
|
-
empty.className = 'cxp-account-empty';
|
|
4014
|
-
empty.textContent = 'Loading accounts…';
|
|
4015
|
-
list.appendChild(empty);
|
|
4016
|
-
}
|
|
4017
|
-
for (const acct of _codexAccounts) {
|
|
4018
|
-
const row = document.createElement('div');
|
|
4019
|
-
row.className = 'cxp-account-row' + (acct.id === activeAcctId ? ' active' : '');
|
|
4020
|
-
const main = document.createElement('button');
|
|
4021
|
-
main.className = 'cxp-account-row-main';
|
|
4022
|
-
main.type = 'button';
|
|
4023
|
-
const sub = acct.email && acct.email !== acct.label
|
|
4024
|
-
? `<span class="cxp-account-row-sub">${esc(acct.email)}${acct.planType ? ` · ${esc(acct.planType)}` : ''}</span>`
|
|
4025
|
-
: (acct.planType ? `<span class="cxp-account-row-sub">${esc(acct.planType)}</span>` : '');
|
|
4026
|
-
main.innerHTML = `
|
|
4027
|
-
<span class="cxp-account-check">${acct.id === activeAcctId ? '✓' : ''}</span>
|
|
4028
|
-
<span class="cxp-account-row-text">
|
|
4029
|
-
<span class="cxp-account-row-label">${esc(acct.label || acct.email || (acct.isDefault ? 'Default' : 'Account'))}</span>
|
|
4030
|
-
${sub}
|
|
4031
|
-
</span>`;
|
|
4032
|
-
main.addEventListener('click', () => { menu.classList.remove('open'); switchToAccount(acct.id); });
|
|
4033
|
-
row.appendChild(main);
|
|
4034
|
-
if (!acct.isDefault) {
|
|
4035
|
-
const removeBtn = document.createElement('button');
|
|
4036
|
-
removeBtn.className = 'cxp-account-row-remove';
|
|
4037
|
-
removeBtn.type = 'button';
|
|
4038
|
-
removeBtn.title = 'Remove account';
|
|
4039
|
-
removeBtn.innerHTML = '✕';
|
|
4040
|
-
removeBtn.addEventListener('click', (e) => { e.stopPropagation(); removeCodexAccount(acct.id); });
|
|
4041
|
-
row.appendChild(removeBtn);
|
|
4042
|
-
}
|
|
4043
|
-
list.appendChild(row);
|
|
4044
|
-
}
|
|
4045
|
-
menu.appendChild(list);
|
|
4046
|
-
|
|
4047
|
-
const addBtn = document.createElement('button');
|
|
4048
|
-
addBtn.className = 'cxp-account-add';
|
|
4049
|
-
addBtn.type = 'button';
|
|
4050
|
-
addBtn.textContent = '+ Add ChatGPT account…';
|
|
4051
|
-
addBtn.addEventListener('click', () => { menu.classList.remove('open'); addCodexAccount(); });
|
|
4052
|
-
menu.appendChild(addBtn);
|
|
4065
|
+
/** Open the header account menu (`manage`: one account's management). */
|
|
4066
|
+
export function openAccountMenu({ manage = '' } = {}) {
|
|
4067
|
+
if (!_accountMenu) return;
|
|
4068
|
+
_accountMenu.open(manage ? { manage } : {});
|
|
4069
|
+
}
|
|
4070
|
+
// The Context settings popover's Account row and older callers.
|
|
4071
|
+
export function toggleAccountMenu() {
|
|
4072
|
+
if (_accountMenu?.isOpen()) _accountMenu.close({ restore: true });
|
|
4073
|
+
else openAccountMenu();
|
|
4053
4074
|
}
|
|
4054
4075
|
|
|
4055
|
-
async function
|
|
4056
|
-
const
|
|
4057
|
-
|
|
4058
|
-
if ((
|
|
4059
|
-
|
|
4060
|
-
try {
|
|
4061
|
-
setStatus('Switching account…', 'working');
|
|
4062
|
-
await requestSocketPayloadForTab(tab, 'account_switch', { accountId });
|
|
4063
|
-
// account_switched push (handled in handleAccountMessage) updates the view.
|
|
4064
|
-
} catch (err) {
|
|
4065
|
-
if (!tab.closed) withTab(tab, () => {
|
|
4066
|
-
appendSystem(err.message || 'Could not switch account', 'error');
|
|
4067
|
-
setStatus(err.message || 'Switch failed', 'error');
|
|
4068
|
-
});
|
|
4069
|
-
}
|
|
4076
|
+
async function codexAccountRequest(url, options = {}) {
|
|
4077
|
+
const response = await fetch(url, { ...options, cache: 'no-store', headers: { 'Content-Type': 'application/json' } });
|
|
4078
|
+
const data = await response.json().catch(() => ({}));
|
|
4079
|
+
if (!response.ok || data.error) throw new Error(data.error || 'Codex account request failed.');
|
|
4080
|
+
return data;
|
|
4070
4081
|
}
|
|
4071
4082
|
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
const
|
|
4079
|
-
if (
|
|
4080
|
-
|
|
4081
|
-
if (authUrl) window.open(authUrl, '_blank', 'noopener,noreferrer');
|
|
4082
|
-
if (isActiveTab(tab)) syncAccountChip();
|
|
4083
|
-
} catch (err) {
|
|
4084
|
-
if (!tab.closed) withTab(tab, () => {
|
|
4085
|
-
appendSystem(err.message || 'Could not start login', 'error');
|
|
4086
|
-
setStatus(err.message || 'Login failed', 'error');
|
|
4087
|
-
});
|
|
4083
|
+
// Pick an account for a tab: the tab switches before its first message; a tab with a conversation keeps it
|
|
4084
|
+
// and the other account opens in a new tab.
|
|
4085
|
+
function pickCodexAccount(tab, id) {
|
|
4086
|
+
const plan = accountSwitchPlan({ rows: _codexAccounts, currentId: tab.accountId || 'default', targetId: id, hasConversation: !!tab.threadId, provider: 'codex' });
|
|
4087
|
+
if (plan.effect === 'missing' || plan.effect === 'same') { withTab(tab, () => appendSystem(plan.message, 'muted')); return; }
|
|
4088
|
+
if (plan.effect === 'next-chat') {
|
|
4089
|
+
const fresh = createTab({ project: tab.project || '', accountId: id });
|
|
4090
|
+
if (fresh) withTab(fresh, () => appendSystem(accountText('newChatUnder', { label: accountLabelFor(id) }, 'codex'), 'muted'));
|
|
4091
|
+
return;
|
|
4088
4092
|
}
|
|
4093
|
+
if (tab.running) { withTab(tab, () => appendSystem(accountText('busyTurn', {}, 'codex'), 'error')); return; }
|
|
4094
|
+
setStatus('Switching account…', 'working');
|
|
4095
|
+
requestSocketPayloadForTab(tab, 'account_switch', { accountId: id })
|
|
4096
|
+
.then(() => { if (!tab.closed) withTab(tab, () => appendSystem(plan.message, 'muted')); })
|
|
4097
|
+
.catch((err) => {
|
|
4098
|
+
if (!tab.closed) withTab(tab, () => {
|
|
4099
|
+
appendSystem(err.message || 'Could not switch account', 'error');
|
|
4100
|
+
setStatus(err.message || 'Switch failed', 'error');
|
|
4101
|
+
});
|
|
4102
|
+
});
|
|
4089
4103
|
}
|
|
4090
4104
|
|
|
4105
|
+
// Remove an account. The server refuses while a tab (this window's or another's), the Assistant or a run
|
|
4106
|
+
// uses it, with what to do: the menu says it. A conversation is never reset to free an account.
|
|
4091
4107
|
async function removeCodexAccount(accountId) {
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
const
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4108
|
+
await codexAccountRequest(`/api/codex/accounts/${encodeURIComponent(accountId)}`, { method: 'DELETE' });
|
|
4109
|
+
}
|
|
4110
|
+
|
|
4111
|
+
function ensureCodexTerminalAuth(tab) {
|
|
4112
|
+
const accountId = tab.accountId || 'default';
|
|
4113
|
+
if (tab.closed || !tab.messagesEl) return;
|
|
4114
|
+
if (tab.terminalAuthView && tab.terminalAuthAccount === accountId) { void tab.terminalAuthView.refresh(); return; }
|
|
4115
|
+
tab.terminalAuthView?.dispose();
|
|
4116
|
+
tab.terminalAuthAccount = accountId;
|
|
4117
|
+
const named = accountId !== 'default' ? _codexAccounts.find((a) => a.id === accountId) : null;
|
|
4118
|
+
tab.terminalAuthView = mountProviderTerminalAuth({
|
|
4119
|
+
host: tab.messagesEl, provider: 'codex', accountId, logo: OPENAI_ICON,
|
|
4120
|
+
...(named ? { message: `Sign in to Codex to use ${accountName(named, 'codex')}.` } : {}),
|
|
4121
|
+
// Another account (or a new one) is one click away from the sign-in screen: the header account menu.
|
|
4122
|
+
moreAction: { label: accountText('otherAccounts', {}, 'codex'), run: () => { if (isActiveTab(tab)) openAccountMenu(); } },
|
|
4123
|
+
isCurrent: () => !tab.closed && (tab.accountId || 'default') === accountId,
|
|
4124
|
+
// The account as the server reads it (its ChatGPT sign-in and the key it holds), not one app-server's view.
|
|
4125
|
+
readAccount: async () => {
|
|
4126
|
+
const result = await codexAccountRequest(`/api/codex/accounts/${encodeURIComponent(accountId)}/auth?refresh=true`);
|
|
4127
|
+
const row = result.account;
|
|
4128
|
+
if (row?.id) {
|
|
4129
|
+
const index = _codexAccounts.findIndex((a) => a.id === row.id);
|
|
4130
|
+
if (index >= 0) _codexAccounts[index] = row; else _codexAccounts.push(row);
|
|
4131
|
+
if (isActiveTab(tab)) syncAccountChip();
|
|
4132
|
+
}
|
|
4133
|
+
return signInStateOf(row);
|
|
4134
|
+
},
|
|
4135
|
+
requestApiKey: (provider, id, key) => providerApiKeyRequest(provider, id, key),
|
|
4136
|
+
onSignedIn: () => { invalidateCodexFeatureCaches(tab); refreshModelCatalog(tab); refreshCodexAccounts().catch(() => {}); },
|
|
4137
|
+
});
|
|
4114
4138
|
}
|
|
4115
4139
|
|
|
4116
4140
|
export async function renderSessionMenu() {
|
|
@@ -4970,7 +4994,7 @@ export function syncInputEnabled() {
|
|
|
4970
4994
|
if (send) {
|
|
4971
4995
|
const isStopMode = !!(tab?.running || _running);
|
|
4972
4996
|
send.classList.toggle('cxp-send-stopping', !!isStopMode);
|
|
4973
|
-
send.title = actionBlockedByCli ?
|
|
4997
|
+
send.title = actionBlockedByCli ? codexCliBlockedText() : (isStopMode ? 'Stop' : 'Send');
|
|
4974
4998
|
send.disabled = actionBlockedByCli || (isStopMode ? false : (!_connected || !_bootstrapped || _running || _startingThread || blockedByRequest || (!hasText && !hasImages && !hasPaths && !hasMentions)));
|
|
4975
4999
|
}
|
|
4976
5000
|
if (fresh) {
|
|
@@ -5268,6 +5292,12 @@ function noteCodexRevert(event) {
|
|
|
5268
5292
|
|
|
5269
5293
|
// ── Notification handler (lines 7538-7698) ──
|
|
5270
5294
|
export function handleNotify(method, params) {
|
|
5295
|
+
// Codex's own account changed: the server's reading of the account (its ChatGPT sign-in and the
|
|
5296
|
+
// key SynaBun holds) decides what the tab shows, so the sign-in screen and the menu ask it again.
|
|
5297
|
+
if (method === 'account/updated') {
|
|
5298
|
+
void _boundTab?.terminalAuthView?.refresh();
|
|
5299
|
+
refreshCodexAccounts().catch(() => {});
|
|
5300
|
+
}
|
|
5271
5301
|
if (['skills/changed', 'app/list/updated', 'account/updated', 'account/rateLimits/updated', 'config/updated', 'thread/attachment/updated', 'thread/settings/updated', 'account/gatewayOAuth/changed'].includes(method)) {
|
|
5272
5302
|
invalidateCodexFeatureCaches(_boundTab);
|
|
5273
5303
|
}
|
|
@@ -5632,7 +5662,7 @@ export function handleNotify(method, params) {
|
|
|
5632
5662
|
break;
|
|
5633
5663
|
}
|
|
5634
5664
|
case 'configWarning': {
|
|
5635
|
-
|
|
5665
|
+
showCodexConfigWarning(params);
|
|
5636
5666
|
break;
|
|
5637
5667
|
}
|
|
5638
5668
|
case 'deprecationNotice':
|
|
@@ -6339,7 +6369,7 @@ function formatStatusSnapshotMarkdown(snapshot, tab = activeTab()) {
|
|
|
6339
6369
|
`- Protocol baseline: \`${runtime.protocolBaseline || 'not reported'}\``,
|
|
6340
6370
|
];
|
|
6341
6371
|
if (account) {
|
|
6342
|
-
lines.push(`- Account: \`${account.email || account.name || account.type || 'signed in'}\`${account.planType ? ` (${account.planType})` : ''}`);
|
|
6372
|
+
lines.push(`- Account: \`${account.type === 'apiKey' ? 'API key' : account.email || account.name || account.type || 'signed in'}\`${account.planType ? ` (${account.planType})` : ''}`);
|
|
6343
6373
|
} else {
|
|
6344
6374
|
lines.push('- Account: signed out');
|
|
6345
6375
|
}
|
|
@@ -6742,6 +6772,15 @@ async function handleLocalSlashCommand(payload = currentComposerPayload()) {
|
|
|
6742
6772
|
invalidateCodexFeatureCaches(tab);
|
|
6743
6773
|
appendMarkdown('Logged out of Codex.');
|
|
6744
6774
|
break;
|
|
6775
|
+
case 'login':
|
|
6776
|
+
// Sign-in lives in the header account menu: this tab's account, its two ways to sign in.
|
|
6777
|
+
consumeComposer(input, tab, { clearAttachments: false });
|
|
6778
|
+
openAccountMenu({ manage: serverAccountId(tab.accountId) });
|
|
6779
|
+
break;
|
|
6780
|
+
case 'account':
|
|
6781
|
+
consumeComposer(input, tab, { clearAttachments: false });
|
|
6782
|
+
openAccountMenu();
|
|
6783
|
+
break;
|
|
6745
6784
|
case 'diff':
|
|
6746
6785
|
consumeComposer(input, tab, { clearAttachments: false });
|
|
6747
6786
|
if (!tab.project) {
|
|
@@ -6802,6 +6841,13 @@ async function handleLocalSlashCommand(payload = currentComposerPayload()) {
|
|
|
6802
6841
|
return true;
|
|
6803
6842
|
}
|
|
6804
6843
|
|
|
6844
|
+
// Why Send is off while the CLI banner shows (ui-cli-banner.js): the banner's own title, in the page's
|
|
6845
|
+
// language — not installed, being installed, or failed to start.
|
|
6846
|
+
function codexCliBlockedText() {
|
|
6847
|
+
const key = isCliInstalling('codex') ? 'titleInstalling' : getCliState('codex') === 'broken' ? 'titleBroken' : 'titleMissing';
|
|
6848
|
+
return cliInstallText(key, { label: 'Codex' });
|
|
6849
|
+
}
|
|
6850
|
+
|
|
6805
6851
|
// ── Send prompt & queue (lines 8165-8320) ──
|
|
6806
6852
|
export function sendPrompt() {
|
|
6807
6853
|
const payload = currentComposerPayload();
|
|
@@ -6811,7 +6857,7 @@ export function sendPrompt() {
|
|
|
6811
6857
|
// Block when CLI binary missing — banner already informs user.
|
|
6812
6858
|
const panel = document.getElementById('codex-panel');
|
|
6813
6859
|
if (panel?.classList.contains('cxp-cli-blocked')) {
|
|
6814
|
-
appendSystem(
|
|
6860
|
+
appendSystem(`${codexCliBlockedText()}.`, 'error');
|
|
6815
6861
|
return;
|
|
6816
6862
|
}
|
|
6817
6863
|
handleLocalSlashCommand(payload).then((handled) => {
|
|
@@ -7053,6 +7099,13 @@ export function renderImageStrip() {
|
|
|
7053
7099
|
}
|
|
7054
7100
|
|
|
7055
7101
|
// ── Whiteboard "Send to Panel" — receive image via event bus ──
|
|
7102
|
+
// Any window or surface changed a Codex account (signed in or out, a key, its mode, renamed, added,
|
|
7103
|
+
// removed): the menu re-reads the list, and the tabs on that account re-check sign-in.
|
|
7104
|
+
appOn('sync:codex:accounts-changed', (msg = {}) => {
|
|
7105
|
+
refreshCodexAccounts().catch(() => {});
|
|
7106
|
+
for (const tab of _tabs) if (!msg.accountId || serverAccountId(tab.accountId) === msg.accountId) void tab.terminalAuthView?.refresh();
|
|
7107
|
+
});
|
|
7108
|
+
|
|
7056
7109
|
appOn('wb:send-to-panel', ({ dataUrl }) => {
|
|
7057
7110
|
if (!dataUrl) return;
|
|
7058
7111
|
if (appState.lastActivePanel !== 'codex' || isHostedSessionFocused()) return;
|
|
@@ -7447,512 +7500,59 @@ export function confirmSlashHint() {
|
|
|
7447
7500
|
}
|
|
7448
7501
|
|
|
7449
7502
|
// ── Phase 6: Settings panel ──
|
|
7450
|
-
|
|
7503
|
+
function clearCodexConfigWarnings({ obsoleteOnly = false } = {}) {
|
|
7504
|
+
_getPanelEl()?.querySelectorAll('.cxp-config-warning').forEach(node => {
|
|
7505
|
+
if (!obsoleteOnly || /features\.personality/.test(node.textContent || '')) node.remove();
|
|
7506
|
+
});
|
|
7507
|
+
// Remove historical copies of the obsolete Settings warning as well.
|
|
7508
|
+
_getPanelEl()?.querySelectorAll('.cxp-system.error').forEach(node => {
|
|
7509
|
+
if (/features\.personality.*ignored/s.test(node.textContent || '')) node.remove();
|
|
7510
|
+
});
|
|
7511
|
+
}
|
|
7512
|
+
|
|
7513
|
+
function showCodexConfigWarning(params) {
|
|
7514
|
+
clearCodexConfigWarnings();
|
|
7515
|
+
const warning = document.createElement('div'); warning.className = 'cxp-config-warning'; warning.setAttribute('role', 'status');
|
|
7516
|
+
const text = document.createElement('div'); text.textContent = formatCodexConfigWarning(params);
|
|
7517
|
+
const hint = document.createElement('div'); hint.textContent = t('codexSettings.warningHelp');
|
|
7518
|
+
const settings = document.createElement('button'); settings.className = 'cxp-btn cxp-btn-sm'; settings.textContent = t('codexSettings.openSettings'); settings.onclick = () => openSettingsPanel();
|
|
7519
|
+
const dismiss = document.createElement('button'); dismiss.className = 'cxp-btn cxp-btn-sm'; dismiss.textContent = t('codexSettings.dismiss'); dismiss.onclick = () => warning.remove();
|
|
7520
|
+
warning.append(text, hint, settings, dismiss);
|
|
7521
|
+
_getPanelEl()?.querySelector('.cxp-input-wrap')?.before(warning);
|
|
7522
|
+
}
|
|
7451
7523
|
|
|
7452
|
-
|
|
7524
|
+
export async function openSettingsPanel({ section = '' } = {}) {
|
|
7453
7525
|
const settingsTab = activeTab();
|
|
7454
7526
|
if (!settingsTab) return;
|
|
7455
7527
|
const settingsOwner = { accountId: settingsTab.accountId, threadId: settingsTab.threadId, connectionEpoch: settingsTab.connectionEpoch };
|
|
7456
|
-
const requestForSettings = (type, data = {}) => requestForCodexOwner(settingsTab, settingsOwner, type, data,
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
<div class="cxp-settings-section">
|
|
7476
|
-
<div class="cxp-settings-section-title">Runtime and features</div>
|
|
7477
|
-
<div class="cxp-settings-loading" id="cxp-settings-runtime">Loading…</div>
|
|
7478
|
-
<div id="cxp-settings-features"></div>
|
|
7479
|
-
</div>
|
|
7480
|
-
<div class="cxp-settings-section">
|
|
7481
|
-
<div class="cxp-settings-section-title">MCP Servers</div>
|
|
7482
|
-
<div class="cxp-settings-loading" id="cxp-settings-mcp">Loading…</div>
|
|
7483
|
-
</div>
|
|
7484
|
-
<div class="cxp-settings-section">
|
|
7485
|
-
<div class="cxp-settings-section-title">Always Allowed Folders</div>
|
|
7486
|
-
<div class="cxp-settings-loading" id="cxp-settings-permissions">Loading…</div>
|
|
7487
|
-
</div>
|
|
7488
|
-
<div class="cxp-settings-section">
|
|
7489
|
-
<div class="cxp-settings-section-title">Configuration</div>
|
|
7490
|
-
<div class="cxp-settings-loading" id="cxp-settings-config">Loading…</div>
|
|
7491
|
-
</div>
|
|
7492
|
-
</div>
|
|
7493
|
-
</div>
|
|
7494
|
-
`;
|
|
7495
|
-
_getPanelEl().appendChild(overlay);
|
|
7496
|
-
overlay.querySelector('.cxp-settings-close')?.addEventListener('click', () => overlay.remove());
|
|
7497
|
-
overlay.addEventListener('click', (e) => { if (e.target === overlay) overlay.remove(); });
|
|
7498
|
-
|
|
7499
|
-
// Fetch data in parallel
|
|
7500
|
-
try {
|
|
7501
|
-
const [accountData, mcpData, configData, rateLimitData, permissionData, requirementsData, capabilityData] = await Promise.allSettled([
|
|
7502
|
-
requestForSettings('account_read', {}),
|
|
7503
|
-
requestForSettings('mcp_status', {}),
|
|
7504
|
-
requestForSettings('config_read', { cwd: settingsTab.project || null, threadId: settingsTab.threadId || null }),
|
|
7505
|
-
requestForSettings('rate_limits_read', {}),
|
|
7506
|
-
requestForSettings('permission_roots_list', {}),
|
|
7507
|
-
requestForSettings('config_requirements', {}),
|
|
7508
|
-
getCodexCapabilities(settingsTab),
|
|
7509
|
-
]);
|
|
7510
|
-
if (settingsTab.closed) {
|
|
7511
|
-
overlay.remove();
|
|
7512
|
-
return;
|
|
7513
|
-
}
|
|
7514
|
-
const capabilities = capabilityData.status === 'fulfilled' ? capabilityData.value : {};
|
|
7515
|
-
const runtime = settingsTab.codexRuntime || {};
|
|
7516
|
-
const runtimeEl = overlay.querySelector('#cxp-settings-runtime');
|
|
7517
|
-
runtimeEl.className = 'cxp-settings-hint';
|
|
7518
|
-
runtimeEl.textContent = `CLI ${runtime.cliVersion || 'unknown'} · Automation SDK ${runtime.sdkVersion || 'not installed'} · Protocol ${runtime.protocolBaseline || 'unknown'}\n${runtime.codexBin || 'Executable path not reported'}\nAccount: ${runtime.accountId || settingsTab.accountId || 'default'}`;
|
|
7519
|
-
const featureEl = overlay.querySelector('#cxp-settings-features');
|
|
7520
|
-
for (const kind of ['skills', 'mcp', 'apps', 'plugins', 'hooks', 'ps', 'experimental', 'goal', 'feedback']) {
|
|
7521
|
-
const command = CODEX_COMMAND_BY_NAME.get(kind);
|
|
7522
|
-
const available = capabilityAvailability(capabilities, command.capability);
|
|
7523
|
-
const btn = document.createElement('button');
|
|
7524
|
-
btn.className = 'cxp-btn cxp-btn-sm';
|
|
7525
|
-
btn.textContent = `${command.name}${available.experimental ? ' · Experimental' : ''}`;
|
|
7526
|
-
btn.disabled = !available.supported || (['goal', 'ps'].includes(kind) && !settingsTab.threadId);
|
|
7527
|
-
btn.title = !available.supported ? available.reason : command.desc;
|
|
7528
|
-
btn.addEventListener('click', async () => {
|
|
7529
|
-
const context = {
|
|
7530
|
-
host: _getPanelEl(), request: requestForSettings, tab: settingsTab, capabilities,
|
|
7531
|
-
authenticate: (name) => startMcpOAuthLogin(settingsTab, name),
|
|
7532
|
-
onChanged: () => invalidateCodexFeatureCaches(settingsTab),
|
|
7533
|
-
};
|
|
7534
|
-
try {
|
|
7535
|
-
if (kind === 'goal') await openCodexGoal(context);
|
|
7536
|
-
else if (kind === 'feedback') await openCodexFeedback(context);
|
|
7537
|
-
else await openCodexCatalog({ ...context, kind });
|
|
7538
|
-
} catch (error) { appendSettingsError(error.message); }
|
|
7539
|
-
});
|
|
7540
|
-
featureEl.append(btn);
|
|
7541
|
-
if (!available.supported) {
|
|
7542
|
-
const reason = document.createElement('div'); reason.className = 'cxp-settings-hint';
|
|
7543
|
-
reason.textContent = `${command.name}: ${available.reason || 'Unavailable in this runtime'}`; featureEl.append(reason);
|
|
7544
|
-
}
|
|
7545
|
-
}
|
|
7546
|
-
|
|
7547
|
-
// Account
|
|
7548
|
-
const accountEl = overlay.querySelector('#cxp-settings-account');
|
|
7549
|
-
if (accountEl) {
|
|
7550
|
-
const acctResult = accountData.status === 'fulfilled' ? (accountData.value?.account || {}) : {};
|
|
7551
|
-
const acct = acctResult?.account || null;
|
|
7552
|
-
const acctName = acct?.email || acct?.name || acct?.type;
|
|
7553
|
-
const limitLines = rateLimitData.status === 'fulfilled'
|
|
7554
|
-
? rateLimitLines(rateLimitData.value?.rateLimits || {})
|
|
7555
|
-
: [];
|
|
7556
|
-
if (acctName) {
|
|
7557
|
-
accountEl.innerHTML = '';
|
|
7558
|
-
accountEl.className = '';
|
|
7559
|
-
const value = document.createElement('div');
|
|
7560
|
-
value.className = 'cxp-settings-value';
|
|
7561
|
-
value.textContent = acctName;
|
|
7562
|
-
accountEl.appendChild(value);
|
|
7563
|
-
if (acct?.planType) {
|
|
7564
|
-
const plan = document.createElement('div');
|
|
7565
|
-
plan.className = 'cxp-settings-hint';
|
|
7566
|
-
plan.textContent = `Plan: ${acct.planType}`;
|
|
7567
|
-
accountEl.appendChild(plan);
|
|
7568
|
-
}
|
|
7569
|
-
if (limitLines.length) {
|
|
7570
|
-
const limits = document.createElement('div');
|
|
7571
|
-
limits.className = 'cxp-settings-hint';
|
|
7572
|
-
limits.innerHTML = limitLines.map((line) => `<div>${esc(line.replace(/^- /, ''))}</div>`).join('');
|
|
7573
|
-
accountEl.appendChild(limits);
|
|
7574
|
-
}
|
|
7575
|
-
const logoutBtn = document.createElement('button');
|
|
7576
|
-
logoutBtn.className = 'cxp-settings-login-btn';
|
|
7577
|
-
logoutBtn.textContent = 'Logout';
|
|
7578
|
-
logoutBtn.addEventListener('click', async () => {
|
|
7579
|
-
logoutBtn.disabled = true;
|
|
7580
|
-
try {
|
|
7581
|
-
await requestForSettings('account_logout', {});
|
|
7582
|
-
invalidateCodexFeatureCaches(settingsTab);
|
|
7583
|
-
overlay.remove();
|
|
7584
|
-
if (isActiveTab(settingsTab)) openSettingsPanel();
|
|
7585
|
-
} catch (err) {
|
|
7586
|
-
logoutBtn.disabled = false;
|
|
7587
|
-
appendSettingsError(err.message || 'Logout failed');
|
|
7588
|
-
}
|
|
7589
|
-
});
|
|
7590
|
-
accountEl.appendChild(logoutBtn);
|
|
7591
|
-
} else {
|
|
7592
|
-
accountEl.innerHTML = '';
|
|
7593
|
-
accountEl.className = '';
|
|
7594
|
-
const hint = document.createElement('div');
|
|
7595
|
-
hint.className = 'cxp-settings-hint';
|
|
7596
|
-
hint.textContent = 'Not signed in';
|
|
7597
|
-
const loginBtn = document.createElement('button');
|
|
7598
|
-
loginBtn.className = 'cxp-settings-login-btn';
|
|
7599
|
-
loginBtn.textContent = 'Login';
|
|
7600
|
-
loginBtn.addEventListener('click', async () => {
|
|
7601
|
-
loginBtn.disabled = true;
|
|
7602
|
-
loginBtn.textContent = 'Opening…';
|
|
7603
|
-
try {
|
|
7604
|
-
const result = await requestForSettings('codex_login', {});
|
|
7605
|
-
const authUrl = result?.login?.login?.authUrl || result?.login?.authUrl;
|
|
7606
|
-
if (authUrl) window.open(authUrl, '_blank', 'noopener,noreferrer');
|
|
7607
|
-
loginBtn.textContent = authUrl ? 'Browser opened' : 'Waiting…';
|
|
7608
|
-
} catch {
|
|
7609
|
-
loginBtn.textContent = 'Login';
|
|
7610
|
-
loginBtn.disabled = false;
|
|
7611
|
-
}
|
|
7612
|
-
});
|
|
7613
|
-
accountEl.append(hint, loginBtn);
|
|
7614
|
-
}
|
|
7615
|
-
}
|
|
7616
|
-
|
|
7617
|
-
await mountCodexAccountSecurity({ host: accountEl, request: requestForSettings, tab: settingsTab, capabilities });
|
|
7618
|
-
|
|
7619
|
-
// MCP Servers
|
|
7620
|
-
const mcpEl = overlay.querySelector('#cxp-settings-mcp');
|
|
7621
|
-
if (mcpEl) {
|
|
7622
|
-
const servers = mcpData.status === 'fulfilled' ? (mcpData.value?.servers || []) : [];
|
|
7623
|
-
if (!servers.length) {
|
|
7624
|
-
mcpEl.innerHTML = '';
|
|
7625
|
-
mcpEl.className = '';
|
|
7626
|
-
const hint = document.createElement('div');
|
|
7627
|
-
hint.className = 'cxp-settings-hint';
|
|
7628
|
-
hint.textContent = 'Configure in ~/.codex/config.toml under [mcp_servers]';
|
|
7629
|
-
mcpEl.appendChild(hint);
|
|
7630
|
-
} else {
|
|
7631
|
-
mcpEl.innerHTML = '';
|
|
7632
|
-
for (const server of servers) {
|
|
7633
|
-
const row = document.createElement('div');
|
|
7634
|
-
row.className = 'cxp-mcp-row';
|
|
7635
|
-
const name = document.createElement('span');
|
|
7636
|
-
name.className = 'cxp-mcp-name';
|
|
7637
|
-
name.textContent = server.name || 'Unknown';
|
|
7638
|
-
const status = document.createElement('span');
|
|
7639
|
-
status.className = 'cxp-mcp-status';
|
|
7640
|
-
status.textContent = server.status || 'unknown';
|
|
7641
|
-
status.dataset.status = server.status || 'unknown';
|
|
7642
|
-
const trusted = document.createElement('span');
|
|
7643
|
-
trusted.className = 'cxp-mcp-status';
|
|
7644
|
-
trusted.dataset.status = 'running';
|
|
7645
|
-
trusted.textContent = 'always allowed';
|
|
7646
|
-
trusted.hidden = !server.alwaysAllowed;
|
|
7647
|
-
const refreshBtn = document.createElement('button');
|
|
7648
|
-
refreshBtn.className = 'cxp-btn cxp-btn-sm';
|
|
7649
|
-
refreshBtn.textContent = 'Refresh';
|
|
7650
|
-
refreshBtn.addEventListener('click', async () => {
|
|
7651
|
-
try {
|
|
7652
|
-
await requestForSettings('mcp_refresh', { name: server.name });
|
|
7653
|
-
refreshBtn.textContent = 'Done';
|
|
7654
|
-
setTimeout(() => { refreshBtn.textContent = 'Refresh'; }, 2000);
|
|
7655
|
-
} catch (err) {
|
|
7656
|
-
appendSettingsError(`MCP refresh failed: ${err.message}`);
|
|
7657
|
-
}
|
|
7658
|
-
});
|
|
7659
|
-
row.append(name, status, trusted, refreshBtn);
|
|
7660
|
-
if (server.alwaysAllowed) {
|
|
7661
|
-
const revokeBtn = document.createElement('button');
|
|
7662
|
-
revokeBtn.className = 'cxp-btn cxp-btn-sm';
|
|
7663
|
-
revokeBtn.textContent = 'Revoke';
|
|
7664
|
-
revokeBtn.title = 'Require approval for this MCP server again';
|
|
7665
|
-
revokeBtn.addEventListener('click', async () => {
|
|
7666
|
-
revokeBtn.disabled = true;
|
|
7667
|
-
try {
|
|
7668
|
-
await requestForSettings('mcp_approval_set', {
|
|
7669
|
-
name: server.name,
|
|
7670
|
-
approvalMode: 'prompt',
|
|
7671
|
-
});
|
|
7672
|
-
server.approvalMode = 'prompt';
|
|
7673
|
-
server.alwaysAllowed = false;
|
|
7674
|
-
trusted.hidden = true;
|
|
7675
|
-
revokeBtn.remove();
|
|
7676
|
-
} catch (err) {
|
|
7677
|
-
revokeBtn.disabled = false;
|
|
7678
|
-
appendSettingsError(`MCP approval update failed: ${err.message}`);
|
|
7679
|
-
}
|
|
7680
|
-
});
|
|
7681
|
-
row.appendChild(revokeBtn);
|
|
7682
|
-
}
|
|
7683
|
-
if (server.requiresOAuth) {
|
|
7684
|
-
const loginBtn = document.createElement('button');
|
|
7685
|
-
loginBtn.className = 'cxp-btn cxp-btn-sm cxp-mcp-oauth-btn';
|
|
7686
|
-
loginBtn.dataset.mcpServer = server.name;
|
|
7687
|
-
loginBtn.textContent = 'Authenticate';
|
|
7688
|
-
loginBtn.addEventListener('click', async () => {
|
|
7689
|
-
try {
|
|
7690
|
-
await startMcpOAuthLogin(settingsTab, server.name);
|
|
7691
|
-
} catch (err) {
|
|
7692
|
-
appendSettingsError(`MCP OAuth failed: ${err.message}`);
|
|
7693
|
-
}
|
|
7694
|
-
});
|
|
7695
|
-
row.appendChild(loginBtn);
|
|
7696
|
-
}
|
|
7697
|
-
mcpEl.appendChild(row);
|
|
7698
|
-
}
|
|
7699
|
-
}
|
|
7700
|
-
}
|
|
7701
|
-
|
|
7702
|
-
const permissionsEl = overlay.querySelector('#cxp-settings-permissions');
|
|
7703
|
-
if (permissionsEl) {
|
|
7704
|
-
const stored = permissionData.status === 'fulfilled'
|
|
7705
|
-
? permissionData.value?.permissions?.filesystem || {}
|
|
7706
|
-
: {};
|
|
7707
|
-
const roots = ['write', 'read'].flatMap((access) => (
|
|
7708
|
-
(Array.isArray(stored[access]) ? stored[access] : []).map((path) => ({ access, path }))
|
|
7709
|
-
));
|
|
7710
|
-
permissionsEl.innerHTML = '';
|
|
7711
|
-
permissionsEl.className = '';
|
|
7712
|
-
if (!roots.length) {
|
|
7713
|
-
const hint = document.createElement('div');
|
|
7714
|
-
hint.className = 'cxp-settings-hint';
|
|
7715
|
-
hint.textContent = 'None';
|
|
7716
|
-
permissionsEl.appendChild(hint);
|
|
7717
|
-
} else {
|
|
7718
|
-
for (const root of roots) {
|
|
7719
|
-
const row = document.createElement('div');
|
|
7720
|
-
row.className = 'cxp-mcp-row';
|
|
7721
|
-
const path = document.createElement('span');
|
|
7722
|
-
path.className = 'cxp-mcp-name cxp-permission-root-path';
|
|
7723
|
-
path.textContent = root.path;
|
|
7724
|
-
path.title = root.path;
|
|
7725
|
-
const access = document.createElement('span');
|
|
7726
|
-
access.className = 'cxp-mcp-status';
|
|
7727
|
-
access.textContent = root.access;
|
|
7728
|
-
const remove = document.createElement('button');
|
|
7729
|
-
remove.type = 'button';
|
|
7730
|
-
remove.className = 'cxp-bar-action';
|
|
7731
|
-
remove.innerHTML = ICON_X;
|
|
7732
|
-
remove.title = 'Revoke folder access';
|
|
7733
|
-
remove.setAttribute('aria-label', `Revoke access to ${root.path}`);
|
|
7734
|
-
remove.addEventListener('click', async () => {
|
|
7735
|
-
remove.disabled = true;
|
|
7736
|
-
try {
|
|
7737
|
-
await requestForSettings('permission_root_remove', root);
|
|
7738
|
-
row.remove();
|
|
7739
|
-
if (!permissionsEl.querySelector('.cxp-mcp-row')) {
|
|
7740
|
-
const hint = document.createElement('div');
|
|
7741
|
-
hint.className = 'cxp-settings-hint';
|
|
7742
|
-
hint.textContent = 'None';
|
|
7743
|
-
permissionsEl.appendChild(hint);
|
|
7744
|
-
}
|
|
7745
|
-
} catch (err) {
|
|
7746
|
-
remove.disabled = false;
|
|
7747
|
-
appendSettingsError(err.message || 'Could not revoke folder access');
|
|
7748
|
-
}
|
|
7749
|
-
});
|
|
7750
|
-
row.append(path, access, remove);
|
|
7751
|
-
permissionsEl.appendChild(row);
|
|
7752
|
-
}
|
|
7753
|
-
}
|
|
7754
|
-
}
|
|
7755
|
-
|
|
7756
|
-
// Config — editable fields
|
|
7757
|
-
const configEl = overlay.querySelector('#cxp-settings-config');
|
|
7758
|
-
if (configEl) {
|
|
7759
|
-
const rawCfg = configData.status === 'fulfilled' ? (configData.value?.config || configData.value || {}) : {};
|
|
7760
|
-
const { effective: cfg, layers } = normalizeConfigResult(rawCfg);
|
|
7761
|
-
if (configData.status === 'fulfilled' && configData.value?.sessionOverrides) {
|
|
7762
|
-
settingsTab.sessionConfigOverrides = Object.fromEntries(Object.entries(SESSION_CONFIG_FIELDS)
|
|
7763
|
-
.filter(([, field]) => Object.hasOwn(configData.value.sessionOverrides, field))
|
|
7764
|
-
.map(([key, field]) => [key, configData.value.sessionOverrides[field]]));
|
|
7765
|
-
}
|
|
7766
|
-
const requirements = requirementsData.status === 'fulfilled' ? requirementsData.value : {};
|
|
7767
|
-
|
|
7768
|
-
// Get dynamic model list (fall back to hardcoded defaults)
|
|
7769
|
-
let models;
|
|
7770
|
-
try { models = await requestModelList(settingsTab); } catch { models = null; }
|
|
7771
|
-
const modelList = mergeCodexModelList(models);
|
|
7772
|
-
|
|
7773
|
-
configEl.innerHTML = '';
|
|
7774
|
-
const fieldDefs = [
|
|
7775
|
-
{ key: 'model', label: 'Model', type: 'select', options: modelList.map(m => ({ value: getCodexModelName(m), label: m?.label || getCodexModelName(m) })) },
|
|
7776
|
-
{ key: 'review_model', label: 'Review Model', type: 'select', options: [{ value: '', label: '(none)' }, ...modelList.map(m => ({ value: getCodexModelName(m), label: m?.label || getCodexModelName(m) }))] },
|
|
7777
|
-
{ key: 'model_provider', label: 'Provider', type: 'text', placeholder: 'openai, ollama…' },
|
|
7778
|
-
{ key: 'approval_policy', label: 'Approval Policy', type: 'select', options: [
|
|
7779
|
-
{ value: 'never', label: 'Never (No prompts)' },
|
|
7780
|
-
{ value: 'untrusted', label: 'Untrusted' },
|
|
7781
|
-
{ value: 'on-request', label: 'On Request' },
|
|
7782
|
-
]},
|
|
7783
|
-
{ key: 'sandbox_mode', label: 'Sandbox Mode', type: 'select', options: [
|
|
7784
|
-
{ value: 'workspace-write', label: 'Workspace Write' },
|
|
7785
|
-
{ value: 'read-only', label: 'Read Only' },
|
|
7786
|
-
{ value: 'danger-full-access', label: 'Full Access (Dangerous)' },
|
|
7787
|
-
]},
|
|
7788
|
-
{ key: 'personality', label: 'Personality', type: 'select', options: [
|
|
7789
|
-
{ value: '', label: '(default)' },
|
|
7790
|
-
{ value: 'pragmatic', label: 'Pragmatic' },
|
|
7791
|
-
{ value: 'friendly', label: 'Friendly' },
|
|
7792
|
-
]},
|
|
7793
|
-
{ key: 'service_tier', label: 'Service Tier', type: 'select', options: [
|
|
7794
|
-
{ value: '', label: '(default)' },
|
|
7795
|
-
]},
|
|
7796
|
-
{ key: 'model_reasoning_effort', label: 'Reasoning Effort', type: 'select', options: [
|
|
7797
|
-
{ value: '', label: '(default)' },
|
|
7798
|
-
{ value: 'minimal', label: 'Minimal' },
|
|
7799
|
-
{ value: 'low', label: 'Low' },
|
|
7800
|
-
{ value: 'medium', label: 'Medium' },
|
|
7801
|
-
{ value: 'high', label: 'High' },
|
|
7802
|
-
{ value: 'xhigh', label: 'Extra High' },
|
|
7803
|
-
{ value: 'max', label: 'Maximum' },
|
|
7804
|
-
{ value: 'ultra', label: 'Ultra' },
|
|
7805
|
-
]},
|
|
7806
|
-
{ key: 'model_reasoning_summary', label: 'Reasoning Summary', type: 'select', options: [
|
|
7807
|
-
{ value: '', label: '(default)' },
|
|
7808
|
-
{ value: 'auto', label: 'Auto' },
|
|
7809
|
-
{ value: 'concise', label: 'Concise' },
|
|
7810
|
-
{ value: 'detailed', label: 'Detailed' },
|
|
7811
|
-
{ value: 'none', label: 'None' },
|
|
7812
|
-
]},
|
|
7813
|
-
{ key: 'model_verbosity', label: 'Response Verbosity', type: 'select', options: [
|
|
7814
|
-
{ value: '', label: '(default)' },
|
|
7815
|
-
{ value: 'low', label: 'Low' },
|
|
7816
|
-
{ value: 'medium', label: 'Medium' },
|
|
7817
|
-
{ value: 'high', label: 'High' },
|
|
7818
|
-
]},
|
|
7819
|
-
{ key: 'model_context_window', label: 'Context Window', type: 'number', placeholder: 'tokens' },
|
|
7820
|
-
{ key: 'model_auto_compact_token_limit', label: 'Auto-Compact', type: 'number', placeholder: 'token limit' },
|
|
7821
|
-
{ key: 'web_search', label: 'Web Search', type: 'select', options: [
|
|
7822
|
-
{ value: '', label: '(default)' },
|
|
7823
|
-
{ value: 'disabled', label: 'Disabled' },
|
|
7824
|
-
{ value: 'cached', label: 'Cached' },
|
|
7825
|
-
{ value: 'indexed', label: 'Indexed' },
|
|
7826
|
-
{ value: 'live', label: 'Live' },
|
|
7827
|
-
] },
|
|
7828
|
-
{ key: 'features.fast_mode', label: 'Enable Fast Toggle', type: 'checkbox' },
|
|
7829
|
-
{ key: 'features.personality', label: 'Enable Personality', type: 'checkbox' },
|
|
7830
|
-
{ key: 'features.apps', label: 'Enable Apps', type: 'checkbox' },
|
|
7831
|
-
{ key: 'features.unified_exec', label: 'Unified Exec', type: 'checkbox' },
|
|
7832
|
-
];
|
|
7833
|
-
const effortDefinition = fieldDefs.find((def) => def.key === 'model_reasoning_effort');
|
|
7834
|
-
const modelMetadata = selectedModelOption(modelList, cfg.model || settingsTab.model);
|
|
7835
|
-
if (modelMetadata) effortDefinition.options = normalizeReasoningEfforts(modelMetadata).map((option) => ({ value: option.id === 'off' ? '' : option.id, label: option.label || option.id }));
|
|
7836
|
-
fieldDefs.find((def) => def.key === 'service_tier').options.push(...modelServiceTiers(modelMetadata));
|
|
7837
|
-
const form = document.createElement('div');
|
|
7838
|
-
form.className = 'cxp-config-form';
|
|
7839
|
-
const scopeLabel = document.createElement('label');
|
|
7840
|
-
scopeLabel.className = 'cxp-config-row';
|
|
7841
|
-
scopeLabel.textContent = 'Apply to ';
|
|
7842
|
-
const scope = document.createElement('select');
|
|
7843
|
-
scope.className = 'cxp-config-input';
|
|
7844
|
-
const savedOption = document.createElement('option'); savedOption.value = 'saved'; savedOption.textContent = 'Saved defaults';
|
|
7845
|
-
const sessionOption = document.createElement('option'); sessionOption.value = 'session'; sessionOption.textContent = 'Current thread';
|
|
7846
|
-
sessionOption.disabled = !settingsTab.threadId || !capabilityAvailability(capabilities, 'thread_settings_update').supported;
|
|
7847
|
-
scope.append(savedOption, sessionOption); scopeLabel.append(scope); form.append(scopeLabel);
|
|
7848
|
-
const scopeHint = document.createElement('div'); scopeHint.className = 'cxp-settings-hint';
|
|
7849
|
-
scopeHint.textContent = 'Saved defaults affect future sessions. Current thread settings apply to subsequent turns.';
|
|
7850
|
-
form.append(scopeHint);
|
|
7851
|
-
const inputs = {};
|
|
7852
|
-
const restrictions = {};
|
|
7853
|
-
for (const def of fieldDefs) {
|
|
7854
|
-
const row = document.createElement('div');
|
|
7855
|
-
row.className = 'cxp-config-row';
|
|
7856
|
-
const label = document.createElement('label');
|
|
7857
|
-
label.className = 'cxp-config-label';
|
|
7858
|
-
label.textContent = def.label;
|
|
7859
|
-
row.appendChild(label);
|
|
7860
|
-
const val = configValue(cfg, def.key);
|
|
7861
|
-
const restriction = configRestriction(requirements, def.key);
|
|
7862
|
-
restrictions[def.key] = restriction;
|
|
7863
|
-
if (def.type === 'select') {
|
|
7864
|
-
const sel = document.createElement('select');
|
|
7865
|
-
sel.className = 'cxp-config-input';
|
|
7866
|
-
for (const opt of def.options) {
|
|
7867
|
-
const o = document.createElement('option');
|
|
7868
|
-
o.value = opt.value;
|
|
7869
|
-
o.textContent = opt.label;
|
|
7870
|
-
if (String(val ?? '') === opt.value) o.selected = true;
|
|
7871
|
-
if (restriction.allowed && opt.value && !restriction.allowed.some((allowed) => JSON.stringify(allowed) === JSON.stringify(opt.value))) o.disabled = true;
|
|
7872
|
-
sel.appendChild(o);
|
|
7873
|
-
}
|
|
7874
|
-
if (val != null && !def.options.some((opt) => opt.value === String(val))) {
|
|
7875
|
-
const unknown = document.createElement('option');
|
|
7876
|
-
unknown.value = typeof val === 'object' ? JSON.stringify(val) : String(val);
|
|
7877
|
-
unknown.textContent = `${unknown.value} (configured)`; unknown.selected = true;
|
|
7878
|
-
sel.appendChild(unknown);
|
|
7879
|
-
sel.dataset.originalValue = JSON.stringify(val);
|
|
7880
|
-
}
|
|
7881
|
-
row.appendChild(sel);
|
|
7882
|
-
inputs[def.key] = sel;
|
|
7883
|
-
} else if (def.type === 'checkbox') {
|
|
7884
|
-
const cb = document.createElement('input');
|
|
7885
|
-
cb.type = 'checkbox';
|
|
7886
|
-
cb.className = 'cxp-config-checkbox';
|
|
7887
|
-
cb.checked = typeof restriction.fixed === 'boolean' ? restriction.fixed : !!val;
|
|
7888
|
-
row.appendChild(cb);
|
|
7889
|
-
inputs[def.key] = cb;
|
|
7890
|
-
} else {
|
|
7891
|
-
const inp = document.createElement('input');
|
|
7892
|
-
inp.type = def.type === 'number' ? 'number' : 'text';
|
|
7893
|
-
inp.className = 'cxp-config-input';
|
|
7894
|
-
inp.value = val != null ? val : '';
|
|
7895
|
-
inp.placeholder = def.placeholder || '';
|
|
7896
|
-
row.appendChild(inp);
|
|
7897
|
-
inputs[def.key] = inp;
|
|
7898
|
-
}
|
|
7899
|
-
// Config layer badge
|
|
7900
|
-
if (layers[def.key] || restriction.reason) {
|
|
7901
|
-
const badge = document.createElement('span');
|
|
7902
|
-
badge.className = 'cxp-config-layer';
|
|
7903
|
-
badge.textContent = `(${restriction.reason || layers[def.key]})`;
|
|
7904
|
-
row.appendChild(badge);
|
|
7905
|
-
}
|
|
7906
|
-
form.appendChild(row);
|
|
7528
|
+
const requestForSettings = (type, data = {}) => requestForCodexOwner(settingsTab, settingsOwner, type, data, t('codexSettings.changedConversation'));
|
|
7529
|
+
const capabilities = await getCodexCapabilities(settingsTab);
|
|
7530
|
+
if (settingsTab.closed || !isActiveTab(settingsTab)) return;
|
|
7531
|
+
const view = await mountCodexSettings({
|
|
7532
|
+
host: _getPanelEl(), tab: settingsTab,
|
|
7533
|
+
request: requestForSettings,
|
|
7534
|
+
capabilities,
|
|
7535
|
+
account: _codexAccounts.find(a => a.id === (settingsTab.accountId || 'default')),
|
|
7536
|
+
models: async () => (await requestModelList(settingsTab)) || [],
|
|
7537
|
+
normalizeConfig: normalizeConfigResult,
|
|
7538
|
+
manageAccount: () => { if (isActiveTab(settingsTab)) openAccountMenu({ manage: settingsTab.accountId || 'default' }); },
|
|
7539
|
+
authenticate: name => startMcpOAuthLogin(settingsTab, name),
|
|
7540
|
+
onSaved: ({ scope, patch, overrides }) => {
|
|
7541
|
+
settingsTab.sessionConfigOverrides = overrides;
|
|
7542
|
+
if (scope === 'session') {
|
|
7543
|
+
if (Object.hasOwn(patch, 'model')) settingsTab.model = patch.model;
|
|
7544
|
+
if (Object.hasOwn(patch, 'model_reasoning_effort')) settingsTab.effort = patch.model_reasoning_effort || 'off';
|
|
7545
|
+
if (Object.hasOwn(patch, 'approval_policy')) settingsTab.autoAccept = patch.approval_policy === 'never';
|
|
7546
|
+
syncToolbarState(); saveTabs();
|
|
7907
7547
|
}
|
|
7908
|
-
|
|
7909
|
-
|
|
7910
|
-
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
else inputs[def.key].value = value != null ? (typeof value === 'object' ? JSON.stringify(value) : String(value)) : '';
|
|
7917
|
-
}
|
|
7918
|
-
saveBtn.textContent = scope.value === 'session' ? 'Apply to Current Thread' : 'Save Defaults';
|
|
7919
|
-
};
|
|
7920
|
-
scope.addEventListener('change', refreshScope);
|
|
7921
|
-
refreshScope();
|
|
7922
|
-
saveBtn.addEventListener('click', async () => {
|
|
7923
|
-
saveBtn.disabled = true;
|
|
7924
|
-
saveBtn.textContent = 'Saving…';
|
|
7925
|
-
try {
|
|
7926
|
-
const currentConfig = scope.value === 'session' ? { ...cfg, ...(settingsTab.sessionConfigOverrides || {}) } : cfg;
|
|
7927
|
-
const newCfg = configChanges(fieldDefs, inputs, currentConfig);
|
|
7928
|
-
if (scope.value === 'session') {
|
|
7929
|
-
if (settingsTab.running) throw new Error('Wait for the active turn to finish before applying thread settings.');
|
|
7930
|
-
await requestForSettings('thread_settings_update', { threadId: settingsTab.threadId, ...sessionSettings(newCfg) });
|
|
7931
|
-
settingsTab.sessionConfigOverrides = { ...(settingsTab.sessionConfigOverrides || {}), ...newCfg };
|
|
7932
|
-
if (Object.hasOwn(newCfg, 'model')) settingsTab.model = newCfg.model;
|
|
7933
|
-
if (Object.hasOwn(newCfg, 'model_reasoning_effort')) settingsTab.effort = newCfg.model_reasoning_effort || 'off';
|
|
7934
|
-
if (Object.hasOwn(newCfg, 'approval_policy')) settingsTab.autoAccept = newCfg.approval_policy === 'never';
|
|
7935
|
-
syncToolbarState(); saveTabs();
|
|
7936
|
-
} else if (Object.keys(newCfg).length) {
|
|
7937
|
-
await requestForSettings('config_write', { config: newCfg });
|
|
7938
|
-
Object.assign(cfg, newCfg);
|
|
7939
|
-
}
|
|
7940
|
-
invalidateCodexFeatureCaches(settingsTab);
|
|
7941
|
-
saveBtn.textContent = 'Saved!';
|
|
7942
|
-
refreshModelCatalog(settingsTab);
|
|
7943
|
-
setTimeout(() => { refreshScope(); saveBtn.disabled = false; }, 1500);
|
|
7944
|
-
} catch (err) {
|
|
7945
|
-
saveBtn.textContent = 'Save Failed';
|
|
7946
|
-
appendSettingsError(`Config save failed: ${err.message}`);
|
|
7947
|
-
setTimeout(() => { refreshScope(); saveBtn.disabled = false; }, 1500);
|
|
7948
|
-
}
|
|
7949
|
-
});
|
|
7950
|
-
form.appendChild(saveBtn);
|
|
7951
|
-
configEl.appendChild(form);
|
|
7952
|
-
}
|
|
7953
|
-
// Opened for one section (the Context settings popover's "Manage"): bring it into view.
|
|
7954
|
-
if (section) overlay.querySelector(`#cxp-settings-${section}`)?.closest('.cxp-settings-section')?.scrollIntoView({ block: 'start' });
|
|
7955
|
-
} catch (error) { appendSettingsError(error.message || 'Could not load Codex settings.'); }
|
|
7548
|
+
invalidateCodexFeatureCaches(settingsTab); refreshModelCatalog(settingsTab);
|
|
7549
|
+
clearCodexConfigWarnings({ obsoleteOnly: true });
|
|
7550
|
+
},
|
|
7551
|
+
});
|
|
7552
|
+
if (section && view) {
|
|
7553
|
+
const target = section === 'mcp' ? view.sections.tools : view.sections[section];
|
|
7554
|
+
target?.scrollIntoView({ block: 'start' });
|
|
7555
|
+
}
|
|
7956
7556
|
}
|
|
7957
7557
|
|
|
7958
7558
|
export function startCompaction() {
|