@node9/proxy 1.61.0 → 1.62.0
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 +1054 -634
- package/dist/cli.mjs +1048 -628
- package/dist/dashboard.mjs +20 -1
- package/dist/index.js +94 -2
- package/dist/index.mjs +94 -2
- package/dist/scan-ink.mjs +19 -0
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -248,8 +248,8 @@ function sanitizeConfig(raw) {
|
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
const lines = result.error.issues.map((issue) => {
|
|
251
|
-
const
|
|
252
|
-
return ` \u2022 ${
|
|
251
|
+
const path71 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
252
|
+
return ` \u2022 ${path71}: ${issue.message}`;
|
|
253
253
|
});
|
|
254
254
|
return {
|
|
255
255
|
sanitized,
|
|
@@ -983,6 +983,91 @@ function analyzeFsOperation(command) {
|
|
|
983
983
|
fsOpCache.set(normalized, computed);
|
|
984
984
|
return computed;
|
|
985
985
|
}
|
|
986
|
+
function isSensitiveCleanupName(p) {
|
|
987
|
+
const base = p.replace(/^.*[\\/]/, "");
|
|
988
|
+
return /^\.env(\.|$)/i.test(base) || /(?:^|[\\/])\.(?:ssh|aws|gnupg|git)(?:[\\/]|$)/i.test(p) || /\.(?:pem|key|p12|pfx|crt)$/i.test(base) || /^\.?(?:netrc|npmrc|pgpass|htpasswd)$/i.test(base) || /^id_(?:rsa|dsa|ecdsa|ed25519)/i.test(base) || /credential/i.test(p) || /secret/i.test(base);
|
|
989
|
+
}
|
|
990
|
+
function isWaivableCleanupTarget(p) {
|
|
991
|
+
if (/^[/~]/.test(p) || /^\$/.test(p)) return false;
|
|
992
|
+
if (/(?:^|[\\/])\.\.(?:[\\/]|$)/.test(p)) return false;
|
|
993
|
+
if (/[*?[{]/.test(p)) return false;
|
|
994
|
+
if (isSensitiveCleanupName(p)) return false;
|
|
995
|
+
return true;
|
|
996
|
+
}
|
|
997
|
+
function deriveRedirOp(sample) {
|
|
998
|
+
try {
|
|
999
|
+
const f = sharedParser.Parse(sample, "cmd");
|
|
1000
|
+
let op = -1;
|
|
1001
|
+
syntax.Walk(f, (node) => {
|
|
1002
|
+
const n = node;
|
|
1003
|
+
if (n && syntax.NodeType(n) === "Redirect" && op < 0) op = n.Op;
|
|
1004
|
+
return true;
|
|
1005
|
+
});
|
|
1006
|
+
return op;
|
|
1007
|
+
} catch {
|
|
1008
|
+
return -1;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
function collectSameCommandCreations(f) {
|
|
1012
|
+
const created = /* @__PURE__ */ new Set();
|
|
1013
|
+
try {
|
|
1014
|
+
const stmts = Array.isArray(f?.Stmts) ? f.Stmts : [];
|
|
1015
|
+
for (const stmt of stmts) {
|
|
1016
|
+
if (!stmt || !stmt.Cmd || syntax.NodeType(stmt.Cmd) !== "CallExpr") continue;
|
|
1017
|
+
const redirs = stmt.Redirs || [];
|
|
1018
|
+
if (!redirs.some((r) => r && REDIR_HEREDOC_OPS.has(r.Op))) continue;
|
|
1019
|
+
for (const r of redirs) {
|
|
1020
|
+
if (r && REDIR_TRUNCATE_OPS.has(r.Op) && r.N == null) {
|
|
1021
|
+
const w = resolveWordLiteral(r.Word);
|
|
1022
|
+
if (w) created.add(stripDotSlash(w));
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
} catch {
|
|
1027
|
+
return created;
|
|
1028
|
+
}
|
|
1029
|
+
return created;
|
|
1030
|
+
}
|
|
1031
|
+
function isRmCreatedInCommandCleanup(command) {
|
|
1032
|
+
if (!/\brm\b/.test(command)) return false;
|
|
1033
|
+
const f = parseShared(command);
|
|
1034
|
+
if (f === PARSE_FAIL) return false;
|
|
1035
|
+
const created = collectSameCommandCreations(f);
|
|
1036
|
+
if (created.size === 0) return false;
|
|
1037
|
+
let sawRm = false;
|
|
1038
|
+
let ok2 = true;
|
|
1039
|
+
try {
|
|
1040
|
+
syntax.Walk(f, (node) => {
|
|
1041
|
+
if (!node || !ok2) return false;
|
|
1042
|
+
const n = node;
|
|
1043
|
+
if (syntax.NodeType(n) !== "CallExpr") return true;
|
|
1044
|
+
const args = n.Args || [];
|
|
1045
|
+
const name = (resolveWordLiteral(args[0]) ?? "").toLowerCase();
|
|
1046
|
+
if (name !== "rm") return true;
|
|
1047
|
+
sawRm = true;
|
|
1048
|
+
const { flags, paths } = extractLiteralArgs(n);
|
|
1049
|
+
if (args.length - 1 > flags.length + paths.length) {
|
|
1050
|
+
ok2 = false;
|
|
1051
|
+
return false;
|
|
1052
|
+
}
|
|
1053
|
+
if (paths.length === 0) {
|
|
1054
|
+
ok2 = false;
|
|
1055
|
+
return false;
|
|
1056
|
+
}
|
|
1057
|
+
for (const p of paths) {
|
|
1058
|
+
const np = stripDotSlash(p);
|
|
1059
|
+
if (!created.has(np) || !isWaivableCleanupTarget(np)) {
|
|
1060
|
+
ok2 = false;
|
|
1061
|
+
return false;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
return true;
|
|
1065
|
+
});
|
|
1066
|
+
} catch {
|
|
1067
|
+
return false;
|
|
1068
|
+
}
|
|
1069
|
+
return sawRm && ok2;
|
|
1070
|
+
}
|
|
986
1071
|
function analyzeFsOperationImpl(command) {
|
|
987
1072
|
const f = parseShared(command);
|
|
988
1073
|
if (f === PARSE_FAIL) return null;
|
|
@@ -1379,9 +1464,9 @@ function matchesPattern(text, patterns) {
|
|
|
1379
1464
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
1380
1465
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
1381
1466
|
}
|
|
1382
|
-
function getNestedValue(obj,
|
|
1467
|
+
function getNestedValue(obj, path71) {
|
|
1383
1468
|
if (!obj || typeof obj !== "object") return null;
|
|
1384
|
-
const segments =
|
|
1469
|
+
const segments = path71.split(".");
|
|
1385
1470
|
for (const seg of segments) {
|
|
1386
1471
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
1387
1472
|
}
|
|
@@ -1553,8 +1638,9 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
1553
1638
|
}
|
|
1554
1639
|
}
|
|
1555
1640
|
if (config.policy.smartRules.length > 0) {
|
|
1641
|
+
const rmCleanupWaiver = bashCommand !== null && isRmCreatedInCommandCleanup(bashCommand);
|
|
1556
1642
|
const matches = config.policy.smartRules.filter(
|
|
1557
|
-
(rule) => matchesPattern(toolName, rule.tool) && !(bashCommand !== null && rule.name && AST_FS_REGEX_RULES.has(rule.name)) && evaluateSmartConditions(args, rule)
|
|
1643
|
+
(rule) => matchesPattern(toolName, rule.tool) && !(bashCommand !== null && rule.name && AST_FS_REGEX_RULES.has(rule.name)) && !(rmCleanupWaiver && rule.name === "review-rm" && rule.verdict === "review") && evaluateSmartConditions(args, rule)
|
|
1558
1644
|
);
|
|
1559
1645
|
const matchedRule = resolvePinned(matches);
|
|
1560
1646
|
if (matchedRule) {
|
|
@@ -2295,7 +2381,7 @@ function* stringValues(obj, depth = 0) {
|
|
|
2295
2381
|
}
|
|
2296
2382
|
for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
|
|
2297
2383
|
}
|
|
2298
|
-
var MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, VERDICT_RANK, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, COST_PER_LOOP_ITER_USD, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE, ENGINE_VERSION;
|
|
2384
|
+
var MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_HEREDOC_OPS, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, VERDICT_RANK, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, COST_PER_LOOP_ITER_USD, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE, ENGINE_VERSION;
|
|
2299
2385
|
var init_dist = __esm({
|
|
2300
2386
|
"packages/policy-engine/dist/index.mjs"() {
|
|
2301
2387
|
"use strict";
|
|
@@ -2966,7 +3052,7 @@ var init_dist = __esm({
|
|
|
2966
3052
|
"mongosh"
|
|
2967
3053
|
]);
|
|
2968
3054
|
SQL_DDL_RE = /\b(DROP|TRUNCATE)\s+(TABLE|DATABASE|SCHEMA|INDEX)\b/i;
|
|
2969
|
-
CHMOD_OPEN_PERM_TOKENS = /* @__PURE__ */ new Set(["777", "0777", "a+rwx"
|
|
3055
|
+
CHMOD_OPEN_PERM_TOKENS = /* @__PURE__ */ new Set(["777", "0777", "a+rwx"]);
|
|
2970
3056
|
COMMAND_WRAPPERS = /* @__PURE__ */ new Set([
|
|
2971
3057
|
"sudo",
|
|
2972
3058
|
"doas",
|
|
@@ -3069,6 +3155,12 @@ var init_dist = __esm({
|
|
|
3069
3155
|
};
|
|
3070
3156
|
FS_OP_CACHE_MAX = 5e3;
|
|
3071
3157
|
fsOpCache = /* @__PURE__ */ new Map();
|
|
3158
|
+
stripDotSlash = (p) => p.replace(/^\.\//, "");
|
|
3159
|
+
REDIR_TRUNCATE_OPS = /* @__PURE__ */ new Set([deriveRedirOp(">_f")]);
|
|
3160
|
+
REDIR_HEREDOC_OPS = /* @__PURE__ */ new Set([
|
|
3161
|
+
deriveRedirOp("cat <<X\nX"),
|
|
3162
|
+
deriveRedirOp("cat <<-X\nX")
|
|
3163
|
+
]);
|
|
3072
3164
|
DEFAULT_EGRESS_ALLOWLIST = [
|
|
3073
3165
|
"*.github.com",
|
|
3074
3166
|
"*.githubusercontent.com",
|
|
@@ -4757,10 +4849,10 @@ function getConfig(cwd) {
|
|
|
4757
4849
|
}
|
|
4758
4850
|
if (Array.isArray(mc.jailPaths)) {
|
|
4759
4851
|
for (const jp of mc.jailPaths) {
|
|
4760
|
-
const
|
|
4761
|
-
if (!
|
|
4852
|
+
const path71 = typeof jp?.path === "string" ? jp.path.trim() : "";
|
|
4853
|
+
if (!path71) continue;
|
|
4762
4854
|
const verdict = jp?.verdict === "review" ? "review" : "block";
|
|
4763
|
-
for (const r of pathRules(
|
|
4855
|
+
for (const r of pathRules(path71, verdict, "org-managed jail")) {
|
|
4764
4856
|
mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
|
|
4765
4857
|
}
|
|
4766
4858
|
}
|
|
@@ -17871,6 +17963,66 @@ function pickSyncIntervalMs(cloudHours, localSettings) {
|
|
|
17871
17963
|
function effectiveSyncIntervalMs() {
|
|
17872
17964
|
return pickSyncIntervalMs(readCachedSyncIntervalHours(), getConfig().settings);
|
|
17873
17965
|
}
|
|
17966
|
+
function readSyncHealth() {
|
|
17967
|
+
try {
|
|
17968
|
+
const raw = JSON.parse(fs36.readFileSync(syncHealthFile(), "utf-8"));
|
|
17969
|
+
return {
|
|
17970
|
+
lastCheckedAt: typeof raw.lastCheckedAt === "string" ? raw.lastCheckedAt : void 0,
|
|
17971
|
+
lastChangedAt: typeof raw.lastChangedAt === "string" ? raw.lastChangedAt : void 0,
|
|
17972
|
+
lastError: typeof raw.lastError === "string" ? raw.lastError : void 0,
|
|
17973
|
+
lastErrorAt: typeof raw.lastErrorAt === "string" ? raw.lastErrorAt : void 0,
|
|
17974
|
+
consecutiveFailures: typeof raw.consecutiveFailures === "number" && raw.consecutiveFailures >= 0 ? raw.consecutiveFailures : 0
|
|
17975
|
+
};
|
|
17976
|
+
} catch {
|
|
17977
|
+
return { consecutiveFailures: 0 };
|
|
17978
|
+
}
|
|
17979
|
+
}
|
|
17980
|
+
function writeSyncHealth(h) {
|
|
17981
|
+
try {
|
|
17982
|
+
const file = syncHealthFile();
|
|
17983
|
+
const dir = path35.dirname(file);
|
|
17984
|
+
if (!fs36.existsSync(dir)) fs36.mkdirSync(dir, { recursive: true });
|
|
17985
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
17986
|
+
fs36.writeFileSync(tmp, JSON.stringify(h, null, 2) + "\n", "utf-8");
|
|
17987
|
+
fs36.renameSync(tmp, file);
|
|
17988
|
+
} catch {
|
|
17989
|
+
}
|
|
17990
|
+
}
|
|
17991
|
+
function readCacheFetchedAt() {
|
|
17992
|
+
try {
|
|
17993
|
+
const raw = JSON.parse(fs36.readFileSync(rulesCacheFile(), "utf-8"));
|
|
17994
|
+
return typeof raw.fetchedAt === "string" ? raw.fetchedAt : void 0;
|
|
17995
|
+
} catch {
|
|
17996
|
+
return void 0;
|
|
17997
|
+
}
|
|
17998
|
+
}
|
|
17999
|
+
function recordSyncHealth(result) {
|
|
18000
|
+
const h = readSyncHealth();
|
|
18001
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
18002
|
+
if (result.ok) {
|
|
18003
|
+
h.lastCheckedAt = now;
|
|
18004
|
+
if (result.changed) h.lastChangedAt = now;
|
|
18005
|
+
h.consecutiveFailures = 0;
|
|
18006
|
+
h.lastError = void 0;
|
|
18007
|
+
h.lastErrorAt = void 0;
|
|
18008
|
+
} else {
|
|
18009
|
+
h.consecutiveFailures += 1;
|
|
18010
|
+
h.lastError = result.error;
|
|
18011
|
+
h.lastErrorAt = now;
|
|
18012
|
+
}
|
|
18013
|
+
writeSyncHealth(h);
|
|
18014
|
+
}
|
|
18015
|
+
function stalenessThresholdMs(intervalMs) {
|
|
18016
|
+
return Math.min(STALE_MAX_MS, Math.max(STALE_MIN_MS, intervalMs * STALE_FACTOR));
|
|
18017
|
+
}
|
|
18018
|
+
function isPolicyStale(nowMs = Date.now(), health) {
|
|
18019
|
+
const h = health ?? readSyncHealth();
|
|
18020
|
+
const lastKnownGood = h.lastCheckedAt ?? readCacheFetchedAt();
|
|
18021
|
+
if (!lastKnownGood) return false;
|
|
18022
|
+
const last = Date.parse(lastKnownGood);
|
|
18023
|
+
if (Number.isNaN(last)) return false;
|
|
18024
|
+
return nowMs - last > stalenessThresholdMs(effectiveSyncIntervalMs());
|
|
18025
|
+
}
|
|
17874
18026
|
function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
|
|
17875
18027
|
const parsed = new URL(apiUrl);
|
|
17876
18028
|
const headers = {
|
|
@@ -18035,6 +18187,7 @@ async function syncOnce() {
|
|
|
18035
18187
|
try {
|
|
18036
18188
|
const result = await fetchCloudPolicy(creds.apiKey, creds.apiUrl, readCachedEtag());
|
|
18037
18189
|
if (result.kind === "unchanged") {
|
|
18190
|
+
recordSyncHealth({ ok: true });
|
|
18038
18191
|
} else {
|
|
18039
18192
|
const cache = {
|
|
18040
18193
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -18048,8 +18201,19 @@ async function syncOnce() {
|
|
|
18048
18201
|
managedConfig: extractManagedConfig(result.body)
|
|
18049
18202
|
};
|
|
18050
18203
|
writeCache2(cache);
|
|
18204
|
+
recordSyncHealth({ ok: true, changed: true });
|
|
18205
|
+
}
|
|
18206
|
+
} catch (err2) {
|
|
18207
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
18208
|
+
recordSyncHealth({ ok: false, error: msg });
|
|
18209
|
+
try {
|
|
18210
|
+
appendToLog(HOOK_DEBUG_LOG, {
|
|
18211
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18212
|
+
kind: "policy-sync-error",
|
|
18213
|
+
error: msg
|
|
18214
|
+
});
|
|
18215
|
+
} catch {
|
|
18051
18216
|
}
|
|
18052
|
-
} catch {
|
|
18053
18217
|
}
|
|
18054
18218
|
if (process.env.NODE9_BLAST_DISABLE !== "1") {
|
|
18055
18219
|
void pushBlastSnapshot(creds);
|
|
@@ -18225,6 +18389,7 @@ async function runCloudSync() {
|
|
|
18225
18389
|
const result = await fetchCloudPolicy(creds.apiKey, creds.apiUrl, readCachedEtag());
|
|
18226
18390
|
if (result.kind === "unchanged") {
|
|
18227
18391
|
const status = getCloudSyncStatus();
|
|
18392
|
+
recordSyncHealth({ ok: true });
|
|
18228
18393
|
maybePushBlast();
|
|
18229
18394
|
return status.cached ? { ok: true, rules: status.rules, fetchedAt: status.fetchedAt, unchanged: true } : { ok: true, rules: 0, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), unchanged: true };
|
|
18230
18395
|
}
|
|
@@ -18240,11 +18405,14 @@ async function runCloudSync() {
|
|
|
18240
18405
|
managedConfig: extractManagedConfig(result.body)
|
|
18241
18406
|
};
|
|
18242
18407
|
writeCache2(cache);
|
|
18408
|
+
recordSyncHealth({ ok: true, changed: true });
|
|
18243
18409
|
maybePushBlast();
|
|
18244
18410
|
return { ok: true, rules: cache.rules.length, fetchedAt: cache.fetchedAt };
|
|
18245
18411
|
} catch (err2) {
|
|
18412
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
18413
|
+
recordSyncHealth({ ok: false, error: msg });
|
|
18246
18414
|
maybePushBlast();
|
|
18247
|
-
return { ok: false, reason:
|
|
18415
|
+
return { ok: false, reason: msg };
|
|
18248
18416
|
}
|
|
18249
18417
|
}
|
|
18250
18418
|
function getCloudSyncStatus() {
|
|
@@ -18301,7 +18469,7 @@ function startForensicBroadcast() {
|
|
|
18301
18469
|
const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
|
|
18302
18470
|
recurring.unref();
|
|
18303
18471
|
}
|
|
18304
|
-
var FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL2, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
|
|
18472
|
+
var FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL2, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, syncHealthFile, STALE_MIN_MS, STALE_MAX_MS, STALE_FACTOR, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
|
|
18305
18473
|
var init_sync = __esm({
|
|
18306
18474
|
"src/daemon/sync.ts"() {
|
|
18307
18475
|
"use strict";
|
|
@@ -18335,6 +18503,10 @@ var init_sync = __esm({
|
|
|
18335
18503
|
DEFAULT_INTERVAL_HOURS = 5;
|
|
18336
18504
|
MIN_INTERVAL_SECONDS = 15;
|
|
18337
18505
|
MAX_INTERVAL_SECONDS = 24 * 60 * 60;
|
|
18506
|
+
syncHealthFile = () => path35.join(os33.homedir(), ".node9", "sync-health.json");
|
|
18507
|
+
STALE_MIN_MS = 3 * 60 * 60 * 1e3;
|
|
18508
|
+
STALE_MAX_MS = 24 * 60 * 60 * 1e3;
|
|
18509
|
+
STALE_FACTOR = 3;
|
|
18338
18510
|
FORENSIC_BROADCAST_INTERVAL_MS = 3e4;
|
|
18339
18511
|
FORENSIC_INITIAL_DELAY_MS = 5e3;
|
|
18340
18512
|
forensicBroadcastOffsets = /* @__PURE__ */ new Map();
|
|
@@ -18949,23 +19121,68 @@ var init_hook_heal = __esm({
|
|
|
18949
19121
|
}
|
|
18950
19122
|
});
|
|
18951
19123
|
|
|
18952
|
-
// src/daemon/
|
|
18953
|
-
import http3 from "http";
|
|
19124
|
+
// src/daemon/startup-log.ts
|
|
18954
19125
|
import fs40 from "fs";
|
|
18955
19126
|
import path39 from "path";
|
|
18956
19127
|
import os37 from "os";
|
|
19128
|
+
function openStartupLogFd() {
|
|
19129
|
+
try {
|
|
19130
|
+
const file = DAEMON_STARTUP_LOG();
|
|
19131
|
+
const dir = path39.dirname(file);
|
|
19132
|
+
if (!fs40.existsSync(dir)) fs40.mkdirSync(dir, { recursive: true });
|
|
19133
|
+
try {
|
|
19134
|
+
if (fs40.statSync(file).size > MAX_STARTUP_LOG_BYTES) fs40.truncateSync(file);
|
|
19135
|
+
} catch {
|
|
19136
|
+
}
|
|
19137
|
+
return fs40.openSync(file, "a");
|
|
19138
|
+
} catch {
|
|
19139
|
+
return void 0;
|
|
19140
|
+
}
|
|
19141
|
+
}
|
|
19142
|
+
function logDaemonStartup(kind, detail) {
|
|
19143
|
+
try {
|
|
19144
|
+
const file = DAEMON_STARTUP_LOG();
|
|
19145
|
+
const dir = path39.dirname(file);
|
|
19146
|
+
if (!fs40.existsSync(dir)) fs40.mkdirSync(dir, { recursive: true });
|
|
19147
|
+
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-startup:${kind}${detail ? ` ${detail}` : ""}
|
|
19148
|
+
`;
|
|
19149
|
+
fs40.appendFileSync(file, line, "utf-8");
|
|
19150
|
+
} catch {
|
|
19151
|
+
}
|
|
19152
|
+
}
|
|
19153
|
+
var DAEMON_STARTUP_LOG, MAX_STARTUP_LOG_BYTES;
|
|
19154
|
+
var init_startup_log = __esm({
|
|
19155
|
+
"src/daemon/startup-log.ts"() {
|
|
19156
|
+
"use strict";
|
|
19157
|
+
DAEMON_STARTUP_LOG = () => path39.join(os37.homedir(), ".node9", "daemon-startup.log");
|
|
19158
|
+
MAX_STARTUP_LOG_BYTES = 256 * 1024;
|
|
19159
|
+
}
|
|
19160
|
+
});
|
|
19161
|
+
|
|
19162
|
+
// src/daemon/server.ts
|
|
19163
|
+
import http3 from "http";
|
|
19164
|
+
import fs41 from "fs";
|
|
19165
|
+
import path40 from "path";
|
|
19166
|
+
import os38 from "os";
|
|
18957
19167
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
18958
19168
|
import { spawnSync } from "child_process";
|
|
18959
19169
|
import chalk6 from "chalk";
|
|
18960
19170
|
function startDaemon() {
|
|
18961
|
-
|
|
18962
|
-
|
|
18963
|
-
|
|
18964
|
-
|
|
18965
|
-
|
|
18966
|
-
|
|
18967
|
-
|
|
18968
|
-
|
|
19171
|
+
try {
|
|
19172
|
+
startCostSync();
|
|
19173
|
+
startCloudSync();
|
|
19174
|
+
startForensicBroadcast();
|
|
19175
|
+
startAuditShipper();
|
|
19176
|
+
startDlpScanner();
|
|
19177
|
+
startMcpReconciler();
|
|
19178
|
+
startHookHeal();
|
|
19179
|
+
loadInsightCounts();
|
|
19180
|
+
} catch (err2) {
|
|
19181
|
+
const stack = err2 instanceof Error ? err2.stack ?? err2.message : String(err2);
|
|
19182
|
+
console.error("\n\u{1F6D1} Node9 daemon startup failed:\n" + stack);
|
|
19183
|
+
logDaemonStartup("startup-throw", err2 instanceof Error ? err2.message : String(err2));
|
|
19184
|
+
process.exit(1);
|
|
19185
|
+
}
|
|
18969
19186
|
const internalToken = randomUUID4();
|
|
18970
19187
|
const validToken = (req) => req.headers["x-node9-internal"] === internalToken || req.headers["x-node9-token"] === internalToken;
|
|
18971
19188
|
const IDLE_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
|
|
@@ -18977,7 +19194,7 @@ function startDaemon() {
|
|
|
18977
19194
|
idleTimer = setTimeout(() => {
|
|
18978
19195
|
if (autoStarted) {
|
|
18979
19196
|
try {
|
|
18980
|
-
|
|
19197
|
+
fs41.unlinkSync(DAEMON_PID_FILE);
|
|
18981
19198
|
} catch {
|
|
18982
19199
|
}
|
|
18983
19200
|
}
|
|
@@ -19122,7 +19339,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
19122
19339
|
mcpServer: entry.mcpServer
|
|
19123
19340
|
});
|
|
19124
19341
|
}
|
|
19125
|
-
const projectCwd = typeof cwd === "string" &&
|
|
19342
|
+
const projectCwd = typeof cwd === "string" && path40.isAbsolute(cwd) ? cwd : void 0;
|
|
19126
19343
|
const projectConfig = getConfig(projectCwd);
|
|
19127
19344
|
const browserEnabled = projectConfig.settings.approvers?.browser !== false;
|
|
19128
19345
|
const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
|
|
@@ -19414,8 +19631,8 @@ data: ${JSON.stringify(item.data)}
|
|
|
19414
19631
|
if (!validToken(req)) return res.writeHead(403).end();
|
|
19415
19632
|
const periodParam = reqUrl.searchParams.get("period") || "7d";
|
|
19416
19633
|
const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
|
|
19417
|
-
const logPath =
|
|
19418
|
-
if (!
|
|
19634
|
+
const logPath = path40.join(os38.homedir(), ".node9", "audit.log");
|
|
19635
|
+
if (!fs41.existsSync(logPath)) {
|
|
19419
19636
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
19420
19637
|
return res.end(
|
|
19421
19638
|
JSON.stringify({
|
|
@@ -19428,7 +19645,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
19428
19645
|
);
|
|
19429
19646
|
}
|
|
19430
19647
|
try {
|
|
19431
|
-
const raw =
|
|
19648
|
+
const raw = fs41.readFileSync(logPath, "utf-8");
|
|
19432
19649
|
const allEntries = raw.split("\n").flatMap((line) => {
|
|
19433
19650
|
if (!line.trim()) return [];
|
|
19434
19651
|
try {
|
|
@@ -19811,14 +20028,15 @@ data: ${JSON.stringify(item.data)}
|
|
|
19811
20028
|
server.on("error", (e) => {
|
|
19812
20029
|
if (e.code === "EADDRINUSE") {
|
|
19813
20030
|
try {
|
|
19814
|
-
if (
|
|
19815
|
-
const { pid } = JSON.parse(
|
|
20031
|
+
if (fs41.existsSync(DAEMON_PID_FILE)) {
|
|
20032
|
+
const { pid } = JSON.parse(fs41.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
19816
20033
|
process.kill(pid, 0);
|
|
20034
|
+
logDaemonStartup("port-in-use", `another daemon (pid ${pid}) owns :${DAEMON_PORT}`);
|
|
19817
20035
|
return process.exit(0);
|
|
19818
20036
|
}
|
|
19819
20037
|
} catch {
|
|
19820
20038
|
try {
|
|
19821
|
-
|
|
20039
|
+
fs41.unlinkSync(DAEMON_PID_FILE);
|
|
19822
20040
|
} catch {
|
|
19823
20041
|
}
|
|
19824
20042
|
server.listen(DAEMON_PORT, DAEMON_HOST);
|
|
@@ -19867,6 +20085,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
19867
20085
|
});
|
|
19868
20086
|
return;
|
|
19869
20087
|
}
|
|
20088
|
+
logDaemonStartup("bind-failed", e.message);
|
|
19870
20089
|
console.error(chalk6.red("\n\u{1F6D1} Node9 Daemon Error:"), e.message);
|
|
19871
20090
|
process.exit(1);
|
|
19872
20091
|
});
|
|
@@ -19904,20 +20123,21 @@ var init_server = __esm({
|
|
|
19904
20123
|
init_dlp_scanner();
|
|
19905
20124
|
init_mcp_reconciler();
|
|
19906
20125
|
init_hook_heal();
|
|
20126
|
+
init_startup_log();
|
|
19907
20127
|
init_mcp_tools();
|
|
19908
20128
|
}
|
|
19909
20129
|
});
|
|
19910
20130
|
|
|
19911
20131
|
// src/daemon/service.ts
|
|
19912
|
-
import
|
|
19913
|
-
import
|
|
19914
|
-
import
|
|
20132
|
+
import fs42 from "fs";
|
|
20133
|
+
import path41 from "path";
|
|
20134
|
+
import os39 from "os";
|
|
19915
20135
|
import { spawnSync as spawnSync2, execFileSync } from "child_process";
|
|
19916
20136
|
function resolveNode9Binary() {
|
|
19917
20137
|
try {
|
|
19918
20138
|
const script = process.argv[1];
|
|
19919
|
-
if (typeof script === "string" &&
|
|
19920
|
-
return
|
|
20139
|
+
if (typeof script === "string" && path41.isAbsolute(script) && fs42.existsSync(script)) {
|
|
20140
|
+
return fs42.realpathSync(script);
|
|
19921
20141
|
}
|
|
19922
20142
|
} catch {
|
|
19923
20143
|
}
|
|
@@ -19935,11 +20155,11 @@ function xmlEscape(s) {
|
|
|
19935
20155
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
19936
20156
|
}
|
|
19937
20157
|
function launchdPlist(binaryPath) {
|
|
19938
|
-
const logDir =
|
|
20158
|
+
const logDir = path41.join(os39.homedir(), ".node9");
|
|
19939
20159
|
const nodePath = xmlEscape(process.execPath);
|
|
19940
20160
|
const scriptPath = xmlEscape(binaryPath);
|
|
19941
|
-
const outLog = xmlEscape(
|
|
19942
|
-
const errLog = xmlEscape(
|
|
20161
|
+
const outLog = xmlEscape(path41.join(logDir, "daemon.log"));
|
|
20162
|
+
const errLog = xmlEscape(path41.join(logDir, "daemon-error.log"));
|
|
19943
20163
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
19944
20164
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
19945
20165
|
<plist version="1.0">
|
|
@@ -19972,9 +20192,9 @@ function launchdPlist(binaryPath) {
|
|
|
19972
20192
|
`;
|
|
19973
20193
|
}
|
|
19974
20194
|
function installLaunchd(binaryPath) {
|
|
19975
|
-
const dir =
|
|
19976
|
-
if (!
|
|
19977
|
-
|
|
20195
|
+
const dir = path41.dirname(LAUNCHD_PLIST);
|
|
20196
|
+
if (!fs42.existsSync(dir)) fs42.mkdirSync(dir, { recursive: true });
|
|
20197
|
+
fs42.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
|
|
19978
20198
|
spawnSync2("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
|
|
19979
20199
|
const r = spawnSync2("launchctl", ["load", "-w", LAUNCHD_PLIST], {
|
|
19980
20200
|
encoding: "utf8",
|
|
@@ -19985,13 +20205,13 @@ function installLaunchd(binaryPath) {
|
|
|
19985
20205
|
}
|
|
19986
20206
|
}
|
|
19987
20207
|
function uninstallLaunchd() {
|
|
19988
|
-
if (
|
|
20208
|
+
if (fs42.existsSync(LAUNCHD_PLIST)) {
|
|
19989
20209
|
spawnSync2("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
|
|
19990
|
-
|
|
20210
|
+
fs42.unlinkSync(LAUNCHD_PLIST);
|
|
19991
20211
|
}
|
|
19992
20212
|
}
|
|
19993
20213
|
function isLaunchdInstalled() {
|
|
19994
|
-
return
|
|
20214
|
+
return fs42.existsSync(LAUNCHD_PLIST);
|
|
19995
20215
|
}
|
|
19996
20216
|
function systemdUnit(binaryPath) {
|
|
19997
20217
|
return `[Unit]
|
|
@@ -20010,12 +20230,12 @@ WantedBy=default.target
|
|
|
20010
20230
|
`;
|
|
20011
20231
|
}
|
|
20012
20232
|
function installSystemd(binaryPath) {
|
|
20013
|
-
if (!
|
|
20014
|
-
|
|
20233
|
+
if (!fs42.existsSync(SYSTEMD_UNIT_DIR)) {
|
|
20234
|
+
fs42.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
|
|
20015
20235
|
}
|
|
20016
|
-
|
|
20236
|
+
fs42.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
|
|
20017
20237
|
try {
|
|
20018
|
-
execFileSync("loginctl", ["enable-linger",
|
|
20238
|
+
execFileSync("loginctl", ["enable-linger", os39.userInfo().username], { timeout: 3e3 });
|
|
20019
20239
|
} catch {
|
|
20020
20240
|
}
|
|
20021
20241
|
const reload = spawnSync2("systemctl", ["--user", "daemon-reload"], {
|
|
@@ -20035,23 +20255,23 @@ function installSystemd(binaryPath) {
|
|
|
20035
20255
|
}
|
|
20036
20256
|
}
|
|
20037
20257
|
function uninstallSystemd() {
|
|
20038
|
-
if (
|
|
20258
|
+
if (fs42.existsSync(SYSTEMD_UNIT)) {
|
|
20039
20259
|
spawnSync2("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
|
|
20040
20260
|
encoding: "utf8",
|
|
20041
20261
|
timeout: 5e3
|
|
20042
20262
|
});
|
|
20043
20263
|
spawnSync2("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
|
|
20044
|
-
|
|
20264
|
+
fs42.unlinkSync(SYSTEMD_UNIT);
|
|
20045
20265
|
}
|
|
20046
20266
|
}
|
|
20047
20267
|
function isSystemdInstalled() {
|
|
20048
|
-
return
|
|
20268
|
+
return fs42.existsSync(SYSTEMD_UNIT);
|
|
20049
20269
|
}
|
|
20050
20270
|
function stopRunningDaemon() {
|
|
20051
|
-
const pidFile =
|
|
20052
|
-
if (!
|
|
20271
|
+
const pidFile = path41.join(os39.homedir(), ".node9", "daemon.pid");
|
|
20272
|
+
if (!fs42.existsSync(pidFile)) return;
|
|
20053
20273
|
try {
|
|
20054
|
-
const data = JSON.parse(
|
|
20274
|
+
const data = JSON.parse(fs42.readFileSync(pidFile, "utf-8"));
|
|
20055
20275
|
const pid = data.pid;
|
|
20056
20276
|
const MAX_PID2 = 4194304;
|
|
20057
20277
|
if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
|
|
@@ -20071,7 +20291,7 @@ function stopRunningDaemon() {
|
|
|
20071
20291
|
}
|
|
20072
20292
|
}
|
|
20073
20293
|
try {
|
|
20074
|
-
|
|
20294
|
+
fs42.unlinkSync(pidFile);
|
|
20075
20295
|
} catch {
|
|
20076
20296
|
}
|
|
20077
20297
|
} catch {
|
|
@@ -20141,24 +20361,93 @@ function isDaemonServiceInstalled() {
|
|
|
20141
20361
|
if (process.platform === "linux") return isSystemdInstalled();
|
|
20142
20362
|
return false;
|
|
20143
20363
|
}
|
|
20364
|
+
function autostartRepairDecision(opts) {
|
|
20365
|
+
if (!opts.autoStartDaemon) return "skip";
|
|
20366
|
+
if (process.platform !== "linux" && process.platform !== "darwin") return "unsupported";
|
|
20367
|
+
if (!opts.installed) return "skip";
|
|
20368
|
+
return opts.enabled ? "ok" : "repair";
|
|
20369
|
+
}
|
|
20370
|
+
function enableDaemonServiceQuiet() {
|
|
20371
|
+
try {
|
|
20372
|
+
if (process.platform === "linux") {
|
|
20373
|
+
const r = spawnSync2("systemctl", ["--user", "enable", "node9-daemon"], {
|
|
20374
|
+
encoding: "utf8",
|
|
20375
|
+
timeout: 3e3
|
|
20376
|
+
});
|
|
20377
|
+
return r.status === 0;
|
|
20378
|
+
}
|
|
20379
|
+
return process.platform === "darwin";
|
|
20380
|
+
} catch {
|
|
20381
|
+
return false;
|
|
20382
|
+
}
|
|
20383
|
+
}
|
|
20384
|
+
function ensureAutostartHealthy(autoStartDaemon) {
|
|
20385
|
+
const decision = autostartRepairDecision({
|
|
20386
|
+
installed: isDaemonServiceInstalled(),
|
|
20387
|
+
enabled: isDaemonServiceEnabled(),
|
|
20388
|
+
autoStartDaemon
|
|
20389
|
+
});
|
|
20390
|
+
if (decision === "repair") return enableDaemonServiceQuiet() ? "repaired" : "skipped";
|
|
20391
|
+
return decision === "ok" ? "ok" : decision === "unsupported" ? "unsupported" : "skipped";
|
|
20392
|
+
}
|
|
20393
|
+
function autostartAdvice(opts) {
|
|
20394
|
+
const installable = process.platform === "linux" || process.platform === "darwin";
|
|
20395
|
+
if (!opts.cloudEnabled || !installable) return null;
|
|
20396
|
+
const installHint = process.platform === "linux" ? "Run: systemctl --user enable --now node9-daemon (or: node9 daemon install)" : "Run: node9 daemon install";
|
|
20397
|
+
if (opts.installed && !opts.enabled) {
|
|
20398
|
+
return {
|
|
20399
|
+
level: "warn",
|
|
20400
|
+
message: "Daemon autostart is INSTALLED but DISABLED \u2014 it will NOT survive a reboot, so cloud policy can silently go stale.",
|
|
20401
|
+
hint: installHint
|
|
20402
|
+
};
|
|
20403
|
+
}
|
|
20404
|
+
if (!opts.installed) {
|
|
20405
|
+
return {
|
|
20406
|
+
level: "warn",
|
|
20407
|
+
message: "No daemon autostart installed \u2014 the daemon only runs when an agent happens to spawn it; cloud policy may lag.",
|
|
20408
|
+
hint: installHint
|
|
20409
|
+
};
|
|
20410
|
+
}
|
|
20411
|
+
return null;
|
|
20412
|
+
}
|
|
20413
|
+
function isDaemonServiceEnabled() {
|
|
20414
|
+
try {
|
|
20415
|
+
if (process.platform === "linux") {
|
|
20416
|
+
const r = spawnSync2("systemctl", ["--user", "is-enabled", "node9-daemon"], {
|
|
20417
|
+
encoding: "utf8",
|
|
20418
|
+
timeout: 3e3
|
|
20419
|
+
});
|
|
20420
|
+
return r.status === 0 && (r.stdout ?? "").trim() === "enabled";
|
|
20421
|
+
}
|
|
20422
|
+
if (process.platform === "darwin") {
|
|
20423
|
+
const r = spawnSync2("launchctl", ["list", LAUNCHD_LABEL], {
|
|
20424
|
+
encoding: "utf8",
|
|
20425
|
+
timeout: 3e3
|
|
20426
|
+
});
|
|
20427
|
+
return r.status === 0;
|
|
20428
|
+
}
|
|
20429
|
+
} catch {
|
|
20430
|
+
}
|
|
20431
|
+
return false;
|
|
20432
|
+
}
|
|
20144
20433
|
var LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
|
|
20145
20434
|
var init_service = __esm({
|
|
20146
20435
|
"src/daemon/service.ts"() {
|
|
20147
20436
|
"use strict";
|
|
20148
20437
|
LAUNCHD_LABEL = "ai.node9.daemon";
|
|
20149
|
-
LAUNCHD_PLIST =
|
|
20150
|
-
SYSTEMD_UNIT_DIR =
|
|
20151
|
-
SYSTEMD_UNIT =
|
|
20438
|
+
LAUNCHD_PLIST = path41.join(os39.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
20439
|
+
SYSTEMD_UNIT_DIR = path41.join(os39.homedir(), ".config", "systemd", "user");
|
|
20440
|
+
SYSTEMD_UNIT = path41.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
|
|
20152
20441
|
}
|
|
20153
20442
|
});
|
|
20154
20443
|
|
|
20155
20444
|
// src/daemon/index.ts
|
|
20156
|
-
import
|
|
20445
|
+
import fs43 from "fs";
|
|
20157
20446
|
import chalk7 from "chalk";
|
|
20158
20447
|
function stopDaemon() {
|
|
20159
|
-
if (!
|
|
20448
|
+
if (!fs43.existsSync(DAEMON_PID_FILE)) return console.log(chalk7.yellow("Not running."));
|
|
20160
20449
|
try {
|
|
20161
|
-
const data = JSON.parse(
|
|
20450
|
+
const data = JSON.parse(fs43.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
20162
20451
|
const pid = data.pid;
|
|
20163
20452
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
20164
20453
|
console.log(chalk7.gray("Cleaned up invalid PID file."));
|
|
@@ -20170,7 +20459,7 @@ function stopDaemon() {
|
|
|
20170
20459
|
console.log(chalk7.gray("Cleaned up stale PID file."));
|
|
20171
20460
|
} finally {
|
|
20172
20461
|
try {
|
|
20173
|
-
|
|
20462
|
+
fs43.unlinkSync(DAEMON_PID_FILE);
|
|
20174
20463
|
} catch {
|
|
20175
20464
|
}
|
|
20176
20465
|
}
|
|
@@ -20179,9 +20468,9 @@ function daemonStatus() {
|
|
|
20179
20468
|
const serviceInstalled = isDaemonServiceInstalled();
|
|
20180
20469
|
const serviceLabel = serviceInstalled ? chalk7.green("installed (starts on login)") : chalk7.yellow("not installed \u2014 run: node9 daemon install");
|
|
20181
20470
|
let processStatus;
|
|
20182
|
-
if (
|
|
20471
|
+
if (fs43.existsSync(DAEMON_PID_FILE)) {
|
|
20183
20472
|
try {
|
|
20184
|
-
const data = JSON.parse(
|
|
20473
|
+
const data = JSON.parse(fs43.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
20185
20474
|
const pid = data.pid;
|
|
20186
20475
|
const port = data.port;
|
|
20187
20476
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
@@ -21324,14 +21613,14 @@ var require_util = __commonJS({
|
|
|
21324
21613
|
}
|
|
21325
21614
|
const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
|
|
21326
21615
|
let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
|
|
21327
|
-
let
|
|
21616
|
+
let path71 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
|
|
21328
21617
|
if (origin[origin.length - 1] === "/") {
|
|
21329
21618
|
origin = origin.slice(0, origin.length - 1);
|
|
21330
21619
|
}
|
|
21331
|
-
if (
|
|
21332
|
-
|
|
21620
|
+
if (path71 && path71[0] !== "/") {
|
|
21621
|
+
path71 = `/${path71}`;
|
|
21333
21622
|
}
|
|
21334
|
-
return new URL(`${origin}${
|
|
21623
|
+
return new URL(`${origin}${path71}`);
|
|
21335
21624
|
}
|
|
21336
21625
|
if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
|
|
21337
21626
|
throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
|
|
@@ -22152,9 +22441,9 @@ var require_diagnostics = __commonJS({
|
|
|
22152
22441
|
"undici:client:sendHeaders",
|
|
22153
22442
|
(evt) => {
|
|
22154
22443
|
const {
|
|
22155
|
-
request: { method, path:
|
|
22444
|
+
request: { method, path: path71, origin }
|
|
22156
22445
|
} = evt;
|
|
22157
|
-
debugLog("sending request to %s %s%s", method, origin,
|
|
22446
|
+
debugLog("sending request to %s %s%s", method, origin, path71);
|
|
22158
22447
|
}
|
|
22159
22448
|
);
|
|
22160
22449
|
}
|
|
@@ -22172,14 +22461,14 @@ var require_diagnostics = __commonJS({
|
|
|
22172
22461
|
"undici:request:headers",
|
|
22173
22462
|
(evt) => {
|
|
22174
22463
|
const {
|
|
22175
|
-
request: { method, path:
|
|
22464
|
+
request: { method, path: path71, origin },
|
|
22176
22465
|
response: { statusCode }
|
|
22177
22466
|
} = evt;
|
|
22178
22467
|
debugLog(
|
|
22179
22468
|
"received response to %s %s%s - HTTP %d",
|
|
22180
22469
|
method,
|
|
22181
22470
|
origin,
|
|
22182
|
-
|
|
22471
|
+
path71,
|
|
22183
22472
|
statusCode
|
|
22184
22473
|
);
|
|
22185
22474
|
}
|
|
@@ -22188,23 +22477,23 @@ var require_diagnostics = __commonJS({
|
|
|
22188
22477
|
"undici:request:trailers",
|
|
22189
22478
|
(evt) => {
|
|
22190
22479
|
const {
|
|
22191
|
-
request: { method, path:
|
|
22480
|
+
request: { method, path: path71, origin }
|
|
22192
22481
|
} = evt;
|
|
22193
|
-
debugLog("trailers received from %s %s%s", method, origin,
|
|
22482
|
+
debugLog("trailers received from %s %s%s", method, origin, path71);
|
|
22194
22483
|
}
|
|
22195
22484
|
);
|
|
22196
22485
|
diagnosticsChannel.subscribe(
|
|
22197
22486
|
"undici:request:error",
|
|
22198
22487
|
(evt) => {
|
|
22199
22488
|
const {
|
|
22200
|
-
request: { method, path:
|
|
22489
|
+
request: { method, path: path71, origin },
|
|
22201
22490
|
error
|
|
22202
22491
|
} = evt;
|
|
22203
22492
|
debugLog(
|
|
22204
22493
|
"request to %s %s%s errored - %s",
|
|
22205
22494
|
method,
|
|
22206
22495
|
origin,
|
|
22207
|
-
|
|
22496
|
+
path71,
|
|
22208
22497
|
error.message
|
|
22209
22498
|
);
|
|
22210
22499
|
}
|
|
@@ -22307,7 +22596,7 @@ var require_request = __commonJS({
|
|
|
22307
22596
|
var kHandler = /* @__PURE__ */ Symbol("handler");
|
|
22308
22597
|
var Request = class {
|
|
22309
22598
|
constructor(origin, {
|
|
22310
|
-
path:
|
|
22599
|
+
path: path71,
|
|
22311
22600
|
method,
|
|
22312
22601
|
body,
|
|
22313
22602
|
headers,
|
|
@@ -22324,11 +22613,11 @@ var require_request = __commonJS({
|
|
|
22324
22613
|
maxRedirections,
|
|
22325
22614
|
typeOfService
|
|
22326
22615
|
}, handler) {
|
|
22327
|
-
if (typeof
|
|
22616
|
+
if (typeof path71 !== "string") {
|
|
22328
22617
|
throw new InvalidArgumentError("path must be a string");
|
|
22329
|
-
} else if (
|
|
22618
|
+
} else if (path71[0] !== "/" && !(path71.startsWith("http://") || path71.startsWith("https://")) && method !== "CONNECT") {
|
|
22330
22619
|
throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
|
|
22331
|
-
} else if (invalidPathRegex.test(
|
|
22620
|
+
} else if (invalidPathRegex.test(path71)) {
|
|
22332
22621
|
throw new InvalidArgumentError("invalid request path");
|
|
22333
22622
|
}
|
|
22334
22623
|
if (typeof method !== "string") {
|
|
@@ -22403,7 +22692,7 @@ var require_request = __commonJS({
|
|
|
22403
22692
|
this.completed = false;
|
|
22404
22693
|
this.aborted = false;
|
|
22405
22694
|
this.upgrade = upgrade || null;
|
|
22406
|
-
this.path = query ? serializePathWithQuery(
|
|
22695
|
+
this.path = query ? serializePathWithQuery(path71, query) : path71;
|
|
22407
22696
|
this.origin = origin;
|
|
22408
22697
|
this.protocol = getProtocolFromUrlString(origin);
|
|
22409
22698
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
|
|
@@ -27442,7 +27731,7 @@ var require_client_h1 = __commonJS({
|
|
|
27442
27731
|
return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
|
|
27443
27732
|
}
|
|
27444
27733
|
function writeH1(client, request2) {
|
|
27445
|
-
const { method, path:
|
|
27734
|
+
const { method, path: path71, host, upgrade, blocking, reset } = request2;
|
|
27446
27735
|
let { body, headers, contentLength } = request2;
|
|
27447
27736
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
|
|
27448
27737
|
if (util.isFormDataLike(body)) {
|
|
@@ -27511,7 +27800,7 @@ var require_client_h1 = __commonJS({
|
|
|
27511
27800
|
if (socket.setTypeOfService) {
|
|
27512
27801
|
socket.setTypeOfService(request2.typeOfService);
|
|
27513
27802
|
}
|
|
27514
|
-
let header = `${method} ${
|
|
27803
|
+
let header = `${method} ${path71} HTTP/1.1\r
|
|
27515
27804
|
`;
|
|
27516
27805
|
if (typeof host === "string") {
|
|
27517
27806
|
header += `host: ${host}\r
|
|
@@ -28164,7 +28453,7 @@ var require_client_h2 = __commonJS({
|
|
|
28164
28453
|
function writeH2(client, request2) {
|
|
28165
28454
|
const requestTimeout = request2.bodyTimeout ?? client[kBodyTimeout];
|
|
28166
28455
|
const session = client[kHTTP2Session];
|
|
28167
|
-
const { method, path:
|
|
28456
|
+
const { method, path: path71, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
|
|
28168
28457
|
let { body } = request2;
|
|
28169
28458
|
if (upgrade != null && upgrade !== "websocket") {
|
|
28170
28459
|
util.errorRequest(client, request2, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
|
|
@@ -28232,7 +28521,7 @@ var require_client_h2 = __commonJS({
|
|
|
28232
28521
|
}
|
|
28233
28522
|
headers[HTTP2_HEADER_METHOD] = "CONNECT";
|
|
28234
28523
|
headers[HTTP2_HEADER_PROTOCOL] = "websocket";
|
|
28235
|
-
headers[HTTP2_HEADER_PATH] =
|
|
28524
|
+
headers[HTTP2_HEADER_PATH] = path71;
|
|
28236
28525
|
if (protocol === "ws:" || protocol === "wss:") {
|
|
28237
28526
|
headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
|
|
28238
28527
|
} else {
|
|
@@ -28273,7 +28562,7 @@ var require_client_h2 = __commonJS({
|
|
|
28273
28562
|
stream.setTimeout(requestTimeout);
|
|
28274
28563
|
return true;
|
|
28275
28564
|
}
|
|
28276
|
-
headers[HTTP2_HEADER_PATH] =
|
|
28565
|
+
headers[HTTP2_HEADER_PATH] = path71;
|
|
28277
28566
|
headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
|
|
28278
28567
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
|
|
28279
28568
|
if (body && typeof body.read === "function") {
|
|
@@ -30575,10 +30864,10 @@ var require_proxy_agent = __commonJS({
|
|
|
30575
30864
|
};
|
|
30576
30865
|
const {
|
|
30577
30866
|
origin,
|
|
30578
|
-
path:
|
|
30867
|
+
path: path71 = "/",
|
|
30579
30868
|
headers = {}
|
|
30580
30869
|
} = opts;
|
|
30581
|
-
opts.path = origin +
|
|
30870
|
+
opts.path = origin + path71;
|
|
30582
30871
|
if (!("host" in headers) && !("Host" in headers)) {
|
|
30583
30872
|
const { host } = new URL(origin);
|
|
30584
30873
|
headers.host = host;
|
|
@@ -32641,20 +32930,20 @@ var require_mock_utils = __commonJS({
|
|
|
32641
32930
|
}
|
|
32642
32931
|
return normalizedQp;
|
|
32643
32932
|
}
|
|
32644
|
-
function safeUrl(
|
|
32645
|
-
if (typeof
|
|
32646
|
-
return
|
|
32933
|
+
function safeUrl(path71) {
|
|
32934
|
+
if (typeof path71 !== "string") {
|
|
32935
|
+
return path71;
|
|
32647
32936
|
}
|
|
32648
|
-
const pathSegments =
|
|
32937
|
+
const pathSegments = path71.split("?", 3);
|
|
32649
32938
|
if (pathSegments.length !== 2) {
|
|
32650
|
-
return
|
|
32939
|
+
return path71;
|
|
32651
32940
|
}
|
|
32652
32941
|
const qp = new URLSearchParams(pathSegments.pop());
|
|
32653
32942
|
qp.sort();
|
|
32654
32943
|
return [...pathSegments, qp.toString()].join("?");
|
|
32655
32944
|
}
|
|
32656
|
-
function matchKey(mockDispatch2, { path:
|
|
32657
|
-
const pathMatch = matchValue(mockDispatch2.path,
|
|
32945
|
+
function matchKey(mockDispatch2, { path: path71, method, body, headers }) {
|
|
32946
|
+
const pathMatch = matchValue(mockDispatch2.path, path71);
|
|
32658
32947
|
const methodMatch = matchValue(mockDispatch2.method, method);
|
|
32659
32948
|
const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
|
|
32660
32949
|
const headersMatch = matchHeaders(mockDispatch2, headers);
|
|
@@ -32679,8 +32968,8 @@ var require_mock_utils = __commonJS({
|
|
|
32679
32968
|
const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
|
|
32680
32969
|
const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
|
|
32681
32970
|
const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
|
|
32682
|
-
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path:
|
|
32683
|
-
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(
|
|
32971
|
+
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path71, ignoreTrailingSlash }) => {
|
|
32972
|
+
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path71)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path71), resolvedPath);
|
|
32684
32973
|
});
|
|
32685
32974
|
if (matchedMockDispatches.length === 0) {
|
|
32686
32975
|
throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
|
|
@@ -32719,19 +33008,19 @@ var require_mock_utils = __commonJS({
|
|
|
32719
33008
|
mockDispatches.splice(index, 1);
|
|
32720
33009
|
}
|
|
32721
33010
|
}
|
|
32722
|
-
function removeTrailingSlash(
|
|
32723
|
-
while (
|
|
32724
|
-
|
|
33011
|
+
function removeTrailingSlash(path71) {
|
|
33012
|
+
while (path71.endsWith("/")) {
|
|
33013
|
+
path71 = path71.slice(0, -1);
|
|
32725
33014
|
}
|
|
32726
|
-
if (
|
|
32727
|
-
|
|
33015
|
+
if (path71.length === 0) {
|
|
33016
|
+
path71 = "/";
|
|
32728
33017
|
}
|
|
32729
|
-
return
|
|
33018
|
+
return path71;
|
|
32730
33019
|
}
|
|
32731
33020
|
function buildKey(opts) {
|
|
32732
|
-
const { path:
|
|
33021
|
+
const { path: path71, method, body, headers, query } = opts;
|
|
32733
33022
|
return {
|
|
32734
|
-
path:
|
|
33023
|
+
path: path71,
|
|
32735
33024
|
method,
|
|
32736
33025
|
body,
|
|
32737
33026
|
headers,
|
|
@@ -33421,10 +33710,10 @@ var require_pending_interceptors_formatter = __commonJS({
|
|
|
33421
33710
|
}
|
|
33422
33711
|
format(pendingInterceptors) {
|
|
33423
33712
|
const withPrettyHeaders = pendingInterceptors.map(
|
|
33424
|
-
({ method, path:
|
|
33713
|
+
({ method, path: path71, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
33425
33714
|
Method: method,
|
|
33426
33715
|
Origin: origin,
|
|
33427
|
-
Path:
|
|
33716
|
+
Path: path71,
|
|
33428
33717
|
"Status code": statusCode,
|
|
33429
33718
|
Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
|
|
33430
33719
|
Invocations: timesInvoked,
|
|
@@ -33506,9 +33795,9 @@ var require_mock_agent = __commonJS({
|
|
|
33506
33795
|
const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
|
|
33507
33796
|
const dispatchOpts = { ...opts };
|
|
33508
33797
|
if (acceptNonStandardSearchParameters && dispatchOpts.path) {
|
|
33509
|
-
const [
|
|
33798
|
+
const [path71, searchParams] = dispatchOpts.path.split("?");
|
|
33510
33799
|
const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
|
|
33511
|
-
dispatchOpts.path = `${
|
|
33800
|
+
dispatchOpts.path = `${path71}?${normalizedSearchParams}`;
|
|
33512
33801
|
}
|
|
33513
33802
|
return this[kAgent].dispatch(dispatchOpts, handler);
|
|
33514
33803
|
}
|
|
@@ -33909,12 +34198,12 @@ var require_snapshot_recorder = __commonJS({
|
|
|
33909
34198
|
* @return {Promise<void>} - Resolves when snapshots are loaded
|
|
33910
34199
|
*/
|
|
33911
34200
|
async loadSnapshots(filePath) {
|
|
33912
|
-
const
|
|
33913
|
-
if (!
|
|
34201
|
+
const path71 = filePath || this.#snapshotPath;
|
|
34202
|
+
if (!path71) {
|
|
33914
34203
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
33915
34204
|
}
|
|
33916
34205
|
try {
|
|
33917
|
-
const data = await readFile(resolve2(
|
|
34206
|
+
const data = await readFile(resolve2(path71), "utf8");
|
|
33918
34207
|
const parsed = JSON.parse(data);
|
|
33919
34208
|
if (Array.isArray(parsed)) {
|
|
33920
34209
|
this.#snapshots.clear();
|
|
@@ -33928,7 +34217,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
33928
34217
|
if (error.code === "ENOENT") {
|
|
33929
34218
|
this.#snapshots.clear();
|
|
33930
34219
|
} else {
|
|
33931
|
-
throw new UndiciError(`Failed to load snapshots from ${
|
|
34220
|
+
throw new UndiciError(`Failed to load snapshots from ${path71}`, { cause: error });
|
|
33932
34221
|
}
|
|
33933
34222
|
}
|
|
33934
34223
|
}
|
|
@@ -33939,11 +34228,11 @@ var require_snapshot_recorder = __commonJS({
|
|
|
33939
34228
|
* @returns {Promise<void>} - Resolves when snapshots are saved
|
|
33940
34229
|
*/
|
|
33941
34230
|
async saveSnapshots(filePath) {
|
|
33942
|
-
const
|
|
33943
|
-
if (!
|
|
34231
|
+
const path71 = filePath || this.#snapshotPath;
|
|
34232
|
+
if (!path71) {
|
|
33944
34233
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
33945
34234
|
}
|
|
33946
|
-
const resolvedPath = resolve2(
|
|
34235
|
+
const resolvedPath = resolve2(path71);
|
|
33947
34236
|
await mkdir(dirname2(resolvedPath), { recursive: true });
|
|
33948
34237
|
const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
|
|
33949
34238
|
hash,
|
|
@@ -34568,15 +34857,15 @@ var require_redirect_handler = __commonJS({
|
|
|
34568
34857
|
return;
|
|
34569
34858
|
}
|
|
34570
34859
|
const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
|
|
34571
|
-
const
|
|
34572
|
-
const redirectUrlString = `${origin}${
|
|
34860
|
+
const path71 = search ? `${pathname}${search}` : pathname;
|
|
34861
|
+
const redirectUrlString = `${origin}${path71}`;
|
|
34573
34862
|
for (const historyUrl of this.history) {
|
|
34574
34863
|
if (historyUrl.toString() === redirectUrlString) {
|
|
34575
34864
|
throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
|
|
34576
34865
|
}
|
|
34577
34866
|
}
|
|
34578
34867
|
this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
|
|
34579
|
-
this.opts.path =
|
|
34868
|
+
this.opts.path = path71;
|
|
34580
34869
|
this.opts.origin = origin;
|
|
34581
34870
|
this.opts.query = null;
|
|
34582
34871
|
}
|
|
@@ -40783,11 +41072,11 @@ var require_fetch = __commonJS({
|
|
|
40783
41072
|
function dispatch({ body }) {
|
|
40784
41073
|
const url = requestCurrentURL(request2);
|
|
40785
41074
|
const agent = fetchParams.controller.dispatcher;
|
|
40786
|
-
const
|
|
41075
|
+
const path71 = url.pathname + url.search;
|
|
40787
41076
|
const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
|
|
40788
41077
|
return new Promise((resolve2, reject) => agent.dispatch(
|
|
40789
41078
|
{
|
|
40790
|
-
path: hasTrailingQuestionMark ? `${
|
|
41079
|
+
path: hasTrailingQuestionMark ? `${path71}?` : path71,
|
|
40791
41080
|
origin: url.origin,
|
|
40792
41081
|
method: request2.method,
|
|
40793
41082
|
body: agent.isMockActive ? request2.body && (request2.body.source || request2.body.stream) : body,
|
|
@@ -41718,9 +42007,9 @@ var require_util4 = __commonJS({
|
|
|
41718
42007
|
}
|
|
41719
42008
|
}
|
|
41720
42009
|
}
|
|
41721
|
-
function validateCookiePath(
|
|
41722
|
-
for (let i = 0; i <
|
|
41723
|
-
const code =
|
|
42010
|
+
function validateCookiePath(path71) {
|
|
42011
|
+
for (let i = 0; i < path71.length; ++i) {
|
|
42012
|
+
const code = path71.charCodeAt(i);
|
|
41724
42013
|
if (code < 32 || // exclude CTLs (0-31)
|
|
41725
42014
|
code === 127 || // DEL
|
|
41726
42015
|
code === 59) {
|
|
@@ -44890,11 +45179,11 @@ var require_undici = __commonJS({
|
|
|
44890
45179
|
if (typeof opts.path !== "string") {
|
|
44891
45180
|
throw new InvalidArgumentError("invalid opts.path");
|
|
44892
45181
|
}
|
|
44893
|
-
let
|
|
45182
|
+
let path71 = opts.path;
|
|
44894
45183
|
if (!opts.path.startsWith("/")) {
|
|
44895
|
-
|
|
45184
|
+
path71 = `/${path71}`;
|
|
44896
45185
|
}
|
|
44897
|
-
url = new URL(util.parseOrigin(url).origin +
|
|
45186
|
+
url = new URL(util.parseOrigin(url).origin + path71);
|
|
44898
45187
|
} else {
|
|
44899
45188
|
if (!opts) {
|
|
44900
45189
|
opts = typeof url === "object" ? url : {};
|
|
@@ -45013,9 +45302,9 @@ __export(tail_exports, {
|
|
|
45013
45302
|
});
|
|
45014
45303
|
import http5 from "http";
|
|
45015
45304
|
import chalk40 from "chalk";
|
|
45016
|
-
import
|
|
45017
|
-
import
|
|
45018
|
-
import
|
|
45305
|
+
import fs71 from "fs";
|
|
45306
|
+
import os61 from "os";
|
|
45307
|
+
import path68 from "path";
|
|
45019
45308
|
import readline6 from "readline";
|
|
45020
45309
|
import { spawn as spawn8 } from "child_process";
|
|
45021
45310
|
function shortenPathSummary(s) {
|
|
@@ -45039,20 +45328,20 @@ function getModelContextLimit(model) {
|
|
|
45039
45328
|
return 2e5;
|
|
45040
45329
|
}
|
|
45041
45330
|
function readSessionUsage() {
|
|
45042
|
-
const projectsDir =
|
|
45043
|
-
if (!
|
|
45331
|
+
const projectsDir = path68.join(os61.homedir(), ".claude", "projects");
|
|
45332
|
+
if (!fs71.existsSync(projectsDir)) return null;
|
|
45044
45333
|
let latestFile = null;
|
|
45045
45334
|
let latestMtime = 0;
|
|
45046
45335
|
try {
|
|
45047
|
-
for (const dir of
|
|
45048
|
-
const dirPath =
|
|
45336
|
+
for (const dir of fs71.readdirSync(projectsDir)) {
|
|
45337
|
+
const dirPath = path68.join(projectsDir, dir);
|
|
45049
45338
|
try {
|
|
45050
|
-
if (!
|
|
45051
|
-
for (const file of
|
|
45339
|
+
if (!fs71.statSync(dirPath).isDirectory()) continue;
|
|
45340
|
+
for (const file of fs71.readdirSync(dirPath)) {
|
|
45052
45341
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
45053
|
-
const filePath =
|
|
45342
|
+
const filePath = path68.join(dirPath, file);
|
|
45054
45343
|
try {
|
|
45055
|
-
const mtime =
|
|
45344
|
+
const mtime = fs71.statSync(filePath).mtimeMs;
|
|
45056
45345
|
if (mtime > latestMtime) {
|
|
45057
45346
|
latestMtime = mtime;
|
|
45058
45347
|
latestFile = filePath;
|
|
@@ -45067,7 +45356,7 @@ function readSessionUsage() {
|
|
|
45067
45356
|
}
|
|
45068
45357
|
if (!latestFile) return null;
|
|
45069
45358
|
try {
|
|
45070
|
-
const lines =
|
|
45359
|
+
const lines = fs71.readFileSync(latestFile, "utf-8").split("\n");
|
|
45071
45360
|
let lastModel = "";
|
|
45072
45361
|
let lastInput = 0;
|
|
45073
45362
|
let lastOutput = 0;
|
|
@@ -45128,7 +45417,7 @@ function formatBase(activity) {
|
|
|
45128
45417
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
45129
45418
|
const icon = getIcon(activity.tool);
|
|
45130
45419
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
45131
|
-
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(
|
|
45420
|
+
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(os61.homedir(), "~");
|
|
45132
45421
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
45133
45422
|
return `${chalk40.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${chalk40.white.bold(toolName)} ${chalk40.dim(argsPreview)}`;
|
|
45134
45423
|
}
|
|
@@ -45167,9 +45456,9 @@ function renderPending(activity) {
|
|
|
45167
45456
|
}
|
|
45168
45457
|
async function ensureDaemon() {
|
|
45169
45458
|
let pidPort = null;
|
|
45170
|
-
if (
|
|
45459
|
+
if (fs71.existsSync(PID_FILE)) {
|
|
45171
45460
|
try {
|
|
45172
|
-
const { port } = JSON.parse(
|
|
45461
|
+
const { port } = JSON.parse(fs71.readFileSync(PID_FILE, "utf-8"));
|
|
45173
45462
|
pidPort = port;
|
|
45174
45463
|
} catch {
|
|
45175
45464
|
console.error(chalk40.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -45325,9 +45614,9 @@ function buildRecoveryCardLines(req) {
|
|
|
45325
45614
|
];
|
|
45326
45615
|
}
|
|
45327
45616
|
function readApproversFromDisk() {
|
|
45328
|
-
const configPath =
|
|
45617
|
+
const configPath = path68.join(os61.homedir(), ".node9", "config.json");
|
|
45329
45618
|
try {
|
|
45330
|
-
const raw = JSON.parse(
|
|
45619
|
+
const raw = JSON.parse(fs71.readFileSync(configPath, "utf-8"));
|
|
45331
45620
|
const settings = raw.settings ?? {};
|
|
45332
45621
|
return settings.approvers ?? {};
|
|
45333
45622
|
} catch {
|
|
@@ -45343,15 +45632,15 @@ function approverStatusLine() {
|
|
|
45343
45632
|
return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
45344
45633
|
}
|
|
45345
45634
|
function toggleApprover(channel) {
|
|
45346
|
-
const configPath =
|
|
45635
|
+
const configPath = path68.join(os61.homedir(), ".node9", "config.json");
|
|
45347
45636
|
try {
|
|
45348
|
-
const raw = JSON.parse(
|
|
45637
|
+
const raw = JSON.parse(fs71.readFileSync(configPath, "utf-8"));
|
|
45349
45638
|
const settings = raw.settings ?? {};
|
|
45350
45639
|
const approvers = settings.approvers ?? {};
|
|
45351
45640
|
approvers[channel] = approvers[channel] === false;
|
|
45352
45641
|
settings.approvers = approvers;
|
|
45353
45642
|
raw.settings = settings;
|
|
45354
|
-
|
|
45643
|
+
fs71.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
45355
45644
|
} catch (err2) {
|
|
45356
45645
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
45357
45646
|
`);
|
|
@@ -45523,8 +45812,8 @@ async function startTail(options = {}) {
|
|
|
45523
45812
|
}
|
|
45524
45813
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
45525
45814
|
try {
|
|
45526
|
-
|
|
45527
|
-
|
|
45815
|
+
fs71.appendFileSync(
|
|
45816
|
+
path68.join(os61.homedir(), ".node9", "hook-debug.log"),
|
|
45528
45817
|
`[tail] POST /decision failed: ${String(err2)}
|
|
45529
45818
|
`
|
|
45530
45819
|
);
|
|
@@ -45588,9 +45877,9 @@ async function startTail(options = {}) {
|
|
|
45588
45877
|
};
|
|
45589
45878
|
process.stdin.on("keypress", onKeypress);
|
|
45590
45879
|
}
|
|
45591
|
-
const auditLog =
|
|
45880
|
+
const auditLog = path68.join(os61.homedir(), ".node9", "audit.log");
|
|
45592
45881
|
try {
|
|
45593
|
-
const unackedDlp =
|
|
45882
|
+
const unackedDlp = fs71.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
45594
45883
|
if (unackedDlp > 0) {
|
|
45595
45884
|
console.log("");
|
|
45596
45885
|
console.log(
|
|
@@ -45630,7 +45919,7 @@ async function startTail(options = {}) {
|
|
|
45630
45919
|
if (stallWarned) return;
|
|
45631
45920
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
45632
45921
|
try {
|
|
45633
|
-
const auditMtime =
|
|
45922
|
+
const auditMtime = fs71.statSync(auditLog).mtimeMs;
|
|
45634
45923
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
45635
45924
|
console.log("");
|
|
45636
45925
|
console.log(
|
|
@@ -45821,7 +46110,7 @@ var init_tail = __esm({
|
|
|
45821
46110
|
"use strict";
|
|
45822
46111
|
init_daemon2();
|
|
45823
46112
|
init_daemon();
|
|
45824
|
-
PID_FILE =
|
|
46113
|
+
PID_FILE = path68.join(os61.homedir(), ".node9", "daemon.pid");
|
|
45825
46114
|
ICONS = {
|
|
45826
46115
|
bash: "\u{1F4BB}",
|
|
45827
46116
|
shell: "\u{1F4BB}",
|
|
@@ -45869,9 +46158,9 @@ __export(hud_exports, {
|
|
|
45869
46158
|
main: () => main,
|
|
45870
46159
|
renderEnvironmentLine: () => renderEnvironmentLine
|
|
45871
46160
|
});
|
|
45872
|
-
import
|
|
45873
|
-
import
|
|
45874
|
-
import
|
|
46161
|
+
import fs72 from "fs";
|
|
46162
|
+
import path69 from "path";
|
|
46163
|
+
import os62 from "os";
|
|
45875
46164
|
import http6 from "http";
|
|
45876
46165
|
async function readStdin() {
|
|
45877
46166
|
const chunks = [];
|
|
@@ -45947,9 +46236,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
45947
46236
|
return ` (${m}m left)`;
|
|
45948
46237
|
}
|
|
45949
46238
|
function safeReadJson(filePath) {
|
|
45950
|
-
if (!
|
|
46239
|
+
if (!fs72.existsSync(filePath)) return null;
|
|
45951
46240
|
try {
|
|
45952
|
-
return JSON.parse(
|
|
46241
|
+
return JSON.parse(fs72.readFileSync(filePath, "utf-8"));
|
|
45953
46242
|
} catch {
|
|
45954
46243
|
return null;
|
|
45955
46244
|
}
|
|
@@ -45970,12 +46259,12 @@ function countHooksInFile(filePath) {
|
|
|
45970
46259
|
return Object.keys(cfg.hooks).length;
|
|
45971
46260
|
}
|
|
45972
46261
|
function countRulesInDir(rulesDir) {
|
|
45973
|
-
if (!
|
|
46262
|
+
if (!fs72.existsSync(rulesDir)) return 0;
|
|
45974
46263
|
let count = 0;
|
|
45975
46264
|
try {
|
|
45976
|
-
for (const entry of
|
|
46265
|
+
for (const entry of fs72.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
45977
46266
|
if (entry.isDirectory()) {
|
|
45978
|
-
count += countRulesInDir(
|
|
46267
|
+
count += countRulesInDir(path69.join(rulesDir, entry.name));
|
|
45979
46268
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
45980
46269
|
count++;
|
|
45981
46270
|
}
|
|
@@ -45986,46 +46275,46 @@ function countRulesInDir(rulesDir) {
|
|
|
45986
46275
|
}
|
|
45987
46276
|
function isSamePath(a, b) {
|
|
45988
46277
|
try {
|
|
45989
|
-
return
|
|
46278
|
+
return path69.resolve(a) === path69.resolve(b);
|
|
45990
46279
|
} catch {
|
|
45991
46280
|
return false;
|
|
45992
46281
|
}
|
|
45993
46282
|
}
|
|
45994
46283
|
function countConfigs(cwd) {
|
|
45995
|
-
const homeDir2 =
|
|
45996
|
-
const claudeDir =
|
|
46284
|
+
const homeDir2 = os62.homedir();
|
|
46285
|
+
const claudeDir = path69.join(homeDir2, ".claude");
|
|
45997
46286
|
let claudeMdCount = 0;
|
|
45998
46287
|
let rulesCount = 0;
|
|
45999
46288
|
let hooksCount = 0;
|
|
46000
46289
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
46001
46290
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
46002
|
-
if (
|
|
46003
|
-
rulesCount += countRulesInDir(
|
|
46004
|
-
const userSettings =
|
|
46291
|
+
if (fs72.existsSync(path69.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
46292
|
+
rulesCount += countRulesInDir(path69.join(claudeDir, "rules"));
|
|
46293
|
+
const userSettings = path69.join(claudeDir, "settings.json");
|
|
46005
46294
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
46006
46295
|
hooksCount += countHooksInFile(userSettings);
|
|
46007
|
-
const userClaudeJson =
|
|
46296
|
+
const userClaudeJson = path69.join(homeDir2, ".claude.json");
|
|
46008
46297
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
46009
46298
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
46010
46299
|
userMcpServers.delete(name);
|
|
46011
46300
|
}
|
|
46012
46301
|
if (cwd) {
|
|
46013
|
-
if (
|
|
46014
|
-
if (
|
|
46015
|
-
const projectClaudeDir =
|
|
46302
|
+
if (fs72.existsSync(path69.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
46303
|
+
if (fs72.existsSync(path69.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
46304
|
+
const projectClaudeDir = path69.join(cwd, ".claude");
|
|
46016
46305
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
46017
46306
|
if (!overlapsUserScope) {
|
|
46018
|
-
if (
|
|
46019
|
-
rulesCount += countRulesInDir(
|
|
46020
|
-
const projSettings =
|
|
46307
|
+
if (fs72.existsSync(path69.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
46308
|
+
rulesCount += countRulesInDir(path69.join(projectClaudeDir, "rules"));
|
|
46309
|
+
const projSettings = path69.join(projectClaudeDir, "settings.json");
|
|
46021
46310
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
46022
46311
|
hooksCount += countHooksInFile(projSettings);
|
|
46023
46312
|
}
|
|
46024
|
-
if (
|
|
46025
|
-
const localSettings =
|
|
46313
|
+
if (fs72.existsSync(path69.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
46314
|
+
const localSettings = path69.join(projectClaudeDir, "settings.local.json");
|
|
46026
46315
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
46027
46316
|
hooksCount += countHooksInFile(localSettings);
|
|
46028
|
-
const mcpJsonServers = getMcpServerNames(
|
|
46317
|
+
const mcpJsonServers = getMcpServerNames(path69.join(cwd, ".mcp.json"));
|
|
46029
46318
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
46030
46319
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
46031
46320
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -46058,12 +46347,12 @@ function readActiveShieldsHud() {
|
|
|
46058
46347
|
return shieldsCache.value;
|
|
46059
46348
|
}
|
|
46060
46349
|
try {
|
|
46061
|
-
const shieldsPath =
|
|
46062
|
-
if (!
|
|
46350
|
+
const shieldsPath = path69.join(os62.homedir(), ".node9", "shields.json");
|
|
46351
|
+
if (!fs72.existsSync(shieldsPath)) {
|
|
46063
46352
|
shieldsCache = { value: [], ts: now };
|
|
46064
46353
|
return [];
|
|
46065
46354
|
}
|
|
46066
|
-
const parsed = JSON.parse(
|
|
46355
|
+
const parsed = JSON.parse(fs72.readFileSync(shieldsPath, "utf-8"));
|
|
46067
46356
|
if (!Array.isArray(parsed.active)) {
|
|
46068
46357
|
shieldsCache = { value: [], ts: now };
|
|
46069
46358
|
return [];
|
|
@@ -46165,17 +46454,17 @@ function renderContextLine(stdin) {
|
|
|
46165
46454
|
async function main() {
|
|
46166
46455
|
try {
|
|
46167
46456
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
46168
|
-
if (
|
|
46457
|
+
if (fs72.existsSync(path69.join(os62.homedir(), ".node9", "hud-debug"))) {
|
|
46169
46458
|
try {
|
|
46170
|
-
const logPath =
|
|
46459
|
+
const logPath = path69.join(os62.homedir(), ".node9", "hud-debug.log");
|
|
46171
46460
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
46172
46461
|
let size = 0;
|
|
46173
46462
|
try {
|
|
46174
|
-
size =
|
|
46463
|
+
size = fs72.statSync(logPath).size;
|
|
46175
46464
|
} catch {
|
|
46176
46465
|
}
|
|
46177
46466
|
if (size < MAX_LOG_SIZE) {
|
|
46178
|
-
|
|
46467
|
+
fs72.appendFileSync(
|
|
46179
46468
|
logPath,
|
|
46180
46469
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
46181
46470
|
);
|
|
@@ -46196,11 +46485,11 @@ async function main() {
|
|
|
46196
46485
|
try {
|
|
46197
46486
|
const cwd = stdin.cwd ?? process.cwd();
|
|
46198
46487
|
for (const configPath of [
|
|
46199
|
-
|
|
46200
|
-
|
|
46488
|
+
path69.join(cwd, "node9.config.json"),
|
|
46489
|
+
path69.join(os62.homedir(), ".node9", "config.json")
|
|
46201
46490
|
]) {
|
|
46202
|
-
if (!
|
|
46203
|
-
const cfg = JSON.parse(
|
|
46491
|
+
if (!fs72.existsSync(configPath)) continue;
|
|
46492
|
+
const cfg = JSON.parse(fs72.readFileSync(configPath, "utf-8"));
|
|
46204
46493
|
const hud = cfg.settings?.hud;
|
|
46205
46494
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
46206
46495
|
}
|
|
@@ -46342,9 +46631,9 @@ function writeCredentialsAndConfig(apiKey, opts = {}) {
|
|
|
46342
46631
|
// src/cli.ts
|
|
46343
46632
|
init_daemon2();
|
|
46344
46633
|
import chalk41 from "chalk";
|
|
46345
|
-
import
|
|
46346
|
-
import
|
|
46347
|
-
import
|
|
46634
|
+
import fs73 from "fs";
|
|
46635
|
+
import path70 from "path";
|
|
46636
|
+
import os63 from "os";
|
|
46348
46637
|
import { spawn as spawn9 } from "child_process";
|
|
46349
46638
|
import { confirm as confirm2 } from "@inquirer/prompts";
|
|
46350
46639
|
|
|
@@ -46531,26 +46820,48 @@ async function runProxy(targetCommand) {
|
|
|
46531
46820
|
|
|
46532
46821
|
// src/cli/daemon-starter.ts
|
|
46533
46822
|
init_daemon();
|
|
46823
|
+
init_startup_log();
|
|
46534
46824
|
import { spawn as spawn3 } from "child_process";
|
|
46535
|
-
import
|
|
46536
|
-
import
|
|
46825
|
+
import path42 from "path";
|
|
46826
|
+
import fs44 from "fs";
|
|
46827
|
+
import os40 from "os";
|
|
46537
46828
|
function isTestingMode() {
|
|
46538
46829
|
return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
|
|
46539
46830
|
}
|
|
46831
|
+
var SKIP_STAMP = () => path42.join(os40.homedir(), ".node9", ".autostart-skip-stamp");
|
|
46832
|
+
var SKIP_THROTTLE_MS = 60 * 60 * 1e3;
|
|
46833
|
+
function logAutostartSkipThrottled(reason) {
|
|
46834
|
+
try {
|
|
46835
|
+
const stamp = SKIP_STAMP();
|
|
46836
|
+
try {
|
|
46837
|
+
if (Date.now() - fs44.statSync(stamp).mtimeMs < SKIP_THROTTLE_MS) return;
|
|
46838
|
+
} catch {
|
|
46839
|
+
}
|
|
46840
|
+
fs44.writeFileSync(stamp, "", "utf-8");
|
|
46841
|
+
fs44.appendFileSync(
|
|
46842
|
+
path42.join(os40.homedir(), ".node9", "hook-debug.log"),
|
|
46843
|
+
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-skip: ${reason}
|
|
46844
|
+
`,
|
|
46845
|
+
"utf-8"
|
|
46846
|
+
);
|
|
46847
|
+
} catch {
|
|
46848
|
+
}
|
|
46849
|
+
}
|
|
46540
46850
|
async function autoStartDaemonAndWait() {
|
|
46541
46851
|
if (isTestingMode()) return false;
|
|
46542
|
-
if (!
|
|
46852
|
+
if (!path42.isAbsolute(process.argv[1])) return false;
|
|
46543
46853
|
let resolvedArgv1;
|
|
46544
46854
|
try {
|
|
46545
|
-
resolvedArgv1 =
|
|
46855
|
+
resolvedArgv1 = fs44.realpathSync(process.argv[1]);
|
|
46546
46856
|
} catch {
|
|
46547
46857
|
return false;
|
|
46548
46858
|
}
|
|
46549
46859
|
if (!resolvedArgv1.endsWith(".js")) return false;
|
|
46860
|
+
const startupFd = openStartupLogFd();
|
|
46550
46861
|
try {
|
|
46551
46862
|
const child = spawn3(process.execPath, [resolvedArgv1, "daemon"], {
|
|
46552
46863
|
detached: true,
|
|
46553
|
-
stdio: "ignore",
|
|
46864
|
+
stdio: ["ignore", "ignore", startupFd ?? "ignore"],
|
|
46554
46865
|
env: {
|
|
46555
46866
|
...process.env,
|
|
46556
46867
|
NODE9_AUTO_STARTED: "1"
|
|
@@ -46563,30 +46874,41 @@ async function autoStartDaemonAndWait() {
|
|
|
46563
46874
|
if (await isDaemonReachable()) return true;
|
|
46564
46875
|
}
|
|
46565
46876
|
} catch {
|
|
46877
|
+
} finally {
|
|
46878
|
+
if (startupFd !== void 0) {
|
|
46879
|
+
try {
|
|
46880
|
+
fs44.closeSync(startupFd);
|
|
46881
|
+
} catch {
|
|
46882
|
+
}
|
|
46883
|
+
}
|
|
46566
46884
|
}
|
|
46567
46885
|
return false;
|
|
46568
46886
|
}
|
|
46569
46887
|
|
|
46888
|
+
// src/cli.ts
|
|
46889
|
+
init_service();
|
|
46890
|
+
|
|
46570
46891
|
// src/cli/commands/check.ts
|
|
46571
46892
|
init_orchestrator();
|
|
46572
46893
|
init_state();
|
|
46573
46894
|
init_daemon();
|
|
46895
|
+
init_startup_log();
|
|
46574
46896
|
init_config();
|
|
46575
46897
|
init_policy();
|
|
46576
46898
|
import chalk9 from "chalk";
|
|
46577
|
-
import
|
|
46899
|
+
import fs48 from "fs";
|
|
46578
46900
|
import { spawn as spawn5 } from "child_process";
|
|
46579
|
-
import
|
|
46580
|
-
import
|
|
46901
|
+
import path46 from "path";
|
|
46902
|
+
import os44 from "os";
|
|
46581
46903
|
|
|
46582
46904
|
// src/undo.ts
|
|
46583
46905
|
import { spawnSync as spawnSync3, spawn as spawn4 } from "child_process";
|
|
46584
46906
|
import crypto7 from "crypto";
|
|
46585
|
-
import
|
|
46907
|
+
import fs45 from "fs";
|
|
46586
46908
|
import net3 from "net";
|
|
46587
|
-
import
|
|
46588
|
-
import
|
|
46589
|
-
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
46909
|
+
import path43 from "path";
|
|
46910
|
+
import os41 from "os";
|
|
46911
|
+
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path43.join(os41.tmpdir(), "node9-activity.sock");
|
|
46590
46912
|
function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
46591
46913
|
try {
|
|
46592
46914
|
const payload = JSON.stringify({
|
|
@@ -46606,22 +46928,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
|
46606
46928
|
} catch {
|
|
46607
46929
|
}
|
|
46608
46930
|
}
|
|
46609
|
-
var SNAPSHOT_STACK_PATH =
|
|
46610
|
-
var UNDO_LATEST_PATH =
|
|
46931
|
+
var SNAPSHOT_STACK_PATH = path43.join(os41.homedir(), ".node9", "snapshots.json");
|
|
46932
|
+
var UNDO_LATEST_PATH = path43.join(os41.homedir(), ".node9", "undo_latest.txt");
|
|
46611
46933
|
var MAX_SNAPSHOTS = 10;
|
|
46612
46934
|
var GIT_TIMEOUT = 15e3;
|
|
46613
46935
|
function readStack() {
|
|
46614
46936
|
try {
|
|
46615
|
-
if (
|
|
46616
|
-
return JSON.parse(
|
|
46937
|
+
if (fs45.existsSync(SNAPSHOT_STACK_PATH))
|
|
46938
|
+
return JSON.parse(fs45.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
|
|
46617
46939
|
} catch {
|
|
46618
46940
|
}
|
|
46619
46941
|
return [];
|
|
46620
46942
|
}
|
|
46621
46943
|
function writeStack(stack) {
|
|
46622
|
-
const dir =
|
|
46623
|
-
if (!
|
|
46624
|
-
|
|
46944
|
+
const dir = path43.dirname(SNAPSHOT_STACK_PATH);
|
|
46945
|
+
if (!fs45.existsSync(dir)) fs45.mkdirSync(dir, { recursive: true });
|
|
46946
|
+
fs45.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
|
|
46625
46947
|
}
|
|
46626
46948
|
function extractFilePath(args) {
|
|
46627
46949
|
if (!args || typeof args !== "object") return null;
|
|
@@ -46641,12 +46963,12 @@ function buildArgsSummary(tool, args) {
|
|
|
46641
46963
|
return "";
|
|
46642
46964
|
}
|
|
46643
46965
|
function findProjectRoot(filePath) {
|
|
46644
|
-
let dir =
|
|
46966
|
+
let dir = path43.dirname(filePath);
|
|
46645
46967
|
while (true) {
|
|
46646
|
-
if (
|
|
46968
|
+
if (fs45.existsSync(path43.join(dir, ".git")) || fs45.existsSync(path43.join(dir, "package.json"))) {
|
|
46647
46969
|
return dir;
|
|
46648
46970
|
}
|
|
46649
|
-
const parent =
|
|
46971
|
+
const parent = path43.dirname(dir);
|
|
46650
46972
|
if (parent === dir) return process.cwd();
|
|
46651
46973
|
dir = parent;
|
|
46652
46974
|
}
|
|
@@ -46654,7 +46976,7 @@ function findProjectRoot(filePath) {
|
|
|
46654
46976
|
function normalizeCwdForHash(cwd) {
|
|
46655
46977
|
let normalized;
|
|
46656
46978
|
try {
|
|
46657
|
-
normalized =
|
|
46979
|
+
normalized = fs45.realpathSync(cwd);
|
|
46658
46980
|
} catch {
|
|
46659
46981
|
normalized = cwd;
|
|
46660
46982
|
}
|
|
@@ -46664,16 +46986,16 @@ function normalizeCwdForHash(cwd) {
|
|
|
46664
46986
|
}
|
|
46665
46987
|
function getShadowRepoDir(cwd) {
|
|
46666
46988
|
const hash = crypto7.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
|
|
46667
|
-
return
|
|
46989
|
+
return path43.join(os41.homedir(), ".node9", "snapshots", hash);
|
|
46668
46990
|
}
|
|
46669
46991
|
function cleanOrphanedIndexFiles(shadowDir) {
|
|
46670
46992
|
try {
|
|
46671
46993
|
const cutoff = Date.now() - 6e4;
|
|
46672
|
-
for (const f of
|
|
46994
|
+
for (const f of fs45.readdirSync(shadowDir)) {
|
|
46673
46995
|
if (f.startsWith("index_")) {
|
|
46674
|
-
const fp =
|
|
46996
|
+
const fp = path43.join(shadowDir, f);
|
|
46675
46997
|
try {
|
|
46676
|
-
if (
|
|
46998
|
+
if (fs45.statSync(fp).mtimeMs < cutoff) fs45.unlinkSync(fp);
|
|
46677
46999
|
} catch {
|
|
46678
47000
|
}
|
|
46679
47001
|
}
|
|
@@ -46685,7 +47007,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
|
|
|
46685
47007
|
const hardcoded = [".git", ".node9"];
|
|
46686
47008
|
const lines = [...hardcoded, ...ignorePaths].join("\n");
|
|
46687
47009
|
try {
|
|
46688
|
-
|
|
47010
|
+
fs45.writeFileSync(path43.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
|
|
46689
47011
|
} catch {
|
|
46690
47012
|
}
|
|
46691
47013
|
}
|
|
@@ -46698,25 +47020,25 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
46698
47020
|
timeout: 3e3
|
|
46699
47021
|
});
|
|
46700
47022
|
if (check.status === 0) {
|
|
46701
|
-
const ptPath =
|
|
47023
|
+
const ptPath = path43.join(shadowDir, "project-path.txt");
|
|
46702
47024
|
try {
|
|
46703
|
-
const stored =
|
|
47025
|
+
const stored = fs45.readFileSync(ptPath, "utf8").trim();
|
|
46704
47026
|
if (stored === normalizedCwd) return true;
|
|
46705
47027
|
if (process.env.NODE9_DEBUG === "1")
|
|
46706
47028
|
console.error(
|
|
46707
47029
|
`[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
|
|
46708
47030
|
);
|
|
46709
|
-
|
|
47031
|
+
fs45.rmSync(shadowDir, { recursive: true, force: true });
|
|
46710
47032
|
} catch {
|
|
46711
47033
|
try {
|
|
46712
|
-
|
|
47034
|
+
fs45.writeFileSync(ptPath, normalizedCwd, "utf8");
|
|
46713
47035
|
} catch {
|
|
46714
47036
|
}
|
|
46715
47037
|
return true;
|
|
46716
47038
|
}
|
|
46717
47039
|
}
|
|
46718
47040
|
try {
|
|
46719
|
-
|
|
47041
|
+
fs45.mkdirSync(shadowDir, { recursive: true });
|
|
46720
47042
|
} catch {
|
|
46721
47043
|
}
|
|
46722
47044
|
const init = spawnSync3("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
|
|
@@ -46725,7 +47047,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
46725
47047
|
if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
|
|
46726
47048
|
return false;
|
|
46727
47049
|
}
|
|
46728
|
-
const configFile =
|
|
47050
|
+
const configFile = path43.join(shadowDir, "config");
|
|
46729
47051
|
spawnSync3("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
|
|
46730
47052
|
timeout: 3e3
|
|
46731
47053
|
});
|
|
@@ -46733,7 +47055,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
46733
47055
|
timeout: 3e3
|
|
46734
47056
|
});
|
|
46735
47057
|
try {
|
|
46736
|
-
|
|
47058
|
+
fs45.writeFileSync(path43.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
|
|
46737
47059
|
} catch {
|
|
46738
47060
|
}
|
|
46739
47061
|
return true;
|
|
@@ -46756,12 +47078,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
46756
47078
|
let indexFile = null;
|
|
46757
47079
|
try {
|
|
46758
47080
|
const rawFilePath = extractFilePath(args);
|
|
46759
|
-
const absFilePath = rawFilePath &&
|
|
47081
|
+
const absFilePath = rawFilePath && path43.isAbsolute(rawFilePath) ? rawFilePath : null;
|
|
46760
47082
|
const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
|
|
46761
47083
|
const shadowDir = getShadowRepoDir(cwd);
|
|
46762
47084
|
if (!ensureShadowRepo(shadowDir, cwd)) return null;
|
|
46763
47085
|
writeShadowExcludes(shadowDir, ignorePaths);
|
|
46764
|
-
indexFile =
|
|
47086
|
+
indexFile = path43.join(shadowDir, `index_${process.pid}_${Date.now()}`);
|
|
46765
47087
|
const shadowEnv = {
|
|
46766
47088
|
...process.env,
|
|
46767
47089
|
GIT_DIR: shadowDir,
|
|
@@ -46833,7 +47155,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
46833
47155
|
writeStack(stack);
|
|
46834
47156
|
const entry = stack[stack.length - 1];
|
|
46835
47157
|
notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
|
|
46836
|
-
|
|
47158
|
+
fs45.writeFileSync(UNDO_LATEST_PATH, commitHash);
|
|
46837
47159
|
if (shouldGc) {
|
|
46838
47160
|
spawn4("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
|
|
46839
47161
|
}
|
|
@@ -46844,7 +47166,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
46844
47166
|
} finally {
|
|
46845
47167
|
if (indexFile) {
|
|
46846
47168
|
try {
|
|
46847
|
-
|
|
47169
|
+
fs45.unlinkSync(indexFile);
|
|
46848
47170
|
} catch {
|
|
46849
47171
|
}
|
|
46850
47172
|
}
|
|
@@ -46920,9 +47242,9 @@ function applyUndo(hash, cwd) {
|
|
|
46920
47242
|
timeout: GIT_TIMEOUT
|
|
46921
47243
|
}).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
|
|
46922
47244
|
for (const file of [...tracked, ...untracked]) {
|
|
46923
|
-
const fullPath =
|
|
46924
|
-
if (!snapshotFiles.has(file) &&
|
|
46925
|
-
|
|
47245
|
+
const fullPath = path43.join(dir, file);
|
|
47246
|
+
if (!snapshotFiles.has(file) && fs45.existsSync(fullPath)) {
|
|
47247
|
+
fs45.unlinkSync(fullPath);
|
|
46926
47248
|
}
|
|
46927
47249
|
}
|
|
46928
47250
|
return true;
|
|
@@ -46932,12 +47254,12 @@ function applyUndo(hash, cwd) {
|
|
|
46932
47254
|
}
|
|
46933
47255
|
|
|
46934
47256
|
// src/skill-pin.ts
|
|
46935
|
-
import
|
|
46936
|
-
import
|
|
46937
|
-
import
|
|
47257
|
+
import fs46 from "fs";
|
|
47258
|
+
import path44 from "path";
|
|
47259
|
+
import os42 from "os";
|
|
46938
47260
|
import crypto8 from "crypto";
|
|
46939
47261
|
function getPinsFilePath2() {
|
|
46940
|
-
return
|
|
47262
|
+
return path44.join(os42.homedir(), ".node9", "skill-pins.json");
|
|
46941
47263
|
}
|
|
46942
47264
|
var MAX_FILES = 5e3;
|
|
46943
47265
|
var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
@@ -46951,18 +47273,18 @@ function walkDir(root) {
|
|
|
46951
47273
|
if (out.length >= MAX_FILES) return;
|
|
46952
47274
|
let entries;
|
|
46953
47275
|
try {
|
|
46954
|
-
entries =
|
|
47276
|
+
entries = fs46.readdirSync(dir, { withFileTypes: true });
|
|
46955
47277
|
} catch {
|
|
46956
47278
|
return;
|
|
46957
47279
|
}
|
|
46958
47280
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
46959
47281
|
for (const entry of entries) {
|
|
46960
47282
|
if (out.length >= MAX_FILES) return;
|
|
46961
|
-
const full =
|
|
46962
|
-
const rel = relDir ?
|
|
47283
|
+
const full = path44.join(dir, entry.name);
|
|
47284
|
+
const rel = relDir ? path44.posix.join(relDir, entry.name) : entry.name;
|
|
46963
47285
|
let lst;
|
|
46964
47286
|
try {
|
|
46965
|
-
lst =
|
|
47287
|
+
lst = fs46.lstatSync(full);
|
|
46966
47288
|
} catch {
|
|
46967
47289
|
continue;
|
|
46968
47290
|
}
|
|
@@ -46974,7 +47296,7 @@ function walkDir(root) {
|
|
|
46974
47296
|
if (!lst.isFile()) continue;
|
|
46975
47297
|
if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
|
|
46976
47298
|
try {
|
|
46977
|
-
const buf =
|
|
47299
|
+
const buf = fs46.readFileSync(full);
|
|
46978
47300
|
totalBytes += buf.length;
|
|
46979
47301
|
out.push({ rel, hash: sha256Bytes(buf) });
|
|
46980
47302
|
} catch {
|
|
@@ -46988,14 +47310,14 @@ function walkDir(root) {
|
|
|
46988
47310
|
function hashSkillRoot(absPath) {
|
|
46989
47311
|
let lst;
|
|
46990
47312
|
try {
|
|
46991
|
-
lst =
|
|
47313
|
+
lst = fs46.lstatSync(absPath);
|
|
46992
47314
|
} catch {
|
|
46993
47315
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
46994
47316
|
}
|
|
46995
47317
|
if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
|
|
46996
47318
|
if (lst.isFile()) {
|
|
46997
47319
|
try {
|
|
46998
|
-
return { exists: true, contentHash: sha256Bytes(
|
|
47320
|
+
return { exists: true, contentHash: sha256Bytes(fs46.readFileSync(absPath)), fileCount: 1 };
|
|
46999
47321
|
} catch {
|
|
47000
47322
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
47001
47323
|
}
|
|
@@ -47013,7 +47335,7 @@ function getRootKey(absPath) {
|
|
|
47013
47335
|
function readSkillPinsSafe() {
|
|
47014
47336
|
const filePath = getPinsFilePath2();
|
|
47015
47337
|
try {
|
|
47016
|
-
const raw =
|
|
47338
|
+
const raw = fs46.readFileSync(filePath, "utf-8");
|
|
47017
47339
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
47018
47340
|
const parsed = JSON.parse(raw);
|
|
47019
47341
|
if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
|
|
@@ -47033,10 +47355,10 @@ function readSkillPins() {
|
|
|
47033
47355
|
}
|
|
47034
47356
|
function writeSkillPins(data) {
|
|
47035
47357
|
const filePath = getPinsFilePath2();
|
|
47036
|
-
|
|
47358
|
+
fs46.mkdirSync(path44.dirname(filePath), { recursive: true });
|
|
47037
47359
|
const tmp = `${filePath}.${crypto8.randomBytes(6).toString("hex")}.tmp`;
|
|
47038
|
-
|
|
47039
|
-
|
|
47360
|
+
fs46.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
47361
|
+
fs46.renameSync(tmp, filePath);
|
|
47040
47362
|
}
|
|
47041
47363
|
function removePin2(rootKey) {
|
|
47042
47364
|
const pins = readSkillPins();
|
|
@@ -47080,36 +47402,36 @@ function verifyAndPinRoots(roots) {
|
|
|
47080
47402
|
return { kind: "verified" };
|
|
47081
47403
|
}
|
|
47082
47404
|
function defaultSkillRoots(_cwd) {
|
|
47083
|
-
const marketplaces =
|
|
47405
|
+
const marketplaces = path44.join(os42.homedir(), ".claude", "plugins", "marketplaces");
|
|
47084
47406
|
const roots = [];
|
|
47085
47407
|
let registries;
|
|
47086
47408
|
try {
|
|
47087
|
-
registries =
|
|
47409
|
+
registries = fs46.readdirSync(marketplaces, { withFileTypes: true });
|
|
47088
47410
|
} catch {
|
|
47089
47411
|
return [];
|
|
47090
47412
|
}
|
|
47091
47413
|
for (const registry of registries) {
|
|
47092
47414
|
if (!registry.isDirectory()) continue;
|
|
47093
|
-
const pluginsDir =
|
|
47415
|
+
const pluginsDir = path44.join(marketplaces, registry.name, "plugins");
|
|
47094
47416
|
let plugins;
|
|
47095
47417
|
try {
|
|
47096
|
-
plugins =
|
|
47418
|
+
plugins = fs46.readdirSync(pluginsDir, { withFileTypes: true });
|
|
47097
47419
|
} catch {
|
|
47098
47420
|
continue;
|
|
47099
47421
|
}
|
|
47100
47422
|
for (const plugin of plugins) {
|
|
47101
47423
|
if (!plugin.isDirectory()) continue;
|
|
47102
|
-
roots.push(
|
|
47424
|
+
roots.push(path44.join(pluginsDir, plugin.name));
|
|
47103
47425
|
}
|
|
47104
47426
|
}
|
|
47105
47427
|
return roots;
|
|
47106
47428
|
}
|
|
47107
47429
|
function resolveUserSkillRoot(entry, cwd) {
|
|
47108
47430
|
if (!entry) return null;
|
|
47109
|
-
if (entry.startsWith("~/") || entry === "~") return
|
|
47110
|
-
if (
|
|
47111
|
-
if (!cwd || !
|
|
47112
|
-
return
|
|
47431
|
+
if (entry.startsWith("~/") || entry === "~") return path44.join(os42.homedir(), entry.slice(1));
|
|
47432
|
+
if (path44.isAbsolute(entry)) return entry;
|
|
47433
|
+
if (!cwd || !path44.isAbsolute(cwd)) return null;
|
|
47434
|
+
return path44.join(cwd, entry);
|
|
47113
47435
|
}
|
|
47114
47436
|
|
|
47115
47437
|
// src/cli/commands/check.ts
|
|
@@ -47118,11 +47440,11 @@ init_audit();
|
|
|
47118
47440
|
|
|
47119
47441
|
// src/review-pending.ts
|
|
47120
47442
|
init_hasher();
|
|
47121
|
-
import
|
|
47122
|
-
import
|
|
47123
|
-
import
|
|
47443
|
+
import fs47 from "fs";
|
|
47444
|
+
import os43 from "os";
|
|
47445
|
+
import path45 from "path";
|
|
47124
47446
|
function storePath() {
|
|
47125
|
-
return process.env.NODE9_PENDING_STORE ||
|
|
47447
|
+
return process.env.NODE9_PENDING_STORE || path45.join(os43.homedir(), ".node9", "pending-reviews.json");
|
|
47126
47448
|
}
|
|
47127
47449
|
var TTL_MS2 = 6 * 60 * 60 * 1e3;
|
|
47128
47450
|
var MAX_ENTRIES = 500;
|
|
@@ -47139,7 +47461,7 @@ function reviewCorrelationKey(payload) {
|
|
|
47139
47461
|
}
|
|
47140
47462
|
function read() {
|
|
47141
47463
|
try {
|
|
47142
|
-
const parsed = JSON.parse(
|
|
47464
|
+
const parsed = JSON.parse(fs47.readFileSync(storePath(), "utf-8"));
|
|
47143
47465
|
if (parsed && Array.isArray(parsed.entries)) return parsed;
|
|
47144
47466
|
} catch {
|
|
47145
47467
|
}
|
|
@@ -47148,11 +47470,11 @@ function read() {
|
|
|
47148
47470
|
function write(store) {
|
|
47149
47471
|
try {
|
|
47150
47472
|
const p = storePath();
|
|
47151
|
-
const dir =
|
|
47152
|
-
if (!
|
|
47473
|
+
const dir = path45.dirname(p);
|
|
47474
|
+
if (!fs47.existsSync(dir)) fs47.mkdirSync(dir, { recursive: true });
|
|
47153
47475
|
const tmp = `${p}.${process.pid}.tmp`;
|
|
47154
|
-
|
|
47155
|
-
|
|
47476
|
+
fs47.writeFileSync(tmp, JSON.stringify(store));
|
|
47477
|
+
fs47.renameSync(tmp, p);
|
|
47156
47478
|
} catch {
|
|
47157
47479
|
}
|
|
47158
47480
|
}
|
|
@@ -47265,9 +47587,9 @@ function registerCheckCommand(program2) {
|
|
|
47265
47587
|
} catch (err2) {
|
|
47266
47588
|
const tempConfig = getConfig();
|
|
47267
47589
|
if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
|
|
47268
|
-
const logPath =
|
|
47590
|
+
const logPath = path46.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
47269
47591
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
47270
|
-
|
|
47592
|
+
fs48.appendFileSync(
|
|
47271
47593
|
logPath,
|
|
47272
47594
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
|
|
47273
47595
|
RAW: ${raw}
|
|
@@ -47280,14 +47602,14 @@ RAW: ${raw}
|
|
|
47280
47602
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
47281
47603
|
if (process.env.NODE9_DEBUG === "1") {
|
|
47282
47604
|
try {
|
|
47283
|
-
const logPath =
|
|
47284
|
-
if (!
|
|
47285
|
-
|
|
47605
|
+
const logPath = path46.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
47606
|
+
if (!fs48.existsSync(path46.dirname(logPath)))
|
|
47607
|
+
fs48.mkdirSync(path46.dirname(logPath), { recursive: true });
|
|
47286
47608
|
const sanitized = JSON.stringify({
|
|
47287
47609
|
...payload,
|
|
47288
47610
|
prompt: `<redacted, ${prompt.length} bytes>`
|
|
47289
47611
|
});
|
|
47290
|
-
|
|
47612
|
+
fs48.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
|
|
47291
47613
|
`);
|
|
47292
47614
|
} catch {
|
|
47293
47615
|
}
|
|
@@ -47308,8 +47630,8 @@ RAW: ${raw}
|
|
|
47308
47630
|
);
|
|
47309
47631
|
const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
|
|
47310
47632
|
try {
|
|
47311
|
-
const ttyFd =
|
|
47312
|
-
|
|
47633
|
+
const ttyFd = fs48.openSync("/dev/tty", "w");
|
|
47634
|
+
fs48.writeSync(
|
|
47313
47635
|
ttyFd,
|
|
47314
47636
|
chalk9.bgRed.white.bold(`
|
|
47315
47637
|
\u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
|
|
@@ -47319,7 +47641,7 @@ RAW: ${raw}
|
|
|
47319
47641
|
|
|
47320
47642
|
`)
|
|
47321
47643
|
);
|
|
47322
|
-
|
|
47644
|
+
fs48.closeSync(ttyFd);
|
|
47323
47645
|
} catch {
|
|
47324
47646
|
}
|
|
47325
47647
|
const isCodex = agent2 === "Codex";
|
|
@@ -47338,16 +47660,17 @@ RAW: ${raw}
|
|
|
47338
47660
|
process.exit(2);
|
|
47339
47661
|
}
|
|
47340
47662
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
47341
|
-
const safeCwdForConfig = typeof payloadCwd === "string" &&
|
|
47663
|
+
const safeCwdForConfig = typeof payloadCwd === "string" && path46.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
47342
47664
|
const config = getConfig(safeCwdForConfig);
|
|
47343
|
-
|
|
47665
|
+
const daemonDown = !isDaemonRunning();
|
|
47666
|
+
if (config.settings.autoStartDaemon && daemonDown && !process.env.NODE9_NO_AUTO_DAEMON) {
|
|
47344
47667
|
try {
|
|
47345
47668
|
const scriptPath = process.argv[1];
|
|
47346
|
-
if (typeof scriptPath !== "string" || !
|
|
47669
|
+
if (typeof scriptPath !== "string" || !path46.isAbsolute(scriptPath))
|
|
47347
47670
|
throw new Error("node9: argv[1] is not an absolute path");
|
|
47348
|
-
const resolvedScript =
|
|
47349
|
-
const packageDist =
|
|
47350
|
-
if (!resolvedScript.startsWith(packageDist +
|
|
47671
|
+
const resolvedScript = fs48.realpathSync(scriptPath);
|
|
47672
|
+
const packageDist = fs48.realpathSync(path46.resolve(__dirname, "../.."));
|
|
47673
|
+
if (!resolvedScript.startsWith(packageDist + path46.sep) && resolvedScript !== packageDist)
|
|
47351
47674
|
throw new Error(
|
|
47352
47675
|
`node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
|
|
47353
47676
|
);
|
|
@@ -47362,17 +47685,27 @@ RAW: ${raw}
|
|
|
47362
47685
|
]) {
|
|
47363
47686
|
delete safeEnv[key];
|
|
47364
47687
|
}
|
|
47365
|
-
const
|
|
47366
|
-
|
|
47367
|
-
|
|
47368
|
-
|
|
47369
|
-
|
|
47370
|
-
|
|
47688
|
+
const startupFd = openStartupLogFd();
|
|
47689
|
+
try {
|
|
47690
|
+
const d = spawn5(process.execPath, [scriptPath, "daemon"], {
|
|
47691
|
+
detached: true,
|
|
47692
|
+
stdio: ["ignore", "ignore", startupFd ?? "ignore"],
|
|
47693
|
+
env: { ...safeEnv, NODE9_AUTO_STARTED: "1" }
|
|
47694
|
+
});
|
|
47695
|
+
d.unref();
|
|
47696
|
+
} finally {
|
|
47697
|
+
if (startupFd !== void 0) {
|
|
47698
|
+
try {
|
|
47699
|
+
fs48.closeSync(startupFd);
|
|
47700
|
+
} catch {
|
|
47701
|
+
}
|
|
47702
|
+
}
|
|
47703
|
+
}
|
|
47371
47704
|
} catch (spawnErr) {
|
|
47372
|
-
const logPath =
|
|
47705
|
+
const logPath = path46.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
47373
47706
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
47374
47707
|
try {
|
|
47375
|
-
|
|
47708
|
+
fs48.appendFileSync(
|
|
47376
47709
|
logPath,
|
|
47377
47710
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
|
|
47378
47711
|
`
|
|
@@ -47380,12 +47713,16 @@ RAW: ${raw}
|
|
|
47380
47713
|
} catch {
|
|
47381
47714
|
}
|
|
47382
47715
|
}
|
|
47716
|
+
} else if (daemonDown && !isTestingMode()) {
|
|
47717
|
+
logAutostartSkipThrottled(
|
|
47718
|
+
!config.settings.autoStartDaemon ? "autoStartDaemon=false" : process.env.NODE9_NO_AUTO_DAEMON ? "NODE9_NO_AUTO_DAEMON" : "unknown"
|
|
47719
|
+
);
|
|
47383
47720
|
}
|
|
47384
47721
|
if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
|
|
47385
|
-
const logPath =
|
|
47386
|
-
if (!
|
|
47387
|
-
|
|
47388
|
-
|
|
47722
|
+
const logPath = path46.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
47723
|
+
if (!fs48.existsSync(path46.dirname(logPath)))
|
|
47724
|
+
fs48.mkdirSync(path46.dirname(logPath), { recursive: true });
|
|
47725
|
+
fs48.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
|
|
47389
47726
|
`);
|
|
47390
47727
|
}
|
|
47391
47728
|
const rawToolName = sanitize2(extractToolName(payload));
|
|
@@ -47399,8 +47736,8 @@ RAW: ${raw}
|
|
|
47399
47736
|
const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
|
|
47400
47737
|
let ttyFd = null;
|
|
47401
47738
|
try {
|
|
47402
|
-
ttyFd =
|
|
47403
|
-
const writeTty = (line) =>
|
|
47739
|
+
ttyFd = fs48.openSync("/dev/tty", "w");
|
|
47740
|
+
const writeTty = (line) => fs48.writeSync(ttyFd, line + "\n");
|
|
47404
47741
|
if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
|
|
47405
47742
|
writeTty(chalk9.bgRed.white.bold(`
|
|
47406
47743
|
\u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
|
|
@@ -47419,7 +47756,7 @@ RAW: ${raw}
|
|
|
47419
47756
|
} finally {
|
|
47420
47757
|
if (ttyFd !== null)
|
|
47421
47758
|
try {
|
|
47422
|
-
|
|
47759
|
+
fs48.closeSync(ttyFd);
|
|
47423
47760
|
} catch {
|
|
47424
47761
|
}
|
|
47425
47762
|
}
|
|
@@ -47476,8 +47813,8 @@ RAW: ${raw}
|
|
|
47476
47813
|
} catch {
|
|
47477
47814
|
}
|
|
47478
47815
|
try {
|
|
47479
|
-
const ttyFd =
|
|
47480
|
-
|
|
47816
|
+
const ttyFd = fs48.openSync("/dev/tty", "w");
|
|
47817
|
+
fs48.writeSync(
|
|
47481
47818
|
ttyFd,
|
|
47482
47819
|
chalk9.yellow(
|
|
47483
47820
|
`
|
|
@@ -47485,7 +47822,7 @@ RAW: ${raw}
|
|
|
47485
47822
|
`
|
|
47486
47823
|
)
|
|
47487
47824
|
);
|
|
47488
|
-
|
|
47825
|
+
fs48.closeSync(ttyFd);
|
|
47489
47826
|
} catch {
|
|
47490
47827
|
}
|
|
47491
47828
|
if (agent === "GitHub Copilot") {
|
|
@@ -47517,17 +47854,17 @@ RAW: ${raw}
|
|
|
47517
47854
|
const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
|
|
47518
47855
|
if (skillPinCfg.enabled && safeSessionId) {
|
|
47519
47856
|
try {
|
|
47520
|
-
const sessionsDir =
|
|
47521
|
-
const flagPath =
|
|
47857
|
+
const sessionsDir = path46.join(os44.homedir(), ".node9", "skill-sessions");
|
|
47858
|
+
const flagPath = path46.join(sessionsDir, `${safeSessionId}.json`);
|
|
47522
47859
|
let flag = null;
|
|
47523
47860
|
try {
|
|
47524
|
-
flag = JSON.parse(
|
|
47861
|
+
flag = JSON.parse(fs48.readFileSync(flagPath, "utf-8"));
|
|
47525
47862
|
} catch {
|
|
47526
47863
|
}
|
|
47527
47864
|
const writeFlag = (data2) => {
|
|
47528
47865
|
try {
|
|
47529
|
-
|
|
47530
|
-
|
|
47866
|
+
fs48.mkdirSync(sessionsDir, { recursive: true });
|
|
47867
|
+
fs48.writeFileSync(
|
|
47531
47868
|
flagPath,
|
|
47532
47869
|
JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
47533
47870
|
{ mode: 384 }
|
|
@@ -47538,8 +47875,8 @@ RAW: ${raw}
|
|
|
47538
47875
|
const sendSkillWarn = (detail, recoveryCmd) => {
|
|
47539
47876
|
let ttyFd = null;
|
|
47540
47877
|
try {
|
|
47541
|
-
ttyFd =
|
|
47542
|
-
const w = (line) =>
|
|
47878
|
+
ttyFd = fs48.openSync("/dev/tty", "w");
|
|
47879
|
+
const w = (line) => fs48.writeSync(ttyFd, line + "\n");
|
|
47543
47880
|
w(chalk9.yellow(`
|
|
47544
47881
|
\u26A0\uFE0F Node9: installed skill drift detected`));
|
|
47545
47882
|
w(chalk9.gray(` ${detail}`));
|
|
@@ -47554,7 +47891,7 @@ RAW: ${raw}
|
|
|
47554
47891
|
} finally {
|
|
47555
47892
|
if (ttyFd !== null)
|
|
47556
47893
|
try {
|
|
47557
|
-
|
|
47894
|
+
fs48.closeSync(ttyFd);
|
|
47558
47895
|
} catch {
|
|
47559
47896
|
}
|
|
47560
47897
|
}
|
|
@@ -47570,7 +47907,7 @@ RAW: ${raw}
|
|
|
47570
47907
|
return;
|
|
47571
47908
|
}
|
|
47572
47909
|
if (!flag || flag.state !== "verified" && flag.state !== "warned") {
|
|
47573
|
-
const absoluteCwd = typeof payloadCwd === "string" &&
|
|
47910
|
+
const absoluteCwd = typeof payloadCwd === "string" && path46.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
47574
47911
|
const extraRoots = skillPinCfg.roots;
|
|
47575
47912
|
const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
|
|
47576
47913
|
const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
|
|
@@ -47611,10 +47948,10 @@ RAW: ${raw}
|
|
|
47611
47948
|
}
|
|
47612
47949
|
try {
|
|
47613
47950
|
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
47614
|
-
for (const name of
|
|
47615
|
-
const p =
|
|
47951
|
+
for (const name of fs48.readdirSync(sessionsDir)) {
|
|
47952
|
+
const p = path46.join(sessionsDir, name);
|
|
47616
47953
|
try {
|
|
47617
|
-
if (
|
|
47954
|
+
if (fs48.statSync(p).mtimeMs < cutoff) fs48.unlinkSync(p);
|
|
47618
47955
|
} catch {
|
|
47619
47956
|
}
|
|
47620
47957
|
}
|
|
@@ -47624,9 +47961,9 @@ RAW: ${raw}
|
|
|
47624
47961
|
} catch (err2) {
|
|
47625
47962
|
if (process.env.NODE9_DEBUG === "1") {
|
|
47626
47963
|
try {
|
|
47627
|
-
const dbg =
|
|
47964
|
+
const dbg = path46.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
47628
47965
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
47629
|
-
|
|
47966
|
+
fs48.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
|
|
47630
47967
|
`);
|
|
47631
47968
|
} catch {
|
|
47632
47969
|
}
|
|
@@ -47636,7 +47973,7 @@ RAW: ${raw}
|
|
|
47636
47973
|
if (shouldSnapshot(toolName, toolInput, config)) {
|
|
47637
47974
|
await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
|
|
47638
47975
|
}
|
|
47639
|
-
const safeCwdForAuth = typeof payloadCwd === "string" &&
|
|
47976
|
+
const safeCwdForAuth = typeof payloadCwd === "string" && path46.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
47640
47977
|
const askMode = resolveAskMode(agent, opts, config);
|
|
47641
47978
|
const result = await authorizeHeadless(toolName, toolInput, meta, {
|
|
47642
47979
|
cwd: safeCwdForAuth,
|
|
@@ -47654,12 +47991,12 @@ RAW: ${raw}
|
|
|
47654
47991
|
}
|
|
47655
47992
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
|
|
47656
47993
|
try {
|
|
47657
|
-
const tty =
|
|
47658
|
-
|
|
47994
|
+
const tty = fs48.openSync("/dev/tty", "w");
|
|
47995
|
+
fs48.writeSync(
|
|
47659
47996
|
tty,
|
|
47660
47997
|
chalk9.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
|
|
47661
47998
|
);
|
|
47662
|
-
|
|
47999
|
+
fs48.closeSync(tty);
|
|
47663
48000
|
} catch {
|
|
47664
48001
|
}
|
|
47665
48002
|
const daemonReady = await autoStartDaemonAndWait();
|
|
@@ -47686,9 +48023,9 @@ RAW: ${raw}
|
|
|
47686
48023
|
});
|
|
47687
48024
|
} catch (err2) {
|
|
47688
48025
|
if (process.env.NODE9_DEBUG === "1") {
|
|
47689
|
-
const logPath =
|
|
48026
|
+
const logPath = path46.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
47690
48027
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
47691
|
-
|
|
48028
|
+
fs48.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
|
|
47692
48029
|
`);
|
|
47693
48030
|
}
|
|
47694
48031
|
process.exit(0);
|
|
@@ -47724,9 +48061,9 @@ RAW: ${raw}
|
|
|
47724
48061
|
// src/cli/commands/log.ts
|
|
47725
48062
|
init_audit();
|
|
47726
48063
|
init_config();
|
|
47727
|
-
import
|
|
47728
|
-
import
|
|
47729
|
-
import
|
|
48064
|
+
import fs49 from "fs";
|
|
48065
|
+
import path47 from "path";
|
|
48066
|
+
import os45 from "os";
|
|
47730
48067
|
init_daemon();
|
|
47731
48068
|
init_dlp();
|
|
47732
48069
|
|
|
@@ -47834,10 +48171,10 @@ function registerLogCommand(program2) {
|
|
|
47834
48171
|
if (rawToolName !== tool) entry.agentToolName = rawToolName;
|
|
47835
48172
|
const payloadSessionId = payload.session_id ?? payload.conversationId;
|
|
47836
48173
|
if (payloadSessionId) entry.sessionId = payloadSessionId;
|
|
47837
|
-
const logPath =
|
|
47838
|
-
if (!
|
|
47839
|
-
|
|
47840
|
-
|
|
48174
|
+
const logPath = path47.join(os45.homedir(), ".node9", "audit.log");
|
|
48175
|
+
if (!fs49.existsSync(path47.dirname(logPath)))
|
|
48176
|
+
fs49.mkdirSync(path47.dirname(logPath), { recursive: true });
|
|
48177
|
+
fs49.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
47841
48178
|
if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
|
|
47842
48179
|
const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
47843
48180
|
if (command) {
|
|
@@ -47871,7 +48208,7 @@ function registerLogCommand(program2) {
|
|
|
47871
48208
|
}
|
|
47872
48209
|
}
|
|
47873
48210
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
47874
|
-
const safeCwd = typeof payloadCwd === "string" &&
|
|
48211
|
+
const safeCwd = typeof payloadCwd === "string" && path47.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
47875
48212
|
const config = getConfig(safeCwd);
|
|
47876
48213
|
{
|
|
47877
48214
|
const toolOutput = payload.tool_response?.output;
|
|
@@ -47948,9 +48285,9 @@ function registerLogCommand(program2) {
|
|
|
47948
48285
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
47949
48286
|
process.stderr.write(`[Node9] audit log error: ${msg}
|
|
47950
48287
|
`);
|
|
47951
|
-
const debugPath =
|
|
48288
|
+
const debugPath = path47.join(os45.homedir(), ".node9", "hook-debug.log");
|
|
47952
48289
|
try {
|
|
47953
|
-
|
|
48290
|
+
fs49.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
|
|
47954
48291
|
`);
|
|
47955
48292
|
} catch {
|
|
47956
48293
|
}
|
|
@@ -47977,16 +48314,16 @@ function registerLogCommand(program2) {
|
|
|
47977
48314
|
init_shields();
|
|
47978
48315
|
init_build();
|
|
47979
48316
|
import chalk10 from "chalk";
|
|
47980
|
-
import
|
|
47981
|
-
import
|
|
47982
|
-
import
|
|
48317
|
+
import fs51 from "fs";
|
|
48318
|
+
import path49 from "path";
|
|
48319
|
+
import os46 from "os";
|
|
47983
48320
|
|
|
47984
48321
|
// src/shields/create.ts
|
|
47985
48322
|
init_dist();
|
|
47986
48323
|
init_shields();
|
|
47987
48324
|
init_audit();
|
|
47988
|
-
import
|
|
47989
|
-
import
|
|
48325
|
+
import fs50 from "fs";
|
|
48326
|
+
import path48 from "path";
|
|
47990
48327
|
function builtinNames() {
|
|
47991
48328
|
const names = /* @__PURE__ */ new Set();
|
|
47992
48329
|
for (const def of Object.values(BUILTIN_SHIELDS)) {
|
|
@@ -48003,8 +48340,8 @@ function createShield(def, opts = {}) {
|
|
|
48003
48340
|
error: `"${name}" is a built-in shield \u2014 choose a different name (a user shield with this name would shadow the built-in).`
|
|
48004
48341
|
};
|
|
48005
48342
|
}
|
|
48006
|
-
const filePath =
|
|
48007
|
-
if (!opts.overwrite &&
|
|
48343
|
+
const filePath = path48.join(USER_SHIELDS_DIR_PATH, `${name}.json`);
|
|
48344
|
+
if (!opts.overwrite && fs50.existsSync(filePath)) {
|
|
48008
48345
|
return {
|
|
48009
48346
|
ok: false,
|
|
48010
48347
|
error: `Shield "${name}" already exists at ${filePath}. Pass --overwrite to replace it.`
|
|
@@ -48069,8 +48406,8 @@ var COMMUNITY_INDEX_URL = "https://raw.githubusercontent.com/node9ai/node9-proxy
|
|
|
48069
48406
|
function readCloudShields() {
|
|
48070
48407
|
const out = /* @__PURE__ */ new Set();
|
|
48071
48408
|
try {
|
|
48072
|
-
const file =
|
|
48073
|
-
const raw = JSON.parse(
|
|
48409
|
+
const file = path49.join(os46.homedir(), ".node9", "rules-cache.json");
|
|
48410
|
+
const raw = JSON.parse(fs51.readFileSync(file, "utf-8"));
|
|
48074
48411
|
for (const r of raw.rules ?? []) {
|
|
48075
48412
|
const rule = r;
|
|
48076
48413
|
const fromSource = rule.source?.startsWith("SHIELD:") ? rule.source.slice("SHIELD:".length).toLowerCase() : void 0;
|
|
@@ -48387,7 +48724,7 @@ function registerShieldCommand(program2) {
|
|
|
48387
48724
|
if (opts.fromFile) {
|
|
48388
48725
|
let raw;
|
|
48389
48726
|
try {
|
|
48390
|
-
raw = JSON.parse(
|
|
48727
|
+
raw = JSON.parse(fs51.readFileSync(opts.fromFile, "utf-8"));
|
|
48391
48728
|
} catch (err2) {
|
|
48392
48729
|
console.error(
|
|
48393
48730
|
chalk10.red(`
|
|
@@ -48509,14 +48846,31 @@ function registerConfigShowCommand(program2) {
|
|
|
48509
48846
|
init_daemon();
|
|
48510
48847
|
init_config();
|
|
48511
48848
|
init_agent_wiring();
|
|
48849
|
+
init_sync();
|
|
48850
|
+
init_service();
|
|
48512
48851
|
import chalk11 from "chalk";
|
|
48513
|
-
import
|
|
48514
|
-
import
|
|
48515
|
-
import
|
|
48852
|
+
import fs52 from "fs";
|
|
48853
|
+
import path50 from "path";
|
|
48854
|
+
import os47 from "os";
|
|
48516
48855
|
import { execSync } from "child_process";
|
|
48856
|
+
|
|
48857
|
+
// src/lib/relative-time.ts
|
|
48858
|
+
function agoLabel(iso, now = Date.now()) {
|
|
48859
|
+
const ms = now - new Date(iso).getTime();
|
|
48860
|
+
if (!Number.isFinite(ms) || ms < 0) return "just now";
|
|
48861
|
+
const min = Math.floor(ms / 6e4);
|
|
48862
|
+
if (min < 1) return "just now";
|
|
48863
|
+
if (min < 60) return `${min} min ago`;
|
|
48864
|
+
const hr = Math.floor(min / 60);
|
|
48865
|
+
if (hr < 24) return `${hr} hour${hr === 1 ? "" : "s"} ago`;
|
|
48866
|
+
const d = Math.floor(hr / 24);
|
|
48867
|
+
return `${d} day${d === 1 ? "" : "s"} ago`;
|
|
48868
|
+
}
|
|
48869
|
+
|
|
48870
|
+
// src/cli/commands/doctor.ts
|
|
48517
48871
|
function registerDoctorCommand(program2, version2) {
|
|
48518
48872
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
|
|
48519
|
-
const homeDir2 =
|
|
48873
|
+
const homeDir2 = os47.homedir();
|
|
48520
48874
|
let failures = 0;
|
|
48521
48875
|
function pass(msg) {
|
|
48522
48876
|
console.log(chalk11.green(" \u2705 ") + msg);
|
|
@@ -48562,10 +48916,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48562
48916
|
);
|
|
48563
48917
|
}
|
|
48564
48918
|
section("Configuration");
|
|
48565
|
-
const globalConfigPath =
|
|
48566
|
-
if (
|
|
48919
|
+
const globalConfigPath = path50.join(homeDir2, ".node9", "config.json");
|
|
48920
|
+
if (fs52.existsSync(globalConfigPath)) {
|
|
48567
48921
|
try {
|
|
48568
|
-
JSON.parse(
|
|
48922
|
+
JSON.parse(fs52.readFileSync(globalConfigPath, "utf-8"));
|
|
48569
48923
|
pass("~/.node9/config.json found and valid");
|
|
48570
48924
|
} catch {
|
|
48571
48925
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -48573,10 +48927,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48573
48927
|
} else {
|
|
48574
48928
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
48575
48929
|
}
|
|
48576
|
-
const projectConfigPath =
|
|
48577
|
-
if (
|
|
48930
|
+
const projectConfigPath = path50.join(process.cwd(), "node9.config.json");
|
|
48931
|
+
if (fs52.existsSync(projectConfigPath)) {
|
|
48578
48932
|
try {
|
|
48579
|
-
JSON.parse(
|
|
48933
|
+
JSON.parse(fs52.readFileSync(projectConfigPath, "utf-8"));
|
|
48580
48934
|
pass("node9.config.json found and valid (project)");
|
|
48581
48935
|
} catch {
|
|
48582
48936
|
fail(
|
|
@@ -48585,8 +48939,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48585
48939
|
);
|
|
48586
48940
|
}
|
|
48587
48941
|
}
|
|
48588
|
-
const credsPath =
|
|
48589
|
-
if (
|
|
48942
|
+
const credsPath = path50.join(homeDir2, ".node9", "credentials.json");
|
|
48943
|
+
if (fs52.existsSync(credsPath)) {
|
|
48590
48944
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
48591
48945
|
} else {
|
|
48592
48946
|
warn(
|
|
@@ -48626,11 +48980,31 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48626
48980
|
"Run: node9 daemon --background"
|
|
48627
48981
|
);
|
|
48628
48982
|
}
|
|
48983
|
+
const autostart = autostartAdvice({
|
|
48984
|
+
installed: isDaemonServiceInstalled(),
|
|
48985
|
+
enabled: isDaemonServiceEnabled(),
|
|
48986
|
+
cloudEnabled: !!getConfig().settings.approvers?.cloud
|
|
48987
|
+
});
|
|
48988
|
+
if (autostart) warn(autostart.message, autostart.hint);
|
|
48989
|
+
if (fs52.existsSync(path50.join(os47.homedir(), ".node9", "credentials.json")) && getConfig().settings.approvers?.cloud) {
|
|
48990
|
+
section("Policy sync");
|
|
48991
|
+
const health = readSyncHealth();
|
|
48992
|
+
if (isPolicyStale(Date.now(), health)) {
|
|
48993
|
+
const when = health.lastCheckedAt ? `last reached the cloud ${agoLabel(health.lastCheckedAt)}` : "never reached the cloud";
|
|
48994
|
+
const fails = health.consecutiveFailures > 0 ? ` (${health.consecutiveFailures} consecutive failure${health.consecutiveFailures === 1 ? "" : "s"}${health.lastError ? `: ${health.lastError}` : ""})` : "";
|
|
48995
|
+
warn(
|
|
48996
|
+
`Cloud policy is STALE \u2014 ${when}${fails}. The cached policy is still enforced, but changes from the dashboard are not reaching this machine.`,
|
|
48997
|
+
"Run: node9 policy sync (and ensure the daemon autostarts: systemctl --user enable --now node9-daemon)"
|
|
48998
|
+
);
|
|
48999
|
+
} else if (health.lastCheckedAt) {
|
|
49000
|
+
pass(`Cloud policy fresh \u2014 last synced ${agoLabel(health.lastCheckedAt)}`);
|
|
49001
|
+
}
|
|
49002
|
+
}
|
|
48629
49003
|
section("Cloud audit shipping");
|
|
48630
49004
|
try {
|
|
48631
49005
|
const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
|
|
48632
49006
|
const cfg = getConfig();
|
|
48633
|
-
const creds =
|
|
49007
|
+
const creds = fs52.existsSync(path50.join(os47.homedir(), ".node9", "credentials.json"));
|
|
48634
49008
|
if (!creds) {
|
|
48635
49009
|
warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
|
|
48636
49010
|
} else if (!cfg.settings.approvers.cloud) {
|
|
@@ -48680,9 +49054,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48680
49054
|
|
|
48681
49055
|
// src/cli/commands/audit.ts
|
|
48682
49056
|
import chalk12 from "chalk";
|
|
48683
|
-
import
|
|
48684
|
-
import
|
|
48685
|
-
import
|
|
49057
|
+
import fs53 from "fs";
|
|
49058
|
+
import path51 from "path";
|
|
49059
|
+
import os48 from "os";
|
|
48686
49060
|
function formatRelativeTime(timestamp) {
|
|
48687
49061
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
48688
49062
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -48695,14 +49069,14 @@ function formatRelativeTime(timestamp) {
|
|
|
48695
49069
|
}
|
|
48696
49070
|
function registerAuditCommand(program2) {
|
|
48697
49071
|
program2.command("audit").description("View local execution audit log").option("--tail <n>", "Number of entries to show", "20").option("--tool <pattern>", "Filter by tool name (substring match)").option("--deny", "Show only denied actions").option("--json", "Output raw JSON").action((options) => {
|
|
48698
|
-
const logPath =
|
|
48699
|
-
if (!
|
|
49072
|
+
const logPath = path51.join(os48.homedir(), ".node9", "audit.log");
|
|
49073
|
+
if (!fs53.existsSync(logPath)) {
|
|
48700
49074
|
console.log(
|
|
48701
49075
|
chalk12.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
48702
49076
|
);
|
|
48703
49077
|
return;
|
|
48704
49078
|
}
|
|
48705
|
-
const raw =
|
|
49079
|
+
const raw = fs53.readFileSync(logPath, "utf-8");
|
|
48706
49080
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
48707
49081
|
let entries = lines.flatMap((line) => {
|
|
48708
49082
|
try {
|
|
@@ -48761,9 +49135,9 @@ import chalk13 from "chalk";
|
|
|
48761
49135
|
init_costSync();
|
|
48762
49136
|
init_litellm();
|
|
48763
49137
|
init_cost_codex();
|
|
48764
|
-
import
|
|
48765
|
-
import
|
|
48766
|
-
import
|
|
49138
|
+
import fs54 from "fs";
|
|
49139
|
+
import os49 from "os";
|
|
49140
|
+
import path52 from "path";
|
|
48767
49141
|
var TEST_COMMAND_RE3 = /(?:^|\s)(npm\s+(?:run\s+)?test|npx\s+(?:vitest|jest|mocha)|yarn\s+(?:run\s+)?test|pnpm\s+(?:run\s+)?test|vitest|jest|mocha|pytest|py\.test|cargo\s+test|go\s+test|bundle\s+exec\s+rspec|rspec|phpunit|dotnet\s+test)\b/i;
|
|
48768
49142
|
function buildTestTimestamps(allEntries) {
|
|
48769
49143
|
const testTs = /* @__PURE__ */ new Set();
|
|
@@ -48843,8 +49217,8 @@ function getDateRange(period, now) {
|
|
|
48843
49217
|
}
|
|
48844
49218
|
}
|
|
48845
49219
|
function parseAuditLog(logPath) {
|
|
48846
|
-
if (!
|
|
48847
|
-
const raw =
|
|
49220
|
+
if (!fs54.existsSync(logPath)) return [];
|
|
49221
|
+
const raw = fs54.readFileSync(logPath, "utf-8");
|
|
48848
49222
|
return raw.split("\n").flatMap((line) => {
|
|
48849
49223
|
if (!line.trim()) return [];
|
|
48850
49224
|
try {
|
|
@@ -48891,25 +49265,25 @@ function freezeClaudeCost(acc) {
|
|
|
48891
49265
|
};
|
|
48892
49266
|
}
|
|
48893
49267
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
48894
|
-
const projPath =
|
|
49268
|
+
const projPath = path52.join(projectsDir, proj);
|
|
48895
49269
|
let files;
|
|
48896
49270
|
try {
|
|
48897
|
-
const stat =
|
|
49271
|
+
const stat = fs54.statSync(projPath);
|
|
48898
49272
|
if (!stat.isDirectory()) return;
|
|
48899
|
-
files =
|
|
49273
|
+
files = fs54.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
48900
49274
|
} catch {
|
|
48901
49275
|
return;
|
|
48902
49276
|
}
|
|
48903
49277
|
const startMs = start.getTime();
|
|
48904
49278
|
for (const file of files) {
|
|
48905
|
-
const filePath =
|
|
49279
|
+
const filePath = path52.join(projPath, file);
|
|
48906
49280
|
try {
|
|
48907
|
-
if (
|
|
49281
|
+
if (fs54.statSync(filePath).mtimeMs < startMs) continue;
|
|
48908
49282
|
} catch {
|
|
48909
49283
|
continue;
|
|
48910
49284
|
}
|
|
48911
49285
|
try {
|
|
48912
|
-
const raw =
|
|
49286
|
+
const raw = fs54.readFileSync(filePath, "utf-8");
|
|
48913
49287
|
for (const line of raw.split("\n")) {
|
|
48914
49288
|
if (!line.trim()) continue;
|
|
48915
49289
|
let entry;
|
|
@@ -48959,10 +49333,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
48959
49333
|
}
|
|
48960
49334
|
function loadClaudeCost(start, end, projectsDir) {
|
|
48961
49335
|
const acc = emptyClaudeCostAccumulator();
|
|
48962
|
-
if (!
|
|
49336
|
+
if (!fs54.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
48963
49337
|
let dirs;
|
|
48964
49338
|
try {
|
|
48965
|
-
dirs =
|
|
49339
|
+
dirs = fs54.readdirSync(projectsDir);
|
|
48966
49340
|
} catch {
|
|
48967
49341
|
return freezeClaudeCost(acc);
|
|
48968
49342
|
}
|
|
@@ -48974,7 +49348,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
48974
49348
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
48975
49349
|
let lines;
|
|
48976
49350
|
try {
|
|
48977
|
-
lines =
|
|
49351
|
+
lines = fs54.readFileSync(filePath, "utf-8").split("\n");
|
|
48978
49352
|
} catch {
|
|
48979
49353
|
return;
|
|
48980
49354
|
}
|
|
@@ -49029,31 +49403,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
49029
49403
|
}
|
|
49030
49404
|
function listCodexSessionFiles2(sessionsBase) {
|
|
49031
49405
|
const jsonlFiles = [];
|
|
49032
|
-
if (!
|
|
49406
|
+
if (!fs54.existsSync(sessionsBase)) return jsonlFiles;
|
|
49033
49407
|
try {
|
|
49034
|
-
for (const year of
|
|
49035
|
-
const yearPath =
|
|
49408
|
+
for (const year of fs54.readdirSync(sessionsBase)) {
|
|
49409
|
+
const yearPath = path52.join(sessionsBase, year);
|
|
49036
49410
|
try {
|
|
49037
|
-
if (!
|
|
49411
|
+
if (!fs54.statSync(yearPath).isDirectory()) continue;
|
|
49038
49412
|
} catch {
|
|
49039
49413
|
continue;
|
|
49040
49414
|
}
|
|
49041
|
-
for (const month of
|
|
49042
|
-
const monthPath =
|
|
49415
|
+
for (const month of fs54.readdirSync(yearPath)) {
|
|
49416
|
+
const monthPath = path52.join(yearPath, month);
|
|
49043
49417
|
try {
|
|
49044
|
-
if (!
|
|
49418
|
+
if (!fs54.statSync(monthPath).isDirectory()) continue;
|
|
49045
49419
|
} catch {
|
|
49046
49420
|
continue;
|
|
49047
49421
|
}
|
|
49048
|
-
for (const day of
|
|
49049
|
-
const dayPath =
|
|
49422
|
+
for (const day of fs54.readdirSync(monthPath)) {
|
|
49423
|
+
const dayPath = path52.join(monthPath, day);
|
|
49050
49424
|
try {
|
|
49051
|
-
if (!
|
|
49425
|
+
if (!fs54.statSync(dayPath).isDirectory()) continue;
|
|
49052
49426
|
} catch {
|
|
49053
49427
|
continue;
|
|
49054
49428
|
}
|
|
49055
|
-
for (const file of
|
|
49056
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
49429
|
+
for (const file of fs54.readdirSync(dayPath)) {
|
|
49430
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path52.join(dayPath, file));
|
|
49057
49431
|
}
|
|
49058
49432
|
}
|
|
49059
49433
|
}
|
|
@@ -49118,13 +49492,13 @@ function freezeGeminiCost(acc) {
|
|
|
49118
49492
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
49119
49493
|
const startMs = start.getTime();
|
|
49120
49494
|
try {
|
|
49121
|
-
if (
|
|
49495
|
+
if (fs54.statSync(filePath).mtimeMs < startMs) return;
|
|
49122
49496
|
} catch {
|
|
49123
49497
|
return;
|
|
49124
49498
|
}
|
|
49125
49499
|
let raw;
|
|
49126
49500
|
try {
|
|
49127
|
-
raw =
|
|
49501
|
+
raw = fs54.readFileSync(filePath, "utf-8");
|
|
49128
49502
|
} catch {
|
|
49129
49503
|
return;
|
|
49130
49504
|
}
|
|
@@ -49173,30 +49547,30 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
|
|
|
49173
49547
|
const out = [];
|
|
49174
49548
|
let dirs;
|
|
49175
49549
|
try {
|
|
49176
|
-
if (!
|
|
49177
|
-
dirs =
|
|
49550
|
+
if (!fs54.statSync(geminiTmpDir2).isDirectory()) return out;
|
|
49551
|
+
dirs = fs54.readdirSync(geminiTmpDir2);
|
|
49178
49552
|
} catch {
|
|
49179
49553
|
return out;
|
|
49180
49554
|
}
|
|
49181
49555
|
for (const proj of dirs) {
|
|
49182
|
-
const chatsDir =
|
|
49556
|
+
const chatsDir = path52.join(geminiTmpDir2, proj, "chats");
|
|
49183
49557
|
let files;
|
|
49184
49558
|
try {
|
|
49185
|
-
if (!
|
|
49186
|
-
files =
|
|
49559
|
+
if (!fs54.statSync(chatsDir).isDirectory()) continue;
|
|
49560
|
+
files = fs54.readdirSync(chatsDir);
|
|
49187
49561
|
} catch {
|
|
49188
49562
|
continue;
|
|
49189
49563
|
}
|
|
49190
49564
|
for (const f of files) {
|
|
49191
49565
|
if (!f.endsWith(".jsonl")) continue;
|
|
49192
|
-
out.push({ projectKey: proj, file:
|
|
49566
|
+
out.push({ projectKey: proj, file: path52.join(chatsDir, f) });
|
|
49193
49567
|
}
|
|
49194
49568
|
}
|
|
49195
49569
|
return out;
|
|
49196
49570
|
}
|
|
49197
49571
|
function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
49198
49572
|
const acc = emptyGeminiAccumulator();
|
|
49199
|
-
if (!
|
|
49573
|
+
if (!fs54.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
|
|
49200
49574
|
for (const { projectKey, file } of listGeminiSessionFiles2(geminiTmpDir2)) {
|
|
49201
49575
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
49202
49576
|
}
|
|
@@ -49214,11 +49588,11 @@ function dimensionOfBlock(checkedBy, ruleName) {
|
|
|
49214
49588
|
}
|
|
49215
49589
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
49216
49590
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
49217
|
-
const auditLogPath = opts.auditLogPath ??
|
|
49218
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
49219
|
-
const codexSessionsDir2 = opts.codexSessionsDir ??
|
|
49220
|
-
const geminiTmpDir2 = opts.geminiTmpDir ??
|
|
49221
|
-
const hasAuditFile =
|
|
49591
|
+
const auditLogPath = opts.auditLogPath ?? path52.join(os49.homedir(), ".node9", "audit.log");
|
|
49592
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? path52.join(os49.homedir(), ".claude", "projects");
|
|
49593
|
+
const codexSessionsDir2 = opts.codexSessionsDir ?? path52.join(os49.homedir(), ".codex", "sessions");
|
|
49594
|
+
const geminiTmpDir2 = opts.geminiTmpDir ?? path52.join(os49.homedir(), ".gemini", "tmp");
|
|
49595
|
+
const hasAuditFile = fs54.existsSync(auditLogPath);
|
|
49222
49596
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
49223
49597
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
49224
49598
|
const { start, end } = getDateRange(period, now);
|
|
@@ -50011,10 +50385,12 @@ function registerDaemonCommand(program2) {
|
|
|
50011
50385
|
init_core();
|
|
50012
50386
|
init_daemon();
|
|
50013
50387
|
init_agent_wiring();
|
|
50388
|
+
init_sync();
|
|
50389
|
+
init_service();
|
|
50014
50390
|
import chalk15 from "chalk";
|
|
50015
|
-
import
|
|
50016
|
-
import
|
|
50017
|
-
import
|
|
50391
|
+
import fs55 from "fs";
|
|
50392
|
+
import path53 from "path";
|
|
50393
|
+
import os50 from "os";
|
|
50018
50394
|
function printAgentSection(label2, hookPairs, wrapped) {
|
|
50019
50395
|
console.log(chalk15.bold(` ${label2}`));
|
|
50020
50396
|
for (const { name, present } of hookPairs) {
|
|
@@ -50043,6 +50419,15 @@ function registerStatusCommand(program2) {
|
|
|
50043
50419
|
console.log("");
|
|
50044
50420
|
if (creds && settings.approvers.cloud) {
|
|
50045
50421
|
console.log(chalk15.green(" \u25CF Agent mode") + chalk15.gray(" \u2014 cloud team policy enforced"));
|
|
50422
|
+
const health = readSyncHealth();
|
|
50423
|
+
if (isPolicyStale(Date.now(), health)) {
|
|
50424
|
+
const when = health.lastCheckedAt ? `last synced ${agoLabel(health.lastCheckedAt)}` : "never synced";
|
|
50425
|
+
const fails = health.consecutiveFailures > 0 ? ` \xB7 ${health.consecutiveFailures} failed attempt${health.consecutiveFailures === 1 ? "" : "s"}${health.lastError ? ` (${health.lastError})` : ""}` : "";
|
|
50426
|
+
console.log(chalk15.yellow(" \u26A0 Policy sync STALE") + chalk15.gray(` \u2014 ${when}${fails}`));
|
|
50427
|
+
console.log(chalk15.gray(" the cached policy is still enforced \u2014 run: node9 doctor"));
|
|
50428
|
+
} else if (health.lastCheckedAt) {
|
|
50429
|
+
console.log(chalk15.gray(` \u21B3 policy synced ${agoLabel(health.lastCheckedAt)}`));
|
|
50430
|
+
}
|
|
50046
50431
|
} else if (creds && !settings.approvers.cloud) {
|
|
50047
50432
|
console.log(
|
|
50048
50433
|
chalk15.blue(" \u25CF Privacy mode \u{1F6E1}\uFE0F") + chalk15.gray(" \u2014 all decisions stay on this machine")
|
|
@@ -50060,6 +50445,16 @@ function registerStatusCommand(program2) {
|
|
|
50060
50445
|
} else {
|
|
50061
50446
|
console.log(chalk15.gray(" \u25CB Daemon stopped"));
|
|
50062
50447
|
}
|
|
50448
|
+
const autostart = autostartAdvice({
|
|
50449
|
+
installed: isDaemonServiceInstalled(),
|
|
50450
|
+
enabled: isDaemonServiceEnabled(),
|
|
50451
|
+
cloudEnabled: !!(creds && settings.approvers.cloud)
|
|
50452
|
+
});
|
|
50453
|
+
if (autostart) {
|
|
50454
|
+
console.log(
|
|
50455
|
+
chalk15.yellow(" \u26A0 daemon autostart not active") + chalk15.gray(" \u2014 won't survive reboot; run: node9 doctor")
|
|
50456
|
+
);
|
|
50457
|
+
}
|
|
50063
50458
|
if (settings.enableUndo) {
|
|
50064
50459
|
console.log(
|
|
50065
50460
|
chalk15.magenta(" \u25CF Undo Engine") + chalk15.gray(` \u2192 Auto-snapshotting Git repos on AI change`)
|
|
@@ -50068,20 +50463,20 @@ function registerStatusCommand(program2) {
|
|
|
50068
50463
|
console.log("");
|
|
50069
50464
|
const modeLabel = settings.mode === "audit" ? chalk15.blue("audit") : settings.mode === "strict" ? chalk15.red("strict") : chalk15.white("standard");
|
|
50070
50465
|
console.log(` Mode: ${modeLabel}`);
|
|
50071
|
-
const projectConfig =
|
|
50072
|
-
const globalConfig =
|
|
50466
|
+
const projectConfig = path53.join(process.cwd(), "node9.config.json");
|
|
50467
|
+
const globalConfig = path53.join(os50.homedir(), ".node9", "config.json");
|
|
50073
50468
|
console.log(
|
|
50074
|
-
` Local: ${
|
|
50469
|
+
` Local: ${fs55.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
|
|
50075
50470
|
);
|
|
50076
50471
|
console.log(
|
|
50077
|
-
` Global: ${
|
|
50472
|
+
` Global: ${fs55.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
|
|
50078
50473
|
);
|
|
50079
50474
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
50080
50475
|
console.log(
|
|
50081
50476
|
` Sandbox: ${chalk15.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
50082
50477
|
);
|
|
50083
50478
|
}
|
|
50084
|
-
const wiring = getAgentWiring(
|
|
50479
|
+
const wiring = getAgentWiring(os50.homedir()).filter((a) => a.present);
|
|
50085
50480
|
if (wiring.length > 0) {
|
|
50086
50481
|
console.log("");
|
|
50087
50482
|
console.log(chalk15.bold(" Agent Wiring:"));
|
|
@@ -50119,10 +50514,11 @@ init_core();
|
|
|
50119
50514
|
init_setup();
|
|
50120
50515
|
init_shields();
|
|
50121
50516
|
init_service();
|
|
50517
|
+
init_core();
|
|
50122
50518
|
import chalk16 from "chalk";
|
|
50123
|
-
import
|
|
50124
|
-
import
|
|
50125
|
-
import
|
|
50519
|
+
import fs56 from "fs";
|
|
50520
|
+
import path54 from "path";
|
|
50521
|
+
import os51 from "os";
|
|
50126
50522
|
import https6 from "https";
|
|
50127
50523
|
var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
|
|
50128
50524
|
function buildTelemetryPayload(agents, firstInstall) {
|
|
@@ -50208,16 +50604,16 @@ function registerInitCommand(program2) {
|
|
|
50208
50604
|
}
|
|
50209
50605
|
console.log("");
|
|
50210
50606
|
}
|
|
50211
|
-
const configPath =
|
|
50212
|
-
const isFirstInstall = !
|
|
50213
|
-
if (
|
|
50607
|
+
const configPath = path54.join(os51.homedir(), ".node9", "config.json");
|
|
50608
|
+
const isFirstInstall = !fs56.existsSync(configPath);
|
|
50609
|
+
if (fs56.existsSync(configPath) && !options.force) {
|
|
50214
50610
|
try {
|
|
50215
|
-
const existing = JSON.parse(
|
|
50611
|
+
const existing = JSON.parse(fs56.readFileSync(configPath, "utf-8"));
|
|
50216
50612
|
const settings = existing.settings ?? {};
|
|
50217
50613
|
if (settings.mode !== chosenMode) {
|
|
50218
50614
|
settings.mode = chosenMode;
|
|
50219
50615
|
existing.settings = settings;
|
|
50220
|
-
|
|
50616
|
+
fs56.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
50221
50617
|
console.log(chalk16.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
50222
50618
|
} else {
|
|
50223
50619
|
console.log(chalk16.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -50230,9 +50626,9 @@ function registerInitCommand(program2) {
|
|
|
50230
50626
|
...DEFAULT_CONFIG,
|
|
50231
50627
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
50232
50628
|
};
|
|
50233
|
-
const dir =
|
|
50234
|
-
if (!
|
|
50235
|
-
|
|
50629
|
+
const dir = path54.dirname(configPath);
|
|
50630
|
+
if (!fs56.existsSync(dir)) fs56.mkdirSync(dir, { recursive: true });
|
|
50631
|
+
fs56.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
50236
50632
|
console.log(chalk16.green(`\u2705 Config created: ${configPath}`));
|
|
50237
50633
|
console.log(chalk16.gray(` Mode: ${chosenMode}`));
|
|
50238
50634
|
}
|
|
@@ -50284,8 +50680,13 @@ function registerInitCommand(program2) {
|
|
|
50284
50680
|
console.log(chalk16.gray(" You can try again later with: node9 daemon install"));
|
|
50285
50681
|
}
|
|
50286
50682
|
}
|
|
50683
|
+
} else if (isDaemonServiceEnabled()) {
|
|
50684
|
+
console.log(chalk16.green(" \u2713 Daemon login service already installed & enabled"));
|
|
50287
50685
|
} else {
|
|
50288
|
-
|
|
50686
|
+
const healed = ensureAutostartHealthy(!!getConfig().settings.autoStartDaemon);
|
|
50687
|
+
console.log(
|
|
50688
|
+
healed === "repaired" ? chalk16.green(" \u2713 Re-enabled daemon login service (was installed but disabled)") : chalk16.gray(" \xB7 Daemon login service is disabled (autostart off) \u2014 left as-is")
|
|
50689
|
+
);
|
|
50289
50690
|
}
|
|
50290
50691
|
if (!isTestingMode()) {
|
|
50291
50692
|
process.stdout.write(chalk16.dim(" Starting daemon..."));
|
|
@@ -50330,11 +50731,11 @@ init_agent_wiring();
|
|
|
50330
50731
|
init_setup();
|
|
50331
50732
|
init_hook_baseline();
|
|
50332
50733
|
import chalk17 from "chalk";
|
|
50333
|
-
import
|
|
50734
|
+
import fs57 from "fs";
|
|
50334
50735
|
var hasHookSurface = (a) => a.hooks.length > 0;
|
|
50335
50736
|
function backupForHeal(file) {
|
|
50336
50737
|
try {
|
|
50337
|
-
if (file &&
|
|
50738
|
+
if (file && fs57.existsSync(file)) fs57.copyFileSync(file, `${file}.node9-heal-bak`);
|
|
50338
50739
|
} catch {
|
|
50339
50740
|
}
|
|
50340
50741
|
}
|
|
@@ -50501,7 +50902,7 @@ function registerConnectCommand(program2) {
|
|
|
50501
50902
|
}
|
|
50502
50903
|
|
|
50503
50904
|
// src/cli/commands/undo.ts
|
|
50504
|
-
import
|
|
50905
|
+
import path55 from "path";
|
|
50505
50906
|
import chalk20 from "chalk";
|
|
50506
50907
|
|
|
50507
50908
|
// src/tui/undo-navigator.ts
|
|
@@ -50660,7 +51061,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
50660
51061
|
let dir = startDir;
|
|
50661
51062
|
while (true) {
|
|
50662
51063
|
if (cwds.has(dir)) return dir;
|
|
50663
|
-
const parent =
|
|
51064
|
+
const parent = path55.dirname(dir);
|
|
50664
51065
|
if (parent === dir) return null;
|
|
50665
51066
|
dir = parent;
|
|
50666
51067
|
}
|
|
@@ -50828,7 +51229,7 @@ function normalizeClientName(name) {
|
|
|
50828
51229
|
const sanitized = sanitize4(name).slice(0, 40);
|
|
50829
51230
|
return sanitized.length > 0 ? sanitized : void 0;
|
|
50830
51231
|
}
|
|
50831
|
-
function reportPinMismatchToCloud(serverKey, agent) {
|
|
51232
|
+
function reportPinMismatchToCloud(serverKey, serverLabel, agent) {
|
|
50832
51233
|
try {
|
|
50833
51234
|
const creds = getCredentials();
|
|
50834
51235
|
if (!creds) return;
|
|
@@ -50837,18 +51238,18 @@ function reportPinMismatchToCloud(serverKey, agent) {
|
|
|
50837
51238
|
{ serverKey, reason: "tool-pin-mismatch" },
|
|
50838
51239
|
"mcp-pin-mismatch",
|
|
50839
51240
|
creds,
|
|
50840
|
-
{ mcpServer:
|
|
51241
|
+
{ mcpServer: serverLabel, agent },
|
|
50841
51242
|
void 0,
|
|
50842
51243
|
false,
|
|
50843
51244
|
{
|
|
50844
51245
|
ruleName: "MCP tool definitions changed (possible rug pull)",
|
|
50845
|
-
ruleDescription: `The MCP server "${
|
|
51246
|
+
ruleDescription: `The MCP server "${serverLabel}" changed its tool definitions since they were pinned. This can indicate a supply-chain attack (tool poisoning). The session was quarantined. Review with: node9 mcp pin update ${serverKey}`
|
|
50846
51247
|
}
|
|
50847
51248
|
);
|
|
50848
51249
|
} catch {
|
|
50849
51250
|
}
|
|
50850
51251
|
}
|
|
50851
|
-
function reportInventoryToCloud(serverKey, toolCount, agent) {
|
|
51252
|
+
function reportInventoryToCloud(serverKey, serverLabel, toolCount, agent) {
|
|
50852
51253
|
try {
|
|
50853
51254
|
const creds = getCredentials();
|
|
50854
51255
|
if (!creds) return;
|
|
@@ -50857,7 +51258,7 @@ function reportInventoryToCloud(serverKey, toolCount, agent) {
|
|
|
50857
51258
|
{ serverKey, toolCount },
|
|
50858
51259
|
"mcp-discovered",
|
|
50859
51260
|
creds,
|
|
50860
|
-
{ mcpServer:
|
|
51261
|
+
{ mcpServer: serverLabel, agent },
|
|
50861
51262
|
void 0,
|
|
50862
51263
|
false,
|
|
50863
51264
|
{ mcpToolCount: toolCount }
|
|
@@ -50865,7 +51266,7 @@ function reportInventoryToCloud(serverKey, toolCount, agent) {
|
|
|
50865
51266
|
} catch {
|
|
50866
51267
|
}
|
|
50867
51268
|
}
|
|
50868
|
-
function reportLargeResponseToCloud(serverKey, responseBytes, agent) {
|
|
51269
|
+
function reportLargeResponseToCloud(serverKey, serverLabel, responseBytes, agent) {
|
|
50869
51270
|
try {
|
|
50870
51271
|
const creds = getCredentials();
|
|
50871
51272
|
if (!creds) return;
|
|
@@ -50874,7 +51275,7 @@ function reportLargeResponseToCloud(serverKey, responseBytes, agent) {
|
|
|
50874
51275
|
{ serverKey, responseBytes },
|
|
50875
51276
|
"mcp-large-response",
|
|
50876
51277
|
creds,
|
|
50877
|
-
{ mcpServer:
|
|
51278
|
+
{ mcpServer: serverLabel, agent },
|
|
50878
51279
|
void 0,
|
|
50879
51280
|
false,
|
|
50880
51281
|
{ mcpResponseBytes: responseBytes }
|
|
@@ -51111,7 +51512,12 @@ async function runMcpGateway(upstreamCommand, configName) {
|
|
|
51111
51512
|
const currentHash = hashToolDefinitions(tools);
|
|
51112
51513
|
const pinStatus = checkPin(serverKey, currentHash, gatewayCwd);
|
|
51113
51514
|
const token = getInternalToken();
|
|
51114
|
-
reportInventoryToCloud(
|
|
51515
|
+
reportInventoryToCloud(
|
|
51516
|
+
serverKey,
|
|
51517
|
+
resolveServerLabel("", serverKey, upstreamCommand, configName),
|
|
51518
|
+
tools.length,
|
|
51519
|
+
clientName
|
|
51520
|
+
);
|
|
51115
51521
|
if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
|
|
51116
51522
|
const toolSummary = tools.map((t) => ({ name: t.name, description: t.description }));
|
|
51117
51523
|
fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/mcp/discovered`, {
|
|
@@ -51183,7 +51589,11 @@ async function runMcpGateway(upstreamCommand, configName) {
|
|
|
51183
51589
|
console.error(chalk21.red(" Session quarantined \u2014 all tool calls blocked."));
|
|
51184
51590
|
console.error(chalk21.yellow(` Run: node9 mcp pin update ${serverKey}
|
|
51185
51591
|
`));
|
|
51186
|
-
reportPinMismatchToCloud(
|
|
51592
|
+
reportPinMismatchToCloud(
|
|
51593
|
+
serverKey,
|
|
51594
|
+
resolveServerLabel("", serverKey, upstreamCommand, configName),
|
|
51595
|
+
clientName
|
|
51596
|
+
);
|
|
51187
51597
|
const errorResponse = {
|
|
51188
51598
|
jsonrpc: "2.0",
|
|
51189
51599
|
id: parsed.id,
|
|
@@ -51229,7 +51639,12 @@ async function runMcpGateway(upstreamCommand, configName) {
|
|
|
51229
51639
|
`\u26A1 Node9: Large MCP response from '${toolName}' (${(line.length / 1024).toFixed(0)}KB) \u2014 context window enlarged`
|
|
51230
51640
|
)
|
|
51231
51641
|
);
|
|
51232
|
-
reportLargeResponseToCloud(
|
|
51642
|
+
reportLargeResponseToCloud(
|
|
51643
|
+
serverKey,
|
|
51644
|
+
resolveServerLabel("", serverKey, upstreamCommand, configName),
|
|
51645
|
+
line.length,
|
|
51646
|
+
clientName
|
|
51647
|
+
);
|
|
51233
51648
|
if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
|
|
51234
51649
|
const token = getInternalToken();
|
|
51235
51650
|
fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/mcp/large-response`, {
|
|
@@ -51280,18 +51695,18 @@ function registerMcpGatewayCommand(program2) {
|
|
|
51280
51695
|
|
|
51281
51696
|
// src/mcp-server/index.ts
|
|
51282
51697
|
import readline5 from "readline";
|
|
51283
|
-
import
|
|
51284
|
-
import
|
|
51285
|
-
import
|
|
51698
|
+
import fs59 from "fs";
|
|
51699
|
+
import os53 from "os";
|
|
51700
|
+
import path57 from "path";
|
|
51286
51701
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
51287
51702
|
init_core();
|
|
51288
51703
|
init_daemon();
|
|
51289
51704
|
init_shields();
|
|
51290
51705
|
|
|
51291
51706
|
// src/auth/egress-config.ts
|
|
51292
|
-
import
|
|
51293
|
-
import
|
|
51294
|
-
import
|
|
51707
|
+
import fs58 from "fs";
|
|
51708
|
+
import os52 from "os";
|
|
51709
|
+
import path56 from "path";
|
|
51295
51710
|
var DEFAULT_EGRESS = {
|
|
51296
51711
|
enabled: false,
|
|
51297
51712
|
mode: "review",
|
|
@@ -51300,12 +51715,12 @@ var DEFAULT_EGRESS = {
|
|
|
51300
51715
|
allowPrivate: true
|
|
51301
51716
|
};
|
|
51302
51717
|
function egressConfigPath() {
|
|
51303
|
-
return
|
|
51718
|
+
return path56.join(os52.homedir(), ".node9", "config.json");
|
|
51304
51719
|
}
|
|
51305
51720
|
function readEgressRawConfig() {
|
|
51306
51721
|
let text;
|
|
51307
51722
|
try {
|
|
51308
|
-
text =
|
|
51723
|
+
text = fs58.readFileSync(egressConfigPath(), "utf8");
|
|
51309
51724
|
} catch (err2) {
|
|
51310
51725
|
if (err2.code === "ENOENT") return {};
|
|
51311
51726
|
throw err2;
|
|
@@ -51320,8 +51735,8 @@ function readEgressRawConfig() {
|
|
|
51320
51735
|
}
|
|
51321
51736
|
function writeEgressRawConfig(config) {
|
|
51322
51737
|
const p = egressConfigPath();
|
|
51323
|
-
|
|
51324
|
-
|
|
51738
|
+
fs58.mkdirSync(path56.dirname(p), { recursive: true });
|
|
51739
|
+
fs58.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
51325
51740
|
}
|
|
51326
51741
|
function applyEgress(config, change) {
|
|
51327
51742
|
const policy = config.policy = config.policy ?? {};
|
|
@@ -51706,13 +52121,13 @@ function handleStatus() {
|
|
|
51706
52121
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
51707
52122
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
51708
52123
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
51709
|
-
const projectConfig =
|
|
51710
|
-
const globalConfig =
|
|
52124
|
+
const projectConfig = path57.join(process.cwd(), "node9.config.json");
|
|
52125
|
+
const globalConfig = path57.join(os53.homedir(), ".node9", "config.json");
|
|
51711
52126
|
lines.push(
|
|
51712
|
-
`Project config (node9.config.json): ${
|
|
52127
|
+
`Project config (node9.config.json): ${fs59.existsSync(projectConfig) ? "present" : "not found"}`
|
|
51713
52128
|
);
|
|
51714
52129
|
lines.push(
|
|
51715
|
-
`Global config (~/.node9/config.json): ${
|
|
52130
|
+
`Global config (~/.node9/config.json): ${fs59.existsSync(globalConfig) ? "present" : "not found"}`
|
|
51716
52131
|
);
|
|
51717
52132
|
return lines.join("\n");
|
|
51718
52133
|
}
|
|
@@ -51818,21 +52233,21 @@ function handleEgressDeny(args) {
|
|
|
51818
52233
|
addEgressHost("deny", host);
|
|
51819
52234
|
return `Denied egress to ${host} (deny always wins over allow).`;
|
|
51820
52235
|
}
|
|
51821
|
-
var GLOBAL_CONFIG_PATH =
|
|
52236
|
+
var GLOBAL_CONFIG_PATH = path57.join(os53.homedir(), ".node9", "config.json");
|
|
51822
52237
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
51823
52238
|
function readGlobalConfigRaw() {
|
|
51824
52239
|
try {
|
|
51825
|
-
if (
|
|
51826
|
-
return JSON.parse(
|
|
52240
|
+
if (fs59.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
52241
|
+
return JSON.parse(fs59.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
|
|
51827
52242
|
}
|
|
51828
52243
|
} catch {
|
|
51829
52244
|
}
|
|
51830
52245
|
return {};
|
|
51831
52246
|
}
|
|
51832
52247
|
function writeGlobalConfigRaw(data) {
|
|
51833
|
-
const dir =
|
|
51834
|
-
if (!
|
|
51835
|
-
|
|
52248
|
+
const dir = path57.dirname(GLOBAL_CONFIG_PATH);
|
|
52249
|
+
if (!fs59.existsSync(dir)) fs59.mkdirSync(dir, { recursive: true });
|
|
52250
|
+
fs59.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
|
|
51836
52251
|
}
|
|
51837
52252
|
function handleApproverList() {
|
|
51838
52253
|
const config = getConfig();
|
|
@@ -51876,9 +52291,9 @@ function handleApproverSet(args) {
|
|
|
51876
52291
|
function handleAuditGet(args) {
|
|
51877
52292
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
51878
52293
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
51879
|
-
const auditPath =
|
|
51880
|
-
if (!
|
|
51881
|
-
const rawLines =
|
|
52294
|
+
const auditPath = path57.join(os53.homedir(), ".node9", "audit.log");
|
|
52295
|
+
if (!fs59.existsSync(auditPath)) return "No audit log found.";
|
|
52296
|
+
const rawLines = fs59.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
51882
52297
|
const parsed = [];
|
|
51883
52298
|
for (const line of rawLines) {
|
|
51884
52299
|
try {
|
|
@@ -52252,7 +52667,7 @@ function registerTrustCommand(program2) {
|
|
|
52252
52667
|
// src/cli/commands/mcp-pin.ts
|
|
52253
52668
|
init_mcp_pin();
|
|
52254
52669
|
import chalk24 from "chalk";
|
|
52255
|
-
import
|
|
52670
|
+
import fs60 from "fs";
|
|
52256
52671
|
|
|
52257
52672
|
// src/cli/commands/mcp-gateway-cmd.ts
|
|
52258
52673
|
init_mcp_wrap();
|
|
@@ -52459,7 +52874,7 @@ function registerMcpPinCommand(program2) {
|
|
|
52459
52874
|
let repoCorrupt = false;
|
|
52460
52875
|
if (found.source === "repo") {
|
|
52461
52876
|
try {
|
|
52462
|
-
const raw =
|
|
52877
|
+
const raw = fs60.readFileSync(found.path, "utf-8");
|
|
52463
52878
|
const parsed = JSON.parse(raw);
|
|
52464
52879
|
repoEntries = parsed.servers ?? {};
|
|
52465
52880
|
} catch {
|
|
@@ -52960,8 +53375,8 @@ import chalk30 from "chalk";
|
|
|
52960
53375
|
|
|
52961
53376
|
// src/ci-check/fetch.ts
|
|
52962
53377
|
var import_undici = __toESM(require_undici());
|
|
52963
|
-
import
|
|
52964
|
-
import
|
|
53378
|
+
import fs61 from "fs";
|
|
53379
|
+
import path58 from "path";
|
|
52965
53380
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
52966
53381
|
var cachedGhToken;
|
|
52967
53382
|
function resolveGitHubToken() {
|
|
@@ -53044,7 +53459,7 @@ function parseRepoUrl(input) {
|
|
|
53044
53459
|
function isLocalPath(input) {
|
|
53045
53460
|
if (input.startsWith(".") || input.startsWith("/") || input.startsWith("~")) return true;
|
|
53046
53461
|
try {
|
|
53047
|
-
return
|
|
53462
|
+
return fs61.existsSync(input) && fs61.statSync(input).isDirectory();
|
|
53048
53463
|
} catch {
|
|
53049
53464
|
return false;
|
|
53050
53465
|
}
|
|
@@ -53159,10 +53574,10 @@ function readLocalTree(dir) {
|
|
|
53159
53574
|
const files = [];
|
|
53160
53575
|
const notes = [];
|
|
53161
53576
|
const add = (rel) => {
|
|
53162
|
-
const abs =
|
|
53577
|
+
const abs = path58.join(root, rel);
|
|
53163
53578
|
try {
|
|
53164
|
-
if (
|
|
53165
|
-
files.push({ path: rel, content:
|
|
53579
|
+
if (fs61.existsSync(abs) && fs61.statSync(abs).isFile()) {
|
|
53580
|
+
files.push({ path: rel, content: fs61.readFileSync(abs, "utf8") });
|
|
53166
53581
|
}
|
|
53167
53582
|
} catch {
|
|
53168
53583
|
}
|
|
@@ -53182,7 +53597,7 @@ function readLocalTree(dir) {
|
|
|
53182
53597
|
dirsVisited++;
|
|
53183
53598
|
let entries;
|
|
53184
53599
|
try {
|
|
53185
|
-
entries =
|
|
53600
|
+
entries = fs61.readdirSync(path58.join(root, relDir), { withFileTypes: true });
|
|
53186
53601
|
} catch {
|
|
53187
53602
|
return;
|
|
53188
53603
|
}
|
|
@@ -53203,11 +53618,11 @@ function readLocalTree(dir) {
|
|
|
53203
53618
|
`repo is large \u2014 some agent-surface files may be INCOMPLETE (capped at ${MAX_SURFACE_FILES} files / ${MAX_DIRS} dirs).`
|
|
53204
53619
|
);
|
|
53205
53620
|
for (const rel of matches) collect(rel);
|
|
53206
|
-
const wfDir =
|
|
53621
|
+
const wfDir = path58.join(root, WORKFLOW_DIR);
|
|
53207
53622
|
try {
|
|
53208
|
-
if (
|
|
53209
|
-
for (const name of
|
|
53210
|
-
if (/\.ya?ml$/.test(name)) add(
|
|
53623
|
+
if (fs61.existsSync(wfDir)) {
|
|
53624
|
+
for (const name of fs61.readdirSync(wfDir)) {
|
|
53625
|
+
if (/\.ya?ml$/.test(name)) add(path58.join(WORKFLOW_DIR, name));
|
|
53211
53626
|
}
|
|
53212
53627
|
}
|
|
53213
53628
|
} catch {
|
|
@@ -53480,7 +53895,7 @@ function severityFromScore(score) {
|
|
|
53480
53895
|
if (score >= 1) return "advisory";
|
|
53481
53896
|
return null;
|
|
53482
53897
|
}
|
|
53483
|
-
function analyzeWorkflow(
|
|
53898
|
+
function analyzeWorkflow(path71, content) {
|
|
53484
53899
|
let raw;
|
|
53485
53900
|
try {
|
|
53486
53901
|
raw = parseYaml(content) ?? {};
|
|
@@ -53601,7 +54016,7 @@ function analyzeWorkflow(path70, content) {
|
|
|
53601
54016
|
dimension: "workflows",
|
|
53602
54017
|
severity,
|
|
53603
54018
|
title,
|
|
53604
|
-
file:
|
|
54019
|
+
file: path71,
|
|
53605
54020
|
signals,
|
|
53606
54021
|
mitigations: mitigations.length ? mitigations : void 0,
|
|
53607
54022
|
fix: head === "root" && privileged ? "Do not check out the untrusted PR head into the workspace root under a privileged trigger (pull_request_target/workflow_run) \u2014 check out the base ref, or isolate the head in a subdir (--add-dir). Add an actor gate and scope the agent tools." : head === "root" ? "This runs under `pull_request` (fork PRs get a read-only token), so the head checkout is low-risk today \u2014 keep it on `pull_request` (not `pull_request_target`) and keep the actor gate + scoped tools." : "Add/verify an actor gate, scope the agent tools to read-only, and env-deny secrets. See Anthropic\u2019s claude-code-action security doc."
|
|
@@ -53677,7 +54092,7 @@ function evalAgentJob(job, wf, raw, untrustedTrigger, reusable) {
|
|
|
53677
54092
|
if (reusable && !loadedGun && SEVERITY_RANK2[severity] > SEVERITY_RANK2.medium) severity = "medium";
|
|
53678
54093
|
return { severity, secrets, injectable, canReadEnv };
|
|
53679
54094
|
}
|
|
53680
|
-
function analyzeWorkflowSecrets(
|
|
54095
|
+
function analyzeWorkflowSecrets(path71, content) {
|
|
53681
54096
|
let raw;
|
|
53682
54097
|
try {
|
|
53683
54098
|
raw = parseYaml(content) ?? {};
|
|
@@ -53697,7 +54112,7 @@ function analyzeWorkflowSecrets(path70, content) {
|
|
|
53697
54112
|
dimension: "data",
|
|
53698
54113
|
severity: worst.severity,
|
|
53699
54114
|
title: worst.severity === "advisory" ? "Secrets reachable by the agent \u2014 hardening" : "Exfiltratable secrets reachable by an injectable agent",
|
|
53700
|
-
file:
|
|
54115
|
+
file: path71,
|
|
53701
54116
|
signals: [
|
|
53702
54117
|
`agent can reach: ${worst.secrets.map((s) => s.name).join(", ")}`,
|
|
53703
54118
|
worst.injectable ? "the agent is externally triggerable (untrusted trigger, no gate)" : "gated / not externally triggerable \u2014 latent risk only",
|
|
@@ -53724,7 +54139,7 @@ function hookCommands(hooks) {
|
|
|
53724
54139
|
}
|
|
53725
54140
|
return out;
|
|
53726
54141
|
}
|
|
53727
|
-
function analyzeAgentConfig(
|
|
54142
|
+
function analyzeAgentConfig(path71, content) {
|
|
53728
54143
|
let cfg;
|
|
53729
54144
|
try {
|
|
53730
54145
|
cfg = JSON.parse(content);
|
|
@@ -53743,7 +54158,7 @@ function analyzeAgentConfig(path70, content) {
|
|
|
53743
54158
|
dimension: "toolRules",
|
|
53744
54159
|
severity: high ? "high" : "medium",
|
|
53745
54160
|
title: high ? "Agent hook runs UNPINNED/remote third-party code on every action" : "Agent hook runs third-party code in the agent hot path",
|
|
53746
|
-
file:
|
|
54161
|
+
file: path71,
|
|
53747
54162
|
signals: [
|
|
53748
54163
|
`hook command: \`${cmd.slice(0, 120)}\``,
|
|
53749
54164
|
remoteExec ? "fetch-and-run (curl|wget / pipe-to-shell) \u2014 unpinnable remote code execution on every contributor" : unpinned ? "unpinned \u2014 a compromised/yanked package = code execution on every contributor" : "pinned, but still a standing supply-chain dependency in the agent hot path"
|
|
@@ -53763,7 +54178,7 @@ function analyzeAgentConfig(path70, content) {
|
|
|
53763
54178
|
dimension: "toolRules",
|
|
53764
54179
|
severity: hasBackstop ? "medium" : "high",
|
|
53765
54180
|
title: hasBackstop ? "Committed agent config pre-authorizes broad tools" : "Committed agent config pre-authorizes broad tools with no deny backstop",
|
|
53766
|
-
file:
|
|
54181
|
+
file: path71,
|
|
53767
54182
|
signals: [
|
|
53768
54183
|
`broad allow(s): ${broad.slice(0, 5).join(", ")}`,
|
|
53769
54184
|
hasBackstop ? "a `deny` list backstops the broad allow" : "no `deny` entry covers Bash/Write/Edit \u2014 every contributor is pre-authorized for catastrophic tools"
|
|
@@ -53776,16 +54191,16 @@ function analyzeAgentConfig(path70, content) {
|
|
|
53776
54191
|
|
|
53777
54192
|
// src/ci-check/mcp.ts
|
|
53778
54193
|
init_dist();
|
|
53779
|
-
function analyzeMcp(
|
|
54194
|
+
function analyzeMcp(path71, content) {
|
|
53780
54195
|
let cfg;
|
|
53781
54196
|
try {
|
|
53782
54197
|
cfg = JSON.parse(content);
|
|
53783
54198
|
} catch {
|
|
53784
54199
|
return [];
|
|
53785
54200
|
}
|
|
53786
|
-
return analyzeMcpServers(cfg.mcpServers ?? {},
|
|
54201
|
+
return analyzeMcpServers(cfg.mcpServers ?? {}, path71);
|
|
53787
54202
|
}
|
|
53788
|
-
function analyzeMcpServers(servers,
|
|
54203
|
+
function analyzeMcpServers(servers, path71) {
|
|
53789
54204
|
const findings = [];
|
|
53790
54205
|
for (const [name, srv] of Object.entries(servers ?? {})) {
|
|
53791
54206
|
if (!srv || srv.disabled) continue;
|
|
@@ -53796,7 +54211,7 @@ function analyzeMcpServers(servers, path70) {
|
|
|
53796
54211
|
dimension: "mcp",
|
|
53797
54212
|
severity: "medium",
|
|
53798
54213
|
title: `MCP server "${name}" runs an unpinned executable`,
|
|
53799
|
-
file:
|
|
54214
|
+
file: path71,
|
|
53800
54215
|
signals: [`\`${argv.slice(0, 120)}\` \u2014 unversioned/@latest npx`],
|
|
53801
54216
|
fix: "Pin the MCP server package to an exact version so a PR (or a registry compromise) can\u2019t swap the toolchain."
|
|
53802
54217
|
});
|
|
@@ -53810,7 +54225,7 @@ function analyzeMcpServers(servers, path70) {
|
|
|
53810
54225
|
dimension: "mcp",
|
|
53811
54226
|
severity: "high",
|
|
53812
54227
|
title: `MCP server "${name}" has an inline credential`,
|
|
53813
|
-
file:
|
|
54228
|
+
file: path71,
|
|
53814
54229
|
signals: [
|
|
53815
54230
|
`env.${k} matches ${hit.patternName} \u2014 agent-reachable secret committed to the repo`
|
|
53816
54231
|
],
|
|
@@ -53824,7 +54239,7 @@ function analyzeMcpServers(servers, path70) {
|
|
|
53824
54239
|
|
|
53825
54240
|
// src/ci-check/codex.ts
|
|
53826
54241
|
import { parse as parseToml5 } from "smol-toml";
|
|
53827
|
-
function analyzeCodexConfig(
|
|
54242
|
+
function analyzeCodexConfig(path71, content) {
|
|
53828
54243
|
let cfg;
|
|
53829
54244
|
try {
|
|
53830
54245
|
cfg = parseToml5(content);
|
|
@@ -53832,7 +54247,7 @@ function analyzeCodexConfig(path70, content) {
|
|
|
53832
54247
|
return [];
|
|
53833
54248
|
}
|
|
53834
54249
|
const findings = [];
|
|
53835
|
-
findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {},
|
|
54250
|
+
findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {}, path71));
|
|
53836
54251
|
const sandbox = typeof cfg.sandbox_mode === "string" ? cfg.sandbox_mode : "";
|
|
53837
54252
|
const approval = typeof cfg.approval_policy === "string" ? cfg.approval_policy : "";
|
|
53838
54253
|
const fullAccess = /danger-full-access/i.test(sandbox);
|
|
@@ -53847,7 +54262,7 @@ function analyzeCodexConfig(path70, content) {
|
|
|
53847
54262
|
dimension: "toolRules",
|
|
53848
54263
|
severity: fullAccess ? "high" : "medium",
|
|
53849
54264
|
title: fullAccess ? "Codex config grants a full-access sandbox" : "Codex config never requires approval",
|
|
53850
|
-
file:
|
|
54265
|
+
file: path71,
|
|
53851
54266
|
signals,
|
|
53852
54267
|
fix: 'Commit a least-privilege Codex config: prefer `sandbox_mode = "read-only"` (or `"workspace-write"`) and `approval_policy = "on-request"`/`"on-failure"`. A repo-committed config applies to every contributor who runs Codex here.'
|
|
53853
54268
|
});
|
|
@@ -53903,10 +54318,10 @@ function decodeSuspiciousBase64(text) {
|
|
|
53903
54318
|
}
|
|
53904
54319
|
return out;
|
|
53905
54320
|
}
|
|
53906
|
-
function mk(severity, title, signals, fix,
|
|
53907
|
-
return { check: "CI-6", dimension: "instructions", severity, title, file:
|
|
54321
|
+
function mk(severity, title, signals, fix, path71) {
|
|
54322
|
+
return { check: "CI-6", dimension: "instructions", severity, title, file: path71, signals, fix };
|
|
53908
54323
|
}
|
|
53909
|
-
function analyzeInstructionFile(
|
|
54324
|
+
function analyzeInstructionFile(path71, content) {
|
|
53910
54325
|
const findings = [];
|
|
53911
54326
|
const decoded = decodeSuspiciousBase64(content);
|
|
53912
54327
|
if (TAG_CHARS.test(content))
|
|
@@ -53918,7 +54333,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
53918
54333
|
"contains Unicode tag characters (U+E0000\u2013E007F) \u2014 an invisible instruction-smuggling channel with no legitimate use in text"
|
|
53919
54334
|
],
|
|
53920
54335
|
"Remove the tag characters. Instruction files must be plain, reviewable text.",
|
|
53921
|
-
|
|
54336
|
+
path71
|
|
53922
54337
|
)
|
|
53923
54338
|
);
|
|
53924
54339
|
if (BIDI_OVERRIDE.test(content))
|
|
@@ -53930,7 +54345,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
53930
54345
|
"contains a bidi override (U+202D/U+202E) \u2014 a Trojan-Source technique that visually reorders text so a human reads something different from what the agent parses"
|
|
53931
54346
|
],
|
|
53932
54347
|
"Remove the bidi override characters.",
|
|
53933
|
-
|
|
54348
|
+
path71
|
|
53934
54349
|
)
|
|
53935
54350
|
);
|
|
53936
54351
|
else if (BIDI_EMBED_ISOLATE.test(content))
|
|
@@ -53942,7 +54357,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
53942
54357
|
"contains bidi embed/isolate characters (U+202A\u2013202C / U+2066\u20132069) \u2014 legitimate in right-to-left text, but confirm they are not being used to hide or reorder instructions"
|
|
53943
54358
|
],
|
|
53944
54359
|
"Confirm the bidi marks are legitimate RTL formatting; remove otherwise.",
|
|
53945
|
-
|
|
54360
|
+
path71
|
|
53946
54361
|
)
|
|
53947
54362
|
);
|
|
53948
54363
|
const zw = suspiciousZeroWidth(content);
|
|
@@ -53956,7 +54371,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
53956
54371
|
revealed ? "a zero-width character conceals a prompt-override directive that only appears once the hidden characters are stripped" : "a zero-width character splits a visible Latin word \u2014 a concealment technique (hides text from human review while the agent reads it as contiguous)"
|
|
53957
54372
|
],
|
|
53958
54373
|
"Remove the zero-width characters. Instruction files must be plain, reviewable text.",
|
|
53959
|
-
|
|
54374
|
+
path71
|
|
53960
54375
|
)
|
|
53961
54376
|
);
|
|
53962
54377
|
}
|
|
@@ -53972,7 +54387,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
53972
54387
|
`contains a prompt-override / role-impersonation directive (\`${m[0].slice(0, 60).trim()}\`)${ovEnc ? " \u2014 concealed in a base64 blob" : ""}`
|
|
53973
54388
|
],
|
|
53974
54389
|
"Remove the override text. An instruction file should not tell the agent to ignore its own rules.",
|
|
53975
|
-
|
|
54390
|
+
path71
|
|
53976
54391
|
)
|
|
53977
54392
|
);
|
|
53978
54393
|
}
|
|
@@ -53984,7 +54399,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
53984
54399
|
"Instruction directs the agent to fetch and run remote code",
|
|
53985
54400
|
[`\`${fo[0].slice(0, 70).trim()}\` \u2014 fetch-and-obey, outside an install/setup section`],
|
|
53986
54401
|
"Do not instruct the agent to pipe remote content into a shell; pin and vendor scripts instead.",
|
|
53987
|
-
|
|
54402
|
+
path71
|
|
53988
54403
|
)
|
|
53989
54404
|
);
|
|
53990
54405
|
}
|
|
@@ -53996,7 +54411,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
53996
54411
|
"Instruction points the agent at credential material",
|
|
53997
54412
|
[`references \`${sp[0].slice(0, 50).trim()}\` \u2014 directs the agent toward secrets`],
|
|
53998
54413
|
"Do not reference credential files or paths in agent instructions.",
|
|
53999
|
-
|
|
54414
|
+
path71
|
|
54000
54415
|
)
|
|
54001
54416
|
);
|
|
54002
54417
|
}
|
|
@@ -54008,7 +54423,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
54008
54423
|
"Instruction directs the agent to send data to an external endpoint",
|
|
54009
54424
|
[`\`${ex[0].slice(0, 70).trim()}\` \u2014 possible exfiltration directive`],
|
|
54010
54425
|
"Remove external post/upload directives from agent instructions.",
|
|
54011
|
-
|
|
54426
|
+
path71
|
|
54012
54427
|
)
|
|
54013
54428
|
);
|
|
54014
54429
|
}
|
|
@@ -54310,17 +54725,17 @@ import chalk32 from "chalk";
|
|
|
54310
54725
|
// src/shields/jail.ts
|
|
54311
54726
|
init_build();
|
|
54312
54727
|
init_shields();
|
|
54313
|
-
import
|
|
54314
|
-
import
|
|
54315
|
-
import
|
|
54728
|
+
import fs62 from "fs";
|
|
54729
|
+
import os54 from "os";
|
|
54730
|
+
import path59 from "path";
|
|
54316
54731
|
var USER_JAIL_SHIELD = "user-jail";
|
|
54317
54732
|
function jailStorePath() {
|
|
54318
|
-
return
|
|
54733
|
+
return path59.join(os54.homedir(), ".node9", "jail-paths.json");
|
|
54319
54734
|
}
|
|
54320
54735
|
function readJailPaths() {
|
|
54321
54736
|
let text;
|
|
54322
54737
|
try {
|
|
54323
|
-
text =
|
|
54738
|
+
text = fs62.readFileSync(jailStorePath(), "utf8");
|
|
54324
54739
|
} catch (err2) {
|
|
54325
54740
|
if (err2.code === "ENOENT") return [];
|
|
54326
54741
|
throw err2;
|
|
@@ -54338,8 +54753,8 @@ function readJailPaths() {
|
|
|
54338
54753
|
}
|
|
54339
54754
|
function writeJailPaths(paths) {
|
|
54340
54755
|
const p = jailStorePath();
|
|
54341
|
-
|
|
54342
|
-
|
|
54756
|
+
fs62.mkdirSync(path59.dirname(p), { recursive: true });
|
|
54757
|
+
fs62.writeFileSync(p, JSON.stringify({ paths }, null, 2) + "\n", { mode: 384 });
|
|
54343
54758
|
}
|
|
54344
54759
|
function addJailPath(rawPath, verdict) {
|
|
54345
54760
|
const norm = rawPath.trim();
|
|
@@ -54361,14 +54776,14 @@ function removeJailPath(rawPath) {
|
|
|
54361
54776
|
return { removed, paths: after };
|
|
54362
54777
|
}
|
|
54363
54778
|
function regenerateUserJail(paths) {
|
|
54364
|
-
const file =
|
|
54779
|
+
const file = path59.join(USER_SHIELDS_DIR_PATH, `${USER_JAIL_SHIELD}.json`);
|
|
54365
54780
|
if (paths.length === 0) {
|
|
54366
54781
|
const active2 = readActiveShields();
|
|
54367
54782
|
if (active2.includes(USER_JAIL_SHIELD)) {
|
|
54368
54783
|
writeActiveShields(active2.filter((s) => s !== USER_JAIL_SHIELD));
|
|
54369
54784
|
}
|
|
54370
54785
|
try {
|
|
54371
|
-
|
|
54786
|
+
fs62.rmSync(file, { force: true });
|
|
54372
54787
|
} catch {
|
|
54373
54788
|
}
|
|
54374
54789
|
return;
|
|
@@ -54483,13 +54898,13 @@ function registerJailCommand(program2) {
|
|
|
54483
54898
|
// src/cli/commands/sandbox.ts
|
|
54484
54899
|
init_config();
|
|
54485
54900
|
import chalk33 from "chalk";
|
|
54486
|
-
import
|
|
54487
|
-
import
|
|
54901
|
+
import fs65 from "fs";
|
|
54902
|
+
import path62 from "path";
|
|
54488
54903
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
54489
54904
|
|
|
54490
54905
|
// src/sandbox/config.ts
|
|
54491
|
-
import
|
|
54492
|
-
import
|
|
54906
|
+
import fs63 from "fs";
|
|
54907
|
+
import path60 from "path";
|
|
54493
54908
|
import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
|
|
54494
54909
|
var SANDBOX_CONFIG_FILE = "node9.sandbox.yaml";
|
|
54495
54910
|
var FORBIDDEN_ENV = /* @__PURE__ */ new Set(["NODE9_API_KEY", "NODE9_API_URL"]);
|
|
@@ -54562,16 +54977,16 @@ function scaffoldSandboxYaml(agent) {
|
|
|
54562
54977
|
return header + stringifyYaml(defaultSandboxConfig(agent));
|
|
54563
54978
|
}
|
|
54564
54979
|
function sandboxConfigPath(cwd = process.cwd()) {
|
|
54565
|
-
return
|
|
54980
|
+
return path60.join(cwd, SANDBOX_CONFIG_FILE);
|
|
54566
54981
|
}
|
|
54567
54982
|
function loadSandboxConfig(cwd = process.cwd(), fallbackAgent = "claude") {
|
|
54568
54983
|
const p = sandboxConfigPath(cwd);
|
|
54569
|
-
if (!
|
|
54984
|
+
if (!fs63.existsSync(p)) {
|
|
54570
54985
|
throw new Error(`sandbox: ${SANDBOX_CONFIG_FILE} not found \u2014 run \`node9 sandbox new\` first.`);
|
|
54571
54986
|
}
|
|
54572
54987
|
let raw;
|
|
54573
54988
|
try {
|
|
54574
|
-
raw = parseYaml2(
|
|
54989
|
+
raw = parseYaml2(fs63.readFileSync(p, "utf-8"));
|
|
54575
54990
|
} catch (err2) {
|
|
54576
54991
|
throw new Error(
|
|
54577
54992
|
`sandbox: ${SANDBOX_CONFIG_FILE} is not valid YAML \u2014 ${err2.message}`
|
|
@@ -54630,13 +55045,13 @@ init_templates();
|
|
|
54630
55045
|
|
|
54631
55046
|
// src/sandbox/runtime.ts
|
|
54632
55047
|
init_templates();
|
|
54633
|
-
import
|
|
54634
|
-
import
|
|
54635
|
-
import
|
|
55048
|
+
import fs64 from "fs";
|
|
55049
|
+
import os55 from "os";
|
|
55050
|
+
import path61 from "path";
|
|
54636
55051
|
import crypto9 from "crypto";
|
|
54637
55052
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
54638
55053
|
function sandboxDataDir(cwd = process.cwd()) {
|
|
54639
|
-
return
|
|
55054
|
+
return path61.join(cwd, ".node9", "sandbox", "data");
|
|
54640
55055
|
}
|
|
54641
55056
|
function detectEngine(engine) {
|
|
54642
55057
|
const r = spawnSync5(engine, ["--version"], { encoding: "utf-8" });
|
|
@@ -54647,7 +55062,7 @@ function detectEngine(engine) {
|
|
|
54647
55062
|
}
|
|
54648
55063
|
function agentCredentialsMount(agent) {
|
|
54649
55064
|
const rel = agent === "codex" ? ".codex/auth.json" : ".claude/.credentials.json";
|
|
54650
|
-
return { hostPath:
|
|
55065
|
+
return { hostPath: path61.join(os55.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
|
|
54651
55066
|
}
|
|
54652
55067
|
function buildRunArgs(opts) {
|
|
54653
55068
|
const { config, workspaceHostPath, dataHostPath, allowlistHostPath, agentArgs } = opts;
|
|
@@ -54657,7 +55072,7 @@ function buildRunArgs(opts) {
|
|
|
54657
55072
|
args.push("-v", `${allowlistHostPath}:${ALLOWED_DOMAINS_PATH}:ro`);
|
|
54658
55073
|
if (config.node9.mountAgentCredentials) {
|
|
54659
55074
|
const creds = agentCredentialsMount(config.agent);
|
|
54660
|
-
if (
|
|
55075
|
+
if (fs64.existsSync(creds.hostPath)) {
|
|
54661
55076
|
args.push("-v", `${creds.hostPath}:${creds.target}`);
|
|
54662
55077
|
}
|
|
54663
55078
|
}
|
|
@@ -54675,30 +55090,30 @@ function imageContentHash(dockerfile, entrypoint) {
|
|
|
54675
55090
|
return crypto9.createHash("sha256").update(dockerfile).update("\0").update(entrypoint).digest("hex").slice(0, 16);
|
|
54676
55091
|
}
|
|
54677
55092
|
function sandboxBuildDir(cwd = process.cwd()) {
|
|
54678
|
-
return
|
|
55093
|
+
return path61.join(cwd, ".node9", "sandbox", "build");
|
|
54679
55094
|
}
|
|
54680
55095
|
function writeBuildContext(cwd, dockerfile, entrypoint) {
|
|
54681
55096
|
const dir = sandboxBuildDir(cwd);
|
|
54682
|
-
|
|
54683
|
-
|
|
54684
|
-
|
|
55097
|
+
fs64.mkdirSync(dir, { recursive: true });
|
|
55098
|
+
fs64.writeFileSync(path61.join(dir, "Dockerfile"), dockerfile);
|
|
55099
|
+
fs64.writeFileSync(path61.join(dir, "entrypoint.sh"), entrypoint);
|
|
54685
55100
|
return dir;
|
|
54686
55101
|
}
|
|
54687
55102
|
function writeAllowlist(cwd, hosts) {
|
|
54688
|
-
const dir =
|
|
54689
|
-
|
|
54690
|
-
const p =
|
|
54691
|
-
|
|
55103
|
+
const dir = path61.join(cwd, ".node9", "sandbox");
|
|
55104
|
+
fs64.mkdirSync(dir, { recursive: true });
|
|
55105
|
+
const p = path61.join(dir, "allowed-domains.txt");
|
|
55106
|
+
fs64.writeFileSync(p, hosts.join("\n") + "\n");
|
|
54692
55107
|
return p;
|
|
54693
55108
|
}
|
|
54694
55109
|
function resolveHomePath(p) {
|
|
54695
|
-
return p.startsWith("~") ?
|
|
55110
|
+
return p.startsWith("~") ? path61.join(os55.homedir(), p.slice(1)) : path61.resolve(p);
|
|
54696
55111
|
}
|
|
54697
55112
|
|
|
54698
55113
|
// src/cli/commands/sandbox.ts
|
|
54699
55114
|
function seedDataDirConfig(dataDir, sandbox) {
|
|
54700
|
-
|
|
54701
|
-
const configPath =
|
|
55115
|
+
fs65.mkdirSync(dataDir, { recursive: true });
|
|
55116
|
+
const configPath = path62.join(dataDir, "config.json");
|
|
54702
55117
|
const seed = {
|
|
54703
55118
|
settings: {
|
|
54704
55119
|
approvers: {
|
|
@@ -54709,7 +55124,7 @@ function seedDataDirConfig(dataDir, sandbox) {
|
|
|
54709
55124
|
}
|
|
54710
55125
|
}
|
|
54711
55126
|
};
|
|
54712
|
-
|
|
55127
|
+
fs65.writeFileSync(configPath, JSON.stringify(seed, null, 2), { mode: 384 });
|
|
54713
55128
|
}
|
|
54714
55129
|
function registerSandboxCommand(program2, version2) {
|
|
54715
55130
|
const node9Version2 = pinnedNode9Version(version2);
|
|
@@ -54717,13 +55132,13 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54717
55132
|
cmd.command("new").description(`Scaffold ${SANDBOX_CONFIG_FILE} in this project`).option("--agent <agent>", "claude (default) or codex", "claude").action((opts) => {
|
|
54718
55133
|
const agent = opts.agent === "codex" ? "codex" : "claude";
|
|
54719
55134
|
const p = sandboxConfigPath();
|
|
54720
|
-
if (
|
|
55135
|
+
if (fs65.existsSync(p)) {
|
|
54721
55136
|
console.log(
|
|
54722
55137
|
chalk33.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
|
|
54723
55138
|
);
|
|
54724
55139
|
return;
|
|
54725
55140
|
}
|
|
54726
|
-
|
|
55141
|
+
fs65.writeFileSync(p, scaffoldSandboxYaml(agent));
|
|
54727
55142
|
console.log(
|
|
54728
55143
|
chalk33.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + chalk33.dim(` (agent: ${agent})`)
|
|
54729
55144
|
);
|
|
@@ -54763,8 +55178,8 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54763
55178
|
const buildDir = writeBuildContext(cwd, dockerfile, entrypoint);
|
|
54764
55179
|
const hash = imageContentHash(dockerfile, entrypoint);
|
|
54765
55180
|
const image = sandbox.runtime.image;
|
|
54766
|
-
const hashFile =
|
|
54767
|
-
const lastHash =
|
|
55181
|
+
const hashFile = path62.join(sandboxBuildDir(cwd), ".image-hash");
|
|
55182
|
+
const lastHash = fs65.existsSync(hashFile) ? fs65.readFileSync(hashFile, "utf-8").trim() : "";
|
|
54768
55183
|
const imageExists = spawnSync6(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
|
|
54769
55184
|
const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
|
|
54770
55185
|
if (needBuild) {
|
|
@@ -54776,7 +55191,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54776
55191
|
console.error(chalk33.red(" build failed."));
|
|
54777
55192
|
process.exit(b.status ?? 1);
|
|
54778
55193
|
}
|
|
54779
|
-
|
|
55194
|
+
fs65.writeFileSync(hashFile, hash);
|
|
54780
55195
|
}
|
|
54781
55196
|
const dataDir = sandboxDataDir(cwd);
|
|
54782
55197
|
seedDataDirConfig(dataDir, sandbox);
|
|
@@ -54790,7 +55205,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54790
55205
|
});
|
|
54791
55206
|
if (sandbox.node9.mountAgentCredentials) {
|
|
54792
55207
|
const creds = agentCredentialsMount(sandbox.agent);
|
|
54793
|
-
if (
|
|
55208
|
+
if (fs65.existsSync(creds.hostPath)) {
|
|
54794
55209
|
console.log(chalk33.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
|
|
54795
55210
|
} else {
|
|
54796
55211
|
console.log(
|
|
@@ -54806,20 +55221,20 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54806
55221
|
process.exit(r.status ?? 0);
|
|
54807
55222
|
});
|
|
54808
55223
|
cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
|
|
54809
|
-
const auditPath =
|
|
54810
|
-
if (!
|
|
55224
|
+
const auditPath = path62.join(sandboxDataDir(), "audit.log");
|
|
55225
|
+
if (!fs65.existsSync(auditPath)) {
|
|
54811
55226
|
console.log(chalk33.dim(" no sandbox audit yet."));
|
|
54812
55227
|
return;
|
|
54813
55228
|
}
|
|
54814
55229
|
spawnSync6("tail", ["-f", auditPath], { stdio: "inherit" });
|
|
54815
55230
|
});
|
|
54816
55231
|
cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
|
|
54817
|
-
const auditPath =
|
|
54818
|
-
if (!
|
|
55232
|
+
const auditPath = path62.join(sandboxDataDir(), "audit.log");
|
|
55233
|
+
if (!fs65.existsSync(auditPath)) {
|
|
54819
55234
|
console.log(chalk33.dim(" no sandbox audit yet."));
|
|
54820
55235
|
return;
|
|
54821
55236
|
}
|
|
54822
|
-
process.stdout.write(
|
|
55237
|
+
process.stdout.write(fs65.readFileSync(auditPath, "utf-8"));
|
|
54823
55238
|
});
|
|
54824
55239
|
cmd.command("clean").description("Remove the sandbox image, build context, and data").action(() => {
|
|
54825
55240
|
const cwd = process.cwd();
|
|
@@ -54833,7 +55248,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54833
55248
|
stdio: "ignore"
|
|
54834
55249
|
});
|
|
54835
55250
|
}
|
|
54836
|
-
|
|
55251
|
+
fs65.rmSync(path62.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
|
|
54837
55252
|
console.log(chalk33.green(" \u2713 sandbox image + build + data removed."));
|
|
54838
55253
|
});
|
|
54839
55254
|
}
|
|
@@ -54844,9 +55259,9 @@ init_litellm();
|
|
|
54844
55259
|
init_cost_gemini();
|
|
54845
55260
|
init_cost_codex();
|
|
54846
55261
|
import chalk34 from "chalk";
|
|
54847
|
-
import
|
|
54848
|
-
import
|
|
54849
|
-
import
|
|
55262
|
+
import fs66 from "fs";
|
|
55263
|
+
import path63 from "path";
|
|
55264
|
+
import os56 from "os";
|
|
54850
55265
|
function modelPrice(model) {
|
|
54851
55266
|
const t = pricingFor(model);
|
|
54852
55267
|
if (!t) return null;
|
|
@@ -54863,10 +55278,10 @@ function encodeProjectPath(projectPath) {
|
|
|
54863
55278
|
}
|
|
54864
55279
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
54865
55280
|
const encoded = encodeProjectPath(projectPath);
|
|
54866
|
-
return
|
|
55281
|
+
return path63.join(os56.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
54867
55282
|
}
|
|
54868
55283
|
function projectLabel(projectPath) {
|
|
54869
|
-
return projectPath.replace(
|
|
55284
|
+
return projectPath.replace(os56.homedir(), "~");
|
|
54870
55285
|
}
|
|
54871
55286
|
function parseHistoryLines(lines) {
|
|
54872
55287
|
const entries = [];
|
|
@@ -54935,10 +55350,10 @@ function parseSessionLines(lines) {
|
|
|
54935
55350
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
54936
55351
|
}
|
|
54937
55352
|
function loadAuditEntries(auditPath) {
|
|
54938
|
-
const aPath = auditPath ??
|
|
55353
|
+
const aPath = auditPath ?? path63.join(os56.homedir(), ".node9", "audit.log");
|
|
54939
55354
|
let raw;
|
|
54940
55355
|
try {
|
|
54941
|
-
raw =
|
|
55356
|
+
raw = fs66.readFileSync(aPath, "utf-8");
|
|
54942
55357
|
} catch {
|
|
54943
55358
|
return [];
|
|
54944
55359
|
}
|
|
@@ -54974,8 +55389,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
54974
55389
|
return result;
|
|
54975
55390
|
}
|
|
54976
55391
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
54977
|
-
const tmpDir =
|
|
54978
|
-
if (!
|
|
55392
|
+
const tmpDir = path63.join(os56.homedir(), ".gemini", "tmp");
|
|
55393
|
+
if (!fs66.existsSync(tmpDir)) return [];
|
|
54979
55394
|
const cutoff = days !== null ? (() => {
|
|
54980
55395
|
const d = /* @__PURE__ */ new Date();
|
|
54981
55396
|
d.setDate(d.getDate() - days);
|
|
@@ -54984,35 +55399,35 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
54984
55399
|
})() : null;
|
|
54985
55400
|
let slugDirs;
|
|
54986
55401
|
try {
|
|
54987
|
-
slugDirs =
|
|
55402
|
+
slugDirs = fs66.readdirSync(tmpDir);
|
|
54988
55403
|
} catch {
|
|
54989
55404
|
return [];
|
|
54990
55405
|
}
|
|
54991
55406
|
const summaries = [];
|
|
54992
55407
|
for (const slug2 of slugDirs) {
|
|
54993
|
-
const slugPath =
|
|
55408
|
+
const slugPath = path63.join(tmpDir, slug2);
|
|
54994
55409
|
try {
|
|
54995
|
-
if (!
|
|
55410
|
+
if (!fs66.statSync(slugPath).isDirectory()) continue;
|
|
54996
55411
|
} catch {
|
|
54997
55412
|
continue;
|
|
54998
55413
|
}
|
|
54999
|
-
let projectRoot =
|
|
55414
|
+
let projectRoot = path63.join(os56.homedir(), slug2);
|
|
55000
55415
|
try {
|
|
55001
|
-
projectRoot =
|
|
55416
|
+
projectRoot = fs66.readFileSync(path63.join(slugPath, ".project_root"), "utf-8").trim();
|
|
55002
55417
|
} catch {
|
|
55003
55418
|
}
|
|
55004
|
-
const chatsDir =
|
|
55005
|
-
if (!
|
|
55419
|
+
const chatsDir = path63.join(slugPath, "chats");
|
|
55420
|
+
if (!fs66.existsSync(chatsDir)) continue;
|
|
55006
55421
|
let chatFiles;
|
|
55007
55422
|
try {
|
|
55008
|
-
chatFiles =
|
|
55423
|
+
chatFiles = fs66.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
55009
55424
|
} catch {
|
|
55010
55425
|
continue;
|
|
55011
55426
|
}
|
|
55012
55427
|
for (const chatFile of chatFiles) {
|
|
55013
55428
|
let raw;
|
|
55014
55429
|
try {
|
|
55015
|
-
raw =
|
|
55430
|
+
raw = fs66.readFileSync(path63.join(chatsDir, chatFile), "utf-8");
|
|
55016
55431
|
} catch {
|
|
55017
55432
|
continue;
|
|
55018
55433
|
}
|
|
@@ -55092,8 +55507,8 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
55092
55507
|
return summaries;
|
|
55093
55508
|
}
|
|
55094
55509
|
function buildCodexSessions(days, allAuditEntries) {
|
|
55095
|
-
const sessionsBase =
|
|
55096
|
-
if (!
|
|
55510
|
+
const sessionsBase = path63.join(os56.homedir(), ".codex", "sessions");
|
|
55511
|
+
if (!fs66.existsSync(sessionsBase)) return [];
|
|
55097
55512
|
const cutoff = days !== null ? (() => {
|
|
55098
55513
|
const d = /* @__PURE__ */ new Date();
|
|
55099
55514
|
d.setDate(d.getDate() - days);
|
|
@@ -55102,29 +55517,29 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
55102
55517
|
})() : null;
|
|
55103
55518
|
const jsonlFiles = [];
|
|
55104
55519
|
try {
|
|
55105
|
-
for (const year of
|
|
55106
|
-
const yearPath =
|
|
55520
|
+
for (const year of fs66.readdirSync(sessionsBase)) {
|
|
55521
|
+
const yearPath = path63.join(sessionsBase, year);
|
|
55107
55522
|
try {
|
|
55108
|
-
if (!
|
|
55523
|
+
if (!fs66.statSync(yearPath).isDirectory()) continue;
|
|
55109
55524
|
} catch {
|
|
55110
55525
|
continue;
|
|
55111
55526
|
}
|
|
55112
|
-
for (const month of
|
|
55113
|
-
const monthPath =
|
|
55527
|
+
for (const month of fs66.readdirSync(yearPath)) {
|
|
55528
|
+
const monthPath = path63.join(yearPath, month);
|
|
55114
55529
|
try {
|
|
55115
|
-
if (!
|
|
55530
|
+
if (!fs66.statSync(monthPath).isDirectory()) continue;
|
|
55116
55531
|
} catch {
|
|
55117
55532
|
continue;
|
|
55118
55533
|
}
|
|
55119
|
-
for (const day of
|
|
55120
|
-
const dayPath =
|
|
55534
|
+
for (const day of fs66.readdirSync(monthPath)) {
|
|
55535
|
+
const dayPath = path63.join(monthPath, day);
|
|
55121
55536
|
try {
|
|
55122
|
-
if (!
|
|
55537
|
+
if (!fs66.statSync(dayPath).isDirectory()) continue;
|
|
55123
55538
|
} catch {
|
|
55124
55539
|
continue;
|
|
55125
55540
|
}
|
|
55126
|
-
for (const file of
|
|
55127
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
55541
|
+
for (const file of fs66.readdirSync(dayPath)) {
|
|
55542
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path63.join(dayPath, file));
|
|
55128
55543
|
}
|
|
55129
55544
|
}
|
|
55130
55545
|
}
|
|
@@ -55136,7 +55551,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
55136
55551
|
for (const filePath of jsonlFiles) {
|
|
55137
55552
|
let lines;
|
|
55138
55553
|
try {
|
|
55139
|
-
lines =
|
|
55554
|
+
lines = fs66.readFileSync(filePath, "utf-8").split("\n");
|
|
55140
55555
|
} catch {
|
|
55141
55556
|
continue;
|
|
55142
55557
|
}
|
|
@@ -55222,10 +55637,10 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
55222
55637
|
return summaries;
|
|
55223
55638
|
}
|
|
55224
55639
|
function buildSessions(days, historyPath) {
|
|
55225
|
-
const hPath = historyPath ??
|
|
55640
|
+
const hPath = historyPath ?? path63.join(os56.homedir(), ".claude", "history.jsonl");
|
|
55226
55641
|
let historyRaw = "";
|
|
55227
55642
|
try {
|
|
55228
|
-
historyRaw =
|
|
55643
|
+
historyRaw = fs66.readFileSync(hPath, "utf-8");
|
|
55229
55644
|
} catch {
|
|
55230
55645
|
}
|
|
55231
55646
|
const cutoff = days !== null ? (() => {
|
|
@@ -55249,7 +55664,7 @@ function buildSessions(days, historyPath) {
|
|
|
55249
55664
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
55250
55665
|
let sessionLines = [];
|
|
55251
55666
|
try {
|
|
55252
|
-
sessionLines =
|
|
55667
|
+
sessionLines = fs66.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
55253
55668
|
} catch {
|
|
55254
55669
|
}
|
|
55255
55670
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -55643,12 +56058,12 @@ function registerSessionTaintCommand(program2) {
|
|
|
55643
56058
|
|
|
55644
56059
|
// src/cli/commands/skill-pin.ts
|
|
55645
56060
|
import chalk36 from "chalk";
|
|
55646
|
-
import
|
|
55647
|
-
import
|
|
55648
|
-
import
|
|
56061
|
+
import fs67 from "fs";
|
|
56062
|
+
import os57 from "os";
|
|
56063
|
+
import path64 from "path";
|
|
55649
56064
|
function wipeSkillSessions() {
|
|
55650
56065
|
try {
|
|
55651
|
-
|
|
56066
|
+
fs67.rmSync(path64.join(os57.homedir(), ".node9", "skill-sessions"), {
|
|
55652
56067
|
recursive: true,
|
|
55653
56068
|
force: true
|
|
55654
56069
|
});
|
|
@@ -55730,15 +56145,15 @@ function registerSkillPinCommand(program2) {
|
|
|
55730
56145
|
}
|
|
55731
56146
|
|
|
55732
56147
|
// src/cli/commands/decisions.ts
|
|
55733
|
-
import
|
|
55734
|
-
import
|
|
55735
|
-
import
|
|
56148
|
+
import fs68 from "fs";
|
|
56149
|
+
import os58 from "os";
|
|
56150
|
+
import path65 from "path";
|
|
55736
56151
|
import chalk37 from "chalk";
|
|
55737
|
-
var DECISIONS_FILE2 =
|
|
56152
|
+
var DECISIONS_FILE2 = path65.join(os58.homedir(), ".node9", "decisions.json");
|
|
55738
56153
|
function readDecisions() {
|
|
55739
56154
|
try {
|
|
55740
|
-
if (!
|
|
55741
|
-
const raw =
|
|
56155
|
+
if (!fs68.existsSync(DECISIONS_FILE2)) return {};
|
|
56156
|
+
const raw = fs68.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
55742
56157
|
const parsed = JSON.parse(raw);
|
|
55743
56158
|
const out = {};
|
|
55744
56159
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -55750,11 +56165,11 @@ function readDecisions() {
|
|
|
55750
56165
|
}
|
|
55751
56166
|
}
|
|
55752
56167
|
function writeDecisions(d) {
|
|
55753
|
-
const dir =
|
|
55754
|
-
if (!
|
|
56168
|
+
const dir = path65.dirname(DECISIONS_FILE2);
|
|
56169
|
+
if (!fs68.existsSync(dir)) fs68.mkdirSync(dir, { recursive: true });
|
|
55755
56170
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
55756
|
-
|
|
55757
|
-
|
|
56171
|
+
fs68.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
56172
|
+
fs68.renameSync(tmp, DECISIONS_FILE2);
|
|
55758
56173
|
}
|
|
55759
56174
|
function registerDecisionsCommand(program2) {
|
|
55760
56175
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -55811,18 +56226,18 @@ Persistent decisions (${entries.length})
|
|
|
55811
56226
|
|
|
55812
56227
|
// src/cli/commands/dlp.ts
|
|
55813
56228
|
import chalk38 from "chalk";
|
|
55814
|
-
import
|
|
55815
|
-
import
|
|
55816
|
-
import
|
|
55817
|
-
var AUDIT_LOG =
|
|
55818
|
-
var RESOLVED_FILE =
|
|
56229
|
+
import fs69 from "fs";
|
|
56230
|
+
import path66 from "path";
|
|
56231
|
+
import os59 from "os";
|
|
56232
|
+
var AUDIT_LOG = path66.join(os59.homedir(), ".node9", "audit.log");
|
|
56233
|
+
var RESOLVED_FILE = path66.join(os59.homedir(), ".node9", "dlp-resolved.json");
|
|
55819
56234
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
55820
56235
|
function stripAnsi(s) {
|
|
55821
56236
|
return s.replace(ANSI_RE, "");
|
|
55822
56237
|
}
|
|
55823
56238
|
function loadResolved() {
|
|
55824
56239
|
try {
|
|
55825
|
-
const raw = JSON.parse(
|
|
56240
|
+
const raw = JSON.parse(fs69.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
55826
56241
|
return new Set(raw);
|
|
55827
56242
|
} catch {
|
|
55828
56243
|
return /* @__PURE__ */ new Set();
|
|
@@ -55830,13 +56245,13 @@ function loadResolved() {
|
|
|
55830
56245
|
}
|
|
55831
56246
|
function saveResolved(resolved) {
|
|
55832
56247
|
try {
|
|
55833
|
-
|
|
56248
|
+
fs69.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
55834
56249
|
} catch {
|
|
55835
56250
|
}
|
|
55836
56251
|
}
|
|
55837
56252
|
function loadDlpFindings() {
|
|
55838
|
-
if (!
|
|
55839
|
-
return
|
|
56253
|
+
if (!fs69.existsSync(AUDIT_LOG)) return [];
|
|
56254
|
+
return fs69.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
55840
56255
|
if (!line.trim()) return [];
|
|
55841
56256
|
try {
|
|
55842
56257
|
const e = JSON.parse(line);
|
|
@@ -55935,14 +56350,14 @@ function registerDlpCommand(program2) {
|
|
|
55935
56350
|
// src/cli/commands/mask.ts
|
|
55936
56351
|
init_dlp();
|
|
55937
56352
|
import chalk39 from "chalk";
|
|
55938
|
-
import
|
|
55939
|
-
import
|
|
55940
|
-
import
|
|
56353
|
+
import fs70 from "fs";
|
|
56354
|
+
import path67 from "path";
|
|
56355
|
+
import os60 from "os";
|
|
55941
56356
|
function findJsonlFiles(dir) {
|
|
55942
56357
|
const results = [];
|
|
55943
|
-
if (!
|
|
55944
|
-
for (const entry of
|
|
55945
|
-
const full =
|
|
56358
|
+
if (!fs70.existsSync(dir)) return results;
|
|
56359
|
+
for (const entry of fs70.readdirSync(dir, { withFileTypes: true })) {
|
|
56360
|
+
const full = path67.join(dir, entry.name);
|
|
55946
56361
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
55947
56362
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
55948
56363
|
}
|
|
@@ -55985,7 +56400,7 @@ function redactJson(obj) {
|
|
|
55985
56400
|
function processFile(filePath, dryRun) {
|
|
55986
56401
|
let raw;
|
|
55987
56402
|
try {
|
|
55988
|
-
raw =
|
|
56403
|
+
raw = fs70.readFileSync(filePath, "utf-8");
|
|
55989
56404
|
} catch {
|
|
55990
56405
|
return { redactedLines: 0, patterns: [] };
|
|
55991
56406
|
}
|
|
@@ -56017,14 +56432,14 @@ function processFile(filePath, dryRun) {
|
|
|
56017
56432
|
}
|
|
56018
56433
|
}
|
|
56019
56434
|
if (!dryRun && redactedLines > 0) {
|
|
56020
|
-
|
|
56435
|
+
fs70.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
56021
56436
|
}
|
|
56022
56437
|
return { redactedLines, patterns };
|
|
56023
56438
|
}
|
|
56024
56439
|
function processJsonFile(filePath, dryRun) {
|
|
56025
56440
|
let raw;
|
|
56026
56441
|
try {
|
|
56027
|
-
raw =
|
|
56442
|
+
raw = fs70.readFileSync(filePath, "utf-8");
|
|
56028
56443
|
} catch {
|
|
56029
56444
|
return { redactedLines: 0, patterns: [] };
|
|
56030
56445
|
}
|
|
@@ -56037,15 +56452,15 @@ function processJsonFile(filePath, dryRun) {
|
|
|
56037
56452
|
const { value, modified, found } = redactJson(parsed);
|
|
56038
56453
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
56039
56454
|
if (!dryRun) {
|
|
56040
|
-
|
|
56455
|
+
fs70.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
56041
56456
|
}
|
|
56042
56457
|
return { redactedLines: 1, patterns: found };
|
|
56043
56458
|
}
|
|
56044
56459
|
function findJsonFiles(dir) {
|
|
56045
56460
|
const results = [];
|
|
56046
|
-
if (!
|
|
56047
|
-
for (const entry of
|
|
56048
|
-
const full =
|
|
56461
|
+
if (!fs70.existsSync(dir)) return results;
|
|
56462
|
+
for (const entry of fs70.readdirSync(dir, { withFileTypes: true })) {
|
|
56463
|
+
const full = path67.join(dir, entry.name);
|
|
56049
56464
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
56050
56465
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
56051
56466
|
}
|
|
@@ -56054,9 +56469,9 @@ function findJsonFiles(dir) {
|
|
|
56054
56469
|
function registerMaskCommand(program2) {
|
|
56055
56470
|
program2.command("mask").description("Redact plaintext secrets from local AI session history files").option("--dry-run", "show what would be redacted without making changes").option("--all", "scan all history (default: last 30 days)").action(async (options) => {
|
|
56056
56471
|
const dryRun = !!options.dryRun;
|
|
56057
|
-
const home =
|
|
56058
|
-
const claudeDir =
|
|
56059
|
-
const geminiDir =
|
|
56472
|
+
const home = os60.homedir();
|
|
56473
|
+
const claudeDir = path67.join(home, ".claude", "projects");
|
|
56474
|
+
const geminiDir = path67.join(home, ".gemini", "tmp");
|
|
56060
56475
|
const allFiles = [
|
|
56061
56476
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
56062
56477
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -56064,7 +56479,7 @@ function registerMaskCommand(program2) {
|
|
|
56064
56479
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
56065
56480
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
56066
56481
|
try {
|
|
56067
|
-
return
|
|
56482
|
+
return fs70.statSync(f.path).mtime >= cutoff;
|
|
56068
56483
|
} catch {
|
|
56069
56484
|
return false;
|
|
56070
56485
|
}
|
|
@@ -56120,7 +56535,7 @@ function registerMaskCommand(program2) {
|
|
|
56120
56535
|
// src/cli.ts
|
|
56121
56536
|
init_blast();
|
|
56122
56537
|
var { version } = JSON.parse(
|
|
56123
|
-
|
|
56538
|
+
fs73.readFileSync(path70.join(__dirname, "../package.json"), "utf-8")
|
|
56124
56539
|
);
|
|
56125
56540
|
var program = new Command();
|
|
56126
56541
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
@@ -56146,6 +56561,11 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
56146
56561
|
} else {
|
|
56147
56562
|
console.log(chalk41.green(`\u2705 Logged in \u2014 agent mode`));
|
|
56148
56563
|
console.log(chalk41.gray(` Team policy enforced for all calls via Node9 cloud.`));
|
|
56564
|
+
if (!isTestingMode()) {
|
|
56565
|
+
const healed = ensureAutostartHealthy(!!getConfig().settings.autoStartDaemon);
|
|
56566
|
+
if (healed === "repaired")
|
|
56567
|
+
console.log(chalk41.green(` \u2713 Re-enabled daemon autostart (survives reboot)`));
|
|
56568
|
+
}
|
|
56149
56569
|
}
|
|
56150
56570
|
});
|
|
56151
56571
|
program.command("signup").description("Create your node9 account / open the dashboard in your browser").option("--login", "Open the login page instead of signup").action((options) => {
|
|
@@ -56294,15 +56714,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
56294
56714
|
} catch {
|
|
56295
56715
|
}
|
|
56296
56716
|
if (options.purge) {
|
|
56297
|
-
const node9Dir =
|
|
56298
|
-
if (
|
|
56717
|
+
const node9Dir = path70.join(os63.homedir(), ".node9");
|
|
56718
|
+
if (fs73.existsSync(node9Dir)) {
|
|
56299
56719
|
const confirmed = await confirm2({
|
|
56300
56720
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
56301
56721
|
default: false
|
|
56302
56722
|
});
|
|
56303
56723
|
if (confirmed) {
|
|
56304
|
-
|
|
56305
|
-
if (
|
|
56724
|
+
fs73.rmSync(node9Dir, { recursive: true });
|
|
56725
|
+
if (fs73.existsSync(node9Dir)) {
|
|
56306
56726
|
console.error(
|
|
56307
56727
|
chalk41.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
56308
56728
|
);
|
|
@@ -56427,7 +56847,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
56427
56847
|
});
|
|
56428
56848
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
56429
56849
|
try {
|
|
56430
|
-
const dashboardPath =
|
|
56850
|
+
const dashboardPath = path70.join(__dirname, "dashboard.mjs");
|
|
56431
56851
|
const dynamicImport = new Function("id", "return import(id)");
|
|
56432
56852
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
56433
56853
|
await mod.startMonitor();
|
|
@@ -56465,14 +56885,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
56465
56885
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
56466
56886
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
56467
56887
|
if (subcommand === "debug") {
|
|
56468
|
-
const flagFile =
|
|
56888
|
+
const flagFile = path70.join(os63.homedir(), ".node9", "hud-debug");
|
|
56469
56889
|
if (state === "on") {
|
|
56470
|
-
|
|
56471
|
-
|
|
56890
|
+
fs73.mkdirSync(path70.dirname(flagFile), { recursive: true });
|
|
56891
|
+
fs73.writeFileSync(flagFile, "");
|
|
56472
56892
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
56473
56893
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
56474
56894
|
} else if (state === "off") {
|
|
56475
|
-
if (
|
|
56895
|
+
if (fs73.existsSync(flagFile)) fs73.unlinkSync(flagFile);
|
|
56476
56896
|
console.log("HUD debug logging disabled.");
|
|
56477
56897
|
} else {
|
|
56478
56898
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -56595,9 +57015,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
56595
57015
|
const isCheckHook = process.argv[2] === "check";
|
|
56596
57016
|
if (isCheckHook) {
|
|
56597
57017
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
56598
|
-
const logPath =
|
|
57018
|
+
const logPath = path70.join(os63.homedir(), ".node9", "hook-debug.log");
|
|
56599
57019
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
56600
|
-
|
|
57020
|
+
fs73.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
56601
57021
|
`);
|
|
56602
57022
|
}
|
|
56603
57023
|
process.exit(0);
|