payment-skill 1.0.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/LICENSE +62 -0
- package/README.md +545 -0
- package/SKILL.md +99 -0
- package/SUPPORT.md +153 -0
- package/bin/payment-skill.js +2 -0
- package/dashboard.html +669 -0
- package/dist/api/bunq.d.ts +35 -0
- package/dist/api/bunq.d.ts.map +1 -0
- package/dist/api/bunq.js +164 -0
- package/dist/api/bunq.js.map +1 -0
- package/dist/api/wise.d.ts +32 -0
- package/dist/api/wise.d.ts.map +1 -0
- package/dist/api/wise.js +155 -0
- package/dist/api/wise.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +69 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/bunq.d.ts +8 -0
- package/dist/commands/bunq.d.ts.map +1 -0
- package/dist/commands/bunq.js +193 -0
- package/dist/commands/bunq.js.map +1 -0
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +70 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/emergency.d.ts +8 -0
- package/dist/commands/emergency.d.ts.map +1 -0
- package/dist/commands/emergency.js +85 -0
- package/dist/commands/emergency.js.map +1 -0
- package/dist/commands/limits.d.ts +6 -0
- package/dist/commands/limits.d.ts.map +1 -0
- package/dist/commands/limits.js +125 -0
- package/dist/commands/limits.js.map +1 -0
- package/dist/commands/merchant.d.ts +6 -0
- package/dist/commands/merchant.d.ts.map +1 -0
- package/dist/commands/merchant.js +41 -0
- package/dist/commands/merchant.js.map +1 -0
- package/dist/commands/pay.d.ts +10 -0
- package/dist/commands/pay.d.ts.map +1 -0
- package/dist/commands/pay.js +112 -0
- package/dist/commands/pay.js.map +1 -0
- package/dist/commands/provider.d.ts +6 -0
- package/dist/commands/provider.d.ts.map +1 -0
- package/dist/commands/provider.js +74 -0
- package/dist/commands/provider.js.map +1 -0
- package/dist/commands/server.d.ts +8 -0
- package/dist/commands/server.d.ts.map +1 -0
- package/dist/commands/server.js +92 -0
- package/dist/commands/server.js.map +1 -0
- package/dist/commands/template.d.ts +8 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/template.js +161 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/commands/transaction.d.ts +6 -0
- package/dist/commands/transaction.d.ts.map +1 -0
- package/dist/commands/transaction.js +72 -0
- package/dist/commands/transaction.js.map +1 -0
- package/dist/commands/wise.d.ts +8 -0
- package/dist/commands/wise.d.ts.map +1 -0
- package/dist/commands/wise.js +240 -0
- package/dist/commands/wise.js.map +1 -0
- package/dist/core/config.d.ts +40 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +201 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/template-engine.d.ts +27 -0
- package/dist/core/template-engine.d.ts.map +1 -0
- package/dist/core/template-engine.js +410 -0
- package/dist/core/template-engine.js.map +1 -0
- package/dist/core/transaction.d.ts +31 -0
- package/dist/core/transaction.d.ts.map +1 -0
- package/dist/core/transaction.js +214 -0
- package/dist/core/transaction.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/server/server.d.ts +14 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +120 -0
- package/dist/server/server.js.map +1 -0
- package/dist/types/index.d.ts +141 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/logo.png +0 -0
- package/package.json +78 -0
- package/src/api/bunq.ts +257 -0
- package/src/api/wise.ts +204 -0
- package/src/cli.ts +67 -0
- package/src/commands/bunq.ts +223 -0
- package/src/commands/config.ts +72 -0
- package/src/commands/emergency.ts +94 -0
- package/src/commands/limits.ts +126 -0
- package/src/commands/merchant.ts +39 -0
- package/src/commands/pay.ts +109 -0
- package/src/commands/provider.ts +75 -0
- package/src/commands/server.ts +59 -0
- package/src/commands/template.ts +172 -0
- package/src/commands/transaction.ts +66 -0
- package/src/commands/wise.ts +279 -0
- package/src/core/config.ts +202 -0
- package/src/core/template-engine.ts +454 -0
- package/src/core/transaction.ts +228 -0
- package/src/index.ts +14 -0
- package/src/server/server.ts +131 -0
- package/src/types/index.ts +178 -0
- package/tsconfig.json +23 -0
- package/verified-merchants.json +63 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payment Skill - Bunq Commands
|
|
3
|
+
*
|
|
4
|
+
* Bunq API CLI commands
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import ora from 'ora';
|
|
10
|
+
import { BunqClient } from '../api/bunq';
|
|
11
|
+
import { configManager } from '../core/config';
|
|
12
|
+
import { transactionManager } from '../core/transaction';
|
|
13
|
+
|
|
14
|
+
export const bunqCommands = new Command('bunq')
|
|
15
|
+
.description('Bunq API operations');
|
|
16
|
+
|
|
17
|
+
// List accounts
|
|
18
|
+
bunqCommands
|
|
19
|
+
.command('accounts')
|
|
20
|
+
.description('List monetary accounts')
|
|
21
|
+
.requiredOption('-u, --user <id>', 'User ID')
|
|
22
|
+
.action(async (options) => {
|
|
23
|
+
const spinner = ora('Fetching accounts...').start();
|
|
24
|
+
try {
|
|
25
|
+
const config = configManager.getProvider('bunq');
|
|
26
|
+
if (!config) {
|
|
27
|
+
throw new Error('Bunq not configured. Run: payment-skill provider add bunq');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const client = new BunqClient(config as any);
|
|
31
|
+
const accounts = await client.getMonetaryAccounts(options.user);
|
|
32
|
+
|
|
33
|
+
spinner.stop();
|
|
34
|
+
console.log(chalk.blue('Monetary Accounts:'));
|
|
35
|
+
accounts.forEach((acc: any) => {
|
|
36
|
+
console.log(` ${acc.id} - ${acc.description} - ${acc.balance.value} ${acc.balance.currency}`);
|
|
37
|
+
});
|
|
38
|
+
} catch (error: any) {
|
|
39
|
+
spinner.fail(error.message);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Get balance
|
|
45
|
+
bunqCommands
|
|
46
|
+
.command('balance')
|
|
47
|
+
.description('Get account balance')
|
|
48
|
+
.requiredOption('-u, --user <id>', 'User ID')
|
|
49
|
+
.requiredOption('-a, --account <id>', 'Account ID')
|
|
50
|
+
.action(async (options) => {
|
|
51
|
+
const spinner = ora('Fetching balance...').start();
|
|
52
|
+
try {
|
|
53
|
+
const config = configManager.getProvider('bunq');
|
|
54
|
+
if (!config) {
|
|
55
|
+
throw new Error('Bunq not configured');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const client = new BunqClient(config as any);
|
|
59
|
+
const account = await client.getMonetaryAccount(options.user, options.account);
|
|
60
|
+
|
|
61
|
+
spinner.stop();
|
|
62
|
+
console.log(chalk.blue('Account Balance:'));
|
|
63
|
+
console.log(` ${account.balance.value} ${account.balance.currency}`);
|
|
64
|
+
} catch (error: any) {
|
|
65
|
+
spinner.fail(error.message);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Create payment
|
|
71
|
+
bunqCommands
|
|
72
|
+
.command('pay')
|
|
73
|
+
.description('Create a payment')
|
|
74
|
+
.requiredOption('-u, --user <id>', 'User ID')
|
|
75
|
+
.requiredOption('-a, --account <id>', 'Account ID')
|
|
76
|
+
.requiredOption('--amount <amount>', 'Payment amount')
|
|
77
|
+
.requiredOption('--currency <currency>', 'Currency (e.g., EUR)')
|
|
78
|
+
.requiredOption('--to-iban <iban>', 'Recipient IBAN')
|
|
79
|
+
.requiredOption('--to-name <name>', 'Recipient name')
|
|
80
|
+
.requiredOption('--description <text>', 'Payment description')
|
|
81
|
+
.action(async (options) => {
|
|
82
|
+
const spinner = ora('Creating payment...').start();
|
|
83
|
+
try {
|
|
84
|
+
const config = configManager.getProvider('bunq');
|
|
85
|
+
if (!config) {
|
|
86
|
+
throw new Error('Bunq not configured');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Create transaction record
|
|
90
|
+
const tx = transactionManager.createTransaction(
|
|
91
|
+
'bunq',
|
|
92
|
+
'bunq-payment',
|
|
93
|
+
parseFloat(options.amount),
|
|
94
|
+
options.currency,
|
|
95
|
+
{ toIban: options.toIban, description: options.description }
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const client = new BunqClient(config as any);
|
|
99
|
+
const payment = await client.createPayment(
|
|
100
|
+
options.user,
|
|
101
|
+
options.account,
|
|
102
|
+
options.amount,
|
|
103
|
+
options.currency,
|
|
104
|
+
options.toIban,
|
|
105
|
+
options.toName,
|
|
106
|
+
options.description
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
transactionManager.updateTransactionStatus(tx.id, 'completed');
|
|
110
|
+
|
|
111
|
+
spinner.succeed(chalk.green('Payment created'));
|
|
112
|
+
console.log(` Transaction ID: ${tx.id}`);
|
|
113
|
+
console.log(` Payment ID: ${payment.id}`);
|
|
114
|
+
console.log(` Status: ${payment.status}`);
|
|
115
|
+
} catch (error: any) {
|
|
116
|
+
spinner.fail(error.message);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Create payment request
|
|
122
|
+
bunqCommands
|
|
123
|
+
.command('request')
|
|
124
|
+
.description('Create a payment request (RequestInquiry)')
|
|
125
|
+
.requiredOption('-u, --user <id>', 'User ID')
|
|
126
|
+
.requiredOption('-a, --account <id>', 'Account ID')
|
|
127
|
+
.requiredOption('--amount <amount>', 'Request amount')
|
|
128
|
+
.requiredOption('--currency <currency>', 'Currency')
|
|
129
|
+
.requiredOption('--to <alias>', 'Counterparty alias (email/phone/IBAN)')
|
|
130
|
+
.requiredOption('--description <text>', 'Request description')
|
|
131
|
+
.option('--type <type>', 'Alias type (EMAIL/PHONE/IBAN)', 'EMAIL')
|
|
132
|
+
.action(async (options) => {
|
|
133
|
+
const spinner = ora('Creating payment request...').start();
|
|
134
|
+
try {
|
|
135
|
+
const config = configManager.getProvider('bunq');
|
|
136
|
+
if (!config) {
|
|
137
|
+
throw new Error('Bunq not configured');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const client = new BunqClient(config as any);
|
|
141
|
+
const request = await client.createRequestInquiry(
|
|
142
|
+
options.user,
|
|
143
|
+
options.account,
|
|
144
|
+
options.amount,
|
|
145
|
+
options.currency,
|
|
146
|
+
{
|
|
147
|
+
type: options.type,
|
|
148
|
+
value: options.to,
|
|
149
|
+
name: options.to
|
|
150
|
+
},
|
|
151
|
+
options.description
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
spinner.succeed(chalk.green('Payment request created'));
|
|
155
|
+
console.log(` Request ID: ${request.id}`);
|
|
156
|
+
console.log(` Status: ${request.status}`);
|
|
157
|
+
console.log(chalk.yellow(' Waiting for recipient to accept...'));
|
|
158
|
+
} catch (error: any) {
|
|
159
|
+
spinner.fail(error.message);
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// List payments
|
|
165
|
+
bunqCommands
|
|
166
|
+
.command('payments')
|
|
167
|
+
.description('List payments')
|
|
168
|
+
.requiredOption('-u, --user <id>', 'User ID')
|
|
169
|
+
.requiredOption('-a, --account <id>', 'Account ID')
|
|
170
|
+
.option('-l, --limit <number>', 'Limit results', '10')
|
|
171
|
+
.action(async (options) => {
|
|
172
|
+
const spinner = ora('Fetching payments...').start();
|
|
173
|
+
try {
|
|
174
|
+
const config = configManager.getProvider('bunq');
|
|
175
|
+
if (!config) {
|
|
176
|
+
throw new Error('Bunq not configured');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const client = new BunqClient(config as any);
|
|
180
|
+
const payments = await client.getPayments(options.user, options.account, parseInt(options.limit));
|
|
181
|
+
|
|
182
|
+
spinner.stop();
|
|
183
|
+
console.log(chalk.blue(`Payments (${payments.length}):`));
|
|
184
|
+
payments.forEach((p: any) => {
|
|
185
|
+
const direction = p.amount.value.startsWith('-') ? 'OUT' : 'IN';
|
|
186
|
+
const color = direction === 'OUT' ? chalk.red : chalk.green;
|
|
187
|
+
console.log(` ${p.id} - ${color(direction)} - ${p.amount.value} ${p.amount.currency} - ${p.description}`);
|
|
188
|
+
});
|
|
189
|
+
} catch (error: any) {
|
|
190
|
+
spinner.fail(error.message);
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// List requests
|
|
196
|
+
bunqCommands
|
|
197
|
+
.command('requests')
|
|
198
|
+
.description('List payment requests')
|
|
199
|
+
.requiredOption('-u, --user <id>', 'User ID')
|
|
200
|
+
.requiredOption('-a, --account <id>', 'Account ID')
|
|
201
|
+
.action(async (options) => {
|
|
202
|
+
const spinner = ora('Fetching requests...').start();
|
|
203
|
+
try {
|
|
204
|
+
const config = configManager.getProvider('bunq');
|
|
205
|
+
if (!config) {
|
|
206
|
+
throw new Error('Bunq not configured');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const client = new BunqClient(config as any);
|
|
210
|
+
const requests = await client.getRequestInquiries(options.user, options.account);
|
|
211
|
+
|
|
212
|
+
spinner.stop();
|
|
213
|
+
console.log(chalk.blue(`Payment Requests (${requests.length}):`));
|
|
214
|
+
requests.forEach((r: any) => {
|
|
215
|
+
const statusColor = r.status === 'ACCEPTED' ? chalk.green :
|
|
216
|
+
r.status === 'PENDING' ? chalk.yellow : chalk.red;
|
|
217
|
+
console.log(` ${r.id} - ${statusColor(r.status)} - ${r.amount_inquired.value} ${r.amount_inquired.currency}`);
|
|
218
|
+
});
|
|
219
|
+
} catch (error: any) {
|
|
220
|
+
spinner.fail(error.message);
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payment Skill - Config Commands
|
|
3
|
+
*
|
|
4
|
+
* Configuration management CLI commands
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import { configManager } from '../core/config';
|
|
10
|
+
|
|
11
|
+
export const configCommands = new Command('config')
|
|
12
|
+
.description('Manage payment-skill configuration');
|
|
13
|
+
|
|
14
|
+
configCommands
|
|
15
|
+
.command('get')
|
|
16
|
+
.description('Get configuration value')
|
|
17
|
+
.argument('<key>', 'Configuration key')
|
|
18
|
+
.action((key) => {
|
|
19
|
+
const config = configManager.getConfig();
|
|
20
|
+
const value = config[key];
|
|
21
|
+
if (value !== undefined) {
|
|
22
|
+
console.log(JSON.stringify(value, null, 2));
|
|
23
|
+
} else {
|
|
24
|
+
console.log(chalk.yellow(`Key '${key}' not found`));
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
configCommands
|
|
29
|
+
.command('set')
|
|
30
|
+
.description('Set configuration value')
|
|
31
|
+
.argument('<key>', 'Configuration key')
|
|
32
|
+
.argument('<value>', 'Configuration value')
|
|
33
|
+
.action((key, value) => {
|
|
34
|
+
try {
|
|
35
|
+
const parsedValue = JSON.parse(value);
|
|
36
|
+
configManager.setConfig(key, parsedValue);
|
|
37
|
+
console.log(chalk.green(`✓ Set ${key} = ${value}`));
|
|
38
|
+
} catch {
|
|
39
|
+
configManager.setConfig(key, value);
|
|
40
|
+
console.log(chalk.green(`✓ Set ${key} = ${value}`));
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
configCommands
|
|
45
|
+
.command('list')
|
|
46
|
+
.description('List all configuration')
|
|
47
|
+
.action(() => {
|
|
48
|
+
const config = configManager.getConfig();
|
|
49
|
+
console.log(chalk.blue('Configuration:'));
|
|
50
|
+
console.log(JSON.stringify(config, null, 2));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
configCommands
|
|
54
|
+
.command('init')
|
|
55
|
+
.description('Initialize configuration')
|
|
56
|
+
.action(() => {
|
|
57
|
+
console.log(chalk.blue('Initializing payment-skill configuration...'));
|
|
58
|
+
console.log(chalk.green('✓ Configuration initialized'));
|
|
59
|
+
console.log(chalk.gray('Use "payment-skill provider add" to configure providers'));
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
configCommands
|
|
63
|
+
.command('path')
|
|
64
|
+
.description('Show configuration file path')
|
|
65
|
+
.action(() => {
|
|
66
|
+
const path = require('path').join(
|
|
67
|
+
process.env.HOME || process.env.USERPROFILE || '.',
|
|
68
|
+
'.payment-skill',
|
|
69
|
+
'config.json'
|
|
70
|
+
);
|
|
71
|
+
console.log(path);
|
|
72
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payment Skill - Emergency Commands
|
|
3
|
+
*
|
|
4
|
+
* Emergency stop and safety CLI commands
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import { configManager } from '../core/config';
|
|
10
|
+
import { transactionManager } from '../core/transaction';
|
|
11
|
+
|
|
12
|
+
export const emergencyCommands = new Command('emergency')
|
|
13
|
+
.description('Emergency stop and safety controls');
|
|
14
|
+
|
|
15
|
+
emergencyCommands
|
|
16
|
+
.command('stop')
|
|
17
|
+
.description('Activate emergency stop - halt all transactions')
|
|
18
|
+
.option('-r, --reason <reason>', 'Reason for emergency stop')
|
|
19
|
+
.action((options) => {
|
|
20
|
+
const reason = options.reason || 'Manual activation';
|
|
21
|
+
|
|
22
|
+
console.log(chalk.red.bold('🚨 ACTIVATING EMERGENCY STOP'));
|
|
23
|
+
console.log(chalk.red(`Reason: ${reason}`));
|
|
24
|
+
|
|
25
|
+
// Get pending transactions
|
|
26
|
+
const pending = transactionManager.getPendingTransactions();
|
|
27
|
+
console.log(chalk.yellow(`Found ${pending.length} pending transactions`));
|
|
28
|
+
|
|
29
|
+
// Activate emergency stop
|
|
30
|
+
configManager.activateEmergencyStop(reason);
|
|
31
|
+
|
|
32
|
+
// Cancel all pending
|
|
33
|
+
const cancelled = transactionManager.cancelAllPending();
|
|
34
|
+
|
|
35
|
+
console.log(chalk.green(`✓ Emergency stop activated`));
|
|
36
|
+
console.log(chalk.green(`✓ Cancelled ${cancelled} pending transactions`));
|
|
37
|
+
console.log(chalk.red.bold('\n⚠️ All API operations are now BLOCKED'));
|
|
38
|
+
console.log(chalk.gray('Use "payment-skill emergency resume" to re-enable'));
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
emergencyCommands
|
|
42
|
+
.command('resume')
|
|
43
|
+
.description('Deactivate emergency stop - resume operations')
|
|
44
|
+
.action(() => {
|
|
45
|
+
if (!configManager.isEmergencyStopActive()) {
|
|
46
|
+
console.log(chalk.yellow('Emergency stop is not active'));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log(chalk.blue('Deactivating emergency stop...'));
|
|
51
|
+
configManager.deactivateEmergencyStop();
|
|
52
|
+
console.log(chalk.green('✓ Emergency stop deactivated'));
|
|
53
|
+
console.log(chalk.green('✓ API operations resumed'));
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
emergencyCommands
|
|
57
|
+
.command('status')
|
|
58
|
+
.description('Check emergency stop status')
|
|
59
|
+
.action(() => {
|
|
60
|
+
const state = configManager.getEmergencyStopState();
|
|
61
|
+
|
|
62
|
+
if (state.active) {
|
|
63
|
+
console.log(chalk.red.bold('🚨 EMERGENCY STOP IS ACTIVE'));
|
|
64
|
+
console.log(chalk.red(`Activated: ${state.activatedAt}`));
|
|
65
|
+
console.log(chalk.red(`Reason: ${state.reason}`));
|
|
66
|
+
console.log(chalk.yellow(`Pending transactions on hold: ${state.pendingTransactions.length}`));
|
|
67
|
+
} else {
|
|
68
|
+
console.log(chalk.green('✓ Emergency stop is inactive'));
|
|
69
|
+
console.log(chalk.gray('All operations normal'));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
emergencyCommands
|
|
74
|
+
.command('kill-all')
|
|
75
|
+
.description('Kill all pending transactions (use with caution)')
|
|
76
|
+
.option('-f, --force', 'Force without confirmation')
|
|
77
|
+
.action((options) => {
|
|
78
|
+
const pending = transactionManager.getPendingTransactions();
|
|
79
|
+
|
|
80
|
+
if (pending.length === 0) {
|
|
81
|
+
console.log(chalk.yellow('No pending transactions to kill'));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log(chalk.red.bold(`⚠️ About to kill ${pending.length} pending transactions`));
|
|
86
|
+
|
|
87
|
+
if (!options.force) {
|
|
88
|
+
console.log(chalk.yellow('Use --force to confirm'));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const cancelled = transactionManager.cancelAllPending();
|
|
93
|
+
console.log(chalk.green(`✓ Killed ${cancelled} transactions`));
|
|
94
|
+
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payment Skill - Limit Commands
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { configManager } from '../core/config';
|
|
8
|
+
|
|
9
|
+
export const limitCommands = new Command('limits')
|
|
10
|
+
.description('Manage payment limits and controls');
|
|
11
|
+
|
|
12
|
+
limitCommands
|
|
13
|
+
.command('get')
|
|
14
|
+
.description('Get current limits')
|
|
15
|
+
.action(() => {
|
|
16
|
+
const limits = configManager.getLimits();
|
|
17
|
+
console.log(chalk.blue('Current Limits:'));
|
|
18
|
+
console.log(` Per Transaction: ${limits.perTransaction}`);
|
|
19
|
+
console.log(` Daily: ${limits.daily}`);
|
|
20
|
+
console.log(` Weekly: ${limits.weekly}`);
|
|
21
|
+
console.log(` Monthly: ${limits.monthly}`);
|
|
22
|
+
console.log(` Max per Hour: ${limits.maxTransactionsPerHour}`);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
limitCommands
|
|
26
|
+
.command('set')
|
|
27
|
+
.description('Set limits')
|
|
28
|
+
.option('--per-transaction <amount>', 'Per transaction limit')
|
|
29
|
+
.option('--daily <amount>', 'Daily limit')
|
|
30
|
+
.option('--weekly <amount>', 'Weekly limit')
|
|
31
|
+
.option('--monthly <amount>', 'Monthly limit')
|
|
32
|
+
.option('--max-per-hour <count>', 'Max transactions per hour')
|
|
33
|
+
.action((options) => {
|
|
34
|
+
const limits: any = {};
|
|
35
|
+
if (options.perTransaction) limits.perTransaction = parseInt(options.perTransaction);
|
|
36
|
+
if (options.daily) limits.daily = parseInt(options.daily);
|
|
37
|
+
if (options.weekly) limits.weekly = parseInt(options.weekly);
|
|
38
|
+
if (options.monthly) limits.monthly = parseInt(options.monthly);
|
|
39
|
+
if (options.maxPerHour) limits.maxTransactionsPerHour = parseInt(options.maxPerHour);
|
|
40
|
+
|
|
41
|
+
configManager.setLimits(limits);
|
|
42
|
+
console.log(chalk.green('✓ Limits updated'));
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const timeWindowCommands = new Command('time-window')
|
|
46
|
+
.description('Time window controls');
|
|
47
|
+
|
|
48
|
+
timeWindowCommands
|
|
49
|
+
.command('get')
|
|
50
|
+
.description('Get time window settings')
|
|
51
|
+
.action(() => {
|
|
52
|
+
const tw = configManager.getTimeWindow();
|
|
53
|
+
console.log(chalk.blue('Time Window:'));
|
|
54
|
+
console.log(` Enabled: ${tw.enabled}`);
|
|
55
|
+
console.log(` Start: ${tw.start}`);
|
|
56
|
+
console.log(` End: ${tw.end}`);
|
|
57
|
+
console.log(` Timezone: ${tw.timezone}`);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
timeWindowCommands
|
|
61
|
+
.command('set')
|
|
62
|
+
.description('Set time window')
|
|
63
|
+
.option('--start <time>', 'Start time (HH:MM)')
|
|
64
|
+
.option('--end <time>', 'End time (HH:MM)')
|
|
65
|
+
.option('--timezone <tz>', 'Timezone')
|
|
66
|
+
.action((options) => {
|
|
67
|
+
const tw: any = {};
|
|
68
|
+
if (options.start) tw.start = options.start;
|
|
69
|
+
if (options.end) tw.end = options.end;
|
|
70
|
+
if (options.timezone) tw.timezone = options.timezone;
|
|
71
|
+
|
|
72
|
+
configManager.setTimeWindow(tw);
|
|
73
|
+
console.log(chalk.green('✓ Time window updated'));
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
timeWindowCommands
|
|
77
|
+
.command('enable')
|
|
78
|
+
.description('Enable time window')
|
|
79
|
+
.action(() => {
|
|
80
|
+
configManager.setTimeWindow({ enabled: true });
|
|
81
|
+
console.log(chalk.green('✓ Time window enabled'));
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
timeWindowCommands
|
|
85
|
+
.command('disable')
|
|
86
|
+
.description('Disable time window')
|
|
87
|
+
.action(() => {
|
|
88
|
+
configManager.setTimeWindow({ enabled: false });
|
|
89
|
+
console.log(chalk.green('✓ Time window disabled'));
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
limitCommands.addCommand(timeWindowCommands);
|
|
93
|
+
|
|
94
|
+
limitCommands
|
|
95
|
+
.command('block')
|
|
96
|
+
.description('Block a merchant')
|
|
97
|
+
.argument('<merchant-id>', 'Merchant ID')
|
|
98
|
+
.action((merchantId) => {
|
|
99
|
+
console.log(chalk.yellow(`Merchant blocking not yet implemented for ${merchantId}`));
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
limitCommands
|
|
103
|
+
.command('unblock')
|
|
104
|
+
.description('Unblock a merchant')
|
|
105
|
+
.argument('<merchant-id>', 'Merchant ID')
|
|
106
|
+
.action((merchantId) => {
|
|
107
|
+
console.log(chalk.yellow(`Merchant unblocking not yet implemented for ${merchantId}`));
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
limitCommands
|
|
111
|
+
.command('block-category')
|
|
112
|
+
.description('Block a category')
|
|
113
|
+
.argument('<category>', 'Category name')
|
|
114
|
+
.action((category) => {
|
|
115
|
+
configManager.addBlockedCategory(category);
|
|
116
|
+
console.log(chalk.green(`✓ Category '${category}' blocked`));
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
limitCommands
|
|
120
|
+
.command('unblock-category')
|
|
121
|
+
.description('Unblock a category')
|
|
122
|
+
.argument('<category>', 'Category name')
|
|
123
|
+
.action((category) => {
|
|
124
|
+
configManager.removeBlockedCategory(category);
|
|
125
|
+
console.log(chalk.green(`✓ Category '${category}' unblocked`));
|
|
126
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payment Skill - Merchant Commands
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
export const merchantCommands = new Command('merchant')
|
|
9
|
+
.description('Merchant detection and management');
|
|
10
|
+
|
|
11
|
+
merchantCommands
|
|
12
|
+
.command('detect')
|
|
13
|
+
.description('Detect merchant API capabilities')
|
|
14
|
+
.argument('<domain>', 'Merchant domain')
|
|
15
|
+
.action(async (domain) => {
|
|
16
|
+
console.log(chalk.blue(`Detecting API capabilities for ${domain}...`));
|
|
17
|
+
// Implementation would detect actual API
|
|
18
|
+
console.log(chalk.yellow('Merchant detection not yet implemented'));
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
merchantCommands
|
|
22
|
+
.command('list-apis')
|
|
23
|
+
.description('List supported merchant APIs')
|
|
24
|
+
.action(() => {
|
|
25
|
+
console.log(chalk.blue('Supported Merchant APIs:'));
|
|
26
|
+
console.log(' - wise.com (Wise Platform)');
|
|
27
|
+
console.log(' - bunq.com (Bunq API)');
|
|
28
|
+
console.log(' - stripe.com (Stripe Connect)');
|
|
29
|
+
console.log(' - airwallex.com (Airwallex API)');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
merchantCommands
|
|
33
|
+
.command('capabilities')
|
|
34
|
+
.description('Get merchant capabilities')
|
|
35
|
+
.argument('<merchant-id>', 'Merchant ID')
|
|
36
|
+
.action((merchantId) => {
|
|
37
|
+
console.log(chalk.blue(`Capabilities for ${merchantId}:`));
|
|
38
|
+
console.log(chalk.yellow('Not yet implemented'));
|
|
39
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payment Skill - Pay Command
|
|
3
|
+
*
|
|
4
|
+
* Execute payment using templates - HYBRID ARCHITECTURE
|
|
5
|
+
* OpenClaw selects template and provides parameters
|
|
6
|
+
* Payment-skill executes the predefined flow
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import ora from 'ora';
|
|
12
|
+
import { templateEngine } from '../core/template-engine';
|
|
13
|
+
|
|
14
|
+
export const payCommand = new Command('pay')
|
|
15
|
+
.description('Execute a payment using a template (HYBRID ARCHITECTURE)')
|
|
16
|
+
.requiredOption('-t, --template <id>', 'Template ID (e.g., wise_standard_transfer, bunq_instant_payment)')
|
|
17
|
+
.requiredOption('--amount <amount>', 'Payment amount')
|
|
18
|
+
.requiredOption('--currency <currency>', 'Currency code (EUR, USD, etc.)')
|
|
19
|
+
.option('--profile-id <id>', 'Wise profile ID')
|
|
20
|
+
.option('--user-id <id>', 'Bunq user ID')
|
|
21
|
+
.option('--account-id <id>', 'Bunq account ID')
|
|
22
|
+
.option('--recipient-id <id>', 'Recipient/account ID')
|
|
23
|
+
.option('--recipient-iban <iban>', 'Recipient IBAN')
|
|
24
|
+
.option('--recipient-name <name>', 'Recipient name')
|
|
25
|
+
.option('--reference <text>', 'Payment reference')
|
|
26
|
+
.option('--description <text>', 'Payment description')
|
|
27
|
+
.option('--dry-run', 'Show what would be executed without actually doing it')
|
|
28
|
+
.action(async (options) => {
|
|
29
|
+
const spinner = ora('Initializing payment...').start();
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
// Get template
|
|
33
|
+
const template = templateEngine.getTemplate(options.template);
|
|
34
|
+
if (!template) {
|
|
35
|
+
spinner.fail(`Template '${options.template}' not found`);
|
|
36
|
+
console.log(chalk.yellow('\nAvailable templates:'));
|
|
37
|
+
const templates = templateEngine.getAllTemplates();
|
|
38
|
+
templates.forEach(t => {
|
|
39
|
+
console.log(` ${t.templateId} - ${t.description}`);
|
|
40
|
+
});
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
spinner.succeed(`Using template: ${template.templateId}`);
|
|
45
|
+
console.log(chalk.blue(`Description: ${template.description}`));
|
|
46
|
+
console.log(chalk.gray(`Merchant: ${template.merchant}`));
|
|
47
|
+
|
|
48
|
+
// Build parameters
|
|
49
|
+
const params: Record<string, any> = {
|
|
50
|
+
amount: options.amount,
|
|
51
|
+
currency: options.currency.toUpperCase()
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
if (options.profileId) params.profileId = options.profileId;
|
|
55
|
+
if (options.userId) params.userId = options.userId;
|
|
56
|
+
if (options.accountId) params.accountId = options.accountId;
|
|
57
|
+
if (options.recipientId) params.recipientId = options.recipientId;
|
|
58
|
+
if (options.recipientIban) params.recipientIban = options.recipientIban;
|
|
59
|
+
if (options.recipientName) params.recipientName = options.recipientName;
|
|
60
|
+
if (options.reference) params.reference = options.reference;
|
|
61
|
+
if (options.description) params.description = options.description;
|
|
62
|
+
|
|
63
|
+
// Show execution plan
|
|
64
|
+
console.log(chalk.blue('\nExecution Plan:'));
|
|
65
|
+
template.steps.sort((a, b) => a.order - b.order).forEach(step => {
|
|
66
|
+
console.log(` ${step.order}. ${step.name}`);
|
|
67
|
+
if (step.async) {
|
|
68
|
+
console.log(chalk.yellow(` [ASYNC - ${step.confirmation?.type || 'manual'} confirmation]`));
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
console.log(chalk.blue('\nParameters:'));
|
|
73
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
74
|
+
console.log(` ${key}: ${value}`);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (options.dryRun) {
|
|
78
|
+
console.log(chalk.yellow('\n[DRY RUN - No actual payment will be made]'));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Confirm execution
|
|
83
|
+
console.log(chalk.yellow('\n⚠️ This will execute the payment flow above.'));
|
|
84
|
+
console.log(chalk.gray('Use --dry-run to preview without executing.'));
|
|
85
|
+
|
|
86
|
+
// Execute template
|
|
87
|
+
const execSpinner = ora('Executing payment flow...').start();
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const tx = await templateEngine.executeTemplate(options.template, params);
|
|
91
|
+
|
|
92
|
+
execSpinner.succeed(chalk.green('Payment flow completed!'));
|
|
93
|
+
console.log(chalk.green(`\n✓ Transaction ID: ${tx.id}`));
|
|
94
|
+
console.log(` Status: ${tx.status}`);
|
|
95
|
+
console.log(` Amount: ${tx.amount} ${tx.currency}`);
|
|
96
|
+
|
|
97
|
+
if (template.steps.some(s => s.async)) {
|
|
98
|
+
console.log(chalk.yellow('\n⚠️ Some steps are async and may require confirmation.'));
|
|
99
|
+
console.log(chalk.gray('Check status with: payment-skill transaction status ' + tx.id));
|
|
100
|
+
}
|
|
101
|
+
} catch (error: any) {
|
|
102
|
+
execSpinner.fail(chalk.red('Payment failed'));
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
} catch (error: any) {
|
|
106
|
+
console.error(chalk.red('\nError:'), error.message);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
});
|