@levr-one/cli 0.10.19 → 0.10.21
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/{addHandler-r0Yw1vu-.js → addHandler-DUulKXOX.js} +68 -68
- package/dist/appendHandler-DkbMvFOn.js +80 -0
- package/dist/artifact-upload-BnqeVY_b.js +296 -0
- package/dist/attachHandler-BOxIqxAw.js +151 -0
- package/dist/cli.js +237 -17
- package/dist/connect-CPybjrXT.js +36 -0
- package/dist/{currentHandler-BBHqC26D.js → currentHandler-B_sWXNeW.js} +1 -1
- package/dist/{importHandler-DptPgXYU.js → importHandler-oENkrali.js} +8 -8
- package/dist/{listHandler-Ct_-wWi2.js → listHandler-E666F9uV.js} +5 -5
- package/dist/{loginHandler-CVxKJV6A.js → loginHandler-DS29PzLz.js} +5 -10
- package/dist/{logoutHandler-BFutKash.js → logoutHandler-TSQlZGpU.js} +2 -2
- package/dist/{pushHandler-MQdf0TVK.js → pushHandler-CR5vu3ci.js} +142 -9
- package/dist/{resolve-token-DbQsmn03.js → resolve-token-7xb7kG7h.js} +2 -2
- package/dist/{resolve-workspace-BrmiCTJO.js → resolve-workspace-Dsm8Xzut.js} +2 -2
- package/dist/{runHandler-BTCT0Ugi.js → runHandler-B2DlFleh.js} +8 -8
- package/dist/{sdk-client-SXw7oTbQ.js → sdk-client-B_urshDp.js} +334 -73
- package/dist/{selectHandler-Co3MDgXz.js → selectHandler-Cv5fJl-p.js} +5 -5
- package/dist/sleep-BpJ39Ypm.js +7 -0
- package/dist/{statusHandler-Cu4DULGh.js → statusHandler-CwO5kl3m.js} +3 -3
- package/dist/{token-refresh-Cu5RpkLJ.js → token-refresh-DeusLK8H.js} +1 -1
- package/package.json +1 -1
- /package/dist/{env-CHeKHu5S.js → env-CdwyPHGV.js} +0 -0
- /package/dist/{workspace-store-DDOxnut1.js → workspace-store-CnrxyYRB.js} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getApiUrl } from "./env-
|
|
1
|
+
import { getApiUrl } from "./env-CdwyPHGV.js";
|
|
2
2
|
import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { basename, delimiter, dirname, join, resolve } from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
|
@@ -90,9 +90,9 @@ function renderTomlBodyLines(value, pathPrefix) {
|
|
|
90
90
|
lines.push(`${renderTomlKey(key)} = ${renderTomlValue(v)}`);
|
|
91
91
|
}
|
|
92
92
|
for (const [key, v] of nested) {
|
|
93
|
-
const path = [...pathPrefix, key];
|
|
94
|
-
lines.push("", `[${path.map(renderTomlKey).join(".")}]`);
|
|
95
|
-
lines.push(...renderTomlBodyLines(v, path));
|
|
93
|
+
const path$1 = [...pathPrefix, key];
|
|
94
|
+
lines.push("", `[${path$1.map(renderTomlKey).join(".")}]`);
|
|
95
|
+
lines.push(...renderTomlBodyLines(v, path$1));
|
|
96
96
|
}
|
|
97
97
|
return lines;
|
|
98
98
|
}
|
|
@@ -970,17 +970,17 @@ function readServerEntry(harness, scope, configPath, cwdKey, parseJsonc) {
|
|
|
970
970
|
return getAtPath(parseJsonc(text), entryPathFor(harness, scope, cwdKey));
|
|
971
971
|
}
|
|
972
972
|
/** Read a text file, or `null` if it doesn't exist / can't be read. */
|
|
973
|
-
function readTextOrNull(path) {
|
|
973
|
+
function readTextOrNull(path$1) {
|
|
974
974
|
try {
|
|
975
|
-
return readFileSync(path, "utf8");
|
|
975
|
+
return readFileSync(path$1, "utf8");
|
|
976
976
|
} catch {
|
|
977
977
|
return null;
|
|
978
978
|
}
|
|
979
979
|
}
|
|
980
980
|
/** Safe nested lookup over an unknown-typed parsed JSON value. */
|
|
981
|
-
function getAtPath(obj, path) {
|
|
981
|
+
function getAtPath(obj, path$1) {
|
|
982
982
|
let cur = obj;
|
|
983
|
-
for (const key of path) {
|
|
983
|
+
for (const key of path$1) {
|
|
984
984
|
if (cur === null || typeof cur !== "object") return void 0;
|
|
985
985
|
cur = cur[key];
|
|
986
986
|
}
|
|
@@ -1057,35 +1057,35 @@ function parseDocument$1(text) {
|
|
|
1057
1057
|
}
|
|
1058
1058
|
const jsoncAdapter = {
|
|
1059
1059
|
empty: "{}",
|
|
1060
|
-
readAt(text, path) {
|
|
1060
|
+
readAt(text, path$1) {
|
|
1061
1061
|
if (text.trim() === "") return { kind: "absent" };
|
|
1062
1062
|
const doc = parseDocument$1(text);
|
|
1063
1063
|
if (!doc.ok) return {
|
|
1064
1064
|
kind: "unsupported",
|
|
1065
1065
|
detail: doc.detail
|
|
1066
1066
|
};
|
|
1067
|
-
const value = getAtPath(doc.root, path);
|
|
1067
|
+
const value = getAtPath(doc.root, path$1);
|
|
1068
1068
|
return value === void 0 ? { kind: "absent" } : {
|
|
1069
1069
|
kind: "value",
|
|
1070
1070
|
value
|
|
1071
1071
|
};
|
|
1072
1072
|
},
|
|
1073
|
-
setAt(text, path, value) {
|
|
1074
|
-
return edit(text, path, value);
|
|
1073
|
+
setAt(text, path$1, value) {
|
|
1074
|
+
return edit(text, path$1, value);
|
|
1075
1075
|
},
|
|
1076
|
-
removeAt(text, path) {
|
|
1077
|
-
return edit(text, path, void 0);
|
|
1076
|
+
removeAt(text, path$1) {
|
|
1077
|
+
return edit(text, path$1, void 0);
|
|
1078
1078
|
}
|
|
1079
1079
|
};
|
|
1080
1080
|
/** Shared by set and remove: jsonc-parser removes a key when `value` is `undefined`. */
|
|
1081
|
-
function edit(text, path, value) {
|
|
1081
|
+
function edit(text, path$1, value) {
|
|
1082
1082
|
const doc = parseDocument$1(text);
|
|
1083
1083
|
if (!doc.ok) throw new UnsupportedConfigShapeError(doc.detail);
|
|
1084
1084
|
try {
|
|
1085
|
-
return applyEdits(text, modify(text, path, value, { formattingOptions: FORMAT }));
|
|
1085
|
+
return applyEdits(text, modify(text, path$1, value, { formattingOptions: FORMAT }));
|
|
1086
1086
|
} catch (err) {
|
|
1087
1087
|
const message = err instanceof Error ? err.message : String(err);
|
|
1088
|
-
throw new UnsupportedConfigShapeError(`cannot edit path ${path.join(".")}: ${message}`);
|
|
1088
|
+
throw new UnsupportedConfigShapeError(`cannot edit path ${path$1.join(".")}: ${message}`);
|
|
1089
1089
|
}
|
|
1090
1090
|
}
|
|
1091
1091
|
|
|
@@ -1267,8 +1267,8 @@ function probeHeader(doc, idx) {
|
|
|
1267
1267
|
function samePath(a, b) {
|
|
1268
1268
|
return a.length === b.length && a.every((s, i) => s === b[i]);
|
|
1269
1269
|
}
|
|
1270
|
-
function isSubPath(path, prefix) {
|
|
1271
|
-
return path.length > prefix.length && prefix.every((s, i) => s === path[i]);
|
|
1270
|
+
function isSubPath(path$1, prefix) {
|
|
1271
|
+
return path$1.length > prefix.length && prefix.every((s, i) => s === path$1[i]);
|
|
1272
1272
|
}
|
|
1273
1273
|
/**
|
|
1274
1274
|
* Locate our table: the header line index and the index just past its body.
|
|
@@ -1280,12 +1280,12 @@ function isSubPath(path, prefix) {
|
|
|
1280
1280
|
* scanner cannot read, or one whose probe breaks the document, still ends
|
|
1281
1281
|
* the body. Misjudging a line can only make our region smaller.
|
|
1282
1282
|
*/
|
|
1283
|
-
function locateTable(doc, path) {
|
|
1283
|
+
function locateTable(doc, path$1) {
|
|
1284
1284
|
const { lines } = doc;
|
|
1285
1285
|
let start = -1;
|
|
1286
1286
|
for (let i = 0; i < lines.length; i++) {
|
|
1287
1287
|
const hp = headerPathOf(lines[i]);
|
|
1288
|
-
if (hp && samePath(hp, path) && probeHeader(doc, i) === "real") {
|
|
1288
|
+
if (hp && samePath(hp, path$1) && probeHeader(doc, i) === "real") {
|
|
1289
1289
|
start = i;
|
|
1290
1290
|
break;
|
|
1291
1291
|
}
|
|
@@ -1299,7 +1299,7 @@ function locateTable(doc, path) {
|
|
|
1299
1299
|
const verdict = probeHeader(doc, i);
|
|
1300
1300
|
if (verdict === "text") continue;
|
|
1301
1301
|
const hp = headerPathOf(lines[i]);
|
|
1302
|
-
if (hp && isSubPath(hp, path) && verdict === "real") continue;
|
|
1302
|
+
if (hp && isSubPath(hp, path$1) && verdict === "real") continue;
|
|
1303
1303
|
end = i;
|
|
1304
1304
|
break;
|
|
1305
1305
|
}
|
|
@@ -1309,49 +1309,49 @@ function locateTable(doc, path) {
|
|
|
1309
1309
|
end
|
|
1310
1310
|
};
|
|
1311
1311
|
}
|
|
1312
|
-
function requireEditable(text, path) {
|
|
1312
|
+
function requireEditable(text, path$1) {
|
|
1313
1313
|
const parsed = parseDocument(text);
|
|
1314
1314
|
if (!parsed.ok) throw new UnsupportedConfigShapeError(parsed.detail);
|
|
1315
1315
|
return {
|
|
1316
1316
|
doc: splitLines(text),
|
|
1317
|
-
exists: getAtPath(parsed.root, path) !== void 0
|
|
1317
|
+
exists: getAtPath(parsed.root, path$1) !== void 0
|
|
1318
1318
|
};
|
|
1319
1319
|
}
|
|
1320
|
-
function notStandalone(path) {
|
|
1321
|
-
return new UnsupportedConfigShapeError(`${path.join(".")} exists but not as a standalone [${path.join(".")}] table (inline table or dotted key) — refusing to restructure it`);
|
|
1320
|
+
function notStandalone(path$1) {
|
|
1321
|
+
return new UnsupportedConfigShapeError(`${path$1.join(".")} exists but not as a standalone [${path$1.join(".")}] table (inline table or dotted key) — refusing to restructure it`);
|
|
1322
1322
|
}
|
|
1323
1323
|
const tomlAdapter = {
|
|
1324
1324
|
empty: "",
|
|
1325
1325
|
backupSuffix: TOML_BACKUP_SUFFIX,
|
|
1326
|
-
readAt(text, path) {
|
|
1326
|
+
readAt(text, path$1) {
|
|
1327
1327
|
if (stripBom(text).trim() === "") return { kind: "absent" };
|
|
1328
1328
|
const doc = parseDocument(text);
|
|
1329
1329
|
if (!doc.ok) return {
|
|
1330
1330
|
kind: "unsupported",
|
|
1331
1331
|
detail: doc.detail
|
|
1332
1332
|
};
|
|
1333
|
-
const value = getAtPath(doc.root, path);
|
|
1333
|
+
const value = getAtPath(doc.root, path$1);
|
|
1334
1334
|
return value === void 0 ? { kind: "absent" } : {
|
|
1335
1335
|
kind: "value",
|
|
1336
1336
|
value
|
|
1337
1337
|
};
|
|
1338
1338
|
},
|
|
1339
|
-
setAt(text, path, value) {
|
|
1339
|
+
setAt(text, path$1, value) {
|
|
1340
1340
|
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new UnsupportedConfigShapeError(`a TOML table body must be an object, got ${value === null ? "null" : Array.isArray(value) ? "array" : typeof value}`);
|
|
1341
1341
|
const body = value;
|
|
1342
1342
|
const bom = text.startsWith(BOM) ? BOM : "";
|
|
1343
1343
|
const inner = stripBom(text);
|
|
1344
|
-
if (inner.trim() === "") return bom + renderTable(path, body, inner.includes("\r\n") ? "\r\n" : "\n");
|
|
1345
|
-
const { doc, exists } = requireEditable(inner, path);
|
|
1346
|
-
const table = locateTable(doc, path);
|
|
1344
|
+
if (inner.trim() === "") return bom + renderTable(path$1, body, inner.includes("\r\n") ? "\r\n" : "\n");
|
|
1345
|
+
const { doc, exists } = requireEditable(inner, path$1);
|
|
1346
|
+
const table = locateTable(doc, path$1);
|
|
1347
1347
|
if (!table) {
|
|
1348
|
-
if (exists) throw notStandalone(path);
|
|
1348
|
+
if (exists) throw notStandalone(path$1);
|
|
1349
1349
|
const { eol } = doc;
|
|
1350
1350
|
let base = inner.endsWith("\n") ? inner : inner + eol;
|
|
1351
1351
|
if (!/\r?\n\r?\n$/.test(base)) base += eol;
|
|
1352
|
-
return bom + base + renderTable(path, body, eol);
|
|
1352
|
+
return bom + base + renderTable(path$1, body, eol);
|
|
1353
1353
|
}
|
|
1354
|
-
const rendered = renderTomlBodyLines(body, path);
|
|
1354
|
+
const rendered = renderTomlBodyLines(body, path$1);
|
|
1355
1355
|
const atEof = table.end === doc.lines.length;
|
|
1356
1356
|
return bom + joinLines([
|
|
1357
1357
|
...doc.lines.slice(0, table.start + 1),
|
|
@@ -1363,14 +1363,14 @@ const tomlAdapter = {
|
|
|
1363
1363
|
...doc.eols.slice(table.end)
|
|
1364
1364
|
]);
|
|
1365
1365
|
},
|
|
1366
|
-
removeAt(text, path) {
|
|
1366
|
+
removeAt(text, path$1) {
|
|
1367
1367
|
const bom = text.startsWith(BOM) ? BOM : "";
|
|
1368
1368
|
const inner = stripBom(text);
|
|
1369
1369
|
if (inner.trim() === "") return text;
|
|
1370
|
-
const { doc, exists } = requireEditable(inner, path);
|
|
1370
|
+
const { doc, exists } = requireEditable(inner, path$1);
|
|
1371
1371
|
if (!exists) return text;
|
|
1372
|
-
const table = locateTable(doc, path);
|
|
1373
|
-
if (!table) throw notStandalone(path);
|
|
1372
|
+
const table = locateTable(doc, path$1);
|
|
1373
|
+
if (!table) throw notStandalone(path$1);
|
|
1374
1374
|
const lines = [...doc.lines.slice(0, table.start), ...doc.lines.slice(table.end)];
|
|
1375
1375
|
const eols = [...doc.eols.slice(0, table.start), ...doc.eols.slice(table.end)];
|
|
1376
1376
|
const at = table.start;
|
|
@@ -1386,8 +1386,8 @@ const tomlAdapter = {
|
|
|
1386
1386
|
return bom + joinLines(lines, eols);
|
|
1387
1387
|
}
|
|
1388
1388
|
};
|
|
1389
|
-
function renderTable(path, body, eol) {
|
|
1390
|
-
return [`[${path.map(renderTomlKey).join(".")}]`, ...renderTomlBodyLines(body, path)].join(eol) + eol;
|
|
1389
|
+
function renderTable(path$1, body, eol) {
|
|
1390
|
+
return [`[${path$1.map(renderTomlKey).join(".")}]`, ...renderTomlBodyLines(body, path$1)].join(eol) + eol;
|
|
1391
1391
|
}
|
|
1392
1392
|
|
|
1393
1393
|
//#endregion
|
|
@@ -1565,9 +1565,9 @@ function resolveTarget(harness, env, scope) {
|
|
|
1565
1565
|
reason: "scope-collision",
|
|
1566
1566
|
collidesWith: collides
|
|
1567
1567
|
};
|
|
1568
|
-
const path = resolveConfigPath(harness, env, scope);
|
|
1569
|
-
if (!path) return { reason: "no-location" };
|
|
1570
|
-
return { path };
|
|
1568
|
+
const path$1 = resolveConfigPath(harness, env, scope);
|
|
1569
|
+
if (!path$1) return { reason: "no-location" };
|
|
1570
|
+
return { path: path$1 };
|
|
1571
1571
|
}
|
|
1572
1572
|
/**
|
|
1573
1573
|
* What the client currently holds for this scope, read from its own config.
|
|
@@ -1683,36 +1683,36 @@ function installHarnessSync(harness, mcpUrl, opts = {}) {
|
|
|
1683
1683
|
reason: target.reason,
|
|
1684
1684
|
...target.collidesWith ? { collidesWith: target.collidesWith } : {}
|
|
1685
1685
|
};
|
|
1686
|
-
const { path } = target;
|
|
1686
|
+
const { path: path$1 } = target;
|
|
1687
1687
|
const entryValue = buildServerEntry(harness, mcpUrl, scope)[SERVER_NAME];
|
|
1688
1688
|
const modPath = entryPathFor(harness, scope, env.cwd);
|
|
1689
1689
|
const adapter = adapterFor(harness);
|
|
1690
|
-
const existing = readTextOrNull(path);
|
|
1690
|
+
const existing = readTextOrNull(path$1);
|
|
1691
1691
|
const baseText = existing && existing.trim() ? existing : adapter.empty;
|
|
1692
1692
|
const current = adapter.readAt(baseText, modPath);
|
|
1693
|
-
if (current.kind === "unsupported") return unsupportedShape(path, dryRun, scope, current.detail);
|
|
1693
|
+
if (current.kind === "unsupported") return unsupportedShape(path$1, dryRun, scope, current.detail);
|
|
1694
1694
|
const alreadyConfigured = current.kind === "value" && sameValue(current.value, entryValue);
|
|
1695
1695
|
let nextText;
|
|
1696
1696
|
try {
|
|
1697
1697
|
nextText = adapter.setAt(baseText, modPath, entryValue);
|
|
1698
1698
|
} catch (err) {
|
|
1699
|
-
if (err instanceof UnsupportedConfigShapeError) return unsupportedShape(path, dryRun, scope, err.detail);
|
|
1699
|
+
if (err instanceof UnsupportedConfigShapeError) return unsupportedShape(path$1, dryRun, scope, err.detail);
|
|
1700
1700
|
throw err;
|
|
1701
1701
|
}
|
|
1702
1702
|
if (alreadyConfigured) return {
|
|
1703
1703
|
ok: true,
|
|
1704
1704
|
wrote: false,
|
|
1705
|
-
path,
|
|
1705
|
+
path: path$1,
|
|
1706
1706
|
alreadyConfigured: true,
|
|
1707
1707
|
dryRun,
|
|
1708
1708
|
scope,
|
|
1709
1709
|
preview: nextText
|
|
1710
1710
|
};
|
|
1711
|
-
const backupPath = backupPathFor(path, adapter.backupSuffix);
|
|
1711
|
+
const backupPath = backupPathFor(path$1, adapter.backupSuffix);
|
|
1712
1712
|
if (dryRun) return {
|
|
1713
1713
|
ok: true,
|
|
1714
1714
|
wrote: false,
|
|
1715
|
-
path,
|
|
1715
|
+
path: path$1,
|
|
1716
1716
|
alreadyConfigured: false,
|
|
1717
1717
|
dryRun: true,
|
|
1718
1718
|
scope,
|
|
@@ -1721,16 +1721,16 @@ function installHarnessSync(harness, mcpUrl, opts = {}) {
|
|
|
1721
1721
|
};
|
|
1722
1722
|
const finalText = nextText.endsWith("\n") ? nextText : `${nextText}\n`;
|
|
1723
1723
|
try {
|
|
1724
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
1725
|
-
if (backupPath) backupOnce(path, backupPath);
|
|
1726
|
-
writeConfigAtomic(path, finalText);
|
|
1724
|
+
mkdirSync(dirname(path$1), { recursive: true });
|
|
1725
|
+
if (backupPath) backupOnce(path$1, backupPath);
|
|
1726
|
+
writeConfigAtomic(path$1, finalText);
|
|
1727
1727
|
} catch (err) {
|
|
1728
|
-
return writeFailed(path, scope, err);
|
|
1728
|
+
return writeFailed(path$1, scope, err);
|
|
1729
1729
|
}
|
|
1730
1730
|
return {
|
|
1731
1731
|
ok: true,
|
|
1732
1732
|
wrote: true,
|
|
1733
|
-
path,
|
|
1733
|
+
path: path$1,
|
|
1734
1734
|
alreadyConfigured: false,
|
|
1735
1735
|
dryRun: false,
|
|
1736
1736
|
scope,
|
|
@@ -1743,21 +1743,21 @@ function installHarnessSync(harness, mcpUrl, opts = {}) {
|
|
|
1743
1743
|
* asks for one — `undefined` when the format does not, or when there is no
|
|
1744
1744
|
* original to protect yet.
|
|
1745
1745
|
*/
|
|
1746
|
-
function backupPathFor(path, suffix) {
|
|
1747
|
-
if (!suffix || !existsSync(path)) return void 0;
|
|
1748
|
-
return `${path}${suffix}`;
|
|
1746
|
+
function backupPathFor(path$1, suffix) {
|
|
1747
|
+
if (!suffix || !existsSync(path$1)) return void 0;
|
|
1748
|
+
return `${path$1}${suffix}`;
|
|
1749
1749
|
}
|
|
1750
1750
|
/** Copy the original once. An existing backup is never overwritten. */
|
|
1751
|
-
function backupOnce(path, backupPath) {
|
|
1751
|
+
function backupOnce(path$1, backupPath) {
|
|
1752
1752
|
if (existsSync(backupPath)) return;
|
|
1753
|
-
copyFileSync(path, backupPath);
|
|
1753
|
+
copyFileSync(path$1, backupPath);
|
|
1754
1754
|
}
|
|
1755
1755
|
/** The refusal every format shares: the file is there, and we will not touch it. */
|
|
1756
|
-
function unsupportedShape(path, dryRun, scope, detail) {
|
|
1756
|
+
function unsupportedShape(path$1, dryRun, scope, detail) {
|
|
1757
1757
|
return {
|
|
1758
1758
|
ok: false,
|
|
1759
1759
|
wrote: false,
|
|
1760
|
-
path,
|
|
1760
|
+
path: path$1,
|
|
1761
1761
|
alreadyConfigured: false,
|
|
1762
1762
|
dryRun,
|
|
1763
1763
|
scope,
|
|
@@ -1766,11 +1766,11 @@ function unsupportedShape(path, dryRun, scope, detail) {
|
|
|
1766
1766
|
};
|
|
1767
1767
|
}
|
|
1768
1768
|
/** The filesystem said no: report it per client instead of aborting the run. */
|
|
1769
|
-
function writeFailed(path, scope, err) {
|
|
1769
|
+
function writeFailed(path$1, scope, err) {
|
|
1770
1770
|
return {
|
|
1771
1771
|
ok: false,
|
|
1772
1772
|
wrote: false,
|
|
1773
|
-
path,
|
|
1773
|
+
path: path$1,
|
|
1774
1774
|
alreadyConfigured: false,
|
|
1775
1775
|
dryRun: false,
|
|
1776
1776
|
scope,
|
|
@@ -1788,11 +1788,11 @@ function writeFailed(path, scope, err) {
|
|
|
1788
1788
|
* This matters more than it did: a harness config can be the file that also
|
|
1789
1789
|
* holds a user's model providers, profiles and sandbox policy (review F-005).
|
|
1790
1790
|
*/
|
|
1791
|
-
function writeConfigAtomic(path, text) {
|
|
1792
|
-
let target = path;
|
|
1791
|
+
function writeConfigAtomic(path$1, text) {
|
|
1792
|
+
let target = path$1;
|
|
1793
1793
|
let mode;
|
|
1794
1794
|
try {
|
|
1795
|
-
target = realpathSync(path);
|
|
1795
|
+
target = realpathSync(path$1);
|
|
1796
1796
|
mode = statSync(target).mode & 511;
|
|
1797
1797
|
} catch {}
|
|
1798
1798
|
const tmp = join(dirname(target), `.${basename(target)}.${process.pid}.tmp`);
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { appendActualResult } from "./sdk-client-B_urshDp.js";
|
|
2
|
+
import "./env-CdwyPHGV.js";
|
|
3
|
+
import "./token-refresh-DeusLK8H.js";
|
|
4
|
+
import "./resolve-token-7xb7kG7h.js";
|
|
5
|
+
import "./workspace-store-CnrxyYRB.js";
|
|
6
|
+
import "./resolve-workspace-Dsm8Xzut.js";
|
|
7
|
+
import { connect } from "./connect-CPybjrXT.js";
|
|
8
|
+
import "./sleep-BpJ39Ypm.js";
|
|
9
|
+
import { embedMarkdown, parseTarget, uploadArtifactFile } from "./artifact-upload-BnqeVY_b.js";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import { basename } from "node:path";
|
|
12
|
+
|
|
13
|
+
//#region src/commands/result/appendHandler.ts
|
|
14
|
+
/**
|
|
15
|
+
* `levr result append` (ENG-6164 D4, DD4). Uploads the --attach files first
|
|
16
|
+
* (private: Levr serves their url to signed-in members, so the embedded
|
|
17
|
+
* links render there; ENG-6165 code review F-006), then sends ONE server-side
|
|
18
|
+
* `append_actual_result` carrying the text plus a markdown link per file,
|
|
19
|
+
* through PATCH /v1/run/run-result-variant/:id — the only public append that
|
|
20
|
+
* needs no run or run-result id (audit A2). fail_closed: any failed upload
|
|
21
|
+
* or a failed append exits 1; nothing is appended when an upload failed.
|
|
22
|
+
*/
|
|
23
|
+
async function resultAppendHandler(flags, targetArg) {
|
|
24
|
+
if (flags.verbose) this.logger.setVerbose(true);
|
|
25
|
+
let target;
|
|
26
|
+
try {
|
|
27
|
+
target = parseTarget(targetArg);
|
|
28
|
+
} catch (err) {
|
|
29
|
+
this.logger.error(err instanceof Error ? err.message : String(err));
|
|
30
|
+
this.process.exitCode = 1;
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (target.relatedType !== "run_result_variant") {
|
|
34
|
+
this.logger.error("levr result append takes run_result_variant:<uuid> (an execution result id).");
|
|
35
|
+
this.process.exitCode = 1;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (flags.text === void 0 === (flags.file === void 0)) {
|
|
39
|
+
this.logger.error("Provide exactly one of --text or --file.");
|
|
40
|
+
this.process.exitCode = 1;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
let text;
|
|
44
|
+
try {
|
|
45
|
+
text = flags.text ?? readFileSync(flags.file, "utf8");
|
|
46
|
+
} catch (err) {
|
|
47
|
+
this.logger.error(`Cannot read ${flags.file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
48
|
+
this.process.exitCode = 1;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (!await connect(this, flags["workspace-id"])) return;
|
|
52
|
+
const links = [];
|
|
53
|
+
for (const file of flags.attach ?? []) {
|
|
54
|
+
const result = await uploadArtifactFile({
|
|
55
|
+
target,
|
|
56
|
+
filePath: file
|
|
57
|
+
});
|
|
58
|
+
if ((result.status === "uploaded" || result.status === "deduplicated") && result.url) {
|
|
59
|
+
links.push(embedMarkdown(basename(file), result.url));
|
|
60
|
+
this.process.stdout.write(` attached ${file} (${result.id})\n`);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const why = result.status === "skipped" ? "larger than 50 MiB" : result.status === "missing" ? "not found" : "message" in result ? result.message : result.status;
|
|
64
|
+
this.logger.error(`failed ${file}: ${why}`);
|
|
65
|
+
this.process.exitCode = 1;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const appendText = [text.trimEnd(), ...links].filter((t) => t).join("\n");
|
|
69
|
+
try {
|
|
70
|
+
await appendActualResult(target.relatedId, appendText);
|
|
71
|
+
} catch (err) {
|
|
72
|
+
this.logger.error(err instanceof Error ? err.message : String(err));
|
|
73
|
+
this.process.exitCode = 1;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
this.process.stdout.write(`Appended to ${target.relatedId}${links.length ? ` with ${links.length} attachment(s)` : ""}.\n`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
//#endregion
|
|
80
|
+
export { resultAppendHandler };
|