earnrate 0.2.16 → 0.2.17
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 +14 -8
- package/data/CHANGELOG.md +14 -0
- package/data/VERSION +1 -1
- package/data/cards/amex-business-platinum.yaml +15 -1
- package/data/cards/barclays-jetblue-plus.yaml +19 -1
- package/data/cards/chase-freedom-flex.yaml +7 -7
- package/data/cards/chase-ihg-one-rewards-business.yaml +19 -3
- package/data/cards/chase-ihg-one-rewards-premier-select.yaml +5 -1
- package/data/cards/chase-ihg-one-rewards-premier.yaml +5 -1
- package/data/cards/chase-ihg-one-rewards.yaml +13 -2
- package/data/cards/chase-ink-business-cash.yaml +5 -1
- package/data/cards/chase-ink-business-unlimited.yaml +5 -1
- package/data/cards/chase-prime-visa.yaml +3 -3
- package/data/cards/chase-sapphire-reserve.yaml +12 -3
- package/data/cards/chase-united-business.yaml +5 -1
- package/data/cards/chase-united-club-business.yaml +5 -1
- package/data/cards/chase-united-club.yaml +5 -1
- package/data/cards/chase-united-explorer.yaml +5 -1
- package/data/cards/chase-united-quest.yaml +5 -1
- package/data/cards/citi-strata-premier.yaml +14 -1
- package/data/cards/wells-fargo-autograph-journey.yaml +16 -1
- package/data/merchants/overrides.yaml +3 -3
- package/dist/cli/args.js +13 -7
- package/dist/cli/run.js +4 -0
- package/dist/cli/wallet.js +18 -8
- package/dist/data/integrity.js +13 -0
- package/dist/data/wallet-edit.js +5 -0
- package/dist/engine/checklist.js +25 -5
- package/dist/engine/credits.js +56 -7
- package/dist/engine/evaluate.js +21 -1
- package/dist/engine/explore.js +27 -9
- package/dist/engine/memberships.js +21 -9
- package/dist/engine/milestones.js +11 -3
- package/dist/engine/offers.js +9 -4
- package/dist/engine/recommend.js +21 -2
- package/dist/engine/rule-text.js +20 -7
- package/dist/engine/setup.js +7 -6
- package/dist/engine/simulate.js +43 -10
- package/dist/engine/text.js +46 -5
- package/dist/engine/wallet-change.js +18 -7
- package/dist/engine/wallet-summary.js +25 -10
- package/dist/format/card-text.js +2 -10
- package/dist/format/explore.js +12 -8
- package/dist/format/offers.js +1 -1
- package/dist/format/wallet.js +2 -0
- package/dist/mcp/inputs.js +9 -1
- package/dist/mcp/schemas.js +23 -0
- package/dist/mcp/tools/account.js +1 -1
- package/dist/mcp/tools/wallet.js +5 -1
- package/dist/schema/card.js +11 -0
- package/dist/schema/wallet.js +6 -2
- package/package.json +1 -1
package/dist/mcp/schemas.js
CHANGED
|
@@ -179,6 +179,8 @@ export const WalletSummarySchema = z.object({
|
|
|
179
179
|
period: CreditPeriod,
|
|
180
180
|
enroll: z.boolean(),
|
|
181
181
|
enrolled: z.boolean(),
|
|
182
|
+
skipped: z.boolean(), // the user doesn't use it: not counted anywhere
|
|
183
|
+
confirmed: z.boolean(), // said in use: counts against the annual fee
|
|
182
184
|
currentPeriod: z.string().nullable(),
|
|
183
185
|
until: z.string().nullable(),
|
|
184
186
|
used: z.number(),
|
|
@@ -186,6 +188,8 @@ export const WalletSummarySchema = z.object({
|
|
|
186
188
|
tracked: z.boolean(),
|
|
187
189
|
text: z.string(),
|
|
188
190
|
})),
|
|
191
|
+
usedCredits: z.number(), // a year, counted against the annual fee
|
|
192
|
+
usedCreditsText: z.string().nullable(),
|
|
189
193
|
chosen: z
|
|
190
194
|
.object({
|
|
191
195
|
period: z.string(),
|
|
@@ -282,6 +286,10 @@ export const OfferComparisonSchema = z.object({
|
|
|
282
286
|
ineligible: z.string().nullable(),
|
|
283
287
|
bonusValue: z.number(),
|
|
284
288
|
firstYearValue: z.number(),
|
|
289
|
+
// Statement credits, a year at face value, and the first-year value
|
|
290
|
+
// if all were used. Not ranked on.
|
|
291
|
+
credits: z.number(),
|
|
292
|
+
firstYearValueIfCreditsUsed: z.number(),
|
|
285
293
|
held: z.boolean(),
|
|
286
294
|
lastVerified: z.string(),
|
|
287
295
|
verifiedBy: z.string(),
|
|
@@ -381,6 +389,7 @@ export const ExplorationSchema = z.object({
|
|
|
381
389
|
enroll: z.boolean(),
|
|
382
390
|
note: z.string().nullable(),
|
|
383
391
|
back: z.string(),
|
|
392
|
+
terms: z.string(),
|
|
384
393
|
earn: z.string(),
|
|
385
394
|
text: z.string(),
|
|
386
395
|
evidence: z.object({ quote: z.string(), url: z.string() }).nullable(),
|
|
@@ -431,7 +440,19 @@ const SimulationSchema = z.object({
|
|
|
431
440
|
cardIds: z.array(z.string()),
|
|
432
441
|
})),
|
|
433
442
|
membershipFees: z.number(),
|
|
443
|
+
// Credits the user uses on cards they hold, a year: counted in net.
|
|
444
|
+
heldCredits: z.number(),
|
|
434
445
|
net: z.number(),
|
|
446
|
+
// Credits on cards not held, a year at face value: not in net.
|
|
447
|
+
otherCredits: z.number(),
|
|
448
|
+
netIfCreditsUsed: z.number(),
|
|
449
|
+
credits: z.array(z.object({
|
|
450
|
+
cardId: z.string(),
|
|
451
|
+
yearly: z.number(),
|
|
452
|
+
creditIds: z.array(z.string()),
|
|
453
|
+
names: z.array(z.string()),
|
|
454
|
+
held: z.boolean(),
|
|
455
|
+
})),
|
|
435
456
|
lines: z.array(z.object({
|
|
436
457
|
label: z.string(),
|
|
437
458
|
spend: z.number(),
|
|
@@ -459,6 +480,8 @@ export const SpendingSimulationSchema = z.object({
|
|
|
459
480
|
annualFee: z.number(),
|
|
460
481
|
membershipFee: z.number(),
|
|
461
482
|
gain: z.number(),
|
|
483
|
+
credits: z.number(), // its statement credits, a year: not in gain
|
|
484
|
+
gainIfCreditsUsed: z.number(),
|
|
462
485
|
})),
|
|
463
486
|
});
|
|
464
487
|
export const CheatSheetSchema = z.object({
|
|
@@ -57,7 +57,7 @@ export function registerAccountTools(server, catalog, store, ctx) {
|
|
|
57
57
|
const importWallet = importHandler(catalog, store, ctx);
|
|
58
58
|
server.registerTool('export_wallet', {
|
|
59
59
|
title: 'Export the wallet',
|
|
60
|
-
description: 'The saved wallet as a wallet.yaml file: card ids, checkout labels, picks, activations, opening dates and anniversaries, memberships, point values, cap usage, welcome-bonus progress, yearly spending toward spend bonuses, and statement credits enrolled in and used. earnrate.dev imports it, and the earnrate command line reads it saved as ~/.earnrate/wallet.yaml. Never card numbers.',
|
|
60
|
+
description: 'The saved wallet as a wallet.yaml file: card ids, checkout labels, picks, activations, opening dates and anniversaries, memberships, point values, cap usage, welcome-bonus progress, yearly spending toward spend bonuses, and statement credits enrolled in, used and not used. earnrate.dev imports it, and the earnrate command line reads it saved as ~/.earnrate/wallet.yaml. Never card numbers.',
|
|
61
61
|
inputSchema: z.object({}),
|
|
62
62
|
outputSchema: z.object({ yaml: z.string() }),
|
|
63
63
|
annotations: {
|
package/dist/mcp/tools/wallet.js
CHANGED
|
@@ -57,6 +57,10 @@ function changes(catalog, args) {
|
|
|
57
57
|
: `enrolled in: ${args.enrolled.join(', ')}`);
|
|
58
58
|
for (const [id, used] of Object.entries(args.creditUsed ?? {}))
|
|
59
59
|
out.push(`${money(used)} of the ${id} credit used this period`);
|
|
60
|
+
if (args.skippedCredits !== undefined)
|
|
61
|
+
out.push(args.skippedCredits.length === 0
|
|
62
|
+
? 'every credit counted'
|
|
63
|
+
: `credits not used: ${args.skippedCredits.join(', ')}`);
|
|
60
64
|
if (args.bonus === null)
|
|
61
65
|
out.push('welcome bonus no longer tracked');
|
|
62
66
|
else if (args.bonus !== undefined)
|
|
@@ -291,7 +295,7 @@ export function registerWalletTools(server, deps, ctx, inputs) {
|
|
|
291
295
|
}, (args) => tools.add_card.run(args));
|
|
292
296
|
server.registerTool('update_card', {
|
|
293
297
|
title: 'Update a card',
|
|
294
|
-
description: `Changes settings on a card already in the wallet: its category picks for this period, checkout label, anniversary, opening date (optional; for first-year rates), activated categories, cap spending so far (capSpent), spending this year toward its spend bonuses (milestoneSpent), statement credits enrolled in (enrolled)
|
|
298
|
+
description: `Changes settings on a card already in the wallet: its category picks for this period, checkout label, anniversary, opening date (optional; for first-year rates), activated categories, cap spending so far (capSpent), spending this year toward its spend bonuses (milestoneSpent), statement credits enrolled in (enrolled), used this period (creditUsed) or not used at all (skippedCredits), or a welcome bonus to track. Picks replace the saved ones in each choice group you set (other groups are kept) for the current period. Use it when the user picks new categories, such as each quarter on U.S. Bank Cash+. ${ctx.walletUse}`,
|
|
295
299
|
inputSchema: tools.update_card.input,
|
|
296
300
|
outputSchema: WalletChangeSchema,
|
|
297
301
|
annotations: {
|
package/dist/schema/card.js
CHANGED
|
@@ -23,6 +23,9 @@ export const MilestoneSchema = z
|
|
|
23
23
|
period: z.enum(['calendar_year', 'cardmember_year']),
|
|
24
24
|
points: z.number().positive().optional(), // in the card's currency
|
|
25
25
|
rewards: z.array(z.string().min(1)).min(1).optional(),
|
|
26
|
+
// The day the issuer starts it, for one announced ahead: spending counts
|
|
27
|
+
// from then.
|
|
28
|
+
valid_from: IsoDate.optional(),
|
|
26
29
|
note: z.string().optional(),
|
|
27
30
|
})
|
|
28
31
|
.refine((m) => m.points !== undefined || m.rewards !== undefined, 'a milestone needs points, rewards or both');
|
|
@@ -76,6 +79,9 @@ export const RuleSchema = z
|
|
|
76
79
|
geography: z
|
|
77
80
|
.enum(['us_only', 'foreign_only', 'worldwide'])
|
|
78
81
|
.default('worldwide'),
|
|
82
|
+
// Only a purchase of at least this many dollars. Unknown without an
|
|
83
|
+
// amount, so then it never applies by assumption.
|
|
84
|
+
min_amount: z.number().positive().optional(),
|
|
79
85
|
// Inline cap, or the id of a shared cap in the card's `caps`.
|
|
80
86
|
cap: z.union([CapSchema, KebabId]).optional(),
|
|
81
87
|
requires: z
|
|
@@ -186,6 +192,11 @@ export const CreditSchema = z.strictObject({
|
|
|
186
192
|
period: CreditPeriod,
|
|
187
193
|
// The cardholder must enroll with the issuer before it pays.
|
|
188
194
|
enroll: z.literal(true).optional(),
|
|
195
|
+
// It pays only on a purchase of at least this many dollars.
|
|
196
|
+
min_amount: z.number().positive().optional(),
|
|
197
|
+
// The issuer's last day for it. Past it the credit counts nowhere, and a
|
|
198
|
+
// year's worth counts only the periods that start by then.
|
|
199
|
+
valid_to: IsoDate.optional(),
|
|
189
200
|
note: z.string().optional(),
|
|
190
201
|
});
|
|
191
202
|
const HexColor = z.string().regex(/^#[0-9a-f]{6}$/);
|
package/dist/schema/wallet.js
CHANGED
|
@@ -46,10 +46,14 @@ export const WalletCardSchema = z.strictObject({
|
|
|
46
46
|
activated: z.array(KebabId).default([]),
|
|
47
47
|
// Keyed by milestone id: every purchase on the card this period.
|
|
48
48
|
milestone_usage: z.record(KebabId, CapUsage).optional(),
|
|
49
|
-
// Merchant credits (the card's `credits`) the cardholder has enrolled in
|
|
50
|
-
//
|
|
49
|
+
// Merchant credits (the card's `credits`) the cardholder has enrolled in
|
|
50
|
+
// or, for ones that need no enrolling, says they use, by credit id; and
|
|
51
|
+
// the dollars of each credit already received this period.
|
|
51
52
|
enrolled: z.array(KebabId).optional(),
|
|
52
53
|
credit_usage: z.record(KebabId, CreditUsage).optional(),
|
|
54
|
+
// Credits the cardholder doesn't use: left out of the pick, the to-do
|
|
55
|
+
// list and the fee math, even if enrolled.
|
|
56
|
+
skipped_credits: z.array(KebabId).optional(),
|
|
53
57
|
// A welcome bonus in progress. Terms default to the card's published
|
|
54
58
|
// offer; set spend, by, points or dollars when yours was different.
|
|
55
59
|
bonus: z
|