@milldr/crono 0.1.0 → 0.3.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/README.md +128 -0
- package/dist/commands/add.d.ts +9 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +65 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/export.d.ts +8 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +142 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/log.d.ts +6 -0
- package/dist/commands/log.d.ts.map +1 -0
- package/dist/commands/log.js +40 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/quick-add.d.ts +2 -0
- package/dist/commands/quick-add.d.ts.map +1 -1
- package/dist/commands/quick-add.js +20 -3
- package/dist/commands/quick-add.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/cronometer/auth.d.ts +31 -0
- package/dist/cronometer/auth.d.ts.map +1 -0
- package/dist/cronometer/auth.js +151 -0
- package/dist/cronometer/auth.js.map +1 -0
- package/dist/cronometer/export.d.ts +22 -0
- package/dist/cronometer/export.d.ts.map +1 -0
- package/dist/cronometer/export.js +83 -0
- package/dist/cronometer/export.js.map +1 -0
- package/dist/cronometer/parse.d.ts +35 -0
- package/dist/cronometer/parse.d.ts.map +1 -0
- package/dist/cronometer/parse.js +158 -0
- package/dist/cronometer/parse.js.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -1
- package/dist/kernel/add-custom-food.d.ts +22 -0
- package/dist/kernel/add-custom-food.d.ts.map +1 -0
- package/dist/kernel/add-custom-food.js +314 -0
- package/dist/kernel/add-custom-food.js.map +1 -0
- package/dist/kernel/client.d.ts +17 -0
- package/dist/kernel/client.d.ts.map +1 -1
- package/dist/kernel/client.js +92 -1
- package/dist/kernel/client.js.map +1 -1
- package/dist/kernel/log-food.d.ts +17 -0
- package/dist/kernel/log-food.d.ts.map +1 -0
- package/dist/kernel/log-food.js +230 -0
- package/dist/kernel/log-food.js.map +1 -0
- package/dist/kernel/login.d.ts.map +1 -1
- package/dist/kernel/login.js +24 -1
- package/dist/kernel/login.js.map +1 -1
- package/dist/kernel/quick-add.d.ts.map +1 -1
- package/dist/kernel/quick-add.js +27 -1
- package/dist/kernel/quick-add.js.map +1 -1
- package/dist/utils/date.d.ts +9 -0
- package/dist/utils/date.d.ts.map +1 -1
- package/dist/utils/date.js +22 -0
- package/dist/utils/date.js.map +1 -1
- package/package.json +5 -1
- package/dist/debug-nav.d.ts +0 -2
- package/dist/debug-nav.d.ts.map +0 -1
- package/dist/debug-nav.js +0 -99
- package/dist/debug-nav.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# 🍎 crono
|
|
2
2
|
|
|
3
|
+
[](https://ko-fi.com/milldr)
|
|
4
|
+
|
|
3
5
|
CLI for Cronometer automation via [Kernel.sh](https://kernel.sh).
|
|
4
6
|
|
|
5
7
|
Cronometer has no public API, so crono automates the web UI through Kernel.sh browser automation. Log macros from your terminal in seconds.
|
|
@@ -101,6 +103,69 @@ crono quick-add -p 30 -c 100 -f 20
|
|
|
101
103
|
crono quick-add -p 30 -c 50 -f 15 --meal Dinner
|
|
102
104
|
```
|
|
103
105
|
|
|
106
|
+
### `crono add custom-food`
|
|
107
|
+
|
|
108
|
+
Create a custom food in Cronometer with specified macros.
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
crono add custom-food <name> [options]
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Options:**
|
|
115
|
+
|
|
116
|
+
| Flag | Long | Description |
|
|
117
|
+
| ---- | --------------- | ------------------------------------------- |
|
|
118
|
+
| `-p` | `--protein <g>` | Grams of protein |
|
|
119
|
+
| `-c` | `--carbs <g>` | Grams of carbohydrates |
|
|
120
|
+
| `-f` | `--fat <g>` | Grams of fat |
|
|
121
|
+
| | `--log [meal]` | Also log to diary (optionally specify meal) |
|
|
122
|
+
|
|
123
|
+
At least one macro flag (`-p`, `-c`, or `-f`) is required.
|
|
124
|
+
|
|
125
|
+
**Examples:**
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Create a custom food with all macros
|
|
129
|
+
crono add custom-food "Wendy's Chicken Sandwich" -p 50 -c 100 -f 50
|
|
130
|
+
|
|
131
|
+
# Just protein and carbs
|
|
132
|
+
crono add custom-food "Post-Workout Shake" -p 40 -c 60
|
|
133
|
+
|
|
134
|
+
# Create and immediately log to Uncategorized
|
|
135
|
+
crono add custom-food "Wendy's Chicken Sandwich" -p 50 -c 100 -f 50 --log
|
|
136
|
+
|
|
137
|
+
# Create and immediately log to Dinner
|
|
138
|
+
crono add custom-food "Wendy's Chicken Sandwich" -p 50 -c 100 -f 50 --log Dinner
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### `crono log`
|
|
142
|
+
|
|
143
|
+
Log a saved food to your diary by name. Works with custom foods, custom recipes, and database items.
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
crono log <name> [options]
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Options:**
|
|
150
|
+
|
|
151
|
+
| Flag | Long | Description |
|
|
152
|
+
| ---- | -------------------- | ------------------------------------------------ |
|
|
153
|
+
| `-m` | `--meal <name>` | Meal category (Breakfast, Lunch, Dinner, Snacks) |
|
|
154
|
+
| `-s` | `--servings <count>` | Number of servings (default: 1) |
|
|
155
|
+
|
|
156
|
+
**Examples:**
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Log a custom food
|
|
160
|
+
crono log "Wendy's Chicken Sandwich"
|
|
161
|
+
|
|
162
|
+
# Log to a specific meal
|
|
163
|
+
crono log "Wendy's Chicken Sandwich" -m Dinner
|
|
164
|
+
|
|
165
|
+
# Log multiple servings
|
|
166
|
+
crono log "Post-Workout Shake" -s 2 -m Snacks
|
|
167
|
+
```
|
|
168
|
+
|
|
104
169
|
### `crono weight`
|
|
105
170
|
|
|
106
171
|
Check your weight from Cronometer. Defaults to today if no date or range is specified.
|
|
@@ -188,6 +253,63 @@ crono diary -r 7d --json
|
|
|
188
253
|
# → [{"date":"2026-02-11","calories":1847,"protein":168,"carbs":142,"fat":58}, ...]
|
|
189
254
|
```
|
|
190
255
|
|
|
256
|
+
### `crono export`
|
|
257
|
+
|
|
258
|
+
Export data directly from Cronometer's API — no browser automation, much faster than `diary` or `weight`.
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
crono export <type> [options]
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Types:**
|
|
265
|
+
|
|
266
|
+
| Type | Description |
|
|
267
|
+
| ------------ | ----------------------------------- |
|
|
268
|
+
| `nutrition` | Daily nutrition totals (macros) |
|
|
269
|
+
| `exercises` | Exercise entries with duration/cals |
|
|
270
|
+
| `biometrics` | Biometric measurements (weight, BP) |
|
|
271
|
+
|
|
272
|
+
**Options:**
|
|
273
|
+
|
|
274
|
+
| Flag | Long | Description |
|
|
275
|
+
| ---- | ----------------- | ----------------------------------------- |
|
|
276
|
+
| `-d` | `--date <date>` | Date (YYYY-MM-DD) |
|
|
277
|
+
| `-r` | `--range <range>` | Range (7d, 30d, or YYYY-MM-DD:YYYY-MM-DD) |
|
|
278
|
+
| | `--csv` | Output as raw CSV |
|
|
279
|
+
| | `--json` | Output as JSON |
|
|
280
|
+
|
|
281
|
+
`-d` and `-r` are mutually exclusive. `--csv` and `--json` are mutually exclusive.
|
|
282
|
+
|
|
283
|
+
**Examples:**
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
# Today's nutrition
|
|
287
|
+
crono export nutrition
|
|
288
|
+
# → 1847 kcal | P: 168g | C: 142g | F: 58g
|
|
289
|
+
|
|
290
|
+
# Last 7 days of nutrition as JSON
|
|
291
|
+
crono export nutrition -r 7d --json
|
|
292
|
+
|
|
293
|
+
# Today's exercises
|
|
294
|
+
crono export exercises
|
|
295
|
+
# → Running: 30 min, 350 kcal
|
|
296
|
+
|
|
297
|
+
# Biometrics for last 30 days
|
|
298
|
+
crono export biometrics -r 30d
|
|
299
|
+
# → 2026-02-11: Weight: 212.5 lbs
|
|
300
|
+
# → 2026-02-09: Blood Pressure: 120/80 mmHg
|
|
301
|
+
|
|
302
|
+
# Raw CSV export
|
|
303
|
+
crono export nutrition -r 30d --csv
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**GWT overrides:** If Cronometer updates break the export, override GWT values in `~/.config/crono/config.json` or via environment variables:
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
export CRONO_GWT_PERMUTATION=<new-value>
|
|
310
|
+
export CRONO_GWT_HEADER=<new-value>
|
|
311
|
+
```
|
|
312
|
+
|
|
191
313
|
## Requirements
|
|
192
314
|
|
|
193
315
|
- Node.js 18+
|
|
@@ -214,6 +336,12 @@ npm test
|
|
|
214
336
|
npm run build
|
|
215
337
|
```
|
|
216
338
|
|
|
339
|
+
## Support
|
|
340
|
+
|
|
341
|
+
I build and maintain projects like crono in my free time as personal hobbies. They're completely free and always will be. If you find this useful and want to show some support, feel free to buy me a coffee:
|
|
342
|
+
|
|
343
|
+
[](https://ko-fi.com/milldr)
|
|
344
|
+
|
|
217
345
|
## License
|
|
218
346
|
|
|
219
347
|
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface AddCustomFoodOptions {
|
|
2
|
+
protein?: number;
|
|
3
|
+
carbs?: number;
|
|
4
|
+
fat?: number;
|
|
5
|
+
total?: number;
|
|
6
|
+
log?: string | boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function addCustomFood(name: string, options: AddCustomFoodOptions): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=add.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAID,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAsEf"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import { getKernelClient } from "../kernel/client.js";
|
|
3
|
+
const VALID_MEALS = ["breakfast", "lunch", "dinner", "snacks"];
|
|
4
|
+
export async function addCustomFood(name, options) {
|
|
5
|
+
// Validate at least one macro is provided
|
|
6
|
+
if (!options.protein && !options.carbs && !options.fat) {
|
|
7
|
+
p.log.error("At least one macro (-p, -c, or -f) is required");
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
// Validate --log meal if specified as a string
|
|
11
|
+
if (typeof options.log === "string") {
|
|
12
|
+
const normalizedMeal = options.log.toLowerCase();
|
|
13
|
+
if (!VALID_MEALS.includes(normalizedMeal)) {
|
|
14
|
+
p.log.error(`Invalid meal "${options.log}". Use: Breakfast, Lunch, Dinner, or Snacks`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// Calculate total calories
|
|
19
|
+
const calories = options.total ??
|
|
20
|
+
(options.protein ?? 0) * 4 +
|
|
21
|
+
(options.carbs ?? 0) * 4 +
|
|
22
|
+
(options.fat ?? 0) * 9;
|
|
23
|
+
// Build macro display
|
|
24
|
+
const macroParts = [];
|
|
25
|
+
macroParts.push(`${calories} cal`);
|
|
26
|
+
if (options.protein)
|
|
27
|
+
macroParts.push(`P: ${options.protein}g`);
|
|
28
|
+
if (options.carbs)
|
|
29
|
+
macroParts.push(`C: ${options.carbs}g`);
|
|
30
|
+
if (options.fat)
|
|
31
|
+
macroParts.push(`F: ${options.fat}g`);
|
|
32
|
+
const macroDisplay = macroParts.join(" | ");
|
|
33
|
+
const logMeal = options.log
|
|
34
|
+
? typeof options.log === "string"
|
|
35
|
+
? options.log.charAt(0).toUpperCase() + options.log.slice(1).toLowerCase()
|
|
36
|
+
: "Uncategorized"
|
|
37
|
+
: null;
|
|
38
|
+
p.intro("🍎 crono add");
|
|
39
|
+
const s = p.spinner();
|
|
40
|
+
s.start("Connecting...");
|
|
41
|
+
try {
|
|
42
|
+
const kernel = await getKernelClient();
|
|
43
|
+
await kernel.addCustomFood({
|
|
44
|
+
name,
|
|
45
|
+
protein: options.protein,
|
|
46
|
+
carbs: options.carbs,
|
|
47
|
+
fat: options.fat,
|
|
48
|
+
calories,
|
|
49
|
+
log: options.log,
|
|
50
|
+
}, (msg) => s.message(msg));
|
|
51
|
+
s.stop("Done.");
|
|
52
|
+
if (logMeal) {
|
|
53
|
+
p.outro(`Created and logged: ${name} (${macroDisplay}) → ${logMeal}`);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
p.outro(`Created custom food: ${name} (${macroDisplay})`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
s.stop("Failed.");
|
|
61
|
+
p.log.error(`Failed to create custom food: ${error}`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CAwGf"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import { exportData } from "../cronometer/export.js";
|
|
3
|
+
import { parseNutrition, parseExercises, parseBiometrics, } from "../cronometer/parse.js";
|
|
4
|
+
import { parseDate, parseRange, todayStr } from "../utils/date.js";
|
|
5
|
+
const VALID_TYPES = ["nutrition", "exercises", "biometrics"];
|
|
6
|
+
export async function exportCmd(type, options) {
|
|
7
|
+
// Validate type
|
|
8
|
+
if (!VALID_TYPES.includes(type)) {
|
|
9
|
+
p.log.error("Unknown export type. Use: nutrition, exercises, biometrics");
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
// Validate mutual exclusivity
|
|
13
|
+
if (options.date && options.range) {
|
|
14
|
+
p.log.error("-d and -r are mutually exclusive");
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
if (options.csv && options.json) {
|
|
18
|
+
p.log.error("--csv and --json are mutually exclusive");
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
// Resolve date range
|
|
22
|
+
let start;
|
|
23
|
+
let end;
|
|
24
|
+
let isRange = false;
|
|
25
|
+
try {
|
|
26
|
+
if (options.range) {
|
|
27
|
+
isRange = true;
|
|
28
|
+
const range = parseRange(options.range);
|
|
29
|
+
start = range.start;
|
|
30
|
+
end = range.end;
|
|
31
|
+
}
|
|
32
|
+
else if (options.date) {
|
|
33
|
+
start = parseDate(options.date);
|
|
34
|
+
end = start;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
start = todayStr();
|
|
38
|
+
end = start;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
p.log.error(String(error instanceof Error ? error.message : error));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
const silent = options.json || options.csv;
|
|
46
|
+
if (!silent) {
|
|
47
|
+
p.intro("🍎 crono export");
|
|
48
|
+
}
|
|
49
|
+
const s = silent ? null : p.spinner();
|
|
50
|
+
s?.start("Connecting...");
|
|
51
|
+
try {
|
|
52
|
+
const csv = await exportData(type, start, end, (msg) => s?.message(msg));
|
|
53
|
+
s?.stop("Done.");
|
|
54
|
+
// Raw CSV passthrough
|
|
55
|
+
if (options.csv) {
|
|
56
|
+
console.log(csv);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// Parse and output
|
|
60
|
+
const exportType = type;
|
|
61
|
+
if (exportType === "nutrition") {
|
|
62
|
+
const entries = parseNutrition(csv);
|
|
63
|
+
if (entries.length === 0) {
|
|
64
|
+
if (!silent)
|
|
65
|
+
p.outro("No nutrition data found for the requested dates");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (options.json) {
|
|
69
|
+
console.log(JSON.stringify(isRange ? entries : entries[0], null, 2));
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
formatNutrition(entries, isRange);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else if (exportType === "exercises") {
|
|
76
|
+
const entries = parseExercises(csv);
|
|
77
|
+
if (entries.length === 0) {
|
|
78
|
+
if (!silent)
|
|
79
|
+
p.outro("No exercises data found for the requested dates");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (options.json) {
|
|
83
|
+
console.log(JSON.stringify(isRange ? entries : entries, null, 2));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
formatExercises(entries, isRange);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const entries = parseBiometrics(csv);
|
|
91
|
+
if (entries.length === 0) {
|
|
92
|
+
if (!silent)
|
|
93
|
+
p.outro("No biometrics data found for the requested dates");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (options.json) {
|
|
97
|
+
console.log(JSON.stringify(isRange ? entries : entries, null, 2));
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
formatBiometrics(entries, isRange);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
s?.stop("Failed.");
|
|
106
|
+
p.log.error(`${error instanceof Error ? error.message : error}`);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function formatNutrition(entries, isRange) {
|
|
111
|
+
if (!isRange) {
|
|
112
|
+
const e = entries[0];
|
|
113
|
+
p.outro(`${e.calories} kcal | P: ${e.protein}g | C: ${e.carbs}g | F: ${e.fat}g`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
for (const e of entries) {
|
|
117
|
+
p.log.info(`${e.date}: ${e.calories} kcal | P: ${e.protein}g | C: ${e.carbs}g | F: ${e.fat}g`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function formatExercises(entries, isRange) {
|
|
121
|
+
if (!isRange) {
|
|
122
|
+
for (const e of entries) {
|
|
123
|
+
p.outro(`${e.exercise}: ${e.minutes} min, ${e.caloriesBurned} kcal`);
|
|
124
|
+
}
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
for (const e of entries) {
|
|
128
|
+
p.log.info(`${e.date}: ${e.exercise}: ${e.minutes} min, ${e.caloriesBurned} kcal`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function formatBiometrics(entries, isRange) {
|
|
132
|
+
if (!isRange) {
|
|
133
|
+
for (const e of entries) {
|
|
134
|
+
p.outro(`${e.metric}: ${e.amount} ${e.unit}`);
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
for (const e of entries) {
|
|
139
|
+
p.log.info(`${e.date}: ${e.metric}: ${e.amount} ${e.unit}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/commands/log.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAID,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA6C1E"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import { getKernelClient } from "../kernel/client.js";
|
|
3
|
+
const VALID_MEALS = ["breakfast", "lunch", "dinner", "snacks"];
|
|
4
|
+
export async function log(name, options) {
|
|
5
|
+
// Validate meal if provided
|
|
6
|
+
if (options.meal) {
|
|
7
|
+
const normalizedMeal = options.meal.toLowerCase();
|
|
8
|
+
if (!VALID_MEALS.includes(normalizedMeal)) {
|
|
9
|
+
p.log.error(`Invalid meal "${options.meal}". Use: Breakfast, Lunch, Dinner, or Snacks`);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
// Validate servings if provided
|
|
14
|
+
if (options.servings !== undefined && options.servings <= 0) {
|
|
15
|
+
p.log.error("Servings must be a positive number");
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
const mealLabel = options.meal
|
|
19
|
+
? options.meal.charAt(0).toUpperCase() + options.meal.slice(1).toLowerCase()
|
|
20
|
+
: "Uncategorized";
|
|
21
|
+
p.intro("🍎 crono log");
|
|
22
|
+
const s = p.spinner();
|
|
23
|
+
s.start("Connecting...");
|
|
24
|
+
try {
|
|
25
|
+
const kernel = await getKernelClient();
|
|
26
|
+
await kernel.logFood({
|
|
27
|
+
name,
|
|
28
|
+
meal: options.meal,
|
|
29
|
+
servings: options.servings,
|
|
30
|
+
}, (msg) => s.message(msg));
|
|
31
|
+
s.stop("Done.");
|
|
32
|
+
p.outro(`Logged: ${name} → ${mealLabel}`);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
s.stop("Failed.");
|
|
36
|
+
p.log.error(`Failed to log food: ${error}`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/commands/log.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAOtD,MAAM,WAAW,GAAG,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAE/D,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAY,EAAE,OAAmB;IACzD,4BAA4B;IAC5B,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAClD,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAC1C,CAAC,CAAC,GAAG,CAAC,KAAK,CACT,iBAAiB,OAAO,CAAC,IAAI,6CAA6C,CAC3E,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC;QAC5D,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI;QAC5B,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;QAC5E,CAAC,CAAC,eAAe,CAAC;IAEpB,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAEzB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAC;QACvC,MAAM,MAAM,CAAC,OAAO,CAClB;YACE,IAAI;YACJ,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,EACD,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CACxB,CAAC;QAEF,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChB,CAAC,CAAC,KAAK,CAAC,WAAW,IAAI,MAAM,SAAS,EAAE,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,uBAAuB,KAAK,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -2,7 +2,9 @@ export interface QuickAddOptions {
|
|
|
2
2
|
protein?: number;
|
|
3
3
|
carbs?: number;
|
|
4
4
|
fat?: number;
|
|
5
|
+
alcohol?: number;
|
|
5
6
|
meal?: string;
|
|
7
|
+
date?: string;
|
|
6
8
|
}
|
|
7
9
|
export declare function quickAdd(options: QuickAddOptions): Promise<void>;
|
|
8
10
|
//# sourceMappingURL=quick-add.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quick-add.d.ts","sourceRoot":"","sources":["../../src/commands/quick-add.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"quick-add.d.ts","sourceRoot":"","sources":["../../src/commands/quick-add.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAmEtE"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as p from "@clack/prompts";
|
|
2
2
|
import { getKernelClient } from "../kernel/client.js";
|
|
3
|
+
import { resolveDate } from "../utils/date.js";
|
|
3
4
|
const VALID_MEALS = ["breakfast", "lunch", "dinner", "snacks"];
|
|
4
5
|
export async function quickAdd(options) {
|
|
5
6
|
// Validate at least one macro is provided
|
|
6
|
-
if (!options.protein && !options.carbs && !options.fat) {
|
|
7
|
-
p.log.error("At least one macro (-p, -c, or -
|
|
7
|
+
if (!options.protein && !options.carbs && !options.fat && !options.alcohol) {
|
|
8
|
+
p.log.error("At least one macro (-p, -c, -f, or -a) is required");
|
|
8
9
|
process.exit(1);
|
|
9
10
|
}
|
|
10
11
|
// Validate meal if provided
|
|
@@ -15,6 +16,17 @@ export async function quickAdd(options) {
|
|
|
15
16
|
process.exit(1);
|
|
16
17
|
}
|
|
17
18
|
}
|
|
19
|
+
// Resolve date if provided
|
|
20
|
+
let resolvedDate;
|
|
21
|
+
if (options.date) {
|
|
22
|
+
try {
|
|
23
|
+
resolvedDate = resolveDate(options.date);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
p.log.error(`${err instanceof Error ? err.message : err}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
18
30
|
// Build entry description
|
|
19
31
|
const parts = [];
|
|
20
32
|
if (options.protein)
|
|
@@ -23,6 +35,8 @@ export async function quickAdd(options) {
|
|
|
23
35
|
parts.push(`${options.carbs}g carbs`);
|
|
24
36
|
if (options.fat)
|
|
25
37
|
parts.push(`${options.fat}g fat`);
|
|
38
|
+
if (options.alcohol)
|
|
39
|
+
parts.push(`${options.alcohol}g alcohol`);
|
|
26
40
|
const mealLabel = options.meal
|
|
27
41
|
? options.meal.charAt(0).toUpperCase() + options.meal.slice(1).toLowerCase()
|
|
28
42
|
: "Uncategorized";
|
|
@@ -35,10 +49,13 @@ export async function quickAdd(options) {
|
|
|
35
49
|
protein: options.protein,
|
|
36
50
|
carbs: options.carbs,
|
|
37
51
|
fat: options.fat,
|
|
52
|
+
alcohol: options.alcohol,
|
|
38
53
|
meal: options.meal,
|
|
54
|
+
date: resolvedDate,
|
|
39
55
|
}, (msg) => s.message(msg));
|
|
40
56
|
s.stop("Done.");
|
|
41
|
-
|
|
57
|
+
const dateInfo = resolvedDate ? ` on ${resolvedDate}` : "";
|
|
58
|
+
p.outro(`Added: ${parts.join(", ")} → ${mealLabel}${dateInfo}`);
|
|
42
59
|
}
|
|
43
60
|
catch (error) {
|
|
44
61
|
s.stop("Failed.");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quick-add.js","sourceRoot":"","sources":["../../src/commands/quick-add.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"quick-add.js","sourceRoot":"","sources":["../../src/commands/quick-add.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAcD;;GAEG;AACH,wBAAgB,UAAU,IAAI,WAAW,CAaxC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAGpD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAS5B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AACvD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEpD;;GAEG;AACH,SAAS,eAAe;IACtB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,eAAe,EAAE,CAAC;IAElB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAmB;IAC5C,eAAe,EAAE,CAAC;IAClB,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct HTTP authentication with Cronometer.
|
|
3
|
+
*
|
|
4
|
+
* Three-step flow:
|
|
5
|
+
* 1. GET /login/ — parse anticsrf token and JSESSIONID cookie
|
|
6
|
+
* 2. POST /login — form-encoded login, get sesnonce cookie
|
|
7
|
+
* 3. POST /cronometer/app — GWT RPC authenticate, get user ID
|
|
8
|
+
*/
|
|
9
|
+
export interface CronometerSession {
|
|
10
|
+
cookies: string;
|
|
11
|
+
sesnonce: string;
|
|
12
|
+
userId: number;
|
|
13
|
+
}
|
|
14
|
+
/** Extract a named cookie value from a set-cookie header array. */
|
|
15
|
+
export declare function extractCookie(headers: Headers, name: string): string | null;
|
|
16
|
+
/** Collect all cookies from set-cookie headers as "name=value; name2=value2" string. */
|
|
17
|
+
export declare function collectCookies(headers: Headers): string;
|
|
18
|
+
/** Merge two cookie strings, with later values overriding earlier ones. */
|
|
19
|
+
export declare function mergeCookies(a: string, b: string): string;
|
|
20
|
+
/** Parse the anticsrf token from Cronometer's login page HTML. */
|
|
21
|
+
export declare function parseAnticsrf(html: string): string | null;
|
|
22
|
+
/** Extract user ID from GWT authenticate response. */
|
|
23
|
+
export declare function parseUserId(body: string): number | null;
|
|
24
|
+
/** Build GWT RPC body for the authenticate call. */
|
|
25
|
+
export declare function buildAuthenticateBody(gwtHeader: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Authenticate with Cronometer via HTTP.
|
|
28
|
+
* Returns a session object with cookies and user ID.
|
|
29
|
+
*/
|
|
30
|
+
export declare function login(username: string, password: string, gwtPermutation?: string, gwtHeader?: string): Promise<CronometerSession>;
|
|
31
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/cronometer/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO3E;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAQvD;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CASzD;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGzD;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKvD;AAED,oDAAoD;AACpD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG/D;AAcD;;;GAGG;AACH,wBAAsB,KAAK,CACzB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,cAAc,CAAC,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC,CA2F5B"}
|