@node9/proxy 2.41.0 → 2.41.2
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/cli.js +1799 -1508
- package/dist/cli.mjs +1752 -1462
- package/dist/dashboard.mjs +597 -388
- package/dist/index.js +102 -2
- package/dist/index.mjs +102 -2
- package/dist/scan-ink.mjs +42 -0
- package/package.json +1 -1
package/dist/dashboard.mjs
CHANGED
|
@@ -869,12 +869,12 @@ function judgeInlineCode(language, code, isProtected) {
|
|
|
869
869
|
category
|
|
870
870
|
};
|
|
871
871
|
}
|
|
872
|
-
const
|
|
873
|
-
if (
|
|
872
|
+
const path42 = protectedLiteral(text, isProtected);
|
|
873
|
+
if (path42) {
|
|
874
874
|
return {
|
|
875
875
|
outcome: "dangerous",
|
|
876
876
|
what: WHAT["reads-protected"],
|
|
877
|
-
evidence:
|
|
877
|
+
evidence: path42.slice(0, 60),
|
|
878
878
|
category: "reads-protected"
|
|
879
879
|
};
|
|
880
880
|
}
|
|
@@ -1072,6 +1072,66 @@ function foldCommandWords(reading) {
|
|
|
1072
1072
|
function commandReadingsImpl(command) {
|
|
1073
1073
|
return cachedNormalize(command, () => normalizeCommandForPolicyImpl(command));
|
|
1074
1074
|
}
|
|
1075
|
+
function readsStdinAsCode(interp, rest) {
|
|
1076
|
+
const ok = (w) => {
|
|
1077
|
+
if (w === null) return false;
|
|
1078
|
+
if (w === "-") return true;
|
|
1079
|
+
if (/^python/.test(interp))
|
|
1080
|
+
return ["-u", "-B", "-E", "-I", "-s", "-q", "-O", "-OO"].includes(w) || /^-[WX]\S/.test(w);
|
|
1081
|
+
if (interp === "perl" || interp === "ruby") return w === "-w" || w === "-W";
|
|
1082
|
+
return false;
|
|
1083
|
+
};
|
|
1084
|
+
return rest.every(ok);
|
|
1085
|
+
}
|
|
1086
|
+
function interpreterHeredocSpans(f, at) {
|
|
1087
|
+
const stmts = f?.Stmts || [];
|
|
1088
|
+
const candidates = [];
|
|
1089
|
+
let unsafe = false;
|
|
1090
|
+
syntax.Walk(f, (node) => {
|
|
1091
|
+
if (!node || unsafe) return false;
|
|
1092
|
+
const n = node;
|
|
1093
|
+
const t = syntax.NodeType(n);
|
|
1094
|
+
if (t === "FuncDecl") {
|
|
1095
|
+
unsafe = true;
|
|
1096
|
+
return false;
|
|
1097
|
+
}
|
|
1098
|
+
if (t !== "CallExpr") return true;
|
|
1099
|
+
const words = (n.Args || []).map((a) => resolveWordLiteral(a));
|
|
1100
|
+
const head = unwrapCommandHead(words);
|
|
1101
|
+
const raw = words[head];
|
|
1102
|
+
if (raw === null || raw === void 0) {
|
|
1103
|
+
unsafe = true;
|
|
1104
|
+
return false;
|
|
1105
|
+
}
|
|
1106
|
+
const name = raw.split("/").pop()?.toLowerCase() ?? "";
|
|
1107
|
+
if (raw.includes("/") && !STDIN_CODE_INTERPRETERS.test(name)) unsafe = true;
|
|
1108
|
+
if (RUNS_TEXT_ELSEWHERE.has(name)) unsafe = true;
|
|
1109
|
+
return !unsafe;
|
|
1110
|
+
});
|
|
1111
|
+
if (unsafe) return [];
|
|
1112
|
+
for (const st of stmts) {
|
|
1113
|
+
if (!st?.Cmd || syntax.NodeType(st.Cmd) !== "CallExpr") continue;
|
|
1114
|
+
const words = (st.Cmd.Args || []).map((a) => resolveWordLiteral(a));
|
|
1115
|
+
const name = (words[0] ?? "").toLowerCase();
|
|
1116
|
+
if (!STDIN_CODE_INTERPRETERS.test(name)) continue;
|
|
1117
|
+
if (!readsStdinAsCode(name, words.slice(1))) continue;
|
|
1118
|
+
candidates.push(st);
|
|
1119
|
+
}
|
|
1120
|
+
const spans = [];
|
|
1121
|
+
for (const st of candidates) {
|
|
1122
|
+
const heredocs = (st.Redirs || []).filter((r2) => r2?.Hdoc);
|
|
1123
|
+
const stdin = heredocs.filter((r2) => r2.N == null || r2.N.Value === "0");
|
|
1124
|
+
const others = heredocs.length - stdin.length;
|
|
1125
|
+
if (stdin.length !== 1 || others > 0) continue;
|
|
1126
|
+
const r = stdin[0];
|
|
1127
|
+
if (heredocText(r.Hdoc) === null) continue;
|
|
1128
|
+
const hs = at(r.Hdoc.Pos().Offset());
|
|
1129
|
+
const he = at(r.Hdoc.End().Offset());
|
|
1130
|
+
if (hs < 0 || he < 0 || he <= hs) continue;
|
|
1131
|
+
spans.push([hs, he]);
|
|
1132
|
+
}
|
|
1133
|
+
return spans;
|
|
1134
|
+
}
|
|
1075
1135
|
function normalizeCommandForPolicyImpl(command) {
|
|
1076
1136
|
const f = parseShared(command);
|
|
1077
1137
|
if (f === PARSE_FAIL) return { posix: command, separator: command, folded: command };
|
|
@@ -1082,6 +1142,10 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
1082
1142
|
const rewrites = [];
|
|
1083
1143
|
const quoteOnlyRewrites = [];
|
|
1084
1144
|
const msgSpans = /* @__PURE__ */ new Set();
|
|
1145
|
+
for (const [hs, he] of interpreterHeredocSpans(f, at)) {
|
|
1146
|
+
strips.push([hs, he]);
|
|
1147
|
+
msgSpans.add(`${hs}:${he}`);
|
|
1148
|
+
}
|
|
1085
1149
|
syntax.Walk(f, (node) => {
|
|
1086
1150
|
if (!node) return false;
|
|
1087
1151
|
const n = node;
|
|
@@ -1135,7 +1199,12 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
1135
1199
|
});
|
|
1136
1200
|
const stripEdits = strips.map(([s, e]) => [s, e, '""']);
|
|
1137
1201
|
const apply = (extra) => {
|
|
1138
|
-
const
|
|
1202
|
+
const all = [...stripEdits, ...extra];
|
|
1203
|
+
const edits = all.filter(
|
|
1204
|
+
(e, i) => !all.some(
|
|
1205
|
+
(o, k) => k !== i && o[0] <= e[0] && e[1] <= o[1] && (o[0] < e[0] || e[1] < o[1] || k < i)
|
|
1206
|
+
)
|
|
1207
|
+
);
|
|
1139
1208
|
if (edits.length === 0) return command;
|
|
1140
1209
|
edits.sort((a, b) => b[0] - a[0]);
|
|
1141
1210
|
let out = command;
|
|
@@ -2950,9 +3019,9 @@ function ruleServerMatches(rule, serverLabel) {
|
|
|
2950
3019
|
if (rule.notServer && label2 && matchesPattern(label2, rule.notServer)) return false;
|
|
2951
3020
|
return true;
|
|
2952
3021
|
}
|
|
2953
|
-
function getNestedValue(obj,
|
|
3022
|
+
function getNestedValue(obj, path42) {
|
|
2954
3023
|
if (!obj || typeof obj !== "object") return null;
|
|
2955
|
-
const segments2 =
|
|
3024
|
+
const segments2 = path42.split(".");
|
|
2956
3025
|
for (const seg of segments2) {
|
|
2957
3026
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
2958
3027
|
}
|
|
@@ -3909,8 +3978,8 @@ function collectFileAccesses(tool, args, context = {}, inspection = {}) {
|
|
|
3909
3978
|
}
|
|
3910
3979
|
return out;
|
|
3911
3980
|
}
|
|
3912
|
-
function within(
|
|
3913
|
-
return
|
|
3981
|
+
function within(path42, root) {
|
|
3982
|
+
return path42 === root || path42.startsWith(root === "/" ? "/" : root + "/");
|
|
3914
3983
|
}
|
|
3915
3984
|
function hits(access, paths, directories, context) {
|
|
3916
3985
|
const home = context.homeDirs?.[0] ?? "~";
|
|
@@ -5882,9 +5951,9 @@ function bareToolName(toolName) {
|
|
|
5882
5951
|
const parts = toolName.split("__");
|
|
5883
5952
|
return (parts.length >= 3 ? parts.slice(2).join("__") : toolName).toLowerCase();
|
|
5884
5953
|
}
|
|
5885
|
-
function valuesAt(args,
|
|
5954
|
+
function valuesAt(args, path42) {
|
|
5886
5955
|
let cursors = [args];
|
|
5887
|
-
for (const rawSegment of
|
|
5956
|
+
for (const rawSegment of path42.split(".")) {
|
|
5888
5957
|
const isArray = rawSegment.endsWith("[]");
|
|
5889
5958
|
const key = isArray ? rawSegment.slice(0, -2) : rawSegment;
|
|
5890
5959
|
const next = [];
|
|
@@ -5915,8 +5984,8 @@ function extractToolDestinations(toolName, args) {
|
|
|
5915
5984
|
try {
|
|
5916
5985
|
const out = [];
|
|
5917
5986
|
const paths = DESTINATION_ARGS.get(bareToolName(toolName)) ?? [];
|
|
5918
|
-
for (const
|
|
5919
|
-
for (const value of valuesAt(args,
|
|
5987
|
+
for (const path42 of paths) {
|
|
5988
|
+
for (const value of valuesAt(args, path42)) {
|
|
5920
5989
|
const host2 = hostOf(value);
|
|
5921
5990
|
if (host2) out.push({ host: host2, binary: toolName, raw: value });
|
|
5922
5991
|
}
|
|
@@ -5942,8 +6011,8 @@ function ssrfDestinationFloor(toolName, args, opts = {}) {
|
|
|
5942
6011
|
try {
|
|
5943
6012
|
const paths = DESTINATION_ARGS.get(bareToolName(toolName));
|
|
5944
6013
|
if (!paths) return null;
|
|
5945
|
-
for (const
|
|
5946
|
-
for (const value of valuesAt(args,
|
|
6014
|
+
for (const path42 of paths) {
|
|
6015
|
+
for (const value of valuesAt(args, path42)) {
|
|
5947
6016
|
const host2 = hostOf(value);
|
|
5948
6017
|
if (!host2) continue;
|
|
5949
6018
|
const m = classifySsrf(host2);
|
|
@@ -5952,7 +6021,7 @@ function ssrfDestinationFloor(toolName, args, opts = {}) {
|
|
|
5952
6021
|
const decision = ssrfFloorDecision(m, written, opts);
|
|
5953
6022
|
if (decision === null) continue;
|
|
5954
6023
|
const reason = decision === "review" ? ssrfDisguisedReason(m, written) : ssrfReason(m, host2);
|
|
5955
|
-
return { ...m, argPath:
|
|
6024
|
+
return { ...m, argPath: path42, host: host2, reason, decision };
|
|
5956
6025
|
}
|
|
5957
6026
|
}
|
|
5958
6027
|
return null;
|
|
@@ -7520,7 +7589,7 @@ function matchCanaryArgs(args, values) {
|
|
|
7520
7589
|
return null;
|
|
7521
7590
|
}
|
|
7522
7591
|
}
|
|
7523
|
-
var MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, finance_default, identity_default, publishing_default, ACTION_TEMPLATES, ACTION_CHECKS, GAP, prog, httpTo, httpWrite, HTTP_WRITE, HTTP_WRITE_ANY, NOT_STRIPE_TEST, postTo, STRIPE_OBJECTS, APP_SHIELD_SPECS, APP_SHIELDS, APP_SHIELD_NAMES, APP_SERVER_GLOB, GENERAL_ACTION_RULES, BUILTIN_SHIELDS, SSRF_MAX_HOST, METADATA_ADDRESSES, STRICT_TIERS, METADATA_HOSTNAMES, v4Octets, TIER_REASON, CHECK_TEXT, LEVELS, MODE_VALUES, SOFT, STRICT, BLOCK_ALL, LEVEL_CHECKS, VERDICTS, CHECK_VERDICT_RANK, ALL, BUILTIN_DANGEROUS_WORDS, PRODUCT_CHECKS, SHIELD_RULE_NAME, SHIELD_RULES_FOLDED_INTO_PRODUCT, CHECKS, CHECK_BY_ID, LEGACY_TO_ID, PROJECT_JAIL_BLOCK_READ, OVERRIDE_PREFIX, LABEL_WRAPPERS, LEGACY_READERS, INVISIBLE_RE, INVISIBLE_ONE, HOMOGLYPHS, HOMOGLYPH_RE, MAX_BLOBS, MIN_DECODED, BASE64_RUN_RE, HEX_RUN_RE, HEX_ESCAPE_RUN_RE, SYSTEM_AUTH_FILES, SYSTEM_AUTH_DIRS, PASSWORD_HASH_FILES, STARTUP_NAMES, SYSTEM_DIRS, SYSTEM_DIRS_EXEMPT, UPLOAD_SYSTEM_DIRS, AGENT_INSTRUCTION_FILES, AGENT_INSTRUCTION_DIRS, LEGACY_SYSTEM_PATH_RE, MAX_INLINE_CODE, WHAT, OUTSIDE, pyImport, either, PYTHON, NODE, PERL, RUBY, PHP, TABLES, STRING_LITERAL, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, INTERPRETER_LINE, PROGRAM_DIR, ACCESS_VIEW_CACHE_MAX, accessViewCache, MAX_READING_PAYLOADS, defaultExpansionOps, VARIABLE_READERS, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, CURL_SOURCE_FLAGS, CURL_VALUE_LETTERS, WGET_VALUE_LETTERS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_MUTATION_TOOLS, INTERP_LEADING_TARGET, MAX_PAYLOAD_NESTING, payloadNesting, MAX_INLINE_CALLS, INLINE_EXEC_FALLBACK, UNREADABLE_SOURCE, SCRIPT_RUNNERS, SCRIPT_RUNNER_VALUE_FLAGS, MAX_SCRIPT_OPERANDS, NET_BINARIES, VALUE_FLAGS, HOME_VARIABLES, assignmentTable, currentStmtOffset, PAYLOAD_BUDGET, payloadBudget, seenPayloads, UNANALYSABLE_NESTING, ASSIGNMENT_HEADS, AND_OP, OR_OP, AND_OR_OPS, MAX_CALL_DEPTH, MAX_CALL_WALKS, callDepth, callWalks, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, NONE, UNKNOWN, FORBIDDEN_PATH_SEGMENTS, BASH_TOOL_NAMES, MCP_EXECUTORS, BUILTIN_FIELDS, ARGV_FIELDS, BARE_WORD, MAX_ARGV_CHARACTERS, syntax2, MAX_ALTERNATIVES, MAX_CALL_DEPTH2, MAX_CALL_WALKS2, POSITIONAL, MAX_DEPTH, MAX_PAYLOAD_DEPTH, unique, clone, SENDING_STDIN, DOWNLOAD_SHORT_VALUE, DOWNLOAD_LONG_VALUE, DOWNLOAD_OUTPUT_FLAGS, DOWNLOAD_DIR_FLAGS, base, quoteGlob, asWord, WRITES, READS, DUP_OUT, HERE_STRING, AND, OR, DEFAULT_OPS, exempt, RANK, BIP39_ENGLISH, BIP39_PUBLIC_VECTORS, indices, lengths, hash, MAX_MNEMONIC_HASHES, SECRET_VIEW_LIMITS, IBAN_LENGTH, IBAN_BBAN_SHAPE, B58, B58_INDEX, XPRV_VERSIONS, B62, CRC32_TABLE, GITHUB_TOKEN_RE, B64URL, B64URL_INDEX, CASK_TWO_ZERO_SUFFIX, CASK_FOUR_ZERO_SUFFIX, CF_ODD, CF_EVEN, SPANISH_LETTERS, HETU_CHARS, MAX, UNTRUSTED_TOOLS, SIGNALS, MENTION_QUOTE_RE, MENTION_WORD_RE, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, REFERENCE_VALUE_RE, IDENTIFIER_VALUE_RE, PATH_VALUE_RE, DOTTED_REFERENCE_RE, CONCATENATION_RE, EMAIL_VALUE_RE, FIXTURE_NAME_RE, DERIVATIVE_NAME_RE, QUERY_CREDENTIAL_VALUE_RE, OTP_SECRET_RE, OTP_DOC_SECRETS, ASSIGNED_SECRET_VALUE_RE, ASSIGNED_SECRET_NAME_RE, NAME_KEYWORD_RE, ARN_CONTEXT_RE, CIPHER_KEY_NAME_RE, CIPHER_NAME_PARTS, CIPHER_KEY_VALUE_RE, LARAVEL_KEY_VALUE_RE, SQL_PASSWORD_VALUE_RE, GRAFANA_KEY_VALUE_RE, BASIC_VALUE_RE, BASIC_PAIR_RE, OTP_CAPTURE_RE, DB_URL_PASSWORD_RE, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, SENSITIVE_PATH_REGEXES, MAX_DEPTH2, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, BATCH_SEPARATOR, syntax3, NPM_INSTALL_VERBS, NPM_EXEC_VERBS, PNPM_INSTALL_VERBS, YARN_INSTALL_VERBS, BUN_INSTALL_VERBS, DLX_VERBS, NON_REGISTRY_RE, NPM_NAME_RE, EXACT_SEMVER_RE, NPM_VALUE_FLAGS, PNPM_VALUE_FLAGS, YARN_VALUE_FLAGS, BUN_VALUE_FLAGS, PIP_VALUE_FLAGS, UV_VALUE_FLAGS, POETRY_VALUE_FLAGS, PIPENV_VALUE_FLAGS, PIPX_VALUE_FLAGS, PY_SPEC_RE, PY_EXACT_RE, EXACT_VERSION_RE, GEM_NAME_RE, GEM_VALUE_FLAGS, BUNDLE_VALUE_FLAGS, CRATE_NAME_RE, CARGO_ADD_VALUE_FLAGS, CARGO_INSTALL_VALUE_FLAGS, GO_VALUE_FLAGS, GO_PATH_RE, NUGET_NAME_RE, DOTNET_ADD_VALUE_FLAGS, DOTNET_TOOL_VALUE_FLAGS, NUGET_VALUE_FLAGS, MAVEN_COORD_RE, COMPOSER_NAME_RE, COMPOSER_VALUE_FLAGS, EDITOR_HEADS, EXTENSION_ID_RE, MANAGER_HEADS, SHELLS, MAX_NESTING, SHELL_VALUE_FLAGS, TUNING_FIELDS, MAP_GOVERNED, KNOB_GOVERNED, CONFIGURABLE_CHECK_IDS, DEFAULT_EGRESS_ALLOWLIST, PRIVATE_HOST_SUFFIXES, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, DESTINATION_ARGS, MCP_DESTINATION_KEYS, ARGUMENT_SCAN_LIMITS, RUN_CHAR, runChar, VERDICT_RANK, SQL_DML_KEYWORDS, MAX_DESTINATIONS, MAX_SCAN_CHARS, EMAIL_RE, URL_RE, IBAN_RE, RECIPIENT_KEYS, DESTRUCTIVE_VERB_RE, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC16_RE, PII_CC15_RE, PII_CC14_RE, PII_CC13_RE, PII_CC19_RE, CARD_PATTERNS, PII_ROUTING_RE, ROUTING_LABEL_RE, ROUTING_LABEL_WINDOW, NATIONAL_ID_SHAPES, NATIONAL_ID_LABEL_RE, NATIONAL_ID_LABEL_WINDOW, NATIONAL_ID_GUARD_RE, PII_IBAN_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, IBAN_DESTINATION_KEYS, WHOLE_IBAN_RE, JSON_ESCAPE_RE, JSON_ESCAPES, MASKED_KINDS, ENTRY_RE, IBAN_TEXT_RE, EMAIL_TEXT_RE, ACCOUNT_KEY_RE, ACCOUNT_VALUE_RE, MAX_MASK_DEPTH, syntax4, EMPTY, CURL_SEND_FLAGS, WGET_SEND_FLAGS, IWR_SEND_FLAGS, WRITE_METHODS, GH_READ, GH_WRITE, GH_HOSTNAME_FLAGS, GH_REPO_VALUE_FLAGS, GH_API_VALUE_FLAGS, GIT_FETCH, PUBLISH, SHELLS2, OWN_HEADS, MAX_DEPTH3, CWD_CHANGERS, TERMINAL_ESCAPE_RE, LOOP_MAX_RECORDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH4, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION;
|
|
7592
|
+
var MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, finance_default, identity_default, publishing_default, ACTION_TEMPLATES, ACTION_CHECKS, GAP, prog, httpTo, httpWrite, HTTP_WRITE, HTTP_WRITE_ANY, NOT_STRIPE_TEST, postTo, STRIPE_OBJECTS, APP_SHIELD_SPECS, APP_SHIELDS, APP_SHIELD_NAMES, APP_SERVER_GLOB, GENERAL_ACTION_RULES, BUILTIN_SHIELDS, SSRF_MAX_HOST, METADATA_ADDRESSES, STRICT_TIERS, METADATA_HOSTNAMES, v4Octets, TIER_REASON, CHECK_TEXT, LEVELS, MODE_VALUES, SOFT, STRICT, BLOCK_ALL, LEVEL_CHECKS, VERDICTS, CHECK_VERDICT_RANK, ALL, BUILTIN_DANGEROUS_WORDS, PRODUCT_CHECKS, SHIELD_RULE_NAME, SHIELD_RULES_FOLDED_INTO_PRODUCT, CHECKS, CHECK_BY_ID, LEGACY_TO_ID, PROJECT_JAIL_BLOCK_READ, OVERRIDE_PREFIX, LABEL_WRAPPERS, LEGACY_READERS, INVISIBLE_RE, INVISIBLE_ONE, HOMOGLYPHS, HOMOGLYPH_RE, MAX_BLOBS, MIN_DECODED, BASE64_RUN_RE, HEX_RUN_RE, HEX_ESCAPE_RUN_RE, SYSTEM_AUTH_FILES, SYSTEM_AUTH_DIRS, PASSWORD_HASH_FILES, STARTUP_NAMES, SYSTEM_DIRS, SYSTEM_DIRS_EXEMPT, UPLOAD_SYSTEM_DIRS, AGENT_INSTRUCTION_FILES, AGENT_INSTRUCTION_DIRS, LEGACY_SYSTEM_PATH_RE, MAX_INLINE_CODE, WHAT, OUTSIDE, pyImport, either, PYTHON, NODE, PERL, RUBY, PHP, TABLES, STRING_LITERAL, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, INTERPRETER_LINE, PROGRAM_DIR, ACCESS_VIEW_CACHE_MAX, accessViewCache, MAX_READING_PAYLOADS, STDIN_CODE_INTERPRETERS, RUNS_TEXT_ELSEWHERE, defaultExpansionOps, VARIABLE_READERS, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, CURL_SOURCE_FLAGS, CURL_VALUE_LETTERS, WGET_VALUE_LETTERS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_MUTATION_TOOLS, INTERP_LEADING_TARGET, MAX_PAYLOAD_NESTING, payloadNesting, MAX_INLINE_CALLS, INLINE_EXEC_FALLBACK, UNREADABLE_SOURCE, SCRIPT_RUNNERS, SCRIPT_RUNNER_VALUE_FLAGS, MAX_SCRIPT_OPERANDS, NET_BINARIES, VALUE_FLAGS, HOME_VARIABLES, assignmentTable, currentStmtOffset, PAYLOAD_BUDGET, payloadBudget, seenPayloads, UNANALYSABLE_NESTING, ASSIGNMENT_HEADS, AND_OP, OR_OP, AND_OR_OPS, MAX_CALL_DEPTH, MAX_CALL_WALKS, callDepth, callWalks, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, NONE, UNKNOWN, FORBIDDEN_PATH_SEGMENTS, BASH_TOOL_NAMES, MCP_EXECUTORS, BUILTIN_FIELDS, ARGV_FIELDS, BARE_WORD, MAX_ARGV_CHARACTERS, syntax2, MAX_ALTERNATIVES, MAX_CALL_DEPTH2, MAX_CALL_WALKS2, POSITIONAL, MAX_DEPTH, MAX_PAYLOAD_DEPTH, unique, clone, SENDING_STDIN, DOWNLOAD_SHORT_VALUE, DOWNLOAD_LONG_VALUE, DOWNLOAD_OUTPUT_FLAGS, DOWNLOAD_DIR_FLAGS, base, quoteGlob, asWord, WRITES, READS, DUP_OUT, HERE_STRING, AND, OR, DEFAULT_OPS, exempt, RANK, BIP39_ENGLISH, BIP39_PUBLIC_VECTORS, indices, lengths, hash, MAX_MNEMONIC_HASHES, SECRET_VIEW_LIMITS, IBAN_LENGTH, IBAN_BBAN_SHAPE, B58, B58_INDEX, XPRV_VERSIONS, B62, CRC32_TABLE, GITHUB_TOKEN_RE, B64URL, B64URL_INDEX, CASK_TWO_ZERO_SUFFIX, CASK_FOUR_ZERO_SUFFIX, CF_ODD, CF_EVEN, SPANISH_LETTERS, HETU_CHARS, MAX, UNTRUSTED_TOOLS, SIGNALS, MENTION_QUOTE_RE, MENTION_WORD_RE, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, REFERENCE_VALUE_RE, IDENTIFIER_VALUE_RE, PATH_VALUE_RE, DOTTED_REFERENCE_RE, CONCATENATION_RE, EMAIL_VALUE_RE, FIXTURE_NAME_RE, DERIVATIVE_NAME_RE, QUERY_CREDENTIAL_VALUE_RE, OTP_SECRET_RE, OTP_DOC_SECRETS, ASSIGNED_SECRET_VALUE_RE, ASSIGNED_SECRET_NAME_RE, NAME_KEYWORD_RE, ARN_CONTEXT_RE, CIPHER_KEY_NAME_RE, CIPHER_NAME_PARTS, CIPHER_KEY_VALUE_RE, LARAVEL_KEY_VALUE_RE, SQL_PASSWORD_VALUE_RE, GRAFANA_KEY_VALUE_RE, BASIC_VALUE_RE, BASIC_PAIR_RE, OTP_CAPTURE_RE, DB_URL_PASSWORD_RE, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, SENSITIVE_PATH_REGEXES, MAX_DEPTH2, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, BATCH_SEPARATOR, syntax3, NPM_INSTALL_VERBS, NPM_EXEC_VERBS, PNPM_INSTALL_VERBS, YARN_INSTALL_VERBS, BUN_INSTALL_VERBS, DLX_VERBS, NON_REGISTRY_RE, NPM_NAME_RE, EXACT_SEMVER_RE, NPM_VALUE_FLAGS, PNPM_VALUE_FLAGS, YARN_VALUE_FLAGS, BUN_VALUE_FLAGS, PIP_VALUE_FLAGS, UV_VALUE_FLAGS, POETRY_VALUE_FLAGS, PIPENV_VALUE_FLAGS, PIPX_VALUE_FLAGS, PY_SPEC_RE, PY_EXACT_RE, EXACT_VERSION_RE, GEM_NAME_RE, GEM_VALUE_FLAGS, BUNDLE_VALUE_FLAGS, CRATE_NAME_RE, CARGO_ADD_VALUE_FLAGS, CARGO_INSTALL_VALUE_FLAGS, GO_VALUE_FLAGS, GO_PATH_RE, NUGET_NAME_RE, DOTNET_ADD_VALUE_FLAGS, DOTNET_TOOL_VALUE_FLAGS, NUGET_VALUE_FLAGS, MAVEN_COORD_RE, COMPOSER_NAME_RE, COMPOSER_VALUE_FLAGS, EDITOR_HEADS, EXTENSION_ID_RE, MANAGER_HEADS, SHELLS, MAX_NESTING, SHELL_VALUE_FLAGS, TUNING_FIELDS, MAP_GOVERNED, KNOB_GOVERNED, CONFIGURABLE_CHECK_IDS, DEFAULT_EGRESS_ALLOWLIST, PRIVATE_HOST_SUFFIXES, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, DESTINATION_ARGS, MCP_DESTINATION_KEYS, ARGUMENT_SCAN_LIMITS, RUN_CHAR, runChar, VERDICT_RANK, SQL_DML_KEYWORDS, MAX_DESTINATIONS, MAX_SCAN_CHARS, EMAIL_RE, URL_RE, IBAN_RE, RECIPIENT_KEYS, DESTRUCTIVE_VERB_RE, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC16_RE, PII_CC15_RE, PII_CC14_RE, PII_CC13_RE, PII_CC19_RE, CARD_PATTERNS, PII_ROUTING_RE, ROUTING_LABEL_RE, ROUTING_LABEL_WINDOW, NATIONAL_ID_SHAPES, NATIONAL_ID_LABEL_RE, NATIONAL_ID_LABEL_WINDOW, NATIONAL_ID_GUARD_RE, PII_IBAN_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, IBAN_DESTINATION_KEYS, WHOLE_IBAN_RE, JSON_ESCAPE_RE, JSON_ESCAPES, MASKED_KINDS, ENTRY_RE, IBAN_TEXT_RE, EMAIL_TEXT_RE, ACCOUNT_KEY_RE, ACCOUNT_VALUE_RE, MAX_MASK_DEPTH, syntax4, EMPTY, CURL_SEND_FLAGS, WGET_SEND_FLAGS, IWR_SEND_FLAGS, WRITE_METHODS, GH_READ, GH_WRITE, GH_HOSTNAME_FLAGS, GH_REPO_VALUE_FLAGS, GH_API_VALUE_FLAGS, GIT_FETCH, PUBLISH, SHELLS2, OWN_HEADS, MAX_DEPTH3, CWD_CHANGERS, TERMINAL_ESCAPE_RE, LOOP_MAX_RECORDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH4, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION;
|
|
7524
7593
|
var init_dist = __esm({
|
|
7525
7594
|
"packages/policy-engine/dist/index.mjs"() {
|
|
7526
7595
|
"use strict";
|
|
@@ -10196,6 +10265,37 @@ var init_dist = __esm({
|
|
|
10196
10265
|
ACCESS_VIEW_CACHE_MAX = 1e3;
|
|
10197
10266
|
accessViewCache = /* @__PURE__ */ new Map();
|
|
10198
10267
|
MAX_READING_PAYLOADS = 8;
|
|
10268
|
+
STDIN_CODE_INTERPRETERS = /^(python[0-9.]*|node|nodejs|perl|ruby|php|lua)$/;
|
|
10269
|
+
RUNS_TEXT_ELSEWHERE = /* @__PURE__ */ new Set([
|
|
10270
|
+
...SHELL_INTERPRETERS,
|
|
10271
|
+
"csh",
|
|
10272
|
+
"tcsh",
|
|
10273
|
+
"ash",
|
|
10274
|
+
"mksh",
|
|
10275
|
+
"busybox",
|
|
10276
|
+
"eval",
|
|
10277
|
+
"source",
|
|
10278
|
+
".",
|
|
10279
|
+
"exec",
|
|
10280
|
+
"xargs",
|
|
10281
|
+
"ssh",
|
|
10282
|
+
"scp",
|
|
10283
|
+
"docker",
|
|
10284
|
+
"podman",
|
|
10285
|
+
"kubectl",
|
|
10286
|
+
"su",
|
|
10287
|
+
"nsenter",
|
|
10288
|
+
"at",
|
|
10289
|
+
"batch",
|
|
10290
|
+
"crontab",
|
|
10291
|
+
"flock",
|
|
10292
|
+
"psql",
|
|
10293
|
+
"mysql",
|
|
10294
|
+
"mongo",
|
|
10295
|
+
"mongosh",
|
|
10296
|
+
"redis-cli",
|
|
10297
|
+
"sqlite3"
|
|
10298
|
+
]);
|
|
10199
10299
|
defaultExpansionOps = null;
|
|
10200
10300
|
VARIABLE_READERS = /* @__PURE__ */ new Set([
|
|
10201
10301
|
"read",
|
|
@@ -15203,7 +15303,7 @@ zoo`.split("\n");
|
|
|
15203
15303
|
{ view: "separators-stripped", decoder: "separators", stripped: true }
|
|
15204
15304
|
];
|
|
15205
15305
|
LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
|
|
15206
|
-
CANONICAL_EXTRACTOR_VERSION = "canonical-
|
|
15306
|
+
CANONICAL_EXTRACTOR_VERSION = "canonical-v31";
|
|
15207
15307
|
}
|
|
15208
15308
|
});
|
|
15209
15309
|
|
|
@@ -15873,87 +15973,69 @@ var init_dlp = __esm({
|
|
|
15873
15973
|
}
|
|
15874
15974
|
});
|
|
15875
15975
|
|
|
15976
|
+
// src/credential-files.ts
|
|
15977
|
+
import path5 from "path";
|
|
15978
|
+
function homeCredentialFiles(home) {
|
|
15979
|
+
const f = (parts, description, score, kind = "credential") => ({
|
|
15980
|
+
full: path5.join(home, ...parts),
|
|
15981
|
+
label: "~/" + parts.join("/"),
|
|
15982
|
+
description,
|
|
15983
|
+
score,
|
|
15984
|
+
kind
|
|
15985
|
+
});
|
|
15986
|
+
return [
|
|
15987
|
+
f([".ssh", "id_rsa"], "RSA private key: grants SSH access to your servers", 20),
|
|
15988
|
+
f([".ssh", "id_ed25519"], "Ed25519 private key: grants SSH access to your servers", 20),
|
|
15989
|
+
f([".ssh", "id_ecdsa"], "ECDSA private key: grants SSH access to your servers", 20),
|
|
15990
|
+
f([".ssh", "id_dsa"], "DSA private key: grants SSH access to your servers", 20),
|
|
15991
|
+
f([".aws", "credentials"], "AWS access keys: full cloud account access", 20),
|
|
15992
|
+
f([".aws", "config"], "AWS configuration: account and region settings", 5, "config"),
|
|
15993
|
+
f([".config", "gcloud", "credentials.db"], "Google Cloud credentials", 15),
|
|
15994
|
+
f(
|
|
15995
|
+
[".config", "gcloud", "application_default_credentials.json"],
|
|
15996
|
+
"Google Cloud application default credentials",
|
|
15997
|
+
15
|
|
15998
|
+
),
|
|
15999
|
+
f([".docker", "config.json"], "Docker registry auth tokens", 10),
|
|
16000
|
+
f([".netrc"], "FTP/HTTP credentials in plain text", 15),
|
|
16001
|
+
f([".npmrc"], "npm auth token: can publish packages as you", 10),
|
|
16002
|
+
f([".node9", "credentials.json"], "Node9 cloud API key", 10)
|
|
16003
|
+
];
|
|
16004
|
+
}
|
|
16005
|
+
var init_credential_files = __esm({
|
|
16006
|
+
"src/credential-files.ts"() {
|
|
16007
|
+
"use strict";
|
|
16008
|
+
}
|
|
16009
|
+
});
|
|
16010
|
+
|
|
15876
16011
|
// src/cli/commands/blast.ts
|
|
15877
16012
|
import chalk from "chalk";
|
|
15878
16013
|
import fs5 from "fs";
|
|
15879
|
-
import
|
|
16014
|
+
import path6 from "path";
|
|
15880
16015
|
import os4 from "os";
|
|
15881
16016
|
function buildSensitivePaths(home, cwd) {
|
|
16017
|
+
const homeFiles = homeCredentialFiles(home).map(({ full, label: label2, description, score }) => ({
|
|
16018
|
+
full,
|
|
16019
|
+
label: label2,
|
|
16020
|
+
description,
|
|
16021
|
+
score
|
|
16022
|
+
}));
|
|
15882
16023
|
return [
|
|
16024
|
+
...homeFiles,
|
|
15883
16025
|
{
|
|
15884
|
-
full:
|
|
15885
|
-
label: "~/.ssh/id_rsa",
|
|
15886
|
-
description: "RSA private key \u2014 grants SSH access to your servers",
|
|
15887
|
-
score: 20
|
|
15888
|
-
},
|
|
15889
|
-
{
|
|
15890
|
-
full: path5.join(home, ".ssh", "id_ed25519"),
|
|
15891
|
-
label: "~/.ssh/id_ed25519",
|
|
15892
|
-
description: "Ed25519 private key \u2014 grants SSH access to your servers",
|
|
15893
|
-
score: 20
|
|
15894
|
-
},
|
|
15895
|
-
{
|
|
15896
|
-
full: path5.join(home, ".ssh", "id_ecdsa"),
|
|
15897
|
-
label: "~/.ssh/id_ecdsa",
|
|
15898
|
-
description: "ECDSA private key \u2014 grants SSH access to your servers",
|
|
15899
|
-
score: 20
|
|
15900
|
-
},
|
|
15901
|
-
{
|
|
15902
|
-
full: path5.join(home, ".aws", "credentials"),
|
|
15903
|
-
label: "~/.aws/credentials",
|
|
15904
|
-
description: "AWS access keys \u2014 full cloud account access",
|
|
15905
|
-
score: 20
|
|
15906
|
-
},
|
|
15907
|
-
{
|
|
15908
|
-
full: path5.join(home, ".aws", "config"),
|
|
15909
|
-
label: "~/.aws/config",
|
|
15910
|
-
description: "AWS configuration \u2014 account and region settings",
|
|
15911
|
-
score: 5
|
|
15912
|
-
},
|
|
15913
|
-
{
|
|
15914
|
-
full: path5.join(home, ".config", "gcloud", "credentials.db"),
|
|
15915
|
-
label: "~/.config/gcloud/credentials.db",
|
|
15916
|
-
description: "Google Cloud credentials",
|
|
15917
|
-
score: 15
|
|
15918
|
-
},
|
|
15919
|
-
{
|
|
15920
|
-
full: path5.join(home, ".docker", "config.json"),
|
|
15921
|
-
label: "~/.docker/config.json",
|
|
15922
|
-
description: "Docker registry auth tokens",
|
|
15923
|
-
score: 10
|
|
15924
|
-
},
|
|
15925
|
-
{
|
|
15926
|
-
full: path5.join(home, ".netrc"),
|
|
15927
|
-
label: "~/.netrc",
|
|
15928
|
-
description: "FTP/HTTP credentials in plain text",
|
|
15929
|
-
score: 15
|
|
15930
|
-
},
|
|
15931
|
-
{
|
|
15932
|
-
full: path5.join(home, ".npmrc"),
|
|
15933
|
-
label: "~/.npmrc",
|
|
15934
|
-
description: "npm auth token \u2014 can publish packages as you",
|
|
15935
|
-
score: 10
|
|
15936
|
-
},
|
|
15937
|
-
{
|
|
15938
|
-
full: path5.join(home, ".node9", "credentials.json"),
|
|
15939
|
-
label: "~/.node9/credentials.json",
|
|
15940
|
-
description: "Node9 cloud API key",
|
|
15941
|
-
score: 10
|
|
15942
|
-
},
|
|
15943
|
-
{
|
|
15944
|
-
full: path5.join(cwd, ".env"),
|
|
16026
|
+
full: path6.join(cwd, ".env"),
|
|
15945
16027
|
label: ".env (current folder)",
|
|
15946
|
-
description: "App secrets
|
|
16028
|
+
description: "App secrets: database passwords, API keys",
|
|
15947
16029
|
score: 20
|
|
15948
16030
|
},
|
|
15949
16031
|
{
|
|
15950
|
-
full:
|
|
16032
|
+
full: path6.join(cwd, ".env.local"),
|
|
15951
16033
|
label: ".env.local (current folder)",
|
|
15952
|
-
description: "Local overrides
|
|
16034
|
+
description: "Local overrides: often contains real credentials",
|
|
15953
16035
|
score: 15
|
|
15954
16036
|
},
|
|
15955
16037
|
{
|
|
15956
|
-
full:
|
|
16038
|
+
full: path6.join(cwd, ".env.production"),
|
|
15957
16039
|
label: ".env.production (current folder)",
|
|
15958
16040
|
description: "Production secrets",
|
|
15959
16041
|
score: 20
|
|
@@ -15995,6 +16077,7 @@ var init_blast = __esm({
|
|
|
15995
16077
|
"src/cli/commands/blast.ts"() {
|
|
15996
16078
|
"use strict";
|
|
15997
16079
|
init_dlp();
|
|
16080
|
+
init_credential_files();
|
|
15998
16081
|
}
|
|
15999
16082
|
});
|
|
16000
16083
|
|
|
@@ -16154,7 +16237,7 @@ var init_decision_record = __esm({
|
|
|
16154
16237
|
// src/auth/daemon.ts
|
|
16155
16238
|
import fs6 from "fs";
|
|
16156
16239
|
import http from "http";
|
|
16157
|
-
import
|
|
16240
|
+
import path7 from "path";
|
|
16158
16241
|
import os5 from "os";
|
|
16159
16242
|
async function checkStatePredicates(predicates) {
|
|
16160
16243
|
if (predicates.length === 0) return {};
|
|
@@ -16181,7 +16264,7 @@ function resolveDaemonPort(env = process.env) {
|
|
|
16181
16264
|
function getInternalToken() {
|
|
16182
16265
|
if (forecastRun()) return null;
|
|
16183
16266
|
try {
|
|
16184
|
-
const pidFile =
|
|
16267
|
+
const pidFile = path7.join(os5.homedir(), ".node9", "daemon.pid");
|
|
16185
16268
|
if (!fs6.existsSync(pidFile)) return null;
|
|
16186
16269
|
const data = JSON.parse(fs6.readFileSync(pidFile, "utf-8"));
|
|
16187
16270
|
process.kill(data.pid, 0);
|
|
@@ -16192,7 +16275,7 @@ function getInternalToken() {
|
|
|
16192
16275
|
}
|
|
16193
16276
|
function isDaemonRunning() {
|
|
16194
16277
|
if (forecastRun()) return false;
|
|
16195
|
-
const pidFile =
|
|
16278
|
+
const pidFile = path7.join(os5.homedir(), ".node9", "daemon.pid");
|
|
16196
16279
|
if (fs6.existsSync(pidFile)) {
|
|
16197
16280
|
let pid;
|
|
16198
16281
|
let port;
|
|
@@ -16554,7 +16637,7 @@ var init_daemon = __esm({
|
|
|
16554
16637
|
"use strict";
|
|
16555
16638
|
init_forecast_context();
|
|
16556
16639
|
init_decision_record();
|
|
16557
|
-
ACTIVITY_SOCKET_PATH = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
16640
|
+
ACTIVITY_SOCKET_PATH = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path7.join(os5.tmpdir(), "node9-activity.sock");
|
|
16558
16641
|
DEFAULT_DAEMON_PORT = 7391;
|
|
16559
16642
|
DAEMON_PORT = resolveDaemonPort();
|
|
16560
16643
|
DAEMON_HOST = "127.0.0.1";
|
|
@@ -16565,8 +16648,8 @@ var init_daemon = __esm({
|
|
|
16565
16648
|
import { z } from "zod";
|
|
16566
16649
|
function formatIssues(issues) {
|
|
16567
16650
|
const lines = issues.map((issue) => {
|
|
16568
|
-
const
|
|
16569
|
-
return ` \u2022 ${
|
|
16651
|
+
const path42 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
16652
|
+
return ` \u2022 ${path42}: ${issue.message}`;
|
|
16570
16653
|
});
|
|
16571
16654
|
return `Invalid config:
|
|
16572
16655
|
${lines.join("\n")}`;
|
|
@@ -16579,9 +16662,9 @@ function prunePaths(root, paths) {
|
|
|
16579
16662
|
const yi = y[y.length - 1];
|
|
16580
16663
|
return typeof xi === "number" && typeof yi === "number" ? yi - xi : 0;
|
|
16581
16664
|
});
|
|
16582
|
-
for (const
|
|
16665
|
+
for (const path42 of ordered) {
|
|
16583
16666
|
let cur = root;
|
|
16584
|
-
for (const key of
|
|
16667
|
+
for (const key of path42.slice(0, -1)) {
|
|
16585
16668
|
if (cur === null || typeof cur !== "object") {
|
|
16586
16669
|
cur = void 0;
|
|
16587
16670
|
break;
|
|
@@ -16589,7 +16672,7 @@ function prunePaths(root, paths) {
|
|
|
16589
16672
|
cur = cur[key];
|
|
16590
16673
|
}
|
|
16591
16674
|
if (cur === null || typeof cur !== "object") continue;
|
|
16592
|
-
const last =
|
|
16675
|
+
const last = path42[path42.length - 1];
|
|
16593
16676
|
if (Array.isArray(cur)) {
|
|
16594
16677
|
const i = Number(last);
|
|
16595
16678
|
if (Number.isInteger(i) && i >= 0 && i < cur.length) {
|
|
@@ -16625,7 +16708,7 @@ function sanitizeConfig(raw) {
|
|
|
16625
16708
|
return issue.keys.map((k) => [...at, k]);
|
|
16626
16709
|
}
|
|
16627
16710
|
return [at.slice(0, -level || void 0)];
|
|
16628
|
-
}).filter((
|
|
16711
|
+
}).filter((path42) => path42.length > 0);
|
|
16629
16712
|
if (paths.length === 0 || !prunePaths(working, paths)) break;
|
|
16630
16713
|
}
|
|
16631
16714
|
if (ConfigFileSchema.safeParse(working).success) break;
|
|
@@ -16923,7 +17006,7 @@ var init_build = __esm({
|
|
|
16923
17006
|
|
|
16924
17007
|
// src/shields.ts
|
|
16925
17008
|
import fs7 from "fs";
|
|
16926
|
-
import
|
|
17009
|
+
import path8 from "path";
|
|
16927
17010
|
import os6 from "os";
|
|
16928
17011
|
function loadUserShields() {
|
|
16929
17012
|
const result = {};
|
|
@@ -16940,7 +17023,7 @@ function loadUserShields() {
|
|
|
16940
17023
|
return result;
|
|
16941
17024
|
}
|
|
16942
17025
|
for (const file2 of entries) {
|
|
16943
|
-
const filePath =
|
|
17026
|
+
const filePath = path8.join(USER_SHIELDS_DIR, file2);
|
|
16944
17027
|
try {
|
|
16945
17028
|
const raw = JSON.parse(fs7.readFileSync(filePath, "utf-8"));
|
|
16946
17029
|
const v = validateShieldDefinition(raw);
|
|
@@ -17007,9 +17090,9 @@ var init_shields = __esm({
|
|
|
17007
17090
|
init_dist();
|
|
17008
17091
|
init_build();
|
|
17009
17092
|
init_dist();
|
|
17010
|
-
USER_SHIELDS_DIR =
|
|
17093
|
+
USER_SHIELDS_DIR = path8.join(os6.homedir(), ".node9", "shields");
|
|
17011
17094
|
SHIELDS = buildSHIELDS();
|
|
17012
|
-
SHIELDS_STATE_FILE =
|
|
17095
|
+
SHIELDS_STATE_FILE = path8.join(os6.homedir(), ".node9", "shields.json");
|
|
17013
17096
|
}
|
|
17014
17097
|
});
|
|
17015
17098
|
|
|
@@ -17143,10 +17226,10 @@ var init_managed = __esm({
|
|
|
17143
17226
|
|
|
17144
17227
|
// src/auth/trusted-hosts.ts
|
|
17145
17228
|
import fs8 from "fs";
|
|
17146
|
-
import
|
|
17229
|
+
import path9 from "path";
|
|
17147
17230
|
import os7 from "os";
|
|
17148
17231
|
function getTrustedHostsPath() {
|
|
17149
|
-
return
|
|
17232
|
+
return path9.join(os7.homedir(), ".node9", "trusted-hosts.json");
|
|
17150
17233
|
}
|
|
17151
17234
|
function readTrustedHosts() {
|
|
17152
17235
|
try {
|
|
@@ -17379,7 +17462,7 @@ var init_api_url = __esm({
|
|
|
17379
17462
|
|
|
17380
17463
|
// src/config/index.ts
|
|
17381
17464
|
import fs9 from "fs";
|
|
17382
|
-
import
|
|
17465
|
+
import path10 from "path";
|
|
17383
17466
|
import os8 from "os";
|
|
17384
17467
|
function sanitizeSsrfAllow(entries, source) {
|
|
17385
17468
|
const kept = [];
|
|
@@ -17403,7 +17486,7 @@ function noteRejectedApiUrl(raw) {
|
|
|
17403
17486
|
rejectedApiUrlsSeen.add(key);
|
|
17404
17487
|
try {
|
|
17405
17488
|
fs9.appendFileSync(
|
|
17406
|
-
|
|
17489
|
+
path10.join(os8.homedir(), ".node9", "hook-debug.log"),
|
|
17407
17490
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] REFUSED apiUrl, using the default instead: ${String(raw).slice(0, 200).replace(/[\r\n]+/g, " ")}
|
|
17408
17491
|
`
|
|
17409
17492
|
);
|
|
@@ -17420,7 +17503,7 @@ function getCredentials() {
|
|
|
17420
17503
|
};
|
|
17421
17504
|
}
|
|
17422
17505
|
try {
|
|
17423
|
-
const credPath =
|
|
17506
|
+
const credPath = path10.join(os8.homedir(), ".node9", "credentials.json");
|
|
17424
17507
|
if (fs9.existsSync(credPath)) {
|
|
17425
17508
|
const creds = JSON.parse(fs9.readFileSync(credPath, "utf-8"));
|
|
17426
17509
|
const profileName = process.env.NODE9_PROFILE || "default";
|
|
@@ -17469,7 +17552,7 @@ function readRulesCacheResilient(cacheFile) {
|
|
|
17469
17552
|
}
|
|
17470
17553
|
}
|
|
17471
17554
|
if (existed || sawReadError) {
|
|
17472
|
-
const backup =
|
|
17555
|
+
const backup = path10.join(path10.dirname(cacheFile), "rules-cache.last-good.json");
|
|
17473
17556
|
if (backup !== cacheFile) {
|
|
17474
17557
|
try {
|
|
17475
17558
|
const raw = JSON.parse(fs9.readFileSync(backup, "utf-8"));
|
|
@@ -17493,7 +17576,7 @@ function logCacheReadIssue(cacheFile, kind) {
|
|
|
17493
17576
|
cacheReadLastLoggedAt = now;
|
|
17494
17577
|
try {
|
|
17495
17578
|
fs9.appendFileSync(
|
|
17496
|
-
|
|
17579
|
+
path10.join(os8.homedir(), ".node9", "hook-debug.log"),
|
|
17497
17580
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] ${kind} ${cacheFile}
|
|
17498
17581
|
`
|
|
17499
17582
|
);
|
|
@@ -17510,8 +17593,8 @@ function catalogSettingsFrom(settings, policy) {
|
|
|
17510
17593
|
}
|
|
17511
17594
|
function getConfig(cwd) {
|
|
17512
17595
|
if (!cwd && cachedConfig) return cachedConfig;
|
|
17513
|
-
const globalPath =
|
|
17514
|
-
const projectPath =
|
|
17596
|
+
const globalPath = path10.join(os8.homedir(), ".node9", "config.json");
|
|
17597
|
+
const projectPath = path10.join(cwd ?? process.cwd(), "node9.config.json");
|
|
17515
17598
|
const globalConfig = tryLoadConfig(globalPath);
|
|
17516
17599
|
const projectConfig = tryLoadConfig(projectPath, { project: true });
|
|
17517
17600
|
const mergedSettings = {
|
|
@@ -17756,7 +17839,7 @@ function getConfig(cwd) {
|
|
|
17756
17839
|
let cloudMandatesEnforcement = false;
|
|
17757
17840
|
let cloudMandatesAppPerm = false;
|
|
17758
17841
|
{
|
|
17759
|
-
const cacheFile =
|
|
17842
|
+
const cacheFile = path10.join(os8.homedir(), ".node9", "rules-cache.json");
|
|
17760
17843
|
try {
|
|
17761
17844
|
const raw = readRulesCacheResilient(cacheFile);
|
|
17762
17845
|
if (Array.isArray(raw.rules) && raw.rules.length > 0) {
|
|
@@ -17949,13 +18032,13 @@ function getConfig(cwd) {
|
|
|
17949
18032
|
}
|
|
17950
18033
|
if (Array.isArray(mc.jailPaths)) {
|
|
17951
18034
|
for (const jp of mc.jailPaths) {
|
|
17952
|
-
const
|
|
17953
|
-
if (!
|
|
18035
|
+
const path42 = typeof jp?.path === "string" ? jp.path.trim() : "";
|
|
18036
|
+
if (!path42) continue;
|
|
17954
18037
|
const verdict = jp?.verdict === "review" ? "review" : "block";
|
|
17955
|
-
for (const r of pathRules(
|
|
18038
|
+
for (const r of pathRules(path42, verdict, "org-managed jail")) {
|
|
17956
18039
|
mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
|
|
17957
18040
|
}
|
|
17958
|
-
mergedPolicy.managedJailPaths.push({ path:
|
|
18041
|
+
mergedPolicy.managedJailPaths.push({ path: path42, verdict });
|
|
17959
18042
|
}
|
|
17960
18043
|
}
|
|
17961
18044
|
if (Array.isArray(mc.trustedHosts)) {
|
|
@@ -18675,7 +18758,7 @@ var init_cost_copilot = __esm({
|
|
|
18675
18758
|
|
|
18676
18759
|
// src/session-files.ts
|
|
18677
18760
|
import * as fs10 from "fs";
|
|
18678
|
-
import * as
|
|
18761
|
+
import * as path11 from "path";
|
|
18679
18762
|
function listSessionFiles(dir2, maxDepth = 6) {
|
|
18680
18763
|
const out = [];
|
|
18681
18764
|
const walk2 = (d, rel, depth) => {
|
|
@@ -18687,8 +18770,8 @@ function listSessionFiles(dir2, maxDepth = 6) {
|
|
|
18687
18770
|
return;
|
|
18688
18771
|
}
|
|
18689
18772
|
for (const e of entries) {
|
|
18690
|
-
const childRel = rel ?
|
|
18691
|
-
if (e.isDirectory()) walk2(
|
|
18773
|
+
const childRel = rel ? path11.join(rel, e.name) : e.name;
|
|
18774
|
+
if (e.isDirectory()) walk2(path11.join(d, e.name), childRel, depth + 1);
|
|
18692
18775
|
else if (e.name.endsWith(".jsonl")) out.push(childRel);
|
|
18693
18776
|
}
|
|
18694
18777
|
};
|
|
@@ -18696,7 +18779,7 @@ function listSessionFiles(dir2, maxDepth = 6) {
|
|
|
18696
18779
|
return out;
|
|
18697
18780
|
}
|
|
18698
18781
|
function sessionIdOf(relPath) {
|
|
18699
|
-
return
|
|
18782
|
+
return path11.basename(relPath).replace(/\.jsonl$/, "");
|
|
18700
18783
|
}
|
|
18701
18784
|
var init_session_files = __esm({
|
|
18702
18785
|
"src/session-files.ts"() {
|
|
@@ -18802,9 +18885,9 @@ var init_decision = __esm({
|
|
|
18802
18885
|
// src/shields/jail.ts
|
|
18803
18886
|
import fs11 from "fs";
|
|
18804
18887
|
import os9 from "os";
|
|
18805
|
-
import
|
|
18888
|
+
import path12 from "path";
|
|
18806
18889
|
function jailStorePath() {
|
|
18807
|
-
return
|
|
18890
|
+
return path12.join(os9.homedir(), ".node9", "jail-paths.json");
|
|
18808
18891
|
}
|
|
18809
18892
|
function readJailPaths() {
|
|
18810
18893
|
let text;
|
|
@@ -18849,9 +18932,9 @@ var init_jail = __esm({
|
|
|
18849
18932
|
// src/canary/registry.ts
|
|
18850
18933
|
import fs12 from "fs";
|
|
18851
18934
|
import os10 from "os";
|
|
18852
|
-
import
|
|
18935
|
+
import path13 from "path";
|
|
18853
18936
|
function canaryStorePath() {
|
|
18854
|
-
return
|
|
18937
|
+
return path13.join(os10.homedir(), ".node9", "canaries.json");
|
|
18855
18938
|
}
|
|
18856
18939
|
function isRecord(x) {
|
|
18857
18940
|
if (!x || typeof x !== "object") return false;
|
|
@@ -18916,7 +18999,7 @@ var init_scan_watermark = __esm({
|
|
|
18916
18999
|
// src/cli/aggregate/report-audit.ts
|
|
18917
19000
|
import fs13 from "fs";
|
|
18918
19001
|
import os11 from "os";
|
|
18919
|
-
import
|
|
19002
|
+
import path14 from "path";
|
|
18920
19003
|
function buildTestTimestamps(allEntries) {
|
|
18921
19004
|
const testTs = /* @__PURE__ */ new Set();
|
|
18922
19005
|
for (const e of allEntries) {
|
|
@@ -19052,7 +19135,7 @@ function freezeClaudeCost(acc) {
|
|
|
19052
19135
|
};
|
|
19053
19136
|
}
|
|
19054
19137
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
19055
|
-
const projPath =
|
|
19138
|
+
const projPath = path14.join(projectsDir, proj);
|
|
19056
19139
|
let files;
|
|
19057
19140
|
try {
|
|
19058
19141
|
const stat = fs13.statSync(projPath);
|
|
@@ -19063,7 +19146,7 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
19063
19146
|
}
|
|
19064
19147
|
const startMs = start.getTime();
|
|
19065
19148
|
for (const file2 of files) {
|
|
19066
|
-
const filePath =
|
|
19149
|
+
const filePath = path14.join(projPath, file2);
|
|
19067
19150
|
try {
|
|
19068
19151
|
if (fs13.statSync(filePath).mtimeMs < startMs) continue;
|
|
19069
19152
|
} catch {
|
|
@@ -19302,7 +19385,7 @@ function listGeminiSessionFiles(geminiTmpDir) {
|
|
|
19302
19385
|
return out;
|
|
19303
19386
|
}
|
|
19304
19387
|
for (const proj of dirs) {
|
|
19305
|
-
const chatsDir =
|
|
19388
|
+
const chatsDir = path14.join(geminiTmpDir, proj, "chats");
|
|
19306
19389
|
let files;
|
|
19307
19390
|
try {
|
|
19308
19391
|
if (!fs13.statSync(chatsDir).isDirectory()) continue;
|
|
@@ -19312,7 +19395,7 @@ function listGeminiSessionFiles(geminiTmpDir) {
|
|
|
19312
19395
|
}
|
|
19313
19396
|
for (const f of files) {
|
|
19314
19397
|
if (!f.endsWith(".jsonl")) continue;
|
|
19315
|
-
out.push({ projectKey: proj, file:
|
|
19398
|
+
out.push({ projectKey: proj, file: path14.join(chatsDir, f) });
|
|
19316
19399
|
}
|
|
19317
19400
|
}
|
|
19318
19401
|
return out;
|
|
@@ -19353,10 +19436,10 @@ function dimensionOfBlock(checkedBy, ruleName) {
|
|
|
19353
19436
|
}
|
|
19354
19437
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
19355
19438
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
19356
|
-
const auditLogPath2 = opts.auditLogPath ??
|
|
19357
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
19439
|
+
const auditLogPath2 = opts.auditLogPath ?? path14.join(os11.homedir(), ".node9", "audit.log");
|
|
19440
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? path14.join(os11.homedir(), ".claude", "projects");
|
|
19358
19441
|
const codexSessionsDir2 = opts.codexSessionsDir ?? codexSessionsDir();
|
|
19359
|
-
const geminiTmpDir = opts.geminiTmpDir ??
|
|
19442
|
+
const geminiTmpDir = opts.geminiTmpDir ?? path14.join(os11.homedir(), ".gemini", "tmp");
|
|
19360
19443
|
const hasAuditFile = fs13.existsSync(auditLogPath2);
|
|
19361
19444
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath2);
|
|
19362
19445
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
@@ -19756,10 +19839,10 @@ var init_mcp_cmd = __esm({
|
|
|
19756
19839
|
|
|
19757
19840
|
// src/daemon/mcp-tools.ts
|
|
19758
19841
|
import fs14 from "fs";
|
|
19759
|
-
import
|
|
19842
|
+
import path15 from "path";
|
|
19760
19843
|
import os12 from "os";
|
|
19761
19844
|
function getMcpToolsFile() {
|
|
19762
|
-
return
|
|
19845
|
+
return path15.join(os12.homedir(), ".node9", "mcp-tools.json");
|
|
19763
19846
|
}
|
|
19764
19847
|
function readMcpToolsConfig() {
|
|
19765
19848
|
try {
|
|
@@ -19781,9 +19864,9 @@ var init_mcp_tools = __esm({
|
|
|
19781
19864
|
// src/apps/state.ts
|
|
19782
19865
|
import fs15 from "fs";
|
|
19783
19866
|
import os13 from "os";
|
|
19784
|
-
import
|
|
19867
|
+
import path16 from "path";
|
|
19785
19868
|
function appsFilePath(home = os13.homedir()) {
|
|
19786
|
-
return
|
|
19869
|
+
return path16.join(home, ".node9", "apps.json");
|
|
19787
19870
|
}
|
|
19788
19871
|
function emptyFile() {
|
|
19789
19872
|
return { version: 1, apps: /* @__PURE__ */ Object.create(null), links: /* @__PURE__ */ Object.create(null) };
|
|
@@ -19896,7 +19979,7 @@ var init_state = __esm({
|
|
|
19896
19979
|
});
|
|
19897
19980
|
|
|
19898
19981
|
// src/context-sniper.ts
|
|
19899
|
-
import
|
|
19982
|
+
import path17 from "path";
|
|
19900
19983
|
function smartTruncate(str, maxLen = 500) {
|
|
19901
19984
|
if (str.length <= maxLen) return str;
|
|
19902
19985
|
const edge = Math.floor(maxLen / 2) - 3;
|
|
@@ -19948,7 +20031,7 @@ function computeRiskMetadata(args, tier, blockedByLabel, matchedField, matchedWo
|
|
|
19948
20031
|
intent = "EDIT";
|
|
19949
20032
|
if (obj.file_path) {
|
|
19950
20033
|
editFilePath = String(obj.file_path);
|
|
19951
|
-
editFileName =
|
|
20034
|
+
editFileName = path17.basename(editFilePath);
|
|
19952
20035
|
}
|
|
19953
20036
|
const result = extractContext(String(obj.new_string), matchedWord);
|
|
19954
20037
|
contextSnippet = result.snippet;
|
|
@@ -20005,7 +20088,7 @@ var init_context_sniper = __esm({
|
|
|
20005
20088
|
|
|
20006
20089
|
// src/ui/native.ts
|
|
20007
20090
|
import { spawn } from "child_process";
|
|
20008
|
-
import
|
|
20091
|
+
import path18 from "path";
|
|
20009
20092
|
function resolveNativeDecision(opts) {
|
|
20010
20093
|
const { code, output, elapsedMs, locked } = opts;
|
|
20011
20094
|
if (locked) return "deny";
|
|
@@ -20033,7 +20116,7 @@ function formatArgs(args, matchedField, matchedWord) {
|
|
|
20033
20116
|
if (typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
20034
20117
|
const obj = parsed;
|
|
20035
20118
|
if (obj.old_string !== void 0 && obj.new_string !== void 0) {
|
|
20036
|
-
const file2 = obj.file_path ?
|
|
20119
|
+
const file2 = obj.file_path ? path18.basename(String(obj.file_path)) : "file";
|
|
20037
20120
|
const oldPreview = smartTruncate(String(obj.old_string), 120);
|
|
20038
20121
|
const newPreview = extractContext(String(obj.new_string), matchedWord).snippet;
|
|
20039
20122
|
return {
|
|
@@ -20250,16 +20333,16 @@ var init_native = __esm({
|
|
|
20250
20333
|
// src/policy/file-access.ts
|
|
20251
20334
|
import fs16 from "fs";
|
|
20252
20335
|
import os14 from "os";
|
|
20253
|
-
import
|
|
20336
|
+
import path19 from "path";
|
|
20254
20337
|
function absoluteSpelling(p, cwd, home) {
|
|
20255
20338
|
if (p === "~" || p.startsWith("~/")) p = home + p.slice(1);
|
|
20256
|
-
return
|
|
20339
|
+
return path19.isAbsolute(p) ? p : `${cwd}/${p}`;
|
|
20257
20340
|
}
|
|
20258
20341
|
function physical(p, followFinal, links = 0) {
|
|
20259
20342
|
if (links > 40) throw new Error("Too many symbolic links");
|
|
20260
20343
|
if (!followFinal) {
|
|
20261
|
-
const parent = physical(
|
|
20262
|
-
return { path: `${parent.path}/${
|
|
20344
|
+
const parent = physical(path19.dirname(p), true, links);
|
|
20345
|
+
return { path: `${parent.path}/${path19.basename(p)}`, missing: parent.missing };
|
|
20263
20346
|
}
|
|
20264
20347
|
try {
|
|
20265
20348
|
return { path: fs16.realpathSync.native(p), missing: false };
|
|
@@ -20270,7 +20353,7 @@ function physical(p, followFinal, links = 0) {
|
|
|
20270
20353
|
if (fs16.lstatSync(p).isSymbolicLink()) {
|
|
20271
20354
|
const target = fs16.readlinkSync(p);
|
|
20272
20355
|
return physical(
|
|
20273
|
-
|
|
20356
|
+
path19.isAbsolute(target) ? target : `${path19.dirname(p)}/${target}`,
|
|
20274
20357
|
true,
|
|
20275
20358
|
links + 1
|
|
20276
20359
|
);
|
|
@@ -20279,10 +20362,10 @@ function physical(p, followFinal, links = 0) {
|
|
|
20279
20362
|
if (!["ENOENT", "ENOTDIR"].includes(linkError.code ?? ""))
|
|
20280
20363
|
throw linkError;
|
|
20281
20364
|
}
|
|
20282
|
-
const parent =
|
|
20365
|
+
const parent = path19.dirname(p);
|
|
20283
20366
|
if (parent === p) return { path: p, missing: true };
|
|
20284
20367
|
const resolved = physical(parent, true, links);
|
|
20285
|
-
return { path: `${resolved.path}/${
|
|
20368
|
+
return { path: `${resolved.path}/${path19.basename(p)}`, missing: true };
|
|
20286
20369
|
}
|
|
20287
20370
|
}
|
|
20288
20371
|
function prepareFileAccesses(tool, args, cwd = process.cwd(), inspection = {}, home = os14.homedir()) {
|
|
@@ -20372,7 +20455,7 @@ var init_file_access = __esm({
|
|
|
20372
20455
|
// src/auth/session-script.ts
|
|
20373
20456
|
import fs17 from "fs";
|
|
20374
20457
|
import os15 from "os";
|
|
20375
|
-
import
|
|
20458
|
+
import path20 from "path";
|
|
20376
20459
|
function readScriptFile(resolved) {
|
|
20377
20460
|
let fd;
|
|
20378
20461
|
try {
|
|
@@ -20401,7 +20484,7 @@ function readScriptFile(resolved) {
|
|
|
20401
20484
|
}
|
|
20402
20485
|
function absolute(p, cwd, home) {
|
|
20403
20486
|
const spelled = p === "~" || p.startsWith("~/") ? home + p.slice(1) : p;
|
|
20404
|
-
return
|
|
20487
|
+
return path20.resolve(cwd, spelled);
|
|
20405
20488
|
}
|
|
20406
20489
|
async function resolveSessionScript(toolName, args, cwd, layers, deps, home = os15.homedir()) {
|
|
20407
20490
|
try {
|
|
@@ -20468,7 +20551,7 @@ var init_session_script = __esm({
|
|
|
20468
20551
|
|
|
20469
20552
|
// src/utils/git-remotes.ts
|
|
20470
20553
|
import fs18 from "fs";
|
|
20471
|
-
import
|
|
20554
|
+
import path21 from "path";
|
|
20472
20555
|
function readSmallFile(p, max) {
|
|
20473
20556
|
let fd;
|
|
20474
20557
|
try {
|
|
@@ -20500,20 +20583,20 @@ function gitRemoteHost(url) {
|
|
|
20500
20583
|
return null;
|
|
20501
20584
|
}
|
|
20502
20585
|
function findGitConfig(dir2, walkUp = true) {
|
|
20503
|
-
let cur =
|
|
20586
|
+
let cur = path21.resolve(dir2);
|
|
20504
20587
|
for (let i = 0; i < (walkUp ? 64 : 1); i++) {
|
|
20505
|
-
const dotGit =
|
|
20506
|
-
const direct = readSmallFile(
|
|
20588
|
+
const dotGit = path21.join(cur, ".git");
|
|
20589
|
+
const direct = readSmallFile(path21.join(dotGit, "config"), 1e6);
|
|
20507
20590
|
if (direct !== null) return direct;
|
|
20508
20591
|
const pointer = readSmallFile(dotGit, 4096);
|
|
20509
20592
|
const m = pointer && /^gitdir:\s*(.+?)\s*$/m.exec(pointer);
|
|
20510
20593
|
if (m) {
|
|
20511
|
-
let gitDir =
|
|
20512
|
-
const common = readSmallFile(
|
|
20513
|
-
if (common !== null) gitDir =
|
|
20514
|
-
return readSmallFile(
|
|
20594
|
+
let gitDir = path21.resolve(cur, m[1]);
|
|
20595
|
+
const common = readSmallFile(path21.join(gitDir, "commondir"), 4096);
|
|
20596
|
+
if (common !== null) gitDir = path21.resolve(gitDir, common.trim());
|
|
20597
|
+
return readSmallFile(path21.join(gitDir, "config"), 1e6);
|
|
20515
20598
|
}
|
|
20516
|
-
const parent =
|
|
20599
|
+
const parent = path21.dirname(cur);
|
|
20517
20600
|
if (parent === cur) return null;
|
|
20518
20601
|
cur = parent;
|
|
20519
20602
|
}
|
|
@@ -20522,12 +20605,12 @@ function findGitConfig(dir2, walkUp = true) {
|
|
|
20522
20605
|
function readGitRemotes(dir2, opts = {}) {
|
|
20523
20606
|
if (!dir2) return [];
|
|
20524
20607
|
const walkUp = opts.walkUp !== false;
|
|
20525
|
-
const key = `${walkUp ? "up" : "at"}:${
|
|
20608
|
+
const key = `${walkUp ? "up" : "at"}:${path21.resolve(dir2)}`;
|
|
20526
20609
|
const hit = cache.get(key);
|
|
20527
20610
|
if (hit) return hit;
|
|
20528
20611
|
const out = [];
|
|
20529
20612
|
try {
|
|
20530
|
-
const cfg = findGitConfig(
|
|
20613
|
+
const cfg = findGitConfig(path21.resolve(dir2), walkUp);
|
|
20531
20614
|
if (cfg !== null) {
|
|
20532
20615
|
let current = null;
|
|
20533
20616
|
for (const line of cfg.split(/\r?\n/)) {
|
|
@@ -20563,17 +20646,17 @@ var init_git_remotes = __esm({
|
|
|
20563
20646
|
|
|
20564
20647
|
// src/exposure/known-hosts.ts
|
|
20565
20648
|
import fs19 from "fs";
|
|
20566
|
-
import
|
|
20649
|
+
import path22 from "path";
|
|
20567
20650
|
function manifestRoot(dir2) {
|
|
20568
|
-
let cur =
|
|
20651
|
+
let cur = path22.resolve(dir2);
|
|
20569
20652
|
for (let i = 0; i < 64; i++) {
|
|
20570
20653
|
for (const [m] of ECOSYSTEMS) {
|
|
20571
20654
|
try {
|
|
20572
|
-
if (fs19.existsSync(
|
|
20655
|
+
if (fs19.existsSync(path22.join(cur, m))) return cur;
|
|
20573
20656
|
} catch {
|
|
20574
20657
|
}
|
|
20575
20658
|
}
|
|
20576
|
-
const parent =
|
|
20659
|
+
const parent = path22.dirname(cur);
|
|
20577
20660
|
if (parent === cur) return null;
|
|
20578
20661
|
cur = parent;
|
|
20579
20662
|
}
|
|
@@ -20582,7 +20665,7 @@ function manifestRoot(dir2) {
|
|
|
20582
20665
|
function knownProjectHosts(dir2) {
|
|
20583
20666
|
const empty = { hosts: /* @__PURE__ */ new Set(), repos: /* @__PURE__ */ new Set(), remotes: /* @__PURE__ */ new Map() };
|
|
20584
20667
|
if (!dir2) return empty;
|
|
20585
|
-
const key =
|
|
20668
|
+
const key = path22.resolve(dir2);
|
|
20586
20669
|
const hit = cache2.get(key);
|
|
20587
20670
|
if (hit) return hit;
|
|
20588
20671
|
const out = { hosts: /* @__PURE__ */ new Set(), repos: /* @__PURE__ */ new Set(), remotes: /* @__PURE__ */ new Map() };
|
|
@@ -20595,7 +20678,7 @@ function knownProjectHosts(dir2) {
|
|
|
20595
20678
|
const root = manifestRoot(key);
|
|
20596
20679
|
if (root !== null) {
|
|
20597
20680
|
for (const [m, registry] of ECOSYSTEMS) {
|
|
20598
|
-
if (fs19.existsSync(
|
|
20681
|
+
if (fs19.existsSync(path22.join(root, m))) out.hosts.add(registry);
|
|
20599
20682
|
}
|
|
20600
20683
|
try {
|
|
20601
20684
|
if (fs19.readdirSync(root).some((f) => f.endsWith(".gemspec")))
|
|
@@ -20627,7 +20710,7 @@ var init_known_hosts = __esm({
|
|
|
20627
20710
|
// src/exposure/writes.ts
|
|
20628
20711
|
import fs20 from "fs";
|
|
20629
20712
|
import os16 from "os";
|
|
20630
|
-
import
|
|
20713
|
+
import path23 from "path";
|
|
20631
20714
|
function writtenContent(args) {
|
|
20632
20715
|
if (!args || typeof args !== "object" || Array.isArray(args)) return [];
|
|
20633
20716
|
const a = args;
|
|
@@ -20675,7 +20758,7 @@ function judgeWritesAfterExposure(opts) {
|
|
|
20675
20758
|
seen.add(p);
|
|
20676
20759
|
if (p === "/dev" || p.startsWith("/dev/")) continue;
|
|
20677
20760
|
if (root !== null && isInside(root, p)) {
|
|
20678
|
-
if (isAgentInstructionPath(p, root) && (
|
|
20761
|
+
if (isAgentInstructionPath(p, root) && (path23.basename(p) !== "package.json" || packageScriptsTouched(opts.args, p, opts.shellCommand)))
|
|
20679
20762
|
holds.push({ path: p, why: "agent-instruction" });
|
|
20680
20763
|
continue;
|
|
20681
20764
|
}
|
|
@@ -20717,13 +20800,13 @@ var init_exposure_store = __esm({
|
|
|
20717
20800
|
import crypto3 from "crypto";
|
|
20718
20801
|
import fs21 from "fs";
|
|
20719
20802
|
import os17 from "os";
|
|
20720
|
-
import
|
|
20803
|
+
import path24 from "path";
|
|
20721
20804
|
function dir() {
|
|
20722
|
-
return
|
|
20805
|
+
return path24.join(os17.homedir(), ".node9", "exposure-sessions");
|
|
20723
20806
|
}
|
|
20724
20807
|
function file(sessionId) {
|
|
20725
20808
|
const id = crypto3.createHash("sha256").update(sessionId).digest("hex").slice(0, 32);
|
|
20726
|
-
return
|
|
20809
|
+
return path24.join(dir(), id);
|
|
20727
20810
|
}
|
|
20728
20811
|
function maybeSessionExposed(sessionId) {
|
|
20729
20812
|
if (!sessionId) return false;
|
|
@@ -20847,10 +20930,10 @@ var init_roles = __esm({
|
|
|
20847
20930
|
|
|
20848
20931
|
// src/auth/trusted-recipients.ts
|
|
20849
20932
|
import fs23 from "fs";
|
|
20850
|
-
import
|
|
20933
|
+
import path25 from "path";
|
|
20851
20934
|
import os18 from "os";
|
|
20852
20935
|
function getTrustedRecipientsPath() {
|
|
20853
|
-
return
|
|
20936
|
+
return path25.join(os18.homedir(), ".node9", "trusted-recipients.json");
|
|
20854
20937
|
}
|
|
20855
20938
|
function readTrustedRecipients() {
|
|
20856
20939
|
try {
|
|
@@ -20863,7 +20946,7 @@ function readTrustedRecipients() {
|
|
|
20863
20946
|
}
|
|
20864
20947
|
function writeTrustedRecipients(entries) {
|
|
20865
20948
|
const filePath = getTrustedRecipientsPath();
|
|
20866
|
-
fs23.mkdirSync(
|
|
20949
|
+
fs23.mkdirSync(path25.dirname(filePath), { recursive: true });
|
|
20867
20950
|
const tmp = filePath + ".node9-tmp";
|
|
20868
20951
|
fs23.writeFileSync(tmp, JSON.stringify({ entries }, null, 2), { mode: 384 });
|
|
20869
20952
|
fs23.renameSync(tmp, filePath);
|
|
@@ -20903,10 +20986,10 @@ var init_trusted_recipients = __esm({
|
|
|
20903
20986
|
|
|
20904
20987
|
// src/utils/atomic-write.ts
|
|
20905
20988
|
import fs24 from "fs";
|
|
20906
|
-
import
|
|
20989
|
+
import path26 from "path";
|
|
20907
20990
|
import { randomUUID } from "crypto";
|
|
20908
20991
|
function atomicWriteSync(filePath, data, options) {
|
|
20909
|
-
const dir2 =
|
|
20992
|
+
const dir2 = path26.dirname(filePath);
|
|
20910
20993
|
if (!fs24.existsSync(dir2)) fs24.mkdirSync(dir2, { recursive: true });
|
|
20911
20994
|
const tmpPath = `${filePath}.${randomUUID()}.tmp`;
|
|
20912
20995
|
try {
|
|
@@ -20937,13 +21020,13 @@ var init_atomic_write = __esm({
|
|
|
20937
21020
|
// src/supply-chain/osv-index.ts
|
|
20938
21021
|
import fs25 from "fs";
|
|
20939
21022
|
import os19 from "os";
|
|
20940
|
-
import
|
|
21023
|
+
import path27 from "path";
|
|
20941
21024
|
import { createHash as createHash4 } from "crypto";
|
|
20942
21025
|
function osvRoot() {
|
|
20943
|
-
return
|
|
21026
|
+
return path27.join(os19.homedir(), ".node9", "osv");
|
|
20944
21027
|
}
|
|
20945
21028
|
function ecoDir(eco) {
|
|
20946
|
-
return
|
|
21029
|
+
return path27.join(osvRoot(), eco);
|
|
20947
21030
|
}
|
|
20948
21031
|
function indexKey(eco, name) {
|
|
20949
21032
|
switch (eco) {
|
|
@@ -20962,11 +21045,11 @@ function shardOf(key) {
|
|
|
20962
21045
|
return createHash4("sha1").update(key).digest("hex").slice(0, 2);
|
|
20963
21046
|
}
|
|
20964
21047
|
function shardPath(eco, shard) {
|
|
20965
|
-
return
|
|
21048
|
+
return path27.join(ecoDir(eco), "shards", `${shard}.json`);
|
|
20966
21049
|
}
|
|
20967
21050
|
function readMeta(eco) {
|
|
20968
21051
|
try {
|
|
20969
|
-
const m = JSON.parse(fs25.readFileSync(
|
|
21052
|
+
const m = JSON.parse(fs25.readFileSync(path27.join(ecoDir(eco), "meta.json"), "utf8"));
|
|
20970
21053
|
if (typeof m?.syncedAt !== "string" || typeof m?.lastModifiedMs !== "number") return null;
|
|
20971
21054
|
return m;
|
|
20972
21055
|
} catch {
|
|
@@ -21358,14 +21441,14 @@ var init_registry2 = __esm({
|
|
|
21358
21441
|
|
|
21359
21442
|
// src/supply-chain/local-resolve.ts
|
|
21360
21443
|
import fs26 from "fs";
|
|
21361
|
-
import
|
|
21444
|
+
import path28 from "path";
|
|
21362
21445
|
function resolveInstalled(name, cwd) {
|
|
21363
|
-
if (!cwd || !
|
|
21446
|
+
if (!cwd || !path28.isAbsolute(cwd)) return null;
|
|
21364
21447
|
if (!/^(?:@[^/\\]+\/)?[^/\\]+$/.test(name)) return null;
|
|
21365
|
-
let dir2 =
|
|
21448
|
+
let dir2 = path28.resolve(cwd);
|
|
21366
21449
|
for (let i = 0; i < MAX_LEVELS; i++) {
|
|
21367
|
-
const pkgDir =
|
|
21368
|
-
const manifest =
|
|
21450
|
+
const pkgDir = path28.join(dir2, "node_modules", ...name.split("/"));
|
|
21451
|
+
const manifest = path28.join(pkgDir, "package.json");
|
|
21369
21452
|
try {
|
|
21370
21453
|
const raw = fs26.readFileSync(manifest, "utf8");
|
|
21371
21454
|
const parsed = JSON.parse(raw);
|
|
@@ -21375,7 +21458,7 @@ function resolveInstalled(name, cwd) {
|
|
|
21375
21458
|
return null;
|
|
21376
21459
|
} catch {
|
|
21377
21460
|
}
|
|
21378
|
-
const parent =
|
|
21461
|
+
const parent = path28.dirname(dir2);
|
|
21379
21462
|
if (parent === dir2) break;
|
|
21380
21463
|
dir2 = parent;
|
|
21381
21464
|
}
|
|
@@ -21392,7 +21475,7 @@ var init_local_resolve = __esm({
|
|
|
21392
21475
|
|
|
21393
21476
|
// src/supply-chain/check.ts
|
|
21394
21477
|
import picomatch2 from "picomatch";
|
|
21395
|
-
import
|
|
21478
|
+
import path29 from "path";
|
|
21396
21479
|
function commandOf(toolName, args) {
|
|
21397
21480
|
if (!isBashTool(toolName) || !args || typeof args !== "object") return null;
|
|
21398
21481
|
const a = args;
|
|
@@ -21494,7 +21577,7 @@ function checkInstalled(p, version, misses) {
|
|
|
21494
21577
|
}
|
|
21495
21578
|
async function checkOne(p, cfg, misses, networkCapped, cwd) {
|
|
21496
21579
|
if (p.ecosystem === "npm" && LOCAL_FIRST_MANAGERS.has(p.manager) && p.localCwd !== null && (p.raw === p.name || p.version)) {
|
|
21497
|
-
const localCwd = cwd &&
|
|
21580
|
+
const localCwd = cwd && path29.isAbsolute(cwd) ? (p.localCwd ?? []).reduce((dir2, step) => path29.resolve(dir2, step), cwd) : void 0;
|
|
21498
21581
|
const installed = resolveInstalled(p.name, localCwd);
|
|
21499
21582
|
if (installed && (!p.version || p.version === installed.version))
|
|
21500
21583
|
return checkInstalled(p, installed.version, misses);
|
|
@@ -21664,14 +21747,14 @@ var init_check = __esm({
|
|
|
21664
21747
|
|
|
21665
21748
|
// src/utils/provenance.ts
|
|
21666
21749
|
import fs27 from "fs";
|
|
21667
|
-
import
|
|
21750
|
+
import path30 from "path";
|
|
21668
21751
|
import os20 from "os";
|
|
21669
21752
|
function findInPath(cmd) {
|
|
21670
|
-
if (
|
|
21753
|
+
if (path30.posix.isAbsolute(cmd)) return cmd;
|
|
21671
21754
|
const pathEnv = process.env.PATH ?? "";
|
|
21672
|
-
for (const dir2 of pathEnv.split(
|
|
21755
|
+
for (const dir2 of pathEnv.split(path30.delimiter)) {
|
|
21673
21756
|
if (!dir2) continue;
|
|
21674
|
-
const full =
|
|
21757
|
+
const full = path30.join(dir2, cmd);
|
|
21675
21758
|
try {
|
|
21676
21759
|
fs27.accessSync(full, fs27.constants.X_OK);
|
|
21677
21760
|
return full;
|
|
@@ -21702,7 +21785,7 @@ function _classifyPath(resolved, cwd) {
|
|
|
21702
21785
|
}
|
|
21703
21786
|
function checkProvenance(cmd, cwd) {
|
|
21704
21787
|
const bare = cmd.startsWith("./") ? cmd.slice(2) : cmd;
|
|
21705
|
-
if (
|
|
21788
|
+
if (path30.posix.isAbsolute(bare)) {
|
|
21706
21789
|
const early = _classifyPath(bare, cwd);
|
|
21707
21790
|
if (early.trustLevel === "suspect") {
|
|
21708
21791
|
return { resolvedPath: bare, ...early };
|
|
@@ -21752,11 +21835,11 @@ var init_provenance2 = __esm({
|
|
|
21752
21835
|
SYSTEM_PREFIXES = ["/usr/bin", "/usr/sbin", "/bin", "/sbin"];
|
|
21753
21836
|
MANAGED_PREFIXES = ["/usr/local/bin", "/opt/homebrew", "/home/linuxbrew", "/nix/store"];
|
|
21754
21837
|
USER_PREFIXES = [
|
|
21755
|
-
|
|
21756
|
-
|
|
21757
|
-
|
|
21758
|
-
|
|
21759
|
-
|
|
21838
|
+
path30.join(os20.homedir(), "bin"),
|
|
21839
|
+
path30.join(os20.homedir(), ".local", "bin"),
|
|
21840
|
+
path30.join(os20.homedir(), ".cargo", "bin"),
|
|
21841
|
+
path30.join(os20.homedir(), ".npm-global", "bin"),
|
|
21842
|
+
path30.join(os20.homedir(), ".volta", "bin")
|
|
21760
21843
|
];
|
|
21761
21844
|
SUSPECT_PREFIXES = ["/tmp", "/var/tmp", "/dev/shm"];
|
|
21762
21845
|
}
|
|
@@ -21811,7 +21894,7 @@ var init_policy = __esm({
|
|
|
21811
21894
|
|
|
21812
21895
|
// src/auth/state.ts
|
|
21813
21896
|
import fs28 from "fs";
|
|
21814
|
-
import
|
|
21897
|
+
import path31 from "path";
|
|
21815
21898
|
import os21 from "os";
|
|
21816
21899
|
function extractCommandPattern(toolName, args) {
|
|
21817
21900
|
const lower2 = toolName.toLowerCase();
|
|
@@ -21889,7 +21972,7 @@ function writeTrustSession(toolName, durationMs, args) {
|
|
|
21889
21972
|
}
|
|
21890
21973
|
function getPersistentDecision(toolName) {
|
|
21891
21974
|
try {
|
|
21892
|
-
const file2 =
|
|
21975
|
+
const file2 = path31.join(os21.homedir(), ".node9", "decisions.json");
|
|
21893
21976
|
if (!fs28.existsSync(file2)) return null;
|
|
21894
21977
|
const decisions = JSON.parse(fs28.readFileSync(file2, "utf-8"));
|
|
21895
21978
|
const d = decisions[toolName];
|
|
@@ -21905,8 +21988,8 @@ var init_state2 = __esm({
|
|
|
21905
21988
|
init_policy();
|
|
21906
21989
|
init_atomic_write();
|
|
21907
21990
|
init_forecast_context();
|
|
21908
|
-
PAUSED_FILE =
|
|
21909
|
-
TRUST_FILE =
|
|
21991
|
+
PAUSED_FILE = path31.join(os21.homedir(), ".node9", "PAUSED");
|
|
21992
|
+
TRUST_FILE = path31.join(os21.homedir(), ".node9", "trust.json");
|
|
21910
21993
|
}
|
|
21911
21994
|
});
|
|
21912
21995
|
|
|
@@ -21957,7 +22040,7 @@ var init_read_capped = __esm({
|
|
|
21957
22040
|
// src/auth/cloud.ts
|
|
21958
22041
|
import fs30 from "fs";
|
|
21959
22042
|
import os22 from "os";
|
|
21960
|
-
import
|
|
22043
|
+
import path32 from "path";
|
|
21961
22044
|
function maskArgsForCloud(args) {
|
|
21962
22045
|
if (args === void 0 || args === null) return args;
|
|
21963
22046
|
try {
|
|
@@ -21990,7 +22073,7 @@ async function initNode9SaaS(toolName, args, creds, meta, riskMetadata, agentPol
|
|
|
21990
22073
|
let ciContext;
|
|
21991
22074
|
if (process.env.CI) {
|
|
21992
22075
|
try {
|
|
21993
|
-
const ciContextPath =
|
|
22076
|
+
const ciContextPath = path32.join(os22.homedir(), ".node9", "ci-context.json");
|
|
21994
22077
|
const ci = readCappedText(ciContextPath, 1e4);
|
|
21995
22078
|
if (!ci) throw new Error("ci-context.json unreadable");
|
|
21996
22079
|
if (ci.truncated) throw new Error("ci-context.json exceeds 10 KB");
|
|
@@ -22137,10 +22220,10 @@ var init_cloud = __esm({
|
|
|
22137
22220
|
|
|
22138
22221
|
// src/loop-detector.ts
|
|
22139
22222
|
import fs31 from "fs";
|
|
22140
|
-
import
|
|
22223
|
+
import path33 from "path";
|
|
22141
22224
|
import os23 from "os";
|
|
22142
22225
|
function loopStateFile() {
|
|
22143
|
-
return
|
|
22226
|
+
return path33.join(os23.homedir(), ".node9", "loop-state.json");
|
|
22144
22227
|
}
|
|
22145
22228
|
function readState() {
|
|
22146
22229
|
try {
|
|
@@ -22154,7 +22237,7 @@ function readState() {
|
|
|
22154
22237
|
}
|
|
22155
22238
|
}
|
|
22156
22239
|
function writeState(records) {
|
|
22157
|
-
const dir2 =
|
|
22240
|
+
const dir2 = path33.dirname(loopStateFile());
|
|
22158
22241
|
if (!fs31.existsSync(dir2)) fs31.mkdirSync(dir2, { recursive: true });
|
|
22159
22242
|
const tmpPath = `${loopStateFile()}.${os23.hostname()}.${process.pid}.tmp`;
|
|
22160
22243
|
fs31.writeFileSync(tmpPath, JSON.stringify(records));
|
|
@@ -23954,17 +24037,17 @@ var init_forecast = __esm({
|
|
|
23954
24037
|
|
|
23955
24038
|
// src/version.ts
|
|
23956
24039
|
import fs32 from "fs";
|
|
23957
|
-
import
|
|
24040
|
+
import path34 from "path";
|
|
23958
24041
|
function readVersion() {
|
|
23959
24042
|
let dir2 = __dirname;
|
|
23960
24043
|
for (let i = 0; i < 5; i++) {
|
|
23961
|
-
const p =
|
|
24044
|
+
const p = path34.join(dir2, "package.json");
|
|
23962
24045
|
try {
|
|
23963
24046
|
const pkg = JSON.parse(fs32.readFileSync(p, "utf-8"));
|
|
23964
24047
|
if (pkg.name === "@node9/proxy" && typeof pkg.version === "string") return pkg.version;
|
|
23965
24048
|
} catch {
|
|
23966
24049
|
}
|
|
23967
|
-
const parent =
|
|
24050
|
+
const parent = path34.dirname(dir2);
|
|
23968
24051
|
if (parent === dir2) break;
|
|
23969
24052
|
dir2 = parent;
|
|
23970
24053
|
}
|
|
@@ -23981,10 +24064,10 @@ var init_version = __esm({
|
|
|
23981
24064
|
// src/cli/commands/scan-cache.ts
|
|
23982
24065
|
import fs33 from "fs";
|
|
23983
24066
|
import os25 from "os";
|
|
23984
|
-
import
|
|
24067
|
+
import path35 from "path";
|
|
23985
24068
|
import { createHash as createHash5 } from "crypto";
|
|
23986
24069
|
function scanCacheRoot() {
|
|
23987
|
-
return
|
|
24070
|
+
return path35.join(os25.homedir(), ".node9", "scan-cache");
|
|
23988
24071
|
}
|
|
23989
24072
|
function configHashOf(config) {
|
|
23990
24073
|
const h = createHash5("sha256");
|
|
@@ -23992,7 +24075,7 @@ function configHashOf(config) {
|
|
|
23992
24075
|
h.update(JSON.stringify(config.policySource));
|
|
23993
24076
|
h.update(JSON.stringify(config.policy));
|
|
23994
24077
|
for (const name of SIDECAR_FILES) {
|
|
23995
|
-
const st = fileStamp(
|
|
24078
|
+
const st = fileStamp(path35.join(os25.homedir(), ".node9", name));
|
|
23996
24079
|
h.update(`|${name}:${st ? `${st.size}:${st.mtimeMs}` : "absent"}`);
|
|
23997
24080
|
}
|
|
23998
24081
|
return h.digest("hex").slice(0, 16);
|
|
@@ -24005,17 +24088,16 @@ function fileStamp(filePath) {
|
|
|
24005
24088
|
return null;
|
|
24006
24089
|
}
|
|
24007
24090
|
}
|
|
24008
|
-
|
|
24009
|
-
return startDate ? startDate.toISOString().slice(0, 10) : "all";
|
|
24010
|
-
}
|
|
24011
|
-
var SCAN_CACHE_VERSION, KEPT_WINDOWS, SIDECAR_FILES, ScanCache;
|
|
24091
|
+
var SCAN_CACHE_VERSION, FLUSH_EVERY_FILES, FLUSH_EVERY_MS, activeCaches, SIDECAR_FILES, ScanCache;
|
|
24012
24092
|
var init_scan_cache = __esm({
|
|
24013
24093
|
"src/cli/commands/scan-cache.ts"() {
|
|
24014
24094
|
"use strict";
|
|
24015
24095
|
init_dist();
|
|
24016
24096
|
init_version();
|
|
24017
|
-
SCAN_CACHE_VERSION =
|
|
24018
|
-
|
|
24097
|
+
SCAN_CACHE_VERSION = 3;
|
|
24098
|
+
FLUSH_EVERY_FILES = 25;
|
|
24099
|
+
FLUSH_EVERY_MS = 1e4;
|
|
24100
|
+
activeCaches = /* @__PURE__ */ new Set();
|
|
24019
24101
|
SIDECAR_FILES = [
|
|
24020
24102
|
"canaries.json",
|
|
24021
24103
|
"shields.json",
|
|
@@ -24024,8 +24106,8 @@ var init_scan_cache = __esm({
|
|
|
24024
24106
|
"trusted-hosts.json",
|
|
24025
24107
|
"trusted-recipients.json",
|
|
24026
24108
|
"rules-cache.json",
|
|
24027
|
-
|
|
24028
|
-
|
|
24109
|
+
path35.join("osv", "npm", "meta.json"),
|
|
24110
|
+
path35.join("osv", "PyPI", "meta.json")
|
|
24029
24111
|
];
|
|
24030
24112
|
ScanCache = class {
|
|
24031
24113
|
root;
|
|
@@ -24035,10 +24117,13 @@ var init_scan_cache = __esm({
|
|
|
24035
24117
|
/** Counters for the run, so a caller can say what was reused. */
|
|
24036
24118
|
hits = 0;
|
|
24037
24119
|
misses = 0;
|
|
24120
|
+
pendingPuts = 0;
|
|
24121
|
+
lastFlush = Date.now();
|
|
24038
24122
|
constructor(opts) {
|
|
24039
24123
|
this.root = opts.root ?? scanCacheRoot();
|
|
24040
24124
|
this.enabled = opts.enabled ?? process.env.NODE9_SCAN_CACHE !== "0";
|
|
24041
24125
|
this.index = this.load(opts.configHash);
|
|
24126
|
+
activeCaches.add(this);
|
|
24042
24127
|
}
|
|
24043
24128
|
load(configHash) {
|
|
24044
24129
|
const fresh = {
|
|
@@ -24051,7 +24136,7 @@ var init_scan_cache = __esm({
|
|
|
24051
24136
|
if (!this.enabled) return fresh;
|
|
24052
24137
|
try {
|
|
24053
24138
|
const raw = JSON.parse(
|
|
24054
|
-
fs33.readFileSync(
|
|
24139
|
+
fs33.readFileSync(path35.join(this.root, "index.json"), "utf8")
|
|
24055
24140
|
);
|
|
24056
24141
|
if (raw.cacheVersion !== SCAN_CACHE_VERSION || raw.engineVersion !== CANONICAL_EXTRACTOR_VERSION || raw.proxyVersion !== PROXY_VERSION || raw.configHash !== configHash || typeof raw.files !== "object") {
|
|
24057
24142
|
this.dropAll();
|
|
@@ -24068,15 +24153,19 @@ var init_scan_cache = __esm({
|
|
|
24068
24153
|
} catch {
|
|
24069
24154
|
}
|
|
24070
24155
|
}
|
|
24071
|
-
/** The cached result for an unchanged file
|
|
24156
|
+
/** The cached whole-file result for an unchanged file, judged under
|
|
24072
24157
|
* configurations that have not changed either, or null. */
|
|
24073
|
-
get(filePath, stamp,
|
|
24158
|
+
get(filePath, stamp, hasher, judgeFrom = null) {
|
|
24074
24159
|
if (!this.enabled) return null;
|
|
24075
|
-
const e = this.index.files[
|
|
24160
|
+
const e = this.index.files[filePath];
|
|
24076
24161
|
if (!e || e.size !== stamp.size || e.mtimeMs !== stamp.mtimeMs) {
|
|
24077
24162
|
this.misses++;
|
|
24078
24163
|
return null;
|
|
24079
24164
|
}
|
|
24165
|
+
if (e.judgedFrom && (!judgeFrom || judgeFrom.getTime() < Date.parse(e.judgedFrom))) {
|
|
24166
|
+
this.misses++;
|
|
24167
|
+
return null;
|
|
24168
|
+
}
|
|
24080
24169
|
for (const [cwd, hash2] of Object.entries(e.configHashes ?? {})) {
|
|
24081
24170
|
if (hasher && hasher.configHashFor(cwd) !== hash2) {
|
|
24082
24171
|
this.misses++;
|
|
@@ -24084,67 +24173,78 @@ var init_scan_cache = __esm({
|
|
|
24084
24173
|
}
|
|
24085
24174
|
}
|
|
24086
24175
|
try {
|
|
24087
|
-
const
|
|
24176
|
+
const stored = JSON.parse(fs33.readFileSync(path35.join(this.root, e.result), "utf8"));
|
|
24177
|
+
if ((stored.judgedFrom ?? null) !== (e.judgedFrom ?? null) || !stored.result) {
|
|
24178
|
+
this.misses++;
|
|
24179
|
+
return null;
|
|
24180
|
+
}
|
|
24088
24181
|
this.hits++;
|
|
24089
|
-
return
|
|
24182
|
+
return stored.result;
|
|
24090
24183
|
} catch {
|
|
24091
24184
|
this.misses++;
|
|
24092
24185
|
return null;
|
|
24093
24186
|
}
|
|
24094
24187
|
}
|
|
24095
|
-
put(filePath, stamp,
|
|
24188
|
+
put(filePath, stamp, agent, result, hasher, judgeFrom = null) {
|
|
24096
24189
|
if (!this.enabled) return;
|
|
24097
|
-
const name = createHash5("sha256").update(`${agent}|${filePath}
|
|
24098
|
-
const rel =
|
|
24190
|
+
const name = createHash5("sha256").update(`${agent}|${filePath}`).digest("hex").slice(0, 40);
|
|
24191
|
+
const rel = path35.join("files", name.slice(0, 2), `${name}.json`);
|
|
24099
24192
|
const configHashes = {};
|
|
24100
24193
|
if (hasher)
|
|
24101
24194
|
for (const cwd of result.configCwds ?? []) configHashes[cwd] = hasher.configHashFor(cwd);
|
|
24102
24195
|
try {
|
|
24103
|
-
const abs =
|
|
24104
|
-
fs33.mkdirSync(
|
|
24105
|
-
fs33.writeFileSync(
|
|
24106
|
-
|
|
24196
|
+
const abs = path35.join(this.root, rel);
|
|
24197
|
+
fs33.mkdirSync(path35.dirname(abs), { recursive: true, mode: 448 });
|
|
24198
|
+
fs33.writeFileSync(
|
|
24199
|
+
abs,
|
|
24200
|
+
JSON.stringify({ judgedFrom: judgeFrom ? judgeFrom.toISOString() : null, result }),
|
|
24201
|
+
{ mode: 384 }
|
|
24202
|
+
);
|
|
24203
|
+
this.index.files[filePath] = {
|
|
24107
24204
|
...stamp,
|
|
24108
|
-
window,
|
|
24109
24205
|
agent,
|
|
24110
24206
|
result: rel,
|
|
24111
24207
|
configHashes,
|
|
24112
|
-
at: Date.now()
|
|
24208
|
+
at: Date.now(),
|
|
24209
|
+
...judgeFrom && { judgedFrom: judgeFrom.toISOString() }
|
|
24113
24210
|
};
|
|
24114
24211
|
this.dirty = true;
|
|
24212
|
+
this.pendingPuts++;
|
|
24213
|
+
if (this.pendingPuts >= FLUSH_EVERY_FILES || Date.now() - this.lastFlush > FLUSH_EVERY_MS)
|
|
24214
|
+
this.flush();
|
|
24115
24215
|
} catch {
|
|
24116
24216
|
}
|
|
24117
24217
|
}
|
|
24118
|
-
/** Drop the entries
|
|
24119
|
-
* daily `--days 30` moves the window every day and would otherwise leave
|
|
24120
|
-
* one orphan set per day. */
|
|
24218
|
+
/** Drop the entries of transcripts that no longer exist, and their files. */
|
|
24121
24219
|
prune() {
|
|
24122
|
-
const byWindow = /* @__PURE__ */ new Map();
|
|
24123
|
-
for (const e of Object.values(this.index.files))
|
|
24124
|
-
byWindow.set(e.window, Math.max(byWindow.get(e.window) ?? 0, e.at ?? 0));
|
|
24125
|
-
const keep = new Set(
|
|
24126
|
-
[...byWindow.entries()].sort((a, b) => b[1] - a[1]).slice(0, KEPT_WINDOWS).map(([w]) => w)
|
|
24127
|
-
);
|
|
24128
24220
|
for (const [key, e] of Object.entries(this.index.files)) {
|
|
24129
|
-
if (
|
|
24221
|
+
if (fs33.existsSync(key)) continue;
|
|
24130
24222
|
try {
|
|
24131
|
-
fs33.rmSync(
|
|
24223
|
+
fs33.rmSync(path35.join(this.root, e.result), { force: true });
|
|
24132
24224
|
} catch {
|
|
24133
24225
|
}
|
|
24134
24226
|
delete this.index.files[key];
|
|
24135
24227
|
this.dirty = true;
|
|
24136
24228
|
}
|
|
24137
24229
|
}
|
|
24138
|
-
/**
|
|
24230
|
+
/** The final flush of a run: the cache leaves the interrupt registry, so a
|
|
24231
|
+
* long-lived daemon does not keep every index it ever opened. */
|
|
24232
|
+
close() {
|
|
24233
|
+
this.flush();
|
|
24234
|
+
activeCaches.delete(this);
|
|
24235
|
+
}
|
|
24236
|
+
/** Write the index: every few files, on an interrupt, and at the end. */
|
|
24139
24237
|
flush() {
|
|
24140
24238
|
if (!this.enabled) return;
|
|
24141
|
-
this.prune();
|
|
24239
|
+
if (this.pendingPuts === 0) this.prune();
|
|
24240
|
+
this.pendingPuts = 0;
|
|
24241
|
+
this.lastFlush = Date.now();
|
|
24142
24242
|
if (!this.dirty) return;
|
|
24143
24243
|
try {
|
|
24144
24244
|
fs33.mkdirSync(this.root, { recursive: true, mode: 448 });
|
|
24145
|
-
const tmp =
|
|
24245
|
+
const tmp = path35.join(this.root, `index.${process.pid}.tmp`);
|
|
24146
24246
|
fs33.writeFileSync(tmp, JSON.stringify(this.index), { mode: 384 });
|
|
24147
|
-
fs33.renameSync(tmp,
|
|
24247
|
+
fs33.renameSync(tmp, path35.join(this.root, "index.json"));
|
|
24148
24248
|
this.dirty = false;
|
|
24149
24249
|
} catch {
|
|
24150
24250
|
}
|
|
@@ -24156,7 +24256,7 @@ var init_scan_cache = __esm({
|
|
|
24156
24256
|
// src/cli/commands/scan-judge.ts
|
|
24157
24257
|
import fs34 from "fs";
|
|
24158
24258
|
import os26 from "os";
|
|
24159
|
-
import
|
|
24259
|
+
import path36 from "path";
|
|
24160
24260
|
function findingDedupKey(f) {
|
|
24161
24261
|
return `${f.source.rule.name ?? "<unnamed>"}|${preview(f.input)}|${f.project}|${f.repo ?? ""}`;
|
|
24162
24262
|
}
|
|
@@ -24234,6 +24334,7 @@ var init_scan_judge = __esm({
|
|
|
24234
24334
|
init_roles();
|
|
24235
24335
|
init_scan_cache();
|
|
24236
24336
|
init_dlp();
|
|
24337
|
+
init_scan();
|
|
24237
24338
|
PREVIEW_LEN = 120;
|
|
24238
24339
|
HistoryJudge = class {
|
|
24239
24340
|
configs = /* @__PURE__ */ new Map();
|
|
@@ -24254,20 +24355,20 @@ var init_scan_judge = __esm({
|
|
|
24254
24355
|
* file, so worktrees count), home-relative; undefined when none. Cached per
|
|
24255
24356
|
* directory: history repeats the same few cwds thousands of times. */
|
|
24256
24357
|
repoOf(cwd) {
|
|
24257
|
-
if (!cwd || !
|
|
24358
|
+
if (!cwd || !path36.isAbsolute(cwd)) return void 0;
|
|
24258
24359
|
if (this.repos.has(cwd)) return this.repos.get(cwd);
|
|
24259
24360
|
let dir2 = cwd;
|
|
24260
24361
|
let found;
|
|
24261
24362
|
for (; ; ) {
|
|
24262
24363
|
try {
|
|
24263
|
-
if (fs34.existsSync(
|
|
24364
|
+
if (fs34.existsSync(path36.join(dir2, ".git"))) {
|
|
24264
24365
|
found = dir2;
|
|
24265
24366
|
break;
|
|
24266
24367
|
}
|
|
24267
24368
|
} catch {
|
|
24268
24369
|
break;
|
|
24269
24370
|
}
|
|
24270
|
-
const parent =
|
|
24371
|
+
const parent = path36.dirname(dir2);
|
|
24271
24372
|
if (parent === dir2) break;
|
|
24272
24373
|
dir2 = parent;
|
|
24273
24374
|
}
|
|
@@ -24346,7 +24447,7 @@ var init_scan_judge = __esm({
|
|
|
24346
24447
|
agent: call.agent,
|
|
24347
24448
|
...where
|
|
24348
24449
|
};
|
|
24349
|
-
const k = `${finding.patternName}|${finding.redactedSample}|${call.project}`;
|
|
24450
|
+
const k = `${finding.patternName}|${finding.redactedSample}|${call.project}|${dayKey(call.timestamp || void 0)}`;
|
|
24350
24451
|
if (!dedup.dlpKeys.has(k)) {
|
|
24351
24452
|
dedup.dlpKeys.add(k);
|
|
24352
24453
|
result.dlpFindings.push(finding);
|
|
@@ -24356,7 +24457,7 @@ var init_scan_judge = __esm({
|
|
|
24356
24457
|
const m = scanArgs(call.scrubbed);
|
|
24357
24458
|
if (m) {
|
|
24358
24459
|
dlpMatched = true;
|
|
24359
|
-
const k = `${m.patternName}|${m.redactedSample}|${call.project}`;
|
|
24460
|
+
const k = `${m.patternName}|${m.redactedSample}|${call.project}|${dayKey(call.timestamp || void 0)}`;
|
|
24360
24461
|
if (!dedup.dlpKeys.has(k)) {
|
|
24361
24462
|
dedup.dlpKeys.add(k);
|
|
24362
24463
|
result.dlpFindings.push({
|
|
@@ -24374,7 +24475,7 @@ var init_scan_judge = __esm({
|
|
|
24374
24475
|
}
|
|
24375
24476
|
if (verdict.decision !== "allow" && verdict.layer !== "dlp" && verdict.layer !== "canary") {
|
|
24376
24477
|
const source = ruleSourceFor(verdict, call.toolName, config);
|
|
24377
|
-
const k = `${source.rule.name ?? "<unnamed>"}|${preview(call.input)}|${call.project}|${repo ?? ""}`;
|
|
24478
|
+
const k = `${source.rule.name ?? "<unnamed>"}|${preview(call.input)}|${call.project}|${repo ?? ""}|${dayKey(call.timestamp || void 0)}`;
|
|
24378
24479
|
if (!dedup.findingsKeys.has(k)) {
|
|
24379
24480
|
dedup.findingsKeys.add(k);
|
|
24380
24481
|
result.findings.push({
|
|
@@ -24434,7 +24535,7 @@ var init_scan_summary = __esm({
|
|
|
24434
24535
|
|
|
24435
24536
|
// src/agent-wiring.ts
|
|
24436
24537
|
import fs35 from "fs";
|
|
24437
|
-
import
|
|
24538
|
+
import path37 from "path";
|
|
24438
24539
|
import * as yaml from "yaml";
|
|
24439
24540
|
import { parse as parseToml } from "smol-toml";
|
|
24440
24541
|
var exists, ck, lg, AGENT_SPECS;
|
|
@@ -24456,55 +24557,55 @@ var init_agent_wiring = __esm({
|
|
|
24456
24557
|
id: "claude",
|
|
24457
24558
|
label: "Claude Code",
|
|
24458
24559
|
setupCommand: "node9 agents add claude",
|
|
24459
|
-
hookFile: (h) =>
|
|
24560
|
+
hookFile: (h) => path37.join(h, ".claude", "settings.json"),
|
|
24460
24561
|
hookFormat: "matcher",
|
|
24461
24562
|
// UserPromptSubmit is prompt DLP. setup.ts has written it for Claude since
|
|
24462
24563
|
// that shipped; the spec must name it too, or status/doctor never show the
|
|
24463
24564
|
// row and heal (which repairs via setupAgent) has no signal it is missing.
|
|
24464
24565
|
hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
|
|
24465
|
-
mcpFile: (h) =>
|
|
24466
|
-
present: (h) => exists(
|
|
24566
|
+
mcpFile: (h) => path37.join(h, ".claude.json"),
|
|
24567
|
+
present: (h) => exists(path37.join(h, ".claude", "settings.json")) || exists(path37.join(h, ".claude.json"))
|
|
24467
24568
|
},
|
|
24468
24569
|
{
|
|
24469
24570
|
id: "gemini",
|
|
24470
24571
|
label: "Gemini CLI",
|
|
24471
24572
|
setupCommand: "node9 agents add gemini",
|
|
24472
|
-
hookFile: (h) =>
|
|
24573
|
+
hookFile: (h) => path37.join(h, ".gemini", "settings.json"),
|
|
24473
24574
|
hookFormat: "matcher",
|
|
24474
24575
|
hookEvents: [ck("BeforeTool"), lg("AfterTool")],
|
|
24475
|
-
mcpFile: (h) =>
|
|
24476
|
-
present: (h) => exists(
|
|
24576
|
+
mcpFile: (h) => path37.join(h, ".gemini", "settings.json"),
|
|
24577
|
+
present: (h) => exists(path37.join(h, ".gemini", "settings.json"))
|
|
24477
24578
|
},
|
|
24478
24579
|
{
|
|
24479
24580
|
id: "codex",
|
|
24480
24581
|
label: "Codex",
|
|
24481
24582
|
setupCommand: "node9 agents add codex",
|
|
24482
|
-
hookFile: (h) =>
|
|
24583
|
+
hookFile: (h) => path37.join(h, ".codex", "hooks.json"),
|
|
24483
24584
|
hookFormat: "matcher",
|
|
24484
24585
|
hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
|
|
24485
|
-
mcpFile: (h) =>
|
|
24586
|
+
mcpFile: (h) => path37.join(h, ".codex", "config.toml"),
|
|
24486
24587
|
mcpFormat: "toml",
|
|
24487
|
-
present: (h) => exists(
|
|
24588
|
+
present: (h) => exists(path37.join(h, ".codex"))
|
|
24488
24589
|
},
|
|
24489
24590
|
{
|
|
24490
24591
|
id: "antigravity",
|
|
24491
24592
|
label: "Antigravity",
|
|
24492
24593
|
setupCommand: "node9 agents add antigravity",
|
|
24493
|
-
hookFile: (h) =>
|
|
24594
|
+
hookFile: (h) => path37.join(h, ".gemini", "config", "hooks.json"),
|
|
24494
24595
|
hookFormat: "matcher",
|
|
24495
24596
|
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
24496
|
-
mcpFile: (h) =>
|
|
24497
|
-
present: (h) => exists(
|
|
24597
|
+
mcpFile: (h) => path37.join(h, ".gemini", "config", "mcp_config.json"),
|
|
24598
|
+
present: (h) => exists(path37.join(h, ".gemini", "config", "hooks.json")) || exists(path37.join(h, ".gemini", "antigravity-cli")) || exists(path37.join(h, ".gemini", "antigravity-ide"))
|
|
24498
24599
|
},
|
|
24499
24600
|
{
|
|
24500
24601
|
id: "copilot",
|
|
24501
24602
|
label: "GitHub Copilot",
|
|
24502
24603
|
setupCommand: "node9 agents add copilot",
|
|
24503
|
-
hookFile: (h) =>
|
|
24604
|
+
hookFile: (h) => path37.join(h, ".copilot", "hooks", "node9.json"),
|
|
24504
24605
|
hookFormat: "flat",
|
|
24505
24606
|
hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
|
|
24506
|
-
mcpFile: (h) =>
|
|
24507
|
-
present: (h) => exists(
|
|
24607
|
+
mcpFile: (h) => path37.join(h, ".copilot", "mcp-config.json"),
|
|
24608
|
+
present: (h) => exists(path37.join(h, ".copilot"))
|
|
24508
24609
|
},
|
|
24509
24610
|
{
|
|
24510
24611
|
id: "cursor",
|
|
@@ -24513,8 +24614,8 @@ var init_agent_wiring = __esm({
|
|
|
24513
24614
|
// MCP-only — no hook file (see note above).
|
|
24514
24615
|
hookFormat: "flat",
|
|
24515
24616
|
hookEvents: [],
|
|
24516
|
-
mcpFile: (h) =>
|
|
24517
|
-
present: (h) => exists(
|
|
24617
|
+
mcpFile: (h) => path37.join(h, ".cursor", "mcp.json"),
|
|
24618
|
+
present: (h) => exists(path37.join(h, ".cursor", "mcp.json"))
|
|
24518
24619
|
},
|
|
24519
24620
|
{
|
|
24520
24621
|
id: "hermes",
|
|
@@ -24535,8 +24636,8 @@ var init_agent_wiring = __esm({
|
|
|
24535
24636
|
setupCommand: "node9 agents add opencode",
|
|
24536
24637
|
hookFormat: "flat",
|
|
24537
24638
|
hookEvents: [],
|
|
24538
|
-
shimFile: (h) =>
|
|
24539
|
-
present: (h) => exists(opencodeConfigDir(h)) || exists(
|
|
24639
|
+
shimFile: (h) => path37.join(opencodeConfigDir(h), "plugins", "node9.js"),
|
|
24640
|
+
present: (h) => exists(opencodeConfigDir(h)) || exists(path37.join(opencodeConfigDir(h), "plugins", "node9.js"))
|
|
24540
24641
|
},
|
|
24541
24642
|
{
|
|
24542
24643
|
id: "pi",
|
|
@@ -24544,8 +24645,8 @@ var init_agent_wiring = __esm({
|
|
|
24544
24645
|
setupCommand: "node9 agents add pi",
|
|
24545
24646
|
hookFormat: "flat",
|
|
24546
24647
|
hookEvents: [],
|
|
24547
|
-
shimFile: (h) =>
|
|
24548
|
-
present: (h) => exists(
|
|
24648
|
+
shimFile: (h) => path37.join(h, ".pi", "agent", "extensions", "node9.js"),
|
|
24649
|
+
present: (h) => exists(path37.join(h, ".pi", "agent")) || exists(path37.join(h, ".pi", "agent", "extensions", "node9.js"))
|
|
24549
24650
|
}
|
|
24550
24651
|
];
|
|
24551
24652
|
}
|
|
@@ -24596,14 +24697,14 @@ var init_codex_trust = __esm({
|
|
|
24596
24697
|
});
|
|
24597
24698
|
|
|
24598
24699
|
// src/daemon/hook-baseline.ts
|
|
24599
|
-
import
|
|
24700
|
+
import path38 from "path";
|
|
24600
24701
|
import os27 from "os";
|
|
24601
24702
|
var BASELINE_FILE, NOTIFIED_FILE;
|
|
24602
24703
|
var init_hook_baseline = __esm({
|
|
24603
24704
|
"src/daemon/hook-baseline.ts"() {
|
|
24604
24705
|
"use strict";
|
|
24605
|
-
BASELINE_FILE =
|
|
24606
|
-
NOTIFIED_FILE =
|
|
24706
|
+
BASELINE_FILE = path38.join(os27.homedir(), ".node9", "hooks-baseline.json");
|
|
24707
|
+
NOTIFIED_FILE = path38.join(os27.homedir(), ".node9", "hook-heal-notified.json");
|
|
24607
24708
|
}
|
|
24608
24709
|
});
|
|
24609
24710
|
|
|
@@ -24622,7 +24723,7 @@ var init_setup_pi_shim = __esm({
|
|
|
24622
24723
|
});
|
|
24623
24724
|
|
|
24624
24725
|
// src/setup.ts
|
|
24625
|
-
import
|
|
24726
|
+
import path39 from "path";
|
|
24626
24727
|
import os28 from "os";
|
|
24627
24728
|
import chalk3 from "chalk";
|
|
24628
24729
|
import { confirm as rawConfirm } from "@inquirer/prompts";
|
|
@@ -24630,16 +24731,16 @@ import { parse as parseToml5, stringify as stringifyToml2 } from "smol-toml";
|
|
|
24630
24731
|
import * as yaml2 from "yaml";
|
|
24631
24732
|
function opencodeConfigDir(home = os28.homedir()) {
|
|
24632
24733
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
24633
|
-
const base2 = xdg &&
|
|
24634
|
-
return
|
|
24734
|
+
const base2 = xdg && path39.isAbsolute(xdg) ? xdg : path39.join(home, ".config");
|
|
24735
|
+
return path39.join(base2, "opencode");
|
|
24635
24736
|
}
|
|
24636
24737
|
function hermesHomeDir(homeDir = os28.homedir()) {
|
|
24637
24738
|
const env = process.env.HERMES_HOME?.trim();
|
|
24638
|
-
if (env &&
|
|
24639
|
-
return
|
|
24739
|
+
if (env && path39.isAbsolute(env)) return env;
|
|
24740
|
+
return path39.join(homeDir, ".hermes");
|
|
24640
24741
|
}
|
|
24641
24742
|
function hermesConfigPath(homeDir = os28.homedir()) {
|
|
24642
|
-
return
|
|
24743
|
+
return path39.join(hermesHomeDir(homeDir), HERMES_CONFIG_FILENAME);
|
|
24643
24744
|
}
|
|
24644
24745
|
var HERMES_CONFIG_FILENAME;
|
|
24645
24746
|
var init_setup = __esm({
|
|
@@ -24685,15 +24786,66 @@ var init_scan_history = __esm({
|
|
|
24685
24786
|
// src/cli/commands/scan.ts
|
|
24686
24787
|
import chalk5 from "chalk";
|
|
24687
24788
|
import fs36 from "fs";
|
|
24688
|
-
import
|
|
24789
|
+
import path40 from "path";
|
|
24689
24790
|
import os29 from "os";
|
|
24690
24791
|
import stringWidth2 from "string-width";
|
|
24691
|
-
function
|
|
24792
|
+
function dayKey(ts) {
|
|
24793
|
+
if (!ts) return "unknown";
|
|
24794
|
+
if (typeof ts === "string" && /^\d{4}-\d{2}-\d{2}$/.test(ts)) return ts;
|
|
24795
|
+
const d = typeof ts === "string" ? new Date(ts) : ts;
|
|
24796
|
+
if (Number.isNaN(d.getTime())) return "unknown";
|
|
24797
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
24798
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
24799
|
+
return `${d.getFullYear()}-${m}-${day}`;
|
|
24800
|
+
}
|
|
24801
|
+
function dayOf(result, ts, event = true) {
|
|
24802
|
+
result.days ??= {};
|
|
24803
|
+
const key = dayKey(ts);
|
|
24804
|
+
let d = result.days[key];
|
|
24805
|
+
if (!d) {
|
|
24806
|
+
d = {
|
|
24807
|
+
events: 0,
|
|
24808
|
+
toolCalls: 0,
|
|
24809
|
+
bashCalls: 0,
|
|
24810
|
+
mcpCalls: 0,
|
|
24811
|
+
mcpByServer: {},
|
|
24812
|
+
costUSD: 0,
|
|
24813
|
+
unknownInputs: {}
|
|
24814
|
+
};
|
|
24815
|
+
result.days[key] = d;
|
|
24816
|
+
}
|
|
24817
|
+
if (!event) return d;
|
|
24818
|
+
d.events++;
|
|
24819
|
+
if (ts) {
|
|
24820
|
+
if (!d.first || ts < d.first) d.first = ts;
|
|
24821
|
+
if (!d.last || ts > d.last) d.last = ts;
|
|
24822
|
+
}
|
|
24823
|
+
return d;
|
|
24824
|
+
}
|
|
24825
|
+
function addUnknown(day, unknown) {
|
|
24826
|
+
for (const u of unknown) day.unknownInputs[u] = (day.unknownInputs[u] ?? 0) + 1;
|
|
24827
|
+
}
|
|
24828
|
+
function countMcpCall(result, toolName, day) {
|
|
24692
24829
|
const m = /^mcp__(.+?)__/.exec(toolName);
|
|
24693
24830
|
if (!m) return;
|
|
24694
24831
|
result.mcpCalls = (result.mcpCalls ?? 0) + 1;
|
|
24695
24832
|
result.mcpByServer ??= {};
|
|
24696
24833
|
result.mcpByServer[m[1]] = (result.mcpByServer[m[1]] ?? 0) + 1;
|
|
24834
|
+
if (day) {
|
|
24835
|
+
day.mcpCalls++;
|
|
24836
|
+
day.mcpByServer[m[1]] = (day.mcpByServer[m[1]] ?? 0) + 1;
|
|
24837
|
+
}
|
|
24838
|
+
}
|
|
24839
|
+
function judgeFromFor(startDate) {
|
|
24840
|
+
return startDate ? new Date(startDate.getTime() - STATE_LOOKBACK_MS) : null;
|
|
24841
|
+
}
|
|
24842
|
+
function beforeJudged(judgeFrom, ts) {
|
|
24843
|
+
if (!judgeFrom || !ts) return false;
|
|
24844
|
+
const t = Date.parse(ts);
|
|
24845
|
+
return Number.isFinite(t) && t < judgeFrom.getTime();
|
|
24846
|
+
}
|
|
24847
|
+
function fileMayHoldWindow(stamp, startDate) {
|
|
24848
|
+
return !startDate || !stamp || stamp.mtimeMs >= startDate.getTime();
|
|
24697
24849
|
}
|
|
24698
24850
|
function claudeModelPrice2(model) {
|
|
24699
24851
|
const t = pricingFor(model);
|
|
@@ -24722,8 +24874,8 @@ function preview2(input, max) {
|
|
|
24722
24874
|
function emptyScanDedup() {
|
|
24723
24875
|
return { findingsKeys: /* @__PURE__ */ new Set(), dlpKeys: /* @__PURE__ */ new Set(), canaryIndex: /* @__PURE__ */ new Map() };
|
|
24724
24876
|
}
|
|
24725
|
-
function dlpKey(patternName, redactedSample, projLabel) {
|
|
24726
|
-
return `${patternName}|${redactedSample}|${projLabel}`;
|
|
24877
|
+
function dlpKey(patternName, redactedSample, projLabel, timestamp2) {
|
|
24878
|
+
return `${patternName}|${redactedSample}|${projLabel}|${dayKey(timestamp2 || void 0)}`;
|
|
24727
24879
|
}
|
|
24728
24880
|
function safeCanaryScanValues() {
|
|
24729
24881
|
try {
|
|
@@ -24742,7 +24894,7 @@ function recordCanaries(scanned, toolName, timestamp2, projLabel, sessionId, age
|
|
|
24742
24894
|
const v = pool.find((x) => x.id === hit.id);
|
|
24743
24895
|
if (v) matched.push(v.value);
|
|
24744
24896
|
pool = pool.filter((x) => x.id !== hit.id);
|
|
24745
|
-
const key = `canary|${hit.id}|${sessionId}|${agent}`;
|
|
24897
|
+
const key = `canary|${hit.id}|${sessionId}|${agent}|${dayKey(timestamp2 || void 0)}`;
|
|
24746
24898
|
const existing = dedup.canaryIndex.get(key);
|
|
24747
24899
|
if (existing) {
|
|
24748
24900
|
existing.count++;
|
|
@@ -24843,13 +24995,12 @@ function geminiChatFiles(chatsDir) {
|
|
|
24843
24995
|
return true;
|
|
24844
24996
|
});
|
|
24845
24997
|
}
|
|
24846
|
-
async function processClaudeFile(file2, projPath, projLabel, judge,
|
|
24847
|
-
let sessionCounted = false;
|
|
24998
|
+
async function processClaudeFile(file2, projPath, projLabel, judge, judgeFrom, result, dedup, canaryVals, onLine) {
|
|
24848
24999
|
const sessionId = sessionIdOf(file2);
|
|
24849
25000
|
const session = { sessionId, costUSD: 0, toolCalls: 0 };
|
|
24850
25001
|
let raw;
|
|
24851
25002
|
try {
|
|
24852
|
-
raw = fs36.readFileSync(
|
|
25003
|
+
raw = fs36.readFileSync(path40.join(projPath, file2), "utf-8");
|
|
24853
25004
|
} catch {
|
|
24854
25005
|
return false;
|
|
24855
25006
|
}
|
|
@@ -24868,13 +25019,9 @@ async function processClaudeFile(file2, projPath, projLabel, judge, startDate, r
|
|
|
24868
25019
|
continue;
|
|
24869
25020
|
}
|
|
24870
25021
|
if (entry.type !== "assistant" && entry.type !== "user") continue;
|
|
24871
|
-
if (
|
|
24872
|
-
|
|
24873
|
-
|
|
24874
|
-
if (!sessionCounted) {
|
|
24875
|
-
sessionCounted = true;
|
|
24876
|
-
result.sessions++;
|
|
24877
|
-
}
|
|
25022
|
+
if (beforeJudged(judgeFrom, entry.timestamp)) continue;
|
|
25023
|
+
const day = dayOf(result, entry.timestamp);
|
|
25024
|
+
if (result.sessions === 0) result.sessions = 1;
|
|
24878
25025
|
if (entry.timestamp) {
|
|
24879
25026
|
if (!result.firstDate || entry.timestamp < result.firstDate)
|
|
24880
25027
|
result.firstDate = entry.timestamp;
|
|
@@ -24898,7 +25045,12 @@ async function processClaudeFile(file2, projPath, projLabel, judge, startDate, r
|
|
|
24898
25045
|
);
|
|
24899
25046
|
const dlpMatch = scanArgs(scrubDecoys({ text }, decoysHere0));
|
|
24900
25047
|
if (dlpMatch) {
|
|
24901
|
-
const k = dlpKey(
|
|
25048
|
+
const k = dlpKey(
|
|
25049
|
+
dlpMatch.patternName,
|
|
25050
|
+
dlpMatch.redactedSample,
|
|
25051
|
+
projLabel,
|
|
25052
|
+
entry.timestamp ?? ""
|
|
25053
|
+
);
|
|
24902
25054
|
if (!dedup.dlpKeys.has(k)) {
|
|
24903
25055
|
dedup.dlpKeys.add(k);
|
|
24904
25056
|
result.dlpFindings.push({
|
|
@@ -24917,7 +25069,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, startDate, r
|
|
|
24917
25069
|
if (block.type !== "tool_result") continue;
|
|
24918
25070
|
const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
|
|
24919
25071
|
if (filePath) {
|
|
24920
|
-
const ext =
|
|
25072
|
+
const ext = path40.extname(filePath).toLowerCase();
|
|
24921
25073
|
if (CODE_EXTENSIONS.has(ext)) continue;
|
|
24922
25074
|
}
|
|
24923
25075
|
const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
|
|
@@ -24941,7 +25093,12 @@ async function processClaudeFile(file2, projPath, projLabel, judge, startDate, r
|
|
|
24941
25093
|
if (dlpMatch) {
|
|
24942
25094
|
if (firstDlpTs === null) firstDlpTs = entry.timestamp ?? null;
|
|
24943
25095
|
judge.noteOutputSecret(sessionId, dlpMatch.patternName, entry.timestamp ?? "");
|
|
24944
|
-
const k = dlpKey(
|
|
25096
|
+
const k = dlpKey(
|
|
25097
|
+
dlpMatch.patternName,
|
|
25098
|
+
dlpMatch.redactedSample,
|
|
25099
|
+
projLabel,
|
|
25100
|
+
entry.timestamp ?? ""
|
|
25101
|
+
);
|
|
24945
25102
|
if (!dedup.dlpKeys.has(k)) {
|
|
24946
25103
|
dedup.dlpKeys.add(k);
|
|
24947
25104
|
result.dlpFindings.push({
|
|
@@ -24967,6 +25124,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, startDate, r
|
|
|
24967
25124
|
const rowCost = (usage2.input_tokens ?? 0) * p.i + (usage2.output_tokens ?? 0) * p.o + (usage2.cache_creation_input_tokens ?? 0) * p.cw + (usage2.cache_read_input_tokens ?? 0) * p.cr;
|
|
24968
25125
|
result.totalCostUSD += rowCost;
|
|
24969
25126
|
session.costUSD += rowCost;
|
|
25127
|
+
day.costUSD += rowCost;
|
|
24970
25128
|
}
|
|
24971
25129
|
}
|
|
24972
25130
|
const content = entry.message?.content;
|
|
@@ -24975,8 +25133,9 @@ async function processClaudeFile(file2, projPath, projLabel, judge, startDate, r
|
|
|
24975
25133
|
if (block.type !== "tool_use") continue;
|
|
24976
25134
|
result.totalToolCalls++;
|
|
24977
25135
|
session.toolCalls++;
|
|
25136
|
+
day.toolCalls++;
|
|
24978
25137
|
const toolName = block.name ?? "";
|
|
24979
|
-
countMcpCall(result, toolName);
|
|
25138
|
+
countMcpCall(result, toolName, day);
|
|
24980
25139
|
const toolNameLower = toolName.toLowerCase();
|
|
24981
25140
|
const input = block.input ?? {};
|
|
24982
25141
|
if (block.id && typeof input.file_path === "string") {
|
|
@@ -24986,6 +25145,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, startDate, r
|
|
|
24986
25145
|
sessionCalls.push({ toolName, input, timestamp: entry.timestamp ?? "" });
|
|
24987
25146
|
if (toolNameLower === "bash" || toolNameLower === "execute_bash") {
|
|
24988
25147
|
result.bashCalls++;
|
|
25148
|
+
day.bashCalls++;
|
|
24989
25149
|
}
|
|
24990
25150
|
if (firstEditTs === null && (toolNameLower === "edit" || toolNameLower === "write" || toolNameLower === "write_file" || toolNameLower === "edit_file" || toolNameLower === "multiedit")) {
|
|
24991
25151
|
firstEditTs = entry.timestamp ?? null;
|
|
@@ -25017,6 +25177,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, startDate, r
|
|
|
25017
25177
|
result,
|
|
25018
25178
|
dedup
|
|
25019
25179
|
);
|
|
25180
|
+
addUnknown(day, judged.verdict.unknown);
|
|
25020
25181
|
if (judged.dlpMatched && firstDlpTs === null) firstDlpTs = entry.timestamp ?? null;
|
|
25021
25182
|
}
|
|
25022
25183
|
}
|
|
@@ -25027,8 +25188,8 @@ async function processClaudeFile(file2, projPath, projLabel, judge, startDate, r
|
|
|
25027
25188
|
result.perSession.push(session);
|
|
25028
25189
|
return true;
|
|
25029
25190
|
}
|
|
25030
|
-
async function processClaudeProjectAsync(proj, projectsDir, judge, cache4,
|
|
25031
|
-
const projPath =
|
|
25191
|
+
async function processClaudeProjectAsync(proj, projectsDir, judge, cache4, startDate, result, dedup, canaryVals, onProgress, onLine) {
|
|
25192
|
+
const projPath = path40.join(projectsDir, proj);
|
|
25032
25193
|
try {
|
|
25033
25194
|
if (!fs36.statSync(projPath).isDirectory()) return;
|
|
25034
25195
|
} catch {
|
|
@@ -25042,13 +25203,15 @@ async function processClaudeProjectAsync(proj, projectsDir, judge, cache4, windo
|
|
|
25042
25203
|
return;
|
|
25043
25204
|
}
|
|
25044
25205
|
for (const file2 of files) {
|
|
25045
|
-
const filePath =
|
|
25206
|
+
const filePath = path40.join(projPath, file2);
|
|
25207
|
+
const stamp = fileStamp(filePath);
|
|
25208
|
+
if (!fileMayHoldWindow(stamp, startDate)) continue;
|
|
25046
25209
|
result.filesScanned++;
|
|
25047
25210
|
onProgress?.(result.filesScanned);
|
|
25048
|
-
const
|
|
25049
|
-
const cached = stamp ? cache4.get(filePath, stamp,
|
|
25211
|
+
const judgeFrom = judgeFromFor(startDate);
|
|
25212
|
+
const cached = stamp ? cache4.get(filePath, stamp, judge, judgeFrom) : null;
|
|
25050
25213
|
if (cached) {
|
|
25051
|
-
mergeFileScan(result, cached, dedup);
|
|
25214
|
+
mergeFileScan(result, cached, dedup, startDate);
|
|
25052
25215
|
continue;
|
|
25053
25216
|
}
|
|
25054
25217
|
const fileResult = emptyScan();
|
|
@@ -25058,14 +25221,15 @@ async function processClaudeProjectAsync(proj, projectsDir, judge, cache4, windo
|
|
|
25058
25221
|
projPath,
|
|
25059
25222
|
projLabel,
|
|
25060
25223
|
judge,
|
|
25061
|
-
|
|
25224
|
+
judgeFrom,
|
|
25062
25225
|
fileResult,
|
|
25063
25226
|
fileDedup,
|
|
25064
25227
|
canaryVals,
|
|
25065
25228
|
onLine
|
|
25066
25229
|
);
|
|
25067
|
-
if (read2 && stamp) cache4.put(filePath, stamp,
|
|
25068
|
-
mergeFileScan(result, fileResult, dedup);
|
|
25230
|
+
if (read2 && stamp) cache4.put(filePath, stamp, "claude", fileResult, judge, judgeFrom);
|
|
25231
|
+
mergeFileScan(result, fileResult, dedup, startDate);
|
|
25232
|
+
await yieldTick();
|
|
25069
25233
|
await yieldTick();
|
|
25070
25234
|
}
|
|
25071
25235
|
}
|
|
@@ -25104,40 +25268,71 @@ function openScanCache(judge, opts) {
|
|
|
25104
25268
|
enabled: opts.cache !== false && process.env.NODE9_SCAN_CACHE !== "0"
|
|
25105
25269
|
});
|
|
25106
25270
|
}
|
|
25107
|
-
function mergeFileScan(result, file2, dedup) {
|
|
25108
|
-
|
|
25109
|
-
|
|
25110
|
-
|
|
25111
|
-
|
|
25112
|
-
|
|
25113
|
-
|
|
25114
|
-
|
|
25115
|
-
|
|
25116
|
-
result.
|
|
25117
|
-
|
|
25118
|
-
result.
|
|
25119
|
-
|
|
25120
|
-
|
|
25121
|
-
result.
|
|
25122
|
-
|
|
25123
|
-
|
|
25124
|
-
|
|
25125
|
-
|
|
25126
|
-
|
|
25271
|
+
function mergeFileScan(result, file2, dedup, startDate = null) {
|
|
25272
|
+
const startKey = startDate ? dayKey(startDate) : null;
|
|
25273
|
+
const dayIn = (key) => !startKey || key === "unknown" || key >= startKey;
|
|
25274
|
+
const tsIn = (ts) => dayIn(dayKey(ts || void 0));
|
|
25275
|
+
const days = Object.entries(file2.days ?? {}).filter(([k]) => dayIn(k));
|
|
25276
|
+
const inWindow = !startKey || days.some(([, d]) => d.events > 0 || d.toolCalls > 0);
|
|
25277
|
+
if (!startKey) {
|
|
25278
|
+
result.sessions += file2.sessions;
|
|
25279
|
+
result.totalToolCalls += file2.totalToolCalls;
|
|
25280
|
+
result.bashCalls += file2.bashCalls;
|
|
25281
|
+
result.totalCostUSD += file2.totalCostUSD;
|
|
25282
|
+
result.sessionsWithEarlySecrets += file2.sessionsWithEarlySecrets;
|
|
25283
|
+
if (file2.firstDate && (!result.firstDate || file2.firstDate < result.firstDate))
|
|
25284
|
+
result.firstDate = file2.firstDate;
|
|
25285
|
+
if (file2.lastDate && (!result.lastDate || file2.lastDate > result.lastDate))
|
|
25286
|
+
result.lastDate = file2.lastDate;
|
|
25287
|
+
if (file2.mcpCalls) result.mcpCalls = (result.mcpCalls ?? 0) + file2.mcpCalls;
|
|
25288
|
+
for (const [server, n] of Object.entries(file2.mcpByServer ?? {})) {
|
|
25289
|
+
result.mcpByServer ??= {};
|
|
25290
|
+
result.mcpByServer[server] = (result.mcpByServer[server] ?? 0) + n;
|
|
25291
|
+
}
|
|
25292
|
+
for (const [what, n] of Object.entries(file2.unknownInputs ?? {})) {
|
|
25293
|
+
result.unknownInputs ??= {};
|
|
25294
|
+
result.unknownInputs[what] = (result.unknownInputs[what] ?? 0) + n;
|
|
25295
|
+
}
|
|
25296
|
+
} else {
|
|
25297
|
+
if (inWindow) {
|
|
25298
|
+
result.sessions += Math.min(1, file2.sessions);
|
|
25299
|
+
result.sessionsWithEarlySecrets += file2.sessionsWithEarlySecrets;
|
|
25300
|
+
}
|
|
25301
|
+
for (const [, d] of days) {
|
|
25302
|
+
result.totalToolCalls += d.toolCalls;
|
|
25303
|
+
result.bashCalls += d.bashCalls;
|
|
25304
|
+
result.totalCostUSD += d.costUSD;
|
|
25305
|
+
if (d.mcpCalls) result.mcpCalls = (result.mcpCalls ?? 0) + d.mcpCalls;
|
|
25306
|
+
for (const [server, n] of Object.entries(d.mcpByServer)) {
|
|
25307
|
+
result.mcpByServer ??= {};
|
|
25308
|
+
result.mcpByServer[server] = (result.mcpByServer[server] ?? 0) + n;
|
|
25309
|
+
}
|
|
25310
|
+
for (const [what, n] of Object.entries(d.unknownInputs)) {
|
|
25311
|
+
result.unknownInputs ??= {};
|
|
25312
|
+
result.unknownInputs[what] = (result.unknownInputs[what] ?? 0) + n;
|
|
25313
|
+
}
|
|
25314
|
+
if (d.first && (!result.firstDate || d.first < result.firstDate)) result.firstDate = d.first;
|
|
25315
|
+
if (d.last && (!result.lastDate || d.last > result.lastDate)) result.lastDate = d.last;
|
|
25316
|
+
}
|
|
25127
25317
|
}
|
|
25318
|
+
if (inWindow) result.perSession.push(...file2.perSession);
|
|
25319
|
+
result.loopFindings.push(...file2.loopFindings.filter((l) => tsIn(l.timestamp)));
|
|
25128
25320
|
for (const f of file2.findings) {
|
|
25321
|
+
if (!tsIn(f.timestamp)) continue;
|
|
25129
25322
|
const k = findingDedupKey(f);
|
|
25130
25323
|
if (dedup.findingsKeys.has(k)) continue;
|
|
25131
25324
|
dedup.findingsKeys.add(k);
|
|
25132
25325
|
result.findings.push(f);
|
|
25133
25326
|
}
|
|
25134
25327
|
for (const d of file2.dlpFindings) {
|
|
25328
|
+
if (!tsIn(d.timestamp)) continue;
|
|
25135
25329
|
const k = dlpDedupKey(d);
|
|
25136
25330
|
if (dedup.dlpKeys.has(k)) continue;
|
|
25137
25331
|
dedup.dlpKeys.add(k);
|
|
25138
25332
|
result.dlpFindings.push(d);
|
|
25139
25333
|
}
|
|
25140
25334
|
for (const c of file2.canaryFindings) {
|
|
25335
|
+
if (!tsIn(c.timestamp)) continue;
|
|
25141
25336
|
const k = `canary|${c.canaryId}|${c.sessionId}|${c.agent}`;
|
|
25142
25337
|
const existing = dedup.canaryIndex.get(k);
|
|
25143
25338
|
if (existing) {
|
|
@@ -25151,7 +25346,7 @@ function mergeFileScan(result, file2, dedup) {
|
|
|
25151
25346
|
}
|
|
25152
25347
|
}
|
|
25153
25348
|
async function scanClaudeHistoryAsync(startDate, onProgress, onLine, opts = {}) {
|
|
25154
|
-
const projectsDir =
|
|
25349
|
+
const projectsDir = path40.join(os29.homedir(), ".claude", "projects");
|
|
25155
25350
|
const result = emptyClaudeScan();
|
|
25156
25351
|
if (!fs36.existsSync(projectsDir)) return result;
|
|
25157
25352
|
let projDirs;
|
|
@@ -25162,7 +25357,6 @@ async function scanClaudeHistoryAsync(startDate, onProgress, onLine, opts = {})
|
|
|
25162
25357
|
}
|
|
25163
25358
|
const judge = new HistoryJudge();
|
|
25164
25359
|
const cache4 = openScanCache(judge, opts);
|
|
25165
|
-
const window = windowKey(startDate);
|
|
25166
25360
|
const dedup = emptyScanDedup();
|
|
25167
25361
|
const canaryVals = safeCanaryScanValues();
|
|
25168
25362
|
for (const proj of projDirs) {
|
|
@@ -25171,7 +25365,6 @@ async function scanClaudeHistoryAsync(startDate, onProgress, onLine, opts = {})
|
|
|
25171
25365
|
projectsDir,
|
|
25172
25366
|
judge,
|
|
25173
25367
|
cache4,
|
|
25174
|
-
window,
|
|
25175
25368
|
startDate,
|
|
25176
25369
|
result,
|
|
25177
25370
|
dedup,
|
|
@@ -25180,13 +25373,13 @@ async function scanClaudeHistoryAsync(startDate, onProgress, onLine, opts = {})
|
|
|
25180
25373
|
onLine
|
|
25181
25374
|
);
|
|
25182
25375
|
}
|
|
25183
|
-
cache4.
|
|
25376
|
+
cache4.close();
|
|
25184
25377
|
result.policy = judge.policy(result.unknownInputs ?? {});
|
|
25185
25378
|
return result;
|
|
25186
25379
|
}
|
|
25187
25380
|
async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
25188
25381
|
const canaryVals = safeCanaryScanValues();
|
|
25189
|
-
const tmpDir =
|
|
25382
|
+
const tmpDir = path40.join(os29.homedir(), ".gemini", "tmp");
|
|
25190
25383
|
const result = {
|
|
25191
25384
|
filesScanned: 0,
|
|
25192
25385
|
sessions: 0,
|
|
@@ -25212,9 +25405,8 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25212
25405
|
}
|
|
25213
25406
|
const judge = new HistoryJudge();
|
|
25214
25407
|
const cache4 = openScanCache(judge, opts);
|
|
25215
|
-
const window = windowKey(startDate);
|
|
25216
25408
|
for (const slug2 of slugDirs) {
|
|
25217
|
-
const slugPath =
|
|
25409
|
+
const slugPath = path40.join(tmpDir, slug2);
|
|
25218
25410
|
try {
|
|
25219
25411
|
if (!fs36.statSync(slugPath).isDirectory()) continue;
|
|
25220
25412
|
} catch {
|
|
@@ -25223,11 +25415,11 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25223
25415
|
let projLabel = stripTerminalEscapes(slug2).slice(0, 40);
|
|
25224
25416
|
try {
|
|
25225
25417
|
projLabel = stripTerminalEscapes(
|
|
25226
|
-
fs36.readFileSync(
|
|
25418
|
+
fs36.readFileSync(path40.join(slugPath, ".project_root"), "utf-8").trim()
|
|
25227
25419
|
).replace(os29.homedir(), "~").slice(0, 40);
|
|
25228
25420
|
} catch {
|
|
25229
25421
|
}
|
|
25230
|
-
const chatsDir =
|
|
25422
|
+
const chatsDir = path40.join(slugPath, "chats");
|
|
25231
25423
|
if (!fs36.existsSync(chatsDir)) continue;
|
|
25232
25424
|
let chatFiles;
|
|
25233
25425
|
try {
|
|
@@ -25237,20 +25429,21 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25237
25429
|
}
|
|
25238
25430
|
for (const chatFile of chatFiles) {
|
|
25239
25431
|
const sessionId = chatFile.replace(/\.jsonl?$/, "");
|
|
25432
|
+
const filePath = path40.join(chatsDir, chatFile);
|
|
25433
|
+
const stamp = fileStamp(filePath);
|
|
25434
|
+
if (!fileMayHoldWindow(stamp, startDate)) continue;
|
|
25240
25435
|
result.filesScanned++;
|
|
25241
25436
|
onProgress?.(result.filesScanned);
|
|
25242
|
-
const
|
|
25243
|
-
const stamp = fileStamp(filePath);
|
|
25244
|
-
const cached = stamp ? cache4.get(filePath, stamp, window, judge) : null;
|
|
25437
|
+
const cached = stamp ? cache4.get(filePath, stamp, judge, judgeFromFor(startDate)) : null;
|
|
25245
25438
|
if (cached) {
|
|
25246
|
-
mergeFileScan(result, cached, dedup);
|
|
25439
|
+
mergeFileScan(result, cached, dedup, startDate);
|
|
25247
25440
|
continue;
|
|
25248
25441
|
}
|
|
25249
25442
|
const fileResult = emptyScan();
|
|
25250
25443
|
const fileDedup = emptyScanDedup();
|
|
25251
25444
|
let raw;
|
|
25252
25445
|
try {
|
|
25253
|
-
raw = fs36.readFileSync(
|
|
25446
|
+
raw = fs36.readFileSync(path40.join(chatsDir, chatFile), "utf-8");
|
|
25254
25447
|
} catch {
|
|
25255
25448
|
continue;
|
|
25256
25449
|
}
|
|
@@ -25272,7 +25465,6 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25272
25465
|
} catch {
|
|
25273
25466
|
continue;
|
|
25274
25467
|
}
|
|
25275
|
-
let sessionCounted = false;
|
|
25276
25468
|
for (const msg of session.messages ?? []) {
|
|
25277
25469
|
onLine?.();
|
|
25278
25470
|
if (msg.type === "user") {
|
|
@@ -25292,7 +25484,12 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25292
25484
|
);
|
|
25293
25485
|
const dlpMatch = scanArgs(scrubDecoys({ text }, decoysHere3));
|
|
25294
25486
|
if (dlpMatch) {
|
|
25295
|
-
const k = dlpKey(
|
|
25487
|
+
const k = dlpKey(
|
|
25488
|
+
dlpMatch.patternName,
|
|
25489
|
+
dlpMatch.redactedSample,
|
|
25490
|
+
projLabel,
|
|
25491
|
+
msg.timestamp ?? ""
|
|
25492
|
+
);
|
|
25296
25493
|
if (!fileDedup.dlpKeys.has(k)) {
|
|
25297
25494
|
fileDedup.dlpKeys.add(k);
|
|
25298
25495
|
fileResult.dlpFindings.push({
|
|
@@ -25310,11 +25507,9 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25310
25507
|
continue;
|
|
25311
25508
|
}
|
|
25312
25509
|
if (msg.type !== "gemini") continue;
|
|
25313
|
-
if (startDate
|
|
25314
|
-
|
|
25315
|
-
|
|
25316
|
-
fileResult.sessions++;
|
|
25317
|
-
}
|
|
25510
|
+
if (beforeJudged(judgeFromFor(startDate), msg.timestamp)) continue;
|
|
25511
|
+
const day = dayOf(fileResult, msg.timestamp);
|
|
25512
|
+
if (fileResult.sessions === 0) fileResult.sessions = 1;
|
|
25318
25513
|
if (msg.timestamp) {
|
|
25319
25514
|
if (!fileResult.firstDate || msg.timestamp < fileResult.firstDate)
|
|
25320
25515
|
fileResult.firstDate = msg.timestamp;
|
|
@@ -25327,18 +25522,22 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25327
25522
|
const p = geminiModelPrice(model);
|
|
25328
25523
|
if (p) {
|
|
25329
25524
|
const nonCached = Math.max(0, tokens.input - tokens.cached);
|
|
25330
|
-
|
|
25525
|
+
const cost = nonCached * p.i + tokens.cached * p.cr + tokens.output * p.o;
|
|
25526
|
+
fileResult.totalCostUSD += cost;
|
|
25527
|
+
day.costUSD += cost;
|
|
25331
25528
|
}
|
|
25332
25529
|
}
|
|
25333
25530
|
for (const tc of msg.toolCalls ?? []) {
|
|
25334
25531
|
fileResult.totalToolCalls++;
|
|
25532
|
+
day.toolCalls++;
|
|
25335
25533
|
const toolName = tc.name ?? "";
|
|
25336
|
-
countMcpCall(fileResult, toolName);
|
|
25534
|
+
countMcpCall(fileResult, toolName, day);
|
|
25337
25535
|
const toolNameLower = toolName.toLowerCase();
|
|
25338
25536
|
const input = tc.args ?? {};
|
|
25339
25537
|
sessionCalls.push({ toolName, input, timestamp: msg.timestamp ?? "" });
|
|
25340
25538
|
if (toolNameLower === "run_shell_command" || toolNameLower === "shell") {
|
|
25341
25539
|
fileResult.bashCalls++;
|
|
25540
|
+
day.bashCalls++;
|
|
25342
25541
|
}
|
|
25343
25542
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
25344
25543
|
if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd))
|
|
@@ -25367,15 +25566,16 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25367
25566
|
fileResult,
|
|
25368
25567
|
fileDedup
|
|
25369
25568
|
);
|
|
25370
|
-
|
|
25569
|
+
addUnknown(day, judged.verdict.unknown);
|
|
25371
25570
|
}
|
|
25372
25571
|
}
|
|
25373
25572
|
fileResult.loopFindings.push(...detectLoops(sessionCalls, projLabel, sessionId, "gemini"));
|
|
25374
|
-
if (stamp) cache4.put(filePath, stamp,
|
|
25375
|
-
mergeFileScan(result, fileResult, dedup);
|
|
25573
|
+
if (stamp) cache4.put(filePath, stamp, "gemini", fileResult, judge, judgeFromFor(startDate));
|
|
25574
|
+
mergeFileScan(result, fileResult, dedup, startDate);
|
|
25575
|
+
await yieldTick();
|
|
25376
25576
|
}
|
|
25377
25577
|
}
|
|
25378
|
-
cache4.
|
|
25578
|
+
cache4.close();
|
|
25379
25579
|
result.policy = judge.policy(result.unknownInputs ?? {});
|
|
25380
25580
|
return result;
|
|
25381
25581
|
}
|
|
@@ -25400,14 +25600,14 @@ async function scanCodexHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25400
25600
|
const jsonlFiles = listCodexSessionFiles();
|
|
25401
25601
|
const judge = new HistoryJudge();
|
|
25402
25602
|
const cache4 = openScanCache(judge, opts);
|
|
25403
|
-
const window = windowKey(startDate);
|
|
25404
25603
|
for (const filePath of jsonlFiles) {
|
|
25604
|
+
const stamp = fileStamp(filePath);
|
|
25605
|
+
if (!fileMayHoldWindow(stamp, startDate)) continue;
|
|
25405
25606
|
result.filesScanned++;
|
|
25406
25607
|
onProgress?.(result.filesScanned);
|
|
25407
|
-
const
|
|
25408
|
-
const cached = stamp ? cache4.get(filePath, stamp, window, judge) : null;
|
|
25608
|
+
const cached = stamp ? cache4.get(filePath, stamp, judge, judgeFromFor(startDate)) : null;
|
|
25409
25609
|
if (cached) {
|
|
25410
|
-
mergeFileScan(result, cached, dedup);
|
|
25610
|
+
mergeFileScan(result, cached, dedup, startDate);
|
|
25411
25611
|
continue;
|
|
25412
25612
|
}
|
|
25413
25613
|
const fileResult = emptyScan();
|
|
@@ -25422,7 +25622,6 @@ async function scanCodexHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25422
25622
|
let startTime = "";
|
|
25423
25623
|
let projLabel = "";
|
|
25424
25624
|
let sessionCwd;
|
|
25425
|
-
let sessionCounted = false;
|
|
25426
25625
|
const sessionCalls = [];
|
|
25427
25626
|
for (const line of lines) {
|
|
25428
25627
|
if (!line.trim()) continue;
|
|
@@ -25439,7 +25638,7 @@ async function scanCodexHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25439
25638
|
startTime = String(payload["timestamp"] ?? "");
|
|
25440
25639
|
const cwd = String(payload["cwd"] ?? "");
|
|
25441
25640
|
projLabel = stripTerminalEscapes(cwd.replace(os29.homedir(), "~")).slice(0, 40);
|
|
25442
|
-
if (
|
|
25641
|
+
if (path40.isAbsolute(cwd)) sessionCwd = cwd;
|
|
25443
25642
|
continue;
|
|
25444
25643
|
}
|
|
25445
25644
|
if (entry.type === "event_msg" && payload["type"] === "user_message") {
|
|
@@ -25458,7 +25657,12 @@ async function scanCodexHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25458
25657
|
);
|
|
25459
25658
|
const dlpMatch = scanArgs(scrubDecoys({ text }, decoysHere9));
|
|
25460
25659
|
if (dlpMatch) {
|
|
25461
|
-
const k = dlpKey(
|
|
25660
|
+
const k = dlpKey(
|
|
25661
|
+
dlpMatch.patternName,
|
|
25662
|
+
dlpMatch.redactedSample,
|
|
25663
|
+
projLabel,
|
|
25664
|
+
entry.timestamp ?? startTime
|
|
25665
|
+
);
|
|
25462
25666
|
if (!fileDedup.dlpKeys.has(k)) {
|
|
25463
25667
|
fileDedup.dlpKeys.add(k);
|
|
25464
25668
|
fileResult.dlpFindings.push({
|
|
@@ -25478,18 +25682,18 @@ async function scanCodexHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25478
25682
|
if (entry.type !== "response_item") continue;
|
|
25479
25683
|
if (payload["type"] !== "function_call") continue;
|
|
25480
25684
|
const ts = startTime;
|
|
25481
|
-
|
|
25482
|
-
if (
|
|
25483
|
-
|
|
25484
|
-
|
|
25485
|
-
}
|
|
25685
|
+
const callTs = typeof entry.timestamp === "string" ? entry.timestamp : ts;
|
|
25686
|
+
if (beforeJudged(judgeFromFor(startDate), callTs || void 0)) continue;
|
|
25687
|
+
const day = dayOf(fileResult, callTs || void 0);
|
|
25688
|
+
if (fileResult.sessions === 0) fileResult.sessions = 1;
|
|
25486
25689
|
if (ts) {
|
|
25487
25690
|
if (!fileResult.firstDate || ts < fileResult.firstDate) fileResult.firstDate = ts;
|
|
25488
25691
|
if (!fileResult.lastDate || ts > fileResult.lastDate) fileResult.lastDate = ts;
|
|
25489
25692
|
}
|
|
25490
25693
|
fileResult.totalToolCalls++;
|
|
25694
|
+
day.toolCalls++;
|
|
25491
25695
|
const toolName = String(payload["name"] ?? "");
|
|
25492
|
-
countMcpCall(fileResult, toolName);
|
|
25696
|
+
countMcpCall(fileResult, toolName, day);
|
|
25493
25697
|
const toolNameLower = toolName.toLowerCase();
|
|
25494
25698
|
let input = {};
|
|
25495
25699
|
try {
|
|
@@ -25502,6 +25706,7 @@ async function scanCodexHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25502
25706
|
sessionCalls.push({ toolName, input, timestamp: ts });
|
|
25503
25707
|
if (toolNameLower === "exec_command" || toolNameLower === "shell") {
|
|
25504
25708
|
fileResult.bashCalls++;
|
|
25709
|
+
day.bashCalls++;
|
|
25505
25710
|
}
|
|
25506
25711
|
const rawCmd = String(input["command"] ?? "").trimStart();
|
|
25507
25712
|
if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
|
|
@@ -25525,7 +25730,7 @@ async function scanCodexHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25525
25730
|
// The window filter uses the session start (ts); the gate's clock
|
|
25526
25731
|
// (loop window, taint expiry) is the call's own time when the line
|
|
25527
25732
|
// carries one.
|
|
25528
|
-
timestamp:
|
|
25733
|
+
timestamp: callTs,
|
|
25529
25734
|
sessionId,
|
|
25530
25735
|
project: projLabel,
|
|
25531
25736
|
cwd: sessionCwd
|
|
@@ -25533,20 +25738,23 @@ async function scanCodexHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
25533
25738
|
fileResult,
|
|
25534
25739
|
fileDedup
|
|
25535
25740
|
);
|
|
25536
|
-
|
|
25741
|
+
addUnknown(day, judged.verdict.unknown);
|
|
25537
25742
|
}
|
|
25538
|
-
for (const event of
|
|
25743
|
+
for (const event of parseCodexUsage(lines).events) {
|
|
25744
|
+
if (beforeJudged(judgeFromFor(startDate), event.timestamp || void 0)) continue;
|
|
25539
25745
|
fileResult.totalCostUSD += event.costUSD;
|
|
25746
|
+
dayOf(fileResult, event.timestamp || void 0, false).costUSD += event.costUSD;
|
|
25540
25747
|
}
|
|
25541
25748
|
fileResult.loopFindings.push(...detectLoops(sessionCalls, projLabel, sessionId, "codex"));
|
|
25542
|
-
if (stamp) cache4.put(filePath, stamp,
|
|
25543
|
-
mergeFileScan(result, fileResult, dedup);
|
|
25749
|
+
if (stamp) cache4.put(filePath, stamp, "codex", fileResult, judge, judgeFromFor(startDate));
|
|
25750
|
+
mergeFileScan(result, fileResult, dedup, startDate);
|
|
25751
|
+
await yieldTick();
|
|
25544
25752
|
}
|
|
25545
|
-
cache4.
|
|
25753
|
+
cache4.close();
|
|
25546
25754
|
result.policy = judge.policy(result.unknownInputs ?? {});
|
|
25547
25755
|
return result;
|
|
25548
25756
|
}
|
|
25549
|
-
var toolInspectionMap, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS, LOOP_TOOLS, LOOP_THRESHOLD, LOOP_TIMESPAN_THRESHOLD_MS;
|
|
25757
|
+
var toolInspectionMap, STATE_LOOKBACK_MS, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS, LOOP_TOOLS, LOOP_THRESHOLD, LOOP_TIMESPAN_THRESHOLD_MS;
|
|
25550
25758
|
var init_scan = __esm({
|
|
25551
25759
|
"src/cli/commands/scan.ts"() {
|
|
25552
25760
|
"use strict";
|
|
@@ -25576,6 +25784,7 @@ var init_scan = __esm({
|
|
|
25576
25784
|
init_scan_history();
|
|
25577
25785
|
init_safe_text();
|
|
25578
25786
|
toolInspectionMap = DEFAULT_CONFIG.policy.toolInspection;
|
|
25787
|
+
STATE_LOOKBACK_MS = 24 * 60 * 60 * 1e3;
|
|
25579
25788
|
CODE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
25580
25789
|
".ts",
|
|
25581
25790
|
".tsx",
|
|
@@ -25629,10 +25838,10 @@ var init_scan = __esm({
|
|
|
25629
25838
|
// src/tui/dashboard/data.ts
|
|
25630
25839
|
import fs37 from "fs";
|
|
25631
25840
|
import os30 from "os";
|
|
25632
|
-
import
|
|
25841
|
+
import path41 from "path";
|
|
25633
25842
|
import http2 from "http";
|
|
25634
25843
|
function auditLogPath() {
|
|
25635
|
-
return
|
|
25844
|
+
return path41.join(os30.homedir(), ".node9", "audit.log");
|
|
25636
25845
|
}
|
|
25637
25846
|
function readAuditEntriesAsync(chunkSize = 1e3, customPath) {
|
|
25638
25847
|
return new Promise((resolve) => {
|
|
@@ -25779,9 +25988,9 @@ function shortenPath(p) {
|
|
|
25779
25988
|
return p.startsWith(home) ? p.replace(home, "~") : p;
|
|
25780
25989
|
}
|
|
25781
25990
|
async function loadReportAuditAsync(period) {
|
|
25782
|
-
const claudeProjectsDir =
|
|
25991
|
+
const claudeProjectsDir = path41.join(os30.homedir(), ".claude", "projects");
|
|
25783
25992
|
const codexSessionsDir2 = codexSessionsDir();
|
|
25784
|
-
const geminiTmpDir =
|
|
25993
|
+
const geminiTmpDir = path41.join(os30.homedir(), ".gemini", "tmp");
|
|
25785
25994
|
const { start, end } = getDateRange(period, /* @__PURE__ */ new Date());
|
|
25786
25995
|
const entries = await readAuditEntriesAsync();
|
|
25787
25996
|
void ensurePricingLoaded();
|
|
@@ -26893,8 +27102,8 @@ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-run
|
|
|
26893
27102
|
function TopToolsProjects({ audit }) {
|
|
26894
27103
|
const data = audit?.data;
|
|
26895
27104
|
const tools = data ? [...data.toolMap.entries()].sort(([, a], [, b]) => b.calls - a.calls).slice(0, ROW_LIMIT) : [];
|
|
26896
|
-
const projects = data ? [...data.cost.byProject.entries()].map(([
|
|
26897
|
-
name: basenameOf(
|
|
27105
|
+
const projects = data ? [...data.cost.byProject.entries()].map(([path42, r]) => ({
|
|
27106
|
+
name: basenameOf(path42),
|
|
26898
27107
|
cost: r.cost,
|
|
26899
27108
|
tokens: r.inputTokens + r.outputTokens
|
|
26900
27109
|
})).sort((a, b) => b.cost - a.cost).slice(0, ROW_LIMIT) : [];
|
|
@@ -27331,8 +27540,8 @@ function pickTopLoopFile(loops) {
|
|
|
27331
27540
|
map.set(k, (map.get(k) ?? 0) + (l.count ?? 0));
|
|
27332
27541
|
}
|
|
27333
27542
|
if (map.size === 0) return void 0;
|
|
27334
|
-
const [
|
|
27335
|
-
return { path:
|
|
27543
|
+
const [path42, count] = [...map.entries()].sort((a, b) => b[1] - a[1])[0];
|
|
27544
|
+
return { path: path42, count };
|
|
27336
27545
|
}
|
|
27337
27546
|
var EMPTY_FILTERED_SCAN;
|
|
27338
27547
|
var init_derive = __esm({
|