@envarai/envarpay 0.2.0-alpha.8 → 2026.1025.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +18 -56
  2. package/dist/commerce/agent-setup.d.ts +19 -0
  3. package/dist/commerce/agent-setup.js +210 -0
  4. package/dist/commerce/alerts.d.ts +5 -15
  5. package/dist/commerce/alerts.js +21 -77
  6. package/dist/commerce/card.js +1 -1
  7. package/dist/commerce/cli.js +74 -137
  8. package/dist/commerce/config.d.ts +1 -4
  9. package/dist/commerce/config.js +5 -81
  10. package/dist/commerce/configure.d.ts +2 -0
  11. package/dist/commerce/configure.js +78 -0
  12. package/dist/commerce/discovery.d.ts +20 -0
  13. package/dist/commerce/discovery.js +162 -0
  14. package/dist/commerce/envar-balance.d.ts +25 -0
  15. package/dist/commerce/envar-balance.js +65 -0
  16. package/dist/commerce/envar-runtime.d.ts +1 -0
  17. package/dist/commerce/envar-runtime.js +7 -0
  18. package/dist/commerce/envar.d.ts +13 -31
  19. package/dist/commerce/envar.js +35 -83
  20. package/dist/commerce/external-agent.d.ts +26 -0
  21. package/dist/commerce/external-agent.js +129 -0
  22. package/dist/commerce/external-events.d.ts +76 -0
  23. package/dist/commerce/external-events.js +273 -0
  24. package/dist/commerce/external-mcp.d.ts +10 -0
  25. package/dist/commerce/external-mcp.js +199 -0
  26. package/dist/commerce/external-oauth.d.ts +12 -0
  27. package/dist/commerce/external-oauth.js +230 -0
  28. package/dist/commerce/external-runtime.d.ts +25 -0
  29. package/dist/commerce/external-runtime.js +244 -0
  30. package/dist/commerce/managed.d.ts +3 -0
  31. package/dist/commerce/managed.js +143 -0
  32. package/dist/commerce/native-inventory.d.ts +9 -0
  33. package/dist/commerce/native-inventory.js +75 -0
  34. package/dist/commerce/native-skills.d.ts +8 -0
  35. package/dist/commerce/native-skills.js +11 -8
  36. package/dist/commerce/openclaw-setup.d.ts +28 -0
  37. package/dist/commerce/openclaw-setup.js +43 -0
  38. package/dist/commerce/operations.d.ts +1 -2
  39. package/dist/commerce/operations.js +17 -20
  40. package/dist/commerce/pricing.d.ts +0 -1
  41. package/dist/commerce/pricing.js +1 -3
  42. package/dist/commerce/runtime.d.ts +2 -2
  43. package/dist/commerce/runtime.js +2 -2
  44. package/dist/commerce/server.d.ts +0 -1
  45. package/dist/commerce/server.js +2 -3
  46. package/dist/commerce/setup.d.ts +25 -0
  47. package/dist/commerce/setup.js +379 -0
  48. package/dist/commerce/store.d.ts +11 -1
  49. package/dist/commerce/store.js +36 -2
  50. package/dist/commerce/types.d.ts +1 -56
  51. package/examples/envar-integration-policy.json +1 -9
  52. package/examples/seller.json +143 -26
  53. package/package.json +11 -20
  54. package/runtime/hermes-setup-probe.py +109 -0
  55. package/runtime/hermes-skill-inventory.py +108 -0
  56. package/schemas/envarpay.config.schema.json +7 -73
  57. package/dist/commerce/buyer-store.d.ts +0 -101
  58. package/dist/commerce/buyer-store.js +0 -168
  59. package/dist/commerce/buyer.d.ts +0 -138
  60. package/dist/commerce/buyer.js +0 -775
  61. package/dist/commerce/chain.d.ts +0 -24
  62. package/dist/commerce/chain.js +0 -146
  63. package/dist/commerce/client-runtime.d.ts +0 -8
  64. package/dist/commerce/client-runtime.js +0 -7
  65. package/dist/commerce/management.d.ts +0 -14
  66. package/dist/commerce/management.js +0 -140
  67. package/dist/commerce/mpp-client.d.ts +0 -70
  68. package/dist/commerce/mpp-client.js +0 -29
  69. package/dist/commerce/mpp-runtime.d.ts +0 -4
  70. package/dist/commerce/mpp-runtime.js +0 -4
  71. package/dist/commerce/mpp.d.ts +0 -53
  72. package/dist/commerce/mpp.js +0 -163
  73. package/dist/commerce/peer-proxy.d.ts +0 -44
  74. package/dist/commerce/peer-proxy.js +0 -673
  75. package/dist/commerce/stripe-issuer.d.ts +0 -41
  76. package/dist/commerce/stripe-issuer.js +0 -351
  77. package/dist/commerce/stripe-provider.d.ts +0 -11
  78. package/dist/commerce/stripe-provider.js +0 -132
  79. package/dist/commerce/x402.d.ts +0 -37
  80. package/dist/commerce/x402.js +0 -174
  81. package/dist/index.d.ts +0 -95
  82. package/dist/index.js +0 -163
  83. package/examples/buyer-policy.json +0 -18
  84. package/schemas/buyer-policy.schema.json +0 -253
  85. /package/{examples → runtime}/native-skill-runner.py +0 -0
