agim-cli 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1234 -0
- package/LICENSE +21 -0
- package/README.md +422 -0
- package/README.zh-CN.md +414 -0
- package/dist/cli-ui/cmd-handlers.d.ts +11 -0
- package/dist/cli-ui/cmd-handlers.d.ts.map +1 -0
- package/dist/cli-ui/cmd-handlers.js +240 -0
- package/dist/cli-ui/cmd-handlers.js.map +1 -0
- package/dist/cli-ui/config-wizard.d.ts +3 -0
- package/dist/cli-ui/config-wizard.d.ts.map +1 -0
- package/dist/cli-ui/config-wizard.js +851 -0
- package/dist/cli-ui/config-wizard.js.map +1 -0
- package/dist/cli-ui/entry-menu.d.ts +28 -0
- package/dist/cli-ui/entry-menu.d.ts.map +1 -0
- package/dist/cli-ui/entry-menu.js +50 -0
- package/dist/cli-ui/entry-menu.js.map +1 -0
- package/dist/cli-ui/env-file.d.ts +35 -0
- package/dist/cli-ui/env-file.d.ts.map +1 -0
- package/dist/cli-ui/env-file.js +163 -0
- package/dist/cli-ui/env-file.js.map +1 -0
- package/dist/cli-ui/i18n.d.ts +204 -0
- package/dist/cli-ui/i18n.d.ts.map +1 -0
- package/dist/cli-ui/i18n.js +455 -0
- package/dist/cli-ui/i18n.js.map +1 -0
- package/dist/cli-ui/lang-picker.d.ts +10 -0
- package/dist/cli-ui/lang-picker.d.ts.map +1 -0
- package/dist/cli-ui/lang-picker.js +33 -0
- package/dist/cli-ui/lang-picker.js.map +1 -0
- package/dist/cli-ui/paths.d.ts +4 -0
- package/dist/cli-ui/paths.d.ts.map +1 -0
- package/dist/cli-ui/paths.js +11 -0
- package/dist/cli-ui/paths.js.map +1 -0
- package/dist/cli-ui/prompts.d.ts +65 -0
- package/dist/cli-ui/prompts.d.ts.map +1 -0
- package/dist/cli-ui/prompts.js +125 -0
- package/dist/cli-ui/prompts.js.map +1 -0
- package/dist/cli-ui/service.d.ts +41 -0
- package/dist/cli-ui/service.d.ts.map +1 -0
- package/dist/cli-ui/service.js +241 -0
- package/dist/cli-ui/service.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1143 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/acp-server.d.ts +8 -0
- package/dist/core/acp-server.d.ts.map +1 -0
- package/dist/core/acp-server.js +266 -0
- package/dist/core/acp-server.js.map +1 -0
- package/dist/core/agent-base.d.ts +94 -0
- package/dist/core/agent-base.d.ts.map +1 -0
- package/dist/core/agent-base.js +373 -0
- package/dist/core/agent-base.js.map +1 -0
- package/dist/core/agent-cwd.d.ts +48 -0
- package/dist/core/agent-cwd.d.ts.map +1 -0
- package/dist/core/agent-cwd.js +181 -0
- package/dist/core/agent-cwd.js.map +1 -0
- package/dist/core/agent-helper.d.ts +65 -0
- package/dist/core/agent-helper.d.ts.map +1 -0
- package/dist/core/agent-helper.js +150 -0
- package/dist/core/agent-helper.js.map +1 -0
- package/dist/core/agim-paths.d.ts +10 -0
- package/dist/core/agim-paths.d.ts.map +1 -0
- package/dist/core/agim-paths.js +64 -0
- package/dist/core/agim-paths.js.map +1 -0
- package/dist/core/approval-bus.d.ts +300 -0
- package/dist/core/approval-bus.d.ts.map +1 -0
- package/dist/core/approval-bus.js +990 -0
- package/dist/core/approval-bus.js.map +1 -0
- package/dist/core/approval-router.d.ts +101 -0
- package/dist/core/approval-router.d.ts.map +1 -0
- package/dist/core/approval-router.js +540 -0
- package/dist/core/approval-router.js.map +1 -0
- package/dist/core/audit-log.d.ts +55 -0
- package/dist/core/audit-log.d.ts.map +1 -0
- package/dist/core/audit-log.js +203 -0
- package/dist/core/audit-log.js.map +1 -0
- package/dist/core/bgjob-reader.d.ts +65 -0
- package/dist/core/bgjob-reader.d.ts.map +1 -0
- package/dist/core/bgjob-reader.js +212 -0
- package/dist/core/bgjob-reader.js.map +1 -0
- package/dist/core/circuit-breaker.d.ts +37 -0
- package/dist/core/circuit-breaker.d.ts.map +1 -0
- package/dist/core/circuit-breaker.js +115 -0
- package/dist/core/circuit-breaker.js.map +1 -0
- package/dist/core/commands/agent.d.ts +4 -0
- package/dist/core/commands/agent.d.ts.map +1 -0
- package/dist/core/commands/agent.js +40 -0
- package/dist/core/commands/agent.js.map +1 -0
- package/dist/core/commands/approval.d.ts +3 -0
- package/dist/core/commands/approval.d.ts.map +1 -0
- package/dist/core/commands/approval.js +85 -0
- package/dist/core/commands/approval.js.map +1 -0
- package/dist/core/commands/audit.d.ts +3 -0
- package/dist/core/commands/audit.d.ts.map +1 -0
- package/dist/core/commands/audit.js +84 -0
- package/dist/core/commands/audit.js.map +1 -0
- package/dist/core/commands/builtin.d.ts +3 -0
- package/dist/core/commands/builtin.d.ts.map +1 -0
- package/dist/core/commands/builtin.js +304 -0
- package/dist/core/commands/builtin.js.map +1 -0
- package/dist/core/commands/cron.d.ts +3 -0
- package/dist/core/commands/cron.d.ts.map +1 -0
- package/dist/core/commands/cron.js +128 -0
- package/dist/core/commands/cron.js.map +1 -0
- package/dist/core/commands/job.d.ts +3 -0
- package/dist/core/commands/job.d.ts.map +1 -0
- package/dist/core/commands/job.js +195 -0
- package/dist/core/commands/job.js.map +1 -0
- package/dist/core/commands/memo.d.ts +3 -0
- package/dist/core/commands/memo.d.ts.map +1 -0
- package/dist/core/commands/memo.js +151 -0
- package/dist/core/commands/memo.js.map +1 -0
- package/dist/core/commands/model.d.ts +9 -0
- package/dist/core/commands/model.d.ts.map +1 -0
- package/dist/core/commands/model.js +183 -0
- package/dist/core/commands/model.js.map +1 -0
- package/dist/core/commands/plan.d.ts +3 -0
- package/dist/core/commands/plan.d.ts.map +1 -0
- package/dist/core/commands/plan.js +75 -0
- package/dist/core/commands/plan.js.map +1 -0
- package/dist/core/commands/remind.d.ts +3 -0
- package/dist/core/commands/remind.d.ts.map +1 -0
- package/dist/core/commands/remind.js +271 -0
- package/dist/core/commands/remind.js.map +1 -0
- package/dist/core/commands/router.d.ts +3 -0
- package/dist/core/commands/router.d.ts.map +1 -0
- package/dist/core/commands/router.js +71 -0
- package/dist/core/commands/router.js.map +1 -0
- package/dist/core/commands/sessions.d.ts +3 -0
- package/dist/core/commands/sessions.d.ts.map +1 -0
- package/dist/core/commands/sessions.js +88 -0
- package/dist/core/commands/sessions.js.map +1 -0
- package/dist/core/commands/stats.d.ts +3 -0
- package/dist/core/commands/stats.d.ts.map +1 -0
- package/dist/core/commands/stats.js +73 -0
- package/dist/core/commands/stats.js.map +1 -0
- package/dist/core/commands/think.d.ts +3 -0
- package/dist/core/commands/think.d.ts.map +1 -0
- package/dist/core/commands/think.js +28 -0
- package/dist/core/commands/think.js.map +1 -0
- package/dist/core/commands/workspaces.d.ts +3 -0
- package/dist/core/commands/workspaces.d.ts.map +1 -0
- package/dist/core/commands/workspaces.js +47 -0
- package/dist/core/commands/workspaces.js.map +1 -0
- package/dist/core/config-schema.d.ts +60 -0
- package/dist/core/config-schema.d.ts.map +1 -0
- package/dist/core/config-schema.js +75 -0
- package/dist/core/config-schema.js.map +1 -0
- package/dist/core/coord-systems.d.ts +65 -0
- package/dist/core/coord-systems.d.ts.map +1 -0
- package/dist/core/coord-systems.js +229 -0
- package/dist/core/coord-systems.js.map +1 -0
- package/dist/core/cron.d.ts +29 -0
- package/dist/core/cron.d.ts.map +1 -0
- package/dist/core/cron.js +184 -0
- package/dist/core/cron.js.map +1 -0
- package/dist/core/event-bus.d.ts +80 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +62 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/intent-llm.d.ts +27 -0
- package/dist/core/intent-llm.d.ts.map +1 -0
- package/dist/core/intent-llm.js +170 -0
- package/dist/core/intent-llm.js.map +1 -0
- package/dist/core/intent.d.ts +12 -0
- package/dist/core/intent.d.ts.map +1 -0
- package/dist/core/intent.js +187 -0
- package/dist/core/intent.js.map +1 -0
- package/dist/core/job-board.d.ts +82 -0
- package/dist/core/job-board.d.ts.map +1 -0
- package/dist/core/job-board.js +379 -0
- package/dist/core/job-board.js.map +1 -0
- package/dist/core/location-context.d.ts +32 -0
- package/dist/core/location-context.d.ts.map +1 -0
- package/dist/core/location-context.js +69 -0
- package/dist/core/location-context.js.map +1 -0
- package/dist/core/location-token.d.ts +57 -0
- package/dist/core/location-token.d.ts.map +1 -0
- package/dist/core/location-token.js +128 -0
- package/dist/core/location-token.js.map +1 -0
- package/dist/core/logger.d.ts +6 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +54 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/memo-rpc.d.ts +13 -0
- package/dist/core/memo-rpc.d.ts.map +1 -0
- package/dist/core/memo-rpc.js +288 -0
- package/dist/core/memo-rpc.js.map +1 -0
- package/dist/core/memos.d.ts +163 -0
- package/dist/core/memos.d.ts.map +1 -0
- package/dist/core/memos.js +502 -0
- package/dist/core/memos.js.map +1 -0
- package/dist/core/metrics.d.ts +55 -0
- package/dist/core/metrics.d.ts.map +1 -0
- package/dist/core/metrics.js +291 -0
- package/dist/core/metrics.js.map +1 -0
- package/dist/core/onboarding.d.ts +99 -0
- package/dist/core/onboarding.d.ts.map +1 -0
- package/dist/core/onboarding.js +426 -0
- package/dist/core/onboarding.js.map +1 -0
- package/dist/core/pending-reminder.d.ts +25 -0
- package/dist/core/pending-reminder.d.ts.map +1 -0
- package/dist/core/pending-reminder.js +53 -0
- package/dist/core/pending-reminder.js.map +1 -0
- package/dist/core/rate-limiter.d.ts +44 -0
- package/dist/core/rate-limiter.d.ts.map +1 -0
- package/dist/core/rate-limiter.js +115 -0
- package/dist/core/rate-limiter.js.map +1 -0
- package/dist/core/registry.d.ts +32 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +126 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/remind-intent.d.ts +25 -0
- package/dist/core/remind-intent.d.ts.map +1 -0
- package/dist/core/remind-intent.js +196 -0
- package/dist/core/remind-intent.js.map +1 -0
- package/dist/core/reminder-rpc.d.ts +17 -0
- package/dist/core/reminder-rpc.d.ts.map +1 -0
- package/dist/core/reminder-rpc.js +169 -0
- package/dist/core/reminder-rpc.js.map +1 -0
- package/dist/core/reminders.d.ts +159 -0
- package/dist/core/reminders.d.ts.map +1 -0
- package/dist/core/reminders.js +977 -0
- package/dist/core/reminders.js.map +1 -0
- package/dist/core/router.d.ts +55 -0
- package/dist/core/router.d.ts.map +1 -0
- package/dist/core/router.js +497 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/schedule.d.ts +65 -0
- package/dist/core/schedule.d.ts.map +1 -0
- package/dist/core/schedule.js +323 -0
- package/dist/core/schedule.js.map +1 -0
- package/dist/core/session.d.ts +182 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +807 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/sqlite-helper.d.ts +37 -0
- package/dist/core/sqlite-helper.d.ts.map +1 -0
- package/dist/core/sqlite-helper.js +79 -0
- package/dist/core/sqlite-helper.js.map +1 -0
- package/dist/core/transcribe.d.ts +25 -0
- package/dist/core/transcribe.d.ts.map +1 -0
- package/dist/core/transcribe.js +217 -0
- package/dist/core/transcribe.js.map +1 -0
- package/dist/core/types.d.ts +360 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/workspace.d.ts +67 -0
- package/dist/core/workspace.d.ts.map +1 -0
- package/dist/core/workspace.js +113 -0
- package/dist/core/workspace.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/agents/acp/acp-adapter.d.ts +16 -0
- package/dist/plugins/agents/acp/acp-adapter.d.ts.map +1 -0
- package/dist/plugins/agents/acp/acp-adapter.js +49 -0
- package/dist/plugins/agents/acp/acp-adapter.js.map +1 -0
- package/dist/plugins/agents/acp/acp-client.d.ts +32 -0
- package/dist/plugins/agents/acp/acp-client.d.ts.map +1 -0
- package/dist/plugins/agents/acp/acp-client.js +177 -0
- package/dist/plugins/agents/acp/acp-client.js.map +1 -0
- package/dist/plugins/agents/acp/discovery.d.ts +19 -0
- package/dist/plugins/agents/acp/discovery.d.ts.map +1 -0
- package/dist/plugins/agents/acp/discovery.js +111 -0
- package/dist/plugins/agents/acp/discovery.js.map +1 -0
- package/dist/plugins/agents/acp/index.d.ts +4 -0
- package/dist/plugins/agents/acp/index.d.ts.map +1 -0
- package/dist/plugins/agents/acp/index.js +4 -0
- package/dist/plugins/agents/acp/index.js.map +1 -0
- package/dist/plugins/agents/acp/types.d.ts +62 -0
- package/dist/plugins/agents/acp/types.d.ts.map +1 -0
- package/dist/plugins/agents/acp/types.js +5 -0
- package/dist/plugins/agents/acp/types.js.map +1 -0
- package/dist/plugins/agents/claude-code/index.d.ts +25 -0
- package/dist/plugins/agents/claude-code/index.d.ts.map +1 -0
- package/dist/plugins/agents/claude-code/index.js +184 -0
- package/dist/plugins/agents/claude-code/index.js.map +1 -0
- package/dist/plugins/agents/claude-code/mcp-approval-server.d.ts +59 -0
- package/dist/plugins/agents/claude-code/mcp-approval-server.d.ts.map +1 -0
- package/dist/plugins/agents/claude-code/mcp-approval-server.js +645 -0
- package/dist/plugins/agents/claude-code/mcp-approval-server.js.map +1 -0
- package/dist/plugins/agents/codex/build-mcp-cli-args.d.ts +28 -0
- package/dist/plugins/agents/codex/build-mcp-cli-args.d.ts.map +1 -0
- package/dist/plugins/agents/codex/build-mcp-cli-args.js +74 -0
- package/dist/plugins/agents/codex/build-mcp-cli-args.js.map +1 -0
- package/dist/plugins/agents/codex/index.d.ts +53 -0
- package/dist/plugins/agents/codex/index.d.ts.map +1 -0
- package/dist/plugins/agents/codex/index.js +341 -0
- package/dist/plugins/agents/codex/index.js.map +1 -0
- package/dist/plugins/agents/copilot/index.d.ts +35 -0
- package/dist/plugins/agents/copilot/index.d.ts.map +1 -0
- package/dist/plugins/agents/copilot/index.js +182 -0
- package/dist/plugins/agents/copilot/index.js.map +1 -0
- package/dist/plugins/agents/opencode/ensure-mcp-config.d.ts +11 -0
- package/dist/plugins/agents/opencode/ensure-mcp-config.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/ensure-mcp-config.js +100 -0
- package/dist/plugins/agents/opencode/ensure-mcp-config.js.map +1 -0
- package/dist/plugins/agents/opencode/index.d.ts +5 -0
- package/dist/plugins/agents/opencode/index.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/index.js +30 -0
- package/dist/plugins/agents/opencode/index.js.map +1 -0
- package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts +166 -0
- package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/opencode-http-adapter.js +682 -0
- package/dist/plugins/agents/opencode/opencode-http-adapter.js.map +1 -0
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts +32 -0
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.js +137 -0
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.js.map +1 -0
- package/dist/plugins/agents/opencode/serve-manager.d.ts +27 -0
- package/dist/plugins/agents/opencode/serve-manager.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/serve-manager.js +194 -0
- package/dist/plugins/agents/opencode/serve-manager.js.map +1 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.d.ts +57 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js +409 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js.map +1 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-client.d.ts +48 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-client.d.ts.map +1 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-client.js +236 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-client.js.map +1 -0
- package/dist/plugins/messengers/dingtalk/index.d.ts +3 -0
- package/dist/plugins/messengers/dingtalk/index.d.ts.map +1 -0
- package/dist/plugins/messengers/dingtalk/index.js +3 -0
- package/dist/plugins/messengers/dingtalk/index.js.map +1 -0
- package/dist/plugins/messengers/dingtalk/link-coords.d.ts +23 -0
- package/dist/plugins/messengers/dingtalk/link-coords.d.ts.map +1 -0
- package/dist/plugins/messengers/dingtalk/link-coords.js +89 -0
- package/dist/plugins/messengers/dingtalk/link-coords.js.map +1 -0
- package/dist/plugins/messengers/dingtalk/media-store.d.ts +16 -0
- package/dist/plugins/messengers/dingtalk/media-store.d.ts.map +1 -0
- package/dist/plugins/messengers/dingtalk/media-store.js +77 -0
- package/dist/plugins/messengers/dingtalk/media-store.js.map +1 -0
- package/dist/plugins/messengers/dingtalk/types.d.ts +82 -0
- package/dist/plugins/messengers/dingtalk/types.d.ts.map +1 -0
- package/dist/plugins/messengers/dingtalk/types.js +14 -0
- package/dist/plugins/messengers/dingtalk/types.js.map +1 -0
- package/dist/plugins/messengers/discord/discord-adapter.d.ts +21 -0
- package/dist/plugins/messengers/discord/discord-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/discord/discord-adapter.js +238 -0
- package/dist/plugins/messengers/discord/discord-adapter.js.map +1 -0
- package/dist/plugins/messengers/discord/index.d.ts +4 -0
- package/dist/plugins/messengers/discord/index.d.ts.map +1 -0
- package/dist/plugins/messengers/discord/index.js +4 -0
- package/dist/plugins/messengers/discord/index.js.map +1 -0
- package/dist/plugins/messengers/discord/markdown-to-discord.d.ts +11 -0
- package/dist/plugins/messengers/discord/markdown-to-discord.d.ts.map +1 -0
- package/dist/plugins/messengers/discord/markdown-to-discord.js +59 -0
- package/dist/plugins/messengers/discord/markdown-to-discord.js.map +1 -0
- package/dist/plugins/messengers/discord/types.d.ts +9 -0
- package/dist/plugins/messengers/discord/types.d.ts.map +1 -0
- package/dist/plugins/messengers/discord/types.js +3 -0
- package/dist/plugins/messengers/discord/types.js.map +1 -0
- package/dist/plugins/messengers/email/email-adapter.d.ts +33 -0
- package/dist/plugins/messengers/email/email-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/email/email-adapter.js +137 -0
- package/dist/plugins/messengers/email/email-adapter.js.map +1 -0
- package/dist/plugins/messengers/feishu/card-builder.d.ts +23 -0
- package/dist/plugins/messengers/feishu/card-builder.d.ts.map +1 -0
- package/dist/plugins/messengers/feishu/card-builder.js +89 -0
- package/dist/plugins/messengers/feishu/card-builder.js.map +1 -0
- package/dist/plugins/messengers/feishu/feishu-adapter.d.ts +23 -0
- package/dist/plugins/messengers/feishu/feishu-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/feishu/feishu-adapter.js +250 -0
- package/dist/plugins/messengers/feishu/feishu-adapter.js.map +1 -0
- package/dist/plugins/messengers/feishu/feishu-client.d.ts +43 -0
- package/dist/plugins/messengers/feishu/feishu-client.d.ts.map +1 -0
- package/dist/plugins/messengers/feishu/feishu-client.js +118 -0
- package/dist/plugins/messengers/feishu/feishu-client.js.map +1 -0
- package/dist/plugins/messengers/feishu/index.d.ts +4 -0
- package/dist/plugins/messengers/feishu/index.d.ts.map +1 -0
- package/dist/plugins/messengers/feishu/index.js +4 -0
- package/dist/plugins/messengers/feishu/index.js.map +1 -0
- package/dist/plugins/messengers/feishu/types.d.ts +113 -0
- package/dist/plugins/messengers/feishu/types.d.ts.map +1 -0
- package/dist/plugins/messengers/feishu/types.js +4 -0
- package/dist/plugins/messengers/feishu/types.js.map +1 -0
- package/dist/plugins/messengers/telegram/index.d.ts +4 -0
- package/dist/plugins/messengers/telegram/index.d.ts.map +1 -0
- package/dist/plugins/messengers/telegram/index.js +4 -0
- package/dist/plugins/messengers/telegram/index.js.map +1 -0
- package/dist/plugins/messengers/telegram/markdown-to-html.d.ts +5 -0
- package/dist/plugins/messengers/telegram/markdown-to-html.d.ts.map +1 -0
- package/dist/plugins/messengers/telegram/markdown-to-html.js +186 -0
- package/dist/plugins/messengers/telegram/markdown-to-html.js.map +1 -0
- package/dist/plugins/messengers/telegram/media-download.d.ts +59 -0
- package/dist/plugins/messengers/telegram/media-download.d.ts.map +1 -0
- package/dist/plugins/messengers/telegram/media-download.js +228 -0
- package/dist/plugins/messengers/telegram/media-download.js.map +1 -0
- package/dist/plugins/messengers/telegram/telegram-adapter.d.ts +77 -0
- package/dist/plugins/messengers/telegram/telegram-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/telegram/telegram-adapter.js +880 -0
- package/dist/plugins/messengers/telegram/telegram-adapter.js.map +1 -0
- package/dist/plugins/messengers/telegram/types.d.ts +47 -0
- package/dist/plugins/messengers/telegram/types.d.ts.map +1 -0
- package/dist/plugins/messengers/telegram/types.js +3 -0
- package/dist/plugins/messengers/telegram/types.js.map +1 -0
- package/dist/plugins/messengers/wechat/context-store.d.ts +18 -0
- package/dist/plugins/messengers/wechat/context-store.d.ts.map +1 -0
- package/dist/plugins/messengers/wechat/context-store.js +105 -0
- package/dist/plugins/messengers/wechat/context-store.js.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-adapter.d.ts +71 -0
- package/dist/plugins/messengers/wechat/ilink-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-adapter.js +664 -0
- package/dist/plugins/messengers/wechat/ilink-adapter.js.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-client.d.ts +75 -0
- package/dist/plugins/messengers/wechat/ilink-client.d.ts.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-client.js +331 -0
- package/dist/plugins/messengers/wechat/ilink-client.js.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-types.d.ts +181 -0
- package/dist/plugins/messengers/wechat/ilink-types.d.ts.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-types.js +22 -0
- package/dist/plugins/messengers/wechat/ilink-types.js.map +1 -0
- package/dist/plugins/messengers/wechat/media-download.d.ts +32 -0
- package/dist/plugins/messengers/wechat/media-download.d.ts.map +1 -0
- package/dist/plugins/messengers/wechat/media-download.js +78 -0
- package/dist/plugins/messengers/wechat/media-download.js.map +1 -0
- package/dist/scripts/migrate-gcj02-to-wgs84.d.ts +3 -0
- package/dist/scripts/migrate-gcj02-to-wgs84.d.ts.map +1 -0
- package/dist/scripts/migrate-gcj02-to-wgs84.js +52 -0
- package/dist/scripts/migrate-gcj02-to-wgs84.js.map +1 -0
- package/dist/utils/backoff.d.ts +35 -0
- package/dist/utils/backoff.d.ts.map +1 -0
- package/dist/utils/backoff.js +59 -0
- package/dist/utils/backoff.js.map +1 -0
- package/dist/utils/cross-platform.d.ts +26 -0
- package/dist/utils/cross-platform.d.ts.map +1 -0
- package/dist/utils/cross-platform.js +58 -0
- package/dist/utils/cross-platform.js.map +1 -0
- package/dist/utils/message-split.d.ts +14 -0
- package/dist/utils/message-split.d.ts.map +1 -0
- package/dist/utils/message-split.js +65 -0
- package/dist/utils/message-split.js.map +1 -0
- package/dist/utils/safe-equal.d.ts +2 -0
- package/dist/utils/safe-equal.d.ts.map +1 -0
- package/dist/utils/safe-equal.js +11 -0
- package/dist/utils/safe-equal.js.map +1 -0
- package/dist/web/public/_app.js +196 -0
- package/dist/web/public/index.html +936 -0
- package/dist/web/public/loc.html +305 -0
- package/dist/web/public/login.html +106 -0
- package/dist/web/public/memos.html +271 -0
- package/dist/web/public/reminders.html +234 -0
- package/dist/web/public/settings.html +1355 -0
- package/dist/web/public/tasks.html +1835 -0
- package/dist/web/server.d.ts +12 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +2399 -0
- package/dist/web/server.js.map +1 -0
- package/package.json +92 -0
|
@@ -0,0 +1,851 @@
|
|
|
1
|
+
// cli-ui/config-wizard.ts — interactive `agim config` flow.
|
|
2
|
+
//
|
|
3
|
+
// Top-level menu has 5 sections:
|
|
4
|
+
// 1. Messengers — list-of-channels; each opens its own sub-menu
|
|
5
|
+
// (WeChat QR scan / Telegram & Feishu & Discord
|
|
6
|
+
// credential prompts / Email toggle)
|
|
7
|
+
// 2. Agents — list-of-agents with live CLI install detection;
|
|
8
|
+
// per-agent sub-menu lets you enable/disable, see
|
|
9
|
+
// install / auth instructions, set as default
|
|
10
|
+
// 3. Remote ACP — list / add / edit / remove
|
|
11
|
+
// 4. SMTP — Edit / Disable / Back; preset picker → host/port/
|
|
12
|
+
// user/pass/from/secure (writes to ENV_FILE)
|
|
13
|
+
// 5. Baidu Maps AK — Set / Clear / Back (writes IMHUB_BAIDU_MAP_AK)
|
|
14
|
+
//
|
|
15
|
+
// Design rule: every sub-menu has a ← Back entry. The wizard never
|
|
16
|
+
// requires Ctrl-C to escape (first-time users don't know it works).
|
|
17
|
+
//
|
|
18
|
+
// Edits land in the in-memory Config object until "Done — save and exit".
|
|
19
|
+
// SMTP / Baidu writes are immediate to env-file.ts so a crash mid-wizard
|
|
20
|
+
// doesn't lose the secrets the user already typed.
|
|
21
|
+
import { crossSpawn } from '../utils/cross-platform.js';
|
|
22
|
+
import { menu, inputText, inputSecret, yesNo, BACK, UserAbortError, } from './prompts.js';
|
|
23
|
+
import { t } from './i18n.js';
|
|
24
|
+
import { loadConfig, saveConfig } from '../core/onboarding.js';
|
|
25
|
+
import { CONFIG_DIR } from './paths.js';
|
|
26
|
+
import { ENV_FILE, readEffectiveEnv, updateEnvFile, unsetEnvKey, hasProcessEnvOverride } from './env-file.js';
|
|
27
|
+
/** Probe whether a CLI command exists on PATH. Mirrors the `--version`
|
|
28
|
+
* spawn check the legacy `config <agent>` flow used. Resolves quickly:
|
|
29
|
+
* most install probes finish in <200ms, missing binaries return
|
|
30
|
+
* ENOENT immediately. */
|
|
31
|
+
function cliAvailable(cmd) {
|
|
32
|
+
return new Promise((resolve) => {
|
|
33
|
+
const proc = crossSpawn(cmd, ['--version'], { stdio: 'ignore' });
|
|
34
|
+
proc.on('close', (code) => resolve(code === 0));
|
|
35
|
+
proc.on('error', () => resolve(false));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export async function runConfigWizard(lang) {
|
|
39
|
+
let config = await loadConfig();
|
|
40
|
+
console.log();
|
|
41
|
+
console.log(t(lang, 'config.title'));
|
|
42
|
+
console.log(t(lang, 'config.subtitle'));
|
|
43
|
+
console.log();
|
|
44
|
+
while (true) {
|
|
45
|
+
let picked;
|
|
46
|
+
try {
|
|
47
|
+
picked = (await menu({
|
|
48
|
+
lang,
|
|
49
|
+
message: t(lang, 'menu.subtitle'),
|
|
50
|
+
choices: [
|
|
51
|
+
{ value: 'messengers', name: t(lang, 'config.section.messengers') },
|
|
52
|
+
{ value: 'agents', name: t(lang, 'config.section.agents') },
|
|
53
|
+
{ value: 'acp', name: t(lang, 'config.section.acp') },
|
|
54
|
+
{ value: 'smtp', name: t(lang, 'config.section.smtp') },
|
|
55
|
+
{ value: 'baidu', name: t(lang, 'config.section.baidu') },
|
|
56
|
+
{ value: 'done', name: t(lang, 'config.section.done'), separatorBefore: true },
|
|
57
|
+
],
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
if (err instanceof UserAbortError)
|
|
62
|
+
return;
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
if (picked === BACK || picked === 'done')
|
|
66
|
+
break;
|
|
67
|
+
try {
|
|
68
|
+
if (picked === 'messengers')
|
|
69
|
+
config = await sectionMessengers(lang, config);
|
|
70
|
+
else if (picked === 'agents')
|
|
71
|
+
config = await sectionAgents(lang, config);
|
|
72
|
+
else if (picked === 'acp')
|
|
73
|
+
config = await sectionAcp(lang, config);
|
|
74
|
+
else if (picked === 'smtp')
|
|
75
|
+
await sectionSmtp(lang);
|
|
76
|
+
else if (picked === 'baidu')
|
|
77
|
+
await sectionBaidu(lang);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
if (err instanceof UserAbortError)
|
|
81
|
+
continue; // Ctrl-C inside a section → bounce back to the top menu
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
await saveConfig(config);
|
|
86
|
+
console.log();
|
|
87
|
+
console.log(t(lang, 'config.saved', { file: `${CONFIG_DIR}/config.json` }));
|
|
88
|
+
}
|
|
89
|
+
const MESSENGER_SPECS = [
|
|
90
|
+
{ id: 'wechat-ilink', labelKey: 'messengers.label.wechat', hasCreds: false },
|
|
91
|
+
{ id: 'telegram', labelKey: 'messengers.label.telegram', hasCreds: true },
|
|
92
|
+
{ id: 'feishu', labelKey: 'messengers.label.feishu', hasCreds: true },
|
|
93
|
+
{ id: 'dingtalk', labelKey: 'messengers.label.dingtalk', hasCreds: true },
|
|
94
|
+
{ id: 'discord', labelKey: 'messengers.label.discord', hasCreds: true },
|
|
95
|
+
{ id: 'email', labelKey: 'messengers.label.email', hasCreds: false },
|
|
96
|
+
];
|
|
97
|
+
/** Return the localized one-line status (enabled / enabled-no-creds /
|
|
98
|
+
* not configured) for a messenger. Used in the top-level list. */
|
|
99
|
+
function messengerStatus(lang, spec, cfg) {
|
|
100
|
+
const enabled = (cfg.messengers || []).includes(spec.id);
|
|
101
|
+
if (!enabled)
|
|
102
|
+
return t(lang, 'messengers.status.disabled');
|
|
103
|
+
if (spec.id === 'telegram' && !cfg.telegram?.botToken) {
|
|
104
|
+
return t(lang, 'messengers.status.enabled_no_creds');
|
|
105
|
+
}
|
|
106
|
+
if (spec.id === 'feishu' && !(cfg.feishu?.appId && cfg.feishu?.appSecret)) {
|
|
107
|
+
return t(lang, 'messengers.status.enabled_no_creds');
|
|
108
|
+
}
|
|
109
|
+
if (spec.id === 'dingtalk' && !(cfg.dingtalk?.clientId && cfg.dingtalk?.clientSecret)) {
|
|
110
|
+
return t(lang, 'messengers.status.enabled_no_creds');
|
|
111
|
+
}
|
|
112
|
+
if (spec.id === 'discord' && !cfg.discord?.botToken) {
|
|
113
|
+
return t(lang, 'messengers.status.enabled_no_creds');
|
|
114
|
+
}
|
|
115
|
+
return t(lang, 'messengers.status.enabled');
|
|
116
|
+
}
|
|
117
|
+
async function sectionMessengers(lang, cfg) {
|
|
118
|
+
let config = cfg;
|
|
119
|
+
while (true) {
|
|
120
|
+
console.log();
|
|
121
|
+
console.log(t(lang, 'messengers.title'));
|
|
122
|
+
console.log(t(lang, 'messengers.subtitle'));
|
|
123
|
+
console.log();
|
|
124
|
+
const choices = MESSENGER_SPECS.map(spec => ({
|
|
125
|
+
value: spec.id,
|
|
126
|
+
name: t(lang, 'messengers.row', {
|
|
127
|
+
label: t(lang, spec.labelKey),
|
|
128
|
+
status: messengerStatus(lang, spec, config),
|
|
129
|
+
}),
|
|
130
|
+
}));
|
|
131
|
+
const picked = await menu({
|
|
132
|
+
lang,
|
|
133
|
+
message: t(lang, 'menu.subtitle'),
|
|
134
|
+
choices,
|
|
135
|
+
back: 'messengers.action.back',
|
|
136
|
+
});
|
|
137
|
+
if (picked === BACK)
|
|
138
|
+
return config;
|
|
139
|
+
const spec = MESSENGER_SPECS.find(s => s.id === picked);
|
|
140
|
+
config = await messengerSubMenu(lang, config, spec);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** Per-messenger sub-menu: shows current state, lets user configure,
|
|
144
|
+
* re-configure, or remove (and for email just enable/disable). All
|
|
145
|
+
* paths land back here so user can keep editing; ← Back returns to the
|
|
146
|
+
* list above. */
|
|
147
|
+
async function messengerSubMenu(lang, cfg, spec) {
|
|
148
|
+
let config = cfg;
|
|
149
|
+
while (true) {
|
|
150
|
+
const enabled = (config.messengers || []).includes(spec.id);
|
|
151
|
+
console.log();
|
|
152
|
+
console.log(t(lang, spec.labelKey) + ' — ' + messengerStatus(lang, spec, config));
|
|
153
|
+
console.log();
|
|
154
|
+
const choices = [];
|
|
155
|
+
if (spec.id === 'email') {
|
|
156
|
+
// Email is just a toggle — SMTP creds live in env file, not config.
|
|
157
|
+
if (!enabled) {
|
|
158
|
+
choices.push({ value: 'enable_email', name: t(lang, 'messengers.action.enable_email') });
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
choices.push({ value: 'disable_email', name: t(lang, 'messengers.action.disable_email') });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else if (spec.id === 'wechat-ilink') {
|
|
165
|
+
// WeChat: configure = scan QR.
|
|
166
|
+
choices.push({
|
|
167
|
+
value: 'configure',
|
|
168
|
+
name: enabled
|
|
169
|
+
? t(lang, 'messengers.action.reconfigure')
|
|
170
|
+
: t(lang, 'messengers.action.configure'),
|
|
171
|
+
});
|
|
172
|
+
if (enabled) {
|
|
173
|
+
choices.push({ value: 'remove', name: t(lang, 'messengers.action.remove') });
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
// Telegram / Feishu / Discord — prompt for credentials.
|
|
178
|
+
choices.push({
|
|
179
|
+
value: 'configure',
|
|
180
|
+
name: enabled
|
|
181
|
+
? t(lang, 'messengers.action.reconfigure')
|
|
182
|
+
: t(lang, 'messengers.action.configure'),
|
|
183
|
+
});
|
|
184
|
+
if (enabled) {
|
|
185
|
+
choices.push({ value: 'remove', name: t(lang, 'messengers.action.remove') });
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const action = await menu({
|
|
189
|
+
lang,
|
|
190
|
+
message: t(lang, 'menu.subtitle'),
|
|
191
|
+
choices,
|
|
192
|
+
back: 'messengers.action.back',
|
|
193
|
+
});
|
|
194
|
+
if (action === BACK)
|
|
195
|
+
return config;
|
|
196
|
+
try {
|
|
197
|
+
if (action === 'enable_email' || action === 'disable_email') {
|
|
198
|
+
config = toggleEmail(config, action === 'enable_email');
|
|
199
|
+
if (action === 'enable_email') {
|
|
200
|
+
console.log(t(lang, 'messengers.smtp_hint'));
|
|
201
|
+
console.log(t(lang, 'messengers.enabled', { label: t(lang, spec.labelKey) }));
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
console.log(t(lang, 'messengers.removed', { label: t(lang, spec.labelKey) }));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else if (action === 'remove') {
|
|
208
|
+
config = removeMessenger(config, spec.id);
|
|
209
|
+
console.log(t(lang, 'messengers.removed', { label: t(lang, spec.labelKey) }));
|
|
210
|
+
}
|
|
211
|
+
else if (action === 'configure') {
|
|
212
|
+
if (spec.id === 'wechat-ilink')
|
|
213
|
+
config = await configureWechat(lang, config);
|
|
214
|
+
else if (spec.id === 'telegram')
|
|
215
|
+
config = await configureTelegram(lang, config);
|
|
216
|
+
else if (spec.id === 'feishu')
|
|
217
|
+
config = await configureFeishu(lang, config);
|
|
218
|
+
else if (spec.id === 'dingtalk')
|
|
219
|
+
config = await configureDingtalk(lang, config);
|
|
220
|
+
else if (spec.id === 'discord')
|
|
221
|
+
config = await configureDiscord(lang, config);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
if (err instanceof UserAbortError)
|
|
226
|
+
continue; // Ctrl-C inside a sub-flow → bounce back to this menu
|
|
227
|
+
throw err;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function removeMessenger(cfg, id) {
|
|
232
|
+
const messengers = (cfg.messengers || []).filter(m => m !== id);
|
|
233
|
+
const next = { ...cfg, messengers };
|
|
234
|
+
if (id === 'telegram')
|
|
235
|
+
delete next.telegram;
|
|
236
|
+
if (id === 'feishu')
|
|
237
|
+
delete next.feishu;
|
|
238
|
+
if (id === 'dingtalk')
|
|
239
|
+
delete next.dingtalk;
|
|
240
|
+
if (id === 'discord')
|
|
241
|
+
delete next.discord;
|
|
242
|
+
return next;
|
|
243
|
+
}
|
|
244
|
+
function toggleEmail(cfg, enable) {
|
|
245
|
+
const current = new Set(cfg.messengers || []);
|
|
246
|
+
if (enable)
|
|
247
|
+
current.add('email');
|
|
248
|
+
else
|
|
249
|
+
current.delete('email');
|
|
250
|
+
return { ...cfg, messengers: Array.from(current) };
|
|
251
|
+
}
|
|
252
|
+
async function configureWechat(lang, cfg) {
|
|
253
|
+
console.log(t(lang, 'wechat.fetching'));
|
|
254
|
+
const { ILinkWeChatAdapter } = await import('../plugins/messengers/wechat/ilink-adapter.js');
|
|
255
|
+
const adapter = new ILinkWeChatAdapter();
|
|
256
|
+
try {
|
|
257
|
+
const { qrUrl, qrToken } = await adapter.startQRLogin();
|
|
258
|
+
console.log();
|
|
259
|
+
console.log(t(lang, 'wechat.scan'));
|
|
260
|
+
console.log(qrUrl);
|
|
261
|
+
console.log();
|
|
262
|
+
console.log(t(lang, 'wechat.waiting'));
|
|
263
|
+
const credentials = await adapter.waitForQRLogin(qrToken, (status) => {
|
|
264
|
+
console.log(`[${new Date().toLocaleTimeString()}] ${status}`);
|
|
265
|
+
});
|
|
266
|
+
if (!credentials) {
|
|
267
|
+
console.log(t(lang, 'wechat.failed'));
|
|
268
|
+
return cfg;
|
|
269
|
+
}
|
|
270
|
+
console.log(t(lang, 'wechat.logged_in', { user: credentials.userId ?? '', bot: credentials.accountId ?? '' }));
|
|
271
|
+
const messengers = new Set(cfg.messengers || []);
|
|
272
|
+
messengers.add('wechat-ilink');
|
|
273
|
+
return { ...cfg, messengers: Array.from(messengers) };
|
|
274
|
+
}
|
|
275
|
+
catch (err) {
|
|
276
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
277
|
+
console.log(`❌ ${msg}`);
|
|
278
|
+
return cfg;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/** Mask a secret so we can show "(current: ...XYZ)" without leaking the
|
|
282
|
+
* whole token. Keeps the last 4 chars; pads with • for the prefix so the
|
|
283
|
+
* visible chunk looks roughly the right shape. */
|
|
284
|
+
function maskSecret(s) {
|
|
285
|
+
if (!s)
|
|
286
|
+
return '(empty)';
|
|
287
|
+
if (s.length <= 6)
|
|
288
|
+
return '•'.repeat(s.length);
|
|
289
|
+
return '•'.repeat(Math.min(8, s.length - 4)) + s.slice(-4);
|
|
290
|
+
}
|
|
291
|
+
async function configureTelegram(lang, cfg) {
|
|
292
|
+
console.log();
|
|
293
|
+
console.log(t(lang, 'tg.docs'));
|
|
294
|
+
console.log();
|
|
295
|
+
const current = cfg.telegram;
|
|
296
|
+
const tokenLabel = current?.botToken
|
|
297
|
+
? t(lang, 'tg.field.token_keep', { hint: maskSecret(current.botToken) })
|
|
298
|
+
: t(lang, 'tg.field.token');
|
|
299
|
+
const tokenIn = await inputSecret({
|
|
300
|
+
message: tokenLabel,
|
|
301
|
+
required: !current?.botToken,
|
|
302
|
+
});
|
|
303
|
+
const token = tokenIn || current?.botToken || '';
|
|
304
|
+
const channelId = await inputText({
|
|
305
|
+
message: t(lang, 'tg.field.channel'),
|
|
306
|
+
default: current?.channelId ?? 'default',
|
|
307
|
+
});
|
|
308
|
+
const messengers = new Set(cfg.messengers || []);
|
|
309
|
+
messengers.add('telegram');
|
|
310
|
+
return {
|
|
311
|
+
...cfg,
|
|
312
|
+
messengers: Array.from(messengers),
|
|
313
|
+
telegram: { botToken: token, channelId: channelId || 'default' },
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
async function configureFeishu(lang, cfg) {
|
|
317
|
+
console.log();
|
|
318
|
+
console.log(t(lang, 'feishu.docs'));
|
|
319
|
+
console.log();
|
|
320
|
+
const current = cfg.feishu;
|
|
321
|
+
const appId = await inputText({
|
|
322
|
+
message: t(lang, 'feishu.field.app_id'),
|
|
323
|
+
default: current?.appId,
|
|
324
|
+
required: true,
|
|
325
|
+
});
|
|
326
|
+
const secretLabel = current?.appSecret
|
|
327
|
+
? t(lang, 'feishu.field.app_secret_keep')
|
|
328
|
+
: t(lang, 'feishu.field.app_secret');
|
|
329
|
+
const secretIn = await inputSecret({
|
|
330
|
+
message: secretLabel,
|
|
331
|
+
required: !current?.appSecret,
|
|
332
|
+
});
|
|
333
|
+
const appSecret = secretIn || current?.appSecret || '';
|
|
334
|
+
const messengers = new Set(cfg.messengers || []);
|
|
335
|
+
messengers.add('feishu');
|
|
336
|
+
return {
|
|
337
|
+
...cfg,
|
|
338
|
+
messengers: Array.from(messengers),
|
|
339
|
+
feishu: { appId, appSecret, channelId: current?.channelId },
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
async function configureDingtalk(lang, cfg) {
|
|
343
|
+
console.log();
|
|
344
|
+
console.log(t(lang, 'dingtalk.docs'));
|
|
345
|
+
console.log();
|
|
346
|
+
const current = cfg.dingtalk;
|
|
347
|
+
const clientId = await inputText({
|
|
348
|
+
message: t(lang, 'dingtalk.field.client_id'),
|
|
349
|
+
default: current?.clientId,
|
|
350
|
+
required: true,
|
|
351
|
+
});
|
|
352
|
+
const secretLabel = current?.clientSecret
|
|
353
|
+
? t(lang, 'dingtalk.field.client_secret_keep')
|
|
354
|
+
: t(lang, 'dingtalk.field.client_secret');
|
|
355
|
+
const secretIn = await inputSecret({
|
|
356
|
+
message: secretLabel,
|
|
357
|
+
required: !current?.clientSecret,
|
|
358
|
+
});
|
|
359
|
+
const clientSecret = secretIn || current?.clientSecret || '';
|
|
360
|
+
const messengers = new Set(cfg.messengers || []);
|
|
361
|
+
messengers.add('dingtalk');
|
|
362
|
+
return {
|
|
363
|
+
...cfg,
|
|
364
|
+
messengers: Array.from(messengers),
|
|
365
|
+
dingtalk: { clientId, clientSecret, channelId: current?.channelId },
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
async function configureDiscord(lang, cfg) {
|
|
369
|
+
console.log();
|
|
370
|
+
console.log(t(lang, 'discord.docs'));
|
|
371
|
+
console.log();
|
|
372
|
+
const current = cfg.discord;
|
|
373
|
+
const tokenLabel = current?.botToken
|
|
374
|
+
? t(lang, 'discord.field.token_keep')
|
|
375
|
+
: t(lang, 'discord.field.token');
|
|
376
|
+
const tokenIn = await inputSecret({
|
|
377
|
+
message: tokenLabel,
|
|
378
|
+
required: !current?.botToken,
|
|
379
|
+
});
|
|
380
|
+
const token = tokenIn || current?.botToken || '';
|
|
381
|
+
const channelId = await inputText({
|
|
382
|
+
message: t(lang, 'discord.field.channel'),
|
|
383
|
+
default: current?.channelId ?? 'default',
|
|
384
|
+
});
|
|
385
|
+
const guildsRaw = await inputText({
|
|
386
|
+
message: t(lang, 'discord.field.guilds'),
|
|
387
|
+
default: (current?.allowedGuilds ?? []).join(','),
|
|
388
|
+
});
|
|
389
|
+
const channelsRaw = await inputText({
|
|
390
|
+
message: t(lang, 'discord.field.channels'),
|
|
391
|
+
default: (current?.allowedChannels ?? []).join(','),
|
|
392
|
+
});
|
|
393
|
+
const messengers = new Set(cfg.messengers || []);
|
|
394
|
+
messengers.add('discord');
|
|
395
|
+
return {
|
|
396
|
+
...cfg,
|
|
397
|
+
messengers: Array.from(messengers),
|
|
398
|
+
discord: {
|
|
399
|
+
botToken: token,
|
|
400
|
+
channelId: channelId || 'default',
|
|
401
|
+
allowedGuilds: guildsRaw ? guildsRaw.split(',').map(s => s.trim()).filter(Boolean) : undefined,
|
|
402
|
+
allowedChannels: channelsRaw ? channelsRaw.split(',').map(s => s.trim()).filter(Boolean) : undefined,
|
|
403
|
+
},
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
const AGENT_SPECS = [
|
|
407
|
+
{ id: 'claude-code', cmd: 'claude' },
|
|
408
|
+
{ id: 'opencode', cmd: 'opencode', authHintKey: 'agents.auth_hint.opencode' },
|
|
409
|
+
{ id: 'codex', cmd: 'codex', authHintKey: 'agents.auth_hint.codex' },
|
|
410
|
+
{ id: 'copilot', cmd: 'copilot' },
|
|
411
|
+
];
|
|
412
|
+
/** Detect install state once per sectionAgents() call, but always
|
|
413
|
+
* re-detect after the user picks "Re-check". */
|
|
414
|
+
async function detectAgentInstalls() {
|
|
415
|
+
const out = new Map();
|
|
416
|
+
await Promise.all(AGENT_SPECS.map(async (spec) => {
|
|
417
|
+
if (spec.id === 'copilot') {
|
|
418
|
+
// Copilot has multiple install paths; use the plugin's own check
|
|
419
|
+
// which knows about VSCode extension / gh-copilot extension / etc.
|
|
420
|
+
try {
|
|
421
|
+
const { copilotAdapter } = await import('../plugins/agents/copilot/index.js');
|
|
422
|
+
out.set(spec.id, await copilotAdapter.isAvailable());
|
|
423
|
+
}
|
|
424
|
+
catch {
|
|
425
|
+
out.set(spec.id, false);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
out.set(spec.id, await cliAvailable(spec.cmd));
|
|
430
|
+
}
|
|
431
|
+
}));
|
|
432
|
+
return out;
|
|
433
|
+
}
|
|
434
|
+
function agentStatus(lang, id, enabled, installed) {
|
|
435
|
+
if (enabled && installed)
|
|
436
|
+
return t(lang, 'agents.status.enabled_installed');
|
|
437
|
+
if (enabled && !installed)
|
|
438
|
+
return t(lang, 'agents.status.enabled_missing');
|
|
439
|
+
if (!enabled && installed)
|
|
440
|
+
return t(lang, 'agents.status.disabled_installed');
|
|
441
|
+
return t(lang, 'agents.status.disabled_missing');
|
|
442
|
+
}
|
|
443
|
+
async function sectionAgents(lang, cfg) {
|
|
444
|
+
let config = cfg;
|
|
445
|
+
let installs = await detectAgentInstalls();
|
|
446
|
+
while (true) {
|
|
447
|
+
// Effective enabled list: union of cfg.agents + cfg.defaultAgent.
|
|
448
|
+
// Historical configs can drift into `agents: []` + a non-empty
|
|
449
|
+
// `defaultAgent` from the legacy `config <agent>` flow.
|
|
450
|
+
const validIds = new Set(AGENT_SPECS.map(s => s.id));
|
|
451
|
+
const effective = new Set([
|
|
452
|
+
...((config.agents || []).filter(a => validIds.has(a))),
|
|
453
|
+
...(config.defaultAgent && validIds.has(config.defaultAgent) ? [config.defaultAgent] : []),
|
|
454
|
+
]);
|
|
455
|
+
console.log();
|
|
456
|
+
console.log(t(lang, 'agents.title'));
|
|
457
|
+
console.log(t(lang, 'agents.subtitle'));
|
|
458
|
+
console.log();
|
|
459
|
+
const choices = [];
|
|
460
|
+
for (const spec of AGENT_SPECS) {
|
|
461
|
+
const enabled = effective.has(spec.id);
|
|
462
|
+
const installed = installs.get(spec.id) ?? false;
|
|
463
|
+
choices.push({
|
|
464
|
+
value: spec.id,
|
|
465
|
+
name: t(lang, 'agents.row', {
|
|
466
|
+
label: t(lang, ('agents.label.' + spec.id)),
|
|
467
|
+
status: agentStatus(lang, spec.id, enabled, installed),
|
|
468
|
+
}),
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
if (effective.size > 0) {
|
|
472
|
+
choices.push({
|
|
473
|
+
value: '__set_default__',
|
|
474
|
+
name: t(lang, 'agents.set_default_action'),
|
|
475
|
+
separatorBefore: true,
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
choices.push({
|
|
479
|
+
value: '__recheck__',
|
|
480
|
+
name: t(lang, 'agents.action.recheck'),
|
|
481
|
+
separatorBefore: effective.size === 0,
|
|
482
|
+
});
|
|
483
|
+
const picked = await menu({
|
|
484
|
+
lang,
|
|
485
|
+
message: t(lang, 'menu.subtitle'),
|
|
486
|
+
choices,
|
|
487
|
+
back: 'agents.action.back',
|
|
488
|
+
});
|
|
489
|
+
if (picked === BACK)
|
|
490
|
+
return config;
|
|
491
|
+
if (picked === '__recheck__') {
|
|
492
|
+
installs = await detectAgentInstalls();
|
|
493
|
+
console.log('🔄 Re-checked all agents.');
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
if (picked === '__set_default__') {
|
|
497
|
+
const enabledIds = Array.from(effective);
|
|
498
|
+
const def = await menu({
|
|
499
|
+
lang,
|
|
500
|
+
message: t(lang, 'agents.default_picker'),
|
|
501
|
+
choices: enabledIds.map(id => ({
|
|
502
|
+
value: id,
|
|
503
|
+
name: t(lang, ('agents.label.' + id)),
|
|
504
|
+
})),
|
|
505
|
+
default: enabledIds.includes(config.defaultAgent) ? config.defaultAgent : enabledIds[0],
|
|
506
|
+
back: 'agents.action.back',
|
|
507
|
+
});
|
|
508
|
+
if (def === BACK)
|
|
509
|
+
continue;
|
|
510
|
+
// Also ensure the picked default is in agents[] (it must be for
|
|
511
|
+
// routing to work).
|
|
512
|
+
const agents = new Set(config.agents || []);
|
|
513
|
+
agents.add(def);
|
|
514
|
+
config = { ...config, agents: Array.from(agents), defaultAgent: def };
|
|
515
|
+
console.log(t(lang, 'agents.default_set', { label: t(lang, ('agents.label.' + def)) }));
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
const spec = AGENT_SPECS.find(s => s.id === picked);
|
|
519
|
+
try {
|
|
520
|
+
config = await agentSubMenu(lang, config, spec, installs, effective.has(spec.id));
|
|
521
|
+
}
|
|
522
|
+
catch (err) {
|
|
523
|
+
if (err instanceof UserAbortError)
|
|
524
|
+
continue;
|
|
525
|
+
throw err;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
async function agentSubMenu(lang, cfg, spec, installs, enabled) {
|
|
530
|
+
let config = cfg;
|
|
531
|
+
let isEnabled = enabled;
|
|
532
|
+
while (true) {
|
|
533
|
+
const installed = installs.get(spec.id) ?? false;
|
|
534
|
+
const label = t(lang, ('agents.label.' + spec.id));
|
|
535
|
+
console.log();
|
|
536
|
+
console.log(label + ' — ' + agentStatus(lang, spec.id, isEnabled, installed));
|
|
537
|
+
console.log(installed
|
|
538
|
+
? t(lang, 'agents.installed_msg', { label })
|
|
539
|
+
: t(lang, 'agents.missing_msg', { label }));
|
|
540
|
+
if (spec.authHintKey)
|
|
541
|
+
console.log(t(lang, spec.authHintKey));
|
|
542
|
+
console.log();
|
|
543
|
+
const choices = [];
|
|
544
|
+
if (!isEnabled) {
|
|
545
|
+
choices.push({ value: 'enable', name: t(lang, 'agents.action.enable') });
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
choices.push({ value: 'set_default', name: t(lang, 'agents.action.set_default') });
|
|
549
|
+
choices.push({ value: 'disable', name: t(lang, 'agents.action.disable') });
|
|
550
|
+
}
|
|
551
|
+
choices.push({ value: 'install_hint', name: t(lang, 'agents.action.install_hint') });
|
|
552
|
+
choices.push({ value: 'recheck', name: t(lang, 'agents.action.recheck') });
|
|
553
|
+
const action = await menu({
|
|
554
|
+
lang,
|
|
555
|
+
message: t(lang, 'menu.subtitle'),
|
|
556
|
+
choices,
|
|
557
|
+
back: 'agents.action.back',
|
|
558
|
+
});
|
|
559
|
+
if (action === BACK)
|
|
560
|
+
return config;
|
|
561
|
+
if (action === 'enable') {
|
|
562
|
+
const agents = new Set(config.agents || []);
|
|
563
|
+
agents.add(spec.id);
|
|
564
|
+
// If there's no default yet, this agent becomes the default.
|
|
565
|
+
const alsoDefault = !config.defaultAgent;
|
|
566
|
+
const next = {
|
|
567
|
+
...config,
|
|
568
|
+
agents: Array.from(agents),
|
|
569
|
+
defaultAgent: alsoDefault ? spec.id : config.defaultAgent,
|
|
570
|
+
};
|
|
571
|
+
config = next;
|
|
572
|
+
isEnabled = true;
|
|
573
|
+
console.log(t(lang, 'agents.enabled', {
|
|
574
|
+
label,
|
|
575
|
+
also_default: alsoDefault ? t(lang, 'agents.also_default') : '',
|
|
576
|
+
}));
|
|
577
|
+
}
|
|
578
|
+
else if (action === 'disable') {
|
|
579
|
+
const agents = (config.agents || []).filter(a => a !== spec.id);
|
|
580
|
+
let defaultAgent = config.defaultAgent;
|
|
581
|
+
if (defaultAgent === spec.id) {
|
|
582
|
+
// Promote the next enabled agent (or empty).
|
|
583
|
+
defaultAgent = agents[0] ?? '';
|
|
584
|
+
}
|
|
585
|
+
config = { ...config, agents, defaultAgent };
|
|
586
|
+
isEnabled = false;
|
|
587
|
+
console.log(t(lang, 'agents.removed', { label }));
|
|
588
|
+
}
|
|
589
|
+
else if (action === 'set_default') {
|
|
590
|
+
const agents = new Set(config.agents || []);
|
|
591
|
+
agents.add(spec.id);
|
|
592
|
+
config = { ...config, agents: Array.from(agents), defaultAgent: spec.id };
|
|
593
|
+
console.log(t(lang, 'agents.default_set', { label }));
|
|
594
|
+
}
|
|
595
|
+
else if (action === 'install_hint') {
|
|
596
|
+
console.log();
|
|
597
|
+
console.log(t(lang, ('agents.install_hint.' + spec.id)));
|
|
598
|
+
if (spec.authHintKey)
|
|
599
|
+
console.log(t(lang, spec.authHintKey));
|
|
600
|
+
console.log();
|
|
601
|
+
}
|
|
602
|
+
else if (action === 'recheck') {
|
|
603
|
+
const newInstalls = await detectAgentInstalls();
|
|
604
|
+
installs.set(spec.id, newInstalls.get(spec.id) ?? false);
|
|
605
|
+
console.log('🔄 Re-checked.');
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
// ─── ACP section ───────────────────────────────────────────────────────
|
|
610
|
+
async function sectionAcp(lang, cfg) {
|
|
611
|
+
let agents = [...(cfg.acpAgents ?? [])];
|
|
612
|
+
while (true) {
|
|
613
|
+
const choices = [];
|
|
614
|
+
choices.push({ value: '__add__', name: t(lang, 'acp.action.add') });
|
|
615
|
+
for (const a of agents) {
|
|
616
|
+
choices.push({ value: `edit:${a.name}`, name: t(lang, 'acp.action.edit', { name: a.name }) });
|
|
617
|
+
choices.push({ value: `remove:${a.name}`, name: t(lang, 'acp.action.remove', { name: a.name }) });
|
|
618
|
+
}
|
|
619
|
+
const picked = (await menu({
|
|
620
|
+
lang,
|
|
621
|
+
message: t(lang, 'acp.subtitle'),
|
|
622
|
+
choices,
|
|
623
|
+
back: 'acp.action.back',
|
|
624
|
+
}));
|
|
625
|
+
if (picked === BACK)
|
|
626
|
+
break;
|
|
627
|
+
if (picked === '__add__') {
|
|
628
|
+
const a = await promptAcpAgent(lang);
|
|
629
|
+
if (a)
|
|
630
|
+
agents.push(a);
|
|
631
|
+
}
|
|
632
|
+
else if (picked.startsWith('remove:')) {
|
|
633
|
+
const name = picked.slice('remove:'.length);
|
|
634
|
+
agents = agents.filter(x => x.name !== name);
|
|
635
|
+
console.log(t(lang, 'acp.removed', { name }));
|
|
636
|
+
}
|
|
637
|
+
else if (picked.startsWith('edit:')) {
|
|
638
|
+
const name = picked.slice('edit:'.length);
|
|
639
|
+
const idx = agents.findIndex(x => x.name === name);
|
|
640
|
+
if (idx >= 0) {
|
|
641
|
+
const updated = await promptAcpAgent(lang, agents[idx]);
|
|
642
|
+
if (updated)
|
|
643
|
+
agents[idx] = updated;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return { ...cfg, acpAgents: agents };
|
|
648
|
+
}
|
|
649
|
+
async function promptAcpAgent(lang, existing) {
|
|
650
|
+
const name = await inputText({
|
|
651
|
+
message: t(lang, 'acp.field.name'),
|
|
652
|
+
default: existing?.name,
|
|
653
|
+
required: true,
|
|
654
|
+
});
|
|
655
|
+
const endpoint = await inputText({
|
|
656
|
+
message: t(lang, 'acp.field.endpoint'),
|
|
657
|
+
default: existing?.endpoint,
|
|
658
|
+
required: true,
|
|
659
|
+
validate: v => /^https?:\/\//.test(v) || 'must start with http:// or https://',
|
|
660
|
+
});
|
|
661
|
+
const authType = (await menu({
|
|
662
|
+
lang,
|
|
663
|
+
message: t(lang, 'acp.field.auth_type'),
|
|
664
|
+
choices: [
|
|
665
|
+
{ value: 'none', name: t(lang, 'acp.auth.none') },
|
|
666
|
+
{ value: 'bearer', name: t(lang, 'acp.auth.bearer') },
|
|
667
|
+
],
|
|
668
|
+
default: (existing?.auth?.type === 'bearer' ? 'bearer' : 'none'),
|
|
669
|
+
}));
|
|
670
|
+
let token;
|
|
671
|
+
if (authType === 'bearer') {
|
|
672
|
+
token = await inputSecret({
|
|
673
|
+
message: t(lang, 'acp.field.auth_token'),
|
|
674
|
+
required: true,
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
console.log(t(lang, 'acp.added', { name }));
|
|
678
|
+
return {
|
|
679
|
+
name,
|
|
680
|
+
endpoint,
|
|
681
|
+
auth: authType === 'none' ? { type: 'none' } : { type: 'bearer', token },
|
|
682
|
+
enabled: true,
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
const SMTP_PRESETS = [
|
|
686
|
+
{ id: 'gmail', host: 'smtp.gmail.com', port: 465, secure: 'true' },
|
|
687
|
+
{ id: 'outlook', host: 'smtp.office365.com', port: 587, secure: 'false' },
|
|
688
|
+
{ id: 'qq', host: 'smtp.qq.com', port: 465, secure: 'true' },
|
|
689
|
+
{ id: '163', host: 'smtp.163.com', port: 465, secure: 'true' },
|
|
690
|
+
{ id: 'custom' },
|
|
691
|
+
{ id: 'skip' },
|
|
692
|
+
];
|
|
693
|
+
async function sectionSmtp(lang) {
|
|
694
|
+
console.log();
|
|
695
|
+
console.log(t(lang, 'smtp.title'));
|
|
696
|
+
console.log(t(lang, 'smtp.subtitle', { envFile: ENV_FILE }));
|
|
697
|
+
// Use the effective env (env file + process.env fallback) so SMTP keys
|
|
698
|
+
// set via the systemd unit's Environment= lines also show up in the
|
|
699
|
+
// prefill — historical installs put them there directly.
|
|
700
|
+
const current = readEffectiveEnv();
|
|
701
|
+
const hasExisting = Boolean(current.IMHUB_SMTP_HOST && current.IMHUB_SMTP_USER);
|
|
702
|
+
console.log(hasExisting
|
|
703
|
+
? t(lang, 'smtp.current_set', {
|
|
704
|
+
user: current.IMHUB_SMTP_USER ?? '',
|
|
705
|
+
host: current.IMHUB_SMTP_HOST ?? '',
|
|
706
|
+
port: current.IMHUB_SMTP_PORT ?? '?',
|
|
707
|
+
})
|
|
708
|
+
: t(lang, 'smtp.current_unset'));
|
|
709
|
+
console.log();
|
|
710
|
+
const action = (await menu({
|
|
711
|
+
lang,
|
|
712
|
+
message: t(lang, 'menu.subtitle'),
|
|
713
|
+
choices: [
|
|
714
|
+
{ value: 'edit', name: t(lang, 'smtp.action.edit') },
|
|
715
|
+
{ value: 'disable', name: t(lang, 'smtp.action.disable'), disabled: !hasExisting },
|
|
716
|
+
],
|
|
717
|
+
back: 'smtp.action.back',
|
|
718
|
+
}));
|
|
719
|
+
if (action === BACK)
|
|
720
|
+
return;
|
|
721
|
+
if (action === 'disable') {
|
|
722
|
+
for (const k of ['IMHUB_SMTP_HOST', 'IMHUB_SMTP_PORT', 'IMHUB_SMTP_USER', 'IMHUB_SMTP_PASS', 'IMHUB_SMTP_FROM', 'IMHUB_SMTP_SECURE']) {
|
|
723
|
+
unsetEnvKey(k);
|
|
724
|
+
}
|
|
725
|
+
console.log(t(lang, 'smtp.cleared', { file: ENV_FILE }));
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
const presetId = (await menu({
|
|
729
|
+
lang,
|
|
730
|
+
message: t(lang, 'smtp.preset'),
|
|
731
|
+
choices: SMTP_PRESETS.filter(p => p.id !== 'skip').map(p => ({
|
|
732
|
+
value: p.id,
|
|
733
|
+
name: t(lang, `smtp.preset.${p.id}`),
|
|
734
|
+
})),
|
|
735
|
+
back: 'smtp.action.back',
|
|
736
|
+
}));
|
|
737
|
+
if (presetId === BACK)
|
|
738
|
+
return;
|
|
739
|
+
const preset = SMTP_PRESETS.find(p => p.id === presetId);
|
|
740
|
+
// Prefill priority: existing user value first, then preset default.
|
|
741
|
+
// Picking a known preset (gmail/qq/etc) while already-configured shouldn't
|
|
742
|
+
// erase the user's working host — they probably picked it just to grab the
|
|
743
|
+
// suggested port/TLS pair.
|
|
744
|
+
const host = await inputText({
|
|
745
|
+
message: t(lang, 'smtp.field.host'),
|
|
746
|
+
default: current.IMHUB_SMTP_HOST ?? preset.host,
|
|
747
|
+
required: true,
|
|
748
|
+
});
|
|
749
|
+
const port = await inputText({
|
|
750
|
+
message: t(lang, 'smtp.field.port'),
|
|
751
|
+
default: String(current.IMHUB_SMTP_PORT ?? preset.port ?? 465),
|
|
752
|
+
required: true,
|
|
753
|
+
validate: v => /^\d+$/.test(v) && Number(v) > 0 && Number(v) < 65536 || '1..65535',
|
|
754
|
+
});
|
|
755
|
+
const user = await inputText({
|
|
756
|
+
message: t(lang, 'smtp.field.user'),
|
|
757
|
+
default: current.IMHUB_SMTP_USER,
|
|
758
|
+
required: true,
|
|
759
|
+
});
|
|
760
|
+
// Password: never prefill literally (leaks via scrollback). Empty input
|
|
761
|
+
// means "keep what's stored". When nothing is stored yet, require it.
|
|
762
|
+
const passInput = await inputSecret({
|
|
763
|
+
message: t(lang, current.IMHUB_SMTP_PASS ? 'smtp.field.pass_keep' : 'smtp.field.pass'),
|
|
764
|
+
required: !current.IMHUB_SMTP_PASS,
|
|
765
|
+
});
|
|
766
|
+
const pass = passInput || current.IMHUB_SMTP_PASS || '';
|
|
767
|
+
const from = await inputText({
|
|
768
|
+
message: t(lang, 'smtp.field.from'),
|
|
769
|
+
default: current.IMHUB_SMTP_FROM || user,
|
|
770
|
+
});
|
|
771
|
+
let secure = preset.secure ?? current.IMHUB_SMTP_SECURE ?? 'auto';
|
|
772
|
+
if (presetId === 'custom') {
|
|
773
|
+
secure = (await menu({
|
|
774
|
+
lang,
|
|
775
|
+
message: t(lang, 'smtp.field.secure'),
|
|
776
|
+
choices: [
|
|
777
|
+
{ value: 'auto', name: t(lang, 'smtp.secure.auto') },
|
|
778
|
+
{ value: 'true', name: t(lang, 'smtp.secure.true') },
|
|
779
|
+
{ value: 'false', name: t(lang, 'smtp.secure.false') },
|
|
780
|
+
],
|
|
781
|
+
default: secure,
|
|
782
|
+
}));
|
|
783
|
+
}
|
|
784
|
+
updateEnvFile({
|
|
785
|
+
IMHUB_SMTP_HOST: host,
|
|
786
|
+
IMHUB_SMTP_PORT: port,
|
|
787
|
+
IMHUB_SMTP_USER: user,
|
|
788
|
+
IMHUB_SMTP_PASS: pass,
|
|
789
|
+
IMHUB_SMTP_FROM: from,
|
|
790
|
+
IMHUB_SMTP_SECURE: secure,
|
|
791
|
+
});
|
|
792
|
+
console.log(t(lang, 'smtp.saved', { file: ENV_FILE }));
|
|
793
|
+
// Warn if any wizard-managed SMTP key is also set by the running env
|
|
794
|
+
// (most commonly: systemd unit's `Environment=` lines). Writing the
|
|
795
|
+
// env file alone won't change the active value in that case.
|
|
796
|
+
for (const k of ['IMHUB_SMTP_HOST', 'IMHUB_SMTP_PORT', 'IMHUB_SMTP_USER', 'IMHUB_SMTP_PASS', 'IMHUB_SMTP_FROM']) {
|
|
797
|
+
if (hasProcessEnvOverride(k)) {
|
|
798
|
+
console.log(t(lang, 'env.shadowed_warn', { key: k, file: ENV_FILE }));
|
|
799
|
+
break; // one warning is enough; user gets the picture
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
// ─── Baidu Maps section ────────────────────────────────────────────────
|
|
804
|
+
async function sectionBaidu(lang) {
|
|
805
|
+
while (true) {
|
|
806
|
+
console.log();
|
|
807
|
+
console.log(t(lang, 'baidu.title'));
|
|
808
|
+
console.log(t(lang, 'baidu.subtitle'));
|
|
809
|
+
console.log(t(lang, 'baidu.howto'));
|
|
810
|
+
console.log();
|
|
811
|
+
// Effective env so a key set via the systemd unit / shell export
|
|
812
|
+
// still shows up here, not just keys written into ~/.im-hub/env.
|
|
813
|
+
const current = readEffectiveEnv().IMHUB_BAIDU_MAP_AK;
|
|
814
|
+
const status = current ? `${current.slice(0, 6)}…${current.slice(-4)} (set)` : '(unset)';
|
|
815
|
+
const action = (await menu({
|
|
816
|
+
lang,
|
|
817
|
+
message: `current: ${status}`,
|
|
818
|
+
choices: [
|
|
819
|
+
{ value: 'set', name: t(lang, 'baidu.action.set') },
|
|
820
|
+
{ value: 'clear', name: t(lang, 'baidu.action.clear'), disabled: !current },
|
|
821
|
+
],
|
|
822
|
+
back: 'baidu.action.back',
|
|
823
|
+
}));
|
|
824
|
+
if (action === BACK)
|
|
825
|
+
return;
|
|
826
|
+
if (action === 'clear') {
|
|
827
|
+
unsetEnvKey('IMHUB_BAIDU_MAP_AK');
|
|
828
|
+
console.log(t(lang, 'baidu.cleared'));
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
const ak = await inputText({
|
|
832
|
+
message: t(lang, 'baidu.input'),
|
|
833
|
+
default: current,
|
|
834
|
+
validate: v => {
|
|
835
|
+
if (!v)
|
|
836
|
+
return 'Required (or pick ← Back)';
|
|
837
|
+
if (v.length < 24 || v.length > 64)
|
|
838
|
+
return 'AK length looks wrong (expected ~32 chars)';
|
|
839
|
+
return true;
|
|
840
|
+
},
|
|
841
|
+
});
|
|
842
|
+
updateEnvFile({ IMHUB_BAIDU_MAP_AK: ak });
|
|
843
|
+
console.log(t(lang, 'baidu.saved', { file: ENV_FILE }));
|
|
844
|
+
if (hasProcessEnvOverride('IMHUB_BAIDU_MAP_AK')) {
|
|
845
|
+
console.log(t(lang, 'env.shadowed_warn', { key: 'IMHUB_BAIDU_MAP_AK', file: ENV_FILE }));
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
// Suppress an unused-import warning for yesNo — exposed for future sections.
|
|
850
|
+
void yesNo;
|
|
851
|
+
//# sourceMappingURL=config-wizard.js.map
|