@datarails-ai/dr-cli 0.0.1-locked → 1.6.71

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.
Files changed (58) hide show
  1. package/README.md +608 -0
  2. package/dist/chunk-DWMCBGQH.js +242 -0
  3. package/dist/cli.js +64468 -0
  4. package/dist/kb-6UWI7Q32.js +21 -0
  5. package/dist/scopes-map.json +4412 -0
  6. package/dist/skills/connector-sandbox/SKILL.md +95 -0
  7. package/dist/skills/datarails-connect-workato/SKILL.md +140 -0
  8. package/dist/skills/datarails-connectors-onboard-connector/SKILL.md +813 -0
  9. package/dist/skills/dr-cli/SKILL.md +659 -0
  10. package/dist/skills/dr-cli/reference/admin.md +796 -0
  11. package/dist/skills/dr-cli/reference/budget-builder.md +151 -0
  12. package/dist/skills/dr-cli/reference/calc-vals.md +73 -0
  13. package/dist/skills/dr-cli/reference/calcmodels.md +76 -0
  14. package/dist/skills/dr-cli/reference/cash.md +61 -0
  15. package/dist/skills/dr-cli/reference/dashboards-widgets.md +85 -0
  16. package/dist/skills/dr-cli/reference/datamappers.md +150 -0
  17. package/dist/skills/dr-cli/reference/desk.md +472 -0
  18. package/dist/skills/dr-cli/reference/filebox-documents.md +373 -0
  19. package/dist/skills/dr-cli/reference/forecast.md +51 -0
  20. package/dist/skills/dr-cli/reference/integrations.md +57 -0
  21. package/dist/skills/dr-cli/reference/lookups.md +168 -0
  22. package/dist/skills/dr-cli/reference/metrics.md +512 -0
  23. package/dist/skills/dr-cli/reference/multi-product.md +180 -0
  24. package/dist/skills/dr-cli/reference/reconciliation-mec.md +76 -0
  25. package/dist/skills/dr-cli/reference/rh-config.md +84 -0
  26. package/dist/skills/dr-cli/reference/safety.md +143 -0
  27. package/dist/skills/dr-cli/reference/spend-control.md +206 -0
  28. package/dist/skills/dr-cli/reference/templates.md +163 -0
  29. package/dist/skills/dr-cli/reference/workflows.md +137 -0
  30. package/dist/skills/dr-error-enrichment/SKILL.md +80 -0
  31. package/dist/skills/dr-error-enrichment/reference/core.md +257 -0
  32. package/dist/skills/dr-error-enrichment/reference/groundcover.md +84 -0
  33. package/dist/skills/dr-error-enrichment/reference/jira-bugs.md +219 -0
  34. package/dist/skills/dr-error-enrichment/reference/safety-backup.md +122 -0
  35. package/dist/skills/dr-error-enrichment-author/SKILL.md +219 -0
  36. package/dist/skills/dr-error-enrichment-improve/SKILL.md +218 -0
  37. package/dist/skills/dr-error-enrichment-maintain/SKILL.md +237 -0
  38. package/dist/skills/dr-error-enrichment-reconcile/SKILL.md +167 -0
  39. package/dist/skills/dr-filebox-api-setup/SKILL.md +170 -0
  40. package/dist/skills/dr-switch-user/SKILL.md +395 -0
  41. package/dist/skills/dr-validate/SKILL.md +392 -0
  42. package/dist/skills/dr-validate/report-template.html +950 -0
  43. package/dist/skills/fx-conversion-matrix/SKILL.md +763 -0
  44. package/dist/skills/fx-conversion-matrix/scripts/_args.mjs +52 -0
  45. package/dist/skills/fx-conversion-matrix/scripts/_xlsx.mjs +241 -0
  46. package/dist/skills/fx-conversion-matrix/scripts/build-matrix.mjs +366 -0
  47. package/dist/skills/fx-conversion-matrix/scripts/gen-mappers.mjs +171 -0
  48. package/dist/skills/fx-conversion-matrix/scripts/rates-to-xlsx.mjs +172 -0
  49. package/dist/skills/fx-onboard/SKILL.md +325 -0
  50. package/dist/skills/mec-table-validation/SKILL.md +383 -0
  51. package/dist/skills/plugins.json +24 -0
  52. package/dist/skills/validate-workato-migration/SKILL.md +167 -0
  53. package/dist/skills/validate-workato-migration/reference/gotchas.md +16 -0
  54. package/dist/skills/validate-workato-migration/reference/staging-orgs.md +26 -0
  55. package/dist/skills/validate-workato-migration/scripts/compare_files.py +255 -0
  56. package/dist/zendeskKb-JPSHVOPH.js +243 -0
  57. package/package.json +56 -9
  58. package/scripts/postinstall.mjs +91 -0
