@datarails-ai/dr-cli 1.6.120 → 1.6.121

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.120",
11
+ version: "1.6.121",
12
12
  description: "Datarails CLI",
13
13
  type: "module",
14
14
  engines: {
@@ -69,7 +69,7 @@ var package_default = {
69
69
  };
70
70
 
71
71
  // src/buildInfo.ts
72
- var BUILD_TIME = "2026-10-12T10:19:56.130Z";
72
+ var BUILD_TIME = "2026-10-12T10:41:54.439Z";
73
73
  function formatBuildTime(iso) {
74
74
  if (iso === "") return "";
75
75
  const d = new Date(iso);
@@ -37590,6 +37590,34 @@ function requireTagPermission(details, perm, docId, action) {
37590
37590
  );
37591
37591
  }
37592
37592
  }
37593
+ var TagWriteRefusedError = class extends Error {
37594
+ constructor(message, reason) {
37595
+ super(message);
37596
+ this.reason = reason;
37597
+ this.name = "TagWriteRefusedError";
37598
+ }
37599
+ reason;
37600
+ };
37601
+ function fullTagSetWith(stored, write) {
37602
+ const kept = [];
37603
+ for (const raw of stored ?? []) {
37604
+ if (typeof raw !== "object" || raw === null) {
37605
+ continue;
37606
+ }
37607
+ const t = raw;
37608
+ const id = typeof t.id === "string" && t.id.trim() !== "" ? Number(t.id) : t.id;
37609
+ if (typeof id !== "number" || !Number.isInteger(id) || id === write.id || kept.some((k) => k.id === id) || t.value === void 0 || t.value === null) {
37610
+ continue;
37611
+ }
37612
+ kept.push({
37613
+ id,
37614
+ value: t.value,
37615
+ ...typeof t.name === "string" ? { name: t.name } : {},
37616
+ ...typeof t.label === "string" ? { label: t.label } : {}
37617
+ });
37618
+ }
37619
+ return [...kept, write].sort((a, b) => a.id - b.id);
37620
+ }
37593
37621
  async function runFileboxSetVersionFileStatus(cfg) {
37594
37622
  if (cfg.docId <= 0) {
37595
37623
  throw new Error("document id must be positive");
@@ -37644,6 +37672,8 @@ async function runFileboxSetVersionFileStatus(cfg) {
37644
37672
  changed: false,
37645
37673
  verified: true,
37646
37674
  reapplied: false,
37675
+ date_tag_value: target.date_tag_value ?? null,
37676
+ date_tag_value_preserved: true,
37647
37677
  demoted_version_ids: [],
37648
37678
  rescan_queued: false
37649
37679
  });
@@ -37675,19 +37705,31 @@ async function runFileboxSetVersionFileStatus(cfg) {
37675
37705
  );
37676
37706
  }
37677
37707
  }
37678
- const tagsToUpdate = JSON.stringify([
37679
- { id: tag.id, value: cfg.status, name: tag.name, label: cfg.status }
37680
- ]);
37708
+ const statusWrite = {
37709
+ id: tag.id,
37710
+ value: cfg.status,
37711
+ name: tag.name,
37712
+ label: cfg.status
37713
+ };
37714
+ let base = target.tags ?? [];
37715
+ const refreshBase = (v) => {
37716
+ if (v !== null && v.tags.length > 0) {
37717
+ base = v.tags;
37718
+ }
37719
+ };
37681
37720
  const write = async () => {
37682
37721
  const res = await setVersionTagsAndLabel(
37683
37722
  cfg.client,
37684
37723
  cfg.versionId,
37685
- { tags_to_update: tagsToUpdate },
37724
+ { tags_to_update: JSON.stringify(fullTagSetWith(base, statusWrite)) },
37686
37725
  { signal: cfg.signal }
37687
37726
  );
37688
37727
  if (res.status < 200 || res.status >= 300) {
37689
37728
  const body = await res.text();
37690
- throw new Error(`set version file status refused (HTTP ${res.status}): ${body.trim()}`);
37729
+ throw new TagWriteRefusedError(
37730
+ `set version file status refused (HTTP ${res.status}): ${body.trim()}`,
37731
+ `(HTTP ${res.status}): ${body.trim()}`
37732
+ );
37691
37733
  }
37692
37734
  };
