makea-cli 0.2.14__tar.gz → 0.2.16__tar.gz
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.
- {makea_cli-0.2.14 → makea_cli-0.2.16}/CHANGELOG.md +50 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/PKG-INFO +7 -2
- {makea_cli-0.2.14 → makea_cli-0.2.16}/README.md +6 -1
- makea_cli-0.2.16/makea_cli/__init__.py +1 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/api_client.py +66 -3
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/__init__.py +2 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/metrics/cmd.py +27 -65
- makea_cli-0.2.16/makea_cli/commands/playbook/__init__.py +0 -0
- makea_cli-0.2.16/makea_cli/commands/playbook/cmd.py +329 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/pyproject.toml +1 -1
- {makea_cli-0.2.14 → makea_cli-0.2.16}/tests/golden_manifest.json +440 -3
- makea_cli-0.2.16/tests/test_currency_conversion.py +106 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/tests/test_persona_commands.py +78 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/uv.lock +1 -1
- makea_cli-0.2.14/makea_cli/__init__.py +0 -1
- {makea_cli-0.2.14 → makea_cli-0.2.16}/.claude/skills/create-supplier-profile/SKILL.md +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/.claude/skills/lark-cli-setup/SKILL.md +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/.claude/skills/link-supplier-user/SKILL.md +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/.claude/skills/makea-cli-setup/SKILL.md +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/.claude/skills/payment-revenue-report/SKILL.md +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/.claude/skills/supplier-user-id-migration/SKILL.md +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/.gitignore +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea-collection-upload/SKILL.md +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea-collection-upload/scripts/create_products.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/__main__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/auth_pkce.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/broker.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/_util.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/analytics/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/analytics/cmd.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/auth/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/auth/cmd.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/brand/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/brand/cmd.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/designer/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/designer/cmd.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/directory/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/directory/cmd.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/document/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/document/cmd.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/email/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/email/cmd.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/factory/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/factory/cmd.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/library/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/library/cmd.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/metrics/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/orders/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/orders/cmd.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/product/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/product/cmd.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/production/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/production/cmd.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/production/pricing_spec.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/supplier/__init__.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/commands/supplier/cmd.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/config.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/errors.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/identity.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/main.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/output.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/posthog_client.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/makea_cli/registry.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/npm/makea-cli/README.md +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/npm/makea-cli/makea-cli.mjs +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/npm/makea-cli/package.json +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/tests/test_broker.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/tests/test_output_contract.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/tests/test_pm_reads.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/tests/test_registry.py +0 -0
- {makea_cli-0.2.14 → makea_cli-0.2.16}/tests/test_supplier_scorecard.py +0 -0
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.16
|
|
4
|
+
|
|
5
|
+
New: an admin can read, add, edit and remove the AI playbook rules of one
|
|
6
|
+
person (backend 2026-10-18, deploy e408a077 or later).
|
|
7
|
+
|
|
8
|
+
- `admin list rule --user <user_id|email> [--status …] [--all]`: every rule
|
|
9
|
+
that holds for the person, from their team, their own account and, for a
|
|
10
|
+
factory, its company. Archived rules only with `--all`.
|
|
11
|
+
- `admin get rule <rule_id> --user …`: one rule with its evidence.
|
|
12
|
+
- `admin create rule --user … --text … --reason …`: admin-authored, active
|
|
13
|
+
unless `--status`. Goes to the team when there is one (`--scope` to pick).
|
|
14
|
+
A repeat or a conflict is refused unless `--force`.
|
|
15
|
+
- `admin update rule <rule_id> --user … --reason …`: text, status,
|
|
16
|
+
applies_to, which products (`--when`) or mode.
|
|
17
|
+
- `admin delete rule <rule_id> --user … --reason …`: archives the rule, the
|
|
18
|
+
way the brand's own dismiss does. It leaves the brand's Rules page and every
|
|
19
|
+
prompt, and Beeboo will not propose the same words again. `update rule
|
|
20
|
+
--status active` brings it back.
|
|
21
|
+
|
|
22
|
+
Every write needs `--reason`; the rule records who changed it, why and what
|
|
23
|
+
it was before. An email on two accounts is refused with both user ids.
|
|
24
|
+
|
|
25
|
+
## 0.2.15
|
|
26
|
+
|
|
27
|
+
**Behaviour change: `admin get currency-conversion` returns different
|
|
28
|
+
numbers.** This is not only a bug fix. Anyone who reconciled figures with
|
|
29
|
+
this command should expect them to move, by up to several percent per
|
|
30
|
+
currency. The same call on 2026-10-16:
|
|
31
|
+
|
|
32
|
+
| GBP per | 0.2.14 | 0.2.15 | 1,000 converted, 0.2.14 → 0.2.15 |
|
|
33
|
+
|---|---|---|---|
|
|
34
|
+
| CNY | 0.12 | 0.113 | 120.00 → 113.00 (−5.8%) |
|
|
35
|
+
| USD | 0.76 | 0.752 | 760.00 → 752.00 |
|
|
36
|
+
| EUR | 0.85 | 0.848 | 850.00 → 848.00 |
|
|
37
|
+
|
|
38
|
+
What changed:
|
|
39
|
+
|
|
40
|
+
- Rates now come from the platform (`GET /admin/fx/rates`, backend
|
|
41
|
+
2026-10-16) instead of the CLI fetching the free FX source itself. They are
|
|
42
|
+
rounded **up to 3 decimals**, as the platform rounds them; 0.2.14 rounded
|
|
43
|
+
up to 2, which overstated cheap currencies such as CNY most.
|
|
44
|
+
- With one `--from` and `--amount`, `converted` is the platform's own
|
|
45
|
+
conversion, rounded **up** to the cent; 0.2.14 rounded to the nearest cent.
|
|
46
|
+
- So the numbers now match the platform's prices and revenue metrics, which
|
|
47
|
+
the 0.2.14 ones did not.
|
|
48
|
+
- Output keys are unchanged except `rounding` (now `"up"`, was
|
|
49
|
+
`"ceil_2dp"`), plus new `rate_decimals` and `unavailable`. A currency with
|
|
50
|
+
no rate still fails the command. Needs an admin login, like every `admin`
|
|
51
|
+
command.
|
|
52
|
+
|
|
3
53
|
## 0.2.14
|
|
4
54
|
|
|
5
55
|
- `admin update tracking-status`: help text no longer describes it as "the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: makea-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.16
|
|
4
4
|
Summary: Makea admin CLI (browser login + Makea admin HTTP API)
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Requires-Dist: click<9,>=8.1
|
|
@@ -92,20 +92,23 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
92
92
|
| `makea-cli admin backfill supplier-id` | write(never) | `POST /admin/supplier/backfill_supplier_id_with_quote_requests` | Migrate supplier_id from a wrong UUID to the Cognito user sub (user_id): profile + Cognito supplierReferenceId, optio… | `backfill-supplier-id` |
|
|
93
93
|
| `makea-cli admin create library-element` | write(auto) | `POST /admin/designer/{user_id}/library_components` | save a reusable component under a designer. Provide --section and --values (see admin get library-schema). | `library-create` |
|
|
94
94
|
| `makea-cli admin create quote-request` | write(ask) | `POST /admin/supplier/create_quote_request` | create/send a quote request to a supplier for a product (admin). | `create-quote-request` |
|
|
95
|
+
| `makea-cli admin create rule` | write(ask) | `POST /admin/playbook/users/{user}/rules` | add a rule to one person's AI playbook (user_id or email); admin-authored, active unless --status. Refuses a repeat or a conflict unless --force. --reason required. | — |
|
|
95
96
|
| `makea-cli admin create supplier` | write(ask) | `POST /admin/supplier/add_supplier` | create supplier from JSON file (admin). Run `makea-cli get-supplier-profile-schema` FIRST to get the field taxonomy (… | `add-supplier` |
|
|
96
97
|
| `makea-cli admin create user` | write(never) | `POST /admin/users/create` | register a user and confirm the Cognito account in one step (no verification email). Allowed --user-type values: "Fas… | `create-user` |
|
|
97
98
|
| `makea-cli admin delete library-element` | write(never) | `DELETE /admin/designer/{user_id}/library_components/{component_id}` | remove a component from the designer's org library. | `library-delete` |
|
|
99
|
+
| `makea-cli admin delete rule` | write(ask) | `DELETE /admin/playbook/users/{user}/rules/{rule_id}` | remove a rule: archived, with who and why kept on it (`update rule --status active` restores it). --reason required. | — |
|
|
98
100
|
| `makea-cli admin download document` | read | `GET /admin/document/download` | save a document file (document id + designer user_id). | `download-document` |
|
|
99
101
|
| `makea-cli admin download product-document` | read | `GET /admin/document/download` | Resolve product via admin list product-order payload, then GET /admin/document/download. | `download-product-document` |
|
|
100
102
|
| `makea-cli admin generate pricing-groups` | write(ask) | `POST /admin/production_orders/{id}/details/update` | Lay a production order's variants into pricing groups along one axis (--by style \| colour \| variant \| all) with th… | `production-groups-generate` |
|
|
101
103
|
| `makea-cli admin get active-users` | read | `POST /admin/analytics/query` | Distinct active users per day over the last N days (DAU series). | `analytics-active-users` |
|
|
102
104
|
| `makea-cli admin get analytics-query` | read | `POST /admin/analytics/query` | Run an arbitrary HogQL query (escape hatch). Example: analytics-query "SELECT count() FROM events" | `analytics-query` |
|
|
103
|
-
| `makea-cli admin get currency-conversion` | read | `
|
|
105
|
+
| `makea-cli admin get currency-conversion` | read | `GET /admin/fx/rates` | the platform's own exchange rates and rounding (rate table for several --from; one --from with --amount converts it). | `convert-currency` |
|
|
104
106
|
| `makea-cli admin get feature-usage` | read | `POST /admin/analytics/query` | How many distinct users used a feature recently, plus event volume. Matches $pageview path and feature_time_spent eve… | `analytics-feature-usage` |
|
|
105
107
|
| `makea-cli admin get library-schema` | read | `GET /admin/library_components/schema` | the tech-pack library taxonomy: sections and their library-role field keys (run this before create/update). | `library-schema` |
|
|
106
108
|
| `makea-cli admin get production-pricing` | read | `GET /admin/production_orders/{id}/details` | show a production order's price tiers, MOQ, sizes/colours, pricing groups and cart coverage. | `production-pricing-show` |
|
|
107
109
|
| `makea-cli admin get quote-request` | read | `GET /admin/quote_requests/{quote_request_id}` | one quote request in full. | — |
|
|
108
110
|
| `makea-cli admin get revenue-metrics` | read | `GET /admin/business-metrics/cumulative-payment-and-platform-revenue` | platform-wide payment received and platform revenue (service fee + transaction fee) bucketed over a date range. | `get-cumulative-payment-and-platform-revenue` |
|
|
111
|
+
| `makea-cli admin get rule` | read | `GET /admin/playbook/users/{user}/rules/{rule_id}` | one rule in full, with its evidence: where it came from, who changed it and why. | — |
|
|
109
112
|
| `makea-cli admin get supplier-profile-schema` | read | `GET /admin/supplier/profile/schema` | supplier profile v2 schema (section/field taxonomy: sections, fields, options, required rules). | `get-supplier-profile-schema` |
|
|
110
113
|
| `makea-cli admin get tech-spec-extraction` | read | `GET /admin/products/{id}/extract-tech-specifications` | AI-generate specs (not saved). | `extract-ai-tech-spec` |
|
|
111
114
|
| `makea-cli admin get top-clicks` | read | `POST /admin/analytics/query` | which buttons/elements get clicked most. | `analytics-top-clicks` |
|
|
@@ -116,6 +119,7 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
116
119
|
| `makea-cli admin list production-order` | read | `GET /admin/production_orders?type=PRODUCTION` | 大货 (production) orders only. For restock use admin list restock-order; for shipping use admin list shipping-order. | `list-all-production-orders` |
|
|
117
120
|
| `makea-cli admin list quote-request` | read | `GET /admin/quote_requests` | quote requests, optionally for one product (--product) or one supplier (--supplier, GET /admin/quote_requests/supplie… | — |
|
|
118
121
|
| `makea-cli admin list restock-order` | read | `GET /admin/production_orders?type=RESTOCK` | restock orders only. Restock shares the production_orders table; this filters to type=RESTOCK. | `list-all-restock-orders` |
|
|
122
|
+
| `makea-cli admin list rule` | read | `GET /admin/playbook/users/{user}/rules` | every AI playbook rule that holds for one person (team, own account, factory): status, scope, text, which products, effect, source. Archived ones only with --all. | — |
|
|
119
123
|
| `makea-cli admin list sampling-order` | read | `GET /admin/sampling_orders/get_all` | paginated list of all sampling orders (admin). | `list-all-sampling-orders` |
|
|
120
124
|
| `makea-cli admin list shipping-order` | read | `GET /admin/shipping_orders` | paginated list of all shipping orders (admin). | `list-all-shipping-orders` |
|
|
121
125
|
| `makea-cli admin list supplier` | read | `GET /admin/supplier/get_all_suppliers` | list all suppliers (admin). | `list-suppliers` |
|
|
@@ -129,6 +133,7 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
129
133
|
| `makea-cli admin update library-element` | write(auto) | `PATCH /admin/designer/{user_id}/library_components/{component_id}` | update a component's name and/or values (empty value clears a field). | `library-update` |
|
|
130
134
|
| `makea-cli admin update quote` | write(ask) | `POST /admin/product/edit_supplier_link_override_info` | admin updates an existing quote (supplier link) in place. Only the options you pass are sent, and the backend leaves … | `update-supplier-quote` |
|
|
131
135
|
| `makea-cli admin update quote-request` | write(ask) | `PATCH /admin/quote_requests/{quote_request_id}/update` | set a quote request's stage, status and/or due date. Only what you pass is changed. This is the door that unblocks a … | `update-quote-request` |
|
|
136
|
+
| `makea-cli admin update rule` | write(ask) | `PATCH /admin/playbook/users/{user}/rules/{rule_id}` | change a rule's text, status, applies_to, when or mode. --reason required; the rule keeps what it was before. | — |
|
|
132
137
|
| `makea-cli admin update supplier` | write(ask) | `PUT /admin/supplier/update_supplier` | update an existing supplier from a JSON file (admin). Run `makea-cli get-supplier-profile-schema` FIRST to get the fi… | `update-supplier` |
|
|
133
138
|
| `makea-cli admin update tech-spec` | write(ask) | `POST /admin/products/{id}/technical-specifications` | persist specs from a JSON file. | `save-product-tech-spec` |
|
|
134
139
|
| `makea-cli admin update tracking-status` | write(ask) | `POST /admin/tracking/carrier_status` | apply a carrier status looked up by hand (tracking-sweep skill) to one order: status, fan-out, delivered emails (--silent: state only). | — |
|
|
@@ -80,20 +80,23 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
80
80
|
| `makea-cli admin backfill supplier-id` | write(never) | `POST /admin/supplier/backfill_supplier_id_with_quote_requests` | Migrate supplier_id from a wrong UUID to the Cognito user sub (user_id): profile + Cognito supplierReferenceId, optio… | `backfill-supplier-id` |
|
|
81
81
|
| `makea-cli admin create library-element` | write(auto) | `POST /admin/designer/{user_id}/library_components` | save a reusable component under a designer. Provide --section and --values (see admin get library-schema). | `library-create` |
|
|
82
82
|
| `makea-cli admin create quote-request` | write(ask) | `POST /admin/supplier/create_quote_request` | create/send a quote request to a supplier for a product (admin). | `create-quote-request` |
|
|
83
|
+
| `makea-cli admin create rule` | write(ask) | `POST /admin/playbook/users/{user}/rules` | add a rule to one person's AI playbook (user_id or email); admin-authored, active unless --status. Refuses a repeat or a conflict unless --force. --reason required. | — |
|
|
83
84
|
| `makea-cli admin create supplier` | write(ask) | `POST /admin/supplier/add_supplier` | create supplier from JSON file (admin). Run `makea-cli get-supplier-profile-schema` FIRST to get the field taxonomy (… | `add-supplier` |
|
|
84
85
|
| `makea-cli admin create user` | write(never) | `POST /admin/users/create` | register a user and confirm the Cognito account in one step (no verification email). Allowed --user-type values: "Fas… | `create-user` |
|
|
85
86
|
| `makea-cli admin delete library-element` | write(never) | `DELETE /admin/designer/{user_id}/library_components/{component_id}` | remove a component from the designer's org library. | `library-delete` |
|
|
87
|
+
| `makea-cli admin delete rule` | write(ask) | `DELETE /admin/playbook/users/{user}/rules/{rule_id}` | remove a rule: archived, with who and why kept on it (`update rule --status active` restores it). --reason required. | — |
|
|
86
88
|
| `makea-cli admin download document` | read | `GET /admin/document/download` | save a document file (document id + designer user_id). | `download-document` |
|
|
87
89
|
| `makea-cli admin download product-document` | read | `GET /admin/document/download` | Resolve product via admin list product-order payload, then GET /admin/document/download. | `download-product-document` |
|
|
88
90
|
| `makea-cli admin generate pricing-groups` | write(ask) | `POST /admin/production_orders/{id}/details/update` | Lay a production order's variants into pricing groups along one axis (--by style \| colour \| variant \| all) with th… | `production-groups-generate` |
|
|
89
91
|
| `makea-cli admin get active-users` | read | `POST /admin/analytics/query` | Distinct active users per day over the last N days (DAU series). | `analytics-active-users` |
|
|
90
92
|
| `makea-cli admin get analytics-query` | read | `POST /admin/analytics/query` | Run an arbitrary HogQL query (escape hatch). Example: analytics-query "SELECT count() FROM events" | `analytics-query` |
|
|
91
|
-
| `makea-cli admin get currency-conversion` | read | `
|
|
93
|
+
| `makea-cli admin get currency-conversion` | read | `GET /admin/fx/rates` | the platform's own exchange rates and rounding (rate table for several --from; one --from with --amount converts it). | `convert-currency` |
|
|
92
94
|
| `makea-cli admin get feature-usage` | read | `POST /admin/analytics/query` | How many distinct users used a feature recently, plus event volume. Matches $pageview path and feature_time_spent eve… | `analytics-feature-usage` |
|
|
93
95
|
| `makea-cli admin get library-schema` | read | `GET /admin/library_components/schema` | the tech-pack library taxonomy: sections and their library-role field keys (run this before create/update). | `library-schema` |
|
|
94
96
|
| `makea-cli admin get production-pricing` | read | `GET /admin/production_orders/{id}/details` | show a production order's price tiers, MOQ, sizes/colours, pricing groups and cart coverage. | `production-pricing-show` |
|
|
95
97
|
| `makea-cli admin get quote-request` | read | `GET /admin/quote_requests/{quote_request_id}` | one quote request in full. | — |
|
|
96
98
|
| `makea-cli admin get revenue-metrics` | read | `GET /admin/business-metrics/cumulative-payment-and-platform-revenue` | platform-wide payment received and platform revenue (service fee + transaction fee) bucketed over a date range. | `get-cumulative-payment-and-platform-revenue` |
|
|
99
|
+
| `makea-cli admin get rule` | read | `GET /admin/playbook/users/{user}/rules/{rule_id}` | one rule in full, with its evidence: where it came from, who changed it and why. | — |
|
|
97
100
|
| `makea-cli admin get supplier-profile-schema` | read | `GET /admin/supplier/profile/schema` | supplier profile v2 schema (section/field taxonomy: sections, fields, options, required rules). | `get-supplier-profile-schema` |
|
|
98
101
|
| `makea-cli admin get tech-spec-extraction` | read | `GET /admin/products/{id}/extract-tech-specifications` | AI-generate specs (not saved). | `extract-ai-tech-spec` |
|
|
99
102
|
| `makea-cli admin get top-clicks` | read | `POST /admin/analytics/query` | which buttons/elements get clicked most. | `analytics-top-clicks` |
|
|
@@ -104,6 +107,7 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
104
107
|
| `makea-cli admin list production-order` | read | `GET /admin/production_orders?type=PRODUCTION` | 大货 (production) orders only. For restock use admin list restock-order; for shipping use admin list shipping-order. | `list-all-production-orders` |
|
|
105
108
|
| `makea-cli admin list quote-request` | read | `GET /admin/quote_requests` | quote requests, optionally for one product (--product) or one supplier (--supplier, GET /admin/quote_requests/supplie… | — |
|
|
106
109
|
| `makea-cli admin list restock-order` | read | `GET /admin/production_orders?type=RESTOCK` | restock orders only. Restock shares the production_orders table; this filters to type=RESTOCK. | `list-all-restock-orders` |
|
|
110
|
+
| `makea-cli admin list rule` | read | `GET /admin/playbook/users/{user}/rules` | every AI playbook rule that holds for one person (team, own account, factory): status, scope, text, which products, effect, source. Archived ones only with --all. | — |
|
|
107
111
|
| `makea-cli admin list sampling-order` | read | `GET /admin/sampling_orders/get_all` | paginated list of all sampling orders (admin). | `list-all-sampling-orders` |
|
|
108
112
|
| `makea-cli admin list shipping-order` | read | `GET /admin/shipping_orders` | paginated list of all shipping orders (admin). | `list-all-shipping-orders` |
|
|
109
113
|
| `makea-cli admin list supplier` | read | `GET /admin/supplier/get_all_suppliers` | list all suppliers (admin). | `list-suppliers` |
|
|
@@ -117,6 +121,7 @@ exit code:`0` 成功 · `2` 用法错 · `3` 未登录或身份与 persona 不
|
|
|
117
121
|
| `makea-cli admin update library-element` | write(auto) | `PATCH /admin/designer/{user_id}/library_components/{component_id}` | update a component's name and/or values (empty value clears a field). | `library-update` |
|
|
118
122
|
| `makea-cli admin update quote` | write(ask) | `POST /admin/product/edit_supplier_link_override_info` | admin updates an existing quote (supplier link) in place. Only the options you pass are sent, and the backend leaves … | `update-supplier-quote` |
|
|
119
123
|
| `makea-cli admin update quote-request` | write(ask) | `PATCH /admin/quote_requests/{quote_request_id}/update` | set a quote request's stage, status and/or due date. Only what you pass is changed. This is the door that unblocks a … | `update-quote-request` |
|
|
124
|
+
| `makea-cli admin update rule` | write(ask) | `PATCH /admin/playbook/users/{user}/rules/{rule_id}` | change a rule's text, status, applies_to, when or mode. --reason required; the rule keeps what it was before. | — |
|
|
120
125
|
| `makea-cli admin update supplier` | write(ask) | `PUT /admin/supplier/update_supplier` | update an existing supplier from a JSON file (admin). Run `makea-cli get-supplier-profile-schema` FIRST to get the fi… | `update-supplier` |
|
|
121
126
|
| `makea-cli admin update tech-spec` | write(ask) | `POST /admin/products/{id}/technical-specifications` | persist specs from a JSON file. | `save-product-tech-spec` |
|
|
122
127
|
| `makea-cli admin update tracking-status` | write(ask) | `POST /admin/tracking/carrier_status` | apply a carrier status looked up by hand (tracking-sweep skill) to one order: status, fan-out, delivered emails (--silent: state only). | — |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.16"
|
|
@@ -5,7 +5,7 @@ import mimetypes
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from pathlib import PurePosixPath
|
|
7
7
|
from typing import Any
|
|
8
|
-
from urllib.parse import unquote
|
|
8
|
+
from urllib.parse import quote, unquote
|
|
9
9
|
|
|
10
10
|
import httpx
|
|
11
11
|
|
|
@@ -197,8 +197,14 @@ def patch_json(path: str, body: Any, *, timeout: float = 60.0) -> Any:
|
|
|
197
197
|
return _request("PATCH", path, json_body=body, timeout=timeout)
|
|
198
198
|
|
|
199
199
|
|
|
200
|
-
def delete_json(
|
|
201
|
-
|
|
200
|
+
def delete_json(
|
|
201
|
+
path: str,
|
|
202
|
+
*,
|
|
203
|
+
params: dict[str, Any] | None = None,
|
|
204
|
+
body: Any = None,
|
|
205
|
+
timeout: float = 60.0,
|
|
206
|
+
) -> Any:
|
|
207
|
+
return _request("DELETE", path, params=params, json_body=body, timeout=timeout)
|
|
202
208
|
|
|
203
209
|
|
|
204
210
|
def send_admin_raw_email(body: dict[str, Any]) -> Any:
|
|
@@ -844,6 +850,18 @@ def get_cumulative_payment_and_platform_revenue(
|
|
|
844
850
|
)
|
|
845
851
|
|
|
846
852
|
|
|
853
|
+
def get_fx_rates(*, to: str, sources: list[str], amount: float | None = None) -> Any:
|
|
854
|
+
"""
|
|
855
|
+
GET /admin/fx/rates — the platform's own exchange rates (rounded up to its
|
|
856
|
+
RATE_DECIMALS), and with one source and an amount, that amount converted the
|
|
857
|
+
way the platform converts it.
|
|
858
|
+
"""
|
|
859
|
+
params: dict[str, Any] = {"to": to, "from": ",".join(sources)}
|
|
860
|
+
if amount is not None:
|
|
861
|
+
params["amount"] = amount
|
|
862
|
+
return get_json("/admin/fx/rates", params=params)
|
|
863
|
+
|
|
864
|
+
|
|
847
865
|
def extract_ai_tech_specifications(product_reference_id: str, *, timeout: float = 300.0) -> Any:
|
|
848
866
|
"""
|
|
849
867
|
GET /admin/products/{id}/extract-tech-specifications — synchronous AI extraction;
|
|
@@ -1035,6 +1053,51 @@ def admin_delete_library_component(
|
|
|
1035
1053
|
)
|
|
1036
1054
|
|
|
1037
1055
|
|
|
1056
|
+
# --- admin: one person's AI playbook rules ---------------------------------------
|
|
1057
|
+
# Addressed by user_id or email; the backend resolves every scope the person's
|
|
1058
|
+
# rules live in (team, own account, factory) and refuses an email that is on
|
|
1059
|
+
# more than one account. Every write carries a reason the rule keeps.
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
def _user_rules_path(user: str, rule_id: str | None = None) -> str:
|
|
1063
|
+
path = f"/admin/playbook/users/{quote(user.strip(), safe='@')}/rules"
|
|
1064
|
+
return f"{path}/{quote(rule_id, safe='')}" if rule_id else path
|
|
1065
|
+
|
|
1066
|
+
|
|
1067
|
+
def admin_list_user_rules(
|
|
1068
|
+
user: str, *, status: str | None = None, include_archived: bool = False
|
|
1069
|
+
) -> Any:
|
|
1070
|
+
"""GET /admin/playbook/users/{user}/rules — every rule that holds for one person."""
|
|
1071
|
+
params: dict[str, Any] = {}
|
|
1072
|
+
if status:
|
|
1073
|
+
params["status"] = status
|
|
1074
|
+
if include_archived:
|
|
1075
|
+
params["include_archived"] = "1"
|
|
1076
|
+
return get_json(_user_rules_path(user), params=params or None)
|
|
1077
|
+
|
|
1078
|
+
|
|
1079
|
+
def admin_get_user_rule(user: str, rule_id: str) -> Any:
|
|
1080
|
+
"""GET /admin/playbook/users/{user}/rules/{rule_id} — one rule, evidence included."""
|
|
1081
|
+
return get_json(_user_rules_path(user, rule_id))
|
|
1082
|
+
|
|
1083
|
+
|
|
1084
|
+
def admin_create_user_rule(user: str, body: dict[str, Any]) -> Any:
|
|
1085
|
+
"""POST /admin/playbook/users/{user}/rules — {text, reason, scope?, applies_to?,
|
|
1086
|
+
when?, mode?, category?, polarity?, status?, force?}."""
|
|
1087
|
+
return post_json(_user_rules_path(user), body)
|
|
1088
|
+
|
|
1089
|
+
|
|
1090
|
+
def admin_update_user_rule(user: str, rule_id: str, body: dict[str, Any]) -> Any:
|
|
1091
|
+
"""PATCH /admin/playbook/users/{user}/rules/{rule_id} — {text?, status?,
|
|
1092
|
+
applies_to?, when?, mode?, reason}."""
|
|
1093
|
+
return patch_json(_user_rules_path(user, rule_id), body)
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
def admin_delete_user_rule(user: str, rule_id: str, reason: str) -> Any:
|
|
1097
|
+
"""DELETE /admin/playbook/users/{user}/rules/{rule_id} — archives it, with the reason."""
|
|
1098
|
+
return delete_json(_user_rules_path(user, rule_id), body={"reason": reason})
|
|
1099
|
+
|
|
1100
|
+
|
|
1038
1101
|
# --- supplier persona: a factory acting on its own RFQs, quotes and orders --------
|
|
1039
1102
|
|
|
1040
1103
|
|
|
@@ -13,6 +13,7 @@ from makea_cli.commands.factory.cmd import register as register_factory
|
|
|
13
13
|
from makea_cli.commands.library.cmd import register as register_library
|
|
14
14
|
from makea_cli.commands.metrics.cmd import register as register_metrics
|
|
15
15
|
from makea_cli.commands.orders.cmd import register as register_orders
|
|
16
|
+
from makea_cli.commands.playbook.cmd import register as register_playbook
|
|
16
17
|
from makea_cli.commands.product.cmd import register as register_product
|
|
17
18
|
from makea_cli.commands.production.cmd import register as register_production
|
|
18
19
|
from makea_cli.commands.supplier.cmd import register as register_supplier
|
|
@@ -33,3 +34,4 @@ def register_all(app: typer.Typer) -> None:
|
|
|
33
34
|
register_library(app)
|
|
34
35
|
register_factory(app)
|
|
35
36
|
register_brand(app)
|
|
37
|
+
register_playbook(app)
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import math
|
|
4
|
-
|
|
5
|
-
import httpx
|
|
6
3
|
import typer
|
|
7
4
|
from rich.console import Console
|
|
8
5
|
|
|
@@ -16,38 +13,6 @@ console = Console()
|
|
|
16
13
|
_GRANULARITIES = ("day", "week", "month")
|
|
17
14
|
_ORDER_TYPES = ("all", "sampling", "production")
|
|
18
15
|
|
|
19
|
-
# Same free FX source the backend uses (FreeCurrencyService), so converted
|
|
20
|
-
# amounts match the platform's revenue metrics.
|
|
21
|
-
_FX_PRIMARY = (
|
|
22
|
-
"https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/{base}.json"
|
|
23
|
-
)
|
|
24
|
-
_FX_FALLBACK = "https://latest.currency-api.pages.dev/v1/currencies/{base}.json"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def _fx_rate(base: str, target: str) -> float:
|
|
28
|
-
"""Exchange rate base -> target, rounded UP to 2dp exactly like the backend
|
|
29
|
-
(math.ceil(raw * 100) / 100) so totals reconcile with revenue metrics."""
|
|
30
|
-
base, target = base.lower(), target.lower()
|
|
31
|
-
if base == target:
|
|
32
|
-
return 1.0
|
|
33
|
-
last_err: Exception | None = None
|
|
34
|
-
for url in (_FX_PRIMARY.format(base=base), _FX_FALLBACK.format(base=base)):
|
|
35
|
-
try:
|
|
36
|
-
with httpx.Client(timeout=10) as client:
|
|
37
|
-
resp = client.get(url)
|
|
38
|
-
resp.raise_for_status()
|
|
39
|
-
data = resp.json()
|
|
40
|
-
raw = data.get(base, {}).get(target)
|
|
41
|
-
if raw is not None:
|
|
42
|
-
return math.ceil(float(raw) * 100) / 100
|
|
43
|
-
except Exception as e: # noqa: BLE001 - try fallback URL
|
|
44
|
-
last_err = e
|
|
45
|
-
continue
|
|
46
|
-
raise RuntimeError(
|
|
47
|
-
f"FX rate {base.upper()}->{target.upper()} unavailable"
|
|
48
|
-
+ (f": {last_err}" if last_err else "")
|
|
49
|
-
)
|
|
50
|
-
|
|
51
16
|
|
|
52
17
|
def register(app: typer.Typer) -> None:
|
|
53
18
|
@command(
|
|
@@ -141,13 +106,13 @@ def register(app: typer.Typer) -> None:
|
|
|
141
106
|
"get",
|
|
142
107
|
"currency-conversion",
|
|
143
108
|
legacy="convert-currency",
|
|
144
|
-
api="GET
|
|
145
|
-
external="currency-api",
|
|
109
|
+
api="GET /admin/fx/rates",
|
|
146
110
|
help=(
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"one call, then convert
|
|
111
|
+
"GET /admin/fx/rates — convert money between currencies at the "
|
|
112
|
+
"platform's own rates and rounding, so totals reconcile with its "
|
|
113
|
+
"prices and revenue metrics. Pass several source currencies via --from "
|
|
114
|
+
"(comma-separated) to get a full rate table in one call, then convert "
|
|
115
|
+
"locally — avoids repeated lookups."
|
|
151
116
|
),
|
|
152
117
|
)
|
|
153
118
|
def convert_currency(
|
|
@@ -165,17 +130,20 @@ def register(app: typer.Typer) -> None:
|
|
|
165
130
|
help="Optional amount to convert (only meaningful with a single --from).",
|
|
166
131
|
),
|
|
167
132
|
) -> None:
|
|
168
|
-
"""Return source->target rates
|
|
169
|
-
|
|
133
|
+
"""Return source->target rates, and optionally a converted amount, as the
|
|
134
|
+
platform computes them.
|
|
170
135
|
|
|
171
136
|
Use it to collapse a mixed-currency set into one currency: collect the
|
|
172
137
|
distinct currencies, call once with --from a,b,c to get every rate, then
|
|
173
|
-
multiply locally.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
{"
|
|
178
|
-
|
|
138
|
+
multiply locally. The rates are the platform's (FreeCurrencyService,
|
|
139
|
+
rounded up to ``rate_decimals``) and come from the backend rather than
|
|
140
|
+
being fetched and rounded here, so they cannot drift from it.
|
|
141
|
+
|
|
142
|
+
Output JSON: {"to", "rates": {CUR: rate, ...}, "rate_decimals",
|
|
143
|
+
"rounding", "source", "unavailable"} plus {"from", "rate", "amount",
|
|
144
|
+
"converted"} when a single --from and --amount are given; "converted" is
|
|
145
|
+
the platform's own conversion, rounding included. A currency with no
|
|
146
|
+
rate fails the command rather than coming back null.
|
|
179
147
|
"""
|
|
180
148
|
sources = [s.strip() for s in from_.split(",") if s.strip()]
|
|
181
149
|
if not sources:
|
|
@@ -183,22 +151,16 @@ def register(app: typer.Typer) -> None:
|
|
|
183
151
|
raise typer.Exit(1)
|
|
184
152
|
|
|
185
153
|
def _do() -> dict:
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
{
|
|
197
|
-
"from": sources[0].upper(),
|
|
198
|
-
"rate": rate,
|
|
199
|
-
"amount": amount,
|
|
200
|
-
"converted": round(amount * rate, 2),
|
|
201
|
-
}
|
|
154
|
+
payload = api_client.get_fx_rates(
|
|
155
|
+
to=to,
|
|
156
|
+
sources=sources,
|
|
157
|
+
amount=amount if len(sources) == 1 else None,
|
|
158
|
+
)
|
|
159
|
+
out = (payload or {}).get("result") or {}
|
|
160
|
+
if out.get("unavailable"):
|
|
161
|
+
raise RuntimeError(
|
|
162
|
+
"FX rate unavailable: "
|
|
163
|
+
+ ", ".join(f"{s}->{to.upper()}" for s in out["unavailable"])
|
|
202
164
|
)
|
|
203
165
|
return out
|
|
204
166
|
|
|
File without changes
|