trainbud 0.5.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/.env.example +11 -0
- package/CHANGELOG.md +675 -0
- package/LICENSE +21 -0
- package/QUICKSTART.md +182 -0
- package/README.md +322 -0
- package/dist/appDb.d.ts +83 -0
- package/dist/appDb.d.ts.map +1 -0
- package/dist/appDb.js +239 -0
- package/dist/appDb.js.map +1 -0
- package/dist/check.d.ts +12 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +230 -0
- package/dist/check.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +457 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +61 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +241 -0
- package/dist/config.js.map +1 -0
- package/dist/dashboard.d.ts +8 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/dashboard.js +1004 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/dashboardCharts.d.ts +99 -0
- package/dist/dashboardCharts.d.ts.map +1 -0
- package/dist/dashboardCharts.js +317 -0
- package/dist/dashboardCharts.js.map +1 -0
- package/dist/dashboardData.d.ts +89 -0
- package/dist/dashboardData.d.ts.map +1 -0
- package/dist/dashboardData.js +228 -0
- package/dist/dashboardData.js.map +1 -0
- package/dist/detect/baseline.d.ts +17 -0
- package/dist/detect/baseline.d.ts.map +1 -0
- package/dist/detect/baseline.js +62 -0
- package/dist/detect/baseline.js.map +1 -0
- package/dist/detect/countdown.d.ts +30 -0
- package/dist/detect/countdown.d.ts.map +1 -0
- package/dist/detect/countdown.js +79 -0
- package/dist/detect/countdown.js.map +1 -0
- package/dist/detect/detectors.d.ts +20 -0
- package/dist/detect/detectors.d.ts.map +1 -0
- package/dist/detect/detectors.js +291 -0
- package/dist/detect/detectors.js.map +1 -0
- package/dist/detect/findings.d.ts +29 -0
- package/dist/detect/findings.d.ts.map +1 -0
- package/dist/detect/findings.js +2 -0
- package/dist/detect/findings.js.map +1 -0
- package/dist/detect/forecast.d.ts +33 -0
- package/dist/detect/forecast.d.ts.map +1 -0
- package/dist/detect/forecast.js +122 -0
- package/dist/detect/forecast.js.map +1 -0
- package/dist/detect/index.d.ts +50 -0
- package/dist/detect/index.d.ts.map +1 -0
- package/dist/detect/index.js +114 -0
- package/dist/detect/index.js.map +1 -0
- package/dist/detect/sleepQuality.d.ts +21 -0
- package/dist/detect/sleepQuality.d.ts.map +1 -0
- package/dist/detect/sleepQuality.js +164 -0
- package/dist/detect/sleepQuality.js.map +1 -0
- package/dist/detect/trimp.d.ts +22 -0
- package/dist/detect/trimp.d.ts.map +1 -0
- package/dist/detect/trimp.js +77 -0
- package/dist/detect/trimp.js.map +1 -0
- package/dist/detect/week.d.ts +31 -0
- package/dist/detect/week.d.ts.map +1 -0
- package/dist/detect/week.js +184 -0
- package/dist/detect/week.js.map +1 -0
- package/dist/garmin/auth.d.ts +10 -0
- package/dist/garmin/auth.d.ts.map +1 -0
- package/dist/garmin/auth.js +81 -0
- package/dist/garmin/auth.js.map +1 -0
- package/dist/garmin/cache.d.ts +42 -0
- package/dist/garmin/cache.d.ts.map +1 -0
- package/dist/garmin/cache.js +141 -0
- package/dist/garmin/cache.js.map +1 -0
- package/dist/garmin/client.d.ts +22 -0
- package/dist/garmin/client.d.ts.map +1 -0
- package/dist/garmin/client.js +237 -0
- package/dist/garmin/client.js.map +1 -0
- package/dist/garmin/daily.d.ts +24 -0
- package/dist/garmin/daily.d.ts.map +1 -0
- package/dist/garmin/daily.js +96 -0
- package/dist/garmin/daily.js.map +1 -0
- package/dist/garmin/garminApiTypes.d.ts +70 -0
- package/dist/garmin/garminApiTypes.d.ts.map +1 -0
- package/dist/garmin/garminApiTypes.js +3 -0
- package/dist/garmin/garminApiTypes.js.map +1 -0
- package/dist/garmin/garminConnect.d.ts +17 -0
- package/dist/garmin/garminConnect.d.ts.map +1 -0
- package/dist/garmin/garminConnect.js +5 -0
- package/dist/garmin/garminConnect.js.map +1 -0
- package/dist/garmin/partial.d.ts +32 -0
- package/dist/garmin/partial.d.ts.map +1 -0
- package/dist/garmin/partial.js +38 -0
- package/dist/garmin/partial.js.map +1 -0
- package/dist/garmin/rawApi.d.ts +59 -0
- package/dist/garmin/rawApi.d.ts.map +1 -0
- package/dist/garmin/rawApi.js +113 -0
- package/dist/garmin/rawApi.js.map +1 -0
- package/dist/garmin/types.d.ts +85 -0
- package/dist/garmin/types.d.ts.map +1 -0
- package/dist/garmin/types.js +11 -0
- package/dist/garmin/types.js.map +1 -0
- package/dist/history/capture.d.ts +12 -0
- package/dist/history/capture.d.ts.map +1 -0
- package/dist/history/capture.js +63 -0
- package/dist/history/capture.js.map +1 -0
- package/dist/history/context.d.ts +51 -0
- package/dist/history/context.d.ts.map +1 -0
- package/dist/history/context.js +122 -0
- package/dist/history/context.js.map +1 -0
- package/dist/history/fallback.d.ts +72 -0
- package/dist/history/fallback.d.ts.map +1 -0
- package/dist/history/fallback.js +185 -0
- package/dist/history/fallback.js.map +1 -0
- package/dist/history/ingest.d.ts +44 -0
- package/dist/history/ingest.d.ts.map +1 -0
- package/dist/history/ingest.js +347 -0
- package/dist/history/ingest.js.map +1 -0
- package/dist/history/scheduler.d.ts +20 -0
- package/dist/history/scheduler.d.ts.map +1 -0
- package/dist/history/scheduler.js +54 -0
- package/dist/history/scheduler.js.map +1 -0
- package/dist/history/schema.d.ts +41 -0
- package/dist/history/schema.d.ts.map +1 -0
- package/dist/history/schema.js +91 -0
- package/dist/history/schema.js.map +1 -0
- package/dist/history/store.d.ts +112 -0
- package/dist/history/store.d.ts.map +1 -0
- package/dist/history/store.js +282 -0
- package/dist/history/store.js.map +1 -0
- package/dist/httpServer.d.ts +55 -0
- package/dist/httpServer.d.ts.map +1 -0
- package/dist/httpServer.js +1027 -0
- package/dist/httpServer.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/mcpConfig.d.ts +56 -0
- package/dist/mcpConfig.d.ts.map +1 -0
- package/dist/mcpConfig.js +106 -0
- package/dist/mcpConfig.js.map +1 -0
- package/dist/pairApi.d.ts +14 -0
- package/dist/pairApi.d.ts.map +1 -0
- package/dist/pairApi.js +38 -0
- package/dist/pairApi.js.map +1 -0
- package/dist/paths.d.ts +45 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +105 -0
- package/dist/paths.js.map +1 -0
- package/dist/profile.d.ts +123 -0
- package/dist/profile.d.ts.map +1 -0
- package/dist/profile.js +327 -0
- package/dist/profile.js.map +1 -0
- package/dist/promptApi.d.ts +43 -0
- package/dist/promptApi.d.ts.map +1 -0
- package/dist/promptApi.js +328 -0
- package/dist/promptApi.js.map +1 -0
- package/dist/promptSuggestions.d.ts +16 -0
- package/dist/promptSuggestions.d.ts.map +1 -0
- package/dist/promptSuggestions.js +141 -0
- package/dist/promptSuggestions.js.map +1 -0
- package/dist/selfTest.d.ts +53 -0
- package/dist/selfTest.d.ts.map +1 -0
- package/dist/selfTest.js +225 -0
- package/dist/selfTest.js.map +1 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +67 -0
- package/dist/server.js.map +1 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +210 -0
- package/dist/setup.js.map +1 -0
- package/dist/toolErrors.d.ts +2 -0
- package/dist/toolErrors.d.ts.map +1 -0
- package/dist/toolErrors.js +18 -0
- package/dist/toolErrors.js.map +1 -0
- package/dist/tools/activities.d.ts +18 -0
- package/dist/tools/activities.d.ts.map +1 -0
- package/dist/tools/activities.js +182 -0
- package/dist/tools/activities.js.map +1 -0
- package/dist/tools/bodyComposition.d.ts +10 -0
- package/dist/tools/bodyComposition.d.ts.map +1 -0
- package/dist/tools/bodyComposition.js +139 -0
- package/dist/tools/bodyComposition.js.map +1 -0
- package/dist/tools/context.d.ts +8 -0
- package/dist/tools/context.d.ts.map +1 -0
- package/dist/tools/context.js +148 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/findings.d.ts +7 -0
- package/dist/tools/findings.d.ts.map +1 -0
- package/dist/tools/findings.js +51 -0
- package/dist/tools/findings.js.map +1 -0
- package/dist/tools/heartRate.d.ts +10 -0
- package/dist/tools/heartRate.d.ts.map +1 -0
- package/dist/tools/heartRate.js +105 -0
- package/dist/tools/heartRate.js.map +1 -0
- package/dist/tools/index.d.ts +66 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +101 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/payloads.d.ts +148 -0
- package/dist/tools/payloads.d.ts.map +1 -0
- package/dist/tools/payloads.js +2 -0
- package/dist/tools/payloads.js.map +1 -0
- package/dist/tools/recovery.d.ts +31 -0
- package/dist/tools/recovery.d.ts.map +1 -0
- package/dist/tools/recovery.js +350 -0
- package/dist/tools/recovery.js.map +1 -0
- package/dist/tools/sleep.d.ts +10 -0
- package/dist/tools/sleep.d.ts.map +1 -0
- package/dist/tools/sleep.js +124 -0
- package/dist/tools/sleep.js.map +1 -0
- package/dist/tools/stress.d.ts +11 -0
- package/dist/tools/stress.d.ts.map +1 -0
- package/dist/tools/stress.js +108 -0
- package/dist/tools/stress.js.map +1 -0
- package/dist/tools/trainingInsights.d.ts +15 -0
- package/dist/tools/trainingInsights.d.ts.map +1 -0
- package/dist/tools/trainingInsights.js +79 -0
- package/dist/tools/trainingInsights.js.map +1 -0
- package/dist/tools/types.d.ts +12 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/vo2Max.d.ts +11 -0
- package/dist/tools/vo2Max.d.ts.map +1 -0
- package/dist/tools/vo2Max.js +110 -0
- package/dist/tools/vo2Max.js.map +1 -0
- package/dist/tools/week.d.ts +12 -0
- package/dist/tools/week.d.ts.map +1 -0
- package/dist/tools/week.js +74 -0
- package/dist/tools/week.js.map +1 -0
- package/dist/usage.d.ts +104 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +247 -0
- package/dist/usage.js.map +1 -0
- package/dist/utils/batch.d.ts +2 -0
- package/dist/utils/batch.d.ts.map +1 -0
- package/dist/utils/batch.js +18 -0
- package/dist/utils/batch.js.map +1 -0
- package/dist/utils/helpers.d.ts +32 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +188 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/jsonFile.d.ts +19 -0
- package/dist/utils/jsonFile.d.ts.map +1 -0
- package/dist/utils/jsonFile.js +24 -0
- package/dist/utils/jsonFile.js.map +1 -0
- package/dist/utils/logger.d.ts +4 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +97 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/secretFile.d.ts +15 -0
- package/dist/utils/secretFile.d.ts.map +1 -0
- package/dist/utils/secretFile.js +47 -0
- package/dist/utils/secretFile.js.map +1 -0
- package/dist/utils/stdio.d.ts +10 -0
- package/dist/utils/stdio.d.ts.map +1 -0
- package/dist/utils/stdio.js +70 -0
- package/dist/utils/stdio.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/dist/watchApi.d.ts +264 -0
- package/dist/watchApi.d.ts.map +1 -0
- package/dist/watchApi.js +333 -0
- package/dist/watchApi.js.map +1 -0
- package/package.json +77 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import { Command, InvalidArgumentError } from "commander";
|
|
2
|
+
import { authenticateGarmin, clearStoredSession, sessionExists } from "./garmin/auth.js";
|
|
3
|
+
import { closeCache, getCache } from "./garmin/cache.js";
|
|
4
|
+
import { resetGarminClient } from "./garmin/client.js";
|
|
5
|
+
import { createMcpServer } from "./server.js";
|
|
6
|
+
import { createHttpMcpServer, getRemoteConnectorInstructions } from "./httpServer.js";
|
|
7
|
+
import { assertGarminCredentials, appConfig, assertApiKey, deprecatedEnvNames } from "./config.js";
|
|
8
|
+
import { DATA_DIR_NAME, LEGACY_DATA_DIR_NAME, migrateLegacyDataDir } from "./paths.js";
|
|
9
|
+
import { configureLogger, logger } from "./utils/logger.js";
|
|
10
|
+
import { protectStdout } from "./utils/stdio.js";
|
|
11
|
+
import { packageVersion } from "./version.js";
|
|
12
|
+
import { runSetup } from "./setup.js";
|
|
13
|
+
import { withGarminClient } from "./garmin/client.js";
|
|
14
|
+
import { DEFAULT_SOURCES, runIngest } from "./history/ingest.js";
|
|
15
|
+
import { GarminApiError } from "./garmin/types.js";
|
|
16
|
+
import { startHistoryScheduler } from "./history/scheduler.js";
|
|
17
|
+
import { closeHistoryDb, historyStats, pruneRawPayloads, RAW_RETENTION_DAYS, RAW_REVISIONS_KEPT, } from "./history/store.js";
|
|
18
|
+
import { describeFindingsCoverage, runDetectors } from "./detect/index.js";
|
|
19
|
+
import { printLiveCheckResults, runLiveCheck } from "./check.js";
|
|
20
|
+
// SECTION: Bootstrap
|
|
21
|
+
//
|
|
22
|
+
// Runs before every command. Moves pre-0.3.0 state out of `.garmin/` and warns
|
|
23
|
+
// once about renamed environment variables, so an existing install keeps its
|
|
24
|
+
// session, cache and watch pairing across the rename.
|
|
25
|
+
/**
|
|
26
|
+
* A numeric option, or a clear refusal.
|
|
27
|
+
*
|
|
28
|
+
* Number.parseInt("abc") is NaN, and NaN flowed straight through: `--days abc`
|
|
29
|
+
* printed "Backfilling NaN days", every date arithmetic produced Invalid Date,
|
|
30
|
+
* and the run did nothing while reporting that it was working. `--delay-ms abc`
|
|
31
|
+
* was worse -- a NaN delay is not a pause, so the throttle between Garmin
|
|
32
|
+
* requests silently disappeared on the one command that makes hundreds of them.
|
|
33
|
+
*/
|
|
34
|
+
function positiveIntOption(name, min = 1) {
|
|
35
|
+
return (value) => {
|
|
36
|
+
const parsed = Number.parseInt(value, 10);
|
|
37
|
+
if (!Number.isFinite(parsed) || parsed < min) {
|
|
38
|
+
throw new InvalidArgumentError(`${name} must be a whole number of at least ${min}. Got "${value}".`);
|
|
39
|
+
}
|
|
40
|
+
return parsed;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Print a failure the way its cause deserves.
|
|
45
|
+
*
|
|
46
|
+
* A Garmin rate limit is an expected, actionable wait, and it was being reported
|
|
47
|
+
* with `logger.error` plus a full stack trace — so the screen filled with a
|
|
48
|
+
* kilobyte of Cloudflare JSON and a stack, and the one line that mattered ("wait
|
|
49
|
+
* N seconds") was buried in the middle of it. That reads as a crash, and the
|
|
50
|
+
* natural response to a crash is to run the command again, which is exactly the
|
|
51
|
+
* behaviour that extends the block.
|
|
52
|
+
*/
|
|
53
|
+
function reportCliFailure(error, fallback) {
|
|
54
|
+
const rateLimited = error instanceof GarminApiError && error.statusCode === 429 ? error : null;
|
|
55
|
+
if (rateLimited) {
|
|
56
|
+
logger.warn({ retryAfterSeconds: rateLimited.retryAfterSeconds }, fallback);
|
|
57
|
+
console.error("");
|
|
58
|
+
console.error(rateLimited.message);
|
|
59
|
+
console.error("Nothing was lost — every day already fetched is checkpointed.");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
logger.error({ error }, fallback);
|
|
63
|
+
console.error(error instanceof Error ? error.message : fallback);
|
|
64
|
+
}
|
|
65
|
+
function bootstrap() {
|
|
66
|
+
// stdio transport speaks MCP on stdout — never print there.
|
|
67
|
+
const notify = (message) => {
|
|
68
|
+
process.stderr.write(`${message}\n`);
|
|
69
|
+
};
|
|
70
|
+
try {
|
|
71
|
+
const result = migrateLegacyDataDir();
|
|
72
|
+
if (result.migrated) {
|
|
73
|
+
notify(`Migrated ${result.movedEntries?.length ?? 0} item(s) from ${LEGACY_DATA_DIR_NAME}/ to ${DATA_DIR_NAME}/.`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
notify(`Could not migrate ${LEGACY_DATA_DIR_NAME}/ to ${DATA_DIR_NAME}/: ${error instanceof Error ? error.message : String(error)}`);
|
|
78
|
+
notify(`Move the directory manually, or run "trainbud setup" to start fresh.`);
|
|
79
|
+
}
|
|
80
|
+
const deprecated = deprecatedEnvNames();
|
|
81
|
+
if (deprecated.length > 0) {
|
|
82
|
+
notify(`Deprecated environment variable(s) in use: ${deprecated.join(", ")}. ` +
|
|
83
|
+
`These still work but were renamed to TRAINBUD_*; run "trainbud setup" to rewrite .env.`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// SECTION: CLI Commands
|
|
87
|
+
async function runStart() {
|
|
88
|
+
assertGarminCredentials();
|
|
89
|
+
configureLogger(appConfig.logPath);
|
|
90
|
+
// Stdout is the MCP channel from here on, and a dependency's `console.log`
|
|
91
|
+
// lands on it. garmin-connect prints "login page title: ..." on every
|
|
92
|
+
// re-login, which puts two lines of English in the middle of a JSON-RPC
|
|
93
|
+
// stream and drops the client. See utils/stdio.ts.
|
|
94
|
+
protectStdout();
|
|
95
|
+
const server = createMcpServer();
|
|
96
|
+
const shutdown = async (signal) => {
|
|
97
|
+
logger.info({ signal }, "Shutting down TrainBud server");
|
|
98
|
+
await server.close();
|
|
99
|
+
closeCache();
|
|
100
|
+
process.exit(0);
|
|
101
|
+
};
|
|
102
|
+
process.once("SIGTERM", () => {
|
|
103
|
+
void shutdown("SIGTERM");
|
|
104
|
+
});
|
|
105
|
+
process.once("SIGINT", () => {
|
|
106
|
+
void shutdown("SIGINT");
|
|
107
|
+
});
|
|
108
|
+
process.once("exit", () => {
|
|
109
|
+
closeCache();
|
|
110
|
+
});
|
|
111
|
+
await server.start();
|
|
112
|
+
}
|
|
113
|
+
async function runAuth() {
|
|
114
|
+
configureLogger(appConfig.logPath);
|
|
115
|
+
clearStoredSession();
|
|
116
|
+
resetGarminClient();
|
|
117
|
+
await authenticateGarmin(true);
|
|
118
|
+
console.log("Garmin authentication successful. Session saved.");
|
|
119
|
+
}
|
|
120
|
+
function runCacheClear() {
|
|
121
|
+
const cache = getCache();
|
|
122
|
+
const removed = cache.clear();
|
|
123
|
+
console.log(`Cleared ${removed} cache entries.`);
|
|
124
|
+
}
|
|
125
|
+
async function runStatus() {
|
|
126
|
+
const cache = getCache();
|
|
127
|
+
const cacheStats = cache.stats();
|
|
128
|
+
console.log("TrainBud status");
|
|
129
|
+
console.log(`Session: ${sessionExists() ? "present" : "missing"}`);
|
|
130
|
+
console.log(`Cache entries: ${cacheStats.entries}`);
|
|
131
|
+
console.log(`Expired cache entries: ${cacheStats.expiredEntries}`);
|
|
132
|
+
const history = historyStats();
|
|
133
|
+
const span = history.oldestDate && history.newestDate
|
|
134
|
+
? `${history.oldestDate} to ${history.newestDate}`
|
|
135
|
+
: "empty — run `trainbud backfill`";
|
|
136
|
+
console.log(`History span: ${span}`);
|
|
137
|
+
console.log(`History measurements: ${history.metricRows}`);
|
|
138
|
+
console.log(`History raw payloads: ${history.rawRows}`);
|
|
139
|
+
console.log(`History activities: ${history.activityRows}`);
|
|
140
|
+
if (history.emptyDays > 0) {
|
|
141
|
+
// Almost always days before the watch was bought. Reported so a small span
|
|
142
|
+
// reads as "that is all Garmin has" rather than as a broken backfill.
|
|
143
|
+
console.log(`Days Garmin had no data for: ${history.emptyDays}`);
|
|
144
|
+
}
|
|
145
|
+
closeHistoryDb();
|
|
146
|
+
}
|
|
147
|
+
async function runPrune(retentionDays) {
|
|
148
|
+
const before = historyStats();
|
|
149
|
+
const result = pruneRawPayloads(undefined, retentionDays);
|
|
150
|
+
const after = historyStats();
|
|
151
|
+
console.log("TrainBud prune — raw payload archive only");
|
|
152
|
+
console.log(`Dropped for being older than ${retentionDays} days: ${result.agedOut}`);
|
|
153
|
+
console.log(`Dropped for being past revision ${RAW_REVISIONS_KEPT} of a day: ${result.supersededRevisions}`);
|
|
154
|
+
console.log(`Raw payloads: ${before.rawRows} → ${after.rawRows}`);
|
|
155
|
+
console.log(`Measurements and activities untouched: ${after.metricRows} measurements, ${after.activityRows} activities.`);
|
|
156
|
+
closeHistoryDb();
|
|
157
|
+
}
|
|
158
|
+
async function runFindings() {
|
|
159
|
+
const result = runDetectors();
|
|
160
|
+
if (!result.coverage.ready) {
|
|
161
|
+
// Shared with the MCP tool and the watch prompt. Written here once, this
|
|
162
|
+
// surface printed "74 of the 14 days needed" on a 74-day store for as long
|
|
163
|
+
// as the stale case existed.
|
|
164
|
+
const coverage = describeFindingsCoverage(result.coverage);
|
|
165
|
+
console.log(coverage.detail);
|
|
166
|
+
if (coverage.fix) {
|
|
167
|
+
console.log(coverage.fix);
|
|
168
|
+
}
|
|
169
|
+
closeHistoryDb();
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
console.log(`TrainBud findings — ${result.coverage.days} days of history`);
|
|
173
|
+
console.log("");
|
|
174
|
+
if (result.findings.length === 0) {
|
|
175
|
+
console.log("Nothing stands out against your own baselines.");
|
|
176
|
+
closeHistoryDb();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
for (const finding of result.findings) {
|
|
180
|
+
console.log(`[${finding.severity}] ${finding.headline}`);
|
|
181
|
+
console.log(` ${finding.detail}`);
|
|
182
|
+
console.log("");
|
|
183
|
+
}
|
|
184
|
+
console.log("General training guidance only. Not medical advice.");
|
|
185
|
+
closeHistoryDb();
|
|
186
|
+
}
|
|
187
|
+
async function runBackfill(options) {
|
|
188
|
+
assertGarminCredentials();
|
|
189
|
+
const sources = options.source?.length
|
|
190
|
+
? options.source.map((name) => {
|
|
191
|
+
if (!DEFAULT_SOURCES.includes(name)) {
|
|
192
|
+
throw new Error(`Unknown source "${name}". Choose from: ${DEFAULT_SOURCES.join(", ")}`);
|
|
193
|
+
}
|
|
194
|
+
return name;
|
|
195
|
+
})
|
|
196
|
+
: DEFAULT_SOURCES;
|
|
197
|
+
const days = options.days ?? 365;
|
|
198
|
+
const delayMs = options.delayMs ?? 1000;
|
|
199
|
+
console.log(`Backfilling ${days} days from ${sources.length} sources, ${delayMs}ms apart.`);
|
|
200
|
+
console.log("Safe to interrupt — every day is checkpointed and the next run resumes.");
|
|
201
|
+
if (options.capture) {
|
|
202
|
+
console.log(`Capturing redacted responses to ${options.capture} — read them before committing.`);
|
|
203
|
+
}
|
|
204
|
+
console.log("");
|
|
205
|
+
const result = await withGarminClient(async (client) => runIngest(client, {
|
|
206
|
+
days,
|
|
207
|
+
delayMs,
|
|
208
|
+
sources,
|
|
209
|
+
captureDir: options.capture,
|
|
210
|
+
stopAfterEmptyDays: options.earlyStop === false ? 0 : undefined,
|
|
211
|
+
onProgress: (progress) => {
|
|
212
|
+
// One line per day so an hour-long run is legible and a stall is
|
|
213
|
+
// obvious. This is the only feedback the user gets while it walks a
|
|
214
|
+
// year.
|
|
215
|
+
console.log(`[${progress.done}/${progress.total}] ${progress.source} ${progress.date} — ${progress.outcome}`);
|
|
216
|
+
},
|
|
217
|
+
}));
|
|
218
|
+
console.log("");
|
|
219
|
+
console.log(`Done. ${result.fetched} fetched, ${result.errors} failed, ${result.skipped} skipped.`);
|
|
220
|
+
if (result.stoppedBy === "rate_limit") {
|
|
221
|
+
console.log("");
|
|
222
|
+
console.log("Garmin rate limited this run, so it stopped rather than making");
|
|
223
|
+
console.log("hundreds more requests that could not have succeeded. Wait a few");
|
|
224
|
+
console.log("minutes and run it again — every day already fetched is checkpointed.");
|
|
225
|
+
}
|
|
226
|
+
else if (result.errors > 0) {
|
|
227
|
+
console.log("Failed days are retried automatically on the next run.");
|
|
228
|
+
}
|
|
229
|
+
closeHistoryDb();
|
|
230
|
+
}
|
|
231
|
+
async function runCheck() {
|
|
232
|
+
const results = await runLiveCheck();
|
|
233
|
+
printLiveCheckResults(results);
|
|
234
|
+
if (results.some((result) => !result.ok)) {
|
|
235
|
+
process.exitCode = 1;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async function runServe() {
|
|
239
|
+
assertGarminCredentials();
|
|
240
|
+
assertApiKey();
|
|
241
|
+
const server = createHttpMcpServer();
|
|
242
|
+
// Catch up on start, then hourly while this process lives. Garmin retains
|
|
243
|
+
// the history, so a machine that was off overnight loses nothing -- the gap
|
|
244
|
+
// is simply the next run's work.
|
|
245
|
+
let stopHistory = null;
|
|
246
|
+
const shutdown = async (signal) => {
|
|
247
|
+
logger.info({ signal }, "Shutting down TrainBud HTTP server");
|
|
248
|
+
stopHistory?.();
|
|
249
|
+
closeHistoryDb();
|
|
250
|
+
await server.close();
|
|
251
|
+
process.exit(0);
|
|
252
|
+
};
|
|
253
|
+
process.once("SIGTERM", () => {
|
|
254
|
+
void shutdown("SIGTERM");
|
|
255
|
+
});
|
|
256
|
+
process.once("SIGINT", () => {
|
|
257
|
+
void shutdown("SIGINT");
|
|
258
|
+
});
|
|
259
|
+
await server.start();
|
|
260
|
+
stopHistory = startHistoryScheduler();
|
|
261
|
+
console.log(`TrainBud HTTP MCP server running at http://${appConfig.mcpHost}:${appConfig.mcpPort}/mcp`);
|
|
262
|
+
console.log(`Health check: http://${appConfig.mcpHost}:${appConfig.mcpPort}/health`);
|
|
263
|
+
console.log("");
|
|
264
|
+
console.log(getRemoteConnectorInstructions(`https://your-tunnel-url.example.com`));
|
|
265
|
+
}
|
|
266
|
+
export function createCliProgram() {
|
|
267
|
+
const program = new Command();
|
|
268
|
+
program.hook("preAction", () => {
|
|
269
|
+
bootstrap();
|
|
270
|
+
});
|
|
271
|
+
program
|
|
272
|
+
.name("trainbud")
|
|
273
|
+
.description("TrainBud — MCP server for Garmin Connect fitness data")
|
|
274
|
+
.version(packageVersion);
|
|
275
|
+
program
|
|
276
|
+
.command("start")
|
|
277
|
+
.description("Start the MCP server using stdio transport")
|
|
278
|
+
.action(async () => {
|
|
279
|
+
try {
|
|
280
|
+
await runStart();
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
logger.error({ error }, "Failed to start MCP server");
|
|
284
|
+
process.exitCode = 1;
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
program
|
|
288
|
+
.command("auth")
|
|
289
|
+
.description("Force Garmin re-authentication")
|
|
290
|
+
.action(async () => {
|
|
291
|
+
try {
|
|
292
|
+
await runAuth();
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
logger.error({ error }, "Garmin authentication failed");
|
|
296
|
+
console.error(error instanceof Error ? error.message : "Authentication failed");
|
|
297
|
+
process.exitCode = 1;
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
const cacheCommand = program.command("cache").description("Manage local cache");
|
|
301
|
+
cacheCommand
|
|
302
|
+
.command("clear")
|
|
303
|
+
.description("Clear all cached Garmin data")
|
|
304
|
+
.action(() => {
|
|
305
|
+
try {
|
|
306
|
+
runCacheClear();
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
logger.error({ error }, "Failed to clear cache");
|
|
310
|
+
process.exitCode = 1;
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
program
|
|
314
|
+
.command("serve")
|
|
315
|
+
.description("Start remote MCP server (Streamable HTTP) for web AI connectors")
|
|
316
|
+
.option("-p, --port <number>", "HTTP port", positiveIntOption("--port"))
|
|
317
|
+
.option("-H, --host <host>", "Bind host")
|
|
318
|
+
.action(async (options) => {
|
|
319
|
+
try {
|
|
320
|
+
if (options.port) {
|
|
321
|
+
process.env.TRAINBUD_PORT = String(options.port);
|
|
322
|
+
}
|
|
323
|
+
if (options.host) {
|
|
324
|
+
process.env.TRAINBUD_HOST = options.host;
|
|
325
|
+
}
|
|
326
|
+
await runServe();
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
logger.error({ error }, "Failed to start HTTP MCP server");
|
|
330
|
+
console.error(error instanceof Error ? error.message : "Failed to start HTTP MCP server");
|
|
331
|
+
process.exitCode = 1;
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
program
|
|
335
|
+
.command("backfill")
|
|
336
|
+
.description("Fetch Garmin history into the local store — resumable, safe to interrupt")
|
|
337
|
+
.option("-d, --days <number>", "How many days back to fetch", positiveIntOption("--days"))
|
|
338
|
+
.option("--delay-ms <number>", "Delay between requests", positiveIntOption("--delay-ms", 0))
|
|
339
|
+
.option("-s, --source <name>", "Limit to one source (repeatable)", (value, previous = []) => [...previous, value])
|
|
340
|
+
.option("--capture <dir>", "Also write each redacted response there, as a test fixture")
|
|
341
|
+
.option("--no-early-stop", "Keep asking past a long run of empty days instead of assuming the record has run out")
|
|
342
|
+
.action(async (options) => {
|
|
343
|
+
try {
|
|
344
|
+
await runBackfill(options);
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
reportCliFailure(error, "Backfill failed");
|
|
348
|
+
process.exitCode = 1;
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
program
|
|
352
|
+
.command("findings")
|
|
353
|
+
.description("Show what stands out in your history, against your own baselines")
|
|
354
|
+
.action(async () => {
|
|
355
|
+
try {
|
|
356
|
+
await runFindings();
|
|
357
|
+
}
|
|
358
|
+
catch (error) {
|
|
359
|
+
logger.error({ error }, "Failed to compute findings");
|
|
360
|
+
console.error(error instanceof Error ? error.message : "Failed to compute findings");
|
|
361
|
+
process.exitCode = 1;
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
program
|
|
365
|
+
.command("setup")
|
|
366
|
+
.description("Interactive first-time setup — credentials, auth, and MCP client config")
|
|
367
|
+
.action(async () => {
|
|
368
|
+
try {
|
|
369
|
+
await runSetup();
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
logger.error({ error }, "Setup failed");
|
|
373
|
+
console.error(error instanceof Error ? error.message : "Setup failed");
|
|
374
|
+
process.exitCode = 1;
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
program
|
|
378
|
+
.command("check")
|
|
379
|
+
.description("Run live diagnostics against all TrainBud tools")
|
|
380
|
+
.action(async () => {
|
|
381
|
+
try {
|
|
382
|
+
await runCheck();
|
|
383
|
+
}
|
|
384
|
+
catch (error) {
|
|
385
|
+
reportCliFailure(error, "Live check failed");
|
|
386
|
+
process.exitCode = 1;
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
// Separate from `check`, which exercises the Garmin tools. This asks the one
|
|
390
|
+
// question `check` cannot: what would the watch see if it called right now.
|
|
391
|
+
// The -400 report took days partly because every diagnostic ran on this
|
|
392
|
+
// machine, where everything was genuinely healthy; the broken hop was the one
|
|
393
|
+
// nothing looked at from the outside.
|
|
394
|
+
program
|
|
395
|
+
.command("doctor")
|
|
396
|
+
.description("Check what the watch would see: public URL, AI key, history depth")
|
|
397
|
+
.action(async () => {
|
|
398
|
+
try {
|
|
399
|
+
const { runSelfTest } = await import("./selfTest.js");
|
|
400
|
+
const result = await runSelfTest();
|
|
401
|
+
console.log("");
|
|
402
|
+
console.log("TrainBud doctor");
|
|
403
|
+
console.log("");
|
|
404
|
+
for (const check of result.checks) {
|
|
405
|
+
const mark = check.ok ? "✓" : check.warning ? "!" : "✗";
|
|
406
|
+
console.log(` ${mark} ${check.name}`);
|
|
407
|
+
console.log(` ${check.detail}`);
|
|
408
|
+
if (check.fix) {
|
|
409
|
+
console.log(` → ${check.fix}`);
|
|
410
|
+
}
|
|
411
|
+
console.log("");
|
|
412
|
+
}
|
|
413
|
+
if (!result.ok) {
|
|
414
|
+
process.exitCode = 1;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
catch (error) {
|
|
418
|
+
logger.error({ error }, "Doctor failed");
|
|
419
|
+
console.error(error instanceof Error ? error.message : "Doctor failed");
|
|
420
|
+
process.exitCode = 1;
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
program
|
|
424
|
+
.command("prune")
|
|
425
|
+
.description("Bound the raw payload archive. Never touches measurements or activities.")
|
|
426
|
+
.option("--days <number>", `Drop raw payloads older than this many days (default ${RAW_RETENTION_DAYS})`, String(RAW_RETENTION_DAYS))
|
|
427
|
+
.action(async (options) => {
|
|
428
|
+
try {
|
|
429
|
+
const days = Number(options.days);
|
|
430
|
+
if (!Number.isFinite(days) || days < 1) {
|
|
431
|
+
console.error(`--days must be a positive number, got "${options.days}".`);
|
|
432
|
+
process.exitCode = 1;
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
await runPrune(Math.floor(days));
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
logger.error({ error }, "Prune failed");
|
|
439
|
+
console.error(error instanceof Error ? error.message : "Prune failed");
|
|
440
|
+
process.exitCode = 1;
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
program
|
|
444
|
+
.command("status")
|
|
445
|
+
.description("Show session and cache status")
|
|
446
|
+
.action(async () => {
|
|
447
|
+
try {
|
|
448
|
+
await runStatus();
|
|
449
|
+
}
|
|
450
|
+
catch (error) {
|
|
451
|
+
logger.error({ error }, "Failed to read status");
|
|
452
|
+
process.exitCode = 1;
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
return program;
|
|
456
|
+
}
|
|
457
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { getProjectRoot } from "./paths.js";
|
|
2
|
+
/** Legacy env var names still present in the environment, for a one-time warning. */
|
|
3
|
+
export declare function deprecatedEnvNames(): string[];
|
|
4
|
+
export declare function getSessionPath(): string;
|
|
5
|
+
export { getProjectRoot };
|
|
6
|
+
export declare function getEnvFilePath(): string;
|
|
7
|
+
export declare function getDistIndexPath(): string;
|
|
8
|
+
export declare function generateApiKey(): string;
|
|
9
|
+
/**
|
|
10
|
+
* Quote a value so dotenv reads back exactly what was written.
|
|
11
|
+
*
|
|
12
|
+
* Values were written bare, and dotenv treats an unquoted `#` as the start of a
|
|
13
|
+
* comment: a Garmin password containing one was silently truncated at that
|
|
14
|
+
* character, so setup "succeeded" and every login afterwards failed with bad
|
|
15
|
+
* credentials the user could see were correct. Measured, not assumed --
|
|
16
|
+
* `P=pa#ss` parses back as `pa`.
|
|
17
|
+
*
|
|
18
|
+
* Single quotes are preferred: dotenv does no unescaping inside them, so `#`,
|
|
19
|
+
* `"`, `$`, spaces and backslashes all survive verbatim. Double quotes are the
|
|
20
|
+
* fallback for a value containing a single quote. A value containing both
|
|
21
|
+
* cannot be represented -- dotenv has no escape that works inside either kind --
|
|
22
|
+
* so that is an error rather than a silent corruption.
|
|
23
|
+
*/
|
|
24
|
+
export declare function quoteEnvValue(value: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Every assignment in an existing .env that this file does not manage.
|
|
27
|
+
*
|
|
28
|
+
* writeEnvFile rebuilt the file from a fixed template, so re-running
|
|
29
|
+
* `trainbud setup` deleted ANTHROPIC_API_KEY and TRAINBUD_PUBLIC_URL outright --
|
|
30
|
+
* a user who had followed the AI setup guide lost their key by running the
|
|
31
|
+
* command the guide tells them to run when something is wrong.
|
|
32
|
+
*/
|
|
33
|
+
export declare function carriedEnvLines(existing: string): string[];
|
|
34
|
+
export declare function writeEnvFile(credentials: {
|
|
35
|
+
email: string;
|
|
36
|
+
password: string;
|
|
37
|
+
apiKey?: string;
|
|
38
|
+
}): string;
|
|
39
|
+
export declare const appConfig: {
|
|
40
|
+
readonly garminEmail: string;
|
|
41
|
+
readonly garminPassword: string;
|
|
42
|
+
readonly sessionPath: string;
|
|
43
|
+
readonly logPath: string;
|
|
44
|
+
readonly cachePath: string;
|
|
45
|
+
readonly cacheTtlActivities: number;
|
|
46
|
+
readonly cacheTtlSleep: number;
|
|
47
|
+
readonly cacheTtlStats: number;
|
|
48
|
+
readonly mcpHost: string;
|
|
49
|
+
readonly mcpPort: number;
|
|
50
|
+
readonly mcpApiKey: string;
|
|
51
|
+
readonly anthropicApiKey: string;
|
|
52
|
+
readonly publicUrl: string;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Why the watch setup file could not be read, when it exists but is unusable.
|
|
56
|
+
* `null` when it parsed, or when there is simply no file.
|
|
57
|
+
*/
|
|
58
|
+
export declare function watchSetupReadError(): string | null;
|
|
59
|
+
export declare function assertApiKey(): void;
|
|
60
|
+
export declare function assertGarminCredentials(): void;
|
|
61
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,cAAc,EAGf,MAAM,YAAY,CAAC;AAmCpB,qFAAqF;AACrF,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAI7C;AAWD,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUnD;AA0BD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAW1D;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAwCtG;AAID,eAAO,MAAM,SAAS;0BACD,MAAM;6BAGH,MAAM;0BAGT,MAAM;sBAGV,MAAM;wBAGJ,MAAM;iCAGG,MAAM;4BAGX,MAAM;4BAGN,MAAM;sBAGZ,MAAM;sBAGN,MAAM;wBAGJ,MAAM;8BAGA,MAAM;wBAGZ,MAAM;CAkBxB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,IAAI,CAEnD;AAED,wBAAgB,YAAY,IAAI,IAAI,CAMnC;AAED,wBAAgB,uBAAuB,IAAI,IAAI,CAM9C"}
|