@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.
- package/README.md +18 -56
- package/dist/commerce/agent-setup.d.ts +19 -0
- package/dist/commerce/agent-setup.js +210 -0
- package/dist/commerce/alerts.d.ts +5 -15
- package/dist/commerce/alerts.js +21 -77
- package/dist/commerce/card.js +1 -1
- package/dist/commerce/cli.js +74 -137
- package/dist/commerce/config.d.ts +1 -4
- package/dist/commerce/config.js +5 -81
- package/dist/commerce/configure.d.ts +2 -0
- package/dist/commerce/configure.js +78 -0
- package/dist/commerce/discovery.d.ts +20 -0
- package/dist/commerce/discovery.js +162 -0
- package/dist/commerce/envar-balance.d.ts +25 -0
- package/dist/commerce/envar-balance.js +65 -0
- package/dist/commerce/envar-runtime.d.ts +1 -0
- package/dist/commerce/envar-runtime.js +7 -0
- package/dist/commerce/envar.d.ts +13 -31
- package/dist/commerce/envar.js +35 -83
- package/dist/commerce/external-agent.d.ts +26 -0
- package/dist/commerce/external-agent.js +129 -0
- package/dist/commerce/external-events.d.ts +76 -0
- package/dist/commerce/external-events.js +273 -0
- package/dist/commerce/external-mcp.d.ts +10 -0
- package/dist/commerce/external-mcp.js +199 -0
- package/dist/commerce/external-oauth.d.ts +12 -0
- package/dist/commerce/external-oauth.js +230 -0
- package/dist/commerce/external-runtime.d.ts +25 -0
- package/dist/commerce/external-runtime.js +244 -0
- package/dist/commerce/managed.d.ts +3 -0
- package/dist/commerce/managed.js +143 -0
- package/dist/commerce/native-inventory.d.ts +9 -0
- package/dist/commerce/native-inventory.js +75 -0
- package/dist/commerce/native-skills.d.ts +8 -0
- package/dist/commerce/native-skills.js +11 -8
- package/dist/commerce/openclaw-setup.d.ts +28 -0
- package/dist/commerce/openclaw-setup.js +43 -0
- package/dist/commerce/operations.d.ts +1 -2
- package/dist/commerce/operations.js +17 -20
- package/dist/commerce/pricing.d.ts +0 -1
- package/dist/commerce/pricing.js +1 -3
- package/dist/commerce/runtime.d.ts +2 -2
- package/dist/commerce/runtime.js +2 -2
- package/dist/commerce/server.d.ts +0 -1
- package/dist/commerce/server.js +2 -3
- package/dist/commerce/setup.d.ts +25 -0
- package/dist/commerce/setup.js +379 -0
- package/dist/commerce/store.d.ts +11 -1
- package/dist/commerce/store.js +36 -2
- package/dist/commerce/types.d.ts +1 -56
- package/examples/envar-integration-policy.json +1 -9
- package/examples/seller.json +143 -26
- package/package.json +11 -20
- package/runtime/hermes-setup-probe.py +109 -0
- package/runtime/hermes-skill-inventory.py +108 -0
- package/schemas/envarpay.config.schema.json +7 -73
- package/dist/commerce/buyer-store.d.ts +0 -101
- package/dist/commerce/buyer-store.js +0 -168
- package/dist/commerce/buyer.d.ts +0 -138
- package/dist/commerce/buyer.js +0 -775
- package/dist/commerce/chain.d.ts +0 -24
- package/dist/commerce/chain.js +0 -146
- package/dist/commerce/client-runtime.d.ts +0 -8
- package/dist/commerce/client-runtime.js +0 -7
- package/dist/commerce/management.d.ts +0 -14
- package/dist/commerce/management.js +0 -140
- package/dist/commerce/mpp-client.d.ts +0 -70
- package/dist/commerce/mpp-client.js +0 -29
- package/dist/commerce/mpp-runtime.d.ts +0 -4
- package/dist/commerce/mpp-runtime.js +0 -4
- package/dist/commerce/mpp.d.ts +0 -53
- package/dist/commerce/mpp.js +0 -163
- package/dist/commerce/peer-proxy.d.ts +0 -44
- package/dist/commerce/peer-proxy.js +0 -673
- package/dist/commerce/stripe-issuer.d.ts +0 -41
- package/dist/commerce/stripe-issuer.js +0 -351
- package/dist/commerce/stripe-provider.d.ts +0 -11
- package/dist/commerce/stripe-provider.js +0 -132
- package/dist/commerce/x402.d.ts +0 -37
- package/dist/commerce/x402.js +0 -174
- package/dist/index.d.ts +0 -95
- package/dist/index.js +0 -163
- package/examples/buyer-policy.json +0 -18
- package/schemas/buyer-policy.schema.json +0 -253
- /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 (
|
|
60
|
-
throw new CommerceError('skill_inventory', 'Install
|
|
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
|
-
|
|
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('../../
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
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;
|
package/dist/commerce/pricing.js
CHANGED
|
@@ -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?.
|
|
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 './
|
|
8
|
+
export * from './envar-balance.js';
|
|
9
9
|
export * from './vault.js';
|
|
10
|
-
export * from './
|
|
10
|
+
export * from './external-agent.js';
|
package/dist/commerce/runtime.js
CHANGED
|
@@ -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 './
|
|
8
|
+
export * from './envar-balance.js';
|
|
9
9
|
export * from './vault.js';
|
|
10
|
-
export * from './
|
|
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
|
}
|
package/dist/commerce/server.js
CHANGED
|
@@ -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] }
|
|
237
|
-
|
|
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>;
|