@datarails-ai/dr-cli 1.6.185 → 1.6.187
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
|
@@ -332,9 +332,9 @@ are covered); a missing `--server`, or a missing `--account` in customer mode;
|
|
|
332
332
|
`--user-id`); a host override (`--app-space-host`, `DR_APP_SPACE_HOST`,
|
|
333
333
|
`--connectors-url`); in org mode, any command the scopes map does not prove
|
|
334
334
|
read-only, plus the few read-scoped commands with side effects
|
|
335
|
-
(`devices request-logs`, `desk smtp test`, `dashboards prepare
|
|
336
|
-
|
|
337
|
-
|
|
335
|
+
(`devices request-logs`, `desk smtp test`, `dashboards prepare`). A pin that is
|
|
336
|
+
set but malformed refuses every command (`--help` and `--version` still print).
|
|
337
|
+
A refusal exits 3, like a scope denial.
|
|
338
338
|
|
|
339
339
|
### API keys (headless and CI)
|
|
340
340
|
|
|
@@ -465,6 +465,7 @@ dr skill print <name> # print an embedded skill's SKILL.md
|
|
|
465
465
|
| Connectors | `connectors publish <dataqueryFile>`, `connectors query repoint <queryId>`, `connectors binding get <fileboxUuid>` (drives the connectors control-plane over VPN) |
|
|
466
466
|
| Agent Studio | `agents list/get/versions/test-link/refresh/pull/update/create/mcp-servers/cli-scopes/scope-registry`, `agents set-listed/set-global/set-visibility/archive` (two-step confirm), `agents models/catalog/system-entities`, `agents skills list/get/versions/bundle/pull/create/publish/delete` (`delete` two-step confirm). A CLI-exposed agent's `dr` sessions are capped by its CLI scopes (`resource:action`, default `*:read`): set with `update --cli-scopes <list>` / `--reset-cli-scopes [--cli-scopes-reason <text>]` or `create --expose-cli --cli-scopes <list>`, read with `cli-scopes`; the scope history and restore stay in the Backoffice (service-token only) |
|
|
467
467
|
| Agent release pins | `agents served`, `agents pin/unpin` (two-step confirm): the version each deployment serves; `--server`, `--servers <keys>` or `--production` |
|
|
468
|
+
| Agent schedules | `agents schedules list/create/update/delete` (`delete` two-step confirm): ai-service cron runs of a managed agent, as the session user. `--agent-id` defaults to the token's `agent_id` claim. Like every `agents` command, an agent needs `managed-agents:write` in its CLI scopes (`managed-agents:destructive` for `delete`): `agents update --id <agentId> --cli-scopes '*:read,managed-agents:write,managed-agents:destructive'` |
|
|
468
469
|
| Skill | `skill` — prints embedded `SKILL.md` |
|
|
469
470
|
|
|
470
471
|
### Connectors: TLS over VPN
|
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.187",
|
|
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-11-
|
|
72
|
+
var BUILD_TIME = "2026-11-02T11:55:21.441Z";
|
|
73
73
|
function formatBuildTime(iso) {
|
|
74
74
|
if (iso === "") return "";
|
|
75
75
|
const d = new Date(iso);
|
|
@@ -4390,7 +4390,11 @@ var PROD_GATE_TIER_B = /* @__PURE__ */ new Set([
|
|
|
4390
4390
|
"template-library|update",
|
|
4391
4391
|
"template-library|unpublish",
|
|
4392
4392
|
"template-library|archive",
|
|
4393
|
-
"template-library|restore"
|
|
4393
|
+
"template-library|restore",
|
|
4394
|
+
// agent schedules (dr agents schedules delete). One org row; the plan prints its cron,
|
|
4395
|
+
// timezone, agent, prompt and run-as user, and `dr agents schedules create` with them
|
|
4396
|
+
// restores it (running as the re-creator: create cannot set the run-as user).
|
|
4397
|
+
"managed-agent-schedule|delete"
|
|
4394
4398
|
]);
|
|
4395
4399
|
var PROD_GATE_TIER_A = /* @__PURE__ */ new Set([
|
|
4396
4400
|
// workflow / mec — soft-delete + cascade deletes. `archive` also covers the
|
|
@@ -5211,8 +5215,7 @@ var ORG_MODE_UNSCOPED_ALLOWED = /* @__PURE__ */ new Set([
|
|
|
5211
5215
|
var ORG_MODE_READ_SCOPED_REFUSED = /* @__PURE__ */ new Set([
|
|
5212
5216
|
"devices request-logs",
|
|
5213
5217
|
"desk smtp test",
|
|
5214
|
-
"dashboards prepare"
|
|
5215
|
-
"storyboards prepare"
|
|
5218
|
+
"dashboards prepare"
|
|
5216
5219
|
]);
|
|
5217
5220
|
var LOCAL_COMMANDS_WITH_TARGET_FLAGS = /* @__PURE__ */ new Set([
|
|
5218
5221
|
"app-space scaffold"
|
|
@@ -23605,7 +23608,7 @@ async function getById2(client, id, options) {
|
|
|
23605
23608
|
return out;
|
|
23606
23609
|
}
|
|
23607
23610
|
function scenarioContextQuery(ctx) {
|
|
23608
|
-
return `scenario=${encodeURIComponent(ctx.scenario)}&scenario_cycle=${encodeURIComponent(ctx.scenario_cycle)}&planning_scenario=${encodeURIComponent(ctx.planning_scenario)}`;
|
|
23611
|
+
return `scenario=${encodeURIComponent(ctx.scenario)}&scenario_cycle=${encodeURIComponent(ctx.scenario_cycle)}&cycle_year=${ctx.cycle_year ?? ""}&planning_scenario=${encodeURIComponent(ctx.planning_scenario)}`;
|
|
23609
23612
|
}
|
|
23610
23613
|
var NO_DRIVER_404_RE = /: HTTP 404: \{\}\s*$/;
|
|
23611
23614
|
async function getDriver(client, id, ctx, options) {
|
|
@@ -28323,27 +28326,54 @@ import { promises as fs14 } from "fs";
|
|
|
28323
28326
|
var DEFAULT_SCENARIO = "Actuals";
|
|
28324
28327
|
function addScenarioContextFlags(cmd) {
|
|
28325
28328
|
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(
|
|
28329
|
+
"--cycle-year <yyyy>",
|
|
28330
|
+
"Fiscal year of the --cycle, e.g. 2027 \u2014 required with --cycle, refused without it"
|
|
28331
|
+
).option(
|
|
28326
28332
|
"--planning-scenario <name>",
|
|
28327
28333
|
"Planning scenario name \u2014 free text, matched exactly (default: none)"
|
|
28328
28334
|
);
|
|
28329
28335
|
}
|
|
28336
|
+
function parseCycleYear(raw2) {
|
|
28337
|
+
const s = raw2.trim();
|
|
28338
|
+
if (!/^\d{4}$/.test(s)) {
|
|
28339
|
+
throw new Error(`invalid --cycle-year "${raw2}" (expected a four-digit fiscal year, e.g. 2027)`);
|
|
28340
|
+
}
|
|
28341
|
+
return Number(s);
|
|
28342
|
+
}
|
|
28330
28343
|
function resolveScenarioContext(opts) {
|
|
28331
28344
|
const scenario = opts.scenario ?? "";
|
|
28345
|
+
const cycle = opts.cycle ?? "";
|
|
28346
|
+
const cycleYear = opts.cycleYear === void 0 ? null : parseCycleYear(opts.cycleYear);
|
|
28347
|
+
if (cycle !== "" && cycleYear === null) {
|
|
28348
|
+
throw new Error(
|
|
28349
|
+
`--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`
|
|
28350
|
+
);
|
|
28351
|
+
}
|
|
28352
|
+
if (cycle === "" && cycleYear !== null) {
|
|
28353
|
+
throw new Error("--cycle-year is given only with --cycle <label>");
|
|
28354
|
+
}
|
|
28332
28355
|
return {
|
|
28333
28356
|
scenario: scenario === "" ? DEFAULT_SCENARIO : scenario,
|
|
28334
|
-
scenario_cycle:
|
|
28357
|
+
scenario_cycle: cycle,
|
|
28358
|
+
cycle_year: cycleYear,
|
|
28335
28359
|
planning_scenario: opts.planningScenario ?? ""
|
|
28336
28360
|
};
|
|
28337
28361
|
}
|
|
28338
28362
|
function formatScenarioContext(ctx) {
|
|
28339
|
-
return `scenario=${JSON.stringify(ctx.scenario)} cycle=${JSON.stringify(ctx.scenario_cycle)} planning-scenario=${JSON.stringify(ctx.planning_scenario)}`;
|
|
28363
|
+
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
28364
|
}
|
|
28341
28365
|
function sameScenarioContext(a, b) {
|
|
28342
|
-
|
|
28366
|
+
const yearUnknown = a.cycle_year === void 0 || b.cycle_year === void 0;
|
|
28367
|
+
return a.scenario === b.scenario && a.scenario_cycle === b.scenario_cycle && (yearUnknown || a.cycle_year === b.cycle_year) && a.planning_scenario === b.planning_scenario;
|
|
28368
|
+
}
|
|
28369
|
+
function findScenarioContext(rows, ctx) {
|
|
28370
|
+
const exact = rows.findIndex((r) => r.cycle_year !== void 0 && sameScenarioContext(r, ctx));
|
|
28371
|
+
return exact >= 0 ? exact : rows.findIndex((r) => sameScenarioContext(r, ctx));
|
|
28343
28372
|
}
|
|
28344
28373
|
function scenarioContextFlags(ctx) {
|
|
28345
28374
|
const parts = [`--scenario ${shellQuote(ctx.scenario)}`];
|
|
28346
28375
|
if (ctx.scenario_cycle !== "") parts.push(`--cycle ${shellQuote(ctx.scenario_cycle)}`);
|
|
28376
|
+
if (ctx.cycle_year !== null) parts.push(`--cycle-year ${ctx.cycle_year}`);
|
|
28347
28377
|
if (ctx.planning_scenario !== "") {
|
|
28348
28378
|
parts.push(`--planning-scenario ${shellQuote(ctx.planning_scenario)}`);
|
|
28349
28379
|
}
|
|
@@ -28518,6 +28548,7 @@ function renderDriver(out, d) {
|
|
|
28518
28548
|
writeRows4(out, [
|
|
28519
28549
|
["scenario", dash(d.scenario)],
|
|
28520
28550
|
["cycle", dash(d.scenario_cycle)],
|
|
28551
|
+
["cycle_year", dash(d.cycle_year)],
|
|
28521
28552
|
["planning_scenario", dash(d.planning_scenario)],
|
|
28522
28553
|
["unit", dash(d.unit)],
|
|
28523
28554
|
["is_additive", dash(d.is_additive)],
|
|
@@ -28546,12 +28577,15 @@ function renderCalculations(out, calcs) {
|
|
|
28546
28577
|
out.write("(no scenario calculations)\n");
|
|
28547
28578
|
return;
|
|
28548
28579
|
}
|
|
28549
|
-
const rows = [
|
|
28580
|
+
const rows = [
|
|
28581
|
+
["ID", "SCENARIO", "CYCLE", "CYCLE_YEAR", "PLANNING_SCENARIO", "FORMULA"]
|
|
28582
|
+
];
|
|
28550
28583
|
for (const c of calcs) {
|
|
28551
28584
|
rows.push([
|
|
28552
28585
|
dash(c.id),
|
|
28553
28586
|
dash(c.scenario),
|
|
28554
28587
|
dash(c.scenario_cycle),
|
|
28588
|
+
dash(c.cycle_year),
|
|
28555
28589
|
dash(c.planning_scenario),
|
|
28556
28590
|
c.presented_formula
|
|
28557
28591
|
]);
|
|
@@ -28681,10 +28715,21 @@ function toCalcPayload(c) {
|
|
|
28681
28715
|
return {
|
|
28682
28716
|
scenario: c.scenario,
|
|
28683
28717
|
scenario_cycle: c.scenario_cycle,
|
|
28718
|
+
cycle_year: c.cycle_year ?? null,
|
|
28684
28719
|
planning_scenario: c.planning_scenario,
|
|
28685
28720
|
presented_formula: c.presented_formula
|
|
28686
28721
|
};
|
|
28687
28722
|
}
|
|
28723
|
+
function assertKeptRowsHaveYear(id, calculations, skip) {
|
|
28724
|
+
if (!calculations.some((c) => c.cycle_year !== void 0)) return;
|
|
28725
|
+
const bad = calculations.find(
|
|
28726
|
+
(c, i) => i !== skip && c.scenario_cycle !== "" && (c.cycle_year ?? null) === null
|
|
28727
|
+
);
|
|
28728
|
+
if (bad === void 0) return;
|
|
28729
|
+
throw new Error(
|
|
28730
|
+
`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.`
|
|
28731
|
+
);
|
|
28732
|
+
}
|
|
28688
28733
|
async function readCalculations(client, id, signal) {
|
|
28689
28734
|
const m = decodeShape(await getById2(client, id, { signal }));
|
|
28690
28735
|
return { name: m.name ?? "", calculations: m.calculations ?? [] };
|
|
@@ -28701,12 +28746,13 @@ async function runCalculationsAdd(cfg) {
|
|
|
28701
28746
|
const presented_formula = toWireFormula(cfg.formula);
|
|
28702
28747
|
const { calculations } = await readCalculations(cfg.client, cfg.id, cfg.signal);
|
|
28703
28748
|
const current = calculations.map(toCalcPayload);
|
|
28704
|
-
const idx =
|
|
28749
|
+
const idx = findScenarioContext(calculations, cfg.ctx);
|
|
28705
28750
|
if (idx >= 0 && !cfg.replace) {
|
|
28706
28751
|
throw new Error(
|
|
28707
28752
|
`metric ${cfg.id} already has a calculation for ${formatScenarioContext(cfg.ctx)} (${current[idx].presented_formula}); pass --replace to overwrite it`
|
|
28708
28753
|
);
|
|
28709
28754
|
}
|
|
28755
|
+
assertKeptRowsHaveYear(cfg.id, calculations, idx);
|
|
28710
28756
|
const entry = { ...cfg.ctx, presented_formula };
|
|
28711
28757
|
const next = idx >= 0 ? current.map((c, i) => i === idx ? entry : c) : [...current, entry];
|
|
28712
28758
|
const updated = await update6(
|
|
@@ -28747,13 +28793,15 @@ async function runCalculationsRemove(cfg) {
|
|
|
28747
28793
|
describe: async () => {
|
|
28748
28794
|
const { name, calculations } = await readCalculations(cfg.client, cfg.id, cfg.signal);
|
|
28749
28795
|
const all = calculations.map(toCalcPayload);
|
|
28750
|
-
const
|
|
28796
|
+
const idx = findScenarioContext(calculations, cfg.ctx);
|
|
28797
|
+
const hit = all[idx];
|
|
28751
28798
|
if (hit === void 0) {
|
|
28752
28799
|
throw new Error(
|
|
28753
28800
|
`metric ${cfg.id} has no calculation for ${formatScenarioContext(cfg.ctx)}; list them with \`dr metrics calculations list ${cfg.id}\``
|
|
28754
28801
|
);
|
|
28755
28802
|
}
|
|
28756
|
-
|
|
28803
|
+
assertKeptRowsHaveYear(cfg.id, calculations, idx);
|
|
28804
|
+
remaining = all.filter((_, i) => i !== idx);
|
|
28757
28805
|
return [
|
|
28758
28806
|
`metric: ${JSON.stringify(name === "" ? "(unnamed)" : name)}`,
|
|
28759
28807
|
`context: ${formatScenarioContext(cfg.ctx)}`,
|
|
@@ -28932,7 +28980,7 @@ function collectArray5(value, previous) {
|
|
|
28932
28980
|
}
|
|
28933
28981
|
function wireMetricsDrivers(metrics) {
|
|
28934
28982
|
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)"
|
|
28983
|
+
"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
28984
|
);
|
|
28937
28985
|
const driverGetCmd = addScenarioContextFlags(
|
|
28938
28986
|
driver.command("get").description("Show the driver definition for one scenario context").argument("<id>", "DRIVER metric id (positive integer)")
|
|
@@ -29068,7 +29116,7 @@ function wireMetricsDrivers(metrics) {
|
|
|
29068
29116
|
addServerFlag(valuesSetCmd);
|
|
29069
29117
|
addAccountFlag(valuesSetCmd);
|
|
29070
29118
|
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)"
|
|
29119
|
+
"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
29120
|
);
|
|
29073
29121
|
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
29122
|
const id = parseMetricIdArg(idStr);
|
|
@@ -55634,9 +55682,9 @@ async function listTemplates(client, params, options) {
|
|
|
55634
55682
|
);
|
|
55635
55683
|
return out ?? [];
|
|
55636
55684
|
}
|
|
55637
|
-
async function getTemplate(client, id, options) {
|
|
55685
|
+
async function getTemplate(client, id, options, params) {
|
|
55638
55686
|
const out = await client.getJSON(
|
|
55639
|
-
`/api/processes/v2/process_templates/${id}`,
|
|
55687
|
+
`/api/processes/v2/process_templates/${id}${buildQueryString(params)}`,
|
|
55640
55688
|
options
|
|
55641
55689
|
);
|
|
55642
55690
|
if (out === null) {
|
|
@@ -55655,9 +55703,9 @@ async function createTemplate(client, payload, options) {
|
|
|
55655
55703
|
}
|
|
55656
55704
|
return out;
|
|
55657
55705
|
}
|
|
55658
|
-
async function updateTemplate(client, id, payload, options) {
|
|
55706
|
+
async function updateTemplate(client, id, payload, options, params) {
|
|
55659
55707
|
const out = await client.putJSON(
|
|
55660
|
-
`/api/processes/v2/process_templates/${id}`,
|
|
55708
|
+
`/api/processes/v2/process_templates/${id}${buildQueryString(params)}`,
|
|
55661
55709
|
payload,
|
|
55662
55710
|
options
|
|
55663
55711
|
);
|
|
@@ -57123,6 +57171,10 @@ function validateTagsArray2(raw2) {
|
|
|
57123
57171
|
}
|
|
57124
57172
|
|
|
57125
57173
|
// src/commands/mecWorkflow.ts
|
|
57174
|
+
var MEC_DETAIL = { only_mec: true };
|
|
57175
|
+
function getMecTemplate(client, id, signal, params = {}) {
|
|
57176
|
+
return getTemplate(client, id, { signal }, { ...params, ...MEC_DETAIL });
|
|
57177
|
+
}
|
|
57126
57178
|
function dash6(s) {
|
|
57127
57179
|
if (s === null || s === void 0) return "-";
|
|
57128
57180
|
if (typeof s === "number") return String(s);
|
|
@@ -57258,7 +57310,7 @@ function renderMecWorkflowList(out, rows) {
|
|
|
57258
57310
|
}
|
|
57259
57311
|
async function runMecWorkflowGet(cfg) {
|
|
57260
57312
|
await requireMec(cfg.client, { signal: cfg.signal });
|
|
57261
|
-
const tmpl = await withMec(() =>
|
|
57313
|
+
const tmpl = await withMec(() => getMecTemplate(cfg.client, cfg.id, cfg.signal));
|
|
57262
57314
|
if (cfg.asJson) {
|
|
57263
57315
|
writeJSONIndented(cfg.out, tmpl);
|
|
57264
57316
|
return;
|
|
@@ -57743,9 +57795,7 @@ async function runMecWorkflowUpdate(cfg) {
|
|
|
57743
57795
|
server: cfg.serverFlag,
|
|
57744
57796
|
confirmCmd: `dr mec workflow update ${cfg.id} --file ${cfg.payloadFile} --server ${cfg.serverFlag}`,
|
|
57745
57797
|
describe: async () => {
|
|
57746
|
-
const current = await withMec(
|
|
57747
|
-
() => getTemplate(cfg.client, cfg.id, { signal: cfg.signal })
|
|
57748
|
-
);
|
|
57798
|
+
const current = await withMec(() => getMecTemplate(cfg.client, cfg.id, cfg.signal));
|
|
57749
57799
|
const lines = [`current name: ${current.name}`];
|
|
57750
57800
|
if (cfg.payload.config?.name !== void 0 && cfg.payload.config.name !== current.name) {
|
|
57751
57801
|
lines.push(`new name: ${cfg.payload.config.name}`);
|
|
@@ -57760,9 +57810,7 @@ async function runMecWorkflowUpdate(cfg) {
|
|
|
57760
57810
|
},
|
|
57761
57811
|
execute: async () => {
|
|
57762
57812
|
const updated = await withMec(
|
|
57763
|
-
() => updateTemplate(cfg.client, cfg.id, cfg.payload, {
|
|
57764
|
-
signal: cfg.signal
|
|
57765
|
-
})
|
|
57813
|
+
() => updateTemplate(cfg.client, cfg.id, cfg.payload, { signal: cfg.signal }, MEC_DETAIL)
|
|
57766
57814
|
);
|
|
57767
57815
|
if (cfg.asJson) {
|
|
57768
57816
|
writeJSONIndented(cfg.out, updated);
|
|
@@ -57783,9 +57831,7 @@ async function runMecWorkflowState(cfg) {
|
|
|
57783
57831
|
};
|
|
57784
57832
|
await preflightConfirmToken(action, cfg.token);
|
|
57785
57833
|
await requireMec(cfg.client, { signal: cfg.signal });
|
|
57786
|
-
const current = await withMec(
|
|
57787
|
-
() => getTemplate(cfg.client, cfg.id, { signal: cfg.signal })
|
|
57788
|
-
);
|
|
57834
|
+
const current = await withMec(() => getMecTemplate(cfg.client, cfg.id, cfg.signal));
|
|
57789
57835
|
let cascadeWarning = [];
|
|
57790
57836
|
if (cfg.active) {
|
|
57791
57837
|
cascadeWarning = await collectMecActivationCascade(cfg.client, current, cfg.signal);
|
|
@@ -57835,8 +57881,8 @@ async function collectMecActivationCascade(client, template, signal) {
|
|
|
57835
57881
|
const lines = [];
|
|
57836
57882
|
const instancesAll = template.process_instances ?? [];
|
|
57837
57883
|
if (instancesAll.length === 0) return lines;
|
|
57838
|
-
const
|
|
57839
|
-
|
|
57884
|
+
const created = (p) => Date.parse(p.create_time ?? "") || 0;
|
|
57885
|
+
const latest = instancesAll.reduce((a, b) => created(b) > created(a) ? b : a);
|
|
57840
57886
|
let process2;
|
|
57841
57887
|
try {
|
|
57842
57888
|
process2 = await withMec(() => getProcess(client, latest.id, { signal }));
|
|
@@ -57865,7 +57911,9 @@ async function runMecWorkflowArchive(cfg) {
|
|
|
57865
57911
|
await requireMec(cfg.client, { signal: cfg.signal });
|
|
57866
57912
|
let current = null;
|
|
57867
57913
|
try {
|
|
57868
|
-
current = await withMec(
|
|
57914
|
+
current = await withMec(
|
|
57915
|
+
() => getMecTemplate(cfg.client, cfg.id, cfg.signal, cfg.archive ? {} : { is_archive: true })
|
|
57916
|
+
);
|
|
57869
57917
|
} catch {
|
|
57870
57918
|
current = null;
|
|
57871
57919
|
}
|
|
@@ -57880,7 +57928,7 @@ async function runMecWorkflowArchive(cfg) {
|
|
|
57880
57928
|
return [
|
|
57881
57929
|
`id: ${cfg.id}`,
|
|
57882
57930
|
`target archived: ${cfg.archive ? "yes" : "no"}`,
|
|
57883
|
-
|
|
57931
|
+
`(template not visible via the ${cfg.archive ? "active" : "archived"}-template detail GET \u2014 likely already in the opposite state)`
|
|
57884
57932
|
];
|
|
57885
57933
|
}
|
|
57886
57934
|
return [
|
|
@@ -57916,9 +57964,7 @@ async function runMecWorkflowClone(cfg) {
|
|
|
57916
57964
|
`cloning MEC workflow template ${cfg.templateId} (carries existing members forward)`
|
|
57917
57965
|
);
|
|
57918
57966
|
await requireMec(cfg.client, { signal: cfg.signal });
|
|
57919
|
-
const current = await withMec(
|
|
57920
|
-
() => getTemplate(cfg.client, cfg.templateId, { signal: cfg.signal })
|
|
57921
|
-
);
|
|
57967
|
+
const current = await withMec(() => getMecTemplate(cfg.client, cfg.templateId, cfg.signal));
|
|
57922
57968
|
const dateConfig = resolveDateTagConfig(current);
|
|
57923
57969
|
const source = resolveCopyFrom(current, cfg.copyFrom, dateConfig.id);
|
|
57924
57970
|
const extraTags = resolveExtraTags(current, parseExtraTagFlags(cfg.tagFlags), dateConfig.id);
|
|
@@ -76527,6 +76573,9 @@ async function aiServicePost(client, path13, body, attribute, options) {
|
|
|
76527
76573
|
const fresh = await tokenFor(client, signal, true);
|
|
76528
76574
|
res = await sendOnce(url, fresh.token, payload, extra, signal);
|
|
76529
76575
|
}
|
|
76576
|
+
return parseResponse(rel, res);
|
|
76577
|
+
}
|
|
76578
|
+
async function parseResponse(rel, res) {
|
|
76530
76579
|
const text2 = await res.text();
|
|
76531
76580
|
if (!res.ok) {
|
|
76532
76581
|
const envelope = parseErrorEnvelope(text2);
|
|
@@ -76633,6 +76682,26 @@ function listModels(client, options) {
|
|
|
76633
76682
|
function getSystemEntities(client, options) {
|
|
76634
76683
|
return read(client, "v1/ManagedAgents/getSystemEntities", {}, options);
|
|
76635
76684
|
}
|
|
76685
|
+
async function writeSchedule(client, path13, body, options) {
|
|
76686
|
+
const res = await write(client, path13, body, options);
|
|
76687
|
+
const schedule = res !== null && typeof res === "object" ? res.schedule : void 0;
|
|
76688
|
+
if (schedule === null || typeof schedule !== "object" || Array.isArray(schedule)) {
|
|
76689
|
+
throw new Error(`POST /ai-service/external/${path13}: response has no schedule object`);
|
|
76690
|
+
}
|
|
76691
|
+
return res;
|
|
76692
|
+
}
|
|
76693
|
+
function listSchedules(client, body, options) {
|
|
76694
|
+
return read(client, "v1/ManagedAgentSchedules/listSchedules", body, options);
|
|
76695
|
+
}
|
|
76696
|
+
function createSchedule(client, body, options) {
|
|
76697
|
+
return writeSchedule(client, "v1/ManagedAgentSchedules/createSchedule", body, options);
|
|
76698
|
+
}
|
|
76699
|
+
function updateSchedule(client, body, options) {
|
|
76700
|
+
return writeSchedule(client, "v1/ManagedAgentSchedules/updateSchedule", body, options);
|
|
76701
|
+
}
|
|
76702
|
+
function deleteSchedule(client, body, options) {
|
|
76703
|
+
return write(client, "v1/ManagedAgentSchedules/deleteSchedule", body, options);
|
|
76704
|
+
}
|
|
76636
76705
|
|
|
76637
76706
|
// src/commands/_agentCliScopes.ts
|
|
76638
76707
|
var DEFAULT_CLI_SCOPES = ["*:read"];
|
|
@@ -77644,6 +77713,218 @@ function registerAgentPinCommands(agents) {
|
|
|
77644
77713
|
withPinTargets(unpin);
|
|
77645
77714
|
}
|
|
77646
77715
|
|
|
77716
|
+
// src/commands/agents_schedules.ts
|
|
77717
|
+
var SCHEDULE_ID = "<scheduleId>";
|
|
77718
|
+
function requirePrompt(prompt) {
|
|
77719
|
+
if (prompt.trim() === "") {
|
|
77720
|
+
throw new Error("--prompt must not be empty (omit it, or use update --clear-prompt)");
|
|
77721
|
+
}
|
|
77722
|
+
return prompt;
|
|
77723
|
+
}
|
|
77724
|
+
function tokenAgentId(client) {
|
|
77725
|
+
try {
|
|
77726
|
+
return firstString(decodeJwtClaims(client.session.jwtAccess ?? ""), "agent_id");
|
|
77727
|
+
} catch {
|
|
77728
|
+
return "";
|
|
77729
|
+
}
|
|
77730
|
+
}
|
|
77731
|
+
function agentIdFor(flag, client) {
|
|
77732
|
+
const id = (flag ?? "").trim();
|
|
77733
|
+
return id !== "" ? id : tokenAgentId(client);
|
|
77734
|
+
}
|
|
77735
|
+
function scheduleLine(s) {
|
|
77736
|
+
const state = s.enabled === void 0 ? "?" : s.enabled ? "enabled" : "disabled";
|
|
77737
|
+
return [
|
|
77738
|
+
s.id ?? "?",
|
|
77739
|
+
state,
|
|
77740
|
+
`cron "${s.crontab ?? "?"}" ${s.timezone ?? "UTC"}`,
|
|
77741
|
+
`agent ${s.agentId ?? "?"}`,
|
|
77742
|
+
`last ${s.lastRunStatus ?? "-"}`
|
|
77743
|
+
].join(" ");
|
|
77744
|
+
}
|
|
77745
|
+
function writeResult(cfg, verb, res) {
|
|
77746
|
+
if (cfg.asJson) {
|
|
77747
|
+
writeJSONIndented(cfg.out, res);
|
|
77748
|
+
return;
|
|
77749
|
+
}
|
|
77750
|
+
cfg.out.write(`${verb} ${scheduleLine(res.schedule)}
|
|
77751
|
+
`);
|
|
77752
|
+
}
|
|
77753
|
+
async function runSchedulesList(cfg) {
|
|
77754
|
+
const agentId = agentIdFor(cfg.agentId, cfg.client);
|
|
77755
|
+
const res = await listSchedules(cfg.client, agentId !== "" ? { agentId } : {}, {
|
|
77756
|
+
signal: cfg.signal
|
|
77757
|
+
});
|
|
77758
|
+
if (cfg.asJson) {
|
|
77759
|
+
writeJSONIndented(cfg.out, res);
|
|
77760
|
+
return;
|
|
77761
|
+
}
|
|
77762
|
+
const list29 = res.schedules ?? [];
|
|
77763
|
+
if (list29.length === 0) {
|
|
77764
|
+
cfg.out.write("(no schedules)\n");
|
|
77765
|
+
return;
|
|
77766
|
+
}
|
|
77767
|
+
for (const s of list29) cfg.out.write(`${scheduleLine(s)}
|
|
77768
|
+
`);
|
|
77769
|
+
}
|
|
77770
|
+
async function runSchedulesCreate(cfg) {
|
|
77771
|
+
const agentId = agentIdFor(cfg.agentId, cfg.client);
|
|
77772
|
+
if (agentId === "") {
|
|
77773
|
+
throw new Error(
|
|
77774
|
+
"missing required option: --agent-id <agentId> (the session token names no agent)"
|
|
77775
|
+
);
|
|
77776
|
+
}
|
|
77777
|
+
if (cfg.cron === void 0) throw new Error("missing required option: --cron <expr>");
|
|
77778
|
+
const body = { agentId, crontab: parseCron(cfg.cron) };
|
|
77779
|
+
if (cfg.tz !== void 0) body.timezone = cfg.tz;
|
|
77780
|
+
if (cfg.prompt !== void 0) body.prompt = requirePrompt(cfg.prompt);
|
|
77781
|
+
if (cfg.environmentId !== void 0) body.environmentId = cfg.environmentId;
|
|
77782
|
+
if (cfg.enabled !== void 0) body.enabled = requireBool(cfg.enabled, "--enabled");
|
|
77783
|
+
writeResult(cfg, "Created", await createSchedule(cfg.client, body, { signal: cfg.signal }));
|
|
77784
|
+
}
|
|
77785
|
+
async function runSchedulesUpdate(cfg) {
|
|
77786
|
+
const id = requireId(cfg.id, SCHEDULE_ID);
|
|
77787
|
+
if (cfg.prompt !== void 0 && cfg.clearPrompt === true) {
|
|
77788
|
+
throw new Error("give --prompt or --clear-prompt, not both");
|
|
77789
|
+
}
|
|
77790
|
+
const body = { id };
|
|
77791
|
+
if (cfg.cron !== void 0) body.crontab = parseCron(cfg.cron);
|
|
77792
|
+
if (cfg.tz !== void 0) body.timezone = cfg.tz;
|
|
77793
|
+
if (cfg.prompt !== void 0) body.prompt = requirePrompt(cfg.prompt);
|
|
77794
|
+
if (cfg.clearPrompt === true) body.prompt = null;
|
|
77795
|
+
if (cfg.environmentId !== void 0) body.environmentId = cfg.environmentId;
|
|
77796
|
+
if (cfg.enabled !== void 0) body.enabled = requireBool(cfg.enabled, "--enabled");
|
|
77797
|
+
if (Object.keys(body).length === 1) throw new Error("nothing to change: give at least one flag");
|
|
77798
|
+
writeResult(cfg, "Updated", await updateSchedule(cfg.client, body, { signal: cfg.signal }));
|
|
77799
|
+
}
|
|
77800
|
+
async function runSchedulesDelete(cfg) {
|
|
77801
|
+
const id = requireId(cfg.id, SCHEDULE_ID);
|
|
77802
|
+
const serverKey = cfg.client.serverKey;
|
|
77803
|
+
const action = {
|
|
77804
|
+
resource: "managed-agent-schedule",
|
|
77805
|
+
id: `${serverKey}:${id}`,
|
|
77806
|
+
verb: "delete"
|
|
77807
|
+
};
|
|
77808
|
+
await preflightConfirmToken(action, cfg.token);
|
|
77809
|
+
await twoStepConfirm({
|
|
77810
|
+
out: proseStream(cfg),
|
|
77811
|
+
action,
|
|
77812
|
+
token: cfg.token,
|
|
77813
|
+
server: serverKey,
|
|
77814
|
+
confirmCmd: `dr agents schedules delete --id ${shellArg(id)} --server ${shellArg(serverKey)}`,
|
|
77815
|
+
describe: async () => {
|
|
77816
|
+
const agentId = tokenAgentId(cfg.client);
|
|
77817
|
+
const res = await listSchedules(cfg.client, agentId !== "" ? { agentId } : {}, {
|
|
77818
|
+
signal: cfg.signal
|
|
77819
|
+
});
|
|
77820
|
+
const s = (res.schedules ?? []).find((row) => row.id === id);
|
|
77821
|
+
if (s === void 0) {
|
|
77822
|
+
throw new Error(`no schedule ${id} in this org (see: dr agents schedules list)`);
|
|
77823
|
+
}
|
|
77824
|
+
return [
|
|
77825
|
+
scheduleLine(s),
|
|
77826
|
+
`prompt: ${JSON.stringify(s.prompt ?? null)}`,
|
|
77827
|
+
`environment: ${s.environmentId ?? "(resolved per run)"}`,
|
|
77828
|
+
// `create` cannot set this: a restored schedule runs as whoever re-creates it.
|
|
77829
|
+
`runs as: user ${s.runAsUserId ?? "?"}`
|
|
77830
|
+
];
|
|
77831
|
+
},
|
|
77832
|
+
execute: async () => {
|
|
77833
|
+
const res = await deleteSchedule(cfg.client, { id }, { signal: cfg.signal });
|
|
77834
|
+
proseStream(cfg).write(`Deleted schedule ${id}.
|
|
77835
|
+
`);
|
|
77836
|
+
if (cfg.asJson) writeJSONIndented(cfg.out, res);
|
|
77837
|
+
}
|
|
77838
|
+
});
|
|
77839
|
+
}
|
|
77840
|
+
var AGENT_ID_HELP = "Agent id (default: the session token's agent_id claim, which a managed agent's token carries).";
|
|
77841
|
+
function registerAgentSchedulesCommands(agents) {
|
|
77842
|
+
const schedules = agents.command("schedules").description(
|
|
77843
|
+
"Cron schedules that open a conversation with a managed agent, as the session user."
|
|
77844
|
+
);
|
|
77845
|
+
const list29 = schedules.command("list").description("List the org's schedules.").option(
|
|
77846
|
+
"--agent-id <agentId>",
|
|
77847
|
+
"Only this agent's (default: the session token's agent_id claim; without one, every agent's)."
|
|
77848
|
+
).option("--json", JSON_HELP).action(async (opts) => {
|
|
77849
|
+
const setup = await setupCall(opts.server, opts.account);
|
|
77850
|
+
try {
|
|
77851
|
+
await runSchedulesList({
|
|
77852
|
+
client: setup.client,
|
|
77853
|
+
signal: setup.signal,
|
|
77854
|
+
...std(),
|
|
77855
|
+
agentId: opts.agentId,
|
|
77856
|
+
asJson: opts.json === true
|
|
77857
|
+
});
|
|
77858
|
+
} finally {
|
|
77859
|
+
setup.cleanup();
|
|
77860
|
+
}
|
|
77861
|
+
});
|
|
77862
|
+
withTarget(list29);
|
|
77863
|
+
const create20 = schedules.command("create").description("Schedule an agent; its runs act as you.").option("--agent-id <agentId>", AGENT_ID_HELP).option(
|
|
77864
|
+
"--cron <expr>",
|
|
77865
|
+
'Five-field cron line, runs at least 5 minutes apart, e.g. "0 8 * * 1".'
|
|
77866
|
+
).option("--tz <iana>", "Timezone the cron line is read in (default UTC).").option("--prompt <text>", "What each run is asked (default: a bare trigger turn).").option(
|
|
77867
|
+
"--environment-id <id>",
|
|
77868
|
+
"Anthropic environment for the runs (default: resolved per run)."
|
|
77869
|
+
).option("--enabled <true|false>", "Create it enabled (default true).").option("--json", JSON_HELP).action(async (opts) => {
|
|
77870
|
+
const setup = await setupCall(opts.server, opts.account);
|
|
77871
|
+
try {
|
|
77872
|
+
await runSchedulesCreate({
|
|
77873
|
+
client: setup.client,
|
|
77874
|
+
signal: setup.signal,
|
|
77875
|
+
...std(),
|
|
77876
|
+
agentId: opts.agentId,
|
|
77877
|
+
cron: opts.cron,
|
|
77878
|
+
tz: opts.tz,
|
|
77879
|
+
prompt: opts.prompt,
|
|
77880
|
+
environmentId: opts.environmentId,
|
|
77881
|
+
enabled: opts.enabled,
|
|
77882
|
+
asJson: opts.json === true
|
|
77883
|
+
});
|
|
77884
|
+
} finally {
|
|
77885
|
+
setup.cleanup();
|
|
77886
|
+
}
|
|
77887
|
+
});
|
|
77888
|
+
withTarget(create20);
|
|
77889
|
+
const update13 = schedules.command("update").description("Change a schedule (only the flags given change); its runs then act as you.").option("--id <scheduleId>", "Schedule id.").option("--cron <expr>", "New five-field cron line.").option("--tz <iana>", "New timezone.").option("--prompt <text>", "New prompt.").option("--clear-prompt", "Remove the prompt (runs get a bare trigger turn).").option("--environment-id <id>", "New Anthropic environment.").option("--enabled <true|false>", "Enable or disable it.").option("--json", JSON_HELP).action(async (opts) => {
|
|
77890
|
+
const setup = await setupCall(opts.server, opts.account);
|
|
77891
|
+
try {
|
|
77892
|
+
await runSchedulesUpdate({
|
|
77893
|
+
client: setup.client,
|
|
77894
|
+
signal: setup.signal,
|
|
77895
|
+
...std(),
|
|
77896
|
+
id: opts.id,
|
|
77897
|
+
cron: opts.cron,
|
|
77898
|
+
tz: opts.tz,
|
|
77899
|
+
prompt: opts.prompt,
|
|
77900
|
+
clearPrompt: opts.clearPrompt,
|
|
77901
|
+
environmentId: opts.environmentId,
|
|
77902
|
+
enabled: opts.enabled,
|
|
77903
|
+
asJson: opts.json === true
|
|
77904
|
+
});
|
|
77905
|
+
} finally {
|
|
77906
|
+
setup.cleanup();
|
|
77907
|
+
}
|
|
77908
|
+
});
|
|
77909
|
+
withTarget(update13);
|
|
77910
|
+
const del = schedules.command("delete").description("Delete a schedule. (two-step confirm)").option("--id <scheduleId>", "Schedule id.").option("--confirm-token <token>", CONFIRM_HELP).option("--json", JSON_HELP).action(async (opts) => {
|
|
77911
|
+
const setup = await setupCall(opts.server, opts.account);
|
|
77912
|
+
try {
|
|
77913
|
+
await runSchedulesDelete({
|
|
77914
|
+
client: setup.client,
|
|
77915
|
+
signal: setup.signal,
|
|
77916
|
+
...std(),
|
|
77917
|
+
id: opts.id,
|
|
77918
|
+
token: opts.confirmToken,
|
|
77919
|
+
asJson: opts.json === true
|
|
77920
|
+
});
|
|
77921
|
+
} finally {
|
|
77922
|
+
setup.cleanup();
|
|
77923
|
+
}
|
|
77924
|
+
});
|
|
77925
|
+
withTarget(del);
|
|
77926
|
+
}
|
|
77927
|
+
|
|
77647
77928
|
// src/commands/agents_skills.ts
|
|
77648
77929
|
import { mkdir as mkdir4, writeFile as writeFile7 } from "fs/promises";
|
|
77649
77930
|
import { dirname as dirname9, join as join17 } from "path";
|
|
@@ -79212,6 +79493,7 @@ function registerAgentsCommand(root) {
|
|
|
79212
79493
|
registerAgentPinCommands(agents);
|
|
79213
79494
|
registerAgentStudioCommands(agents);
|
|
79214
79495
|
registerAgentSkillsCommand(agents);
|
|
79496
|
+
registerAgentSchedulesCommands(agents);
|
|
79215
79497
|
}
|
|
79216
79498
|
|
|
79217
79499
|
// src/auth/versionCheck.ts
|
package/dist/scopes-map.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"cliVersion": "1.6.
|
|
3
|
+
"cliVersion": "1.6.187",
|
|
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": {
|
|
@@ -695,7 +695,7 @@
|
|
|
695
695
|
"requires": [
|
|
696
696
|
{
|
|
697
697
|
"resource": "tables",
|
|
698
|
-
"action": "
|
|
698
|
+
"action": "write"
|
|
699
699
|
}
|
|
700
700
|
]
|
|
701
701
|
},
|
|
@@ -851,7 +851,7 @@
|
|
|
851
851
|
"requires": [
|
|
852
852
|
{
|
|
853
853
|
"resource": "dashboards",
|
|
854
|
-
"action": "
|
|
854
|
+
"action": "write"
|
|
855
855
|
}
|
|
856
856
|
]
|
|
857
857
|
},
|
|
@@ -1067,7 +1067,7 @@
|
|
|
1067
1067
|
"requires": [
|
|
1068
1068
|
{
|
|
1069
1069
|
"resource": "tables",
|
|
1070
|
-
"action": "
|
|
1070
|
+
"action": "write"
|
|
1071
1071
|
}
|
|
1072
1072
|
]
|
|
1073
1073
|
},
|
|
@@ -1075,7 +1075,7 @@
|
|
|
1075
1075
|
"requires": [
|
|
1076
1076
|
{
|
|
1077
1077
|
"resource": "tables",
|
|
1078
|
-
"action": "
|
|
1078
|
+
"action": "write"
|
|
1079
1079
|
}
|
|
1080
1080
|
]
|
|
1081
1081
|
},
|
|
@@ -1083,7 +1083,7 @@
|
|
|
1083
1083
|
"requires": [
|
|
1084
1084
|
{
|
|
1085
1085
|
"resource": "tables",
|
|
1086
|
-
"action": "
|
|
1086
|
+
"action": "write"
|
|
1087
1087
|
}
|
|
1088
1088
|
]
|
|
1089
1089
|
},
|
|
@@ -1863,7 +1863,7 @@
|
|
|
1863
1863
|
"requires": [
|
|
1864
1864
|
{
|
|
1865
1865
|
"resource": "integrations",
|
|
1866
|
-
"action": "
|
|
1866
|
+
"action": "write"
|
|
1867
1867
|
}
|
|
1868
1868
|
]
|
|
1869
1869
|
},
|
|
@@ -5220,6 +5220,38 @@
|
|
|
5220
5220
|
"action": "destructive"
|
|
5221
5221
|
}
|
|
5222
5222
|
]
|
|
5223
|
+
},
|
|
5224
|
+
"agents schedules list": {
|
|
5225
|
+
"requires": [
|
|
5226
|
+
{
|
|
5227
|
+
"resource": "managed-agents",
|
|
5228
|
+
"action": "read"
|
|
5229
|
+
}
|
|
5230
|
+
]
|
|
5231
|
+
},
|
|
5232
|
+
"agents schedules create": {
|
|
5233
|
+
"requires": [
|
|
5234
|
+
{
|
|
5235
|
+
"resource": "managed-agents",
|
|
5236
|
+
"action": "write"
|
|
5237
|
+
}
|
|
5238
|
+
]
|
|
5239
|
+
},
|
|
5240
|
+
"agents schedules update": {
|
|
5241
|
+
"requires": [
|
|
5242
|
+
{
|
|
5243
|
+
"resource": "managed-agents",
|
|
5244
|
+
"action": "write"
|
|
5245
|
+
}
|
|
5246
|
+
]
|
|
5247
|
+
},
|
|
5248
|
+
"agents schedules delete": {
|
|
5249
|
+
"requires": [
|
|
5250
|
+
{
|
|
5251
|
+
"resource": "managed-agents",
|
|
5252
|
+
"action": "destructive"
|
|
5253
|
+
}
|
|
5254
|
+
]
|
|
5223
5255
|
}
|
|
5224
5256
|
},
|
|
5225
5257
|
"aliases": {
|
|
@@ -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
|
|
@@ -57,7 +57,9 @@ Reads never need confirmation. Gated **writes** fall into two tiers (full table:
|
|
|
57
57
|
every server, because the agent and skill registry is shared by every
|
|
58
58
|
environment (a write on DEV-1 changes production agents too).
|
|
59
59
|
|
|
60
|
-
**Tier A is the smaller set:** every `delete` (across all resources
|
|
60
|
+
**Tier A is the smaller set:** every `delete` (across all resources, except
|
|
61
|
+
`agents schedules delete`: one schedule row, which `create` restores, though
|
|
62
|
+
the restored row runs as whoever re-creates it), plus
|
|
61
63
|
`workflow`/`mec workflow` `archive` (and its `delete` alias), `process delete`,
|
|
62
64
|
`step delete`, `task delete`; `forecast scenarios bulk-edit`; `cash rules
|
|
63
65
|
delete-all`; `filebox archive` and `filebox data-query clear`;
|