@datarails-ai/dr-cli 1.6.188 → 1.6.190

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 CHANGED
@@ -436,7 +436,7 @@ dr skill print <name> # print an embedded skill's SKILL.md
436
436
  | Folders | `folders list/create`, `folders reorder --container <root\|id> (--items folder:12,entity:87 \| --move <kind:id> --to-index <n>)`, `folders move <id> --parent <root\|id>` (dashboard / story picker tree, flag-gated; reorder and move are two-step confirm; a dashboard moves with `dashboards set-folder`) |
437
437
  | Functions | `functions list/get/create/delete` |
438
438
  | Dynamic ranges | `dynamic-ranges list/get/data/create/delete` |
439
- | Calc models | `calcmodels list/get/create/update/set-flow/recalculate/delete`; AGENT builder: `calcmodels agent ask/preview/save/approve` (`save` makes a draft; `approve` is two-step, Tier A) |
439
+ | Calc models | `calcmodels list/get/create/update/set-flow/recalculate/delete`; AGENT builder: `calcmodels agent ask/preview/create/save/approve` (`create` saves and activates, two-step, Tier A; `save` makes a draft; `approve` is two-step, Tier A) |
440
440
  | Lookups (LUTs) | `lut list/create/update/delete/reorder/unmapped` (alias `lookups`) |
441
441
  | Documents | `documents support-api set <id> --on/--off`, `documents calculate <id> --year/--quarter/--month/--day/--week ... [--backward] [--no-roll]` |
