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,645 @@
|
|
|
1
|
+
// MCP sidecar — Claude Code 通过 --permission-prompt-tool 调用本进程的 `request` 工具,
|
|
2
|
+
// 本进程把请求转发给 im-hub 主进程的 approval-bus(unix socket),等用户决策回包后
|
|
3
|
+
// 翻译成 MCP tool result。
|
|
4
|
+
//
|
|
5
|
+
// 这是个独立进程,由 claude 子进程通过 --mcp-config 启动;与 im-hub 通信只走 socket。
|
|
6
|
+
// 启动需要两个 env:
|
|
7
|
+
// IMHUB_APPROVAL_SOCK unix socket 路径
|
|
8
|
+
// IMHUB_RUN_ID 本次 claude run 的 ID(与 approvalBus.registerRun 配套)
|
|
9
|
+
//
|
|
10
|
+
// 协议见 src/core/approval-bus.ts。
|
|
11
|
+
//
|
|
12
|
+
// 入口(编译后):node dist/plugins/agents/claude-code/mcp-approval-server.js
|
|
13
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
14
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import { createConnection } from 'node:net';
|
|
17
|
+
import { randomUUID } from 'node:crypto';
|
|
18
|
+
const SERVER_NAME = 'imhub';
|
|
19
|
+
const TOOL_NAME = 'request';
|
|
20
|
+
class ApprovalClient {
|
|
21
|
+
socketPath;
|
|
22
|
+
runId;
|
|
23
|
+
socket = null;
|
|
24
|
+
buf = '';
|
|
25
|
+
pending = new Map();
|
|
26
|
+
pendingReminders = new Map();
|
|
27
|
+
pendingMemos = new Map();
|
|
28
|
+
connectErr = null;
|
|
29
|
+
closed = false;
|
|
30
|
+
connectPromise;
|
|
31
|
+
constructor(socketPath, runId) {
|
|
32
|
+
this.socketPath = socketPath;
|
|
33
|
+
this.runId = runId;
|
|
34
|
+
this.connectPromise = this.connect();
|
|
35
|
+
}
|
|
36
|
+
connect() {
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
const sock = createConnection(this.socketPath);
|
|
39
|
+
sock.setEncoding('utf8');
|
|
40
|
+
const onConnectError = (err) => {
|
|
41
|
+
this.connectErr = err;
|
|
42
|
+
this.closed = true;
|
|
43
|
+
// stderr surfaces inside Claude Code's MCP log
|
|
44
|
+
process.stderr.write(`[mcp-approval-server] connect failed: ${err.message}\n`);
|
|
45
|
+
resolve();
|
|
46
|
+
};
|
|
47
|
+
sock.once('error', onConnectError);
|
|
48
|
+
sock.once('connect', () => {
|
|
49
|
+
sock.removeListener('error', onConnectError);
|
|
50
|
+
sock.on('error', (err) => {
|
|
51
|
+
process.stderr.write(`[mcp-approval-server] socket error: ${err.message}\n`);
|
|
52
|
+
});
|
|
53
|
+
sock.on('data', (chunk) => this.onData(chunk));
|
|
54
|
+
sock.on('close', () => this.onClose());
|
|
55
|
+
this.socket = sock;
|
|
56
|
+
resolve();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
onData(chunk) {
|
|
61
|
+
this.buf += chunk;
|
|
62
|
+
while (true) {
|
|
63
|
+
const nl = this.buf.indexOf('\n');
|
|
64
|
+
if (nl === -1)
|
|
65
|
+
break;
|
|
66
|
+
const line = this.buf.slice(0, nl);
|
|
67
|
+
this.buf = this.buf.slice(nl + 1);
|
|
68
|
+
if (!line)
|
|
69
|
+
continue;
|
|
70
|
+
let msg;
|
|
71
|
+
try {
|
|
72
|
+
msg = JSON.parse(line);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
process.stderr.write(`[mcp-approval-server] bad json from bus: ${line.slice(0, 200)}\n`);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
this.dispatch(msg);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
dispatch(msg) {
|
|
82
|
+
if (!msg || typeof msg !== 'object')
|
|
83
|
+
return;
|
|
84
|
+
const m = msg;
|
|
85
|
+
if (m.v !== 1)
|
|
86
|
+
return;
|
|
87
|
+
if (m.type === 'decision') {
|
|
88
|
+
const reqId = typeof m.reqId === 'string' ? m.reqId : null;
|
|
89
|
+
if (!reqId)
|
|
90
|
+
return;
|
|
91
|
+
const p = this.pending.get(reqId);
|
|
92
|
+
if (!p)
|
|
93
|
+
return;
|
|
94
|
+
this.pending.delete(reqId);
|
|
95
|
+
if (m.behavior === 'allow') {
|
|
96
|
+
const updatedInput = (m.updatedInput && typeof m.updatedInput === 'object' && !Array.isArray(m.updatedInput))
|
|
97
|
+
? m.updatedInput
|
|
98
|
+
: p.originalInput; // Claude Code requires updatedInput; echo original
|
|
99
|
+
p.resolve({ behavior: 'allow', updatedInput });
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
const message = typeof m.message === 'string' ? m.message : undefined;
|
|
103
|
+
p.resolve({ behavior: 'deny', ...(message ? { message } : {}) });
|
|
104
|
+
}
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (m.type === 'reminder.result') {
|
|
108
|
+
const reqId = typeof m.reqId === 'string' ? m.reqId : null;
|
|
109
|
+
if (!reqId)
|
|
110
|
+
return;
|
|
111
|
+
const p = this.pendingReminders.get(reqId);
|
|
112
|
+
if (!p)
|
|
113
|
+
return;
|
|
114
|
+
this.pendingReminders.delete(reqId);
|
|
115
|
+
const ok = m.ok === true;
|
|
116
|
+
if (ok) {
|
|
117
|
+
p.resolve({ ok: true, result: m.result });
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
const error = typeof m.error === 'string' ? m.error : 'unknown error';
|
|
121
|
+
p.resolve({ ok: false, error });
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (m.type === 'memo.result') {
|
|
126
|
+
const reqId = typeof m.reqId === 'string' ? m.reqId : null;
|
|
127
|
+
if (!reqId)
|
|
128
|
+
return;
|
|
129
|
+
const p = this.pendingMemos.get(reqId);
|
|
130
|
+
if (!p)
|
|
131
|
+
return;
|
|
132
|
+
this.pendingMemos.delete(reqId);
|
|
133
|
+
const ok = m.ok === true;
|
|
134
|
+
if (ok) {
|
|
135
|
+
p.resolve({ ok: true, result: m.result });
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
const error = typeof m.error === 'string' ? m.error : 'unknown error';
|
|
139
|
+
p.resolve({ ok: false, error });
|
|
140
|
+
}
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
onClose() {
|
|
145
|
+
this.closed = true;
|
|
146
|
+
// Drain pending with deny — claude is left hanging otherwise
|
|
147
|
+
for (const [, p] of this.pending) {
|
|
148
|
+
p.resolve({ behavior: 'deny', message: 'approval bus disconnected' });
|
|
149
|
+
}
|
|
150
|
+
this.pending.clear();
|
|
151
|
+
for (const [, p] of this.pendingReminders) {
|
|
152
|
+
p.resolve({ ok: false, error: 'approval bus disconnected' });
|
|
153
|
+
}
|
|
154
|
+
this.pendingReminders.clear();
|
|
155
|
+
for (const [, p] of this.pendingMemos) {
|
|
156
|
+
p.resolve({ ok: false, error: 'approval bus disconnected' });
|
|
157
|
+
}
|
|
158
|
+
this.pendingMemos.clear();
|
|
159
|
+
}
|
|
160
|
+
// request(): see below — request → register pending → write payload
|
|
161
|
+
/**
|
|
162
|
+
* Send an approval request and wait for the decision. If the bus is
|
|
163
|
+
* unreachable or the connection has dropped, returns a deny synchronously.
|
|
164
|
+
*/
|
|
165
|
+
async request(args) {
|
|
166
|
+
await this.connectPromise;
|
|
167
|
+
if (this.connectErr || this.closed || !this.socket) {
|
|
168
|
+
return { behavior: 'deny', message: `approval bus unavailable: ${this.connectErr?.message ?? 'closed'}` };
|
|
169
|
+
}
|
|
170
|
+
const reqId = randomUUID();
|
|
171
|
+
const payload = `${JSON.stringify({
|
|
172
|
+
v: 1,
|
|
173
|
+
type: 'approval',
|
|
174
|
+
runId: this.runId,
|
|
175
|
+
reqId,
|
|
176
|
+
toolName: args.toolName,
|
|
177
|
+
input: args.input,
|
|
178
|
+
toolUseId: args.toolUseId,
|
|
179
|
+
})}\n`;
|
|
180
|
+
return new Promise((resolve) => {
|
|
181
|
+
this.pending.set(reqId, { resolve, originalInput: args.input });
|
|
182
|
+
this.socket?.write(payload, (err) => {
|
|
183
|
+
if (err) {
|
|
184
|
+
this.pending.delete(reqId);
|
|
185
|
+
resolve({ behavior: 'deny', message: `write failed: ${err.message}` });
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Send a reminder RPC and wait for the result. Same socket as approvals,
|
|
192
|
+
* different message type. Bus delegates to reminder-rpc.ts which actually
|
|
193
|
+
* touches reminders.db.
|
|
194
|
+
*/
|
|
195
|
+
async requestReminder(op, payload) {
|
|
196
|
+
await this.connectPromise;
|
|
197
|
+
if (this.connectErr || this.closed || !this.socket) {
|
|
198
|
+
return { ok: false, error: `bus unavailable: ${this.connectErr?.message ?? 'closed'}` };
|
|
199
|
+
}
|
|
200
|
+
const reqId = randomUUID();
|
|
201
|
+
const wire = `${JSON.stringify({
|
|
202
|
+
v: 1,
|
|
203
|
+
type: 'reminder',
|
|
204
|
+
runId: this.runId,
|
|
205
|
+
reqId,
|
|
206
|
+
op,
|
|
207
|
+
payload,
|
|
208
|
+
})}\n`;
|
|
209
|
+
return new Promise((resolve) => {
|
|
210
|
+
this.pendingReminders.set(reqId, { resolve });
|
|
211
|
+
this.socket?.write(wire, (err) => {
|
|
212
|
+
if (err) {
|
|
213
|
+
this.pendingReminders.delete(reqId);
|
|
214
|
+
resolve({ ok: false, error: `write failed: ${err.message}` });
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
/** Same shape as requestReminder, different message type. Bus delegates
|
|
220
|
+
* to memo-rpc.ts which actually writes memos.db. */
|
|
221
|
+
async requestMemo(op, payload) {
|
|
222
|
+
await this.connectPromise;
|
|
223
|
+
if (this.connectErr || this.closed || !this.socket) {
|
|
224
|
+
return { ok: false, error: `bus unavailable: ${this.connectErr?.message ?? 'closed'}` };
|
|
225
|
+
}
|
|
226
|
+
const reqId = randomUUID();
|
|
227
|
+
const wire = `${JSON.stringify({
|
|
228
|
+
v: 1,
|
|
229
|
+
type: 'memo',
|
|
230
|
+
runId: this.runId,
|
|
231
|
+
reqId,
|
|
232
|
+
op,
|
|
233
|
+
payload,
|
|
234
|
+
})}\n`;
|
|
235
|
+
return new Promise((resolve) => {
|
|
236
|
+
this.pendingMemos.set(reqId, { resolve });
|
|
237
|
+
this.socket?.write(wire, (err) => {
|
|
238
|
+
if (err) {
|
|
239
|
+
this.pendingMemos.delete(reqId);
|
|
240
|
+
resolve({ ok: false, error: `write failed: ${err.message}` });
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
async close() {
|
|
246
|
+
this.closed = true;
|
|
247
|
+
if (this.socket && !this.socket.destroyed) {
|
|
248
|
+
await new Promise((resolve) => {
|
|
249
|
+
this.socket?.once('close', () => resolve());
|
|
250
|
+
this.socket?.end();
|
|
251
|
+
setTimeout(() => { if (this.socket && !this.socket.destroyed)
|
|
252
|
+
this.socket.destroy(); }, 200).unref();
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Build the MCP server. Exposed as a function (rather than top-level `await`)
|
|
259
|
+
* so tests can construct it without spinning up stdio.
|
|
260
|
+
*/
|
|
261
|
+
export function buildServer(client) {
|
|
262
|
+
const server = new McpServer({
|
|
263
|
+
name: SERVER_NAME,
|
|
264
|
+
version: '0.1.0',
|
|
265
|
+
});
|
|
266
|
+
// Accept both snake_case (what Claude Code sends over the wire) and
|
|
267
|
+
// camelCase (defensive — some forks normalize). passthrough so unknown
|
|
268
|
+
// future fields are not stripped before we see them.
|
|
269
|
+
const inputSchema = {
|
|
270
|
+
tool_name: z.string().optional(),
|
|
271
|
+
toolName: z.string().optional(),
|
|
272
|
+
input: z.record(z.string(), z.unknown()).optional(),
|
|
273
|
+
tool_use_id: z.string().optional(),
|
|
274
|
+
toolUseId: z.string().optional(),
|
|
275
|
+
};
|
|
276
|
+
server.registerTool(TOOL_NAME, {
|
|
277
|
+
title: 'IM hub permission prompt',
|
|
278
|
+
description: 'Routes Claude Code permission prompts to im-hub for human approval over IM. ' +
|
|
279
|
+
'Returns {behavior: "allow"|"deny", ...} as a JSON-encoded text block.',
|
|
280
|
+
inputSchema,
|
|
281
|
+
}, async (args) => {
|
|
282
|
+
const toolName = args.tool_name ?? args.toolName ?? '<unknown>';
|
|
283
|
+
const input = (args.input ?? {});
|
|
284
|
+
const toolUseId = args.tool_use_id ?? args.toolUseId ?? '';
|
|
285
|
+
// Auto-allow im-hub's own MCP tools. These are user-scoped, idempotent,
|
|
286
|
+
// and easily reversible via /remind cancel — asking the user to
|
|
287
|
+
// approve "do you really want this reminder you literally just asked
|
|
288
|
+
// for" is double-confirmation and clutters the chat. The tool body
|
|
289
|
+
// itself runs through bus.handleReminder which validates payloads.
|
|
290
|
+
if (toolName.startsWith('mcp__imhub__')) {
|
|
291
|
+
return {
|
|
292
|
+
content: [
|
|
293
|
+
{
|
|
294
|
+
type: 'text',
|
|
295
|
+
text: JSON.stringify({ behavior: 'allow', updatedInput: input }),
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
const decision = await client.request({ toolName, input, toolUseId });
|
|
301
|
+
return {
|
|
302
|
+
content: [
|
|
303
|
+
{ type: 'text', text: JSON.stringify(decision) },
|
|
304
|
+
],
|
|
305
|
+
};
|
|
306
|
+
});
|
|
307
|
+
// ─── Reminder tools ───────────────────────────────────────────────
|
|
308
|
+
// These let Claude create / list / cancel / snooze reminders for the
|
|
309
|
+
// current IM user without going back to the user with a slash command.
|
|
310
|
+
// Bus uses runId → RunContext to know which user/thread the call belongs
|
|
311
|
+
// to. All four tools return JSON-encoded text blocks; the result schema
|
|
312
|
+
// is `{ok: true, result: {...}} | {ok: false, error: string}`.
|
|
313
|
+
//
|
|
314
|
+
// `_im_context` is a single-user fallback for adapter setups where the
|
|
315
|
+
// MCP server is shared (e.g. opencode http daemon — see ensure-mcp-config.ts):
|
|
316
|
+
// the runId env var was set when opencode serve started and is the SAME
|
|
317
|
+
// for all sessions, so we can't disambiguate via runId. Instead the agent
|
|
318
|
+
// is instructed (via prompt injection) to pass an `_im_context` block,
|
|
319
|
+
// which the bus uses iff the runId lookup fails. Untrusted in multi-user
|
|
320
|
+
// deployments — operators must understand the trust model.
|
|
321
|
+
const imContextSchema = z.object({
|
|
322
|
+
platform: z.string(),
|
|
323
|
+
threadId: z.string(),
|
|
324
|
+
channelId: z.string(),
|
|
325
|
+
userId: z.string().optional(),
|
|
326
|
+
}).optional().describe('IM context override. Only set this when the system prompt explicitly tells you to. ' +
|
|
327
|
+
'Otherwise omit and the server figures it out via runId.');
|
|
328
|
+
const wrapReminder = (op) => async (args) => {
|
|
329
|
+
const result = await client.requestReminder(op, args);
|
|
330
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
331
|
+
};
|
|
332
|
+
const wrapMemo = (op) => async (args) => {
|
|
333
|
+
const result = await client.requestMemo(op, args);
|
|
334
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
335
|
+
};
|
|
336
|
+
server.registerTool('create_reminder', {
|
|
337
|
+
title: 'Create a reminder',
|
|
338
|
+
description: 'Create a one-shot or recurring reminder for the current user. CALL THIS PROACTIVELY ' +
|
|
339
|
+
'whenever the user mentions a future commitment, event, task, or anything they might ' +
|
|
340
|
+
'want to be reminded about — including casual mentions like "明天中午要开会", ' +
|
|
341
|
+
'"下周三去医院复查", or explicit asks like "提醒我30分钟后喝水". ' +
|
|
342
|
+
'The reminder will fire at fireAt and be delivered to this same IM thread. ' +
|
|
343
|
+
'After creating, briefly acknowledge to the user (e.g. "✅ 已为你设了提醒,明天12点 团队聚餐"). ' +
|
|
344
|
+
'For recurring: use "every:5m", "daily:08:00", or "weekly:1,3,5:09:00". ' +
|
|
345
|
+
'High-frequency (interval < 1h) + LLM polish is auto-confirmed via card; ' +
|
|
346
|
+
'agent should keep its reply terse in that case.',
|
|
347
|
+
inputSchema: {
|
|
348
|
+
fireAt: z.string().describe('First fire time as ISO 8601 local-time, e.g. "2026-05-10T12:00:00"'),
|
|
349
|
+
text: z.string().describe('What to remind the user about, ≤ 60 chars. Just the activity, not the time.'),
|
|
350
|
+
recurrence: z.string().optional().describe('Optional. "every:5m" | "daily:HH:MM" | "weekly:1,3,5:HH:MM"'),
|
|
351
|
+
promptMode: z.enum(['literal', 'llm']).optional().describe('Default "llm" (LLM polishes the reminder text at fire time). Pass "literal" for verbatim delivery.'),
|
|
352
|
+
_im_context: imContextSchema,
|
|
353
|
+
},
|
|
354
|
+
}, wrapReminder('create'));
|
|
355
|
+
server.registerTool('list_reminders', {
|
|
356
|
+
title: 'List reminders',
|
|
357
|
+
description: 'List the current user\'s pending reminders. Use this when the user asks "我有什么提醒" / ' +
|
|
358
|
+
'"接下来要做什么" or before suggesting cancel/snooze.',
|
|
359
|
+
inputSchema: { _im_context: imContextSchema },
|
|
360
|
+
}, wrapReminder('list'));
|
|
361
|
+
server.registerTool('cancel_reminder', {
|
|
362
|
+
title: 'Cancel a reminder',
|
|
363
|
+
description: 'Cancel a pending reminder by id. Find ids via list_reminders. For recurring reminders, ' +
|
|
364
|
+
'this terminates the entire loop.',
|
|
365
|
+
inputSchema: {
|
|
366
|
+
id: z.number().int().positive().describe('Reminder id from list_reminders'),
|
|
367
|
+
_im_context: imContextSchema,
|
|
368
|
+
},
|
|
369
|
+
}, wrapReminder('cancel'));
|
|
370
|
+
server.registerTool('snooze_reminder', {
|
|
371
|
+
title: 'Snooze a reminder',
|
|
372
|
+
description: 'Push a reminder back by a duration ("5m", "30m", "2h"). Creates a new reminder with the ' +
|
|
373
|
+
'same text and cancels the original.',
|
|
374
|
+
inputSchema: {
|
|
375
|
+
id: z.number().int().positive().describe('Reminder id to snooze'),
|
|
376
|
+
duration: z.string().describe('Duration like "5m" / "30m" / "2h" / "1d"'),
|
|
377
|
+
_im_context: imContextSchema,
|
|
378
|
+
},
|
|
379
|
+
}, wrapReminder('snooze'));
|
|
380
|
+
// ─── Memo tools (5W1H persistent memory) ─────────────────────────────
|
|
381
|
+
// Generalized "记下来" memory database. Each memo carries optional 5W1H
|
|
382
|
+
// fields — what (REQUIRED), who, when_at/when_text, where_lat/lng/label,
|
|
383
|
+
// how, why. Plus expires_at (NULL = permanent). Five tools:
|
|
384
|
+
//
|
|
385
|
+
// save_memo agent extracts whatever 5W1H it can from
|
|
386
|
+
// the user's natural language and persists.
|
|
387
|
+
// request_location_capture one-time HTTPS link for browser GPS;
|
|
388
|
+
// creates a NEW memo OR augments an
|
|
389
|
+
// existing memo's where_*. Result delivery
|
|
390
|
+
// is async — im-hub pushes "✅ 已记下..."
|
|
391
|
+
// to the IM thread once coords arrive.
|
|
392
|
+
// search_memos recall: free-text + structured filters.
|
|
393
|
+
// update_memo patch an existing memo when user adds
|
|
394
|
+
// context after the initial save.
|
|
395
|
+
// delete_memo drop one memo by id.
|
|
396
|
+
server.registerTool('save_memo', {
|
|
397
|
+
title: 'Save a memo (5W1H persistent record)',
|
|
398
|
+
description: 'Record any kind of memo for the user — "请记下" / "帮我记一下" / "别忘了" / "重要的事". ' +
|
|
399
|
+
'Extract 5W1H from the user\'s message: what (the core thing — REQUIRED), who (person/org), ' +
|
|
400
|
+
'when_at (parseable datetime) or when_text (raw phrase if not parseable), where_lat/lng + ' +
|
|
401
|
+
'where_label OR address (server geocodes), how (manner), why (reason). Examples:\n' +
|
|
402
|
+
' "我爸爸的生日是5月8日" → { what: "生日", who: "爸爸", when_text: "5月8日" }\n' +
|
|
403
|
+
' "明天下午3点开会" → { what: "开会", when_at: "<2026-05-11 15:00:00>" }\n' +
|
|
404
|
+
' "我朋友的茶馆在 X 路 Y 号" → { what: "茶馆", who: "朋友", address: "X路Y号" } [PERMANENT]\n' +
|
|
405
|
+
' "苹果今年发了AVP2" → { what: "AVP2", who: "苹果" }\n' +
|
|
406
|
+
' "国贸三期是公司新址" → { what: "公司新址", address: "国贸三期" } (geocoded)\n' +
|
|
407
|
+
' "我把车停在地下B区了" → DO NOT call save_memo — use request_location_capture\n\n' +
|
|
408
|
+
'⏰ TIMEZONE: ALL times are interpreted as Asia/Shanghai (UTC+8). When the user says "明天" ' +
|
|
409
|
+
'"下午3点" "下周" etc., compute the absolute datetime in UTC+8 and format as ' +
|
|
410
|
+
'"YYYY-MM-DD HH:MM:SS" (no T, no offset suffix — bare local). Do NOT use ISO with `Z` or ' +
|
|
411
|
+
'`+00:00` — that would store UTC and display 8h off in CN. Server normalizes "+08:00" / "Z" ' +
|
|
412
|
+
'inputs to local for safety, but emit local directly.\n\n' +
|
|
413
|
+
'⚠️ EXPIRY (this is subtle — read carefully):\n' +
|
|
414
|
+
'Default = PERMANENT. Only set expires_in_hours when the memo is genuinely transient. ' +
|
|
415
|
+
'The signal is the SEMANTICS of the user\'s words, NOT whether the memo has location.\n\n' +
|
|
416
|
+
' TRANSIENT (set expires_in_hours):\n' +
|
|
417
|
+
' • "刚刚 / 刚才 / 暂时 / 临时 / 今天 / 这次" + 状态描述\n' +
|
|
418
|
+
' • "我把车停在这了" (parking — typically 24)\n' +
|
|
419
|
+
' • "我把伞放在前台了" (today\'s ad-hoc placement — 24)\n' +
|
|
420
|
+
' • "今天的会议在 3 楼" (one-day-relevant — 24)\n\n' +
|
|
421
|
+
' PERMANENT (omit expires_in_hours):\n' +
|
|
422
|
+
' • "X 是我朋友常去的茶馆" / "X 是我们老地方" → 永久存(即使有 location!)\n' +
|
|
423
|
+
' • "我家在 X" / "我公司在 Y" → 永久\n' +
|
|
424
|
+
' • "爸爸生日是..." / "妈妈电话是..." → 永久\n' +
|
|
425
|
+
' • Anything user explicitly says "永久 / 记住 / 总是 / 重要" → 永久\n\n' +
|
|
426
|
+
'When ambiguous, ASK the user: "这个要永久记还是 24h 后忘掉?" then use the answer. ' +
|
|
427
|
+
'NEVER guess "transient" just because there\'s a location — friends\' regular hangouts, ' +
|
|
428
|
+
'home/office addresses, favorite places are all permanent.\n\n' +
|
|
429
|
+
'IF the user wants to record their CURRENT GPS location ("我把车停这" / "记一下我现在 ' +
|
|
430
|
+
'的位置"), DO NOT call save_memo — call request_location_capture instead (it can take a ' +
|
|
431
|
+
'`what` arg to label the new memo at capture time).\n\n' +
|
|
432
|
+
'📍 LOCATION ANNOTATION (Telegram / Feishu native pin or venue share):\n' +
|
|
433
|
+
'If the user\'s message STARTS with a tag like\n' +
|
|
434
|
+
' [user just shared location: lat=30.27, lng=120.12, name="黄龙国际中心", address="学院路77号", accuracy_m=5]\n' +
|
|
435
|
+
'...the adapter received a native GPS pin and stashed the coords here. The follow-up text\n' +
|
|
436
|
+
'after the annotation is the user\'s actual instruction. Common patterns:\n' +
|
|
437
|
+
' • "记下/记一下/帮我记 X" → save_memo({what: <extract from text>, where_lat, where_lng,\n' +
|
|
438
|
+
' where_label: <name + address if both present, joined by " · ">})\n' +
|
|
439
|
+
' • "这是我公司/家/...的地方" → save_memo(same — use the noun the user named)\n' +
|
|
440
|
+
' • "这是哪里?" → answer the question; the venue name/address in the annotation IS the\n' +
|
|
441
|
+
' answer. No save_memo needed.\n' +
|
|
442
|
+
' • "不用" / silence on a new topic → ignore the location, just respond.\n' +
|
|
443
|
+
'DO NOT call request_location_capture here — the coords are ALREADY provided. Use lat/lng\n' +
|
|
444
|
+
'from the annotation directly via where_lat/where_lng. Do NOT echo the raw annotation\n' +
|
|
445
|
+
'back to the user; it\'s for you, not them.\n\n' +
|
|
446
|
+
'🧭 PROACTIVE FOLLOW-UP for place-like memos:\n' +
|
|
447
|
+
'When the memo what is clearly a PLACE (家/公司/茶馆/餐厅/酒店/朋友的工作室/老孙家 ' +
|
|
448
|
+
'etc.) AND the user did NOT supply where_lat/lng/address, AFTER saving, ASK ONE short ' +
|
|
449
|
+
'clarifying question, e.g.:\n' +
|
|
450
|
+
' "记下了 ✅ 老孙家(常聚会的地方),永久保存。\n' +
|
|
451
|
+
' 要不要顺带补个坐标?\n' +
|
|
452
|
+
' • 我现在就在那 → 抓 GPS\n' +
|
|
453
|
+
' • 告诉你地址 → 帮你解析\n' +
|
|
454
|
+
' • 不用了"\n' +
|
|
455
|
+
'Then route the answer into the right tool (see "TOOL INVENTORY" below).\n' +
|
|
456
|
+
'Skip this for non-place memos (生日 / 联系方式 / 新闻条目 / preferences / 任何抽象事物).\n\n' +
|
|
457
|
+
'🧰 TOOL INVENTORY (you have these RIGHT NOW — do NOT tell the user any of them is gone):\n' +
|
|
458
|
+
' • save_memo with `address` arg — geocode + save in one shot (this tool, address path)\n' +
|
|
459
|
+
' • request_location_capture({what?, memo_id?}) — GPS via H5 link\n' +
|
|
460
|
+
' - {what} → creates a new memo at capture time\n' +
|
|
461
|
+
' - {memo_id} → AUGMENTS an existing memo (use this to fill where_* on a memo\n' +
|
|
462
|
+
' you already saved without coords)\n' +
|
|
463
|
+
' • update_memo({id, address}) — geocode + patch existing memo\'s where_*\n' +
|
|
464
|
+
' • update_memo({id, where_lat, where_lng, where_label}) — patch directly\n\n' +
|
|
465
|
+
'Returns the saved memo summary including id, fields, and (if where_* set) mapUrls. ' +
|
|
466
|
+
'Confirm to the user with one sentence + (if where_* set) the map links using markdown ' +
|
|
467
|
+
'`[百度地图](url) · [高德地图](url) · [Google](url)`. Do NOT print raw URLs.',
|
|
468
|
+
inputSchema: {
|
|
469
|
+
what: z.string().describe('Core thing being recorded (REQUIRED). ≤200 chars'),
|
|
470
|
+
who: z.string().optional().describe('Person/org/role involved (e.g. "爸爸", "团队")'),
|
|
471
|
+
when_at: z.string().optional().describe('Asia/Shanghai (UTC+8) datetime, format "YYYY-MM-DD HH:MM:SS" (no T, no offset)'),
|
|
472
|
+
when_text: z.string().optional().describe('Raw user phrase if when_at not parseable, e.g. "明年5月" / "下个月底"'),
|
|
473
|
+
where_lat: z.number().min(-90).max(90).optional().describe('WGS-84 latitude (pair with where_lng)'),
|
|
474
|
+
where_lng: z.number().min(-180).max(180).optional().describe('WGS-84 longitude'),
|
|
475
|
+
where_label: z.string().optional().describe('Place name / address text'),
|
|
476
|
+
address: z.string().optional().describe('Free-text address — geocoded server-side via Baidu when where_lat/lng absent'),
|
|
477
|
+
how: z.string().optional().describe('Manner / process'),
|
|
478
|
+
why: z.string().optional().describe('Reason / motivation'),
|
|
479
|
+
memo: z.string().optional().describe('Free-text full intent — preserves the user\'s complete phrasing when `what` is a ' +
|
|
480
|
+
'shorter extracted noun. Set this when the user said something longer than the noun ' +
|
|
481
|
+
'you captured in `what` (e.g. what="车", memo="我车暂时停这里,晚点过来取"). ' +
|
|
482
|
+
'Searchable via search_memos query. Omit when `what` already captures the full intent.'),
|
|
483
|
+
expires_in_hours: z.number().positive().optional().describe('Auto-expire in N hours. Omit for permanent.'),
|
|
484
|
+
_im_context: imContextSchema,
|
|
485
|
+
},
|
|
486
|
+
}, wrapMemo('save'));
|
|
487
|
+
server.registerTool('request_location_capture', {
|
|
488
|
+
title: 'Get user\'s current device GPS via one-time link',
|
|
489
|
+
description: 'Generate a one-time HTTPS link that opens a page asking for browser geolocation. ' +
|
|
490
|
+
'CALL THIS when the user wants to record where they ARE RIGHT NOW: "我把车停这了" / ' +
|
|
491
|
+
'"记一下我现在的位置" / "伞放这儿了,记一下". Two modes:\n\n' +
|
|
492
|
+
' 1. Create new memo (pass `what`): the H5 callback creates a fresh memo with ' +
|
|
493
|
+
' where_lat/lng + the what label. Use when this is the first time the topic is ' +
|
|
494
|
+
' being captured.\n' +
|
|
495
|
+
' 2. Update existing memo (pass `memo_id`): the callback patches an existing memo\'s ' +
|
|
496
|
+
' where_* fields. Use after save_memo when you saved the structural info but ' +
|
|
497
|
+
' still need GPS.\n\n' +
|
|
498
|
+
'Returns { url, expiresAt, ttlSeconds, what?, memoId? }. Reply to the user with ' +
|
|
499
|
+
'markdown link syntax `[👉 点击共享当前位置](url)` on its own line so iLink renders ' +
|
|
500
|
+
'a tappable label (the URL itself stays hidden). Do NOT print the raw URL.\n\n' +
|
|
501
|
+
'After the user taps and grants permission, im-hub pushes a "✅ 已记下..." confirmation ' +
|
|
502
|
+
'to this thread directly — you do NOT need to wait. Link is single-use and expires in ' +
|
|
503
|
+
'10 minutes. EXPIRY for the memo itself is set via save_memo separately if needed; ' +
|
|
504
|
+
'capture-flow memos default to permanent unless you call save_memo first with ' +
|
|
505
|
+
'expires_in_hours then attach via memo_id here.',
|
|
506
|
+
inputSchema: {
|
|
507
|
+
what: z.string().optional().describe('Short label for what is being recorded (e.g. "车", "伞"). Used as the new memo\'s what field. ≤80 chars. Mutually exclusive with memo_id.'),
|
|
508
|
+
memo_id: z.number().int().positive().optional().describe('Existing memo id to augment with GPS instead of creating a new one. Mutually exclusive with what.'),
|
|
509
|
+
_im_context: imContextSchema,
|
|
510
|
+
},
|
|
511
|
+
}, wrapMemo('request_capture'));
|
|
512
|
+
server.registerTool('search_memos', {
|
|
513
|
+
title: 'Search the user\'s memos',
|
|
514
|
+
description: 'Recall memos for ANY query the user makes about their saved knowledge: "我的车在哪" / ' +
|
|
515
|
+
'"我爸爸的生日" / "上周记了什么" / "找下AVP2那条". Combines free-text query with optional ' +
|
|
516
|
+
'structured filters; all filters AND-combine. Empty query returns most recent.\n\n' +
|
|
517
|
+
'Examples:\n' +
|
|
518
|
+
' "我的车在哪?" → { query: "车", has_location: true }\n' +
|
|
519
|
+
' "我爸爸生日是哪天?" → { who: "爸爸", what: "生日" }\n' +
|
|
520
|
+
' "今天记了什么?" → { when_after: "<2026-05-11 00:00:00>" } (UTC+8)\n' +
|
|
521
|
+
' "找下苹果发布会" → { query: "苹果发布会" }\n\n' +
|
|
522
|
+
'Returns { items: [{ id, what, who, whenAt/whenText, where: { lat, lng, label, mapUrl, ' +
|
|
523
|
+
'mapUrls } if location set, how, why, memo (full user phrasing when set), expiresAt, ' +
|
|
524
|
+
'createdAt }] }. Format the answer naturally for the user: 1-2 sentences summarizing the ' +
|
|
525
|
+
'find + (if where set) all three map URLs using markdown links `[百度地图](url) · ' +
|
|
526
|
+
'[高德地图](url) · [Google](url)`. When `memo` is set on the match (the full original ' +
|
|
527
|
+
'phrasing), quote it briefly so the user recognizes the entry. Do NOT print raw URLs. ' +
|
|
528
|
+
'If multiple matches, lead with the most recent.',
|
|
529
|
+
inputSchema: {
|
|
530
|
+
query: z.string().optional().describe('Free-text — fuzzy LIKE match across what/who/where_label/how/why/when_text/memo'),
|
|
531
|
+
who: z.string().optional().describe('Filter by who field (LIKE match)'),
|
|
532
|
+
what: z.string().optional().describe('Filter by what field (LIKE match)'),
|
|
533
|
+
has_location: z.boolean().optional().describe('When true, only memos with where_lat set'),
|
|
534
|
+
when_after: z.string().optional().describe('Asia/Shanghai (UTC+8) datetime — memos with when_at OR created_at >= this. Format "YYYY-MM-DD HH:MM:SS"'),
|
|
535
|
+
when_before: z.string().optional().describe('Asia/Shanghai (UTC+8) datetime — memos with when_at OR created_at <= this'),
|
|
536
|
+
include_expired: z.boolean().optional().describe('Include expired memos in results (default false)'),
|
|
537
|
+
limit: z.number().int().min(1).max(50).optional().describe('Max rows (default 10)'),
|
|
538
|
+
_im_context: imContextSchema,
|
|
539
|
+
},
|
|
540
|
+
}, wrapMemo('search'));
|
|
541
|
+
server.registerTool('update_memo', {
|
|
542
|
+
title: 'Patch fields on an existing memo',
|
|
543
|
+
description: 'Update ANY 5W1H field on an existing memo. CALL THIS when the user adds info to a ' +
|
|
544
|
+
'previously-saved memo: "对了,那个会议在 3 楼 A 区" → update_memo({ id, where_label: ' +
|
|
545
|
+
'"3楼A区" }). Or to extend / shorten the expiry: "把车那条改成永久" → update_memo({ ' +
|
|
546
|
+
'id, expires_at: null }).\n\n' +
|
|
547
|
+
'Pass null to a field to CLEAR it (vs omitting which leaves alone). For expiry, you ' +
|
|
548
|
+
'can pass either expires_in_hours (relative) or expires_at (absolute ISO; null clears).\n\n' +
|
|
549
|
+
'🌍 ADDRESS PATH: when the user gives you a textual address ("在国贸三期" / "北京天安门"), ' +
|
|
550
|
+
'pass `address` and the server will geocode it via Baidu Maps + populate where_lat/lng/' +
|
|
551
|
+
'label in one shot. Use this for the "place-memo augment" flow — after save_memo of a ' +
|
|
552
|
+
'place without coords, the user replies with an address → call update_memo({id, address}). ' +
|
|
553
|
+
'If `address` is provided AND where_lat/lng are NOT explicitly set, the geocoded coords ' +
|
|
554
|
+
'fill them. If you also pass where_label, it overrides the geocoded one (so user\'s ' +
|
|
555
|
+
'"老孙家" beats Baidu\'s "X街 Y号").\n\n' +
|
|
556
|
+
'📍 GPS PATH: if the user is AT the place right now ("我现在就在那"), do NOT use ' +
|
|
557
|
+
'update_memo — call request_location_capture({memo_id}) instead, which sends a ' +
|
|
558
|
+
'one-time browser-GPS link. The H5 callback patches the existing memo\'s where_*.\n\n' +
|
|
559
|
+
'Returns the updated memo summary. Confirm to the user with one sentence + (if where_* ' +
|
|
560
|
+
'now set) the markdown map links.',
|
|
561
|
+
inputSchema: {
|
|
562
|
+
id: z.number().int().positive().describe('Memo id from search_memos'),
|
|
563
|
+
what: z.string().optional(),
|
|
564
|
+
who: z.string().nullable().optional(),
|
|
565
|
+
when_at: z.string().nullable().optional(),
|
|
566
|
+
when_text: z.string().nullable().optional(),
|
|
567
|
+
where_lat: z.number().min(-90).max(90).nullable().optional(),
|
|
568
|
+
where_lng: z.number().min(-180).max(180).nullable().optional(),
|
|
569
|
+
where_label: z.string().nullable().optional(),
|
|
570
|
+
address: z.string().optional().describe('Free-text address — server geocodes + sets where_lat/lng. Mutually compatible with where_label override.'),
|
|
571
|
+
how: z.string().nullable().optional(),
|
|
572
|
+
why: z.string().nullable().optional(),
|
|
573
|
+
expires_in_hours: z.number().positive().optional(),
|
|
574
|
+
expires_at: z.string().nullable().optional().describe('ISO datetime or null to clear'),
|
|
575
|
+
_im_context: imContextSchema,
|
|
576
|
+
},
|
|
577
|
+
}, wrapMemo('update'));
|
|
578
|
+
server.registerTool('delete_memo', {
|
|
579
|
+
title: 'Delete a memo by id',
|
|
580
|
+
description: 'Remove a memo. Find ids via search_memos. Use when user explicitly says to delete / ' +
|
|
581
|
+
'forget / clear ("删了车那条" / "把生日那条记录忘掉"). ⚠️ Permanent — confirm with the ' +
|
|
582
|
+
'user before calling for important-looking memos (no expiry set, who/when fields populated).',
|
|
583
|
+
inputSchema: {
|
|
584
|
+
id: z.number().int().positive().describe('Memo id from search_memos'),
|
|
585
|
+
_im_context: imContextSchema,
|
|
586
|
+
},
|
|
587
|
+
}, wrapMemo('delete'));
|
|
588
|
+
return server;
|
|
589
|
+
}
|
|
590
|
+
export { ApprovalClient };
|
|
591
|
+
async function main() {
|
|
592
|
+
const sockPath = process.env.IMHUB_APPROVAL_SOCK;
|
|
593
|
+
if (!sockPath) {
|
|
594
|
+
process.stderr.write('[mcp-approval-server] missing IMHUB_APPROVAL_SOCK\n');
|
|
595
|
+
process.exit(1);
|
|
596
|
+
}
|
|
597
|
+
// IMHUB_RUN_ID is optional. Per-spawn paths (claude-code --mcp-config,
|
|
598
|
+
// opencode stdio extraEnv) set a unique runId so the bus can look up
|
|
599
|
+
// the IM thread context. Long-lived shared paths (opencode http daemon
|
|
600
|
+
// spawning the MCP server once at startup) leave it unset; reminder.*
|
|
601
|
+
// tool calls then route via the agent-asserted `_im_context` payload.
|
|
602
|
+
// Approval tool calls without a runId can't be routed and will be
|
|
603
|
+
// denied by the bus — but those paths don't use this sidecar anyway
|
|
604
|
+
// (opencode http does approvals via SSE, not MCP).
|
|
605
|
+
const runId = process.env.IMHUB_RUN_ID || '';
|
|
606
|
+
const client = new ApprovalClient(sockPath, runId);
|
|
607
|
+
const server = buildServer(client);
|
|
608
|
+
const transport = new StdioServerTransport();
|
|
609
|
+
await server.connect(transport);
|
|
610
|
+
// When stdio closes (claude went away), shut down cleanly.
|
|
611
|
+
const shutdown = async () => {
|
|
612
|
+
try {
|
|
613
|
+
await client.close();
|
|
614
|
+
}
|
|
615
|
+
catch { /* ignore */ }
|
|
616
|
+
try {
|
|
617
|
+
await server.close();
|
|
618
|
+
}
|
|
619
|
+
catch { /* ignore */ }
|
|
620
|
+
process.exit(0);
|
|
621
|
+
};
|
|
622
|
+
process.on('SIGTERM', shutdown);
|
|
623
|
+
process.on('SIGINT', shutdown);
|
|
624
|
+
}
|
|
625
|
+
// Detect "run as script" — when imported by tests we don't want to spin up stdio.
|
|
626
|
+
const isMainModule = (() => {
|
|
627
|
+
if (typeof process === 'undefined' || !process.argv[1])
|
|
628
|
+
return false;
|
|
629
|
+
try {
|
|
630
|
+
const url = new URL(import.meta.url);
|
|
631
|
+
return url.pathname.endsWith(process.argv[1].replace(/^.*?(?=\/|$)/, '')) ||
|
|
632
|
+
url.pathname === process.argv[1] ||
|
|
633
|
+
process.argv[1].endsWith('mcp-approval-server.js');
|
|
634
|
+
}
|
|
635
|
+
catch {
|
|
636
|
+
return false;
|
|
637
|
+
}
|
|
638
|
+
})();
|
|
639
|
+
if (isMainModule) {
|
|
640
|
+
main().catch((err) => {
|
|
641
|
+
process.stderr.write(`[mcp-approval-server] fatal: ${err}\n`);
|
|
642
|
+
process.exit(1);
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
//# sourceMappingURL=mcp-approval-server.js.map
|