37693
37735
  const readBack = async () => {
@@ -37699,6 +37741,7 @@ async function runFileboxSetVersionFileStatus(cfg) {
37699
37741
  let seen = await readBack();
37700
37742
  if (seen !== null && tagValueOf(seen.tags, tag.id) !== cfg.status) {
37701
37743
  reapplied = true;
37744
+ refreshBase(seen);
37702
37745
  await write();
37703
37746
  seen = await readBack();
37704
37747
  const now = seen === null ? void 0 : tagValueOf(seen.tags, tag.id);
@@ -37708,6 +37751,53 @@ async function runFileboxSetVersionFileStatus(cfg) {
37708
37751
  );
37709
37752
  }
37710
37753
  }
37754
+ const dateBefore = target.date_tag_value;
37755
+ const dateMoved = (v) => v !== null && typeof dateBefore === "number" && v.row.date_tag_value !== void 0 && v.row.date_tag_value !== dateBefore;
37756
+ let dateUnknown = false;
37757
+ if (dateMoved(seen)) {
37758
+ err.write(
37759
+ `warning: date_tag_value on version ${cfg.versionId} changed (${JSON.stringify(dateBefore)} -> ${JSON.stringify(seen.row.date_tag_value ?? null)}) when its File Status was set; re-applying the full tag set once
37760
+ `
37761
+ );
37762
+ reapplied = true;
37763
+ refreshBase(seen);
37764
+ let refused = false;
37765
+ try {
37766
+ await write();
37767
+ } catch (e) {
37768
+ if (cfg.signal.aborted) {
37769
+ throw e;
37770
+ }
37771
+ if (e instanceof TagWriteRefusedError) {
37772
+ refused = true;
37773
+ err.write(`warning: re-applying the full tag set was refused ${e.reason}
37774
+ `);
37775
+ } else {
37776
+ err.write(
37777
+ `warning: re-applying the full tag set failed (${e instanceof Error ? e.message : String(e)}); its outcome is unknown, reading the version again
37778
+ `
37779
+ );
37780
+ }
37781
+ }
37782
+ const after = refused ? seen : await readBack();
37783
+ if (after === null) {
37784
+ dateUnknown = true;
37785
+ err.write(
37786
+ `warning: could not read version ${cfg.versionId} back to confirm its date_tag_value after re-applying the full tag set \u2014 check it with \`dr filebox versions ${cfg.docId} --json\`
37787
+ `
37788
+ );
37789
+ } else {
37790
+ seen = after;
37791
+ }
37792
+ }
37793
+ const dateAfter = dateUnknown || seen === null || seen.row.date_tag_value === void 0 ? null : seen.row.date_tag_value;
37794
+ const datePreserved = dateUnknown || seen === null || dateBefore === void 0 || seen.row.date_tag_value === void 0 ? null : !dateMoved(seen);
37795
+ if (datePreserved === false) {
37796
+ err.write(
37797
+ `warning: date_tag_value on version ${cfg.versionId} is still ${JSON.stringify(dateAfter)} (was ${JSON.stringify(dateBefore)}) after one re-apply; its tags still carry the date. Restore it with \`dr filebox set-version-date-tag ${cfg.versionId} --doc ${cfg.docId} --<dimension> <date>\` (it sends the date tag alone; on a planning filebox use \`dr filebox set-version-cycle ${cfg.versionId} --doc ${cfg.docId} --date <date> --scenario <name>\` instead, which keeps the cycle), then check \`dr filebox versions ${cfg.docId} --json\`
37798
+ `
37799
+ );
37800
+ }
37711
37801
  if (seen === null) {
37712
37802
  err.write(
37713
37803
  `warning: could not read version ${cfg.versionId} back to verify its File Status \u2014 confirm with \`dr filebox versions ${cfg.docId}\`
@@ -37733,6 +37823,8 @@ async function runFileboxSetVersionFileStatus(cfg) {
37733
37823
  changed: true,
37734
37824
  verified,
37735
37825
  reapplied,
37826
+ date_tag_value: dateAfter,
37827
+ date_tag_value_preserved: datePreserved,
37736
37828
  demoted_version_ids: demotedIds,
37737
37829
  rescan_queued: true
37738
37830
  });
@@ -37743,6 +37835,12 @@ async function runFileboxSetVersionFileStatus(cfg) {
37743
37835
  `Set File Status on version ${cfg.versionId}: ${JSON.stringify(previous ?? "(unset)")} -> "${cfg.status}" (${verdict}).
37744
37836
  `
37745
37837
  );
37838
+ if (datePreserved === false) {
37839
+ cfg.out.write(
37840
+ `date_tag_value NOT preserved: it reads ${JSON.stringify(dateAfter)}, was ${JSON.stringify(dateBefore)} (see the warning above).
37841
+ `
37842
+ );
37843
+ }
37746
37844
  if (demotedIds.length > 0) {
37747
37845
  cfg.out.write(
37748
37846
  `Only one version per period can be ${cfg.status}: ${plural2(demotedIds.length, "version", "versions")} ${demotedIds.join(", ")} ${plural2(demotedIds.length, "was", "were")} moved to Draft by the server.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 1,
3
- "cliVersion": "1.6.120",
3
+ "cliVersion": "1.6.121",
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": {
@@ -154,7 +154,11 @@ set-version-include` (below).
154
154
 
155
155
  - `filebox set-version-date-tag <vid> --doc <id> --month|--quarter|--day|--year|--week …
156
156
  [--json]` — set the date tag on one version (resolves the tag id from the doc's
157
- config; other tags untouched).
157
+ config; other tags untouched in `tags`). It sends the date tag alone, and the
158
+ server rebuilds the version's dimension value from the submitted tags, so on
159
+ a filebox with a second dimension tag (a cycle or plan LIST tag) that tag
160
+ drops out of the dimension. On a planning filebox use `set-version-cycle`,
161
+ which sends the date and the cycle together.
158
162
  - `filebox set-version-label <vid> --label "<text>" | --clear [--json]` — set or
159
163
  remove a version's free-text label; name, date and dimension tags are
160
164
  untouched, and a locked date tag does not block it. No confirm step. Address it
@@ -176,6 +180,27 @@ set-version-include` (below).
176
180
  moves that version to Draft (the output names it). The status is read back and
177
181
  re-applied once if it did not stick. The write queues a rescan of the version,
178
182
  so mapped tables show the new `File Status` only after it finishes.
183
+ Like the UI, it sends the version's **full tag set** with File Status
184
+ replaced, not File Status alone. The server merges the submitted tags into
185
+ `tags` but rebuilds the version's dimension value, and with it the
186
+ `date_tag_value` that `filebox versions --json` shows, from the submitted tags
187
+ only. A File Status-only body (CLI releases before DR-54157) therefore left
188
+ `date_tag_value` null while `tags` still held the month. That is not harmless:
189
+ the server uses the dimension value to pick the latest version per period, to
190
+ apply date locks and in rescan events. The command reads `date_tag_value` back,
191
+ re-applies the full set once if it changed, and otherwise reports it: a stderr
192
+ warning, a `date_tag_value NOT preserved` line, and
193
+ `date_tag_value_preserved: false` in `--json`. `--json` also returns
194
+ `date_tag_value`, and `date_tag_value_preserved: null` when the server does
195
+ not serve it. **To repair a version left with a null date**, run
196
+ `set-version-date-tag` with the period its `tags` hold. That writes the date
197
+ tag, and the server rebuilds the dimension from it. It sends the date tag
198
+ alone, so use it only when the date is the filebox's only dimension tag. On a
199
+ planning filebox, run `set-version-cycle` with the version's existing date
200
+ and scenario instead, which sends both. Re-running
201
+ `set-version-file-status` with the same status does not repair it, because
202
+ it writes nothing. A real status change does restore it, because it re-sends
203
+ the date tag.
179
204
  - `filebox set-version-cycle <vid> --doc <id> --date <date> --scenario <name>
180
205
  [--date-tag-name <n>] [--json]` — **forecast/budget (planning) fileboxes only.**
181
206
  Sets the cycle date tag and the scenario LIST-tag together (both flags
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datarails-ai/dr-cli",
3
- "version": "1.6.120",
3
+ "version": "1.6.121",
4
4
  "description": "Datarails CLI",
5
5
  "type": "module",
6
6
  "engines": {