@moda-ai/cli 1.55.24 → 1.55.26
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-b4tdzy9q.js → agent-nqmha8ck.js} +8 -8
- package/dist/{cli-9hc5bg2r.js → cli-1mbb0ct0.js} +1 -1
- package/dist/{cli-vg88mg20.js → cli-5g1tv80h.js} +5 -5
- package/dist/{cli-rt26sbz7.js → cli-8tfk8qeb.js} +10 -6
- package/dist/{cli-y2ty9vtv.js → cli-b4740tnv.js} +210 -23
- package/dist/{cli-qvg26twp.js → cli-cdrvjva5.js} +11 -8
- package/dist/{cli-7xc585hc.js → cli-d577kq6h.js} +5 -5
- package/dist/{cli-dn91fb56.js → cli-jgfm7w1r.js} +89 -47
- package/dist/{cli-9btx12wp.js → cli-jtyvbd8d.js} +1 -1
- package/dist/{cli-qycsmxev.js → cli-k6q8dbpk.js} +3 -3
- package/dist/{cli-0wr3483h.js → cli-q6f6vrrr.js} +1 -1
- package/dist/{cli-dve50x7p.js → cli-sqsjd08w.js} +784 -725
- package/dist/cli.js +713 -234
- package/dist/{doctor-3r19ry92.js → doctor-w913fj4g.js} +8 -8
- package/dist/{fix-exvxzvtz.js → fix-crkwdkt4.js} +6 -6
- package/dist/{harness-github-actions-atc5bbkj.js → harness-github-actions-fjhvhgpj.js} +5 -5
- package/dist/{harness-vzy7n7ea.js → harness-x3e7d68b.js} +5 -5
- package/dist/{index-e1pf1qz2.js → index-2kf3fnnb.js} +11 -11
- package/dist/{production-intelligence-c8e0xw3n.js → production-intelligence-7n83c701.js} +75 -15
- package/dist/{profile-commands-6e2dgv72.js → profile-commands-ct2t0bfr.js} +3 -3
- package/dist/prompt-source-mcp.js +5 -5
- package/dist/{prompts-cvzt994j.js → prompts-92aqqb2k.js} +6 -6
- package/dist/{provision-q86phh4a.js → provision-gn8raqpt.js} +5 -5
- package/dist/{registry-s2vdsfw8.js → registry-ex162j5y.js} +3 -3
- package/dist/{skills-tadh1jss.js → skills-2mbsj9bt.js} +5 -5
- package/dist/{sync-g8wtecz1.js → sync-kghmmmk5.js} +7 -7
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
- package/skills/moda-cli/SKILL.md +8 -2
- package/skills/moda-cli/references/dashboard-parity.md +1 -1
- package/skills/moda-cli/references/output-protocol.md +35 -10
- package/skills/moda-cli/references/production-intelligence.md +3 -2
- package/skills/moda-cli/references/prompts.md +6 -2
- package/skills/moda-cli/references/search-and-traces.md +20 -2
|
@@ -689,767 +689,767 @@ function resetApiRequestCount() {
|
|
|
689
689
|
apiRequestCount = 0;
|
|
690
690
|
}
|
|
691
691
|
|
|
692
|
-
// src/
|
|
693
|
-
|
|
694
|
-
var
|
|
695
|
-
var
|
|
696
|
-
var
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
692
|
+
// ../../packages/harness-snapshot/src/policy.ts
|
|
693
|
+
var MAX_SCANNED_FILE_BYTES = 512 * 1024;
|
|
694
|
+
var DEFAULT_MAX_INVENTORY_FILES = 12000;
|
|
695
|
+
var DEFAULT_MAX_INVENTORY_TEXT_BYTES = 48 * 1024 * 1024;
|
|
696
|
+
var MAX_SNAPSHOT_BODY_BYTES = 4500000;
|
|
697
|
+
var MAX_RECORDED_SKIPS = 1000;
|
|
698
|
+
var SKIPPED_DIRS = new Set([
|
|
699
|
+
".angular",
|
|
700
|
+
".cache",
|
|
701
|
+
".expo",
|
|
702
|
+
".git",
|
|
703
|
+
".hg",
|
|
704
|
+
".idea",
|
|
705
|
+
".svn",
|
|
706
|
+
".next",
|
|
707
|
+
".nuxt",
|
|
708
|
+
".output",
|
|
709
|
+
".parcel-cache",
|
|
710
|
+
".pytest_cache",
|
|
711
|
+
".ruff_cache",
|
|
712
|
+
".serverless",
|
|
713
|
+
".sst",
|
|
714
|
+
".turbo",
|
|
715
|
+
".wrangler",
|
|
716
|
+
".wrangler-shared",
|
|
717
|
+
".moda",
|
|
718
|
+
".moda-test",
|
|
719
|
+
".moda-test-home",
|
|
720
|
+
".moda-cli-workspaces",
|
|
721
|
+
".moda-cli-benchmarks",
|
|
722
|
+
"node_modules",
|
|
723
|
+
"dist",
|
|
724
|
+
"build",
|
|
725
|
+
"coverage",
|
|
726
|
+
"out",
|
|
727
|
+
"target",
|
|
728
|
+
"logs",
|
|
729
|
+
"tmp",
|
|
730
|
+
"temp",
|
|
731
|
+
"__pycache__",
|
|
732
|
+
".venv",
|
|
733
|
+
"venv"
|
|
734
|
+
]);
|
|
735
|
+
var SKIPPED_PATH_PREFIXES = [
|
|
736
|
+
".claude/worktrees",
|
|
737
|
+
".codex/environments"
|
|
738
|
+
];
|
|
739
|
+
function posixNormalize(path) {
|
|
740
|
+
const absolute = path.startsWith("/");
|
|
741
|
+
const parts = path.split("/").filter((part) => part !== "" && part !== ".");
|
|
742
|
+
const normalized = parts.join("/");
|
|
743
|
+
return absolute ? `/${normalized}` : normalized;
|
|
734
744
|
}
|
|
735
|
-
function
|
|
736
|
-
|
|
745
|
+
function basename(path) {
|
|
746
|
+
const normalized = posixNormalize(path);
|
|
747
|
+
const index = normalized.lastIndexOf("/");
|
|
748
|
+
return index === -1 ? normalized : normalized.slice(index + 1);
|
|
737
749
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
const chunks = [];
|
|
743
|
-
for await (const chunk of process.stdin)
|
|
744
|
-
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
745
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
750
|
+
function extname(path) {
|
|
751
|
+
const name = basename(path);
|
|
752
|
+
const index = name.lastIndexOf(".");
|
|
753
|
+
return index <= 0 ? "" : name.slice(index);
|
|
746
754
|
}
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
throw new CliInputError("--ids-from needs a value: - (stdin) or a file path.", usage, "missing_flag_value");
|
|
750
|
-
}
|
|
751
|
-
if (source === "-")
|
|
752
|
-
return readStdinText();
|
|
753
|
-
try {
|
|
754
|
-
return await readFile(source, "utf8");
|
|
755
|
-
} catch (error) {
|
|
756
|
-
const code = error.code;
|
|
757
|
-
throw new CliInputError(`Could not read --ids-from file ${JSON.stringify(source)}${typeof code === "string" ? ` (${code})` : ""}.`, usage, "ids_from_unreadable");
|
|
758
|
-
}
|
|
755
|
+
function isSkippedDir(path) {
|
|
756
|
+
return SKIPPED_DIRS.has(basename(path));
|
|
759
757
|
}
|
|
760
|
-
|
|
761
|
-
const
|
|
762
|
-
|
|
763
|
-
targets.push(...parseTargetLines(await readIdsFrom(idsFrom, options.usage), options.anchors, options.usage));
|
|
764
|
-
}
|
|
765
|
-
const seen = new Set;
|
|
766
|
-
const unique = targets.filter((target) => {
|
|
767
|
-
const key = `${target.id}\x00${target.msgIndex ?? ""}`;
|
|
768
|
-
if (seen.has(key))
|
|
769
|
-
return false;
|
|
770
|
-
seen.add(key);
|
|
771
|
-
return true;
|
|
772
|
-
});
|
|
773
|
-
if (unique.length === 0) {
|
|
774
|
-
throw new CliInputError(`No targets: --ids-from gave no ids (one per line).`, options.usage, "missing_positional");
|
|
775
|
-
}
|
|
776
|
-
if (unique.length > BATCH_MAX_TARGETS) {
|
|
777
|
-
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");
|
|
778
|
-
}
|
|
779
|
-
return unique;
|
|
758
|
+
function isSkippedPathPrefix(path) {
|
|
759
|
+
const normalized = posixNormalize(path);
|
|
760
|
+
return SKIPPED_PATH_PREFIXES.some((prefix) => normalized === prefix || normalized.startsWith(`${prefix}/`));
|
|
780
761
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
let next = 0;
|
|
784
|
-
let failure;
|
|
785
|
-
const worker = async () => {
|
|
786
|
-
while (!failure && next < items.length) {
|
|
787
|
-
const index = next++;
|
|
788
|
-
try {
|
|
789
|
-
results[index] = await fn(items[index], index);
|
|
790
|
-
} catch (error) {
|
|
791
|
-
failure ??= { error };
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
};
|
|
795
|
-
await Promise.all(Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, worker));
|
|
796
|
-
if (failure)
|
|
797
|
-
throw failure.error;
|
|
798
|
-
return results;
|
|
762
|
+
function isSourceFile(path) {
|
|
763
|
+
return /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(path);
|
|
799
764
|
}
|
|
800
|
-
function
|
|
801
|
-
return
|
|
765
|
+
function isPackageOrLockfile(path) {
|
|
766
|
+
return path === "package.json" || path === "pyproject.toml" || path === "bun.lock" || path === "bun.lockb" || path === "pnpm-lock.yaml" || path === "yarn.lock";
|
|
802
767
|
}
|
|
803
|
-
function
|
|
804
|
-
|
|
805
|
-
return verbatim ? id : JSON.stringify({ id });
|
|
768
|
+
function isPromptLikePath(path) {
|
|
769
|
+
return /(^|\/)prompts?\//i.test(path) && /\.(prompt\.)?(md|json|ya?ml)$/i.test(path);
|
|
806
770
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
function asRecord(value) {
|
|
810
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
811
|
-
return value;
|
|
812
|
-
}
|
|
813
|
-
return null;
|
|
771
|
+
function isSkillLikePath(path) {
|
|
772
|
+
return /(^|\/)(\.claude\/skills|\.cursor\/rules|skills?)\//i.test(path) && /\.(md|mdc)$/i.test(path);
|
|
814
773
|
}
|
|
815
|
-
function
|
|
816
|
-
return
|
|
774
|
+
function isEvalLikePath(path) {
|
|
775
|
+
return /(^|\/)(evals?|tests?|__tests__)\//i.test(path) && /\.(ts|tsx|js|mjs|py|json|ya?ml)$/i.test(path);
|
|
817
776
|
}
|
|
818
|
-
function
|
|
819
|
-
return
|
|
777
|
+
function isDeploymentLikePath(path) {
|
|
778
|
+
return /(^|\/)(wrangler\.toml|vercel\.json|render\.ya?ml|railway\.json|Dockerfile|docker-compose\.ya?ml)$/i.test(path) || /^\.github\/workflows\/[^/]+\.ya?ml$/i.test(path);
|
|
820
779
|
}
|
|
821
|
-
function
|
|
822
|
-
|
|
823
|
-
return null;
|
|
824
|
-
const userQuotes = Array.isArray(row.user_quotes) ? row.user_quotes : [];
|
|
825
|
-
const firstQuote = asRecord(userQuotes[0]);
|
|
826
|
-
const resolved = asNumber(firstQuote?.msg_index) ?? asNumber(row.anchor_msg_index);
|
|
827
|
-
if (resolved !== null)
|
|
828
|
-
return resolved;
|
|
829
|
-
const keyTurns = Array.isArray(row.key_turns) ? row.key_turns : [];
|
|
830
|
-
const firstTurn = keyTurns.find((t) => typeof t === "number");
|
|
831
|
-
if (firstTurn !== undefined)
|
|
832
|
-
return firstTurn;
|
|
833
|
-
return asNumber(firstQuote?.turn);
|
|
780
|
+
function isDeveloperAgentConfigPath(path) {
|
|
781
|
+
return path === ".claude/settings.json" || path === ".codex/hooks.json" || path === ".cursor/hooks.json";
|
|
834
782
|
}
|
|
835
|
-
function
|
|
836
|
-
const
|
|
837
|
-
|
|
838
|
-
const firstQuote = asRecord(userQuotes[0]);
|
|
839
|
-
const keyTurnsRaw = Array.isArray(row.key_turns) ? row.key_turns : [];
|
|
840
|
-
const all_turns = keyTurnsRaw.filter((t) => typeof t === "number");
|
|
841
|
-
const msg_index = frustrationAnchorIndex(row);
|
|
842
|
-
let signal = null;
|
|
843
|
-
let quote_preview = null;
|
|
844
|
-
if (firstQuote) {
|
|
845
|
-
signal = asString(firstQuote.signal);
|
|
846
|
-
const quote = asString(firstQuote.quote);
|
|
847
|
-
if (quote !== null) {
|
|
848
|
-
let end = 0;
|
|
849
|
-
let points = 0;
|
|
850
|
-
for (const ch of quote) {
|
|
851
|
-
if (points++ === 200)
|
|
852
|
-
break;
|
|
853
|
-
end += ch.length;
|
|
854
|
-
}
|
|
855
|
-
quote_preview = quote.slice(0, end);
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
return {
|
|
859
|
-
kind: "frustration",
|
|
860
|
-
conversation_id,
|
|
861
|
-
msg_index,
|
|
862
|
-
signal,
|
|
863
|
-
quote_preview,
|
|
864
|
-
all_turns,
|
|
865
|
-
no_anchor: msg_index === null
|
|
866
|
-
};
|
|
783
|
+
function isReadmeOrAgents(path) {
|
|
784
|
+
const name = basename(path);
|
|
785
|
+
return name === "README.md" || name === "AGENTS.md";
|
|
867
786
|
}
|
|
868
|
-
function
|
|
869
|
-
const
|
|
870
|
-
const
|
|
871
|
-
const
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
if (
|
|
885
|
-
return
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
const totalAnalyzed = asNumber(summary.conversations_analyzed) ?? 0;
|
|
890
|
-
const byFamilyConversations = asRecord(summary.conversations_by_family);
|
|
891
|
-
const frustrated = asNumber(byFamilyConversations?.frustration) ?? asNumber(byFamily.frustration) ?? 0;
|
|
892
|
-
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 }) => ({
|
|
893
|
-
...row,
|
|
894
|
-
is_frustrated: is_detected === true,
|
|
895
|
-
frustration_score: score,
|
|
896
|
-
target: row.elicitor === "bot" || row.elicitor === "external" ? row.elicitor : "ambiguous",
|
|
897
|
-
conversation: conversation_context ?? null
|
|
898
|
-
}));
|
|
899
|
-
const atRisk = asNumber(pagination.at_risk) ?? Math.max(0, (asNumber(pagination.total) ?? 0) - frustrated);
|
|
900
|
-
const signalBreakdown = {};
|
|
901
|
-
for (const item of Array.isArray(response.signal_breakdown) ? response.signal_breakdown : []) {
|
|
902
|
-
const row = asRecord(item);
|
|
903
|
-
if (row?.family === "frustration" && typeof row.signal === "string") {
|
|
904
|
-
signalBreakdown[row.signal] = asNumber(row.count) ?? 0;
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
const { detections: _detections, ...rest } = response;
|
|
908
|
-
return {
|
|
909
|
-
...rest,
|
|
910
|
-
summary: {
|
|
911
|
-
total_analyzed: totalAnalyzed,
|
|
912
|
-
frustrated_count: frustrated,
|
|
913
|
-
at_risk_count: atRisk,
|
|
914
|
-
frustration_rate_pct: totalAnalyzed > 0 ? Math.round(frustrated / totalAnalyzed * 1000) / 10 : 0
|
|
915
|
-
},
|
|
916
|
-
signal_breakdown: signalBreakdown,
|
|
917
|
-
frustrations,
|
|
918
|
-
source: "emotion_detections"
|
|
919
|
-
};
|
|
920
|
-
}
|
|
921
|
-
function withFrustrationAnchors(response) {
|
|
922
|
-
if (!Array.isArray(response.frustrations))
|
|
923
|
-
return response;
|
|
924
|
-
const frustrations = response.frustrations.map((item) => {
|
|
925
|
-
const row = asRecord(item);
|
|
926
|
-
if (!row)
|
|
927
|
-
return item;
|
|
928
|
-
const anchor = buildFrustrationAnchor(row);
|
|
929
|
-
return { ...row, anchor };
|
|
930
|
-
});
|
|
931
|
-
return { ...response, frustrations };
|
|
932
|
-
}
|
|
933
|
-
var TOOL_FAILURE_CONTEXT_RADIUS = 2;
|
|
934
|
-
function shellWord(value) {
|
|
935
|
-
return /^[\w@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\\''`)}'`;
|
|
936
|
-
}
|
|
937
|
-
function trimFailureWindow(value, radius, fallbackCenter) {
|
|
938
|
-
const conv = asRecord(value);
|
|
939
|
-
if (!conv)
|
|
940
|
-
return value ?? null;
|
|
941
|
-
const { coverage: _coverage, context, ...convRest } = conv;
|
|
942
|
-
const ctx = asRecord(context);
|
|
943
|
-
if (!ctx)
|
|
944
|
-
return convRest;
|
|
945
|
-
const center = asNumber(ctx.center_index) ?? fallbackCenter;
|
|
946
|
-
const messages = (Array.isArray(ctx.messages) ? ctx.messages : []).map((message) => asRecord(message)).filter((message) => {
|
|
947
|
-
const index = asNumber(message?.index);
|
|
948
|
-
return message !== null && (center === null || index === null || Math.abs(index - center) <= radius);
|
|
949
|
-
}).map(({ content_blocks, ...message }) => {
|
|
950
|
-
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;
|
|
951
|
-
return covered || content_blocks === undefined ? message : { ...message, content_blocks };
|
|
952
|
-
});
|
|
953
|
-
const indexes = messages.map((message) => asNumber(message.index)).filter((index) => index !== null);
|
|
954
|
-
return {
|
|
955
|
-
...convRest,
|
|
956
|
-
context: {
|
|
957
|
-
...ctx,
|
|
958
|
-
...indexes.length > 0 ? { from_index: Math.min(...indexes), to_index: Math.max(...indexes) } : {},
|
|
959
|
-
messages
|
|
960
|
-
}
|
|
961
|
-
};
|
|
962
|
-
}
|
|
963
|
-
function trimToolFailureConversations(response, opts) {
|
|
964
|
-
if (!Array.isArray(response.examples))
|
|
965
|
-
return response;
|
|
966
|
-
const examples = response.examples.map((item) => {
|
|
967
|
-
const row = asRecord(item);
|
|
968
|
-
if (!row)
|
|
969
|
-
return item;
|
|
970
|
-
const { conversation, window, ...rest } = row;
|
|
971
|
-
const conversationId = asString(row.conversation_id);
|
|
972
|
-
const msgIndex = asNumber(asRecord(row.anchor)?.msg_index) ?? asNumber(row.msg_index);
|
|
973
|
-
return {
|
|
974
|
-
...rest,
|
|
975
|
-
...conversationId && msgIndex !== null ? { context_command: `moda traces get ${shellWord(contextTarget(conversationId))} --msg-index=${msgIndex} --window=${TOOL_FAILURE_CONTEXT_RADIUS}` } : {},
|
|
976
|
-
...opts.drop ? {} : { conversation: trimFailureWindow(conversation, TOOL_FAILURE_CONTEXT_RADIUS, msgIndex) },
|
|
977
|
-
..."window" in row ? { window: trimFailureWindow(window, opts.windowRadius ?? TOOL_FAILURE_CONTEXT_RADIUS, msgIndex) } : {}
|
|
978
|
-
};
|
|
979
|
-
});
|
|
980
|
-
return { ...response, examples };
|
|
981
|
-
}
|
|
982
|
-
function withToolFailureAnchors(response) {
|
|
983
|
-
if (!Array.isArray(response.examples))
|
|
984
|
-
return response;
|
|
985
|
-
const toolName = asString(response.tool_name) ?? "";
|
|
986
|
-
const examples = response.examples.map((item) => {
|
|
987
|
-
const row = asRecord(item);
|
|
988
|
-
if (!row)
|
|
989
|
-
return item;
|
|
990
|
-
const anchor = buildToolFailureAnchor(row, toolName);
|
|
991
|
-
return { ...row, anchor };
|
|
992
|
-
});
|
|
993
|
-
return { ...response, examples };
|
|
994
|
-
}
|
|
995
|
-
function embeddedWindowSize(conversation) {
|
|
996
|
-
if (!conversation)
|
|
997
|
-
return null;
|
|
998
|
-
const ctx = asRecord(conversation.context);
|
|
999
|
-
if (!ctx)
|
|
1000
|
-
return null;
|
|
1001
|
-
const center = asNumber(ctx.center_index);
|
|
1002
|
-
const from = asNumber(ctx.from_index);
|
|
1003
|
-
const to = asNumber(ctx.to_index);
|
|
1004
|
-
if (center === null || from === null || to === null)
|
|
1005
|
-
return null;
|
|
1006
|
-
return Math.min(center - from, to - center);
|
|
1007
|
-
}
|
|
1008
|
-
var DETECTION_CONTEXT_RADIUS = 2;
|
|
1009
|
-
function withoutDetectionWindows(response, listKey, windowKey) {
|
|
1010
|
-
const list = response[listKey];
|
|
1011
|
-
if (!Array.isArray(list))
|
|
1012
|
-
return response;
|
|
1013
|
-
const rows = list.map((item) => {
|
|
1014
|
-
const row = asRecord(item);
|
|
1015
|
-
if (!row)
|
|
1016
|
-
return item;
|
|
1017
|
-
const { [windowKey]: _window, ...rest } = row;
|
|
1018
|
-
const conversationId = asString(row.conversation_id);
|
|
1019
|
-
const msgIndex = asNumber(asRecord(row.anchor)?.msg_index) ?? frustrationAnchorIndex(row);
|
|
1020
|
-
return {
|
|
1021
|
-
...rest,
|
|
1022
|
-
...conversationId && msgIndex !== null ? { context_command: `moda traces get ${shellWord(contextTarget(conversationId))} --msg-index=${msgIndex} --window=${DETECTION_CONTEXT_RADIUS}` } : {}
|
|
1023
|
-
};
|
|
1024
|
-
});
|
|
1025
|
-
return { ...response, [listKey]: rows };
|
|
1026
|
-
}
|
|
1027
|
-
var PROBLEM_COMPACT_EVIDENCE = 5;
|
|
1028
|
-
var PROBLEM_COMPACT_OMITTED_BLOCKS = [
|
|
1029
|
-
"rubric",
|
|
1030
|
-
"trend",
|
|
1031
|
-
"sub_problems",
|
|
1032
|
-
"affected_conversations",
|
|
1033
|
-
"remainder",
|
|
1034
|
-
"confidence",
|
|
1035
|
-
"change_history",
|
|
1036
|
-
"stories"
|
|
1037
|
-
];
|
|
1038
|
-
function readCommand(command, purpose) {
|
|
1039
|
-
return { command, purpose, mutability: "read", requires_approval: false };
|
|
787
|
+
function shouldInventoryFile(path) {
|
|
788
|
+
const normalized = posixNormalize(path);
|
|
789
|
+
const name = basename(normalized);
|
|
790
|
+
const extension = extname(normalized).toLowerCase();
|
|
791
|
+
if (isSourceFile(normalized))
|
|
792
|
+
return true;
|
|
793
|
+
if (isPackageOrLockfile(normalized))
|
|
794
|
+
return true;
|
|
795
|
+
if (isPromptLikePath(normalized))
|
|
796
|
+
return true;
|
|
797
|
+
if (isSkillLikePath(normalized))
|
|
798
|
+
return true;
|
|
799
|
+
if (isEvalLikePath(normalized))
|
|
800
|
+
return true;
|
|
801
|
+
if (isDeploymentLikePath(normalized))
|
|
802
|
+
return true;
|
|
803
|
+
if (isDeveloperAgentConfigPath(normalized))
|
|
804
|
+
return true;
|
|
805
|
+
if (isReadmeOrAgents(normalized))
|
|
806
|
+
return true;
|
|
807
|
+
return extension === ".toml" && (name === "pyproject.toml" || name === "wrangler.toml");
|
|
1040
808
|
}
|
|
1041
|
-
function
|
|
1042
|
-
|
|
809
|
+
function isTextFile(path) {
|
|
810
|
+
const extension = extname(path).toLowerCase();
|
|
811
|
+
return [
|
|
812
|
+
"",
|
|
813
|
+
".cjs",
|
|
814
|
+
".js",
|
|
815
|
+
".json",
|
|
816
|
+
".jsx",
|
|
817
|
+
".md",
|
|
818
|
+
".mdc",
|
|
819
|
+
".mjs",
|
|
820
|
+
".py",
|
|
821
|
+
".toml",
|
|
822
|
+
".ts",
|
|
823
|
+
".tsx",
|
|
824
|
+
".txt",
|
|
825
|
+
".yaml",
|
|
826
|
+
".yml"
|
|
827
|
+
].includes(extension);
|
|
1043
828
|
}
|
|
1044
|
-
function
|
|
1045
|
-
const
|
|
1046
|
-
|
|
1047
|
-
const topEvidence = evidence.slice(0, PROBLEM_COMPACT_EVIDENCE).map((row) => {
|
|
1048
|
-
const conversationId = asString(row.conversation_id);
|
|
1049
|
-
const msgIndex = evidenceMsgIndex(row);
|
|
1050
|
-
return {
|
|
1051
|
-
attribution_id: row.attribution_id ?? null,
|
|
1052
|
-
conversation_id: conversationId,
|
|
1053
|
-
msg_index: msgIndex,
|
|
1054
|
-
signal_family: row.signal_family ?? null,
|
|
1055
|
-
signal_type: row.signal_type ?? null,
|
|
1056
|
-
confidence: row.confidence ?? null,
|
|
1057
|
-
causal_rationale: row.causal_rationale ?? null,
|
|
1058
|
-
door: row.door ?? null,
|
|
1059
|
-
replay_verified: row.replay_verified ?? null,
|
|
1060
|
-
...conversationId && msgIndex !== null ? { context_command: `moda traces get ${shellWord(contextTarget(conversationId))} --msg-index=${msgIndex}` } : {}
|
|
1061
|
-
};
|
|
1062
|
-
});
|
|
1063
|
-
const reportsBlock = asRecord(response.investigation_reports);
|
|
1064
|
-
const reports = (Array.isArray(reportsBlock?.items) ? reportsBlock.items : []).map((item) => asRecord(item)).filter((row) => row !== null).map((row) => ({
|
|
1065
|
-
report_id: row.report_id ?? null,
|
|
1066
|
-
conversation_id: row.conversation_id ?? null,
|
|
1067
|
-
mechanism: row.mechanism ?? null,
|
|
1068
|
-
suspected_surface: row.suspected_surface ?? null,
|
|
1069
|
-
severity: row.severity ?? null,
|
|
1070
|
-
problem_found: row.problem_found ?? null
|
|
1071
|
-
}));
|
|
1072
|
-
const verification = asRecord(response.verification);
|
|
1073
|
-
const { samples: _samples, ...verificationCounts } = verification ?? {};
|
|
1074
|
-
const dossier = asRecord(response.dossier);
|
|
1075
|
-
const { representative_story_keys: _storyKeys, ...dossierSummary } = dossier ?? {};
|
|
1076
|
-
const trend = Array.isArray(response.trend) ? response.trend : [];
|
|
1077
|
-
const data = {
|
|
1078
|
-
found: response.found ?? true,
|
|
1079
|
-
problem_id: response.problem_id ?? problemId,
|
|
1080
|
-
requested_problem_id: response.requested_problem_id ?? problemId,
|
|
1081
|
-
alias_resolved: response.alias_resolved ?? false,
|
|
1082
|
-
view: "compact",
|
|
1083
|
-
header: response.header ?? null,
|
|
1084
|
-
dossier: dossier ? dossierSummary : null,
|
|
1085
|
-
verification: verification ? verificationCounts : null,
|
|
1086
|
-
...response.impact_identity !== undefined ? { impact_identity: response.impact_identity } : {},
|
|
1087
|
-
...response.hierarchy !== undefined ? { hierarchy: response.hierarchy } : {},
|
|
1088
|
-
...trend.length > 0 ? { trend_latest: trend[trend.length - 1], trend_points: trend.length } : {},
|
|
1089
|
-
top_evidence: topEvidence,
|
|
1090
|
-
evidence_in_dossier: evidence.length,
|
|
1091
|
-
reports,
|
|
1092
|
-
omitted: {
|
|
1093
|
-
evidence_rows: Math.max(0, evidence.length - topEvidence.length),
|
|
1094
|
-
report_narratives: reports.length,
|
|
1095
|
-
reports_has_more: reportsBlock?.has_more === true,
|
|
1096
|
-
blocks: PROBLEM_COMPACT_OMITTED_BLOCKS.filter((key) => (key in response))
|
|
1097
|
-
},
|
|
1098
|
-
full_command: `moda problems get ${id} --full`
|
|
1099
|
-
};
|
|
1100
|
-
const nextCommands = [
|
|
1101
|
-
readCommand(`moda problems get ${id} --evidence --limit=20`, "Page every evidence row with its anchor (follow next_cursor)."),
|
|
1102
|
-
readCommand(`moda problems get ${id} --reports`, "Page investigation reports with narratives and citations."),
|
|
1103
|
-
readCommand(`moda problems get ${id} --traces`, "Page affected traces with their latest anchor."),
|
|
1104
|
-
readCommand(`moda problems get ${id} --full`, "The complete dossier, every block (large).")
|
|
1105
|
-
];
|
|
1106
|
-
const first = topEvidence.find((row) => typeof row.context_command === "string");
|
|
1107
|
-
if (first?.context_command) {
|
|
1108
|
-
nextCommands.push(readCommand(first.context_command, "Read the trace around the top evidence anchor."));
|
|
1109
|
-
}
|
|
1110
|
-
return { data, nextCommands };
|
|
829
|
+
function isSecretishPath(path) {
|
|
830
|
+
const name = basename(path).toLowerCase();
|
|
831
|
+
return name === ".env" || name.startsWith(".env.") || name.includes("secret") || name.includes("private-key") || name.endsWith(".pem");
|
|
1111
832
|
}
|
|
1112
833
|
|
|
1113
|
-
// ../../packages/harness-snapshot/src/
|
|
1114
|
-
var
|
|
1115
|
-
var
|
|
1116
|
-
var
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
"
|
|
1121
|
-
"
|
|
1122
|
-
"
|
|
1123
|
-
"
|
|
1124
|
-
"
|
|
1125
|
-
".idea",
|
|
1126
|
-
".svn",
|
|
1127
|
-
".next",
|
|
1128
|
-
".nuxt",
|
|
1129
|
-
".output",
|
|
1130
|
-
".parcel-cache",
|
|
1131
|
-
".pytest_cache",
|
|
1132
|
-
".ruff_cache",
|
|
1133
|
-
".serverless",
|
|
1134
|
-
".sst",
|
|
1135
|
-
".turbo",
|
|
1136
|
-
".wrangler",
|
|
1137
|
-
".wrangler-shared",
|
|
1138
|
-
".moda",
|
|
1139
|
-
".moda-test",
|
|
1140
|
-
".moda-test-home",
|
|
1141
|
-
".moda-cli-workspaces",
|
|
1142
|
-
".moda-cli-benchmarks",
|
|
1143
|
-
"node_modules",
|
|
1144
|
-
"dist",
|
|
1145
|
-
"build",
|
|
1146
|
-
"coverage",
|
|
1147
|
-
"out",
|
|
1148
|
-
"target",
|
|
1149
|
-
"logs",
|
|
1150
|
-
"tmp",
|
|
1151
|
-
"temp",
|
|
1152
|
-
"__pycache__",
|
|
1153
|
-
".venv",
|
|
1154
|
-
"venv"
|
|
834
|
+
// ../../packages/harness-snapshot/src/redact.ts
|
|
835
|
+
var REDACTED = "[REDACTED]";
|
|
836
|
+
var MAX_DEPTH = 256;
|
|
837
|
+
var SECRET_KEYS = new Set([
|
|
838
|
+
"api_key",
|
|
839
|
+
"apikey",
|
|
840
|
+
"token",
|
|
841
|
+
"access_token",
|
|
842
|
+
"authorization",
|
|
843
|
+
"secret",
|
|
844
|
+
"password",
|
|
845
|
+
"cli_token"
|
|
1155
846
|
]);
|
|
1156
|
-
var
|
|
1157
|
-
|
|
1158
|
-
|
|
847
|
+
var SECRET_PATTERNS = [
|
|
848
|
+
{ pattern: /\bmoda_sk_[A-Za-z0-9_-]+\b/g, prefixLength: 8 },
|
|
849
|
+
{ pattern: /\bmoda_pk_[A-Za-z0-9_-]+\b/g, prefixLength: 8 },
|
|
850
|
+
{ pattern: /\bmoda_ct_[A-Za-z0-9_-]+\b/g, prefixLength: 8 },
|
|
851
|
+
{ pattern: /\bBearer\s+([A-Za-z0-9._~+/-]+=*)\b/gi, prefixLength: 8 },
|
|
852
|
+
{ pattern: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, prefixLength: 8 },
|
|
853
|
+
{ pattern: /\bsk-ant-api\d{2}-[A-Za-z0-9_-]{20,}\b/g, prefixLength: 12 },
|
|
854
|
+
{ pattern: /\bsk-(?:proj-|svcacct-)?[A-Za-z0-9_-]{20,}\b/g, prefixLength: 8 },
|
|
855
|
+
{ pattern: /\bAKIA[A-Z0-9]{16}\b/g, prefixLength: 8 },
|
|
856
|
+
{ pattern: /\bAIza[A-Za-z0-9_-]{35}\b/g, prefixLength: 8 },
|
|
857
|
+
{ pattern: /\bgh[pousr]_[A-Za-z0-9]{36,}\b/g, prefixLength: 8 },
|
|
858
|
+
{ pattern: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, prefixLength: 8 }
|
|
1159
859
|
];
|
|
1160
|
-
function
|
|
1161
|
-
|
|
1162
|
-
const parts = path.split("/").filter((part) => part !== "" && part !== ".");
|
|
1163
|
-
const normalized = parts.join("/");
|
|
1164
|
-
return absolute ? `/${normalized}` : normalized;
|
|
860
|
+
function redactDeep(value) {
|
|
861
|
+
return redactValue(value, 0, new WeakSet);
|
|
1165
862
|
}
|
|
1166
|
-
function
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
863
|
+
function redactValue(value, depth, seen) {
|
|
864
|
+
if (typeof value === "string")
|
|
865
|
+
return redactString(value);
|
|
866
|
+
if (value === null || typeof value !== "object")
|
|
867
|
+
return value;
|
|
868
|
+
if (depth >= MAX_DEPTH)
|
|
869
|
+
return "[MaxDepth]";
|
|
870
|
+
if (seen.has(value))
|
|
871
|
+
return "[Circular]";
|
|
872
|
+
seen.add(value);
|
|
873
|
+
if (Array.isArray(value)) {
|
|
874
|
+
try {
|
|
875
|
+
return value.map((item) => redactValue(item, depth + 1, seen));
|
|
876
|
+
} finally {
|
|
877
|
+
seen.delete(value);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
const out = {};
|
|
881
|
+
try {
|
|
882
|
+
for (const [key, item] of Object.entries(value)) {
|
|
883
|
+
out[key] = shouldRedactKey(key) ? redactSecretValue(item) : redactValue(item, depth + 1, seen);
|
|
884
|
+
}
|
|
885
|
+
} finally {
|
|
886
|
+
seen.delete(value);
|
|
887
|
+
}
|
|
888
|
+
return out;
|
|
1170
889
|
}
|
|
1171
|
-
function
|
|
1172
|
-
|
|
1173
|
-
const index = name.lastIndexOf(".");
|
|
1174
|
-
return index <= 0 ? "" : name.slice(index);
|
|
890
|
+
function shouldRedactKey(key) {
|
|
891
|
+
return SECRET_KEYS.has(key.replace(/[-\s]/g, "_").toLowerCase());
|
|
1175
892
|
}
|
|
1176
|
-
function
|
|
1177
|
-
|
|
893
|
+
function redactSecretValue(value) {
|
|
894
|
+
if (typeof value !== "string")
|
|
895
|
+
return REDACTED;
|
|
896
|
+
const redacted = redactString(value);
|
|
897
|
+
if (redacted !== value)
|
|
898
|
+
return redacted;
|
|
899
|
+
if (/^(configured|missing|not_configured|none|present|absent)$/i.test(value))
|
|
900
|
+
return value;
|
|
901
|
+
return REDACTED;
|
|
902
|
+
}
|
|
903
|
+
function redactStringWithCount(input) {
|
|
904
|
+
let text = input;
|
|
905
|
+
let redactionCount = 0;
|
|
906
|
+
for (const { pattern, prefixLength } of SECRET_PATTERNS) {
|
|
907
|
+
text = text.replace(pattern, (match) => {
|
|
908
|
+
redactionCount += 1;
|
|
909
|
+
if (/^Bearer\s+/i.test(match)) {
|
|
910
|
+
const token = match.replace(/^Bearer\s+/i, "");
|
|
911
|
+
return `Bearer ${token.slice(0, prefixLength)}...[REDACTED]`;
|
|
912
|
+
}
|
|
913
|
+
return `${match.slice(0, prefixLength)}...[REDACTED]`;
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
return { text, redactionCount };
|
|
1178
917
|
}
|
|
1179
|
-
function
|
|
1180
|
-
|
|
1181
|
-
return SKIPPED_PATH_PREFIXES.some((prefix) => normalized === prefix || normalized.startsWith(`${prefix}/`));
|
|
918
|
+
function redactString(input) {
|
|
919
|
+
return redactStringWithCount(input).text;
|
|
1182
920
|
}
|
|
1183
|
-
function
|
|
1184
|
-
|
|
921
|
+
function redactSnapshotText(text) {
|
|
922
|
+
const parts = text.split(/(\r\n|\r|\n)/);
|
|
923
|
+
let redactionCount = 0;
|
|
924
|
+
for (let index = 0;index < parts.length; index += 2) {
|
|
925
|
+
const redacted = redactStringWithCount(parts[index] ?? "");
|
|
926
|
+
parts[index] = redacted.text;
|
|
927
|
+
redactionCount += redacted.redactionCount;
|
|
928
|
+
}
|
|
929
|
+
return { text: parts.join(""), redactionCount };
|
|
1185
930
|
}
|
|
1186
|
-
|
|
1187
|
-
|
|
931
|
+
|
|
932
|
+
// ../../packages/harness-snapshot/src/pack.ts
|
|
933
|
+
function utf8ByteLength(value) {
|
|
934
|
+
let bytes = 0;
|
|
935
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
936
|
+
const code = value.charCodeAt(index);
|
|
937
|
+
if (code <= 127) {
|
|
938
|
+
bytes += 1;
|
|
939
|
+
} else if (code <= 2047) {
|
|
940
|
+
bytes += 2;
|
|
941
|
+
} else if (code >= 55296 && code <= 56319) {
|
|
942
|
+
const next = value.charCodeAt(index + 1);
|
|
943
|
+
if (next >= 56320 && next <= 57343) {
|
|
944
|
+
bytes += 4;
|
|
945
|
+
index += 1;
|
|
946
|
+
} else {
|
|
947
|
+
bytes += 3;
|
|
948
|
+
}
|
|
949
|
+
} else {
|
|
950
|
+
bytes += 3;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
return bytes;
|
|
1188
954
|
}
|
|
1189
|
-
function
|
|
1190
|
-
|
|
955
|
+
function isValidRelativePath(path) {
|
|
956
|
+
if (path.length === 0 || path.startsWith("/") || path.includes("\\"))
|
|
957
|
+
return false;
|
|
958
|
+
return !path.split("/").some((part) => part === "..");
|
|
1191
959
|
}
|
|
1192
|
-
function
|
|
1193
|
-
|
|
960
|
+
function packSnapshot(inputs, opts) {
|
|
961
|
+
const maxFiles = opts.maxFiles ?? DEFAULT_MAX_INVENTORY_FILES;
|
|
962
|
+
const maxTextBytes = opts.maxTextBytes ?? DEFAULT_MAX_INVENTORY_TEXT_BYTES;
|
|
963
|
+
const maxSnapshotBytes = opts.maxSnapshotBytes ?? MAX_SNAPSHOT_BODY_BYTES;
|
|
964
|
+
const files = [];
|
|
965
|
+
const skips = [];
|
|
966
|
+
let inventoryTextBytes = 0;
|
|
967
|
+
let serializedBytes = 0;
|
|
968
|
+
let byteCount = 0;
|
|
969
|
+
let truncated = false;
|
|
970
|
+
const recordSkip = (path, reason) => {
|
|
971
|
+
if (skips.length < MAX_RECORDED_SKIPS)
|
|
972
|
+
skips.push({ path, reason });
|
|
973
|
+
};
|
|
974
|
+
const sorted = [...inputs].sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
|
|
975
|
+
for (const input of sorted) {
|
|
976
|
+
if (!isValidRelativePath(input.path)) {
|
|
977
|
+
recordSkip(input.path, "invalid relative path");
|
|
978
|
+
continue;
|
|
979
|
+
}
|
|
980
|
+
const path = posixNormalize(input.path);
|
|
981
|
+
if (input.isSymlink) {
|
|
982
|
+
recordSkip(path, "symlink skipped for safety");
|
|
983
|
+
continue;
|
|
984
|
+
}
|
|
985
|
+
if (isSecretishPath(path)) {
|
|
986
|
+
recordSkip(path, "secret-bearing path");
|
|
987
|
+
continue;
|
|
988
|
+
}
|
|
989
|
+
if (!shouldInventoryFile(path)) {
|
|
990
|
+
recordSkip(path, "not an inventory file");
|
|
991
|
+
continue;
|
|
992
|
+
}
|
|
993
|
+
if (!isTextFile(path)) {
|
|
994
|
+
recordSkip(path, "non-text file");
|
|
995
|
+
continue;
|
|
996
|
+
}
|
|
997
|
+
if (input.byteSize > MAX_SCANNED_FILE_BYTES) {
|
|
998
|
+
recordSkip(path, "file too large");
|
|
999
|
+
truncated = true;
|
|
1000
|
+
continue;
|
|
1001
|
+
}
|
|
1002
|
+
if (files.length >= maxFiles || inventoryTextBytes + input.byteSize > maxTextBytes) {
|
|
1003
|
+
recordSkip(path, "inventory budget");
|
|
1004
|
+
truncated = true;
|
|
1005
|
+
continue;
|
|
1006
|
+
}
|
|
1007
|
+
const text = opts.redact === false ? input.text : redactSnapshotText(input.text).text;
|
|
1008
|
+
const file = { path, text };
|
|
1009
|
+
const serializedCost = utf8ByteLength(JSON.stringify(file)) + 1;
|
|
1010
|
+
if (serializedBytes + serializedCost > maxSnapshotBytes) {
|
|
1011
|
+
recordSkip(path, "snapshot budget");
|
|
1012
|
+
truncated = true;
|
|
1013
|
+
break;
|
|
1014
|
+
}
|
|
1015
|
+
files.push(file);
|
|
1016
|
+
inventoryTextBytes += input.byteSize;
|
|
1017
|
+
serializedBytes += serializedCost;
|
|
1018
|
+
byteCount += utf8ByteLength(text);
|
|
1019
|
+
}
|
|
1020
|
+
return {
|
|
1021
|
+
snapshot: {
|
|
1022
|
+
repo: { name: opts.repoName, root: "." },
|
|
1023
|
+
files,
|
|
1024
|
+
truncated,
|
|
1025
|
+
fileCount: files.length,
|
|
1026
|
+
byteCount,
|
|
1027
|
+
...opts.gitCommit ? { gitCommit: opts.gitCommit } : {}
|
|
1028
|
+
},
|
|
1029
|
+
skips
|
|
1030
|
+
};
|
|
1194
1031
|
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1032
|
+
// src/batch-reads.ts
|
|
1033
|
+
import { readFile } from "node:fs/promises";
|
|
1034
|
+
var BATCH_MAX_TARGETS = 25;
|
|
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 };
|
|
1197
1074
|
}
|
|
1198
|
-
function
|
|
1199
|
-
return /(
|
|
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));
|
|
1200
1077
|
}
|
|
1201
|
-
function
|
|
1202
|
-
|
|
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");
|
|
1203
1086
|
}
|
|
1204
|
-
function
|
|
1205
|
-
|
|
1206
|
-
|
|
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
|
+
}
|
|
1207
1099
|
}
|
|
1208
|
-
function
|
|
1209
|
-
const
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
return true;
|
|
1220
|
-
if (isEvalLikePath(normalized))
|
|
1221
|
-
return true;
|
|
1222
|
-
if (isDeploymentLikePath(normalized))
|
|
1223
|
-
return true;
|
|
1224
|
-
if (isDeveloperAgentConfigPath(normalized))
|
|
1225
|
-
return true;
|
|
1226
|
-
if (isReadmeOrAgents(normalized))
|
|
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);
|
|
1227
1111
|
return true;
|
|
1228
|
-
|
|
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;
|
|
1229
1139
|
}
|
|
1230
|
-
function
|
|
1231
|
-
|
|
1232
|
-
return [
|
|
1233
|
-
"",
|
|
1234
|
-
".cjs",
|
|
1235
|
-
".js",
|
|
1236
|
-
".json",
|
|
1237
|
-
".jsx",
|
|
1238
|
-
".md",
|
|
1239
|
-
".mdc",
|
|
1240
|
-
".mjs",
|
|
1241
|
-
".py",
|
|
1242
|
-
".toml",
|
|
1243
|
-
".ts",
|
|
1244
|
-
".tsx",
|
|
1245
|
-
".txt",
|
|
1246
|
-
".yaml",
|
|
1247
|
-
".yml"
|
|
1248
|
-
].includes(extension);
|
|
1140
|
+
function idNeedsJsonTarget(id) {
|
|
1141
|
+
return ANCHOR_SUFFIX.test(id);
|
|
1249
1142
|
}
|
|
1250
|
-
function
|
|
1251
|
-
const
|
|
1252
|
-
return
|
|
1143
|
+
function contextTarget(id) {
|
|
1144
|
+
const verbatim = id === id.trim() && !id.startsWith("{") && !idNeedsJsonTarget(id);
|
|
1145
|
+
return verbatim ? id : JSON.stringify({ id });
|
|
1253
1146
|
}
|
|
1254
1147
|
|
|
1255
|
-
//
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
var SECRET_KEYS = new Set([
|
|
1259
|
-
"api_key",
|
|
1260
|
-
"apikey",
|
|
1261
|
-
"token",
|
|
1262
|
-
"access_token",
|
|
1263
|
-
"authorization",
|
|
1264
|
-
"secret",
|
|
1265
|
-
"password",
|
|
1266
|
-
"cli_token"
|
|
1267
|
-
]);
|
|
1268
|
-
var SECRET_PATTERNS = [
|
|
1269
|
-
{ pattern: /\bmoda_sk_[A-Za-z0-9_-]+\b/g, prefixLength: 8 },
|
|
1270
|
-
{ pattern: /\bmoda_pk_[A-Za-z0-9_-]+\b/g, prefixLength: 8 },
|
|
1271
|
-
{ pattern: /\bmoda_ct_[A-Za-z0-9_-]+\b/g, prefixLength: 8 },
|
|
1272
|
-
{ pattern: /\bBearer\s+([A-Za-z0-9._~+/-]+=*)\b/gi, prefixLength: 8 },
|
|
1273
|
-
{ pattern: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, prefixLength: 8 },
|
|
1274
|
-
{ pattern: /\bsk-ant-api\d{2}-[A-Za-z0-9_-]{20,}\b/g, prefixLength: 12 },
|
|
1275
|
-
{ pattern: /\bsk-(?:proj-|svcacct-)?[A-Za-z0-9_-]{20,}\b/g, prefixLength: 8 },
|
|
1276
|
-
{ pattern: /\bAKIA[A-Z0-9]{16}\b/g, prefixLength: 8 },
|
|
1277
|
-
{ pattern: /\bAIza[A-Za-z0-9_-]{35}\b/g, prefixLength: 8 },
|
|
1278
|
-
{ pattern: /\bgh[pousr]_[A-Za-z0-9]{36,}\b/g, prefixLength: 8 },
|
|
1279
|
-
{ pattern: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, prefixLength: 8 }
|
|
1280
|
-
];
|
|
1281
|
-
function redactDeep(value) {
|
|
1282
|
-
return redactValue(value, 0, new WeakSet);
|
|
1283
|
-
}
|
|
1284
|
-
function redactValue(value, depth, seen) {
|
|
1285
|
-
if (typeof value === "string")
|
|
1286
|
-
return redactString(value);
|
|
1287
|
-
if (value === null || typeof value !== "object")
|
|
1148
|
+
// src/transforms.ts
|
|
1149
|
+
function asRecord(value) {
|
|
1150
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1288
1151
|
return value;
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1152
|
+
}
|
|
1153
|
+
return null;
|
|
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);
|
|
1299
1196
|
}
|
|
1300
1197
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
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;
|
|
1305
1245
|
}
|
|
1306
|
-
} finally {
|
|
1307
|
-
seen.delete(value);
|
|
1308
1246
|
}
|
|
1309
|
-
|
|
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
|
+
};
|
|
1310
1260
|
}
|
|
1311
|
-
function
|
|
1312
|
-
|
|
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 };
|
|
1313
1272
|
}
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
if (
|
|
1321
|
-
return value;
|
|
1322
|
-
|
|
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 };
|
|
1323
1321
|
}
|
|
1324
|
-
function
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
}
|
|
1337
|
-
return { text, redactionCount };
|
|
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 };
|
|
1338
1334
|
}
|
|
1339
|
-
function
|
|
1340
|
-
|
|
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);
|
|
1341
1347
|
}
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
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 };
|
|
1351
1366
|
}
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
bytes += 4;
|
|
1366
|
-
index += 1;
|
|
1367
|
-
} else {
|
|
1368
|
-
bytes += 3;
|
|
1369
|
-
}
|
|
1370
|
-
} else {
|
|
1371
|
-
bytes += 3;
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
return bytes;
|
|
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 };
|
|
1375
1380
|
}
|
|
1376
|
-
function
|
|
1377
|
-
|
|
1378
|
-
return false;
|
|
1379
|
-
return !path.split("/").some((part) => part === "..");
|
|
1381
|
+
function evidenceMsgIndex(row) {
|
|
1382
|
+
return asNumber(row.anchor_msg_index) ?? asNumber(asRecord(asRecord(row.snippet_parsed)?.anchor)?.msg_index);
|
|
1380
1383
|
}
|
|
1381
|
-
function
|
|
1382
|
-
const
|
|
1383
|
-
const
|
|
1384
|
-
const
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
break;
|
|
1435
|
-
}
|
|
1436
|
-
files.push(file);
|
|
1437
|
-
inventoryTextBytes += input.byteSize;
|
|
1438
|
-
serializedBytes += serializedCost;
|
|
1439
|
-
byteCount += utf8ByteLength(text);
|
|
1440
|
-
}
|
|
1441
|
-
return {
|
|
1442
|
-
snapshot: {
|
|
1443
|
-
repo: { name: opts.repoName, root: "." },
|
|
1444
|
-
files,
|
|
1445
|
-
truncated,
|
|
1446
|
-
fileCount: files.length,
|
|
1447
|
-
byteCount,
|
|
1448
|
-
...opts.gitCommit ? { gitCommit: opts.gitCommit } : {}
|
|
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))
|
|
1449
1437
|
},
|
|
1450
|
-
|
|
1438
|
+
full_command: `moda problems get ${id} --full`
|
|
1451
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 };
|
|
1452
1451
|
}
|
|
1452
|
+
|
|
1453
1453
|
// src/legacy-names.ts
|
|
1454
1454
|
var LEGACY_NAMES = [
|
|
1455
1455
|
{ legacy: "conversations", use: "moda traces list", canonical: { command: "traces", subcommand: "list" }, silent: true },
|
|
@@ -1542,7 +1542,9 @@ function quotedArgumentSpans(text) {
|
|
|
1542
1542
|
return spans;
|
|
1543
1543
|
}
|
|
1544
1544
|
function canonicalInvocation(entry, rest) {
|
|
1545
|
-
|
|
1545
|
+
const separator = rest.indexOf("--");
|
|
1546
|
+
const afterSeparator = separator === -1 ? [] : rest.slice(separator);
|
|
1547
|
+
let words = separator === -1 ? [...rest] : rest.slice(0, separator);
|
|
1546
1548
|
const takeFlag = (pattern) => {
|
|
1547
1549
|
const index = words.findIndex((word2) => pattern.test(word2));
|
|
1548
1550
|
if (index === -1)
|
|
@@ -1563,7 +1565,7 @@ function canonicalInvocation(entry, rest) {
|
|
|
1563
1565
|
takeFlag(/^--detections(=true)?$/);
|
|
1564
1566
|
break;
|
|
1565
1567
|
case "false-positive":
|
|
1566
|
-
words = words.map((word) => /^--undo(=true)
|
|
1568
|
+
words = words.filter((word) => !/^--undo=(false|0)$/i.test(word)).map((word) => /^--undo(=true|=1)?$/i.test(word) ? "--verdict=clear" : word);
|
|
1567
1569
|
break;
|
|
1568
1570
|
case "signal-label":
|
|
1569
1571
|
words = words.map((word) => word.replace(/^--label=fits$/, "--verdict=correct").replace(/^--label=does_not_fit$/, "--verdict=false_positive").replace(/^--label=.*$/, "--verdict=correct|false_positive"));
|
|
@@ -1585,7 +1587,7 @@ function canonicalInvocation(entry, rest) {
|
|
|
1585
1587
|
out.push(token.startsWith("--family=") ? `${token}${familySuffix}` : token);
|
|
1586
1588
|
}
|
|
1587
1589
|
}
|
|
1588
|
-
return [...out, ...positionals, ...words].join(" ");
|
|
1590
|
+
return [...out, ...positionals, ...words, ...afterSeparator].join(" ");
|
|
1589
1591
|
}
|
|
1590
1592
|
function canonicalCommandText(text) {
|
|
1591
1593
|
if (!text.includes("moda "))
|
|
@@ -1684,20 +1686,51 @@ var MODA_COMMAND = /^(?:moda |.*\| moda )/;
|
|
|
1684
1686
|
function withProfileFlag(command, flag) {
|
|
1685
1687
|
return MODA_COMMAND.test(command) && !/(?:^|\s)--profile(?:[=\s]|$)/.test(command) ? `${command} ${flag}` : command;
|
|
1686
1688
|
}
|
|
1689
|
+
var GENERATED_COMMAND_KEY = /_commands?$/;
|
|
1690
|
+
var GENERATED_COMMAND_LIST_KEY = /(?:_commands|^recommended_actions|^recommendedActions|^setupPlan)$/;
|
|
1691
|
+
var CUSTOMER_CONTENT_KEYS = new Set([
|
|
1692
|
+
"messages",
|
|
1693
|
+
"context",
|
|
1694
|
+
"conversation",
|
|
1695
|
+
"conversation_context",
|
|
1696
|
+
"window",
|
|
1697
|
+
"tool_calls",
|
|
1698
|
+
"tool_results",
|
|
1699
|
+
"content",
|
|
1700
|
+
"content_blocks",
|
|
1701
|
+
"input",
|
|
1702
|
+
"output",
|
|
1703
|
+
"tool_input",
|
|
1704
|
+
"tool_output",
|
|
1705
|
+
"spans",
|
|
1706
|
+
"ingest",
|
|
1707
|
+
"raw_event",
|
|
1708
|
+
"attributes",
|
|
1709
|
+
"payload",
|
|
1710
|
+
"snippet_parsed",
|
|
1711
|
+
"evidence_snippet",
|
|
1712
|
+
"request",
|
|
1713
|
+
"response"
|
|
1714
|
+
]);
|
|
1687
1715
|
function withProfileOnCommands(value, profile) {
|
|
1688
1716
|
const flag = `--profile=${shellWord(profile)}`;
|
|
1689
|
-
const visit = (node, key) => {
|
|
1690
|
-
const isCommandKey = key !== undefined &&
|
|
1717
|
+
const visit = (node, key, inCommandList) => {
|
|
1718
|
+
const isCommandKey = key !== undefined && (GENERATED_COMMAND_KEY.test(key) || inCommandList && key === "command");
|
|
1691
1719
|
if (typeof node === "string")
|
|
1692
1720
|
return isCommandKey ? withProfileFlag(node, flag) : node;
|
|
1693
|
-
if (Array.isArray(node))
|
|
1694
|
-
|
|
1721
|
+
if (Array.isArray(node)) {
|
|
1722
|
+
const list = key !== undefined && GENERATED_COMMAND_LIST_KEY.test(key);
|
|
1723
|
+
return node.map((item) => typeof item === "string" ? visit(item, isCommandKey ? key : undefined, false) : visit(item, undefined, list));
|
|
1724
|
+
}
|
|
1695
1725
|
const record = asRecord2(node);
|
|
1696
1726
|
if (!record)
|
|
1697
1727
|
return node;
|
|
1698
|
-
return Object.fromEntries(Object.entries(record).map(([entryKey, entry]) => [
|
|
1728
|
+
return Object.fromEntries(Object.entries(record).map(([entryKey, entry]) => [
|
|
1729
|
+
entryKey,
|
|
1730
|
+
CUSTOMER_CONTENT_KEYS.has(entryKey) ? entry : visit(entry, entryKey, inCommandList)
|
|
1731
|
+
]));
|
|
1699
1732
|
};
|
|
1700
|
-
return visit(value, undefined);
|
|
1733
|
+
return visit(value, undefined, false);
|
|
1701
1734
|
}
|
|
1702
1735
|
var FALLBACK_RUN_ID = randomUUID();
|
|
1703
1736
|
var fallbackSeq = 0;
|
|
@@ -1879,12 +1912,16 @@ function createCliOutput(options) {
|
|
|
1879
1912
|
if (options.quiet && !bypassQuiet)
|
|
1880
1913
|
return;
|
|
1881
1914
|
const profile = options.invocation?.flags.profile;
|
|
1915
|
+
const agentOutput = options.mode === "agent" || options.mode === "agent-stream";
|
|
1882
1916
|
if (profile) {
|
|
1883
|
-
|
|
1917
|
+
if (agentOutput)
|
|
1918
|
+
data = withProfileOnCommands(data, profile);
|
|
1884
1919
|
if (writeOptions.nextCommands)
|
|
1885
|
-
writeOptions = { ...writeOptions, nextCommands: withProfileOnCommands(writeOptions.nextCommands, profile) };
|
|
1920
|
+
writeOptions = { ...writeOptions, nextCommands: withProfileOnCommands({ next_commands: writeOptions.nextCommands }, profile).next_commands };
|
|
1921
|
+
if (writeOptions.recommendedActions)
|
|
1922
|
+
writeOptions = { ...writeOptions, recommendedActions: withProfileOnCommands({ recommended_actions: writeOptions.recommendedActions }, profile).recommended_actions };
|
|
1886
1923
|
}
|
|
1887
|
-
if (
|
|
1924
|
+
if (agentOutput) {
|
|
1888
1925
|
if (state.terminal)
|
|
1889
1926
|
return;
|
|
1890
1927
|
const envelope = writeEnvelope(data, writeOptions);
|
|
@@ -1905,7 +1942,8 @@ function createCliOutput(options) {
|
|
|
1905
1942
|
}
|
|
1906
1943
|
return;
|
|
1907
1944
|
}
|
|
1908
|
-
|
|
1945
|
+
const indent = options.mode === "human" || (options.pretty ?? Boolean(process.stdout.isTTY)) ? 2 : undefined;
|
|
1946
|
+
safeWriteStdout(`${JSON.stringify(canonicalSuggestionFields(redactDeep(data)), null, indent)}
|
|
1909
1947
|
`);
|
|
1910
1948
|
for (const warning of writeOptions.warnings ?? []) {
|
|
1911
1949
|
safeWriteStderr(`Warning: ${canonicalCommandText(warning)}
|
|
@@ -2368,6 +2406,16 @@ function errorToAgentError(error) {
|
|
|
2368
2406
|
blocking: true
|
|
2369
2407
|
};
|
|
2370
2408
|
}
|
|
2409
|
+
if (apiErrorStatus(error) === 404 && !error.readable) {
|
|
2410
|
+
const suggestions = "suggestions" in error && Array.isArray(error.suggestions) ? error.suggestions.filter((s) => typeof s === "string") : [];
|
|
2411
|
+
return {
|
|
2412
|
+
code: "not_found",
|
|
2413
|
+
message: `Not found (HTTP 404): ${serverErrorMessage(error) ?? "the Moda API has no such resource"}.`,
|
|
2414
|
+
cause: "The id may be mistyped, from another tenant or profile, or deleted.",
|
|
2415
|
+
...suggestions.length > 0 ? { suggested_commands: suggestions } : {},
|
|
2416
|
+
blocking: true
|
|
2417
|
+
};
|
|
2418
|
+
}
|
|
2371
2419
|
if (isApiLikeError(error)) {
|
|
2372
2420
|
const statusCode = "statusCode" in error ? error.statusCode : undefined;
|
|
2373
2421
|
const typedCode = "code" in error && typeof error.code === "string" ? error.code : undefined;
|
|
@@ -2618,7 +2666,10 @@ function continuationCommand(invocation, overrides) {
|
|
|
2618
2666
|
const normalize2 = (key) => key.replace(/_/g, "-");
|
|
2619
2667
|
const overridden = new Set(Object.keys(overrides).map(normalize2));
|
|
2620
2668
|
const bare = new Set((invocation.bareFlags ?? []).map(normalize2));
|
|
2621
|
-
const
|
|
2669
|
+
const dashAt = invocation.positionals.findIndex((value) => value.startsWith("-"));
|
|
2670
|
+
const leading = dashAt === -1 ? invocation.positionals : invocation.positionals.slice(0, dashAt);
|
|
2671
|
+
const trailing = dashAt === -1 ? [] : invocation.positionals.slice(dashAt);
|
|
2672
|
+
const parts = ["moda", invocation.command, ...leading.map((value) => shellWord(value))];
|
|
2622
2673
|
for (const [key, value] of Object.entries(invocation.flags)) {
|
|
2623
2674
|
const flag = normalize2(key);
|
|
2624
2675
|
if (overridden.has(flag) || CONTINUATION_SECRET_FLAGS.has(flag))
|
|
@@ -2627,13 +2678,17 @@ function continuationCommand(invocation, overrides) {
|
|
|
2627
2678
|
}
|
|
2628
2679
|
for (const [key, value] of Object.entries(overrides))
|
|
2629
2680
|
parts.push(`--${normalize2(key)}=${shellWord(String(value))}`);
|
|
2681
|
+
if (trailing.length > 0)
|
|
2682
|
+
parts.push("--", ...trailing.map((value) => shellWord(value)));
|
|
2630
2683
|
return canonicalCommandText(parts.join(" "));
|
|
2631
2684
|
}
|
|
2632
2685
|
var PAGED_LIST_BY_COMMAND = {
|
|
2633
2686
|
"tool-failure-detail": "examples",
|
|
2634
2687
|
emotions: "detections",
|
|
2635
2688
|
frustrations: "frustrations",
|
|
2636
|
-
|
|
2689
|
+
laziness: "conversations",
|
|
2690
|
+
"problems remainder": "groups",
|
|
2691
|
+
"problem remainder": "groups"
|
|
2637
2692
|
};
|
|
2638
2693
|
function pagedListFor(invocation) {
|
|
2639
2694
|
const { command, positionals } = invocation.routedAs ?? invocation;
|
|
@@ -2663,7 +2718,7 @@ function rewritePagination(list, isTopLevel, invocation) {
|
|
|
2663
2718
|
const kept = array.length;
|
|
2664
2719
|
const omitted = originalLength - kept;
|
|
2665
2720
|
const offset = typeof pagination.offset === "number" && Number.isFinite(pagination.offset) ? pagination.offset : undefined;
|
|
2666
|
-
const hadCursor = typeof pagination.next_cursor === "string" && pagination.next_cursor.length > 0;
|
|
2721
|
+
const hadCursor = typeof pagination.next_cursor === "string" && pagination.next_cursor.length > 0 || typeof pagination.nextCursor === "string" && pagination.nextCursor.length > 0;
|
|
2667
2722
|
if (typeof pagination.limit === "number") {
|
|
2668
2723
|
pagination.requested_limit = pagination.limit;
|
|
2669
2724
|
pagination.limit = kept;
|
|
@@ -2671,6 +2726,10 @@ function rewritePagination(list, isTopLevel, invocation) {
|
|
|
2671
2726
|
pagination.returned = kept;
|
|
2672
2727
|
pagination.omitted_for_byte_limit = omitted;
|
|
2673
2728
|
pagination.has_more = true;
|
|
2729
|
+
if ("hasMore" in pagination)
|
|
2730
|
+
pagination.hasMore = true;
|
|
2731
|
+
if ("nextCursor" in pagination && typeof pagination.nextCursor === "string" && pagination.nextCursor)
|
|
2732
|
+
pagination.nextCursor = null;
|
|
2674
2733
|
const pastOffsetCap = offset !== undefined && offset + kept > MAX_PAGE_OFFSET;
|
|
2675
2734
|
if (offset !== undefined && !pastOffsetCap)
|
|
2676
2735
|
pagination.next_offset = offset + kept;
|
|
@@ -2852,4 +2911,4 @@ function apiKeyHeaders(key, options = {}, url) {
|
|
|
2852
2911
|
return headers;
|
|
2853
2912
|
}
|
|
2854
2913
|
|
|
2855
|
-
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,
|
|
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, BATCH_MAX_TARGETS, BATCH_CONCURRENCY, parseBatchTarget, collectBatchTargets, mapWithConcurrency, contextTarget, asRecord, asString, asNumber, frustrationAnchorIndex, frustrationsFromEmotions, withFrustrationAnchors, shellWord, trimToolFailureConversations, withToolFailureAnchors, embeddedWindowSize, withoutDetectionWindows, compactProblemDossier, 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 };
|