@intent-systems/nexus 2026.1.5-4 → 2026.1.5-8
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/dist/agents/agent-id.js +41 -0
- package/dist/agents/auth-profiles.js +114 -25
- package/dist/agents/identity-state.js +101 -0
- package/dist/agents/model-auth.js +1 -0
- package/dist/agents/model-fallback.js +15 -9
- package/dist/agents/model-selection.js +1 -1
- package/dist/agents/models-config.js +17 -11
- package/dist/agents/pi-embedded-runner.js +101 -9
- package/dist/agents/sandbox.js +12 -3
- package/dist/agents/skill-runner.js +41 -6
- package/dist/agents/skill-usage.js +117 -17
- package/dist/agents/skills-status.js +4 -3
- package/dist/agents/skills.js +38 -30
- package/dist/agents/subagent-registry.js +25 -11
- package/dist/agents/system-prompt.js +16 -0
- package/dist/agents/tool-policy.js +19 -3
- package/dist/agents/tools/browser-tool.js +5 -2
- package/dist/agents/tools/image-tool.js +93 -8
- package/dist/agents/tools/sessions-announce-target.js +5 -1
- package/dist/agents/workspace.js +81 -59
- package/dist/auto-reply/command-detection.js +2 -1
- package/dist/auto-reply/reply/directive-handling.js +153 -28
- package/dist/auto-reply/reply/directives.js +17 -2
- package/dist/auto-reply/reply/model-selection.js +8 -3
- package/dist/auto-reply/reply/queue.js +2 -2
- package/dist/auto-reply/reply.js +1 -1
- package/dist/auto-reply/thinking.js +15 -0
- package/dist/browser/chrome.js +1 -1
- package/dist/browser/client.js +2 -0
- package/dist/browser/config.js +6 -2
- package/dist/browser/pw-tools-core.js +3 -0
- package/dist/browser/routes/agent.js +14 -0
- package/dist/canvas-host/server.js +1 -1
- package/dist/capabilities/detector.js +46 -15
- package/dist/capabilities/registry.js +2 -1
- package/dist/cli/cloud-cli.js +70 -7
- package/dist/cli/credential-cli.js +214 -23
- package/dist/cli/gateway-cli.js +1 -1
- package/dist/cli/log-cli.js +25 -0
- package/dist/cli/pairing-cli.js +1 -1
- package/dist/cli/program.js +82 -8
- package/dist/cli/run-main.js +1 -1
- package/dist/cli/skills-cli.js +165 -30
- package/dist/cli/skills-hub-cli.js +68 -36
- package/dist/cli/tool-connector-cli.js +99 -24
- package/dist/cli/upstream-sync-cli.js +253 -96
- package/dist/cli/usage-cli.js +14 -0
- package/dist/commands/auth-choice-options.js +6 -1
- package/dist/commands/auth-choice.js +157 -5
- package/dist/commands/bootstrap-preset.js +26 -12
- package/dist/commands/capabilities.js +33 -6
- package/dist/commands/claude-md.js +3 -2
- package/dist/commands/config-view.js +1 -1
- package/dist/commands/config.js +85 -0
- package/dist/commands/configure.js +4 -4
- package/dist/commands/credential.js +497 -36
- package/dist/commands/cursor-hooks.js +240 -0
- package/dist/commands/cursor-rules.js +14 -188
- package/dist/commands/doctor.js +5 -4
- package/dist/commands/identity.js +29 -32
- package/dist/commands/init.js +304 -20
- package/dist/commands/log.js +134 -0
- package/dist/commands/models/fallbacks.js +1 -1
- package/dist/commands/models/image-fallbacks.js +1 -1
- package/dist/commands/models/list.js +1 -1
- package/dist/commands/models/scan.js +1 -1
- package/dist/commands/onboard-auth.js +27 -2
- package/dist/commands/onboard-eve-identity.js +8 -9
- package/dist/commands/onboard-non-interactive.js +4 -2
- package/dist/commands/onboard-quickstart.js +18 -11
- package/dist/commands/quest-state.js +271 -0
- package/dist/commands/quest.js +53 -13
- package/dist/commands/reset.js +1 -1
- package/dist/commands/sessions-ingest.js +5 -4
- package/dist/commands/setup.js +4 -2
- package/dist/commands/skills-manifest.js +89 -29
- package/dist/commands/status.js +193 -73
- package/dist/commands/suggestions.js +1 -1
- package/dist/commands/usage-tracking.js +32 -0
- package/dist/commands/usage-upload.js +6 -1
- package/dist/config/defaults.js +1 -3
- package/dist/config/includes.js +5 -7
- package/dist/config/io.js +88 -16
- package/dist/config/legacy.js +4 -2
- package/dist/config/paths.js +16 -0
- package/dist/config/sessions.js +9 -5
- package/dist/config/zod-schema.js +4 -3
- package/dist/control-plane/broker/broker.js +131 -78
- package/dist/control-plane/compaction.js +3 -5
- package/dist/control-plane/factory.js +2 -2
- package/dist/control-plane/index.js +2 -2
- package/dist/control-plane/odu/agents.js +28 -23
- package/dist/control-plane/odu/interaction-tools.js +62 -50
- package/dist/control-plane/odu/prompt-loader.js +8 -8
- package/dist/control-plane/odu/runtime.js +87 -75
- package/dist/control-plane/odu-control-plane.js +14 -12
- package/dist/control-plane/single-agent.js +13 -13
- package/dist/credentials/store.js +133 -7
- package/dist/daemon/launchd.js +14 -0
- package/dist/entry.js +0 -0
- package/dist/gateway/server-browser.js +5 -4
- package/dist/gateway/server-methods/cron.js +11 -1
- package/dist/gateway/server.js +14 -7
- package/dist/infra/bonjour.js +1 -1
- package/dist/infra/event-log.js +8 -2
- package/dist/infra/path-env.js +1 -2
- package/dist/infra/provider-usage.auth.js +5 -3
- package/dist/infra/provider-usage.fetch.claude.js +16 -6
- package/dist/infra/provider-usage.fetch.minimax.js +8 -3
- package/dist/infra/provider-usage.js +9 -5
- package/dist/infra/restart.js +2 -2
- package/dist/infra/usage-settings.js +78 -0
- package/dist/infra/usage-suggestions.js +17 -5
- package/dist/infra/usage-upload.js +38 -1
- package/dist/infra/voicewake.js +2 -2
- package/dist/media/image-ops.js +3 -1
- package/dist/memory/index.js +2 -381
- package/dist/native/nexus-cloud/darwin-arm64/nexus-cloud +0 -0
- package/dist/native/nexus-cloud/darwin-arm64/nexus-cloud-rs +0 -0
- package/dist/pairing/pairing-store.js +24 -0
- package/dist/providers/github-copilot-auth.js +1 -1
- package/dist/routing/resolve-route.js +6 -6
- package/dist/routing/session-key.js +3 -1
- package/dist/sessions/send-policy.js +5 -5
- package/dist/slack/monitor.js +22 -1
- package/dist/telegram/reaction-level.js +2 -1
- package/dist/utils.js +8 -3
- package/dist/wizard/onboarding.js +29 -7
- package/docs/AGENTS.default.md +1 -1
- package/docs/configuration.md +1 -1
- package/docs/feature-inventory/overview.md +2 -2
- package/docs/reference/templates/AGENTS.md +172 -109
- package/docs/templates/AGENTS.md +140 -199
- package/docs/templates/BOOTSTRAP.md +40 -20
- package/docs/templates/IDENTITY.md +6 -0
- package/docs/templates/USER.md +22 -2
- package/package.json +3 -1
- package/skills/{notion → connectors/notion}/SKILL.md +1 -1
- package/skills/{filesystem → guides/filesystem}/SKILL.md +1 -1
- package/skills/{onboarding → guides/onboarding}/SKILL.md +1 -1
- package/skills/{onboarding → guides/onboarding}/docs/CAPABILITY_TAXONOMY.md +5 -5
- package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR.md +8 -8
- package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR_ONBOARDING.md +2 -2
- package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR_SKILLS.md +26 -20
- package/skills/{onboarding → guides/onboarding}/docs/GOAL_STATE_ARCHITECTURE.md +38 -43
- package/skills/{onboarding → guides/onboarding}/docs/NEXUS_SYSTEM_OVERVIEW.md +4 -4
- package/skills/{onboarding → guides/onboarding}/docs/SKILLS_HUB_SPEC.md +1 -1
- package/skills/{onboarding → guides/onboarding}/docs/SKILLS_SPECIFICATION.md +8 -7
- package/skills/{onboarding → guides/onboarding}/docs/SKILL_GATEWAY_DESIGN.md +16 -16
- package/skills/{onboarding → guides/onboarding}/docs/SKILL_GATEWAY_PRD.md +10 -12
- package/skills/guides/onboarding/docs/canonical/00_CONFLICT_ANALYSIS.md +463 -0
- package/skills/guides/onboarding/docs/canonical/01_NEXUS_OVERVIEW.md +167 -0
- package/skills/guides/onboarding/docs/canonical/02_CLI_REFERENCE.md +404 -0
- package/skills/guides/onboarding/docs/canonical/03_STATE_ARCHITECTURE.md +357 -0
- package/skills/guides/onboarding/docs/canonical/04_SKILL_SPECIFICATION.md +393 -0
- package/skills/guides/onboarding/docs/canonical/05_CAPABILITY_TAXONOMY.md +298 -0
- package/skills/guides/onboarding/docs/canonical/06_CAPABILITIES_REFERENCE.md +207 -0
- package/skills/guides/onboarding/docs/canonical/07_AGENT_BINDINGS.md +85 -0
- package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/nexus-cloud.md +2 -2
- package/skills/{onboarding → guides/onboarding}/scripts/ralph/progress.txt +1 -1
- package/skills/{nexus-cloud → tools/nexus-cloud}/SKILL.md +2 -1
- package/skills/{nexus-cloud → tools/nexus-cloud}/docs/setup.md +1 -1
- package/docs/templates/PROFILE.md +0 -14
- /package/skills/{brave-search → connectors/brave-search}/SKILL.md +0 -0
- /package/skills/{brave-search → connectors/brave-search}/docs/setup.md +0 -0
- /package/skills/{brave-search → connectors/brave-search}/docs/troubleshooting.md +0 -0
- /package/skills/{brave-search → connectors/brave-search}/docs/usage.md +0 -0
- /package/skills/{brave-search → connectors/brave-search}/scripts/content.mjs +0 -0
- /package/skills/{brave-search → connectors/brave-search}/scripts/search.mjs +0 -0
- /package/skills/{discord → connectors/discord}/SKILL.md +0 -0
- /package/skills/{gemini → connectors/gemini}/SKILL.md +0 -0
- /package/skills/{github → connectors/github}/SKILL.md +0 -0
- /package/skills/{github → connectors/github}/docs/setup.md +0 -0
- /package/skills/{github → connectors/github}/docs/troubleshooting.md +0 -0
- /package/skills/{google-oauth → connectors/google-oauth}/SKILL.md +0 -0
- /package/skills/{slack → connectors/slack}/SKILL.md +0 -0
- /package/skills/{telegram → connectors/telegram}/SKILL.md +0 -0
- /package/skills/{telegram → connectors/telegram}/docs/pairing.md +0 -0
- /package/skills/{telegram → connectors/telegram}/docs/setup.md +0 -0
- /package/skills/{telegram → connectors/telegram}/docs/webhook.md +0 -0
- /package/skills/{wacli → connectors/wacli}/SKILL.md +0 -0
- /package/skills/{wacli → connectors/wacli}/docs/auth.md +0 -0
- /package/skills/{wacli → connectors/wacli}/docs/backup.md +0 -0
- /package/skills/{wacli → connectors/wacli}/docs/troubleshooting.md +0 -0
- /package/skills/{browser-use-agent-sdk → guides/browser-use-agent-sdk}/SKILL.md +0 -0
- /package/skills/{json-render → guides/json-render}/SKILL.md +0 -0
- /package/skills/{json-render → guides/json-render}/assets/components/README.md +0 -0
- /package/skills/{json-render → guides/json-render}/assets/components/catalog.ts +0 -0
- /package/skills/{json-render → guides/json-render}/assets/components/registry.tsx +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/App.css +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/App.tsx +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/README.md +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/catalog.ts +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/data/nexus-core.json +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/index.css +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/registry.tsx +0 -0
- /package/skills/{json-render → guides/json-render}/docs/nexus-state-demo.md +0 -0
- /package/skills/{json-render → guides/json-render}/docs/shadcn-preset.md +0 -0
- /package/skills/{json-render → guides/json-render}/scripts/create-vite-demo.sh +0 -0
- /package/skills/{json-render → guides/json-render}/scripts/llm-server/README.md +0 -0
- /package/skills/{json-render → guides/json-render}/scripts/llm-server/catalog.ts +0 -0
- /package/skills/{json-render → guides/json-render}/scripts/llm-server/package-lock.json +0 -0
- /package/skills/{json-render → guides/json-render}/scripts/llm-server/package.json +0 -0
- /package/skills/{json-render → guides/json-render}/scripts/llm-server/server.ts +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/CAPABILITIES.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR_CREDENTIALS.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/DOCUMENTATION_OVERVIEW.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/ENTITY_MODEL.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/SKILL_INVENTORY.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/STATE_ARCHITECTURE.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/TROUBLESHOOTING.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/USER_JOURNEY.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/WOW_MOMENTS.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/agent-apple-id.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/1password.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/TEMPLATE.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/aix.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/bird.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/brave-search.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/comms.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/computer-use.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/cron-and-heartbeat.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/eve.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/github.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/gog.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/homebrew-prereqs.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/qmd.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/telegram.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/wacli.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/weather.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/scripts/ralph/prd.json +0 -0
- /package/skills/{onboarding → guides/onboarding}/scripts/ralph/prompt.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/scripts/ralph/ralph.log +0 -0
- /package/skills/{onboarding → guides/onboarding}/scripts/ralph/ralph.sh +0 -0
- /package/skills/{onboarding → guides/onboarding}/scripts/setup-cursor-skills.sh +0 -0
- /package/skills/{1password → tools/1password}/SKILL.md +0 -0
- /package/skills/{1password → tools/1password}/docs/setup.md +0 -0
- /package/skills/{1password → tools/1password}/docs/troubleshooting.md +0 -0
- /package/skills/{1password → tools/1password}/references/cli-examples.md +0 -0
- /package/skills/{1password → tools/1password}/references/get-started.md +0 -0
- /package/skills/{agent-browser → tools/agent-browser}/SKILL.md +0 -0
- /package/skills/{agent-browser → tools/agent-browser}/docs/browser-use-eval.md +0 -0
- /package/skills/{agent-browser → tools/agent-browser}/docs/first-tests.md +0 -0
- /package/skills/{agent-browser → tools/agent-browser}/docs/wordle-nyt-eval.js +0 -0
- /package/skills/{aix → tools/aix}/SKILL.md +0 -0
- /package/skills/{aix → tools/aix}/docs/embeddings.md +0 -0
- /package/skills/{aix → tools/aix}/docs/setup.md +0 -0
- /package/skills/{aix → tools/aix}/docs/troubleshooting.md +0 -0
- /package/skills/{aix → tools/aix}/references/sql.md +0 -0
- /package/skills/{apple-notes → tools/apple-notes}/SKILL.md +0 -0
- /package/skills/{apple-reminders → tools/apple-reminders}/SKILL.md +0 -0
- /package/skills/{bear-notes → tools/bear-notes}/SKILL.md +0 -0
- /package/skills/{bird → tools/bird}/SKILL.md +0 -0
- /package/skills/{bird → tools/bird}/docs/auth.md +0 -0
- /package/skills/{bird → tools/bird}/docs/troubleshooting.md +0 -0
- /package/skills/{blogwatcher → tools/blogwatcher}/SKILL.md +0 -0
- /package/skills/{blucli → tools/blucli}/SKILL.md +0 -0
- /package/skills/{camsnap → tools/camsnap}/SKILL.md +0 -0
- /package/skills/{clawdhub → tools/clawdhub}/SKILL.md +0 -0
- /package/skills/{coding-agent → tools/coding-agent}/SKILL.md +0 -0
- /package/skills/{comms → tools/comms}/SKILL.md +0 -0
- /package/skills/{comms → tools/comms}/docs/adapters.md +0 -0
- /package/skills/{comms → tools/comms}/docs/setup.md +0 -0
- /package/skills/{comms → tools/comms}/docs/troubleshooting.md +0 -0
- /package/skills/{comms → tools/comms}/references/schema.md +0 -0
- /package/skills/{computer-use → tools/computer-use}/SKILL.md +0 -0
- /package/skills/{computer-use → tools/computer-use}/docs/open-interpreter.md +0 -0
- /package/skills/{computer-use → tools/computer-use}/docs/peekaboo.md +0 -0
- /package/skills/{computer-use → tools/computer-use}/docs/setup.md +0 -0
- /package/skills/{computer-use → tools/computer-use}/docs/troubleshooting.md +0 -0
- /package/skills/{eightctl → tools/eightctl}/SKILL.md +0 -0
- /package/skills/{eve → tools/eve}/SKILL.md +0 -0
- /package/skills/{eve → tools/eve}/docs/dual-account.md +0 -0
- /package/skills/{eve → tools/eve}/docs/intelligence.md +0 -0
- /package/skills/{eve → tools/eve}/docs/setup.md +0 -0
- /package/skills/{eve → tools/eve}/docs/troubleshooting.md +0 -0
- /package/skills/{eve → tools/eve}/scripts/setup-dual-account.sh +0 -0
- /package/skills/{food-order → tools/food-order}/SKILL.md +0 -0
- /package/skills/{gh → tools/gh}/SKILL.md +0 -0
- /package/skills/{gh → tools/gh}/docs/usage.md +0 -0
- /package/skills/{gifgrep → tools/gifgrep}/SKILL.md +0 -0
- /package/skills/{gog → tools/gog}/SKILL.md +0 -0
- /package/skills/{gog → tools/gog}/docs/portability.md +0 -0
- /package/skills/{gog → tools/gog}/docs/setup.md +0 -0
- /package/skills/{gog → tools/gog}/docs/troubleshooting.md +0 -0
- /package/skills/{gog → tools/gog}/scripts/cdp/README.md +0 -0
- /package/skills/{gog → tools/gog}/scripts/cdp/add_test_users.py +0 -0
- /package/skills/{gog → tools/gog}/scripts/cdp/auth_add_accounts.py +0 -0
- /package/skills/{gog → tools/gog}/scripts/cdp/auth_add_accounts_manual.py +0 -0
- /package/skills/{gog → tools/gog}/scripts/cdp/create_oauth_client.py +0 -0
- /package/skills/{gog → tools/gog}/scripts/cdp/launch_cdp_chrome.sh +0 -0
- /package/skills/{goplaces → tools/goplaces}/SKILL.md +0 -0
- /package/skills/{imsg → tools/imsg}/SKILL.md +0 -0
- /package/skills/{local-places → tools/local-places}/SERVER_README.md +0 -0
- /package/skills/{local-places → tools/local-places}/SKILL.md +0 -0
- /package/skills/{local-places → tools/local-places}/pyproject.toml +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/__init__.py +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/__init__.cpython-314.pyc +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/google_places.cpython-314.pyc +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/main.cpython-314.pyc +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/schemas.cpython-314.pyc +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/google_places.py +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/main.py +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/schemas.py +0 -0
- /package/skills/{mcporter → tools/mcporter}/SKILL.md +0 -0
- /package/skills/{model-usage → tools/model-usage}/SKILL.md +0 -0
- /package/skills/{model-usage → tools/model-usage}/references/codexbar-cli.md +0 -0
- /package/skills/{model-usage → tools/model-usage}/scripts/model_usage.py +0 -0
- /package/skills/{nano-banana-pro → tools/nano-banana-pro}/SKILL.md +0 -0
- /package/skills/{nano-banana-pro → tools/nano-banana-pro}/scripts/generate_image.py +0 -0
- /package/skills/{nano-pdf → tools/nano-pdf}/SKILL.md +0 -0
- /package/skills/{nexus-cloud → tools/nexus-cloud}/docs/security.md +0 -0
- /package/skills/{nexus-cloud → tools/nexus-cloud}/docs/troubleshooting.md +0 -0
- /package/skills/{obsidian → tools/obsidian}/SKILL.md +0 -0
- /package/skills/{openai-image-gen → tools/openai-image-gen}/SKILL.md +0 -0
- /package/skills/{openai-image-gen → tools/openai-image-gen}/scripts/gen.py +0 -0
- /package/skills/{openai-whisper → tools/openai-whisper}/SKILL.md +0 -0
- /package/skills/{openai-whisper-api → tools/openai-whisper-api}/SKILL.md +0 -0
- /package/skills/{openai-whisper-api → tools/openai-whisper-api}/scripts/transcribe.sh +0 -0
- /package/skills/{openhue → tools/openhue}/SKILL.md +0 -0
- /package/skills/{oracle → tools/oracle}/SKILL.md +0 -0
- /package/skills/{ordercli → tools/ordercli}/SKILL.md +0 -0
- /package/skills/{peekaboo → tools/peekaboo}/SKILL.md +0 -0
- /package/skills/{qmd → tools/qmd}/SKILL.md +0 -0
- /package/skills/{qmd → tools/qmd}/docs/mcp.md +0 -0
- /package/skills/{qmd → tools/qmd}/docs/ollama.md +0 -0
- /package/skills/{qmd → tools/qmd}/docs/setup.md +0 -0
- /package/skills/{sag → tools/sag}/SKILL.md +0 -0
- /package/skills/{skill-cli-template → tools/skill-cli-template}/SKILL.md +0 -0
- /package/skills/{songsee → tools/songsee}/SKILL.md +0 -0
- /package/skills/{sonoscli → tools/sonoscli}/SKILL.md +0 -0
- /package/skills/{spotify-player → tools/spotify-player}/SKILL.md +0 -0
- /package/skills/{summarize → tools/summarize}/SKILL.md +0 -0
- /package/skills/{things-mac → tools/things-mac}/SKILL.md +0 -0
- /package/skills/{tmux → tools/tmux}/SKILL.md +0 -0
- /package/skills/{tmux → tools/tmux}/scripts/find-sessions.sh +0 -0
- /package/skills/{tmux → tools/tmux}/scripts/wait-for-text.sh +0 -0
- /package/skills/{trello → tools/trello}/SKILL.md +0 -0
- /package/skills/{upstream-sync → tools/upstream-sync}/SKILL.md +0 -0
- /package/skills/{upstream-sync → tools/upstream-sync}/scripts/auto-port.sh +0 -0
- /package/skills/{upstream-sync → tools/upstream-sync}/scripts/check-all.sh +0 -0
- /package/skills/{upstream-sync → tools/upstream-sync}/scripts/check-nexus.sh +0 -0
- /package/skills/{upstream-sync → tools/upstream-sync}/scripts/check-pi-ai.sh +0 -0
- /package/skills/{video-frames → tools/video-frames}/SKILL.md +0 -0
- /package/skills/{video-frames → tools/video-frames}/scripts/frame.sh +0 -0
- /package/skills/{weather → tools/weather}/SKILL.md +0 -0
- /package/skills/{weather → tools/weather}/docs/usage.md +0 -0
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import fsSync from "node:fs";
|
|
1
4
|
import fs from "node:fs/promises";
|
|
2
|
-
import
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { buildCredentialIndex, listCredentialEntries, readCredentialIndex, readCredentialRecord, resolveDefaultEnvVar, resolveCredentialIndexPath, resolveCredentialPath, resolveCredentialsDir, resolveCredentialValue, storeKeychainSecret, writeCredentialIndex, writeCredentialRecord, } from "../credentials/store.js";
|
|
7
|
+
import { resolveUserPath } from "../utils.js";
|
|
3
8
|
const KNOWN_ENV_SPECS = [
|
|
4
9
|
{ env: "ANTHROPIC_API_KEY", service: "anthropic", type: "api_key" },
|
|
5
10
|
{ env: "OPENAI_API_KEY", service: "openai", type: "api_key" },
|
|
@@ -28,7 +33,9 @@ function looksLikePath(value) {
|
|
|
28
33
|
const trimmed = value.trim();
|
|
29
34
|
if (!trimmed)
|
|
30
35
|
return false;
|
|
31
|
-
if (trimmed.startsWith("/") ||
|
|
36
|
+
if (trimmed.startsWith("/") ||
|
|
37
|
+
trimmed.startsWith("./") ||
|
|
38
|
+
trimmed.startsWith("~/"))
|
|
32
39
|
return true;
|
|
33
40
|
if (trimmed.includes(":/") || trimmed.includes("\\"))
|
|
34
41
|
return true;
|
|
@@ -38,7 +45,7 @@ function detectValuePattern(value) {
|
|
|
38
45
|
const trimmed = value.trim();
|
|
39
46
|
if (!trimmed)
|
|
40
47
|
return null;
|
|
41
|
-
if (
|
|
48
|
+
if (trimmed.startsWith("sk-ant-")) {
|
|
42
49
|
return { service: "anthropic", type: "api_key", reason: "pattern:sk-ant" };
|
|
43
50
|
}
|
|
44
51
|
if (/^sk-[A-Za-z0-9]/.test(trimmed)) {
|
|
@@ -135,8 +142,23 @@ export function scanCredentialEnv(opts) {
|
|
|
135
142
|
}
|
|
136
143
|
return { deep, known, discovered, missing };
|
|
137
144
|
}
|
|
145
|
+
function mergeIndexMetadata(params) {
|
|
146
|
+
const merged = { ...params.base };
|
|
147
|
+
if (params.existing) {
|
|
148
|
+
merged.order = params.existing.order;
|
|
149
|
+
merged.lastGood = params.existing.lastGood;
|
|
150
|
+
merged.usageStats = params.existing.usageStats;
|
|
151
|
+
}
|
|
152
|
+
return merged;
|
|
153
|
+
}
|
|
138
154
|
export async function listCredentials(params = {}) {
|
|
139
|
-
const
|
|
155
|
+
const entries = await listCredentialEntries();
|
|
156
|
+
const existing = await readCredentialIndex();
|
|
157
|
+
const index = mergeIndexMetadata({
|
|
158
|
+
base: buildCredentialIndex(entries),
|
|
159
|
+
existing,
|
|
160
|
+
});
|
|
161
|
+
await writeCredentialIndex(index);
|
|
140
162
|
if (params.service) {
|
|
141
163
|
const key = params.service.trim();
|
|
142
164
|
return {
|
|
@@ -148,7 +170,11 @@ export async function listCredentials(params = {}) {
|
|
|
148
170
|
}
|
|
149
171
|
export async function scanCredentials() {
|
|
150
172
|
const entries = await listCredentialEntries();
|
|
151
|
-
const
|
|
173
|
+
const existing = await readCredentialIndex();
|
|
174
|
+
const index = mergeIndexMetadata({
|
|
175
|
+
base: buildCredentialIndex(entries),
|
|
176
|
+
existing,
|
|
177
|
+
});
|
|
152
178
|
await writeCredentialIndex(index);
|
|
153
179
|
return index;
|
|
154
180
|
}
|
|
@@ -160,49 +186,121 @@ export async function getCredential(params) {
|
|
|
160
186
|
}
|
|
161
187
|
return { filePath, record };
|
|
162
188
|
}
|
|
189
|
+
export async function getCredentialValue(params) {
|
|
190
|
+
const result = await getCredential(params);
|
|
191
|
+
if (!result)
|
|
192
|
+
return null;
|
|
193
|
+
const resolved = await resolveCredentialValue(result.record);
|
|
194
|
+
if (!resolved)
|
|
195
|
+
return null;
|
|
196
|
+
return { ...result, value: resolved.value, field: resolved.field };
|
|
197
|
+
}
|
|
198
|
+
function buildFallbackPayload(params) {
|
|
199
|
+
const value = params.value?.trim() ?? "";
|
|
200
|
+
if (!value) {
|
|
201
|
+
throw new Error("Missing credential value.");
|
|
202
|
+
}
|
|
203
|
+
if (params.type === "api_key") {
|
|
204
|
+
return { value };
|
|
205
|
+
}
|
|
206
|
+
if (params.type === "token") {
|
|
207
|
+
if (!params.refreshToken && params.expiresAt === undefined) {
|
|
208
|
+
return { value };
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
value: JSON.stringify({
|
|
212
|
+
token: value,
|
|
213
|
+
refreshToken: params.refreshToken,
|
|
214
|
+
expiresAt: params.expiresAt,
|
|
215
|
+
}),
|
|
216
|
+
format: "json",
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
value: JSON.stringify({
|
|
221
|
+
accessToken: value,
|
|
222
|
+
refreshToken: params.refreshToken,
|
|
223
|
+
expiresAt: params.expiresAt,
|
|
224
|
+
}),
|
|
225
|
+
format: "json",
|
|
226
|
+
};
|
|
227
|
+
}
|
|
163
228
|
export async function addCredential(params) {
|
|
164
229
|
const authId = params.authId?.trim() || params.type;
|
|
230
|
+
let storage;
|
|
231
|
+
if (params.storage.provider === "keychain") {
|
|
232
|
+
storage = {
|
|
233
|
+
provider: "keychain",
|
|
234
|
+
service: params.storage.serviceName ?? `nexus.${params.service}`,
|
|
235
|
+
account: params.storage.accountName ?? params.account,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
else if (params.storage.provider === "1password") {
|
|
239
|
+
storage = {
|
|
240
|
+
provider: "1password",
|
|
241
|
+
vault: params.storage.vault,
|
|
242
|
+
item: params.storage.item,
|
|
243
|
+
fields: params.storage.fields,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
else if (params.storage.provider === "env") {
|
|
247
|
+
storage = {
|
|
248
|
+
provider: "env",
|
|
249
|
+
var: params.storage.var,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
const command = params.storage.command ?? params.storage.syncCommand;
|
|
254
|
+
if (!command || !command.trim()) {
|
|
255
|
+
throw new Error("External storage requires --command or --sync-command.");
|
|
256
|
+
}
|
|
257
|
+
storage = {
|
|
258
|
+
provider: "external",
|
|
259
|
+
command,
|
|
260
|
+
format: params.storage.format,
|
|
261
|
+
jsonPath: params.storage.jsonPath,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
165
264
|
const record = {
|
|
166
265
|
owner: params.owner ?? "user",
|
|
167
266
|
type: params.type,
|
|
168
267
|
configuredAt: new Date().toISOString(),
|
|
169
|
-
storage
|
|
170
|
-
? { provider: "plaintext" }
|
|
171
|
-
: params.storage.provider === "keychain"
|
|
172
|
-
? {
|
|
173
|
-
provider: "keychain",
|
|
174
|
-
service: params.storage.serviceName ?? `nexus.${params.service}`,
|
|
175
|
-
account: params.storage.accountName ?? params.account,
|
|
176
|
-
}
|
|
177
|
-
: params.storage.provider === "1password"
|
|
178
|
-
? {
|
|
179
|
-
provider: "1password",
|
|
180
|
-
vault: params.storage.vault,
|
|
181
|
-
item: params.storage.item,
|
|
182
|
-
fields: params.storage.fields,
|
|
183
|
-
}
|
|
184
|
-
: { provider: "external", syncCommand: params.storage.syncCommand },
|
|
268
|
+
storage,
|
|
185
269
|
...(params.expiresAt ? { expiresAt: params.expiresAt } : {}),
|
|
186
270
|
};
|
|
187
|
-
if (params.storage.provider === "plaintext") {
|
|
188
|
-
const value = params.storage.value?.trim();
|
|
189
|
-
if (params.type === "api_key")
|
|
190
|
-
record.key = value;
|
|
191
|
-
if (params.type === "token")
|
|
192
|
-
record.token = value;
|
|
193
|
-
if (params.type === "oauth")
|
|
194
|
-
record.accessToken = value;
|
|
195
|
-
if (params.refreshToken)
|
|
196
|
-
record.refreshToken = params.refreshToken;
|
|
197
|
-
}
|
|
198
271
|
if (params.storage.provider === "keychain") {
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
account: record.storage.provider === "keychain" ? record.storage.account : params.account,
|
|
272
|
+
const payload = buildFallbackPayload({
|
|
273
|
+
type: params.type,
|
|
202
274
|
value: params.storage.value,
|
|
275
|
+
refreshToken: params.refreshToken,
|
|
276
|
+
expiresAt: params.expiresAt,
|
|
277
|
+
});
|
|
278
|
+
const stored = await storeKeychainSecret({
|
|
279
|
+
service: record.storage.provider === "keychain"
|
|
280
|
+
? record.storage.service
|
|
281
|
+
: `nexus.${params.service}`,
|
|
282
|
+
account: record.storage.provider === "keychain"
|
|
283
|
+
? record.storage.account
|
|
284
|
+
: params.account,
|
|
285
|
+
value: payload.value,
|
|
203
286
|
});
|
|
204
287
|
if (!stored) {
|
|
205
|
-
|
|
288
|
+
const envVar = resolveDefaultEnvVar({
|
|
289
|
+
service: params.service,
|
|
290
|
+
type: params.type,
|
|
291
|
+
});
|
|
292
|
+
process.env[envVar] = payload.value;
|
|
293
|
+
record.storage = {
|
|
294
|
+
provider: "env",
|
|
295
|
+
var: envVar,
|
|
296
|
+
...(payload.format ? { format: payload.format } : {}),
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
else if (payload.format === "json") {
|
|
300
|
+
record.storage = {
|
|
301
|
+
...record.storage,
|
|
302
|
+
format: "json",
|
|
303
|
+
};
|
|
206
304
|
}
|
|
207
305
|
}
|
|
208
306
|
const filePath = resolveCredentialPath(params.service, params.account, authId);
|
|
@@ -210,6 +308,180 @@ export async function addCredential(params) {
|
|
|
210
308
|
await scanCredentials();
|
|
211
309
|
return { filePath, record };
|
|
212
310
|
}
|
|
311
|
+
function quoteShellValue(value) {
|
|
312
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
313
|
+
}
|
|
314
|
+
function resolveClaudeCliCredentialsPath() {
|
|
315
|
+
return path.join(resolveUserPath("~"), ".claude", ".credentials.json");
|
|
316
|
+
}
|
|
317
|
+
function resolveCodexHomePath() {
|
|
318
|
+
const configured = process.env.CODEX_HOME;
|
|
319
|
+
const home = configured
|
|
320
|
+
? resolveUserPath(configured)
|
|
321
|
+
: resolveUserPath("~/.codex");
|
|
322
|
+
try {
|
|
323
|
+
return fsSync.realpathSync.native(home);
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
return home;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function computeCodexKeychainAccount(codexHome) {
|
|
330
|
+
const hash = createHash("sha256").update(codexHome).digest("hex");
|
|
331
|
+
return `cli|${hash.slice(0, 16)}`;
|
|
332
|
+
}
|
|
333
|
+
function extractClaudeAccessToken(payload) {
|
|
334
|
+
if (!payload || typeof payload !== "object")
|
|
335
|
+
return null;
|
|
336
|
+
const claudeOauth = payload.claudeAiOauth;
|
|
337
|
+
if (!claudeOauth || typeof claudeOauth !== "object")
|
|
338
|
+
return null;
|
|
339
|
+
const access = claudeOauth.accessToken;
|
|
340
|
+
if (typeof access !== "string" || !access.trim())
|
|
341
|
+
return null;
|
|
342
|
+
return access.trim();
|
|
343
|
+
}
|
|
344
|
+
function extractCodexAccessToken(payload) {
|
|
345
|
+
if (!payload || typeof payload !== "object")
|
|
346
|
+
return null;
|
|
347
|
+
const tokens = payload.tokens;
|
|
348
|
+
if (!tokens || typeof tokens !== "object")
|
|
349
|
+
return null;
|
|
350
|
+
const access = tokens.access_token;
|
|
351
|
+
if (typeof access !== "string" || !access.trim())
|
|
352
|
+
return null;
|
|
353
|
+
return access.trim();
|
|
354
|
+
}
|
|
355
|
+
function safeParseJson(raw) {
|
|
356
|
+
try {
|
|
357
|
+
return JSON.parse(raw);
|
|
358
|
+
}
|
|
359
|
+
catch {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
async function readJsonFile(filePath) {
|
|
364
|
+
try {
|
|
365
|
+
const raw = await fs.readFile(filePath, "utf-8");
|
|
366
|
+
return JSON.parse(raw);
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
async function resolveClaudeCliExternalStorage(params) {
|
|
373
|
+
const jsonPath = "claudeAiOauth.accessToken";
|
|
374
|
+
if (process.platform === "darwin" && params.allowKeychainPrompt !== false) {
|
|
375
|
+
try {
|
|
376
|
+
const raw = execFileSync("security", ["find-generic-password", "-s", "Claude Code-credentials", "-w"], { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
377
|
+
const parsed = safeParseJson(raw);
|
|
378
|
+
if (extractClaudeAccessToken(parsed)) {
|
|
379
|
+
return {
|
|
380
|
+
command: `security find-generic-password -s ${quoteShellValue("Claude Code-credentials")} -w`,
|
|
381
|
+
format: "json",
|
|
382
|
+
jsonPath,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
catch {
|
|
387
|
+
// ignore
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
const filePath = resolveClaudeCliCredentialsPath();
|
|
391
|
+
const parsed = await readJsonFile(filePath);
|
|
392
|
+
if (extractClaudeAccessToken(parsed)) {
|
|
393
|
+
return {
|
|
394
|
+
command: `cat ${quoteShellValue(filePath)}`,
|
|
395
|
+
format: "json",
|
|
396
|
+
jsonPath,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
async function resolveCodexCliExternalStorage(params) {
|
|
402
|
+
const jsonPath = "tokens.access_token";
|
|
403
|
+
const codexHome = resolveCodexHomePath();
|
|
404
|
+
if (process.platform === "darwin" && params.allowKeychainPrompt !== false) {
|
|
405
|
+
const account = computeCodexKeychainAccount(codexHome);
|
|
406
|
+
try {
|
|
407
|
+
const raw = execFileSync("security", ["find-generic-password", "-s", "Codex Auth", "-a", account, "-w"], { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
408
|
+
const parsed = safeParseJson(raw);
|
|
409
|
+
if (extractCodexAccessToken(parsed)) {
|
|
410
|
+
return {
|
|
411
|
+
command: `security find-generic-password -s ${quoteShellValue("Codex Auth")} -a ${quoteShellValue(account)} -w`,
|
|
412
|
+
format: "json",
|
|
413
|
+
jsonPath,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
catch {
|
|
418
|
+
// ignore
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
const authPath = path.join(codexHome, "auth.json");
|
|
422
|
+
const parsed = await readJsonFile(authPath);
|
|
423
|
+
if (extractCodexAccessToken(parsed)) {
|
|
424
|
+
return {
|
|
425
|
+
command: `cat ${quoteShellValue(authPath)}`,
|
|
426
|
+
format: "json",
|
|
427
|
+
jsonPath,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
export async function importCliCredential(params) {
|
|
433
|
+
const source = params.source;
|
|
434
|
+
const owner = params.owner ?? "user";
|
|
435
|
+
const service = source === "claude-cli" ? "anthropic" : "openai-codex";
|
|
436
|
+
const accountDefault = source === "claude-cli" ? "claude-cli" : "codex-cli";
|
|
437
|
+
const account = params.account?.trim() || accountDefault;
|
|
438
|
+
if (!account) {
|
|
439
|
+
throw new Error("Account is required to import CLI credentials.");
|
|
440
|
+
}
|
|
441
|
+
const storage = source === "claude-cli"
|
|
442
|
+
? await resolveClaudeCliExternalStorage({
|
|
443
|
+
allowKeychainPrompt: params.allowKeychainPrompt,
|
|
444
|
+
})
|
|
445
|
+
: await resolveCodexCliExternalStorage({
|
|
446
|
+
allowKeychainPrompt: params.allowKeychainPrompt,
|
|
447
|
+
});
|
|
448
|
+
if (!storage) {
|
|
449
|
+
throw new Error(source === "claude-cli"
|
|
450
|
+
? "No Claude CLI credentials found in Keychain or ~/.claude/.credentials.json."
|
|
451
|
+
: `No Codex CLI credentials found in Keychain or ${path.join(resolveCodexHomePath(), "auth.json")}.`);
|
|
452
|
+
}
|
|
453
|
+
const authId = "oauth";
|
|
454
|
+
const filePath = resolveCredentialPath(service, account, authId);
|
|
455
|
+
const existing = await readCredentialRecord(filePath);
|
|
456
|
+
if (existing && !params.force) {
|
|
457
|
+
const existingSource = existing.metadata?.externalSource;
|
|
458
|
+
if (existing.storage.provider !== "external" || existingSource !== source) {
|
|
459
|
+
throw new Error(`Credential already exists at ${filePath}. Use --force to overwrite.`);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
const record = {
|
|
463
|
+
owner,
|
|
464
|
+
type: "oauth",
|
|
465
|
+
configuredAt: new Date().toISOString(),
|
|
466
|
+
storage: {
|
|
467
|
+
provider: "external",
|
|
468
|
+
command: storage.command,
|
|
469
|
+
format: storage.format,
|
|
470
|
+
jsonPath: storage.jsonPath,
|
|
471
|
+
},
|
|
472
|
+
metadata: {
|
|
473
|
+
externalSource: source,
|
|
474
|
+
},
|
|
475
|
+
};
|
|
476
|
+
await writeCredentialRecord(service, account, authId, record);
|
|
477
|
+
await scanCredentials();
|
|
478
|
+
return {
|
|
479
|
+
filePath,
|
|
480
|
+
record,
|
|
481
|
+
profileId: `${service}:${account}`,
|
|
482
|
+
source,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
213
485
|
export async function removeCredential(params) {
|
|
214
486
|
const filePath = resolveCredentialPath(params.service, params.account, params.authId);
|
|
215
487
|
await fs.rm(filePath, { force: true });
|
|
@@ -234,3 +506,192 @@ export function getCredentialPaths() {
|
|
|
234
506
|
indexPath: resolveCredentialIndexPath(),
|
|
235
507
|
};
|
|
236
508
|
}
|
|
509
|
+
async function fetchWithTimeout(input, init, timeoutMs) {
|
|
510
|
+
const controller = new AbortController();
|
|
511
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
512
|
+
try {
|
|
513
|
+
return await fetch(input, { ...init, signal: controller.signal });
|
|
514
|
+
}
|
|
515
|
+
finally {
|
|
516
|
+
clearTimeout(timeout);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
async function verifyTokenAgainstApi(params) {
|
|
520
|
+
const service = params.service.toLowerCase();
|
|
521
|
+
const token = params.token;
|
|
522
|
+
try {
|
|
523
|
+
if (service === "anthropic") {
|
|
524
|
+
const res = await fetchWithTimeout("https://api.anthropic.com/v1/models", {
|
|
525
|
+
method: "GET",
|
|
526
|
+
headers: {
|
|
527
|
+
"x-api-key": token,
|
|
528
|
+
"anthropic-version": "2023-06-01",
|
|
529
|
+
},
|
|
530
|
+
}, 10_000);
|
|
531
|
+
if (!res.ok) {
|
|
532
|
+
return { ok: false, error: `anthropic ${res.status}`, status: res.status };
|
|
533
|
+
}
|
|
534
|
+
return { ok: true };
|
|
535
|
+
}
|
|
536
|
+
if (service === "openai" || service === "openai-codex") {
|
|
537
|
+
const res = await fetchWithTimeout("https://api.openai.com/v1/models", {
|
|
538
|
+
method: "GET",
|
|
539
|
+
headers: {
|
|
540
|
+
Authorization: `Bearer ${token}`,
|
|
541
|
+
},
|
|
542
|
+
}, 10_000);
|
|
543
|
+
if (!res.ok) {
|
|
544
|
+
return { ok: false, error: `openai ${res.status}`, status: res.status };
|
|
545
|
+
}
|
|
546
|
+
return { ok: true };
|
|
547
|
+
}
|
|
548
|
+
if (service === "gemini") {
|
|
549
|
+
const res = await fetchWithTimeout(`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(token)}`, { method: "GET" }, 10_000);
|
|
550
|
+
if (!res.ok) {
|
|
551
|
+
return { ok: false, error: `gemini ${res.status}`, status: res.status };
|
|
552
|
+
}
|
|
553
|
+
return { ok: true };
|
|
554
|
+
}
|
|
555
|
+
if (service === "github") {
|
|
556
|
+
const res = await fetchWithTimeout("https://api.github.com/user", {
|
|
557
|
+
method: "GET",
|
|
558
|
+
headers: {
|
|
559
|
+
Authorization: `Bearer ${token}`,
|
|
560
|
+
"User-Agent": "nexus",
|
|
561
|
+
},
|
|
562
|
+
}, 10_000);
|
|
563
|
+
if (!res.ok) {
|
|
564
|
+
return { ok: false, error: `github ${res.status}`, status: res.status };
|
|
565
|
+
}
|
|
566
|
+
return { ok: true };
|
|
567
|
+
}
|
|
568
|
+
if (service === "slack") {
|
|
569
|
+
const res = await fetchWithTimeout("https://slack.com/api/auth.test", {
|
|
570
|
+
method: "GET",
|
|
571
|
+
headers: {
|
|
572
|
+
Authorization: `Bearer ${token}`,
|
|
573
|
+
},
|
|
574
|
+
}, 10_000);
|
|
575
|
+
const body = (await res.json().catch(() => ({})));
|
|
576
|
+
if (!res.ok || body.ok === false) {
|
|
577
|
+
return { ok: false, error: "slack auth failed", status: res.status };
|
|
578
|
+
}
|
|
579
|
+
return { ok: true };
|
|
580
|
+
}
|
|
581
|
+
if (service === "discord") {
|
|
582
|
+
const attempt = async (auth) => {
|
|
583
|
+
const res = await fetchWithTimeout("https://discord.com/api/v10/users/@me", {
|
|
584
|
+
method: "GET",
|
|
585
|
+
headers: { Authorization: auth },
|
|
586
|
+
}, 10_000);
|
|
587
|
+
return res;
|
|
588
|
+
};
|
|
589
|
+
const botRes = await attempt(`Bot ${token}`);
|
|
590
|
+
if (botRes.ok)
|
|
591
|
+
return { ok: true };
|
|
592
|
+
const userRes = await attempt(`Bearer ${token}`);
|
|
593
|
+
if (userRes.ok)
|
|
594
|
+
return { ok: true };
|
|
595
|
+
return {
|
|
596
|
+
ok: false,
|
|
597
|
+
error: `discord ${userRes.status}`,
|
|
598
|
+
status: userRes.status,
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
if (service === "brave-search") {
|
|
602
|
+
const res = await fetchWithTimeout("https://api.search.brave.com/res/v1/web/search?q=nexus&count=1", {
|
|
603
|
+
method: "GET",
|
|
604
|
+
headers: {
|
|
605
|
+
"X-Subscription-Token": token,
|
|
606
|
+
},
|
|
607
|
+
}, 10_000);
|
|
608
|
+
if (!res.ok) {
|
|
609
|
+
return {
|
|
610
|
+
ok: false,
|
|
611
|
+
error: `brave-search ${res.status}`,
|
|
612
|
+
status: res.status,
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
return { ok: true };
|
|
616
|
+
}
|
|
617
|
+
if (service === "google-oauth" || service === "gog" || service === "google") {
|
|
618
|
+
const res = await fetchWithTimeout(`https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=${encodeURIComponent(token)}`, { method: "GET" }, 10_000);
|
|
619
|
+
if (!res.ok) {
|
|
620
|
+
return {
|
|
621
|
+
ok: false,
|
|
622
|
+
error: `google-oauth ${res.status}`,
|
|
623
|
+
status: res.status,
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
return { ok: true };
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
catch (err) {
|
|
630
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
631
|
+
}
|
|
632
|
+
return { ok: true };
|
|
633
|
+
}
|
|
634
|
+
export async function verifyCredentials(params) {
|
|
635
|
+
const service = params.service.trim();
|
|
636
|
+
if (!service)
|
|
637
|
+
return null;
|
|
638
|
+
const entries = await listCredentialEntries();
|
|
639
|
+
const matching = entries.filter((entry) => entry.service.toLowerCase() === service.toLowerCase());
|
|
640
|
+
if (matching.length === 0)
|
|
641
|
+
return null;
|
|
642
|
+
const verifiedAt = new Date().toISOString();
|
|
643
|
+
const checked = [];
|
|
644
|
+
for (const entry of matching) {
|
|
645
|
+
const record = entry.record;
|
|
646
|
+
if (record.type === "config") {
|
|
647
|
+
checked.push({
|
|
648
|
+
account: entry.account,
|
|
649
|
+
authId: entry.authId,
|
|
650
|
+
status: "skipped",
|
|
651
|
+
});
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
const resolved = await resolveCredentialValue(record);
|
|
655
|
+
if (!resolved) {
|
|
656
|
+
record.lastError = "missing credential value";
|
|
657
|
+
record.lastVerified = verifiedAt;
|
|
658
|
+
await writeCredentialRecord(entry.service, entry.account, entry.authId, record);
|
|
659
|
+
checked.push({
|
|
660
|
+
account: entry.account,
|
|
661
|
+
authId: entry.authId,
|
|
662
|
+
status: "error",
|
|
663
|
+
error: "missing credential value",
|
|
664
|
+
});
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
667
|
+
const outcome = await verifyTokenAgainstApi({
|
|
668
|
+
service,
|
|
669
|
+
token: resolved.value,
|
|
670
|
+
});
|
|
671
|
+
record.lastVerified = verifiedAt;
|
|
672
|
+
record.lastError = outcome.ok ? null : outcome.error ?? "verification failed";
|
|
673
|
+
await writeCredentialRecord(entry.service, entry.account, entry.authId, record);
|
|
674
|
+
checked.push({
|
|
675
|
+
account: entry.account,
|
|
676
|
+
authId: entry.authId,
|
|
677
|
+
status: outcome.ok ? "ok" : "error",
|
|
678
|
+
error: outcome.ok ? undefined : record.lastError ?? undefined,
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
await scanCredentials();
|
|
682
|
+
const broken = checked
|
|
683
|
+
.filter((item) => item.status === "error")
|
|
684
|
+
.map((item) => ({
|
|
685
|
+
account: item.account,
|
|
686
|
+
auths: [item.authId],
|
|
687
|
+
lastError: item.error,
|
|
688
|
+
}));
|
|
689
|
+
return {
|
|
690
|
+
ok: broken.length === 0,
|
|
691
|
+
service,
|
|
692
|
+
accounts: matching.length,
|
|
693
|
+
broken,
|
|
694
|
+
checked,
|
|
695
|
+
verifiedAt,
|
|
696
|
+
};
|
|
697
|
+
}
|