@stithy/mileage 0.1.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 +26 -0
- package/README.md +75 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +43 -0
- package/dist/cli.js.map +1 -0
- package/dist/db.d.ts +3 -0
- package/dist/db.js +55 -0
- package/dist/db.js.map +1 -0
- package/dist/install.d.ts +2 -0
- package/dist/install.js +168 -0
- package/dist/install.js.map +1 -0
- package/dist/rates.d.ts +22 -0
- package/dist/rates.js +31 -0
- package/dist/rates.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +348 -0
- package/dist/server.js.map +1 -0
- package/dist/store.d.ts +126 -0
- package/dist/store.js +289 -0
- package/dist/store.js.map +1 -0
- package/package.json +57 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { verifyLicense } from "@mcp_marketplace/license";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { openDb, VALID_CATEGORIES } from "./db.js";
|
|
9
|
+
import { Store } from "./store.js";
|
|
10
|
+
import { knownYears } from "./rates.js";
|
|
11
|
+
const SLUG = "stithy-mileage";
|
|
12
|
+
const SKIP_LICENSE = process.env.STITHY_SKIP_LICENSE === "1";
|
|
13
|
+
if (!SKIP_LICENSE) {
|
|
14
|
+
const result = await verifyLicense({ slug: SLUG });
|
|
15
|
+
if (!result.valid) {
|
|
16
|
+
console.error(`Stithy Mileage: license check failed (${result.reason ?? "unknown"}).\n` +
|
|
17
|
+
`Set MCP_LICENSE_KEY in your environment.\n` +
|
|
18
|
+
`Get a key: https://mcp-marketplace.io/${SLUG}`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const dbPath = process.env.STITHY_MILEAGE_DB ?? join(homedir(), ".stithy", "mileage.db");
|
|
23
|
+
const db = openDb(dbPath);
|
|
24
|
+
const store = new Store(db);
|
|
25
|
+
const server = new McpServer({ name: "stithy-mileage", version: "0.1.0" }, {
|
|
26
|
+
instructions: "IRS-audit-proof mileage tracker. Workflow: add_vehicle (set is_default=true) once, then add_trip whenever you drive for business / medical / charitable / moving (military). At tax time, run annual_deduction year=YYYY for the Schedule C number. export_csv produces the audit-trail file. Trip dates must be ISO yyyy-mm-dd.",
|
|
27
|
+
});
|
|
28
|
+
const ISO_DATE = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "must be ISO yyyy-mm-dd");
|
|
29
|
+
const categoryEnum = z.enum(VALID_CATEGORIES);
|
|
30
|
+
function err(e) {
|
|
31
|
+
return e instanceof Error ? e.message : String(e);
|
|
32
|
+
}
|
|
33
|
+
function ok(text) {
|
|
34
|
+
return { content: [{ type: "text", text }] };
|
|
35
|
+
}
|
|
36
|
+
function fail(text) {
|
|
37
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
38
|
+
}
|
|
39
|
+
// -- vehicle tools --
|
|
40
|
+
server.registerTool("add_vehicle", {
|
|
41
|
+
title: "Add Vehicle",
|
|
42
|
+
description: "Register a vehicle for mileage tracking. Set is_default=true on your primary vehicle so add_trip can omit vehicle_id.",
|
|
43
|
+
inputSchema: {
|
|
44
|
+
name: z.string().min(1).max(100),
|
|
45
|
+
year: z.number().int().min(1900).max(2100).optional(),
|
|
46
|
+
make: z.string().max(50).optional(),
|
|
47
|
+
model: z.string().max(50).optional(),
|
|
48
|
+
license_plate: z.string().max(20).optional(),
|
|
49
|
+
placed_in_service_date: ISO_DATE.optional(),
|
|
50
|
+
is_default: z.boolean().optional(),
|
|
51
|
+
},
|
|
52
|
+
}, async (args) => {
|
|
53
|
+
try {
|
|
54
|
+
const v = store.addVehicle(args);
|
|
55
|
+
return ok(`Added '${v.name}'${v.is_default ? " (default)" : ""}. id: ${v.id}`);
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
return fail(err(e));
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
server.registerTool("list_vehicles", {
|
|
62
|
+
title: "List Vehicles",
|
|
63
|
+
description: "All registered vehicles. Default first.",
|
|
64
|
+
inputSchema: {},
|
|
65
|
+
}, async () => {
|
|
66
|
+
try {
|
|
67
|
+
const vs = store.listVehicles();
|
|
68
|
+
if (vs.length === 0)
|
|
69
|
+
return ok("No vehicles. Run add_vehicle first.");
|
|
70
|
+
return ok(vs
|
|
71
|
+
.map((v) => `- ${v.is_default ? "★ " : " "}${v.name}` +
|
|
72
|
+
(v.year || v.make || v.model
|
|
73
|
+
? ` (${[v.year, v.make, v.model].filter(Boolean).join(" ")})`
|
|
74
|
+
: "") +
|
|
75
|
+
(v.license_plate ? ` [${v.license_plate}]` : "") +
|
|
76
|
+
`\n id: ${v.id}`)
|
|
77
|
+
.join("\n"));
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
return fail(err(e));
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
server.registerTool("set_default_vehicle", {
|
|
84
|
+
title: "Set Default Vehicle",
|
|
85
|
+
description: "Make this vehicle the default used by add_trip when no vehicle_id is given.",
|
|
86
|
+
inputSchema: { id: z.string() },
|
|
87
|
+
}, async ({ id }) => {
|
|
88
|
+
try {
|
|
89
|
+
const v = store.setDefaultVehicle(id);
|
|
90
|
+
return v ? ok(`'${v.name}' is now the default.`) : fail("Vehicle not found.");
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
return fail(err(e));
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
server.registerTool("remove_vehicle", {
|
|
97
|
+
title: "Remove Vehicle",
|
|
98
|
+
description: "Delete a vehicle. Fails if any trips reference it — delete trips first.",
|
|
99
|
+
inputSchema: { id: z.string() },
|
|
100
|
+
}, async ({ id }) => {
|
|
101
|
+
try {
|
|
102
|
+
const okRm = store.removeVehicle(id);
|
|
103
|
+
return okRm ? ok(`Removed ${id}.`) : fail("Vehicle not found.");
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
return fail(err(e));
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
// -- trip tools --
|
|
110
|
+
server.registerTool("add_trip", {
|
|
111
|
+
title: "Add Trip",
|
|
112
|
+
description: "Log one trip. trip_date must be ISO yyyy-mm-dd. category is business / medical / moving / charitable. If vehicle_id omitted, uses the default vehicle.",
|
|
113
|
+
inputSchema: {
|
|
114
|
+
trip_date: ISO_DATE,
|
|
115
|
+
miles: z.number().positive().max(5000),
|
|
116
|
+
category: categoryEnum,
|
|
117
|
+
purpose: z.string().min(1).max(500),
|
|
118
|
+
vehicle_id: z.string().optional(),
|
|
119
|
+
start_location: z.string().max(200).optional(),
|
|
120
|
+
end_location: z.string().max(200).optional(),
|
|
121
|
+
notes: z.string().max(1000).optional(),
|
|
122
|
+
},
|
|
123
|
+
}, async (args) => {
|
|
124
|
+
try {
|
|
125
|
+
const t = store.addTrip(args);
|
|
126
|
+
return ok(`Logged ${t.miles}mi on ${t.trip_date} (${t.category}) — ${t.purpose}. id: ${t.id}`);
|
|
127
|
+
}
|
|
128
|
+
catch (e) {
|
|
129
|
+
return fail(err(e));
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
server.registerTool("update_trip", {
|
|
133
|
+
title: "Update Trip",
|
|
134
|
+
description: "Patch fields on a trip.",
|
|
135
|
+
inputSchema: {
|
|
136
|
+
id: z.string(),
|
|
137
|
+
trip_date: ISO_DATE.optional(),
|
|
138
|
+
miles: z.number().positive().max(5000).optional(),
|
|
139
|
+
category: categoryEnum.optional(),
|
|
140
|
+
purpose: z.string().min(1).max(500).optional(),
|
|
141
|
+
vehicle_id: z.string().optional(),
|
|
142
|
+
start_location: z.string().max(200).nullable().optional(),
|
|
143
|
+
end_location: z.string().max(200).nullable().optional(),
|
|
144
|
+
notes: z.string().max(1000).nullable().optional(),
|
|
145
|
+
},
|
|
146
|
+
}, async ({ id, ...patch }) => {
|
|
147
|
+
try {
|
|
148
|
+
const t = store.updateTrip(id, patch);
|
|
149
|
+
return t ? ok(`Updated ${id}.`) : fail("Trip not found.");
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
return fail(err(e));
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
server.registerTool("delete_trip", {
|
|
156
|
+
title: "Delete Trip",
|
|
157
|
+
description: "Delete a trip permanently.",
|
|
158
|
+
inputSchema: { id: z.string() },
|
|
159
|
+
}, async ({ id }) => {
|
|
160
|
+
try {
|
|
161
|
+
const okDel = store.deleteTrip(id);
|
|
162
|
+
return okDel ? ok(`Deleted ${id}.`) : fail("Trip not found.");
|
|
163
|
+
}
|
|
164
|
+
catch (e) {
|
|
165
|
+
return fail(err(e));
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
server.registerTool("list_trips", {
|
|
169
|
+
title: "List Trips",
|
|
170
|
+
description: "List trips, newest first, optionally filtered by date range, category, or vehicle.",
|
|
171
|
+
inputSchema: {
|
|
172
|
+
from_date: ISO_DATE.optional(),
|
|
173
|
+
to_date: ISO_DATE.optional(),
|
|
174
|
+
category: categoryEnum.optional(),
|
|
175
|
+
vehicle_id: z.string().optional(),
|
|
176
|
+
limit: z.number().int().min(1).max(1000).optional(),
|
|
177
|
+
offset: z.number().int().min(0).optional(),
|
|
178
|
+
},
|
|
179
|
+
}, async (args) => {
|
|
180
|
+
try {
|
|
181
|
+
const trips = store.listTrips(args);
|
|
182
|
+
if (trips.length === 0)
|
|
183
|
+
return ok("No trips match.");
|
|
184
|
+
const lines = trips.map((t) => `- ${t.trip_date} | ${t.miles}mi | ${t.category.padEnd(10)} | ${t.purpose}` +
|
|
185
|
+
(t.start_location && t.end_location
|
|
186
|
+
? `\n ${t.start_location} → ${t.end_location}`
|
|
187
|
+
: "") +
|
|
188
|
+
`\n id: ${t.id}`);
|
|
189
|
+
return ok(lines.join("\n"));
|
|
190
|
+
}
|
|
191
|
+
catch (e) {
|
|
192
|
+
return fail(err(e));
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
// -- odometer --
|
|
196
|
+
server.registerTool("log_odometer", {
|
|
197
|
+
title: "Log Odometer Reading",
|
|
198
|
+
description: "Record a year-start, year-end, or interim odometer reading. The IRS strongly recommends yearly endpoints for substantiation.",
|
|
199
|
+
inputSchema: {
|
|
200
|
+
vehicle_id: z.string(),
|
|
201
|
+
snapshot_date: ISO_DATE,
|
|
202
|
+
reading: z.number().int().min(0),
|
|
203
|
+
note: z.string().max(200).optional(),
|
|
204
|
+
},
|
|
205
|
+
}, async (args) => {
|
|
206
|
+
try {
|
|
207
|
+
const o = store.addOdometer(args);
|
|
208
|
+
return ok(`Logged odometer ${o.reading} on ${o.snapshot_date}.`);
|
|
209
|
+
}
|
|
210
|
+
catch (e) {
|
|
211
|
+
return fail(err(e));
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
server.registerTool("list_odometer", {
|
|
215
|
+
title: "List Odometer Readings",
|
|
216
|
+
description: "Show all odometer snapshots for a vehicle, oldest first.",
|
|
217
|
+
inputSchema: { vehicle_id: z.string() },
|
|
218
|
+
}, async ({ vehicle_id }) => {
|
|
219
|
+
try {
|
|
220
|
+
const snaps = store.listOdometers(vehicle_id);
|
|
221
|
+
if (snaps.length === 0)
|
|
222
|
+
return ok("No readings.");
|
|
223
|
+
return ok(snaps
|
|
224
|
+
.map((s) => `- ${s.snapshot_date} | ${s.reading.toLocaleString()}${s.note ? ` | ${s.note}` : ""}`)
|
|
225
|
+
.join("\n"));
|
|
226
|
+
}
|
|
227
|
+
catch (e) {
|
|
228
|
+
return fail(err(e));
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
// -- summaries --
|
|
232
|
+
server.registerTool("mileage_summary", {
|
|
233
|
+
title: "Mileage Summary",
|
|
234
|
+
description: "Sum miles per category for any date range. Use for monthly check-ins or quarterly estimates.",
|
|
235
|
+
inputSchema: {
|
|
236
|
+
from_date: ISO_DATE,
|
|
237
|
+
to_date: ISO_DATE,
|
|
238
|
+
vehicle_id: z.string().optional(),
|
|
239
|
+
},
|
|
240
|
+
}, async (args) => {
|
|
241
|
+
try {
|
|
242
|
+
const s = store.summary(args);
|
|
243
|
+
const lines = [
|
|
244
|
+
`Range: ${args.from_date} → ${args.to_date}`,
|
|
245
|
+
`Total: ${s.total_miles.toFixed(1)} miles across ${s.total_trips} trips`,
|
|
246
|
+
``,
|
|
247
|
+
`By category:`,
|
|
248
|
+
];
|
|
249
|
+
for (const [cat, v] of Object.entries(s.by_category)) {
|
|
250
|
+
if (v.miles > 0) {
|
|
251
|
+
lines.push(` ${cat.padEnd(10)} ${v.miles.toFixed(1)}mi (${v.trips} trip${v.trips === 1 ? "" : "s"})`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return ok(lines.join("\n"));
|
|
255
|
+
}
|
|
256
|
+
catch (e) {
|
|
257
|
+
return fail(err(e));
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
server.registerTool("annual_deduction", {
|
|
261
|
+
title: "Annual Tax Deduction",
|
|
262
|
+
description: "Compute the IRS standard-mileage deduction for a tax year. Multiplies miles per category × the IRS rate published for that year. Returns the dollar amount you'd put on Schedule C line 9 (business) or Schedule A (medical). Rates available for years: " +
|
|
263
|
+
knownYears().join(", "),
|
|
264
|
+
inputSchema: {
|
|
265
|
+
year: z.number().int().min(2000).max(2100),
|
|
266
|
+
vehicle_id: z.string().optional(),
|
|
267
|
+
},
|
|
268
|
+
}, async ({ year, vehicle_id }) => {
|
|
269
|
+
try {
|
|
270
|
+
const r = store.annualDeduction(year, vehicle_id);
|
|
271
|
+
const lines = [
|
|
272
|
+
`Tax year ${r.year}`,
|
|
273
|
+
`Total miles: ${r.total_miles.toFixed(1)}`,
|
|
274
|
+
`Total deduction: $${r.total_deduction_dollars.toFixed(2)}`,
|
|
275
|
+
``,
|
|
276
|
+
`Breakdown:`,
|
|
277
|
+
];
|
|
278
|
+
for (const [cat, v] of Object.entries(r.by_category)) {
|
|
279
|
+
if (v.miles > 0) {
|
|
280
|
+
lines.push(` ${cat.padEnd(10)} ${v.miles.toFixed(1)}mi × ${v.rate_cents_per_mile}¢/mi = $${v.deduction_dollars.toFixed(2)} (${v.trips} trip${v.trips === 1 ? "" : "s"})`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
lines.push("");
|
|
284
|
+
lines.push("Schedule C line 9 = the 'business' row above.");
|
|
285
|
+
lines.push("Schedule A medical = the 'medical' row above (only if itemizing).");
|
|
286
|
+
lines.push("Reminder: standard-mileage method requires you DID NOT take actual-expense in year 1.");
|
|
287
|
+
return ok(lines.join("\n"));
|
|
288
|
+
}
|
|
289
|
+
catch (e) {
|
|
290
|
+
return fail(err(e));
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
server.registerTool("export_csv", {
|
|
294
|
+
title: "Export CSV",
|
|
295
|
+
description: "IRS-audit-ready CSV: Date, Miles, Category, Purpose, Start, End, Vehicle, Notes. Filter by date range, category, or vehicle.",
|
|
296
|
+
inputSchema: {
|
|
297
|
+
from_date: ISO_DATE.optional(),
|
|
298
|
+
to_date: ISO_DATE.optional(),
|
|
299
|
+
category: categoryEnum.optional(),
|
|
300
|
+
vehicle_id: z.string().optional(),
|
|
301
|
+
},
|
|
302
|
+
}, async (args) => {
|
|
303
|
+
try {
|
|
304
|
+
const csv = store.exportCsv(args);
|
|
305
|
+
return ok(csv);
|
|
306
|
+
}
|
|
307
|
+
catch (e) {
|
|
308
|
+
return fail(err(e));
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
server.registerTool("irs_rates", {
|
|
312
|
+
title: "IRS Standard Mileage Rates",
|
|
313
|
+
description: "Reference: IRS standard-mileage rates per year, in cents per mile.",
|
|
314
|
+
inputSchema: { year: z.number().int().min(2000).max(2100).optional() },
|
|
315
|
+
}, async ({ year }) => {
|
|
316
|
+
try {
|
|
317
|
+
const { RATES } = await import("./rates.js");
|
|
318
|
+
const lines = [`Year Business Medical Moving Charitable`];
|
|
319
|
+
const years = year ? [year] : Object.keys(RATES).map(Number).sort();
|
|
320
|
+
for (const y of years) {
|
|
321
|
+
const r = RATES[y];
|
|
322
|
+
if (!r) {
|
|
323
|
+
lines.push(`${y} (no rate published yet)`);
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
lines.push(`${y} ${r.business.toString().padEnd(8)} ${r.medical.toString().padEnd(7)} ${r.moving.toString().padEnd(6)} ${r.charitable}`);
|
|
327
|
+
}
|
|
328
|
+
lines.push("(All values in cents per mile.)");
|
|
329
|
+
return ok(lines.join("\n"));
|
|
330
|
+
}
|
|
331
|
+
catch (e) {
|
|
332
|
+
return fail(err(e));
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
const shutdown = (sig) => {
|
|
336
|
+
console.error(`stithy-mileage: ${sig}, closing db`);
|
|
337
|
+
try {
|
|
338
|
+
db.close();
|
|
339
|
+
}
|
|
340
|
+
catch { }
|
|
341
|
+
process.exit(0);
|
|
342
|
+
};
|
|
343
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
344
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
345
|
+
const transport = new StdioServerTransport();
|
|
346
|
+
await server.connect(transport);
|
|
347
|
+
console.error(`stithy-mileage v0.1.0 ready (db: ${dbPath})`);
|
|
348
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
2
|
+
import { type Category } from "./rates.js";
|
|
3
|
+
export interface Vehicle {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
year: number | null;
|
|
7
|
+
make: string | null;
|
|
8
|
+
model: string | null;
|
|
9
|
+
license_plate: string | null;
|
|
10
|
+
is_default: boolean;
|
|
11
|
+
placed_in_service_date: number | null;
|
|
12
|
+
created_at: number;
|
|
13
|
+
}
|
|
14
|
+
export interface Trip {
|
|
15
|
+
id: string;
|
|
16
|
+
vehicle_id: string;
|
|
17
|
+
trip_date: string;
|
|
18
|
+
miles: number;
|
|
19
|
+
category: Category;
|
|
20
|
+
purpose: string;
|
|
21
|
+
start_location: string | null;
|
|
22
|
+
end_location: string | null;
|
|
23
|
+
notes: string | null;
|
|
24
|
+
created_at: number;
|
|
25
|
+
}
|
|
26
|
+
export interface OdometerSnapshot {
|
|
27
|
+
id: string;
|
|
28
|
+
vehicle_id: string;
|
|
29
|
+
snapshot_date: string;
|
|
30
|
+
reading: number;
|
|
31
|
+
note: string | null;
|
|
32
|
+
created_at: number;
|
|
33
|
+
}
|
|
34
|
+
export declare class Store {
|
|
35
|
+
private readonly db;
|
|
36
|
+
constructor(db: Database.Database);
|
|
37
|
+
addVehicle(input: {
|
|
38
|
+
name: string;
|
|
39
|
+
year?: number;
|
|
40
|
+
make?: string;
|
|
41
|
+
model?: string;
|
|
42
|
+
license_plate?: string;
|
|
43
|
+
placed_in_service_date?: string;
|
|
44
|
+
is_default?: boolean;
|
|
45
|
+
}): Vehicle;
|
|
46
|
+
getVehicle(id: string): Vehicle | null;
|
|
47
|
+
listVehicles(): Vehicle[];
|
|
48
|
+
setDefaultVehicle(id: string): Vehicle | null;
|
|
49
|
+
defaultVehicle(): Vehicle | null;
|
|
50
|
+
removeVehicle(id: string): boolean;
|
|
51
|
+
addTrip(input: {
|
|
52
|
+
vehicle_id?: string;
|
|
53
|
+
trip_date: string;
|
|
54
|
+
miles: number;
|
|
55
|
+
category: string;
|
|
56
|
+
purpose: string;
|
|
57
|
+
start_location?: string;
|
|
58
|
+
end_location?: string;
|
|
59
|
+
notes?: string;
|
|
60
|
+
}): Trip;
|
|
61
|
+
getTrip(id: string): Trip | null;
|
|
62
|
+
updateTrip(id: string, patch: Partial<{
|
|
63
|
+
trip_date: string;
|
|
64
|
+
miles: number;
|
|
65
|
+
category: string;
|
|
66
|
+
purpose: string;
|
|
67
|
+
start_location: string | null;
|
|
68
|
+
end_location: string | null;
|
|
69
|
+
notes: string | null;
|
|
70
|
+
vehicle_id: string;
|
|
71
|
+
}>): Trip | null;
|
|
72
|
+
deleteTrip(id: string): boolean;
|
|
73
|
+
listTrips(filter?: {
|
|
74
|
+
from_date?: string;
|
|
75
|
+
to_date?: string;
|
|
76
|
+
category?: string;
|
|
77
|
+
vehicle_id?: string;
|
|
78
|
+
limit?: number;
|
|
79
|
+
offset?: number;
|
|
80
|
+
}): Trip[];
|
|
81
|
+
addOdometer(input: {
|
|
82
|
+
vehicle_id: string;
|
|
83
|
+
snapshot_date: string;
|
|
84
|
+
reading: number;
|
|
85
|
+
note?: string;
|
|
86
|
+
}): OdometerSnapshot;
|
|
87
|
+
listOdometers(vehicle_id: string): OdometerSnapshot[];
|
|
88
|
+
/**
|
|
89
|
+
* Sum miles per category for a date range. Use this for monthly check-ins.
|
|
90
|
+
*/
|
|
91
|
+
summary(input: {
|
|
92
|
+
from_date: string;
|
|
93
|
+
to_date: string;
|
|
94
|
+
vehicle_id?: string;
|
|
95
|
+
}): {
|
|
96
|
+
by_category: Record<Category, {
|
|
97
|
+
miles: number;
|
|
98
|
+
trips: number;
|
|
99
|
+
}>;
|
|
100
|
+
total_miles: number;
|
|
101
|
+
total_trips: number;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Annual deduction for a tax year: miles per category × IRS rate for that year.
|
|
105
|
+
*/
|
|
106
|
+
annualDeduction(year: number, vehicle_id?: string): {
|
|
107
|
+
year: number;
|
|
108
|
+
by_category: Record<Category, {
|
|
109
|
+
miles: number;
|
|
110
|
+
trips: number;
|
|
111
|
+
rate_cents_per_mile: number;
|
|
112
|
+
deduction_dollars: number;
|
|
113
|
+
}>;
|
|
114
|
+
total_miles: number;
|
|
115
|
+
total_deduction_dollars: number;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* IRS-audit-ready CSV. One row per trip. Header row matches what an auditor expects:
|
|
119
|
+
* Date | Miles | Category | Purpose | Start | End | Vehicle | Notes
|
|
120
|
+
*/
|
|
121
|
+
exportCsv(filter?: {
|
|
122
|
+
from_date?: string;
|
|
123
|
+
to_date?: string;
|
|
124
|
+
vehicle_id?: string;
|
|
125
|
+
}): string;
|
|
126
|
+
}
|