@purveyors/cli 0.8.3 → 0.9.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 +276 -254
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +6 -4
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/catalog.d.ts +2 -2
- package/dist/commands/catalog.d.ts.map +1 -1
- package/dist/commands/catalog.js +30 -35
- package/dist/commands/catalog.js.map +1 -1
- package/dist/commands/context.d.ts +0 -5
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +197 -267
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/roast.d.ts.map +1 -1
- package/dist/commands/roast.js +46 -0
- package/dist/commands/roast.js.map +1 -1
- package/dist/index.js +12 -9
- package/dist/index.js.map +1 -1
- package/dist/lib/catalog.d.ts +3 -0
- package/dist/lib/catalog.d.ts.map +1 -1
- package/dist/lib/catalog.js +19 -2
- package/dist/lib/catalog.js.map +1 -1
- package/dist/lib/output.d.ts +6 -0
- package/dist/lib/output.d.ts.map +1 -1
- package/dist/lib/output.js +8 -0
- package/dist/lib/output.js.map +1 -1
- package/dist/lib/roast.d.ts +6 -0
- package/dist/lib/roast.d.ts.map +1 -1
- package/dist/lib/roast.js +60 -0
- package/dist/lib/roast.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/commands/context.js
CHANGED
|
@@ -1,294 +1,224 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// This text is optimized for token efficiency: dense, structured, no fluff.
|
|
5
|
-
// An agent reading this once should be able to use every CLI command correctly.
|
|
2
|
+
// This text is intentionally dense. An agent should be able to read it once,
|
|
3
|
+
// then use the CLI correctly without hunting through help output.
|
|
6
4
|
const CONTEXT_TEXT = `
|
|
7
|
-
PURVEY CLI
|
|
8
|
-
|
|
9
|
-
CLI for purveyors.io
|
|
10
|
-
Credentials: ~/.config/purvey/credentials.json
|
|
5
|
+
PURVEY CLI - Agent Reference
|
|
6
|
+
============================
|
|
7
|
+
Official CLI for purveyors.io. Node.js 20+.
|
|
8
|
+
Credentials file: ~/.config/purvey/credentials.json
|
|
9
|
+
Config file: ~/.config/purvey/config.json
|
|
11
10
|
|
|
12
11
|
ROLES
|
|
13
12
|
-----
|
|
14
|
-
viewer
|
|
15
|
-
member
|
|
13
|
+
viewer valid authenticated session; required for catalog commands
|
|
14
|
+
member required for inventory, roast, sales, and tasting commands
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
AUTH
|
|
17
|
+
----
|
|
18
|
+
Interactive login:
|
|
20
19
|
purvey auth login
|
|
21
20
|
|
|
22
|
-
Headless login
|
|
21
|
+
Headless login:
|
|
23
22
|
purvey auth login --headless
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Token auto-refreshes; no action needed between sessions.
|
|
23
|
+
1. CLI prints a Google OAuth URL
|
|
24
|
+
2. User opens it in any browser and signs in
|
|
25
|
+
3. User pastes the full callback URL back into the terminal
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
purvey auth status
|
|
31
|
-
purvey auth status --pretty
|
|
32
|
-
purvey auth status | jq '.email' # compact JSON on stdout
|
|
27
|
+
Status:
|
|
28
|
+
purvey auth status
|
|
29
|
+
purvey auth status --pretty
|
|
33
30
|
|
|
34
31
|
Logout:
|
|
35
32
|
purvey auth logout
|
|
36
33
|
|
|
37
|
-
OUTPUT
|
|
34
|
+
OUTPUT
|
|
35
|
+
------
|
|
36
|
+
Most commands emit compact JSON to stdout by default.
|
|
37
|
+
Use --json to request compact JSON explicitly.
|
|
38
|
+
Use --pretty for indented JSON.
|
|
39
|
+
Use --csv for array-shaped results that support CSV output.
|
|
40
|
+
User feedback goes to stderr.
|
|
41
|
+
|
|
42
|
+
Important exception:
|
|
43
|
+
- auth status prints human-readable output in an interactive TTY unless --json, --pretty, or --csv is passed; otherwise it emits structured output
|
|
44
|
+
|
|
45
|
+
ID MAP
|
|
46
|
+
------
|
|
47
|
+
catalog_id coffee_catalog row; used by catalog get, inventory add --catalog-id, tasting get, roast list --catalog-id
|
|
48
|
+
inventory_id green_coffee_inv row; used by inventory get/update/delete, roast --coffee-id, roast list --coffee-id, tasting rate
|
|
49
|
+
roast_id roast_data row; used by roast get/delete, roast list --roast-id, sales --roast-id
|
|
50
|
+
sale_id coffee_sales row; used by sales update/delete
|
|
51
|
+
|
|
52
|
+
COMMANDS
|
|
53
|
+
--------
|
|
54
|
+
auth
|
|
55
|
+
login [--headless]
|
|
56
|
+
status
|
|
57
|
+
logout
|
|
58
|
+
|
|
59
|
+
catalog
|
|
60
|
+
search [options]
|
|
61
|
+
--origin <text>
|
|
62
|
+
--process <method>
|
|
63
|
+
--price-min <n>
|
|
64
|
+
--price-max <n>
|
|
65
|
+
--flavor <keywords>
|
|
66
|
+
--name <text>
|
|
67
|
+
--supplier <name>
|
|
68
|
+
--ids <n,n,...>
|
|
69
|
+
--variety <text>
|
|
70
|
+
--drying-method <text>
|
|
71
|
+
--stocked-days <n>
|
|
72
|
+
--stocked
|
|
73
|
+
--sort <price|price-desc|name|origin|newest>
|
|
74
|
+
--offset <n>
|
|
75
|
+
--limit <n>
|
|
76
|
+
get <catalog_id>
|
|
77
|
+
stats
|
|
78
|
+
similar <catalog_id>
|
|
79
|
+
--threshold <0-1> default 0.70
|
|
80
|
+
--limit <n> default 10
|
|
81
|
+
--stocked-only
|
|
82
|
+
|
|
83
|
+
inventory (member)
|
|
84
|
+
list [--stocked] [--limit <n>]
|
|
85
|
+
get <inventory_id>
|
|
86
|
+
add
|
|
87
|
+
--catalog-id <id> required in flag mode
|
|
88
|
+
--qty <lbs> required in flag mode
|
|
89
|
+
--cost <dollars>
|
|
90
|
+
--tax-ship <dollars>
|
|
91
|
+
--notes <text>
|
|
92
|
+
--purchase-date <YYYY-MM-DD>
|
|
93
|
+
--form
|
|
94
|
+
update <inventory_id>
|
|
95
|
+
--qty <lbs>
|
|
96
|
+
--cost <dollars>
|
|
97
|
+
--tax-ship <dollars>
|
|
98
|
+
--notes <text>
|
|
99
|
+
--stocked <true|false>
|
|
100
|
+
delete <inventory_id> [--yes]
|
|
101
|
+
|
|
102
|
+
roast (member)
|
|
103
|
+
list
|
|
104
|
+
--coffee-id <inventory_id>
|
|
105
|
+
--roast-id <roast_id>
|
|
106
|
+
--batch-name <text>
|
|
107
|
+
--date-start <YYYY-MM-DD>
|
|
108
|
+
--date-end <YYYY-MM-DD>
|
|
109
|
+
--stocked
|
|
110
|
+
--catalog-id <catalog_id>
|
|
111
|
+
--limit <n>
|
|
112
|
+
get <roast_id>
|
|
113
|
+
--include-temps
|
|
114
|
+
--include-events
|
|
115
|
+
create
|
|
116
|
+
--coffee-id <inventory_id> required in flag mode
|
|
117
|
+
--batch-name <name>
|
|
118
|
+
--oz-in <oz>
|
|
119
|
+
--oz-out <oz>
|
|
120
|
+
--roast-date <YYYY-MM-DD>
|
|
121
|
+
--notes <text>
|
|
122
|
+
--form
|
|
123
|
+
update <roast_id>
|
|
124
|
+
--notes <text>
|
|
125
|
+
--oz-out <oz>
|
|
126
|
+
--batch-name <name>
|
|
127
|
+
--targets <text>
|
|
128
|
+
delete <roast_id> [--yes]
|
|
129
|
+
import [file]
|
|
130
|
+
--coffee-id <inventory_id> required in flag mode
|
|
131
|
+
--batch-name <name>
|
|
132
|
+
--oz-in <oz>
|
|
133
|
+
--roast-notes <text>
|
|
134
|
+
--form
|
|
135
|
+
watch [directory]
|
|
136
|
+
--coffee-id <inventory_id> required unless --auto-match
|
|
137
|
+
--batch-prefix <name>
|
|
138
|
+
--prompt-each
|
|
139
|
+
--auto-match mutually exclusive with --coffee-id
|
|
140
|
+
--resume
|
|
141
|
+
--form
|
|
142
|
+
|
|
143
|
+
sales (member)
|
|
144
|
+
list [--limit <n>]
|
|
145
|
+
record
|
|
146
|
+
--roast-id <roast_id> required in flag mode
|
|
147
|
+
--oz <amount> required in flag mode
|
|
148
|
+
--price <dollars> required in flag mode
|
|
149
|
+
--buyer <name>
|
|
150
|
+
--sell-date <YYYY-MM-DD>
|
|
151
|
+
--form
|
|
152
|
+
update <sale_id>
|
|
153
|
+
--oz <amount>
|
|
154
|
+
--price <dollars>
|
|
155
|
+
--buyer <name>
|
|
156
|
+
--sell-date <YYYY-MM-DD>
|
|
157
|
+
delete <sale_id> [--yes]
|
|
158
|
+
|
|
159
|
+
tasting (member)
|
|
160
|
+
get <catalog_id>
|
|
161
|
+
--filter <user|supplier|both> default both
|
|
162
|
+
rate [inventory_id]
|
|
163
|
+
--aroma <1-5> required in flag mode
|
|
164
|
+
--body <1-5> required in flag mode
|
|
165
|
+
--acidity <1-5> required in flag mode
|
|
166
|
+
--sweetness <1-5> required in flag mode
|
|
167
|
+
--aftertaste <1-5> required in flag mode
|
|
168
|
+
--brew-method <method>
|
|
169
|
+
--notes <text>
|
|
170
|
+
--form
|
|
171
|
+
|
|
172
|
+
config
|
|
173
|
+
list
|
|
174
|
+
get <key>
|
|
175
|
+
set <key> <value>
|
|
176
|
+
reset
|
|
177
|
+
|
|
178
|
+
Current config keys:
|
|
179
|
+
form-mode true|false
|
|
180
|
+
|
|
181
|
+
WORKFLOWS
|
|
182
|
+
---------
|
|
183
|
+
Catalog -> inventory:
|
|
184
|
+
purvey catalog search --origin "Ethiopia" --stocked --pretty
|
|
185
|
+
purvey inventory add --catalog-id 128 --qty 10 --cost 8.50
|
|
186
|
+
|
|
187
|
+
Import a roast from Artisan:
|
|
188
|
+
purvey inventory list --stocked --pretty
|
|
189
|
+
purvey roast import ~/artisan/ethiopia.alog --coffee-id 7 --pretty
|
|
190
|
+
|
|
191
|
+
Watch a folder for new roasts:
|
|
192
|
+
purvey roast watch ~/artisan/ --coffee-id 7
|
|
193
|
+
purvey roast watch ~/artisan/ --auto-match
|
|
194
|
+
purvey roast watch --resume
|
|
195
|
+
|
|
196
|
+
Rate coffee and record a sale:
|
|
197
|
+
purvey tasting rate 7 --aroma 4 --body 3 --acidity 5 --sweetness 4 --aftertaste 4
|
|
198
|
+
purvey sales record --roast-id 123 --oz 12 --price 22.00 --buyer "Jane Smith"
|
|
199
|
+
|
|
200
|
+
ERROR PATTERNS
|
|
38
201
|
--------------
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
--csv: CSV rows (pipeable to spreadsheets)
|
|
42
|
-
User feedback (spinners, success/error) → stderr only; stdout is always clean data.
|
|
43
|
-
|
|
44
|
-
DATA MODEL
|
|
45
|
-
----------
|
|
46
|
-
coffee_catalog (catalog_id)
|
|
47
|
-
└─ green_coffee_inv (id, user, catalog_id) ← your inventory
|
|
48
|
-
├─ roast_data (roast_id, coffee_id) ← your roast profiles
|
|
49
|
-
│ ├─ roast_temperatures ← temperature curve
|
|
50
|
-
│ └─ roast_events ← FC, drop, etc.
|
|
51
|
-
├─ coffee_sales (id, roast_id) ← your sales
|
|
52
|
-
└─ cupping notes stored on green_coffee_inv (aroma/body/acidity/sweetness/aftertaste)
|
|
53
|
-
|
|
54
|
-
CATALOG COMMANDS (no auth required)
|
|
55
|
-
-------------------------------------
|
|
56
|
-
Search the public catalog:
|
|
57
|
-
purvey catalog search [options]
|
|
58
|
-
Options (all optional):
|
|
59
|
-
--origin <text> country/region (e.g. "Ethiopia", "Colombia")
|
|
60
|
-
--process <method> natural|washed|honey
|
|
61
|
-
--price-min <n> min USD/lb (filters on price_per_lb)
|
|
62
|
-
--price-max <n> max USD/lb (filters on price_per_lb)
|
|
63
|
-
--flavor <keywords> comma-separated (e.g. "blueberry,citrus")
|
|
64
|
-
--name <text> filter by coffee name (partial match, case-insensitive)
|
|
65
|
-
--supplier <name> filter by supplier/source name (partial match, case-insensitive)
|
|
66
|
-
--ids <n,n,...> fetch specific catalog IDs (comma-separated, ignores limit)
|
|
67
|
-
--stocked only currently stocked
|
|
68
|
-
--sort <field> price|price-desc|name|origin|newest
|
|
69
|
-
--offset <n> skip N results for pagination (default: 0)
|
|
70
|
-
--limit <n> max results (default: 10)
|
|
71
|
-
Returns: array of catalog items with id, name, origin, process, flavor_notes, price_per_lb, cost_lb, stocked
|
|
72
|
-
|
|
73
|
-
Get one catalog item by ID:
|
|
74
|
-
purvey catalog get <catalog_id>
|
|
75
|
-
Returns: single catalog item object
|
|
76
|
-
|
|
77
|
-
Catalog statistics:
|
|
78
|
-
purvey catalog stats
|
|
79
|
-
Returns: aggregate stats (count, avg_price, origins, processes, etc.)
|
|
80
|
-
|
|
81
|
-
INVENTORY COMMANDS (member role required)
|
|
82
|
-
------------------------------------------
|
|
83
|
-
List your green coffee inventory:
|
|
84
|
-
purvey inventory list [options]
|
|
85
|
-
Options:
|
|
86
|
-
--stocked only stocked beans
|
|
87
|
-
--limit <n> max results (default: 20)
|
|
88
|
-
Returns: array with id, catalog_id, qty, cost, stocked, purchase_date, plus joined catalog fields
|
|
89
|
-
|
|
90
|
-
Get one inventory item:
|
|
91
|
-
purvey inventory get <id>
|
|
92
|
-
Returns: single inventory item
|
|
93
|
-
|
|
94
|
-
Add bean to inventory (REQUIRED: --catalog-id, --qty):
|
|
95
|
-
purvey inventory add --catalog-id <id> --qty <lbs> [options]
|
|
96
|
-
Options:
|
|
97
|
-
--catalog-id <id> [REQUIRED] coffee_catalog id
|
|
98
|
-
--qty <lbs> [REQUIRED] pounds purchased
|
|
99
|
-
--cost <dollars> cost per lb
|
|
100
|
-
--tax-ship <dollars> tax + shipping cost
|
|
101
|
-
--notes <text> notes
|
|
102
|
-
--purchase-date <YYYY-MM-DD> defaults to today
|
|
103
|
-
--form interactive wizard
|
|
104
|
-
Returns: created inventory item
|
|
105
|
-
|
|
106
|
-
Update inventory item:
|
|
107
|
-
purvey inventory update <id> [options]
|
|
108
|
-
Options (at least one required):
|
|
109
|
-
--qty <lbs> updated quantity
|
|
110
|
-
--cost <dollars> updated cost
|
|
111
|
-
--tax-ship <dollars> updated tax/shipping
|
|
112
|
-
--notes <text> updated notes
|
|
113
|
-
--stocked <true|false> mark as stocked/unstocked
|
|
114
|
-
Returns: updated inventory item
|
|
115
|
-
|
|
116
|
-
Delete inventory item:
|
|
117
|
-
purvey inventory delete <id> [-y]
|
|
118
|
-
-y skips confirmation prompt
|
|
119
|
-
|
|
120
|
-
ROAST COMMANDS (member role required)
|
|
121
|
-
---------------------------------------
|
|
122
|
-
List roast profiles:
|
|
123
|
-
purvey roast list [options]
|
|
124
|
-
Options:
|
|
125
|
-
--coffee-id <id> filter by inventory item id
|
|
126
|
-
--limit <n> max results (default: 20)
|
|
127
|
-
Returns: array of roast profiles with roast_id, batch_name, roast_date, oz_in, oz_out
|
|
128
|
-
|
|
129
|
-
Get roast profile:
|
|
130
|
-
purvey roast get <roast_id> [options]
|
|
131
|
-
Options:
|
|
132
|
-
--include-temps include temperature curve data
|
|
133
|
-
--include-events include roast events (FC, drop, etc.)
|
|
134
|
-
Returns: roast profile object
|
|
135
|
-
|
|
136
|
-
Create roast profile (REQUIRED: --coffee-id):
|
|
137
|
-
purvey roast create --coffee-id <id> [options]
|
|
138
|
-
Options:
|
|
139
|
-
--coffee-id <id> [REQUIRED] green_coffee_inv id
|
|
140
|
-
--batch-name <name> defaults to "CoffeeName YYYY-MM-DD"
|
|
141
|
-
--oz-in <oz> green weight in ounces
|
|
142
|
-
--oz-out <oz> roasted weight in ounces
|
|
143
|
-
--roast-date <YYYY-MM-DD> defaults to today
|
|
144
|
-
--notes <text> roast notes
|
|
145
|
-
--form interactive wizard
|
|
146
|
-
Returns: created roast profile
|
|
147
|
-
|
|
148
|
-
Delete roast profile:
|
|
149
|
-
purvey roast delete <roast_id> [-y]
|
|
150
|
-
|
|
151
|
-
Update roast profile:
|
|
152
|
-
purvey roast update <roast_id> [options]
|
|
153
|
-
Options:
|
|
154
|
-
--notes <text> updated roast notes
|
|
155
|
-
--oz-out <oz> updated roasted weight (recalculates weight_loss_percent)
|
|
156
|
-
--batch-name <name> updated batch name
|
|
157
|
-
--targets <text> updated roast targets (planning/goals)
|
|
158
|
-
At least one flag required.
|
|
202
|
+
Not logged in:
|
|
203
|
+
run purvey auth login or purvey auth login --headless
|
|
159
204
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
Options:
|
|
163
|
-
--coffee-id <id> [REQUIRED] green_coffee_inv id
|
|
164
|
-
--batch-name <name> auto-generated if omitted
|
|
165
|
-
--oz-in <oz> extracted from .alog if omitted
|
|
166
|
-
--roast-notes <text> additional notes
|
|
167
|
-
--form interactive wizard
|
|
168
|
-
Returns: roast profile + milestone_events + control_events counts
|
|
169
|
-
|
|
170
|
-
Watch directory for new .alog files (REQUIRED: <directory>):
|
|
171
|
-
purvey roast watch <directory> [options]
|
|
172
|
-
Options:
|
|
173
|
-
--coffee-id <id> [REQUIRED unless --auto-match] green_coffee_inv id
|
|
174
|
-
--batch-prefix <name> prefix for batch names
|
|
175
|
-
--auto-match AI matches bean per file (requires member role; mutually exclusive with --coffee-id)
|
|
176
|
-
--prompt-each prompt for bean on each new file
|
|
177
|
-
--resume resume previous watch session
|
|
178
|
-
--form interactive wizard
|
|
179
|
-
Runs continuously (Ctrl+C to stop). Persists session for --resume.
|
|
180
|
-
|
|
181
|
-
SALES COMMANDS (member role required)
|
|
182
|
-
---------------------------------------
|
|
183
|
-
List sales:
|
|
184
|
-
purvey sales list [--limit <n>]
|
|
185
|
-
Returns: array with id, roast_id, oz, price, buyer, sell_date
|
|
186
|
-
|
|
187
|
-
Record sale (REQUIRED: --roast-id, --oz, --price):
|
|
188
|
-
purvey sales record --roast-id <id> --oz <amount> --price <dollars> [options]
|
|
189
|
-
Options:
|
|
190
|
-
--roast-id <id> [REQUIRED] roast_data id
|
|
191
|
-
--oz <amount> [REQUIRED] ounces sold
|
|
192
|
-
--price <dollars> [REQUIRED] sale price
|
|
193
|
-
--buyer <name> buyer name/identifier
|
|
194
|
-
--sell-date <YYYY-MM-DD> defaults to today
|
|
195
|
-
--form interactive wizard
|
|
196
|
-
Returns: created sale record
|
|
197
|
-
|
|
198
|
-
Update sale:
|
|
199
|
-
purvey sales update <id> [--oz <n>] [--price <n>] [--buyer <name>] [--sell-date <date>]
|
|
200
|
-
|
|
201
|
-
Delete sale:
|
|
202
|
-
purvey sales delete <id> [-y]
|
|
203
|
-
|
|
204
|
-
TASTING COMMANDS (member role required)
|
|
205
|
-
-----------------------------------------
|
|
206
|
-
Get tasting notes for a catalog item:
|
|
207
|
-
purvey tasting get <catalog_id> [--filter user|supplier|both]
|
|
208
|
-
--filter both (default): returns {supplier: {...}, user: {...}}
|
|
209
|
-
--filter user: only your cupping notes from green_coffee_inv
|
|
210
|
-
--filter supplier: only the supplier's flavor notes from coffee_catalog
|
|
211
|
-
|
|
212
|
-
Rate a bean (REQUIRED: <inventory_id>, all score flags):
|
|
213
|
-
purvey tasting rate <inventory_id> --aroma <1-5> --body <1-5> --acidity <1-5> --sweetness <1-5> --aftertaste <1-5> [options]
|
|
214
|
-
Options:
|
|
215
|
-
--aroma <1-5> [REQUIRED in flag mode] integer 1-5
|
|
216
|
-
--body <1-5> [REQUIRED in flag mode] integer 1-5
|
|
217
|
-
--acidity <1-5> [REQUIRED in flag mode] integer 1-5
|
|
218
|
-
--sweetness <1-5> [REQUIRED in flag mode] integer 1-5
|
|
219
|
-
--aftertaste <1-5> [REQUIRED in flag mode] integer 1-5
|
|
220
|
-
--brew-method pour_over|french_press|espresso|etc
|
|
221
|
-
--notes <text> tasting notes
|
|
222
|
-
--form interactive wizard
|
|
223
|
-
Note: <inventory_id> is green_coffee_inv.id, NOT catalog_id.
|
|
224
|
-
Scores are stored on the green_coffee_inv row.
|
|
225
|
-
|
|
226
|
-
CONFIG COMMANDS
|
|
227
|
-
---------------
|
|
228
|
-
purvey config list show all config
|
|
229
|
-
purvey config get form-mode get a value
|
|
230
|
-
purvey config set form-mode true|false set a value
|
|
231
|
-
purvey config reset clear all config
|
|
232
|
-
|
|
233
|
-
Config keys:
|
|
234
|
-
form-mode true|false — when true, write commands auto-enter interactive
|
|
235
|
-
wizard if required args are missing (default: false)
|
|
236
|
-
|
|
237
|
-
COMMON WORKFLOWS
|
|
238
|
-
----------------
|
|
239
|
-
1. Import a roast and rate it:
|
|
240
|
-
purvey inventory list --stocked --pretty # find your bean id
|
|
241
|
-
purvey roast import roast.alog --coffee-id 42 # import
|
|
242
|
-
purvey tasting rate 42 --aroma 4 --body 3 --acidity 5 --sweetness 4 --aftertaste 4
|
|
243
|
-
|
|
244
|
-
2. Full workflow: buy → roast → sell:
|
|
245
|
-
purvey catalog search --origin "Ethiopia" --stocked --pretty
|
|
246
|
-
purvey inventory add --catalog-id 128 --qty 10 --cost 8.50
|
|
247
|
-
purvey roast create --coffee-id 7 --oz-in 16 --batch-name "Ethiopia Guji Light"
|
|
248
|
-
purvey sales record --roast-id 123 --oz 12 --price 22.00 --buyer "Jane"
|
|
249
|
-
|
|
250
|
-
3. Watch directory and auto-import roasts:
|
|
251
|
-
purvey roast watch ~/artisan/ --coffee-id 7
|
|
252
|
-
# or with AI bean matching:
|
|
253
|
-
purvey roast watch ~/artisan/ --auto-match
|
|
254
|
-
|
|
255
|
-
4. Find a coffee and check tasting notes:
|
|
256
|
-
purvey catalog search --flavor "blueberry,floral" --pretty
|
|
257
|
-
purvey tasting get 128 --filter both --pretty
|
|
258
|
-
|
|
259
|
-
ERROR HANDLING
|
|
260
|
-
--------------
|
|
261
|
-
Exit 0: success
|
|
262
|
-
Exit 1: error (auth failure, not found, validation error, API error)
|
|
263
|
-
Errors go to stderr as: Error: <message>
|
|
205
|
+
Wrong ID type:
|
|
206
|
+
verify whether the command wants catalog_id, inventory_id, roast_id, or sale_id
|
|
264
207
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
"Not found" → check the ID; must be yours (RLS enforced)
|
|
268
|
-
"INVALID_ARGUMENT" → check flags; use --form for interactive mode
|
|
269
|
-
"--auto-match and --coffee-id are mutually exclusive" → use one or the other
|
|
208
|
+
Missing required args in write commands:
|
|
209
|
+
pass the required flags or use --form
|
|
270
210
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
catalog_id → coffee_catalog table; used with: catalog get, inventory add --catalog-id, tasting get
|
|
274
|
-
inventory_id → green_coffee_inv table (your beans); used with: inventory get/update/delete, roast --coffee-id, tasting rate
|
|
275
|
-
roast_id → roast_data table; used with: roast get/delete, sales --roast-id
|
|
276
|
-
sale_id → coffee_sales table; used with: sales update/delete
|
|
211
|
+
Mutually exclusive watch flags:
|
|
212
|
+
roast watch forbids using --auto-match together with --coffee-id
|
|
277
213
|
`.trim();
|
|
278
|
-
// ─── Command builder ──────────────────────────────────────────────────────────
|
|
279
|
-
/**
|
|
280
|
-
* `purvey context`
|
|
281
|
-
* Outputs a comprehensive CLI reference for AI agent onboarding.
|
|
282
|
-
* Optimized for token efficiency — dense, structured, no fluff.
|
|
283
|
-
*/
|
|
284
214
|
export function buildContextCommand() {
|
|
285
215
|
return new Command('context')
|
|
286
216
|
.description('Output full CLI reference for AI agent onboarding')
|
|
287
217
|
.addHelpText('after', `
|
|
288
218
|
Examples:
|
|
289
|
-
purvey context
|
|
290
|
-
purvey context | head -50
|
|
291
|
-
purvey context > cli-
|
|
219
|
+
purvey context
|
|
220
|
+
purvey context | head -50
|
|
221
|
+
purvey context > cli-reference.txt
|
|
292
222
|
`)
|
|
293
223
|
.action(() => {
|
|
294
224
|
console.log(CONTEXT_TEXT);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,6EAA6E;AAC7E,kEAAkE;AAElE,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiNpB,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,UAAU,mBAAmB;IACjC,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC;SAC1B,WAAW,CAAC,mDAAmD,CAAC;SAChE,WAAW,CACV,OAAO,EACP;;;;;CAKL,CACI;SACA,MAAM,CAAC,GAAG,EAAE;QACX,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roast.d.ts","sourceRoot":"","sources":["../../src/commands/roast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,eAAe,EAEhB,MAAM,iBAAiB,CAAC;AAOzB,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,CAAC;AAIhE;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,
|
|
1
|
+
{"version":3,"file":"roast.d.ts","sourceRoot":"","sources":["../../src/commands/roast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,eAAe,EAEhB,MAAM,iBAAiB,CAAC;AAOzB,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,CAAC;AAIhE;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAgyB3C"}
|
package/dist/commands/roast.js
CHANGED
|
@@ -22,24 +22,70 @@ export function buildRoastCommand() {
|
|
|
22
22
|
.command('list')
|
|
23
23
|
.description('List your roast profiles, sorted by date (newest first)')
|
|
24
24
|
.option('--coffee-id <id>', 'Filter by green_coffee_inv ID')
|
|
25
|
+
.option('--roast-id <id>', 'Filter by roast profile ID')
|
|
26
|
+
.option('--batch-name <text>', 'Filter by batch name (partial match, case-insensitive)')
|
|
27
|
+
.option('--date-start <YYYY-MM-DD>', 'Only show roasts on or after this date')
|
|
28
|
+
.option('--date-end <YYYY-MM-DD>', 'Only show roasts on or before this date')
|
|
29
|
+
.option('--stocked', 'Only show roasts for currently stocked beans')
|
|
30
|
+
.option('--catalog-id <id>', 'Filter by coffee_catalog ID')
|
|
25
31
|
.option('--limit <n>', 'Maximum results to return', '20')
|
|
26
32
|
.addHelpText('after', `
|
|
27
33
|
Examples:
|
|
28
34
|
purvey roast list --pretty
|
|
29
35
|
purvey roast list --coffee-id 7 --pretty
|
|
36
|
+
purvey roast list --roast-id 123 --pretty
|
|
37
|
+
purvey roast list --batch-name "Ethiopia Guji" --pretty
|
|
38
|
+
purvey roast list --date-start 2026-03-01 --date-end 2026-03-31
|
|
39
|
+
purvey roast list --stocked --limit 10
|
|
40
|
+
purvey roast list --catalog-id 128 --pretty
|
|
30
41
|
purvey roast list --limit 5 | jq '.[].roast_id'
|
|
31
42
|
purvey roast list --csv > roasts.csv
|
|
32
43
|
|
|
33
44
|
Notes:
|
|
34
45
|
--coffee-id filters by inventory item (green_coffee_inv.id), not catalog_id.
|
|
46
|
+
--roast-id filters by the exact roast profile ID while preserving list output shape.
|
|
47
|
+
--catalog-id filters by coffee_catalog ID (cross-reference from catalog search).
|
|
48
|
+
--batch-name accepts partial matches (case-insensitive).
|
|
49
|
+
--date-start and --date-end accept YYYY-MM-DD format; use together for a range.
|
|
50
|
+
--stocked only returns roasts for beans currently marked as stocked in inventory.
|
|
35
51
|
Returns roast_id, batch_name, roast_date, oz_in, oz_out, and bean details.
|
|
36
52
|
Requires authentication (member role).
|
|
37
53
|
`)
|
|
38
54
|
.action(withErrorHandling(async (opts, cmd) => {
|
|
39
55
|
const globalOpts = cmd.optsWithGlobals();
|
|
40
56
|
const { supabase, userId } = await requireAuth('member');
|
|
57
|
+
// Parse --date-start and --date-end format
|
|
58
|
+
const dateStart = opts.dateStart;
|
|
59
|
+
const dateEnd = opts.dateEnd;
|
|
60
|
+
if (dateStart && !/^\d{4}-\d{2}-\d{2}$/.test(dateStart)) {
|
|
61
|
+
throw new PrvrsError('INVALID_ARGUMENT', `Invalid --date-start: "${dateStart}". Must be YYYY-MM-DD format.`);
|
|
62
|
+
}
|
|
63
|
+
if (dateEnd && !/^\d{4}-\d{2}-\d{2}$/.test(dateEnd)) {
|
|
64
|
+
throw new PrvrsError('INVALID_ARGUMENT', `Invalid --date-end: "${dateEnd}". Must be YYYY-MM-DD format.`);
|
|
65
|
+
}
|
|
66
|
+
// Parse exact-id filters
|
|
67
|
+
let roastId;
|
|
68
|
+
if (opts.roastId !== undefined) {
|
|
69
|
+
roastId = parseInt(opts.roastId, 10);
|
|
70
|
+
if (isNaN(roastId) || roastId <= 0) {
|
|
71
|
+
throw new PrvrsError('INVALID_ARGUMENT', `Invalid --roast-id: "${opts.roastId}". Must be a positive integer.`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
let catalogId;
|
|
75
|
+
if (opts.catalogId !== undefined) {
|
|
76
|
+
catalogId = parseInt(opts.catalogId, 10);
|
|
77
|
+
if (isNaN(catalogId) || catalogId <= 0) {
|
|
78
|
+
throw new PrvrsError('INVALID_ARGUMENT', `Invalid --catalog-id: "${opts.catalogId}". Must be a positive integer.`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
41
81
|
const data = await listRoasts(supabase, userId, {
|
|
42
82
|
coffee_id: opts.coffeeId !== undefined ? parseInt(opts.coffeeId, 10) : undefined,
|
|
83
|
+
roast_id: roastId,
|
|
84
|
+
batch_name: opts.batchName,
|
|
85
|
+
date_start: dateStart,
|
|
86
|
+
date_end: dateEnd,
|
|
87
|
+
stocked_only: opts.stocked === true ? true : undefined,
|
|
88
|
+
catalog_id: catalogId,
|
|
43
89
|
limit: Math.max(1, parseInt(opts.limit, 10)),
|
|
44
90
|
});
|
|
45
91
|
if (data.length === 0) {
|