@profullstack/coinpay 0.19.0 → 0.20.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/bin/coinpay.js +1 -1
- package/package.json +1 -1
- package/src/finances-commands.js +15 -4
- package/src/finances-reports.js +15 -0
- package/src/mcp.js +5 -3
package/bin/coinpay.js
CHANGED
|
@@ -682,7 +682,7 @@ ${colors.cyan}Commands:${colors.reset}
|
|
|
682
682
|
due [--days 7] What is due and overdue across every account (--days up to 60)
|
|
683
683
|
recurring Every recurring charge detected, with next date and monthly cost
|
|
684
684
|
due-day <id> <1-31|clear> A card/loan's statement due day (--amount 810.46, or balance)
|
|
685
|
-
daily [show|on|off|send-now] Daily summary email:
|
|
685
|
+
daily [show|on|off|send-now] Daily summary email: spend vs target, top cuts, due soon, position (--hour 7 --to …, --target 100)
|
|
686
686
|
|
|
687
687
|
${colors.bright}escrow${colors.reset}
|
|
688
688
|
create Create a new escrow
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@profullstack/coinpay",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "CoinPay SDK & CLI \u2014 Accept cryptocurrency and card payments (BTC, ETH, SOL, POL, BCH, USDC) with wallet, swap and a live finances dashboard",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
package/src/finances-commands.js
CHANGED
|
@@ -891,10 +891,21 @@ export async function runFinancesCommand(subcommand, args, flags, ctx) {
|
|
|
891
891
|
const action = flags.off ? 'off' : args[0] || 'show';
|
|
892
892
|
const describe = (s) => s
|
|
893
893
|
? `Daily summary ${s.active ? 'on' : 'off'} · ${String(s.hour).padStart(2, '0')}:00 ${s.timezone} · to ${s.recipients.join(', ')}${s.nextRunAt ? ` · next ${s.nextRunAt}` : ''}${s.lastSentAt ? ` · last ${s.lastSentAt}` : ''}`
|
|
894
|
-
: 'No daily summary configured. Turn it on with: coinpay finances daily on --hour 7
|
|
894
|
+
: 'No daily summary configured. Turn it on with: coinpay finances daily on --hour 7';
|
|
895
|
+
const targetText = (t) => (t === null || t === undefined ? 'no daily spend target' : `target $${t}/day`);
|
|
896
|
+
if (flags.target !== undefined) {
|
|
897
|
+
const raw = String(flags.target);
|
|
898
|
+
const target = ['off', 'clear', 'none'].includes(raw) ? null : Number(raw.replace(/^\$/, ''));
|
|
899
|
+
if (target !== null && (!Number.isFinite(target) || target < 0)) throw new CliExit(EXIT.INVALID, 'The target is a daily amount, e.g. --target 100, or --target clear');
|
|
900
|
+
const data = await api.setDailySpendTarget(client, target);
|
|
901
|
+
if (action === 'show') {
|
|
902
|
+
emit({ schedule: data.schedule, target: data.target }, `${describe(data.schedule)}\n${target === null ? 'Cleared the daily spend target.' : `Daily spend target set to $${data.target}/day.`}`);
|
|
903
|
+
return EXIT.OK;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
895
906
|
if (action === 'show') {
|
|
896
|
-
const s = await api.
|
|
897
|
-
emit({ schedule: s }, describe(s));
|
|
907
|
+
const { schedule: s, target } = await api.getDailySummaryWithTarget(client);
|
|
908
|
+
emit({ schedule: s, target }, `${describe(s)} · ${targetText(target)}`);
|
|
898
909
|
return EXIT.OK;
|
|
899
910
|
}
|
|
900
911
|
if (action === 'on' || action === 'set') {
|
|
@@ -917,7 +928,7 @@ export async function runFinancesCommand(subcommand, args, flags, ctx) {
|
|
|
917
928
|
emit(data, `Sent to ${data.sent.join(', ') || 'nobody'} (${data.due} due, ${data.overdue} overdue)${data.failed.length ? `; failed: ${data.failed.map((f) => `${f.to} (${f.error})`).join(', ')}` : ''}`);
|
|
918
929
|
return data.sent.length > 0 ? EXIT.OK : EXIT.FAILURE;
|
|
919
930
|
}
|
|
920
|
-
throw new CliExit(EXIT.INVALID, 'Usage: coinpay finances daily [show|on --hour 7 --to a@x|off|send-now]');
|
|
931
|
+
throw new CliExit(EXIT.INVALID, 'Usage: coinpay finances daily [show|on --hour 7 --to a@x|off|send-now] [--target 100|--target clear]');
|
|
921
932
|
}
|
|
922
933
|
|
|
923
934
|
case 'payloads': {
|
package/src/finances-reports.js
CHANGED
|
@@ -461,6 +461,12 @@ export async function getDailySummary(client) {
|
|
|
461
461
|
return data.schedule;
|
|
462
462
|
}
|
|
463
463
|
|
|
464
|
+
/** The daily summary schedule plus the owner's $/day spend target (null when none). */
|
|
465
|
+
export async function getDailySummaryWithTarget(client) {
|
|
466
|
+
const data = await call(client, '/finances/email-schedules?kind=daily_summary');
|
|
467
|
+
return { schedule: data.schedule, target: data.dailySpendTarget ?? null };
|
|
468
|
+
}
|
|
469
|
+
|
|
464
470
|
export async function setDailySummary(client, { weekdays, hour, timezone, recipients, active } = {}) {
|
|
465
471
|
const data = await call(client, '/finances/email-schedules', {
|
|
466
472
|
method: 'POST',
|
|
@@ -469,6 +475,15 @@ export async function setDailySummary(client, { weekdays, hour, timezone, recipi
|
|
|
469
475
|
return data.schedule;
|
|
470
476
|
}
|
|
471
477
|
|
|
478
|
+
/** Set the daily summary's $/day spend target, or clear it with null. Does not turn the summary on. */
|
|
479
|
+
export async function setDailySpendTarget(client, target) {
|
|
480
|
+
const data = await call(client, '/finances/email-schedules', {
|
|
481
|
+
method: 'POST',
|
|
482
|
+
body: JSON.stringify({ kind: 'daily_summary', target }),
|
|
483
|
+
});
|
|
484
|
+
return { schedule: data.schedule, target: data.dailySpendTarget ?? null };
|
|
485
|
+
}
|
|
486
|
+
|
|
472
487
|
export async function deleteDailySummary(client) {
|
|
473
488
|
return call(client, '/finances/email-schedules?kind=daily_summary', { method: 'DELETE' });
|
|
474
489
|
}
|
package/src/mcp.js
CHANGED
|
@@ -95,13 +95,14 @@ export const TOOLS = [
|
|
|
95
95
|
},
|
|
96
96
|
{
|
|
97
97
|
name: 'finance_daily_summary',
|
|
98
|
-
description: 'The daily summary email (due soon, new activity, position): show it, turn it on (optionally hour 0-23 and recipients), turn it off,
|
|
98
|
+
description: 'The daily summary email (spend vs a $/day target, top cuts, due soon, new activity, position): show it, turn it on (optionally hour 0-23 and recipients), turn it off, send one now, or set_target (target in $/day, null clears).',
|
|
99
99
|
inputSchema: {
|
|
100
100
|
type: 'object',
|
|
101
101
|
properties: {
|
|
102
|
-
action: { type: 'string', enum: ['show', 'on', 'off', 'send_now'] },
|
|
102
|
+
action: { type: 'string', enum: ['show', 'on', 'off', 'send_now', 'set_target'] },
|
|
103
103
|
hour: { type: 'integer', minimum: 0, maximum: 23 },
|
|
104
104
|
to: { type: 'array', items: { type: 'string' }, maxItems: 5 },
|
|
105
|
+
target: { type: ['number', 'null'], minimum: 0 },
|
|
105
106
|
},
|
|
106
107
|
required: ['action'],
|
|
107
108
|
additionalProperties: false,
|
|
@@ -110,7 +111,8 @@ export const TOOLS = [
|
|
|
110
111
|
if (args.action === 'on') return text({ schedule: await reports.setDailySummary(client, { hour: args.hour, recipients: args.to, active: true }) });
|
|
111
112
|
if (args.action === 'off') return text(await reports.deleteDailySummary(client));
|
|
112
113
|
if (args.action === 'send_now') return text(await reports.sendDailySummaryNow(client));
|
|
113
|
-
return text(
|
|
114
|
+
if (args.action === 'set_target') return text(await reports.setDailySpendTarget(client, args.target ?? null));
|
|
115
|
+
return text(await reports.getDailySummaryWithTarget(client));
|
|
114
116
|
},
|
|
115
117
|
},
|
|
116
118
|
{
|