@datarails-ai/dr-cli 1.6.184 → 1.6.186
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/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.186",
|
|
12
12
|
description: "Datarails CLI",
|
|
13
13
|
type: "module",
|
|
14
14
|
engines: {
|
|
@@ -40,7 +40,7 @@ var package_default = {
|
|
|
40
40
|
postinstall: "node scripts/postinstall.mjs"
|
|
41
41
|
},
|
|
42
42
|
dependencies: {
|
|
43
|
-
"@datarails-ai/dr-appspace-cli": "0.12.
|
|
43
|
+
"@datarails-ai/dr-appspace-cli": "0.12.61",
|
|
44
44
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
45
45
|
"@napi-rs/keyring": "^1.3.0",
|
|
46
46
|
commander: "^12.1.0",
|
|
@@ -69,7 +69,7 @@ var package_default = {
|
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
// src/buildInfo.ts
|
|
72
|
-
var BUILD_TIME = "2026-11-
|
|
72
|
+
var BUILD_TIME = "2026-11-02T07:19:02.800Z";
|
|
73
73
|
function formatBuildTime(iso) {
|
|
74
74
|
if (iso === "") return "";
|
|
75
75
|
const d = new Date(iso);
|
|
@@ -23605,7 +23605,7 @@ async function getById2(client, id, options) {
|
|
|
23605
23605
|
return out;
|
|
23606
23606
|
}
|
|
23607
23607
|
function scenarioContextQuery(ctx) {
|
|
23608
|
-
return `scenario=${encodeURIComponent(ctx.scenario)}&scenario_cycle=${encodeURIComponent(ctx.scenario_cycle)}&planning_scenario=${encodeURIComponent(ctx.planning_scenario)}`;
|
|
23608
|
+
return `scenario=${encodeURIComponent(ctx.scenario)}&scenario_cycle=${encodeURIComponent(ctx.scenario_cycle)}&cycle_year=${ctx.cycle_year ?? ""}&planning_scenario=${encodeURIComponent(ctx.planning_scenario)}`;
|
|
23609
23609
|
}
|
|
23610
23610
|
var NO_DRIVER_404_RE = /: HTTP 404: \{\}\s*$/;
|
|
23611
23611
|
async function getDriver(client, id, ctx, options) {
|
|
@@ -28323,27 +28323,54 @@ import { promises as fs14 } from "fs";
|
|
|
28323
28323
|
var DEFAULT_SCENARIO = "Actuals";
|
|
28324
28324
|
function addScenarioContextFlags(cmd) {
|
|
28325
28325
|
return cmd.option("--scenario <name>", "Scenario name \u2014 free text, matched exactly", DEFAULT_SCENARIO).option("--cycle <label>", "Scenario cycle label \u2014 free text, matched exactly (default: none)").option(
|
|
28326
|
+
"--cycle-year <yyyy>",
|
|
28327
|
+
"Fiscal year of the --cycle, e.g. 2027 \u2014 required with --cycle, refused without it"
|
|
28328
|
+
).option(
|
|
28326
28329
|
"--planning-scenario <name>",
|
|
28327
28330
|
"Planning scenario name \u2014 free text, matched exactly (default: none)"
|
|
28328
28331
|
);
|
|
28329
28332
|
}
|
|
28333
|
+
function parseCycleYear(raw2) {
|
|
28334
|
+
const s = raw2.trim();
|
|
28335
|
+
if (!/^\d{4}$/.test(s)) {
|
|
28336
|
+
throw new Error(`invalid --cycle-year "${raw2}" (expected a four-digit fiscal year, e.g. 2027)`);
|
|
28337
|
+
}
|
|
28338
|
+
return Number(s);
|
|
28339
|
+
}
|
|
28330
28340
|
function resolveScenarioContext(opts) {
|
|
28331
28341
|
const scenario = opts.scenario ?? "";
|
|
28342
|
+
const cycle = opts.cycle ?? "";
|
|
28343
|
+
const cycleYear = opts.cycleYear === void 0 ? null : parseCycleYear(opts.cycleYear);
|
|
28344
|
+
if (cycle !== "" && cycleYear === null) {
|
|
28345
|
+
throw new Error(
|
|
28346
|
+
`--cycle ${JSON.stringify(cycle)} needs --cycle-year <yyyy>: a cycle name repeats every year, so the server addresses a cycle only with its fiscal year`
|
|
28347
|
+
);
|
|
28348
|
+
}
|
|
28349
|
+
if (cycle === "" && cycleYear !== null) {
|
|
28350
|
+
throw new Error("--cycle-year is given only with --cycle <label>");
|
|
28351
|
+
}
|
|
28332
28352
|
return {
|
|
28333
28353
|
scenario: scenario === "" ? DEFAULT_SCENARIO : scenario,
|
|
28334
|
-
scenario_cycle:
|
|
28354
|
+
scenario_cycle: cycle,
|
|
28355
|
+
cycle_year: cycleYear,
|
|
28335
28356
|
planning_scenario: opts.planningScenario ?? ""
|
|
28336
28357
|
};
|
|
28337
28358
|
}
|
|
28338
28359
|
function formatScenarioContext(ctx) {
|
|
28339
|
-
return `scenario=${JSON.stringify(ctx.scenario)} cycle=${JSON.stringify(ctx.scenario_cycle)} planning-scenario=${JSON.stringify(ctx.planning_scenario)}`;
|
|
28360
|
+
return `scenario=${JSON.stringify(ctx.scenario)} cycle=${JSON.stringify(ctx.scenario_cycle)} ` + (ctx.cycle_year === null ? "" : `cycle-year=${ctx.cycle_year} `) + `planning-scenario=${JSON.stringify(ctx.planning_scenario)}`;
|
|
28340
28361
|
}
|
|
28341
28362
|
function sameScenarioContext(a, b) {
|
|
28342
|
-
|
|
28363
|
+
const yearUnknown = a.cycle_year === void 0 || b.cycle_year === void 0;
|
|
28364
|
+
return a.scenario === b.scenario && a.scenario_cycle === b.scenario_cycle && (yearUnknown || a.cycle_year === b.cycle_year) && a.planning_scenario === b.planning_scenario;
|
|
28365
|
+
}
|
|
28366
|
+
function findScenarioContext(rows, ctx) {
|
|
28367
|
+
const exact = rows.findIndex((r) => r.cycle_year !== void 0 && sameScenarioContext(r, ctx));
|
|
28368
|
+
return exact >= 0 ? exact : rows.findIndex((r) => sameScenarioContext(r, ctx));
|
|
28343
28369
|
}
|
|
28344
28370
|
function scenarioContextFlags(ctx) {
|
|
28345
28371
|
const parts = [`--scenario ${shellQuote(ctx.scenario)}`];
|
|
28346
28372
|
if (ctx.scenario_cycle !== "") parts.push(`--cycle ${shellQuote(ctx.scenario_cycle)}`);
|
|
28373
|
+
if (ctx.cycle_year !== null) parts.push(`--cycle-year ${ctx.cycle_year}`);
|
|
28347
28374
|
if (ctx.planning_scenario !== "") {
|
|
28348
28375
|
parts.push(`--planning-scenario ${shellQuote(ctx.planning_scenario)}`);
|
|
28349
28376
|
}
|
|
@@ -28518,6 +28545,7 @@ function renderDriver(out, d) {
|
|
|
28518
28545
|
writeRows4(out, [
|
|
28519
28546
|
["scenario", dash(d.scenario)],
|
|
28520
28547
|
["cycle", dash(d.scenario_cycle)],
|
|
28548
|
+
["cycle_year", dash(d.cycle_year)],
|
|
28521
28549
|
["planning_scenario", dash(d.planning_scenario)],
|
|
28522
28550
|
["unit", dash(d.unit)],
|
|
28523
28551
|
["is_additive", dash(d.is_additive)],
|
|
@@ -28546,12 +28574,15 @@ function renderCalculations(out, calcs) {
|
|
|
28546
28574
|
out.write("(no scenario calculations)\n");
|
|
28547
28575
|
return;
|
|
28548
28576
|
}
|
|
28549
|
-
const rows = [
|
|
28577
|
+
const rows = [
|
|
28578
|
+
["ID", "SCENARIO", "CYCLE", "CYCLE_YEAR", "PLANNING_SCENARIO", "FORMULA"]
|
|
28579
|
+
];
|
|
28550
28580
|
for (const c of calcs) {
|
|
28551
28581
|
rows.push([
|
|
28552
28582
|
dash(c.id),
|
|
28553
28583
|
dash(c.scenario),
|
|
28554
28584
|
dash(c.scenario_cycle),
|
|
28585
|
+
dash(c.cycle_year),
|
|
28555
28586
|
dash(c.planning_scenario),
|
|
28556
28587
|
c.presented_formula
|
|
28557
28588
|
]);
|
|
@@ -28681,10 +28712,21 @@ function toCalcPayload(c) {
|
|
|
28681
28712
|
return {
|
|
28682
28713
|
scenario: c.scenario,
|
|
28683
28714
|
scenario_cycle: c.scenario_cycle,
|
|
28715
|
+
cycle_year: c.cycle_year ?? null,
|
|
28684
28716
|
planning_scenario: c.planning_scenario,
|
|
28685
28717
|
presented_formula: c.presented_formula
|
|
28686
28718
|
};
|
|
28687
28719
|
}
|
|
28720
|
+
function assertKeptRowsHaveYear(id, calculations, skip) {
|
|
28721
|
+
if (!calculations.some((c) => c.cycle_year !== void 0)) return;
|
|
28722
|
+
const bad = calculations.find(
|
|
28723
|
+
(c, i) => i !== skip && c.scenario_cycle !== "" && (c.cycle_year ?? null) === null
|
|
28724
|
+
);
|
|
28725
|
+
if (bad === void 0) return;
|
|
28726
|
+
throw new Error(
|
|
28727
|
+
`metric ${id} keeps a calculation for ${formatScenarioContext({ ...bad, cycle_year: null })}${bad.id === void 0 ? "" : ` (id ${bad.id})`} with no cycle year; the server refuses any calculations list holding a cycle without its fiscal year, so nothing was changed. Fix or remove that calculation in the web app first.`
|
|
28728
|
+
);
|
|
28729
|
+
}
|
|
28688
28730
|
async function readCalculations(client, id, signal) {
|
|
28689
28731
|
const m = decodeShape(await getById2(client, id, { signal }));
|
|
28690
28732
|
return { name: m.name ?? "", calculations: m.calculations ?? [] };
|
|
@@ -28701,12 +28743,13 @@ async function runCalculationsAdd(cfg) {
|
|
|
28701
28743
|
const presented_formula = toWireFormula(cfg.formula);
|
|
28702
28744
|
const { calculations } = await readCalculations(cfg.client, cfg.id, cfg.signal);
|
|
28703
28745
|
const current = calculations.map(toCalcPayload);
|
|
28704
|
-
const idx =
|
|
28746
|
+
const idx = findScenarioContext(calculations, cfg.ctx);
|
|
28705
28747
|
if (idx >= 0 && !cfg.replace) {
|
|
28706
28748
|
throw new Error(
|
|
28707
28749
|
`metric ${cfg.id} already has a calculation for ${formatScenarioContext(cfg.ctx)} (${current[idx].presented_formula}); pass --replace to overwrite it`
|
|
28708
28750
|
);
|
|
28709
28751
|
}
|
|
28752
|
+
assertKeptRowsHaveYear(cfg.id, calculations, idx);
|
|
28710
28753
|
const entry = { ...cfg.ctx, presented_formula };
|
|
28711
28754
|
const next = idx >= 0 ? current.map((c, i) => i === idx ? entry : c) : [...current, entry];
|
|
28712
28755
|
const updated = await update6(
|
|
@@ -28747,13 +28790,15 @@ async function runCalculationsRemove(cfg) {
|
|
|
28747
28790
|
describe: async () => {
|
|
28748
28791
|
const { name, calculations } = await readCalculations(cfg.client, cfg.id, cfg.signal);
|
|
28749
28792
|
const all = calculations.map(toCalcPayload);
|
|
28750
|
-
const
|
|
28793
|
+
const idx = findScenarioContext(calculations, cfg.ctx);
|
|
28794
|
+
const hit = all[idx];
|
|
28751
28795
|
if (hit === void 0) {
|
|
28752
28796
|
throw new Error(
|
|
28753
28797
|
`metric ${cfg.id} has no calculation for ${formatScenarioContext(cfg.ctx)}; list them with \`dr metrics calculations list ${cfg.id}\``
|
|
28754
28798
|
);
|
|
28755
28799
|
}
|
|
28756
|
-
|
|
28800
|
+
assertKeptRowsHaveYear(cfg.id, calculations, idx);
|
|
28801
|
+
remaining = all.filter((_, i) => i !== idx);
|
|
28757
28802
|
return [
|
|
28758
28803
|
`metric: ${JSON.stringify(name === "" ? "(unnamed)" : name)}`,
|
|
28759
28804
|
`context: ${formatScenarioContext(cfg.ctx)}`,
|
|
@@ -28932,7 +28977,7 @@ function collectArray5(value, previous) {
|
|
|
28932
28977
|
}
|
|
28933
28978
|
function wireMetricsDrivers(metrics) {
|
|
28934
28979
|
const driver = metrics.command("driver").description(
|
|
28935
|
-
"Driver definition and values of a DRIVER metric, per scenario context (--scenario / --cycle / --planning-scenario: free-text names, matched exactly)"
|
|
28980
|
+
"Driver definition and values of a DRIVER metric, per scenario context (--scenario / --cycle / --planning-scenario: free-text names, matched exactly; --cycle-year: the fiscal year, required with --cycle)"
|
|
28936
28981
|
);
|
|
28937
28982
|
const driverGetCmd = addScenarioContextFlags(
|
|
28938
28983
|
driver.command("get").description("Show the driver definition for one scenario context").argument("<id>", "DRIVER metric id (positive integer)")
|
|
@@ -29068,7 +29113,7 @@ function wireMetricsDrivers(metrics) {
|
|
|
29068
29113
|
addServerFlag(valuesSetCmd);
|
|
29069
29114
|
addAccountFlag(valuesSetCmd);
|
|
29070
29115
|
const calculations = metrics.command("calculations").description(
|
|
29071
|
-
"Scenario-bound formulas of a CALC metric, one per scenario context (--scenario / --cycle / --planning-scenario: free-text names, matched exactly)"
|
|
29116
|
+
"Scenario-bound formulas of a CALC metric, one per scenario context (--scenario / --cycle / --planning-scenario: free-text names, matched exactly; --cycle-year: the fiscal year, required with --cycle)"
|
|
29072
29117
|
);
|
|
29073
29118
|
const calcListCmd = calculations.command("list").description("List a CALC metric's scenario calculations").argument("<id>", "CALC metric id (positive integer)").option("--json", "Output raw JSON instead of a table", false).action(async (idStr, opts) => {
|
|
29074
29119
|
const id = parseMetricIdArg(idStr);
|
package/dist/scopes-map.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"cliVersion": "1.6.
|
|
3
|
+
"cliVersion": "1.6.186",
|
|
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": {
|
|
@@ -241,7 +241,7 @@ area's gotchas.
|
|
|
241
241
|
**Metrics (KPIs) & functions** → [reference/metrics.md](reference/metrics.md)
|
|
242
242
|
- `metrics list|get|data|drilldown`
|
|
243
243
|
- `metrics create base|calc|driver`, `metrics update|delete`
|
|
244
|
-
- `metrics driver get|set|delete`, `metrics driver values get|set`, `metrics calculations list|add|remove`, `metrics what-if`: drivers, scenario-bound formulas and what-if runs, addressed per scenario context (`--scenario` / `--cycle` / `--planning-scenario`, matched exactly)
|
|
244
|
+
- `metrics driver get|set|delete`, `metrics driver values get|set`, `metrics calculations list|add|remove`, `metrics what-if`: drivers, scenario-bound formulas and what-if runs, addressed per scenario context (`--scenario` / `--cycle` / `--planning-scenario`, matched exactly; `--cycle` needs `--cycle-year <yyyy>`)
|
|
245
245
|
- `metrics re-aggregate` — rebuild pre-aggregated metric values (targeted ids, or `--all` org-wide); add `--wait [--timeout <s>]` on targeted ids to block until done (exits non-zero on failure/timeout)
|
|
246
246
|
- `metrics migrate` — org-wide metrics+dimensions migration (V1→V2 backfill; `--dry-run` first)
|
|
247
247
|
- `metrics categories list|get|create|update|delete`
|
|
@@ -146,10 +146,14 @@ cycle management). When either is off it answers 400/403/405 with a message,
|
|
|
146
146
|
and the CLI prints that message unchanged.
|
|
147
147
|
|
|
148
148
|
**Scenario context.** `driver …` and `calculations add|remove` address one
|
|
149
|
-
context with `--scenario <name>` (default `Actuals`), `--cycle <label
|
|
150
|
-
`--planning-scenario <name>`.
|
|
151
|
-
exactly. A context never inherits from another one,
|
|
152
|
-
`Budget` is a different row from the `Actuals` one.
|
|
149
|
+
context with `--scenario <name>` (default `Actuals`), `--cycle <label>`,
|
|
150
|
+
`--cycle-year <yyyy>` and `--planning-scenario <name>`. The three names are
|
|
151
|
+
free text and must match exactly. A context never inherits from another one,
|
|
152
|
+
so a driver set under `Budget` is a different row from the `Actuals` one.
|
|
153
|
+
A cycle name repeats every year, so `--cycle` needs `--cycle-year` (the
|
|
154
|
+
cycle's fiscal year, e.g. `--cycle "0+12" --cycle-year 2027`), and
|
|
155
|
+
`--cycle-year` is refused without `--cycle`. The same cycle in another year
|
|
156
|
+
is another context. `calculations list` shows the year in a CYCLE_YEAR column.
|
|
153
157
|
|
|
154
158
|
- `metrics create driver --name <n> [--description] [--category <id>]
|
|
155
159
|
[--dimensions <ids>]` creates a DRIVER metric. It has no table, value or
|
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.186",
|
|
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.12.
|
|
20
|
+
"@datarails-ai/dr-appspace-cli": "0.12.61",
|
|
21
21
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
22
22
|
"@napi-rs/keyring": "^1.3.0",
|
|
23
23
|
"commander": "^12.1.0",
|