@moda-ai/cli 1.55.26 → 1.55.27
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/{agent-nqmha8ck.js → agent-vp9prdma.js} +8 -8
- package/dist/{cli-k6q8dbpk.js → cli-0pkc8jhg.js} +3 -3
- package/dist/{cli-5g1tv80h.js → cli-4h0ave0f.js} +5 -5
- package/dist/{cli-8tfk8qeb.js → cli-6et4z504.js} +7 -6
- package/dist/{cli-1mbb0ct0.js → cli-ccjfwzqx.js} +1 -1
- package/dist/{cli-q6f6vrrr.js → cli-hmjdgxrn.js} +1 -1
- package/dist/{cli-jtyvbd8d.js → cli-pg5qfmqc.js} +1 -1
- package/dist/{cli-b4740tnv.js → cli-q9nsvqqg.js} +14 -14
- package/dist/{cli-d577kq6h.js → cli-qwgct6x7.js} +7 -6
- package/dist/{cli-sqsjd08w.js → cli-r5pp7qny.js} +64 -438
- package/dist/{cli-cdrvjva5.js → cli-v8q7sd7g.js} +28 -6
- package/dist/cli-vdkwkkp5.js +567 -0
- package/dist/{cli-jgfm7w1r.js → cli-wzds257x.js} +5 -4
- package/dist/cli.js +299 -151
- package/dist/{doctor-w913fj4g.js → doctor-wmre3mr7.js} +8 -8
- package/dist/{fix-crkwdkt4.js → fix-75s9s0d6.js} +45 -47
- package/dist/{harness-x3e7d68b.js → harness-a7tb9a23.js} +5 -5
- package/dist/{harness-github-actions-fjhvhgpj.js → harness-github-actions-6v4wydb8.js} +5 -5
- package/dist/{index-2kf3fnnb.js → index-91bpc8g8.js} +15 -14
- package/dist/{production-intelligence-7n83c701.js → production-intelligence-7nqddd4f.js} +15 -15
- package/dist/{profile-commands-ct2t0bfr.js → profile-commands-49yn02yg.js} +5 -4
- package/dist/prompt-source-mcp.js +5 -5
- package/dist/{prompts-92aqqb2k.js → prompts-17wyrst6.js} +6 -6
- package/dist/{provision-gn8raqpt.js → provision-bc3h68e1.js} +5 -5
- package/dist/{registry-ex162j5y.js → registry-fpzhjznj.js} +3 -3
- package/dist/{skills-2mbsj9bt.js → skills-ccdbqghj.js} +5 -5
- package/dist/{sync-kghmmmk5.js → sync-hkxce5zh.js} +7 -7
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
- package/dist/cli-bb7133m7.js +0 -144
|
@@ -449,6 +449,14 @@ function resolveBaseUrl(options = {}) {
|
|
|
449
449
|
return PROD_BASE_URL;
|
|
450
450
|
}
|
|
451
451
|
}
|
|
452
|
+
function resolveBaseUrlStrict(options = {}) {
|
|
453
|
+
try {
|
|
454
|
+
getActiveProfile(options);
|
|
455
|
+
} catch {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
return resolveBaseUrl(options);
|
|
459
|
+
}
|
|
452
460
|
function resolveIngestUrl(options = {}) {
|
|
453
461
|
const environment = activeProfileEnvironment(options);
|
|
454
462
|
const envIngest = optionalString(getEnv(options).MODA_INGEST_URL);
|
|
@@ -668,6 +676,9 @@ var MODA_INGEST_URL = process.env.MODA_INGEST_URL || DEFAULT_INGEST_URL;
|
|
|
668
676
|
function resolveModaBaseUrl(options = {}) {
|
|
669
677
|
return resolveBaseUrl(options) || PROD_BASE_URL;
|
|
670
678
|
}
|
|
679
|
+
function resolveModaBaseUrlStrict(options = {}) {
|
|
680
|
+
return resolveBaseUrlStrict(options);
|
|
681
|
+
}
|
|
671
682
|
function validateConfig() {
|
|
672
683
|
if (!resolveApiKey()) {
|
|
673
684
|
throw new CliAuthError('No Moda API key found. Set MODA_API_KEY=moda_sk_... in the environment, save one with "moda auth login --api-key", or run "moda init" for interactive setup.', {
|
|
@@ -1029,425 +1040,13 @@ function packSnapshot(inputs, opts) {
|
|
|
1029
1040
|
skips
|
|
1030
1041
|
};
|
|
1031
1042
|
}
|
|
1032
|
-
// src/
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
var BATCH_CONCURRENCY = 4;
|
|
1036
|
-
var ANCHOR_SUFFIX = /^(.+)@(\d+)$/;
|
|
1037
|
-
function parseBatchTarget(text, anchors, usage) {
|
|
1038
|
-
const raw = text.trim();
|
|
1039
|
-
if (raw.startsWith("{")) {
|
|
1040
|
-
let parsed;
|
|
1041
|
-
try {
|
|
1042
|
-
parsed = JSON.parse(raw);
|
|
1043
|
-
} catch {
|
|
1044
|
-
throw new CliInputError(`Could not parse the JSON target ${JSON.stringify(raw)}.`, usage, "bad_batch_target");
|
|
1045
|
-
}
|
|
1046
|
-
const record = parsed;
|
|
1047
|
-
const id = record?.id ?? record?.conversation_id ?? record?.trace_id;
|
|
1048
|
-
if (typeof id !== "string" || id.trim() === "") {
|
|
1049
|
-
throw new CliInputError(`JSON target ${JSON.stringify(raw)} has no "id" string.`, usage, "bad_batch_target");
|
|
1050
|
-
}
|
|
1051
|
-
const index = record.msg_index ?? record.message_index;
|
|
1052
|
-
if (index !== undefined && index !== null) {
|
|
1053
|
-
if (!anchors) {
|
|
1054
|
-
throw new CliInputError(`JSON target ${JSON.stringify(raw)} has a msg_index, which this command does not take.`, usage, "bad_batch_target");
|
|
1055
|
-
}
|
|
1056
|
-
if (typeof index !== "number" || !Number.isSafeInteger(index) || index < 0) {
|
|
1057
|
-
throw new CliInputError(`JSON target ${JSON.stringify(raw)} has an invalid msg_index (want an integer >= 0).`, usage, "bad_batch_target");
|
|
1058
|
-
}
|
|
1059
|
-
return { raw, id, msgIndex: index };
|
|
1060
|
-
}
|
|
1061
|
-
return { raw, id };
|
|
1062
|
-
}
|
|
1063
|
-
if (anchors) {
|
|
1064
|
-
const match = ANCHOR_SUFFIX.exec(raw);
|
|
1065
|
-
if (match) {
|
|
1066
|
-
const msgIndex = Number(match[2]);
|
|
1067
|
-
if (!Number.isSafeInteger(msgIndex)) {
|
|
1068
|
-
throw new CliInputError(`Target ${JSON.stringify(raw)} has an @msg_index past ${Number.MAX_SAFE_INTEGER}. ` + 'If the id itself ends in @<digits>, pass it as {"id": "..."}.', usage, "bad_batch_target");
|
|
1069
|
-
}
|
|
1070
|
-
return { raw, id: match[1], msgIndex };
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
return { raw, id: raw };
|
|
1074
|
-
}
|
|
1075
|
-
function parseTargetLines(text, anchors, usage) {
|
|
1076
|
-
return text.split(/\r?\n/).map((line) => line.trim()).filter((line) => line !== "").map((line) => parseBatchTarget(line, anchors, usage));
|
|
1077
|
-
}
|
|
1078
|
-
async function readStdinText() {
|
|
1079
|
-
if (process.stdin.isTTY) {
|
|
1080
|
-
throw new CliInputError("--ids-from=- reads targets from stdin, but stdin is a terminal. Pipe ids in (one per line) or pass a file path.", undefined, "ids_from_tty");
|
|
1081
|
-
}
|
|
1082
|
-
const chunks = [];
|
|
1083
|
-
for await (const chunk of process.stdin)
|
|
1084
|
-
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
1085
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
1086
|
-
}
|
|
1087
|
-
async function readIdsFrom(source, usage) {
|
|
1088
|
-
if (source === "" || source === "true") {
|
|
1089
|
-
throw new CliInputError("--ids-from needs a value: - (stdin) or a file path.", usage, "missing_flag_value");
|
|
1090
|
-
}
|
|
1091
|
-
if (source === "-")
|
|
1092
|
-
return readStdinText();
|
|
1093
|
-
try {
|
|
1094
|
-
return await readFile(source, "utf8");
|
|
1095
|
-
} catch (error) {
|
|
1096
|
-
const code = error.code;
|
|
1097
|
-
throw new CliInputError(`Could not read --ids-from file ${JSON.stringify(source)}${typeof code === "string" ? ` (${code})` : ""}.`, usage, "ids_from_unreadable");
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
async function collectBatchTargets(positionals, idsFrom, options) {
|
|
1101
|
-
const targets = positionals.map((value) => parseBatchTarget(value, options.anchors, options.usage));
|
|
1102
|
-
if (idsFrom !== undefined) {
|
|
1103
|
-
targets.push(...parseTargetLines(await readIdsFrom(idsFrom, options.usage), options.anchors, options.usage));
|
|
1104
|
-
}
|
|
1105
|
-
const seen = new Set;
|
|
1106
|
-
const unique = targets.filter((target) => {
|
|
1107
|
-
const key = `${target.id}\x00${target.msgIndex ?? ""}`;
|
|
1108
|
-
if (seen.has(key))
|
|
1109
|
-
return false;
|
|
1110
|
-
seen.add(key);
|
|
1111
|
-
return true;
|
|
1112
|
-
});
|
|
1113
|
-
if (unique.length === 0) {
|
|
1114
|
-
throw new CliInputError(`No targets: --ids-from gave no ids (one per line).`, options.usage, "missing_positional");
|
|
1115
|
-
}
|
|
1116
|
-
if (unique.length > BATCH_MAX_TARGETS) {
|
|
1117
|
-
throw new CliInputError(`Got ${unique.length} targets; 'moda ${options.command}' reads at most ${BATCH_MAX_TARGETS} per call, so nothing was read. ` + `Split the ids into calls of ${BATCH_MAX_TARGETS} or fewer.`, options.usage, "batch_too_large");
|
|
1118
|
-
}
|
|
1119
|
-
return unique;
|
|
1120
|
-
}
|
|
1121
|
-
async function mapWithConcurrency(items, limit, fn, options = {}) {
|
|
1122
|
-
const results = new Array(items.length);
|
|
1123
|
-
let next = 0;
|
|
1124
|
-
let failure;
|
|
1125
|
-
const worker = async () => {
|
|
1126
|
-
while (!failure && next < items.length && (options.shouldStart?.(next) ?? true)) {
|
|
1127
|
-
const index = next++;
|
|
1128
|
-
try {
|
|
1129
|
-
results[index] = await fn(items[index], index);
|
|
1130
|
-
} catch (error) {
|
|
1131
|
-
failure ??= { error };
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
};
|
|
1135
|
-
await Promise.all(Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, worker));
|
|
1136
|
-
if (failure)
|
|
1137
|
-
throw failure.error;
|
|
1138
|
-
return next < items.length ? results.slice(0, next) : results;
|
|
1139
|
-
}
|
|
1140
|
-
function idNeedsJsonTarget(id) {
|
|
1141
|
-
return ANCHOR_SUFFIX.test(id);
|
|
1142
|
-
}
|
|
1143
|
-
function contextTarget(id) {
|
|
1144
|
-
const verbatim = id === id.trim() && !id.startsWith("{") && !idNeedsJsonTarget(id);
|
|
1145
|
-
return verbatim ? id : JSON.stringify({ id });
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
// src/transforms.ts
|
|
1149
|
-
function asRecord(value) {
|
|
1150
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1043
|
+
// src/shell-quote.ts
|
|
1044
|
+
function shellArg(value) {
|
|
1045
|
+
if (/^[A-Za-z0-9_.,:@%+/=-]+$/.test(value))
|
|
1151
1046
|
return value;
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
}
|
|
1155
|
-
function asString(value) {
|
|
1156
|
-
return typeof value === "string" ? value : null;
|
|
1157
|
-
}
|
|
1158
|
-
function asNumber(value) {
|
|
1159
|
-
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
1160
|
-
}
|
|
1161
|
-
function frustrationAnchorIndex(row) {
|
|
1162
|
-
if (!row)
|
|
1163
|
-
return null;
|
|
1164
|
-
const userQuotes = Array.isArray(row.user_quotes) ? row.user_quotes : [];
|
|
1165
|
-
const firstQuote = asRecord(userQuotes[0]);
|
|
1166
|
-
const resolved = asNumber(firstQuote?.msg_index) ?? asNumber(row.anchor_msg_index);
|
|
1167
|
-
if (resolved !== null)
|
|
1168
|
-
return resolved;
|
|
1169
|
-
const keyTurns = Array.isArray(row.key_turns) ? row.key_turns : [];
|
|
1170
|
-
const firstTurn = keyTurns.find((t) => typeof t === "number");
|
|
1171
|
-
if (firstTurn !== undefined)
|
|
1172
|
-
return firstTurn;
|
|
1173
|
-
return asNumber(firstQuote?.turn);
|
|
1174
|
-
}
|
|
1175
|
-
function buildFrustrationAnchor(row) {
|
|
1176
|
-
const conversation_id = asString(row.conversation_id) ?? "";
|
|
1177
|
-
const userQuotes = Array.isArray(row.user_quotes) ? row.user_quotes : [];
|
|
1178
|
-
const firstQuote = asRecord(userQuotes[0]);
|
|
1179
|
-
const keyTurnsRaw = Array.isArray(row.key_turns) ? row.key_turns : [];
|
|
1180
|
-
const all_turns = keyTurnsRaw.filter((t) => typeof t === "number");
|
|
1181
|
-
const msg_index = frustrationAnchorIndex(row);
|
|
1182
|
-
let signal = null;
|
|
1183
|
-
let quote_preview = null;
|
|
1184
|
-
if (firstQuote) {
|
|
1185
|
-
signal = asString(firstQuote.signal);
|
|
1186
|
-
const quote = asString(firstQuote.quote);
|
|
1187
|
-
if (quote !== null) {
|
|
1188
|
-
let end = 0;
|
|
1189
|
-
let points = 0;
|
|
1190
|
-
for (const ch of quote) {
|
|
1191
|
-
if (points++ === 200)
|
|
1192
|
-
break;
|
|
1193
|
-
end += ch.length;
|
|
1194
|
-
}
|
|
1195
|
-
quote_preview = quote.slice(0, end);
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
return {
|
|
1199
|
-
kind: "frustration",
|
|
1200
|
-
conversation_id,
|
|
1201
|
-
msg_index,
|
|
1202
|
-
signal,
|
|
1203
|
-
quote_preview,
|
|
1204
|
-
all_turns,
|
|
1205
|
-
no_anchor: msg_index === null
|
|
1206
|
-
};
|
|
1207
|
-
}
|
|
1208
|
-
function buildToolFailureAnchor(row, toolName) {
|
|
1209
|
-
const conversation_id = asString(row.conversation_id) ?? "";
|
|
1210
|
-
const msg_index = asNumber(row.msg_index);
|
|
1211
|
-
const tool_use_id = asString(row.tool_use_id);
|
|
1212
|
-
const error_subtype = asString(row.error_subtype);
|
|
1213
|
-
return {
|
|
1214
|
-
kind: "tool_failure",
|
|
1215
|
-
conversation_id,
|
|
1216
|
-
msg_index,
|
|
1217
|
-
tool_name: toolName,
|
|
1218
|
-
tool_use_id,
|
|
1219
|
-
error_subtype,
|
|
1220
|
-
no_anchor: msg_index === null
|
|
1221
|
-
};
|
|
1222
|
-
}
|
|
1223
|
-
function frustrationsFromEmotions(response) {
|
|
1224
|
-
if (!Array.isArray(response.detections) || Array.isArray(response.frustrations))
|
|
1225
|
-
return response;
|
|
1226
|
-
const summary = asRecord(response.summary) ?? {};
|
|
1227
|
-
const pagination = asRecord(response.pagination) ?? {};
|
|
1228
|
-
const byFamily = asRecord(summary.by_family) ?? {};
|
|
1229
|
-
const totalAnalyzed = asNumber(summary.conversations_analyzed) ?? 0;
|
|
1230
|
-
const byFamilyConversations = asRecord(summary.conversations_by_family);
|
|
1231
|
-
const frustrated = asNumber(byFamilyConversations?.frustration) ?? asNumber(byFamily.frustration) ?? 0;
|
|
1232
|
-
const frustrations = response.detections.map((item) => asRecord(item)).filter((row) => row !== null && (row.family === undefined || row.family === "frustration")).map(({ conversation_context, score, is_detected, ...row }) => ({
|
|
1233
|
-
...row,
|
|
1234
|
-
is_frustrated: is_detected === true,
|
|
1235
|
-
frustration_score: score,
|
|
1236
|
-
target: row.elicitor === "bot" || row.elicitor === "external" ? row.elicitor : "ambiguous",
|
|
1237
|
-
conversation: conversation_context ?? null
|
|
1238
|
-
}));
|
|
1239
|
-
const atRisk = asNumber(pagination.at_risk) ?? Math.max(0, (asNumber(pagination.total) ?? 0) - frustrated);
|
|
1240
|
-
const signalBreakdown = {};
|
|
1241
|
-
for (const item of Array.isArray(response.signal_breakdown) ? response.signal_breakdown : []) {
|
|
1242
|
-
const row = asRecord(item);
|
|
1243
|
-
if (row?.family === "frustration" && typeof row.signal === "string") {
|
|
1244
|
-
signalBreakdown[row.signal] = asNumber(row.count) ?? 0;
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
const { detections: _detections, ...rest } = response;
|
|
1248
|
-
return {
|
|
1249
|
-
...rest,
|
|
1250
|
-
summary: {
|
|
1251
|
-
total_analyzed: totalAnalyzed,
|
|
1252
|
-
frustrated_count: frustrated,
|
|
1253
|
-
at_risk_count: atRisk,
|
|
1254
|
-
frustration_rate_pct: totalAnalyzed > 0 ? Math.round(frustrated / totalAnalyzed * 1000) / 10 : 0
|
|
1255
|
-
},
|
|
1256
|
-
signal_breakdown: signalBreakdown,
|
|
1257
|
-
frustrations,
|
|
1258
|
-
source: "emotion_detections"
|
|
1259
|
-
};
|
|
1260
|
-
}
|
|
1261
|
-
function withFrustrationAnchors(response) {
|
|
1262
|
-
if (!Array.isArray(response.frustrations))
|
|
1263
|
-
return response;
|
|
1264
|
-
const frustrations = response.frustrations.map((item) => {
|
|
1265
|
-
const row = asRecord(item);
|
|
1266
|
-
if (!row)
|
|
1267
|
-
return item;
|
|
1268
|
-
const anchor = buildFrustrationAnchor(row);
|
|
1269
|
-
return { ...row, anchor };
|
|
1270
|
-
});
|
|
1271
|
-
return { ...response, frustrations };
|
|
1272
|
-
}
|
|
1273
|
-
var TOOL_FAILURE_CONTEXT_RADIUS = 2;
|
|
1274
|
-
function shellWord(value) {
|
|
1275
|
-
return /^[\w@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\\''`)}'`;
|
|
1276
|
-
}
|
|
1277
|
-
function trimFailureWindow(value, radius, fallbackCenter) {
|
|
1278
|
-
const conv = asRecord(value);
|
|
1279
|
-
if (!conv)
|
|
1280
|
-
return value ?? null;
|
|
1281
|
-
const { coverage: _coverage, context, ...convRest } = conv;
|
|
1282
|
-
const ctx = asRecord(context);
|
|
1283
|
-
if (!ctx)
|
|
1284
|
-
return convRest;
|
|
1285
|
-
const center = asNumber(ctx.center_index) ?? fallbackCenter;
|
|
1286
|
-
const messages = (Array.isArray(ctx.messages) ? ctx.messages : []).map((message) => asRecord(message)).filter((message) => {
|
|
1287
|
-
const index = asNumber(message?.index);
|
|
1288
|
-
return message !== null && (center === null || index === null || Math.abs(index - center) <= radius);
|
|
1289
|
-
}).map(({ content_blocks, ...message }) => {
|
|
1290
|
-
const covered = typeof message.content === "string" && message.content.length > 0 || Array.isArray(message.tool_calls) && message.tool_calls.length > 0 || Array.isArray(message.tool_results) && message.tool_results.length > 0;
|
|
1291
|
-
return covered || content_blocks === undefined ? message : { ...message, content_blocks };
|
|
1292
|
-
});
|
|
1293
|
-
const indexes = messages.map((message) => asNumber(message.index)).filter((index) => index !== null);
|
|
1294
|
-
return {
|
|
1295
|
-
...convRest,
|
|
1296
|
-
context: {
|
|
1297
|
-
...ctx,
|
|
1298
|
-
...indexes.length > 0 ? { from_index: Math.min(...indexes), to_index: Math.max(...indexes) } : {},
|
|
1299
|
-
messages
|
|
1300
|
-
}
|
|
1301
|
-
};
|
|
1302
|
-
}
|
|
1303
|
-
function trimToolFailureConversations(response, opts) {
|
|
1304
|
-
if (!Array.isArray(response.examples))
|
|
1305
|
-
return response;
|
|
1306
|
-
const examples = response.examples.map((item) => {
|
|
1307
|
-
const row = asRecord(item);
|
|
1308
|
-
if (!row)
|
|
1309
|
-
return item;
|
|
1310
|
-
const { conversation, window, ...rest } = row;
|
|
1311
|
-
const conversationId = asString(row.conversation_id);
|
|
1312
|
-
const msgIndex = asNumber(asRecord(row.anchor)?.msg_index) ?? asNumber(row.msg_index);
|
|
1313
|
-
return {
|
|
1314
|
-
...rest,
|
|
1315
|
-
...conversationId && msgIndex !== null ? { context_command: `moda traces get ${shellWord(contextTarget(conversationId))} --msg-index=${msgIndex} --window=${TOOL_FAILURE_CONTEXT_RADIUS}` } : {},
|
|
1316
|
-
...opts.drop ? {} : { conversation: trimFailureWindow(conversation, TOOL_FAILURE_CONTEXT_RADIUS, msgIndex) },
|
|
1317
|
-
..."window" in row ? { window: trimFailureWindow(window, opts.windowRadius ?? TOOL_FAILURE_CONTEXT_RADIUS, msgIndex) } : {}
|
|
1318
|
-
};
|
|
1319
|
-
});
|
|
1320
|
-
return { ...response, examples };
|
|
1321
|
-
}
|
|
1322
|
-
function withToolFailureAnchors(response) {
|
|
1323
|
-
if (!Array.isArray(response.examples))
|
|
1324
|
-
return response;
|
|
1325
|
-
const toolName = asString(response.tool_name) ?? "";
|
|
1326
|
-
const examples = response.examples.map((item) => {
|
|
1327
|
-
const row = asRecord(item);
|
|
1328
|
-
if (!row)
|
|
1329
|
-
return item;
|
|
1330
|
-
const anchor = buildToolFailureAnchor(row, toolName);
|
|
1331
|
-
return { ...row, anchor };
|
|
1332
|
-
});
|
|
1333
|
-
return { ...response, examples };
|
|
1334
|
-
}
|
|
1335
|
-
function embeddedWindowSize(conversation) {
|
|
1336
|
-
if (!conversation)
|
|
1337
|
-
return null;
|
|
1338
|
-
const ctx = asRecord(conversation.context);
|
|
1339
|
-
if (!ctx)
|
|
1340
|
-
return null;
|
|
1341
|
-
const center = asNumber(ctx.center_index);
|
|
1342
|
-
const from = asNumber(ctx.from_index);
|
|
1343
|
-
const to = asNumber(ctx.to_index);
|
|
1344
|
-
if (center === null || from === null || to === null)
|
|
1345
|
-
return null;
|
|
1346
|
-
return Math.min(center - from, to - center);
|
|
1347
|
-
}
|
|
1348
|
-
var DETECTION_CONTEXT_RADIUS = 2;
|
|
1349
|
-
function withoutDetectionWindows(response, listKey, windowKey) {
|
|
1350
|
-
const list = response[listKey];
|
|
1351
|
-
if (!Array.isArray(list))
|
|
1352
|
-
return response;
|
|
1353
|
-
const rows = list.map((item) => {
|
|
1354
|
-
const row = asRecord(item);
|
|
1355
|
-
if (!row)
|
|
1356
|
-
return item;
|
|
1357
|
-
const { [windowKey]: _window, ...rest } = row;
|
|
1358
|
-
const conversationId = asString(row.conversation_id);
|
|
1359
|
-
const msgIndex = asNumber(asRecord(row.anchor)?.msg_index) ?? frustrationAnchorIndex(row);
|
|
1360
|
-
return {
|
|
1361
|
-
...rest,
|
|
1362
|
-
...conversationId && msgIndex !== null ? { context_command: `moda traces get ${shellWord(contextTarget(conversationId))} --msg-index=${msgIndex} --window=${DETECTION_CONTEXT_RADIUS}` } : {}
|
|
1363
|
-
};
|
|
1364
|
-
});
|
|
1365
|
-
return { ...response, [listKey]: rows };
|
|
1366
|
-
}
|
|
1367
|
-
var PROBLEM_COMPACT_EVIDENCE = 5;
|
|
1368
|
-
var PROBLEM_COMPACT_OMITTED_BLOCKS = [
|
|
1369
|
-
"rubric",
|
|
1370
|
-
"trend",
|
|
1371
|
-
"sub_problems",
|
|
1372
|
-
"affected_conversations",
|
|
1373
|
-
"remainder",
|
|
1374
|
-
"confidence",
|
|
1375
|
-
"change_history",
|
|
1376
|
-
"stories"
|
|
1377
|
-
];
|
|
1378
|
-
function readCommand(command, purpose) {
|
|
1379
|
-
return { command, purpose, mutability: "read", requires_approval: false };
|
|
1380
|
-
}
|
|
1381
|
-
function evidenceMsgIndex(row) {
|
|
1382
|
-
return asNumber(row.anchor_msg_index) ?? asNumber(asRecord(asRecord(row.snippet_parsed)?.anchor)?.msg_index);
|
|
1383
|
-
}
|
|
1384
|
-
function compactProblemDossier(response, problemId) {
|
|
1385
|
-
const id = shellWord(asString(response.problem_id) ?? problemId);
|
|
1386
|
-
const evidence = (Array.isArray(response.evidence) ? response.evidence : []).map((item) => asRecord(item)).filter((row) => row !== null);
|
|
1387
|
-
const topEvidence = evidence.slice(0, PROBLEM_COMPACT_EVIDENCE).map((row) => {
|
|
1388
|
-
const conversationId = asString(row.conversation_id);
|
|
1389
|
-
const msgIndex = evidenceMsgIndex(row);
|
|
1390
|
-
return {
|
|
1391
|
-
attribution_id: row.attribution_id ?? null,
|
|
1392
|
-
conversation_id: conversationId,
|
|
1393
|
-
msg_index: msgIndex,
|
|
1394
|
-
signal_family: row.signal_family ?? null,
|
|
1395
|
-
signal_type: row.signal_type ?? null,
|
|
1396
|
-
confidence: row.confidence ?? null,
|
|
1397
|
-
causal_rationale: row.causal_rationale ?? null,
|
|
1398
|
-
door: row.door ?? null,
|
|
1399
|
-
replay_verified: row.replay_verified ?? null,
|
|
1400
|
-
...conversationId && msgIndex !== null ? { context_command: `moda traces get ${shellWord(contextTarget(conversationId))} --msg-index=${msgIndex}` } : {}
|
|
1401
|
-
};
|
|
1402
|
-
});
|
|
1403
|
-
const reportsBlock = asRecord(response.investigation_reports);
|
|
1404
|
-
const reports = (Array.isArray(reportsBlock?.items) ? reportsBlock.items : []).map((item) => asRecord(item)).filter((row) => row !== null).map((row) => ({
|
|
1405
|
-
report_id: row.report_id ?? null,
|
|
1406
|
-
conversation_id: row.conversation_id ?? null,
|
|
1407
|
-
mechanism: row.mechanism ?? null,
|
|
1408
|
-
suspected_surface: row.suspected_surface ?? null,
|
|
1409
|
-
severity: row.severity ?? null,
|
|
1410
|
-
problem_found: row.problem_found ?? null
|
|
1411
|
-
}));
|
|
1412
|
-
const verification = asRecord(response.verification);
|
|
1413
|
-
const { samples: _samples, ...verificationCounts } = verification ?? {};
|
|
1414
|
-
const dossier = asRecord(response.dossier);
|
|
1415
|
-
const { representative_story_keys: _storyKeys, ...dossierSummary } = dossier ?? {};
|
|
1416
|
-
const trend = Array.isArray(response.trend) ? response.trend : [];
|
|
1417
|
-
const data = {
|
|
1418
|
-
found: response.found ?? true,
|
|
1419
|
-
problem_id: response.problem_id ?? problemId,
|
|
1420
|
-
requested_problem_id: response.requested_problem_id ?? problemId,
|
|
1421
|
-
alias_resolved: response.alias_resolved ?? false,
|
|
1422
|
-
view: "compact",
|
|
1423
|
-
header: response.header ?? null,
|
|
1424
|
-
dossier: dossier ? dossierSummary : null,
|
|
1425
|
-
verification: verification ? verificationCounts : null,
|
|
1426
|
-
...response.impact_identity !== undefined ? { impact_identity: response.impact_identity } : {},
|
|
1427
|
-
...response.hierarchy !== undefined ? { hierarchy: response.hierarchy } : {},
|
|
1428
|
-
...trend.length > 0 ? { trend_latest: trend[trend.length - 1], trend_points: trend.length } : {},
|
|
1429
|
-
top_evidence: topEvidence,
|
|
1430
|
-
evidence_in_dossier: evidence.length,
|
|
1431
|
-
reports,
|
|
1432
|
-
omitted: {
|
|
1433
|
-
evidence_rows: Math.max(0, evidence.length - topEvidence.length),
|
|
1434
|
-
report_narratives: reports.length,
|
|
1435
|
-
reports_has_more: reportsBlock?.has_more === true,
|
|
1436
|
-
blocks: PROBLEM_COMPACT_OMITTED_BLOCKS.filter((key) => (key in response))
|
|
1437
|
-
},
|
|
1438
|
-
full_command: `moda problems get ${id} --full`
|
|
1439
|
-
};
|
|
1440
|
-
const nextCommands = [
|
|
1441
|
-
readCommand(`moda problems get ${id} --evidence --limit=20`, "Page every evidence row with its anchor (follow next_cursor)."),
|
|
1442
|
-
readCommand(`moda problems get ${id} --reports`, "Page investigation reports with narratives and citations."),
|
|
1443
|
-
readCommand(`moda problems get ${id} --traces`, "Page affected traces with their latest anchor."),
|
|
1444
|
-
readCommand(`moda problems get ${id} --full`, "The complete dossier, every block (large).")
|
|
1445
|
-
];
|
|
1446
|
-
const first = topEvidence.find((row) => typeof row.context_command === "string");
|
|
1447
|
-
if (first?.context_command) {
|
|
1448
|
-
nextCommands.push(readCommand(first.context_command, "Read the trace around the top evidence anchor."));
|
|
1449
|
-
}
|
|
1450
|
-
return { data, nextCommands };
|
|
1047
|
+
if (!/["$`\\!]/.test(value))
|
|
1048
|
+
return `"${value}"`;
|
|
1049
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
1451
1050
|
}
|
|
1452
1051
|
|
|
1453
1052
|
// src/legacy-names.ts
|
|
@@ -1618,8 +1217,8 @@ function canonicalCommandText(text) {
|
|
|
1618
1217
|
|
|
1619
1218
|
// src/output.ts
|
|
1620
1219
|
import { randomUUID } from "node:crypto";
|
|
1621
|
-
import { lstatSync, mkdirSync as mkdirSync2, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1622
|
-
import { tmpdir } from "node:os";
|
|
1220
|
+
import { chmodSync as chmodSync2, lstatSync, mkdirSync as mkdirSync2, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1221
|
+
import { tmpdir, userInfo } from "node:os";
|
|
1623
1222
|
import { join as join2 } from "node:path";
|
|
1624
1223
|
var SUGGESTION_KEY = /(_commands?|^hints?|^suggestions?)$/i;
|
|
1625
1224
|
function canonicalDeep(value, rewriteStrings) {
|
|
@@ -1713,7 +1312,7 @@ var CUSTOMER_CONTENT_KEYS = new Set([
|
|
|
1713
1312
|
"response"
|
|
1714
1313
|
]);
|
|
1715
1314
|
function withProfileOnCommands(value, profile) {
|
|
1716
|
-
const flag = `--profile=${
|
|
1315
|
+
const flag = `--profile=${shellArg(profile)}`;
|
|
1717
1316
|
const visit = (node, key, inCommandList) => {
|
|
1718
1317
|
const isCommandKey = key !== undefined && (GENERATED_COMMAND_KEY.test(key) || inCommandList && key === "command");
|
|
1719
1318
|
if (typeof node === "string")
|
|
@@ -1722,7 +1321,7 @@ function withProfileOnCommands(value, profile) {
|
|
|
1722
1321
|
const list = key !== undefined && GENERATED_COMMAND_LIST_KEY.test(key);
|
|
1723
1322
|
return node.map((item) => typeof item === "string" ? visit(item, isCommandKey ? key : undefined, false) : visit(item, undefined, list));
|
|
1724
1323
|
}
|
|
1725
|
-
const record =
|
|
1324
|
+
const record = asRecord(node);
|
|
1726
1325
|
if (!record)
|
|
1727
1326
|
return node;
|
|
1728
1327
|
return Object.fromEntries(Object.entries(record).map(([entryKey, entry]) => [
|
|
@@ -2493,11 +2092,11 @@ function normalizeSummary(summary, command, status, data) {
|
|
|
2493
2092
|
return inferSummary(command, status, data);
|
|
2494
2093
|
}
|
|
2495
2094
|
function inferSummary(command, status, data) {
|
|
2496
|
-
const record =
|
|
2095
|
+
const record = asRecord(data);
|
|
2497
2096
|
if (status === "error") {
|
|
2498
2097
|
return { text: `${command} failed.`, confidence: "high" };
|
|
2499
2098
|
}
|
|
2500
|
-
const summary =
|
|
2099
|
+
const summary = asRecord(record?.summary);
|
|
2501
2100
|
if (summary) {
|
|
2502
2101
|
const statusValue = typeof summary.status === "string" ? summary.status : undefined;
|
|
2503
2102
|
const fail = typeof summary.fail === "number" ? summary.fail : undefined;
|
|
@@ -2549,11 +2148,11 @@ function inferMutability(command) {
|
|
|
2549
2148
|
return "read";
|
|
2550
2149
|
}
|
|
2551
2150
|
function inferWarnings(data) {
|
|
2552
|
-
const record =
|
|
2151
|
+
const record = asRecord(data);
|
|
2553
2152
|
const direct = record?.warnings;
|
|
2554
2153
|
if (Array.isArray(direct))
|
|
2555
2154
|
return direct.filter((item) => typeof item === "string");
|
|
2556
|
-
const validation =
|
|
2155
|
+
const validation = asRecord(record?.validation);
|
|
2557
2156
|
if (Array.isArray(validation?.warnings)) {
|
|
2558
2157
|
return validation.warnings.filter((item) => typeof item === "string");
|
|
2559
2158
|
}
|
|
@@ -2591,10 +2190,37 @@ function pruneAgentFullOutputs(dir, keep, now = Date.now()) {
|
|
|
2591
2190
|
} catch {}
|
|
2592
2191
|
}
|
|
2593
2192
|
}
|
|
2193
|
+
function currentUserTag() {
|
|
2194
|
+
if (typeof process.getuid === "function")
|
|
2195
|
+
return String(process.getuid());
|
|
2196
|
+
try {
|
|
2197
|
+
return userInfo().username.replace(/[^A-Za-z0-9_.-]+/g, "_") || "user";
|
|
2198
|
+
} catch {
|
|
2199
|
+
return "user";
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
function defaultAgentOutputDir() {
|
|
2203
|
+
return join2(tmpdir(), `moda-agent-output-${currentUserTag()}`);
|
|
2204
|
+
}
|
|
2205
|
+
function ensurePrivateDir(dir) {
|
|
2206
|
+
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
2207
|
+
const stat = lstatSync(dir);
|
|
2208
|
+
if (!stat.isDirectory())
|
|
2209
|
+
throw new Error(`${dir} is not a directory.`);
|
|
2210
|
+
if (typeof process.getuid === "function" && stat.uid !== process.getuid()) {
|
|
2211
|
+
throw new Error(`${dir} is owned by another user.`);
|
|
2212
|
+
}
|
|
2213
|
+
if (process.platform !== "win32" && (stat.mode & 63) !== 0)
|
|
2214
|
+
chmodSync2(dir, 448);
|
|
2215
|
+
}
|
|
2594
2216
|
function writeAgentFullOutput(command, data) {
|
|
2595
2217
|
try {
|
|
2596
|
-
const
|
|
2597
|
-
|
|
2218
|
+
const configured = process.env.MODA_AGENT_OUTPUT_DIR;
|
|
2219
|
+
const dir = configured || defaultAgentOutputDir();
|
|
2220
|
+
if (configured)
|
|
2221
|
+
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
2222
|
+
else
|
|
2223
|
+
ensurePrivateDir(dir);
|
|
2598
2224
|
const slug = command.replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "output";
|
|
2599
2225
|
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
2600
2226
|
const path = join2(dir, `${slug}-${stamp}-${randomUUID().slice(0, 8)}.json`);
|
|
@@ -2615,7 +2241,7 @@ function contentBlocksRedundant(message) {
|
|
|
2615
2241
|
const hasToolResults = Array.isArray(message.tool_results) && message.tool_results.length > 0;
|
|
2616
2242
|
const texts = [];
|
|
2617
2243
|
for (const item of blocks) {
|
|
2618
|
-
const block =
|
|
2244
|
+
const block = asRecord(item);
|
|
2619
2245
|
if (!block)
|
|
2620
2246
|
return false;
|
|
2621
2247
|
if (block.type === "text") {
|
|
@@ -2647,7 +2273,7 @@ function shedRedundantContentBlocks(value) {
|
|
|
2647
2273
|
visit(item);
|
|
2648
2274
|
return;
|
|
2649
2275
|
}
|
|
2650
|
-
const record =
|
|
2276
|
+
const record = asRecord(node);
|
|
2651
2277
|
if (!record)
|
|
2652
2278
|
return;
|
|
2653
2279
|
if ("content_blocks" in record && contentBlocksRedundant(record)) {
|
|
@@ -2669,17 +2295,17 @@ function continuationCommand(invocation, overrides) {
|
|
|
2669
2295
|
const dashAt = invocation.positionals.findIndex((value) => value.startsWith("-"));
|
|
2670
2296
|
const leading = dashAt === -1 ? invocation.positionals : invocation.positionals.slice(0, dashAt);
|
|
2671
2297
|
const trailing = dashAt === -1 ? [] : invocation.positionals.slice(dashAt);
|
|
2672
|
-
const parts = ["moda", invocation.command, ...leading.map((value) =>
|
|
2298
|
+
const parts = ["moda", invocation.command, ...leading.map((value) => shellArg(value))];
|
|
2673
2299
|
for (const [key, value] of Object.entries(invocation.flags)) {
|
|
2674
2300
|
const flag = normalize2(key);
|
|
2675
2301
|
if (overridden.has(flag) || CONTINUATION_SECRET_FLAGS.has(flag))
|
|
2676
2302
|
continue;
|
|
2677
|
-
parts.push(bare.has(flag) && value === "true" ? `--${flag}` : `--${flag}=${
|
|
2303
|
+
parts.push(bare.has(flag) && value === "true" ? `--${flag}` : `--${flag}=${shellArg(String(value))}`);
|
|
2678
2304
|
}
|
|
2679
2305
|
for (const [key, value] of Object.entries(overrides))
|
|
2680
|
-
parts.push(`--${normalize2(key)}=${
|
|
2306
|
+
parts.push(`--${normalize2(key)}=${shellArg(String(value))}`);
|
|
2681
2307
|
if (trailing.length > 0)
|
|
2682
|
-
parts.push("--", ...trailing.map((value) =>
|
|
2308
|
+
parts.push("--", ...trailing.map((value) => shellArg(value)));
|
|
2683
2309
|
return canonicalCommandText(parts.join(" "));
|
|
2684
2310
|
}
|
|
2685
2311
|
var PAGED_LIST_BY_COMMAND = {
|
|
@@ -2700,7 +2326,7 @@ function rewritePagination(list, isTopLevel, invocation) {
|
|
|
2700
2326
|
const { parent, array, originalLength } = list;
|
|
2701
2327
|
if (!parent)
|
|
2702
2328
|
return;
|
|
2703
|
-
const nested =
|
|
2329
|
+
const nested = asRecord(parent.pagination);
|
|
2704
2330
|
const inline = !nested && !isTopLevel && (("has_more" in parent) || ("next_cursor" in parent)) ? parent : undefined;
|
|
2705
2331
|
const pagination = nested ?? inline;
|
|
2706
2332
|
if (!pagination)
|
|
@@ -2840,7 +2466,7 @@ function boundForAgent(data, maxBytes = agentMaxOutputBytes(), options = {}) {
|
|
|
2840
2466
|
fullOutputPath
|
|
2841
2467
|
};
|
|
2842
2468
|
}
|
|
2843
|
-
const root =
|
|
2469
|
+
const root = asRecord(bounded);
|
|
2844
2470
|
const notes = [];
|
|
2845
2471
|
const nextCommands = [];
|
|
2846
2472
|
for (const list of droppedLists.values()) {
|
|
@@ -2878,7 +2504,7 @@ function boundForAgent(data, maxBytes = agentMaxOutputBytes(), options = {}) {
|
|
|
2878
2504
|
...nextCommands.length > 0 ? { nextCommands } : {}
|
|
2879
2505
|
};
|
|
2880
2506
|
}
|
|
2881
|
-
function
|
|
2507
|
+
function asRecord(value) {
|
|
2882
2508
|
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
2883
2509
|
}
|
|
2884
2510
|
function extractSuggestedCommands(text) {
|
|
@@ -2911,4 +2537,4 @@ function apiKeyHeaders(key, options = {}, url) {
|
|
|
2911
2537
|
return headers;
|
|
2912
2538
|
}
|
|
2913
2539
|
|
|
2914
|
-
export { PROD_BASE_URL, DEFAULT_INGEST_URL, getModaPaths, getModaDir, isLoopbackBaseUrl, describeBaseUrlSource, loadProfileConfig, saveProfileConfig, getActiveProfile, setActiveProfile, upsertProfile, clearStoredApiKeyCredentials, secretFilePathFromRef, resolveSecretReference, resolveApiKeyFromActiveProfile, resolveTenantIdFromActiveProfile, ensureSecretFilePermissions, writeSecretJsonFile, CliInputError, attachInputDetails, inputDetailsOf, CliAccessError, CliInputRequiredError, CliAuthError, CliNotFoundError, CliCancellationError, isNetworkLikeError, isApiLikeError, apiErrorStatus, VERSION, MODA_BASE_URL, loadCliConfig, saveCliConfig, resolveApiKey, embeddedTenantIdFromApiKey, resolveIngestUrl2 as resolveIngestUrl, resolveTenantId, resolveApiTenantId, resolveModaBaseUrl, validateConfig, isPlatformApiKey, setPlatformTenantOverride, apiKeyHeaders, recordApiRequest, getApiRequestCount, resetApiRequestCount, MAX_SCANNED_FILE_BYTES, DEFAULT_MAX_INVENTORY_FILES, DEFAULT_MAX_INVENTORY_TEXT_BYTES, MAX_RECORDED_SKIPS, SKIPPED_DIRS, isSkippedDir, isSkippedPathPrefix, isEvalLikePath, shouldInventoryFile, isTextFile, isSecretishPath, SECRET_KEYS, redactDeep, redactString, packSnapshot,
|
|
2540
|
+
export { PROD_BASE_URL, DEFAULT_INGEST_URL, getModaPaths, getModaDir, isLoopbackBaseUrl, describeBaseUrlSource, loadProfileConfig, saveProfileConfig, getActiveProfile, setActiveProfile, upsertProfile, clearStoredApiKeyCredentials, secretFilePathFromRef, resolveSecretReference, resolveApiKeyFromActiveProfile, resolveTenantIdFromActiveProfile, ensureSecretFilePermissions, writeSecretJsonFile, CliInputError, attachInputDetails, inputDetailsOf, CliAccessError, CliInputRequiredError, CliAuthError, CliNotFoundError, CliCancellationError, isNetworkLikeError, isApiLikeError, apiErrorStatus, VERSION, MODA_BASE_URL, loadCliConfig, saveCliConfig, resolveApiKey, embeddedTenantIdFromApiKey, resolveIngestUrl2 as resolveIngestUrl, resolveTenantId, resolveApiTenantId, resolveModaBaseUrl, resolveModaBaseUrlStrict, validateConfig, isPlatformApiKey, setPlatformTenantOverride, apiKeyHeaders, recordApiRequest, getApiRequestCount, resetApiRequestCount, MAX_SCANNED_FILE_BYTES, DEFAULT_MAX_INVENTORY_FILES, DEFAULT_MAX_INVENTORY_TEXT_BYTES, MAX_RECORDED_SKIPS, SKIPPED_DIRS, isSkippedDir, isSkippedPathPrefix, isEvalLikePath, shouldInventoryFile, isTextFile, isSecretishPath, SECRET_KEYS, redactDeep, redactString, packSnapshot, shellArg, LEGACY_NAMES, canonicalCommandText, setAgentUpdateNotice, EXIT_OK, EXIT_ERROR, EXIT_DEGRADED, EXIT_AUTH_REQUIRED, EXIT_INPUT_REQUIRED, EXIT_CANCELLED, AGENT_ERROR_CODES, wasOutputCancelled, safeWriteStdout, safeWriteStderr, explicitOutputMode, outputModeFromFlags, resolveOutputMode, createCliOutput, agentEnvelopeFits, errorToAgentError, agentMaxOutputBytes, continuationCommand };
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createCliOutput,
|
|
3
3
|
outputModeFromFlags
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-r5pp7qny.js";
|
|
5
5
|
|
|
6
|
-
// src/
|
|
7
|
-
function flagEnabled(flags, key) {
|
|
8
|
-
return flags[key] === "true";
|
|
9
|
-
}
|
|
6
|
+
// src/boolean-words.ts
|
|
10
7
|
var BOOLEAN_TRUE_WORDS = new Set(["true", "yes", "1", "on"]);
|
|
11
8
|
var BOOLEAN_FALSE_WORDS = new Set(["false", "no", "0", "off"]);
|
|
12
9
|
function parseBooleanFlagValue(value) {
|
|
@@ -23,6 +20,31 @@ function parseBooleanFlagValue(value) {
|
|
|
23
20
|
return false;
|
|
24
21
|
return;
|
|
25
22
|
}
|
|
23
|
+
function flagValue(flags, name) {
|
|
24
|
+
return flags[name] ?? flags[name.replace(/-/g, "_")];
|
|
25
|
+
}
|
|
26
|
+
function withoutFlag(flags, name) {
|
|
27
|
+
const snake = name.replace(/-/g, "_");
|
|
28
|
+
return Object.fromEntries(Object.entries(flags).filter(([key]) => key !== name && key !== snake));
|
|
29
|
+
}
|
|
30
|
+
function optOutFlagSet(flags, name, strict = true) {
|
|
31
|
+
const raw = flagValue(flags, name);
|
|
32
|
+
if (raw === undefined)
|
|
33
|
+
return false;
|
|
34
|
+
const value = parseBooleanFlagValue(raw);
|
|
35
|
+
return strict ? value === true : value !== false;
|
|
36
|
+
}
|
|
37
|
+
function envSwitchedOff(value) {
|
|
38
|
+
return parseBooleanFlagValue(value) === false;
|
|
39
|
+
}
|
|
40
|
+
function envOptOutSet(value) {
|
|
41
|
+
return value !== undefined && value.trim() !== "" && parseBooleanFlagValue(value) !== false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/command-context.ts
|
|
45
|
+
function flagEnabled(flags, key) {
|
|
46
|
+
return flags[key] === "true";
|
|
47
|
+
}
|
|
26
48
|
function stringOption(value) {
|
|
27
49
|
if (value === undefined || value === null)
|
|
28
50
|
return;
|
|
@@ -77,4 +99,4 @@ function createCommandContext(input, options = {}) {
|
|
|
77
99
|
};
|
|
78
100
|
}
|
|
79
101
|
|
|
80
|
-
export { parseBooleanFlagValue, stringOption, createCommandContext };
|
|
102
|
+
export { parseBooleanFlagValue, withoutFlag, optOutFlagSet, envSwitchedOff, envOptOutSet, stringOption, createCommandContext };
|