@tabai/sdk 0.2.4 → 0.2.5

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/README.md CHANGED
@@ -192,7 +192,8 @@ The key is read at the moment a Settlement is built, and never from this file. `
192
192
  | `TAB_BOOK_ADDRESS`, `TAB_SETTLEMENT_ADDRESS`, `SERVICE_REGISTRY_ADDRESS`, `BOND_ADDRESS` | resolving credit, Services and Bond |
193
193
  | `NEXT_PUBLIC_REGISTRY_API_URL` | the Service directory and an agent's history. Defaults to the project's hosted registry for the chosen network |
194
194
  | `TAB_HOSTED_DEFAULTS` | `off` stops the hosted registry and demo Service from filling in what you did not configure |
195
- | `AGENT_PRIVATE_KEY` | broadcasting a Settlement, signing a Permit2 witness, or paying an x402 offer, and nothing else. Never written to a configuration file |
195
+ | `AGENT_ADDRESS` | the Agent a metered call lands on, when `tab.config` names none. Public, so `connect` copies it into the MCP stanza |
196
+ | `AGENT_PRIVATE_KEY` | broadcasting a Settlement, signing a Permit2 witness, paying an x402 offer, or signing a call to the hosted demo Service, and nothing else. Never written to a configuration file |
196
197
 
197
198
  ---
198
199
 
@@ -318,7 +319,7 @@ The price is known only after the upstream's `402`, so `pricing` is a book the f
318
319
  services: [{ serviceId, endpoint, hub: { provider: "defillama", prefix: "apihub" } }]
319
320
  ```
320
321
 
321
- The reference metering gateway mounts both: `GATEWAY_HUB_UPSTREAMS` names the upstreams, `X402_ENABLED` and `X402_FACILITATOR_URL` govern the offer on a `402`, and `GATEWAY_COLLECTION_ADDRESS` is the `payTo` fallback when `ServiceRegistry.collectionOf` cannot be read.
322
+ The metering gateway in this repository mounts both: `GATEWAY_HUB_UPSTREAMS` names the upstreams, `X402_ENABLED` and `X402_FACILITATOR_URL` govern the offer on a `402`, and `GATEWAY_COLLECTION_ADDRESS` is the `payTo` fallback when `ServiceRegistry.collectionOf` cannot be read.
322
323
 
323
324
  **What is official and what is not.** The types, the three header codecs and the facilitator HTTP client are `@x402/core`, the reference implementation. The EIP-3009 signing is this package's own, over ethers rather than the reference client's viem, and it is checked two ways: every test recovers the signer with `verifyTypedData`, and the reference client was run over the same authorization while this was written, producing the same signature byte for byte. The request handling is this package's own because the reference server middleware gates every request on payment, which is the model Tab exists to replace.
324
325
 
@@ -402,7 +403,8 @@ Live on Monad Mainnet and Monad Testnet.
402
403
  | Registry read API | `https://registry-mainnet-production.up.railway.app` | `https://registry-testnet-production.up.railway.app` |
403
404
  | Demo Service `tab.demo` | `https://gateway-mainnet-production.up.railway.app` | `https://gateway-testnet-production-a657.up.railway.app` |
404
405
 
405
- **With nothing configured, this package uses them.** `tab_discover` and `tab_status` read the hosted registry for the chosen network, and `tab_call` can reach the demo Service, so a fresh `npx -y @tabai/sdk connect` works before you set anything.
406
+ **With nothing configured, this package uses them.** `tab_discover` and `tab_status` read the hosted registry for the chosen network, so a fresh `npx -y @tabai/sdk connect` works before you set anything.
407
+ The hosted gateways meter only a signed call, so `tab_call` to the demo Service needs `AGENT_ADDRESS` and `AGENT_PRIVATE_KEY` in the environment, and then signs each call with the Agent's own key.
406
408
  Anything you configure wins, and `TAB_HOSTED_DEFAULTS=off` switches the defaults off entirely.
407
409
  They are exported as `TAB_HOSTED`.
408
410
 
