@datarails-ai/dr-cli 1.6.180 → 1.6.182
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 +10 -8
- package/dist/cli.js +812 -119
- package/dist/scopes-map.json +33 -1
- package/dist/skills/dr-cli/SKILL.md +1 -0
- package/dist/skills/dr-cli/reference/calcmodels.md +54 -0
- package/dist/skills/dr-cli/reference/safety.md +4 -0
- package/package.json +2 -2
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.182",
|
|
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.58",
|
|
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-01T16:01:03.304Z";
|
|
73
73
|
function formatBuildTime(iso) {
|
|
74
74
|
if (iso === "") return "";
|
|
75
75
|
const d = new Date(iso);
|
|
@@ -1410,11 +1410,11 @@ function exchangeForSession(store, serverKey, email, session, host, opts) {
|
|
|
1410
1410
|
if (err.throttled && cachedIsUsable) return session;
|
|
1411
1411
|
if (err.transient) {
|
|
1412
1412
|
if (cachedIsUsable) return session;
|
|
1413
|
-
const
|
|
1414
|
-
if (
|
|
1413
|
+
const delay2 = API_KEY_EXCHANGE_RETRY_DELAYS_MS[attempt];
|
|
1414
|
+
if (delay2 !== void 0) {
|
|
1415
1415
|
attempt += 1;
|
|
1416
1416
|
try {
|
|
1417
|
-
await sleep(
|
|
1417
|
+
await sleep(delay2, void 0, { signal });
|
|
1418
1418
|
} catch {
|
|
1419
1419
|
throw new SessionExpiredError(
|
|
1420
1420
|
`${identity2} (api-key exchange ended before its retry)`
|
|
@@ -4438,6 +4438,13 @@ var PROD_GATE_TIER_A = /* @__PURE__ */ new Set([
|
|
|
4438
4438
|
"category|delete",
|
|
4439
4439
|
// calc-models
|
|
4440
4440
|
"calcmodel|delete",
|
|
4441
|
+
// dr calcmodels agent approve — activates an AGENT model's newest version and starts its
|
|
4442
|
+
// first production run, which writes new rows into a table that reports read. Unlike
|
|
4443
|
+
// `set-flow` / `recalculate` (Tier B), which re-run a model already approved, this puts
|
|
4444
|
+
// numbers nobody has run before into production, so a person confirms it. The plan
|
|
4445
|
+
// prints the version and its impact (rows, pool, allocated, coverage); the token binds
|
|
4446
|
+
// that version.
|
|
4447
|
+
"calcmodel|approve",
|
|
4441
4448
|
// filebox
|
|
4442
4449
|
"filebox|archive",
|
|
4443
4450
|
"filebox-data-query|clear",
|
|
@@ -7421,8 +7428,8 @@ async function retryAsync(fn, opts) {
|
|
|
7421
7428
|
const kind = classifyFailure(err);
|
|
7422
7429
|
const retryable = kind === "transient" || kind !== "abort" && opts.alsoRetry?.(err) === true;
|
|
7423
7430
|
if (!retryable || attempt > retries) throw err;
|
|
7424
|
-
const
|
|
7425
|
-
const waitMs = typeof
|
|
7431
|
+
const delay2 = opts.delayMs ?? defaultBackoffMs;
|
|
7432
|
+
const waitMs = typeof delay2 === "function" ? delay2(attempt) : delay2;
|
|
7426
7433
|
opts.onRetry?.(attempt, err, waitMs);
|
|
7427
7434
|
await sleep2(waitMs, opts.signal);
|
|
7428
7435
|
}
|
|
@@ -35556,7 +35563,7 @@ function registerDatamappersCommand(root) {
|
|
|
35556
35563
|
});
|
|
35557
35564
|
addServerFlag(customFnsCmd);
|
|
35558
35565
|
addAccountFlag(customFnsCmd);
|
|
35559
|
-
const
|
|
35566
|
+
const previewCmd2 = dm.command("preview").description(
|
|
35560
35567
|
"Render a mapper config's projected output for a sample input. Posts to `POST /api/templates/preview-data` with the operator-supplied JSON (typically built from a saved mapper config + template_id + document_version + datamapper_id). Output is the server's `{output: {header, projected_config, \u2026}, err}` envelope, emitted as JSON."
|
|
35561
35568
|
).requiredOption("--payload-file <path>", "Path to a JSON body for the preview request").option(
|
|
35562
35569
|
"--json",
|
|
@@ -35576,8 +35583,8 @@ function registerDatamappersCommand(root) {
|
|
|
35576
35583
|
setup.cleanup();
|
|
35577
35584
|
}
|
|
35578
35585
|
});
|
|
35579
|
-
addServerFlag(
|
|
35580
|
-
addAccountFlag(
|
|
35586
|
+
addServerFlag(previewCmd2);
|
|
35587
|
+
addAccountFlag(previewCmd2);
|
|
35581
35588
|
const bindCmd = dm.command("bind").description(
|
|
35582
35589
|
"Update which document IDs a mapper is bound to. The --doc list replaces the mapper's current documents; repeat every filebox you want to keep (dr warns first and names any it drops). Posts to `POST /api/templates/mappers/<id>/binding` with `{selected_document_ids, rescan?}`. The legacy webclient's \"Mapping table with documents\" modal calls this when the operator checks/unchecks docs in the binding picker. Warns first when another mapper of the table on the same ordinal is bound to one of those docs: mappers that share an ordinal are versions of one mapper, so the bind unbinds the other."
|
|
35583
35590
|
).argument("<mapper_id>", "mapper id (positive integer)").option("--doc <id>", "Document id to bind (positive integer; repeatable)", collectInts, []).option(
|
|
@@ -43482,7 +43489,7 @@ function registerFileboxCommand(root) {
|
|
|
43482
43489
|
});
|
|
43483
43490
|
addServerFlag(sheetsCmd);
|
|
43484
43491
|
addAccountFlag(sheetsCmd);
|
|
43485
|
-
const
|
|
43492
|
+
const previewCmd2 = fb.command("preview").description("Preview raw cell data of a filebox version (row 1 is headers)").argument("<version_id>", "version id (positive integer)").option("--sheet <name>", "Sheet name. Defaults to first sheet from /desc.", "").option("--sheet-ind <n>", "Sheet index (0-based). Defaults to 0.", "0").option("--start <n>", "First row to read (1-based)", "1").option("--rows <n>", "Number of rows to return (start..start+rows-1)", "100").option("--data-only", "Return evaluated values only; omit raw formulas", false).option("--json", "Output raw JSON instead of a table", false).action(
|
|
43486
43493
|
async (vidStr, opts) => {
|
|
43487
43494
|
const versionId = parseVersionIdArg2(vidStr);
|
|
43488
43495
|
const sheetInd = parsePositiveIntFlag2(opts.sheetInd, "--sheet-ind", 0);
|
|
@@ -43507,8 +43514,8 @@ function registerFileboxCommand(root) {
|
|
|
43507
43514
|
}
|
|
43508
43515
|
}
|
|
43509
43516
|
);
|
|
43510
|
-
addServerFlag(
|
|
43511
|
-
addAccountFlag(
|
|
43517
|
+
addServerFlag(previewCmd2);
|
|
43518
|
+
addAccountFlag(previewCmd2);
|
|
43512
43519
|
const createCmd = fb.command("create").description(
|
|
43513
43520
|
"Create an empty filebox (no file yet). Resolves the date tag config from /versions/tags. Pass --folder to create a folder filebox instead (no date tag, no version, no data \u2014 used to mirror the org-bootstrap hierarchy of Actuals / COA / FX Rates / Configuration)."
|
|
43514
43521
|
).option("--name <name>", "Filebox display name (required)", "").option("--scenario <s>", `Scenario: ${VALID_SCENARIOS_HELP}`, "Actuals").option(
|
|
@@ -47006,10 +47013,10 @@ function toControlPlaneError(method, path13, err) {
|
|
|
47006
47013
|
}
|
|
47007
47014
|
|
|
47008
47015
|
// src/api/awsConnections.ts
|
|
47009
|
-
async function call(method, path13,
|
|
47016
|
+
async function call(method, path13, send2, what) {
|
|
47010
47017
|
let out;
|
|
47011
47018
|
try {
|
|
47012
|
-
out = await
|
|
47019
|
+
out = await send2();
|
|
47013
47020
|
} catch (err) {
|
|
47014
47021
|
throw toControlPlaneError(method, path13, err);
|
|
47015
47022
|
}
|
|
@@ -48184,10 +48191,10 @@ import { readFileSync as readFileSync3 } from "fs";
|
|
|
48184
48191
|
|
|
48185
48192
|
// src/api/scheduledTasks.ts
|
|
48186
48193
|
var BASE2 = "/scheduled-tasks";
|
|
48187
|
-
async function call2(method, path13,
|
|
48194
|
+
async function call2(method, path13, send2, what) {
|
|
48188
48195
|
let out;
|
|
48189
48196
|
try {
|
|
48190
|
-
out = await
|
|
48197
|
+
out = await send2();
|
|
48191
48198
|
} catch (err) {
|
|
48192
48199
|
throw toControlPlaneError(method, path13, err);
|
|
48193
48200
|
}
|
|
@@ -64827,7 +64834,7 @@ function registerCashCommand(root) {
|
|
|
64827
64834
|
|
|
64828
64835
|
// src/commands/update.ts
|
|
64829
64836
|
import { spawn as spawn2 } from "child_process";
|
|
64830
|
-
var REGISTRY = "https://
|
|
64837
|
+
var REGISTRY = "https://registry.npmjs.org";
|
|
64831
64838
|
var PACKAGE = "@datarails-ai/dr-cli";
|
|
64832
64839
|
function spawnInherit(command, args) {
|
|
64833
64840
|
return new Promise((resolve3) => {
|
|
@@ -65487,6 +65494,757 @@ async function remove(client, id, options) {
|
|
|
65487
65494
|
await client.deleteJSON(`/api/templates/${id}/calcmodels`, options);
|
|
65488
65495
|
}
|
|
65489
65496
|
|
|
65497
|
+
// src/commands/calcmodelsAgent.ts
|
|
65498
|
+
import { setTimeout as delay } from "timers/promises";
|
|
65499
|
+
|
|
65500
|
+
// src/types/calcmodelsAgent.ts
|
|
65501
|
+
import { z as z3 } from "zod";
|
|
65502
|
+
var optionalText = z3.string().nullish();
|
|
65503
|
+
var amount = z3.number().nullish();
|
|
65504
|
+
var calcAgentOperationStatusSchema = z3.enum([
|
|
65505
|
+
"PENDING",
|
|
65506
|
+
"RUNNING",
|
|
65507
|
+
"SUCCEEDED",
|
|
65508
|
+
"NO_PROPOSAL",
|
|
65509
|
+
"FAILED"
|
|
65510
|
+
]);
|
|
65511
|
+
var calcAgentGateErrorSchema = z3.object({
|
|
65512
|
+
code: z3.string(),
|
|
65513
|
+
phase: optionalText,
|
|
65514
|
+
segment: optionalText,
|
|
65515
|
+
suggestion: optionalText,
|
|
65516
|
+
detail: optionalText
|
|
65517
|
+
}).passthrough();
|
|
65518
|
+
var calcAgentTurnAcceptedSchema = z3.object({ operation_id: z3.string().uuid(), conversation_id: z3.string().optional() }).passthrough();
|
|
65519
|
+
var coverageSchema = z3.object({
|
|
65520
|
+
pct: amount,
|
|
65521
|
+
pool_total: amount,
|
|
65522
|
+
allocated_total: amount,
|
|
65523
|
+
unallocated_amount: amount,
|
|
65524
|
+
uncovered_group_count: z3.number().nullish()
|
|
65525
|
+
}).passthrough();
|
|
65526
|
+
var balanceCheckSchema = z3.object({ group: z3.string(), net: z3.number(), ok: z3.boolean() }).passthrough();
|
|
65527
|
+
var warningSchema = z3.object({ code: optionalText, message: optionalText }).passthrough();
|
|
65528
|
+
var calcAgentPreviewResultSchema = z3.object({
|
|
65529
|
+
total_count: z3.number().nullish(),
|
|
65530
|
+
coverage: coverageSchema.nullish(),
|
|
65531
|
+
balance_checks: z3.array(balanceCheckSchema).nullish(),
|
|
65532
|
+
warnings: z3.array(warningSchema).nullish()
|
|
65533
|
+
}).passthrough();
|
|
65534
|
+
var calcAgentDefinitionSchema = z3.object({
|
|
65535
|
+
model_type: optionalText,
|
|
65536
|
+
name: optionalText,
|
|
65537
|
+
destination_template_id: z3.number().nullish()
|
|
65538
|
+
}).passthrough();
|
|
65539
|
+
var calcAgentPreviewSchema = z3.object({
|
|
65540
|
+
status: calcAgentOperationStatusSchema,
|
|
65541
|
+
phase: optionalText,
|
|
65542
|
+
conversation_id: optionalText,
|
|
65543
|
+
answer_text: optionalText,
|
|
65544
|
+
changes_summary: optionalText,
|
|
65545
|
+
definition: calcAgentDefinitionSchema.nullish(),
|
|
65546
|
+
error: calcAgentGateErrorSchema.nullish(),
|
|
65547
|
+
result: calcAgentPreviewResultSchema.nullish()
|
|
65548
|
+
}).passthrough();
|
|
65549
|
+
var calcAgentSaveResultSchema = z3.object({ id: z3.number(), name: z3.string(), version_id: z3.number() }).passthrough();
|
|
65550
|
+
var calcAgentImpactSchema = z3.object({
|
|
65551
|
+
total_rows: amount,
|
|
65552
|
+
pool_total: amount,
|
|
65553
|
+
allocated_total: amount,
|
|
65554
|
+
coverage_pct: amount
|
|
65555
|
+
}).passthrough();
|
|
65556
|
+
var calcAgentApprovalPlanSchema = z3.object({ impact: calcAgentImpactSchema, version_id: z3.number() }).passthrough();
|
|
65557
|
+
var calcAgentApproveResultSchema = z3.object({
|
|
65558
|
+
id: z3.number(),
|
|
65559
|
+
name: z3.string(),
|
|
65560
|
+
impact: calcAgentImpactSchema.nullish(),
|
|
65561
|
+
run_id: z3.string().nullish()
|
|
65562
|
+
}).passthrough();
|
|
65563
|
+
|
|
65564
|
+
// src/api/_htmlEntities.ts
|
|
65565
|
+
var ENTITIES2 = {
|
|
65566
|
+
"&": "&",
|
|
65567
|
+
"<": "<",
|
|
65568
|
+
">": ">",
|
|
65569
|
+
""": '"',
|
|
65570
|
+
"'": "'",
|
|
65571
|
+
"'": "'"
|
|
65572
|
+
};
|
|
65573
|
+
var ENTITY_RE2 = /&(?:amp|lt|gt|quot|#x27|#39);/g;
|
|
65574
|
+
function decodeHtmlDeep(value) {
|
|
65575
|
+
if (typeof value === "string") return value.replace(ENTITY_RE2, (m) => ENTITIES2[m] ?? m);
|
|
65576
|
+
if (Array.isArray(value)) return value.map(decodeHtmlDeep);
|
|
65577
|
+
if (value !== null && typeof value === "object") {
|
|
65578
|
+
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, decodeHtmlDeep(v)]));
|
|
65579
|
+
}
|
|
65580
|
+
return value;
|
|
65581
|
+
}
|
|
65582
|
+
|
|
65583
|
+
// src/api/calcmodelsAgent.ts
|
|
65584
|
+
var BASE3 = "/api/templates/calcmodels/agent";
|
|
65585
|
+
var APPROVAL_ACK_REQUIRED = "CALC_APPROVAL_ACK_REQUIRED";
|
|
65586
|
+
var CalcAgentHttpError = class extends Error {
|
|
65587
|
+
status;
|
|
65588
|
+
body;
|
|
65589
|
+
code;
|
|
65590
|
+
constructor(status2, body, message) {
|
|
65591
|
+
super(message);
|
|
65592
|
+
this.name = "CalcAgentHttpError";
|
|
65593
|
+
this.status = status2;
|
|
65594
|
+
this.body = body;
|
|
65595
|
+
const code = isRecord(body) ? body["code"] : void 0;
|
|
65596
|
+
this.code = typeof code === "string" ? code : void 0;
|
|
65597
|
+
}
|
|
65598
|
+
/** A numeric field of the body (`calc_model_id`, `version_id`), or undefined. */
|
|
65599
|
+
numberField(key) {
|
|
65600
|
+
const v = isRecord(this.body) ? this.body[key] : void 0;
|
|
65601
|
+
return typeof v === "number" ? v : void 0;
|
|
65602
|
+
}
|
|
65603
|
+
};
|
|
65604
|
+
var CONTROL_CHARS2 = /[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g;
|
|
65605
|
+
function escapeControlChars(text2) {
|
|
65606
|
+
return text2.replace(
|
|
65607
|
+
CONTROL_CHARS2,
|
|
65608
|
+
(c) => c === "\r" ? "\\r" : `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`
|
|
65609
|
+
);
|
|
65610
|
+
}
|
|
65611
|
+
function isRecord(v) {
|
|
65612
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
65613
|
+
}
|
|
65614
|
+
function textField(body, key) {
|
|
65615
|
+
if (!isRecord(body)) return void 0;
|
|
65616
|
+
const v = body[key];
|
|
65617
|
+
return typeof v === "string" && v !== "" ? v : void 0;
|
|
65618
|
+
}
|
|
65619
|
+
async function send(client, method, path13, payload, options) {
|
|
65620
|
+
const res = await client.do(
|
|
65621
|
+
method,
|
|
65622
|
+
path13,
|
|
65623
|
+
payload === void 0 ? void 0 : JSON.stringify(payload),
|
|
65624
|
+
options
|
|
65625
|
+
);
|
|
65626
|
+
const text2 = await res.text();
|
|
65627
|
+
let body = text2;
|
|
65628
|
+
if (text2 !== "") {
|
|
65629
|
+
try {
|
|
65630
|
+
body = JSON.parse(text2);
|
|
65631
|
+
} catch {
|
|
65632
|
+
body = text2;
|
|
65633
|
+
}
|
|
65634
|
+
}
|
|
65635
|
+
return { status: res.status, body: decodeHtmlDeep(body) };
|
|
65636
|
+
}
|
|
65637
|
+
function describeServerError(body) {
|
|
65638
|
+
if (!isRecord(body)) {
|
|
65639
|
+
const raw2 = typeof body === "string" ? body.trim() : "";
|
|
65640
|
+
return raw2.length > 200 ? `${raw2.slice(0, 200)}\u2026` : raw2;
|
|
65641
|
+
}
|
|
65642
|
+
const code = textField(body, "code");
|
|
65643
|
+
const phase = textField(body, "phase");
|
|
65644
|
+
const parts = [
|
|
65645
|
+
textField(body, "detail"),
|
|
65646
|
+
textField(body, "suggestion"),
|
|
65647
|
+
textField(body, "segment") !== void 0 ? `[${textField(body, "segment")}]` : void 0
|
|
65648
|
+
].filter((p) => p !== void 0);
|
|
65649
|
+
const head = code !== void 0 ? `${code}${phase !== void 0 ? ` (${phase})` : ""}` : "";
|
|
65650
|
+
if (head === "") return parts.join(" \u2014 ");
|
|
65651
|
+
return parts.length > 0 ? `${head}: ${parts.join(" \u2014 ")}` : head;
|
|
65652
|
+
}
|
|
65653
|
+
function httpError(method, path13, answer, hint) {
|
|
65654
|
+
const detail = escapeControlChars(hint ?? describeServerError(answer.body));
|
|
65655
|
+
const tail = detail !== "" ? `: ${detail}` : "";
|
|
65656
|
+
return new CalcAgentHttpError(
|
|
65657
|
+
answer.status,
|
|
65658
|
+
answer.body,
|
|
65659
|
+
`${method} ${path13}: HTTP ${answer.status}${tail}`
|
|
65660
|
+
);
|
|
65661
|
+
}
|
|
65662
|
+
function parse2(schema, method, path13, body) {
|
|
65663
|
+
const out = schema.safeParse(body);
|
|
65664
|
+
if (!out.success) {
|
|
65665
|
+
const issues = out.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
|
|
65666
|
+
throw new Error(`${method} ${path13}: unexpected response from the server (${issues})`);
|
|
65667
|
+
}
|
|
65668
|
+
return out.data;
|
|
65669
|
+
}
|
|
65670
|
+
async function postTurn(client, input, options) {
|
|
65671
|
+
const path13 = `${BASE3}/turns`;
|
|
65672
|
+
const payload = { message: input.message };
|
|
65673
|
+
if (input.conversationId !== void 0) payload["conversation_id"] = input.conversationId;
|
|
65674
|
+
const answer = await send(client, "POST", path13, payload, options);
|
|
65675
|
+
if (answer.status === 202) return parse2(calcAgentTurnAcceptedSchema, "POST", path13, answer.body);
|
|
65676
|
+
if (answer.status === 404 && input.conversationId !== void 0) {
|
|
65677
|
+
throw httpError(
|
|
65678
|
+
"POST",
|
|
65679
|
+
path13,
|
|
65680
|
+
answer,
|
|
65681
|
+
`conversation ${input.conversationId} not found (only the user who started it can continue it)`
|
|
65682
|
+
);
|
|
65683
|
+
}
|
|
65684
|
+
throw httpError("POST", path13, answer);
|
|
65685
|
+
}
|
|
65686
|
+
async function getPreview2(client, operationId, options) {
|
|
65687
|
+
const path13 = `${BASE3}/preview/${encodeURIComponent(operationId)}`;
|
|
65688
|
+
const answer = await send(client, "GET", path13, void 0, options);
|
|
65689
|
+
if (answer.status === 200) return parse2(calcAgentPreviewSchema, "GET", path13, answer.body);
|
|
65690
|
+
if (answer.status === 404) {
|
|
65691
|
+
throw httpError(
|
|
65692
|
+
"GET",
|
|
65693
|
+
path13,
|
|
65694
|
+
answer,
|
|
65695
|
+
`operation ${operationId} not found (only the user who started the turn can read it)`
|
|
65696
|
+
);
|
|
65697
|
+
}
|
|
65698
|
+
throw httpError("GET", path13, answer);
|
|
65699
|
+
}
|
|
65700
|
+
async function save2(client, input, options) {
|
|
65701
|
+
const payload = {
|
|
65702
|
+
preview_operation_id: input.operationId,
|
|
65703
|
+
name: input.name
|
|
65704
|
+
};
|
|
65705
|
+
if (input.calcModelId !== void 0) payload["calc_model_id"] = input.calcModelId;
|
|
65706
|
+
const answer = await send(client, "POST", BASE3, payload, options);
|
|
65707
|
+
if (answer.status === 201) return parse2(calcAgentSaveResultSchema, "POST", BASE3, answer.body);
|
|
65708
|
+
throw httpError("POST", BASE3, answer);
|
|
65709
|
+
}
|
|
65710
|
+
async function requestApprovalImpact(client, calcModelId, options) {
|
|
65711
|
+
const path13 = `${BASE3}/${calcModelId}/approve`;
|
|
65712
|
+
const answer = await send(client, "POST", path13, {}, options);
|
|
65713
|
+
if (answer.status >= 200 && answer.status < 300) {
|
|
65714
|
+
throw new Error(
|
|
65715
|
+
`POST ${path13}: HTTP ${answer.status} to a request without an acknowledgment; expected ${APPROVAL_ACK_REQUIRED}. Check the model with \`dr calcmodels get ${calcModelId}\`.`
|
|
65716
|
+
);
|
|
65717
|
+
}
|
|
65718
|
+
if (answer.status === 400 && textField(answer.body, "code") === APPROVAL_ACK_REQUIRED) {
|
|
65719
|
+
return parse2(calcAgentApprovalPlanSchema, "POST", path13, answer.body);
|
|
65720
|
+
}
|
|
65721
|
+
throw httpError("POST", path13, answer);
|
|
65722
|
+
}
|
|
65723
|
+
async function confirmApproval(client, calcModelId, versionId, options) {
|
|
65724
|
+
const path13 = `${BASE3}/${calcModelId}/approve`;
|
|
65725
|
+
const answer = await send(
|
|
65726
|
+
client,
|
|
65727
|
+
"POST",
|
|
65728
|
+
path13,
|
|
65729
|
+
{ acknowledged: true, version_id: versionId },
|
|
65730
|
+
options
|
|
65731
|
+
);
|
|
65732
|
+
if (answer.status === 200) return parse2(calcAgentApproveResultSchema, "POST", path13, answer.body);
|
|
65733
|
+
throw httpError("POST", path13, answer);
|
|
65734
|
+
}
|
|
65735
|
+
|
|
65736
|
+
// src/commands/_agentCli.ts
|
|
65737
|
+
import { access } from "fs/promises";
|
|
65738
|
+
var JSON_HELP = "Emit raw JSON to stdout instead of a pretty render.";
|
|
65739
|
+
var CONFIRM_HELP = "Token from a prior plan run \u2014 required to actually write";
|
|
65740
|
+
function withTarget(cmd) {
|
|
65741
|
+
addServerFlag(cmd);
|
|
65742
|
+
addAccountFlag(cmd);
|
|
65743
|
+
return cmd;
|
|
65744
|
+
}
|
|
65745
|
+
function std() {
|
|
65746
|
+
return { out: process.stdout, err: process.stderr };
|
|
65747
|
+
}
|
|
65748
|
+
function requireId(value, placeholder) {
|
|
65749
|
+
const id = (value ?? "").trim();
|
|
65750
|
+
if (id === "") {
|
|
65751
|
+
throw new Error(`missing required option: --id ${placeholder}`);
|
|
65752
|
+
}
|
|
65753
|
+
return id;
|
|
65754
|
+
}
|
|
65755
|
+
function requirePositiveInt(value, flag) {
|
|
65756
|
+
const n = /^\d+$/.test(value) ? Number(value) : NaN;
|
|
65757
|
+
if (!Number.isSafeInteger(n) || n <= 0) {
|
|
65758
|
+
throw new Error(`${flag} ${JSON.stringify(value)}: expected a positive integer`);
|
|
65759
|
+
}
|
|
65760
|
+
return n;
|
|
65761
|
+
}
|
|
65762
|
+
function requireBool(value, flag) {
|
|
65763
|
+
if (value === "true") return true;
|
|
65764
|
+
if (value === "false") return false;
|
|
65765
|
+
throw new Error(`${flag} ${JSON.stringify(value ?? "")}: expected true or false`);
|
|
65766
|
+
}
|
|
65767
|
+
function splitList(value) {
|
|
65768
|
+
return [
|
|
65769
|
+
...new Set(
|
|
65770
|
+
(value ?? "").split(",").map((part) => part.trim()).filter((part) => part !== "")
|
|
65771
|
+
)
|
|
65772
|
+
];
|
|
65773
|
+
}
|
|
65774
|
+
function isNoneSentinel(parts, flag, value, what) {
|
|
65775
|
+
if (!parts.includes("none")) return false;
|
|
65776
|
+
if (parts.length === 1) return true;
|
|
65777
|
+
throw new Error(`${flag} ${JSON.stringify(value)}: "none" cannot be combined with ${what}`);
|
|
65778
|
+
}
|
|
65779
|
+
function shellArg(value) {
|
|
65780
|
+
return /^[A-Za-z0-9_@%+=:,./-]+$/.test(value) ? value : shellQuote(value);
|
|
65781
|
+
}
|
|
65782
|
+
function proseStream(cfg) {
|
|
65783
|
+
return cfg.asJson ? cfg.err : cfg.out;
|
|
65784
|
+
}
|
|
65785
|
+
async function assertNoOverwrite(paths, force) {
|
|
65786
|
+
if (force) return;
|
|
65787
|
+
const existing = [];
|
|
65788
|
+
for (const path13 of paths) {
|
|
65789
|
+
try {
|
|
65790
|
+
await access(path13);
|
|
65791
|
+
existing.push(path13);
|
|
65792
|
+
} catch {
|
|
65793
|
+
}
|
|
65794
|
+
}
|
|
65795
|
+
if (existing.length > 0) {
|
|
65796
|
+
throw new Error(
|
|
65797
|
+
`refusing to overwrite existing file(s): ${existing.join(", ")}. Pull into another --dir, or pass --force to replace them.`
|
|
65798
|
+
);
|
|
65799
|
+
}
|
|
65800
|
+
}
|
|
65801
|
+
|
|
65802
|
+
// src/commands/calcmodelsAgent.ts
|
|
65803
|
+
var AGENT_POLL_INTERVAL_MS = 3e3;
|
|
65804
|
+
var AGENT_DEFAULT_TIMEOUT_S = 900;
|
|
65805
|
+
var MAX_TRANSIENT_READ_FAILURES = 5;
|
|
65806
|
+
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
65807
|
+
function parseOperationIdArg(raw2) {
|
|
65808
|
+
if (!UUID_RE2.test(raw2)) throw new Error(`invalid operation id: "${raw2}" (expected a UUID)`);
|
|
65809
|
+
return raw2.toLowerCase();
|
|
65810
|
+
}
|
|
65811
|
+
function isLive(p) {
|
|
65812
|
+
return p.status === "PENDING" || p.status === "RUNNING";
|
|
65813
|
+
}
|
|
65814
|
+
function formatNumber(n) {
|
|
65815
|
+
return n === null || n === void 0 ? "n/a" : n.toLocaleString("en-US", { maximumFractionDigits: 2 });
|
|
65816
|
+
}
|
|
65817
|
+
function previewLine(result) {
|
|
65818
|
+
const parts = [`${formatNumber(result.total_count)} rows`];
|
|
65819
|
+
const cov = result.coverage;
|
|
65820
|
+
if (cov) {
|
|
65821
|
+
const pct2 = cov.pct === null || cov.pct === void 0 ? "n/a" : `${formatNumber(cov.pct)}%`;
|
|
65822
|
+
parts.push(
|
|
65823
|
+
`coverage ${pct2} (allocated ${formatNumber(cov.allocated_total)} of pool ${formatNumber(cov.pool_total)})`
|
|
65824
|
+
);
|
|
65825
|
+
}
|
|
65826
|
+
const checks = result.balance_checks ?? [];
|
|
65827
|
+
if (checks.length > 0) {
|
|
65828
|
+
const ok = checks.filter((c) => c.ok).length;
|
|
65829
|
+
parts.push(`balance: ${ok} of ${checks.length} groups net to zero`);
|
|
65830
|
+
}
|
|
65831
|
+
return `preview: ${parts.join(" \xB7 ")}`;
|
|
65832
|
+
}
|
|
65833
|
+
function targetFlags(serverFlag, accountFlag) {
|
|
65834
|
+
return accountFlag === void 0 ? `--server ${serverFlag}` : `--server ${serverFlag} --account ${shellQuote(accountFlag)}`;
|
|
65835
|
+
}
|
|
65836
|
+
function previewCmd(operationId, target) {
|
|
65837
|
+
return `dr calcmodels agent preview ${operationId} ${target}`;
|
|
65838
|
+
}
|
|
65839
|
+
function renderPreview(out, p, operationId, target) {
|
|
65840
|
+
out.write(`status: ${p.status}
|
|
65841
|
+
`);
|
|
65842
|
+
if (p.conversation_id) out.write(`conversation: ${escapeControlChars(p.conversation_id)}
|
|
65843
|
+
`);
|
|
65844
|
+
if (isLive(p)) {
|
|
65845
|
+
out.write(
|
|
65846
|
+
`
|
|
65847
|
+
The turn is still running. Check again with:
|
|
65848
|
+
${previewCmd(operationId, target)}
|
|
65849
|
+
`
|
|
65850
|
+
);
|
|
65851
|
+
return;
|
|
65852
|
+
}
|
|
65853
|
+
if (p.answer_text) out.write(`
|
|
65854
|
+
${escapeControlChars(p.answer_text.trim())}
|
|
65855
|
+
`);
|
|
65856
|
+
if (p.changes_summary) {
|
|
65857
|
+
out.write("\nchanges:\n");
|
|
65858
|
+
for (const line of p.changes_summary.trim().split("\n"))
|
|
65859
|
+
out.write(` ${escapeControlChars(line)}
|
|
65860
|
+
`);
|
|
65861
|
+
}
|
|
65862
|
+
const savable = p.status === "SUCCEEDED" && p.result !== null && p.result !== void 0;
|
|
65863
|
+
if (p.status === "SUCCEEDED") {
|
|
65864
|
+
const d = p.definition;
|
|
65865
|
+
if (d) {
|
|
65866
|
+
out.write(
|
|
65867
|
+
`
|
|
65868
|
+
proposal: ${escapeControlChars(JSON.stringify(d.name ?? ""))} (${escapeControlChars(d.model_type ?? "unknown")}) \u2192 destination table ${d.destination_template_id ?? "n/a"}
|
|
65869
|
+
`
|
|
65870
|
+
);
|
|
65871
|
+
}
|
|
65872
|
+
if (p.result) {
|
|
65873
|
+
out.write(`${previewLine(p.result)}
|
|
65874
|
+
`);
|
|
65875
|
+
for (const w of p.result.warnings ?? []) {
|
|
65876
|
+
const label = [w.code, w.message].filter((s) => !!s).join(": ");
|
|
65877
|
+
if (label !== "") out.write(`warning: ${escapeControlChars(label)}
|
|
65878
|
+
`);
|
|
65879
|
+
}
|
|
65880
|
+
} else {
|
|
65881
|
+
out.write(
|
|
65882
|
+
"preview: none ran. The server saves only a turn whose preview ran (CALC_PREVIEW_NOT_READY).\n"
|
|
65883
|
+
);
|
|
65884
|
+
}
|
|
65885
|
+
}
|
|
65886
|
+
const next = [];
|
|
65887
|
+
if (savable) {
|
|
65888
|
+
next.push(`save the draft: dr calcmodels agent save ${operationId} ${target}`);
|
|
65889
|
+
}
|
|
65890
|
+
if (p.conversation_id) {
|
|
65891
|
+
next.push(
|
|
65892
|
+
`reply: dr calcmodels agent ask '<reply>' --conversation ${shellQuote(p.conversation_id)} ${target}`
|
|
65893
|
+
);
|
|
65894
|
+
}
|
|
65895
|
+
if (next.length > 0) out.write(`
|
|
65896
|
+
next:
|
|
65897
|
+
${next.map((l) => ` ${l}
|
|
65898
|
+
`).join("")}`);
|
|
65899
|
+
}
|
|
65900
|
+
function writeOutcome(out, p, operationId, target, asJson) {
|
|
65901
|
+
if (asJson) writeJSONIndented(out, { operation_id: operationId, ...p });
|
|
65902
|
+
else renderPreview(out, p, operationId, target);
|
|
65903
|
+
if (p.status === "FAILED") {
|
|
65904
|
+
const why = p.error ? escapeControlChars(describeServerError(p.error)) : "the server gave no error detail";
|
|
65905
|
+
throw new Error(`turn ${operationId} failed: ${why}`);
|
|
65906
|
+
}
|
|
65907
|
+
}
|
|
65908
|
+
var ReadTimeoutError = class extends Error {
|
|
65909
|
+
constructor(operationId, ms) {
|
|
65910
|
+
super(`reading operation ${operationId} took longer than ${ms} ms`);
|
|
65911
|
+
this.name = "ReadTimeoutError";
|
|
65912
|
+
}
|
|
65913
|
+
};
|
|
65914
|
+
function isTransient(err) {
|
|
65915
|
+
if (err instanceof ReadTimeoutError) return true;
|
|
65916
|
+
if (err instanceof CalcAgentHttpError) return err.status >= 500;
|
|
65917
|
+
return err instanceof TypeError;
|
|
65918
|
+
}
|
|
65919
|
+
var AGENT_READ_TIMEOUT_MS = 3e4;
|
|
65920
|
+
var AGENT_READ_TIMEOUT_FLOOR_MS = 5e3;
|
|
65921
|
+
var defaultSleep8 = (ms, signal) => delay(ms, void 0, { signal });
|
|
65922
|
+
async function runAgentAsk(cfg) {
|
|
65923
|
+
const accepted = await postTurn(
|
|
65924
|
+
cfg.client,
|
|
65925
|
+
{
|
|
65926
|
+
message: cfg.message,
|
|
65927
|
+
...cfg.conversationId !== void 0 && { conversationId: cfg.conversationId }
|
|
65928
|
+
},
|
|
65929
|
+
{ signal: cfg.signal }
|
|
65930
|
+
);
|
|
65931
|
+
const op = accepted.operation_id;
|
|
65932
|
+
const conv = accepted.conversation_id;
|
|
65933
|
+
const target = targetFlags(cfg.serverFlag, cfg.accountFlag);
|
|
65934
|
+
cfg.err.write(
|
|
65935
|
+
`turn started: operation ${op}${conv ? `, conversation ${escapeControlChars(conv)}` : ""}
|
|
65936
|
+
`
|
|
65937
|
+
);
|
|
65938
|
+
if (!cfg.wait) {
|
|
65939
|
+
if (cfg.asJson) {
|
|
65940
|
+
writeJSONIndented(cfg.out, accepted);
|
|
65941
|
+
return;
|
|
65942
|
+
}
|
|
65943
|
+
cfg.out.write(`operation: ${op}
|
|
65944
|
+
Read it with:
|
|
65945
|
+
${previewCmd(op, target)}
|
|
65946
|
+
`);
|
|
65947
|
+
return;
|
|
65948
|
+
}
|
|
65949
|
+
cfg.err.write(
|
|
65950
|
+
`Waiting for the agent. Ctrl-C stops the wait, not the turn; resume with:
|
|
65951
|
+
${previewCmd(op, target)}
|
|
65952
|
+
`
|
|
65953
|
+
);
|
|
65954
|
+
const preview2 = await pollPreview(cfg, op);
|
|
65955
|
+
writeOutcome(cfg.out, preview2, op, target, cfg.asJson);
|
|
65956
|
+
}
|
|
65957
|
+
async function pollPreview(cfg, operationId) {
|
|
65958
|
+
const interval = cfg.pollIntervalMs ?? AGENT_POLL_INTERVAL_MS;
|
|
65959
|
+
const sleep3 = cfg.sleep ?? defaultSleep8;
|
|
65960
|
+
const now = cfg.now ?? Date.now;
|
|
65961
|
+
const deadline = now() + cfg.timeoutMs;
|
|
65962
|
+
const readMax = cfg.readTimeoutMs ?? AGENT_READ_TIMEOUT_MS;
|
|
65963
|
+
const readFloor = cfg.readTimeoutFloorMs ?? AGENT_READ_TIMEOUT_FLOOR_MS;
|
|
65964
|
+
let failures = 0;
|
|
65965
|
+
for (; ; ) {
|
|
65966
|
+
await sleep3(Math.max(0, Math.min(interval, deadline - now())), cfg.signal);
|
|
65967
|
+
try {
|
|
65968
|
+
const budget = Math.min(readMax, Math.max(deadline - now(), readFloor));
|
|
65969
|
+
const p = await readWithin(cfg, operationId, budget);
|
|
65970
|
+
failures = 0;
|
|
65971
|
+
if (!isLive(p)) return p;
|
|
65972
|
+
} catch (err) {
|
|
65973
|
+
failures += 1;
|
|
65974
|
+
if (!isTransient(err)) throw err;
|
|
65975
|
+
if (failures > MAX_TRANSIENT_READ_FAILURES && now() < deadline) throw err;
|
|
65976
|
+
}
|
|
65977
|
+
if (now() >= deadline) {
|
|
65978
|
+
throw new Error(
|
|
65979
|
+
`turn ${operationId} is still running after ${Math.round(cfg.timeoutMs / 1e3)}s. It keeps running on the server; read it with: ${previewCmd(operationId, targetFlags(cfg.serverFlag, cfg.accountFlag))}`
|
|
65980
|
+
);
|
|
65981
|
+
}
|
|
65982
|
+
}
|
|
65983
|
+
}
|
|
65984
|
+
async function readWithin(cfg, operationId, budgetMs) {
|
|
65985
|
+
const ctl = new AbortController();
|
|
65986
|
+
const relay = () => ctl.abort(cfg.signal.reason);
|
|
65987
|
+
if (cfg.signal.aborted) relay();
|
|
65988
|
+
else cfg.signal.addEventListener("abort", relay, { once: true });
|
|
65989
|
+
const timer = setTimeout(() => ctl.abort(), budgetMs);
|
|
65990
|
+
try {
|
|
65991
|
+
return await getPreview2(cfg.client, operationId, { signal: ctl.signal });
|
|
65992
|
+
} catch (err) {
|
|
65993
|
+
if (ctl.signal.aborted && !cfg.signal.aborted)
|
|
65994
|
+
throw new ReadTimeoutError(operationId, budgetMs);
|
|
65995
|
+
throw err;
|
|
65996
|
+
} finally {
|
|
65997
|
+
clearTimeout(timer);
|
|
65998
|
+
cfg.signal.removeEventListener("abort", relay);
|
|
65999
|
+
}
|
|
66000
|
+
}
|
|
66001
|
+
async function runAgentPreview(cfg) {
|
|
66002
|
+
const p = await getPreview2(cfg.client, cfg.operationId, { signal: cfg.signal });
|
|
66003
|
+
writeOutcome(
|
|
66004
|
+
cfg.out,
|
|
66005
|
+
p,
|
|
66006
|
+
cfg.operationId,
|
|
66007
|
+
targetFlags(cfg.serverFlag, cfg.accountFlag),
|
|
66008
|
+
cfg.asJson
|
|
66009
|
+
);
|
|
66010
|
+
}
|
|
66011
|
+
var PREVIEW_ALREADY_SAVED = "CALC_PREVIEW_ALREADY_SAVED";
|
|
66012
|
+
var VERSION_CHANGED = "CALC_APPROVAL_VERSION_CHANGED";
|
|
66013
|
+
async function runAgentSave(cfg) {
|
|
66014
|
+
let name = cfg.name;
|
|
66015
|
+
if (name !== void 0 && name.trim() === "") throw new Error("--name must not be empty");
|
|
66016
|
+
if (name === void 0) {
|
|
66017
|
+
const p = await getPreview2(cfg.client, cfg.operationId, { signal: cfg.signal });
|
|
66018
|
+
name = p.definition?.name ?? void 0;
|
|
66019
|
+
if (name === void 0 || name.trim() === "") {
|
|
66020
|
+
throw new Error(
|
|
66021
|
+
`--name is required: operation ${cfg.operationId} has no proposed name (status ${p.status})`
|
|
66022
|
+
);
|
|
66023
|
+
}
|
|
66024
|
+
}
|
|
66025
|
+
let saved;
|
|
66026
|
+
try {
|
|
66027
|
+
saved = await save2(
|
|
66028
|
+
cfg.client,
|
|
66029
|
+
{
|
|
66030
|
+
operationId: cfg.operationId,
|
|
66031
|
+
name,
|
|
66032
|
+
...cfg.calcModelId !== void 0 && { calcModelId: cfg.calcModelId }
|
|
66033
|
+
},
|
|
66034
|
+
{ signal: cfg.signal }
|
|
66035
|
+
);
|
|
66036
|
+
} catch (err) {
|
|
66037
|
+
if (err instanceof CalcAgentHttpError && err.code === PREVIEW_ALREADY_SAVED) {
|
|
66038
|
+
const modelId = err.numberField("calc_model_id");
|
|
66039
|
+
if (modelId !== void 0) {
|
|
66040
|
+
throw new Error(
|
|
66041
|
+
`${err.message}. To add this turn as a new version of model ${modelId}: dr calcmodels agent save ${cfg.operationId} --model ${modelId} ${targetFlags(cfg.serverFlag, cfg.accountFlag)}`,
|
|
66042
|
+
{ cause: err }
|
|
66043
|
+
);
|
|
66044
|
+
}
|
|
66045
|
+
}
|
|
66046
|
+
throw err;
|
|
66047
|
+
}
|
|
66048
|
+
if (cfg.asJson) {
|
|
66049
|
+
writeJSONIndented(cfg.out, saved);
|
|
66050
|
+
return;
|
|
66051
|
+
}
|
|
66052
|
+
cfg.out.write(
|
|
66053
|
+
`Saved draft calc model ${saved.id} ${escapeControlChars(JSON.stringify(saved.name))} (version ${saved.version_id}). This version does not run until it is approved.
|
|
66054
|
+
|
|
66055
|
+
next:
|
|
66056
|
+
dr calcmodels agent approve ${saved.id} ${targetFlags(cfg.serverFlag, cfg.accountFlag)}
|
|
66057
|
+
`
|
|
66058
|
+
);
|
|
66059
|
+
}
|
|
66060
|
+
function approveAction(calcModelId, versionId) {
|
|
66061
|
+
return { resource: "calcmodel", id: `${calcModelId}@v${versionId}`, verb: "approve" };
|
|
66062
|
+
}
|
|
66063
|
+
function versionChanged(calcModelId, planned, current, cause) {
|
|
66064
|
+
const newer = current !== void 0 ? ` (${current})` : "";
|
|
66065
|
+
return new Error(
|
|
66066
|
+
`calc model ${calcModelId}: a newer version${newer} was saved after the plan for version ${planned}. Review it: re-run without --confirm-token. Nothing was activated.`,
|
|
66067
|
+
cause === void 0 ? void 0 : { cause }
|
|
66068
|
+
);
|
|
66069
|
+
}
|
|
66070
|
+
function impactLines(calcModelId, plan) {
|
|
66071
|
+
const i = plan.impact;
|
|
66072
|
+
const pct2 = i.coverage_pct === null || i.coverage_pct === void 0 ? "n/a" : `${formatNumber(i.coverage_pct)}%`;
|
|
66073
|
+
return [
|
|
66074
|
+
`calc model: ${calcModelId}`,
|
|
66075
|
+
`version: ${plan.version_id}`,
|
|
66076
|
+
`rows the first run writes: ${formatNumber(i.total_rows)}`,
|
|
66077
|
+
`allocated total: ${formatNumber(i.allocated_total)} of pool total ${formatNumber(i.pool_total)} (coverage ${pct2})`,
|
|
66078
|
+
"Approving activates this version and starts its first production run at once."
|
|
66079
|
+
];
|
|
66080
|
+
}
|
|
66081
|
+
async function runAgentApprove(cfg) {
|
|
66082
|
+
const executing = cfg.token !== void 0 && cfg.token.trim() !== "";
|
|
66083
|
+
if (executing && cfg.versionId === void 0) {
|
|
66084
|
+
throw new Error(
|
|
66085
|
+
"--version-id is required with --confirm-token: copy the command the plan printed"
|
|
66086
|
+
);
|
|
66087
|
+
}
|
|
66088
|
+
if (executing) await preflightConfirmToken(approveAction(cfg.id, cfg.versionId), cfg.token);
|
|
66089
|
+
const plan = await requestApprovalImpact(cfg.client, cfg.id, { signal: cfg.signal });
|
|
66090
|
+
if (executing && plan.version_id !== cfg.versionId) {
|
|
66091
|
+
throw versionChanged(cfg.id, cfg.versionId, plan.version_id);
|
|
66092
|
+
}
|
|
66093
|
+
const versionId = executing ? cfg.versionId : plan.version_id;
|
|
66094
|
+
const target = targetFlags(cfg.serverFlag, cfg.accountFlag);
|
|
66095
|
+
await twoStepConfirm({
|
|
66096
|
+
out: cfg.out,
|
|
66097
|
+
action: approveAction(cfg.id, versionId),
|
|
66098
|
+
token: cfg.token,
|
|
66099
|
+
server: cfg.serverFlag,
|
|
66100
|
+
confirmCmd: `dr calcmodels agent approve ${cfg.id} --version-id ${versionId} ${target}${cfg.asJson ? " --json" : ""}`,
|
|
66101
|
+
describe: () => Promise.resolve(impactLines(cfg.id, plan)),
|
|
66102
|
+
execute: async () => {
|
|
66103
|
+
let result;
|
|
66104
|
+
try {
|
|
66105
|
+
result = await confirmApproval(cfg.client, cfg.id, versionId, {
|
|
66106
|
+
signal: cfg.signal
|
|
66107
|
+
});
|
|
66108
|
+
} catch (err) {
|
|
66109
|
+
if (err instanceof CalcAgentHttpError && err.code === VERSION_CHANGED) {
|
|
66110
|
+
throw versionChanged(cfg.id, versionId, err.numberField("version_id"), err);
|
|
66111
|
+
}
|
|
66112
|
+
throw err;
|
|
66113
|
+
}
|
|
66114
|
+
if (cfg.asJson) {
|
|
66115
|
+
writeJSONIndented(cfg.out, result);
|
|
66116
|
+
return;
|
|
66117
|
+
}
|
|
66118
|
+
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}.`;
|
|
66119
|
+
cfg.out.write(`Activated calc model ${cfg.id} (version ${versionId}). ${run2}
|
|
66120
|
+
`);
|
|
66121
|
+
}
|
|
66122
|
+
});
|
|
66123
|
+
}
|
|
66124
|
+
var ASK_SETUP_HEADROOM_MS = 6e4;
|
|
66125
|
+
function registerCalcmodelsAgentCommand(cm) {
|
|
66126
|
+
const agent = cm.command("agent").description(
|
|
66127
|
+
"Build an AGENT (allocation) calc model with the builder agent \u2014 the web builder endpoints. Super Admin + the calc_model_agent_builder flag."
|
|
66128
|
+
);
|
|
66129
|
+
const askCmd = agent.command("ask").description(
|
|
66130
|
+
"Send one message to the builder agent and wait for its answer. Ctrl-C stops the wait, not the turn."
|
|
66131
|
+
).argument("<message>", "what to build, or a reply to the agent").option("--conversation <id>", "continue this conversation (from a previous answer)").option("--no-wait", "return after the server accepts the turn; read it with `preview`").option(
|
|
66132
|
+
"--timeout <seconds>",
|
|
66133
|
+
`stop waiting after this long (default ${AGENT_DEFAULT_TIMEOUT_S})`
|
|
66134
|
+
).option("--json", "Output raw JSON", false).action(
|
|
66135
|
+
async (message, opts) => {
|
|
66136
|
+
if (message.trim() === "") throw new Error("<message> must not be empty");
|
|
66137
|
+
const timeoutMs = parsePositiveSecondsFlag(
|
|
66138
|
+
opts.timeout,
|
|
66139
|
+
"--timeout",
|
|
66140
|
+
AGENT_DEFAULT_TIMEOUT_S * 1e3
|
|
66141
|
+
);
|
|
66142
|
+
const serverKey = resolveServer(opts.server);
|
|
66143
|
+
const setup = await setupCall(opts.server, opts.account, {
|
|
66144
|
+
timeoutMs: timeoutMs + ASK_SETUP_HEADROOM_MS
|
|
66145
|
+
});
|
|
66146
|
+
try {
|
|
66147
|
+
await runAgentAsk({
|
|
66148
|
+
client: setup.client,
|
|
66149
|
+
message,
|
|
66150
|
+
...opts.conversation !== void 0 && { conversationId: opts.conversation },
|
|
66151
|
+
wait: opts.wait !== false,
|
|
66152
|
+
timeoutMs,
|
|
66153
|
+
asJson: opts.json === true,
|
|
66154
|
+
serverFlag: serverKey,
|
|
66155
|
+
accountFlag: normaliseAccount(opts.account),
|
|
66156
|
+
signal: setup.signal,
|
|
66157
|
+
out: process.stdout,
|
|
66158
|
+
err: process.stderr
|
|
66159
|
+
});
|
|
66160
|
+
} finally {
|
|
66161
|
+
setup.cleanup();
|
|
66162
|
+
}
|
|
66163
|
+
}
|
|
66164
|
+
);
|
|
66165
|
+
addServerFlag(askCmd);
|
|
66166
|
+
addAccountFlag(askCmd);
|
|
66167
|
+
const previewCmdDef = agent.command("preview").description("Read one turn: the agent's answer, its proposal, and the preview figures").argument("<operation_id>", "the operation id `ask` printed").option("--json", "Output raw JSON", false).action(async (opArg, opts) => {
|
|
66168
|
+
const operationId = parseOperationIdArg(opArg);
|
|
66169
|
+
const serverKey = resolveServer(opts.server);
|
|
66170
|
+
const setup = await setupCall(opts.server, opts.account);
|
|
66171
|
+
try {
|
|
66172
|
+
await runAgentPreview({
|
|
66173
|
+
client: setup.client,
|
|
66174
|
+
operationId,
|
|
66175
|
+
asJson: opts.json === true,
|
|
66176
|
+
serverFlag: serverKey,
|
|
66177
|
+
accountFlag: normaliseAccount(opts.account),
|
|
66178
|
+
signal: setup.signal,
|
|
66179
|
+
out: process.stdout
|
|
66180
|
+
});
|
|
66181
|
+
} finally {
|
|
66182
|
+
setup.cleanup();
|
|
66183
|
+
}
|
|
66184
|
+
});
|
|
66185
|
+
addServerFlag(previewCmdDef);
|
|
66186
|
+
addAccountFlag(previewCmdDef);
|
|
66187
|
+
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) => {
|
|
66188
|
+
const operationId = parseOperationIdArg(opArg);
|
|
66189
|
+
const calcModelId = opts.model === void 0 ? void 0 : requirePositiveInt(opts.model, "--model");
|
|
66190
|
+
const serverKey = resolveServer(opts.server);
|
|
66191
|
+
const setup = await setupCall(opts.server, opts.account);
|
|
66192
|
+
try {
|
|
66193
|
+
await runAgentSave({
|
|
66194
|
+
client: setup.client,
|
|
66195
|
+
operationId,
|
|
66196
|
+
...opts.name !== void 0 && { name: opts.name },
|
|
66197
|
+
...calcModelId !== void 0 && { calcModelId },
|
|
66198
|
+
asJson: opts.json === true,
|
|
66199
|
+
serverFlag: serverKey,
|
|
66200
|
+
accountFlag: normaliseAccount(opts.account),
|
|
66201
|
+
signal: setup.signal,
|
|
66202
|
+
out: process.stdout
|
|
66203
|
+
});
|
|
66204
|
+
} finally {
|
|
66205
|
+
setup.cleanup();
|
|
66206
|
+
}
|
|
66207
|
+
});
|
|
66208
|
+
addServerFlag(saveCmd);
|
|
66209
|
+
addAccountFlag(saveCmd);
|
|
66210
|
+
const approveCmd = agent.command("approve").description(
|
|
66211
|
+
"Activate an AGENT model's newest version and start its first production run (two-step confirm; a person confirms on production)."
|
|
66212
|
+
).argument("<calc_model_id>", "the model id `save` printed").option("--version-id <n>", "the version the plan showed (required with --confirm-token)").option("--confirm-token <token>", "Token from a prior plan run \u2014 required to activate", "").option("--json", "Output raw JSON of the activation", false).action(
|
|
66213
|
+
async (idArg, opts) => {
|
|
66214
|
+
const id = requirePositiveInt(idArg, "<calc_model_id>");
|
|
66215
|
+
const versionId = opts.versionId === void 0 ? void 0 : requirePositiveInt(opts.versionId, "--version-id");
|
|
66216
|
+
const token = opts.confirmToken;
|
|
66217
|
+
if (token !== void 0 && token.trim() !== "") {
|
|
66218
|
+
if (versionId === void 0) {
|
|
66219
|
+
throw new Error(
|
|
66220
|
+
"--version-id is required with --confirm-token: copy the command the plan printed"
|
|
66221
|
+
);
|
|
66222
|
+
}
|
|
66223
|
+
await preflightConfirmToken(approveAction(id, versionId), token);
|
|
66224
|
+
}
|
|
66225
|
+
const serverKey = resolveServer(opts.server);
|
|
66226
|
+
const setup = await setupCall(opts.server, opts.account);
|
|
66227
|
+
try {
|
|
66228
|
+
await runAgentApprove({
|
|
66229
|
+
client: setup.client,
|
|
66230
|
+
id,
|
|
66231
|
+
...versionId !== void 0 && { versionId },
|
|
66232
|
+
token,
|
|
66233
|
+
asJson: opts.json === true,
|
|
66234
|
+
serverFlag: serverKey,
|
|
66235
|
+
accountFlag: normaliseAccount(opts.account),
|
|
66236
|
+
signal: setup.signal,
|
|
66237
|
+
out: process.stdout
|
|
66238
|
+
});
|
|
66239
|
+
} finally {
|
|
66240
|
+
setup.cleanup();
|
|
66241
|
+
}
|
|
66242
|
+
}
|
|
66243
|
+
);
|
|
66244
|
+
addServerFlag(approveCmd);
|
|
66245
|
+
addAccountFlag(approveCmd);
|
|
66246
|
+
}
|
|
66247
|
+
|
|
65490
66248
|
// src/commands/calcmodels.ts
|
|
65491
66249
|
async function runCalcmodelsList(cfg) {
|
|
65492
66250
|
const models = await list25(cfg.client, { signal: cfg.signal });
|
|
@@ -65891,6 +66649,7 @@ function registerCalcmodelsCommand(root) {
|
|
|
65891
66649
|
});
|
|
65892
66650
|
addServerFlag(deleteCmd);
|
|
65893
66651
|
addAccountFlag(deleteCmd);
|
|
66652
|
+
registerCalcmodelsAgentCommand(cm);
|
|
65894
66653
|
}
|
|
65895
66654
|
|
|
65896
66655
|
// src/commands/calcVals.ts
|
|
@@ -68875,13 +69634,13 @@ import { promises as fsPromises3 } from "fs";
|
|
|
68875
69634
|
import * as nodePath3 from "path";
|
|
68876
69635
|
|
|
68877
69636
|
// src/api/spendControl.ts
|
|
68878
|
-
var
|
|
69637
|
+
var BASE4 = "/api/spend-control/v1";
|
|
68879
69638
|
var BASE_V2 = "/api/spend-control/v2";
|
|
68880
69639
|
var MAX_BULK_STATUS_IDS = 50;
|
|
68881
69640
|
var MAX_PAGE_SIZE = 100;
|
|
68882
69641
|
async function listBillingFrequencies(client, options) {
|
|
68883
69642
|
const out = await client.getJSON(
|
|
68884
|
-
`${
|
|
69643
|
+
`${BASE4}/catalogs/billing-frequencies/`,
|
|
68885
69644
|
options
|
|
68886
69645
|
);
|
|
68887
69646
|
return out ?? [];
|
|
@@ -68915,7 +69674,7 @@ function buildContractListQuery(params) {
|
|
|
68915
69674
|
}
|
|
68916
69675
|
async function listContracts(client, params = {}, options) {
|
|
68917
69676
|
const qs = buildContractListQuery(params);
|
|
68918
|
-
const path13 = qs === "" ? `${
|
|
69677
|
+
const path13 = qs === "" ? `${BASE4}/contracts/` : `${BASE4}/contracts/?${qs}`;
|
|
68919
69678
|
const out = await client.getJSON(path13, options);
|
|
68920
69679
|
if (out === null) {
|
|
68921
69680
|
return { items: [], total: 0, page: null, size: null, pages: null };
|
|
@@ -68943,10 +69702,10 @@ async function getContract(client, contractId, params = {}, options) {
|
|
|
68943
69702
|
qs.set("currency_code", params.convertTo);
|
|
68944
69703
|
}
|
|
68945
69704
|
const suffix = qs.toString() === "" ? "" : `?${qs.toString()}`;
|
|
68946
|
-
return client.getJSON(`${
|
|
69705
|
+
return client.getJSON(`${BASE4}/contracts/${contractId}${suffix}`, options);
|
|
68947
69706
|
}
|
|
68948
69707
|
async function deleteContract(client, contractId, options) {
|
|
68949
|
-
await client.deleteJSON(`${
|
|
69708
|
+
await client.deleteJSON(`${BASE4}/contracts/${contractId}`, options);
|
|
68950
69709
|
}
|
|
68951
69710
|
async function uploadFilesWithAi(client, files, options = {}) {
|
|
68952
69711
|
if (files.length === 0) return [];
|
|
@@ -68954,7 +69713,7 @@ async function uploadFilesWithAi(client, files, options = {}) {
|
|
|
68954
69713
|
throw new Error(`uploadFilesWithAi: max 10 files per call, got ${files.length}`);
|
|
68955
69714
|
}
|
|
68956
69715
|
const out = await client.postMultipartFiles(
|
|
68957
|
-
`${
|
|
69716
|
+
`${BASE4}/contracts/files-with-ai`,
|
|
68958
69717
|
{ is_additional: options.isAdditional === true ? "true" : "false" },
|
|
68959
69718
|
files,
|
|
68960
69719
|
"files",
|
|
@@ -68964,7 +69723,7 @@ async function uploadFilesWithAi(client, files, options = {}) {
|
|
|
68964
69723
|
}
|
|
68965
69724
|
async function uploadContractFile(client, file, options = {}) {
|
|
68966
69725
|
return client.postMultipartFiles(
|
|
68967
|
-
`${
|
|
69726
|
+
`${BASE4}/contracts/file`,
|
|
68968
69727
|
{ is_additional: options.isAdditional === true ? "true" : "false" },
|
|
68969
69728
|
[file],
|
|
68970
69729
|
"file",
|
|
@@ -68977,7 +69736,7 @@ async function listContractFiles(client, contractId, params = {}, options) {
|
|
|
68977
69736
|
if (params.size !== void 0) qs.set("size", String(params.size));
|
|
68978
69737
|
const suffix = qs.toString() === "" ? "" : `?${qs.toString()}`;
|
|
68979
69738
|
const out = await client.getJSON(
|
|
68980
|
-
`${
|
|
69739
|
+
`${BASE4}/contracts/${contractId}/files${suffix}`,
|
|
68981
69740
|
options
|
|
68982
69741
|
);
|
|
68983
69742
|
if (out === null) {
|
|
@@ -69003,13 +69762,13 @@ async function listAllContractFiles(client, contractId, options) {
|
|
|
69003
69762
|
}
|
|
69004
69763
|
async function getContractFileDownload(client, fileId, options) {
|
|
69005
69764
|
return client.postJSON(
|
|
69006
|
-
`${
|
|
69765
|
+
`${BASE4}/contracts/files/${fileId}/download`,
|
|
69007
69766
|
{},
|
|
69008
69767
|
options
|
|
69009
69768
|
);
|
|
69010
69769
|
}
|
|
69011
69770
|
async function deleteContractFile(client, fileId, options) {
|
|
69012
|
-
await client.deleteJSON(`${
|
|
69771
|
+
await client.deleteJSON(`${BASE4}/contracts/files/${fileId}`, options);
|
|
69013
69772
|
}
|
|
69014
69773
|
async function uploadFileWithAiAsync(client, file, options = {}) {
|
|
69015
69774
|
return client.postMultipartFiles(
|
|
@@ -69045,7 +69804,7 @@ var EXTRACT_POLL_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
|
69045
69804
|
function isTerminalAiStatus(status2) {
|
|
69046
69805
|
return status2 === "PROCESSED" || status2 === "FAILED";
|
|
69047
69806
|
}
|
|
69048
|
-
async function
|
|
69807
|
+
async function defaultSleep9(ms, signal) {
|
|
69049
69808
|
if (signal?.aborted === true) return;
|
|
69050
69809
|
await new Promise((resolve3) => {
|
|
69051
69810
|
const timer = setTimeout(resolve3, ms);
|
|
@@ -69062,7 +69821,7 @@ async function defaultSleep8(ms, signal) {
|
|
|
69062
69821
|
async function pollExtractionStatus(client, contractFileIds, options = {}) {
|
|
69063
69822
|
const interval = options.pollIntervalMs ?? EXTRACT_POLL_INTERVAL_MS;
|
|
69064
69823
|
const timeout = options.timeoutMs ?? EXTRACT_POLL_TIMEOUT_MS;
|
|
69065
|
-
const sleep3 = options.sleep ??
|
|
69824
|
+
const sleep3 = options.sleep ?? defaultSleep9;
|
|
69066
69825
|
const now = options.now ?? Date.now;
|
|
69067
69826
|
const resolved = /* @__PURE__ */ new Map();
|
|
69068
69827
|
if (contractFileIds.length === 0) return { resolved, pending: [] };
|
|
@@ -69129,14 +69888,14 @@ async function bulkCreateContracts(client, body, options) {
|
|
|
69129
69888
|
throw new Error(`bulkCreateContracts: max 10 contracts per call, got ${body.contracts.length}`);
|
|
69130
69889
|
}
|
|
69131
69890
|
const out = await client.postJSON(
|
|
69132
|
-
`${
|
|
69891
|
+
`${BASE4}/contracts/bulk-create`,
|
|
69133
69892
|
body,
|
|
69134
69893
|
options
|
|
69135
69894
|
);
|
|
69136
69895
|
return out ?? { contracts: [] };
|
|
69137
69896
|
}
|
|
69138
69897
|
async function partialUpdateContract(client, contractId, body, options) {
|
|
69139
|
-
return client.patchJSON(`${
|
|
69898
|
+
return client.patchJSON(`${BASE4}/contracts/${contractId}`, body, options);
|
|
69140
69899
|
}
|
|
69141
69900
|
|
|
69142
69901
|
// src/types/spendControl.ts
|
|
@@ -69556,7 +70315,7 @@ function chunkContracts(contracts, size = 10) {
|
|
|
69556
70315
|
}
|
|
69557
70316
|
|
|
69558
70317
|
// src/api/spendControlVendors.ts
|
|
69559
|
-
var
|
|
70318
|
+
var BASE5 = "/api/spend-control/v1/vendors";
|
|
69560
70319
|
var MAX_PAGE_SIZE2 = 100;
|
|
69561
70320
|
function buildVendorListQuery(params) {
|
|
69562
70321
|
const qs = new URLSearchParams();
|
|
@@ -69587,19 +70346,19 @@ function emptyPage() {
|
|
|
69587
70346
|
return { items: [], total: 0, page: null, size: null, pages: null };
|
|
69588
70347
|
}
|
|
69589
70348
|
async function listVendors(client, params = {}, options) {
|
|
69590
|
-
const out = await client.getJSON(withQuery(`${
|
|
70349
|
+
const out = await client.getJSON(withQuery(`${BASE5}/`, params), options);
|
|
69591
70350
|
return out ?? emptyPage();
|
|
69592
70351
|
}
|
|
69593
70352
|
async function listAppStoreVendors(client, params = {}, options) {
|
|
69594
70353
|
const out = await client.getJSON(
|
|
69595
|
-
withQuery(`${
|
|
70354
|
+
withQuery(`${BASE5}/app-store`, params),
|
|
69596
70355
|
options
|
|
69597
70356
|
);
|
|
69598
70357
|
return out ?? emptyPage();
|
|
69599
70358
|
}
|
|
69600
70359
|
async function listVendorsWithContracts(client, params = {}, options) {
|
|
69601
70360
|
const out = await client.getJSON(
|
|
69602
|
-
withQuery(`${
|
|
70361
|
+
withQuery(`${BASE5}/with-contracts`, params),
|
|
69603
70362
|
options
|
|
69604
70363
|
);
|
|
69605
70364
|
return out ?? emptyPage();
|
|
@@ -69616,24 +70375,24 @@ async function listAllVendors(fetchPage, client, params = {}, options) {
|
|
|
69616
70375
|
return collected;
|
|
69617
70376
|
}
|
|
69618
70377
|
async function listVendorCategories(client, options) {
|
|
69619
|
-
const out = await client.getJSON(`${
|
|
70378
|
+
const out = await client.getJSON(`${BASE5}/categories`, options);
|
|
69620
70379
|
return out ?? [];
|
|
69621
70380
|
}
|
|
69622
70381
|
async function listVendorsWithMultipleContracts(client, options) {
|
|
69623
|
-
const out = await client.getJSON(`${
|
|
70382
|
+
const out = await client.getJSON(`${BASE5}/with-multiple-contracts`, options);
|
|
69624
70383
|
return out ?? [];
|
|
69625
70384
|
}
|
|
69626
70385
|
async function getVendorOwners(client, vendorId, options) {
|
|
69627
|
-
return client.getJSON(`${
|
|
70386
|
+
return client.getJSON(`${BASE5}/${encodeURIComponent(vendorId)}/owners/`, options);
|
|
69628
70387
|
}
|
|
69629
70388
|
async function createVendor(client, name, options) {
|
|
69630
|
-
return client.postJSON(`${
|
|
70389
|
+
return client.postJSON(`${BASE5}/`, { name }, options);
|
|
69631
70390
|
}
|
|
69632
70391
|
async function bulkUpdateVendorVisibility(client, vendors, options) {
|
|
69633
70392
|
if (vendors.length === 0) {
|
|
69634
70393
|
throw new Error("bulkUpdateVendorVisibility: at least one vendor is required");
|
|
69635
70394
|
}
|
|
69636
|
-
const out = await client.patchJSON(`${
|
|
70395
|
+
const out = await client.patchJSON(`${BASE5}/visibility`, { vendors }, options);
|
|
69637
70396
|
return out ?? [];
|
|
69638
70397
|
}
|
|
69639
70398
|
|
|
@@ -74746,103 +75505,37 @@ import { promises as fs36 } from "fs";
|
|
|
74746
75505
|
import { Option as Option4 } from "commander";
|
|
74747
75506
|
|
|
74748
75507
|
// src/api/templateLibrary.ts
|
|
74749
|
-
var
|
|
75508
|
+
var BASE6 = "/api/report_library/management";
|
|
74750
75509
|
async function list28(client, options) {
|
|
74751
|
-
return await client.getJSON(
|
|
75510
|
+
return await client.getJSON(BASE6, options) ?? [];
|
|
74752
75511
|
}
|
|
74753
75512
|
async function create19(client, body, options) {
|
|
74754
|
-
const out = await client.postJSON(
|
|
75513
|
+
const out = await client.postJSON(BASE6, body, options);
|
|
74755
75514
|
if (out === null) {
|
|
74756
|
-
throw new Error(`unexpected empty response from POST ${
|
|
75515
|
+
throw new Error(`unexpected empty response from POST ${BASE6}`);
|
|
74757
75516
|
}
|
|
74758
75517
|
return out;
|
|
74759
75518
|
}
|
|
74760
75519
|
async function update12(client, id, body, options) {
|
|
74761
|
-
const out = await client.putJSON(`${
|
|
75520
|
+
const out = await client.putJSON(`${BASE6}/${id}`, body, options);
|
|
74762
75521
|
if (out === null) {
|
|
74763
|
-
throw new Error(`unexpected empty response from PUT ${
|
|
75522
|
+
throw new Error(`unexpected empty response from PUT ${BASE6}/${id}`);
|
|
74764
75523
|
}
|
|
74765
75524
|
return out;
|
|
74766
75525
|
}
|
|
74767
75526
|
async function uploadImage(client, id, png, filename, options) {
|
|
74768
75527
|
const out = await client.putMultipart(
|
|
74769
|
-
`${
|
|
75528
|
+
`${BASE6}/${id}`,
|
|
74770
75529
|
{},
|
|
74771
75530
|
new Blob([png], { type: "image/png" }),
|
|
74772
75531
|
{ ...options, fileFieldName: "image", filename }
|
|
74773
75532
|
);
|
|
74774
75533
|
if (out === null) {
|
|
74775
|
-
throw new Error(`unexpected empty response from PUT ${
|
|
75534
|
+
throw new Error(`unexpected empty response from PUT ${BASE6}/${id} (image)`);
|
|
74776
75535
|
}
|
|
74777
75536
|
return out;
|
|
74778
75537
|
}
|
|
74779
75538
|
|
|
74780
|
-
// src/commands/_agentCli.ts
|
|
74781
|
-
import { access } from "fs/promises";
|
|
74782
|
-
var JSON_HELP = "Emit raw JSON to stdout instead of a pretty render.";
|
|
74783
|
-
var CONFIRM_HELP = "Token from a prior plan run \u2014 required to actually write";
|
|
74784
|
-
function withTarget(cmd) {
|
|
74785
|
-
addServerFlag(cmd);
|
|
74786
|
-
addAccountFlag(cmd);
|
|
74787
|
-
return cmd;
|
|
74788
|
-
}
|
|
74789
|
-
function std() {
|
|
74790
|
-
return { out: process.stdout, err: process.stderr };
|
|
74791
|
-
}
|
|
74792
|
-
function requireId(value, placeholder) {
|
|
74793
|
-
const id = (value ?? "").trim();
|
|
74794
|
-
if (id === "") {
|
|
74795
|
-
throw new Error(`missing required option: --id ${placeholder}`);
|
|
74796
|
-
}
|
|
74797
|
-
return id;
|
|
74798
|
-
}
|
|
74799
|
-
function requirePositiveInt(value, flag) {
|
|
74800
|
-
const n = /^\d+$/.test(value) ? Number(value) : NaN;
|
|
74801
|
-
if (!Number.isSafeInteger(n) || n <= 0) {
|
|
74802
|
-
throw new Error(`${flag} ${JSON.stringify(value)}: expected a positive integer`);
|
|
74803
|
-
}
|
|
74804
|
-
return n;
|
|
74805
|
-
}
|
|
74806
|
-
function requireBool(value, flag) {
|
|
74807
|
-
if (value === "true") return true;
|
|
74808
|
-
if (value === "false") return false;
|
|
74809
|
-
throw new Error(`${flag} ${JSON.stringify(value ?? "")}: expected true or false`);
|
|
74810
|
-
}
|
|
74811
|
-
function splitList(value) {
|
|
74812
|
-
return [
|
|
74813
|
-
...new Set(
|
|
74814
|
-
(value ?? "").split(",").map((part) => part.trim()).filter((part) => part !== "")
|
|
74815
|
-
)
|
|
74816
|
-
];
|
|
74817
|
-
}
|
|
74818
|
-
function isNoneSentinel(parts, flag, value, what) {
|
|
74819
|
-
if (!parts.includes("none")) return false;
|
|
74820
|
-
if (parts.length === 1) return true;
|
|
74821
|
-
throw new Error(`${flag} ${JSON.stringify(value)}: "none" cannot be combined with ${what}`);
|
|
74822
|
-
}
|
|
74823
|
-
function shellArg(value) {
|
|
74824
|
-
return /^[A-Za-z0-9_@%+=:,./-]+$/.test(value) ? value : shellQuote(value);
|
|
74825
|
-
}
|
|
74826
|
-
function proseStream(cfg) {
|
|
74827
|
-
return cfg.asJson ? cfg.err : cfg.out;
|
|
74828
|
-
}
|
|
74829
|
-
async function assertNoOverwrite(paths, force) {
|
|
74830
|
-
if (force) return;
|
|
74831
|
-
const existing = [];
|
|
74832
|
-
for (const path13 of paths) {
|
|
74833
|
-
try {
|
|
74834
|
-
await access(path13);
|
|
74835
|
-
existing.push(path13);
|
|
74836
|
-
} catch {
|
|
74837
|
-
}
|
|
74838
|
-
}
|
|
74839
|
-
if (existing.length > 0) {
|
|
74840
|
-
throw new Error(
|
|
74841
|
-
`refusing to overwrite existing file(s): ${existing.join(", ")}. Pull into another --dir, or pass --force to replace them.`
|
|
74842
|
-
);
|
|
74843
|
-
}
|
|
74844
|
-
}
|
|
74845
|
-
|
|
74846
75539
|
// src/commands/_templateLibraryImages.ts
|
|
74847
75540
|
var TEMPLATE_LIBRARY_IMAGE_COLORS = ["pink", "purple", "yellow"];
|
|
74848
75541
|
var TEMPLATE_LIBRARY_IMAGE_FILENAMES = {
|
|
@@ -75699,11 +76392,11 @@ import { mkdir as mkdir5, writeFile as writeFile8 } from "fs/promises";
|
|
|
75699
76392
|
import { join as join18 } from "path";
|
|
75700
76393
|
|
|
75701
76394
|
// src/api/aiService.ts
|
|
75702
|
-
import { z as
|
|
76395
|
+
import { z as z4 } from "zod";
|
|
75703
76396
|
var AI_SERVICE_MINT_PATH = "/api/ai-service/v1/Authentication/authenticate";
|
|
75704
76397
|
var ERROR_BODY_MAX_CHARS = 1e3;
|
|
75705
|
-
var MintResponseSchema =
|
|
75706
|
-
var ErrorEnvelopeSchema =
|
|
76398
|
+
var MintResponseSchema = z4.object({ token: z4.string().min(1) });
|
|
76399
|
+
var ErrorEnvelopeSchema = z4.object({ code: z4.string(), message: z4.string() });
|
|
75707
76400
|
function parseErrorEnvelope(text2) {
|
|
75708
76401
|
let parsed2;
|
|
75709
76402
|
try {
|