@datarails-ai/dr-cli 1.6.74 → 1.6.76
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 +2 -2
- package/dist/cli.js +140 -32
- package/dist/scopes-map.json +1 -1
- package/dist/skills/dr-cli/SKILL.md +6 -5
- package/dist/skills/dr-cli/reference/datamappers.md +6 -0
- package/dist/skills/dr-cli/reference/multi-product.md +1 -1
- package/dist/skills/dr-cli/reference/safety.md +3 -2
- package/dist/skills/dr-cli/reference/templates.md +1 -1
- package/dist/skills/dr-error-enrichment/SKILL.md +1 -1
- package/dist/skills/dr-error-enrichment/reference/groundcover.md +3 -2
- package/dist/skills/dr-error-enrichment/reference/safety-backup.md +2 -2
- package/dist/skills/dr-error-enrichment-improve/SKILL.md +1 -1
- package/dist/skills/dr-filebox-api-setup/SKILL.md +3 -3
- package/dist/skills/dr-switch-user/SKILL.md +3 -3
- package/dist/skills/fx-conversion-matrix/SKILL.md +1 -1
- package/dist/skills/mec-table-validation/SKILL.md +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# dr-cli
|
|
2
2
|
|
|
3
|
-
Datarails CLI. Server keys: `US`, `US2`, `UK`, `CA`, `EU`, `
|
|
4
|
-
`TEST` — or pass a full `https://<host>.datarails.com` URL to reach an
|
|
3
|
+
Datarails CLI. Server keys: `US`, `US2`, `UK`, `CA`, `EU`, `STUDIO`, `DEV`,
|
|
4
|
+
`DEV-1`, `TEST` — or pass a full `https://<host>.datarails.com` URL to reach an
|
|
5
5
|
ad-hoc (e.g. PR-preview) environment. Credentials live in the OS keychain (Windows Credential Manager,
|
|
6
6
|
macOS Keychain), or in a credential file when one is present — which wins over
|
|
7
7
|
the keychain, and is how `dr` runs where no keychain exists (CI, headless hosts,
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { fileURLToPath as fileURLToPath3 } from "url";
|
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "@datarails-ai/dr-cli",
|
|
11
|
-
version: "1.6.
|
|
11
|
+
version: "1.6.76",
|
|
12
12
|
description: "Datarails CLI",
|
|
13
13
|
type: "module",
|
|
14
14
|
engines: {
|
|
@@ -38,7 +38,7 @@ var package_default = {
|
|
|
38
38
|
postinstall: "node scripts/postinstall.mjs"
|
|
39
39
|
},
|
|
40
40
|
dependencies: {
|
|
41
|
-
"@datarails-ai/dr-appspace-cli": "0.
|
|
41
|
+
"@datarails-ai/dr-appspace-cli": "0.10.0",
|
|
42
42
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
43
43
|
"@napi-rs/keyring": "^1.3.0",
|
|
44
44
|
commander: "^12.1.0",
|
|
@@ -67,7 +67,7 @@ var package_default = {
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
// src/buildInfo.ts
|
|
70
|
-
var BUILD_TIME = "2026-09-
|
|
70
|
+
var BUILD_TIME = "2026-09-30T13:02:37.064Z";
|
|
71
71
|
function formatBuildTime(iso) {
|
|
72
72
|
if (iso === "") return "";
|
|
73
73
|
const d = new Date(iso);
|
|
@@ -412,6 +412,7 @@ var ordered = [
|
|
|
412
412
|
{ key: "UK", host: "https://ukapp.datarails.com", subDomain: "uk" },
|
|
413
413
|
{ key: "CA", host: "https://caapp.datarails.com", subDomain: "canada" },
|
|
414
414
|
{ key: "EU", host: "https://euapp.datarails.com", subDomain: "eu" },
|
|
415
|
+
{ key: "STUDIO", host: "https://studio.datarails.com", subDomain: "studio" },
|
|
415
416
|
{ key: "DEV", host: "https://dev.datarails.com", subDomain: "dev" },
|
|
416
417
|
{ key: "DEV-1", host: "https://dev-1.datarails.com", subDomain: "dev-1" },
|
|
417
418
|
{ key: "TEST", host: "https://testapp.datarails.com", subDomain: "test" },
|
|
@@ -437,7 +438,7 @@ function list() {
|
|
|
437
438
|
function keys() {
|
|
438
439
|
return ordered.map((s) => s.key);
|
|
439
440
|
}
|
|
440
|
-
var PROD_KEYS = /* @__PURE__ */ new Set(["US", "US2", "UK", "CA", "EU", "DEMO"]);
|
|
441
|
+
var PROD_KEYS = /* @__PURE__ */ new Set(["US", "US2", "UK", "CA", "EU", "STUDIO", "DEMO"]);
|
|
441
442
|
function isProdServer(input) {
|
|
442
443
|
let server;
|
|
443
444
|
try {
|
|
@@ -5116,7 +5117,7 @@ async function poll(host, path11, deviceCode, options, onSuccess) {
|
|
|
5116
5117
|
const interval = options.interval ?? 2e3;
|
|
5117
5118
|
const maxWait = options.maxWait ?? 6e5;
|
|
5118
5119
|
const now = options.now ?? Date.now;
|
|
5119
|
-
const
|
|
5120
|
+
const sleep4 = options.sleep ?? defaultSleep;
|
|
5120
5121
|
const signal = options.signal;
|
|
5121
5122
|
const base = host.replace(/\/+$/, "");
|
|
5122
5123
|
const deadline = now() + maxWait;
|
|
@@ -5144,7 +5145,7 @@ async function poll(host, path11, deviceCode, options, onSuccess) {
|
|
|
5144
5145
|
}
|
|
5145
5146
|
const errCode = tryParseErrorCode(text2);
|
|
5146
5147
|
if (errCode === "authorization_pending" || errCode === "slow_down") {
|
|
5147
|
-
await
|
|
5148
|
+
await sleep4(interval, signal);
|
|
5148
5149
|
continue;
|
|
5149
5150
|
}
|
|
5150
5151
|
if (errCode) {
|
|
@@ -12048,7 +12049,7 @@ var defaultSleep2 = (ms, signal) => new Promise((resolve3, reject) => {
|
|
|
12048
12049
|
async function pollTask(client, label, path11, options = {}) {
|
|
12049
12050
|
const interval = options.pollIntervalMs ?? AGGREGATE_POLL_INTERVAL_MS;
|
|
12050
12051
|
const timeout = options.timeoutMs ?? AGGREGATE_POLL_TIMEOUT_MS;
|
|
12051
|
-
const
|
|
12052
|
+
const sleep4 = options.sleep ?? defaultSleep2;
|
|
12052
12053
|
const now = options.now ?? Date.now;
|
|
12053
12054
|
const inner = new AbortController();
|
|
12054
12055
|
const onOuterAbort = () => inner.abort(options.signal?.reason);
|
|
@@ -12090,7 +12091,7 @@ async function pollTask(client, label, path11, options = {}) {
|
|
|
12090
12091
|
return result.env;
|
|
12091
12092
|
}
|
|
12092
12093
|
try {
|
|
12093
|
-
await
|
|
12094
|
+
await sleep4(interval, inner.signal);
|
|
12094
12095
|
} catch {
|
|
12095
12096
|
const reason = inner.signal.reason instanceof Error ? inner.signal.reason.message : String(inner.signal.reason ?? "aborted");
|
|
12096
12097
|
throw new Error(`${label} polling timed out: ${reason}`);
|
|
@@ -16881,7 +16882,7 @@ var LUT_SAVE_POLL_TIMEOUT_MS = 3e5;
|
|
|
16881
16882
|
async function saveMappings(client, documentId, body, options = {}) {
|
|
16882
16883
|
const interval = options.pollIntervalMs ?? LUT_SAVE_POLL_INTERVAL_MS;
|
|
16883
16884
|
const timeout = options.timeoutMs ?? LUT_SAVE_POLL_TIMEOUT_MS;
|
|
16884
|
-
const
|
|
16885
|
+
const sleep4 = options.sleep ?? defaultPollSleep;
|
|
16885
16886
|
const now = options.now ?? Date.now;
|
|
16886
16887
|
const deadline = now() + timeout;
|
|
16887
16888
|
const path11 = `/api/documents/${documentId}/web_update_lut`;
|
|
@@ -16903,7 +16904,7 @@ async function saveMappings(client, documentId, body, options = {}) {
|
|
|
16903
16904
|
`lut save-mappings: the server is still writing after ${Math.round(timeout / 1e3)}s (task ${cacheKey}). The write is still running server-side \u2014 re-run the same command to rejoin it, or raise --timeout.`
|
|
16904
16905
|
);
|
|
16905
16906
|
}
|
|
16906
|
-
await
|
|
16907
|
+
await sleep4(interval, options.signal);
|
|
16907
16908
|
const tick = await postOnce(client, pollPath, payload, options.signal);
|
|
16908
16909
|
if (tick.status === 200) {
|
|
16909
16910
|
return toResult(tick.text);
|
|
@@ -17201,7 +17202,7 @@ async function exportDocument(client, id, destinationOrgIds, override, reqOption
|
|
|
17201
17202
|
async function pollDocumentJob(client, basePath, label, requestId, options = {}) {
|
|
17202
17203
|
const interval = options.pollIntervalMs ?? AUTO_CALC_POLL_INTERVAL_MS;
|
|
17203
17204
|
const timeout = options.timeoutMs ?? AUTO_CALC_POLL_TIMEOUT_MS;
|
|
17204
|
-
const
|
|
17205
|
+
const sleep4 = options.sleep ?? defaultSleep3;
|
|
17205
17206
|
const now = options.now ?? Date.now;
|
|
17206
17207
|
const deadline = now() + timeout;
|
|
17207
17208
|
for (; ; ) {
|
|
@@ -17229,7 +17230,7 @@ async function pollDocumentJob(client, basePath, label, requestId, options = {})
|
|
|
17229
17230
|
`${label} polling timed out after ${timeout}ms (request ${requestId} still processing)`
|
|
17230
17231
|
);
|
|
17231
17232
|
}
|
|
17232
|
-
await
|
|
17233
|
+
await sleep4(interval, options.signal);
|
|
17233
17234
|
}
|
|
17234
17235
|
}
|
|
17235
17236
|
|
|
@@ -20454,7 +20455,7 @@ async function waitForReAggregation(cfg) {
|
|
|
20454
20455
|
let interval = cfg.pollIntervalMs ?? REAGG_POLL_INTERVAL_MS;
|
|
20455
20456
|
const maxInterval = cfg.maxPollIntervalMs ?? REAGG_POLL_MAX_INTERVAL_MS;
|
|
20456
20457
|
const timeout = cfg.timeoutMs ?? REAGG_POLL_TIMEOUT_MS;
|
|
20457
|
-
const
|
|
20458
|
+
const sleep4 = cfg.sleep ?? defaultSleep4;
|
|
20458
20459
|
const now = cfg.now ?? Date.now;
|
|
20459
20460
|
const accepted = [...cfg.accepted];
|
|
20460
20461
|
const observedProcessing = /* @__PURE__ */ new Set();
|
|
@@ -20489,7 +20490,7 @@ async function waitForReAggregation(cfg) {
|
|
|
20489
20490
|
break;
|
|
20490
20491
|
}
|
|
20491
20492
|
try {
|
|
20492
|
-
await
|
|
20493
|
+
await sleep4(interval, cfg.signal);
|
|
20493
20494
|
} catch {
|
|
20494
20495
|
aborted = true;
|
|
20495
20496
|
break;
|
|
@@ -23096,7 +23097,7 @@ async function waitForSuggestionRun(r, cfg, runId) {
|
|
|
23096
23097
|
let interval = cfg.pollIntervalMs ?? SUGGESTIONS_POLL_INTERVAL_MS;
|
|
23097
23098
|
const maxInterval = cfg.maxPollIntervalMs ?? SUGGESTIONS_POLL_MAX_INTERVAL_MS;
|
|
23098
23099
|
const timeout = cfg.timeoutMs ?? SUGGESTIONS_POLL_TIMEOUT_MS;
|
|
23099
|
-
const
|
|
23100
|
+
const sleep4 = cfg.sleep ?? defaultSleep5;
|
|
23100
23101
|
const now = cfg.now ?? Date.now;
|
|
23101
23102
|
const errOut = cfg.errOut ?? process.stderr;
|
|
23102
23103
|
const start = now();
|
|
@@ -23126,7 +23127,7 @@ async function waitForSuggestionRun(r, cfg, runId) {
|
|
|
23126
23127
|
break;
|
|
23127
23128
|
}
|
|
23128
23129
|
try {
|
|
23129
|
-
await
|
|
23130
|
+
await sleep4(interval, cfg.signal);
|
|
23130
23131
|
} catch {
|
|
23131
23132
|
aborted = true;
|
|
23132
23133
|
break;
|
|
@@ -25321,7 +25322,7 @@ var defaultSleep6 = (ms, signal) => new Promise((resolve3, reject) => {
|
|
|
25321
25322
|
});
|
|
25322
25323
|
async function putDataWithPolling(client, dashboardId, id, payload, options = {}) {
|
|
25323
25324
|
const interval = options.pollIntervalMs ?? WIDGET_DATA_POLL_INTERVAL_MS;
|
|
25324
|
-
const
|
|
25325
|
+
const sleep4 = options.sleep ?? defaultSleep6;
|
|
25325
25326
|
const path11 = `/api/dashboards/${dashboardId}/widgets/${id}/data`;
|
|
25326
25327
|
const body = JSON.stringify(payload);
|
|
25327
25328
|
const first = await putDataOnce(client, path11, body, options);
|
|
@@ -25338,7 +25339,7 @@ async function putDataWithPolling(client, dashboardId, id, payload, options = {}
|
|
|
25338
25339
|
const pollPath = `${path11}?cache_key=${encodeURIComponent(cacheKey)}`;
|
|
25339
25340
|
for (; ; ) {
|
|
25340
25341
|
try {
|
|
25341
|
-
await
|
|
25342
|
+
await sleep4(interval, options.signal);
|
|
25342
25343
|
} catch (err) {
|
|
25343
25344
|
const reason = err instanceof Error ? err.message : String(err);
|
|
25344
25345
|
throw new Error(`widget data polling timed out: ${reason}`);
|
|
@@ -29099,6 +29100,9 @@ function registerSkillCommand(root) {
|
|
|
29099
29100
|
});
|
|
29100
29101
|
}
|
|
29101
29102
|
|
|
29103
|
+
// src/commands/datamappers.ts
|
|
29104
|
+
import { setTimeout as sleep3 } from "timers/promises";
|
|
29105
|
+
|
|
29102
29106
|
// src/api/datamappers.ts
|
|
29103
29107
|
async function list20(client, tableId, options) {
|
|
29104
29108
|
const out = await client.getJSON(`/api/templates/${tableId}/mappers`, options);
|
|
@@ -29116,6 +29120,14 @@ async function get14(client, tableId, id, options) {
|
|
|
29116
29120
|
}
|
|
29117
29121
|
return out;
|
|
29118
29122
|
}
|
|
29123
|
+
async function getDetails2(client, id, options) {
|
|
29124
|
+
const path11 = `/api/templates/mappers/${id}`;
|
|
29125
|
+
const out = await client.getJSON(path11, options);
|
|
29126
|
+
if (out === null) {
|
|
29127
|
+
throw new Error(`GET ${path11}: empty response from datamapper details`);
|
|
29128
|
+
}
|
|
29129
|
+
return out;
|
|
29130
|
+
}
|
|
29119
29131
|
async function create12(client, tableId, body, options) {
|
|
29120
29132
|
const path11 = `/api/templates/${tableId}/mappers`;
|
|
29121
29133
|
const out = await client.postJSON(path11, body, options);
|
|
@@ -29864,13 +29876,15 @@ async function runDatamappersUpdate(cfg) {
|
|
|
29864
29876
|
body = decodedBody;
|
|
29865
29877
|
}
|
|
29866
29878
|
validateCalcFields(extractCalcFields(body));
|
|
29879
|
+
const err = cfg.err ?? process.stderr;
|
|
29880
|
+
const scanBaseline = rescanValue === "latest" && cfg.verifyScanDispatch !== void 0 ? await captureScanBaseline(cfg.client, cfg.id, cfg.signal, err) : void 0;
|
|
29867
29881
|
let updated;
|
|
29868
29882
|
try {
|
|
29869
29883
|
updated = await update8(cfg.client, cfg.id, body, {
|
|
29870
29884
|
signal: cfg.signal
|
|
29871
29885
|
});
|
|
29872
|
-
} catch (
|
|
29873
|
-
const msg =
|
|
29886
|
+
} catch (err2) {
|
|
29887
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
29874
29888
|
if (/HTTP 500/.test(msg)) {
|
|
29875
29889
|
const hint = "hint: the server logs an `ETLError: Custom Columns: The creation of '<field>' field has failed due to incorrect formula syntax.` line for this case but the response body is a bare 500 HTML page. Common causes the client-side guard cannot detect: (1) a [field] reference in a calc formula that does not resolve to any header `map_to`, calc-field `name`, or system field (`[FileBox_ID]`, `[System_Year]`, `[Posting Date]`, \u2026), (2) an unsupported function name (try copying the function spelling from another working calc field via `dr datamappers get`), (3) a string literal that's a plain-English placeholder (e.g. `\"Customer or Client name\"`) which parses but the ETL refuses. Iterate on calc-field formulas one at a time. If every formula looks correct and PUT still 500s, fall back to the workaround: `dr datamappers create from-file <table> --file <new.json>` then `dr datamappers delete <old_id> --table <table>` (note: this orphans references \u2014 LUTs/dashboards/functions pointing at the old mapper id break).";
|
|
29876
29890
|
const responseBody = extractResponseBodyFromError(msg);
|
|
@@ -29896,13 +29910,106 @@ Full request + response captured to: ${logPath}
|
|
|
29896
29910
|
|
|
29897
29911
|
${hint}${logSuffix}`);
|
|
29898
29912
|
}
|
|
29899
|
-
throw
|
|
29913
|
+
throw err2;
|
|
29900
29914
|
}
|
|
29901
29915
|
if (cfg.asJson) {
|
|
29902
29916
|
writeJSONIndented(cfg.out, updated);
|
|
29903
|
-
|
|
29917
|
+
} else {
|
|
29918
|
+
renderMappersTable(cfg.out, [updated]);
|
|
29919
|
+
}
|
|
29920
|
+
if (scanBaseline !== void 0) {
|
|
29921
|
+
const opts = cfg.verifyScanDispatch ?? {};
|
|
29922
|
+
const started2 = await waitForNewScan(cfg.client, scanBaseline, cfg.signal, opts);
|
|
29923
|
+
if (!started2) {
|
|
29924
|
+
const docIds = await mappedDocumentIds(
|
|
29925
|
+
cfg.client,
|
|
29926
|
+
scanBaseline.templateId,
|
|
29927
|
+
cfg.id,
|
|
29928
|
+
cfg.signal
|
|
29929
|
+
);
|
|
29930
|
+
err.write(
|
|
29931
|
+
formatNoScanWarning({
|
|
29932
|
+
mapperId: cfg.id,
|
|
29933
|
+
templateId: scanBaseline.templateId,
|
|
29934
|
+
timeoutMs: opts.timeoutMs ?? DEFAULT_SCAN_DISPATCH_TIMEOUT_MS,
|
|
29935
|
+
docIds
|
|
29936
|
+
})
|
|
29937
|
+
);
|
|
29938
|
+
}
|
|
29939
|
+
}
|
|
29940
|
+
}
|
|
29941
|
+
var DEFAULT_SCAN_DISPATCH_TIMEOUT_MS = 3e4;
|
|
29942
|
+
var DEFAULT_SCAN_DISPATCH_POLL_MS = 2e3;
|
|
29943
|
+
function scanFingerprint(report) {
|
|
29944
|
+
let maxScanId = 0;
|
|
29945
|
+
for (const doc of report.documents ?? []) {
|
|
29946
|
+
for (const v of doc.versions ?? []) {
|
|
29947
|
+
if (typeof v.scan_id === "number" && v.scan_id > maxScanId) maxScanId = v.scan_id;
|
|
29948
|
+
}
|
|
29949
|
+
}
|
|
29950
|
+
return `${report.scans_status?.last_updated ?? ""}|${maxScanId}`;
|
|
29951
|
+
}
|
|
29952
|
+
async function captureScanBaseline(client, mapperId, signal, err) {
|
|
29953
|
+
try {
|
|
29954
|
+
const details = await getDetails2(client, mapperId, { signal });
|
|
29955
|
+
const templateId = details.template.id;
|
|
29956
|
+
const report = await getStatus(client, templateId, { signal });
|
|
29957
|
+
return { templateId, fingerprint: scanFingerprint(report) };
|
|
29958
|
+
} catch (e) {
|
|
29959
|
+
if (signal.aborted) throw e;
|
|
29960
|
+
err.write(
|
|
29961
|
+
"note: could not read the scan status before the update, so dr cannot confirm a rescan starts. Check with `dr scans status <template_id>` afterwards.\n"
|
|
29962
|
+
);
|
|
29963
|
+
return void 0;
|
|
29904
29964
|
}
|
|
29905
|
-
|
|
29965
|
+
}
|
|
29966
|
+
async function waitForNewScan(client, baseline, signal, opts) {
|
|
29967
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_SCAN_DISPATCH_TIMEOUT_MS;
|
|
29968
|
+
const pollIntervalMs = opts.pollIntervalMs ?? DEFAULT_SCAN_DISPATCH_POLL_MS;
|
|
29969
|
+
const deadline = Date.now() + timeoutMs;
|
|
29970
|
+
for (; ; ) {
|
|
29971
|
+
try {
|
|
29972
|
+
const report = await getStatus(client, baseline.templateId, { signal });
|
|
29973
|
+
if (scanFingerprint(report) !== baseline.fingerprint) return true;
|
|
29974
|
+
} catch (e) {
|
|
29975
|
+
if (signal.aborted) throw e;
|
|
29976
|
+
}
|
|
29977
|
+
const remaining = deadline - Date.now();
|
|
29978
|
+
if (remaining <= 0) return false;
|
|
29979
|
+
await sleep3(Math.min(pollIntervalMs, remaining), void 0, { signal });
|
|
29980
|
+
}
|
|
29981
|
+
}
|
|
29982
|
+
async function mappedDocumentIds(client, templateId, mapperId, signal) {
|
|
29983
|
+
try {
|
|
29984
|
+
const mapper = await get14(client, templateId, mapperId, { signal });
|
|
29985
|
+
return Array.isArray(mapper.mapped_documents_ids) ? mapper.mapped_documents_ids : void 0;
|
|
29986
|
+
} catch (e) {
|
|
29987
|
+
if (signal.aborted) throw e;
|
|
29988
|
+
return void 0;
|
|
29989
|
+
}
|
|
29990
|
+
}
|
|
29991
|
+
function formatNoScanWarning(p) {
|
|
29992
|
+
const secs = Math.round(p.timeoutMs / 1e3);
|
|
29993
|
+
const lines = [
|
|
29994
|
+
`warning: mapper ${p.mapperId} was saved, but no new scan showed up on template ${p.templateId} within ${secs}s.`,
|
|
29995
|
+
' Either the scan is still queued, or this server predates the DR-54200 fix and ignored rescan="latest", so existing data still has the old config.',
|
|
29996
|
+
` Check first: dr scans status ${p.templateId}`
|
|
29997
|
+
];
|
|
29998
|
+
if (p.docIds !== void 0 && p.docIds.length === 0) {
|
|
29999
|
+
lines.push(" The mapper has no bound documents, so there is nothing to scan.");
|
|
30000
|
+
} else {
|
|
30001
|
+
const docFlags = p.docIds !== void 0 ? p.docIds.map((d) => `--doc ${d}`).join(" ") : "--doc <doc_id> [--doc <doc_id> ...]";
|
|
30002
|
+
lines.push(
|
|
30003
|
+
" If no new scan appears there, re-bind the mapper to its current documents with a rescan:"
|
|
30004
|
+
);
|
|
30005
|
+
if (p.docIds === void 0) {
|
|
30006
|
+
lines.push(
|
|
30007
|
+
` dr datamappers get ${p.mapperId} --table ${p.templateId} --json # read mapped_documents_ids`
|
|
30008
|
+
);
|
|
30009
|
+
}
|
|
30010
|
+
lines.push(` dr datamappers bind ${p.mapperId} ${docFlags} --rescan latest`);
|
|
30011
|
+
}
|
|
30012
|
+
return lines.join("\n") + "\n";
|
|
29906
30013
|
}
|
|
29907
30014
|
async function buildConveniencePayload(client, tableId, name, versionId, sheet, flags, signal) {
|
|
29908
30015
|
const fieldTypes = parseFieldOverrides(flags.fieldOverrides);
|
|
@@ -30217,7 +30324,7 @@ function renderMappersTable(out, mappers) {
|
|
|
30217
30324
|
}
|
|
30218
30325
|
];
|
|
30219
30326
|
for (const m of mappers) {
|
|
30220
|
-
const ordinal = m.ordinal
|
|
30327
|
+
const ordinal = m.ordinal == null ? "-" : String(m.ordinal);
|
|
30221
30328
|
rows.push({
|
|
30222
30329
|
cells: [
|
|
30223
30330
|
String(m.id),
|
|
@@ -30515,7 +30622,7 @@ function registerDatamappersCommand(root) {
|
|
|
30515
30622
|
addServerFlag(fromFileCmd);
|
|
30516
30623
|
addAccountFlag(fromFileCmd);
|
|
30517
30624
|
const updateCmd = dm.command("update").description(
|
|
30518
|
-
|
|
30625
|
+
"Update a datamapper in place (payload-file only \u2014 server accepts config+sheet_name+rescan). `--rescan latest` (the default) re-extracts the LATEST version of each document bound to the mapper. Servers without the DR-54200 fix save the config and start no scan, so after the update dr watches the template for a new scan and, when none shows up, prints how to check `dr scans status` and the `dr datamappers bind` fallback. For a full historical rescan (every calculated field re-executed against every document version ever uploaded), use `dr rescan table <template_id>` instead \u2014 that is far more expensive and higher-blast."
|
|
30519
30626
|
).argument("<mapper_id>", "mapper id (positive integer)").option("--payload-file <path>", "Path to a JSON file with the PUT body (required)", "").option(
|
|
30520
30627
|
"--field <NAME:TYPE>",
|
|
30521
30628
|
'Set a column type via fields_to_change (Text|Float|Date|Integer). Repeatable. Mirrors the UI "Publish and scan" so a calc column referencing a LUT-injected column materialises instead of 500ing on inferred types. Note: the server blocks a type change (HTTP 400) when the template has more than one mapper.',
|
|
@@ -30538,7 +30645,8 @@ function registerDatamappersCommand(root) {
|
|
|
30538
30645
|
serverFlag: opts.server ?? "",
|
|
30539
30646
|
asJson: opts.json === true,
|
|
30540
30647
|
signal: setup.signal,
|
|
30541
|
-
out: process.stdout
|
|
30648
|
+
out: process.stdout,
|
|
30649
|
+
verifyScanDispatch: {}
|
|
30542
30650
|
});
|
|
30543
30651
|
} finally {
|
|
30544
30652
|
setup.cleanup();
|
|
@@ -32704,7 +32812,7 @@ async function runIntegrationsSync(cfg) {
|
|
|
32704
32812
|
throw new Error("integration id must be positive");
|
|
32705
32813
|
}
|
|
32706
32814
|
const interval = cfg.pollIntervalMs ?? INTEGRATIONS_SYNC_POLL_INTERVAL_MS;
|
|
32707
|
-
const
|
|
32815
|
+
const sleep4 = cfg.sleep ?? defaultSleep7;
|
|
32708
32816
|
const resp = await resync(cfg.client, cfg.id, {
|
|
32709
32817
|
signal: cfg.signal
|
|
32710
32818
|
});
|
|
@@ -32753,7 +32861,7 @@ async function runIntegrationsSync(cfg) {
|
|
|
32753
32861
|
return;
|
|
32754
32862
|
}
|
|
32755
32863
|
try {
|
|
32756
|
-
await
|
|
32864
|
+
await sleep4(interval, inner.signal);
|
|
32757
32865
|
} catch {
|
|
32758
32866
|
cfg.out.write(
|
|
32759
32867
|
`Timed out waiting for sync to finish \u2014 last status was ${orDash(lastStatus)}
|
|
@@ -37527,7 +37635,7 @@ async function runFileboxSetVersionFileStatus(cfg) {
|
|
|
37527
37635
|
throw new Error("version id must be positive");
|
|
37528
37636
|
}
|
|
37529
37637
|
const err = cfg.err ?? process.stderr;
|
|
37530
|
-
const
|
|
37638
|
+
const sleep4 = cfg.sleep ?? defaultCycleTagSleep;
|
|
37531
37639
|
const settleMs = cfg.tagSettleDelayMs ?? CYCLE_TAG_SETTLE_DELAY_MS;
|
|
37532
37640
|
const details = await getDetails(cfg.client, cfg.docId, { signal: cfg.signal });
|
|
37533
37641
|
const tag = (details.tags_config ?? []).find(isFileStatusTag);
|
|
@@ -37620,7 +37728,7 @@ async function runFileboxSetVersionFileStatus(cfg) {
|
|
|
37620
37728
|
}
|
|
37621
37729
|
};
|
|
37622
37730
|
const readBack = async () => {
|
|
37623
|
-
await
|
|
37731
|
+
await sleep4(settleMs, cfg.signal);
|
|
37624
37732
|
return readVersionForConfirm(cfg.client, cfg.versionId, cfg.docId, cfg.signal);
|
|
37625
37733
|
};
|
|
37626
37734
|
await write();
|
|
@@ -58372,7 +58480,7 @@ async function defaultSleep8(ms, signal) {
|
|
|
58372
58480
|
async function pollExtractionStatus(client, contractFileIds, options = {}) {
|
|
58373
58481
|
const interval = options.pollIntervalMs ?? EXTRACT_POLL_INTERVAL_MS;
|
|
58374
58482
|
const timeout = options.timeoutMs ?? EXTRACT_POLL_TIMEOUT_MS;
|
|
58375
|
-
const
|
|
58483
|
+
const sleep4 = options.sleep ?? defaultSleep8;
|
|
58376
58484
|
const now = options.now ?? Date.now;
|
|
58377
58485
|
const resolved = /* @__PURE__ */ new Map();
|
|
58378
58486
|
if (contractFileIds.length === 0) return { resolved, pending: [] };
|
|
@@ -58422,7 +58530,7 @@ async function pollExtractionStatus(client, contractFileIds, options = {}) {
|
|
|
58422
58530
|
options.onTick?.(resolved.size, contractFileIds.length);
|
|
58423
58531
|
if (resolved.size >= contractFileIds.length) break;
|
|
58424
58532
|
if (now() > deadline || inner.signal.aborted) break;
|
|
58425
|
-
await
|
|
58533
|
+
await sleep4(interval, inner.signal);
|
|
58426
58534
|
}
|
|
58427
58535
|
} finally {
|
|
58428
58536
|
clearTimeout(deadlineTimer);
|
package/dist/scopes-map.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"cliVersion": "1.6.
|
|
3
|
+
"cliVersion": "1.6.76",
|
|
4
4
|
"_contract": "Resolve a command path through `aliases` (canonical prefix + alias segment -> canonical path) before any lookup. A path listed in `pendingCommands`, or whose first segment is a key of `pending`, is UNDECIDED, not unrestricted: fail closed or skip it, and never read a path's absence from `commands` as 'no requirement'. An entry carrying `denied` is UNAVAILABLE to any AGENT-SCOPED credential — one whose `scopes` claim carries at least one `resource:action` entry; a claim that is absent, empty, capability-only or wholly unparseable is UNRESTRICTED, and this mark does not apply to it — whatever else that entry says: it is not a ceiling and it is not always-available, its `denied.reason` says why and `denied.until` names the ticket that lifts it, and the absence of `requires` on it must NEVER be read as 'no requirement'. Only an entry in `commands` with an empty `requires` means always-available.",
|
|
5
5
|
"commands": {
|
|
6
6
|
"login": {
|
|
@@ -23,7 +23,8 @@ for any command come from `dr <command> --help` (the binary is authoritative).
|
|
|
23
23
|
`register-identity`, `bulk-create`, `bulk-set-email`, `bulk-permissions`,
|
|
24
24
|
`set-email`, `set-email-notifications`, `bulk-set-email-notifications`,
|
|
25
25
|
`set-password`, `set-field-type`) — on `US`, `US2`, `UK`, `CA`,
|
|
26
|
-
`EU`, `DEMO` (DEMO is a customer-facing prod tenant, not a sandbox
|
|
26
|
+
`EU`, `STUDIO`, `DEMO` (DEMO is a customer-facing prod tenant, not a sandbox;
|
|
27
|
+
STUDIO is the free-tier environment and holds real prospects' data) must be
|
|
27
28
|
confirmed by the user before you run them. `register-identity --confirm` in
|
|
28
29
|
particular sends real invite emails to customers, so it counts as a prod
|
|
29
30
|
write. Demonstrate on `DEV` / `DEV-1` / `TEST` / `TEST-1`..`TEST-7` first when
|
|
@@ -40,7 +41,7 @@ for any command come from `dr <command> --help` (the binary is authoritative).
|
|
|
40
41
|
dialog (or TTY prompt) where the *user* types a fresh challenge word; in a
|
|
41
42
|
headless shell it refuses non-zero. Don't add your own word ritual in chat.
|
|
42
43
|
Non-prod (`DEV`/`DEV-1`/`TEST`/`TEST-1`..`TEST-7`) is token-only, a plain
|
|
43
|
-
"yes" suffices; `DEMO`
|
|
44
|
+
"yes" suffices; `DEMO` and `STUDIO` count as prod. Details in
|
|
44
45
|
[reference/safety.md](reference/safety.md).
|
|
45
46
|
4. **Credentials are sensitive.** Sessions live in the OS keychain, or in a
|
|
46
47
|
credential file where one is in use — never extract or echo JWTs or session
|
|
@@ -103,7 +104,7 @@ update it in the file alongside the key, or the warning keeps naming the old
|
|
|
103
104
|
one.
|
|
104
105
|
|
|
105
106
|
`--server <KEY>` is **required on every command that hits an API**. Valid keys:
|
|
106
|
-
`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).
|
|
107
|
+
`US`, `US2`, `UK`, `CA`, `EU`, `STUDIO`, `DEV`, `DEV-1`, `TEST`, `TEST-1`, `TEST-2`, `TEST-3`, `TEST-4`, `TEST-5`, `TEST-6`, `TEST-7`, `DEMO` (case-insensitive).
|
|
107
108
|
|
|
108
109
|
You can also pass a full **`https://<host>.datarails.com` URL** instead of a
|
|
109
110
|
key to reach an ad-hoc / PR-preview environment, e.g.
|
|
@@ -539,8 +540,8 @@ returns the source rows behind the number.
|
|
|
539
540
|
counts — and a token; re-run with `--confirm-token` to fire it) → poll `scans
|
|
540
541
|
status` again. This is a **full historical** rescan (every calc field × every
|
|
541
542
|
version). To only pick up a datamapper change on the live template, prefer
|
|
542
|
-
`datamappers update <id> --rescan latest` (latest version
|
|
543
|
-
|
|
543
|
+
`datamappers update <id> --rescan latest` (latest version of the mapper's bound
|
|
544
|
+
documents only) — far cheaper and lower-blast.
|
|
544
545
|
|
|
545
546
|
**Build a `create` body from plain-English intent** (calc models, datamappers,
|
|
546
547
|
metrics): you resolve names → integer IDs yourself against the tenant
|
|
@@ -67,6 +67,12 @@ value-inference behavior. `NAME` is the target **table field** name (the
|
|
|
67
67
|
## Update / preview / bind / delete
|
|
68
68
|
|
|
69
69
|
- `datamappers update`, `datamappers delete` (two-step confirm).
|
|
70
|
+
- `datamappers update --rescan latest` — after the PUT, dr watches the
|
|
71
|
+
template's scan status for up to 30s, because servers without the DR-54200 fix
|
|
72
|
+
save the config but ignore `rescan: "latest"`. If no new scan shows up, it
|
|
73
|
+
prints a warning with a ready `datamappers bind <id> --doc … --rescan latest`
|
|
74
|
+
command. Run `scans status <template_id>` first: the scan may only be queued,
|
|
75
|
+
and `bind` on a queued scan starts a second one. Don't re-run `update`.
|
|
70
76
|
- `datamappers preview --payload-file <p>` — renders mapper output for sample
|
|
71
77
|
input ("what would this extract?") before saving.
|
|
72
78
|
- `datamappers bind <mapper_id> --doc <id> [--rescan latest|all]` — change which
|
|
@@ -117,7 +117,7 @@ org 99.
|
|
|
117
117
|
|
|
118
118
|
Token TTL is 10 minutes — past that, re-run step 1.
|
|
119
119
|
|
|
120
|
-
For prod (`US`/`US2`/`UK`/`CA`/`EU`/`DEMO`), get the user's in-chat "yes" before
|
|
120
|
+
For prod (`US`/`US2`/`UK`/`CA`/`EU`/`STUDIO`/`DEMO`), get the user's in-chat "yes" before
|
|
121
121
|
re-invoking with the token; the binary's interactive gate then has the user
|
|
122
122
|
type a challenge word in a dialog, same as any other destructive write — see
|
|
123
123
|
[safety.md](safety.md).
|
|
@@ -38,7 +38,8 @@ Reads never need confirmation. Gated **writes** fall into two tiers (full table:
|
|
|
38
38
|
`src/commands/_prodGateTiers.ts`):
|
|
39
39
|
|
|
40
40
|
- **Tier A — destructive / irreversible / org-wide.** On a prod tenant (`US`,
|
|
41
|
-
`US2`, `UK`, `CA`, `EU`, `DEMO` — DEMO is customer-facing
|
|
41
|
+
`US2`, `UK`, `CA`, `EU`, `STUDIO`, `DEMO` — DEMO is customer-facing, STUDIO holds
|
|
42
|
+
real prospects' data) the binary requires a
|
|
42
43
|
live human to type a fresh challenge word in a desktop dialog / TTY (see
|
|
43
44
|
"Binary-enforced interactive gate" below). Relay the plan output (target name
|
|
44
45
|
+ blast radius), get a clear in-chat "yes, do it", then re-invoke with
|
|
@@ -105,7 +106,7 @@ the LUT that 4 functions depend on" — before running.
|
|
|
105
106
|
|
|
106
107
|
The human check is enforced **in the binary** — not by prose an agent could
|
|
107
108
|
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
|
+
action against a prod tenant (`US`, `US2`, `UK`, `CA`, `EU`, `STUDIO`, `DEMO` — plus,
|
|
109
110
|
fail-closed, any server the CLI cannot positively classify as non-prod, and any
|
|
110
111
|
action not positively classified as Tier B), the binary requires a live human:
|
|
111
112
|
|
|
@@ -150,7 +150,7 @@ except on `update`, which resolves the range's own table automatically.
|
|
|
150
150
|
`--confirm-token` — token-only, no word gate even on prod (a rescan re-derives
|
|
151
151
|
data, it doesn't delete it). To pick up a datamapper change on the live template
|
|
152
152
|
**without** touching history, use `datamappers update <id> --rescan latest`
|
|
153
|
-
instead (
|
|
153
|
+
instead (re-extracts the latest version of the mapper's bound documents); a full rescan will re-run pre-existing
|
|
154
154
|
calc fields against old rows, so a latent divide-by-null there fails the whole
|
|
155
155
|
scan. Refuses `UsageStats` on every tenant (system data, not customer-owned).
|
|
156
156
|
- `dataflow get` — the dependency graph: inputs → mappers → LUTs → table →
|
|
@@ -67,7 +67,7 @@ These hold in every sub-skill; the detail is in
|
|
|
67
67
|
[reference/safety-backup.md](reference/safety-backup.md).
|
|
68
68
|
|
|
69
69
|
1. **Confirm the target server explicitly** — ask, never infer it from earlier
|
|
70
|
-
conversation. `US`, `US2`, `UK`, `CA`, `EU`, `DEMO` are all prod.
|
|
70
|
+
conversation. `US`, `US2`, `UK`, `CA`, `EU`, `STUDIO`, `DEMO` are all prod.
|
|
71
71
|
2. **Back up every reachable server before the first write** of a session, not
|
|
72
72
|
just the target — the export is also the diff baseline. One command:
|
|
73
73
|
`dr error-enrichments export --all-servers --out <dir>`. Tell the user the
|
|
@@ -64,9 +64,10 @@ Groundcover envs are not dr-cli server keys. Envs are `prod-us`, `prod-east-us`,
|
|
|
64
64
|
| `DEMO` | `prod-demo` |
|
|
65
65
|
| `US` / `US2` | **ambiguous** across `prod-us`, `prod-east-us`, `prod-west-us-2` |
|
|
66
66
|
| `EU` | **unmapped** — resolve it before mining (see below) |
|
|
67
|
+
| `STUDIO` | **unmapped** — resolve it before mining (see below) |
|
|
67
68
|
|
|
68
|
-
`EU`
|
|
69
|
-
groundcover
|
|
69
|
+
`EU` and `STUDIO` were added to the registry after this table was written and
|
|
70
|
+
their groundcover envs have not been confirmed. Resolve them the same way as the US
|
|
70
71
|
ambiguity before mining, and record the answer here once known.
|
|
71
72
|
|
|
72
73
|
Resolve the US ambiguity with
|
|
@@ -9,8 +9,8 @@ reading.
|
|
|
9
9
|
|
|
10
10
|
**1. Confirm the target server explicitly.** Ask (AskUserQuestion) which server
|
|
11
11
|
to change — never infer it from earlier context in the conversation. Prod keys
|
|
12
|
-
are `US`, `US2`, `UK`, `CA`, `EU`, `DEMO` (DEMO is customer-facing prod, not a
|
|
13
|
-
sandbox). Demonstrate on `DEV` / `TEST-*` first when the user is undecided.
|
|
12
|
+
are `US`, `US2`, `UK`, `CA`, `EU`, `STUDIO`, `DEMO` (DEMO is customer-facing prod, not a
|
|
13
|
+
sandbox; STUDIO is the free-tier environment and holds real prospects' data). Demonstrate on `DEV` / `TEST-*` first when the user is undecided.
|
|
14
14
|
|
|
15
15
|
**2. Back up every reachable server first.** Before the first write of a
|
|
16
16
|
session, one command — `export` takes the same sweep flags as `list` / `stats`,
|
|
@@ -44,7 +44,7 @@ fixing disliked rules is `dr-error-enrichment-maintain`.
|
|
|
44
44
|
**1. Pick the region and the window, and prove they line up.** Ask which server
|
|
45
45
|
the user intends to improve, then map it to the groundcover env before querying —
|
|
46
46
|
`UK` is `prod-uk*`, `CA` is `prod-canada-central`, `DEMO` is `prod-demo`, and
|
|
47
|
-
`US`/`US2` are ambiguous across the three US envs and `EU`
|
|
47
|
+
`US`/`US2` are ambiguous across the three US envs and `EU` and `STUDIO` are not mapped at
|
|
48
48
|
all, so resolve those explicitly (see the reference). Mining one region's logs to justify a rule you then write to
|
|
49
49
|
another is the failure mode this step exists to prevent. Start with a tight
|
|
50
50
|
window and widen only after it returns rows.
|
|
@@ -23,7 +23,7 @@ Before issuing any commands, confirm the following with the user if not already
|
|
|
23
23
|
| Input | How to resolve |
|
|
24
24
|
|---|---|
|
|
25
25
|
| **Target fileboxes** | IDs/names, or a folder name to expand — run `dr filebox list --server <S>` and filter by parent folder ID |
|
|
26
|
-
| **Server** | Ask if not obvious from context (`US`, `US2`, `UK`, `CA`, `EU`, `DEV`, `DEV-1`, `TEST`, `TEST-1`, `TEST-2`, `TEST-3`, `TEST-4`, `TEST-5`, `TEST-6`, `TEST-7`, `DEMO`) |
|
|
26
|
+
| **Server** | Ask if not obvious from context (`US`, `US2`, `UK`, `CA`, `EU`, `STUDIO`, `DEV`, `DEV-1`, `TEST`, `TEST-1`, `TEST-2`, `TEST-3`, `TEST-4`, `TEST-5`, `TEST-6`, `TEST-7`, `DEMO`) |
|
|
27
27
|
| **Connection** | Run `dr integrations list --server <S>` and show the WorkatoBased options; ask the user to pick |
|
|
28
28
|
| **Object type** | Ask — commonly `table`; surface the value from a reference filebox if one exists |
|
|
29
29
|
| **Start date / End date** | Ask — commonly "start of month" / "end of month", which maps to `{{date_tag|somonth}}` / `{{date_tag|eomonth}}` |
|
|
@@ -69,7 +69,7 @@ If no reference exists, build the payload from the gathered inputs (see Step 4).
|
|
|
69
69
|
|
|
70
70
|
## Step 3 — Enable Upload via API on all target fileboxes
|
|
71
71
|
|
|
72
|
-
Run in parallel for efficiency. This is a prod write — confirm with the user before running on `US`, `US2`, `UK`, `CA`, `EU`, `DEMO`.
|
|
72
|
+
Run in parallel for efficiency. This is a prod write — confirm with the user before running on `US`, `US2`, `UK`, `CA`, `EU`, `STUDIO`, `DEMO`.
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
75
|
dr documents support-api set <id1> --on --server <S> &
|
|
@@ -152,7 +152,7 @@ Offer to export the table as a CSV if the user wants it.
|
|
|
152
152
|
|
|
153
153
|
## Guard rails
|
|
154
154
|
|
|
155
|
-
- **Prod confirmation required.** `support_api` and `data-query set` are writes. On `US`, `US2`, `UK`, `CA`, `EU`, `DEMO`, confirm in-chat before running.
|
|
155
|
+
- **Prod confirmation required.** `support_api` and `data-query set` are writes. On `US`, `US2`, `UK`, `CA`, `EU`, `STUDIO`, `DEMO`, confirm in-chat before running.
|
|
156
156
|
- **Never read out tokens or JWTs.** The UUID returned is not a secret, but session tokens are — do not surface them.
|
|
157
157
|
- **Always verify the integration ID from `dr integrations list`** — do not guess or reuse IDs from a prior session without confirming they match the current tenant.
|
|
158
158
|
- **Always quote file paths** in `--payload-file` on Windows to handle spaces in directory names.
|
|
@@ -53,7 +53,7 @@ The skill is invoked in one of these forms:
|
|
|
53
53
|
|
|
54
54
|
## Server keys (the universe to probe)
|
|
55
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.
|
|
56
|
+
`US`, `US2`, `UK`, `CA`, `EU`, `STUDIO`, `DEV`, `DEV-1`, `TEST`, `TEST-1`, `TEST-2`, `TEST-3`, `TEST-4`, `TEST-5`, `TEST-6`, `TEST-7`, `DEMO` — case-insensitive.
|
|
57
57
|
These are the only valid `--server` values dr-cli accepts.
|
|
58
58
|
|
|
59
59
|
---
|
|
@@ -82,7 +82,7 @@ across all servers wastes turns and can scope the default wrongly.
|
|
|
82
82
|
Print verbatim, then wait for the user's reply. Do not guess from
|
|
83
83
|
context, prior turns, or `userEmail`:
|
|
84
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`)
|
|
85
|
+
> Which server should I switch to `<email>` on? (`US`, `US2`, `UK`, `CA`, `EU`, `STUDIO`, `DEV`, `DEV-1`, `TEST`, `TEST-1`, `TEST-2`, `TEST-3`, `TEST-4`, `TEST-5`, `TEST-6`, `TEST-7`, `DEMO`)
|
|
86
86
|
|
|
87
87
|
### 2.2. Probe that one server
|
|
88
88
|
|
|
@@ -226,7 +226,7 @@ Use the **single-loop pattern** (same reason as Section 2 — parallel
|
|
|
226
226
|
tool calls cancel each other on the first non-zero exit):
|
|
227
227
|
|
|
228
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
|
|
229
|
+
for srv in US US2 UK CA EU STUDIO DEV DEV-1 TEST TEST-1 TEST-2 TEST-3 TEST-4 TEST-5 TEST-6 TEST-7 DEMO; do
|
|
230
230
|
echo "=== $srv ==="
|
|
231
231
|
dr whoami --server "$srv" 2>&1 || true
|
|
232
232
|
done
|
|
@@ -728,7 +728,7 @@ the package layout reaches every producer.
|
|
|
728
728
|
|
|
729
729
|
- **Every write here is prod-tier.** Functions, filebox, mappers, lookups and custom
|
|
730
730
|
currencies are all mutations. Confirm before running on `US`, `US2`, `UK`, `CA`,
|
|
731
|
-
`EU` — **and on `DEMO`**, which is a customer-facing demo tenant, not a sandbox.
|
|
731
|
+
`EU`, `STUDIO` — **and on `DEMO`**, which is a customer-facing demo tenant, not a sandbox.
|
|
732
732
|
Prefer a `DEV`/`TEST*` rehearsal when the org is unstated.
|
|
733
733
|
- **Never guess a currency, a base, or a missing pair.** Each is a question for the
|
|
734
734
|
customer. A wrong rate mislabels real money and nobody downstream can tell.
|
|
@@ -38,8 +38,8 @@ config before the operator wastes time debugging downstream symptoms.
|
|
|
38
38
|
|
|
39
39
|
## Inputs
|
|
40
40
|
|
|
41
|
-
- `--server <key>` — required. Valid: `US`, `US2`, `UK`, `CA`, `EU`, `
|
|
42
|
-
`DEV-1`, `TEST`, `TEST-1`, `TEST-2`, `TEST-3`, `TEST-4`, `TEST-5`,
|
|
41
|
+
- `--server <key>` — required. Valid: `US`, `US2`, `UK`, `CA`, `EU`, `STUDIO`,
|
|
42
|
+
`DEV`, `DEV-1`, `TEST`, `TEST-1`, `TEST-2`, `TEST-3`, `TEST-4`, `TEST-5`,
|
|
43
43
|
`TEST-6`, `TEST-7`, `DEMO` (case-insensitive). Default per project
|
|
44
44
|
convention: `US`.
|
|
45
45
|
- `--report` — optional. Writes a markdown report to cwd in addition to
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datarails-ai/dr-cli",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.76",
|
|
4
4
|
"description": "Datarails CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@datarails-ai/dr-appspace-cli": "0.
|
|
20
|
+
"@datarails-ai/dr-appspace-cli": "0.10.0",
|
|
21
21
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
22
22
|
"@napi-rs/keyring": "^1.3.0",
|
|
23
23
|
"commander": "^12.1.0",
|