@algosuite/vo-mcp 0.2.0-beta.2 → 0.2.0-beta.4

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.
File without changes
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../scripts/virtual-office/code-runner/agent-key-store.mjs", "../src/set-key-args.mjs", "../src/set-key-cli.mjs"],
4
- "sourcesContent": ["/**\n * agent-key-store \u2014 BYO Phase-B multi-agent. A provider-keyed generalization of\n * [anthropic-key-store] so a friend can store the credential for whichever CLI\n * agent they run (Claude / Codex / Cursor) in the OPERATING-SYSTEM keychain\n * (@napi-rs/keyring). The key lives ONLY on the friend's machine and never\n * reaches Algosuite; the runner reads it at spawn time to authenticate the\n * headless agent.\n *\n * Relationship to anthropic-key-store: that module is the Claude-specific M4\n * path and is left UNTOUCHED. This store uses the SAME service ('algosuite-vo')\n * and the SAME account convention ('<provider>-api-key'), so a key written by\n * `vo-mcp set-key` (account 'anthropic-api-key') is readable here as provider\n * 'anthropic' \u2014 the two are interoperable, not competing stores.\n *\n * Design rules (identical posture to anthropic-key-store):\n * - PURELY graceful: if @napi-rs/keyring is absent, EVERY op no-ops\n * (null/false) so the runner falls back to the ambient env / CLI login.\n * - An explicit credential already in the environment ALWAYS wins over the\n * keychain (a manual override is never silently replaced).\n * - The key travels via process env to the spawned agent, never via argv.\n */\nimport { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\n\nexport const KEY_SERVICE = 'algosuite-vo';\n\n/**\n * Provider \u2192 the env var(s) its CLI reads for its API credential. Filling more\n * than one is harmless (the CLI ignores vars it doesn't use); 'openai' covers\n * both names the Codex CLI accepts across versions.\n */\nexport const PROVIDER_ENV = {\n anthropic: ['ANTHROPIC_API_KEY'],\n openai: ['OPENAI_API_KEY', 'CODEX_API_KEY'],\n cursor: ['CURSOR_API_KEY'],\n};\n\n/** Canonical provider for a runner's logical name (claude\u2192anthropic, codex\u2192openai). */\nconst PROVIDER_ALIAS = {\n claude: 'anthropic',\n anthropic: 'anthropic',\n codex: 'openai',\n openai: 'openai',\n cursor: 'cursor',\n};\n\n/** Normalize a runner/provider label to its credential provider. Returns null if unknown. */\nexport function resolveProvider(name) {\n const key = String(name || '').trim().toLowerCase();\n return PROVIDER_ALIAS[key] || null;\n}\n\n/** Keychain account name for a provider (matches anthropic-key-store's 'anthropic-api-key'). */\nexport function accountFor(provider) {\n return `${provider}-api-key`;\n}\n\nlet _entryCtor;\nlet _loadTried = false;\n\n/** Lazily load @napi-rs/keyring's `Entry`; null when unavailable (\u2192 no-op ops). */\nfunction defaultEntryCtor() {\n if (_loadTried) return _entryCtor;\n _loadTried = true;\n try {\n _entryCtor = require('@napi-rs/keyring').Entry;\n } catch {\n _entryCtor = null; // not installed / unsupported platform \u2192 graceful fallback\n }\n return _entryCtor;\n}\n\n/** Store `key` for `provider` in the OS keychain. Returns true on success. */\nexport function setAgentKey(provider, key, { EntryCtor = defaultEntryCtor() } = {}) {\n const p = resolveProvider(provider);\n if (!p || !key || !EntryCtor) return false;\n try {\n new EntryCtor(KEY_SERVICE, accountFor(p)).setPassword(String(key));\n return true;\n } catch {\n return false;\n }\n}\n\n/** Read `provider`'s key from the OS keychain. Returns the key, or null. */\nexport function getAgentKey(provider, { EntryCtor = defaultEntryCtor() } = {}) {\n const p = resolveProvider(provider);\n if (!p || !EntryCtor) return null;\n try {\n // getPassword throws (keyring-rs NoEntry) when nothing is stored.\n return new EntryCtor(KEY_SERVICE, accountFor(p)).getPassword() || null;\n } catch {\n return null;\n }\n}\n\n/** Delete `provider`'s stored key. Returns true if a key was removed. */\nexport function clearAgentKey(provider, { EntryCtor = defaultEntryCtor() } = {}) {\n const p = resolveProvider(provider);\n if (!p || !EntryCtor) return false;\n try {\n new EntryCtor(KEY_SERVICE, accountFor(p)).deletePassword();\n return true;\n } catch {\n return false;\n }\n}\n\n/** True if a key is currently stored for `provider` (and the keychain is available). */\nexport function hasAgentKey(provider, opts = {}) {\n return getAgentKey(provider, opts) !== null;\n}\n\n/**\n * Return an env for the spawned agent with `provider`'s credential env var(s)\n * filled from the keychain \u2014 but ONLY for vars not already set (explicit env\n * wins) and only when a key is actually stored. Always returns a fresh object;\n * never mutates `baseEnv`. Unknown provider or no stored key \u2192 shallow copy.\n */\nexport function withAgentKey(provider, baseEnv = {}, { getKey = getAgentKey } = {}) {\n const p = resolveProvider(provider);\n const vars = (p && PROVIDER_ENV[p]) || [];\n const out = { ...baseEnv };\n if (!p || vars.length === 0) return out;\n // If any target var is already set, treat the credential as operator-provided.\n if (vars.some((v) => out[v])) return out;\n const key = getKey(p);\n if (!key) return out;\n for (const v of vars) out[v] = key;\n return out;\n}\n", "/**\n * set-key-args \u2014 the PURE arg-parsing + provider table for `vo-mcp set-key`.\n * Split out of set-key-cli.mjs so it can be unit-tested without importing the\n * CLI (whose module body reads stdin and runs on import). esbuild inlines it at\n * bundle time, same as the other runner-tree .mjs imports.\n */\nimport { resolveProvider } from '../../../scripts/virtual-office/code-runner/agent-key-store.mjs';\n\n/**\n * Per-provider metadata: display `label`, the agent `cli` binary, the\n * `selector` keyword the user types after `--provider` (NOT the binary \u2014 e.g.\n * cursor's binary is `cursor-agent`), the `envVar` fallback, and a typical\n * key-prefix `hint` for a gentle (never-blocking) format check.\n */\nexport const PROVIDERS = {\n anthropic: { label: 'Anthropic', cli: 'claude', selector: 'claude', envVar: 'ANTHROPIC_API_KEY', hint: 'sk-' },\n openai: { label: 'OpenAI / Codex', cli: 'codex', selector: 'codex', envVar: 'OPENAI_API_KEY', hint: 'sk-' },\n cursor: { label: 'Cursor', cli: 'cursor-agent', selector: 'cursor', envVar: 'CURSOR_API_KEY', hint: '' },\n};\n\n/**\n * Parse `vo-mcp set-key` argv (the FULL process.argv; the subcommand is argv[2]).\n * Supports `--provider <p>` / `--provider=p` (default anthropic), `--status`,\n * `--clear`. Returns `{ provider, providerArg, mode }` where `provider` is the\n * normalized credential provider (null if the value is unknown) and `mode` is\n * 'set' | 'status' | 'clear'.\n */\nexport function parseSetKeyArgs(argv = []) {\n const rest = argv.slice(3);\n let providerArg = 'anthropic';\n let mode = 'set';\n for (let i = 0; i < rest.length; i += 1) {\n const a = rest[i];\n if (a === '--status') mode = 'status';\n else if (a === '--clear') mode = 'clear';\n else if (a === '--provider') {\n providerArg = rest[i + 1] || '';\n i += 1; // consume the value token\n } else if (a.startsWith('--provider=')) {\n providerArg = a.slice('--provider='.length);\n }\n }\n return { provider: resolveProvider(providerArg), providerArg, mode };\n}\n", "#!/usr/bin/env node\r\n/**\r\n * `vo-mcp set-key` \u2014 BYO Phase-B M4 + multi-agent. Stores the friend's AI API key\r\n * in the OS keychain (Windows Credential Manager / macOS Keychain / libsecret) so\r\n * the runner can authenticate its CLI agent without an env var. The key lives ONLY\r\n * on the friend's machine \u2014 it never travels to Algosuite.\r\n *\r\n * vo-mcp set-key store the Anthropic (Claude) key [default]\r\n * vo-mcp set-key --provider codex store the OpenAI/Codex key\r\n * vo-mcp set-key --provider cursor store the Cursor key\r\n * vo-mcp set-key --status report whether the provider's key is stored\r\n * vo-mcp set-key --clear remove the provider's stored key\r\n *\r\n * The key may be piped (`echo $KEY | vo-mcp set-key --provider codex`) or typed at\r\n * the hidden prompt. .mjs (like runner-cli.mjs) because it imports the runner-tree\r\n * key store, outside tsconfig rootDir \u2014 tsc skips it; esbuild inlines it at bundle.\r\n */\r\nimport {\r\n setAgentKey,\r\n hasAgentKey,\r\n clearAgentKey,\r\n} from '../../../scripts/virtual-office/code-runner/agent-key-store.mjs';\r\nimport { PROVIDERS, parseSetKeyArgs } from './set-key-args.mjs';\r\n\r\nconst log = (m) => console.error(m);\r\nconst mask = (k) => (k && k.length > 8 ? `\u2026${k.slice(-4)}` : '****');\r\n\r\n/** Read a secret from a TTY without echoing; falls back to piped stdin. */\r\nfunction readSecret(promptText) {\r\n return new Promise((resolve) => {\r\n if (!process.stdin.isTTY) {\r\n // Piped: `echo $KEY | vo-mcp set-key` \u2014 read everything, take the first line.\r\n let buf = '';\r\n process.stdin.setEncoding('utf8');\r\n process.stdin.on('data', (d) => (buf += d));\r\n process.stdin.on('end', () => resolve(buf.split(/\\r?\\n/)[0].trim()));\r\n return;\r\n }\r\n // Interactive: print the prompt, then mute the echoed characters.\r\n process.stdout.write(promptText);\r\n const stdin = process.stdin;\r\n stdin.setRawMode?.(true);\r\n stdin.resume();\r\n stdin.setEncoding('utf8');\r\n let val = '';\r\n const onData = (ch) => {\r\n if (ch === '\\r' || ch === '\\n' || ch === '\u0004') {\r\n stdin.setRawMode?.(false);\r\n stdin.pause();\r\n stdin.removeListener('data', onData);\r\n process.stdout.write('\\n');\r\n resolve(val.trim());\r\n } else if (ch === '\u0003') {\r\n // Ctrl-C\r\n process.stdout.write('\\n');\r\n process.exit(130);\r\n } else if (ch === '\u007F' || ch === '\\b') {\r\n val = val.slice(0, -1);\r\n } else {\r\n val += ch;\r\n }\r\n };\r\n stdin.on('data', onData);\r\n });\r\n}\r\n\r\nasync function main() {\r\n const { provider, providerArg, mode } = parseSetKeyArgs(process.argv);\r\n if (!provider) {\r\n log(`Unknown --provider \"${providerArg}\". Use one of: claude, codex, cursor.`);\r\n process.exitCode = 1;\r\n return;\r\n }\r\n const info = PROVIDERS[provider];\r\n\r\n if (mode === 'status') {\r\n log(\r\n hasAgentKey(provider)\r\n ? `\u2713 A ${info.label} API key is stored in your OS keychain.`\r\n : `No ${info.label} API key stored. Run \\`vo-mcp set-key${provider === 'anthropic' ? '' : ` --provider ${info.selector}`}\\` to add one.`,\r\n );\r\n return;\r\n }\r\n\r\n if (mode === 'clear') {\r\n log(\r\n clearAgentKey(provider)\r\n ? `\u2713 Removed the stored ${info.label} API key.`\r\n : `No stored ${info.label} key to remove (or keychain unavailable).`,\r\n );\r\n return;\r\n }\r\n\r\n log(`Paste your ${info.label} API key (for the \\`${info.cli}\\` agent). It is stored ONLY in`);\r\n log(\"your computer's keychain \u2014 it never leaves this machine and Algosuite never sees it.\");\r\n const key = await readSecret(`${info.label} API key: `);\r\n if (!key) {\r\n log('No key entered \u2014 nothing stored.');\r\n process.exitCode = 1;\r\n return;\r\n }\r\n // A gentle format hint only \u2014 key formats change and Cursor's isn't `sk-`, so\r\n // never hard-reject a non-matching key (that would block a valid credential).\r\n if (info.hint && !key.startsWith(info.hint)) {\r\n log(`Heads up: ${info.label} keys usually start with \"${info.hint}\". Storing it anyway.`);\r\n }\r\n if (setAgentKey(provider, key)) {\r\n log(`\u2713 Stored your ${info.label} API key (${mask(key)}) in the OS keychain. The runner will use it automatically.`);\r\n } else {\r\n log(`Could not access the OS keychain on this machine. As a fallback, set ${info.envVar} in your environment before running \\`vo-mcp runner\\`.`);\r\n process.exitCode = 1;\r\n }\r\n}\r\n\r\nmain().catch((e) => {\r\n log(`set-key failed: ${e && e.message ? e.message : e}`);\r\n process.exitCode = 1;\r\n});\r\n"],
4
+ "sourcesContent": ["/**\n * agent-key-store \u2014 BYO Phase-B multi-agent. A provider-keyed generalization of\n * [anthropic-key-store] so a friend can store the credential for whichever CLI\n * agent they run (Claude / Codex / Cursor) in the OPERATING-SYSTEM keychain\n * (@napi-rs/keyring). The key lives ONLY on the friend's machine and never\n * reaches Algosuite; the runner reads it at spawn time to authenticate the\n * headless agent.\n *\n * Relationship to anthropic-key-store: that module is the Claude-specific M4\n * path and is left UNTOUCHED. This store uses the SAME service ('algosuite-vo')\n * and the SAME account convention ('<provider>-api-key'), so a key written by\n * `vo-mcp set-key` (account 'anthropic-api-key') is readable here as provider\n * 'anthropic' \u2014 the two are interoperable, not competing stores.\n *\n * Design rules (identical posture to anthropic-key-store):\n * - PURELY graceful: if @napi-rs/keyring is absent, EVERY op no-ops\n * (null/false) so the runner falls back to the ambient env / CLI login.\n * - An explicit credential already in the environment ALWAYS wins over the\n * keychain (a manual override is never silently replaced).\n * - The key travels via process env to the spawned agent, never via argv.\n */\nimport { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\n\nexport const KEY_SERVICE = 'algosuite-vo';\n\n/**\n * Provider \u2192 the env var(s) its CLI reads for its API credential. Filling more\n * than one is harmless (the CLI ignores vars it doesn't use); 'openai' covers\n * both names the Codex CLI accepts across versions.\n */\nexport const PROVIDER_ENV = {\n anthropic: ['ANTHROPIC_API_KEY'],\n openai: ['OPENAI_API_KEY', 'CODEX_API_KEY'],\n cursor: ['CURSOR_API_KEY'],\n};\n\n/** Canonical provider for a runner's logical name (claude\u2192anthropic, codex\u2192openai). */\nconst PROVIDER_ALIAS = {\n claude: 'anthropic',\n anthropic: 'anthropic',\n codex: 'openai',\n openai: 'openai',\n cursor: 'cursor',\n};\n\n/** Normalize a runner/provider label to its credential provider. Returns null if unknown. */\nexport function resolveProvider(name) {\n const key = String(name || '').trim().toLowerCase();\n return PROVIDER_ALIAS[key] || null;\n}\n\n/** Keychain account name for a provider (matches anthropic-key-store's 'anthropic-api-key'). */\nexport function accountFor(provider) {\n return `${provider}-api-key`;\n}\n\nlet _entryCtor;\nlet _loadTried = false;\n\n/** Lazily load @napi-rs/keyring's `Entry`; null when unavailable (\u2192 no-op ops). */\nfunction defaultEntryCtor() {\n if (_loadTried) return _entryCtor;\n _loadTried = true;\n try {\n _entryCtor = require('@napi-rs/keyring').Entry;\n } catch {\n _entryCtor = null; // not installed / unsupported platform \u2192 graceful fallback\n }\n return _entryCtor;\n}\n\n/** Store `key` for `provider` in the OS keychain. Returns true on success. */\nexport function setAgentKey(provider, key, { EntryCtor = defaultEntryCtor() } = {}) {\n const p = resolveProvider(provider);\n if (!p || !key || !EntryCtor) return false;\n try {\n new EntryCtor(KEY_SERVICE, accountFor(p)).setPassword(String(key));\n return true;\n } catch {\n return false;\n }\n}\n\n/** Read `provider`'s key from the OS keychain. Returns the key, or null. */\nexport function getAgentKey(provider, { EntryCtor = defaultEntryCtor() } = {}) {\n const p = resolveProvider(provider);\n if (!p || !EntryCtor) return null;\n try {\n // getPassword throws (keyring-rs NoEntry) when nothing is stored.\n return new EntryCtor(KEY_SERVICE, accountFor(p)).getPassword() || null;\n } catch {\n return null;\n }\n}\n\n/** Delete `provider`'s stored key. Returns true if a key was removed. */\nexport function clearAgentKey(provider, { EntryCtor = defaultEntryCtor() } = {}) {\n const p = resolveProvider(provider);\n if (!p || !EntryCtor) return false;\n try {\n new EntryCtor(KEY_SERVICE, accountFor(p)).deletePassword();\n return true;\n } catch {\n return false;\n }\n}\n\n/** True if a key is currently stored for `provider` (and the keychain is available). */\nexport function hasAgentKey(provider, opts = {}) {\n return getAgentKey(provider, opts) !== null;\n}\n\n/**\n * Return an env for the spawned agent with `provider`'s credential env var(s)\n * filled from the keychain \u2014 but ONLY for vars not already set (explicit env\n * wins) and only when a key is actually stored. Always returns a fresh object;\n * never mutates `baseEnv`. Unknown provider or no stored key \u2192 shallow copy.\n */\nexport function withAgentKey(provider, baseEnv = {}, { getKey = getAgentKey } = {}) {\n const p = resolveProvider(provider);\n const vars = (p && PROVIDER_ENV[p]) || [];\n const out = { ...baseEnv };\n if (!p || vars.length === 0) return out;\n // If any target var is already set, treat the credential as operator-provided.\n if (vars.some((v) => out[v])) return out;\n const key = getKey(p);\n if (!key) return out;\n for (const v of vars) out[v] = key;\n return out;\n}\n", "/**\n * set-key-args \u2014 the PURE arg-parsing + provider table for `vo-mcp set-key`.\n * Split out of set-key-cli.mjs so it can be unit-tested without importing the\n * CLI (whose module body reads stdin and runs on import). esbuild inlines it at\n * bundle time, same as the other runner-tree .mjs imports.\n */\nimport { resolveProvider } from '../../../scripts/virtual-office/code-runner/agent-key-store.mjs';\n\n/**\n * Per-provider metadata: display `label`, the agent `cli` binary, the\n * `selector` keyword the user types after `--provider` (NOT the binary \u2014 e.g.\n * cursor's binary is `cursor-agent`), the `envVar` fallback, and a typical\n * key-prefix `hint` for a gentle (never-blocking) format check.\n */\nexport const PROVIDERS = {\n anthropic: { label: 'Anthropic', cli: 'claude', selector: 'claude', envVar: 'ANTHROPIC_API_KEY', hint: 'sk-' },\n openai: { label: 'OpenAI / Codex', cli: 'codex', selector: 'codex', envVar: 'OPENAI_API_KEY', hint: 'sk-' },\n cursor: { label: 'Cursor', cli: 'cursor-agent', selector: 'cursor', envVar: 'CURSOR_API_KEY', hint: '' },\n};\n\n/**\n * Parse `vo-mcp set-key` argv (the FULL process.argv; the subcommand is argv[2]).\n * Supports `--provider <p>` / `--provider=p` (default anthropic), `--status`,\n * `--clear`. Returns `{ provider, providerArg, mode }` where `provider` is the\n * normalized credential provider (null if the value is unknown) and `mode` is\n * 'set' | 'status' | 'clear'.\n */\nexport function parseSetKeyArgs(argv = []) {\n const rest = argv.slice(3);\n let providerArg = 'anthropic';\n let mode = 'set';\n for (let i = 0; i < rest.length; i += 1) {\n const a = rest[i];\n if (a === '--status') mode = 'status';\n else if (a === '--clear') mode = 'clear';\n else if (a === '--provider') {\n providerArg = rest[i + 1] || '';\n i += 1; // consume the value token\n } else if (a.startsWith('--provider=')) {\n providerArg = a.slice('--provider='.length);\n }\n }\n return { provider: resolveProvider(providerArg), providerArg, mode };\n}\n", "#!/usr/bin/env node\n/**\n * `vo-mcp set-key` \u2014 BYO Phase-B M4 + multi-agent. Stores the friend's AI API key\n * in the OS keychain (Windows Credential Manager / macOS Keychain / libsecret) so\n * the runner can authenticate its CLI agent without an env var. The key lives ONLY\n * on the friend's machine \u2014 it never travels to Algosuite.\n *\n * vo-mcp set-key store the Anthropic (Claude) key [default]\n * vo-mcp set-key --provider codex store the OpenAI/Codex key\n * vo-mcp set-key --provider cursor store the Cursor key\n * vo-mcp set-key --status report whether the provider's key is stored\n * vo-mcp set-key --clear remove the provider's stored key\n *\n * The key may be piped (`echo $KEY | vo-mcp set-key --provider codex`) or typed at\n * the hidden prompt. .mjs (like runner-cli.mjs) because it imports the runner-tree\n * key store, outside tsconfig rootDir \u2014 tsc skips it; esbuild inlines it at bundle.\n */\nimport {\n setAgentKey,\n hasAgentKey,\n clearAgentKey,\n} from '../../../scripts/virtual-office/code-runner/agent-key-store.mjs';\nimport { PROVIDERS, parseSetKeyArgs } from './set-key-args.mjs';\n\nconst log = (m) => console.error(m);\nconst mask = (k) => (k && k.length > 8 ? `\u2026${k.slice(-4)}` : '****');\n\n/** Read a secret from a TTY without echoing; falls back to piped stdin. */\nfunction readSecret(promptText) {\n return new Promise((resolve) => {\n if (!process.stdin.isTTY) {\n // Piped: `echo $KEY | vo-mcp set-key` \u2014 read everything, take the first line.\n let buf = '';\n process.stdin.setEncoding('utf8');\n process.stdin.on('data', (d) => (buf += d));\n process.stdin.on('end', () => resolve(buf.split(/\\r?\\n/)[0].trim()));\n return;\n }\n // Interactive: print the prompt, then mute the echoed characters.\n process.stdout.write(promptText);\n const stdin = process.stdin;\n stdin.setRawMode?.(true);\n stdin.resume();\n stdin.setEncoding('utf8');\n let val = '';\n const onData = (ch) => {\n if (ch === '\\r' || ch === '\\n' || ch === '\u0004') {\n stdin.setRawMode?.(false);\n stdin.pause();\n stdin.removeListener('data', onData);\n process.stdout.write('\\n');\n resolve(val.trim());\n } else if (ch === '\u0003') {\n // Ctrl-C\n process.stdout.write('\\n');\n process.exit(130);\n } else if (ch === '\u007F' || ch === '\\b') {\n val = val.slice(0, -1);\n } else {\n val += ch;\n }\n };\n stdin.on('data', onData);\n });\n}\n\nasync function main() {\n const { provider, providerArg, mode } = parseSetKeyArgs(process.argv);\n if (!provider) {\n log(`Unknown --provider \"${providerArg}\". Use one of: claude, codex, cursor.`);\n process.exitCode = 1;\n return;\n }\n const info = PROVIDERS[provider];\n\n if (mode === 'status') {\n log(\n hasAgentKey(provider)\n ? `\u2713 A ${info.label} API key is stored in your OS keychain.`\n : `No ${info.label} API key stored. Run \\`vo-mcp set-key${provider === 'anthropic' ? '' : ` --provider ${info.selector}`}\\` to add one.`,\n );\n return;\n }\n\n if (mode === 'clear') {\n log(\n clearAgentKey(provider)\n ? `\u2713 Removed the stored ${info.label} API key.`\n : `No stored ${info.label} key to remove (or keychain unavailable).`,\n );\n return;\n }\n\n log(`Paste your ${info.label} API key (for the \\`${info.cli}\\` agent). It is stored ONLY in`);\n log(\"your computer's keychain \u2014 it never leaves this machine and Algosuite never sees it.\");\n const key = await readSecret(`${info.label} API key: `);\n if (!key) {\n log('No key entered \u2014 nothing stored.');\n process.exitCode = 1;\n return;\n }\n // A gentle format hint only \u2014 key formats change and Cursor's isn't `sk-`, so\n // never hard-reject a non-matching key (that would block a valid credential).\n if (info.hint && !key.startsWith(info.hint)) {\n log(`Heads up: ${info.label} keys usually start with \"${info.hint}\". Storing it anyway.`);\n }\n if (setAgentKey(provider, key)) {\n log(`\u2713 Stored your ${info.label} API key (${mask(key)}) in the OS keychain. The runner will use it automatically.`);\n } else {\n log(`Could not access the OS keychain on this machine. As a fallback, set ${info.envVar} in your environment before running \\`vo-mcp runner\\`.`);\n process.exitCode = 1;\n }\n}\n\nmain().catch((e) => {\n log(`set-key failed: ${e && e.message ? e.message : e}`);\n process.exitCode = 1;\n});\n"],
5
5
  "mappings": ";;;;AAqBA,SAAS,qBAAqB;AAE9B,IAAMA,WAAU,cAAc,YAAY,GAAG;AAEtC,IAAM,cAAc;AAc3B,IAAM,iBAAiB;AAAA,EACrB,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AACV;AAGO,SAAS,gBAAgB,MAAM;AACpC,QAAM,MAAM,OAAO,QAAQ,EAAE,EAAE,KAAK,EAAE,YAAY;AAClD,SAAO,eAAe,GAAG,KAAK;AAChC;AAGO,SAAS,WAAW,UAAU;AACnC,SAAO,GAAG,QAAQ;AACpB;AAEA,IAAI;AACJ,IAAI,aAAa;AAGjB,SAAS,mBAAmB;AAC1B,MAAI,WAAY,QAAO;AACvB,eAAa;AACb,MAAI;AACF,iBAAaC,SAAQ,kBAAkB,EAAE;AAAA,EAC3C,QAAQ;AACN,iBAAa;AAAA,EACf;AACA,SAAO;AACT;AAGO,SAAS,YAAY,UAAU,KAAK,EAAE,YAAY,iBAAiB,EAAE,IAAI,CAAC,GAAG;AAClF,QAAM,IAAI,gBAAgB,QAAQ;AAClC,MAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAW,QAAO;AACrC,MAAI;AACF,QAAI,UAAU,aAAa,WAAW,CAAC,CAAC,EAAE,YAAY,OAAO,GAAG,CAAC;AACjE,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,YAAY,UAAU,EAAE,YAAY,iBAAiB,EAAE,IAAI,CAAC,GAAG;AAC7E,QAAM,IAAI,gBAAgB,QAAQ;AAClC,MAAI,CAAC,KAAK,CAAC,UAAW,QAAO;AAC7B,MAAI;AAEF,WAAO,IAAI,UAAU,aAAa,WAAW,CAAC,CAAC,EAAE,YAAY,KAAK;AAAA,EACpE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,cAAc,UAAU,EAAE,YAAY,iBAAiB,EAAE,IAAI,CAAC,GAAG;AAC/E,QAAM,IAAI,gBAAgB,QAAQ;AAClC,MAAI,CAAC,KAAK,CAAC,UAAW,QAAO;AAC7B,MAAI;AACF,QAAI,UAAU,aAAa,WAAW,CAAC,CAAC,EAAE,eAAe;AACzD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,YAAY,UAAU,OAAO,CAAC,GAAG;AAC/C,SAAO,YAAY,UAAU,IAAI,MAAM;AACzC;;;AClGO,IAAM,YAAY;AAAA,EACvB,WAAW,EAAE,OAAO,aAAa,KAAK,UAAU,UAAU,UAAU,QAAQ,qBAAqB,MAAM,MAAM;AAAA,EAC7G,QAAQ,EAAE,OAAO,kBAAkB,KAAK,SAAS,UAAU,SAAS,QAAQ,kBAAkB,MAAM,MAAM;AAAA,EAC1G,QAAQ,EAAE,OAAO,UAAU,KAAK,gBAAgB,UAAU,UAAU,QAAQ,kBAAkB,MAAM,GAAG;AACzG;AASO,SAAS,gBAAgB,OAAO,CAAC,GAAG;AACzC,QAAM,OAAO,KAAK,MAAM,CAAC;AACzB,MAAI,cAAc;AAClB,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,UAAM,IAAI,KAAK,CAAC;AAChB,QAAI,MAAM,WAAY,QAAO;AAAA,aACpB,MAAM,UAAW,QAAO;AAAA,aACxB,MAAM,cAAc;AAC3B,oBAAc,KAAK,IAAI,CAAC,KAAK;AAC7B,WAAK;AAAA,IACP,WAAW,EAAE,WAAW,aAAa,GAAG;AACtC,oBAAc,EAAE,MAAM,cAAc,MAAM;AAAA,IAC5C;AAAA,EACF;AACA,SAAO,EAAE,UAAU,gBAAgB,WAAW,GAAG,aAAa,KAAK;AACrE;;;ACnBA,IAAM,MAAM,CAAC,MAAM,QAAQ,MAAM,CAAC;AAClC,IAAM,OAAO,CAAC,MAAO,KAAK,EAAE,SAAS,IAAI,SAAI,EAAE,MAAM,EAAE,CAAC,KAAK;AAG7D,SAAS,WAAW,YAAY;AAC9B,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,CAAC,QAAQ,MAAM,OAAO;AAExB,UAAI,MAAM;AACV,cAAQ,MAAM,YAAY,MAAM;AAChC,cAAQ,MAAM,GAAG,QAAQ,CAAC,MAAO,OAAO,CAAE;AAC1C,cAAQ,MAAM,GAAG,OAAO,MAAM,QAAQ,IAAI,MAAM,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;AACnE;AAAA,IACF;AAEA,YAAQ,OAAO,MAAM,UAAU;AAC/B,UAAM,QAAQ,QAAQ;AACtB,UAAM,aAAa,IAAI;AACvB,UAAM,OAAO;AACb,UAAM,YAAY,MAAM;AACxB,QAAI,MAAM;AACV,UAAM,SAAS,CAAC,OAAO;AACrB,UAAI,OAAO,QAAQ,OAAO,QAAQ,OAAO,KAAK;AAC5C,cAAM,aAAa,KAAK;AACxB,cAAM,MAAM;AACZ,cAAM,eAAe,QAAQ,MAAM;AACnC,gBAAQ,OAAO,MAAM,IAAI;AACzB,gBAAQ,IAAI,KAAK,CAAC;AAAA,MACpB,WAAW,OAAO,KAAK;AAErB,gBAAQ,OAAO,MAAM,IAAI;AACzB,gBAAQ,KAAK,GAAG;AAAA,MAClB,WAAW,OAAO,UAAO,OAAO,MAAM;AACpC,cAAM,IAAI,MAAM,GAAG,EAAE;AAAA,MACvB,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF;AACA,UAAM,GAAG,QAAQ,MAAM;AAAA,EACzB,CAAC;AACH;AAEA,eAAe,OAAO;AACpB,QAAM,EAAE,UAAU,aAAa,KAAK,IAAI,gBAAgB,QAAQ,IAAI;AACpE,MAAI,CAAC,UAAU;AACb,QAAI,uBAAuB,WAAW,uCAAuC;AAC7E,YAAQ,WAAW;AACnB;AAAA,EACF;AACA,QAAM,OAAO,UAAU,QAAQ;AAE/B,MAAI,SAAS,UAAU;AACrB;AAAA,MACE,YAAY,QAAQ,IAChB,YAAO,KAAK,KAAK,4CACjB,MAAM,KAAK,KAAK,wCAAwC,aAAa,cAAc,KAAK,eAAe,KAAK,QAAQ,EAAE;AAAA,IAC5H;AACA;AAAA,EACF;AAEA,MAAI,SAAS,SAAS;AACpB;AAAA,MACE,cAAc,QAAQ,IAClB,6BAAwB,KAAK,KAAK,cAClC,aAAa,KAAK,KAAK;AAAA,IAC7B;AACA;AAAA,EACF;AAEA,MAAI,cAAc,KAAK,KAAK,uBAAuB,KAAK,GAAG,iCAAiC;AAC5F,MAAI,2FAAsF;AAC1F,QAAM,MAAM,MAAM,WAAW,GAAG,KAAK,KAAK,YAAY;AACtD,MAAI,CAAC,KAAK;AACR,QAAI,uCAAkC;AACtC,YAAQ,WAAW;AACnB;AAAA,EACF;AAGA,MAAI,KAAK,QAAQ,CAAC,IAAI,WAAW,KAAK,IAAI,GAAG;AAC3C,QAAI,aAAa,KAAK,KAAK,6BAA6B,KAAK,IAAI,uBAAuB;AAAA,EAC1F;AACA,MAAI,YAAY,UAAU,GAAG,GAAG;AAC9B,QAAI,sBAAiB,KAAK,KAAK,aAAa,KAAK,GAAG,CAAC,6DAA6D;AAAA,EACpH,OAAO;AACL,QAAI,wEAAwE,KAAK,MAAM,wDAAwD;AAC/I,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,KAAK,EAAE,MAAM,CAAC,MAAM;AAClB,MAAI,mBAAmB,KAAK,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE;AACvD,UAAQ,WAAW;AACrB,CAAC;",
6
6
  "names": ["require", "require"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@algosuite/vo-mcp",
3
- "version": "0.2.0-beta.2",
3
+ "version": "0.2.0-beta.4",
4
4
  "description": "Virtual Office MCP server — open protocol surface for the VO consensus / ratchet tool family. Stdio transport, cross-vendor MCP client compatible (Claude Code, Claude Desktop, Cursor, Continue).",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",