@uru-intelligence/cli 0.3.55 → 0.3.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/uru.mjs +342 -240
- package/package.json +4 -4
package/dist/uru.mjs
CHANGED
|
@@ -906,171 +906,6 @@ function normalizeTool(value) {
|
|
|
906
906
|
return [tool];
|
|
907
907
|
}
|
|
908
908
|
|
|
909
|
-
// src/cli-helpers.ts
|
|
910
|
-
function parseApiArgs(args) {
|
|
911
|
-
let method = "GET";
|
|
912
|
-
let path;
|
|
913
|
-
let body;
|
|
914
|
-
const fields = {};
|
|
915
|
-
for (let index = 0;index < args.length; index += 1) {
|
|
916
|
-
const arg = args[index];
|
|
917
|
-
if (arg === undefined) {
|
|
918
|
-
continue;
|
|
919
|
-
}
|
|
920
|
-
if (arg === "-X" || arg === "--method") {
|
|
921
|
-
method = requireCommandValue(args[index + 1], `${arg} requires a method`).toUpperCase();
|
|
922
|
-
index += 1;
|
|
923
|
-
continue;
|
|
924
|
-
}
|
|
925
|
-
if (arg.startsWith("-X") && arg.length > 2) {
|
|
926
|
-
method = arg.slice(2).toUpperCase();
|
|
927
|
-
continue;
|
|
928
|
-
}
|
|
929
|
-
if (arg === "--body-json" || arg === "--data-json") {
|
|
930
|
-
body = parseParamsJson(requireCommandValue(args[index + 1], `${arg} requires a JSON object`), arg);
|
|
931
|
-
index += 1;
|
|
932
|
-
continue;
|
|
933
|
-
}
|
|
934
|
-
if (arg === "-F" || arg === "--field") {
|
|
935
|
-
addApiField(fields, requireCommandValue(args[index + 1], `${arg} requires key=value`));
|
|
936
|
-
index += 1;
|
|
937
|
-
continue;
|
|
938
|
-
}
|
|
939
|
-
if (arg.startsWith("-F") && arg.length > 2) {
|
|
940
|
-
addApiField(fields, arg.slice(2));
|
|
941
|
-
continue;
|
|
942
|
-
}
|
|
943
|
-
if (path === undefined) {
|
|
944
|
-
path = normalizeApiPath(arg);
|
|
945
|
-
continue;
|
|
946
|
-
}
|
|
947
|
-
throw new CliError(`Unexpected api argument: ${arg}`);
|
|
948
|
-
}
|
|
949
|
-
if (Object.keys(fields).length > 0) {
|
|
950
|
-
body = { ...body ?? {}, ...fields };
|
|
951
|
-
if (method === "GET") {
|
|
952
|
-
method = "POST";
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
return {
|
|
956
|
-
path: requireCommandValue(path, "Usage: uru api <path> [-X POST] [-F k=v] [--body-json {...}]"),
|
|
957
|
-
method,
|
|
958
|
-
...body === undefined ? {} : { body }
|
|
959
|
-
};
|
|
960
|
-
}
|
|
961
|
-
function normalizeApiPath(value) {
|
|
962
|
-
const trimmed = value.trim();
|
|
963
|
-
if (trimmed.startsWith("/")) {
|
|
964
|
-
return trimmed;
|
|
965
|
-
}
|
|
966
|
-
return `/api/${trimmed.replace(/^api\//, "")}`;
|
|
967
|
-
}
|
|
968
|
-
function addApiField(target, raw) {
|
|
969
|
-
const equals = raw.indexOf("=");
|
|
970
|
-
if (equals <= 0) {
|
|
971
|
-
throw new CliError("-F/--field requires key=value");
|
|
972
|
-
}
|
|
973
|
-
target[raw.slice(0, equals)] = raw.slice(equals + 1);
|
|
974
|
-
}
|
|
975
|
-
function paramsJson(args) {
|
|
976
|
-
for (let index = 0;index < args.length; index += 1) {
|
|
977
|
-
const arg = args[index];
|
|
978
|
-
if (arg === "--params-json" || arg === "--args-json") {
|
|
979
|
-
const value = args[index + 1];
|
|
980
|
-
if (value === undefined) {
|
|
981
|
-
throw new CliError(`${arg} requires a JSON object`);
|
|
982
|
-
}
|
|
983
|
-
return parseParamsJson(value, arg);
|
|
984
|
-
}
|
|
985
|
-
if (arg?.startsWith("--params-json=")) {
|
|
986
|
-
return parseParamsJson(arg.slice("--params-json=".length), "--params-json");
|
|
987
|
-
}
|
|
988
|
-
if (arg?.startsWith("--args-json=")) {
|
|
989
|
-
return parseParamsJson(arg.slice("--args-json=".length), "--args-json");
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
return {};
|
|
993
|
-
}
|
|
994
|
-
function parseParamsJson(value, label) {
|
|
995
|
-
try {
|
|
996
|
-
return parseJsonObject(value, label);
|
|
997
|
-
} catch (error) {
|
|
998
|
-
throw new CliError(error instanceof Error ? error.message : `Invalid ${label}`, {
|
|
999
|
-
cause: error
|
|
1000
|
-
});
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
function parseLocalFlags(args) {
|
|
1004
|
-
const values = {};
|
|
1005
|
-
const booleans = new Set;
|
|
1006
|
-
const positionals = [];
|
|
1007
|
-
for (let index = 0;index < args.length; index += 1) {
|
|
1008
|
-
const arg = args[index];
|
|
1009
|
-
if (arg === undefined) {
|
|
1010
|
-
continue;
|
|
1011
|
-
}
|
|
1012
|
-
if (!arg.startsWith("--")) {
|
|
1013
|
-
positionals.push(arg);
|
|
1014
|
-
continue;
|
|
1015
|
-
}
|
|
1016
|
-
const equals = arg.indexOf("=");
|
|
1017
|
-
if (equals > -1) {
|
|
1018
|
-
values[arg.slice(0, equals)] = arg.slice(equals + 1);
|
|
1019
|
-
continue;
|
|
1020
|
-
}
|
|
1021
|
-
const next = args[index + 1];
|
|
1022
|
-
if (next !== undefined && !next.startsWith("--")) {
|
|
1023
|
-
values[arg] = next;
|
|
1024
|
-
index += 1;
|
|
1025
|
-
} else {
|
|
1026
|
-
booleans.add(arg);
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
return { values, booleans, positionals };
|
|
1030
|
-
}
|
|
1031
|
-
function integerFlag(flags, name, fallback) {
|
|
1032
|
-
const raw = flags.values[name];
|
|
1033
|
-
if (raw === undefined) {
|
|
1034
|
-
return fallback;
|
|
1035
|
-
}
|
|
1036
|
-
const value = Number.parseInt(raw, 10);
|
|
1037
|
-
if (!Number.isFinite(value) || value < 0) {
|
|
1038
|
-
throw new CliError(`${name} must be a non-negative integer`);
|
|
1039
|
-
}
|
|
1040
|
-
return value;
|
|
1041
|
-
}
|
|
1042
|
-
function copyStringFlag(flags, target, flagName, paramName) {
|
|
1043
|
-
const value = flags.values[flagName];
|
|
1044
|
-
if (value !== undefined) {
|
|
1045
|
-
target[paramName] = value;
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
function isJsonRequested(argv) {
|
|
1049
|
-
for (let index = 0;index < argv.length; index += 1) {
|
|
1050
|
-
const arg = argv[index];
|
|
1051
|
-
if (arg === "--json") {
|
|
1052
|
-
return true;
|
|
1053
|
-
}
|
|
1054
|
-
if (arg === "--output-format=json" || arg === "--output-format=stream-json" || arg === "--output=json" || arg === "--output=stream-json") {
|
|
1055
|
-
return true;
|
|
1056
|
-
}
|
|
1057
|
-
if (arg === "--output-format" || arg === "--output") {
|
|
1058
|
-
const value = argv[index + 1];
|
|
1059
|
-
if (value === "json" || value === "stream-json") {
|
|
1060
|
-
return true;
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
return false;
|
|
1065
|
-
}
|
|
1066
|
-
function nonEmptyString(value) {
|
|
1067
|
-
if (value === undefined) {
|
|
1068
|
-
return;
|
|
1069
|
-
}
|
|
1070
|
-
const trimmed = value.trim();
|
|
1071
|
-
return trimmed === "" ? undefined : trimmed;
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
909
|
// src/output.ts
|
|
1075
910
|
function writeJson(io, value) {
|
|
1076
911
|
io.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
@@ -1581,7 +1416,14 @@ async function executeOperationStream(ctx, operationId, params, onEvent) {
|
|
|
1581
1416
|
if (operation.backendOp !== undefined) {
|
|
1582
1417
|
toolParams["op"] = operation.backendOp;
|
|
1583
1418
|
}
|
|
1584
|
-
|
|
1419
|
+
const response = await client(ctx).streamTool(operation.backendToolName, toolParams, (event) => {
|
|
1420
|
+
assertToolResultSuccess(event);
|
|
1421
|
+
onEvent(event);
|
|
1422
|
+
});
|
|
1423
|
+
if (response.payload !== undefined) {
|
|
1424
|
+
assertToolResultSuccess(response.payload);
|
|
1425
|
+
}
|
|
1426
|
+
return response;
|
|
1585
1427
|
}
|
|
1586
1428
|
async function executeOperation(ctx, operationId, params) {
|
|
1587
1429
|
const operation = getPlatformOperation(operationId);
|
|
@@ -1592,7 +1434,9 @@ async function executeOperation(ctx, operationId, params) {
|
|
|
1592
1434
|
if (operation.backendOp !== undefined) {
|
|
1593
1435
|
toolParams["op"] = operation.backendOp;
|
|
1594
1436
|
}
|
|
1595
|
-
|
|
1437
|
+
const result = await client(ctx).runTool(operation.backendToolName, toolParams);
|
|
1438
|
+
assertToolResultSuccess(result);
|
|
1439
|
+
return result;
|
|
1596
1440
|
}
|
|
1597
1441
|
function emit(ctx, value, text) {
|
|
1598
1442
|
if (ctx.outputFormat === "stream-json") {
|
|
@@ -1604,19 +1448,51 @@ function emit(ctx, value, text) {
|
|
|
1604
1448
|
}
|
|
1605
1449
|
}
|
|
1606
1450
|
function unwrapToolResult(value) {
|
|
1607
|
-
|
|
1608
|
-
|
|
1451
|
+
assertToolResultSuccess(value);
|
|
1452
|
+
if (isJsonObject2(value) && Object.hasOwn(value, "result") && (isToolResultEnvelope(value) || isJsonObject2(value["result"]))) {
|
|
1453
|
+
const result = value["result"];
|
|
1454
|
+
if (result !== undefined) {
|
|
1455
|
+
return result;
|
|
1456
|
+
}
|
|
1609
1457
|
}
|
|
1610
1458
|
return value;
|
|
1611
1459
|
}
|
|
1460
|
+
function assertToolResultSuccess(value) {
|
|
1461
|
+
if (!isJsonObject2(value) || !isToolResultEnvelope(value)) {
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
const httpStatus = toolResultHttpStatus(value);
|
|
1465
|
+
const failed = value["success"] === false || Object.hasOwn(value, "error") || Object.hasOwn(value, "errorMessage") || Object.hasOwn(value, "error_message") || Object.hasOwn(value, "errorCode") || Object.hasOwn(value, "error_code") || Object.hasOwn(value, "code") || httpStatus !== undefined && httpStatus >= 400;
|
|
1466
|
+
if (!failed) {
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
const errorCode = stringField(value, ["errorCode", "error_code", "code"]);
|
|
1470
|
+
const toolId = stringField(value, ["toolId", "tool_id"]);
|
|
1471
|
+
const message = stringField(value, ["errorMessage", "error_message", "error", "message"]) ?? `${toolId === undefined ? "Tool operation" : `Tool ${toolId}`} failed`;
|
|
1472
|
+
const details = [
|
|
1473
|
+
errorCode === undefined ? undefined : `[${errorCode}]`,
|
|
1474
|
+
httpStatus === undefined ? undefined : `(HTTP ${httpStatus})`
|
|
1475
|
+
].filter((detail) => detail !== undefined);
|
|
1476
|
+
const tip = stringField(value, ["tip"]);
|
|
1477
|
+
throw new CliError(`${message}${details.length === 0 ? "" : ` ${details.join(" ")}`}${tip === undefined ? "" : ` ${tip}`}`, {
|
|
1478
|
+
code: httpStatus === 409 ? ExitCode.Conflict : httpStatus === 401 || httpStatus === 403 ? ExitCode.AuthRequired : ExitCode.Failure,
|
|
1479
|
+
...errorCode === undefined ? {} : { errorCode }
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
function isToolResultEnvelope(value) {
|
|
1483
|
+
return typeof value["success"] === "boolean" && (typeof value["toolId"] === "string" || typeof value["tool_id"] === "string" || typeof value["executionTimeMs"] === "number" || typeof value["execution_time_ms"] === "number");
|
|
1484
|
+
}
|
|
1485
|
+
function toolResultHttpStatus(value) {
|
|
1486
|
+
const status = value["httpStatus"] ?? value["http_status"];
|
|
1487
|
+
return typeof status === "number" && Number.isFinite(status) ? status : undefined;
|
|
1488
|
+
}
|
|
1612
1489
|
function delegatedPayload(value) {
|
|
1613
1490
|
if (isJsonObject2(value) && isJsonObject2(value["payload"])) {
|
|
1614
1491
|
return value["payload"];
|
|
1615
1492
|
}
|
|
1616
1493
|
return value;
|
|
1617
1494
|
}
|
|
1618
|
-
function gemPathFromArgs(
|
|
1619
|
-
const flags = parseLocalFlags(args);
|
|
1495
|
+
function gemPathFromArgs(flags, linkedProject) {
|
|
1620
1496
|
return flags.values["--path"] ?? flags.values["--gem"] ?? flags.positionals.find((value) => value.startsWith("library/")) ?? linkedProject.libraryPath ?? linkedProject.gemId ?? (() => {
|
|
1621
1497
|
throw new CliError("Gem path required. Pass library/<name>.gem or run `uru link --path library/<name>.gem`.");
|
|
1622
1498
|
})();
|
|
@@ -1840,16 +1716,9 @@ function createMacosKeychainCredentialStore(runCommand) {
|
|
|
1840
1716
|
},
|
|
1841
1717
|
async writeToken(apiUrl, token) {
|
|
1842
1718
|
try {
|
|
1843
|
-
await runCommand("security", [
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
accountForApiUrl(apiUrl),
|
|
1847
|
-
"-s",
|
|
1848
|
-
KEYCHAIN_SERVICE,
|
|
1849
|
-
"-w",
|
|
1850
|
-
token,
|
|
1851
|
-
"-U"
|
|
1852
|
-
]);
|
|
1719
|
+
await runCommand("security", ["-i"], {
|
|
1720
|
+
input: macosKeychainWriteCommand(apiUrl, token)
|
|
1721
|
+
});
|
|
1853
1722
|
} catch (error) {
|
|
1854
1723
|
throw credentialStoreError("macOS Keychain", error);
|
|
1855
1724
|
}
|
|
@@ -1871,6 +1740,11 @@ function createMacosKeychainCredentialStore(runCommand) {
|
|
|
1871
1740
|
}
|
|
1872
1741
|
};
|
|
1873
1742
|
}
|
|
1743
|
+
function macosKeychainWriteCommand(apiUrl, token) {
|
|
1744
|
+
const tokenHex = Buffer.from(token, "utf8").toString("hex");
|
|
1745
|
+
return `add-generic-password -a "${accountForApiUrl(apiUrl)}" -s "${KEYCHAIN_SERVICE}" -X ${tokenHex} -U
|
|
1746
|
+
`;
|
|
1747
|
+
}
|
|
1874
1748
|
function createLinuxSecretToolCredentialStore(runCommand) {
|
|
1875
1749
|
return {
|
|
1876
1750
|
async readToken(apiUrl) {
|
|
@@ -2369,7 +2243,8 @@ var SKIPPED_SOURCE_PATH_SEGMENTS = new Set([
|
|
|
2369
2243
|
"build",
|
|
2370
2244
|
"coverage",
|
|
2371
2245
|
"tmp",
|
|
2372
|
-
"temp"
|
|
2246
|
+
"temp",
|
|
2247
|
+
"__MACOSX"
|
|
2373
2248
|
]);
|
|
2374
2249
|
var SKIPPED_SOURCE_FILE_NAMES = new Set([
|
|
2375
2250
|
".DS_Store",
|
|
@@ -2382,7 +2257,8 @@ var SKIPPED_SOURCE_FILE_NAMES = new Set([
|
|
|
2382
2257
|
]);
|
|
2383
2258
|
function shouldSkipProjectPath(path) {
|
|
2384
2259
|
const segments = path.split("/");
|
|
2385
|
-
|
|
2260
|
+
const name = segments.at(-1) ?? "";
|
|
2261
|
+
return segments.some((segment) => SKIPPED_SOURCE_PATH_SEGMENTS.has(segment)) || SKIPPED_SOURCE_FILE_NAMES.has(name) || name.startsWith("._");
|
|
2386
2262
|
}
|
|
2387
2263
|
function stableStringRecord(record) {
|
|
2388
2264
|
return Object.fromEntries(Object.entries(record).filter(([, value]) => typeof value === "string" && value.trim() !== "").sort(([left], [right]) => compareStrings(left, right)));
|
|
@@ -2437,11 +2313,12 @@ async function maybeNotifyCliUpdate(ctx, options = {}) {
|
|
|
2437
2313
|
if (!shouldCheckForUpdate(ctx, options.env ?? process.env)) {
|
|
2438
2314
|
return;
|
|
2439
2315
|
}
|
|
2316
|
+
const currentConfig = await readConfigBestEffort(ctx);
|
|
2440
2317
|
const now = options.now?.() ?? Date.now();
|
|
2441
|
-
if (!isUpdateCheckDue(
|
|
2318
|
+
if (!isUpdateCheckDue(currentConfig, now)) {
|
|
2442
2319
|
return;
|
|
2443
2320
|
}
|
|
2444
|
-
const checkedConfig = withUpdateCheckTimestamp(
|
|
2321
|
+
const checkedConfig = withUpdateCheckTimestamp(currentConfig, now);
|
|
2445
2322
|
await writeConfigBestEffort(ctx, checkedConfig);
|
|
2446
2323
|
const latestVersion = await fetchLatestVersion({
|
|
2447
2324
|
fetchImpl: ctx.fetch ?? fetch,
|
|
@@ -2463,6 +2340,13 @@ async function maybeNotifyCliUpdate(ctx, options = {}) {
|
|
|
2463
2340
|
ctx.io.stderr.write(`A newer Uru CLI is available: ${CLI_VERSION} → ${latestVersion}. ` + `Run npm install -g ${PACKAGE_NAME}@latest
|
|
2464
2341
|
`);
|
|
2465
2342
|
}
|
|
2343
|
+
async function readConfigBestEffort(ctx) {
|
|
2344
|
+
try {
|
|
2345
|
+
return await ctx.store.read();
|
|
2346
|
+
} catch {
|
|
2347
|
+
return ctx.config;
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2466
2350
|
function shouldCheckForUpdate(ctx, env) {
|
|
2467
2351
|
return ctx.outputFormat === "text" && ctx.terminal.stderrIsTty && !ctx.terminal.ci && env["NO_UPDATE_NOTIFIER"] === undefined && env["URU_NO_UPDATE_NOTIFIER"] === undefined;
|
|
2468
2352
|
}
|
|
@@ -2542,6 +2426,194 @@ function isRecord2(value) {
|
|
|
2542
2426
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2543
2427
|
}
|
|
2544
2428
|
|
|
2429
|
+
// src/cli-helpers.ts
|
|
2430
|
+
var BOOLEAN_LOCAL_FLAGS = new Set([
|
|
2431
|
+
"--blocking",
|
|
2432
|
+
"--create",
|
|
2433
|
+
"--deep",
|
|
2434
|
+
"--dry-run",
|
|
2435
|
+
"--follow",
|
|
2436
|
+
"--force",
|
|
2437
|
+
"--force-build",
|
|
2438
|
+
"--hard-delete",
|
|
2439
|
+
"--no-create",
|
|
2440
|
+
"--no-publish",
|
|
2441
|
+
"--no-wait",
|
|
2442
|
+
"--permanent",
|
|
2443
|
+
"--prod",
|
|
2444
|
+
"--skip-promote",
|
|
2445
|
+
"--stdin",
|
|
2446
|
+
"--value-stdin",
|
|
2447
|
+
"--yes"
|
|
2448
|
+
]);
|
|
2449
|
+
function parseApiArgs(args) {
|
|
2450
|
+
let method = "GET";
|
|
2451
|
+
let path;
|
|
2452
|
+
let body;
|
|
2453
|
+
const fields = {};
|
|
2454
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
2455
|
+
const arg = args[index];
|
|
2456
|
+
if (arg === undefined) {
|
|
2457
|
+
continue;
|
|
2458
|
+
}
|
|
2459
|
+
if (arg === "-X" || arg === "--method") {
|
|
2460
|
+
method = requireCommandValue(args[index + 1], `${arg} requires a method`).toUpperCase();
|
|
2461
|
+
index += 1;
|
|
2462
|
+
continue;
|
|
2463
|
+
}
|
|
2464
|
+
if (arg.startsWith("-X") && arg.length > 2) {
|
|
2465
|
+
method = arg.slice(2).toUpperCase();
|
|
2466
|
+
continue;
|
|
2467
|
+
}
|
|
2468
|
+
if (arg === "--body-json" || arg === "--data-json") {
|
|
2469
|
+
body = parseParamsJson(requireCommandValue(args[index + 1], `${arg} requires a JSON object`), arg);
|
|
2470
|
+
index += 1;
|
|
2471
|
+
continue;
|
|
2472
|
+
}
|
|
2473
|
+
if (arg === "-F" || arg === "--field") {
|
|
2474
|
+
addApiField(fields, requireCommandValue(args[index + 1], `${arg} requires key=value`));
|
|
2475
|
+
index += 1;
|
|
2476
|
+
continue;
|
|
2477
|
+
}
|
|
2478
|
+
if (arg.startsWith("-F") && arg.length > 2) {
|
|
2479
|
+
addApiField(fields, arg.slice(2));
|
|
2480
|
+
continue;
|
|
2481
|
+
}
|
|
2482
|
+
if (path === undefined) {
|
|
2483
|
+
path = normalizeApiPath(arg);
|
|
2484
|
+
continue;
|
|
2485
|
+
}
|
|
2486
|
+
throw new CliError(`Unexpected api argument: ${arg}`);
|
|
2487
|
+
}
|
|
2488
|
+
if (Object.keys(fields).length > 0) {
|
|
2489
|
+
body = { ...body ?? {}, ...fields };
|
|
2490
|
+
if (method === "GET") {
|
|
2491
|
+
method = "POST";
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
return {
|
|
2495
|
+
path: requireCommandValue(path, "Usage: uru api <path> [-X POST] [-F k=v] [--body-json {...}]"),
|
|
2496
|
+
method,
|
|
2497
|
+
...body === undefined ? {} : { body }
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2500
|
+
function normalizeApiPath(value) {
|
|
2501
|
+
const trimmed = value.trim();
|
|
2502
|
+
if (trimmed.startsWith("/")) {
|
|
2503
|
+
return trimmed;
|
|
2504
|
+
}
|
|
2505
|
+
return `/api/${trimmed.replace(/^api\//, "")}`;
|
|
2506
|
+
}
|
|
2507
|
+
function addApiField(target, raw) {
|
|
2508
|
+
const equals = raw.indexOf("=");
|
|
2509
|
+
if (equals <= 0) {
|
|
2510
|
+
throw new CliError("-F/--field requires key=value");
|
|
2511
|
+
}
|
|
2512
|
+
target[raw.slice(0, equals)] = raw.slice(equals + 1);
|
|
2513
|
+
}
|
|
2514
|
+
function paramsJson(args) {
|
|
2515
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
2516
|
+
const arg = args[index];
|
|
2517
|
+
if (arg === "--params-json" || arg === "--args-json") {
|
|
2518
|
+
const value = args[index + 1];
|
|
2519
|
+
if (value === undefined) {
|
|
2520
|
+
throw new CliError(`${arg} requires a JSON object`);
|
|
2521
|
+
}
|
|
2522
|
+
return parseParamsJson(value, arg);
|
|
2523
|
+
}
|
|
2524
|
+
if (arg?.startsWith("--params-json=")) {
|
|
2525
|
+
return parseParamsJson(arg.slice("--params-json=".length), "--params-json");
|
|
2526
|
+
}
|
|
2527
|
+
if (arg?.startsWith("--args-json=")) {
|
|
2528
|
+
return parseParamsJson(arg.slice("--args-json=".length), "--args-json");
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
return {};
|
|
2532
|
+
}
|
|
2533
|
+
function parseParamsJson(value, label) {
|
|
2534
|
+
try {
|
|
2535
|
+
return parseJsonObject(value, label);
|
|
2536
|
+
} catch (error) {
|
|
2537
|
+
throw new CliError(error instanceof Error ? error.message : `Invalid ${label}`, {
|
|
2538
|
+
cause: error
|
|
2539
|
+
});
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
function parseLocalFlags(args) {
|
|
2543
|
+
const values = {};
|
|
2544
|
+
const booleans = new Set;
|
|
2545
|
+
const positionals = [];
|
|
2546
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
2547
|
+
const arg = args[index];
|
|
2548
|
+
if (arg === undefined) {
|
|
2549
|
+
continue;
|
|
2550
|
+
}
|
|
2551
|
+
if (!arg.startsWith("--")) {
|
|
2552
|
+
positionals.push(arg);
|
|
2553
|
+
continue;
|
|
2554
|
+
}
|
|
2555
|
+
const equals = arg.indexOf("=");
|
|
2556
|
+
if (equals > -1) {
|
|
2557
|
+
values[arg.slice(0, equals)] = arg.slice(equals + 1);
|
|
2558
|
+
continue;
|
|
2559
|
+
}
|
|
2560
|
+
if (BOOLEAN_LOCAL_FLAGS.has(arg)) {
|
|
2561
|
+
booleans.add(arg);
|
|
2562
|
+
continue;
|
|
2563
|
+
}
|
|
2564
|
+
const next = args[index + 1];
|
|
2565
|
+
if (next !== undefined && !next.startsWith("--")) {
|
|
2566
|
+
values[arg] = next;
|
|
2567
|
+
index += 1;
|
|
2568
|
+
} else {
|
|
2569
|
+
booleans.add(arg);
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
return { values, booleans, positionals };
|
|
2573
|
+
}
|
|
2574
|
+
function integerFlag(flags, name, fallback) {
|
|
2575
|
+
const raw = flags.values[name];
|
|
2576
|
+
if (raw === undefined) {
|
|
2577
|
+
return fallback;
|
|
2578
|
+
}
|
|
2579
|
+
const value = Number.parseInt(raw, 10);
|
|
2580
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
2581
|
+
throw new CliError(`${name} must be a non-negative integer`);
|
|
2582
|
+
}
|
|
2583
|
+
return value;
|
|
2584
|
+
}
|
|
2585
|
+
function copyStringFlag(flags, target, flagName, paramName) {
|
|
2586
|
+
const value = flags.values[flagName];
|
|
2587
|
+
if (value !== undefined) {
|
|
2588
|
+
target[paramName] = value;
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
function isJsonRequested(argv) {
|
|
2592
|
+
for (let index = 0;index < argv.length; index += 1) {
|
|
2593
|
+
const arg = argv[index];
|
|
2594
|
+
if (arg === "--json") {
|
|
2595
|
+
return true;
|
|
2596
|
+
}
|
|
2597
|
+
if (arg === "--output-format=json" || arg === "--output-format=stream-json" || arg === "--output=json" || arg === "--output=stream-json") {
|
|
2598
|
+
return true;
|
|
2599
|
+
}
|
|
2600
|
+
if (arg === "--output-format" || arg === "--output") {
|
|
2601
|
+
const value = argv[index + 1];
|
|
2602
|
+
if (value === "json" || value === "stream-json") {
|
|
2603
|
+
return true;
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
return false;
|
|
2608
|
+
}
|
|
2609
|
+
function nonEmptyString(value) {
|
|
2610
|
+
if (value === undefined) {
|
|
2611
|
+
return;
|
|
2612
|
+
}
|
|
2613
|
+
const trimmed = value.trim();
|
|
2614
|
+
return trimmed === "" ? undefined : trimmed;
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2545
2617
|
// src/auth-commands.ts
|
|
2546
2618
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
2547
2619
|
import { createServer } from "node:http";
|
|
@@ -3747,7 +3819,8 @@ import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from
|
|
|
3747
3819
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
3748
3820
|
import { join as join3, resolve as resolve3 } from "node:path";
|
|
3749
3821
|
async function dispatchGems(ctx, sub, args, linkedProject) {
|
|
3750
|
-
const
|
|
3822
|
+
const flags = parseLocalFlags(args);
|
|
3823
|
+
const gemPath = () => gemPathFromArgs(flags, linkedProject);
|
|
3751
3824
|
if (sub === "inspect") {
|
|
3752
3825
|
await emitGemTool(ctx, "gem.inspect", { path: gemPath() });
|
|
3753
3826
|
return;
|
|
@@ -3823,6 +3896,12 @@ async function gemDeploy(ctx, args, linkedProject) {
|
|
|
3823
3896
|
}
|
|
3824
3897
|
if (flags.booleans.has("--dry-run")) {
|
|
3825
3898
|
const buildArgs = [...flags.positionals, "--dry-run"];
|
|
3899
|
+
for (const flag of ["--path", "--gem"]) {
|
|
3900
|
+
const value = flags.values[flag];
|
|
3901
|
+
if (value !== undefined) {
|
|
3902
|
+
buildArgs.push(flag, value);
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3826
3905
|
if (flags.booleans.has("--force-build")) {
|
|
3827
3906
|
buildArgs.push("--force");
|
|
3828
3907
|
}
|
|
@@ -3833,7 +3912,7 @@ async function gemDeploy(ctx, args, linkedProject) {
|
|
|
3833
3912
|
await gemBuild(ctx, buildArgs, linkedProject);
|
|
3834
3913
|
return;
|
|
3835
3914
|
}
|
|
3836
|
-
const gemPath = gemPathFromArgs(flags
|
|
3915
|
+
const gemPath = gemPathFromArgs(flags, linkedProject);
|
|
3837
3916
|
const publish = !flags.booleans.has("--no-publish") && !flags.booleans.has("--skip-promote");
|
|
3838
3917
|
const params = {
|
|
3839
3918
|
path: gemPath,
|
|
@@ -3862,7 +3941,7 @@ async function gemDeploy(ctx, args, linkedProject) {
|
|
|
3862
3941
|
async function gemBuild(ctx, args, linkedProject) {
|
|
3863
3942
|
const flags = parseLocalFlags(args);
|
|
3864
3943
|
assertAllowedLocalFlags(flags, ["--dry-run", "--force", "--gem", "--outdir", "--path", "--source-version-id"], "uru build");
|
|
3865
|
-
const gemPath = gemPathFromArgs(flags
|
|
3944
|
+
const gemPath = gemPathFromArgs(flags, linkedProject);
|
|
3866
3945
|
const params = {
|
|
3867
3946
|
path: gemPath
|
|
3868
3947
|
};
|
|
@@ -3911,9 +3990,9 @@ async function gemChecks(ctx, args, linkedProject) {
|
|
|
3911
3990
|
}
|
|
3912
3991
|
assertAllowedLocalFlags(flags, ["--deployment-id", "--gem", "--path"], "uru gems checks");
|
|
3913
3992
|
const explicitDeploymentId = flags.values["--deployment-id"];
|
|
3914
|
-
const
|
|
3993
|
+
const gemPathFlags = explicitDeploymentId === undefined ? shiftPositionals(flags, 1) : flags;
|
|
3915
3994
|
const params = {
|
|
3916
|
-
path: gemPathFromArgs(
|
|
3995
|
+
path: gemPathFromArgs(gemPathFlags, linkedProject)
|
|
3917
3996
|
};
|
|
3918
3997
|
if (explicitDeploymentId !== undefined) {
|
|
3919
3998
|
params["deployment_id"] = explicitDeploymentId;
|
|
@@ -3926,7 +4005,7 @@ async function gemRunCheck(ctx, flags, linkedProject) {
|
|
|
3926
4005
|
assertAllowedLocalFlags(flags, ["--blocking", "--deep", "--deployment-id", "--gem", "--path"], "uru gems checks run");
|
|
3927
4006
|
const kind = requireCommandValue(flags.positionals[1], "Usage: uru gems checks run browser|security [library/name.gem] [--deployment-id <id>] [--blocking]");
|
|
3928
4007
|
const params = {
|
|
3929
|
-
path: gemPathFromArgs(flags
|
|
4008
|
+
path: gemPathFromArgs(shiftPositionals(flags, 2), linkedProject)
|
|
3930
4009
|
};
|
|
3931
4010
|
copyStringFlag(flags, params, "--deployment-id", "deployment_id");
|
|
3932
4011
|
if (flags.booleans.has("--blocking")) {
|
|
@@ -3962,7 +4041,7 @@ async function gemLogs(ctx, args, linkedProject) {
|
|
|
3962
4041
|
"--request-id"
|
|
3963
4042
|
], "uru logs");
|
|
3964
4043
|
const params = {
|
|
3965
|
-
path: gemPathFromArgs(flags
|
|
4044
|
+
path: gemPathFromArgs(flags, linkedProject),
|
|
3966
4045
|
limit: integerFlag(flags, "--limit", 100)
|
|
3967
4046
|
};
|
|
3968
4047
|
copyStringFlag(flags, params, "--level", "level");
|
|
@@ -4110,8 +4189,9 @@ function boundedIntegerFlag(flags, name, fallback, maximum) {
|
|
|
4110
4189
|
return Math.min(value, maximum);
|
|
4111
4190
|
}
|
|
4112
4191
|
async function gemOpen(ctx, args, linkedProject) {
|
|
4192
|
+
const flags = parseLocalFlags(args);
|
|
4113
4193
|
const result = await executeOperation(ctx, "gem.links_list", {
|
|
4114
|
-
path: gemPathFromArgs(
|
|
4194
|
+
path: gemPathFromArgs(flags, linkedProject)
|
|
4115
4195
|
});
|
|
4116
4196
|
const url = firstUrl(unwrapToolResult(result));
|
|
4117
4197
|
if (url === undefined) {
|
|
@@ -4169,7 +4249,7 @@ async function dispatchGemVersions(ctx, args, linkedProject) {
|
|
|
4169
4249
|
assertAllowedLocalFlags(flags, ["--gem", "--link-id", "--no-wait", "--path", "--pct", "--skip-promote"], "uru gems versions deploy");
|
|
4170
4250
|
const version = requireCommandValue(flags.positionals[0], "Usage: uru gems versions deploy <version-id> [library/name.gem] [--pct 100] [--skip-promote]");
|
|
4171
4251
|
const [versionId, trafficPercent] = version.split("@", 2);
|
|
4172
|
-
const gemPath = gemPathFromArgs(flags
|
|
4252
|
+
const gemPath = gemPathFromArgs(shiftPositionals(flags, 1), linkedProject);
|
|
4173
4253
|
const pct = flags.values["--pct"] ?? trafficPercent;
|
|
4174
4254
|
const trafficPercentValue = pct === undefined || pct === "" ? 100 : parseTrafficPercent(pct);
|
|
4175
4255
|
const publish = !flags.booleans.has("--skip-promote");
|
|
@@ -4206,7 +4286,7 @@ async function gemVersionUpload(ctx, args, linkedProject) {
|
|
|
4206
4286
|
"--tag",
|
|
4207
4287
|
"--tags"
|
|
4208
4288
|
], "uru gems versions upload");
|
|
4209
|
-
const gemPath = gemPathFromArgs(flags
|
|
4289
|
+
const gemPath = gemPathFromArgs(flags, linkedProject);
|
|
4210
4290
|
const params = {
|
|
4211
4291
|
path: gemPath
|
|
4212
4292
|
};
|
|
@@ -4242,7 +4322,7 @@ async function deployVersionToPublishedLink(ctx, flags, linkedProject, options)
|
|
|
4242
4322
|
if (deploymentId === undefined && versionId === undefined) {
|
|
4243
4323
|
throw new CliError(options.usage);
|
|
4244
4324
|
}
|
|
4245
|
-
const gemPath = gemPathFromArgs(versionId === undefined ? flags
|
|
4325
|
+
const gemPath = gemPathFromArgs(versionId === undefined ? flags : shiftPositionals(flags, 1), linkedProject);
|
|
4246
4326
|
const trafficPercent = parseTrafficPercent(flags.values["--pct"] ?? "100");
|
|
4247
4327
|
if (trafficPercent !== 100) {
|
|
4248
4328
|
throw new CliError(`${options.operation} does not support partial traffic shifts yet. Deploy the version with --skip-promote for validation, or ${options.operation} with --pct 100.`);
|
|
@@ -4501,7 +4581,7 @@ import { mkdir as mkdir5, rm as rm3, writeFile as writeFile5 } from "node:fs/pro
|
|
|
4501
4581
|
import { dirname as dirname4, join as join4, resolve as resolve4 } from "node:path";
|
|
4502
4582
|
async function gemSourcePull(ctx, args, linkedProject) {
|
|
4503
4583
|
const flags = parseLocalFlags(args);
|
|
4504
|
-
const gemPath = gemPathFromArgs(flags
|
|
4584
|
+
const gemPath = gemPathFromArgs(flags, linkedProject);
|
|
4505
4585
|
const force = flags.booleans.has("--force");
|
|
4506
4586
|
const previousLock = await readSourceLock(ctx.cwd);
|
|
4507
4587
|
const localFilesBeforePull = await collectLocalSourceFiles(ctx.cwd);
|
|
@@ -4521,15 +4601,19 @@ async function gemSourcePull(ctx, args, linkedProject) {
|
|
|
4521
4601
|
}
|
|
4522
4602
|
let sourceVersionId = findSourceVersionId(tree);
|
|
4523
4603
|
const files = {};
|
|
4604
|
+
const pulledFiles = [];
|
|
4524
4605
|
for (const filePath of filePaths) {
|
|
4525
4606
|
const readResult = unwrapToolResult(await executeOperation(ctx, "gem.fs_read", {
|
|
4526
4607
|
path: gemFilePath(gemPath, filePath)
|
|
4527
4608
|
}));
|
|
4528
4609
|
sourceVersionId = sourceVersionId ?? findSourceVersionId(readResult);
|
|
4529
4610
|
const content = extractRemoteFileContent(readResult, filePath);
|
|
4530
|
-
|
|
4611
|
+
pulledFiles.push({ path: filePath, content });
|
|
4531
4612
|
files[filePath] = sha256Hex(content);
|
|
4532
4613
|
}
|
|
4614
|
+
for (const file of pulledFiles) {
|
|
4615
|
+
await writePulledSourceFile(ctx.cwd, file.path, file.content);
|
|
4616
|
+
}
|
|
4533
4617
|
const pruned = await pruneRemoteDeletedSourceFiles(ctx.cwd, previousLock, localFilesBeforePull, new Set(filePaths));
|
|
4534
4618
|
const lock = {
|
|
4535
4619
|
...sourceVersionId === undefined ? {} : { sourceVersionId },
|
|
@@ -4548,11 +4632,11 @@ async function gemSourcePull(ctx, args, linkedProject) {
|
|
|
4548
4632
|
}
|
|
4549
4633
|
async function gemSourceStatus(ctx, args, linkedProject) {
|
|
4550
4634
|
const flags = parseLocalFlags(args);
|
|
4551
|
-
const gemPath = gemPathFromArgs(flags
|
|
4635
|
+
const gemPath = gemPathFromArgs(flags, linkedProject);
|
|
4552
4636
|
const lock = await readSourceLock(ctx.cwd);
|
|
4553
4637
|
const localFiles = await collectLocalSourceFiles(ctx.cwd);
|
|
4554
4638
|
const localStatus = compareSourceLock(lock, localFiles);
|
|
4555
|
-
const remote = await
|
|
4639
|
+
const remote = await remoteSourceOperation(ctx, "gem.fs_status", {
|
|
4556
4640
|
path: gemPath,
|
|
4557
4641
|
...lock.sourceVersionId === undefined ? {} : { base: lock.sourceVersionId }
|
|
4558
4642
|
});
|
|
@@ -4567,12 +4651,12 @@ async function gemSourceStatus(ctx, args, linkedProject) {
|
|
|
4567
4651
|
}
|
|
4568
4652
|
async function gemSourceDiff(ctx, args, linkedProject) {
|
|
4569
4653
|
const flags = parseLocalFlags(args);
|
|
4570
|
-
const gemPath = gemPathFromArgs(flags
|
|
4654
|
+
const gemPath = gemPathFromArgs(flags, linkedProject);
|
|
4571
4655
|
const lock = await readSourceLock(ctx.cwd);
|
|
4572
4656
|
const localFiles = await collectLocalSourceFiles(ctx.cwd);
|
|
4573
4657
|
const localStatus = compareSourceLock(lock, localFiles);
|
|
4574
4658
|
const mode = flags.values["--mode"] ?? "name_status";
|
|
4575
|
-
const remote = await
|
|
4659
|
+
const remote = await remoteSourceOperation(ctx, "gem.fs_diff", {
|
|
4576
4660
|
path: gemPath,
|
|
4577
4661
|
mode,
|
|
4578
4662
|
...lock.sourceVersionId === undefined ? {} : { base: lock.sourceVersionId }
|
|
@@ -4588,7 +4672,7 @@ async function gemSourceDiff(ctx, args, linkedProject) {
|
|
|
4588
4672
|
}
|
|
4589
4673
|
async function gemSourcePush(ctx, args, linkedProject) {
|
|
4590
4674
|
const flags = parseLocalFlags(args);
|
|
4591
|
-
const gemPath = gemPathFromArgs(flags
|
|
4675
|
+
const gemPath = gemPathFromArgs(flags, linkedProject);
|
|
4592
4676
|
const lock = await readSourceLock(ctx.cwd);
|
|
4593
4677
|
const force = flags.booleans.has("--force");
|
|
4594
4678
|
const localFiles = await collectLocalSourceFiles(ctx.cwd);
|
|
@@ -4615,6 +4699,9 @@ async function gemSourcePush(ctx, args, linkedProject) {
|
|
|
4615
4699
|
}));
|
|
4616
4700
|
sourceCas = nextSourceMutationCas(sourceCas, syncResult);
|
|
4617
4701
|
} catch (error) {
|
|
4702
|
+
if (error instanceof CliError && error.exitCode === ExitCode.Conflict) {
|
|
4703
|
+
throw error;
|
|
4704
|
+
}
|
|
4618
4705
|
if (isConflictLikeError(error)) {
|
|
4619
4706
|
throw new CliError(error instanceof Error ? error.message : "Gem source conflict", { code: ExitCode.Conflict, cause: error });
|
|
4620
4707
|
}
|
|
@@ -4780,18 +4867,11 @@ function dirtyPullErrorMessage(status) {
|
|
|
4780
4867
|
Run \`uru status\` to inspect them, save or push your changes, or re-run \`uru pull --force\` to replace local files with server source.
|
|
4781
4868
|
${preview}${moreLine}`;
|
|
4782
4869
|
}
|
|
4783
|
-
async function
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
};
|
|
4789
|
-
} catch (error) {
|
|
4790
|
-
return {
|
|
4791
|
-
available: false,
|
|
4792
|
-
error: error instanceof Error ? error.message : "Remote operation failed"
|
|
4793
|
-
};
|
|
4794
|
-
}
|
|
4870
|
+
async function remoteSourceOperation(ctx, operationId, params) {
|
|
4871
|
+
return {
|
|
4872
|
+
available: true,
|
|
4873
|
+
result: unwrapToolResult(await executeOperation(ctx, operationId, params))
|
|
4874
|
+
};
|
|
4795
4875
|
}
|
|
4796
4876
|
function formatRemoteSummary(remote) {
|
|
4797
4877
|
if (!remote.available) {
|
|
@@ -4937,6 +5017,7 @@ function isConflictLikeError(error) {
|
|
|
4937
5017
|
|
|
4938
5018
|
// src/token-env-secret-commands.ts
|
|
4939
5019
|
import { spawn as spawn2 } from "node:child_process";
|
|
5020
|
+
import { StringDecoder } from "node:string_decoder";
|
|
4940
5021
|
import { chmod, mkdir as mkdir6, readFile as readFile6, writeFile as writeFile6 } from "node:fs/promises";
|
|
4941
5022
|
import { dirname as dirname5, resolve as resolve5 } from "node:path";
|
|
4942
5023
|
async function dispatchTokens(ctx, sub, args, linkedProject) {
|
|
@@ -5188,48 +5269,69 @@ function unquoteEnvValue(value) {
|
|
|
5188
5269
|
}
|
|
5189
5270
|
async function runEnvCommand(ctx, command, envVars) {
|
|
5190
5271
|
const executable = requireCommandValue(command[0], "env run command is required");
|
|
5191
|
-
const
|
|
5272
|
+
const redactions = Object.values(envVars).filter((value) => value.length > 0);
|
|
5273
|
+
const code = await spawnStreaming(executable, command.slice(1), {
|
|
5192
5274
|
cwd: ctx.cwd,
|
|
5193
|
-
env: { ...process.env, ...envVars }
|
|
5275
|
+
env: { ...process.env, ...envVars },
|
|
5276
|
+
redactions,
|
|
5277
|
+
stdout: ctx.io.stdout,
|
|
5278
|
+
stderr: ctx.io.stderr
|
|
5194
5279
|
});
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
const stderr = redactValues2(result.stderr, redactions);
|
|
5198
|
-
if (stdout.length > 0) {
|
|
5199
|
-
ctx.io.stdout.write(stdout);
|
|
5200
|
-
}
|
|
5201
|
-
if (stderr.length > 0) {
|
|
5202
|
-
ctx.io.stderr.write(stderr);
|
|
5203
|
-
}
|
|
5204
|
-
if (result.code !== 0) {
|
|
5205
|
-
throw new CliError(`env run failed with exit code ${result.code}`);
|
|
5280
|
+
if (code !== 0) {
|
|
5281
|
+
throw new CliError(`env run failed with exit code ${code}`);
|
|
5206
5282
|
}
|
|
5207
5283
|
}
|
|
5208
|
-
async function
|
|
5284
|
+
async function spawnStreaming(command, args, options) {
|
|
5209
5285
|
return new Promise((resolvePromise, reject) => {
|
|
5210
5286
|
const child = spawn2(command, [...args], {
|
|
5211
5287
|
cwd: options.cwd,
|
|
5212
5288
|
env: options.env,
|
|
5213
|
-
stdio: ["
|
|
5289
|
+
stdio: ["inherit", "pipe", "pipe"]
|
|
5214
5290
|
});
|
|
5215
|
-
const stdout =
|
|
5216
|
-
const stderr =
|
|
5291
|
+
const stdout = redactingLineWriter(options.stdout, options.redactions);
|
|
5292
|
+
const stderr = redactingLineWriter(options.stderr, options.redactions);
|
|
5217
5293
|
child.stdout?.on("data", (chunk) => {
|
|
5218
|
-
stdout.
|
|
5294
|
+
stdout.write(chunk);
|
|
5219
5295
|
});
|
|
5220
5296
|
child.stderr?.on("data", (chunk) => {
|
|
5221
|
-
stderr.
|
|
5297
|
+
stderr.write(chunk);
|
|
5222
5298
|
});
|
|
5223
5299
|
child.on("error", reject);
|
|
5224
5300
|
child.on("close", (code) => {
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
stderr: stderr.join("")
|
|
5229
|
-
});
|
|
5301
|
+
stdout.end();
|
|
5302
|
+
stderr.end();
|
|
5303
|
+
resolvePromise(code ?? 1);
|
|
5230
5304
|
});
|
|
5231
5305
|
});
|
|
5232
5306
|
}
|
|
5307
|
+
function redactingLineWriter(destination, redactions) {
|
|
5308
|
+
const decoder = new StringDecoder("utf8");
|
|
5309
|
+
let buffered = "";
|
|
5310
|
+
const flushCompleteLines = () => {
|
|
5311
|
+
let newline = buffered.indexOf(`
|
|
5312
|
+
`);
|
|
5313
|
+
while (newline !== -1) {
|
|
5314
|
+
destination.write(redactValues2(buffered.slice(0, newline + 1), redactions));
|
|
5315
|
+
buffered = buffered.slice(newline + 1);
|
|
5316
|
+
newline = buffered.indexOf(`
|
|
5317
|
+
`);
|
|
5318
|
+
}
|
|
5319
|
+
};
|
|
5320
|
+
return {
|
|
5321
|
+
write: (chunk) => {
|
|
5322
|
+
buffered += decoder.write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
5323
|
+
flushCompleteLines();
|
|
5324
|
+
},
|
|
5325
|
+
end: () => {
|
|
5326
|
+
buffered += decoder.end();
|
|
5327
|
+
flushCompleteLines();
|
|
5328
|
+
if (buffered.length > 0) {
|
|
5329
|
+
destination.write(redactValues2(buffered, redactions));
|
|
5330
|
+
buffered = "";
|
|
5331
|
+
}
|
|
5332
|
+
}
|
|
5333
|
+
};
|
|
5334
|
+
}
|
|
5233
5335
|
function redactValues2(content, values) {
|
|
5234
5336
|
let redacted = content;
|
|
5235
5337
|
const ordered = [...new Set(values)].filter((value) => value.length > 0).sort((left, right) => right.length - left.length);
|
|
@@ -5377,7 +5479,7 @@ async function runCli(options) {
|
|
|
5377
5479
|
const explicitGemRef = parsed.flags.gem ?? envGemId;
|
|
5378
5480
|
const apiUrl = parsed.flags.apiUrl ?? envApiUrl ?? config.apiUrl ?? DEFAULT_API_URL;
|
|
5379
5481
|
const token = flagToken ?? envToken ?? await resolveStoredToken(credentialStore, apiUrl, config);
|
|
5380
|
-
const cwd = parsed.flags.cwd ??
|
|
5482
|
+
const cwd = parsed.flags.cwd ?? process.cwd();
|
|
5381
5483
|
const linkedProjectFromDisk = await readLinkedProject(cwd);
|
|
5382
5484
|
const linkedProject = explicitGemRef === undefined ? linkedProjectFromDisk : linkedProjectWithExplicitGemRef(linkedProjectFromDisk, explicitGemRef);
|
|
5383
5485
|
const workspace = parsed.flags.workspace ?? envWorkspace ?? linkedProject.workspaceId ?? config.workspace;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uru-intelligence/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.56",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Uru full-platform command line interface",
|
|
6
6
|
"type": "module",
|
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@uru/platform-operations": "workspace:*",
|
|
34
|
-
"@types/node": "24.13.
|
|
34
|
+
"@types/node": "24.13.3",
|
|
35
35
|
"bun-types": "1.3.13",
|
|
36
|
-
"typescript": "7.0.
|
|
36
|
+
"typescript": "7.0.2"
|
|
37
37
|
},
|
|
38
38
|
"packageManager": "bun@1.3.13",
|
|
39
39
|
"engines": {
|
|
40
|
-
"node": "24
|
|
40
|
+
"node": ">=24"
|
|
41
41
|
},
|
|
42
42
|
"files": [
|
|
43
43
|
"dist",
|