synabun 2.0.7 → 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 +38 -0
- package/README.md +1 -1
- package/hooks/claude-code/post-plan.mjs +6 -30
- package/hooks/claude-code/session-start.mjs +1 -4
- package/hooks/claude-code/shared.mjs +106 -72
- package/lib/package-processes.js +670 -0
- package/lib/runtime-dependencies.js +225 -0
- 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/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/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/tools/agents.d.ts +1 -1
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +1 -1
- 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 +1 -1
- package/mcp-server/dist/tools/whatsapp-send-file.d.ts.map +1 -1
- package/mcp-server/dist/tools/whatsapp-send-file.js +1 -1
- package/mcp-server/dist/tools/whatsapp-send-file.js.map +1 -1
- 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 +16 -4
- package/mcp-server/dist/tui.js.map +1 -1
- package/mcp-server/package-lock.json +3 -3
- package/mcp-server/package.json +3 -3
- package/mcp-server/src/services/browser-bench.ts +1 -1
- package/mcp-server/src/services/categories.ts +77 -32
- package/mcp-server/src/services/desktop-bench.ts +1 -1
- package/mcp-server/src/tools/agents.ts +1 -1
- 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 +1 -1
- 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 +22 -9
- package/neural-interface/i18n/en.json +18 -0
- package/neural-interface/i18n/pt-BR.json +18 -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 +19 -0
- package/neural-interface/lib/assistant-route-gate-codex.js +3 -1
- package/neural-interface/lib/assistant-runtime.js +5 -1
- package/neural-interface/lib/codex-account-auth.js +4 -2
- package/neural-interface/lib/codex-accounts.js +14 -1
- package/neural-interface/lib/codex-settings-schema.js +5 -3
- package/neural-interface/lib/exec-loop-command.js +3 -1
- package/neural-interface/lib/install-details.js +23 -5
- package/neural-interface/lib/native-loop-providers.js +6 -1
- package/neural-interface/lib/provider-panel-terminal-auth.js +3 -2
- package/neural-interface/lib/session-indexer.js +3 -1
- package/neural-interface/lib/session-title-generator.js +2 -0
- package/neural-interface/package-lock.json +2 -2
- package/neural-interface/package.json +1 -1
- package/neural-interface/public/shared/account-menu.js +4 -1
- package/neural-interface/public/shared/account-usage.js +62 -2
- package/neural-interface/public/shared/account-view.js +2 -1
- package/neural-interface/public/shared/assistant/asst-account-menu.js +298 -0
- package/neural-interface/public/shared/assistant/asst-api.js +7 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +232 -75
- package/neural-interface/public/shared/assistant/asst-menu.js +204 -77
- package/neural-interface/public/shared/assistant/asst-model-chip.js +135 -0
- package/neural-interface/public/shared/assistant/asst-panel.js +39 -2
- package/neural-interface/public/shared/assistant/asst-styles.js +66 -17
- package/neural-interface/public/shared/cdx/cdx-panel.js +1 -1
- package/neural-interface/public/shared/cdx/cdx-styles.js +45 -5
- package/neural-interface/public/shared/cdx/cdx-tabs.js +3 -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 +4 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +51 -2
- package/neural-interface/public/shared/showcase-privacy.js +2 -1
- package/neural-interface/public/shared/styles.css +3 -1
- package/neural-interface/public/shared/ui-claude-panel.js +50 -4
- package/neural-interface/public/shared/ui-explorer.js +2 -0
- package/neural-interface/public/shared/ui-sync.js +2 -0
- package/neural-interface/public/shared/ui-update.js +4 -2
- package/neural-interface/scripts/rebuild-pty.js +14 -2
- package/neural-interface/server.js +180 -86
- package/npm-shrinkwrap.json +4424 -0
- package/package.json +54 -2
- package/postinstall.js +61 -47
- package/preuninstall.js +8 -35
- package/setup.js +76 -44
- 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
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
* look successful).
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { z } from 'zod';
|
|
17
|
+
import { z } from 'zod/v3';
|
|
18
18
|
import { v4 as uuidv4 } from 'uuid';
|
|
19
19
|
import * as ni from '../../services/neural-interface.js';
|
|
20
20
|
import { generateEmbedding } from '../../services/local-embeddings.js';
|
|
21
21
|
import { upsertMemory } from '../../services/sqlite.js';
|
|
22
|
-
import {
|
|
22
|
+
import { ensureCategory, FEATURE_CATEGORIES } from '../../services/categories.js';
|
|
23
23
|
import { detectProject } from '../../config.js';
|
|
24
24
|
import type { MemoryPayload } from '../../types.js';
|
|
25
25
|
import { text } from '../response.js';
|
|
@@ -63,17 +63,9 @@ async function ensureOnStudio(r: Resolved): Promise<string | null> {
|
|
|
63
63
|
return ensureAuth(r);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
/** Ensure the dedup-ledger category exists (so it shows in the UI and routing). */
|
|
66
|
+
/** Ensure the dedup-ledger category exists (so it shows in the UI and routing): made on the first upload, under "social" when that exists. */
|
|
67
67
|
function ensureTrailerCategory(): void {
|
|
68
|
-
|
|
69
|
-
if (!categoryExists(TRAILER_CATEGORY)) {
|
|
70
|
-
addCategory(
|
|
71
|
-
TRAILER_CATEGORY,
|
|
72
|
-
'One memory per uploaded YouTube trailer — the dedup ledger. Written automatically by youtube_upload; tagged with canonical source ids (igdb:/appid:/ytid:/name:) that youtube_source reads to skip already-posted trailers. Do not store anything else here.',
|
|
73
|
-
categoryExists('social') ? 'social' : undefined,
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
} catch { /* non-fatal — upsertMemory does not require a registered category */ }
|
|
68
|
+
ensureCategory(TRAILER_CATEGORY, FEATURE_CATEGORIES[TRAILER_CATEGORY].description, { parent: 'social' });
|
|
77
69
|
}
|
|
78
70
|
|
|
79
71
|
/** Write the dedup-ledger memory for a just-uploaded trailer. Returns the memory id, or null on failure. */
|
package/mcp-server/src/tui.ts
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import { retrieveMemory } from './services/memory-retrieval.js';
|
|
3
3
|
|
|
4
4
|
// Load .env from parent directory before any service imports
|
|
5
|
-
import { readFileSync } from 'fs';
|
|
6
|
-
import { resolve } from 'path';
|
|
7
|
-
import { getDataHome } from '../../lib/paths.js';
|
|
8
|
-
|
|
9
|
-
const envPath = process.env.DOTENV_PATH || resolve(getDataHome(), '.env');
|
|
5
|
+
import { readFileSync } from 'fs';
|
|
6
|
+
import { resolve } from 'path';
|
|
7
|
+
import { getDataHome } from '../../lib/paths.js';
|
|
8
|
+
|
|
9
|
+
const envPath = process.env.DOTENV_PATH || resolve(getDataHome(), '.env');
|
|
10
10
|
try {
|
|
11
11
|
const envContent = readFileSync(envPath, 'utf-8');
|
|
12
12
|
for (const line of envContent.split('\n')) {
|
|
@@ -407,6 +407,10 @@ async function editMemory(id: string, payload: MemoryPayload): Promise<void> {
|
|
|
407
407
|
console.log(success(` ${ICONS.check} Content updated & re-embedded.`));
|
|
408
408
|
} else if (field === 'category') {
|
|
409
409
|
const cats = getAllCategories();
|
|
410
|
+
if (cats.length === 0) {
|
|
411
|
+
console.log(warn(` ${ICONS.cross} No categories yet. Create one under Categories first.`));
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
410
414
|
const val = await safePrompt(() =>
|
|
411
415
|
select({
|
|
412
416
|
message: ' Category:',
|
|
@@ -608,6 +612,13 @@ async function searchScreen(): Promise<void> {
|
|
|
608
612
|
async function createScreen(): Promise<void> {
|
|
609
613
|
printScreenHeader(`${ICONS.plus} Create Memory`, 'Store a new piece of knowledge');
|
|
610
614
|
|
|
615
|
+
// A fresh install has no categories until a project is added or one is created.
|
|
616
|
+
const cats = getAllCategories();
|
|
617
|
+
if (cats.length === 0) {
|
|
618
|
+
console.log(warn(` ${ICONS.cross} No categories yet. Create one under Categories first.`));
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
|
|
611
622
|
// Content
|
|
612
623
|
const content = await safePrompt(() =>
|
|
613
624
|
input({
|
|
@@ -618,7 +629,6 @@ async function createScreen(): Promise<void> {
|
|
|
618
629
|
if (content === null) return;
|
|
619
630
|
|
|
620
631
|
// Category
|
|
621
|
-
const cats = getAllCategories();
|
|
622
632
|
const category = await safePrompt(() =>
|
|
623
633
|
select({
|
|
624
634
|
message: accent(` ${ICONS.folder} Category:`),
|
|
@@ -793,12 +803,15 @@ async function categoriesScreen(): Promise<void> {
|
|
|
793
803
|
);
|
|
794
804
|
if (reassign === null || !reassign) continue;
|
|
795
805
|
|
|
806
|
+
const others = getAllCategories().filter(c => c !== name);
|
|
807
|
+
if (others.length === 0) {
|
|
808
|
+
console.log(warn(` ${ICONS.cross} No other category to move them to. Create one first.`));
|
|
809
|
+
continue;
|
|
810
|
+
}
|
|
796
811
|
const target = await safePrompt(() =>
|
|
797
812
|
select({
|
|
798
813
|
message: accent(' Reassign to:'),
|
|
799
|
-
choices:
|
|
800
|
-
.filter(c => c !== name)
|
|
801
|
-
.map(c => ({ name: ` ${colorCategory(c)}`, value: c })),
|
|
814
|
+
choices: others.map(c => ({ name: ` ${colorCategory(c)}`, value: c })),
|
|
802
815
|
})
|
|
803
816
|
);
|
|
804
817
|
if (target === null) continue;
|
|
@@ -6355,6 +6355,12 @@
|
|
|
6355
6355
|
"left": "{percent}% left",
|
|
6356
6356
|
"resets": "resets {time}"
|
|
6357
6357
|
},
|
|
6358
|
+
"accountMenu": {
|
|
6359
|
+
"uses": "{label} uses",
|
|
6360
|
+
"workers": "Workers use",
|
|
6361
|
+
"workersHint": "Used when a dispatch names no account.",
|
|
6362
|
+
"switchNote": "Another account starts a new conversation."
|
|
6363
|
+
},
|
|
6358
6364
|
"usage": {
|
|
6359
6365
|
"task": "Current task",
|
|
6360
6366
|
"tokens": "tokens",
|
|
@@ -7315,6 +7321,8 @@
|
|
|
7315
7321
|
"variant": "Model variant",
|
|
7316
7322
|
"variantDefault": "default variant",
|
|
7317
7323
|
"account": "Account profile",
|
|
7324
|
+
"accountShort": "Account",
|
|
7325
|
+
"accountAutoShort": "Auto",
|
|
7318
7326
|
"accountHint": "as",
|
|
7319
7327
|
"project": "Working project",
|
|
7320
7328
|
"projectHint": "in",
|
|
@@ -7365,6 +7373,16 @@
|
|
|
7365
7373
|
"thorough": "Full coverage, whole suite, live checks."
|
|
7366
7374
|
}
|
|
7367
7375
|
},
|
|
7376
|
+
"adminSandbox": {
|
|
7377
|
+
"group": "Every agent",
|
|
7378
|
+
"label": "Admin sandbox",
|
|
7379
|
+
"on": "On",
|
|
7380
|
+
"off": "Off",
|
|
7381
|
+
"hint": "Only changes anything when SynaBun runs on Windows. On: Codex can set up its strongest sandbox, which asks for administrator approval once per account. Off: no admin prompt; Codex uses a sandbox that needs no admin, with weaker isolation.",
|
|
7382
|
+
"aria": "{label}: {value}. Only changes anything when SynaBun runs on Windows.",
|
|
7383
|
+
"statusOn": "Admin sandbox: on. On Windows, Codex may ask for administrator approval once per account to set up its sandbox.",
|
|
7384
|
+
"statusOff": "Admin sandbox: off. No agent SynaBun starts asks for administrator approval for a sandbox."
|
|
7385
|
+
},
|
|
7368
7386
|
"accounts": {
|
|
7369
7387
|
"signInAccount": "Sign in to {label}…",
|
|
7370
7388
|
"title": "{provider} accounts",
|
|
@@ -6307,6 +6307,12 @@
|
|
|
6307
6307
|
"left": "{percent}% disponível",
|
|
6308
6308
|
"resets": "renova em {time}"
|
|
6309
6309
|
},
|
|
6310
|
+
"accountMenu": {
|
|
6311
|
+
"uses": "{label} usa",
|
|
6312
|
+
"workers": "Workers usam",
|
|
6313
|
+
"workersHint": "Usada quando o despacho não indica uma conta.",
|
|
6314
|
+
"switchNote": "Outra conta inicia uma nova conversa."
|
|
6315
|
+
},
|
|
6310
6316
|
"usage": {
|
|
6311
6317
|
"task": "Tarefa atual",
|
|
6312
6318
|
"tokens": "tokens",
|
|
@@ -7267,6 +7273,8 @@
|
|
|
7267
7273
|
"variant": "Variante do modelo",
|
|
7268
7274
|
"variantDefault": "variante padrão",
|
|
7269
7275
|
"account": "Perfil da conta",
|
|
7276
|
+
"accountShort": "Conta",
|
|
7277
|
+
"accountAutoShort": "Auto",
|
|
7270
7278
|
"accountHint": "como",
|
|
7271
7279
|
"project": "Projeto de trabalho",
|
|
7272
7280
|
"projectHint": "entrada",
|
|
@@ -7317,6 +7325,16 @@
|
|
|
7317
7325
|
"thorough": "Cobertura completa, suíte inteira, verificações ao vivo."
|
|
7318
7326
|
}
|
|
7319
7327
|
},
|
|
7328
|
+
"adminSandbox": {
|
|
7329
|
+
"group": "Todos os agentes",
|
|
7330
|
+
"label": "Sandbox de administrador",
|
|
7331
|
+
"on": "Ativado",
|
|
7332
|
+
"off": "Desativado",
|
|
7333
|
+
"hint": "Só muda algo quando o SynaBun roda no Windows. Ativado: o Codex pode configurar seu sandbox mais forte, que pede aprovação de administrador uma vez por conta. Desativado: nenhum pedido de administrador; o Codex usa um sandbox que não precisa de administrador, com isolamento mais fraco.",
|
|
7334
|
+
"aria": "{label}: {value}. Só muda algo quando o SynaBun roda no Windows.",
|
|
7335
|
+
"statusOn": "Sandbox de administrador: ativado. No Windows, o Codex pode pedir aprovação de administrador uma vez por conta para configurar seu sandbox.",
|
|
7336
|
+
"statusOff": "Sandbox de administrador: desativado. Nenhum agente iniciado pelo SynaBun pede aprovação de administrador para um sandbox."
|
|
7337
|
+
},
|
|
7320
7338
|
"accounts": {
|
|
7321
7339
|
"signInAccount": "Entrar em {label}…",
|
|
7322
7340
|
"title": "Contas de {provider}",
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Admin sandbox: what it means for each agent (pure)
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// One global setting (lib/agent-sandbox-setting.js, the Assistant's permission
|
|
6
|
+
// menu) decides whether an agent SynaBun starts may use a sandbox whose setup
|
|
7
|
+
// needs Windows administrator approval (a UAC prompt). Off is the default:
|
|
8
|
+
// then nothing SynaBun starts can ask for one. Each provider says here what
|
|
9
|
+
// the setting means for it; a launcher asks this module and never decides by
|
|
10
|
+
// itself. A provider SynaBun can start must have an entry
|
|
11
|
+
// (tests/agent-sandbox-elevation.test.mjs fails otherwise).
|
|
12
|
+
//
|
|
13
|
+
// The setting never changes a provider's sandbox policy (read-only,
|
|
14
|
+
// workspace-write, full access): only which implementation of it may need an
|
|
15
|
+
// administrator. It is a launch override, never written into a config file.
|
|
16
|
+
|
|
17
|
+
export const ADMIN_SANDBOX_DEFAULT = false;
|
|
18
|
+
|
|
19
|
+
const CODEX_SETTING = 'windows.sandbox';
|
|
20
|
+
|
|
21
|
+
export const SANDBOX_ELEVATION = Object.freeze({
|
|
22
|
+
// `windows.sandbox` (Codex 0.163: "elevated" | "unelevated" | "mxc"): "elevated"
|
|
23
|
+
// provisions two local sandbox accounts with codex-windows-sandbox-setup.exe, a
|
|
24
|
+
// UAC prompt once per CODEX_HOME (SynaBun's accounts each have one);
|
|
25
|
+
// "unelevated" is Codex's restricted-token sandbox: no administrator, weaker isolation.
|
|
26
|
+
codex: Object.freeze({
|
|
27
|
+
changes: true,
|
|
28
|
+
setting: CODEX_SETTING,
|
|
29
|
+
off: 'unelevated',
|
|
30
|
+
on: 'elevated',
|
|
31
|
+
reason: 'Codex picks its Windows sandbox with windows.sandbox: "elevated" needs a one-time administrator setup per account, "unelevated" needs none.',
|
|
32
|
+
}),
|
|
33
|
+
// Claude Code 2.1.303 has a Windows sandbox whose one-time install asks for
|
|
34
|
+
// administrator approval, but only `claude sandbox install` or `/sandbox install`
|
|
35
|
+
// starts it: a session never does, and SynaBun never runs either command.
|
|
36
|
+
'claude-code': Object.freeze({
|
|
37
|
+
changes: false,
|
|
38
|
+
reason: 'Claude Code installs its Windows sandbox only through `claude sandbox install` or `/sandbox install`, which SynaBun never runs; a session never asks for administrator approval by itself.',
|
|
39
|
+
}),
|
|
40
|
+
// OpenCode has no operating-system sandbox: permission rules only (its
|
|
41
|
+
// "sandboxes" are worktree folders).
|
|
42
|
+
opencode: Object.freeze({
|
|
43
|
+
changes: false,
|
|
44
|
+
reason: 'OpenCode has no operating-system sandbox, only permission rules, so nothing it starts needs administrator approval.',
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
/** Only `true` turns it on: anything else (missing, a string, null) is the default, off. */
|
|
49
|
+
export function normalizeAdminSandbox(value) {
|
|
50
|
+
return value === true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Providers the setting changes (['codex']): what the panel's copy may name. */
|
|
54
|
+
export function adminSandboxProviders() {
|
|
55
|
+
return Object.keys(SANDBOX_ELEVATION).filter((provider) => SANDBOX_ELEVATION[provider].changes);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* What a launcher of `provider` adds for the setting: `args` (CLI words, before
|
|
60
|
+
* the subcommand or anywhere an override is taken), `config` (the same as an
|
|
61
|
+
* SDK config object) and `value`. A provider the setting does not change gets
|
|
62
|
+
* nothing to add and its reason. An unknown provider throws: it must declare
|
|
63
|
+
* its mapping in SANDBOX_ELEVATION first.
|
|
64
|
+
*/
|
|
65
|
+
export function sandboxElevationFor(provider, adminSandbox) {
|
|
66
|
+
const entry = SANDBOX_ELEVATION[provider];
|
|
67
|
+
if (!entry) throw new Error(`No admin sandbox mapping for provider "${provider}": add it to SANDBOX_ELEVATION.`);
|
|
68
|
+
const on = normalizeAdminSandbox(adminSandbox);
|
|
69
|
+
if (!entry.changes) return { provider, changes: false, adminSandbox: on, value: null, args: [], config: {}, reason: entry.reason };
|
|
70
|
+
const value = on ? entry.on : entry.off;
|
|
71
|
+
return { provider, changes: true, adminSandbox: on, value, args: ['-c', `${entry.setting}=${JSON.stringify(value)}`], config: configAt(entry.setting, value), reason: entry.reason };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function configAt(dotted, value) {
|
|
75
|
+
const keys = dotted.split('.');
|
|
76
|
+
const out = {};
|
|
77
|
+
let node = out;
|
|
78
|
+
keys.forEach((key, index) => { node[key] = index === keys.length - 1 ? value : {}; node = node[key]; });
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** 'elevated' when the setting is on, else 'unelevated'. */
|
|
83
|
+
export function codexWindowsSandbox(adminSandbox) {
|
|
84
|
+
return sandboxElevationFor('codex', adminSandbox).value;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** ['-c', 'windows.sandbox="unelevated"'] (or "elevated"): a Codex launch override. */
|
|
88
|
+
export function codexWindowsSandboxArgs(adminSandbox) {
|
|
89
|
+
return sandboxElevationFor('codex', adminSandbox).args;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** { windows: { sandbox: 'unelevated' } } (or 'elevated'): the same for the Codex SDK's `config`. */
|
|
93
|
+
export function codexWindowsSandboxConfig(adminSandbox) {
|
|
94
|
+
return sandboxElevationFor('codex', adminSandbox).config;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* A Codex process that runs no command and no turn (a probe in a throwaway
|
|
99
|
+
* home: hooks, settings schema, feature switches) needs no sandbox at all: it
|
|
100
|
+
* is always started with the one that needs no administrator, whatever the setting.
|
|
101
|
+
*/
|
|
102
|
+
export const CODEX_PROBE_SANDBOX_ARGS = Object.freeze([...codexWindowsSandboxArgs(false)]);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Admin sandbox: the one global value
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// DATA_HOME/data/agent-sandbox.json ({ adminSandbox, updatedAt }), read live:
|
|
6
|
+
// one value for every agent SynaBun starts, not per session or tab. No file
|
|
7
|
+
// (or one that cannot be read) is the default, off. What the value means for
|
|
8
|
+
// each provider is lib/agent-sandbox-elevation.js. Only the UI changes it
|
|
9
|
+
// (PUT /api/assistant/admin-sandbox answers UI_ONLY to agents); a change
|
|
10
|
+
// reaches every window as `agents:admin-sandbox-changed` and every listener
|
|
11
|
+
// (server.js restarts the idle Codex app-servers there).
|
|
12
|
+
|
|
13
|
+
import { mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from 'node:fs';
|
|
14
|
+
import { dirname } from 'node:path';
|
|
15
|
+
import { ADMIN_SANDBOX_DEFAULT, adminSandboxProviders, normalizeAdminSandbox } from './agent-sandbox-elevation.js';
|
|
16
|
+
|
|
17
|
+
export const ADMIN_SANDBOX_EVENT = 'agents:admin-sandbox-changed';
|
|
18
|
+
|
|
19
|
+
export function createAdminSandboxSetting({ path, broadcast = () => {}, log = () => {}, now = Date.now } = {}) {
|
|
20
|
+
if (!path) throw new Error('createAdminSandboxSetting requires a path');
|
|
21
|
+
const listeners = new Set();
|
|
22
|
+
let cache = null; // { mtimeMs, value }
|
|
23
|
+
|
|
24
|
+
function read() {
|
|
25
|
+
try {
|
|
26
|
+
const stat = statSync(path);
|
|
27
|
+
if (cache && cache.mtimeMs === stat.mtimeMs) return cache.value;
|
|
28
|
+
const data = JSON.parse(readFileSync(path, 'utf8'));
|
|
29
|
+
const value = normalizeAdminSandbox(data?.adminSandbox);
|
|
30
|
+
cache = { mtimeMs: stat.mtimeMs, value };
|
|
31
|
+
return value;
|
|
32
|
+
} catch {
|
|
33
|
+
return ADMIN_SANDBOX_DEFAULT;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** What the UI shows: the value and the providers it changes. */
|
|
37
|
+
function view() {
|
|
38
|
+
return { adminSandbox: read(), providers: adminSandboxProviders() };
|
|
39
|
+
}
|
|
40
|
+
function set(value) {
|
|
41
|
+
const next = normalizeAdminSandbox(value);
|
|
42
|
+
const before = read();
|
|
43
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
44
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
45
|
+
writeFileSync(tmp, JSON.stringify({ adminSandbox: next, updatedAt: new Date(now()).toISOString() }, null, 2) + '\n', 'utf8');
|
|
46
|
+
renameSync(tmp, path);
|
|
47
|
+
cache = null;
|
|
48
|
+
const changed = next !== before;
|
|
49
|
+
if (changed) log('agent-sandbox', `admin sandbox ${next ? 'on' : 'off'}`);
|
|
50
|
+
try { broadcast({ type: ADMIN_SANDBOX_EVENT, ...view() }); } catch { /* nobody listening */ }
|
|
51
|
+
if (changed) for (const listener of [...listeners]) { try { listener(next); } catch { /* the listener's own failure */ } }
|
|
52
|
+
return view();
|
|
53
|
+
}
|
|
54
|
+
function subscribe(listener) { listeners.add(listener); return () => listeners.delete(listener); }
|
|
55
|
+
|
|
56
|
+
return { enabled: read, view, set, subscribe, path };
|
|
57
|
+
}
|
|
@@ -150,6 +150,8 @@ export function createAssistantApi({
|
|
|
150
150
|
// after this router), and the port the server listens on (the Host check of that route).
|
|
151
151
|
whatsapp = null,
|
|
152
152
|
port = 3344,
|
|
153
|
+
// The Admin sandbox setting (lib/agent-sandbox-setting.js): one global value for every agent SynaBun starts.
|
|
154
|
+
adminSandbox = null,
|
|
153
155
|
} = {}) {
|
|
154
156
|
if (!dispatcher) throw new Error('createAssistantApi requires a dispatcher');
|
|
155
157
|
const router = Router();
|
|
@@ -1230,6 +1232,23 @@ export function createAssistantApi({
|
|
|
1230
1232
|
} catch (error) { sendError(res, error); }
|
|
1231
1233
|
});
|
|
1232
1234
|
|
|
1235
|
+
// ── Admin sandbox (lib/agent-sandbox-setting.js) ───────────────────────────
|
|
1236
|
+
// Whether an agent SynaBun starts may use a sandbox whose setup needs Windows administrator
|
|
1237
|
+
// approval. Global, not per session. The user's setting: an agent cannot change it.
|
|
1238
|
+
router.get('/admin-sandbox', (req, res) => {
|
|
1239
|
+
if (!adminSandbox) return res.status(503).json({ ok: false, code: 'ADMIN_SANDBOX_UNAVAILABLE', error: 'The Admin sandbox setting is not available on this server' });
|
|
1240
|
+
res.json({ ok: true, ...adminSandbox.view() });
|
|
1241
|
+
});
|
|
1242
|
+
router.put('/admin-sandbox', requireJson, (req, res) => {
|
|
1243
|
+
if (!adminSandbox) return res.status(503).json({ ok: false, code: 'ADMIN_SANDBOX_UNAVAILABLE', error: 'The Admin sandbox setting is not available on this server' });
|
|
1244
|
+
if (callerContext(req).kind !== 'ui' || req.get('x-synabun-desktop-grant')) {
|
|
1245
|
+
return res.status(403).json({ ok: false, code: 'UI_ONLY', error: 'Only the user can change the Admin sandbox.' });
|
|
1246
|
+
}
|
|
1247
|
+
const value = req.body?.adminSandbox;
|
|
1248
|
+
if (typeof value !== 'boolean') return res.status(400).json({ ok: false, code: 'INVALID_VALUE', error: 'adminSandbox must be true or false.' });
|
|
1249
|
+
try { res.json({ ok: true, ...adminSandbox.set(value) }); } catch (error) { sendError(res, error); }
|
|
1250
|
+
});
|
|
1251
|
+
|
|
1233
1252
|
// ── sidepanel tab registry (UI heartbeat) ──────────────────────────────────
|
|
1234
1253
|
function listTabs() {
|
|
1235
1254
|
const cutoff = now() - tabTtlMs;
|
|
@@ -19,6 +19,7 @@ import { mkdirSync } from 'node:fs';
|
|
|
19
19
|
import { tmpdir } from 'node:os';
|
|
20
20
|
import { dirname, resolve, sep } from 'node:path';
|
|
21
21
|
import { fileURLToPath } from 'node:url';
|
|
22
|
+
import { CODEX_PROBE_SANDBOX_ARGS } from './agent-sandbox-elevation.js';
|
|
22
23
|
|
|
23
24
|
export const CODEX_GATE_HOOK_PATH = resolve(dirname(fileURLToPath(import.meta.url)), 'assistant-brains', 'codex-route-gate-hook.mjs');
|
|
24
25
|
export const CODEX_BROWSER_POLICY_HOOK_PATH = resolve(dirname(fileURLToPath(import.meta.url)), 'assistant-brains', 'codex-browser-policy-hook.mjs');
|
|
@@ -80,7 +81,8 @@ function probe({ codexBin, command, timeoutMs, spawnImpl }) {
|
|
|
80
81
|
if (codexNeedsShell(bin)) { done(null); return; }
|
|
81
82
|
const home = resolve(tmpdir(), 'synabun-codex-gate-probe');
|
|
82
83
|
try { mkdirSync(home, { recursive: true }); } catch {}
|
|
83
|
-
|
|
84
|
+
// A probe runs no command: the Windows sandbox that needs no administrator (lib/agent-sandbox-elevation.js).
|
|
85
|
+
const args = [...codexGateHookFlags(command), ...CODEX_PROBE_SANDBOX_ARGS, 'app-server'];
|
|
84
86
|
if (/\.js$/i.test(bin)) { args.unshift(bin); bin = process.execPath; }
|
|
85
87
|
let proc;
|
|
86
88
|
try {
|
|
@@ -246,6 +246,8 @@ export function createAssistantRuntime({
|
|
|
246
246
|
// (capability) → boolean, the verifier of lib/remote-policy.js createPhoneAuthority(): is this the
|
|
247
247
|
// capability of the one WhatsApp bridge? Without a verifier nothing can grant computer use remotely.
|
|
248
248
|
phoneAuthority = null,
|
|
249
|
+
// The Admin sandbox setting (lib/agent-sandbox-setting.js): global, shown in every session view.
|
|
250
|
+
adminSandbox = null,
|
|
249
251
|
} = {}) {
|
|
250
252
|
if (!dataDir) throw new Error('createAssistantRuntime requires dataDir');
|
|
251
253
|
const settings = {
|
|
@@ -906,7 +908,9 @@ export function createAssistantRuntime({
|
|
|
906
908
|
out.testDensity = testDensityOf(record);
|
|
907
909
|
out.testDensityExplicit = normalizeTestDensity(record.testDensity, null);
|
|
908
910
|
// `rename`: this server keeps a rename on the record (userRenamed), so a panel writes it here.
|
|
909
|
-
|
|
911
|
+
// `adminSandbox`: the global setting is served here (PUT /api/assistant/admin-sandbox).
|
|
912
|
+
out.features = { routing: !!router, computer: computerSupported(), testDensity: true, rename: true, adminSandbox: !!adminSandbox };
|
|
913
|
+
if (adminSandbox) { try { out.adminSandbox = adminSandbox.enabled() === true; } catch { out.adminSandbox = false; } }
|
|
910
914
|
out.budget = sessionMoney(record.id);
|
|
911
915
|
out.remoteLevel = policy ? effectiveLevel(policy, { untrusted: live.turnUntrusted === true, now: now() }) : null;
|
|
912
916
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { spawn } from 'node:child_process';
|
|
10
10
|
import { verifyOpenAiApiKey } from './claude-profile-api-key.js';
|
|
11
11
|
import { validateProviderApiKey } from './provider-panel-api-key-auth.js';
|
|
12
|
-
import { applyCodexLaunchEnv } from './codex-accounts.js';
|
|
12
|
+
import { applyCodexLaunchEnv, codexLaunchArgs } from './codex-accounts.js';
|
|
13
13
|
|
|
14
14
|
const fail = (message, status = 409, code = null) => Object.assign(new Error(message), { status, ...(code ? { code } : {}) });
|
|
15
15
|
|
|
@@ -32,13 +32,15 @@ export function createCodexAccountAuth({
|
|
|
32
32
|
}
|
|
33
33
|
// Codex run under the account's own store: inherited credentials out, its
|
|
34
34
|
// CODEX_HOME in, never the key SynaBun holds (that is not Codex's store).
|
|
35
|
-
|
|
35
|
+
// The launch's overrides (the Windows sandbox of the Admin sandbox setting) follow the subcommand.
|
|
36
|
+
function launch(id, words) {
|
|
36
37
|
account(id);
|
|
37
38
|
const plan = accounts.launchFor(id);
|
|
38
39
|
if (!plan.ok) throw fail(plan.message, 404);
|
|
39
40
|
prepareConfig(plan.home);
|
|
40
41
|
let file = codexBin();
|
|
41
42
|
if (!file) throw fail('Codex CLI not found. Install Codex to sign in.', 503);
|
|
43
|
+
const args = [...words, ...codexLaunchArgs(plan)];
|
|
42
44
|
const script = /\.[cm]?js$/i.test(file);
|
|
43
45
|
const shell = process.platform === 'win32' && /\.(cmd|bat)$/i.test(file);
|
|
44
46
|
const proc = spawnProcess(script ? process.execPath : file, script ? [file, ...args] : args, {
|
|
@@ -32,6 +32,7 @@ import { dirname, join, resolve, sep } from 'node:path';
|
|
|
32
32
|
import { homedir } from 'node:os';
|
|
33
33
|
import { readProfileApiKey, saveProfileApiKey, clearProfileApiKey } from './claude-profile-api-key.js';
|
|
34
34
|
import { apiKeyHint, resolveClaudeAuth } from './claude-accounts.js';
|
|
35
|
+
import { normalizeAdminSandbox, sandboxElevationFor } from './agent-sandbox-elevation.js';
|
|
35
36
|
|
|
36
37
|
export const CODEX_DEFAULT_ACCOUNT_ID = 'default';
|
|
37
38
|
export const CODEX_AUTH_MODES = Object.freeze(['subscription', 'apiKey']);
|
|
@@ -123,9 +124,13 @@ export function applyCodexLaunchEnv(base, launch) {
|
|
|
123
124
|
export function codexExecEnv(launch) {
|
|
124
125
|
return { ...(launch?.env || {}), ...(launch?.apiKey ? { CODEX_API_KEY: launch.apiKey } : {}) };
|
|
125
126
|
}
|
|
127
|
+
/** The `-c` overrides every Codex process of the launch starts with: the Windows sandbox the Admin sandbox setting allows. */
|
|
128
|
+
export function codexLaunchArgs(launch) {
|
|
129
|
+
return [...(launch?.configArgs || [])];
|
|
130
|
+
}
|
|
126
131
|
/** The `-c` overrides an app-server of the account starts with (before the subcommand). */
|
|
127
132
|
export function codexAppServerArgs(launch) {
|
|
128
|
-
return launch?.apiKey ?
|
|
133
|
+
return [...codexLaunchArgs(launch), ...(launch?.apiKey ? CODEX_EPHEMERAL_STORE_ARGS : [])];
|
|
129
134
|
}
|
|
130
135
|
|
|
131
136
|
export function createCodexAccounts({
|
|
@@ -141,6 +146,8 @@ export function createCodexAccounts({
|
|
|
141
146
|
statusTimeoutMs = 20_000,
|
|
142
147
|
// Called before a new account links Default's config.toml (server.js repairs it there).
|
|
143
148
|
prepareDefaultConfig = () => {},
|
|
149
|
+
// () => the Admin sandbox setting (lib/agent-sandbox-setting.js): which Windows sandbox every launch may use.
|
|
150
|
+
adminSandbox = () => false,
|
|
144
151
|
} = {}) {
|
|
145
152
|
if (!dataHome) throw new Error('createCodexAccounts requires dataHome');
|
|
146
153
|
const registryPath = resolve(dataHome, 'data', 'codex-accounts.json');
|
|
@@ -273,11 +280,17 @@ export function createCodexAccounts({
|
|
|
273
280
|
}
|
|
274
281
|
const { row, key } = describeProfile(profile, data);
|
|
275
282
|
const apiKey = row.mode === 'apiKey' && row.apiKey.source === 'synabun' && key ? key : null;
|
|
283
|
+
// A launch override, never written into config.toml: Default's home is the user's own ~/.codex.
|
|
284
|
+
let on = false;
|
|
285
|
+
try { on = normalizeAdminSandbox(adminSandbox()); } catch { on = false; }
|
|
286
|
+
const sandbox = sandboxElevationFor('codex', on);
|
|
276
287
|
return {
|
|
277
288
|
ok: true, accountId: wanted, label: row.label, mode: row.mode, signedIn: row.signedIn, identity: row.identity, home: row.home,
|
|
278
289
|
env: { CODEX_HOME: row.home }, unset: [...CODEX_CREDENTIAL_ENV], apiKey,
|
|
279
290
|
// Which credential a process started with: a change means the account's idle processes restart.
|
|
280
291
|
credential: [row.mode || 'none', row.apiKey.source || '', row.apiKey.hint || '', row.subscription.email || ''].join(':'),
|
|
292
|
+
// The Windows sandbox it may use ('elevated' | 'unelevated'): a change restarts idle app-servers too.
|
|
293
|
+
windowsSandbox: sandbox.value, configArgs: sandbox.args,
|
|
281
294
|
};
|
|
282
295
|
}
|
|
283
296
|
|
|
@@ -2,6 +2,8 @@ import { spawnSync } from 'node:child_process';
|
|
|
2
2
|
import { mkdtempSync, readFileSync, rmSync, statSync } from 'node:fs';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
+
// The probes run no command: always the Windows sandbox that needs no administrator (lib/agent-sandbox-elevation.js).
|
|
6
|
+
import { CODEX_PROBE_SANDBOX_ARGS } from './agent-sandbox-elevation.js';
|
|
5
7
|
|
|
6
8
|
const cache = new Map();
|
|
7
9
|
const featureCache = new Map();
|
|
@@ -45,7 +47,7 @@ export function readCodexSettingsSchema(codexBin) {
|
|
|
45
47
|
const home = mkdtempSync(join(tmpdir(), 'synabun-codex-schema-'));
|
|
46
48
|
try {
|
|
47
49
|
const out = join(home, 'schema');
|
|
48
|
-
const run = spawnSync(codexBin, ['app-server', 'generate-json-schema', '--experimental', '--out', out], {
|
|
50
|
+
const run = spawnSync(codexBin, ['app-server', 'generate-json-schema', '--experimental', '--out', out, ...CODEX_PROBE_SANDBOX_ARGS], {
|
|
49
51
|
env: { ...process.env, CODEX_HOME: home }, encoding: 'utf8', timeout: 15000, windowsHide: true,
|
|
50
52
|
});
|
|
51
53
|
if (run.error || run.status !== 0) throw new Error('Codex could not report its settings schema');
|
|
@@ -56,7 +58,7 @@ export function readCodexSettingsSchema(codexBin) {
|
|
|
56
58
|
// `features list` validates config locally and never runs a model or tool.
|
|
57
59
|
for (const [fieldKey, field] of Object.entries(schema.fields)) {
|
|
58
60
|
field.values = field.values.filter(value => {
|
|
59
|
-
const check = spawnSync(codexBin, ['-c', `${fieldKey}=${JSON.stringify(value)}`, 'features', 'list'], {
|
|
61
|
+
const check = spawnSync(codexBin, [...CODEX_PROBE_SANDBOX_ARGS, '-c', `${fieldKey}=${JSON.stringify(value)}`, 'features', 'list'], {
|
|
60
62
|
env: { ...process.env, CODEX_HOME: home }, encoding: 'utf8', timeout: 5000, windowsHide: true,
|
|
61
63
|
});
|
|
62
64
|
return !check.error && check.status === 0;
|
|
@@ -105,7 +107,7 @@ export function readCodexFeatureSupport(codexBin, features) {
|
|
|
105
107
|
const home = mkdtempSync(join(tmpdir(), 'synabun-feature-support-'));
|
|
106
108
|
try {
|
|
107
109
|
const states = [false, true].map(value => {
|
|
108
|
-
const check = spawnSync(codexBin, ['-c', `features={${names.map(name => `${name}=${value}`).join(',')}}`, 'features', 'list'], {
|
|
110
|
+
const check = spawnSync(codexBin, [...CODEX_PROBE_SANDBOX_ARGS, '-c', `features={${names.map(name => `${name}=${value}`).join(',')}}`, 'features', 'list'], {
|
|
109
111
|
env: { ...process.env, CODEX_HOME: home }, encoding: 'utf8', timeout: 10000, windowsHide: true,
|
|
110
112
|
});
|
|
111
113
|
if (check.error || check.status !== 0) throw new Error('Codex could not validate feature switches');
|
|
@@ -82,6 +82,8 @@ export function buildExecInvocation({
|
|
|
82
82
|
model,
|
|
83
83
|
effort,
|
|
84
84
|
mcpEnvOverrides = [],
|
|
85
|
+
// Codex: launch overrides as `-c` words (the Windows sandbox of the Admin sandbox setting).
|
|
86
|
+
codexConfigArgs = [],
|
|
85
87
|
platform = process.platform,
|
|
86
88
|
commandExists = existsSync,
|
|
87
89
|
} = {}) {
|
|
@@ -94,7 +96,7 @@ export function buildExecInvocation({
|
|
|
94
96
|
|
|
95
97
|
switch (profile) {
|
|
96
98
|
case 'codex': {
|
|
97
|
-
args.push('exec', '--dangerously-bypass-approvals-and-sandbox');
|
|
99
|
+
args.push('exec', '--dangerously-bypass-approvals-and-sandbox', ...codexConfigArgs);
|
|
98
100
|
for (const [key, value] of mcpEnvOverrides) {
|
|
99
101
|
args.push('-c', `mcp_servers.SynaBun.env.${key}=${codexConfigString(value)}`);
|
|
100
102
|
}
|
|
@@ -26,15 +26,29 @@ export function packagesInLock(lock) {
|
|
|
26
26
|
return entries.filter(key => /(?:^|\/)node_modules\//.test(key)).length;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/** How many packages of a lockfile are on disk under `root` (npm-shrinkwrap.json of an npm install). */
|
|
30
|
+
export function installedFromLock(lock, root, { exists = existsSync } = {}) {
|
|
31
|
+
const entries = lock && typeof lock.packages === 'object' ? Object.keys(lock.packages) : [];
|
|
32
|
+
return entries.filter(key => /(?:^|\/)node_modules\//.test(key) && exists(path.join(root, ...key.split('/')))).length;
|
|
33
|
+
}
|
|
34
|
+
|
|
29
35
|
/**
|
|
30
|
-
* A part's own dependencies (its package.json), each with the version
|
|
31
|
-
*
|
|
36
|
+
* A part's own dependencies (its package.json), each with the version Node finds for it, or null when it is not
|
|
37
|
+
* installed. Sorted by name. Found in the part's node_modules, and with `stopAt` (the package root) in each folder
|
|
38
|
+
* up to it too: `npm i -g synabun` installs every part's dependencies at the package root.
|
|
32
39
|
*/
|
|
33
|
-
export function directDependencies(dir, { readJson = readJsonFile } = {}) {
|
|
40
|
+
export function directDependencies(dir, { readJson = readJsonFile, stopAt = null } = {}) {
|
|
34
41
|
const manifest = readJson(path.join(dir, 'package.json')) || {};
|
|
35
42
|
const wanted = { ...(manifest.optionalDependencies || {}), ...(manifest.dependencies || {}) };
|
|
43
|
+
const limit = stopAt ? path.resolve(stopAt) : null;
|
|
44
|
+
const find = (name) => {
|
|
45
|
+
for (let folder = path.resolve(dir); ; folder = path.dirname(folder)) {
|
|
46
|
+
const found = readJson(path.join(folder, 'node_modules', ...name.split('/'), 'package.json'));
|
|
47
|
+
if (found || !limit || folder === limit || path.dirname(folder) === folder) return found;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
36
50
|
return Object.keys(wanted).sort().map((name) => {
|
|
37
|
-
const installed =
|
|
51
|
+
const installed = find(name);
|
|
38
52
|
return { name, wanted: String(wanted[name]), installed: installed?.version ? String(installed.version) : null };
|
|
39
53
|
});
|
|
40
54
|
}
|
|
@@ -112,10 +126,14 @@ export async function collectInstallDetails({
|
|
|
112
126
|
const userNpmPath = firstOnPath('npm', osPath, { platform, exists, skip: runtimeBin ? [runtimeBin, impl.dirname(execPath)] : [] });
|
|
113
127
|
const userNpm = userNpmPath && userNpmPath !== ownNpm ? { path: userNpmPath, ...(await version(userNpmPath, { platform, env })) } : null;
|
|
114
128
|
|
|
129
|
+
// A part's own install record when it has one (a development checkout, a desktop build); an npm install keeps
|
|
130
|
+
// both parts' dependencies at the package root instead, pinned by npm-shrinkwrap.json.
|
|
131
|
+
const shrinkwrap = readJson(path.join(packageRoot, 'npm-shrinkwrap.json'));
|
|
115
132
|
const parts = [['Neural Interface', 'neural-interface'], ['MCP server', 'mcp-server']].map(([name, folder]) => {
|
|
116
133
|
const dir = path.join(packageRoot, folder);
|
|
117
134
|
const installed = readJson(path.join(dir, 'node_modules', '.package-lock.json'));
|
|
118
|
-
|
|
135
|
+
const packages = installed ? packagesInLock(installed) : installedFromLock(shrinkwrap, packageRoot, { exists });
|
|
136
|
+
return { name, folder, packages, dependencies: directDependencies(dir, { readJson, stopAt: packageRoot }) };
|
|
119
137
|
});
|
|
120
138
|
const mcpBuilt = exists(path.join(packageRoot, 'mcp-server', 'dist', 'index.js'));
|
|
121
139
|
|
|
@@ -10,6 +10,7 @@ import { codexReasoningEffort } from './effort-levels.js';
|
|
|
10
10
|
import { codexStreamMedia, collectCodexMedia, openCodeMediaPart, ownCodexImages } from './assistant-media.js';
|
|
11
11
|
import { browserToolDenial } from './browser-tool-policy.js';
|
|
12
12
|
import { CODEX_BROWSER_POLICY_UNTRUSTED_NOTE, codexBrowserPolicyHook } from './assistant-route-gate-codex.js';
|
|
13
|
+
import { codexWindowsSandbox, codexWindowsSandboxConfig } from './agent-sandbox-elevation.js';
|
|
13
14
|
|
|
14
15
|
function stringEnv(source) {
|
|
15
16
|
const out = {};
|
|
@@ -251,6 +252,9 @@ export async function createCodexNativeLoopAdapter(options = {}) {
|
|
|
251
252
|
// Inherited variables to remove before extraEnv applies (the Codex account's launch:
|
|
252
253
|
// lib/codex-accounts.js launchFor() — inherited OpenAI/Codex credentials never reach the run).
|
|
253
254
|
unsetEnv = [],
|
|
255
|
+
// The Admin sandbox setting when the run started (lib/agent-sandbox-elevation.js): the Windows
|
|
256
|
+
// sandbox every `codex exec` of the thread may use. The run keeps it while it lives.
|
|
257
|
+
adminSandbox = false,
|
|
254
258
|
} = options;
|
|
255
259
|
const permissionPolicy = normalizePermissionPolicy(rawPolicy);
|
|
256
260
|
const capability = normalizeCapability(rawCapability);
|
|
@@ -287,7 +291,7 @@ export async function createCodexNativeLoopAdapter(options = {}) {
|
|
|
287
291
|
const inherited = { ...process.env };
|
|
288
292
|
for (const key of Array.isArray(unsetEnv) ? unsetEnv : []) delete inherited[key];
|
|
289
293
|
const env = stringEnv({ ...inherited, ...pins, CODEX_HOME: codexHome, ...(browserPolicy ? { SYNABUN_BROWSER_POLICY_CWD: cwd || process.cwd() } : {}), ...stringEnv(extraEnv) });
|
|
290
|
-
const config = {};
|
|
294
|
+
const config = { ...codexWindowsSandboxConfig(adminSandbox) };
|
|
291
295
|
if (Object.keys(pins).length) config.mcp_servers = { SynaBun: { env: pins } };
|
|
292
296
|
if (extended) config.model_context_window = Math.floor(Number(modelContextWindow));
|
|
293
297
|
if (browserPolicy) Object.assign(config, browserPolicy.config);
|
|
@@ -334,6 +338,7 @@ export async function createCodexNativeLoopAdapter(options = {}) {
|
|
|
334
338
|
isAlive: () => alive,
|
|
335
339
|
describe: () => ({
|
|
336
340
|
provider: 'codex', permissionPolicy, capability, sandboxMode: codexSandboxModeFor({ permissionPolicy, capability }),
|
|
341
|
+
windowsSandbox: codexWindowsSandbox(adminSandbox),
|
|
337
342
|
...(task ? { browserPolicy: browserPolicy ? 'hook' : 'instructions' } : {}),
|
|
338
343
|
}),
|
|
339
344
|
async runTurn(prompt, meta = {}) {
|