@@ -1 +1 @@
1
- {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/cli/connect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAI5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,2BAA2B,CAAC;AACzF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAWL,KAAK,SAAS,EACf,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,qDAAqD;IACrD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,gFAAgF;IAChF,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,kCAAkC;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAmFD;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAkDxF"}
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/cli/connect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAI5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,2BAA2B,CAAC;AACzF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAWL,KAAK,SAAS,EACf,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,qDAAqD;IACrD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,gFAAgF;IAChF,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,kCAAkC;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAsFD;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAkDxF"}
@@ -38,6 +38,10 @@ function stanzaEnv(settings, env) {
38
38
  const registry = settings.registryUrl ?? env["NEXT_PUBLIC_REGISTRY_API_URL"];
39
39
  if (registry !== undefined && registry.trim() !== "")
40
40
  values["NEXT_PUBLIC_REGISTRY_API_URL"] = registry.trim();
41
+ // An address is public, and without it tab_call has no Agent to meter against.
42
+ const agent = env["AGENT_ADDRESS"];
43
+ if (agent !== undefined && agent.trim() !== "")
44
+ values["AGENT_ADDRESS"] = agent.trim();
41
45
  return values;
42
46
  }
43
47
  /** Reads the deployment, keylessly, so `connect` can say what it connected to. */
@@ -1 +1 @@
1
- {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/cli/connect.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `tab connect`: the one line of configuration.\n *\n * The whole adoption story is this command. It finds the MCP client's server\n * list, reads the deployment keylessly so it can tell the caller what they are\n * about to be connected to, merges one `mcpServers.tab` stanza, backs up what\n * was there, and prints the diff.\n *\n * ## Read before write\n *\n * The keyless read happens first and its result is reported whether it succeeded\n * or not. A `connect` that silently wrote a stanza pointing at a registry that\n * does not answer would look like success and behave like a broken install, and\n * the person running it would find out from a model instead of from the command.\n * The read never blocks the write: a deployment that is temporarily down is not\n * a reason to refuse to configure a client against it.\n *\n * ## Nothing here is a secret\n *\n * The stanza carries a command, its arguments, and at most two URLs. Every value\n * in it is publishable. {@link assertNoSecret} runs over the `tab` stanza\n * before anything is written, so the property is enforced rather than asserted\n * in a comment.\n */\n\nimport type { Result } from \"../_shared/index.js\";\nimport { ok } from \"../_shared/index.js\";\n\nimport { validationError } from \"../errors.js\";\nimport type { Logger } from \"../logger.js\";\nimport { silentLogger } from \"../logger.js\";\nimport { asArray, field } from \"../mcp/json.js\";\nimport { createRegistryReadClient, type RegistryFetch } from \"../mcp/registry-client.js\";\nimport type { TabMcpSettings } from \"../mcp/settings.js\";\nimport {\n buildTabStanza,\n chooseMcpClient,\n detectMcpClients,\n mergeTabStanza,\n readClientConfig,\n renderConfig,\n unifiedDiff,\n writeClientConfig,\n type McpClientTarget,\n type StanzaEnv,\n type TabStanza,\n} from \"./client-config.js\";\n\nexport interface ConnectOptions {\n readonly settings: TabMcpSettings;\n /** `claude-code`, `claude-desktop`, `cursor`, `windsurf` or `vscode`. */\n readonly client?: string;\n /** An explicit config file, which beats `client` and skips detection. */\n readonly configPath?: string;\n readonly env?: NodeJS.ProcessEnv;\n readonly os?: string;\n readonly cwd?: string;\n /** Injectable clock, so a backup name is testable. */\n readonly now?: () => Date;\n /** Work out and print everything, and write nothing. */\n readonly dryRun?: boolean;\n readonly fetchImpl?: RegistryFetch;\n readonly logger?: Logger;\n}\n\n/** What the deployment said when it was asked, before anything was written. */\nexport interface ConnectPreflight {\n readonly registryUrl: string | undefined;\n /** Services indexed, or null when the read API did not answer. */\n readonly services: number | null;\n readonly note: string;\n}\n\nexport interface ConnectReport {\n readonly client: string;\n readonly configPath: string;\n /** False when the file already said exactly this. */\n readonly changed: boolean;\n /** True when a `tab` stanza was already there, so a message can say updated. */\n readonly hadStanza: boolean;\n readonly backupPath: string | undefined;\n readonly stanza: TabStanza;\n /** Empty when nothing changed. */\n readonly diff: string;\n readonly preflight: ConnectPreflight;\n readonly dryRun: boolean;\n}\n\n/** The environment values that belong in a stanza. Publishable, all of them. */\nfunction stanzaEnv(settings: TabMcpSettings, env: NodeJS.ProcessEnv): StanzaEnv {\n const values: Record<string, string> = {};\n const rpc = settings.rpcUrl ?? env[\"MONAD_RPC_URL\"];\n if (rpc !== undefined && rpc.trim() !== \"\") values[\"MONAD_RPC_URL\"] = rpc.trim();\n values[\"MONAD_CHAIN_ID\"] = String(settings.chainId);\n const registry = settings.registryUrl ?? env[\"NEXT_PUBLIC_REGISTRY_API_URL\"];\n if (registry !== undefined && registry.trim() !== \"\") values[\"NEXT_PUBLIC_REGISTRY_API_URL\"] = registry.trim();\n return values;\n}\n\n/** Reads the deployment, keylessly, so `connect` can say what it connected to. */\nasync function preflight(\n settings: TabMcpSettings,\n fetchImpl: RegistryFetch | undefined,\n logger: Logger,\n): Promise<ConnectPreflight> {\n if (settings.registryUrl === undefined) {\n return {\n registryUrl: undefined,\n services: null,\n note: \"no registry read API is configured, so discovery and status will not work until one is. Calling and settling do not need it\",\n };\n }\n const registry = createRegistryReadClient({\n baseUrl: settings.registryUrl,\n logger,\n ...(fetchImpl === undefined ? {} : { fetchImpl }),\n });\n const services = await registry.services(50);\n if (!services.ok) {\n return {\n registryUrl: registry.baseUrl,\n services: null,\n note: `the read API did not answer: ${services.error.message}`,\n };\n }\n const count = asArray(field(services.value, \"services\")).length;\n const lastBlock = field(field(services.value, \"index\"), \"lastBlock\");\n return {\n registryUrl: registry.baseUrl,\n services: count,\n note:\n typeof lastBlock === \"number\"\n ? `${count} Service(s) indexed at Monad block ${lastBlock}`\n : `${count} Service(s) indexed`,\n };\n}\n\n/** Resolves which file to write, from `--config`, then `--client`, then detection. */\nfunction resolveTarget(options: ConnectOptions): Result<{ id: string; configPath: string }> {\n if (options.configPath !== undefined) {\n return ok({ id: options.client ?? \"custom\", configPath: options.configPath });\n }\n const detected = detectMcpClients({\n ...(options.os === undefined ? {} : { os: options.os }),\n ...(options.env === undefined ? {} : { env: options.env }),\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n });\n if (options.client !== undefined) {\n const named: McpClientTarget | undefined = detected.find((target) => target.id === options.client);\n if (named === undefined || named.configPath === undefined) {\n return validationError(\n \"CLIENT_UNKNOWN\",\n `\\`${options.client}\\` is not an MCP client this command knows on this platform; the known ones are ${detected\n .filter((target) => target.configPath !== undefined)\n .map((target) => target.id)\n .join(\", \")}`,\n { details: { client: options.client } },\n );\n }\n return ok({ id: named.id, configPath: named.configPath });\n }\n const chosen = chooseMcpClient(detected);\n if (!chosen.ok) return chosen;\n if (chosen.value.configPath === undefined) {\n return validationError(\"CLIENT_UNKNOWN\", `\\`${chosen.value.id}\\` has no config path on this platform`);\n }\n return ok({ id: chosen.value.id, configPath: chosen.value.configPath });\n}\n\n/**\n * Runs the command.\n *\n * Every failure is a `Result`, including a config file that will not parse. The\n * one thing this never does is write over something it could not read.\n */\nexport async function runConnect(options: ConnectOptions): Promise<Result<ConnectReport>> {\n const env = options.env ?? process.env;\n const logger = options.logger ?? silentLogger;\n const at = (options.now ?? (() => new Date()))();\n const dryRun = options.dryRun ?? false;\n\n const target = resolveTarget(options);\n if (!target.ok) return target;\n\n const read = readClientConfig(target.value.configPath);\n if (!read.ok) return read;\n\n const stanza = buildTabStanza(stanzaEnv(options.settings, env));\n const merged = mergeTabStanza(read.value.document, stanza);\n if (!merged.ok) return merged;\n\n const checked = await preflight(options.settings, options.fetchImpl, logger);\n\n const before = read.value.existed ? renderConfig(read.value.document) : \"\";\n const after = renderConfig(merged.value.merged);\n const diff = merged.value.changed ? unifiedDiff(before, after) : \"\";\n\n if (dryRun) {\n return ok({\n client: target.value.id,\n configPath: target.value.configPath,\n changed: merged.value.changed,\n hadStanza: merged.value.hadStanza,\n backupPath: undefined,\n stanza,\n diff,\n preflight: checked,\n dryRun: true,\n });\n }\n\n const written = writeClientConfig(target.value.configPath, merged.value, read.value.existed, at);\n if (!written.ok) return written;\n\n return ok({\n client: target.value.id,\n configPath: target.value.configPath,\n changed: written.value.wrote,\n hadStanza: merged.value.hadStanza,\n backupPath: written.value.backupPath,\n stanza,\n diff,\n preflight: checked,\n dryRun: false,\n });\n}\n"]}
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/cli/connect.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `tab connect`: the one line of configuration.\n *\n * The whole adoption story is this command. It finds the MCP client's server\n * list, reads the deployment keylessly so it can tell the caller what they are\n * about to be connected to, merges one `mcpServers.tab` stanza, backs up what\n * was there, and prints the diff.\n *\n * ## Read before write\n *\n * The keyless read happens first and its result is reported whether it succeeded\n * or not. A `connect` that silently wrote a stanza pointing at a registry that\n * does not answer would look like success and behave like a broken install, and\n * the person running it would find out from a model instead of from the command.\n * The read never blocks the write: a deployment that is temporarily down is not\n * a reason to refuse to configure a client against it.\n *\n * ## Nothing here is a secret\n *\n * The stanza carries a command, its arguments, and at most two URLs. Every value\n * in it is publishable. {@link assertNoSecret} runs over the `tab` stanza\n * before anything is written, so the property is enforced rather than asserted\n * in a comment.\n */\n\nimport type { Result } from \"../_shared/index.js\";\nimport { ok } from \"../_shared/index.js\";\n\nimport { validationError } from \"../errors.js\";\nimport type { Logger } from \"../logger.js\";\nimport { silentLogger } from \"../logger.js\";\nimport { asArray, field } from \"../mcp/json.js\";\nimport { createRegistryReadClient, type RegistryFetch } from \"../mcp/registry-client.js\";\nimport type { TabMcpSettings } from \"../mcp/settings.js\";\nimport {\n buildTabStanza,\n chooseMcpClient,\n detectMcpClients,\n mergeTabStanza,\n readClientConfig,\n renderConfig,\n unifiedDiff,\n writeClientConfig,\n type McpClientTarget,\n type StanzaEnv,\n type TabStanza,\n} from \"./client-config.js\";\n\nexport interface ConnectOptions {\n readonly settings: TabMcpSettings;\n /** `claude-code`, `claude-desktop`, `cursor`, `windsurf` or `vscode`. */\n readonly client?: string;\n /** An explicit config file, which beats `client` and skips detection. */\n readonly configPath?: string;\n readonly env?: NodeJS.ProcessEnv;\n readonly os?: string;\n readonly cwd?: string;\n /** Injectable clock, so a backup name is testable. */\n readonly now?: () => Date;\n /** Work out and print everything, and write nothing. */\n readonly dryRun?: boolean;\n readonly fetchImpl?: RegistryFetch;\n readonly logger?: Logger;\n}\n\n/** What the deployment said when it was asked, before anything was written. */\nexport interface ConnectPreflight {\n readonly registryUrl: string | undefined;\n /** Services indexed, or null when the read API did not answer. */\n readonly services: number | null;\n readonly note: string;\n}\n\nexport interface ConnectReport {\n readonly client: string;\n readonly configPath: string;\n /** False when the file already said exactly this. */\n readonly changed: boolean;\n /** True when a `tab` stanza was already there, so a message can say updated. */\n readonly hadStanza: boolean;\n readonly backupPath: string | undefined;\n readonly stanza: TabStanza;\n /** Empty when nothing changed. */\n readonly diff: string;\n readonly preflight: ConnectPreflight;\n readonly dryRun: boolean;\n}\n\n/** The environment values that belong in a stanza. Publishable, all of them. */\nfunction stanzaEnv(settings: TabMcpSettings, env: NodeJS.ProcessEnv): StanzaEnv {\n const values: Record<string, string> = {};\n const rpc = settings.rpcUrl ?? env[\"MONAD_RPC_URL\"];\n if (rpc !== undefined && rpc.trim() !== \"\") values[\"MONAD_RPC_URL\"] = rpc.trim();\n values[\"MONAD_CHAIN_ID\"] = String(settings.chainId);\n const registry = settings.registryUrl ?? env[\"NEXT_PUBLIC_REGISTRY_API_URL\"];\n if (registry !== undefined && registry.trim() !== \"\") values[\"NEXT_PUBLIC_REGISTRY_API_URL\"] = registry.trim();\n // An address is public, and without it tab_call has no Agent to meter against.\n const agent = env[\"AGENT_ADDRESS\"];\n if (agent !== undefined && agent.trim() !== \"\") values[\"AGENT_ADDRESS\"] = agent.trim();\n return values;\n}\n\n/** Reads the deployment, keylessly, so `connect` can say what it connected to. */\nasync function preflight(\n settings: TabMcpSettings,\n fetchImpl: RegistryFetch | undefined,\n logger: Logger,\n): Promise<ConnectPreflight> {\n if (settings.registryUrl === undefined) {\n return {\n registryUrl: undefined,\n services: null,\n note: \"no registry read API is configured, so discovery and status will not work until one is. Calling and settling do not need it\",\n };\n }\n const registry = createRegistryReadClient({\n baseUrl: settings.registryUrl,\n logger,\n ...(fetchImpl === undefined ? {} : { fetchImpl }),\n });\n const services = await registry.services(50);\n if (!services.ok) {\n return {\n registryUrl: registry.baseUrl,\n services: null,\n note: `the read API did not answer: ${services.error.message}`,\n };\n }\n const count = asArray(field(services.value, \"services\")).length;\n const lastBlock = field(field(services.value, \"index\"), \"lastBlock\");\n return {\n registryUrl: registry.baseUrl,\n services: count,\n note:\n typeof lastBlock === \"number\"\n ? `${count} Service(s) indexed at Monad block ${lastBlock}`\n : `${count} Service(s) indexed`,\n };\n}\n\n/** Resolves which file to write, from `--config`, then `--client`, then detection. */\nfunction resolveTarget(options: ConnectOptions): Result<{ id: string; configPath: string }> {\n if (options.configPath !== undefined) {\n return ok({ id: options.client ?? \"custom\", configPath: options.configPath });\n }\n const detected = detectMcpClients({\n ...(options.os === undefined ? {} : { os: options.os }),\n ...(options.env === undefined ? {} : { env: options.env }),\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n });\n if (options.client !== undefined) {\n const named: McpClientTarget | undefined = detected.find((target) => target.id === options.client);\n if (named === undefined || named.configPath === undefined) {\n return validationError(\n \"CLIENT_UNKNOWN\",\n `\\`${options.client}\\` is not an MCP client this command knows on this platform; the known ones are ${detected\n .filter((target) => target.configPath !== undefined)\n .map((target) => target.id)\n .join(\", \")}`,\n { details: { client: options.client } },\n );\n }\n return ok({ id: named.id, configPath: named.configPath });\n }\n const chosen = chooseMcpClient(detected);\n if (!chosen.ok) return chosen;\n if (chosen.value.configPath === undefined) {\n return validationError(\"CLIENT_UNKNOWN\", `\\`${chosen.value.id}\\` has no config path on this platform`);\n }\n return ok({ id: chosen.value.id, configPath: chosen.value.configPath });\n}\n\n/**\n * Runs the command.\n *\n * Every failure is a `Result`, including a config file that will not parse. The\n * one thing this never does is write over something it could not read.\n */\nexport async function runConnect(options: ConnectOptions): Promise<Result<ConnectReport>> {\n const env = options.env ?? process.env;\n const logger = options.logger ?? silentLogger;\n const at = (options.now ?? (() => new Date()))();\n const dryRun = options.dryRun ?? false;\n\n const target = resolveTarget(options);\n if (!target.ok) return target;\n\n const read = readClientConfig(target.value.configPath);\n if (!read.ok) return read;\n\n const stanza = buildTabStanza(stanzaEnv(options.settings, env));\n const merged = mergeTabStanza(read.value.document, stanza);\n if (!merged.ok) return merged;\n\n const checked = await preflight(options.settings, options.fetchImpl, logger);\n\n const before = read.value.existed ? renderConfig(read.value.document) : \"\";\n const after = renderConfig(merged.value.merged);\n const diff = merged.value.changed ? unifiedDiff(before, after) : \"\";\n\n if (dryRun) {\n return ok({\n client: target.value.id,\n configPath: target.value.configPath,\n changed: merged.value.changed,\n hadStanza: merged.value.hadStanza,\n backupPath: undefined,\n stanza,\n diff,\n preflight: checked,\n dryRun: true,\n });\n }\n\n const written = writeClientConfig(target.value.configPath, merged.value, read.value.existed, at);\n if (!written.ok) return written;\n\n return ok({\n client: target.value.id,\n configPath: target.value.configPath,\n changed: written.value.wrote,\n hadStanza: merged.value.hadStanza,\n backupPath: written.value.backupPath,\n stanza,\n diff,\n preflight: checked,\n dryRun: false,\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAYH,sEAAsE;AACtE,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAE9B,MAAM,WAAW,KAAK;IACpB,sGAAsG;IACtG,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,iCAAiC;IACjC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAOD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;IACpB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,+FAA+F;IAC/F,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CACnC;AA0UD,yEAAyE;AACzE,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAyC/F"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAYH,sEAAsE;AACtE,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAE9B,MAAM,WAAW,KAAK;IACpB,sGAAsG;IACtG,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,iCAAiC;IACjC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAOD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;IACpB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,+FAA+F;IAC/F,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CACnC;AA6UD,yEAAyE;AACzE,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAyC/F"}
package/dist/cli/main.js CHANGED
@@ -112,12 +112,15 @@ Environment
112
112
  MONAD_RPC_URL the Monad JSON-RPC endpoint
113
113
  MONAD_CHAIN_ID 143 for Mainnet, 10143 for Testnet
114
114
  NEXT_PUBLIC_REGISTRY_API_URL the Tab registry read API, which serves discovery and status
115
- AGENT_PRIVATE_KEY read only when a Settlement is signed, and never written anywhere
115
+ AGENT_ADDRESS the Agent tab_call meters against, when tab.config names none
116
+ AGENT_PRIVATE_KEY read only when a Settlement or a call to the hosted demo Service
117
+ is signed, and never written anywhere
116
118
 
117
119
  Configuration
118
120
  tab.config.ts beside your project declares the Agent address, the registry URL,
119
121
  the Service endpoints, and the payment strategies. The chain records no Service
120
- endpoint, so tab_call needs one from there.
122
+ endpoint, so tab_call needs one from there, except for the hosted demo Service,
123
+ which is known on both networks.
121
124
  `;
122
125
  // ---------------------------------------------------------------- commands
123
126
  async function settingsFor(flags, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `tab`: the executable entry point of this package.\n *\n * Five commands. `mcp` serves the four tools, and is what the `mcpServers`\n * stanza launches. `connect` writes that stanza. `doctor` checks the whole\n * installation without a key. `status` and `settle` are the two tools a person\n * reaches for outside a model, one to see what is owed and one to pay it.\n *\n * ## stdout belongs to the protocol\n *\n * Under `mcp` the process speaks MCP over stdout, so this file writes every\n * human-readable line to stderr and every machine-readable payload to stdout,\n * and the two never mix. `--json` on `status`, `settle` and `doctor` puts a\n * single JSON document on stdout and nothing else, which is what makes the\n * commands scriptable.\n *\n * ## `settle` does not broadcast unless it is told to\n *\n * A Settlement spends real funds, and a command that spends by default is a\n * command somebody runs to see what it does. So `tab settle` is a dry run unless\n * `--broadcast` is passed: it resolves the strategy, the Collection Address and\n * the surface, reports exactly what would be sent, and sends nothing. The MCP\n * tool has the same `dryRun` field for the same reason, defaulted the other way\n * because a model calling `tab_settle` has already decided.\n */\n\nimport type { Result } from \"../_shared/index.js\";\nimport { ok } from \"../_shared/index.js\";\n\nimport { validationError } from \"../errors.js\";\nimport { TAB_MCP_SERVER_INFO, createTabMcpServer, stderrLogger } from \"../mcp/server.js\";\nimport { resolveTabMcpSettings, type TabMcpSettings } from \"../mcp/settings.js\";\nimport { detectMcpClients } from \"./client-config.js\";\nimport { runConnect } from \"./connect.js\";\nimport { runDoctor, type CheckStatus, type DoctorReport } from \"./doctor.js\";\n\n/** The name the help text uses. `npx @tabai/sdk` resolves to this. */\nexport const CLI_NAME = \"tab\";\n\nexport interface CliIo {\n /** Machine-readable output. Under `mcp` this is the protocol stream and nothing else writes to it. */\n out(line: string): void;\n /** Everything a person reads. */\n err(line: string): void;\n}\n\nconst processIo: CliIo = {\n out: (line) => process.stdout.write(`${line}\\n`),\n err: (line) => process.stderr.write(`${line}\\n`),\n};\n\nexport interface CliOptions {\n readonly io?: CliIo;\n readonly env?: NodeJS.ProcessEnv;\n readonly cwd?: string;\n /** Blocks `settle --broadcast`, the one command that spends, so a test can never broadcast. */\n readonly allowBroadcast?: boolean;\n}\n\n// ---------------------------------------------------------------- flags\n\n/** A flag parse. Everything is `--name value` or `--name` for a boolean. */\ninterface Flags {\n readonly positional: readonly string[];\n readonly values: Readonly<Record<string, string>>;\n readonly booleans: ReadonlySet<string>;\n}\n\nconst BOOLEAN_FLAGS = new Set([\"help\", \"version\", \"json\", \"dry-run\", \"broadcast\", \"http\"]);\n\nfunction parseFlags(argv: readonly string[]): Result<Flags> {\n const positional: string[] = [];\n const values: Record<string, string> = {};\n const booleans = new Set<string>();\n\n for (let index = 0; index < argv.length; index += 1) {\n const token = argv[index]!;\n if (!token.startsWith(\"--\")) {\n positional.push(token);\n continue;\n }\n const body = token.slice(2);\n const equals = body.indexOf(\"=\");\n if (equals >= 0) {\n values[body.slice(0, equals)] = body.slice(equals + 1);\n continue;\n }\n const next = argv[index + 1];\n if (BOOLEAN_FLAGS.has(body) && (next === undefined || next.startsWith(\"--\"))) {\n booleans.add(body);\n continue;\n }\n if (next === undefined || next.startsWith(\"--\")) {\n if (BOOLEAN_FLAGS.has(body)) {\n booleans.add(body);\n continue;\n }\n return validationError(\"FLAG_VALUE_MISSING\", `\\`--${body}\\` needs a value`, { details: { flag: body } });\n }\n values[body] = next;\n index += 1;\n }\n return ok({ positional, values, booleans });\n}\n\n// ---------------------------------------------------------------- rendering\n\n/** Fixed-width so the check names line up in a terminal. */\nconst markOf = (status: CheckStatus): string =>\n status === \"pass\" ? \" ok \" : status === \"warn\" ? \" warn \" : status === \"fail\" ? \" FAIL \" : \" skip \";\n\nfunction renderDoctor(report: DoctorReport, io: CliIo): void {\n io.err(\"\");\n for (const check of report.checks) {\n io.err(`[${markOf(check.status)}] ${check.name}: ${check.detail}`);\n if (check.hint !== undefined) io.err(` ${check.hint}`);\n }\n io.err(\"\");\n io.err(\n `${report.counts.pass} passed, ${report.counts.warn} warned, ${report.counts.fail} failed, ${report.counts.skip} skipped`,\n );\n io.err(report.ok ? \"This installation can read the deployment.\" : \"This installation is not usable as configured.\");\n}\n\nconst HELP = `${CLI_NAME} - post-paid billing for autonomous agents on Monad\n\nUsage\n npx -y @tabai/sdk <command> [options]\n\nCommands\n mcp Serve the four Tab tools over MCP. This is what an MCP client launches.\n connect Write the tab server into an MCP client's config. Never writes a key.\n doctor Check the installation. Every check is a keyless read.\n status What the Agent owes, may still spend, and has settled.\n settle Pay down an Open Tab. A dry run unless --broadcast is given.\n\nOptions\n mcp --http [--port <n>] [--host <h>] [--endpoint <p>] serve streamable HTTP instead of stdio\n connect --client <id> | --config <path> | --dry-run\n clients: ${detectMcpClients()\n .filter((target) => target.configPath !== undefined)\n .map((target) => target.id)\n .join(\", \")}\n doctor --client <id> | --config <path> | --json\n status --agent <0x..> --asset <chainId:0x..> --history-limit <n> --json\n settle --service <0x..> --asset <chainId:0x..> --amount <baseUnits>\n --strategy <id> --broadcast --json\n\nEnvironment\n MONAD_RPC_URL the Monad JSON-RPC endpoint\n MONAD_CHAIN_ID 143 for Mainnet, 10143 for Testnet\n NEXT_PUBLIC_REGISTRY_API_URL the Tab registry read API, which serves discovery and status\n AGENT_PRIVATE_KEY read only when a Settlement is signed, and never written anywhere\n\nConfiguration\n tab.config.ts beside your project declares the Agent address, the registry URL,\n the Service endpoints, and the payment strategies. The chain records no Service\n endpoint, so tab_call needs one from there.\n`;\n\n// ---------------------------------------------------------------- commands\n\nasync function settingsFor(flags: Flags, options: CliOptions): Promise<TabMcpSettings> {\n return resolveTabMcpSettings({\n ...(flags.values[\"agent\"] === undefined ? {} : { agent: flags.values[\"agent\"] }),\n ...(flags.values[\"registry-url\"] === undefined ? {} : { registryUrl: flags.values[\"registry-url\"] }),\n ...(flags.values[\"rpc-url\"] === undefined ? {} : { rpcUrl: flags.values[\"rpc-url\"] }),\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n ...(options.env === undefined ? {} : { env: options.env }),\n logger: stderrLogger,\n });\n}\n\nasync function commandMcp(flags: Flags, options: CliOptions): Promise<number> {\n const io = options.io ?? processIo;\n const server = await createTabMcpServer({\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n ...(options.env === undefined ? {} : { env: options.env }),\n logger: stderrLogger,\n });\n\n if (flags.booleans.has(\"http\") || flags.values[\"port\"] !== undefined) {\n const port = Number.parseInt(flags.values[\"port\"] ?? \"8790\", 10);\n if (!Number.isInteger(port) || port < 1 || port > 65_535) {\n io.err(`tab: --port must be a TCP port, received \\`${flags.values[\"port\"] ?? \"\"}\\``);\n return 1;\n }\n const served = await server.serveHttp({\n port,\n ...(flags.values[\"host\"] === undefined ? {} : { host: flags.values[\"host\"] }),\n ...(flags.values[\"endpoint\"] === undefined ? {} : { endpoint: flags.values[\"endpoint\"] }),\n });\n if (!served.ok) {\n io.err(`tab: ${served.error.message}`);\n return 1;\n }\n io.err(`tab: MCP over streamable HTTP at http://${served.value.host}:${served.value.port}${served.value.endpoint}`);\n // Held open by the listening socket. The process exits when it is closed.\n return 0;\n }\n\n const served = await server.serveStdio();\n if (!served.ok) {\n io.err(`tab: ${served.error.message}`);\n return 1;\n }\n return 0;\n}\n\nasync function commandConnect(flags: Flags, options: CliOptions): Promise<number> {\n const io = options.io ?? processIo;\n const settings = await settingsFor(flags, options);\n const report = await runConnect({\n settings,\n ...(flags.values[\"client\"] === undefined ? {} : { client: flags.values[\"client\"] }),\n ...(flags.values[\"config\"] === undefined ? {} : { configPath: flags.values[\"config\"] }),\n ...(options.env === undefined ? {} : { env: options.env }),\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n dryRun: flags.booleans.has(\"dry-run\"),\n logger: stderrLogger,\n });\n\n if (!report.ok) {\n io.err(`tab connect: ${report.error.message}`);\n return 1;\n }\n\n const value = report.value;\n io.err(\"\");\n io.err(`Client ${value.client}`);\n io.err(`Config ${value.configPath}`);\n io.err(`Registry ${value.preflight.registryUrl ?? \"not configured\"}`);\n io.err(` ${value.preflight.note}`);\n io.err(\"\");\n\n if (!value.changed) {\n io.err(`Already connected. \\`${value.configPath}\\` already runs the tab server, so nothing was written.`);\n } else if (value.dryRun) {\n io.err(\"Dry run. Nothing was written. This is the change that would be made:\");\n io.err(\"\");\n io.err(value.diff);\n } else {\n io.err(value.hadStanza ? \"Updated the tab server stanza.\" : \"Added the tab server stanza.\");\n if (value.backupPath !== undefined) io.err(`Backed up the previous config to ${value.backupPath}`);\n io.err(\"\");\n io.err(value.diff);\n }\n\n io.err(\"\");\n io.err(\"No private key was written. Settlement signing keys are read from the environment at run time.\");\n io.err(\"\");\n io.err(\"Next\");\n io.err(\n value.client === \"custom\"\n ? \" 1. Restart the client that reads that file, so it picks up the new server.\"\n : ` 1. Restart ${value.client} so it picks up the new server.`,\n );\n io.err(\" 2. Ask it to run tab_discover, which lists the Services registered on Monad.\");\n io.err(` 3. Check the whole installation with: npx -y @tabai/sdk doctor --config ${value.configPath}`);\n return 0;\n}\n\nasync function commandDoctor(flags: Flags, options: CliOptions): Promise<number> {\n const io = options.io ?? processIo;\n const settings = await settingsFor(flags, options);\n\n let clientConfigPath = flags.values[\"config\"];\n if (clientConfigPath === undefined) {\n const detected = detectMcpClients({\n ...(options.env === undefined ? {} : { env: options.env }),\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n });\n const named = flags.values[\"client\"];\n const chosen = named === undefined ? detected.find((t) => t.present) : detected.find((t) => t.id === named);\n clientConfigPath = chosen?.configPath;\n }\n\n const report = await runDoctor({\n settings,\n ...(options.env === undefined ? {} : { env: options.env }),\n ...(clientConfigPath === undefined ? {} : { clientConfigPath }),\n logger: stderrLogger,\n });\n\n if (flags.booleans.has(\"json\")) {\n io.out(JSON.stringify(report, null, 2));\n } else {\n renderDoctor(report, io);\n }\n return report.ok ? 0 : 1;\n}\n\nasync function commandStatus(flags: Flags, options: CliOptions): Promise<number> {\n const io = options.io ?? processIo;\n const settings = await settingsFor(flags, options);\n const server = await createTabMcpServer({ settings, logger: stderrLogger });\n\n const output = await server.toolset.status({\n ...(flags.values[\"agent\"] === undefined ? {} : { agent: flags.values[\"agent\"] }),\n ...(flags.values[\"asset\"] === undefined ? {} : { asset: flags.values[\"asset\"] }),\n ...(flags.values[\"history-limit\"] === undefined\n ? {}\n : { historyLimit: Number.parseInt(flags.values[\"history-limit\"], 10) }),\n });\n\n if (flags.booleans.has(\"json\")) {\n io.out(JSON.stringify(output, null, 2));\n return output.error === undefined ? 0 : 1;\n }\n\n io.err(\"\");\n io.err(`Agent ${output.agent}`);\n if (output.error !== undefined) {\n io.err(` ${output.error.code}: ${output.error.message}`);\n return 1;\n }\n if (output.perAsset.length === 0) io.err(\" no Asset activity is indexed for this Agent\");\n for (const entry of output.perAsset) {\n io.err(` ${entry.asset}`);\n io.err(` credit limit ${entry.creditLimitBaseUnits ?? \"withheld\"}`);\n io.err(` open tab ${entry.openTabBaseUnits}`);\n io.err(` headroom ${entry.headroomBaseUnits ?? \"withheld\"}`);\n io.err(` delinquent ${String(entry.delinquent)}`);\n }\n io.err(` settlements ${output.settlements?.length ?? 0}`);\n for (const settlement of output.settlements ?? []) {\n io.err(` ${settlement.txHash} ${settlement.amountBaseUnits} ${settlement.asset}`);\n }\n return 0;\n}\n\nasync function commandSettle(flags: Flags, options: CliOptions): Promise<number> {\n const io = options.io ?? processIo;\n const broadcast = flags.booleans.has(\"broadcast\");\n\n if (broadcast && options.allowBroadcast === false) {\n io.err(\"tab settle: broadcasting is disabled in this process\");\n return 1;\n }\n\n // The strategy comes from `tab.config`, loaded by the toolset the first time a\n // Settlement needs one. Nothing is loaded here, so a dry run that fails for\n // another reason never touches a signer.\n const settings = await settingsFor(flags, options);\n const server = await createTabMcpServer({\n settings,\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n logger: stderrLogger,\n });\n\n const output = await server.toolset.settle({\n ...(flags.values[\"service\"] === undefined ? {} : { serviceId: flags.values[\"service\"] }),\n ...(flags.values[\"asset\"] === undefined ? {} : { asset: flags.values[\"asset\"] }),\n ...(flags.values[\"amount\"] === undefined ? {} : { amountBaseUnits: flags.values[\"amount\"] }),\n ...(flags.values[\"strategy\"] === undefined ? {} : { strategyId: flags.values[\"strategy\"] }),\n dryRun: !broadcast,\n });\n\n if (flags.booleans.has(\"json\")) {\n io.out(JSON.stringify(output, null, 2));\n return output.ok ? 0 : 1;\n }\n\n io.err(\"\");\n if (!output.ok) {\n io.err(`tab settle: ${output.error?.code ?? \"FAILED\"}: ${output.error?.message ?? \"the Settlement was not built\"}`);\n return 1;\n }\n if (output.dryRun) {\n io.err(\"Dry run. Nothing was broadcast.\");\n io.err(` chain id ${String(output.chainId)}`);\n io.err(` amount ${output.amountBaseUnits}`);\n io.err(\"\");\n io.err(\"Add --broadcast to send it. This spends real funds.\");\n return 0;\n }\n io.err(\"Broadcast.\");\n io.err(` tx ${output.txHash ?? \"unknown\"}`);\n io.err(` amount ${output.amountBaseUnits}`);\n io.err(` applied ${output.appliedBaseUnits ?? \"pending\"}`);\n io.err(` prepaid ${output.prepaidBaseUnits ?? \"pending\"}`);\n io.err(` explorer ${output.explorerUrl ?? \"unknown\"}`);\n return 0;\n}\n\n// ---------------------------------------------------------------- entry\n\n/** Runs one invocation and answers a process exit code. Never throws. */\nexport async function runCli(argv: readonly string[], options: CliOptions = {}): Promise<number> {\n const io = options.io ?? processIo;\n const parsed = parseFlags(argv);\n if (!parsed.ok) {\n io.err(`tab: ${parsed.error.message}`);\n return 1;\n }\n const flags = parsed.value;\n const command = flags.positional[0];\n\n if (flags.booleans.has(\"version\")) {\n io.out(TAB_MCP_SERVER_INFO.version);\n return 0;\n }\n if (command === undefined || flags.booleans.has(\"help\") || command === \"help\") {\n io.err(HELP);\n return command === undefined || command === \"help\" || flags.booleans.has(\"help\") ? 0 : 1;\n }\n\n try {\n switch (command) {\n case \"mcp\":\n return await commandMcp(flags, options);\n case \"connect\":\n return await commandConnect(flags, options);\n case \"doctor\":\n return await commandDoctor(flags, options);\n case \"status\":\n return await commandStatus(flags, options);\n case \"settle\":\n return await commandSettle(flags, options);\n default:\n io.err(`tab: \\`${command}\\` is not a command. Run \\`${CLI_NAME} help\\` for the list.`);\n return 1;\n }\n } catch (error) {\n // The commands are written not to reach here. A bug that does should still\n // leave a message and an exit code rather than an unhandled rejection.\n io.err(`tab: ${command} failed unexpectedly: ${error instanceof Error ? error.message : String(error)}`);\n return 1;\n }\n}\n"]}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `tab`: the executable entry point of this package.\n *\n * Five commands. `mcp` serves the four tools, and is what the `mcpServers`\n * stanza launches. `connect` writes that stanza. `doctor` checks the whole\n * installation without a key. `status` and `settle` are the two tools a person\n * reaches for outside a model, one to see what is owed and one to pay it.\n *\n * ## stdout belongs to the protocol\n *\n * Under `mcp` the process speaks MCP over stdout, so this file writes every\n * human-readable line to stderr and every machine-readable payload to stdout,\n * and the two never mix. `--json` on `status`, `settle` and `doctor` puts a\n * single JSON document on stdout and nothing else, which is what makes the\n * commands scriptable.\n *\n * ## `settle` does not broadcast unless it is told to\n *\n * A Settlement spends real funds, and a command that spends by default is a\n * command somebody runs to see what it does. So `tab settle` is a dry run unless\n * `--broadcast` is passed: it resolves the strategy, the Collection Address and\n * the surface, reports exactly what would be sent, and sends nothing. The MCP\n * tool has the same `dryRun` field for the same reason, defaulted the other way\n * because a model calling `tab_settle` has already decided.\n */\n\nimport type { Result } from \"../_shared/index.js\";\nimport { ok } from \"../_shared/index.js\";\n\nimport { validationError } from \"../errors.js\";\nimport { TAB_MCP_SERVER_INFO, createTabMcpServer, stderrLogger } from \"../mcp/server.js\";\nimport { resolveTabMcpSettings, type TabMcpSettings } from \"../mcp/settings.js\";\nimport { detectMcpClients } from \"./client-config.js\";\nimport { runConnect } from \"./connect.js\";\nimport { runDoctor, type CheckStatus, type DoctorReport } from \"./doctor.js\";\n\n/** The name the help text uses. `npx @tabai/sdk` resolves to this. */\nexport const CLI_NAME = \"tab\";\n\nexport interface CliIo {\n /** Machine-readable output. Under `mcp` this is the protocol stream and nothing else writes to it. */\n out(line: string): void;\n /** Everything a person reads. */\n err(line: string): void;\n}\n\nconst processIo: CliIo = {\n out: (line) => process.stdout.write(`${line}\\n`),\n err: (line) => process.stderr.write(`${line}\\n`),\n};\n\nexport interface CliOptions {\n readonly io?: CliIo;\n readonly env?: NodeJS.ProcessEnv;\n readonly cwd?: string;\n /** Blocks `settle --broadcast`, the one command that spends, so a test can never broadcast. */\n readonly allowBroadcast?: boolean;\n}\n\n// ---------------------------------------------------------------- flags\n\n/** A flag parse. Everything is `--name value` or `--name` for a boolean. */\ninterface Flags {\n readonly positional: readonly string[];\n readonly values: Readonly<Record<string, string>>;\n readonly booleans: ReadonlySet<string>;\n}\n\nconst BOOLEAN_FLAGS = new Set([\"help\", \"version\", \"json\", \"dry-run\", \"broadcast\", \"http\"]);\n\nfunction parseFlags(argv: readonly string[]): Result<Flags> {\n const positional: string[] = [];\n const values: Record<string, string> = {};\n const booleans = new Set<string>();\n\n for (let index = 0; index < argv.length; index += 1) {\n const token = argv[index]!;\n if (!token.startsWith(\"--\")) {\n positional.push(token);\n continue;\n }\n const body = token.slice(2);\n const equals = body.indexOf(\"=\");\n if (equals >= 0) {\n values[body.slice(0, equals)] = body.slice(equals + 1);\n continue;\n }\n const next = argv[index + 1];\n if (BOOLEAN_FLAGS.has(body) && (next === undefined || next.startsWith(\"--\"))) {\n booleans.add(body);\n continue;\n }\n if (next === undefined || next.startsWith(\"--\")) {\n if (BOOLEAN_FLAGS.has(body)) {\n booleans.add(body);\n continue;\n }\n return validationError(\"FLAG_VALUE_MISSING\", `\\`--${body}\\` needs a value`, { details: { flag: body } });\n }\n values[body] = next;\n index += 1;\n }\n return ok({ positional, values, booleans });\n}\n\n// ---------------------------------------------------------------- rendering\n\n/** Fixed-width so the check names line up in a terminal. */\nconst markOf = (status: CheckStatus): string =>\n status === \"pass\" ? \" ok \" : status === \"warn\" ? \" warn \" : status === \"fail\" ? \" FAIL \" : \" skip \";\n\nfunction renderDoctor(report: DoctorReport, io: CliIo): void {\n io.err(\"\");\n for (const check of report.checks) {\n io.err(`[${markOf(check.status)}] ${check.name}: ${check.detail}`);\n if (check.hint !== undefined) io.err(` ${check.hint}`);\n }\n io.err(\"\");\n io.err(\n `${report.counts.pass} passed, ${report.counts.warn} warned, ${report.counts.fail} failed, ${report.counts.skip} skipped`,\n );\n io.err(report.ok ? \"This installation can read the deployment.\" : \"This installation is not usable as configured.\");\n}\n\nconst HELP = `${CLI_NAME} - post-paid billing for autonomous agents on Monad\n\nUsage\n npx -y @tabai/sdk <command> [options]\n\nCommands\n mcp Serve the four Tab tools over MCP. This is what an MCP client launches.\n connect Write the tab server into an MCP client's config. Never writes a key.\n doctor Check the installation. Every check is a keyless read.\n status What the Agent owes, may still spend, and has settled.\n settle Pay down an Open Tab. A dry run unless --broadcast is given.\n\nOptions\n mcp --http [--port <n>] [--host <h>] [--endpoint <p>] serve streamable HTTP instead of stdio\n connect --client <id> | --config <path> | --dry-run\n clients: ${detectMcpClients()\n .filter((target) => target.configPath !== undefined)\n .map((target) => target.id)\n .join(\", \")}\n doctor --client <id> | --config <path> | --json\n status --agent <0x..> --asset <chainId:0x..> --history-limit <n> --json\n settle --service <0x..> --asset <chainId:0x..> --amount <baseUnits>\n --strategy <id> --broadcast --json\n\nEnvironment\n MONAD_RPC_URL the Monad JSON-RPC endpoint\n MONAD_CHAIN_ID 143 for Mainnet, 10143 for Testnet\n NEXT_PUBLIC_REGISTRY_API_URL the Tab registry read API, which serves discovery and status\n AGENT_ADDRESS the Agent tab_call meters against, when tab.config names none\n AGENT_PRIVATE_KEY read only when a Settlement or a call to the hosted demo Service\n is signed, and never written anywhere\n\nConfiguration\n tab.config.ts beside your project declares the Agent address, the registry URL,\n the Service endpoints, and the payment strategies. The chain records no Service\n endpoint, so tab_call needs one from there, except for the hosted demo Service,\n which is known on both networks.\n`;\n\n// ---------------------------------------------------------------- commands\n\nasync function settingsFor(flags: Flags, options: CliOptions): Promise<TabMcpSettings> {\n return resolveTabMcpSettings({\n ...(flags.values[\"agent\"] === undefined ? {} : { agent: flags.values[\"agent\"] }),\n ...(flags.values[\"registry-url\"] === undefined ? {} : { registryUrl: flags.values[\"registry-url\"] }),\n ...(flags.values[\"rpc-url\"] === undefined ? {} : { rpcUrl: flags.values[\"rpc-url\"] }),\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n ...(options.env === undefined ? {} : { env: options.env }),\n logger: stderrLogger,\n });\n}\n\nasync function commandMcp(flags: Flags, options: CliOptions): Promise<number> {\n const io = options.io ?? processIo;\n const server = await createTabMcpServer({\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n ...(options.env === undefined ? {} : { env: options.env }),\n logger: stderrLogger,\n });\n\n if (flags.booleans.has(\"http\") || flags.values[\"port\"] !== undefined) {\n const port = Number.parseInt(flags.values[\"port\"] ?? \"8790\", 10);\n if (!Number.isInteger(port) || port < 1 || port > 65_535) {\n io.err(`tab: --port must be a TCP port, received \\`${flags.values[\"port\"] ?? \"\"}\\``);\n return 1;\n }\n const served = await server.serveHttp({\n port,\n ...(flags.values[\"host\"] === undefined ? {} : { host: flags.values[\"host\"] }),\n ...(flags.values[\"endpoint\"] === undefined ? {} : { endpoint: flags.values[\"endpoint\"] }),\n });\n if (!served.ok) {\n io.err(`tab: ${served.error.message}`);\n return 1;\n }\n io.err(`tab: MCP over streamable HTTP at http://${served.value.host}:${served.value.port}${served.value.endpoint}`);\n // Held open by the listening socket. The process exits when it is closed.\n return 0;\n }\n\n const served = await server.serveStdio();\n if (!served.ok) {\n io.err(`tab: ${served.error.message}`);\n return 1;\n }\n return 0;\n}\n\nasync function commandConnect(flags: Flags, options: CliOptions): Promise<number> {\n const io = options.io ?? processIo;\n const settings = await settingsFor(flags, options);\n const report = await runConnect({\n settings,\n ...(flags.values[\"client\"] === undefined ? {} : { client: flags.values[\"client\"] }),\n ...(flags.values[\"config\"] === undefined ? {} : { configPath: flags.values[\"config\"] }),\n ...(options.env === undefined ? {} : { env: options.env }),\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n dryRun: flags.booleans.has(\"dry-run\"),\n logger: stderrLogger,\n });\n\n if (!report.ok) {\n io.err(`tab connect: ${report.error.message}`);\n return 1;\n }\n\n const value = report.value;\n io.err(\"\");\n io.err(`Client ${value.client}`);\n io.err(`Config ${value.configPath}`);\n io.err(`Registry ${value.preflight.registryUrl ?? \"not configured\"}`);\n io.err(` ${value.preflight.note}`);\n io.err(\"\");\n\n if (!value.changed) {\n io.err(`Already connected. \\`${value.configPath}\\` already runs the tab server, so nothing was written.`);\n } else if (value.dryRun) {\n io.err(\"Dry run. Nothing was written. This is the change that would be made:\");\n io.err(\"\");\n io.err(value.diff);\n } else {\n io.err(value.hadStanza ? \"Updated the tab server stanza.\" : \"Added the tab server stanza.\");\n if (value.backupPath !== undefined) io.err(`Backed up the previous config to ${value.backupPath}`);\n io.err(\"\");\n io.err(value.diff);\n }\n\n io.err(\"\");\n io.err(\"No private key was written. Settlement signing keys are read from the environment at run time.\");\n io.err(\"\");\n io.err(\"Next\");\n io.err(\n value.client === \"custom\"\n ? \" 1. Restart the client that reads that file, so it picks up the new server.\"\n : ` 1. Restart ${value.client} so it picks up the new server.`,\n );\n io.err(\" 2. Ask it to run tab_discover, which lists the Services registered on Monad.\");\n io.err(` 3. Check the whole installation with: npx -y @tabai/sdk doctor --config ${value.configPath}`);\n return 0;\n}\n\nasync function commandDoctor(flags: Flags, options: CliOptions): Promise<number> {\n const io = options.io ?? processIo;\n const settings = await settingsFor(flags, options);\n\n let clientConfigPath = flags.values[\"config\"];\n if (clientConfigPath === undefined) {\n const detected = detectMcpClients({\n ...(options.env === undefined ? {} : { env: options.env }),\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n });\n const named = flags.values[\"client\"];\n const chosen = named === undefined ? detected.find((t) => t.present) : detected.find((t) => t.id === named);\n clientConfigPath = chosen?.configPath;\n }\n\n const report = await runDoctor({\n settings,\n ...(options.env === undefined ? {} : { env: options.env }),\n ...(clientConfigPath === undefined ? {} : { clientConfigPath }),\n logger: stderrLogger,\n });\n\n if (flags.booleans.has(\"json\")) {\n io.out(JSON.stringify(report, null, 2));\n } else {\n renderDoctor(report, io);\n }\n return report.ok ? 0 : 1;\n}\n\nasync function commandStatus(flags: Flags, options: CliOptions): Promise<number> {\n const io = options.io ?? processIo;\n const settings = await settingsFor(flags, options);\n const server = await createTabMcpServer({ settings, logger: stderrLogger });\n\n const output = await server.toolset.status({\n ...(flags.values[\"agent\"] === undefined ? {} : { agent: flags.values[\"agent\"] }),\n ...(flags.values[\"asset\"] === undefined ? {} : { asset: flags.values[\"asset\"] }),\n ...(flags.values[\"history-limit\"] === undefined\n ? {}\n : { historyLimit: Number.parseInt(flags.values[\"history-limit\"], 10) }),\n });\n\n if (flags.booleans.has(\"json\")) {\n io.out(JSON.stringify(output, null, 2));\n return output.error === undefined ? 0 : 1;\n }\n\n io.err(\"\");\n io.err(`Agent ${output.agent}`);\n if (output.error !== undefined) {\n io.err(` ${output.error.code}: ${output.error.message}`);\n return 1;\n }\n if (output.perAsset.length === 0) io.err(\" no Asset activity is indexed for this Agent\");\n for (const entry of output.perAsset) {\n io.err(` ${entry.asset}`);\n io.err(` credit limit ${entry.creditLimitBaseUnits ?? \"withheld\"}`);\n io.err(` open tab ${entry.openTabBaseUnits}`);\n io.err(` headroom ${entry.headroomBaseUnits ?? \"withheld\"}`);\n io.err(` delinquent ${String(entry.delinquent)}`);\n }\n io.err(` settlements ${output.settlements?.length ?? 0}`);\n for (const settlement of output.settlements ?? []) {\n io.err(` ${settlement.txHash} ${settlement.amountBaseUnits} ${settlement.asset}`);\n }\n return 0;\n}\n\nasync function commandSettle(flags: Flags, options: CliOptions): Promise<number> {\n const io = options.io ?? processIo;\n const broadcast = flags.booleans.has(\"broadcast\");\n\n if (broadcast && options.allowBroadcast === false) {\n io.err(\"tab settle: broadcasting is disabled in this process\");\n return 1;\n }\n\n // The strategy comes from `tab.config`, loaded by the toolset the first time a\n // Settlement needs one. Nothing is loaded here, so a dry run that fails for\n // another reason never touches a signer.\n const settings = await settingsFor(flags, options);\n const server = await createTabMcpServer({\n settings,\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n logger: stderrLogger,\n });\n\n const output = await server.toolset.settle({\n ...(flags.values[\"service\"] === undefined ? {} : { serviceId: flags.values[\"service\"] }),\n ...(flags.values[\"asset\"] === undefined ? {} : { asset: flags.values[\"asset\"] }),\n ...(flags.values[\"amount\"] === undefined ? {} : { amountBaseUnits: flags.values[\"amount\"] }),\n ...(flags.values[\"strategy\"] === undefined ? {} : { strategyId: flags.values[\"strategy\"] }),\n dryRun: !broadcast,\n });\n\n if (flags.booleans.has(\"json\")) {\n io.out(JSON.stringify(output, null, 2));\n return output.ok ? 0 : 1;\n }\n\n io.err(\"\");\n if (!output.ok) {\n io.err(`tab settle: ${output.error?.code ?? \"FAILED\"}: ${output.error?.message ?? \"the Settlement was not built\"}`);\n return 1;\n }\n if (output.dryRun) {\n io.err(\"Dry run. Nothing was broadcast.\");\n io.err(` chain id ${String(output.chainId)}`);\n io.err(` amount ${output.amountBaseUnits}`);\n io.err(\"\");\n io.err(\"Add --broadcast to send it. This spends real funds.\");\n return 0;\n }\n io.err(\"Broadcast.\");\n io.err(` tx ${output.txHash ?? \"unknown\"}`);\n io.err(` amount ${output.amountBaseUnits}`);\n io.err(` applied ${output.appliedBaseUnits ?? \"pending\"}`);\n io.err(` prepaid ${output.prepaidBaseUnits ?? \"pending\"}`);\n io.err(` explorer ${output.explorerUrl ?? \"unknown\"}`);\n return 0;\n}\n\n// ---------------------------------------------------------------- entry\n\n/** Runs one invocation and answers a process exit code. Never throws. */\nexport async function runCli(argv: readonly string[], options: CliOptions = {}): Promise<number> {\n const io = options.io ?? processIo;\n const parsed = parseFlags(argv);\n if (!parsed.ok) {\n io.err(`tab: ${parsed.error.message}`);\n return 1;\n }\n const flags = parsed.value;\n const command = flags.positional[0];\n\n if (flags.booleans.has(\"version\")) {\n io.out(TAB_MCP_SERVER_INFO.version);\n return 0;\n }\n if (command === undefined || flags.booleans.has(\"help\") || command === \"help\") {\n io.err(HELP);\n return command === undefined || command === \"help\" || flags.booleans.has(\"help\") ? 0 : 1;\n }\n\n try {\n switch (command) {\n case \"mcp\":\n return await commandMcp(flags, options);\n case \"connect\":\n return await commandConnect(flags, options);\n case \"doctor\":\n return await commandDoctor(flags, options);\n case \"status\":\n return await commandStatus(flags, options);\n case \"settle\":\n return await commandSettle(flags, options);\n default:\n io.err(`tab: \\`${command}\\` is not a command. Run \\`${CLI_NAME} help\\` for the list.`);\n return 1;\n }\n } catch (error) {\n // The commands are written not to reach here. A bug that does should still\n // leave a message and an exit code rather than an unhandled rejection.\n io.err(`tab: ${command} failed unexpectedly: ${error instanceof Error ? error.message : String(error)}`);\n return 1;\n }\n}\n"]}
@@ -25,6 +25,12 @@
25
25
  * is signed, by the strategy that signs it, and never travels through a config
26
26
  * file or an MCP client's `mcpServers` stanza. That is what makes `tab connect`
27
27
  * safe to run against a file the client software rewrites.
28
+ *
29
+ * The hosted demo Service is the one place a key is used outside a Settlement:
30
+ * its gateway refuses an unsigned metered call, so the entry this module fills
31
+ * in signs each call with `AGENT_PRIVATE_KEY`, read at the moment the call is
32
+ * signed and only when that key is the Agent the call is metered against. The
33
+ * Agent itself is an address, from `AGENT_ADDRESS` when nothing else names one.
28
34
  */
29
35
  import type { Address } from "../_shared/index.js";
30
36
  import type { TabServiceEntry } from "../payments/config.js";
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/mcp/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,wFAAwF;IACxF,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,0FAA0F;IAC1F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC7C,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACpD;AAED,8EAA8E;AAC9E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAC/C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,iBAAiB,CAAC;IAClC,6EAA6E;IAC7E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;IACpC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,oCAAoC,CAAC;AAEtE,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAsCtC;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,cAAc,CAAC,CA6HzB"}
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/mcp/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAI7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,wFAAwF;IACxF,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,0FAA0F;IAC1F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC7C,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACpD;AAED,8EAA8E;AAC9E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAC/C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,iBAAiB,CAAC;IAClC,6EAA6E;IAC7E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;IACpC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,oCAAoC,CAAC;AAEtE,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAsCtC;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,cAAc,CAAC,CAoJzB"}
@@ -25,10 +25,18 @@
25
25
  * is signed, by the strategy that signs it, and never travels through a config
26
26
  * file or an MCP client's `mcpServers` stanza. That is what makes `tab connect`
27
27
  * safe to run against a file the client software rewrites.
28
+ *
29
+ * The hosted demo Service is the one place a key is used outside a Settlement:
30
+ * its gateway refuses an unsigned metered call, so the entry this module fills
31
+ * in signs each call with `AGENT_PRIVATE_KEY`, read at the moment the call is
32
+ * signed and only when that key is the Agent the call is metered against. The
33
+ * Agent itself is an address, from `AGENT_ADDRESS` when nothing else names one.
28
34
  */
29
35
  import { CHAINS, TAB_HOSTED, isAddress, isMonadChainId } from "../_shared/index.js";
36
+ import { Wallet } from "ethers";
30
37
  import { loadTabConfig } from "../payments/config.js";
31
38
  import { defaultLogger } from "../logger.js";
39
+ import { agentSignedMetering } from "../http/metering-claim.js";
32
40
  /** The public Monad Testnet explorer, used when nothing names one. */
33
41
  export const DEFAULT_EXPLORER_URL = "https://testnet.monadvision.com";
34
42
  /** Monad Testnet, used when nothing names a chain. */
@@ -119,7 +127,8 @@ export async function resolveTabMcpSettings(options = {}) {
119
127
  }
120
128
  return undefined;
121
129
  };
122
- const rawAgent = pick("agent", options.agent, config.agent, undefined);
130
+ const envAgent = trimmed(env["AGENT_ADDRESS"]);
131
+ const rawAgent = pick("agent", options.agent, config.agent, envAgent === undefined ? undefined : { value: envAgent, source: "env AGENT_ADDRESS" });
123
132
  const agent = rawAgent !== undefined && isAddress(rawAgent) ? rawAgent.toLowerCase() : undefined;
124
133
  if (rawAgent !== undefined && agent === undefined) {
125
134
  logger.warn("the configured agent is not a 20-byte address and was ignored", { agent: rawAgent });
@@ -150,7 +159,25 @@ export async function resolveTabMcpSettings(options = {}) {
150
159
  const configured = mergeServices(options.services ?? [], config.services ?? []);
151
160
  if (configured.length > 0)
152
161
  sources["services"] = options.services === undefined ? "tab.config" : "options";
153
- const services = hosted === undefined ? configured : mergeServices(configured, [hosted.demoService]);
162
+ /*
163
+ The hosted gateway meters only a signed call, so the demo Service signs with
164
+ the Agent's own key when one is in the environment. The key is read per call
165
+ and never held here, and a key for any other address signs nothing.
166
+ */
167
+ const agentKey = () => {
168
+ const key = trimmed(env["AGENT_PRIVATE_KEY"]);
169
+ if (key === undefined)
170
+ return undefined;
171
+ try {
172
+ return new Wallet(key);
173
+ }
174
+ catch {
175
+ return undefined;
176
+ }
177
+ };
178
+ const services = hosted === undefined
179
+ ? configured
180
+ : mergeServices(configured, [{ ...hosted.demoService, headers: agentSignedMetering(agentKey) }]);
154
181
  if (configured.length === 0 && services.length > 0)
155
182
  sources["services"] = "default (the project's hosted demo Service)";
156
183
  const strategyId = trimmed(options.strategyId);
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/mcp/settings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Where the MCP server gets its settings, and the order it prefers them in.\n *\n * Three sources, most specific first:\n *\n * 1. the options handed to {@link resolveTabMcpSettings}, which is what a test\n * and an embedding host use;\n * 2. `tab.config.{ts,mts,mjs,js,cjs}`, discovered by walking up from the working\n * directory -- the mechanism this package already has for consumer\n * configuration, so the MCP surface adds no second one;\n * 3. the environment, which is what the `mcpServers` stanza `tab connect` writes\n * actually carries.\n *\n * Every environment variable read here is already declared in the tracked\n * `.env.example` contract. That is not incidental: the repository's environment\n * gate extracts every `process.env` read in the tree and fails the build when\n * one has no declaration, so a new name would be a new line in a contract this\n * surface has no business changing. The RPC endpoint is `MONAD_RPC_URL`, in the\n * stanza and here.\n *\n * ## No key is a setting\n *\n * Nothing in this module reads a private key and nothing returns one. The\n * settlement signing key is read from the environment at the moment a Settlement\n * is signed, by the strategy that signs it, and never travels through a config\n * file or an MCP client's `mcpServers` stanza. That is what makes `tab connect`\n * safe to run against a file the client software rewrites.\n */\n\nimport type { Address } from \"../_shared/index.js\";\nimport { CHAINS, TAB_HOSTED, isAddress, isMonadChainId } from \"../_shared/index.js\";\n\nimport type { TabServiceEntry } from \"../payments/config.js\";\nimport { loadTabConfig, type TabConfig } from \"../payments/config.js\";\nimport { defaultLogger, type Logger } from \"../logger.js\";\nimport type { X402SignerFactory } from \"../x402/client.js\";\n\n/** The settings every tool reads. Each field is resolved or explicitly absent. */\nexport interface TabMcpSettings {\n /** Whose Open Tab a metered call lands on. Undefined until one is configured. */\n readonly agent: Address | undefined;\n /** Absolute base URL of the registry read API, or undefined when none is configured. */\n readonly registryUrl: string | undefined;\n /** The Monad JSON-RPC endpoint, used by `doctor` and by nothing that signs. */\n readonly rpcUrl: string | undefined;\n /** The EVM chain id every Asset is named against: 143 for Mainnet, 10143 for Testnet. */\n readonly chainId: number;\n /** Where a Monad transaction is linked. Always resolved; a default is fine for a link. */\n readonly explorerUrl: string;\n /** The endpoint directory, keyed by lower-case serviceId. */\n readonly services: readonly TabServiceEntry[];\n /** Which strategy `tab_settle` settles through when the call names none. */\n readonly strategyId: string | undefined;\n /**\n * The x402 signer factory, for `tab_call`'s prepaid fallback. Never called\n * while settings are resolved; only when a refused call carries an offer.\n */\n readonly x402: X402SignerFactory | undefined;\n /** Where each setting came from, so `doctor` can print it. */\n readonly sources: Readonly<Record<string, string>>;\n}\n\n/** Explicit settings, which beat both the config file and the environment. */\nexport interface TabMcpSettingsOptions {\n readonly agent?: string;\n readonly chainId?: number;\n readonly registryUrl?: string;\n /**\n * Whether the project's hosted read API and demo Service fill in what nothing\n * else names. Default true; `TAB_HOSTED_DEFAULTS=off` in the environment\n * turns them off as well.\n */\n readonly hostedDefaults?: boolean;\n readonly rpcUrl?: string;\n readonly explorerUrl?: string;\n readonly services?: readonly TabServiceEntry[];\n readonly strategyId?: string;\n readonly x402?: X402SignerFactory;\n /** Where the `tab.config` walk starts. Defaults to the working directory. */\n readonly cwd?: string;\n /** `false` skips config discovery entirely, which is what a hermetic test wants. */\n readonly config?: TabConfig | false;\n readonly env?: NodeJS.ProcessEnv;\n readonly logger?: Logger;\n}\n\n/** The public Monad Testnet explorer, used when nothing names one. */\nexport const DEFAULT_EXPLORER_URL = \"https://testnet.monadvision.com\";\n\n/** Monad Testnet, used when nothing names a chain. */\nexport const DEFAULT_CHAIN_ID = 10143;\n\nconst trimmed = (value: string | undefined): string | undefined => {\n const text = value?.trim();\n return text === undefined || text === \"\" ? undefined : text;\n};\n\n/**\n * The registry read API the environment names.\n *\n * `NEXT_PUBLIC_REGISTRY_API_URL` is the deployment's own name for this value and\n * is already in the environment contract, so it is what is read. When only\n * `REGISTRY_PORT` is set the read API is taken to be local, which is exactly the\n * developer case and saves a second variable that would say the same thing.\n */\nconst registryUrlFromEnv = (env: NodeJS.ProcessEnv): { url: string; source: string } | undefined => {\n const declared = trimmed(env[\"NEXT_PUBLIC_REGISTRY_API_URL\"]);\n if (declared !== undefined) return { url: declared, source: \"env NEXT_PUBLIC_REGISTRY_API_URL\" };\n const port = trimmed(env[\"REGISTRY_PORT\"]);\n if (port !== undefined && /^[0-9]{1,5}$/.test(port)) {\n return { url: `http://127.0.0.1:${port}`, source: \"env REGISTRY_PORT\" };\n }\n return undefined;\n};\n\n/** Keeps the first entry for each serviceId, so a more specific source wins. */\nfunction mergeServices(...groups: readonly (readonly TabServiceEntry[])[]): readonly TabServiceEntry[] {\n const byId = new Map<string, TabServiceEntry>();\n for (const group of groups) {\n for (const entry of group) {\n if (typeof entry?.serviceId !== \"string\" || typeof entry?.endpoint !== \"string\") continue;\n const key = entry.serviceId.toLowerCase();\n if (!byId.has(key)) byId.set(key, { ...entry, serviceId: key });\n }\n }\n return [...byId.values()];\n}\n\n/**\n * Resolves the settings, loading `tab.config` unless one was handed in.\n *\n * Never fails. A config file that cannot be imported is logged and skipped\n * rather than taking the server down: the tools each report their own missing\n * settings by name, which is a better message than a startup failure that names\n * a file the caller may not have known existed.\n */\nexport async function resolveTabMcpSettings(\n options: TabMcpSettingsOptions = {},\n): Promise<TabMcpSettings> {\n const env = options.env ?? process.env;\n const logger = options.logger ?? defaultLogger;\n const sources: Record<string, string> = {};\n\n let config: TabConfig = {};\n if (options.config === undefined) {\n const loaded = await loadTabConfig({\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n registry: false,\n logger,\n });\n if (loaded.ok) {\n config = loaded.value.config;\n if (loaded.value.path !== undefined) sources[\"config\"] = loaded.value.path;\n } else {\n logger.warn(\"tab config could not be loaded; continuing without it\", {\n code: loaded.error.code,\n message: loaded.error.message,\n });\n }\n } else if (options.config !== false) {\n config = options.config;\n sources[\"config\"] = \"supplied\";\n }\n\n const pick = (\n key: string,\n explicit: string | undefined,\n fromConfig: string | undefined,\n fromEnv: { value: string; source: string } | undefined,\n ): string | undefined => {\n if (trimmed(explicit) !== undefined) {\n sources[key] = \"options\";\n return trimmed(explicit);\n }\n if (trimmed(fromConfig) !== undefined) {\n sources[key] = \"tab.config\";\n return trimmed(fromConfig);\n }\n if (fromEnv !== undefined) {\n sources[key] = fromEnv.source;\n return fromEnv.value;\n }\n return undefined;\n };\n\n const rawAgent = pick(\"agent\", options.agent, config.agent, undefined);\n const agent = rawAgent !== undefined && isAddress(rawAgent) ? (rawAgent.toLowerCase() as Address) : undefined;\n if (rawAgent !== undefined && agent === undefined) {\n logger.warn(\"the configured agent is not a 20-byte address and was ignored\", { agent: rawAgent });\n delete sources[\"agent\"];\n }\n\n const envRpc = trimmed(env[\"MONAD_RPC_URL\"]);\n const rpcUrl = pick(\n \"rpcUrl\",\n options.rpcUrl,\n undefined,\n envRpc === undefined ? undefined : { value: envRpc, source: \"env MONAD_RPC_URL\" },\n );\n\n const envChain = trimmed(env[\"MONAD_CHAIN_ID\"]);\n const chainIdText = pick(\n \"chainId\",\n options.chainId === undefined ? undefined : String(options.chainId),\n undefined,\n envChain === undefined ? undefined : { value: envChain, source: \"env MONAD_CHAIN_ID\" },\n );\n const chainId = chainIdText !== undefined && /^[0-9]+$/.test(chainIdText) ? Number(chainIdText) : DEFAULT_CHAIN_ID;\n\n /*\n What this project hosts on the chosen network: its read API and its demo\n Service. The lowest-priority source for both, so anything configured wins,\n and switched off with TAB_HOSTED_DEFAULTS=off for a setup that must reach\n nothing it did not name.\n */\n const hosted =\n options.hostedDefaults !== false && trimmed(env[\"TAB_HOSTED_DEFAULTS\"]) !== \"off\" && isMonadChainId(chainId)\n ? TAB_HOSTED[chainId]\n : undefined;\n\n const envRegistry = registryUrlFromEnv(env);\n let registryUrl = pick(\n \"registryUrl\",\n options.registryUrl,\n config.registryUrl,\n envRegistry === undefined ? undefined : { value: envRegistry.url, source: envRegistry.source },\n );\n if (registryUrl === undefined && hosted !== undefined) {\n registryUrl = hosted.registryUrl;\n sources[\"registryUrl\"] = \"default (the project's hosted read API)\";\n }\n\n const envExplorer = trimmed(env[\"MONAD_EXPLORER_URL\"]);\n const explorerUrl =\n pick(\n \"explorerUrl\",\n options.explorerUrl,\n undefined,\n envExplorer === undefined ? undefined : { value: envExplorer, source: \"env MONAD_EXPLORER_URL\" },\n ) ?? (isMonadChainId(chainId) ? CHAINS[chainId].explorerUrl : DEFAULT_EXPLORER_URL);\n\n const configured = mergeServices(options.services ?? [], config.services ?? []);\n if (configured.length > 0) sources[\"services\"] = options.services === undefined ? \"tab.config\" : \"options\";\n const services = hosted === undefined ? configured : mergeServices(configured, [hosted.demoService]);\n if (configured.length === 0 && services.length > 0) sources[\"services\"] = \"default (the project's hosted demo Service)\";\n\n const strategyId = trimmed(options.strategyId);\n if (strategyId !== undefined) sources[\"strategyId\"] = \"options\";\n\n const x402 = options.x402 ?? (typeof config.x402 === \"function\" ? config.x402 : undefined);\n if (x402 !== undefined) sources[\"x402\"] = options.x402 === undefined ? \"tab.config\" : \"options\";\n\n return {\n agent,\n registryUrl,\n rpcUrl,\n chainId,\n explorerUrl,\n services,\n strategyId,\n x402,\n sources,\n };\n}\n"]}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/mcp/settings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Where the MCP server gets its settings, and the order it prefers them in.\n *\n * Three sources, most specific first:\n *\n * 1. the options handed to {@link resolveTabMcpSettings}, which is what a test\n * and an embedding host use;\n * 2. `tab.config.{ts,mts,mjs,js,cjs}`, discovered by walking up from the working\n * directory -- the mechanism this package already has for consumer\n * configuration, so the MCP surface adds no second one;\n * 3. the environment, which is what the `mcpServers` stanza `tab connect` writes\n * actually carries.\n *\n * Every environment variable read here is already declared in the tracked\n * `.env.example` contract. That is not incidental: the repository's environment\n * gate extracts every `process.env` read in the tree and fails the build when\n * one has no declaration, so a new name would be a new line in a contract this\n * surface has no business changing. The RPC endpoint is `MONAD_RPC_URL`, in the\n * stanza and here.\n *\n * ## No key is a setting\n *\n * Nothing in this module reads a private key and nothing returns one. The\n * settlement signing key is read from the environment at the moment a Settlement\n * is signed, by the strategy that signs it, and never travels through a config\n * file or an MCP client's `mcpServers` stanza. That is what makes `tab connect`\n * safe to run against a file the client software rewrites.\n *\n * The hosted demo Service is the one place a key is used outside a Settlement:\n * its gateway refuses an unsigned metered call, so the entry this module fills\n * in signs each call with `AGENT_PRIVATE_KEY`, read at the moment the call is\n * signed and only when that key is the Agent the call is metered against. The\n * Agent itself is an address, from `AGENT_ADDRESS` when nothing else names one.\n */\n\nimport type { Address } from \"../_shared/index.js\";\nimport { CHAINS, TAB_HOSTED, isAddress, isMonadChainId } from \"../_shared/index.js\";\nimport { Wallet } from \"ethers\";\n\nimport type { TabServiceEntry } from \"../payments/config.js\";\nimport { loadTabConfig, type TabConfig } from \"../payments/config.js\";\nimport { defaultLogger, type Logger } from \"../logger.js\";\nimport { agentSignedMetering } from \"../http/metering-claim.js\";\nimport type { X402SignerFactory } from \"../x402/client.js\";\n\n/** The settings every tool reads. Each field is resolved or explicitly absent. */\nexport interface TabMcpSettings {\n /** Whose Open Tab a metered call lands on. Undefined until one is configured. */\n readonly agent: Address | undefined;\n /** Absolute base URL of the registry read API, or undefined when none is configured. */\n readonly registryUrl: string | undefined;\n /** The Monad JSON-RPC endpoint, used by `doctor` and by nothing that signs. */\n readonly rpcUrl: string | undefined;\n /** The EVM chain id every Asset is named against: 143 for Mainnet, 10143 for Testnet. */\n readonly chainId: number;\n /** Where a Monad transaction is linked. Always resolved; a default is fine for a link. */\n readonly explorerUrl: string;\n /** The endpoint directory, keyed by lower-case serviceId. */\n readonly services: readonly TabServiceEntry[];\n /** Which strategy `tab_settle` settles through when the call names none. */\n readonly strategyId: string | undefined;\n /**\n * The x402 signer factory, for `tab_call`'s prepaid fallback. Never called\n * while settings are resolved; only when a refused call carries an offer.\n */\n readonly x402: X402SignerFactory | undefined;\n /** Where each setting came from, so `doctor` can print it. */\n readonly sources: Readonly<Record<string, string>>;\n}\n\n/** Explicit settings, which beat both the config file and the environment. */\nexport interface TabMcpSettingsOptions {\n readonly agent?: string;\n readonly chainId?: number;\n readonly registryUrl?: string;\n /**\n * Whether the project's hosted read API and demo Service fill in what nothing\n * else names. Default true; `TAB_HOSTED_DEFAULTS=off` in the environment\n * turns them off as well.\n */\n readonly hostedDefaults?: boolean;\n readonly rpcUrl?: string;\n readonly explorerUrl?: string;\n readonly services?: readonly TabServiceEntry[];\n readonly strategyId?: string;\n readonly x402?: X402SignerFactory;\n /** Where the `tab.config` walk starts. Defaults to the working directory. */\n readonly cwd?: string;\n /** `false` skips config discovery entirely, which is what a hermetic test wants. */\n readonly config?: TabConfig | false;\n readonly env?: NodeJS.ProcessEnv;\n readonly logger?: Logger;\n}\n\n/** The public Monad Testnet explorer, used when nothing names one. */\nexport const DEFAULT_EXPLORER_URL = \"https://testnet.monadvision.com\";\n\n/** Monad Testnet, used when nothing names a chain. */\nexport const DEFAULT_CHAIN_ID = 10143;\n\nconst trimmed = (value: string | undefined): string | undefined => {\n const text = value?.trim();\n return text === undefined || text === \"\" ? undefined : text;\n};\n\n/**\n * The registry read API the environment names.\n *\n * `NEXT_PUBLIC_REGISTRY_API_URL` is the deployment's own name for this value and\n * is already in the environment contract, so it is what is read. When only\n * `REGISTRY_PORT` is set the read API is taken to be local, which is exactly the\n * developer case and saves a second variable that would say the same thing.\n */\nconst registryUrlFromEnv = (env: NodeJS.ProcessEnv): { url: string; source: string } | undefined => {\n const declared = trimmed(env[\"NEXT_PUBLIC_REGISTRY_API_URL\"]);\n if (declared !== undefined) return { url: declared, source: \"env NEXT_PUBLIC_REGISTRY_API_URL\" };\n const port = trimmed(env[\"REGISTRY_PORT\"]);\n if (port !== undefined && /^[0-9]{1,5}$/.test(port)) {\n return { url: `http://127.0.0.1:${port}`, source: \"env REGISTRY_PORT\" };\n }\n return undefined;\n};\n\n/** Keeps the first entry for each serviceId, so a more specific source wins. */\nfunction mergeServices(...groups: readonly (readonly TabServiceEntry[])[]): readonly TabServiceEntry[] {\n const byId = new Map<string, TabServiceEntry>();\n for (const group of groups) {\n for (const entry of group) {\n if (typeof entry?.serviceId !== \"string\" || typeof entry?.endpoint !== \"string\") continue;\n const key = entry.serviceId.toLowerCase();\n if (!byId.has(key)) byId.set(key, { ...entry, serviceId: key });\n }\n }\n return [...byId.values()];\n}\n\n/**\n * Resolves the settings, loading `tab.config` unless one was handed in.\n *\n * Never fails. A config file that cannot be imported is logged and skipped\n * rather than taking the server down: the tools each report their own missing\n * settings by name, which is a better message than a startup failure that names\n * a file the caller may not have known existed.\n */\nexport async function resolveTabMcpSettings(\n options: TabMcpSettingsOptions = {},\n): Promise<TabMcpSettings> {\n const env = options.env ?? process.env;\n const logger = options.logger ?? defaultLogger;\n const sources: Record<string, string> = {};\n\n let config: TabConfig = {};\n if (options.config === undefined) {\n const loaded = await loadTabConfig({\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n registry: false,\n logger,\n });\n if (loaded.ok) {\n config = loaded.value.config;\n if (loaded.value.path !== undefined) sources[\"config\"] = loaded.value.path;\n } else {\n logger.warn(\"tab config could not be loaded; continuing without it\", {\n code: loaded.error.code,\n message: loaded.error.message,\n });\n }\n } else if (options.config !== false) {\n config = options.config;\n sources[\"config\"] = \"supplied\";\n }\n\n const pick = (\n key: string,\n explicit: string | undefined,\n fromConfig: string | undefined,\n fromEnv: { value: string; source: string } | undefined,\n ): string | undefined => {\n if (trimmed(explicit) !== undefined) {\n sources[key] = \"options\";\n return trimmed(explicit);\n }\n if (trimmed(fromConfig) !== undefined) {\n sources[key] = \"tab.config\";\n return trimmed(fromConfig);\n }\n if (fromEnv !== undefined) {\n sources[key] = fromEnv.source;\n return fromEnv.value;\n }\n return undefined;\n };\n\n const envAgent = trimmed(env[\"AGENT_ADDRESS\"]);\n const rawAgent = pick(\n \"agent\",\n options.agent,\n config.agent,\n envAgent === undefined ? undefined : { value: envAgent, source: \"env AGENT_ADDRESS\" },\n );\n const agent = rawAgent !== undefined && isAddress(rawAgent) ? (rawAgent.toLowerCase() as Address) : undefined;\n if (rawAgent !== undefined && agent === undefined) {\n logger.warn(\"the configured agent is not a 20-byte address and was ignored\", { agent: rawAgent });\n delete sources[\"agent\"];\n }\n\n const envRpc = trimmed(env[\"MONAD_RPC_URL\"]);\n const rpcUrl = pick(\n \"rpcUrl\",\n options.rpcUrl,\n undefined,\n envRpc === undefined ? undefined : { value: envRpc, source: \"env MONAD_RPC_URL\" },\n );\n\n const envChain = trimmed(env[\"MONAD_CHAIN_ID\"]);\n const chainIdText = pick(\n \"chainId\",\n options.chainId === undefined ? undefined : String(options.chainId),\n undefined,\n envChain === undefined ? undefined : { value: envChain, source: \"env MONAD_CHAIN_ID\" },\n );\n const chainId = chainIdText !== undefined && /^[0-9]+$/.test(chainIdText) ? Number(chainIdText) : DEFAULT_CHAIN_ID;\n\n /*\n What this project hosts on the chosen network: its read API and its demo\n Service. The lowest-priority source for both, so anything configured wins,\n and switched off with TAB_HOSTED_DEFAULTS=off for a setup that must reach\n nothing it did not name.\n */\n const hosted =\n options.hostedDefaults !== false && trimmed(env[\"TAB_HOSTED_DEFAULTS\"]) !== \"off\" && isMonadChainId(chainId)\n ? TAB_HOSTED[chainId]\n : undefined;\n\n const envRegistry = registryUrlFromEnv(env);\n let registryUrl = pick(\n \"registryUrl\",\n options.registryUrl,\n config.registryUrl,\n envRegistry === undefined ? undefined : { value: envRegistry.url, source: envRegistry.source },\n );\n if (registryUrl === undefined && hosted !== undefined) {\n registryUrl = hosted.registryUrl;\n sources[\"registryUrl\"] = \"default (the project's hosted read API)\";\n }\n\n const envExplorer = trimmed(env[\"MONAD_EXPLORER_URL\"]);\n const explorerUrl =\n pick(\n \"explorerUrl\",\n options.explorerUrl,\n undefined,\n envExplorer === undefined ? undefined : { value: envExplorer, source: \"env MONAD_EXPLORER_URL\" },\n ) ?? (isMonadChainId(chainId) ? CHAINS[chainId].explorerUrl : DEFAULT_EXPLORER_URL);\n\n const configured = mergeServices(options.services ?? [], config.services ?? []);\n if (configured.length > 0) sources[\"services\"] = options.services === undefined ? \"tab.config\" : \"options\";\n /*\n The hosted gateway meters only a signed call, so the demo Service signs with\n the Agent's own key when one is in the environment. The key is read per call\n and never held here, and a key for any other address signs nothing.\n */\n const agentKey = () => {\n const key = trimmed(env[\"AGENT_PRIVATE_KEY\"]);\n if (key === undefined) return undefined;\n try {\n return new Wallet(key);\n } catch {\n return undefined;\n }\n };\n const services =\n hosted === undefined\n ? configured\n : mergeServices(configured, [{ ...hosted.demoService, headers: agentSignedMetering(agentKey) }]);\n if (configured.length === 0 && services.length > 0) sources[\"services\"] = \"default (the project's hosted demo Service)\";\n\n const strategyId = trimmed(options.strategyId);\n if (strategyId !== undefined) sources[\"strategyId\"] = \"options\";\n\n const x402 = options.x402 ?? (typeof config.x402 === \"function\" ? config.x402 : undefined);\n if (x402 !== undefined) sources[\"x402\"] = options.x402 === undefined ? \"tab.config\" : \"options\";\n\n return {\n agent,\n registryUrl,\n rpcUrl,\n chainId,\n explorerUrl,\n services,\n strategyId,\n x402,\n sources,\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tabai/sdk",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "Post-paid billing for autonomous agents on Monad. MCP server, CLI and TypeScript SDK: call a priced tool now, settle in USDC later, and let TabSettlement apply the payment to the tab in the same transaction.",
5
5
  "keywords": [
6
6
  "monad",