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.
Files changed (274) hide show
  1. package/.env.example +11 -0
  2. package/CHANGELOG.md +675 -0
  3. package/LICENSE +21 -0
  4. package/QUICKSTART.md +182 -0
  5. package/README.md +322 -0
  6. package/dist/appDb.d.ts +83 -0
  7. package/dist/appDb.d.ts.map +1 -0
  8. package/dist/appDb.js +239 -0
  9. package/dist/appDb.js.map +1 -0
  10. package/dist/check.d.ts +12 -0
  11. package/dist/check.d.ts.map +1 -0
  12. package/dist/check.js +230 -0
  13. package/dist/check.js.map +1 -0
  14. package/dist/cli.d.ts +3 -0
  15. package/dist/cli.d.ts.map +1 -0
  16. package/dist/cli.js +457 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/config.d.ts +61 -0
  19. package/dist/config.d.ts.map +1 -0
  20. package/dist/config.js +241 -0
  21. package/dist/config.js.map +1 -0
  22. package/dist/dashboard.d.ts +8 -0
  23. package/dist/dashboard.d.ts.map +1 -0
  24. package/dist/dashboard.js +1004 -0
  25. package/dist/dashboard.js.map +1 -0
  26. package/dist/dashboardCharts.d.ts +99 -0
  27. package/dist/dashboardCharts.d.ts.map +1 -0
  28. package/dist/dashboardCharts.js +317 -0
  29. package/dist/dashboardCharts.js.map +1 -0
  30. package/dist/dashboardData.d.ts +89 -0
  31. package/dist/dashboardData.d.ts.map +1 -0
  32. package/dist/dashboardData.js +228 -0
  33. package/dist/dashboardData.js.map +1 -0
  34. package/dist/detect/baseline.d.ts +17 -0
  35. package/dist/detect/baseline.d.ts.map +1 -0
  36. package/dist/detect/baseline.js +62 -0
  37. package/dist/detect/baseline.js.map +1 -0
  38. package/dist/detect/countdown.d.ts +30 -0
  39. package/dist/detect/countdown.d.ts.map +1 -0
  40. package/dist/detect/countdown.js +79 -0
  41. package/dist/detect/countdown.js.map +1 -0
  42. package/dist/detect/detectors.d.ts +20 -0
  43. package/dist/detect/detectors.d.ts.map +1 -0
  44. package/dist/detect/detectors.js +291 -0
  45. package/dist/detect/detectors.js.map +1 -0
  46. package/dist/detect/findings.d.ts +29 -0
  47. package/dist/detect/findings.d.ts.map +1 -0
  48. package/dist/detect/findings.js +2 -0
  49. package/dist/detect/findings.js.map +1 -0
  50. package/dist/detect/forecast.d.ts +33 -0
  51. package/dist/detect/forecast.d.ts.map +1 -0
  52. package/dist/detect/forecast.js +122 -0
  53. package/dist/detect/forecast.js.map +1 -0
  54. package/dist/detect/index.d.ts +50 -0
  55. package/dist/detect/index.d.ts.map +1 -0
  56. package/dist/detect/index.js +114 -0
  57. package/dist/detect/index.js.map +1 -0
  58. package/dist/detect/sleepQuality.d.ts +21 -0
  59. package/dist/detect/sleepQuality.d.ts.map +1 -0
  60. package/dist/detect/sleepQuality.js +164 -0
  61. package/dist/detect/sleepQuality.js.map +1 -0
  62. package/dist/detect/trimp.d.ts +22 -0
  63. package/dist/detect/trimp.d.ts.map +1 -0
  64. package/dist/detect/trimp.js +77 -0
  65. package/dist/detect/trimp.js.map +1 -0
  66. package/dist/detect/week.d.ts +31 -0
  67. package/dist/detect/week.d.ts.map +1 -0
  68. package/dist/detect/week.js +184 -0
  69. package/dist/detect/week.js.map +1 -0
  70. package/dist/garmin/auth.d.ts +10 -0
  71. package/dist/garmin/auth.d.ts.map +1 -0
  72. package/dist/garmin/auth.js +81 -0
  73. package/dist/garmin/auth.js.map +1 -0
  74. package/dist/garmin/cache.d.ts +42 -0
  75. package/dist/garmin/cache.d.ts.map +1 -0
  76. package/dist/garmin/cache.js +141 -0
  77. package/dist/garmin/cache.js.map +1 -0
  78. package/dist/garmin/client.d.ts +22 -0
  79. package/dist/garmin/client.d.ts.map +1 -0
  80. package/dist/garmin/client.js +237 -0
  81. package/dist/garmin/client.js.map +1 -0
  82. package/dist/garmin/daily.d.ts +24 -0
  83. package/dist/garmin/daily.d.ts.map +1 -0
  84. package/dist/garmin/daily.js +96 -0
  85. package/dist/garmin/daily.js.map +1 -0
  86. package/dist/garmin/garminApiTypes.d.ts +70 -0
  87. package/dist/garmin/garminApiTypes.d.ts.map +1 -0
  88. package/dist/garmin/garminApiTypes.js +3 -0
  89. package/dist/garmin/garminApiTypes.js.map +1 -0
  90. package/dist/garmin/garminConnect.d.ts +17 -0
  91. package/dist/garmin/garminConnect.d.ts.map +1 -0
  92. package/dist/garmin/garminConnect.js +5 -0
  93. package/dist/garmin/garminConnect.js.map +1 -0
  94. package/dist/garmin/partial.d.ts +32 -0
  95. package/dist/garmin/partial.d.ts.map +1 -0
  96. package/dist/garmin/partial.js +38 -0
  97. package/dist/garmin/partial.js.map +1 -0
  98. package/dist/garmin/rawApi.d.ts +59 -0
  99. package/dist/garmin/rawApi.d.ts.map +1 -0
  100. package/dist/garmin/rawApi.js +113 -0
  101. package/dist/garmin/rawApi.js.map +1 -0
  102. package/dist/garmin/types.d.ts +85 -0
  103. package/dist/garmin/types.d.ts.map +1 -0
  104. package/dist/garmin/types.js +11 -0
  105. package/dist/garmin/types.js.map +1 -0
  106. package/dist/history/capture.d.ts +12 -0
  107. package/dist/history/capture.d.ts.map +1 -0
  108. package/dist/history/capture.js +63 -0
  109. package/dist/history/capture.js.map +1 -0
  110. package/dist/history/context.d.ts +51 -0
  111. package/dist/history/context.d.ts.map +1 -0
  112. package/dist/history/context.js +122 -0
  113. package/dist/history/context.js.map +1 -0
  114. package/dist/history/fallback.d.ts +72 -0
  115. package/dist/history/fallback.d.ts.map +1 -0
  116. package/dist/history/fallback.js +185 -0
  117. package/dist/history/fallback.js.map +1 -0
  118. package/dist/history/ingest.d.ts +44 -0
  119. package/dist/history/ingest.d.ts.map +1 -0
  120. package/dist/history/ingest.js +347 -0
  121. package/dist/history/ingest.js.map +1 -0
  122. package/dist/history/scheduler.d.ts +20 -0
  123. package/dist/history/scheduler.d.ts.map +1 -0
  124. package/dist/history/scheduler.js +54 -0
  125. package/dist/history/scheduler.js.map +1 -0
  126. package/dist/history/schema.d.ts +41 -0
  127. package/dist/history/schema.d.ts.map +1 -0
  128. package/dist/history/schema.js +91 -0
  129. package/dist/history/schema.js.map +1 -0
  130. package/dist/history/store.d.ts +112 -0
  131. package/dist/history/store.d.ts.map +1 -0
  132. package/dist/history/store.js +282 -0
  133. package/dist/history/store.js.map +1 -0
  134. package/dist/httpServer.d.ts +55 -0
  135. package/dist/httpServer.d.ts.map +1 -0
  136. package/dist/httpServer.js +1027 -0
  137. package/dist/httpServer.js.map +1 -0
  138. package/dist/index.d.ts +3 -0
  139. package/dist/index.d.ts.map +1 -0
  140. package/dist/index.js +11 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/mcpConfig.d.ts +56 -0
  143. package/dist/mcpConfig.d.ts.map +1 -0
  144. package/dist/mcpConfig.js +106 -0
  145. package/dist/mcpConfig.js.map +1 -0
  146. package/dist/pairApi.d.ts +14 -0
  147. package/dist/pairApi.d.ts.map +1 -0
  148. package/dist/pairApi.js +38 -0
  149. package/dist/pairApi.js.map +1 -0
  150. package/dist/paths.d.ts +45 -0
  151. package/dist/paths.d.ts.map +1 -0
  152. package/dist/paths.js +105 -0
  153. package/dist/paths.js.map +1 -0
  154. package/dist/profile.d.ts +123 -0
  155. package/dist/profile.d.ts.map +1 -0
  156. package/dist/profile.js +327 -0
  157. package/dist/profile.js.map +1 -0
  158. package/dist/promptApi.d.ts +43 -0
  159. package/dist/promptApi.d.ts.map +1 -0
  160. package/dist/promptApi.js +328 -0
  161. package/dist/promptApi.js.map +1 -0
  162. package/dist/promptSuggestions.d.ts +16 -0
  163. package/dist/promptSuggestions.d.ts.map +1 -0
  164. package/dist/promptSuggestions.js +141 -0
  165. package/dist/promptSuggestions.js.map +1 -0
  166. package/dist/selfTest.d.ts +53 -0
  167. package/dist/selfTest.d.ts.map +1 -0
  168. package/dist/selfTest.js +225 -0
  169. package/dist/selfTest.js.map +1 -0
  170. package/dist/server.d.ts +10 -0
  171. package/dist/server.d.ts.map +1 -0
  172. package/dist/server.js +67 -0
  173. package/dist/server.js.map +1 -0
  174. package/dist/setup.d.ts +2 -0
  175. package/dist/setup.d.ts.map +1 -0
  176. package/dist/setup.js +210 -0
  177. package/dist/setup.js.map +1 -0
  178. package/dist/toolErrors.d.ts +2 -0
  179. package/dist/toolErrors.d.ts.map +1 -0
  180. package/dist/toolErrors.js +18 -0
  181. package/dist/toolErrors.js.map +1 -0
  182. package/dist/tools/activities.d.ts +18 -0
  183. package/dist/tools/activities.d.ts.map +1 -0
  184. package/dist/tools/activities.js +182 -0
  185. package/dist/tools/activities.js.map +1 -0
  186. package/dist/tools/bodyComposition.d.ts +10 -0
  187. package/dist/tools/bodyComposition.d.ts.map +1 -0
  188. package/dist/tools/bodyComposition.js +139 -0
  189. package/dist/tools/bodyComposition.js.map +1 -0
  190. package/dist/tools/context.d.ts +8 -0
  191. package/dist/tools/context.d.ts.map +1 -0
  192. package/dist/tools/context.js +148 -0
  193. package/dist/tools/context.js.map +1 -0
  194. package/dist/tools/findings.d.ts +7 -0
  195. package/dist/tools/findings.d.ts.map +1 -0
  196. package/dist/tools/findings.js +51 -0
  197. package/dist/tools/findings.js.map +1 -0
  198. package/dist/tools/heartRate.d.ts +10 -0
  199. package/dist/tools/heartRate.d.ts.map +1 -0
  200. package/dist/tools/heartRate.js +105 -0
  201. package/dist/tools/heartRate.js.map +1 -0
  202. package/dist/tools/index.d.ts +66 -0
  203. package/dist/tools/index.d.ts.map +1 -0
  204. package/dist/tools/index.js +101 -0
  205. package/dist/tools/index.js.map +1 -0
  206. package/dist/tools/payloads.d.ts +148 -0
  207. package/dist/tools/payloads.d.ts.map +1 -0
  208. package/dist/tools/payloads.js +2 -0
  209. package/dist/tools/payloads.js.map +1 -0
  210. package/dist/tools/recovery.d.ts +31 -0
  211. package/dist/tools/recovery.d.ts.map +1 -0
  212. package/dist/tools/recovery.js +350 -0
  213. package/dist/tools/recovery.js.map +1 -0
  214. package/dist/tools/sleep.d.ts +10 -0
  215. package/dist/tools/sleep.d.ts.map +1 -0
  216. package/dist/tools/sleep.js +124 -0
  217. package/dist/tools/sleep.js.map +1 -0
  218. package/dist/tools/stress.d.ts +11 -0
  219. package/dist/tools/stress.d.ts.map +1 -0
  220. package/dist/tools/stress.js +108 -0
  221. package/dist/tools/stress.js.map +1 -0
  222. package/dist/tools/trainingInsights.d.ts +15 -0
  223. package/dist/tools/trainingInsights.d.ts.map +1 -0
  224. package/dist/tools/trainingInsights.js +79 -0
  225. package/dist/tools/trainingInsights.js.map +1 -0
  226. package/dist/tools/types.d.ts +12 -0
  227. package/dist/tools/types.d.ts.map +1 -0
  228. package/dist/tools/types.js +2 -0
  229. package/dist/tools/types.js.map +1 -0
  230. package/dist/tools/vo2Max.d.ts +11 -0
  231. package/dist/tools/vo2Max.d.ts.map +1 -0
  232. package/dist/tools/vo2Max.js +110 -0
  233. package/dist/tools/vo2Max.js.map +1 -0
  234. package/dist/tools/week.d.ts +12 -0
  235. package/dist/tools/week.d.ts.map +1 -0
  236. package/dist/tools/week.js +74 -0
  237. package/dist/tools/week.js.map +1 -0
  238. package/dist/usage.d.ts +104 -0
  239. package/dist/usage.d.ts.map +1 -0
  240. package/dist/usage.js +247 -0
  241. package/dist/usage.js.map +1 -0
  242. package/dist/utils/batch.d.ts +2 -0
  243. package/dist/utils/batch.d.ts.map +1 -0
  244. package/dist/utils/batch.js +18 -0
  245. package/dist/utils/batch.js.map +1 -0
  246. package/dist/utils/helpers.d.ts +32 -0
  247. package/dist/utils/helpers.d.ts.map +1 -0
  248. package/dist/utils/helpers.js +188 -0
  249. package/dist/utils/helpers.js.map +1 -0
  250. package/dist/utils/jsonFile.d.ts +19 -0
  251. package/dist/utils/jsonFile.d.ts.map +1 -0
  252. package/dist/utils/jsonFile.js +24 -0
  253. package/dist/utils/jsonFile.js.map +1 -0
  254. package/dist/utils/logger.d.ts +4 -0
  255. package/dist/utils/logger.d.ts.map +1 -0
  256. package/dist/utils/logger.js +97 -0
  257. package/dist/utils/logger.js.map +1 -0
  258. package/dist/utils/secretFile.d.ts +15 -0
  259. package/dist/utils/secretFile.d.ts.map +1 -0
  260. package/dist/utils/secretFile.js +47 -0
  261. package/dist/utils/secretFile.js.map +1 -0
  262. package/dist/utils/stdio.d.ts +10 -0
  263. package/dist/utils/stdio.d.ts.map +1 -0
  264. package/dist/utils/stdio.js +70 -0
  265. package/dist/utils/stdio.js.map +1 -0
  266. package/dist/version.d.ts +2 -0
  267. package/dist/version.d.ts.map +1 -0
  268. package/dist/version.js +7 -0
  269. package/dist/version.js.map +1 -0
  270. package/dist/watchApi.d.ts +264 -0
  271. package/dist/watchApi.d.ts.map +1 -0
  272. package/dist/watchApi.js +333 -0
  273. package/dist/watchApi.js.map +1 -0
  274. package/package.json +77 -0
