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,305 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
|
6
|
+
<title>共享位置 · im-hub</title>
|
|
7
|
+
<!-- Leaflet for the interactive map preview. Loaded from unpkg CDN; both
|
|
8
|
+
the page and Leaflet itself fall back gracefully if the CDN is
|
|
9
|
+
blocked — see the `typeof L === 'undefined'` branch in the script. -->
|
|
10
|
+
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
|
11
|
+
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
|
|
12
|
+
crossorigin="">
|
|
13
|
+
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
|
14
|
+
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
|
|
15
|
+
crossorigin=""></script>
|
|
16
|
+
<style>
|
|
17
|
+
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
|
|
18
|
+
html, body { margin: 0; padding: 0; min-height: 100%; font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif; }
|
|
19
|
+
body { background: linear-gradient(180deg, #eff6ff 0%, #ffffff 60%); color: #0f172a; }
|
|
20
|
+
.wrap { max-width: 480px; margin: 0 auto; padding: 24px 20px; }
|
|
21
|
+
h1 { font-size: 22px; margin: 0 0 6px; font-weight: 600; }
|
|
22
|
+
p { color: #475569; line-height: 1.6; margin: 6px 0; }
|
|
23
|
+
.card { background: white; border: 1px solid #e2e8f0; border-radius: 12px; padding: 18px; margin: 18px 0; }
|
|
24
|
+
.btn { display: block; width: 100%; padding: 13px; font-size: 16px; font-weight: 500; color: white; background: #2563eb; border: 0; border-radius: 8px; cursor: pointer; transition: background 0.15s; }
|
|
25
|
+
.btn:hover { background: #1d4ed8; }
|
|
26
|
+
.btn:disabled { background: #94a3b8; cursor: not-allowed; }
|
|
27
|
+
.btn.secondary { background: white; color: #2563eb; border: 1px solid #cbd5e1; margin-top: 8px; }
|
|
28
|
+
.btn.secondary:hover { background: #eff6ff; }
|
|
29
|
+
.status { padding: 14px; border-radius: 8px; margin-top: 14px; font-size: 14px; line-height: 1.5; word-break: break-all; }
|
|
30
|
+
.status.ok { background: #dcfce7; color: #14532d; border: 1px solid #86efac; }
|
|
31
|
+
.status.err { background: #fee2e2; color: #7f1d1d; border: 1px solid #fca5a5; }
|
|
32
|
+
.status.info { background: #dbeafe; color: #1e3a8a; border: 1px solid #93c5fd; }
|
|
33
|
+
.meta { font-size: 12px; color: #94a3b8; margin-top: 18px; text-align: center; line-height: 1.6; }
|
|
34
|
+
code { background: #f1f5f9; padding: 2px 6px; border-radius: 4px; font-family: ui-monospace, "SFMono-Regular", monospace; font-size: 13px; }
|
|
35
|
+
.icon { font-size: 40px; line-height: 1; margin-bottom: 8px; }
|
|
36
|
+
#map { width: 100%; height: 320px; border-radius: 8px; border: 1px solid #e2e8f0; }
|
|
37
|
+
.coords-row { display:flex; align-items:center; justify-content:space-between; margin-top:12px; padding:10px 12px; background:#f8fafc; border-radius:6px; font-size:13px; color:#334155; font-family: ui-monospace, "SFMono-Regular", monospace; }
|
|
38
|
+
.hint { font-size: 12px; color: #64748b; margin-top: 8px; line-height: 1.5; }
|
|
39
|
+
.note-row { display:none; margin-bottom:12px; padding:10px 12px; background:#eff6ff; border-radius:8px; color:#1e40af; font-size:14px; }
|
|
40
|
+
.leaflet-container { background: #e2e8f0; }
|
|
41
|
+
</style>
|
|
42
|
+
</head>
|
|
43
|
+
<body>
|
|
44
|
+
<div class="wrap">
|
|
45
|
+
<div class="icon">📍</div>
|
|
46
|
+
<h1 id="title">共享当前位置给 bot</h1>
|
|
47
|
+
<p id="subtitle">点击下方按钮,浏览器会询问位置授权。授权后可在地图上微调精确位置。</p>
|
|
48
|
+
|
|
49
|
+
<div id="note-row" class="note-row">
|
|
50
|
+
<span id="note-prefix">正在记录</span>: <strong id="note-text"></strong>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<!-- Step 1: get permission + initial coords -->
|
|
54
|
+
<div id="card-prep" class="card">
|
|
55
|
+
<button id="share" class="btn" type="button">📍 获取我的位置</button>
|
|
56
|
+
<div id="status" class="status info" style="display:none"></div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<!-- Step 2: map preview + drag to fine-tune + confirm -->
|
|
60
|
+
<div id="card-map" class="card" style="display:none">
|
|
61
|
+
<div id="map"></div>
|
|
62
|
+
<div class="coords-row">
|
|
63
|
+
<span id="coords-text">—</span>
|
|
64
|
+
<span id="acc-text" style="color:#64748b"></span>
|
|
65
|
+
</div>
|
|
66
|
+
<p class="hint">📌 长按 marker 拖动,或点击地图任意位置移动 marker,可微调到准确位置。</p>
|
|
67
|
+
<button id="confirm" class="btn" type="button">✅ 确认提交这个位置</button>
|
|
68
|
+
<button id="redo" class="btn secondary" type="button">🔄 重新获取定位</button>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<!-- Step 3: done -->
|
|
72
|
+
<div id="card-done" class="card" style="display:none">
|
|
73
|
+
<div class="status ok">✅ 位置已发回 IM。可以关闭页面回到聊天查看。</div>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<p class="meta">
|
|
77
|
+
链接 10 分钟内有效,单次使用<br>
|
|
78
|
+
你的坐标只会发回触发本链接的 IM 会话
|
|
79
|
+
</p>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<script>
|
|
83
|
+
(function () {
|
|
84
|
+
// ── DOM refs ───────────────────────────────────────────────────────
|
|
85
|
+
var status = document.getElementById('status')
|
|
86
|
+
var btnShare = document.getElementById('share')
|
|
87
|
+
var btnConfirm = document.getElementById('confirm')
|
|
88
|
+
var btnRedo = document.getElementById('redo')
|
|
89
|
+
var cardPrep = document.getElementById('card-prep')
|
|
90
|
+
var cardMap = document.getElementById('card-map')
|
|
91
|
+
var cardDone = document.getElementById('card-done')
|
|
92
|
+
var coordsText = document.getElementById('coords-text')
|
|
93
|
+
var accText = document.getElementById('acc-text')
|
|
94
|
+
|
|
95
|
+
// ── Token resolution (supports both /loc?t=… and /l/… shapes) ─────
|
|
96
|
+
var token = ''
|
|
97
|
+
var qp = new URLSearchParams(window.location.search).get('t')
|
|
98
|
+
var pathMatch = window.location.pathname.match(/^\/l\/([A-Za-z0-9_-]+)$/)
|
|
99
|
+
if (qp) {
|
|
100
|
+
token = qp
|
|
101
|
+
} else if (pathMatch) {
|
|
102
|
+
token = pathMatch[1]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ── State ─────────────────────────────────────────────────────────
|
|
106
|
+
var leafletMap = null
|
|
107
|
+
var marker = null
|
|
108
|
+
var currentLat = 0, currentLng = 0, currentAcc = 0
|
|
109
|
+
var leafletAvailable = (typeof L !== 'undefined')
|
|
110
|
+
|
|
111
|
+
function show(kind, html) {
|
|
112
|
+
status.className = 'status ' + kind
|
|
113
|
+
status.innerHTML = html
|
|
114
|
+
status.style.display = 'block'
|
|
115
|
+
}
|
|
116
|
+
function clearStatus() { status.style.display = 'none' }
|
|
117
|
+
|
|
118
|
+
function fmtCoords(lat, lng) {
|
|
119
|
+
return lat.toFixed(6) + ', ' + lng.toFixed(6)
|
|
120
|
+
}
|
|
121
|
+
function updateCoordsDisplay(acc) {
|
|
122
|
+
coordsText.textContent = fmtCoords(currentLat, currentLng)
|
|
123
|
+
if (typeof acc === 'number' && acc > 0) {
|
|
124
|
+
accText.textContent = '初始 ±' + Math.round(acc) + 'm'
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ── Pre-flight ────────────────────────────────────────────────────
|
|
129
|
+
if (!token) {
|
|
130
|
+
btnShare.disabled = true
|
|
131
|
+
show('err', '❌ 链接无效(缺少 token)。请回到 IM 重新发送 <code>/location here</code>。')
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
if (!('geolocation' in navigator)) {
|
|
135
|
+
btnShare.disabled = true
|
|
136
|
+
show('err', '❌ 浏览器不支持地理位置 API。')
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Fetch the pre-filled note for the title bar.
|
|
141
|
+
fetch('/api/loc/info?t=' + encodeURIComponent(token)).then(function (r) {
|
|
142
|
+
if (r.status === 410) {
|
|
143
|
+
btnShare.disabled = true
|
|
144
|
+
show('err', '❌ 链接已过期或已被使用。回到 IM 重新发送 <code>/location here</code> 拿新链接。')
|
|
145
|
+
return null
|
|
146
|
+
}
|
|
147
|
+
return r.ok ? r.json() : null
|
|
148
|
+
}).then(function (j) {
|
|
149
|
+
if (!j) return
|
|
150
|
+
// Two display modes:
|
|
151
|
+
// - augment: token has memo_id → "正在补充'<existing memo's what>'的位置"
|
|
152
|
+
// - create: token has what → "正在记录: <what>"
|
|
153
|
+
var label = j.augmentLabel || j.what || ''
|
|
154
|
+
if (!label) return
|
|
155
|
+
document.getElementById('note-text').textContent = label
|
|
156
|
+
document.getElementById('note-prefix').textContent = j.augmentLabel ? '正在补充' : '正在记录'
|
|
157
|
+
document.getElementById('note-row').style.display = 'block'
|
|
158
|
+
document.getElementById('title').textContent = (j.augmentLabel ? '为"' + label + '"补充位置' : '共享"' + label + '"的位置')
|
|
159
|
+
}).catch(function () { /* network blip — proceed without label */ })
|
|
160
|
+
|
|
161
|
+
// ── Step 1 → Step 2: get permission, switch to map ────────────────
|
|
162
|
+
function captureCoords() {
|
|
163
|
+
btnShare.disabled = true
|
|
164
|
+
btnShare.textContent = '获取定位中…'
|
|
165
|
+
show('info', '⏳ 等待浏览器返回坐标…')
|
|
166
|
+
|
|
167
|
+
navigator.geolocation.getCurrentPosition(
|
|
168
|
+
function (pos) {
|
|
169
|
+
currentLat = pos.coords.latitude
|
|
170
|
+
currentLng = pos.coords.longitude
|
|
171
|
+
currentAcc = pos.coords.accuracy
|
|
172
|
+
clearStatus()
|
|
173
|
+
cardPrep.style.display = 'none'
|
|
174
|
+
cardMap.style.display = 'block'
|
|
175
|
+
updateCoordsDisplay(currentAcc)
|
|
176
|
+
|
|
177
|
+
if (leafletAvailable) {
|
|
178
|
+
renderMap()
|
|
179
|
+
} else {
|
|
180
|
+
fallbackNoMap()
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
function (err) {
|
|
184
|
+
btnShare.disabled = false
|
|
185
|
+
btnShare.textContent = '📍 获取我的位置'
|
|
186
|
+
var map = { 1: '你拒绝了授权', 2: '位置不可用', 3: '获取超时' }
|
|
187
|
+
show('err', '❌ ' + (map[err.code] || err.message || '未知错误'))
|
|
188
|
+
},
|
|
189
|
+
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 30000 }
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// CDN blocked / Leaflet missing → no map preview, but still let the
|
|
194
|
+
// user submit the captured coords directly via the same confirm button.
|
|
195
|
+
function fallbackNoMap() {
|
|
196
|
+
document.getElementById('map').style.display = 'none'
|
|
197
|
+
var hintEl = document.querySelector('.hint')
|
|
198
|
+
if (hintEl) hintEl.textContent = '⚠️ 地图加载失败(网络限制?),无法微调。如坐标不准请用「重新获取定位」。'
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ── Map render (Leaflet + OSM tiles, WGS-84 native, no key) ───────
|
|
202
|
+
function renderMap() {
|
|
203
|
+
leafletMap = L.map('map', {
|
|
204
|
+
zoomControl: true,
|
|
205
|
+
// Touch-friendly defaults; let drag work even on tap-and-hold.
|
|
206
|
+
tap: true,
|
|
207
|
+
}).setView([currentLat, currentLng], 17)
|
|
208
|
+
|
|
209
|
+
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
210
|
+
maxZoom: 19,
|
|
211
|
+
attribution: '© OpenStreetMap',
|
|
212
|
+
}).addTo(leafletMap)
|
|
213
|
+
|
|
214
|
+
// Initial accuracy circle gives the user a sense of GPS uncertainty.
|
|
215
|
+
if (currentAcc > 0) {
|
|
216
|
+
L.circle([currentLat, currentLng], {
|
|
217
|
+
radius: currentAcc,
|
|
218
|
+
color: '#2563eb', fillColor: '#3b82f6', fillOpacity: 0.12, weight: 1,
|
|
219
|
+
}).addTo(leafletMap)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
marker = L.marker([currentLat, currentLng], {
|
|
223
|
+
draggable: true,
|
|
224
|
+
autoPan: true,
|
|
225
|
+
}).addTo(leafletMap)
|
|
226
|
+
|
|
227
|
+
marker.on('dragend', function () {
|
|
228
|
+
var p = marker.getLatLng()
|
|
229
|
+
currentLat = p.lat; currentLng = p.lng
|
|
230
|
+
updateCoordsDisplay()
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
leafletMap.on('click', function (e) {
|
|
234
|
+
marker.setLatLng(e.latlng)
|
|
235
|
+
currentLat = e.latlng.lat; currentLng = e.latlng.lng
|
|
236
|
+
updateCoordsDisplay()
|
|
237
|
+
// Recenter only if marker drifts close to viewport edge — avoids
|
|
238
|
+
// jarring re-pans for small adjustments.
|
|
239
|
+
var bounds = leafletMap.getBounds().pad(-0.15)
|
|
240
|
+
if (!bounds.contains(e.latlng)) leafletMap.panTo(e.latlng)
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
// Some browsers compute layout AFTER tile load; force a redraw.
|
|
244
|
+
setTimeout(function () { leafletMap.invalidateSize() }, 200)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ── Step 2 → Step 3: submit ───────────────────────────────────────
|
|
248
|
+
function submitCoords() {
|
|
249
|
+
btnConfirm.disabled = true
|
|
250
|
+
btnConfirm.textContent = '提交中…'
|
|
251
|
+
show('info', '⏳ 上传到 bot…')
|
|
252
|
+
|
|
253
|
+
fetch('/api/loc', {
|
|
254
|
+
method: 'POST',
|
|
255
|
+
headers: { 'Content-Type': 'application/json' },
|
|
256
|
+
body: JSON.stringify({
|
|
257
|
+
t: token,
|
|
258
|
+
lat: currentLat,
|
|
259
|
+
lng: currentLng,
|
|
260
|
+
// We send 0 for accuracy when the user has manually adjusted —
|
|
261
|
+
// the GPS-reported accuracy no longer applies. A future tweak:
|
|
262
|
+
// track whether marker was moved and report acc only if not.
|
|
263
|
+
accuracy: currentAcc,
|
|
264
|
+
}),
|
|
265
|
+
}).then(function (r) {
|
|
266
|
+
if (r.ok) {
|
|
267
|
+
cardMap.style.display = 'none'
|
|
268
|
+
cardDone.style.display = 'block'
|
|
269
|
+
clearStatus()
|
|
270
|
+
} else {
|
|
271
|
+
return r.json().catch(function () { return {} }).then(function (j) {
|
|
272
|
+
btnConfirm.disabled = false
|
|
273
|
+
btnConfirm.textContent = '✅ 确认提交这个位置'
|
|
274
|
+
show('err', '❌ ' + (j.error || ('上传失败 (HTTP ' + r.status + ')')))
|
|
275
|
+
})
|
|
276
|
+
}
|
|
277
|
+
}).catch(function (err) {
|
|
278
|
+
btnConfirm.disabled = false
|
|
279
|
+
btnConfirm.textContent = '✅ 确认提交这个位置'
|
|
280
|
+
show('err', '❌ 网络错误:' + (err && err.message || err))
|
|
281
|
+
})
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ── Redo: go back to step 1 (re-fetch GPS for higher accuracy) ────
|
|
285
|
+
function redoCapture() {
|
|
286
|
+
if (leafletMap) {
|
|
287
|
+
leafletMap.remove()
|
|
288
|
+
leafletMap = null
|
|
289
|
+
marker = null
|
|
290
|
+
}
|
|
291
|
+
cardMap.style.display = 'none'
|
|
292
|
+
cardPrep.style.display = 'block'
|
|
293
|
+
btnShare.disabled = false
|
|
294
|
+
btnShare.textContent = '📍 获取我的位置'
|
|
295
|
+
clearStatus()
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// ── Wire up ───────────────────────────────────────────────────────
|
|
299
|
+
btnShare.addEventListener('click', captureCoords)
|
|
300
|
+
btnConfirm.addEventListener('click', submitCoords)
|
|
301
|
+
btnRedo.addEventListener('click', redoCapture)
|
|
302
|
+
})()
|
|
303
|
+
</script>
|
|
304
|
+
</body>
|
|
305
|
+
</html>
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>im-hub-pro — Login</title>
|
|
7
|
+
<script src="/_app.js"></script>
|
|
8
|
+
<script>
|
|
9
|
+
const savedLang = localStorage.getItem('im-hub-lang');
|
|
10
|
+
const browserLang = navigator.language.startsWith('zh') ? 'zh' : 'en';
|
|
11
|
+
window.__lang = savedLang || browserLang;
|
|
12
|
+
document.documentElement.lang = window.__lang === 'zh' ? 'zh-CN' : 'en';
|
|
13
|
+
</script>
|
|
14
|
+
<style>
|
|
15
|
+
:root {
|
|
16
|
+
--bg: #f8f9fa; --fg: #1a1a2e; --card-bg: #fff;
|
|
17
|
+
--border: #dee2e6; --accent: #0d6efd; --accent-hover: #0b5ed7;
|
|
18
|
+
--input-bg: #fff; --input-border: #ced4da;
|
|
19
|
+
--error-bg: #f8d7da; --error-fg: #842029;
|
|
20
|
+
}
|
|
21
|
+
:root[data-theme="dark"] {
|
|
22
|
+
--bg: #0d1117; --fg: #c9d1d9; --card-bg: #161b22;
|
|
23
|
+
--border: #30363d; --accent: #58a6ff; --accent-hover: #79b8ff;
|
|
24
|
+
--input-bg: #0d1117; --input-border: #30363d;
|
|
25
|
+
--error-bg: #3d1418; --error-fg: #f8d7da;
|
|
26
|
+
}
|
|
27
|
+
@media (prefers-color-scheme: dark) {
|
|
28
|
+
:root:not([data-theme="light"]) {
|
|
29
|
+
--bg: #0d1117; --fg: #c9d1d9; --card-bg: #161b22;
|
|
30
|
+
--border: #30363d; --accent: #58a6ff; --accent-hover: #79b8ff;
|
|
31
|
+
--input-bg: #0d1117; --input-border: #30363d;
|
|
32
|
+
--error-bg: #3d1418; --error-fg: #f8d7da;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
36
|
+
body { font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
|
|
37
|
+
background: var(--bg); color: var(--fg); display: flex; align-items: center;
|
|
38
|
+
justify-content: center; min-height: 100vh; }
|
|
39
|
+
.card { background: var(--card-bg); border: 1px solid var(--border);
|
|
40
|
+
border-radius: 12px; padding: 2rem; max-width: 400px; width: 90%; box-shadow: 0 4px 24px rgba(0,0,0,.08); }
|
|
41
|
+
h1 { font-size: 1.25rem; margin-bottom: .5rem; }
|
|
42
|
+
p { font-size: .875rem; color: var(--fg); opacity: .7; margin-bottom: 1.5rem; }
|
|
43
|
+
label { display: block; font-size: .875rem; margin-bottom: .25rem; font-weight: 500; }
|
|
44
|
+
input[type="password"] { width: 100%; padding: .5rem .75rem; border: 1px solid var(--input-border);
|
|
45
|
+
border-radius: 6px; background: var(--input-bg); color: var(--fg); font-size: .875rem;
|
|
46
|
+
margin-bottom: 1rem; }
|
|
47
|
+
button { width: 100%; padding: .5rem 1rem; background: var(--accent); color: #fff;
|
|
48
|
+
border: none; border-radius: 6px; font-size: .875rem; cursor: pointer; font-weight: 500; }
|
|
49
|
+
button:hover { background: var(--accent-hover); }
|
|
50
|
+
.error { display: none; background: var(--error-bg); color: var(--error-fg);
|
|
51
|
+
padding: .5rem .75rem; border-radius: 6px; font-size: .8rem; margin-bottom: 1rem; }
|
|
52
|
+
.hint { font-size: .75rem; opacity: .5; margin-top: 1rem; text-align: center; }
|
|
53
|
+
</style>
|
|
54
|
+
</head>
|
|
55
|
+
<body>
|
|
56
|
+
<div class="card">
|
|
57
|
+
<h1 data-i18n="loginTitle">im-hub-pro</h1>
|
|
58
|
+
<p data-i18n="loginDesc">Enter the web console token to continue.</p>
|
|
59
|
+
<div class="error" id="error"></div>
|
|
60
|
+
<form id="form">
|
|
61
|
+
<label for="token" data-i18n="tokenLabel">Token</label>
|
|
62
|
+
<input type="password" id="token" autocomplete="off" >
|
|
63
|
+
<button type="submit" data-i18n="loginBtn">Log in</button>
|
|
64
|
+
</form>
|
|
65
|
+
<div class="hint" data-i18n="tokenHint">Find your token in ~/.im-hub/web-token</div>
|
|
66
|
+
</div>
|
|
67
|
+
<script>
|
|
68
|
+
const T = {
|
|
69
|
+
en: { loginTitle:'im-hub-pro', loginDesc:'Enter the web console token to continue.',
|
|
70
|
+
tokenLabel:'Token', loginBtn:'Log in', tokenHint:'Find your token in ~/.im-hub/web-token',
|
|
71
|
+
badToken:'Invalid token', networkErr:'Network error — is the server running?' },
|
|
72
|
+
zh: { loginTitle:'im-hub-pro', loginDesc:'请输入控制台 token 以继续。',
|
|
73
|
+
tokenLabel:'Token', loginBtn:'登录', tokenHint:'Token 位于 ~/.im-hub/web-token',
|
|
74
|
+
badToken:'Token 无效', networkErr:'网络错误 — 服务是否正在运行?' },
|
|
75
|
+
};
|
|
76
|
+
const L = T[window.__lang] || T.en;
|
|
77
|
+
window.imhub.i18n.apply(L);
|
|
78
|
+
|
|
79
|
+
const form = document.getElementById('form');
|
|
80
|
+
const errEl = document.getElementById('error');
|
|
81
|
+
form.addEventListener('submit', async (e) => {
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
errEl.style.display = 'none';
|
|
84
|
+
const token = document.getElementById('token').value.trim();
|
|
85
|
+
if (!token) return;
|
|
86
|
+
try {
|
|
87
|
+
const res = await fetch('/api/auth/login', {
|
|
88
|
+
method: 'POST',
|
|
89
|
+
headers: { 'Content-Type': 'application/json' },
|
|
90
|
+
body: JSON.stringify({ token }),
|
|
91
|
+
});
|
|
92
|
+
if (res.ok) {
|
|
93
|
+
const dest = new URLSearchParams(location.search).get('next') || '/';
|
|
94
|
+
location.href = dest;
|
|
95
|
+
} else {
|
|
96
|
+
errEl.textContent = L.badToken;
|
|
97
|
+
errEl.style.display = 'block';
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
errEl.textContent = L.networkErr;
|
|
101
|
+
errEl.style.display = 'block';
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
</script>
|
|
105
|
+
</body>
|
|
106
|
+
</html>
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>im-hub-pro — Memos</title>
|
|
7
|
+
<script src="/_app.js"></script>
|
|
8
|
+
<style>
|
|
9
|
+
:root {
|
|
10
|
+
--bg: #fafafa; --fg: #222; --muted: #666; --border: #e5e7eb;
|
|
11
|
+
--card: #fff; --accent: #2563eb; --danger: #dc2626; --warn: #d97706;
|
|
12
|
+
--geo: #059669;
|
|
13
|
+
}
|
|
14
|
+
[data-theme="dark"] {
|
|
15
|
+
--bg: #1a1a1a; --fg: #e5e5e5; --muted: #999; --border: #333;
|
|
16
|
+
--card: #242424; --accent: #60a5fa; --danger: #f87171; --warn: #fbbf24;
|
|
17
|
+
--geo: #34d399;
|
|
18
|
+
}
|
|
19
|
+
body {
|
|
20
|
+
font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", sans-serif;
|
|
21
|
+
background: var(--bg); color: var(--fg); margin: 0; padding: 0;
|
|
22
|
+
}
|
|
23
|
+
header {
|
|
24
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
25
|
+
padding: 14px 20px; border-bottom: 1px solid var(--border); background: var(--card);
|
|
26
|
+
}
|
|
27
|
+
header h1 { margin: 0; font-size: 18px; font-weight: 600; }
|
|
28
|
+
header nav a {
|
|
29
|
+
color: var(--muted); text-decoration: none; padding: 4px 10px;
|
|
30
|
+
border-radius: 4px; font-size: 13px; margin-left: 4px;
|
|
31
|
+
}
|
|
32
|
+
header nav a:hover { background: var(--bg); color: var(--fg); }
|
|
33
|
+
main { padding: 20px; max-width: 980px; margin: 0 auto; }
|
|
34
|
+
.toolbar {
|
|
35
|
+
display: flex; gap: 8px; margin-bottom: 18px; flex-wrap: wrap;
|
|
36
|
+
align-items: center;
|
|
37
|
+
}
|
|
38
|
+
.toolbar input[type="text"] {
|
|
39
|
+
flex: 1; min-width: 200px;
|
|
40
|
+
padding: 7px 12px; border: 1px solid var(--border); border-radius: 6px;
|
|
41
|
+
background: var(--card); color: var(--fg); font-size: 14px;
|
|
42
|
+
}
|
|
43
|
+
.toolbar input[type="text"]:focus { outline: none; border-color: var(--accent); }
|
|
44
|
+
.filter-btn {
|
|
45
|
+
padding: 6px 12px; border: 1px solid var(--border); border-radius: 6px;
|
|
46
|
+
background: transparent; color: var(--muted); cursor: pointer;
|
|
47
|
+
font-size: 13px; transition: all 0.15s;
|
|
48
|
+
}
|
|
49
|
+
.filter-btn:hover { color: var(--fg); border-color: var(--fg); }
|
|
50
|
+
.filter-btn.active { background: var(--accent); color: white; border-color: var(--accent); }
|
|
51
|
+
.stats { color: var(--muted); font-size: 12px; }
|
|
52
|
+
.memo {
|
|
53
|
+
background: var(--card); border: 1px solid var(--border); border-radius: 8px;
|
|
54
|
+
padding: 12px 16px; margin-bottom: 10px;
|
|
55
|
+
display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
|
|
56
|
+
}
|
|
57
|
+
.memo .body { flex: 1; min-width: 0; }
|
|
58
|
+
.memo .what {
|
|
59
|
+
font-weight: 600; margin-bottom: 4px;
|
|
60
|
+
display: flex; align-items: center; gap: 8px;
|
|
61
|
+
}
|
|
62
|
+
.memo .icon { font-size: 16px; }
|
|
63
|
+
.memo .id { color: var(--muted); font-size: 11px; font-weight: normal; }
|
|
64
|
+
.memo .original {
|
|
65
|
+
color: var(--muted); margin-bottom: 6px; font-size: 13px;
|
|
66
|
+
border-left: 2px solid var(--border); padding-left: 8px;
|
|
67
|
+
}
|
|
68
|
+
.memo .meta {
|
|
69
|
+
color: var(--muted); font-size: 12px; margin-top: 4px;
|
|
70
|
+
display: flex; gap: 12px; flex-wrap: wrap;
|
|
71
|
+
}
|
|
72
|
+
.memo .meta .who::before { content: '👤 '; }
|
|
73
|
+
.memo .meta .when::before { content: '🗓 '; }
|
|
74
|
+
.memo .meta .geo { color: var(--geo); }
|
|
75
|
+
.memo .meta .geo::before { content: '📍 '; }
|
|
76
|
+
.memo .meta .platform { opacity: 0.7; }
|
|
77
|
+
.memo .meta .expires { color: var(--warn); }
|
|
78
|
+
.memo .meta .expires::before { content: '⏳ '; }
|
|
79
|
+
.memo .maps { margin-top: 6px; font-size: 12px; display: flex; gap: 12px; flex-wrap: wrap; }
|
|
80
|
+
.memo .maps a { color: var(--accent); text-decoration: none; }
|
|
81
|
+
.memo .maps a:hover { text-decoration: underline; }
|
|
82
|
+
.actions { display: flex; gap: 6px; flex-shrink: 0; }
|
|
83
|
+
.btn {
|
|
84
|
+
padding: 5px 10px; border: 1px solid var(--border); border-radius: 5px;
|
|
85
|
+
background: transparent; color: var(--fg); cursor: pointer; font-size: 12px;
|
|
86
|
+
}
|
|
87
|
+
.btn:hover { border-color: var(--accent); color: var(--accent); }
|
|
88
|
+
.btn.danger:hover { border-color: var(--danger); color: var(--danger); }
|
|
89
|
+
.empty { color: var(--muted); text-align: center; padding: 60px 0; }
|
|
90
|
+
.toast {
|
|
91
|
+
position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%);
|
|
92
|
+
background: var(--card); border: 1px solid var(--border); padding: 10px 16px;
|
|
93
|
+
border-radius: 6px; font-size: 13px;
|
|
94
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
95
|
+
transition: opacity 0.2s;
|
|
96
|
+
}
|
|
97
|
+
.toast.error { color: var(--danger); border-color: var(--danger); }
|
|
98
|
+
@media (max-width: 600px) {
|
|
99
|
+
.memo { flex-direction: column; }
|
|
100
|
+
.actions { width: 100%; justify-content: flex-end; }
|
|
101
|
+
}
|
|
102
|
+
</style>
|
|
103
|
+
</head>
|
|
104
|
+
<body>
|
|
105
|
+
<header>
|
|
106
|
+
<h1>📋 Memos</h1>
|
|
107
|
+
<nav>
|
|
108
|
+
<a href="/">Chat</a>
|
|
109
|
+
<a href="/tasks">Tasks</a>
|
|
110
|
+
<a href="/reminders">Reminders</a>
|
|
111
|
+
<a href="/settings">Settings</a>
|
|
112
|
+
</nav>
|
|
113
|
+
</header>
|
|
114
|
+
<main>
|
|
115
|
+
<div class="toolbar">
|
|
116
|
+
<input type="text" id="q" placeholder="搜索内容(what / memo / who / 地址 …)" />
|
|
117
|
+
<button type="button" class="filter-btn active" data-filter="all">全部</button>
|
|
118
|
+
<button type="button" class="filter-btn" data-filter="geo">有位置</button>
|
|
119
|
+
<button type="button" class="filter-btn" data-filter="expired">已过期</button>
|
|
120
|
+
<span class="stats" id="stats"></span>
|
|
121
|
+
</div>
|
|
122
|
+
<div id="list"></div>
|
|
123
|
+
</main>
|
|
124
|
+
<div id="toast" class="toast" style="display:none"></div>
|
|
125
|
+
|
|
126
|
+
<script>
|
|
127
|
+
(() => {
|
|
128
|
+
const $list = document.getElementById('list')
|
|
129
|
+
const $toast = document.getElementById('toast')
|
|
130
|
+
const $q = document.getElementById('q')
|
|
131
|
+
const $stats = document.getElementById('stats')
|
|
132
|
+
let currentFilter = 'all'
|
|
133
|
+
let queryStr = ''
|
|
134
|
+
let debounceTimer = null
|
|
135
|
+
|
|
136
|
+
function toast(msg, isErr = false) {
|
|
137
|
+
$toast.textContent = msg
|
|
138
|
+
$toast.className = 'toast' + (isErr ? ' error' : '')
|
|
139
|
+
$toast.style.display = 'block'
|
|
140
|
+
setTimeout(() => { $toast.style.display = 'none' }, 2400)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function escapeHtml(s) {
|
|
144
|
+
if (s == null) return ''
|
|
145
|
+
return String(s)
|
|
146
|
+
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
147
|
+
.replace(/"/g, '"').replace(/'/g, ''')
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function fmtTime(iso) {
|
|
151
|
+
if (!iso) return ''
|
|
152
|
+
// memos use 'YYYY-MM-DD HH:MM:SS' (UTC+8 bare-local).
|
|
153
|
+
// Parse via Date and present as local. Worst case display drift is
|
|
154
|
+
// 0 (the user is also in UTC+8 because we already assume that).
|
|
155
|
+
const d = new Date(iso.replace(' ', 'T') + '+08:00')
|
|
156
|
+
if (Number.isNaN(d.getTime())) return iso
|
|
157
|
+
const now = new Date()
|
|
158
|
+
const diffMs = now.getTime() - d.getTime()
|
|
159
|
+
const absMin = Math.abs(Math.round(diffMs / 60000))
|
|
160
|
+
let rel = ''
|
|
161
|
+
if (Math.abs(diffMs) < 60_000) rel = '刚才'
|
|
162
|
+
else if (absMin < 60) rel = `${absMin} 分钟前`
|
|
163
|
+
else if (absMin < 1440) rel = `${(absMin / 60).toFixed(1)} 小时前`
|
|
164
|
+
else rel = `${(absMin / 1440).toFixed(1)} 天前`
|
|
165
|
+
return `${d.toLocaleString()} · ${rel}`
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function load() {
|
|
169
|
+
$list.innerHTML = '<div class="empty">加载中…</div>'
|
|
170
|
+
try {
|
|
171
|
+
const params = new URLSearchParams()
|
|
172
|
+
if (queryStr) params.set('query', queryStr)
|
|
173
|
+
if (currentFilter === 'geo') params.set('has_location', 'true')
|
|
174
|
+
if (currentFilter === 'expired') params.set('include_expired', 'true')
|
|
175
|
+
params.set('limit', '200')
|
|
176
|
+
const data = await window.imhub.api(`/api/memos?${params.toString()}`)
|
|
177
|
+
let items = data.memos || []
|
|
178
|
+
if (currentFilter === 'expired') {
|
|
179
|
+
// Only the rows that have an expires_at in the past.
|
|
180
|
+
const now = new Date()
|
|
181
|
+
items = items.filter(m => m.expiresAt && new Date(m.expiresAt.replace(' ', 'T') + '+08:00') < now)
|
|
182
|
+
}
|
|
183
|
+
render(items)
|
|
184
|
+
$stats.textContent = items.length ? `${items.length} 条` : ''
|
|
185
|
+
} catch (err) {
|
|
186
|
+
$list.innerHTML = ''
|
|
187
|
+
toast(`加载失败:${err.message}`, true)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function render(items) {
|
|
192
|
+
if (!items.length) {
|
|
193
|
+
$list.innerHTML = `<div class="empty">${queryStr ? '没匹配的 memo' : '还没记下任何 memo。在 IM 里说「记下…」让 agent 帮你存。'}</div>`
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
$list.innerHTML = items.map(m => {
|
|
197
|
+
const icon = m.where_lat != null ? '📍' : '📝'
|
|
198
|
+
const idLbl = `<span class="id">#${m.id}</span>`
|
|
199
|
+
const what = `<div class="what"><span class="icon">${icon}</span>${escapeHtml(m.what)} ${idLbl}</div>`
|
|
200
|
+
const original = (m.memo && m.memo !== m.what)
|
|
201
|
+
? `<div class="original">${escapeHtml(m.memo)}</div>` : ''
|
|
202
|
+
const metaBits = []
|
|
203
|
+
if (m.who) metaBits.push(`<span class="who">${escapeHtml(m.who)}</span>`)
|
|
204
|
+
if (m.whenAt) metaBits.push(`<span class="when">${escapeHtml(m.whenAt)}</span>`)
|
|
205
|
+
else if (m.whenText) metaBits.push(`<span class="when">${escapeHtml(m.whenText)}</span>`)
|
|
206
|
+
if (m.where_label) metaBits.push(`<span class="geo">${escapeHtml(m.where_label)}</span>`)
|
|
207
|
+
else if (m.where_lat != null) metaBits.push(`<span class="geo">${m.where_lat.toFixed(5)}, ${m.where_lng.toFixed(5)}</span>`)
|
|
208
|
+
if (m.platform) metaBits.push(`<span class="platform">${escapeHtml(m.platform)}</span>`)
|
|
209
|
+
if (m.expiresAt) metaBits.push(`<span class="expires">${escapeHtml(m.expiresAt)}</span>`)
|
|
210
|
+
metaBits.push(`<span class="when">${fmtTime(m.createdAt)}</span>`)
|
|
211
|
+
const meta = `<div class="meta">${metaBits.join('')}</div>`
|
|
212
|
+
|
|
213
|
+
let maps = ''
|
|
214
|
+
if (m.mapUrls) {
|
|
215
|
+
maps = `<div class="maps">
|
|
216
|
+
<a href="${m.mapUrls.baidu}" target="_blank">百度地图</a>
|
|
217
|
+
<a href="${m.mapUrls.amap}" target="_blank">高德地图</a>
|
|
218
|
+
<a href="${m.mapUrls.google}" target="_blank">Google</a>
|
|
219
|
+
</div>`
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return `<div class="memo" data-id="${m.id}">
|
|
223
|
+
<div class="body">${what}${original}${meta}${maps}</div>
|
|
224
|
+
<div class="actions">
|
|
225
|
+
<button type="button" class="btn danger" data-action="delete">删除</button>
|
|
226
|
+
</div>
|
|
227
|
+
</div>`
|
|
228
|
+
}).join('')
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
$list.addEventListener('click', async (e) => {
|
|
232
|
+
const btn = e.target.closest('button[data-action]')
|
|
233
|
+
if (!btn) return
|
|
234
|
+
const card = btn.closest('.memo')
|
|
235
|
+
if (!card) return
|
|
236
|
+
const id = card.dataset.id
|
|
237
|
+
const action = btn.dataset.action
|
|
238
|
+
if (action === 'delete') {
|
|
239
|
+
if (!confirm(`确定删除 memo #${id}?`)) return
|
|
240
|
+
try {
|
|
241
|
+
await window.imhub.api(`/api/memos/${id}`, { method: 'DELETE' })
|
|
242
|
+
toast(`已删除 #${id}`)
|
|
243
|
+
load()
|
|
244
|
+
} catch (err) { toast(`删除失败:${err.message}`, true) }
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
document.querySelectorAll('.filter-btn').forEach(btn => {
|
|
249
|
+
btn.addEventListener('click', () => {
|
|
250
|
+
document.querySelectorAll('.filter-btn').forEach(b => { b.classList.remove('active') })
|
|
251
|
+
btn.classList.add('active')
|
|
252
|
+
currentFilter = btn.dataset.filter
|
|
253
|
+
load()
|
|
254
|
+
})
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
$q.addEventListener('input', () => {
|
|
258
|
+
clearTimeout(debounceTimer)
|
|
259
|
+
debounceTimer = setTimeout(() => {
|
|
260
|
+
queryStr = $q.value.trim()
|
|
261
|
+
load()
|
|
262
|
+
}, 280)
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
load()
|
|
266
|
+
// Auto-refresh every 30s so newly-saved memos show up.
|
|
267
|
+
setInterval(load, 30_000)
|
|
268
|
+
})()
|
|
269
|
+
</script>
|
|
270
|
+
</body>
|
|
271
|
+
</html>
|