@@ -0,0 +1,395 @@
1
+ ---
2
+ name: dr-switch-user
3
+ description: Set an in-conversation default --account for dr-cli (Datarails CLI), and impersonate a customer via `dr login-as` when needed. Use when the user wants to switch identity, log in as someone else, impersonate a customer, or list saved identities. Triggers - "switch to <email>", "switch user to <email>", "use <email>", "use <email> from now on", "login as <email>", "log me in as <email>", "impersonate <email>", "show me available identities", "show stored identities", "list saved users", "who am I logged in as", "which dr accounts are saved", "/switch-user", "/switch-user <email>". The session default itself is not written to any file - it's a rule Claude follows for the rest of this conversation; credential storage is handled by dr login / dr login-as. Install, update, or log in to the CLI → /dr-cli:install; a CLI that is installed but misbehaving → /dr-cli:doctor.
4
+ ---
5
+
6
+ # dr-switch-user — set the session default --account for dr-cli
7
+
8
+ ## Why this skill exists
9
+
10
+ `dr-cli` is **stateless with respect to identity** — every command takes
11
+ `--account <email>` separately. There is no "active user" in the CLI. So
12
+ "switching user" really means: tell Claude which email to pass as
13
+ `--account` for the rest of *this conversation only*.
14
+
15
+ This skill does three things:
16
+
17
+ 1. **Verify** the chosen email has working credentials on at least one
18
+ server, by probing each server's local JWT via `dr whoami`.
19
+ 2. **Add the identity** if credentials are missing — either by
20
+ impersonating a customer with `dr login-as <email>` (JWT only, no
21
+ browser; needs an operator login first), or by a browser `dr login`
22
+ for the operator's own identity. See Section 3.
23
+ 3. **Record an in-conversation session default** — a directive Claude
24
+ obeys for the rest of this chat.
25
+
26
+ > **Impersonation is now a real CLI command.** `dr login-as <email>
27
+ > --server <X>` mints an impersonation JWT from an existing operator login
28
+ > and stores it as a switchable `(server, email)` identity — no browser
29
+ > round-trip. This is the correct path for "log me in as <customer>";
30
+ > browser `dr login` can only sign you in as whoever the browser is.
31
+
32
+ ## Hard rules
33
+
34
+ - **Never persist.** Do not write to `MEMORY.md`, `CLAUDE.md`,
35
+ `settings.json`, or any other file. The default lives only in
36
+ Claude's context for this conversation. Opening a new Claude Code
37
+ session = no default carries over.
38
+ - **Never assume which identity to use.** This skill is the cure for
39
+ exactly that mistake. If the user's intent is ambiguous (no email
40
+ given, multiple matches, mismatch after login), **ask**.
41
+ - **Server is always passed per-command.** The default scopes only
42
+ `--account`. `--server` stays explicit on every dr invocation.
43
+
44
+ ## Inputs
45
+
46
+ The skill is invoked in one of these forms:
47
+
48
+ | Form | Meaning |
49
+ | ------------------------------------------ | ---------------------------------------------------- |
50
+ | `/switch-user <email>` or "switch to <email>" | Set default to `<email>` (Sections 2 + 3 below) |
51
+ | `/switch-user` (no arg) or "show identities" | List all stored identities + offer picker (Section 4) |
52
+ | "stop defaulting" / "clear default user" | Remove any active session default |
53
+
54
+ ## Server keys (the universe to probe)
55
+
56
+ `US`, `US2`, `UK`, `CA`, `EU`, `DEV`, `DEV-1`, `TEST`, `TEST-1`, `TEST-2`, `TEST-3`, `TEST-4`, `TEST-5`, `TEST-6`, `TEST-7`, `DEMO` — case-insensitive.
57
+ These are the only valid `--server` values dr-cli accepts.
58
+
59
+ ---
60
+
61
+ ## Section 1 — Validate the email
62
+
63
+ Before probing, sanity-check the input:
64
+
65
+ - Must contain a single `@`.
66
+ - Must have at least one character before and after `@`.
67
+ - Must contain at least one `.` after the `@`.
68
+
69
+ If invalid: print `<input> doesn't look like an email — usage:
70
+ /switch-user <user>@<domain>` and stop. Do not probe.
71
+
72
+ ---
73
+
74
+ ## Section 2 — Probe one server for the email (happy path)
75
+
76
+ **Do NOT probe all 16 servers.** When the user invokes the skill with an
77
+ email, they have a specific server in mind. Asking is cheap; guessing
78
+ across all servers wastes turns and can scope the default wrongly.
79
+
80
+ ### 2.1. Ask which server
81
+
82
+ Print verbatim, then wait for the user's reply. Do not guess from
83
+ context, prior turns, or `userEmail`:
84
+
85
+ > Which server should I switch to `<email>` on? (`US`, `US2`, `UK`, `CA`, `EU`, `DEV`, `DEV-1`, `TEST`, `TEST-1`, `TEST-2`, `TEST-3`, `TEST-4`, `TEST-5`, `TEST-6`, `TEST-7`, `DEMO`)
86
+
87
+ ### 2.2. Probe that one server
88
+
89
+ Run a single Bash call:
90
+
91
+ ```bash
92
+ dr whoami --server <X> --account <email> 2>&1 || true
93
+ ```
94
+
95
+ `whoami` is purely offline (decodes the locally-stored JWT, no network).
96
+ Classify the output:
97
+
98
+ | Result | Meaning |
99
+ | ------------------------------------------------------ | ---------------------------------------- |
100
+ | Exit 0, prints matching email + JWT exp | Stored on this server → Section 5 (if it shows `Impersonated by:`, it's a login-as identity — still stored, still fine) |
101
+ | `not logged in to <SERVER>` | Not stored → Section 3 (add it — login-as or browser login) |
102
+ | `no JWT stored for <server>` | Creds malformed → Section 3 (add it — login-as or browser login) |
103
+ | `multiple accounts stored for <SERVER>: ...` with the requested email in the list | Stored on this server (defensive case — passing --account should normally avoid this) → Section 5 |
104
+ | Anything else | Surface verbatim, do not record a default |
105
+
106
+ ---
107
+
108
+ ## Section 3 — Add the identity (email not stored on the chosen server)
109
+
110
+ The server was already chosen in Section 2.1. There are **two ways** to add
111
+ `<email>`, and which is correct depends on *whose* identity it is:
112
+
113
+ - **3A — Impersonate a customer with `dr login-as` (JWT, no browser).**
114
+ Use when `<email>` is a **customer / another user** you want to act as,
115
+ and you (an operator/support user) are already logged in on this server.
116
+ This is the normal path for "log me in as <customer>".
117
+ - **3B — Browser `dr login` (your own / the operator identity).**
118
+ Use when `<email>` is **you** (the operator) and you just haven't logged
119
+ in on this server yet — or when there's *no* operator login on the server
120
+ at all, so nobody can authorize an impersonation.
121
+
122
+ Decide with one offline probe (no network) — list what's stored on <X>:
123
+
124
+ ```bash
125
+ dr whoami --server <X> 2>&1 || true
126
+ ```
127
+
128
+ - **An operator (non-impersonated) login already exists on <X>** and
129
+ `<email>` is *not* that operator → **3A** (login-as).
130
+ - **Nothing is stored on <X>**, or the only way to reach `<email>` is to
131
+ sign in as yourself → **3B** (browser login).
132
+
133
+ If it's genuinely ambiguous whether `<email>` is a customer to impersonate
134
+ or an operator to sign in as, **ask** — don't guess.
135
+
136
+ ### 3A. Impersonate via `dr login-as`
137
+
138
+ ```
139
+ dr login-as <email> --server <X>
140
+ ```
141
+
142
+ Resolves `<email>` to a user id via `can_login_as`, mints an impersonation
143
+ JWT from the monolith authorized by the operator, and stores it as a
144
+ switchable `(server, email)` identity — no browser, no TTY prompt.
145
+
146
+ - **Multiple operators stored on <X>** → the CLI refuses and lists them.
147
+ Re-run with `--as <operator-email>` to pick who authorizes the mint.
148
+ - **Email doesn't resolve** → the CLI suggests near matches; if you already
149
+ know the id, re-run with `--user-id <n>`.
150
+ - **No operator login on <X>** → the CLI says to run `dr login` first. Fall
151
+ back to **3B** to establish the operator, then re-run login-as.
152
+ - **Denials** surface as clear messages — *not permitted to impersonate*,
153
+ *inactive*, *impersonation service unavailable*. Surface verbatim; do not
154
+ retry; do not record a default.
155
+ - **`login-as` needs dr ≥ 1.3.24.** Older installs answer `unknown command
156
+ 'login-as'`. If the browser Login-As works but the CLI "can't", check
157
+ `dr --version` / `dr update` first — that's the common cause, not permissions.
158
+ - **The product `SUPER_ADMIN` role ≠ Django `is_superuser`.** `login-as` runs
159
+ the *same* gate as the browser Login-As (`it_loginas`) and only blocks
160
+ genuine Django `is_superuser` / sync-service / application targets — a
161
+ customer whose product role is `SUPER_ADMIN` is still impersonable (verified
162
+ on DEMO). There is **no** equal-or-higher-privilege rule, so a `can-login-as`
163
+ hit is generally reliable. `not permitted` means a true superuser/sync/
164
+ application target, or you the operator lack scope (superuser operator → any
165
+ non-superuser; supporting-manager → only users in your supported orgs). If it
166
+ fires, surface the message — don't fall back to browser login as that email.
167
+ - **Success** prints
168
+ `Logged into <X> as <email> (impersonated by <operator>). JWT expires in …`
169
+ → go to Section 5 (record the default, scoped to this server). No
170
+ post-login identity check needed — login-as targets `<email>` directly,
171
+ so there's no browser-mismatch risk.
172
+
173
+ ### 3B. Browser login via `dr login`
174
+
175
+ Do **not** prompt the user before running login. Just run it. The
176
+ post-login identity check (3B.2) is the safety net for the
177
+ browser-signed-in-as-the-wrong-account case — we catch the mismatch after
178
+ and let the user decide.
179
+
180
+ Optionally print a single short status line like *"Running `dr login
181
+ --server <X>` — if your browser is signed in as a different account, the
182
+ OAuth flow will pick that one and I'll flag the mismatch after. To
183
+ impersonate a customer instead, I can use `dr login-as` once there's an
184
+ operator login here."* **Do not wait for a reply.**
185
+
186
+ ```
187
+ dr login --server <X>
188
+ ```
189
+
190
+ (No `--account` flag — `dr login` doesn't accept one; the browser flow
191
+ determines identity.)
192
+
193
+ #### 3B.2. Verify post-login identity
194
+
195
+ Capture the email from the success line:
196
+
197
+ ```
198
+ Logged into <X> as <whoever>@datarails.com. JWT expires in ...
199
+ ```
200
+
201
+ Compare `<whoever>@datarails.com` to the requested `<email>`:
202
+
203
+ - **Match** → loop back to Section 5 (announce + record default,
204
+ scoped to this server).
205
+ - **Mismatch** → print and stop:
206
+
207
+ > Browser logged you in as `<whoever>@datarails.com`, not `<email>`. Three options: (1) if `<email>` is a customer, keep `<whoever>` as the operator and re-run `/switch-user <email>` — I'll impersonate via `dr login-as`; (2) sign out of the browser and re-run `/switch-user <email>`; or (3) accept `<whoever>` as the new session default instead. Which?
208
+
209
+ Do **not** auto-pick. Do **not** silently accept the wrong identity.
210
+
211
+ #### 3B.3. Login failures
212
+
213
+ Browser closed, timeout, network error: surface dr-cli's stderr
214
+ verbatim. Do not retry. Do not record any default.
215
+
216
+ ---
217
+
218
+ ## Section 4 — No-arg flow: list saved identities + picker
219
+
220
+ User invokes `/switch-user` with no email, or asks "show identities" /
221
+ "who's logged in" / "which accounts are saved".
222
+
223
+ ### 4.1. Probe every server (no --account)
224
+
225
+ Use the **single-loop pattern** (same reason as Section 2 — parallel
226
+ tool calls cancel each other on the first non-zero exit):
227
+
228
+ ```bash
229
+ for srv in US US2 UK CA EU DEV DEV-1 TEST TEST-1 TEST-2 TEST-3 TEST-4 TEST-5 TEST-6 TEST-7 DEMO; do
230
+ echo "=== $srv ==="
231
+ dr whoami --server "$srv" 2>&1 || true
232
+ done
233
+ ```
234
+
235
+ Possible outcomes per server (parse each `=== <srv> ===` block):
236
+
237
+ - **Exit 0** → one identity is stored; capture the email from output.
238
+ - **Exit 1 with `multiple accounts stored for <SERVER>:`** → parse
239
+ the email list from stderr. Each row shape: ` - <email> (last used <date>)`.
240
+ - **`not logged in`** or **`no JWT stored`** → skip this server.
241
+
242
+ ### 4.2. Render a picker
243
+
244
+ Print a numbered, flat list of every `(server, email, last-used)` pair
245
+ found:
246
+
247
+ ```
248
+ Stored identities:
249
+ 1. US alice@datarails.com (last used 2026-05-14)
250
+ 2. US bob@datarails.com (last used 2026-05-15)
251
+ 3. DEV alice@datarails.com (last used 2026-05-10)
252
+ 4. DEMO carol@datarails.com (last used 2026-04-02)
253
+
254
+ Reply with a number to set as session default, or an email to set that
255
+ email across every server it appears on. Reply 'login' to add a new
256
+ identity (browser login for yourself, or `dr login-as` to impersonate a
257
+ customer).
258
+ ```
259
+
260
+ Wait for the user's pick.
261
+
262
+ ### 4.3. Resolve the pick
263
+
264
+ - **Number** → default is scoped to that one specific `(server, email)`
265
+ pair. Jump straight to Section 5.
266
+ - **Email** → ambiguous when the email shows up on multiple rows. Ask:
267
+ *"On which server should I switch to `<email>`? (servers shown above
268
+ where it's stored: <list>)"* — then jump to Section 5 with the
269
+ chosen `(email, server)`. Do not guess.
270
+ - **`login`** → ask which server to log in to (Section 2.1 prompt),
271
+ then enter Section 3.
272
+
273
+ ### 4.4. Empty case
274
+
275
+ If no identities are stored anywhere across all 16 servers → skip the
276
+ picker entirely, print "No identities are currently stored." and ask
277
+ the user if they want to log in (then enter Section 3).
278
+
279
+ ---
280
+
281
+ ## Section 5 — Announce + record the session default
282
+
283
+ After Section 2 or 3 or 4 successfully resolves an `(email, server)`
284
+ pair, print **two things** to the user.
285
+
286
+ ### 5.1. Human-readable announcement
287
+
288
+ > `<email>` is logged in on **<server>**. For the rest of this session I'll pass `--account <email>` on dr commands targeting that server. For any other server I'll ask before running.
289
+
290
+ If the identity is an impersonation (it was created by `dr login-as`, or
291
+ `whoami` shows `Impersonated by: <operator>`), add:
292
+
293
+ > This is an impersonated identity (operator: `<operator>`). Its token refreshes silently and auto-remints from the operator, so you won't be re-prompted until the operator's own login expires.
294
+
295
+ ### 5.2. Directive block (delimited, durable across compaction)
296
+
297
+ This is the actual mechanism. Print exactly this shape — fenced as
298
+ code, with the visible separators — so Claude treats it as a binding
299
+ rule, not chat prose:
300
+
301
+ ```
302
+ ======== dr-cli session default (this conversation only) ========
303
+ Default --account: <email>
304
+ Scoped to server: <X>
305
+
306
+ Rule for every subsequent dr-cli invocation in this session:
307
+ - If --server is <X>: pass --account <email> automatically.
308
+ Do not ask the user.
309
+ - If --server is any other key: ASK the user which account before
310
+ running. Do not guess.
311
+ - If the user later says "switch to <other email>", "use <other>",
312
+ "stop defaulting", "clear default user", or invokes /switch-user
313
+ again: that supersedes this rule.
314
+
315
+ Do not persist this to memory, MEMORY.md, CLAUDE.md, settings.json,
316
+ or any file. It dies with this conversation.
317
+ =================================================================
318
+ ```
319
+
320
+ After printing the directive, **honor it for the rest of the
321
+ conversation**: on every `dr <subcommand>` invocation thereafter, if
322
+ `--server` matches the scoped server, automatically include
323
+ `--account <email>`. If `--server` is any other key, pause and ask
324
+ before running.
325
+
326
+ ---
327
+
328
+ ## Section 6 — Clearing the default
329
+
330
+ If the user says "stop defaulting", "clear default user", "no default",
331
+ or `/switch-user --clear`:
332
+
333
+ 1. Print: `Cleared. From now on I'll ask which account to use on each dr command.`
334
+ 2. Mentally retire the directive block from Section 5. On subsequent
335
+ `dr` calls, ask the user for `--account` before running, exactly as
336
+ if the skill had never been invoked.
337
+
338
+ Do **not** rewrite or delete files. Do **not** run any dr commands.
339
+
340
+ ---
341
+
342
+ ## Section 7 — Override semantics
343
+
344
+ If the user re-invokes `/switch-user <other email>` while a default is
345
+ already active:
346
+
347
+ - Run Sections 1–5 against the new email from scratch.
348
+ - The new directive block fully replaces the old one. No merging, no
349
+ per-server overrides.
350
+
351
+ If the user reinvokes `/switch-user` (no arg):
352
+
353
+ - Run Section 4 from scratch.
354
+ - The picker shows the current state of the keychain, including any
355
+ identity that was just added by an earlier `/switch-user` call.
356
+
357
+ ---
358
+
359
+ ## Edge cases
360
+
361
+ | Case | Behavior |
362
+ | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
363
+ | Email has a typo / wrong format | Reject up-front (Section 1). Do not probe. |
364
+ | `dr` binary not on PATH | First probe fails with `command not found`. Surface verbatim plus hint: `Run node scripts/install.mjs from the dr-cli repo to install the dr binary.` |
365
+ | JWT expired but refresh token alive | `whoami` decodes locally and still prints the email — treat as stored. dr-cli auto-refreshes on the next real network call. |
366
+ | Refresh token dead | Not visible at switch-time (whoami is offline). User will hit `session expired` on their next real `dr` command — at that point they should re-invoke `/switch-user <email>` to re-login. |
367
+ | Impersonated identity, its refresh dies | dr-cli auto-remints a fresh impersonation JWT from the operator on the next real command — no re-invoke needed, unless the **operator's own** login has also expired (then re-login the operator, then re-run `dr login-as`). |
368
+ | Target email you can't impersonate (`not permitted` / `inactive`) | `dr login-as` fails with that message. Surface verbatim. Do not fall back to browser login as that email. Do not record a default. |
369
+ | User cancels mid-login (closes browser, Ctrl-C, timeout) | dr exits non-zero with a cancel/timeout message. Surface verbatim. Do not record any default. Do not retry automatically. |
370
+ | Same email logged in on multiple servers, user picks the email (not a numbered row from the picker) | Ask the user which of the matching servers to scope to. Do not guess. |
371
+ | Login succeeds, post-login email matches requested email | Section 5 with the just-logged-in server in scope. |
372
+ | Login succeeds, post-login email does NOT match | Section 3B.2 mismatch prompt. Do not record any default until the user decides. |
373
+
374
+ ---
375
+
376
+ ## What this skill does NOT do
377
+
378
+ - It does **not** write the session default to any file. But it *does*
379
+ trigger `dr login` / `dr login-as` when an identity is missing, and those
380
+ commands write credentials to the keychain (the skill never touches the
381
+ keychain directly). Refresh and impersonation auto-remint are handled by
382
+ dr-cli itself.
383
+ - It does **not** write to `MEMORY.md`, `CLAUDE.md`,
384
+ `settings.json`, or anywhere else on disk. The default is purely
385
+ conversational.
386
+ - It does **not** survive context compaction guaranteed. If a long
387
+ conversation compresses the directive block away, the default
388
+ silently dies — re-invoke if you notice Claude stopped honoring it.
389
+ - It does **not** validate refresh-token health (would require network
390
+ round-trips). If the refresh token is dead, the user will discover
391
+ it on their next real `dr` command, not at switch-time.
392
+ - It does **not** override the dr-cli skill's own Guard Rail #5
393
+ ("never assume which identity to send as --account") for ambiguous
394
+ cases — that rule still applies. This skill is the *resolution
395
+ mechanism* for that ambiguity, not a way around it.