package/dist/appDb.js ADDED
@@ -0,0 +1,239 @@
1
+ import Database from "better-sqlite3";
2
+ import { randomInt } from "node:crypto";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { appConfig } from "./config.js";
6
+ import { restrictExistingFile } from "./utils/secretFile.js";
7
+ // SECTION: App DB — settings, pair tokens, prompt jobs
8
+ const DB_PATH = path.resolve(path.dirname(appConfig.cachePath), "app.db");
9
+ let _db = null;
10
+ export const APP_DB_SCHEMA = `
11
+ CREATE TABLE IF NOT EXISTS settings (
12
+ key TEXT PRIMARY KEY,
13
+ value TEXT NOT NULL
14
+ );
15
+ CREATE TABLE IF NOT EXISTS pair_tokens (
16
+ code TEXT PRIMARY KEY,
17
+ created_at INTEGER NOT NULL,
18
+ expires_at INTEGER NOT NULL,
19
+ approved_at INTEGER
20
+ );
21
+ CREATE TABLE IF NOT EXISTS prompt_jobs (
22
+ id TEXT PRIMARY KEY,
23
+ prompt TEXT NOT NULL,
24
+ status TEXT NOT NULL DEFAULT 'pending',
25
+ result TEXT,
26
+ error TEXT,
27
+ created_at INTEGER NOT NULL,
28
+ completed_at INTEGER
29
+ );
30
+
31
+ -- Usage. cost_usd is nullable ON PURPOSE: a model this build has no
32
+ -- published price for records its tokens and leaves the cost unknown,
33
+ -- because a call priced at zero is a monthly cap that can never trip.
34
+ -- The schema lives here rather than in usage.ts so that opening the
35
+ -- database does not have to import the module that writes to it.
36
+ CREATE TABLE IF NOT EXISTS ai_usage (
37
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
38
+ at INTEGER NOT NULL,
39
+ kind TEXT NOT NULL,
40
+ model TEXT NOT NULL,
41
+ source TEXT NOT NULL,
42
+ input_tokens INTEGER NOT NULL,
43
+ output_tokens INTEGER NOT NULL,
44
+ cache_read_tokens INTEGER NOT NULL DEFAULT 0,
45
+ cache_write_tokens INTEGER NOT NULL DEFAULT 0,
46
+ cost_usd REAL
47
+ );
48
+ CREATE INDEX IF NOT EXISTS ai_usage_at ON ai_usage(at);
49
+
50
+ CREATE TABLE IF NOT EXISTS feature_usage (
51
+ name TEXT NOT NULL,
52
+ day TEXT NOT NULL,
53
+ count INTEGER NOT NULL,
54
+ PRIMARY KEY (name, day)
55
+ );
56
+ `;
57
+ function getDb() {
58
+ if (_db)
59
+ return _db;
60
+ fs.mkdirSync(path.dirname(DB_PATH), { recursive: true });
61
+ _db = new Database(DB_PATH);
62
+ // This database holds the Anthropic API key the dashboard saves, in the clear.
63
+ // better-sqlite3 creates the file, so it never went through writeSecretFile
64
+ // and landed 0644 like any other SQLite file -- readable by every account on
65
+ // the machine, while .env and session.json next to it are 0600.
66
+ restrictExistingFile(DB_PATH);
67
+ _db.exec(APP_DB_SCHEMA);
68
+ // Reconciling used to happen here, which meant every process that opened this
69
+ // file reclaimed every other process's in-flight work. See
70
+ // reconcileStalePromptJobs.
71
+ prunePromptJobs(_db);
72
+ return _db;
73
+ }
74
+ /**
75
+ * The open handle, for modules that own their own tables.
76
+ *
77
+ * `usage.ts` needs to read and write two tables of its own; routing that
78
+ * through a per-statement wrapper here would put its SQL in a file that has
79
+ * nothing to do with metering. The connection stays owned in one place -- this
80
+ * hands out the handle, not a second one.
81
+ */
82
+ export function getAppDb() {
83
+ return getDb();
84
+ }
85
+ // Settings
86
+ export function getSetting(key) {
87
+ const row = getDb().prepare("SELECT value FROM settings WHERE key = ?").get(key);
88
+ return row?.value ?? null;
89
+ }
90
+ export function setSetting(key, value) {
91
+ getDb()
92
+ .prepare("INSERT INTO settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value")
93
+ .run(key, value);
94
+ }
95
+ export function deleteSetting(key) {
96
+ getDb().prepare("DELETE FROM settings WHERE key = ?").run(key);
97
+ }
98
+ /** Setting keys starting with `prefix`, used to prune dated cache entries. */
99
+ export function listSettingKeys(prefix) {
100
+ const rows = getDb()
101
+ .prepare("SELECT key FROM settings WHERE key LIKE ?")
102
+ .all(`${prefix}%`);
103
+ return rows.map((row) => row.key);
104
+ }
105
+ // Pair tokens
106
+ const PAIR_TOKEN_TTL_SECONDS = 5 * 60;
107
+ /**
108
+ * A pair code is a bearer credential in disguise: /api/pair is unauthenticated
109
+ * by design, and /api/pair/<code>/status hands out the API key as soon as that
110
+ * code is approved. Math.random() was the source here, which means an attacker
111
+ * who mints a handful of codes from the open endpoint can recover the PRNG
112
+ * state and predict the code the real watch is displaying. randomInt draws from
113
+ * the CSPRNG, uniformly and without modulo bias, and zero-padding keeps the
114
+ * full six-digit space (including 000042) in play.
115
+ */
116
+ export function generatePairCode() {
117
+ return randomInt(0, 1_000_000).toString().padStart(6, "0");
118
+ }
119
+ export function createPairToken() {
120
+ const db = getDb();
121
+ const now = Math.floor(Date.now() / 1000);
122
+ const expiresAt = now + PAIR_TOKEN_TTL_SECONDS;
123
+ // Clean expired tokens
124
+ db.prepare("DELETE FROM pair_tokens WHERE expires_at < ?").run(now);
125
+ let code = generatePairCode();
126
+ let attempts = 0;
127
+ while (attempts < 10) {
128
+ const existing = db.prepare("SELECT code FROM pair_tokens WHERE code = ?").get(code);
129
+ if (!existing)
130
+ break;
131
+ code = generatePairCode();
132
+ attempts++;
133
+ }
134
+ const token = { code, created_at: now, expires_at: expiresAt, approved_at: null };
135
+ db.prepare("INSERT INTO pair_tokens (code, created_at, expires_at, approved_at) VALUES (?, ?, ?, NULL)")
136
+ .run(code, now, expiresAt);
137
+ return token;
138
+ }
139
+ export function getPairToken(code) {
140
+ const row = getDb()
141
+ .prepare("SELECT code, created_at, expires_at, approved_at FROM pair_tokens WHERE code = ?")
142
+ .get(code);
143
+ return row ?? null;
144
+ }
145
+ export function approvePairToken(code) {
146
+ const now = Math.floor(Date.now() / 1000);
147
+ const token = getPairToken(code);
148
+ if (!token || token.expires_at < now)
149
+ return false;
150
+ getDb()
151
+ .prepare("UPDATE pair_tokens SET approved_at = ? WHERE code = ?")
152
+ .run(now, code);
153
+ return true;
154
+ }
155
+ export function deletePairToken(code) {
156
+ getDb().prepare("DELETE FROM pair_tokens WHERE code = ?").run(code);
157
+ }
158
+ export function listPendingPairTokens() {
159
+ const now = Math.floor(Date.now() / 1000);
160
+ return getDb()
161
+ .prepare("SELECT code, created_at, expires_at, approved_at FROM pair_tokens WHERE expires_at > ? AND approved_at IS NULL ORDER BY created_at DESC")
162
+ .all(now);
163
+ }
164
+ // Prompt jobs
165
+ /** Kept long enough to answer "what did it say earlier today", not forever. */
166
+ const PROMPT_JOB_TTL_SECONDS = 7 * 24 * 60 * 60;
167
+ /**
168
+ * How old an unfinished job has to be before it counts as wreckage.
169
+ *
170
+ * The watch polls a job id for about thirty seconds and then gives up, so
171
+ * anything younger than that is, or was until moments ago, an answer somebody
172
+ * is waiting for. Five minutes leaves room for a slow model call as well.
173
+ */
174
+ export const STALE_PROMPT_JOB_SECONDS = 5 * 60;
175
+ /**
176
+ * A job the process died in the middle of is not still running.
177
+ *
178
+ * THIS USED TO RUN INSIDE `getDb()`, so the first time ANY process opened
179
+ * app.db it flipped every pending and running row to
180
+ * "The server stopped before this answer came back." -- including the rows
181
+ * belonging to a `serve` that was, at that moment, waiting on Anthropic. Every
182
+ * entry point opens this file, so asking a question on the watch and then
183
+ * running `trainbud doctor`, `status`, `findings` or a backfill killed the live
184
+ * answer from another process, and the watch drew "AI unavailable".
185
+ *
186
+ * Two changes, and both are needed. It is called once, from `serve` at startup,
187
+ * so a CLI command no longer writes to a server's table at all. And it will not
188
+ * touch a job younger than STALE_PROMPT_JOB_SECONDS, which is what protects a
189
+ * second server on the same box, and a restart racing an answer that is still
190
+ * in flight.
191
+ */
192
+ export function reconcileStalePromptJobs(db, now = Math.floor(Date.now() / 1000)) {
193
+ db.prepare(`UPDATE prompt_jobs
194
+ SET status = 'error',
195
+ error = 'The server stopped before this answer came back.',
196
+ completed_at = ?
197
+ WHERE status IN ('pending', 'running')
198
+ AND created_at < ?`).run(now, now - STALE_PROMPT_JOB_SECONDS);
199
+ prunePromptJobs(db, now);
200
+ }
201
+ /** Drop rows past the retention window. Safe from any process. */
202
+ function prunePromptJobs(db, now = Math.floor(Date.now() / 1000)) {
203
+ db.prepare("DELETE FROM prompt_jobs WHERE created_at < ?").run(now - PROMPT_JOB_TTL_SECONDS);
204
+ }
205
+ /** Called once by `serve`, which is the only process that owns these jobs. */
206
+ export function reconcilePromptJobsOnStartup() {
207
+ reconcileStalePromptJobs(getDb());
208
+ }
209
+ export function createPromptJob(id, prompt) {
210
+ const now = Math.floor(Date.now() / 1000);
211
+ const job = { id, prompt, status: "pending", result: null, error: null, created_at: now, completed_at: null };
212
+ const db = getDb();
213
+ // Prune on write rather than on a timer: this table only grows when a job is
214
+ // created, so this is the one place that needs to care, and it costs a single
215
+ // indexed delete on a table with a handful of rows.
216
+ db.prepare("DELETE FROM prompt_jobs WHERE created_at < ?").run(now - PROMPT_JOB_TTL_SECONDS);
217
+ db.prepare("INSERT INTO prompt_jobs (id, prompt, status, result, error, created_at, completed_at) VALUES (?, ?, 'pending', NULL, NULL, ?, NULL)")
218
+ .run(id, prompt, now);
219
+ return job;
220
+ }
221
+ export function getPromptJob(id) {
222
+ const row = getDb()
223
+ .prepare("SELECT id, prompt, status, result, error, created_at, completed_at FROM prompt_jobs WHERE id = ?")
224
+ .get(id);
225
+ return row ?? null;
226
+ }
227
+ export function updatePromptJob(id, update) {
228
+ const now = Math.floor(Date.now() / 1000);
229
+ getDb()
230
+ .prepare("UPDATE prompt_jobs SET status = ?, result = ?, error = ?, completed_at = ? WHERE id = ?")
231
+ .run(update.status, update.result ?? null, update.error ?? null, update.status === "done" || update.status === "error" ? now : null, id);
232
+ }
233
+ export function closeAppDb() {
234
+ if (_db) {
235
+ _db.close();
236
+ _db = null;
237
+ }
238
+ }
239
+ //# sourceMappingURL=appDb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appDb.js","sourceRoot":"","sources":["../src/appDb.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface ToolCheckResult {
2
+ name: string;
3
+ ok: boolean;
4
+ summary: string;
5
+ /** Non-fatal findings are reported but do not fail the command. */
6
+ warning?: boolean;
7
+ section?: string;
8
+ }
9
+ export declare function checkSetup(): ToolCheckResult[];
10
+ export declare function runLiveCheck(): Promise<ToolCheckResult[]>;
11
+ export declare function printLiveCheckResults(results: ToolCheckResult[]): void;
12
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAWD,wBAAgB,UAAU,IAAI,eAAe,EAAE,CAsE9C;AAkJD,wBAAsB,YAAY,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAqB/D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI,CAsCtE"}
package/dist/check.js ADDED
@@ -0,0 +1,230 @@
1
+ import fs from "node:fs";
2
+ import { DateTime } from "luxon";
3
+ import { assertGarminCredentials, appConfig, deprecatedEnvNames, getEnvFilePath } from "./config.js";
4
+ import { executeTool, listRegisteredToolNames } from "./tools/index.js";
5
+ import { configureLogger } from "./utils/logger.js";
6
+ import { getDataDir, getLegacyDataDir } from "./paths.js";
7
+ import { isAiConfigured } from "./promptApi.js";
8
+ // -----------------------------------------------------------------------------
9
+ // Setup checks
10
+ //
11
+ // The tool checks below only prove the Connect API works. They say nothing about
12
+ // the parts that actually strand people: no API key, no public URL, state left
13
+ // in the pre-rename directory. Those are checked first so `trainbud check`
14
+ // diagnoses the whole stack rather than one layer of it.
15
+ // -----------------------------------------------------------------------------
16
+ export function checkSetup() {
17
+ const results = [];
18
+ const add = (name, ok, summary, warning = false) => {
19
+ results.push({ name, ok, summary, warning, section: "Setup" });
20
+ };
21
+ const envPath = getEnvFilePath();
22
+ add(".env file", fs.existsSync(envPath), fs.existsSync(envPath) ? envPath : `missing — run "trainbud setup"`);
23
+ const hasCredentials = !!appConfig.garminEmail && !!appConfig.garminPassword;
24
+ add("Connect credentials", hasCredentials, hasCredentials ? appConfig.garminEmail : "GARMIN_EMAIL / GARMIN_PASSWORD not set");
25
+ const hasApiKey = appConfig.mcpApiKey.length > 0;
26
+ add("API key", hasApiKey, hasApiKey ? `set (${appConfig.mcpApiKey.length} chars)` : `TRAINBUD_API_KEY not set — run "trainbud setup"`);
27
+ const dataDir = getDataDir();
28
+ let writable;
29
+ try {
30
+ fs.mkdirSync(dataDir, { recursive: true });
31
+ fs.accessSync(dataDir, fs.constants.W_OK);
32
+ writable = true;
33
+ }
34
+ catch {
35
+ writable = false;
36
+ }
37
+ add("Data directory", writable, writable ? dataDir : `not writable: ${dataDir}`);
38
+ const legacyDir = getLegacyDataDir();
39
+ const legacyPresent = fs.existsSync(legacyDir);
40
+ add("Legacy directory", true, legacyPresent
41
+ ? `${legacyDir} still present — safe to delete once everything works`
42
+ : "none", legacyPresent);
43
+ const deprecated = deprecatedEnvNames();
44
+ add("Env var names", true, deprecated.length > 0 ? `using old names: ${deprecated.join(", ")}` : "current", deprecated.length > 0);
45
+ const publicUrl = appConfig.publicUrl;
46
+ add("Public URL", true, publicUrl.length > 0 ? publicUrl : "not set — the watch cannot reach this server without it", publicUrl.length === 0);
47
+ // isAiConfigured(), not appConfig.anthropicApiKey. The dashboard writes the
48
+ // key to the settings table, which is the route the setup guide tells users
49
+ // to take, and reading the environment alone reported every one of those keys
50
+ // as missing. resolveAnthropicKey() was written for exactly this and this
51
+ // call site never used it.
52
+ const aiKey = isAiConfigured();
53
+ add("AI features", true, aiKey ? "key present" : "no key — AI cards stay empty (optional)", !aiKey);
54
+ return results;
55
+ }
56
+ function buildDefaultToolChecks() {
57
+ const endDate = DateTime.now().toISODate();
58
+ const startDate = DateTime.now().minus({ days: 30 }).toISODate();
59
+ return [
60
+ { name: "get_latest_activity", args: {} },
61
+ {
62
+ name: "get_activities_range",
63
+ args: {
64
+ start_date: startDate,
65
+ end_date: endDate,
66
+ },
67
+ },
68
+ { name: "get_sleep_data", args: { nights: 7 } },
69
+ { name: "get_heart_rate_trends", args: { days: 30 } },
70
+ { name: "get_recovery_status", args: {} },
71
+ { name: "get_body_composition", args: { days: 30 } },
72
+ { name: "get_stress_levels", args: { days: 7 } },
73
+ { name: "get_vo2_max_trends", args: { days: 30 } },
74
+ { name: "get_training_insights", args: { days: 7 } },
75
+ ];
76
+ }
77
+ function summarizeToolResult(name, text) {
78
+ const normalized = text.trim();
79
+ const noDataPattern = /^No .+ found/i;
80
+ // "No VO2 max data found" means the watch does not record that metric, not
81
+ // that the tool is broken. Reporting it as a failure made `check` exit 1 for a
82
+ // perfectly healthy setup, so it is advisory instead.
83
+ if (noDataPattern.test(normalized)) {
84
+ return {
85
+ ok: true,
86
+ warning: true,
87
+ summary: `${normalized.split("\n")[0] ?? normalized} (not a fault — this metric is absent)`,
88
+ };
89
+ }
90
+ if (name === "get_latest_activity") {
91
+ const activityLine = normalized.split("\n").find((line) => line.startsWith("Activity:"));
92
+ const dateLine = normalized.split("\n").find((line) => line.startsWith("Date:"));
93
+ const distanceLine = normalized.split("\n").find((line) => line.startsWith("Distance:"));
94
+ const parts = [activityLine, distanceLine, dateLine].filter(Boolean);
95
+ return {
96
+ ok: true,
97
+ summary: parts.length > 0 ? parts.join(", ") : "Latest activity retrieved",
98
+ };
99
+ }
100
+ if (name === "get_activities_range") {
101
+ const countMatch = normalized.match(/(\d+) activit/i);
102
+ return {
103
+ ok: true,
104
+ summary: countMatch ? `${countMatch[1]} activities found` : "Activities retrieved",
105
+ };
106
+ }
107
+ if (name === "get_sleep_data") {
108
+ const nightsMatch = normalized.match(/(\d+) nights?/i);
109
+ return {
110
+ ok: true,
111
+ summary: nightsMatch ? `${nightsMatch[1]} nights retrieved` : "Sleep data retrieved",
112
+ };
113
+ }
114
+ if (name === "get_heart_rate_trends") {
115
+ const daysMatch = normalized.match(/(\d+) days/i);
116
+ return {
117
+ ok: true,
118
+ summary: daysMatch ? `${daysMatch[1]}-day trend loaded` : "Heart rate trends loaded",
119
+ };
120
+ }
121
+ if (name === "get_recovery_status") {
122
+ const scoreMatch = normalized.match(/Recovery score:\s*(\d+)/i);
123
+ const recommendationMatch = normalized.match(/Recommendation:\s*(.+)/i);
124
+ if (scoreMatch) {
125
+ const recommendation = recommendationMatch?.[1]?.trim();
126
+ return {
127
+ ok: true,
128
+ summary: recommendation
129
+ ? `Score: ${scoreMatch[1]} (${recommendation})`
130
+ : `Score: ${scoreMatch[1]}`,
131
+ };
132
+ }
133
+ return { ok: true, summary: "Recovery status retrieved" };
134
+ }
135
+ if (name === "get_body_composition") {
136
+ const daysMatch = normalized.match(/(\d+) recorded days/i);
137
+ return {
138
+ ok: true,
139
+ summary: daysMatch ? `${daysMatch[1]} recorded days` : "Body composition retrieved",
140
+ };
141
+ }
142
+ if (name === "get_stress_levels") {
143
+ const daysMatch = normalized.match(/(\d+) recorded days/i);
144
+ return {
145
+ ok: true,
146
+ summary: daysMatch ? `${daysMatch[1]} stress days loaded` : "Stress data retrieved",
147
+ };
148
+ }
149
+ if (name === "get_vo2_max_trends") {
150
+ const daysMatch = normalized.match(/(\d+) recorded days/i);
151
+ return {
152
+ ok: true,
153
+ summary: daysMatch ? `${daysMatch[1]} VO2 entries loaded` : "VO2 max trends loaded",
154
+ };
155
+ }
156
+ if (name === "get_training_insights") {
157
+ return {
158
+ ok: true,
159
+ summary: "Training insights summary generated",
160
+ };
161
+ }
162
+ const firstLine = normalized.split("\n")[0] ?? normalized;
163
+ return {
164
+ ok: true,
165
+ summary: firstLine.length > 72 ? `${firstLine.slice(0, 69)}...` : firstLine,
166
+ };
167
+ }
168
+ async function runToolCheck(check) {
169
+ try {
170
+ const result = await executeTool(check.name, check.args);
171
+ const { ok, summary, warning } = summarizeToolResult(check.name, result.text);
172
+ return { name: check.name, ok, summary, warning };
173
+ }
174
+ catch (error) {
175
+ const message = error instanceof Error ? error.message : "Unknown error";
176
+ return {
177
+ name: check.name,
178
+ ok: false,
179
+ summary: message,
180
+ };
181
+ }
182
+ }
183
+ export async function runLiveCheck() {
184
+ const results = checkSetup();
185
+ // Without credentials the tool checks can only fail, and their errors would
186
+ // bury the setup finding that actually explains why.
187
+ if (!appConfig.garminEmail || !appConfig.garminPassword) {
188
+ return results;
189
+ }
190
+ assertGarminCredentials();
191
+ configureLogger(appConfig.logPath);
192
+ const registered = new Set(listRegisteredToolNames());
193
+ const checks = buildDefaultToolChecks().filter((check) => registered.has(check.name));
194
+ for (const check of checks) {
195
+ const result = await runToolCheck(check);
196
+ results.push({ ...result, section: "Tools" });
197
+ }
198
+ return results;
199
+ }
200
+ export function printLiveCheckResults(results) {
201
+ console.log("TrainBud check");
202
+ let currentSection = "";
203
+ for (const result of results) {
204
+ const section = result.section ?? "Checks";
205
+ if (section !== currentSection) {
206
+ console.log("");
207
+ console.log(`${section}`);
208
+ currentSection = section;
209
+ }
210
+ const icon = !result.ok ? "✗" : result.warning ? "!" : "✓";
211
+ console.log(` ${result.name.padEnd(26, " ")}${icon} ${result.summary}`);
212
+ }
213
+ console.log("");
214
+ const failed = results.filter((result) => !result.ok);
215
+ const warned = results.filter((result) => result.ok && result.warning);
216
+ const total = results.length;
217
+ if (failed.length === 0 && warned.length === 0) {
218
+ console.log(`All ${total} checks passed. TrainBud is ready to use.`);
219
+ return;
220
+ }
221
+ if (failed.length === 0) {
222
+ console.log(`${total - warned.length}/${total} clean, ${warned.length} advisory (!). Nothing is broken — the notes above are optional setup.`);
223
+ return;
224
+ }
225
+ console.log(`${total - failed.length}/${total} passed, ${failed.length} failed (✗). Fix those first:`);
226
+ for (const result of failed) {
227
+ console.log(` - ${result.name}: ${result.summary}`);
228
+ }
229
+ }
230
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function createCliProgram(): Command;
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAwB,MAAM,WAAW,CAAC;AA2V1D,wBAAgB,gBAAgB,IAAI,OAAO,CAqN1C"}