@purveyors/cli 0.3.0 → 0.4.1
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/dist/commands/config.d.ts +7 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +82 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/inventory.d.ts.map +1 -1
- package/dist/commands/inventory.js +65 -2
- package/dist/commands/inventory.js.map +1 -1
- package/dist/commands/roast.d.ts.map +1 -1
- package/dist/commands/roast.js +315 -3
- package/dist/commands/roast.js.map +1 -1
- package/dist/commands/sales.d.ts.map +1 -1
- package/dist/commands/sales.js +73 -3
- package/dist/commands/sales.js.map +1 -1
- package/dist/commands/tasting.d.ts.map +1 -1
- package/dist/commands/tasting.js +81 -11
- package/dist/commands/tasting.js.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/ai.d.ts +36 -0
- package/dist/lib/ai.d.ts.map +1 -0
- package/dist/lib/ai.js +42 -0
- package/dist/lib/ai.js.map +1 -0
- package/dist/lib/config.d.ts +26 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +59 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/interactive/forms.d.ts +33 -0
- package/dist/lib/interactive/forms.d.ts.map +1 -0
- package/dist/lib/interactive/forms.js +139 -0
- package/dist/lib/interactive/forms.js.map +1 -0
- package/dist/lib/interactive/watch.d.ts +66 -0
- package/dist/lib/interactive/watch.d.ts.map +1 -0
- package/dist/lib/interactive/watch.js +494 -0
- package/dist/lib/interactive/watch.js.map +1 -0
- package/dist/lib/supabase.d.ts.map +1 -1
- package/dist/lib/supabase.js +16 -1
- package/dist/lib/supabase.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Watch module for `purvey roast watch`.
|
|
3
|
+
* CLI-only — not exported via package.json subpaths.
|
|
4
|
+
*
|
|
5
|
+
* Monitors a directory for new .alog files, imports them automatically,
|
|
6
|
+
* and shows a verification table when the session ends (Ctrl+C).
|
|
7
|
+
*/
|
|
8
|
+
import { watch } from 'fs';
|
|
9
|
+
import { readFile, access, writeFile, mkdir } from 'fs/promises';
|
|
10
|
+
import { join, extname } from 'path';
|
|
11
|
+
import { constants } from 'fs';
|
|
12
|
+
import { importRoastFromFile } from '../roast.js';
|
|
13
|
+
import { CONFIG_DIR } from '../config.js';
|
|
14
|
+
// ─── Session persistence ──────────────────────────────────────────────────────
|
|
15
|
+
const SESSION_FILE = join(CONFIG_DIR, 'watch-session.json');
|
|
16
|
+
/** Persist session state to disk after each import. */
|
|
17
|
+
export async function saveWatchSession(session) {
|
|
18
|
+
await mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
19
|
+
await writeFile(SESSION_FILE, JSON.stringify(session, null, 2) + '\n', { mode: 0o600 });
|
|
20
|
+
}
|
|
21
|
+
/** Load a previously saved watch session. Returns null if none exists. */
|
|
22
|
+
export async function loadWatchSession() {
|
|
23
|
+
try {
|
|
24
|
+
await access(SESSION_FILE, constants.R_OK);
|
|
25
|
+
const raw = await readFile(SESSION_FILE, 'utf-8');
|
|
26
|
+
return JSON.parse(raw);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// ─── Batch name generation ────────────────────────────────────────────────────
|
|
33
|
+
/**
|
|
34
|
+
* Generate a sequential batch name: "{prefix} #{n}".
|
|
35
|
+
* sequence is 1-based (first import = 1).
|
|
36
|
+
*/
|
|
37
|
+
export function generateBatchName(prefix, sequence) {
|
|
38
|
+
return `${prefix} #${sequence}`;
|
|
39
|
+
}
|
|
40
|
+
// ─── File extension filter ────────────────────────────────────────────────────
|
|
41
|
+
/** Returns true if filename has a .alog extension (case-insensitive). */
|
|
42
|
+
export function isAlogFile(filename) {
|
|
43
|
+
return extname(filename).toLowerCase() === '.alog';
|
|
44
|
+
}
|
|
45
|
+
// ─── Verification table ───────────────────────────────────────────────────────
|
|
46
|
+
/** Render a padded verification table and print to stderr. */
|
|
47
|
+
export function printVerificationTable(session, autoMatch) {
|
|
48
|
+
const imports = session.imports;
|
|
49
|
+
const showAiColumns = autoMatch === true || imports.some((r) => r.aiMatch !== undefined);
|
|
50
|
+
if (showAiColumns) {
|
|
51
|
+
printVerificationTableAutoMatch(imports);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
printVerificationTableStandard(imports);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function printVerificationTableStandard(imports) {
|
|
58
|
+
// Column widths
|
|
59
|
+
const COL_FILE = 31;
|
|
60
|
+
const COL_ID = 10;
|
|
61
|
+
const COL_BATCH = 26;
|
|
62
|
+
const COL_STATUS = 9;
|
|
63
|
+
function row(file, id, batch, status) {
|
|
64
|
+
return ('│ ' +
|
|
65
|
+
file.padEnd(COL_FILE) +
|
|
66
|
+
'│ ' +
|
|
67
|
+
id.padEnd(COL_ID) +
|
|
68
|
+
'│ ' +
|
|
69
|
+
batch.padEnd(COL_BATCH) +
|
|
70
|
+
'│ ' +
|
|
71
|
+
status.padEnd(COL_STATUS) +
|
|
72
|
+
'│');
|
|
73
|
+
}
|
|
74
|
+
function hline(left, mid, right, fill) {
|
|
75
|
+
return (left +
|
|
76
|
+
fill.repeat(COL_FILE + 2) +
|
|
77
|
+
mid +
|
|
78
|
+
fill.repeat(COL_ID + 2) +
|
|
79
|
+
mid +
|
|
80
|
+
fill.repeat(COL_BATCH + 2) +
|
|
81
|
+
mid +
|
|
82
|
+
fill.repeat(COL_STATUS + 2) +
|
|
83
|
+
right);
|
|
84
|
+
}
|
|
85
|
+
const lines = [];
|
|
86
|
+
lines.push('');
|
|
87
|
+
lines.push(hline('┌', '┬', '┐', '─'));
|
|
88
|
+
lines.push(row('File', 'Roast ID', 'Batch', 'Status'));
|
|
89
|
+
lines.push(hline('├', '┼', '┤', '─'));
|
|
90
|
+
if (imports.length === 0) {
|
|
91
|
+
lines.push(row('(no files imported)', '', '', ''));
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
for (const rec of imports) {
|
|
95
|
+
const file = rec.fileName.length > COL_FILE ? rec.fileName.slice(0, COL_FILE - 1) + '…' : rec.fileName;
|
|
96
|
+
const id = rec.status === 'success' ? `#${rec.roastId}` : '—';
|
|
97
|
+
const batch = rec.batchName.length > COL_BATCH
|
|
98
|
+
? rec.batchName.slice(0, COL_BATCH - 1) + '…'
|
|
99
|
+
: rec.batchName;
|
|
100
|
+
const status = rec.status === 'success' ? '✓' : `✗ ${rec.error?.slice(0, 5) ?? 'Error'}`;
|
|
101
|
+
lines.push(row(file, id, batch, status));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
lines.push(hline('└', '┴', '┘', '─'));
|
|
105
|
+
const succeeded = imports.filter((r) => r.status === 'success').length;
|
|
106
|
+
const failed = imports.filter((r) => r.status === 'failed').length;
|
|
107
|
+
lines.push('');
|
|
108
|
+
lines.push(`Session: ${imports.length} file${imports.length !== 1 ? 's' : ''} processed, ${succeeded} succeeded, ${failed} failed`);
|
|
109
|
+
lines.push('');
|
|
110
|
+
process.stderr.write(lines.join('\n') + '\n');
|
|
111
|
+
}
|
|
112
|
+
function printVerificationTableAutoMatch(imports) {
|
|
113
|
+
// Column widths for auto-match table
|
|
114
|
+
const COL_FILE = 29;
|
|
115
|
+
const COL_ID = 9;
|
|
116
|
+
const COL_BEAN = 22;
|
|
117
|
+
const COL_CONF = 10;
|
|
118
|
+
const COL_STATUS = 7;
|
|
119
|
+
function row(file, id, bean, conf, status) {
|
|
120
|
+
return ('│ ' +
|
|
121
|
+
file.padEnd(COL_FILE) +
|
|
122
|
+
'│ ' +
|
|
123
|
+
id.padEnd(COL_ID) +
|
|
124
|
+
'│ ' +
|
|
125
|
+
bean.padEnd(COL_BEAN) +
|
|
126
|
+
'│ ' +
|
|
127
|
+
conf.padEnd(COL_CONF) +
|
|
128
|
+
'│ ' +
|
|
129
|
+
status.padEnd(COL_STATUS) +
|
|
130
|
+
'│');
|
|
131
|
+
}
|
|
132
|
+
function hline(left, mid, right, fill) {
|
|
133
|
+
return (left +
|
|
134
|
+
fill.repeat(COL_FILE + 2) +
|
|
135
|
+
mid +
|
|
136
|
+
fill.repeat(COL_ID + 2) +
|
|
137
|
+
mid +
|
|
138
|
+
fill.repeat(COL_BEAN + 2) +
|
|
139
|
+
mid +
|
|
140
|
+
fill.repeat(COL_CONF + 2) +
|
|
141
|
+
mid +
|
|
142
|
+
fill.repeat(COL_STATUS + 2) +
|
|
143
|
+
right);
|
|
144
|
+
}
|
|
145
|
+
const lines = [];
|
|
146
|
+
lines.push('');
|
|
147
|
+
lines.push(hline('┌', '┬', '┐', '─'));
|
|
148
|
+
lines.push(row('File', 'Roast ID', 'Matched Bean', 'Confidence', 'Status'));
|
|
149
|
+
lines.push(hline('├', '┼', '┤', '─'));
|
|
150
|
+
if (imports.length === 0) {
|
|
151
|
+
lines.push(row('(no files imported)', '', '', '', ''));
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
for (const rec of imports) {
|
|
155
|
+
const file = rec.fileName.length > COL_FILE ? rec.fileName.slice(0, COL_FILE - 1) + '…' : rec.fileName;
|
|
156
|
+
const id = rec.status === 'success' && rec.roastId !== null ? `#${rec.roastId}` : '—';
|
|
157
|
+
const beanName = rec.aiMatch?.coffeeName ?? (rec.status === 'needs-review' ? '(needs review)' : '—');
|
|
158
|
+
const bean = beanName.length > COL_BEAN ? beanName.slice(0, COL_BEAN - 1) + '…' : beanName;
|
|
159
|
+
const confVal = rec.aiMatch !== undefined ? `${rec.aiMatch.confidence}%` : '';
|
|
160
|
+
const conf = confVal.padEnd(COL_CONF);
|
|
161
|
+
const status = rec.status === 'success'
|
|
162
|
+
? '✓'
|
|
163
|
+
: rec.status === 'needs-review'
|
|
164
|
+
? '⚠'
|
|
165
|
+
: `✗ ${rec.error?.slice(0, 4) ?? 'Err'}`;
|
|
166
|
+
lines.push(row(file, id, bean, conf, status));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
lines.push(hline('└', '┴', '┘', '─'));
|
|
170
|
+
const succeeded = imports.filter((r) => r.status === 'success').length;
|
|
171
|
+
const failed = imports.filter((r) => r.status === 'failed').length;
|
|
172
|
+
const needsReview = imports.filter((r) => r.status === 'needs-review').length;
|
|
173
|
+
lines.push('');
|
|
174
|
+
let summary = `Session: ${imports.length} file${imports.length !== 1 ? 's' : ''} processed, ${succeeded} succeeded, ${failed} failed`;
|
|
175
|
+
if (needsReview > 0) {
|
|
176
|
+
summary += `, ${needsReview} need${needsReview !== 1 ? '' : 's'} review`;
|
|
177
|
+
}
|
|
178
|
+
lines.push(summary);
|
|
179
|
+
lines.push('');
|
|
180
|
+
process.stderr.write(lines.join('\n') + '\n');
|
|
181
|
+
}
|
|
182
|
+
// ─── Main watch function ──────────────────────────────────────────────────────
|
|
183
|
+
/**
|
|
184
|
+
* Start watching a directory for new .alog files.
|
|
185
|
+
* Blocks until SIGINT (Ctrl+C), then prints a summary table and resolves.
|
|
186
|
+
*
|
|
187
|
+
* @param supabase Authenticated Supabase client
|
|
188
|
+
* @param userId Authenticated user ID
|
|
189
|
+
* @param directory Absolute or relative path to watch
|
|
190
|
+
* @param opts Watch options
|
|
191
|
+
* @returns The final WatchSession (all imports recorded)
|
|
192
|
+
*/
|
|
193
|
+
export async function startWatch(supabase, userId, directory, opts) {
|
|
194
|
+
// 1. Validate directory exists
|
|
195
|
+
try {
|
|
196
|
+
await access(directory, constants.R_OK);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
throw new Error(`Directory not found or not readable: "${directory}"`);
|
|
200
|
+
}
|
|
201
|
+
// 2. Snapshot existing .alog files so we only react to NEW ones
|
|
202
|
+
const { readdir } = await import('fs/promises');
|
|
203
|
+
const existingFiles = new Set();
|
|
204
|
+
try {
|
|
205
|
+
const entries = await readdir(directory);
|
|
206
|
+
for (const entry of entries) {
|
|
207
|
+
if (isAlogFile(entry)) {
|
|
208
|
+
existingFiles.add(entry);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// Non-fatal — if readdir fails we just won't filter pre-existing files
|
|
214
|
+
}
|
|
215
|
+
// 3. Create session state
|
|
216
|
+
const session = {
|
|
217
|
+
directory,
|
|
218
|
+
coffeeId: opts.coffeeId,
|
|
219
|
+
coffeeName: opts.coffeeName,
|
|
220
|
+
batchPrefix: opts.batchPrefix,
|
|
221
|
+
startedAt: new Date().toISOString(),
|
|
222
|
+
imports: [],
|
|
223
|
+
};
|
|
224
|
+
const startSequence = opts.startSequence ?? 0;
|
|
225
|
+
// 4. Debounce map: filename → timeout handle
|
|
226
|
+
const debounceTimers = new Map();
|
|
227
|
+
// Track in-progress files to avoid double-processing
|
|
228
|
+
const processing = new Set();
|
|
229
|
+
// processFile: read, import, record result
|
|
230
|
+
async function processFile(filename) {
|
|
231
|
+
if (processing.has(filename))
|
|
232
|
+
return;
|
|
233
|
+
processing.add(filename);
|
|
234
|
+
const filePath = join(directory, filename);
|
|
235
|
+
const sequence = startSequence + session.imports.length + 1;
|
|
236
|
+
const batchName = generateBatchName(opts.batchPrefix, sequence);
|
|
237
|
+
// If promptEach: let user override the bean selection
|
|
238
|
+
let effectiveCoffeeId = opts.coffeeId;
|
|
239
|
+
let effectiveCoffeeName = opts.coffeeName;
|
|
240
|
+
if (opts.promptEach) {
|
|
241
|
+
const { pickBean, guardCancel } = await import('./forms.js');
|
|
242
|
+
process.stderr.write(`\nNew file detected: ${filename}\n`);
|
|
243
|
+
const bean = await pickBean(supabase, userId);
|
|
244
|
+
guardCancel(bean);
|
|
245
|
+
effectiveCoffeeId = bean.id;
|
|
246
|
+
effectiveCoffeeName = bean.name;
|
|
247
|
+
}
|
|
248
|
+
let fileContent;
|
|
249
|
+
try {
|
|
250
|
+
await access(filePath, constants.R_OK);
|
|
251
|
+
fileContent = await readFile(filePath, 'utf-8');
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
const record = {
|
|
255
|
+
fileName: filename,
|
|
256
|
+
roastId: null,
|
|
257
|
+
batchName,
|
|
258
|
+
status: 'failed',
|
|
259
|
+
error: err instanceof Error ? err.message : 'Unreadable',
|
|
260
|
+
importedAt: new Date().toISOString(),
|
|
261
|
+
};
|
|
262
|
+
session.imports.push(record);
|
|
263
|
+
await saveWatchSession(session);
|
|
264
|
+
process.stderr.write(`✗ Failed to read ${filename}: ${record.error}\n`);
|
|
265
|
+
processing.delete(filename);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
// Auto-match mode: use AI to classify the bean
|
|
269
|
+
let aiResult;
|
|
270
|
+
if (opts.autoMatch && !opts.promptEach) {
|
|
271
|
+
aiResult = await runAutoMatch(supabase, userId, filename, fileContent);
|
|
272
|
+
if (aiResult.skip) {
|
|
273
|
+
// AI returned low confidence or failed — mark as needs-review
|
|
274
|
+
const record = {
|
|
275
|
+
fileName: filename,
|
|
276
|
+
roastId: null,
|
|
277
|
+
batchName,
|
|
278
|
+
status: 'needs-review',
|
|
279
|
+
error: aiResult.reason,
|
|
280
|
+
importedAt: new Date().toISOString(),
|
|
281
|
+
...(aiResult.aiMatch !== undefined ? { aiMatch: aiResult.aiMatch } : {}),
|
|
282
|
+
};
|
|
283
|
+
session.imports.push(record);
|
|
284
|
+
await saveWatchSession(session);
|
|
285
|
+
const confStr = aiResult.aiMatch !== undefined ? ` (confidence: ${aiResult.aiMatch.confidence}%)` : '';
|
|
286
|
+
process.stderr.write(`⚠ Needs review: ${filename}${confStr} — ${aiResult.reason}\n`);
|
|
287
|
+
processing.delete(filename);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
effectiveCoffeeId = aiResult.coffeeId;
|
|
291
|
+
effectiveCoffeeName = aiResult.coffeeName;
|
|
292
|
+
process.stderr.write(`🤖 AI matched: ${filename} → ${effectiveCoffeeName} (${aiResult.aiMatch.confidence}% confidence)\n` +
|
|
293
|
+
` Reasoning: ${aiResult.aiMatch.reasoning}\n`);
|
|
294
|
+
}
|
|
295
|
+
try {
|
|
296
|
+
const result = await importRoastFromFile(supabase, userId, {
|
|
297
|
+
fileContent,
|
|
298
|
+
fileName: filename,
|
|
299
|
+
coffeeId: effectiveCoffeeId,
|
|
300
|
+
batchName,
|
|
301
|
+
});
|
|
302
|
+
const milestoneCount = Object.values(result.milestones).filter((v) => v !== undefined && v > 0).length;
|
|
303
|
+
// Carry aiMatch from the local aiResult (threaded as a local variable, not module state)
|
|
304
|
+
const aiMatchField = opts.autoMatch && !opts.promptEach && aiResult?.aiMatch ? aiResult.aiMatch : undefined;
|
|
305
|
+
const record = {
|
|
306
|
+
fileName: filename,
|
|
307
|
+
roastId: result.roast_id,
|
|
308
|
+
batchName,
|
|
309
|
+
status: 'success',
|
|
310
|
+
milestones: result.milestones,
|
|
311
|
+
phases: result.phases,
|
|
312
|
+
importedAt: new Date().toISOString(),
|
|
313
|
+
...(aiMatchField !== undefined ? { aiMatch: aiMatchField } : {}),
|
|
314
|
+
};
|
|
315
|
+
session.imports.push(record);
|
|
316
|
+
await saveWatchSession(session);
|
|
317
|
+
const tempCount = result.message.match(/(\d+) data points/)?.[1] ?? '?';
|
|
318
|
+
process.stderr.write(`✓ Imported: ${filename} → Roast #${result.roast_id} (${tempCount} temps, ${milestoneCount} milestones)` +
|
|
319
|
+
(effectiveCoffeeName !== opts.coffeeName ? ` [${effectiveCoffeeName}]` : '') +
|
|
320
|
+
'\n');
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
324
|
+
const record = {
|
|
325
|
+
fileName: filename,
|
|
326
|
+
roastId: null,
|
|
327
|
+
batchName,
|
|
328
|
+
status: 'failed',
|
|
329
|
+
error: errMsg,
|
|
330
|
+
importedAt: new Date().toISOString(),
|
|
331
|
+
};
|
|
332
|
+
session.imports.push(record);
|
|
333
|
+
await saveWatchSession(session);
|
|
334
|
+
process.stderr.write(`✗ Failed to import ${filename}: ${errMsg}\n`);
|
|
335
|
+
}
|
|
336
|
+
finally {
|
|
337
|
+
processing.delete(filename);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
// debounced handler
|
|
341
|
+
function onFileEvent(filename) {
|
|
342
|
+
if (!isAlogFile(filename))
|
|
343
|
+
return;
|
|
344
|
+
// Skip files that were present when we started
|
|
345
|
+
if (existingFiles.has(filename))
|
|
346
|
+
return;
|
|
347
|
+
if (debounceTimers.has(filename)) {
|
|
348
|
+
clearTimeout(debounceTimers.get(filename));
|
|
349
|
+
}
|
|
350
|
+
debounceTimers.set(filename, setTimeout(() => {
|
|
351
|
+
debounceTimers.delete(filename);
|
|
352
|
+
processFile(filename).catch((err) => {
|
|
353
|
+
process.stderr.write(`✗ Unexpected error processing ${filename}: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
354
|
+
});
|
|
355
|
+
}, 2000));
|
|
356
|
+
}
|
|
357
|
+
// 5. Start fs.watch
|
|
358
|
+
let watcher;
|
|
359
|
+
try {
|
|
360
|
+
watcher = watch(directory, { persistent: true }, (_eventType, filename) => {
|
|
361
|
+
if (filename)
|
|
362
|
+
onFileEvent(filename);
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
catch (err) {
|
|
366
|
+
throw new Error(`Failed to watch directory "${directory}": ${err instanceof Error ? err.message : String(err)}`);
|
|
367
|
+
}
|
|
368
|
+
const modeLabel = opts.autoMatch
|
|
369
|
+
? 'auto-match mode'
|
|
370
|
+
: opts.promptEach
|
|
371
|
+
? 'prompt-each mode'
|
|
372
|
+
: `coffee: ${opts.coffeeName}`;
|
|
373
|
+
process.stderr.write(`👁 Watching ${directory} for new .alog files (${modeLabel}, prefix: "${opts.batchPrefix}")...\n`);
|
|
374
|
+
process.stderr.write(` Press Ctrl+C to stop and view summary.\n\n`);
|
|
375
|
+
// 6. Block until SIGINT, then cleanup and return
|
|
376
|
+
await new Promise((resolve) => {
|
|
377
|
+
process.once('SIGINT', () => {
|
|
378
|
+
// Cancel all pending debounce timers
|
|
379
|
+
for (const timer of debounceTimers.values()) {
|
|
380
|
+
clearTimeout(timer);
|
|
381
|
+
}
|
|
382
|
+
debounceTimers.clear();
|
|
383
|
+
watcher.close();
|
|
384
|
+
process.stderr.write('\n');
|
|
385
|
+
printVerificationTable(session, opts.autoMatch);
|
|
386
|
+
// Prompt about unmatched files if in auto-match mode
|
|
387
|
+
const needsReview = session.imports.filter((r) => r.status === 'needs-review');
|
|
388
|
+
if (opts.autoMatch && needsReview.length > 0) {
|
|
389
|
+
process.stderr.write(`⚠ ${needsReview.length} file${needsReview.length !== 1 ? 's need' : ' needs'} manual bean assignment:\n`);
|
|
390
|
+
for (const rec of needsReview) {
|
|
391
|
+
process.stderr.write(` - ${rec.fileName}\n`);
|
|
392
|
+
}
|
|
393
|
+
process.stderr.write(` Use \`purvey roast import <file> --coffee-id <id>\` to import them manually.\n\n`);
|
|
394
|
+
}
|
|
395
|
+
resolve();
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
return session;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Run AI classification for a newly detected .alog file.
|
|
402
|
+
* Returns skip=true if confidence < 50 or if the AI call fails.
|
|
403
|
+
*/
|
|
404
|
+
async function runAutoMatch(supabase, userId, filename, fileContent) {
|
|
405
|
+
// Parse alog metadata without full import
|
|
406
|
+
let alogMetadata;
|
|
407
|
+
try {
|
|
408
|
+
const { processAlogFile } = await import('../artisan/parser.js');
|
|
409
|
+
const parsed = processAlogFile(fileContent);
|
|
410
|
+
alogMetadata = {
|
|
411
|
+
title: typeof parsed.title === 'string' ? parsed.title : filename,
|
|
412
|
+
roastertype: typeof parsed.roastertype === 'string' ? parsed.roastertype : undefined,
|
|
413
|
+
beans: typeof parsed.beans === 'string' ? parsed.beans : undefined,
|
|
414
|
+
roastingnotes: typeof parsed.roastingnotes === 'string' ? parsed.roastingnotes : undefined,
|
|
415
|
+
weight: Array.isArray(parsed.weight)
|
|
416
|
+
? parsed.weight
|
|
417
|
+
: undefined,
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
catch {
|
|
421
|
+
// If we can't parse the file, fall back to filename as title
|
|
422
|
+
alogMetadata = { title: filename };
|
|
423
|
+
}
|
|
424
|
+
// Fetch the user's stocked inventory
|
|
425
|
+
let inventory = [];
|
|
426
|
+
try {
|
|
427
|
+
const { data, error } = await supabase
|
|
428
|
+
.from('green_coffee_inv')
|
|
429
|
+
.select('id, coffee_catalog!catalog_id (name, country, processing)')
|
|
430
|
+
.eq('user', userId)
|
|
431
|
+
.eq('stocked', true)
|
|
432
|
+
.limit(100);
|
|
433
|
+
if (error)
|
|
434
|
+
throw error;
|
|
435
|
+
const rows = (data ?? []);
|
|
436
|
+
inventory = rows.map((row) => {
|
|
437
|
+
const catalog = Array.isArray(row.coffee_catalog)
|
|
438
|
+
? (row.coffee_catalog[0] ?? null)
|
|
439
|
+
: row.coffee_catalog;
|
|
440
|
+
return {
|
|
441
|
+
id: row.id,
|
|
442
|
+
coffee_name: catalog?.name ?? `Bean #${row.id}`,
|
|
443
|
+
origin: catalog?.country ?? undefined,
|
|
444
|
+
processing: catalog?.processing ?? undefined,
|
|
445
|
+
};
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
catch (err) {
|
|
449
|
+
const reason = `Failed to fetch inventory: ${err instanceof Error ? err.message : String(err)}`;
|
|
450
|
+
process.stderr.write(`⚠ Auto-match skipped for ${filename}: ${reason}\n`);
|
|
451
|
+
return { skip: true, reason };
|
|
452
|
+
}
|
|
453
|
+
if (inventory.length === 0) {
|
|
454
|
+
return { skip: true, reason: 'No stocked inventory items found' };
|
|
455
|
+
}
|
|
456
|
+
// Call the AI classifier
|
|
457
|
+
try {
|
|
458
|
+
const { classifyRoast } = await import('../ai.js');
|
|
459
|
+
const result = await classifyRoast(supabase, { alogMetadata, inventory });
|
|
460
|
+
if (!result.match) {
|
|
461
|
+
return { skip: true, reason: 'AI returned no match' };
|
|
462
|
+
}
|
|
463
|
+
const { inventoryId, coffeeName, confidence, reasoning } = result.match;
|
|
464
|
+
const aiMatch = { coffeeName, confidence, reasoning };
|
|
465
|
+
if (confidence < 50) {
|
|
466
|
+
return {
|
|
467
|
+
skip: true,
|
|
468
|
+
reason: `Low AI confidence (${confidence}%)`,
|
|
469
|
+
aiMatch,
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
// Verify the matched inventoryId is actually in our fetched inventory
|
|
473
|
+
const matchedItem = inventory.find((item) => item.id === inventoryId);
|
|
474
|
+
if (!matchedItem) {
|
|
475
|
+
return {
|
|
476
|
+
skip: true,
|
|
477
|
+
reason: `AI matched unknown inventory ID ${inventoryId}`,
|
|
478
|
+
aiMatch,
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
return {
|
|
482
|
+
skip: false,
|
|
483
|
+
coffeeId: inventoryId,
|
|
484
|
+
coffeeName,
|
|
485
|
+
aiMatch,
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
catch (err) {
|
|
489
|
+
const reason = `AI classification error: ${err instanceof Error ? err.message : String(err)}`;
|
|
490
|
+
process.stderr.write(`⚠ Auto-match failed for ${filename}: ${reason}\n`);
|
|
491
|
+
return { skip: true, reason };
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
//# sourceMappingURL=watch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../../../src/lib/interactive/watch.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../src/lib/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAe1E;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAOjD;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,cAAc,CAAC,CAoCzE;AAED;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../src/lib/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAe1E;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAOjD;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,cAAc,CAAC,CAoCzE;AAED;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CAAC,CA0CR"}
|
package/dist/lib/supabase.js
CHANGED
|
@@ -73,10 +73,25 @@ export async function validateSession() {
|
|
|
73
73
|
const { data: { user }, error, } = await client.auth.getUser();
|
|
74
74
|
if (error || !user)
|
|
75
75
|
return null;
|
|
76
|
+
// Fetch app-level role from user_roles table
|
|
77
|
+
let appRoles = [];
|
|
78
|
+
try {
|
|
79
|
+
const { data: roleData } = await client
|
|
80
|
+
.from('user_roles')
|
|
81
|
+
.select('user_role')
|
|
82
|
+
.eq('id', user.id)
|
|
83
|
+
.single();
|
|
84
|
+
if (roleData?.user_role && Array.isArray(roleData.user_role)) {
|
|
85
|
+
appRoles = roleData.user_role;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// user_roles query failed — fall back to auth role
|
|
90
|
+
}
|
|
76
91
|
return {
|
|
77
92
|
id: user.id,
|
|
78
93
|
email: user.email,
|
|
79
|
-
role: user.role,
|
|
94
|
+
role: appRoles.length > 0 ? appRoles.join(', ') : (user.role ?? 'authenticated'),
|
|
80
95
|
expiresAt: creds.expiresAt,
|
|
81
96
|
};
|
|
82
97
|
}
|
package/dist/lib/supabase.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supabase.js","sourceRoot":"","sources":["../../src/lib/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC;;;;GAIG;AACH,MAAM,YAAY,GAChB,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,0CAA0C,CAAC;AACnF,MAAM,iBAAiB,GACrB,OAAO,CAAC,GAAG,CAAC,2BAA2B;IACvC,kNAAkN,CAAC;AAErN;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,YAAY,CAAC,YAAa,EAAE,iBAAkB,EAAE;QACrD,IAAI,EAAE;YACJ,cAAc,EAAE,KAAK;YACrB,gBAAgB,EAAE,KAAK;SACxB;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB;IAC7C,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAC;IAEtC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,YAAa,EAAE,iBAAkB,EAAE;QAC7D,IAAI,EAAE;YACJ,cAAc,EAAE,KAAK;YACrB,gBAAgB,EAAE,KAAK;SACxB;KACF,CAAC,CAAC;IAEH,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;QACnD,YAAY,EAAE,KAAK,CAAC,WAAW;QAC/B,aAAa,EAAE,KAAK,CAAC,YAAY;KAClC,CAAC,CAAC;IAEH,8EAA8E;IAC9E,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC;QAC9E,MAAM,gBAAgB,CAAC;YACrB,GAAG,KAAK,EAAE,qBAAqB;YAC/B,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY;YACtC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa;YACxC,SAAS,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,CAAC,CAAC,GAAG,IAAI;SACjD,CAAC,CAAC;IACL,CAAC;IAED,IAAI,KAAK,EAAE,CAAC;QACV,2CAA2C;QAC3C,MAAM,iBAAiB,EAAE,CAAC;QAC1B,MAAM,IAAI,SAAS,CAAC,8DAA8D,CAAC,CAAC;IACtF,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IAMnC,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAC;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,0CAA0C;IAC1C,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,yBAAyB,EAAE,CAAC;QACjD,MAAM,EACJ,IAAI,EAAE,EAAE,IAAI,EAAE,EACd,KAAK,GACN,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAEhC,IAAI,KAAK,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QAEhC,OAAO;YACL,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,IAAI,CAAC,IAAI;
|
|
1
|
+
{"version":3,"file":"supabase.js","sourceRoot":"","sources":["../../src/lib/supabase.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@purveyors/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "The official CLI for purveyors.io — coffee intelligence from your terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"./sales": "./dist/lib/sales.js",
|
|
15
15
|
"./tasting": "./dist/lib/tasting.js",
|
|
16
16
|
"./lib": "./dist/lib/index.js",
|
|
17
|
-
"./artisan": "./dist/lib/artisan/index.js"
|
|
17
|
+
"./artisan": "./dist/lib/artisan/index.js",
|
|
18
|
+
"./ai": "./dist/lib/ai.js"
|
|
18
19
|
},
|
|
19
20
|
"files": [
|
|
20
21
|
"dist",
|
|
@@ -49,6 +50,7 @@
|
|
|
49
50
|
"node": ">=20"
|
|
50
51
|
},
|
|
51
52
|
"dependencies": {
|
|
53
|
+
"@clack/prompts": "^1.1.0",
|
|
52
54
|
"@supabase/supabase-js": "^2.49.1",
|
|
53
55
|
"chalk": "^5.4.1",
|
|
54
56
|
"commander": "^13.1.0",
|