ephemeris-cli 0.0.0-stage → 0.4.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.
@@ -0,0 +1,539 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "additionalProperties": false,
5
+ "title": "Ephemeris submission receipt v1",
6
+ "required": [
7
+ "kind",
8
+ "schema_version",
9
+ "created_at",
10
+ "origin",
11
+ "idempotency_key",
12
+ "request_sha256",
13
+ "prepared",
14
+ "status",
15
+ "disclosure"
16
+ ],
17
+ "properties": {
18
+ "kind": {
19
+ "const": "ephemeris.submission"
20
+ },
21
+ "schema_version": {
22
+ "const": "1"
23
+ },
24
+ "created_at": {
25
+ "type": "string",
26
+ "format": "date-time"
27
+ },
28
+ "origin": {
29
+ "type": "string",
30
+ "format": "uri"
31
+ },
32
+ "idempotency_key": {
33
+ "type": "string",
34
+ "pattern": "^[A-Za-z0-9._:-]{8,128}$"
35
+ },
36
+ "request_sha256": {
37
+ "type": "string",
38
+ "pattern": "^[a-f0-9]{64}$"
39
+ },
40
+ "prepared": {
41
+ "type": "object",
42
+ "additionalProperties": false,
43
+ "title": "Ephemeris prepared request v1",
44
+ "required": [
45
+ "kind",
46
+ "schema_version",
47
+ "request",
48
+ "context",
49
+ "disclosure"
50
+ ],
51
+ "properties": {
52
+ "kind": {
53
+ "const": "ephemeris.request"
54
+ },
55
+ "schema_version": {
56
+ "const": "1"
57
+ },
58
+ "request": {
59
+ "$ref": "#/$defs/ForecastRequest"
60
+ },
61
+ "context": {
62
+ "type": "object",
63
+ "required": [
64
+ "series"
65
+ ],
66
+ "additionalProperties": false,
67
+ "properties": {
68
+ "series": {
69
+ "type": "array",
70
+ "items": {
71
+ "type": "object",
72
+ "additionalProperties": false,
73
+ "properties": {
74
+ "series_id": {
75
+ "type": [
76
+ "string",
77
+ "null"
78
+ ]
79
+ },
80
+ "unit": {
81
+ "type": [
82
+ "string",
83
+ "null"
84
+ ]
85
+ },
86
+ "timezone": {
87
+ "type": [
88
+ "string",
89
+ "null"
90
+ ]
91
+ },
92
+ "target_description": {
93
+ "type": [
94
+ "string",
95
+ "null"
96
+ ]
97
+ },
98
+ "measurement": {
99
+ "enum": [
100
+ "period_total",
101
+ "period_average",
102
+ "point_in_time",
103
+ null
104
+ ]
105
+ },
106
+ "timestamps": {
107
+ "type": [
108
+ "array",
109
+ "null"
110
+ ],
111
+ "items": {
112
+ "type": "string"
113
+ }
114
+ },
115
+ "future_timestamps": {
116
+ "type": [
117
+ "array",
118
+ "null"
119
+ ],
120
+ "items": {
121
+ "type": "string"
122
+ }
123
+ },
124
+ "source_available_at": {
125
+ "type": [
126
+ "string",
127
+ "null"
128
+ ]
129
+ },
130
+ "recorded_as_of": {
131
+ "type": [
132
+ "string",
133
+ "null"
134
+ ]
135
+ },
136
+ "future_covariate_roles": {
137
+ "type": "object",
138
+ "additionalProperties": {
139
+ "enum": [
140
+ "known_future",
141
+ "scenario_assumption",
142
+ "unspecified"
143
+ ]
144
+ }
145
+ }
146
+ }
147
+ }
148
+ },
149
+ "scenario_assumptions": {
150
+ "type": "array",
151
+ "items": {
152
+ "type": "string"
153
+ }
154
+ },
155
+ "snapshot_id": {
156
+ "type": [
157
+ "string",
158
+ "null"
159
+ ]
160
+ },
161
+ "source": {
162
+ "type": [
163
+ "object",
164
+ "null"
165
+ ]
166
+ }
167
+ }
168
+ },
169
+ "disclosure": {
170
+ "type": "string"
171
+ }
172
+ }
173
+ },
174
+ "status": {
175
+ "const": "completion_unknown"
176
+ },
177
+ "disclosure": {
178
+ "type": "string"
179
+ }
180
+ },
181
+ "$defs": {
182
+ "Error": {
183
+ "type": "object",
184
+ "required": [
185
+ "error"
186
+ ],
187
+ "properties": {
188
+ "error": {
189
+ "type": "string"
190
+ }
191
+ }
192
+ },
193
+ "Balance": {
194
+ "type": "object",
195
+ "required": [
196
+ "balance_mc",
197
+ "active_holds_mc"
198
+ ],
199
+ "properties": {
200
+ "balance_mc": {
201
+ "type": "string",
202
+ "pattern": "^-?[0-9]+$"
203
+ },
204
+ "active_holds_mc": {
205
+ "type": "string",
206
+ "pattern": "^[0-9]+$"
207
+ }
208
+ }
209
+ },
210
+ "Model": {
211
+ "type": "object",
212
+ "required": [
213
+ "name",
214
+ "price_per_kslot_mc",
215
+ "billing_context_cap"
216
+ ],
217
+ "properties": {
218
+ "name": {
219
+ "type": "string"
220
+ },
221
+ "price_per_kslot_mc": {
222
+ "type": [
223
+ "string",
224
+ "null"
225
+ ]
226
+ },
227
+ "billing_context_cap": {
228
+ "type": [
229
+ "integer",
230
+ "null"
231
+ ]
232
+ }
233
+ },
234
+ "additionalProperties": true
235
+ },
236
+ "ForecastSeries": {
237
+ "type": "object",
238
+ "required": [
239
+ "values"
240
+ ],
241
+ "properties": {
242
+ "values": {
243
+ "oneOf": [
244
+ {
245
+ "type": "array",
246
+ "minItems": 1,
247
+ "items": {
248
+ "type": "number"
249
+ }
250
+ },
251
+ {
252
+ "type": "array",
253
+ "minItems": 1,
254
+ "items": {
255
+ "type": "array",
256
+ "minItems": 1,
257
+ "items": {
258
+ "type": "number"
259
+ }
260
+ }
261
+ }
262
+ ]
263
+ },
264
+ "freq": {
265
+ "type": "string",
266
+ "minLength": 1,
267
+ "description": "Optional per-series frequency. Mixed-frequency batches are split into compatible upstream calls and reassembled in request order."
268
+ },
269
+ "covariates": {
270
+ "$ref": "#/$defs/SeriesCovariates"
271
+ }
272
+ },
273
+ "additionalProperties": true
274
+ },
275
+ "SeriesCovariates": {
276
+ "type": "object",
277
+ "required": [
278
+ "past"
279
+ ],
280
+ "properties": {
281
+ "past": {
282
+ "type": "object",
283
+ "additionalProperties": {
284
+ "type": "array",
285
+ "items": {
286
+ "type": "number"
287
+ }
288
+ },
289
+ "description": "Named historical channels aligned to the series context length."
290
+ },
291
+ "future": {
292
+ "type": "object",
293
+ "additionalProperties": {
294
+ "type": "array",
295
+ "items": {
296
+ "type": "number"
297
+ }
298
+ },
299
+ "description": "Optional known-future channels aligned to the requested horizon. Every future channel must also have past history."
300
+ }
301
+ },
302
+ "additionalProperties": false
303
+ },
304
+ "ForecastRequest": {
305
+ "type": "object",
306
+ "required": [
307
+ "mode",
308
+ "series"
309
+ ],
310
+ "properties": {
311
+ "mode": {
312
+ "type": "string",
313
+ "enum": [
314
+ "explicit",
315
+ "ensemble",
316
+ "route"
317
+ ]
318
+ },
319
+ "model": {
320
+ "type": "string"
321
+ },
322
+ "series": {
323
+ "type": "array",
324
+ "minItems": 1,
325
+ "maxItems": 64,
326
+ "items": {
327
+ "$ref": "#/$defs/ForecastSeries"
328
+ }
329
+ },
330
+ "context_len": {
331
+ "type": "integer",
332
+ "minimum": 1,
333
+ "maximum": 16384
334
+ },
335
+ "horizon": {
336
+ "type": "integer",
337
+ "minimum": 1,
338
+ "maximum": 4096,
339
+ "description": "Maximum 4096 steps. Slots x horizon x quantiles must not exceed 120000 output values; omitted or empty quantiles are budgeted as 21."
340
+ },
341
+ "quantiles": {
342
+ "type": "array",
343
+ "maxItems": 21,
344
+ "items": {
345
+ "type": "number",
346
+ "exclusiveMinimum": 0,
347
+ "exclusiveMaximum": 1
348
+ }
349
+ },
350
+ "top_k": {
351
+ "type": [
352
+ "integer",
353
+ "null"
354
+ ],
355
+ "minimum": 1,
356
+ "maximum": 16,
357
+ "description": "Optional ensemble-only limit on the number of models."
358
+ },
359
+ "combine": {
360
+ "type": "string",
361
+ "enum": [
362
+ "mixture",
363
+ "vincentize"
364
+ ],
365
+ "description": "Optional ensemble combination method."
366
+ }
367
+ },
368
+ "additionalProperties": true
369
+ },
370
+ "ForecastResponse": {
371
+ "type": "object",
372
+ "required": [
373
+ "meta"
374
+ ],
375
+ "properties": {
376
+ "meta": {
377
+ "type": "object",
378
+ "required": [
379
+ "gateway_request_id",
380
+ "billing"
381
+ ],
382
+ "properties": {
383
+ "gateway_request_id": {
384
+ "type": "string"
385
+ },
386
+ "request_id": {
387
+ "type": "string"
388
+ },
389
+ "models_used": {
390
+ "type": "array",
391
+ "items": {
392
+ "type": "string"
393
+ }
394
+ },
395
+ "upstream_request_ids": {
396
+ "type": "array",
397
+ "items": {
398
+ "type": "string"
399
+ },
400
+ "description": "Model request IDs when a mixed-frequency request is split into compatible groups."
401
+ },
402
+ "upstream_calls": {
403
+ "type": "integer",
404
+ "minimum": 1
405
+ },
406
+ "billing": {
407
+ "type": "object",
408
+ "required": [
409
+ "settled_mc",
410
+ "balance_mc"
411
+ ],
412
+ "properties": {
413
+ "settled_mc": {
414
+ "type": "string"
415
+ },
416
+ "balance_mc": {
417
+ "type": "string"
418
+ }
419
+ }
420
+ }
421
+ },
422
+ "additionalProperties": true
423
+ }
424
+ },
425
+ "additionalProperties": true
426
+ },
427
+ "InsufficientCredits": {
428
+ "type": "object",
429
+ "required": [
430
+ "error",
431
+ "balance_mc",
432
+ "required_mc",
433
+ "topup_url"
434
+ ],
435
+ "properties": {
436
+ "error": {
437
+ "type": "string"
438
+ },
439
+ "balance_mc": {
440
+ "type": "string"
441
+ },
442
+ "required_mc": {
443
+ "type": "string"
444
+ },
445
+ "topup_url": {
446
+ "type": "string",
447
+ "format": "uri"
448
+ }
449
+ }
450
+ },
451
+ "UsageRow": {
452
+ "type": "object",
453
+ "required": [
454
+ "requestId"
455
+ ],
456
+ "properties": {
457
+ "requestId": {
458
+ "type": "string"
459
+ },
460
+ "paracastRequestId": {
461
+ "type": [
462
+ "string",
463
+ "null"
464
+ ]
465
+ },
466
+ "estimatedMc": {
467
+ "type": [
468
+ "string",
469
+ "null"
470
+ ]
471
+ },
472
+ "settledMc": {
473
+ "type": [
474
+ "string",
475
+ "null"
476
+ ]
477
+ },
478
+ "status": {
479
+ "type": [
480
+ "integer",
481
+ "null"
482
+ ]
483
+ }
484
+ },
485
+ "additionalProperties": true
486
+ },
487
+ "UsagePage": {
488
+ "type": "object",
489
+ "required": [
490
+ "data",
491
+ "pagination"
492
+ ],
493
+ "properties": {
494
+ "data": {
495
+ "type": "array",
496
+ "items": {
497
+ "$ref": "#/$defs/UsageRow"
498
+ }
499
+ },
500
+ "limit": {
501
+ "type": "integer"
502
+ },
503
+ "offset": {
504
+ "type": "integer"
505
+ },
506
+ "pagination": {
507
+ "type": "object",
508
+ "required": [
509
+ "limit",
510
+ "offset",
511
+ "returned",
512
+ "has_more",
513
+ "next_offset"
514
+ ],
515
+ "properties": {
516
+ "limit": {
517
+ "type": "integer"
518
+ },
519
+ "offset": {
520
+ "type": "integer"
521
+ },
522
+ "returned": {
523
+ "type": "integer"
524
+ },
525
+ "has_more": {
526
+ "type": "boolean"
527
+ },
528
+ "next_offset": {
529
+ "type": [
530
+ "integer",
531
+ "null"
532
+ ]
533
+ }
534
+ }
535
+ }
536
+ }
537
+ }
538
+ }
539
+ }
@@ -0,0 +1,27 @@
1
+ import { CliError } from './errors.js';
2
+
3
+ function distance(a, b) {
4
+ let row = Array.from({ length: b.length + 1 }, (_, i) => i);
5
+ for (let i = 0; i < a.length; i++) {
6
+ const next = [i + 1];
7
+ for (let j = 0; j < b.length; j++) next.push(Math.min(next[j] + 1, row[j + 1] + 1, row[j] + (a[i] === b[j] ? 0 : 1)));
8
+ row = next;
9
+ }
10
+ return row[b.length];
11
+ }
12
+
13
+ // Echo option names only, never argument values or Node's raw parser message.
14
+ export function argumentError(error, argv, options) {
15
+ const token = argv.find((v) => /^--[a-z][a-z-]{0,39}(?:=|$)/.test(v) && !Object.hasOwn(options, v.slice(2).split('=')[0]));
16
+ const option = token?.split('=')[0];
17
+ if (option) {
18
+ const ranked = Object.keys(options).map((name) => ({ name, distance: distance(option.slice(2), name) })).sort((a, b) => a.distance - b.distance);
19
+ const suggestion = ranked[0].distance <= 2 ? `--${ranked[0].name}` : null;
20
+ return new CliError(2, 'Unknown option.', { option, expected: 'a supported option from command help', suggestion, next_action: suggestion ? `Use ${suggestion}; run the command with --help for its meaning.` : 'Run ephemeris --help, then <command> --help.' });
21
+ }
22
+ if (error.code === 'ERR_PARSE_ARGS_INVALID_OPTION_VALUE') {
23
+ const name = Object.keys(options).find((n) => error.message?.includes(`--${n}`));
24
+ return new CliError(2, 'Option value is missing or has the wrong type.', { option: name ? `--${name}` : null, expected: name ? options[name].type : 'the value documented in command help', next_action: 'Supply a value after the option. Run the command with --help for examples.' });
25
+ }
26
+ return new CliError(2, 'Invalid argument.', { next_action: 'Run ephemeris --help or the command --help. Credentials belong in EPHEMERIS_API_KEY, never arguments.' });
27
+ }