@@ -0,0 +1,75 @@
1
+ import { existsSync, lstatSync, readFileSync, readdirSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { extname, join, resolve } from 'node:path';
4
+ import { createHash } from 'node:crypto';
5
+ import { parse } from 'yaml';
6
+ const namePattern = /^[a-z][a-z0-9-]{0,63}$/;
7
+ // Native installer provenance is included in the source digest, but never
8
+ // copied into the executable service package or supplied to the model.
9
+ export const isSkillInstallerMetadata = (path) => path === '.clawhub/origin.json' || path === '.openclaw/source-origin.json';
10
+ export function readSkillInventory(roots) {
11
+ const found = [];
12
+ const seen = new Set();
13
+ function visit(folder, depth) {
14
+ if (depth > 10 || found.length >= 128 || !existsSync(folder))
15
+ return;
16
+ const stat = lstatSync(folder);
17
+ if (!stat.isDirectory() || stat.isSymbolicLink())
18
+ return;
19
+ const entry = join(folder, 'SKILL.md');
20
+ if (!existsSync(entry)) {
21
+ for (const child of readdirSync(folder).sort())
22
+ if (!child.startsWith('.'))
23
+ visit(join(folder, child), depth + 1);
24
+ return;
25
+ }
26
+ const info = lstatSync(entry);
27
+ if (!info.isFile() || info.isSymbolicLink() || info.size > 48000)
28
+ return;
29
+ const raw = readFileSync(entry, 'utf8'), header = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(raw)?.[1];
30
+ let meta;
31
+ try {
32
+ meta = parse(header ?? '') ?? {};
33
+ }
34
+ catch {
35
+ return;
36
+ }
37
+ if (typeof meta.name !== 'string' || !namePattern.test(meta.name) || seen.has(meta.name))
38
+ return;
39
+ const files = [];
40
+ let size = 0, supported = true;
41
+ function collect(path, prefix = '', level = 0) {
42
+ if (level > 10) {
43
+ supported = false;
44
+ return;
45
+ }
46
+ for (const name of readdirSync(path).sort()) {
47
+ const file = join(path, name), s = lstatSync(file);
48
+ if (s.isSymbolicLink()) {
49
+ supported = false;
50
+ continue;
51
+ }
52
+ if (s.isDirectory()) {
53
+ collect(file, prefix + name + '/', level + 1);
54
+ continue;
55
+ }
56
+ if (!s.isFile() || s.size > 512 * 1024 || (size += s.size) > 1024 * 1024 || files.length >= 128) {
57
+ supported = false;
58
+ continue;
59
+ }
60
+ if (!['.md', '.txt'].includes(extname(name).toLowerCase()) && name !== 'LICENSE' && !isSkillInstallerMetadata(prefix + name))
61
+ supported = false;
62
+ files.push([prefix + name, createHash('sha256').update(readFileSync(file)).digest('hex')]);
63
+ }
64
+ }
65
+ collect(folder);
66
+ files.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
67
+ const canonical = JSON.stringify(files).replace(/[\u007f-\uffff]/g, c => '\\u' + c.charCodeAt(0).toString(16).padStart(4, '0'));
68
+ seen.add(meta.name);
69
+ found.push({ name: meta.name, path: resolve(folder), description: String(meta.description ?? '').slice(0, 500), supported, digest: createHash('sha256').update(canonical).digest('hex'), files: files.length });
70
+ }
71
+ for (const root of roots.slice(0, 16))
72
+ if (typeof root === 'string')
73
+ visit(resolve(root.replace(/^~(?=\/|$)/, homedir())), 0);
74
+ return found;
75
+ }
@@ -10,6 +10,14 @@ export interface NativeSkillSettings {
10
10
  model: string;
11
11
  baseUrl: string;
12
12
  apiKeyFile: string;
13
+ /** Host-side Docker CLI, never a Docker socket mounted into the Agent. */
14
+ dockerContainer?: string;
15
+ dockerStateDirectory?: string;
16
+ discovery?: {
17
+ hermesHome: string;
18
+ enabledFromWeb: true;
19
+ roots?: string[];
20
+ };
13
21
  }
14
22
  interface InstalledSkill {
15
23
  descriptor: SkillDescriptor;
@@ -56,8 +56,8 @@ export function readInstalledSkills(root, freeSkills, cardUrl) {
56
56
  throw new CommerceError('skill_size', 'Instruction resources exceed the supported context size');
57
57
  output.push({ descriptor: { name, digest: digest(files), cardUrl, access: freeSkills.includes(name) ? 'free' : 'paid', description }, instructions: instructions + references });
58
58
  }
59
- if (!output.length || output.length > 32 || freeSkills.some(name => !output.some(s => s.descriptor.name === name)))
60
- throw new CommerceError('skill_inventory', 'Install between 1 and 32 skills and declare only installed free skills');
59
+ if (output.length > 32 || freeSkills.some(name => !output.some(s => s.descriptor.name === name)))
60
+ throw new CommerceError('skill_inventory', 'Install at most 32 skills and declare only installed free skills');
61
61
  // Free helpers are executable dependencies of every purchase, so their versions
62
62
  // and access-policy changes must invalidate the quote's selected skill digest too.
63
63
  const helpers = output.filter(s => s.descriptor.access === 'free').map(s => ({ name: s.descriptor.name, digest: s.descriptor.digest }));
@@ -70,7 +70,7 @@ export function createNativeSkillExecutor(settings, origin, agentName) {
70
70
  throw new CommerceError('skill_settings', 'Configure a supported native skill runtime');
71
71
  const cardUrl = new URL('/.well-known/agent-card.json', origin).href;
72
72
  const installed = () => readInstalledSkills(settings.skillsDirectory, settings.freeSkills, cardUrl);
73
- const initial = installed();
73
+ installed();
74
74
  mkdirSync(settings.stateDirectory, { recursive: true, mode: 0o700 });
75
75
  const stateStat = lstatSync(settings.stateDirectory);
76
76
  if (!stateStat.isDirectory() || stateStat.isSymbolicLink() || (stateStat.mode & 0o077) !== 0)
@@ -85,7 +85,7 @@ export function createNativeSkillExecutor(settings, origin, agentName) {
85
85
  }
86
86
  }
87
87
  const inFlight = new Map();
88
- const runner = fileURLToPath(new URL('../../examples/native-skill-runner.py', import.meta.url));
88
+ const runner = fileURLToPath(new URL('../../runtime/native-skill-runner.py', import.meta.url));
89
89
  function readTask(id, invocation) {
90
90
  const row = db.prepare('SELECT order_id,task_json FROM skill_tasks WHERE id=?').get(id);
91
91
  if (!row || row.order_id !== invocation.orderId)
@@ -94,7 +94,12 @@ export function createNativeSkillExecutor(settings, origin, agentName) {
94
94
  }
95
95
  function executeProcess(payload) {
96
96
  return new Promise((accept, reject) => {
97
- const child = spawn(settings.python, [runner], { stdio: ['pipe', 'pipe', 'pipe'], env: { PATH: process.env.PATH, LANG: 'C.UTF-8', PYTHONUNBUFFERED: '1' } });
97
+ const docker = settings.dockerContainer;
98
+ if (docker && !/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/.test(docker))
99
+ throw new CommerceError('skill_container', 'Invalid Docker container name');
100
+ const child = docker
101
+ ? spawn('docker', ['exec', '-i', docker, settings.python, '-c', readFileSync(runner, 'utf8')], { stdio: ['pipe', 'pipe', 'pipe'], env: { PATH: process.env.PATH, HOME: process.env.HOME, DOCKER_CONFIG: process.env.DOCKER_CONFIG, DOCKER_HOST: process.env.DOCKER_HOST } })
102
+ : spawn(settings.python, [runner], { stdio: ['pipe', 'pipe', 'pipe'], env: { PATH: process.env.PATH, LANG: 'C.UTF-8', PYTHONUNBUFFERED: '1' } });
98
103
  const chunks = [];
99
104
  let size = 0;
100
105
  const timeout = setTimeout(() => child.kill('SIGTERM'), 240000);
@@ -145,7 +150,7 @@ export function createNativeSkillExecutor(settings, origin, agentName) {
145
150
  const operation = (async () => {
146
151
  let task;
147
152
  try {
148
- const result = await executeProcess({ settings: { ...settings, stateDirectory: join(settings.stateDirectory, id) }, skillName: name, skills: allowed.map(s => ({ name: s.descriptor.name, instructions: s.instructions })), input });
153
+ const result = await executeProcess({ settings: { ...settings, stateDirectory: join(settings.dockerStateDirectory ?? settings.stateDirectory, id) }, skillName: name, skills: allowed.map(s => ({ name: s.descriptor.name, instructions: s.instructions })), input });
149
154
  task = Task.fromJSON({ id, status: { state: 'TASK_STATE_COMPLETED' }, artifacts: [{ artifactId: 'result', name: name + '.md', parts: [{ text: result.output, mediaType: 'text/markdown' }] }], metadata: { skillName: name, skillDigest: selected.descriptor.digest, allowedSkills: allowed.map(s => s.descriptor.name), framework: settings.framework, tools: result.tools, sessionId: result.sessionId ?? id } });
150
155
  }
151
156
  catch (error) {
@@ -165,7 +170,5 @@ export function createNativeSkillExecutor(settings, origin, agentName) {
165
170
  const skills = installed();
166
171
  return AgentCard.fromJSON({ name: agentName, description: 'Installed Agent Skills', version: '1.0', supportedInterfaces: [{ url: new URL('/a2a', origin).href, protocolBinding: 'JSONRPC', protocolVersion: '1.0' }], capabilities: { extensions: [{ uri: 'urn:envarpay:skill-gate:1', required: false, params: { runtime: 'instruction-only-v1', skills: skills.map(s => ({ name: s.descriptor.name, digest: s.descriptor.digest, access: s.descriptor.access })) } }] }, defaultInputModes: ['application/json'], defaultOutputModes: ['text/markdown'], skills: skills.map(s => ({ id: s.descriptor.name, name: s.descriptor.name, description: s.descriptor.description, tags: [s.descriptor.name] })) });
167
172
  };
168
- if (initial.length === 0)
169
- throw new CommerceError('skill_inventory', 'No installed skills');
170
173
  return { execute, close: async () => { await Promise.allSettled(inFlight.values()); db.close(); } };
171
174
  }
@@ -0,0 +1,28 @@
1
+ export declare function openclawRoots(home?: string): string[];
2
+ export declare function openclawInventory(home?: string): {
3
+ name: string;
4
+ path: string;
5
+ description: string;
6
+ supported: boolean;
7
+ digest: string;
8
+ files: number;
9
+ }[];
10
+ export declare function probeOpenClaw(home?: string, python?: string): {
11
+ home: string;
12
+ python: string;
13
+ command: string[];
14
+ model: string;
15
+ baseUrl: any;
16
+ apiKeyFile: null;
17
+ apiKey: string;
18
+ skillRoots: string[];
19
+ skills: {
20
+ textPackage: boolean;
21
+ name: string;
22
+ path: string;
23
+ description: string;
24
+ supported: boolean;
25
+ digest: string;
26
+ files: number;
27
+ }[];
28
+ };
@@ -0,0 +1,43 @@
1
+ /** Read local OpenClaw configuration and installed Skill metadata without invoking a model. */
2
+ import { existsSync, lstatSync, readFileSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { dirname, join, resolve } from 'node:path';
5
+ import { execFileSync } from 'node:child_process';
6
+ import { readSkillInventory } from './native-inventory.js';
7
+ import { CommerceError } from './types.js';
8
+ function configuration(home) {
9
+ const path = home ? join(resolve(home), 'openclaw.json') : process.env.OPENCLAW_CONFIG_PATH ?? join(process.env.OPENCLAW_STATE_DIR ?? join(homedir(), '.openclaw'), 'openclaw.json');
10
+ const stat = lstatSync(path);
11
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024)
12
+ throw new CommerceError('setup_model', 'Use a bounded local OpenClaw configuration file');
13
+ return { home: dirname(resolve(path)), config: JSON.parse(readFileSync(path, 'utf8')) };
14
+ }
15
+ export function openclawRoots(home) {
16
+ const local = configuration(home), config = local.config, defaults = config.agents?.defaults ?? {};
17
+ const agent = config.agents?.list?.find((a) => a.default || a.id === 'main');
18
+ return [join(local.home, 'skills'), join(agent?.workspace ?? defaults.workspace ?? join(local.home, 'workspace'), 'skills'), ...(config.skills?.load?.extraDirs ?? [])].filter((r) => typeof r === 'string');
19
+ }
20
+ export function openclawInventory(home) { return readSkillInventory(openclawRoots(home)); }
21
+ export function probeOpenClaw(home, python = 'python3') {
22
+ const local = configuration(home), config = local.config;
23
+ const agent = config.agents?.list?.find((a) => a.default || a.id === 'main');
24
+ const selected = agent?.model ?? config.agents?.defaults?.model;
25
+ const primary = typeof selected === 'string' ? selected : selected?.primary;
26
+ if (typeof primary !== 'string' || !primary.includes('/'))
27
+ throw new CommerceError('setup_model', 'Configure an OpenAI-compatible OpenClaw model first');
28
+ const slash = primary.indexOf('/'), provider = config.models?.providers?.[primary.slice(0, slash)], model = primary.slice(slash + 1);
29
+ let key = provider?.apiKey;
30
+ if (typeof key === 'string') {
31
+ const env = /^\$\{([A-Z_][A-Z0-9_]*)\}$/.exec(key);
32
+ if (env)
33
+ key = process.env[env[1]];
34
+ }
35
+ else if (key?.source === 'env' && typeof key.id === 'string')
36
+ key = process.env[key.id];
37
+ if (typeof key !== 'string' || !key.trim() || typeof provider?.baseUrl !== 'string' || (provider.api ?? 'openai-completions') !== 'openai-completions')
38
+ throw new CommerceError('setup_model', 'Use an OpenAI-compatible provider with a locally available API key');
39
+ const command = existsSync('/app/openclaw.mjs') ? [process.execPath, '/app/openclaw.mjs'] : ['openclaw'];
40
+ execFileSync(python, ['--version'], { stdio: 'pipe', timeout: 10000 });
41
+ execFileSync(command[0], [...command.slice(1), '--version'], { stdio: 'pipe', timeout: 30000 });
42
+ return { home: local.home, python, command, model, baseUrl: provider.baseUrl, apiKeyFile: null, apiKey: key, skillRoots: openclawRoots(local.home), skills: openclawInventory(local.home).map(s => ({ ...s, textPackage: s.supported })) };
43
+ }
@@ -1,8 +1,7 @@
1
1
  export { inspectLocalAlerts, type LocalAlertOptions } from './alerts.js';
2
2
  export type InspectionView = 'attention' | 'refund-review';
3
- /** Local owner-only diagnostics: never opens a signer, vault, provider or network. */
4
3
  export declare function inspectLedger(path: string, after?: number, limit?: number, view?: InspectionView): {
5
- role: string;
4
+ role: "seller";
6
5
  view: InspectionView;
7
6
  total: number;
8
7
  attentionCount: number;
@@ -1,37 +1,34 @@
1
+ /** Owner-only, read-only inspection of original seller orders. */
1
2
  import { DatabaseSync } from 'node:sqlite';
2
3
  import { lstatSync } from 'node:fs';
3
4
  import { CommerceError } from './types.js';
4
5
  export { inspectLocalAlerts } from './alerts.js';
5
- /** Local owner-only diagnostics: never opens a signer, vault, provider or network. */
6
+ const ATTENTION = "payment_state IN ('settling','unknown') OR execution_state IN ('dispatching','unknown')";
7
+ const REFUND_REVIEW = "payment_state='confirmed' AND execution_state='failed'";
6
8
  export function inspectLedger(path, after = 0, limit = 100, view = 'attention') {
7
9
  const stat = lstatSync(path);
8
10
  if (!stat.isFile() || stat.isSymbolicLink() || (stat.mode & 0o077) !== 0 || (process.getuid && stat.uid !== process.getuid()))
9
11
  throw new CommerceError('private_file', 'Inspect an existing ledger owned only by the current user');
10
12
  if (!Number.isSafeInteger(after) || after < 0 || !Number.isSafeInteger(limit) || limit < 1 || limit > 100)
11
- throw new CommerceError('inspection_cursor', 'Use a nonnegative row cursor and a limit from1 to100');
13
+ throw new CommerceError('inspection_cursor', 'Use a nonnegative row cursor and a limit from 1 to 100');
12
14
  if (!['attention', 'refund-review'].includes(view))
13
15
  throw new CommerceError('inspection_view', 'Use attention or refund-review inspection');
14
16
  const db = new DatabaseSync(path, { readOnly: true });
15
17
  try {
16
18
  db.exec('PRAGMA query_only=ON; PRAGMA busy_timeout=1000');
17
- const names = new Set(db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all().map(row => row.name));
18
- const role = names.has('buyer_purchases') ? 'buyer' : names.has('commerce_orders') ? 'seller' : null;
19
- if (!role)
20
- throw new CommerceError('store_version', 'Unrecognized commerce ledger');
21
- const meta = role === 'buyer' ? 'buyer_meta' : 'commerce_meta', version = role === 'buyer' ? 1 : 2;
22
- if (db.prepare(`SELECT version FROM ${meta}`).get()?.version !== version)
23
- throw new CommerceError('store_version', 'Unsupported commerce ledger version');
24
- const table = role === 'buyer' ? 'buyer_purchases' : 'commerce_orders';
25
- const total = Number(db.prepare(`SELECT COUNT(*) AS n FROM ${table}`).get().n);
26
- const attention = role === 'buyer' ? "json_extract(record_json,'$.state') IN ('signing','submitted','unknown') OR json_extract(record_json,'$.paymentState') IN ('reserved','unknown') OR json_extract(record_json,'$.executionState')='unknown'" : "payment_state IN ('settling','unknown') OR execution_state IN ('dispatching','unknown')";
27
- const refundReview = role === 'buyer' ? "json_extract(record_json,'$.paymentState')='confirmed' AND json_extract(record_json,'$.executionState')='failed'" : "payment_state='confirmed' AND execution_state='failed'";
28
- const filter = view === 'refund-review' ? refundReview : attention;
29
- const selected = role === 'buyer' ? "rowid AS cursor,id,json_extract(record_json,'$.paymentState') AS payment_state,json_extract(record_json,'$.executionState') AS execution_state,json_extract(record_json,'$.task.id') AS task_id" : "rowid AS cursor,id,payment_state,execution_state,task_id";
30
- const rows = db.prepare(`SELECT ${selected} FROM ${table} WHERE rowid>? AND (${filter}) ORDER BY rowid LIMIT ?`).all(after, limit + 1);
31
- const page = rows.slice(0, limit).map(row => ({ cursor: Number(row.cursor), id: String(row.id), paymentState: String(row.payment_state), executionState: String(row.execution_state), taskId: typeof row.task_id === 'string' ? row.task_id : null, ...(view === 'refund-review' ? { reason: 'confirmed_payment_failed_execution' } : {}) }));
32
- const attentionCount = Number(db.prepare(`SELECT COUNT(*) AS n FROM ${table} WHERE ${attention}`).get().n);
33
- const refundReviewCount = Number(db.prepare(`SELECT COUNT(*) AS n FROM ${table} WHERE ${refundReview}`).get().n);
34
- return { role, view, total, attentionCount, refundReviewCount, items: page, nextCursor: page.at(-1)?.cursor ?? after, hasMore: rows.length > limit, paymentPerformed: false, refundPerformed: false };
19
+ if (db.prepare('SELECT version FROM commerce_meta').get()?.version !== 2)
20
+ throw new CommerceError('store_version', 'Unsupported seller ledger version');
21
+ const total = Number(db.prepare('SELECT COUNT(*) AS n FROM commerce_orders').get().n);
22
+ const filter = view === 'refund-review' ? REFUND_REVIEW : ATTENTION;
23
+ const rows = db.prepare(`SELECT rowid AS cursor,id,payment_state,execution_state,task_id FROM commerce_orders WHERE rowid>? AND (${filter}) ORDER BY rowid LIMIT ?`).all(after, limit + 1);
24
+ const page = rows.slice(0, limit).map(row => ({
25
+ cursor: Number(row.cursor), id: String(row.id), paymentState: String(row.payment_state),
26
+ executionState: String(row.execution_state), taskId: typeof row.task_id === 'string' ? row.task_id : null,
27
+ ...(view === 'refund-review' ? { reason: 'confirmed_payment_failed_execution' } : {}),
28
+ }));
29
+ const attentionCount = Number(db.prepare(`SELECT COUNT(*) AS n FROM commerce_orders WHERE ${ATTENTION}`).get().n);
30
+ const refundReviewCount = Number(db.prepare(`SELECT COUNT(*) AS n FROM commerce_orders WHERE ${REFUND_REVIEW}`).get().n);
31
+ return { role: 'seller', view, total, attentionCount, refundReviewCount, items: page, nextCursor: page.at(-1)?.cursor ?? after, hasMore: rows.length > limit, paymentPerformed: false, refundPerformed: false };
35
32
  }
36
33
  finally {
37
34
  db.close();
@@ -7,6 +7,5 @@ export declare function buildQuote(config: CommerceConfig, args: {
7
7
  input: Input;
8
8
  now?: Date;
9
9
  ttlSeconds?: number;
10
- stripeRecipient?: string;
11
10
  }): Readonly<PriceQuote>;
12
11
  export declare function assertQuoteRequest(quote: Readonly<PriceQuote>, caller: string, messageId: string, input: Input, now?: Date): void;
@@ -33,9 +33,7 @@ export function buildQuote(config, args) {
33
33
  if (amount >= 2n ** 256n)
34
34
  throw new CommerceError('invalid_amount', 'Quoted amount is too large');
35
35
  const profile = offer.paymentProfile ? config.paymentProfiles[offer.paymentProfile] : null;
36
- const recipient = profile?.adapter === 'x402' ? profile.payTo : profile ? args.stripeRecipient : null;
37
- if (profile?.adapter === 'mpp' && !recipient)
38
- throw new CommerceError('merchant_not_ready', 'Resolve and verify the Stripe merchant before quoting');
36
+ const recipient = profile?.accountRef ?? null;
39
37
  const now = args.now ?? new Date();
40
38
  const ttl = args.ttlSeconds ?? 600;
41
39
  if (!Number.isInteger(ttl) || ttl < 1 || ttl > 3600 || !Number.isFinite(now.getTime()))
@@ -5,6 +5,6 @@ export * from './upstream.js';
5
5
  export * from './skill-gate.js';
6
6
  export * from './native-skills.js';
7
7
  export * from './http.js';
8
- export * from './x402.js';
8
+ export * from './envar-balance.js';
9
9
  export * from './vault.js';
10
- export * from './chain.js';
10
+ export * from './external-agent.js';
@@ -5,6 +5,6 @@ export * from './upstream.js';
5
5
  export * from './skill-gate.js';
6
6
  export * from './native-skills.js';
7
7
  export * from './http.js';
8
- export * from './x402.js';
8
+ export * from './envar-balance.js';
9
9
  export * from './vault.js';
10
- export * from './chain.js';
10
+ export * from './external-agent.js';
@@ -23,7 +23,6 @@ export interface CommerceServerOptions {
23
23
  headers: Record<string, string>;
24
24
  }>;
25
25
  };
26
- stripeRecipientFor?: (accountRef: string) => string | undefined;
27
26
  ownershipChallenges?: Readonly<Record<string, string>>;
28
27
  onError?: (code: string, orderId?: string) => void;
29
28
  }
@@ -233,9 +233,8 @@ export class CommerceServer {
233
233
  const frozen = this.store.catalogHistory().find(entry => entry.service.id === service.id && entry.service.revision === service.revision);
234
234
  if (!frozen)
235
235
  throw new CommerceError('unknown_revision', 'Service revision is not registered');
236
- const config = { ...this.currentConfig, paymentProfiles: frozen.profiles, services: [frozen.service] }, offer = frozen.service.offers.find(o => o.id === offerId);
237
- const profile = offer.paymentProfile ? frozen.profiles[offer.paymentProfile] : undefined;
238
- return buildQuote(config, { serviceId: service.id, offerId, caller, messageId, input, ...(profile?.adapter === 'mpp' ? { stripeRecipient: this.options.stripeRecipientFor?.(profile.accountRef) } : {}) });
236
+ const config = { ...this.currentConfig, paymentProfiles: frozen.profiles, services: [frozen.service] };
237
+ return buildQuote(config, { serviceId: service.id, offerId, caller, messageId, input });
239
238
  }
240
239
  async handle(request) {
241
240
  const url = new URL(request.url);
@@ -0,0 +1,25 @@
1
+ export interface SetupBundle {
2
+ version: 1;
3
+ agentId: string;
4
+ agentName: string;
5
+ runtimeAgentId: string;
6
+ platformOrigin: string;
7
+ token: string;
8
+ expiresAt: string;
9
+ }
10
+ export declare function parseSetupBundle(raw: unknown): SetupBundle;
11
+ export declare function prepareTextSkill(source: string, destination: string, name: string): void;
12
+ export declare function setupAgent(options: {
13
+ framework?: "hermes" | "openclaw";
14
+ managed?: boolean;
15
+ file: string;
16
+ directory?: string;
17
+ container?: string;
18
+ python?: string;
19
+ home?: string;
20
+ automatic?: {
21
+ port: number;
22
+ origin: string;
23
+ };
24
+ }): Promise<void>;
25
+ export declare const setupHermes: (options: Parameters<typeof setupAgent>[0]) => Promise<void>;