@datarails-ai/dr-cli 0.0.1-locked → 1.6.70
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 +608 -0
- package/dist/chunk-DWMCBGQH.js +242 -0
- package/dist/cli.js +64468 -0
- package/dist/kb-6UWI7Q32.js +21 -0
- package/dist/scopes-map.json +4412 -0
- package/dist/skills/connector-sandbox/SKILL.md +95 -0
- package/dist/skills/datarails-connect-workato/SKILL.md +140 -0
- package/dist/skills/datarails-connectors-onboard-connector/SKILL.md +813 -0
- package/dist/skills/dr-cli/SKILL.md +659 -0
- package/dist/skills/dr-cli/reference/admin.md +796 -0
- package/dist/skills/dr-cli/reference/budget-builder.md +151 -0
- package/dist/skills/dr-cli/reference/calc-vals.md +73 -0
- package/dist/skills/dr-cli/reference/calcmodels.md +76 -0
- package/dist/skills/dr-cli/reference/cash.md +61 -0
- package/dist/skills/dr-cli/reference/dashboards-widgets.md +85 -0
- package/dist/skills/dr-cli/reference/datamappers.md +150 -0
- package/dist/skills/dr-cli/reference/desk.md +472 -0
- package/dist/skills/dr-cli/reference/filebox-documents.md +373 -0
- package/dist/skills/dr-cli/reference/forecast.md +51 -0
- package/dist/skills/dr-cli/reference/integrations.md +57 -0
- package/dist/skills/dr-cli/reference/lookups.md +168 -0
- package/dist/skills/dr-cli/reference/metrics.md +512 -0
- package/dist/skills/dr-cli/reference/multi-product.md +180 -0
- package/dist/skills/dr-cli/reference/reconciliation-mec.md +76 -0
- package/dist/skills/dr-cli/reference/rh-config.md +84 -0
- package/dist/skills/dr-cli/reference/safety.md +143 -0
- package/dist/skills/dr-cli/reference/spend-control.md +206 -0
- package/dist/skills/dr-cli/reference/templates.md +163 -0
- package/dist/skills/dr-cli/reference/workflows.md +137 -0
- package/dist/skills/dr-error-enrichment/SKILL.md +80 -0
- package/dist/skills/dr-error-enrichment/reference/core.md +257 -0
- package/dist/skills/dr-error-enrichment/reference/groundcover.md +84 -0
- package/dist/skills/dr-error-enrichment/reference/jira-bugs.md +219 -0
- package/dist/skills/dr-error-enrichment/reference/safety-backup.md +122 -0
- package/dist/skills/dr-error-enrichment-author/SKILL.md +219 -0
- package/dist/skills/dr-error-enrichment-improve/SKILL.md +218 -0
- package/dist/skills/dr-error-enrichment-maintain/SKILL.md +237 -0
- package/dist/skills/dr-error-enrichment-reconcile/SKILL.md +167 -0
- package/dist/skills/dr-filebox-api-setup/SKILL.md +170 -0
- package/dist/skills/dr-switch-user/SKILL.md +395 -0
- package/dist/skills/dr-validate/SKILL.md +392 -0
- package/dist/skills/dr-validate/report-template.html +950 -0
- package/dist/skills/fx-conversion-matrix/SKILL.md +763 -0
- package/dist/skills/fx-conversion-matrix/scripts/_args.mjs +52 -0
- package/dist/skills/fx-conversion-matrix/scripts/_xlsx.mjs +241 -0
- package/dist/skills/fx-conversion-matrix/scripts/build-matrix.mjs +366 -0
- package/dist/skills/fx-conversion-matrix/scripts/gen-mappers.mjs +171 -0
- package/dist/skills/fx-conversion-matrix/scripts/rates-to-xlsx.mjs +172 -0
- package/dist/skills/fx-onboard/SKILL.md +325 -0
- package/dist/skills/mec-table-validation/SKILL.md +383 -0
- package/dist/skills/plugins.json +24 -0
- package/dist/skills/validate-workato-migration/SKILL.md +167 -0
- package/dist/skills/validate-workato-migration/reference/gotchas.md +16 -0
- package/dist/skills/validate-workato-migration/reference/staging-orgs.md +26 -0
- package/dist/skills/validate-workato-migration/scripts/compare_files.py +255 -0
- package/dist/zendeskKb-JPSHVOPH.js +243 -0
- package/package.json +56 -9
- package/scripts/postinstall.mjs +91 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# `dr multi-product` — product-content catalog & per-org assignment
|
|
2
|
+
|
|
3
|
+
The `multi-product` microservice (`/api/multi-product/v1/...`) is the
|
|
4
|
+
source of truth for two things:
|
|
5
|
+
|
|
6
|
+
1. **The catalog of available "product contents"** — every row Datarails
|
|
7
|
+
can possibly assign to an organization, tagged with a `type`
|
|
8
|
+
discriminator (`core_interface`, `dataset`, `product`, …).
|
|
9
|
+
2. **The per-organization assignment** — which subset of that catalog a
|
|
10
|
+
given org is entitled to, bucketed by `type`.
|
|
11
|
+
|
|
12
|
+
Two read endpoints + one *replace-the-whole-list* write endpoint. The
|
|
13
|
+
write is destructive in spirit (the server overwrites the org's full
|
|
14
|
+
list with whatever body you send) so it's gated behind a two-step
|
|
15
|
+
confirm token — same flow as `dr entities delete`.
|
|
16
|
+
|
|
17
|
+
## Subcommands
|
|
18
|
+
|
|
19
|
+
All take `--server <key>` (required) and `--account <email>` (when
|
|
20
|
+
multiple identities are stored). Reads accept `--json` for raw
|
|
21
|
+
pass-through; `set` accepts `--json` to emit the server's
|
|
22
|
+
`{"status":"ok"}` ack verbatim.
|
|
23
|
+
|
|
24
|
+
### Catalog (global)
|
|
25
|
+
|
|
26
|
+
- `dr multi-product product-content list` — list every product-content
|
|
27
|
+
row the service knows about. Renders an `ID | NAME | TYPE` table; use
|
|
28
|
+
`--json` for parseable output. Empty → `(no product contents)`.
|
|
29
|
+
→ `GET /api/multi-product/v1/product_content/list`
|
|
30
|
+
|
|
31
|
+
Use this to discover which `(id, name)` pairs are valid for the
|
|
32
|
+
`items` arrays inside the per-org body — names alone don't bind, the
|
|
33
|
+
server matches on the integer `id`.
|
|
34
|
+
|
|
35
|
+
### Per-organization assignment
|
|
36
|
+
|
|
37
|
+
- `dr multi-product org-products list <org_id>` — show the products
|
|
38
|
+
assigned to one org, grouped by `type`. The default text form prints
|
|
39
|
+
each type bucket as a header with `<id>\t<name>` rows underneath;
|
|
40
|
+
`--json` returns the raw `[{type, items:[{id,name}]}]` shape.
|
|
41
|
+
→ `GET /api/multi-product/v1/organizations/<org_id>/products`
|
|
42
|
+
|
|
43
|
+
- `dr multi-product org-products set <org_id> --file <path>
|
|
44
|
+
[--db-only] [--confirm-token <tok>]` — **replace** the org's full
|
|
45
|
+
product list with the JSON in `<path>`. Two-step confirm gated.
|
|
46
|
+
→ `PUT /api/multi-product/v1/organizations/<org_id>/products[?db_only=true]`
|
|
47
|
+
→ server replies `{"status":"ok"}` on success
|
|
48
|
+
|
|
49
|
+
**The body has replace semantics — anything not in the file is
|
|
50
|
+
removed.** Always read the current state first (`org-products list`)
|
|
51
|
+
and either edit that file or apply your delta on top of it. Sending a
|
|
52
|
+
partial body silently revokes everything you forgot.
|
|
53
|
+
|
|
54
|
+
**`--db-only` controls whether the data importer runs.** Omit it (the
|
|
55
|
+
default) when you want the user to actually have data for the new
|
|
56
|
+
product — the server inserts the catalog row AND kicks off the
|
|
57
|
+
data-import workflow. Pass `--db-only` when you only want the
|
|
58
|
+
product row to exist in the MP DB (e.g. provisioning placeholder /
|
|
59
|
+
fixing an out-of-sync catalog) — the server skips the importer
|
|
60
|
+
entirely. Always ask the user which mode they want before running.
|
|
61
|
+
The plan-phase output prints a `MODE:` line (`full` vs `db-only`) so
|
|
62
|
+
you can double-check before confirming.
|
|
63
|
+
|
|
64
|
+
## `--file` body shape
|
|
65
|
+
|
|
66
|
+
`org-products set` takes a JSON array of type buckets — identical to the
|
|
67
|
+
GET response, so a round-trip "list → edit → set" works without
|
|
68
|
+
reshaping. Schema:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
[
|
|
72
|
+
{
|
|
73
|
+
"type": "core_interface",
|
|
74
|
+
"items": [
|
|
75
|
+
{ "id": 1, "name": "full_fpna" }
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"type": "dataset",
|
|
80
|
+
"items": [
|
|
81
|
+
{ "id": 5, "name": "native_fpna" }
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"type": "product",
|
|
86
|
+
"items": [
|
|
87
|
+
{ "id": 11, "name": "ai_agents" }
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
- Root must be an array (not an object).
|
|
94
|
+
- Each entry needs a non-empty string `type` and an `items` array (may
|
|
95
|
+
be empty to clear that bucket).
|
|
96
|
+
- Each item needs an integer `id` and a string `name`. The server
|
|
97
|
+
matches on `id`; the `name` is for human readability.
|
|
98
|
+
- Parser errors are prefixed with the offending location, e.g.
|
|
99
|
+
`--file[0].items[0].id: expected an integer`.
|
|
100
|
+
|
|
101
|
+
## Two-step confirm (the `set` gate)
|
|
102
|
+
|
|
103
|
+
`org-products set` mirrors the `delete`-style flow. The token is bound
|
|
104
|
+
to `(resource:'org-products', id:<org_id>, verb:<verb>)`. `<verb>` is
|
|
105
|
+
`replace` for the default full-import flow and `replace-db-only` when
|
|
106
|
+
`--db-only` is passed — a token issued for one mode cannot be reused
|
|
107
|
+
in the other, and a token issued for org 42 cannot be reused against
|
|
108
|
+
org 99.
|
|
109
|
+
|
|
110
|
+
1. **Plan phase** (no `--confirm-token`): the CLI parses + validates
|
|
111
|
+
the `--file`, prints what it's *about to apply* (one line per type
|
|
112
|
+
bucket with count + `id:name` pairs), and emits the exact confirm
|
|
113
|
+
command with a fresh token. No HTTP call is made.
|
|
114
|
+
2. **Apply phase**: re-run the command with `--confirm-token <tok>`.
|
|
115
|
+
The body is PUT and the server's `{"status":"ok"}` is shown
|
|
116
|
+
(or emitted as raw JSON under `--json`).
|
|
117
|
+
|
|
118
|
+
Token TTL is 10 minutes — past that, re-run step 1.
|
|
119
|
+
|
|
120
|
+
For prod (`US`/`US2`/`UK`/`CA`/`EU`/`DEMO`), get the user's in-chat "yes" before
|
|
121
|
+
re-invoking with the token; the binary's interactive gate then has the user
|
|
122
|
+
type a challenge word in a dialog, same as any other destructive write — see
|
|
123
|
+
[safety.md](safety.md).
|
|
124
|
+
|
|
125
|
+
## Workflow recipe — "give this org access to product X"
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
# 1. Pick the org id (organizations list → find it)
|
|
129
|
+
dr organizations list --server US --json | jq '.[] | {id,name}'
|
|
130
|
+
|
|
131
|
+
# 2. See what's available in the catalog
|
|
132
|
+
dr multi-product product-content list --server US
|
|
133
|
+
|
|
134
|
+
# 3. Read the org's current list as the baseline
|
|
135
|
+
dr multi-product org-products list 42 --server US --json > /tmp/org42.json
|
|
136
|
+
|
|
137
|
+
# 4. Edit /tmp/org42.json to add the new product
|
|
138
|
+
# (e.g. append { "id": 11, "name": "ai_agents" } to the "product" bucket)
|
|
139
|
+
|
|
140
|
+
# 5. Plan phase — review what's about to change
|
|
141
|
+
dr multi-product org-products set 42 --file /tmp/org42.json --server US
|
|
142
|
+
|
|
143
|
+
# 6. Apply with the token printed in step 5
|
|
144
|
+
dr multi-product org-products set 42 --file /tmp/org42.json --server US \
|
|
145
|
+
--confirm-token <tok>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
The "always read first" pattern matters here because the PUT replaces.
|
|
149
|
+
Hand-crafting the file without listing first risks dropping buckets you
|
|
150
|
+
didn't realise existed.
|
|
151
|
+
|
|
152
|
+
## Foot-guns
|
|
153
|
+
|
|
154
|
+
- **Replace, not merge.** `set` overwrites the whole list. Read → edit
|
|
155
|
+
→ write. If the user asks to "add product X" or "remove product Y",
|
|
156
|
+
the recipe still routes through a full-list PUT.
|
|
157
|
+
- **`id` is what binds**, not `name`. A typo in `name` is silently
|
|
158
|
+
accepted at parse time. Cross-check ids against `product-content list`.
|
|
159
|
+
- **`type` is free-form**, not a closed enum. The service may add new
|
|
160
|
+
bucket types over time (the catalog is the source of truth) — don't
|
|
161
|
+
hard-code the three documented buckets (`core_interface`, `dataset`,
|
|
162
|
+
`product`) in scripts; iterate whatever the server returns.
|
|
163
|
+
- **Empty body clears everything**. Sending `[]` is treated as a valid
|
|
164
|
+
replace and revokes all assignments. The plan-phase output flags this
|
|
165
|
+
with `new list: (empty — clears all assignments)`; double-check
|
|
166
|
+
before you confirm.
|
|
167
|
+
- **Token binds to org id.** Generated one for org 42, paste it against
|
|
168
|
+
org 99 — the CLI rejects it with `confirm token does not match this
|
|
169
|
+
resource / action`. Re-run step 1 for the correct id.
|
|
170
|
+
- **Token also binds to `--db-only`.** A plan-phase token issued
|
|
171
|
+
without `--db-only` can't be applied with `--db-only` (or vice
|
|
172
|
+
versa) — the CLI rejects it with the same `does not match this
|
|
173
|
+
resource / action` error. Re-run the plan phase with the mode you
|
|
174
|
+
actually want.
|
|
175
|
+
- **Choose the mode deliberately.** `--db-only` is a row-only
|
|
176
|
+
provisioning lever — the server will NOT start the data-import
|
|
177
|
+
workflow that normally fires when a product is added. If the user
|
|
178
|
+
expects their data to actually show up in the new product, you must
|
|
179
|
+
omit `--db-only` (the default). Confirm with the user which they
|
|
180
|
+
want before confirming the plan-phase token.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Reconciliation + MEC close-dates
|
|
2
|
+
|
|
3
|
+
Alias `recon`. For workflow-engine commands (`mec workflow …`) see
|
|
4
|
+
[workflows.md](workflows.md).
|
|
5
|
+
|
|
6
|
+
## Read
|
|
7
|
+
|
|
8
|
+
- `reconciliation accounts list | entities | entity-currencies | info | progress | settings`.
|
|
9
|
+
- `reconciliation processes dates | accounts`.
|
|
10
|
+
- `reconciliation evidences list | get | process | supporting | file`.
|
|
11
|
+
The v2 verbs (`process`/`supporting`/`file`/`create`) accept either
|
|
12
|
+
`--process <uuid>` **or** `--entity <name> --date <YYYY-MM-DD|YYYY-MM>` (which
|
|
13
|
+
resolves the UUID via the accounts endpoint). The v1 path (`list`, and `file
|
|
14
|
+
--account`) is deprecated and prints a stderr warning.
|
|
15
|
+
- `reconciliation filebox list | get | progress | unlinked`.
|
|
16
|
+
- `reconciliation audit status`.
|
|
17
|
+
|
|
18
|
+
## Write
|
|
19
|
+
|
|
20
|
+
Account assignment / sign-off (all take the bank-account UUID via
|
|
21
|
+
`--account-uuid` — see the flag note below):
|
|
22
|
+
|
|
23
|
+
- `reconciliation accounts update-settings --file <p>` — admin-only PATCH.
|
|
24
|
+
Two-step confirm; the token binds to a hash of the file's rows, so editing
|
|
25
|
+
the file between plan and confirm invalidates it.
|
|
26
|
+
- `reconciliation accounts set-assignee <account_uuid> --date <YYYY-MM-DD>
|
|
27
|
+
--type Preparer|Reviewer --user-id <n> [--user-name <s> --user-email <s>]` —
|
|
28
|
+
resets any prior sign-off; name/email are auto-fetched if not supplied.
|
|
29
|
+
Two-step confirm: first run prints the current holder + a token; re-run
|
|
30
|
+
with `--confirm-token` to actually write.
|
|
31
|
+
- `reconciliation accounts set-assignee --file <csv> --date <YYYY-MM-DD>` —
|
|
32
|
+
the bulk form, for more than a handful of accounts. Header
|
|
33
|
+
`account_id,type,user_id[,user_name,user_email]`, one row per
|
|
34
|
+
(account, role); blank name/email cells are looked up once per user id.
|
|
35
|
+
One plan and one token cover the whole file (the token binds to a hash of
|
|
36
|
+
the rows and the date). The plan reports rows to change, rows skipped
|
|
37
|
+
because the slot already holds that user, and how many sign-offs the write
|
|
38
|
+
resets. Every account is checked before anything is written, and the
|
|
39
|
+
write goes out in PATCHes of 100 accounts. If one fails, the error says
|
|
40
|
+
how many accounts landed; re-run the same file without a token and the
|
|
41
|
+
new plan covers only the rest. Do not script a loop of single
|
|
42
|
+
`set-assignee` calls for this.
|
|
43
|
+
- `reconciliation accounts clear-assignee <account_uuid> --date <YYYY-MM-DD>
|
|
44
|
+
--type Preparer|Reviewer` — unassigns (preserves due_date, resets sign-off).
|
|
45
|
+
Two-step confirm.
|
|
46
|
+
- `reconciliation accounts set-due-date <account_uuid> --date <YYYY-MM-DD>
|
|
47
|
+
--type Preparer|Reviewer (--due-date <YYYY-MM-DD> | --epoch <n> | --clear)`.
|
|
48
|
+
Two-step confirm.
|
|
49
|
+
- `reconciliation accounts sign <account_uuid> --date <YYYY-MM-DD>
|
|
50
|
+
--type Preparer|Reviewer [--revoke]`. Two-step confirm; sign and revoke
|
|
51
|
+
tokens are not interchangeable.
|
|
52
|
+
|
|
53
|
+
Evidences / filebox:
|
|
54
|
+
|
|
55
|
+
- `reconciliation evidences create --file <path> --account-uuid <uuid>
|
|
56
|
+
--amount <n> [--note <s>] [--name <s>]` — multipart upload of a v2 supporting
|
|
57
|
+
item. `--account-uuid` / `--amount` / `--note` are repeatable and
|
|
58
|
+
index-aligned for attaching to multiple accounts.
|
|
59
|
+
- `reconciliation filebox create --file <p>` (`--effective-since` accepts
|
|
60
|
+
`YYYY-MM` or `YYYY-MM-DD`), `reconciliation filebox delete` (two-step confirm).
|
|
61
|
+
|
|
62
|
+
**Flag note:** the bank-account-scoped subcommands take `--account-uuid <uuid>`
|
|
63
|
+
for the bank-account UUID. (`--account` is reserved CLI-wide for the auth-identity
|
|
64
|
+
selector.)
|
|
65
|
+
|
|
66
|
+
## MEC close-dates
|
|
67
|
+
|
|
68
|
+
- `mec close-dates get` — the org's close-date map (whole org, or `--year`).
|
|
69
|
+
- `mec close-dates set --file <p>` — admin-only PUT; replaces the org's
|
|
70
|
+
close-date map from a JSON file.
|
|
71
|
+
|
|
72
|
+
## Customer-facing docs (KB)
|
|
73
|
+
|
|
74
|
+
Help Center → the **"Month End Close"** category. Find current articles with `dr kb search "month end close reconciliation"` (or
|
|
75
|
+
browse `dr kb categories` / `dr kb sections`). Cite the article; don't
|
|
76
|
+
paraphrase from memory.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# `dr rh_config` — legacy RH_CONFIG inspection (read-only)
|
|
2
|
+
|
|
3
|
+
RH_CONFIG is the **legacy** mechanism by which a filebox's "config workbook"
|
|
4
|
+
(the Excel attached to the bucket with `is_config=True`) defines its
|
|
5
|
+
TableTemplates. The Excel contains a sheet literally named `RH_Config` that
|
|
6
|
+
the monolith's parser reads via `LEGACY_get_document_data_from_workbook_rh_config`
|
|
7
|
+
(`HippiWeb/Documents/utils_cython.py:233`) to build the templates and their
|
|
8
|
+
LUTs. A template generated from that path carries `is_rh_config: true`
|
|
9
|
+
(true when `TableTemplate.config == ''` server-side).
|
|
10
|
+
|
|
11
|
+
The `rh_config` family is purely read-only — five GETs for inspecting
|
|
12
|
+
legacy state during audits or debugging. No writes; if you need to upload a
|
|
13
|
+
new config workbook or trigger a rescan, use the standard `filebox` /
|
|
14
|
+
`buckets` write surfaces (which the FE drives).
|
|
15
|
+
|
|
16
|
+
## Subcommands
|
|
17
|
+
|
|
18
|
+
All take `--server <key>` (required) and `--account <email>` (when multiple
|
|
19
|
+
identities are stored). Every read accepts `--json` for raw pass-through.
|
|
20
|
+
|
|
21
|
+
- `dr rh_config config <bucket-id>` — show the config `DocumentVersion`
|
|
22
|
+
attached to a bucket (the workbook with the `RH_Config` sheet). Renders a
|
|
23
|
+
kv summary: version id, document id, name, version number, status,
|
|
24
|
+
created timestamp. `(no config version)` when the bucket has never had a
|
|
25
|
+
config workbook.
|
|
26
|
+
→ `GET /api/buckets/<id>/config`
|
|
27
|
+
|
|
28
|
+
- `dr rh_config tables <bucket-id>` — show the config file URL plus the
|
|
29
|
+
table names defined by the workbook (the names of `ACTIVE`, non-archive
|
|
30
|
+
`TableTemplate` rows that belong to the bucket's data model). Useful
|
|
31
|
+
for "what does this filebox's config say it should create?"
|
|
32
|
+
→ `GET /api/buckets/admin/<id>/config_update`
|
|
33
|
+
|
|
34
|
+
- `dr rh_config download <bucket-id> [--output <path>]` — download the raw
|
|
35
|
+
config `.xlsx`. Default destination is `bucket_<id>_config.xlsx` in the
|
|
36
|
+
current directory; `--output -` streams bytes to stdout (pipe-friendly).
|
|
37
|
+
→ `GET /api/buckets/admin/<id>/file`
|
|
38
|
+
- **Broken — don't use.** The endpoint doesn't accept the CLI's JWT, so the
|
|
39
|
+
command writes the auth login HTML page to disk instead of the workbook
|
|
40
|
+
(exit 0, no error). **Workaround:** get the config version's `id` and
|
|
41
|
+
`document` from `dr rh_config config <bucket-id> --json`, then
|
|
42
|
+
`dr filebox download <document> --doc-version <id> --output <path>`.
|
|
43
|
+
|
|
44
|
+
- `dr rh_config doc-templates <document-id> [--legacy-only]` — list
|
|
45
|
+
templates associated with a document, with the `is_rh_config` flag
|
|
46
|
+
surfaced. `--legacy-only` filters to RH_CONFIG-derived rows (the usual
|
|
47
|
+
ask during a legacy audit). The document id is the `Document` id (not a
|
|
48
|
+
version id, not a bucket id).
|
|
49
|
+
→ `GET /api/documents/<id>/template_configs`
|
|
50
|
+
|
|
51
|
+
- `dr rh_config version-templates <version-id> [--v2] [--legacy-only]` —
|
|
52
|
+
list templates referenced by a document version (functions + extables
|
|
53
|
+
combined). `--v2` switches to the v2 path that also reports
|
|
54
|
+
`split_obj_exists`, the indicator the FE uses to show "this version is
|
|
55
|
+
split". The version id is a `DocumentVersion` id (get it from
|
|
56
|
+
`filebox versions <doc_id>`).
|
|
57
|
+
→ `GET /api/documents/versions/<id>/get_functions_templates`
|
|
58
|
+
→ with `--v2`: `GET /api/documents/v2/versions/<id>/get_functions_templates`
|
|
59
|
+
|
|
60
|
+
## When to reach for `rh_config` instead of `templates` / `filebox`
|
|
61
|
+
|
|
62
|
+
- "Is this template RH_CONFIG-derived?" → `dr rh_config doc-templates <doc>
|
|
63
|
+
--legacy-only` (the regular `templates list` doesn't render the flag).
|
|
64
|
+
- "What does the config workbook look like for this filebox?" → `dr
|
|
65
|
+
rh_config config <bucket> --json` for the version `id` + `document`, then
|
|
66
|
+
`dr filebox download <document> --doc-version <id>` to grab the .xlsx
|
|
67
|
+
(not `rh_config download` — it saves the login page, see above). Or `dr
|
|
68
|
+
rh_config tables <bucket>` for just the table names.
|
|
69
|
+
- "Did this version reference any legacy-config tables?" → `dr rh_config
|
|
70
|
+
version-templates <vid> --legacy-only`.
|
|
71
|
+
|
|
72
|
+
For non-legacy template operations (sample data, distinct, aggregate,
|
|
73
|
+
create, set field type, …) keep using `dr templates ...` — RH_CONFIG is
|
|
74
|
+
about the legacy plumbing only.
|
|
75
|
+
|
|
76
|
+
## Why this family is read-only
|
|
77
|
+
|
|
78
|
+
RH_CONFIG is on the deprecation runway: the monolith's
|
|
79
|
+
`utils_cython.py:72` literally says `# !!! this one should be removed
|
|
80
|
+
after getting rid of RH_CONFIG !!`. Writes against the RH_CONFIG path
|
|
81
|
+
exist (uploading a new config workbook, triggering a rescan), but the
|
|
82
|
+
sanctioned way to drive them is the existing FE flow — exposing them in a
|
|
83
|
+
"legacy" CLI family would invite people to keep extending the surface
|
|
84
|
+
instead of migrating off it.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Safety — confirm flow, prod gate, escalation
|
|
2
|
+
|
|
3
|
+
## Two-step confirm (every `delete`, plus `templates set-field-type`)
|
|
4
|
+
|
|
5
|
+
Running a gated command without a token fetches the target, prints its name +
|
|
6
|
+
key attributes, and emits a short-lived confirmation token. Re-run with
|
|
7
|
+
`--confirm-token <tok>` to actually perform the write.
|
|
8
|
+
|
|
9
|
+
- The token is bound to `(resource, id, verb)`: a token for LUT 12 refuses
|
|
10
|
+
against function 12 — it catches ID typos, not just stray enter-hits.
|
|
11
|
+
- Tokens expire after 10 minutes; the signing secret is per-machine and never
|
|
12
|
+
leaves the local machine.
|
|
13
|
+
- Bulk operations bind the token to a hash of the change set (e.g.
|
|
14
|
+
`templates set-field-type --file`, `cash rules delete-all`), so editing the
|
|
15
|
+
file between plan and confirm invalidates the token.
|
|
16
|
+
- The printed confirm command echoes the plan invocation's `--account`, so on
|
|
17
|
+
a keychain holding several identities for the server it can be pasted
|
|
18
|
+
verbatim — no need to re-add the flag by hand (gap #41).
|
|
19
|
+
|
|
20
|
+
Gated commands include: `dashboards delete`, `datamappers delete`,
|
|
21
|
+
`dynamic-ranges delete`, `extables delete`, `functions delete`, `lut delete`,
|
|
22
|
+
`reports delete`, `storyboards delete`, `metrics delete`, `metrics categories
|
|
23
|
+
delete`, `metrics dimensions delete`, `calcmodels delete|set-flow|recalculate`,
|
|
24
|
+
`reconciliation filebox delete`, `integrations delete`, `integrations it
|
|
25
|
+
delete`, `devices command-delete`, `validate onboarding session delete`,
|
|
26
|
+
`widgets delete`, `cash rules delete|delete-all|reorder|update`,
|
|
27
|
+
`cash hidden-rules upsert|delete`, `forecast` lock/unlock/default/delete/clone
|
|
28
|
+
verbs, `workflow`/`mec workflow` create/update/activate/delete and friends,
|
|
29
|
+
`collection-processes` create/mutate verbs, and the non-`delete` mutations
|
|
30
|
+
`templates set-field-type`, `rescan table`, `features orgs add|remove`,
|
|
31
|
+
`dashboards push`, `filebox push`, and `reconciliation accounts
|
|
32
|
+
set-assignee|clear-assignee|set-due-date|sign|update-settings`. When
|
|
33
|
+
in doubt, run the command without a token and read the plan output.
|
|
34
|
+
|
|
35
|
+
## Prod write gate (when Claude drives the CLI)
|
|
36
|
+
|
|
37
|
+
Reads never need confirmation. Gated **writes** fall into two tiers (full table:
|
|
38
|
+
`src/commands/_prodGateTiers.ts`):
|
|
39
|
+
|
|
40
|
+
- **Tier A — destructive / irreversible / org-wide.** On a prod tenant (`US`,
|
|
41
|
+
`US2`, `UK`, `CA`, `EU`, `DEMO` — DEMO is customer-facing) the binary requires a
|
|
42
|
+
live human to type a fresh challenge word in a desktop dialog / TTY (see
|
|
43
|
+
"Binary-enforced interactive gate" below). Relay the plan output (target name
|
|
44
|
+
+ blast radius), get a clear in-chat "yes, do it", then re-invoke with
|
|
45
|
+
`--confirm-token <tok>`. That dialog IS the attentiveness check — do **not**
|
|
46
|
+
add your own word ritual in chat.
|
|
47
|
+
- **Tier B — reversible / additive / low-blast.** No challenge word on any
|
|
48
|
+
server: token-only, fully scriptable, completable by an agent end-to-end.
|
|
49
|
+
Still relay the plan and get the user's in-chat "yes" before the execute step,
|
|
50
|
+
but it will not pop a dialog.
|
|
51
|
+
- **Non-prod (`DEV`, `DEV-1`, `TEST`, `TEST-1`…`TEST-7`):** a plain `yes` is fine
|
|
52
|
+
for either tier — token only.
|
|
53
|
+
|
|
54
|
+
**Tier A is the smaller set:** every `delete` (across all resources), plus
|
|
55
|
+
`workflow`/`mec workflow` `archive` (and its `delete` alias), `process delete`,
|
|
56
|
+
`step delete`, `task delete`; `forecast scenarios bulk-edit`; `cash rules
|
|
57
|
+
delete-all`; `filebox archive` and `filebox data-query clear`;
|
|
58
|
+
`multi-product org-products set`;
|
|
59
|
+
`error-enrichments import` (replaces every rule on the server, zeroes all
|
|
60
|
+
hits/feedback counters, and reassigns every rule id); and
|
|
61
|
+
`dashboards push --override` / `filebox push --override`. `import` is **not** an
|
|
62
|
+
edit or reconcile tool: changing a fleet of rules — including making one server
|
|
63
|
+
match another — is a batch `create`/`update`, and `import` runs only when the
|
|
64
|
+
user names `import` and confirms the loss of hits/thumbs analytics and the id
|
|
65
|
+
reassignment. Never reach for it on your own initiative. `error-enrichments
|
|
66
|
+
delete` takes several ids at once and spends **one** word gate on the whole
|
|
67
|
+
batch, so the plan output — which lists every targeted rule with its hits and
|
|
68
|
+
feedback — is the blast-radius check; read it per-rule, not as a count. Batch
|
|
69
|
+
writes (`create`/`update`/`delete` with several targets) run sequentially and
|
|
70
|
+
keep going after a per-item failure, then exit non-zero: the per-item summary
|
|
71
|
+
table, not the exit code, is what says which ids actually landed. The two pushes
|
|
72
|
+
**without** `--override` are Tier B — rolling a template out to child orgs is
|
|
73
|
+
the workflow they exist for. One caveat on `filebox push`: create-new is the
|
|
74
|
+
usual outcome but not guaranteed — if a destination already holds a filebox
|
|
75
|
+
with the same alias and tags, the push adds a version to *that* filebox and it
|
|
76
|
+
becomes the one served. The CLI cannot tell in advance and no word gate will
|
|
77
|
+
stop it, so check the destination afterwards.
|
|
78
|
+
Everything else gated is Tier B (all `create`/`update`/`reorder`/`set-*`/`lock`/
|
|
79
|
+
`unlock` verbs, `templates set-field-type`, `rescan table` (a full historical
|
|
80
|
+
rescan — expensive/high-blast but reversible, so token-only; the plan step shows
|
|
81
|
+
the document + version counts), `metrics re-aggregate`, `metrics migrate` (the
|
|
82
|
+
org-wide V1→V2 backfill — deletes nothing, but **overwrites**
|
|
83
|
+
`category`/`time_aggregation` with the name-derived mapping, hand-set values
|
|
84
|
+
included; per-metric before→after is in the response `details[]`. A
|
|
85
|
+
request-level failure (500) rolls back everything; per-metric failures are
|
|
86
|
+
non-fatal — a 200 can carry `metrics.errors[]` with the rest of the org
|
|
87
|
+
committed, and under `--json` that warning is on **stderr**, not stdout.
|
|
88
|
+
Always run `--dry-run` first, and check `metrics.errors[]` after the live
|
|
89
|
+
run), `collection-processes`
|
|
90
|
+
verbs, `cash rules update|reorder`, `spend-control contracts bulk-create`,
|
|
91
|
+
`features orgs add|remove` (a delta over one `(org, flag)` boolean — each verb
|
|
92
|
+
sets it, neither destroys state — so it is token-only even on prod, unlike
|
|
93
|
+
`multi-product org-products set`, which replaces the whole entitlement set and
|
|
94
|
+
stays Tier A. Running the opposite verb is **not** an undo: it sets membership to
|
|
95
|
+
the opposite value, which restores the prior state only if that was the prior
|
|
96
|
+
state, and the CLI never reads current membership. Check with `features orgs list
|
|
97
|
+
<org_id>` before treating either verb as a revert), …).
|
|
98
|
+
When unsure, run the plan step — a Tier-A prod execute in a non-interactive
|
|
99
|
+
channel refuses and names the fix.
|
|
100
|
+
|
|
101
|
+
For destructive operations, surface the blast radius first — e.g. "this removes
|
|
102
|
+
the LUT that 4 functions depend on" — before running.
|
|
103
|
+
|
|
104
|
+
### Binary-enforced interactive gate (Tier A only)
|
|
105
|
+
|
|
106
|
+
The human check is enforced **in the binary** — not by prose an agent could
|
|
107
|
+
skip or forget. When a valid `--confirm-token` is redeemed for a **Tier-A**
|
|
108
|
+
action against a prod tenant (`US`, `US2`, `UK`, `CA`, `EU`, `DEMO` — plus,
|
|
109
|
+
fail-closed, any server the CLI cannot positively classify as non-prod, and any
|
|
110
|
+
action not positively classified as Tier B), the binary requires a live human:
|
|
111
|
+
|
|
112
|
+
- **Interactive human** (desktop dialog on Windows/macOS/Linux, or a TTY
|
|
113
|
+
prompt): a fresh random word is shown *only in the dialog* and must be typed
|
|
114
|
+
back. Wrong word / cancel → the write does not happen.
|
|
115
|
+
- **No interactive channel** (agent shell, pipe, headless/SSH): the command
|
|
116
|
+
refuses — it **exits non-zero** with an error naming the exact line to run
|
|
117
|
+
in a real terminal, so a script can't mistake the refusal for success.
|
|
118
|
+
|
|
119
|
+
Practical consequence when you (Claude) drive the CLI: for a Tier-A prod write,
|
|
120
|
+
run the **plan** step, relay it, get the user's in-chat yes, then run the
|
|
121
|
+
**execute** step with the token yourself. On a desktop machine your subprocess
|
|
122
|
+
runs inside the user's login session, so the dialog pops on *their screen* and
|
|
123
|
+
they answer it there — the challenge word travels on a channel your toolchain
|
|
124
|
+
can't read. In a headless/SSH context the execute step refuses instead, exits
|
|
125
|
+
non-zero, and names the exact command for the user to run in a real terminal.
|
|
126
|
+
Tier-B and non-prod writes are unaffected — token-only, fully scriptable.
|
|
127
|
+
|
|
128
|
+
## Escalate / stop
|
|
129
|
+
|
|
130
|
+
- A prod destructive without a clear in-chat "yes, do it" from the user.
|
|
131
|
+
- A write that affects more than one customer or a shared fixture (e.g. editing
|
|
132
|
+
a data model multiple tenants depend on) — file a ticket instead.
|
|
133
|
+
- **Exception: `dashboards push` / `filebox push`.** Writing into other
|
|
134
|
+
organizations is the whole point of those two, so they are sanctioned rather
|
|
135
|
+
than escalated. What makes them safe is bounded: destinations are refused
|
|
136
|
+
unless they appear in `organizations push-targets` (the caller's own
|
|
137
|
+
inherited orgs — never an arbitrary tenant), the batch is capped at 50, and
|
|
138
|
+
the plan step names every destination as `name (id)` before the token is
|
|
139
|
+
issued. Relay that destination list to the user and get an explicit "yes"
|
|
140
|
+
naming the orgs — the multi-customer blast radius is real even though the
|
|
141
|
+
command is allowed.
|
|
142
|
+
- The task needs a new subcommand / flag / API the CLI doesn't have — open a PR
|
|
143
|
+
against `Datarails/dr-cli`. Don't invent a command to fill the gap.
|