@agenzo/merchant-cli 0.4.1 → 0.4.2
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 +102 -102
- package/dist/index.js +47 -66
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,197 +1,197 @@
|
|
|
1
1
|
# @agenzo/merchant-cli
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
>
|
|
3
|
+
> **Merchant-fulfillment product-line CLI** — binary `agenzo-merchant-cli`, lives in the monorepo `agenzo-cli/apps/merchant-cli`.
|
|
4
|
+
> Covers two noun groups: capability discovery (`services`) and the ride-hailing business loop (`ride-elife`), 7 commands in total.
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Overview
|
|
9
9
|
|
|
10
|
-
`agenzo-merchant-cli`
|
|
10
|
+
`agenzo-merchant-cli` is the command-line entry point for Agents to access Agenzo's merchant-fulfillment capabilities. This iteration ships two noun groups:
|
|
11
11
|
|
|
12
|
-
- **`services
|
|
13
|
-
- **`ride-elife
|
|
12
|
+
- **`services`** (capability discovery): lets an Agent discover available merchant-fulfillment capabilities (which noun/verb to call, and the call flow). The data source this iteration is the **CLI-bundled registry** (the backend `/services` discovery endpoint is pending impl).
|
|
13
|
+
- **`ride-elife`** (ride hailing, the only online provider): the full loop of quote → book → query/poll → cancel → list-orders.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
All shared infrastructure (HTTP client, output rendering, error system, exit codes, version negotiation, config) is reused from `@agenzo/cli-core`; the app only keeps command handling and merchant-domain-specific logic (ride body assembly, NDJSON watch, verb-schema help, services registry, idempotency-key policy).
|
|
16
16
|
|
|
17
|
-
>
|
|
17
|
+
> This CLI keeps its structure, naming, and build configuration consistent with `agenzo-admin-cli` / `agenzo-token-cli` (4-CLI consistency).
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## Features
|
|
20
20
|
|
|
21
|
-
| Noun | Verb |
|
|
21
|
+
| Noun | Verb | Type | HTTP | Description |
|
|
22
22
|
|---|---|---|---|---|
|
|
23
|
-
| `services` | `list` | Read |
|
|
24
|
-
| `services` | `get <service-id>` | Read |
|
|
25
|
-
| `ride-elife` | `quote` | Read | `POST /ride/quote` |
|
|
26
|
-
| `ride-elife` | `book` | Write/Y | `POST /ride/book` |
|
|
27
|
-
| `ride-elife` | `get` | Read | `GET /ride/<id>/status` |
|
|
28
|
-
| `ride-elife` | `cancel` | Write/Y | `POST /ride/<id>/cancel` |
|
|
29
|
-
| `ride-elife` | `list-orders` | Read | `GET /ride/orders` |
|
|
23
|
+
| `services` | `list` | Read | — (bundled registry) | List available merchant-fulfillment capabilities |
|
|
24
|
+
| `services` | `get <service-id>` | Read | — (bundled registry) | View the full metadata of a single capability (miss → `SERVICE_NOT_FOUND`) |
|
|
25
|
+
| `ride-elife` | `quote` | Read | `POST /ride/quote` | Point-to-point quote (`vehicle_classes[]` + meet-and-greet) |
|
|
26
|
+
| `ride-elife` | `book` | Write/Y | `POST /ride/book` | Book against a quote (monthly_settlement-aware, see below) |
|
|
27
|
+
| `ride-elife` | `get` | Read | `GET /ride/<id>/status` | Query order status; `--watch` emits an NDJSON polling stream |
|
|
28
|
+
| `ride-elife` | `cancel` | Write/Y | `POST /ride/<id>/cancel` | Cancel an order (no body, may incur a fee) |
|
|
29
|
+
| `ride-elife` | `list-orders` | Read | `GET /ride/orders` | List booked trips (pagination + filtering) |
|
|
30
30
|
|
|
31
|
-
>
|
|
32
|
-
>
|
|
31
|
+
> Write commands (`book` / `cancel`) are subject to the idempotency-key rules (see [Idempotency-Key](#idempotency-key)).
|
|
32
|
+
> Not implemented: `ride-elife track` (pending impl, the backend has no location-stream interface) — `get --watch` already covers order-status polling.
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## Tech Stack
|
|
35
35
|
|
|
36
|
-
- TypeScript
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
36
|
+
- TypeScript (ESM) + [commander@14](https://github.com/tj/commander.js) + [@inquirer/prompts](https://github.com/SBoudrias/Inquirer.js)
|
|
37
|
+
- Build: [tsup](https://tsup.egoist.dev/) (esm / node18 / dts, banner `#!/usr/bin/env node`)
|
|
38
|
+
- Testing: [vitest](https://vitest.dev/) + [fast-check](https://fast-check.dev/) (PBT)
|
|
39
|
+
- Shared base package: `@agenzo/cli-core` (the only horizontal dependency; importing other apps is **forbidden**)
|
|
40
40
|
|
|
41
|
-
##
|
|
41
|
+
## Quick Start
|
|
42
42
|
|
|
43
|
-
###
|
|
43
|
+
### Requirements
|
|
44
44
|
|
|
45
45
|
- Node.js 18+
|
|
46
|
-
-
|
|
46
|
+
- `npm install` has been run in the monorepo
|
|
47
47
|
|
|
48
|
-
###
|
|
48
|
+
### Build
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
|
-
#
|
|
52
|
-
npm run build -w @agenzo/cli-core #
|
|
53
|
-
npm run build -w @agenzo/merchant-cli # tsup
|
|
51
|
+
# in the monorepo root
|
|
52
|
+
npm run build -w @agenzo/cli-core # must build the shared base package first
|
|
53
|
+
npm run build -w @agenzo/merchant-cli # tsup produces dist/index.js (= bin agenzo-merchant-cli)
|
|
54
54
|
agenzo-merchant-cli --version
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
###
|
|
57
|
+
### Authentication
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
A runtime-plane CLI that uses an **API Key** (`--api-key`, carried per command as the `X-Api-Key` header):
|
|
60
60
|
|
|
61
|
-
- API Key
|
|
62
|
-
-
|
|
63
|
-
-
|
|
61
|
+
- The API Key is issued by `agenzo-admin-cli keys create --scope merchant` and must include the `merchant` scope.
|
|
62
|
+
- When `--api-key` is omitted, it is requested interactively (password input).
|
|
63
|
+
- No Bearer Token / AuthService / keystore — consistent with `agenzo-token-cli`.
|
|
64
64
|
|
|
65
|
-
###
|
|
65
|
+
### End-to-end example
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
# 1.
|
|
68
|
+
# 1. Discover capabilities
|
|
69
69
|
agenzo-merchant-cli services list
|
|
70
70
|
agenzo-merchant-cli services get ride-elife
|
|
71
71
|
|
|
72
|
-
# 2.
|
|
72
|
+
# 2. Quote (produces quote_id)
|
|
73
73
|
agenzo-merchant-cli ride-elife quote --api-key "$API_KEY" \
|
|
74
74
|
--pickup-lat 37.7937 --pickup-lng -122.3956 --pickup-name "1 Market St" \
|
|
75
75
|
--dropoff-lat 37.6213 --dropoff-lng -122.3790 --dropoff-name "SFO Airport" \
|
|
76
76
|
--pickup-time now
|
|
77
77
|
|
|
78
|
-
# 3.
|
|
78
|
+
# 3. Book (write op: --yes auto-confirms + --idempotency-key must be provided)
|
|
79
79
|
agenzo-merchant-cli ride-elife book --api-key "$API_KEY" --yes \
|
|
80
80
|
--quote-id "$QUOTE_ID" --vehicle-class Sedan --price-amount 42.50 \
|
|
81
81
|
--passenger-name "Alice" --passenger-phone "+14155551234" \
|
|
82
82
|
--idempotency-key "book-$(date +%s)"
|
|
83
83
|
|
|
84
|
-
# 4.
|
|
84
|
+
# 4. Query / poll (--watch emits line-by-line NDJSON)
|
|
85
85
|
agenzo-merchant-cli ride-elife get --api-key "$API_KEY" --order-id "$RIDE_ID"
|
|
86
86
|
agenzo-merchant-cli ride-elife get --api-key "$API_KEY" --order-id "$RIDE_ID" \
|
|
87
87
|
--watch --watch-interval 5 --watch-timeout 600
|
|
88
88
|
|
|
89
|
-
# 5.
|
|
89
|
+
# 5. List orders / cancel
|
|
90
90
|
agenzo-merchant-cli ride-elife list-orders --api-key "$API_KEY" --status Pending --page 1 --page-size 20
|
|
91
91
|
agenzo-merchant-cli ride-elife cancel --api-key "$API_KEY" --yes \
|
|
92
92
|
--order-id "$RIDE_ID" --idempotency-key "cancel-$(date +%s)"
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
##
|
|
95
|
+
## Global flags
|
|
96
96
|
|
|
97
|
-
| Flag |
|
|
97
|
+
| Flag | Default | Description |
|
|
98
98
|
|---|---|---|
|
|
99
|
-
| `--format <json\|table>` | **`json`** |
|
|
100
|
-
| `--api-key <key>` |
|
|
101
|
-
| `--yes` | `false` |
|
|
102
|
-
| `--verbose` | `false` |
|
|
99
|
+
| `--format <json\|table>` | **`json`** | Output format. merchant-cli is an agent-first entry point, so it **defaults to `json`** (a deliberate deviation from cli-core's `table` default, D2); also reads the `AGENZO_FORMAT` environment variable |
|
|
100
|
+
| `--api-key <key>` | — (requested interactively) | API Key, carried per command as the `X-Api-Key` header |
|
|
101
|
+
| `--yes` | `false` | Skip interactive confirmation (for CI / Agent); for write commands, `--yes` with a missing idempotency key is a hard error |
|
|
102
|
+
| `--verbose` | `false` | Verbose logging (written to stderr) |
|
|
103
103
|
|
|
104
|
-
##
|
|
104
|
+
## Output and error contract
|
|
105
105
|
|
|
106
|
-
- **`--format json
|
|
107
|
-
- **`--format table
|
|
108
|
-
- **`get --watch
|
|
109
|
-
-
|
|
106
|
+
- **`--format json` (non-watch commands)**: stdout contains only a **single valid JSON** (business payload + `profile`/`endpoint` envelope, where endpoint is host-only without a path); all status/progress/spinner lines go to stderr and are silenced in json mode.
|
|
107
|
+
- **`--format table`**: business output goes to stdout, status lines/spinner go to stderr.
|
|
108
|
+
- **`get --watch`**: stdout is a line-by-line NDJSON stream, **not wrapped** in the profile/endpoint envelope; polling stops when it hits the terminal-status set (`At destination` / `Cancelled` / `Rejected` / `Customer no show` / `Driver no show`, case-sensitive) or times out; on timeout the final line is `{ "watch_status": "timeout", ... }`.
|
|
109
|
+
- **Error envelope** (cli-core §8): `json` → `{ "error": { "code", "code_num", "message", "request_id"? } }`; `table` → `✗ [<code_num>] <message>`.
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
Exit codes (mapped by cli-core's `exitCodeFor`):
|
|
112
112
|
|
|
113
|
-
|
|
|
113
|
+
| Exit code | Meaning | Representative error codes |
|
|
114
114
|
|---|---|---|
|
|
115
|
-
| `0` |
|
|
116
|
-
| `1` |
|
|
117
|
-
| `2` |
|
|
118
|
-
| `3` |
|
|
119
|
-
| `4` |
|
|
120
|
-
| `5` |
|
|
115
|
+
| `0` | Success | — |
|
|
116
|
+
| `1` | Business / param | `PARAM_INVALID`(2101) · `PARAM_IDEMPOTENCY_KEY_REQUIRED`(2102) · `SERVICE_NOT_FOUND`(4101) · `VEHICLE_UNAVAILABLE`(4201) · `QUOTE_EXPIRED`(4202) · `BOOKING_FAILED`(4203) · `CANCELLATION_NOT_ALLOWED`(4204) · `BILLING_MODE_MISMATCH`(3001) · `ACCOUNT_*`(31xx) · `PAYMENT_ORDER_*`(32xx) |
|
|
117
|
+
| `2` | Upgrade required | `UPGRADE_REQUIRED`(9008) |
|
|
118
|
+
| `3` | Auth / invalid key | `KEY_INVALID`(1101) · `KEY_SCOPE_DENIED`(1102) |
|
|
119
|
+
| `4` | Network / 5xx | `RATE_LIMITED`(5001) · `UPSTREAM_ERROR`(5101) · `INTERNAL_ERROR`(5201) |
|
|
120
|
+
| `5` | User cancel | `CLIENT_ABORTED`(9007) · SIGINT |
|
|
121
121
|
|
|
122
|
-
> api-key
|
|
122
|
+
> api-key auth mapping: HTTP 401 → `KEY_INVALID`, 403 → `KEY_SCOPE_DENIED`. A known §8 string code returned by the backend (e.g. `QUOTE_EXPIRED`) takes priority and is preserved; otherwise it falls back to the HTTP-status mapping.
|
|
123
123
|
|
|
124
|
-
##
|
|
124
|
+
## Idempotency-Key
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
The write commands `ride-elife book` / `cancel` accept `--idempotency-key`:
|
|
127
127
|
|
|
128
|
-
-
|
|
129
|
-
- **CLI
|
|
130
|
-
-
|
|
131
|
-
-
|
|
128
|
+
- Format: `[A-Za-z0-9_-]{1,128}`.
|
|
129
|
+
- **The CLI never auto-generates one**: `--yes` with a missing key → hard error `PARAM_IDEMPOTENCY_KEY_REQUIRED` (exit 1), and no request is sent; a missing key without `--yes` → requested interactively.
|
|
130
|
+
- Sent as the `Idempotency-Key` HTTP **header**, **never in the body**.
|
|
131
|
+
- Reuse the same key to retry the same logical request; use a new key for a new request.
|
|
132
132
|
|
|
133
|
-
## book
|
|
133
|
+
## Billing model for book (monthly_settlement-aware)
|
|
134
134
|
|
|
135
|
-
`ride-elife book`
|
|
135
|
+
`ride-elife book` **does not accept** `--payment-method-id` or any card information — the merchant domain holds no payment handle. Funding is decided by the backend according to the Developer's `billing_mode`:
|
|
136
136
|
|
|
137
|
-
- **monthly_settlement
|
|
138
|
-
- **pay_per_call
|
|
137
|
+
- **monthly_settlement**: deducted from the monthly-settlement account, no payment handle; the response has `payment_status=ON_ACCOUNT` and includes `billing_entry_id`.
|
|
138
|
+
- **pay_per_call**: optionally pass through `--payment-order-id` (a PAID order number charged separately, out-of-band); the response echoes `payment_order_id`.
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
The request body contains at most an optional `payment_order_id`.
|
|
141
141
|
|
|
142
|
-
## profile / host
|
|
142
|
+
## profile / host model
|
|
143
143
|
|
|
144
|
-
merchant-cli
|
|
144
|
+
merchant-cli **has no host / config commands** and does not govern environments. It reuses `@agenzo/cli-core`'s `ConfigManager` default configuration (i.e. the environment governed centrally by `agenzo-admin-cli`, persisted by default to `~/.agenzo-admin-cli/`):
|
|
145
145
|
|
|
146
|
-
-
|
|
147
|
-
-
|
|
146
|
+
- Provides the `baseUrl` for `ApiClient` (host + `/api/merchant/v1`).
|
|
147
|
+
- Provides the environment name + host for the `profile` / `endpoint` envelope in json output.
|
|
148
148
|
|
|
149
|
-
|
|
149
|
+
**Environment governance (setting the host / switching environments) belongs to `agenzo-admin-cli`** (`agenzo-admin-cli config set` / `set-host`) — consistent with `agenzo-token-cli`.
|
|
150
150
|
|
|
151
|
-
##
|
|
151
|
+
## Machine-readable verb schema
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
Every `ride-elife` verb supports `--help --format json`, emitting that verb's machine-readable schema (`cli` / `noun` / `verb` / `description` / `flags` / `response` / `example`, some with `error_recovery` / `polling`):
|
|
154
154
|
|
|
155
155
|
```bash
|
|
156
156
|
agenzo-merchant-cli ride-elife quote --help --format json
|
|
157
157
|
agenzo-merchant-cli ride-elife book --help --format json
|
|
158
158
|
```
|
|
159
159
|
|
|
160
|
-
##
|
|
160
|
+
## Development
|
|
161
161
|
|
|
162
162
|
```bash
|
|
163
|
-
npm run build -w @agenzo/merchant-cli # tsup
|
|
164
|
-
npm run test -w @agenzo/merchant-cli # vitest
|
|
163
|
+
npm run build -w @agenzo/merchant-cli # tsup build
|
|
164
|
+
npm run test -w @agenzo/merchant-cli # vitest (incl. fast-check PBT)
|
|
165
165
|
```
|
|
166
166
|
|
|
167
|
-
|
|
167
|
+
Source structure:
|
|
168
168
|
|
|
169
169
|
```text
|
|
170
170
|
apps/merchant-cli/
|
|
171
171
|
src/
|
|
172
|
-
index.ts # commander
|
|
173
|
-
services/{list,get}.ts #
|
|
174
|
-
services/registry.ts #
|
|
172
|
+
index.ts # commander assembly + top-level reportError + SIGINT
|
|
173
|
+
services/{list,get}.ts # capability discovery (this iteration: CLI-bundled registry)
|
|
174
|
+
services/registry.ts # bundled static registry (merchant domain)
|
|
175
175
|
ride-elife/{quote,book,get,cancel,list-orders}.ts
|
|
176
|
-
ride-elife/watch.ts # NDJSON
|
|
177
|
-
verb-schema.ts # --help --format json
|
|
178
|
-
idempotency.ts #
|
|
179
|
-
types/api.ts # ride/service
|
|
180
|
-
docs/ #
|
|
181
|
-
tests/ # vitest
|
|
176
|
+
ride-elife/watch.ts # NDJSON polling engine (merchant domain)
|
|
177
|
+
verb-schema.ts # verb schema for --help --format json (merchant domain)
|
|
178
|
+
idempotency.ts # idempotency key resolve / normalize (merchant domain)
|
|
179
|
+
types/api.ts # ride/service response types (consumed by merchant only, not promoted to cli-core)
|
|
180
|
+
docs/ # test design docs (see below)
|
|
181
|
+
tests/ # vitest unit tests + PBT
|
|
182
182
|
```
|
|
183
183
|
|
|
184
|
-
##
|
|
184
|
+
## Documentation index
|
|
185
185
|
|
|
186
|
-
- [
|
|
187
|
-
-
|
|
188
|
-
- monorepo
|
|
186
|
+
- [Test design doc (command matrix v1)](docs/test-design-command-matrix-v1.md) — a 7-command × requirement/Property coverage matrix, the L1–L4 layered testing strategy, L1 unit / L3 command-level case tables, and L4 manually executable smoke cases.
|
|
187
|
+
- Architecture and standards: `architecture-upgrade/v1/` (cli-standard / cli-design §4+§8 / cli-guide).
|
|
188
|
+
- monorepo overview: [`agenzo-cli/README.md`](../../README.md).
|
|
189
189
|
|
|
190
|
-
##
|
|
190
|
+
## Changelog
|
|
191
191
|
|
|
192
192
|
### 2026-06
|
|
193
193
|
|
|
194
|
-
-
|
|
195
|
-
-
|
|
196
|
-
-
|
|
197
|
-
-
|
|
194
|
+
- Landed merchant-cli in the monorepo `agenzo-cli/apps/merchant-cli` (rewritten per cli-design §4, reusing `@agenzo/cli-core`).
|
|
195
|
+
- Shipped `services` (list / get) + `ride-elife` (quote / book / get [+`--watch`] / cancel / list-orders), 7 commands in total.
|
|
196
|
+
- Output defaults to `json` (agent-first); API Key auth (`X-Api-Key`); write commands require `--idempotency-key`.
|
|
197
|
+
- Added the test design doc `docs/test-design-command-matrix-v1.md`.
|
package/dist/index.js
CHANGED
|
@@ -270,10 +270,6 @@ var ApiClient = class {
|
|
|
270
270
|
const headers = {
|
|
271
271
|
"User-Agent": `agenzo-admin-cli/${getCurrentVersion()}`
|
|
272
272
|
};
|
|
273
|
-
const traceparent = process.env.TRACEPARENT;
|
|
274
|
-
if (traceparent) {
|
|
275
|
-
headers["traceparent"] = traceparent;
|
|
276
|
-
}
|
|
277
273
|
if (auth.type === "bearer") {
|
|
278
274
|
headers["Authorization"] = `Bearer ${auth.token}`;
|
|
279
275
|
} else if (auth.type === "api-key") {
|
|
@@ -564,6 +560,29 @@ var STATUS_ICONS = {
|
|
|
564
560
|
warning: "\u26A0",
|
|
565
561
|
loading: "\u280B"
|
|
566
562
|
};
|
|
563
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
564
|
+
function createSpinner(message, intervalMs = 60) {
|
|
565
|
+
let frameIdx = 0;
|
|
566
|
+
let currentMessage = message;
|
|
567
|
+
const render2 = () => {
|
|
568
|
+
process.stdout.write(`\r\x1B[K${SPINNER_FRAMES[frameIdx]} ${currentMessage}`);
|
|
569
|
+
frameIdx = (frameIdx + 1) % SPINNER_FRAMES.length;
|
|
570
|
+
};
|
|
571
|
+
render2();
|
|
572
|
+
const timer = setInterval(render2, intervalMs);
|
|
573
|
+
return {
|
|
574
|
+
update(msg) {
|
|
575
|
+
currentMessage = msg;
|
|
576
|
+
},
|
|
577
|
+
stop(type, finalMessage) {
|
|
578
|
+
clearInterval(timer);
|
|
579
|
+
process.stdout.write("\r\x1B[K");
|
|
580
|
+
if (type && finalMessage) {
|
|
581
|
+
console.log(Formatter.status(type, finalMessage));
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
}
|
|
567
586
|
var Formatter = class _Formatter {
|
|
568
587
|
/** Get display width of a string (CJK characters count as 2) */
|
|
569
588
|
static displayWidth(str) {
|
|
@@ -673,12 +692,6 @@ function render(result, opts) {
|
|
|
673
692
|
process.stdout.write(`${result.text()}
|
|
674
693
|
`);
|
|
675
694
|
}
|
|
676
|
-
function notify(format, type, message) {
|
|
677
|
-
if (format === "json") {
|
|
678
|
-
return;
|
|
679
|
-
}
|
|
680
|
-
console.error(Formatter.status(type, message));
|
|
681
|
-
}
|
|
682
695
|
async function renderWithContext(result, opts, configManager) {
|
|
683
696
|
if (opts.format !== "json") {
|
|
684
697
|
render(result, opts);
|
|
@@ -696,17 +709,11 @@ async function renderWithContext(result, opts, configManager) {
|
|
|
696
709
|
render({ ...result, data: payload }, opts);
|
|
697
710
|
}
|
|
698
711
|
var PromptEngine = class {
|
|
699
|
-
/** Return flagValue if provided,
|
|
712
|
+
/** Return flagValue directly if provided, otherwise prompt interactively */
|
|
700
713
|
static async resolveInput(flagValue, config) {
|
|
701
714
|
if (flagValue !== void 0) {
|
|
702
715
|
return flagValue;
|
|
703
716
|
}
|
|
704
|
-
if (config.envVar) {
|
|
705
|
-
const envValue = process.env[config.envVar];
|
|
706
|
-
if (envValue !== void 0 && envValue !== "") {
|
|
707
|
-
return envValue;
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
717
|
if (config.type === "password") {
|
|
711
718
|
return password({ message: config.message, mask: "*" });
|
|
712
719
|
}
|
|
@@ -1115,8 +1122,7 @@ function registerQuoteCommand(parent, deps) {
|
|
|
1115
1122
|
const format = resolveFormat(opts.format);
|
|
1116
1123
|
const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
|
|
1117
1124
|
message: "API Key:",
|
|
1118
|
-
type: "password"
|
|
1119
|
-
envVar: "AGENZO_API_KEY"
|
|
1125
|
+
type: "password"
|
|
1120
1126
|
});
|
|
1121
1127
|
const body = {
|
|
1122
1128
|
pickup: {
|
|
@@ -1145,12 +1151,13 @@ function registerQuoteCommand(parent, deps) {
|
|
|
1145
1151
|
if (opts.passengerEmail !== void 0) {
|
|
1146
1152
|
body.passenger_email = opts.passengerEmail;
|
|
1147
1153
|
}
|
|
1148
|
-
|
|
1154
|
+
const spinner = format === "json" ? null : createSpinner("Fetching quotes...");
|
|
1149
1155
|
const result = await deps.apiClient.post(
|
|
1150
1156
|
"/ride/quote",
|
|
1151
1157
|
{ type: "api-key", key: apiKey },
|
|
1152
1158
|
body
|
|
1153
1159
|
);
|
|
1160
|
+
spinner?.stop();
|
|
1154
1161
|
if (!result.success) {
|
|
1155
1162
|
throw CliError.fromApi(result, { auth: "api-key" });
|
|
1156
1163
|
}
|
|
@@ -1244,8 +1251,7 @@ function registerBookCommand(parent, deps) {
|
|
|
1244
1251
|
const isYes = Boolean(opts.yes);
|
|
1245
1252
|
const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
|
|
1246
1253
|
message: "API Key:",
|
|
1247
|
-
type: "password"
|
|
1248
|
-
envVar: "AGENZO_API_KEY"
|
|
1254
|
+
type: "password"
|
|
1249
1255
|
});
|
|
1250
1256
|
const quoteId = need2(opts.quoteId, "quote-id");
|
|
1251
1257
|
const body = {
|
|
@@ -1318,13 +1324,14 @@ function registerBookCommand(parent, deps) {
|
|
|
1318
1324
|
yes: isYes,
|
|
1319
1325
|
commandPath: "ride-elife book"
|
|
1320
1326
|
});
|
|
1321
|
-
|
|
1327
|
+
const spinner = format === "json" ? null : createSpinner("Booking ride...");
|
|
1322
1328
|
const result = await deps.apiClient.post(
|
|
1323
1329
|
"/ride/book",
|
|
1324
1330
|
{ type: "api-key", key: apiKey },
|
|
1325
1331
|
body,
|
|
1326
1332
|
{ "Idempotency-Key": idempotencyKey }
|
|
1327
1333
|
);
|
|
1334
|
+
spinner?.stop();
|
|
1328
1335
|
if (!result.success) {
|
|
1329
1336
|
throw CliError.fromApi(result, { auth: "api-key" });
|
|
1330
1337
|
}
|
|
@@ -1397,8 +1404,7 @@ function registerRideGetCommand(parent, deps) {
|
|
|
1397
1404
|
const format = resolveFormat(opts.format);
|
|
1398
1405
|
const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
|
|
1399
1406
|
message: "API Key:",
|
|
1400
|
-
type: "password"
|
|
1401
|
-
envVar: "AGENZO_API_KEY"
|
|
1407
|
+
type: "password"
|
|
1402
1408
|
});
|
|
1403
1409
|
const orderId = need3(opts.orderId, "order-id");
|
|
1404
1410
|
if (opts.watch) {
|
|
@@ -1414,11 +1420,12 @@ function registerRideGetCommand(parent, deps) {
|
|
|
1414
1420
|
});
|
|
1415
1421
|
return;
|
|
1416
1422
|
}
|
|
1417
|
-
|
|
1423
|
+
const spinner = format === "json" ? null : createSpinner("Fetching ride status...");
|
|
1418
1424
|
const result = await deps.apiClient.get(
|
|
1419
1425
|
`/ride/${encodeURIComponent(orderId)}/status`,
|
|
1420
1426
|
{ type: "api-key", key: apiKey }
|
|
1421
1427
|
);
|
|
1428
|
+
spinner?.stop();
|
|
1422
1429
|
if (!result.success) {
|
|
1423
1430
|
throw CliError.fromApi(result, { auth: "api-key" });
|
|
1424
1431
|
}
|
|
@@ -1467,8 +1474,7 @@ function registerCancelCommand(parent, deps) {
|
|
|
1467
1474
|
const isYes = Boolean(opts.yes);
|
|
1468
1475
|
const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
|
|
1469
1476
|
message: "API Key:",
|
|
1470
|
-
type: "password"
|
|
1471
|
-
envVar: "AGENZO_API_KEY"
|
|
1477
|
+
type: "password"
|
|
1472
1478
|
});
|
|
1473
1479
|
const orderId = need4(opts.orderId, "order-id");
|
|
1474
1480
|
if (!isYes) {
|
|
@@ -1484,13 +1490,14 @@ function registerCancelCommand(parent, deps) {
|
|
|
1484
1490
|
yes: isYes,
|
|
1485
1491
|
commandPath: "ride-elife cancel"
|
|
1486
1492
|
});
|
|
1487
|
-
|
|
1493
|
+
const spinner = format === "json" ? null : createSpinner("Cancelling ride...");
|
|
1488
1494
|
const result = await deps.apiClient.post(
|
|
1489
1495
|
`/ride/${encodeURIComponent(orderId)}/cancel`,
|
|
1490
1496
|
{ type: "api-key", key: apiKey },
|
|
1491
1497
|
void 0,
|
|
1492
1498
|
{ "Idempotency-Key": idempotencyKey }
|
|
1493
1499
|
);
|
|
1500
|
+
spinner?.stop();
|
|
1494
1501
|
if (!result.success) {
|
|
1495
1502
|
throw CliError.fromApi(result, { auth: "api-key" });
|
|
1496
1503
|
}
|
|
@@ -1545,8 +1552,7 @@ function registerListOrdersCommand(parent, deps) {
|
|
|
1545
1552
|
const format = resolveFormat(opts.format);
|
|
1546
1553
|
const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
|
|
1547
1554
|
message: "API Key:",
|
|
1548
|
-
type: "password"
|
|
1549
|
-
envVar: "AGENZO_API_KEY"
|
|
1555
|
+
type: "password"
|
|
1550
1556
|
});
|
|
1551
1557
|
const params = {
|
|
1552
1558
|
page: positiveInt(opts.page ?? DEFAULT_PAGE, "page"),
|
|
@@ -1554,12 +1560,13 @@ function registerListOrdersCommand(parent, deps) {
|
|
|
1554
1560
|
};
|
|
1555
1561
|
if (opts.status !== void 0) params.status = opts.status;
|
|
1556
1562
|
if (opts.orderType !== void 0) params.order_type = opts.orderType;
|
|
1557
|
-
|
|
1563
|
+
const spinner = format === "json" ? null : createSpinner("Fetching orders...");
|
|
1558
1564
|
const result = await deps.apiClient.get(
|
|
1559
1565
|
"/ride/orders",
|
|
1560
1566
|
{ type: "api-key", key: apiKey },
|
|
1561
1567
|
params
|
|
1562
1568
|
);
|
|
1569
|
+
spinner?.stop();
|
|
1563
1570
|
if (!result.success) {
|
|
1564
1571
|
throw CliError.fromApi(result, { auth: "api-key" });
|
|
1565
1572
|
}
|
|
@@ -1614,25 +1621,12 @@ function toListItem(s) {
|
|
|
1614
1621
|
discovery: s.discovery
|
|
1615
1622
|
};
|
|
1616
1623
|
}
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
const result = await apiClient.get(
|
|
1620
|
-
"/services",
|
|
1621
|
-
{ type: "api-key", key: apiKey }
|
|
1622
|
-
);
|
|
1623
|
-
if (result.success && Array.isArray(result.data?.services)) {
|
|
1624
|
-
return result.data.services;
|
|
1625
|
-
}
|
|
1626
|
-
}
|
|
1627
|
-
return SERVICE_REGISTRY.map(toListItem);
|
|
1628
|
-
}
|
|
1629
|
-
function registerServicesListCommand(parent, deps) {
|
|
1630
|
-
const cmd = parent.command("list").description("List available merchant services (live backend feed; falls back to bundled registry)").option("--api-key <key>", "API Key enabling live backend discovery (or set AGENZO_API_KEY)");
|
|
1624
|
+
function registerServicesListCommand(parent) {
|
|
1625
|
+
const cmd = parent.command("list").description("List available merchant services from the registry");
|
|
1631
1626
|
cmd.action(async () => {
|
|
1632
1627
|
const opts = cmd.optsWithGlobals();
|
|
1633
1628
|
const format = resolveFormat(opts.format);
|
|
1634
|
-
const
|
|
1635
|
-
const services = await resolveServiceList(deps?.apiClient, apiKey);
|
|
1629
|
+
const services = SERVICE_REGISTRY.map(toListItem);
|
|
1636
1630
|
const configManager = new ConfigManager();
|
|
1637
1631
|
const commandResult = {
|
|
1638
1632
|
data: { services },
|
|
@@ -1676,25 +1670,12 @@ function formatServiceGet(s) {
|
|
|
1676
1670
|
Verb descriptions:
|
|
1677
1671
|
${verbDetail}`;
|
|
1678
1672
|
}
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
const result = await apiClient.get(
|
|
1682
|
-
`/services/${encodeURIComponent(serviceId)}`,
|
|
1683
|
-
{ type: "api-key", key: apiKey }
|
|
1684
|
-
);
|
|
1685
|
-
if (result.success && result.data?.service_id) {
|
|
1686
|
-
return result.data;
|
|
1687
|
-
}
|
|
1688
|
-
}
|
|
1689
|
-
return findService(serviceId);
|
|
1690
|
-
}
|
|
1691
|
-
function registerServiceGetCommand(parent, deps) {
|
|
1692
|
-
const cmd = parent.command("get <service-id>").description("Retrieve a single merchant service by id (live backend feed; falls back to bundled registry)").option("--api-key <key>", "API Key enabling live backend discovery (or set AGENZO_API_KEY)");
|
|
1673
|
+
function registerServiceGetCommand(parent) {
|
|
1674
|
+
const cmd = parent.command("get <service-id>").description("Retrieve a single merchant service by id");
|
|
1693
1675
|
cmd.action(async (serviceId) => {
|
|
1694
1676
|
const opts = cmd.optsWithGlobals();
|
|
1695
1677
|
const format = resolveFormat(opts.format);
|
|
1696
|
-
const
|
|
1697
|
-
const service = await resolveService(deps?.apiClient, apiKey, serviceId);
|
|
1678
|
+
const service = findService(serviceId);
|
|
1698
1679
|
if (!service) {
|
|
1699
1680
|
throw new CliError(
|
|
1700
1681
|
"SERVICE_NOT_FOUND",
|
|
@@ -1738,8 +1719,8 @@ async function main() {
|
|
|
1738
1719
|
registerCancelCommand(rideCmd, deps);
|
|
1739
1720
|
registerListOrdersCommand(rideCmd, deps);
|
|
1740
1721
|
const servicesCmd = program.command("services").description("Merchant service discovery");
|
|
1741
|
-
registerServicesListCommand(servicesCmd
|
|
1742
|
-
registerServiceGetCommand(servicesCmd
|
|
1722
|
+
registerServicesListCommand(servicesCmd);
|
|
1723
|
+
registerServiceGetCommand(servicesCmd);
|
|
1743
1724
|
await program.parseAsync(process.argv);
|
|
1744
1725
|
}
|
|
1745
1726
|
function resolveActiveFormat() {
|