442
442
  | Semantic tables | `semantic-tables list/get` |
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.188",
11
+ version: "1.6.190",
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.62",
43
+ "@datarails-ai/dr-appspace-cli": "0.12.64",
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-02T15:33:34.634Z";
72
+ var BUILD_TIME = "2026-11-03T10:06:57.999Z";
73
73
  function formatBuildTime(iso) {
74
74
  if (iso === "") return "";
75
75
  const d = new Date(iso);
@@ -4449,6 +4449,10 @@ var PROD_GATE_TIER_A = /* @__PURE__ */ new Set([
4449
4449
  // prints the version and its impact (rows, pool, allocated, coverage); the token binds
4450
4450
  // that version.
4451
4451
  "calcmodel|approve",
4452
+ // dr calcmodels agent create — the web builder's save: one request saves a turn, activates
4453
+ // it, and starts its first production run. Same effect as save + approve, so the same tier.
4454
+ // The plan prints the impact; the token binds the operation (and --model).
4455
+ "calcmodel|create",
4452
4456
  // filebox
4453
4457
  "filebox|archive",
4454
4458
  "filebox-data-query|clear",
@@ -65541,6 +65545,7 @@ async function remove(client, id, options) {
65541
65545
  }
65542
65546
 
65543
65547
  // src/commands/calcmodelsAgent.ts
65548
+ import { createHash as createHash17 } from "crypto";
65544
65549
  import { setTimeout as delay } from "timers/promises";
65545
65550
 
65546
65551
  // src/types/calcmodelsAgent.ts
@@ -65606,6 +65611,14 @@ var calcAgentApproveResultSchema = z3.object({
65606
65611
  impact: calcAgentImpactSchema.nullish(),
65607
65612
  run_id: z3.string().nullish()
65608
65613
  }).passthrough();
65614
+ var calcAgentCreateResultSchema = z3.object({
65615
+ id: z3.number(),
65616
+ name: z3.string(),
65617
+ version_id: z3.number(),
65618
+ impact: calcAgentImpactSchema.nullish(),
65619
+ run_id: z3.string().nullish()
65620
+ }).passthrough();
65621
+ var calcAgentCreatePlanSchema = z3.object({ impact: calcAgentImpactSchema }).passthrough();
65609
65622
 
65610
65623
  // src/api/_htmlEntities.ts
65611
65624
  var ENTITIES2 = {
@@ -65743,13 +65756,16 @@ async function getPreview2(client, operationId, options) {
65743
65756
  }
65744
65757
  throw httpError("GET", path13, answer);
65745
65758
  }
65746
- async function save2(client, input, options) {
65759
+ function savePayload(input) {
65747
65760
  const payload = {
65748
65761
  preview_operation_id: input.operationId,
65749
65762
  name: input.name
65750
65763
  };
65751
65764
  if (input.calcModelId !== void 0) payload["calc_model_id"] = input.calcModelId;
65752
- const answer = await send(client, "POST", BASE3, payload, options);
65765
+ return payload;
65766
+ }
65767
+ async function save2(client, input, options) {
65768
+ const answer = await send(client, "POST", BASE3, savePayload(input), options);
65753
65769
  if (answer.status === 201) return parse2(calcAgentSaveResultSchema, "POST", BASE3, answer.body);
65754
65770
  throw httpError("POST", BASE3, answer);
65755
65771
  }
@@ -65778,6 +65794,35 @@ async function confirmApproval(client, calcModelId, versionId, options) {
65778
65794
  if (answer.status === 200) return parse2(calcAgentApproveResultSchema, "POST", path13, answer.body);
65779
65795
  throw httpError("POST", path13, answer);
65780
65796
  }
65797
+ async function requestCreateImpact(client, input, options) {
65798
+ const answer = await send(
65799
+ client,
65800
+ "POST",
65801
+ BASE3,
65802
+ { ...savePayload(input), activate: true },
65803
+ options
65804
+ );
65805
+ if (answer.status >= 200 && answer.status < 300) {
65806
+ throw new Error(
65807
+ `POST ${BASE3}: HTTP ${answer.status} to a request without an acknowledgment; expected ${APPROVAL_ACK_REQUIRED}. Check the models with \`dr calcmodels list\`.`
65808
+ );
65809
+ }
65810
+ if (answer.status === 400 && textField(answer.body, "code") === APPROVAL_ACK_REQUIRED) {
65811
+ return parse2(calcAgentCreatePlanSchema, "POST", BASE3, answer.body);
65812
+ }
65813
+ throw httpError("POST", BASE3, answer);
65814
+ }
65815
+ async function saveAndActivate(client, input, options) {
65816
+ const answer = await send(
65817
+ client,
65818
+ "POST",
65819
+ BASE3,
65820
+ { ...savePayload(input), activate: true, acknowledged: true },
65821
+ options
65822
+ );
65823
+ if (answer.status === 201) return parse2(calcAgentCreateResultSchema, "POST", BASE3, answer.body);
65824
+ throw httpError("POST", BASE3, answer);
65825
+ }
65781
65826
 
65782
65827
  // src/commands/_agentCli.ts
65783
65828
  import { access } from "fs/promises";
@@ -65931,11 +65976,12 @@ proposal: ${escapeControlChars(JSON.stringify(d.name ?? ""))} (${escapeControlCh
65931
65976
  }
65932
65977
  const next = [];
65933
65978
  if (savable) {
65934
- next.push(`save the draft: dr calcmodels agent save ${operationId} ${target}`);
65979
+ next.push(`create and activate: dr calcmodels agent create ${operationId} ${target}`);
65980
+ next.push(`or save a draft: dr calcmodels agent save ${operationId} ${target}`);
65935
65981
  }
65936
65982
  if (p.conversation_id) {
65937
65983
  next.push(
65938
- `reply: dr calcmodels agent ask '<reply>' --conversation ${shellQuote(p.conversation_id)} ${target}`
65984
+ `reply: dr calcmodels agent ask '<reply>' --conversation ${shellQuote(p.conversation_id)} ${target}`
65939
65985
  );
65940
65986
  }
65941
65987
  if (next.length > 0) out.write(`
@@ -66056,18 +66102,22 @@ async function runAgentPreview(cfg) {
66056
66102
  }
66057
66103
  var PREVIEW_ALREADY_SAVED = "CALC_PREVIEW_ALREADY_SAVED";
66058
66104
  var VERSION_CHANGED = "CALC_APPROVAL_VERSION_CHANGED";
66059
- async function runAgentSave(cfg) {
66060
- let name = cfg.name;
66061
- if (name !== void 0 && name.trim() === "") throw new Error("--name must not be empty");
66062
- if (name === void 0) {
66063
- const p = await getPreview2(cfg.client, cfg.operationId, { signal: cfg.signal });
66064
- name = p.definition?.name ?? void 0;
66065
- if (name === void 0 || name.trim() === "") {
66066
- throw new Error(
66067
- `--name is required: operation ${cfg.operationId} has no proposed name (status ${p.status})`
66068
- );
66069
- }
66105
+ async function resolveModelName(cfg) {
66106
+ if (cfg.name !== void 0) {
66107
+ if (cfg.name.trim() === "") throw new Error("--name must not be empty");
66108
+ return cfg.name;
66070
66109
  }
66110
+ const p = await getPreview2(cfg.client, cfg.operationId, { signal: cfg.signal });
66111
+ const name = p.definition?.name ?? void 0;
66112
+ if (name === void 0 || name.trim() === "") {
66113
+ throw new Error(
66114
+ `--name is required: operation ${cfg.operationId} has no proposed name (status ${p.status})`
66115
+ );
66116
+ }
66117
+ return name;
66118
+ }
66119
+ async function runAgentSave(cfg) {
66120
+ const name = await resolveModelName(cfg);
66071
66121
  let saved;
66072
66122
  try {
66073
66123
  saved = await save2(
@@ -66113,17 +66163,24 @@ function versionChanged(calcModelId, planned, current, cause) {
66113
66163
  cause === void 0 ? void 0 : { cause }
66114
66164
  );
66115
66165
  }
66116
- function impactLines(calcModelId, plan) {
66117
- const i = plan.impact;
66166
+ function impactFigures(i) {
66118
66167
  const pct2 = i.coverage_pct === null || i.coverage_pct === void 0 ? "n/a" : `${formatNumber(i.coverage_pct)}%`;
66168
+ return [
66169
+ `rows the first run writes: ${formatNumber(i.total_rows)}`,
66170
+ `allocated total: ${formatNumber(i.allocated_total)} of pool total ${formatNumber(i.pool_total)} (coverage ${pct2})`
66171
+ ];
66172
+ }
66173
+ function impactLines(calcModelId, plan) {
66119
66174
  return [
66120
66175
  `calc model: ${calcModelId}`,
66121
66176
  `version: ${plan.version_id}`,
66122
- `rows the first run writes: ${formatNumber(i.total_rows)}`,
66123
- `allocated total: ${formatNumber(i.allocated_total)} of pool total ${formatNumber(i.pool_total)} (coverage ${pct2})`,
66177
+ ...impactFigures(plan.impact),
66124
66178
  "Approving activates this version and starts its first production run at once."
66125
66179
  ];
66126
66180
  }
66181
+ function runOutcome(runId, target, calcModelId) {
66182
+ return runId ? `First run: ${escapeControlChars(runId)}.` : `No run was started: the model is not runnable now. Check it with dr calcmodels get ${calcModelId} ${target}.`;
66183
+ }
66127
66184
  async function runAgentApprove(cfg) {
66128
66185
  const executing = cfg.token !== void 0 && cfg.token.trim() !== "";
66129
66186
  if (executing && cfg.versionId === void 0) {
@@ -66161,12 +66218,86 @@ async function runAgentApprove(cfg) {
66161
66218
  writeJSONIndented(cfg.out, result);
66162
66219
  return;
66163
66220
  }
66164
- const run2 = result.run_id ? `First run: ${escapeControlChars(result.run_id)}.` : `No run was started: the model is not runnable now. Check it with dr calcmodels get ${cfg.id} ${target}.`;
66165
- cfg.out.write(`Activated calc model ${cfg.id} (version ${versionId}). ${run2}
66166
- `);
66221
+ cfg.out.write(
66222
+ `Activated calc model ${cfg.id} (version ${versionId}). ${runOutcome(result.run_id, target, cfg.id)}
66223
+ `
66224
+ );
66225
+ }
66226
+ });
66227
+ }
66228
+ var ANY_CONTROL_CHAR = /[\u0000-\u001f\u007f-\u009f]/;
66229
+ function createAction(operationId, name, calcModelId) {
66230
+ const model = calcModelId === void 0 ? "" : `@m${calcModelId}`;
66231
+ const nameHash = createHash17("sha256").update(name, "utf8").digest("hex").slice(0, 16);
66232
+ return { resource: "calcmodel", id: `${operationId}${model}#n${nameHash}`, verb: "create" };
66233
+ }
66234
+ async function runAgentCreate(cfg) {
66235
+ const name = await resolveModelName(cfg);
66236
+ if (ANY_CONTROL_CHAR.test(name)) {
66237
+ throw new Error(
66238
+ `the model name ${escapeControlChars(JSON.stringify(name))} has a control character, so it cannot go into the confirm command: pass --name <name>`
66239
+ );
66240
+ }
66241
+ const action = createAction(cfg.operationId, name, cfg.calcModelId);
66242
+ const executing = cfg.token !== void 0 && cfg.token.trim() !== "";
66243
+ if (executing) await preflightConfirmToken(action, cfg.token);
66244
+ const input = {
66245
+ operationId: cfg.operationId,
66246
+ name,
66247
+ ...cfg.calcModelId !== void 0 && { calcModelId: cfg.calcModelId }
66248
+ };
66249
+ const target = targetFlags(cfg.serverFlag, cfg.accountFlag);
66250
+ const plan = await requestCreateImpact(cfg.client, input, { signal: cfg.signal });
66251
+ const model = cfg.calcModelId === void 0 ? "" : ` --model ${cfg.calcModelId}`;
66252
+ await twoStepConfirm({
66253
+ out: cfg.out,
66254
+ action,
66255
+ token: cfg.token,
66256
+ server: cfg.serverFlag,
66257
+ confirmCmd: `dr calcmodels agent create ${cfg.operationId} --name ${shellQuote(name)}${model} ${target}${cfg.asJson ? " --json" : ""}`,
66258
+ describe: () => Promise.resolve([
66259
+ `operation: ${cfg.operationId}`,
66260
+ `name: ${escapeControlChars(JSON.stringify(name))}`,
66261
+ cfg.calcModelId === void 0 ? "creates: a new calc model" : `creates: a new version of calc model ${cfg.calcModelId}`,
66262
+ ...impactFigures(plan.impact),
66263
+ "Creating activates the model and starts its first production run at once, when the model is runnable."
66264
+ ]),
66265
+ execute: async () => {
66266
+ let result;
66267
+ try {
66268
+ result = await saveAndActivate(cfg.client, input, { signal: cfg.signal });
66269
+ } catch (err) {
66270
+ throw createFailure(err, cfg, target);
66271
+ }
66272
+ if (cfg.asJson) {
66273
+ writeJSONIndented(cfg.out, result);
66274
+ return;
66275
+ }
66276
+ cfg.out.write(
66277
+ `Created and activated calc model ${result.id} ${escapeControlChars(JSON.stringify(result.name))} (version ${result.version_id}). ${runOutcome(result.run_id, target, result.id)}
66278
+ `
66279
+ );
66167
66280
  }
66168
66281
  });
66169
66282
  }
66283
+ function createFailure(err, cfg, target) {
66284
+ if (!(err instanceof CalcAgentHttpError)) return err;
66285
+ const modelId = err.numberField("calc_model_id");
66286
+ if (err.code === PREVIEW_ALREADY_SAVED && modelId !== void 0) {
66287
+ return new Error(
66288
+ `${err.message}. To add this turn as a new, active version of model ${modelId}: dr calcmodels agent create ${cfg.operationId} --model ${modelId} ${target}`,
66289
+ { cause: err }
66290
+ );
66291
+ }
66292
+ const versionId = err.numberField("version_id");
66293
+ if (err.status === 400 && modelId !== void 0 && versionId !== void 0) {
66294
+ return new Error(
66295
+ `operation ${cfg.operationId} was saved as draft calc model ${modelId} (version ${versionId}), but not activated: ${err.message}. After the cause is fixed, activate it with: dr calcmodels agent approve ${modelId} ${target}`,
66296
+ { cause: err }
66297
+ );
66298
+ }
66299
+ return err;
66300
+ }
66170
66301
  var ASK_SETUP_HEADROOM_MS = 6e4;
66171
66302
  function registerCalcmodelsAgentCommand(cm) {
66172
66303
  const agent = cm.command("agent").description(
@@ -66230,6 +66361,38 @@ function registerCalcmodelsAgentCommand(cm) {
66230
66361
  });
66231
66362
  addServerFlag(previewCmdDef);
66232
66363
  addAccountFlag(previewCmdDef);
66364
+ const createCmd = agent.command("create").description(
66365
+ "Create a calc model from a succeeded turn and activate it at once \u2014 the web builder save (two-step confirm; a person confirms on production)."
66366
+ ).argument("<operation_id>", "the operation id of a SUCCEEDED turn").option("--name <name>", "model name (default: the agent's proposed name)").option("--model <calc_model_id>", "add this turn as a new, active version of an AGENT model").option("--confirm-token <token>", "Token from a prior plan run \u2014 required to create", "").option("--json", "Output raw JSON of the created model", false).action(
66367
+ async (opArg, opts) => {
66368
+ const operationId = parseOperationIdArg(opArg);
66369
+ const calcModelId = opts.model === void 0 ? void 0 : requirePositiveInt(opts.model, "--model");
66370
+ const token = opts.confirmToken;
66371
+ if (token !== void 0 && token.trim() !== "" && opts.name !== void 0) {
66372
+ await preflightConfirmToken(createAction(operationId, opts.name, calcModelId), token);
66373
+ }
66374
+ const serverKey = resolveServer(opts.server);
66375
+ const setup = await setupCall(opts.server, opts.account);
66376
+ try {
66377
+ await runAgentCreate({
66378
+ client: setup.client,
66379
+ operationId,
66380
+ ...opts.name !== void 0 && { name: opts.name },
66381
+ ...calcModelId !== void 0 && { calcModelId },
66382
+ token,
66383
+ asJson: opts.json === true,
66384
+ serverFlag: serverKey,
66385
+ accountFlag: normaliseAccount(opts.account),
66386
+ signal: setup.signal,
66387
+ out: process.stdout
66388
+ });
66389
+ } finally {
66390
+ setup.cleanup();
66391
+ }
66392
+ }
66393
+ );
66394
+ addServerFlag(createCmd);
66395
+ addAccountFlag(createCmd);
66233
66396
  const saveCmd = agent.command("save").description("Save a succeeded turn as a DRAFT calc model. Nothing runs until `approve`.").argument("<operation_id>", "the operation id of a SUCCEEDED turn").option("--name <name>", "model name (default: the agent's proposed name)").option("--model <calc_model_id>", "add this turn as a new version of an existing AGENT model").option("--json", "Output raw JSON", false).action(async (opArg, opts) => {
66234
66397
  const operationId = parseOperationIdArg(opArg);
66235
66398
  const calcModelId = opts.model === void 0 ? void 0 : requirePositiveInt(opts.model, "--model");
@@ -75546,7 +75709,7 @@ function registerPalettesCommand(root) {
75546
75709
  }
75547
75710
 
75548
75711
  // src/commands/templateLibrary.ts
75549
- import { createHash as createHash17 } from "crypto";
75712
+ import { createHash as createHash18 } from "crypto";
75550
75713
  import { promises as fs36 } from "fs";
75551
75714
  import { Option as Option4 } from "commander";
75552
75715
 
@@ -75624,7 +75787,7 @@ function boundId(cfg, target, payload) {
75624
75787
  image: cfg.image ?? null,
75625
75788
  payload: Object.fromEntries(Object.entries(payload).sort(([a], [b]) => a.localeCompare(b)))
75626
75789
  });
75627
- return `${target}#${createHash17("sha256").update(canonical).digest("hex").slice(0, 12)}`;
75790
+ return `${target}#${createHash18("sha256").update(canonical).digest("hex").slice(0, 12)}`;
75628
75791
  }
75629
75792
  async function assertOwnFilebox(client, fileboxId, signal) {
75630
75793
  const own2 = await list16(client, {}, { signal });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 1,
3
- "cliVersion": "1.6.188",
3
+ "cliVersion": "1.6.190",
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": {
@@ -4105,6 +4105,14 @@
4105
4105
  }
4106
4106
  ]
4107
4107
  },
4108
+ "calcmodels agent create": {
4109
+ "requires": [
4110
+ {
4111
+ "resource": "tables",
4112
+ "action": "destructive"
4113
+ }
4114
+ ]
4115
+ },
4108
4116
  "calcmodels agent save": {
4109
4117
  "requires": [
4110
4118
  {
@@ -233,7 +233,7 @@ area's gotchas.
233
233
 
234
234
  **Calc models** → [reference/calcmodels.md](reference/calcmodels.md)
235
235
  - `calcmodels list|get|create|update|set-flow|recalculate|delete` (alias `calc-models`)
236
- - `calcmodels agent ask|preview|save|approve` — build an AGENT (allocation) model with the builder agent; `approve` is Tier A
236
+ - `calcmodels agent ask|preview|create|save|approve` — build an AGENT (allocation) model with the builder agent. "Create an allocation model" means `agent ask`, then `agent create` after the operator's in-chat yes to the preview — not `calcmodels create`, which takes a JSON body for the older types only. `create` and `approve` are Tier A
237
237
 
238
238
  **Calculated values (per-table)** → [reference/calc-vals.md](reference/calc-vals.md)
239
239
  - `calc-vals list|get|create|update|delete` (alias `calcvals`) — `--table <id>` required on every subcommand
@@ -92,31 +92,52 @@ Flow:
92
92
  pool), balance groups, warnings. Show these to the operator. To change it,
93
93
  reply in the same conversation. "preview: none ran" means it cannot be saved.
94
94
  - `FAILED` — exits non-zero with the gate code, phase and suggestion.
95
- 3. `dr calcmodels agent save <operation_id> [--name <n>] --server <S>` — saves a
96
- DRAFT. The name defaults to the agent's proposed name. The new version
97
- does not run until it is approved. `--model <id>` adds the turn as a new
98
- version of that AGENT model; an active model keeps running its current
99
- version until then.
100
- 4. `dr calcmodels agent approve <id> --server <S>` — two-step. The plan prints
101
- the version and its impact (rows the first run writes, allocated total,
102
- pool total, coverage). Show it to the operator and stop. Run the printed
103
- command (`--version-id <n> --confirm-token <t>`) only after the operator
104
- gives a clear in-chat "yes" to that version and impact, on every server.
105
- Approving activates the version and starts its first production run at once.
95
+ 3. On `SUCCEEDED`, run `dr calcmodels agent create <operation_id> --server <S>`
96
+ at once, without a token. This plan step saves nothing. It prints the name,
97
+ the impact (rows the first run writes, allocated total, pool total,
98
+ coverage) and a confirm command. The name defaults to the agent's proposed
99
+ name; `--name <n>` sets another. `--model <id>` adds the turn as a new,
100
+ active version of that AGENT model.
101
+ 4. Show the preview, the name and the impact together, and stop. Ask the
102
+ operator in the chat: "Create and activate this model?" Stay in this
103
+ conversation. Do not send the operator to the web builder, and do not save
104
+ a draft instead.
105
+ 5. Run the printed command (`--name <n> --confirm-token <t>`) only after the
106
+ operator gives a clear in-chat "yes" to that name and impact, on every
107
+ server. One request creates the model and activates it, and starts its first
108
+ production run when the model is runnable (else it prints "No run was
109
+ started" and the `get` command).
110
+ 6. On a no, ask what to change and reply in the same conversation (step 2).
111
+
112
+ Drafts and recovery — only when the operator asks for a draft, or `create`
113
+ names one:
114
+
115
+ - `dr calcmodels agent save <operation_id> [--name <n>] [--model <id>] --server <S>`
116
+ saves a DRAFT. It does not run until it is approved. An active model keeps
117
+ running its current version until then.
118
+ - `dr calcmodels agent approve <id> --server <S>` — two-step. The plan prints
119
+ the version and its impact. Run the printed command (`--version-id <n>
120
+ --confirm-token <t>`) only after the operator's in-chat "yes" to that version
121
+ and impact. Approving activates the version and starts its first production
122
+ run at once.
123
+ - When `create` saves the model but the activation fails, it exits non-zero and
124
+ prints the draft's id and the `approve` command. Fix the cause first.
106
125
 
107
126
  Gotchas:
108
127
 
109
- - `approve` is Tier A (see safety.md). On a production server the token run
128
+ - `create` and `approve` are Tier A (see safety.md). On a production server the token run
110
129
  also opens a dialog or terminal prompt where the person types a word; with
111
130
  no interactive channel the binary refuses. On a non-production server the
112
131
  token alone activates, so the operator's in-chat "yes" is the only check.
113
- - `save` never activates, and `ask`/`save` write no rows to the destination
114
- table. Only `approve` starts a run that does.
132
+ - `save` and the `create` plan never activate, and `ask`/`save` write no rows to
133
+ the destination table. Only the `create` and `approve` token runs start a run
134
+ that does.
115
135
  - A newer version saved after the plan stops the token run before anything is
116
136
  activated ("a newer version … was saved"). Re-run `approve` without the
117
137
  token and show the new impact.
118
138
  - `CALC_PREVIEW_ALREADY_SAVED`: that turn is already model N. The error
119
- prints the `save … --model N` command for a new version.
139
+ prints the `create … --model N` (or `save … --model N`) command for a new
140
+ version.
120
141
  - `CALC_TURN_RATE_LIMITED` (429): the org has too many running turns. Wait.
121
142
  A 409 means a turn already runs on this conversation.
122
143
  - Only the user who started a turn can read or continue it (404 otherwise).
@@ -21,7 +21,7 @@ Gated commands include: `dashboards delete`, `datamappers delete`,
21
21
  `dynamic-ranges delete`, `extables delete`, `functions delete`, `lut delete`,
22
22
  `reports delete`, `storyboards delete`, `metrics delete`, `metrics categories
23
23
  delete`, `metrics dimensions delete`, `calcmodels delete|set-flow|recalculate`,
24
- `calcmodels agent approve`,
24
+ `calcmodels agent create|approve`,
25
25
  `reconciliation filebox delete`, `integrations delete`, `integrations it
26
26
  delete`, `devices command-delete`, `validate onboarding session delete`,
27
27
  `widgets delete`, `cash rules delete|delete-all|reorder|update`,
@@ -73,6 +73,9 @@ per-server lines — they are also the undo);
73
73
  `calcmodels agent approve` (activates an AGENT calc model and starts its first
74
74
  production run, which writes new rows; the token is bound to the version whose
75
75
  impact the plan printed);
76
+ `calcmodels agent create` (the same effect in one request: saves a builder turn,
77
+ activates it and starts its first production run; the token is bound to the
78
+ operation, the name, and `--model` when given);
76
79
  `error-enrichments import` (replaces every rule on the server, zeroes all
77
80
  hits/feedback counters, and reassigns every rule id); and
78
81
  `dashboards push --override` / `filebox push --override`. `import` is **not** an
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datarails-ai/dr-cli",
3
- "version": "1.6.188",
3
+ "version": "1.6.190",
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.62",
20
+ "@datarails-ai/dr-appspace-cli": "0.12.64",
21
21
  "@modelcontextprotocol/sdk": "^1.29.0",
22
22
  "@napi-rs/keyring": "^1.3.0",
23
23
  "commander": "^12.1.0",