@weftlabs/cli 0.25.0
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 +186 -0
- package/bin/weft.mjs +5 -0
- package/dist/cli.d.ts +26 -0
- package/dist/cli.js +1104 -0
- package/dist/cli.js.map +1 -0
- package/dist/weft-skill/SKILL.md +220 -0
- package/dist/weft-skill/rules/cli.md +96 -0
- package/examples/agent-bootstrap.sh +69 -0
- package/examples/cli-quickstart.sh +7 -0
- package/package.json +55 -0
- package/scripts/install-skill.mjs +273 -0
- package/scripts/skill-paths.mjs +42 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/credentials.ts","../src/cli.ts","../src/results.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport {\n chmod,\n mkdir,\n open,\n readFile,\n rename,\n rm,\n writeFile,\n} from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\n\nconst CREDENTIALS_FILE_MODE = 0o600;\nconst CREDENTIALS_DIR_MODE = 0o700;\nconst LOCK_RETRY_MS = 50;\nconst LOCK_TIMEOUT_MS = 10_000;\n\nexport interface BootstrapCredentials {\n version: 1;\n type: \"bootstrap\";\n base_url: string;\n bootstrap_id: string;\n temporary_api_key: string;\n device_code: string;\n client_id: string;\n expiry: string;\n polling_interval: number;\n}\n\nexport interface OAuthCredentials {\n version: 1;\n type: \"oauth\";\n base_url: string;\n client_id: string;\n access_token: string;\n refresh_token: string;\n token_type: string;\n scope: string;\n expiry: string;\n}\n\nexport type StoredCredentials = BootstrapCredentials | OAuthCredentials;\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isBootstrapCredentials(\n value: Record<string, unknown>,\n): BootstrapCredentials | undefined {\n if (\n value.type === \"bootstrap\" &&\n typeof value.version === \"number\" &&\n typeof value.base_url === \"string\" &&\n typeof value.bootstrap_id === \"string\" &&\n typeof value.temporary_api_key === \"string\" &&\n typeof value.device_code === \"string\" &&\n typeof value.client_id === \"string\" &&\n typeof value.expiry === \"string\" &&\n typeof value.polling_interval === \"number\"\n ) {\n return value as BootstrapCredentials;\n }\n\n return undefined;\n}\n\nfunction isOAuthCredentials(\n value: Record<string, unknown>,\n): OAuthCredentials | undefined {\n if (\n value.type === \"oauth\" &&\n typeof value.version === \"number\" &&\n typeof value.base_url === \"string\" &&\n typeof value.client_id === \"string\" &&\n typeof value.access_token === \"string\" &&\n typeof value.refresh_token === \"string\" &&\n typeof value.token_type === \"string\" &&\n typeof value.scope === \"string\" &&\n typeof value.expiry === \"string\"\n ) {\n return value as OAuthCredentials;\n }\n\n return undefined;\n}\n\nexport function resolveCredentialsPath(\n env: Record<string, string | undefined>,\n): string | undefined {\n if (env.WEFT_CREDENTIALS_FILE) return env.WEFT_CREDENTIALS_FILE;\n if (env.XDG_CONFIG_HOME)\n return `${env.XDG_CONFIG_HOME}/weft/credentials.json`;\n const home = env.HOME || env.USERPROFILE;\n if (!home) return undefined;\n return `${home}/.config/weft/credentials.json`;\n}\n\nexport async function readStoredCredentials(\n env: Record<string, string | undefined>,\n): Promise<StoredCredentials | undefined> {\n const path = resolveCredentialsPath(env);\n if (!path) return undefined;\n try {\n const raw = await readFile(path, \"utf8\");\n const parsed: unknown = JSON.parse(raw);\n if (!isObject(parsed)) throw new Error(\"Stored credentials malformed\");\n return isBootstrapCredentials(parsed) ?? isOAuthCredentials(parsed);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw error;\n }\n}\n\nexport async function writeStoredCredentials(\n env: Record<string, string | undefined>,\n credentials: StoredCredentials,\n): Promise<void> {\n const path = resolveCredentialsPath(env);\n if (!path) {\n throw new Error(\"HOME, USERPROFILE, or WEFT_CREDENTIALS_FILE is required\");\n }\n const parent = dirname(path);\n await mkdir(parent, { recursive: true, mode: CREDENTIALS_DIR_MODE });\n await chmod(parent, CREDENTIALS_DIR_MODE);\n\n const tempPath = `${path}.${randomUUID()}.tmp`;\n try {\n await writeFile(tempPath, JSON.stringify(credentials), {\n mode: CREDENTIALS_FILE_MODE,\n });\n await rename(tempPath, path);\n await chmod(path, CREDENTIALS_FILE_MODE);\n } catch (error) {\n await rm(tempPath, { force: true });\n throw error;\n }\n}\n\nexport async function withCredentialsLock<T>(\n env: Record<string, string | undefined>,\n action: () => Promise<T>,\n): Promise<T> {\n const path = resolveCredentialsPath(env);\n if (!path) {\n throw new Error(\"HOME, USERPROFILE, or WEFT_CREDENTIALS_FILE is required\");\n }\n const lockPath = `${path}.lock`;\n const deadline = Date.now() + LOCK_TIMEOUT_MS;\n await mkdir(dirname(path), { recursive: true, mode: CREDENTIALS_DIR_MODE });\n\n for (;;) {\n try {\n const lock = await open(lockPath, \"wx\", CREDENTIALS_FILE_MODE);\n await lock.close();\n break;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n if (Date.now() >= deadline) {\n throw new Error(\n `Timed out waiting for the credential lock; if no Weft CLI process is running, remove ${lockPath}`,\n );\n }\n await delay(LOCK_RETRY_MS);\n }\n }\n\n try {\n return await action();\n } finally {\n await rm(lockPath, { force: true });\n }\n}\n","import {\n readStoredCredentials,\n type BootstrapCredentials,\n type OAuthCredentials,\n withCredentialsLock,\n writeStoredCredentials,\n} from \"./credentials\";\nimport { spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport {\n readableBody,\n reserveResultDirectory,\n writeResultFile,\n} from \"./results\";\nimport {\n type PaidFetchRequest,\n ResponseError,\n WeftClient,\n WeftError,\n} from \"@weftlabs/sdk\";\n\nexport const EXIT_SUCCESS = 0;\nexport const EXIT_USAGE = 2;\nexport const EXIT_AUTH = 3;\nexport const EXIT_API = 4;\nexport const EXIT_INTERNAL = 5;\n\ntype Command =\n | \"bootstrap\"\n | \"auth\"\n | \"skill\"\n | \"me\"\n | \"balance\"\n | \"search\"\n | \"fetch\"\n | \"purchases\";\n\nconst COMMANDS: Command[] = [\n \"bootstrap\",\n \"auth\",\n \"skill\",\n \"me\",\n \"balance\",\n \"search\",\n \"fetch\",\n \"purchases\",\n];\n\nconst WEFT_API_BASE = \"https://weft.network\";\nconst OAUTH_SCOPE = \"balance fetch search\";\nconst OAUTH_CLIENT_NAME = \"Weft CLI\";\nconst OAUTH_HOST_NAME = \"Weft CLI\";\nconst OAUTH_REFRESH_SKEW_MS = 60_000;\nconst PROCESS_OUTPUT_LIMIT = 8_192;\nconst SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst CORE_SKILL_NAMES = new Set([\"weft\", \"weft-setup\"]);\n\nconst COMMAND_HELP = {\n bootstrap: {\n description: \"Bootstrap an agent account\",\n usage: \"weft bootstrap --email <email> --agent-name <name> --reason <text>\",\n options: [\n \"--email <email>\",\n \"--agent-name <name>\",\n \"--reason <text>\",\n \"[--base-url <url>]\",\n ],\n },\n auth: {\n description: \"Check bootstrap status and exchange device token\",\n usage: \"weft auth status\",\n options: [\"status\"],\n },\n skill: {\n description: \"Install the core Weft Skill or one optional workflow Skill\",\n usage: \"weft skill install [name --agent <agent> [--global]]\",\n options: [\"install\", \"[name]\", \"--agent <agent>\", \"--global\"],\n },\n me: {\n description: \"Return the authenticated principal\",\n usage: \"weft me\",\n options: [],\n },\n balance: {\n description: \"Return wallet balance and spending policy\",\n usage: \"weft balance\",\n options: [],\n },\n search: {\n description: \"Search for payable resources\",\n usage: \"weft search <query> [--max-results <1..50>]\",\n options: [\"--max-results <1..50>\"],\n },\n fetch: {\n description: \"Fetch a URL within an explicit spending limit\",\n usage:\n \"weft fetch <url> --max-cost-usd <amount> [--method <method>] [--idempotency-key <key>] [--raw]\",\n options: [\n \"--max-cost-usd <amount>\",\n \"--method <method>\",\n \"--idempotency-key <key>\",\n \"--raw\",\n ],\n },\n purchases: {\n description: \"List purchases or return one purchase by ID\",\n usage: \"weft purchases [id] [--page <number>] [--per-page <1..100>]\",\n options: [\"--page <number>\", \"--per-page <1..100>\"],\n },\n} satisfies Record<\n Command,\n { description: string; usage: string; options: string[] }\n>;\n\ninterface SkillInstallResult {\n status: \"ok\" | \"skipped\";\n reason?: string;\n installed: number;\n hosts: string[];\n warnings: string[];\n}\n\ntype SkillInstaller = (options?: {\n force?: boolean;\n silent?: boolean;\n}) => Promise<SkillInstallResult>;\n\n/**\n * The Skill installer ships as a plain script beside `dist/`, and reads the\n * packed Skill relative to its own location. The specifier is built at runtime\n * so the bundler leaves it external and that relative path stays correct in the\n * published package.\n */\nasync function loadSkillInstaller(): Promise<SkillInstaller> {\n const specifier = new URL(\"../scripts/install-skill.mjs\", import.meta.url)\n .href;\n const module = (await import(specifier)) as { installSkill: SkillInstaller };\n return module.installSkill;\n}\n\n/**\n * Best-effort Skill installation on any ordinary command. This is the safety\n * net for a user who never runs `weft skill install`, and it is what lets the\n * Skill appear in an agent host that was installed after the CLI. It is\n * idempotent, it stays silent, and it never fails the command the user asked\n * for.\n */\nasync function installSkillInBackground(): Promise<void> {\n try {\n const installSkill = await loadSkillInstaller();\n await installSkill({ silent: true });\n } catch {\n // Deliberately ignored — `weft skill install` is the surface that reports\n // installation problems.\n }\n}\n\ninterface BootstrapCreateResponse {\n data: {\n id: string;\n status: string;\n capabilities: unknown;\n expires_at: string;\n temporary_api_key: string;\n device_code: string;\n approval: {\n interval: number;\n expires_in: number;\n method: string;\n user_code: string;\n };\n };\n}\n\ninterface BootstrapStatus {\n data: {\n id: string;\n status: string;\n expires_at?: string;\n capabilities?: unknown;\n };\n}\n\ninterface OAuthTokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token: string;\n scope: string;\n}\n\nconst GLOBAL_OPTIONS = [\"--api-key-stdin\", \"--base-url <url>\", \"--help\", \"-h\"];\n\nexport interface CliDependencies {\n env?: Record<string, string | undefined>;\n fetchApi?: typeof fetch;\n readStdin?: () => Promise<string>;\n writeOut?: (value: string) => void | Promise<void>;\n writeErr?: (value: string) => void;\n generateIdempotencyKey?: () => string;\n runProcess?: ProcessRunner;\n platform?: NodeJS.Platform;\n nodeExecutable?: string;\n npxCliPath?: string;\n}\n\ninterface ProcessResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n}\n\ntype ProcessRunner = (\n command: string,\n args: string[],\n) => Promise<ProcessResult>;\n\ninterface ParsedArgs {\n command: Command;\n apiKeyStdin: boolean;\n baseUrl?: string;\n positionals: string[];\n options: Map<string, string | true>;\n}\n\nclass CliError extends Error {\n constructor(\n readonly exitCode: number,\n readonly code: string,\n message: string,\n readonly details?: unknown,\n ) {\n super(message);\n }\n}\n\nfunction takeValue(\n args: string[],\n index: number,\n option: string,\n): [string, number] {\n const value = args[index + 1];\n if (value == null || value.startsWith(\"--\")) {\n throw new CliError(\n EXIT_USAGE,\n \"INVALID_ARGUMENT\",\n `${option} requires a value`,\n );\n }\n return [value, index + 1];\n}\n\nfunction appendBounded(current: string, chunk: Buffer | string): string {\n return `${current}${chunk.toString()}`.slice(-PROCESS_OUTPUT_LIMIT);\n}\n\nfunction defaultRunProcess(\n command: string,\n args: string[],\n): Promise<ProcessResult> {\n return new Promise((resolve) => {\n const child = spawn(command, args, {\n shell: false,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.on(\"data\", (chunk: Buffer) => {\n stdout = appendBounded(stdout, chunk);\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr = appendBounded(stderr, chunk);\n });\n child.on(\"error\", (error) => {\n resolve({\n exitCode: 1,\n stdout,\n stderr: appendBounded(stderr, error.message),\n });\n });\n child.on(\"close\", (exitCode) => {\n resolve({ exitCode: exitCode ?? 1, stdout, stderr });\n });\n });\n}\n\nfunction resolveNpxCliPath(\n env: Record<string, string | undefined>,\n nodeExecutable: string,\n): string | undefined {\n const executableDirectory = dirname(nodeExecutable);\n const candidates = [\n ...(env.npm_execpath\n ? [join(dirname(env.npm_execpath), \"npx-cli.js\")]\n : []),\n join(executableDirectory, \"node_modules\", \"npm\", \"bin\", \"npx-cli.js\"),\n join(\n executableDirectory,\n \"..\",\n \"lib\",\n \"node_modules\",\n \"npm\",\n \"bin\",\n \"npx-cli.js\",\n ),\n ];\n return candidates.find((candidate) => existsSync(candidate));\n}\n\nfunction npxProcessInvocation(\n processArgs: string[],\n dependencies: CliDependencies,\n env: Record<string, string | undefined>,\n): { executable: string; arguments: string[] } {\n if ((dependencies.platform ?? process.platform) !== \"win32\") {\n return { executable: \"npx\", arguments: processArgs };\n }\n\n const nodeExecutable = dependencies.nodeExecutable ?? process.execPath;\n const npxCliPath =\n dependencies.npxCliPath ?? resolveNpxCliPath(env, nodeExecutable);\n if (!npxCliPath) {\n throw new CliError(\n EXIT_INTERNAL,\n \"NPX_NOT_FOUND\",\n \"Could not find the npm npx program. Install npm, then run the command again.\",\n );\n }\n return {\n executable: nodeExecutable,\n arguments: [npxCliPath, ...processArgs],\n };\n}\n\nfunction rejectUnsafeCredentialArgument(args: string[]): void {\n if (args.some((arg) => arg === \"--api-key\" || arg.startsWith(\"--api-key=\"))) {\n throw new CliError(\n EXIT_USAGE,\n \"UNSAFE_CREDENTIAL_ARGUMENT\",\n \"API keys are accepted only through WEFT_API_KEY or --api-key-stdin\",\n );\n }\n}\n\nfunction requestedHelp(args: string[]): Command | \"all\" | undefined {\n const isHelp = (value: string) => value === \"--help\" || value === \"-h\";\n if (args.length === 1 && isHelp(args[0])) return \"all\";\n if (\n args.length === 2 &&\n COMMANDS.includes(args[0] as Command) &&\n isHelp(args[1])\n ) {\n return args[0] as Command;\n }\n return undefined;\n}\n\nfunction helpData(command: Command | \"all\") {\n if (command !== \"all\") {\n return {\n command,\n ...COMMAND_HELP[command],\n global_options: GLOBAL_OPTIONS,\n };\n }\n return {\n usage: \"weft <command> [options]\",\n commands: COMMANDS.map((name) => ({ name, ...COMMAND_HELP[name] })),\n global_options: GLOBAL_OPTIONS,\n authentication: [\"WEFT_API_KEY\", \"--api-key-stdin\"],\n exit_codes: { success: 0, usage: 2, auth: 3, api: 4, internal: 5 },\n };\n}\n\nfunction parseArgs(args: string[]): ParsedArgs {\n let command: Command | undefined;\n let apiKeyStdin = false;\n let baseUrl: string | undefined;\n const positionals: string[] = [];\n const options = new Map<string, string | true>();\n\n for (let index = 0; index < args.length; index += 1) {\n const arg = args[index];\n if (arg === \"--api-key-stdin\") {\n apiKeyStdin = true;\n } else if (arg === \"--base-url\") {\n [baseUrl, index] = takeValue(args, index, arg);\n } else if (arg === \"--global\" || arg === \"--raw\") {\n options.set(arg.slice(2), true);\n } else if (arg.startsWith(\"--\")) {\n const [value, nextIndex] = takeValue(args, index, arg);\n options.set(arg.slice(2), value);\n index = nextIndex;\n } else if (!command) {\n if (!COMMANDS.includes(arg as Command)) {\n throw new CliError(\n EXIT_USAGE,\n \"UNKNOWN_COMMAND\",\n `Unknown command: ${arg}`,\n );\n }\n command = arg as Command;\n } else {\n positionals.push(arg);\n }\n }\n\n if (!command) {\n throw new CliError(\n EXIT_USAGE,\n \"COMMAND_REQUIRED\",\n \"Command required: bootstrap, auth, me, balance, search, fetch, or purchases\",\n );\n }\n\n return { command, apiKeyStdin, baseUrl, positionals, options };\n}\n\nfunction positiveInteger(\n value: string | true | undefined,\n option: string,\n maximum?: number,\n): number | undefined {\n if (value == null) return undefined;\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n throw new CliError(\n EXIT_USAGE,\n \"INVALID_ARGUMENT\",\n `${option} must be a positive integer`,\n );\n }\n if (maximum != null && parsed > maximum) {\n throw new CliError(\n EXIT_USAGE,\n \"INVALID_ARGUMENT\",\n `${option} must be at most ${maximum}`,\n );\n }\n return parsed;\n}\n\nfunction requiredOption(\n options: Map<string, string | true>,\n name: string,\n): string {\n const value = options.get(name);\n if (typeof value !== \"string\" || !value.trim()) {\n throw new CliError(EXIT_USAGE, \"MISSING_ARGUMENT\", `--${name} is required`);\n }\n return value;\n}\n\nfunction baseApiUrl(\n baseUrl: string | undefined,\n env: Record<string, string | undefined>,\n): string {\n const raw = baseUrl ?? env.WEFT_BASE_URL ?? WEFT_API_BASE;\n return raw.endsWith(\"/\") ? raw.slice(0, -1) : raw;\n}\n\nfunction resolveApiKeyFromStored(\n credentials?:\n | {\n temporary_api_key: string;\n type: \"bootstrap\";\n }\n | {\n access_token: string;\n type: \"oauth\";\n },\n): string | undefined {\n if (!credentials) return undefined;\n if (credentials.type === \"oauth\" && credentials.access_token.trim()) {\n return credentials.access_token;\n }\n if (\n credentials.type === \"bootstrap\" &&\n credentials.temporary_api_key.trim()\n ) {\n return credentials.temporary_api_key;\n }\n return undefined;\n}\n\nfunction oauthNeedsRefresh(credentials: OAuthCredentials): boolean {\n const expiry = Date.parse(credentials.expiry);\n return (\n !Number.isFinite(expiry) || expiry <= Date.now() + OAUTH_REFRESH_SKEW_MS\n );\n}\n\nasync function refreshOAuthCredentials(\n fetchApi: typeof fetch,\n env: Record<string, string | undefined>,\n stored: OAuthCredentials,\n): Promise<OAuthCredentials> {\n const token = await requestJson<OAuthTokenResponse>(\n fetchApi,\n `${stored.base_url}/oauth/token`,\n {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: stored.refresh_token,\n client_id: stored.client_id,\n }).toString(),\n },\n true,\n );\n const refreshed: OAuthCredentials = {\n ...stored,\n access_token: token.access_token,\n refresh_token: token.refresh_token,\n token_type: token.token_type,\n scope: token.scope,\n expiry: new Date(Date.now() + token.expires_in * 1000).toISOString(),\n };\n await writeStoredCredentials(env, refreshed);\n return refreshed;\n}\n\nfunction noSecretFields(\n data: Record<string, unknown>,\n): Record<string, unknown> {\n return {\n ...data,\n temporary_api_key: undefined,\n device_code: undefined,\n access_token: undefined,\n refresh_token: undefined,\n client_secret: undefined,\n };\n}\n\nasync function requestJson<T>(\n fetchApi: typeof fetch,\n url: string,\n init: RequestInit,\n redactError = false,\n): Promise<T> {\n const response = await fetchApi(url, init);\n if (!response.ok) {\n if (redactError) {\n throw new CliError(\n response.status === 401 || response.status === 403\n ? EXIT_AUTH\n : response.status >= 500\n ? EXIT_INTERNAL\n : EXIT_API,\n \"OAUTH_TOKEN_ERROR\",\n `OAuth token request failed with HTTP ${response.status}`,\n );\n }\n throw new ResponseError(response);\n }\n\n return (await response.json()) as T;\n}\n\nfunction withCredentials(\n headers: Record<string, string>,\n apiKey: string,\n): Record<string, string> {\n return {\n ...headers,\n authorization: `Bearer ${apiKey}`,\n };\n}\n\nfunction ensureOnly(\n options: Map<string, string | true>,\n allowed: string[],\n): void {\n for (const name of options.keys()) {\n if (!allowed.includes(name)) {\n throw new CliError(\n EXIT_USAGE,\n \"UNKNOWN_OPTION\",\n `Unknown option: --${name}`,\n );\n }\n }\n}\n\nasync function responseDetails(error: ResponseError): Promise<unknown> {\n try {\n return await error.response.json();\n } catch {\n return undefined;\n }\n}\n\nasync function normalizeError(error: unknown): Promise<CliError> {\n if (error instanceof CliError) return error;\n if (error instanceof WeftError) {\n // status 0 is a transport failure with no API response; it exits like an\n // internal failure, not an API rejection.\n const exitCode =\n error.status === 401 || error.status === 403\n ? EXIT_AUTH\n : error.status >= 500 || error.status === 0\n ? EXIT_INTERNAL\n : EXIT_API;\n return new CliError(exitCode, error.code, error.message, error.details);\n }\n if (error instanceof ResponseError) {\n const details = await responseDetails(error);\n const body = details as\n | {\n error?: { code?: string; message?: string } | string;\n error_description?: string;\n }\n | undefined;\n const nested = typeof body?.error === \"object\" ? body.error : undefined;\n const code =\n nested?.code ??\n (typeof body?.error === \"string\"\n ? body.error\n : `HTTP_${error.response.status}`);\n const message =\n nested?.message ??\n body?.error_description ??\n `Weft API returned HTTP ${error.response.status}`;\n const exitCode =\n error.response.status === 401 || error.response.status === 403\n ? EXIT_AUTH\n : error.response.status >= 500\n ? EXIT_INTERNAL\n : EXIT_API;\n return new CliError(exitCode, code, message, details);\n }\n const message = error instanceof Error ? error.message : String(error);\n return new CliError(EXIT_INTERNAL, \"INTERNAL_ERROR\", message);\n}\n\nasync function defaultReadStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\nasync function defaultWriteOut(value: string): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n // The write callback reports failure before the stream emits its error.\n // Keep the one-shot listener until that event to prevent an uncaught EPIPE.\n const onError = (error: Error) => reject(error);\n process.stdout.once(\"error\", onError);\n process.stdout.write(value, (error) => {\n if (error) {\n reject(error);\n } else {\n process.stdout.removeListener(\"error\", onError);\n resolve();\n }\n });\n });\n}\n\nexport async function runCli(\n args: string[],\n dependencies: CliDependencies = {},\n): Promise<number> {\n const outputWriter = dependencies.writeOut ?? defaultWriteOut;\n const writeErr =\n dependencies.writeErr ?? ((value) => process.stderr.write(value));\n let command = \"unknown\";\n let idempotencyKey: string | undefined;\n let schemaVersion = \"1\";\n let meta: Record<string, unknown> | undefined;\n let deliveryReceipt: Record<string, unknown> | undefined;\n const fetchApi = dependencies.fetchApi ?? fetch;\n const writeOut = async (value: string) => {\n try {\n await outputWriter(value);\n } catch {\n throw new CliError(\n EXIT_INTERNAL,\n command === \"fetch\" ? \"RESULT_OUTPUT_FAILED\" : \"OUTPUT_FAILED\",\n \"Cannot write stdout. Use the saved result paths below if present. Otherwise keep this receipt and retry the same fetch with --idempotency-key and the same key.\",\n deliveryReceipt === undefined\n ? undefined\n : { receipt: deliveryReceipt },\n );\n }\n };\n\n try {\n rejectUnsafeCredentialArgument(args);\n const help = requestedHelp(args);\n if (help !== undefined) {\n command = \"help\";\n await writeOut(\n `${JSON.stringify({\n schema_version: \"1\",\n ok: true,\n command,\n data: helpData(help),\n })}\\n`,\n );\n return EXIT_SUCCESS;\n }\n\n const parsed = parseArgs(args);\n command = parsed.command;\n const env = dependencies.env ?? process.env;\n const baseUrl = baseApiUrl(parsed.baseUrl, env);\n\n if (parsed.command === \"skill\") {\n if (\n parsed.positionals[0] !== \"install\" ||\n parsed.positionals.length > 2\n ) {\n throw new CliError(\n EXIT_USAGE,\n \"INVALID_ARGUMENT\",\n \"skill requires 'install' and accepts at most one Skill name\",\n );\n }\n\n const skillName = parsed.positionals[1];\n if (skillName) {\n ensureOnly(parsed.options, [\"agent\", \"global\"]);\n const agent = requiredOption(parsed.options, \"agent\");\n if (!SKILL_NAME_PATTERN.test(skillName)) {\n throw new CliError(\n EXIT_USAGE,\n \"INVALID_ARGUMENT\",\n \"Skill name must contain only lowercase letters, numbers, and single hyphens\",\n );\n }\n if (CORE_SKILL_NAMES.has(skillName)) {\n throw new CliError(\n EXIT_USAGE,\n \"INVALID_ARGUMENT\",\n `Use 'weft skill install' without a name to install the core ${skillName} Skill`,\n );\n }\n if (!SKILL_NAME_PATTERN.test(agent)) {\n throw new CliError(\n EXIT_USAGE,\n \"INVALID_ARGUMENT\",\n \"Agent name must contain only lowercase letters, numbers, and single hyphens\",\n );\n }\n\n const processArgs = [\n \"--yes\",\n \"skills\",\n \"add\",\n \"weftlabs/skills\",\n \"--skill\",\n skillName,\n \"--agent\",\n agent,\n \"--yes\",\n ...(parsed.options.get(\"global\") === true ? [\"--global\"] : []),\n ];\n const invocation = npxProcessInvocation(processArgs, dependencies, env);\n const result = await (dependencies.runProcess ?? defaultRunProcess)(\n invocation.executable,\n invocation.arguments,\n );\n if (result.exitCode !== 0) {\n const remediation = `npx ${processArgs.join(\" \")}`;\n throw new CliError(\n EXIT_INTERNAL,\n \"SKILL_INSTALL_FAILED\",\n `Could not install ${skillName}. Run '${remediation}' directly for more detail.`,\n {\n executable: invocation.executable,\n arguments: invocation.arguments,\n exit_code: result.exitCode,\n stderr: result.stderr,\n },\n );\n }\n await writeOut(\n `${JSON.stringify({\n schema_version: \"1\",\n ok: true,\n command,\n data: {\n status: \"installed\",\n skill: skillName,\n agent,\n scope:\n parsed.options.get(\"global\") === true ? \"global\" : \"project\",\n },\n })}\\n`,\n );\n return EXIT_SUCCESS;\n }\n\n ensureOnly(parsed.options, []);\n const installSkill = await loadSkillInstaller();\n const result = await installSkill({ force: true });\n await writeOut(\n `${JSON.stringify({\n schema_version: \"1\",\n ok: true,\n command,\n data: {\n status: result.status,\n installed: result.installed,\n hosts: result.hosts,\n ...(result.reason === undefined ? {} : { reason: result.reason }),\n ...(result.warnings.length === 0\n ? {}\n : { warnings: result.warnings }),\n },\n })}\\n`,\n );\n return EXIT_SUCCESS;\n }\n\n await installSkillInBackground();\n\n if (parsed.command === \"bootstrap\") {\n ensureOnly(parsed.options, [\"email\", \"agent-name\", \"reason\"]);\n if (parsed.positionals.length !== 0) {\n throw new CliError(\n EXIT_USAGE,\n \"INVALID_ARGUMENT\",\n \"bootstrap does not accept positional arguments\",\n );\n }\n const email = requiredOption(parsed.options, \"email\");\n const agentName = requiredOption(parsed.options, \"agent-name\");\n const reason = requiredOption(parsed.options, \"reason\");\n\n const register = await requestJson<{ client_id: string }>(\n fetchApi,\n `${baseUrl}/oauth/register`,\n {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n client_name: OAUTH_CLIENT_NAME,\n redirect_uris: [\"http://localhost/callback\"],\n grant_types: [\n \"urn:ietf:params:oauth:grant-type:device_code\",\n \"refresh_token\",\n ],\n token_endpoint_auth_method: \"none\",\n scope: OAUTH_SCOPE,\n }),\n },\n );\n\n const clientId = register.client_id;\n const bootstrap = await requestJson<BootstrapCreateResponse>(\n fetchApi,\n `${baseUrl}/api/v1/account_bootstraps`,\n {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n email,\n agent_name: agentName,\n host_name: OAUTH_HOST_NAME,\n reason,\n oauth_client_id: clientId,\n requested_scopes: [\"balance\", \"fetch\", \"search\"],\n }),\n },\n );\n\n const stored: BootstrapCredentials = {\n version: 1,\n type: \"bootstrap\",\n base_url: baseUrl,\n bootstrap_id: bootstrap.data.id,\n temporary_api_key: bootstrap.data.temporary_api_key,\n device_code: bootstrap.data.device_code,\n client_id: clientId,\n expiry: bootstrap.data.expires_at,\n polling_interval: bootstrap.data.approval.interval,\n };\n\n await writeStoredCredentials(env, stored);\n\n await writeOut(\n `${JSON.stringify({\n schema_version: \"1\",\n ok: true,\n command,\n data: noSecretFields({\n ...bootstrap.data,\n client_id: clientId,\n base_url: baseUrl,\n polling_interval: bootstrap.data.approval.interval,\n }),\n })}\\n`,\n );\n return EXIT_SUCCESS;\n }\n\n if (parsed.command === \"auth\") {\n ensureOnly(parsed.options, []);\n if (\n parsed.positionals.length !== 1 ||\n parsed.positionals[0] !== \"status\"\n ) {\n throw new CliError(\n EXIT_USAGE,\n \"INVALID_ARGUMENT\",\n \"auth requires 'status'\",\n );\n }\n\n const stored = await readStoredCredentials(env);\n if (stored?.type === \"oauth\") {\n await writeOut(\n `${JSON.stringify({\n schema_version: \"1\",\n ok: true,\n command,\n data: {\n status: \"consumed\",\n authentication: \"oauth\",\n scope: stored.scope,\n },\n })}\\n`,\n );\n return EXIT_SUCCESS;\n }\n if (!stored) {\n throw new CliError(\n EXIT_AUTH,\n \"BOOTSTRAP_REQUIRED\",\n \"Run weft bootstrap before auth status\",\n );\n }\n\n const statusBaseUrl = stored.base_url;\n const status = await requestJson<BootstrapStatus>(\n fetchApi,\n `${statusBaseUrl}/api/v1/account_bootstraps/${stored.bootstrap_id}`,\n {\n method: \"GET\",\n headers: withCredentials({}, stored.temporary_api_key),\n },\n );\n\n const statusValue = status.data.status;\n if (statusValue !== \"claimed\" && statusValue !== \"consumed\") {\n await writeOut(\n `${JSON.stringify({\n schema_version: \"1\",\n ok: true,\n command,\n data: { status: statusValue },\n })}\\n`,\n );\n return EXIT_SUCCESS;\n }\n\n const token = await requestJson<OAuthTokenResponse>(\n fetchApi,\n `${statusBaseUrl}/oauth/token`,\n {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n },\n body: new URLSearchParams({\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: stored.device_code,\n client_id: stored.client_id,\n name: OAUTH_CLIENT_NAME,\n }).toString(),\n },\n true,\n );\n\n const oauth: OAuthCredentials = {\n version: 1,\n type: \"oauth\",\n base_url: statusBaseUrl,\n client_id: stored.client_id,\n access_token: token.access_token,\n refresh_token: token.refresh_token,\n token_type: token.token_type,\n scope: token.scope,\n expiry: new Date(Date.now() + token.expires_in * 1000).toISOString(),\n };\n await writeStoredCredentials(env, oauth);\n\n await writeOut(\n `${JSON.stringify({\n schema_version: \"1\",\n ok: true,\n command,\n data: {\n status: \"consumed\",\n authentication: \"oauth\",\n scope: token.scope,\n },\n })}\\n`,\n );\n return EXIT_SUCCESS;\n }\n\n const rawKey = parsed.apiKeyStdin\n ? await (dependencies.readStdin ?? defaultReadStdin)()\n : env.WEFT_API_KEY;\n let apiKey = rawKey?.trim();\n let authenticatedBaseUrl = baseUrl;\n if (parsed.apiKeyStdin && !apiKey) {\n throw new CliError(\n EXIT_AUTH,\n \"API_KEY_REQUIRED\",\n \"--api-key-stdin requires a non-empty API key\",\n );\n }\n if (!apiKey && !parsed.apiKeyStdin) {\n let stored = await readStoredCredentials(env);\n if (stored?.type === \"oauth\" && oauthNeedsRefresh(stored)) {\n stored = await withCredentialsLock(env, async () => {\n const current = await readStoredCredentials(env);\n if (current?.type === \"oauth\" && oauthNeedsRefresh(current)) {\n return refreshOAuthCredentials(fetchApi, env, current);\n }\n return current;\n });\n }\n apiKey = resolveApiKeyFromStored(stored);\n if (stored) authenticatedBaseUrl = stored.base_url;\n }\n\n if (!apiKey) {\n throw new CliError(\n EXIT_AUTH,\n \"API_KEY_REQUIRED\",\n \"Set WEFT_API_KEY, pass --api-key-stdin, or store credentials\",\n );\n }\n\n const client = new WeftClient({\n apiKey,\n baseUrl: authenticatedBaseUrl,\n fetchApi,\n });\n\n let data: unknown;\n if (parsed.command === \"me\") {\n ensureOnly(parsed.options, []);\n data = await client.me();\n } else if (parsed.command === \"balance\") {\n ensureOnly(parsed.options, []);\n data = await client.balance();\n } else if (parsed.command === \"search\") {\n ensureOnly(parsed.options, [\"max-results\"]);\n if (parsed.positionals.length !== 1) {\n throw new CliError(\n EXIT_USAGE,\n \"INVALID_ARGUMENT\",\n \"search requires exactly one query\",\n );\n }\n data = await client.search({\n query: parsed.positionals[0],\n maxResults: positiveInteger(\n parsed.options.get(\"max-results\"),\n \"--max-results\",\n 50,\n ),\n });\n } else if (parsed.command === \"fetch\") {\n ensureOnly(parsed.options, [\n \"max-cost-usd\",\n \"method\",\n \"idempotency-key\",\n \"raw\",\n ]);\n const raw = parsed.options.has(\"raw\");\n schemaVersion = raw ? \"1\" : \"2\";\n if (parsed.positionals.length !== 1) {\n throw new CliError(\n EXIT_USAGE,\n \"INVALID_ARGUMENT\",\n \"fetch requires exactly one URL\",\n );\n }\n const maxCostUsd = requiredOption(parsed.options, \"max-cost-usd\");\n if (!/^\\d+(?:\\.\\d+)?$/.test(maxCostUsd) || Number(maxCostUsd) <= 0) {\n throw new CliError(\n EXIT_USAGE,\n \"INVALID_ARGUMENT\",\n \"--max-cost-usd must be a positive decimal\",\n );\n }\n const method = parsed.options.get(\"method\");\n const request: PaidFetchRequest = {\n url: parsed.positionals[0],\n maxCostUsd,\n method:\n typeof method === \"string\"\n ? (method.toUpperCase() as PaidFetchRequest[\"method\"])\n : undefined,\n };\n const explicitKey = parsed.options.get(\"idempotency-key\");\n idempotencyKey =\n typeof explicitKey === \"string\"\n ? explicitKey\n : (dependencies.generateIdempotencyKey ?? randomUUID)();\n let resultDirectory: string | undefined;\n if (!raw) {\n try {\n resultDirectory = await reserveResultDirectory(env);\n } catch {\n throw new CliError(\n EXIT_INTERNAL,\n \"RESULT_STORAGE_UNAVAILABLE\",\n \"Cannot reserve local result storage. Set WEFT_RESULTS_DIR to a directory you own that is writable only by you, with no symlink at that path, then retry. No fetch was sent.\",\n );\n }\n }\n const response = await client.fetch(request, { idempotencyKey });\n meta = { idempotency_key: idempotencyKey };\n data = response;\n const { bodyBase64, ...receipt } = response;\n deliveryReceipt = receipt;\n if (resultDirectory) {\n const savedPath = join(resultDirectory, \"body\");\n const receiptPath = join(resultDirectory, \"receipt.json\");\n const bytes =\n typeof bodyBase64 === \"string\"\n ? Buffer.from(bodyBase64, \"base64\")\n : undefined;\n if (!bytes || bytes.toString(\"base64\") !== bodyBase64) {\n throw new CliError(\n EXIT_INTERNAL,\n \"RESULT_DECODE_FAILED\",\n \"Fetch returned invalid Base64. No body was saved. Keep this receipt and retry the same request with --idempotency-key and the same key; if it persists, report the artifact ID to support.\",\n { receipt, file_complete: false },\n );\n }\n try {\n meta = {\n ...meta,\n saved_path: savedPath,\n receipt_path: receiptPath,\n byte_count: bytes.length,\n };\n await writeResultFile(\n receiptPath,\n `${JSON.stringify({ schema_version: \"2\", meta, data: receipt })}\\n`,\n );\n await writeResultFile(savedPath, bytes);\n data = { ...receipt, ...readableBody(bytes, response.headers) };\n } catch {\n throw new CliError(\n EXIT_INTERNAL,\n \"RESULT_STORAGE_FAILED\",\n \"Fetch returned, but local result delivery failed. Keep this receipt. Check local storage, then retry the same request with --idempotency-key and the key below. Do not use a new key.\",\n {\n receipt,\n saved_path: savedPath,\n receipt_path: receiptPath,\n file_complete: false,\n },\n );\n }\n }\n } else {\n ensureOnly(parsed.options, [\"page\", \"per-page\"]);\n if (parsed.positionals.length > 1) {\n throw new CliError(\n EXIT_USAGE,\n \"INVALID_ARGUMENT\",\n \"purchases accepts at most one purchase ID\",\n );\n }\n data = parsed.positionals[0]\n ? await client.purchase(\n positiveInteger(parsed.positionals[0], \"purchase ID\")!,\n )\n : await client.purchases({\n page: positiveInteger(parsed.options.get(\"page\"), \"--page\"),\n perPage: positiveInteger(\n parsed.options.get(\"per-page\"),\n \"--per-page\",\n 100,\n ),\n });\n }\n\n await writeOut(\n `${JSON.stringify({\n schema_version: schemaVersion,\n ok: true,\n command,\n ...(meta === undefined ? {} : { meta }),\n data,\n })}\\n`,\n );\n return EXIT_SUCCESS;\n } catch (error) {\n const normalized = await normalizeError(error);\n writeErr(\n `${JSON.stringify({\n schema_version: schemaVersion,\n ok: false,\n command,\n ...(idempotencyKey === undefined\n ? {}\n : { meta: { ...meta, idempotency_key: idempotencyKey } }),\n error: {\n code: normalized.code,\n message: normalized.message,\n ...(normalized.details === undefined\n ? {}\n : { details: normalized.details }),\n },\n })}\\n`,\n );\n return normalized.exitCode;\n }\n}\n","import { chmod, lstat, mkdir, mkdtemp, open, realpath } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\n\nexport async function reserveResultDirectory(\n env: Record<string, string | undefined>,\n): Promise<string> {\n const root = resolve(\n env.WEFT_RESULTS_DIR ||\n join(env.HOME || env.USERPROFILE || homedir(), \".weft-results\"),\n );\n await mkdir(root, { recursive: true, mode: 0o700 });\n const stat = await lstat(root);\n if (!stat.isDirectory() || stat.isSymbolicLink()) {\n throw new Error(\n \"The result storage root must be a directory, not a symlink\",\n );\n }\n if (\n process.platform !== \"win32\" &&\n ((stat.mode & 0o022) !== 0 || stat.uid !== process.getuid?.())\n ) {\n throw new Error(\n \"The result storage root must be owned by this user and not writable by others\",\n );\n }\n // A private child keeps payloads protected without changing an existing parent.\n const directory = await mkdtemp(join(await realpath(root), \"result-\"));\n await chmod(directory, 0o700);\n return directory;\n}\n\nexport async function writeResultFile(\n path: string,\n contents: string | Buffer,\n): Promise<void> {\n const file = await open(path, \"wx\", 0o600);\n try {\n await file.chmod(0o600);\n await file.writeFile(contents);\n await file.sync();\n } finally {\n await file.close();\n }\n}\n\nexport function readableBody(\n bytes: Buffer,\n headers: Record<string, string>,\n): {\n media_type: string | null;\n body_encoding: \"utf-8\" | \"file\";\n body?: string;\n} {\n const header = (name: string) =>\n Object.entries(headers).find(([key]) => key.toLowerCase() === name)?.[1];\n const contentType = header(\"content-type\")?.toLowerCase() ?? \"\";\n const mediaType = contentType.split(\";\", 1)[0].trim();\n const charset = /(?:^|;)\\s*charset\\s*=\\s*\"?([^;\"\\s]+)/.exec(contentType)?.[1];\n const encoding = header(\"content-encoding\")?.trim().toLowerCase();\n const file = {\n media_type: mediaType || null,\n body_encoding: \"file\" as const,\n };\n const textual =\n mediaType.startsWith(\"text/\") ||\n /^application\\/(?:json|xml|javascript|x-ndjson|x-www-form-urlencoded|[^;]+\\+(?:json|xml))$/.test(\n mediaType,\n );\n if (\n (encoding && encoding !== \"identity\") ||\n (charset && ![\"utf-8\", \"utf8\", \"us-ascii\"].includes(charset)) ||\n (!textual && !(bytes.length === 0 && !mediaType))\n )\n return file;\n try {\n // Keep a UTF-8 BOM and JSON spelling exactly as delivered.\n const body = new TextDecoder(\"utf-8\", {\n fatal: true,\n ignoreBOM: true,\n }).decode(bytes);\n return { media_type: mediaType || null, body_encoding: \"utf-8\", body };\n } catch {\n return file;\n }\n}\n"],"mappings":"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","names":["randomUUID","dirname","join","chmod","mkdir","open","resolve","dirname","join","message","result","randomUUID"]}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: weft
|
|
3
|
+
description: Find and buy paid data, APIs, or real-world actions for the current task — enrich a list of companies or people, find and verify contact details, get structured social/review/product/market data, or trigger a paid service. Proactively call `weft_search` before writing a scraper, before a generic web fetch for structured data, and before telling the user something is inaccessible. Skip Weft for local coding, writing, file manipulation, ordinary public-web research, or when the user requests no external services or spending. When `weft_*` tools are missing, use the `weft-setup` skill.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Use Weft
|
|
7
|
+
|
|
8
|
+
Weft is a paid-data marketplace for agents. Four tools do all the work:
|
|
9
|
+
|
|
10
|
+
- `weft_search` — FREE. Treat it like a web search engine, but over the
|
|
11
|
+
paid-API index. Use it to discover what exists: providers, capabilities,
|
|
12
|
+
endpoints, call contracts, and prices. Search early, search often, and
|
|
13
|
+
refine with `filters`. It never costs money.
|
|
14
|
+
- `weft_fetch` — PAID. Executes the endpoint you chose and settles the
|
|
15
|
+
micropayment from the user's wallet. This is the only step that spends
|
|
16
|
+
money. Use it to pay for the data or action the search found.
|
|
17
|
+
- `weft_balance` — read-only. Shows the wallet balance and the spending
|
|
18
|
+
policy. Call it before the first paid fetch of a task; the wallet still
|
|
19
|
+
enforces the policy on every call.
|
|
20
|
+
- `weft_connection_status` — read-only. Reports the state of this
|
|
21
|
+
connection and which tools it can currently call. Use it when a call is
|
|
22
|
+
refused, or while a new account claim is still pending.
|
|
23
|
+
|
|
24
|
+
The loop is always the same: **search (free) → choose → fetch (paid) →
|
|
25
|
+
present**. A complex job runs this loop several times: the output of one
|
|
26
|
+
fetch becomes the input of the next. Weft is like giving an agent a shell —
|
|
27
|
+
compose small paid services into a pipeline.
|
|
28
|
+
|
|
29
|
+
On hosts with a shell, the optional Weft CLI mirrors these tools as
|
|
30
|
+
commands; see [rules/cli.md](rules/cli.md). Everything below applies to
|
|
31
|
+
both surfaces — same loop, same receipts, same safety rules.
|
|
32
|
+
|
|
33
|
+
## Workflow
|
|
34
|
+
|
|
35
|
+
### 1. Search first — it is your web search
|
|
36
|
+
|
|
37
|
+
Start every task with `weft_search`. The live results own the endpoint
|
|
38
|
+
contracts and prices; never rely on a remembered provider catalog.
|
|
39
|
+
|
|
40
|
+
- Search is free. Run it early and iterate: broad query first, then
|
|
41
|
+
reformulate or narrow. An empty result set is not a dead end — it is a
|
|
42
|
+
signal to search again with different words.
|
|
43
|
+
- Use `max_results` (1–50, default 10) to control the result count. Never use
|
|
44
|
+
`limit` — the server rejects it.
|
|
45
|
+
- Narrow with `filters` when the user states a constraint:
|
|
46
|
+
|
|
47
|
+
| Filter | Purpose | Example |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `type` | Kind of resource: `api`, `agent`, `mcp_tool`, `webpage`, `feed`, `document`, `dataset` | `{ "type": { "eq": "agent" } }` |
|
|
50
|
+
| `protocol` | How the endpoint is paid: `x402`, `a2a`, `mpp`, `erc_8004` | `{ "protocol": { "eq": "x402" } }` |
|
|
51
|
+
| `price` | Price cap in USD decimal STRINGS. Exactly one of `lte`, `gte`, `eq`, or the pair `range_gte` + `range_lte` | `{ "price": { "lte": "0.001" } }` |
|
|
52
|
+
| `price_atomic` | The same price constraint as integer micro-USD (1 USDC = 1_000_000). Set `price` OR `price_atomic`, never both | `{ "price_atomic": { "lte": 10000 } }` |
|
|
53
|
+
|
|
54
|
+
`price` values must be strings: send `{ "lte": "0.001" }`, never
|
|
55
|
+
`{ "lte": 0.001 }`. A JSON number is rejected.
|
|
56
|
+
|
|
57
|
+
### 2. Choose one result
|
|
58
|
+
|
|
59
|
+
Read the result envelope. Each `results[]` item has:
|
|
60
|
+
|
|
61
|
+
- Curated results are compact: `provider`, `operation`, typed `inputs`, exact
|
|
62
|
+
`request` bindings, one recommended `access`, `attribution`, an output
|
|
63
|
+
summary, and a content-addressed `contract_url` for full details.
|
|
64
|
+
- In `request`, each mapping is `wire_name: input_name`. URL-encode and
|
|
65
|
+
substitute `path`, append URL-encoded `query` values (repeat the key for
|
|
66
|
+
arrays), and JSON-encode `body.fields`. Send the declared headers and body
|
|
67
|
+
media type.
|
|
68
|
+
- `access.price.indexed_usd` is the observed price. The live payment challenge
|
|
69
|
+
remains authoritative.
|
|
70
|
+
- Pass all three `attribution` values to `weft_fetch`; do not reconstruct them.
|
|
71
|
+
- Fetch `contract_url` when the inline inputs, request recipe, price, and output
|
|
72
|
+
summary are insufficient. Always fetch it before an async submission. It
|
|
73
|
+
contains the full provider lifecycle, alternatives, evidence, and known gaps.
|
|
74
|
+
- Platform results retain the legacy `provider` / `capability` / `endpoints[]`
|
|
75
|
+
shape. For those, use `endpoints[0]` and its `call` and `price` blocks.
|
|
76
|
+
- `score` — relevance; higher is better.
|
|
77
|
+
|
|
78
|
+
Select the cheapest endpoint that satisfies the request. When prices are
|
|
79
|
+
equal, prefer the higher `score`. Do not pick the most relevant result if a
|
|
80
|
+
cheaper one does the job. If a merchant looks unproven (very new, no
|
|
81
|
+
settlement history), flag it to the user before spending against it.
|
|
82
|
+
|
|
83
|
+
When the result set is empty, read `match_quality`, `reason`, and
|
|
84
|
+
`suggestion` in the envelope — the server tells you why nothing matched.
|
|
85
|
+
Loosen the filters or change the query and search again; it costs nothing.
|
|
86
|
+
|
|
87
|
+
### 3. Fetch to pay
|
|
88
|
+
|
|
89
|
+
Before the first paid fetch of a task, call `weft_balance`. Abort and tell
|
|
90
|
+
the user when the balance or the remaining transaction, daily, or weekly
|
|
91
|
+
policy headroom is below the expected cost. The wallet enforces the policy
|
|
92
|
+
on every call — this check exists so you never propose spend the wallet
|
|
93
|
+
will refuse.
|
|
94
|
+
|
|
95
|
+
Call `weft_fetch` with:
|
|
96
|
+
|
|
97
|
+
- `url` — the final URL built from the curated `request`, or the exact legacy
|
|
98
|
+
`endpoints[0].url`
|
|
99
|
+
- `max_cost_usd` — a tight cap as a decimal string (e.g. `"0.02"`). Always
|
|
100
|
+
set it — an unset cap silently defaults to `"0.10"`. Never silently raise
|
|
101
|
+
it.
|
|
102
|
+
- `method` / `body` / `headers` — per the curated request recipe or legacy
|
|
103
|
+
endpoint call contract
|
|
104
|
+
- `search_id`, `operation_id`, and `access_method_id` — copy the curated
|
|
105
|
+
`attribution` block. For legacy results, always pass `query_trace_id` as
|
|
106
|
+
`search_id` and pass operation/access ids when present.
|
|
107
|
+
|
|
108
|
+
After the call:
|
|
109
|
+
|
|
110
|
+
- Decode `body_base64` when present — that is the purchased data.
|
|
111
|
+
- Read the receipt. The cost is `paid_usd + held_usd`. `payment_status:
|
|
112
|
+
"pending"` with a `held_usd` amount is a successful paid request whose
|
|
113
|
+
settlement is still confirming — money likely moved, do not retry.
|
|
114
|
+
- Preserve receipt identifiers such as `artifact_id`, `tx_hash`, `protocol`,
|
|
115
|
+
and `payment_status`.
|
|
116
|
+
- When `access.weft_fetch.coverage` is `submission_only`, the paid fetch starts
|
|
117
|
+
the work but does not return the final result. Read the response id at
|
|
118
|
+
`output.workflow.id_pointer`, then follow the documented free poll request
|
|
119
|
+
until a listed success or failure value. Reuse every identity header exactly
|
|
120
|
+
as documented. Do not send the free poll through `weft_fetch`, and do not
|
|
121
|
+
repeat the paid submission while a job is pending.
|
|
122
|
+
|
|
123
|
+
### 4. Present the result
|
|
124
|
+
|
|
125
|
+
Return the decoded data to the user, not the raw receipt. State what you paid
|
|
126
|
+
and from which provider.
|
|
127
|
+
|
|
128
|
+
## Compose services — Weft is your shell
|
|
129
|
+
|
|
130
|
+
One fetch rarely completes a real job. Weft is a toolbox: chain two or more
|
|
131
|
+
services, like shell pipelines. Each stage is one `search → choose → fetch`
|
|
132
|
+
pass. The output of one stage becomes the input of the next. Search at every
|
|
133
|
+
stage is free — use it to find the provider for the next step.
|
|
134
|
+
|
|
135
|
+
**Example — prospect table.** Build a table of CTOs at companies building AI
|
|
136
|
+
agents: `| name | surname | email | website | LinkedIn |`.
|
|
137
|
+
|
|
138
|
+
1. **Find the companies.** Search for a company or web-search provider and
|
|
139
|
+
fetch it to list the target companies with their domains and websites.
|
|
140
|
+
2. **Find the people.** Search for a people-search provider (for example
|
|
141
|
+
Apollo, People Data Labs, or Minerva) and fetch it filtered to the title
|
|
142
|
+
and industry. Collect the names, companies, and any emails already
|
|
143
|
+
returned.
|
|
144
|
+
3. **Enrich.** For the people who still lack an email or LinkedIn URL, search
|
|
145
|
+
for a people-enrichment endpoint and fetch it once per person.
|
|
146
|
+
4. **Verify (optional).** Check the deliverability of the emails with an
|
|
147
|
+
email verifier before the user sends anything.
|
|
148
|
+
5. **Assemble.** Merge the payloads into the requested table and present it.
|
|
149
|
+
|
|
150
|
+
Pipeline rules:
|
|
151
|
+
|
|
152
|
+
- Do not manage the budget. The wallet enforces the spending policy: it
|
|
153
|
+
refuses any call the policy, the per-call cap, or the balance does not
|
|
154
|
+
allow. Set a tight `max_cost_usd` per call and state the expected cost
|
|
155
|
+
before you spend.
|
|
156
|
+
- Prefer one endpoint that returns everything you need over several calls.
|
|
157
|
+
Enrich only the records that still miss fields.
|
|
158
|
+
- Pass each stage's `query_trace_id` as `search_id` on that stage's `fetch`,
|
|
159
|
+
so every purchase is attributed to the search that found it.
|
|
160
|
+
- A failed record is not a failed pipeline. Continue with the rest, then
|
|
161
|
+
report the failures.
|
|
162
|
+
- Do not retry a paid call. If a stage fails, search again for a substitute
|
|
163
|
+
provider — that search is free.
|
|
164
|
+
|
|
165
|
+
## Side-effecting actions (POST)
|
|
166
|
+
|
|
167
|
+
Some endpoints change the world: send an SMS, book a slot, print a label.
|
|
168
|
+
`weft_fetch` with `method: "POST"` is a real-world action.
|
|
169
|
+
|
|
170
|
+
- Search and choose as usual.
|
|
171
|
+
- Before you call it, show the user the recipient and the payload, and get
|
|
172
|
+
explicit confirmation.
|
|
173
|
+
- A policy, balance, price-cap, or denylist refusal is a hard stop. Explain
|
|
174
|
+
it; do not weaken or work around the user's controls.
|
|
175
|
+
|
|
176
|
+
## Spending and side-effect safety
|
|
177
|
+
|
|
178
|
+
The wallet enforces the spending policy on every paid call. It refuses any
|
|
179
|
+
request that exceeds the policy, the per-call cap, or the balance. You do
|
|
180
|
+
not track budgets or compute remaining spend — the wallet does that.
|
|
181
|
+
|
|
182
|
+
- Call `weft_balance` before the first paid fetch of a task; abort when
|
|
183
|
+
the balance or policy headroom is below the expected cost.
|
|
184
|
+
- Set a tight `max_cost_usd` on every fetch. Never silently raise it.
|
|
185
|
+
- State the expected cost before a paid call, and the actual cost after it
|
|
186
|
+
(`paid_usd + held_usd`).
|
|
187
|
+
- A policy, balance, price-cap, or denylist refusal is a hard stop. Explain
|
|
188
|
+
it; do not weaken or work around the user's controls.
|
|
189
|
+
- Do not automatically retry any paid fetch after a timeout or ambiguous
|
|
190
|
+
response. Search, balance, and connection-status calls are safe to retry.
|
|
191
|
+
- Confirm a side-effecting request's recipient and payload when the user did
|
|
192
|
+
not specify them clearly.
|
|
193
|
+
- Never request or forward wallet keys, provider credentials, cookies,
|
|
194
|
+
authorization headers, or payment headers. Never print or ask the human to
|
|
195
|
+
paste a `wk_`, `wbt_`, or OAuth credential.
|
|
196
|
+
- Do not claim durable idempotency for paid calls. A repeated request can
|
|
197
|
+
create a second charge or side effect.
|
|
198
|
+
|
|
199
|
+
## Errors
|
|
200
|
+
|
|
201
|
+
- Missing `weft_*` tools: stop and use the `weft-setup` skill (hosted at
|
|
202
|
+
https://weft.network/setup.md). Do not invent an API key or an MCP
|
|
203
|
+
configuration.
|
|
204
|
+
- A refusal on `weft_balance` or `weft_fetch` while a new account claim is
|
|
205
|
+
still pending is the contract working, not a bug. Check
|
|
206
|
+
`weft_connection_status`, and finish the claim before retrying.
|
|
207
|
+
- `insufficient_scope`: tell the user Weft authorization must be renewed with
|
|
208
|
+
the required scope.
|
|
209
|
+
- `POLICY_VIOLATION_*`: the spending policy refused the call — a cap, a
|
|
210
|
+
spend window, a denylist, or a missing policy, not necessarily
|
|
211
|
+
overspending. Surface the `dashboard_url` so the user can adjust. Hard
|
|
212
|
+
stop; do not retry silently.
|
|
213
|
+
- `SETTLEMENT_FAILED`: settlement failed upstream. The error's `protocol`
|
|
214
|
+
detail names the payment rail that failed. Surface it and stop; do not
|
|
215
|
+
retry a paid call.
|
|
216
|
+
- Search validation errors: correct the request to the live tool schema and
|
|
217
|
+
retry the free search.
|
|
218
|
+
- Paid fetch errors or ambiguous outcomes: surface the receipt and error
|
|
219
|
+
as-is; do not retry unless the user explicitly decides after seeing the
|
|
220
|
+
risk.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Weft CLI reference
|
|
2
|
+
|
|
3
|
+
The `weft` CLI is the machine-local surface for the same account: same
|
|
4
|
+
search → choose → fetch loop, same receipts, same safety rules as the MCP
|
|
5
|
+
tools in [SKILL.md](../SKILL.md). Use it on a persistent machine with a
|
|
6
|
+
shell — for headless runs, scripts, and pipelines. Never install it in an
|
|
7
|
+
ephemeral cloud sandbox: its credential store dies with the container.
|
|
8
|
+
|
|
9
|
+
It prints one versioned JSON object per command — parse the output instead
|
|
10
|
+
of reading prose. `weft --help` and `weft <command> --help` return
|
|
11
|
+
machine-readable JSON and need no credential; read them before guessing a
|
|
12
|
+
flag.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm install -g @weft-labs/cli
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Zero-install equivalent for any command below:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npx --package @weft-labs/cli weft --help
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Commands
|
|
27
|
+
|
|
28
|
+
Once an authenticated credential exists — from the bootstrap flow below or
|
|
29
|
+
an existing `WEFT_API_KEY`:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
weft me # who am I
|
|
33
|
+
weft balance # wallet + spending policy
|
|
34
|
+
weft search "weather data API" --max-results 5 # free
|
|
35
|
+
weft fetch "https://merchant.example/data" --max-cost-usd 0.05
|
|
36
|
+
weft purchases # receipt history
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- `weft fetch` always requires `--max-cost-usd`. Set a tight ceiling; never
|
|
40
|
+
omit it.
|
|
41
|
+
- Every spending rule from SKILL.md applies verbatim: balance before paid
|
|
42
|
+
actions, state costs, no silent retries of paid calls, hard stop on policy
|
|
43
|
+
refusals.
|
|
44
|
+
|
|
45
|
+
## Bootstrap (no credential yet)
|
|
46
|
+
|
|
47
|
+
The CLI can start with nothing but the human's email address. Never ask
|
|
48
|
+
for, accept, or store their password.
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
# 1. Create the temporary bootstrap; a claim link goes to the email only.
|
|
52
|
+
weft bootstrap --email "human@example.com" \
|
|
53
|
+
--agent-name "Research agent" \
|
|
54
|
+
--reason "Find weather data"
|
|
55
|
+
|
|
56
|
+
# 2. Search immediately — free, works while the claim is pending.
|
|
57
|
+
weft search "weather data API"
|
|
58
|
+
|
|
59
|
+
# 3. Tell the human to open the claim email and approve. Show them the
|
|
60
|
+
# user code from the bootstrap response so they can match this session.
|
|
61
|
+
|
|
62
|
+
# 4. Poll at the interval the bootstrap response returned — no faster.
|
|
63
|
+
weft auth status
|
|
64
|
+
|
|
65
|
+
# 5. After approval the stored credential is promoted in place.
|
|
66
|
+
weft me
|
|
67
|
+
|
|
68
|
+
# 6. The balance is the truth: a new wallet holds at most a one-time
|
|
69
|
+
# signup grant. To add money, send the human to
|
|
70
|
+
# https://weft.network/dashboard/wallet.
|
|
71
|
+
weft balance
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Status lifecycle: `pending` (search works, keep polling) → `claimed` /
|
|
75
|
+
`consumed` (done — normal commands work) or `rejected` / `expired`
|
|
76
|
+
(terminal — stop; do not create a second bootstrap for the same request
|
|
77
|
+
without asking the user).
|
|
78
|
+
|
|
79
|
+
The temporary `wbt_` credential is secret, expires in 30 minutes, and is
|
|
80
|
+
search-only until claimed. Refusals on balance/fetch before the claim are
|
|
81
|
+
the contract, not bugs. The CLI stores every credential in a mode-0600
|
|
82
|
+
local file and never prints secrets — neither do you.
|
|
83
|
+
|
|
84
|
+
## Credentials
|
|
85
|
+
|
|
86
|
+
Precedence: `--api-key-stdin`, then `WEFT_API_KEY`, then the stored
|
|
87
|
+
bootstrap/OAuth credential. The CLI rejects API keys passed as command
|
|
88
|
+
arguments so they never reach shell history. Never echo any credential —
|
|
89
|
+
`wbt_`, `wk_`, or an OAuth token — into your output.
|
|
90
|
+
|
|
91
|
+
## Errors
|
|
92
|
+
|
|
93
|
+
One JSON object on stderr with a stable `error.code`. Exit codes: `2`
|
|
94
|
+
invalid usage, `3` missing auth or 401/403, `4` other 4xx or policy
|
|
95
|
+
rejection, `5` 5xx/network/internal. `POLICY_VIOLATION_*` and
|
|
96
|
+
`SETTLEMENT_FAILED` are handled exactly as in SKILL.md.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
# Agent bootstrap and human claim, end to end, with no Weft credential.
|
|
3
|
+
#
|
|
4
|
+
# The agent needs the human's email address and nothing else.
|
|
5
|
+
# It never asks for, receives, or stores the human's password.
|
|
6
|
+
# No promotional balance, free credit, or subsidy exists at any point here:
|
|
7
|
+
# a paid fetch spends the human's own funded wallet.
|
|
8
|
+
#
|
|
9
|
+
# Every command prints one JSON envelope. Parse it; never echo a credential.
|
|
10
|
+
set -eu
|
|
11
|
+
|
|
12
|
+
: "${WEFT_CLAIM_EMAIL:?Set WEFT_CLAIM_EMAIL to the email address of the human}"
|
|
13
|
+
AGENT_NAME="${WEFT_AGENT_NAME:-Example agent}"
|
|
14
|
+
REASON="${WEFT_BOOTSTRAP_REASON:-Find weather data}"
|
|
15
|
+
|
|
16
|
+
# `weft --help` needs no credential and lists every implemented command.
|
|
17
|
+
if ! weft --help | grep -q '"name":"bootstrap"'; then
|
|
18
|
+
echo "This @weftlabs/cli build has no bootstrap command yet; run 'weft --help'." >&2
|
|
19
|
+
exit 0
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
# 1. The email address is the only thing the agent asks the human for.
|
|
23
|
+
# 2. Create the temporary bootstrap. This emails the claim link to that address
|
|
24
|
+
# and stores the wbt_ credential in a mode-0600 local credential file.
|
|
25
|
+
bootstrap="$(weft bootstrap \
|
|
26
|
+
--email "$WEFT_CLAIM_EMAIL" \
|
|
27
|
+
--agent-name "$AGENT_NAME" \
|
|
28
|
+
--reason "$REASON")"
|
|
29
|
+
printf '%s\n' "$bootstrap"
|
|
30
|
+
POLL_INTERVAL="$(printf '%s' "$bootstrap" | node -e \
|
|
31
|
+
'let s=""; process.stdin.on("data", d => s += d).on("end", () => process.stdout.write(String(JSON.parse(s).data.polling_interval)))')"
|
|
32
|
+
|
|
33
|
+
# 3. Search immediately. The temporary credential is search-only and expires
|
|
34
|
+
# 30 minutes after creation.
|
|
35
|
+
weft search "weather data API"
|
|
36
|
+
|
|
37
|
+
# 4. Tell the human to open the claim email and approve this agent. Show them
|
|
38
|
+
# the user code from the bootstrap envelope above; the claim link is only in
|
|
39
|
+
# the email.
|
|
40
|
+
# 5. Poll at the interval the bootstrap response returned. A claimed response
|
|
41
|
+
# completes the OAuth exchange and reports consumed. Other terminal states
|
|
42
|
+
# need a new bootstrap.
|
|
43
|
+
while :; do
|
|
44
|
+
sleep "$POLL_INTERVAL"
|
|
45
|
+
auth="$(weft auth status)"
|
|
46
|
+
printf '%s\n' "$auth"
|
|
47
|
+
status="$(printf '%s' "$auth" | node -e \
|
|
48
|
+
'let s=""; process.stdin.on("data", d => s += d).on("end", () => process.stdout.write(JSON.parse(s).data.status))')"
|
|
49
|
+
case "$status" in
|
|
50
|
+
pending) ;;
|
|
51
|
+
consumed) break ;;
|
|
52
|
+
rejected|expired)
|
|
53
|
+
echo "Bootstrap ended with status: $status" >&2
|
|
54
|
+
exit 1
|
|
55
|
+
;;
|
|
56
|
+
*)
|
|
57
|
+
echo "Unexpected bootstrap status: $status" >&2
|
|
58
|
+
exit 1
|
|
59
|
+
;;
|
|
60
|
+
esac
|
|
61
|
+
done
|
|
62
|
+
|
|
63
|
+
# 6. After approval the CLI replaces the temporary credential with the OAuth
|
|
64
|
+
# tokens the human approved, and ordinary commands work again.
|
|
65
|
+
weft me
|
|
66
|
+
|
|
67
|
+
# 7. Claiming provisions an empty wallet. Ask the human to fund it before any
|
|
68
|
+
# paid fetch.
|
|
69
|
+
weft balance
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@weftlabs/cli",
|
|
3
|
+
"version": "0.25.0",
|
|
4
|
+
"description": "Command-line client for the Weft buyer runtime",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"weft": "./bin/weft.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"dist",
|
|
12
|
+
"examples",
|
|
13
|
+
"README.md",
|
|
14
|
+
"scripts/install-skill.mjs",
|
|
15
|
+
"scripts/skill-paths.mjs"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"weft",
|
|
19
|
+
"cli",
|
|
20
|
+
"agents",
|
|
21
|
+
"x402"
|
|
22
|
+
],
|
|
23
|
+
"author": "Weft Labs",
|
|
24
|
+
"license": "Apache-2.0",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/weftlabs/weft-sdk",
|
|
28
|
+
"directory": "cli"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@weftlabs/sdk": "0.25.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^26.1.2",
|
|
35
|
+
"@typescript-eslint/eslint-plugin": "^8.29.1",
|
|
36
|
+
"@typescript-eslint/parser": "^8.29.1",
|
|
37
|
+
"eslint": "^10.4.1",
|
|
38
|
+
"prettier": "3.9.6",
|
|
39
|
+
"tsup": "^8.4.0",
|
|
40
|
+
"typescript": "^6.0.3",
|
|
41
|
+
"vitest": "^4.1.8"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18.0.0"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsup",
|
|
48
|
+
"pretest": "pnpm --filter @weftlabs/sdk build",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"pretest:unit": "pnpm --filter @weftlabs/sdk build",
|
|
51
|
+
"test:unit": "vitest run",
|
|
52
|
+
"lint:check": "eslint",
|
|
53
|
+
"format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\""
|
|
54
|
+
}
|
|
55
|
+
}
|