@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.js
CHANGED
|
@@ -243,8 +243,8 @@ function sanitizeConfig(raw) {
|
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
245
|
const lines = result.error.issues.map((issue) => {
|
|
246
|
-
const
|
|
247
|
-
return ` \u2022 ${
|
|
246
|
+
const path71 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
247
|
+
return ` \u2022 ${path71}: ${issue.message}`;
|
|
248
248
|
});
|
|
249
249
|
return {
|
|
250
250
|
sanitized,
|
|
@@ -973,6 +973,91 @@ function analyzeFsOperation(command) {
|
|
|
973
973
|
fsOpCache.set(normalized, computed);
|
|
974
974
|
return computed;
|
|
975
975
|
}
|
|
976
|
+
function isSensitiveCleanupName(p) {
|
|
977
|
+
const base = p.replace(/^.*[\\/]/, "");
|
|
978
|
+
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);
|
|
979
|
+
}
|
|
980
|
+
function isWaivableCleanupTarget(p) {
|
|
981
|
+
if (/^[/~]/.test(p) || /^\$/.test(p)) return false;
|
|
982
|
+
if (/(?:^|[\\/])\.\.(?:[\\/]|$)/.test(p)) return false;
|
|
983
|
+
if (/[*?[{]/.test(p)) return false;
|
|
984
|
+
if (isSensitiveCleanupName(p)) return false;
|
|
985
|
+
return true;
|
|
986
|
+
}
|
|
987
|
+
function deriveRedirOp(sample) {
|
|
988
|
+
try {
|
|
989
|
+
const f = sharedParser.Parse(sample, "cmd");
|
|
990
|
+
let op = -1;
|
|
991
|
+
syntax.Walk(f, (node) => {
|
|
992
|
+
const n = node;
|
|
993
|
+
if (n && syntax.NodeType(n) === "Redirect" && op < 0) op = n.Op;
|
|
994
|
+
return true;
|
|
995
|
+
});
|
|
996
|
+
return op;
|
|
997
|
+
} catch {
|
|
998
|
+
return -1;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
function collectSameCommandCreations(f) {
|
|
1002
|
+
const created = /* @__PURE__ */ new Set();
|
|
1003
|
+
try {
|
|
1004
|
+
const stmts = Array.isArray(f?.Stmts) ? f.Stmts : [];
|
|
1005
|
+
for (const stmt of stmts) {
|
|
1006
|
+
if (!stmt || !stmt.Cmd || syntax.NodeType(stmt.Cmd) !== "CallExpr") continue;
|
|
1007
|
+
const redirs = stmt.Redirs || [];
|
|
1008
|
+
if (!redirs.some((r) => r && REDIR_HEREDOC_OPS.has(r.Op))) continue;
|
|
1009
|
+
for (const r of redirs) {
|
|
1010
|
+
if (r && REDIR_TRUNCATE_OPS.has(r.Op) && r.N == null) {
|
|
1011
|
+
const w = resolveWordLiteral(r.Word);
|
|
1012
|
+
if (w) created.add(stripDotSlash(w));
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
} catch {
|
|
1017
|
+
return created;
|
|
1018
|
+
}
|
|
1019
|
+
return created;
|
|
1020
|
+
}
|
|
1021
|
+
function isRmCreatedInCommandCleanup(command) {
|
|
1022
|
+
if (!/\brm\b/.test(command)) return false;
|
|
1023
|
+
const f = parseShared(command);
|
|
1024
|
+
if (f === PARSE_FAIL) return false;
|
|
1025
|
+
const created = collectSameCommandCreations(f);
|
|
1026
|
+
if (created.size === 0) return false;
|
|
1027
|
+
let sawRm = false;
|
|
1028
|
+
let ok2 = true;
|
|
1029
|
+
try {
|
|
1030
|
+
syntax.Walk(f, (node) => {
|
|
1031
|
+
if (!node || !ok2) return false;
|
|
1032
|
+
const n = node;
|
|
1033
|
+
if (syntax.NodeType(n) !== "CallExpr") return true;
|
|
1034
|
+
const args = n.Args || [];
|
|
1035
|
+
const name = (resolveWordLiteral(args[0]) ?? "").toLowerCase();
|
|
1036
|
+
if (name !== "rm") return true;
|
|
1037
|
+
sawRm = true;
|
|
1038
|
+
const { flags, paths } = extractLiteralArgs(n);
|
|
1039
|
+
if (args.length - 1 > flags.length + paths.length) {
|
|
1040
|
+
ok2 = false;
|
|
1041
|
+
return false;
|
|
1042
|
+
}
|
|
1043
|
+
if (paths.length === 0) {
|
|
1044
|
+
ok2 = false;
|
|
1045
|
+
return false;
|
|
1046
|
+
}
|
|
1047
|
+
for (const p of paths) {
|
|
1048
|
+
const np = stripDotSlash(p);
|
|
1049
|
+
if (!created.has(np) || !isWaivableCleanupTarget(np)) {
|
|
1050
|
+
ok2 = false;
|
|
1051
|
+
return false;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
return true;
|
|
1055
|
+
});
|
|
1056
|
+
} catch {
|
|
1057
|
+
return false;
|
|
1058
|
+
}
|
|
1059
|
+
return sawRm && ok2;
|
|
1060
|
+
}
|
|
976
1061
|
function analyzeFsOperationImpl(command) {
|
|
977
1062
|
const f = parseShared(command);
|
|
978
1063
|
if (f === PARSE_FAIL) return null;
|
|
@@ -1369,9 +1454,9 @@ function matchesPattern(text, patterns) {
|
|
|
1369
1454
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
1370
1455
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
1371
1456
|
}
|
|
1372
|
-
function getNestedValue(obj,
|
|
1457
|
+
function getNestedValue(obj, path71) {
|
|
1373
1458
|
if (!obj || typeof obj !== "object") return null;
|
|
1374
|
-
const segments =
|
|
1459
|
+
const segments = path71.split(".");
|
|
1375
1460
|
for (const seg of segments) {
|
|
1376
1461
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
1377
1462
|
}
|
|
@@ -1543,8 +1628,9 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
1543
1628
|
}
|
|
1544
1629
|
}
|
|
1545
1630
|
if (config.policy.smartRules.length > 0) {
|
|
1631
|
+
const rmCleanupWaiver = bashCommand !== null && isRmCreatedInCommandCleanup(bashCommand);
|
|
1546
1632
|
const matches = config.policy.smartRules.filter(
|
|
1547
|
-
(rule) => matchesPattern(toolName, rule.tool) && !(bashCommand !== null && rule.name && AST_FS_REGEX_RULES.has(rule.name)) && evaluateSmartConditions(args, rule)
|
|
1633
|
+
(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)
|
|
1548
1634
|
);
|
|
1549
1635
|
const matchedRule = resolvePinned(matches);
|
|
1550
1636
|
if (matchedRule) {
|
|
@@ -2285,7 +2371,7 @@ function* stringValues(obj, depth = 0) {
|
|
|
2285
2371
|
}
|
|
2286
2372
|
for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
|
|
2287
2373
|
}
|
|
2288
|
-
var import_safe_regex2, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto3, 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;
|
|
2374
|
+
var import_safe_regex2, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto3, 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;
|
|
2289
2375
|
var init_dist = __esm({
|
|
2290
2376
|
"packages/policy-engine/dist/index.mjs"() {
|
|
2291
2377
|
"use strict";
|
|
@@ -2962,7 +3048,7 @@ var init_dist = __esm({
|
|
|
2962
3048
|
"mongosh"
|
|
2963
3049
|
]);
|
|
2964
3050
|
SQL_DDL_RE = /\b(DROP|TRUNCATE)\s+(TABLE|DATABASE|SCHEMA|INDEX)\b/i;
|
|
2965
|
-
CHMOD_OPEN_PERM_TOKENS = /* @__PURE__ */ new Set(["777", "0777", "a+rwx"
|
|
3051
|
+
CHMOD_OPEN_PERM_TOKENS = /* @__PURE__ */ new Set(["777", "0777", "a+rwx"]);
|
|
2966
3052
|
COMMAND_WRAPPERS = /* @__PURE__ */ new Set([
|
|
2967
3053
|
"sudo",
|
|
2968
3054
|
"doas",
|
|
@@ -3065,6 +3151,12 @@ var init_dist = __esm({
|
|
|
3065
3151
|
};
|
|
3066
3152
|
FS_OP_CACHE_MAX = 5e3;
|
|
3067
3153
|
fsOpCache = /* @__PURE__ */ new Map();
|
|
3154
|
+
stripDotSlash = (p) => p.replace(/^\.\//, "");
|
|
3155
|
+
REDIR_TRUNCATE_OPS = /* @__PURE__ */ new Set([deriveRedirOp(">_f")]);
|
|
3156
|
+
REDIR_HEREDOC_OPS = /* @__PURE__ */ new Set([
|
|
3157
|
+
deriveRedirOp("cat <<X\nX"),
|
|
3158
|
+
deriveRedirOp("cat <<-X\nX")
|
|
3159
|
+
]);
|
|
3068
3160
|
DEFAULT_EGRESS_ALLOWLIST = [
|
|
3069
3161
|
"*.github.com",
|
|
3070
3162
|
"*.githubusercontent.com",
|
|
@@ -4750,10 +4842,10 @@ function getConfig(cwd) {
|
|
|
4750
4842
|
}
|
|
4751
4843
|
if (Array.isArray(mc.jailPaths)) {
|
|
4752
4844
|
for (const jp of mc.jailPaths) {
|
|
4753
|
-
const
|
|
4754
|
-
if (!
|
|
4845
|
+
const path71 = typeof jp?.path === "string" ? jp.path.trim() : "";
|
|
4846
|
+
if (!path71) continue;
|
|
4755
4847
|
const verdict = jp?.verdict === "review" ? "review" : "block";
|
|
4756
|
-
for (const r of pathRules(
|
|
4848
|
+
for (const r of pathRules(path71, verdict, "org-managed jail")) {
|
|
4757
4849
|
mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
|
|
4758
4850
|
}
|
|
4759
4851
|
}
|
|
@@ -17873,6 +17965,66 @@ function pickSyncIntervalMs(cloudHours, localSettings) {
|
|
|
17873
17965
|
function effectiveSyncIntervalMs() {
|
|
17874
17966
|
return pickSyncIntervalMs(readCachedSyncIntervalHours(), getConfig().settings);
|
|
17875
17967
|
}
|
|
17968
|
+
function readSyncHealth() {
|
|
17969
|
+
try {
|
|
17970
|
+
const raw = JSON.parse(import_fs35.default.readFileSync(syncHealthFile(), "utf-8"));
|
|
17971
|
+
return {
|
|
17972
|
+
lastCheckedAt: typeof raw.lastCheckedAt === "string" ? raw.lastCheckedAt : void 0,
|
|
17973
|
+
lastChangedAt: typeof raw.lastChangedAt === "string" ? raw.lastChangedAt : void 0,
|
|
17974
|
+
lastError: typeof raw.lastError === "string" ? raw.lastError : void 0,
|
|
17975
|
+
lastErrorAt: typeof raw.lastErrorAt === "string" ? raw.lastErrorAt : void 0,
|
|
17976
|
+
consecutiveFailures: typeof raw.consecutiveFailures === "number" && raw.consecutiveFailures >= 0 ? raw.consecutiveFailures : 0
|
|
17977
|
+
};
|
|
17978
|
+
} catch {
|
|
17979
|
+
return { consecutiveFailures: 0 };
|
|
17980
|
+
}
|
|
17981
|
+
}
|
|
17982
|
+
function writeSyncHealth(h) {
|
|
17983
|
+
try {
|
|
17984
|
+
const file = syncHealthFile();
|
|
17985
|
+
const dir = import_path34.default.dirname(file);
|
|
17986
|
+
if (!import_fs35.default.existsSync(dir)) import_fs35.default.mkdirSync(dir, { recursive: true });
|
|
17987
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
17988
|
+
import_fs35.default.writeFileSync(tmp, JSON.stringify(h, null, 2) + "\n", "utf-8");
|
|
17989
|
+
import_fs35.default.renameSync(tmp, file);
|
|
17990
|
+
} catch {
|
|
17991
|
+
}
|
|
17992
|
+
}
|
|
17993
|
+
function readCacheFetchedAt() {
|
|
17994
|
+
try {
|
|
17995
|
+
const raw = JSON.parse(import_fs35.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
17996
|
+
return typeof raw.fetchedAt === "string" ? raw.fetchedAt : void 0;
|
|
17997
|
+
} catch {
|
|
17998
|
+
return void 0;
|
|
17999
|
+
}
|
|
18000
|
+
}
|
|
18001
|
+
function recordSyncHealth(result) {
|
|
18002
|
+
const h = readSyncHealth();
|
|
18003
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
18004
|
+
if (result.ok) {
|
|
18005
|
+
h.lastCheckedAt = now;
|
|
18006
|
+
if (result.changed) h.lastChangedAt = now;
|
|
18007
|
+
h.consecutiveFailures = 0;
|
|
18008
|
+
h.lastError = void 0;
|
|
18009
|
+
h.lastErrorAt = void 0;
|
|
18010
|
+
} else {
|
|
18011
|
+
h.consecutiveFailures += 1;
|
|
18012
|
+
h.lastError = result.error;
|
|
18013
|
+
h.lastErrorAt = now;
|
|
18014
|
+
}
|
|
18015
|
+
writeSyncHealth(h);
|
|
18016
|
+
}
|
|
18017
|
+
function stalenessThresholdMs(intervalMs) {
|
|
18018
|
+
return Math.min(STALE_MAX_MS, Math.max(STALE_MIN_MS, intervalMs * STALE_FACTOR));
|
|
18019
|
+
}
|
|
18020
|
+
function isPolicyStale(nowMs = Date.now(), health) {
|
|
18021
|
+
const h = health ?? readSyncHealth();
|
|
18022
|
+
const lastKnownGood = h.lastCheckedAt ?? readCacheFetchedAt();
|
|
18023
|
+
if (!lastKnownGood) return false;
|
|
18024
|
+
const last = Date.parse(lastKnownGood);
|
|
18025
|
+
if (Number.isNaN(last)) return false;
|
|
18026
|
+
return nowMs - last > stalenessThresholdMs(effectiveSyncIntervalMs());
|
|
18027
|
+
}
|
|
17876
18028
|
function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
|
|
17877
18029
|
const parsed = new URL(apiUrl);
|
|
17878
18030
|
const headers = {
|
|
@@ -18037,6 +18189,7 @@ async function syncOnce() {
|
|
|
18037
18189
|
try {
|
|
18038
18190
|
const result = await fetchCloudPolicy(creds.apiKey, creds.apiUrl, readCachedEtag());
|
|
18039
18191
|
if (result.kind === "unchanged") {
|
|
18192
|
+
recordSyncHealth({ ok: true });
|
|
18040
18193
|
} else {
|
|
18041
18194
|
const cache = {
|
|
18042
18195
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -18050,8 +18203,19 @@ async function syncOnce() {
|
|
|
18050
18203
|
managedConfig: extractManagedConfig(result.body)
|
|
18051
18204
|
};
|
|
18052
18205
|
writeCache2(cache);
|
|
18206
|
+
recordSyncHealth({ ok: true, changed: true });
|
|
18207
|
+
}
|
|
18208
|
+
} catch (err2) {
|
|
18209
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
18210
|
+
recordSyncHealth({ ok: false, error: msg });
|
|
18211
|
+
try {
|
|
18212
|
+
appendToLog(HOOK_DEBUG_LOG, {
|
|
18213
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18214
|
+
kind: "policy-sync-error",
|
|
18215
|
+
error: msg
|
|
18216
|
+
});
|
|
18217
|
+
} catch {
|
|
18053
18218
|
}
|
|
18054
|
-
} catch {
|
|
18055
18219
|
}
|
|
18056
18220
|
if (process.env.NODE9_BLAST_DISABLE !== "1") {
|
|
18057
18221
|
void pushBlastSnapshot(creds);
|
|
@@ -18227,6 +18391,7 @@ async function runCloudSync() {
|
|
|
18227
18391
|
const result = await fetchCloudPolicy(creds.apiKey, creds.apiUrl, readCachedEtag());
|
|
18228
18392
|
if (result.kind === "unchanged") {
|
|
18229
18393
|
const status = getCloudSyncStatus();
|
|
18394
|
+
recordSyncHealth({ ok: true });
|
|
18230
18395
|
maybePushBlast();
|
|
18231
18396
|
return status.cached ? { ok: true, rules: status.rules, fetchedAt: status.fetchedAt, unchanged: true } : { ok: true, rules: 0, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), unchanged: true };
|
|
18232
18397
|
}
|
|
@@ -18242,11 +18407,14 @@ async function runCloudSync() {
|
|
|
18242
18407
|
managedConfig: extractManagedConfig(result.body)
|
|
18243
18408
|
};
|
|
18244
18409
|
writeCache2(cache);
|
|
18410
|
+
recordSyncHealth({ ok: true, changed: true });
|
|
18245
18411
|
maybePushBlast();
|
|
18246
18412
|
return { ok: true, rules: cache.rules.length, fetchedAt: cache.fetchedAt };
|
|
18247
18413
|
} catch (err2) {
|
|
18414
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
18415
|
+
recordSyncHealth({ ok: false, error: msg });
|
|
18248
18416
|
maybePushBlast();
|
|
18249
|
-
return { ok: false, reason:
|
|
18417
|
+
return { ok: false, reason: msg };
|
|
18250
18418
|
}
|
|
18251
18419
|
}
|
|
18252
18420
|
function getCloudSyncStatus() {
|
|
@@ -18303,7 +18471,7 @@ function startForensicBroadcast() {
|
|
|
18303
18471
|
const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
|
|
18304
18472
|
recurring.unref();
|
|
18305
18473
|
}
|
|
18306
|
-
var import_fs35, import_https4, import_os32, import_path34, 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;
|
|
18474
|
+
var import_fs35, import_https4, import_os32, import_path34, 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;
|
|
18307
18475
|
var init_sync = __esm({
|
|
18308
18476
|
"src/daemon/sync.ts"() {
|
|
18309
18477
|
"use strict";
|
|
@@ -18341,6 +18509,10 @@ var init_sync = __esm({
|
|
|
18341
18509
|
DEFAULT_INTERVAL_HOURS = 5;
|
|
18342
18510
|
MIN_INTERVAL_SECONDS = 15;
|
|
18343
18511
|
MAX_INTERVAL_SECONDS = 24 * 60 * 60;
|
|
18512
|
+
syncHealthFile = () => import_path34.default.join(import_os32.default.homedir(), ".node9", "sync-health.json");
|
|
18513
|
+
STALE_MIN_MS = 3 * 60 * 60 * 1e3;
|
|
18514
|
+
STALE_MAX_MS = 24 * 60 * 60 * 1e3;
|
|
18515
|
+
STALE_FACTOR = 3;
|
|
18344
18516
|
FORENSIC_BROADCAST_INTERVAL_MS = 3e4;
|
|
18345
18517
|
FORENSIC_INITIAL_DELAY_MS = 5e3;
|
|
18346
18518
|
forensicBroadcastOffsets = /* @__PURE__ */ new Map();
|
|
@@ -18955,16 +19127,61 @@ var init_hook_heal = __esm({
|
|
|
18955
19127
|
}
|
|
18956
19128
|
});
|
|
18957
19129
|
|
|
19130
|
+
// src/daemon/startup-log.ts
|
|
19131
|
+
function openStartupLogFd() {
|
|
19132
|
+
try {
|
|
19133
|
+
const file = DAEMON_STARTUP_LOG();
|
|
19134
|
+
const dir = import_path38.default.dirname(file);
|
|
19135
|
+
if (!import_fs39.default.existsSync(dir)) import_fs39.default.mkdirSync(dir, { recursive: true });
|
|
19136
|
+
try {
|
|
19137
|
+
if (import_fs39.default.statSync(file).size > MAX_STARTUP_LOG_BYTES) import_fs39.default.truncateSync(file);
|
|
19138
|
+
} catch {
|
|
19139
|
+
}
|
|
19140
|
+
return import_fs39.default.openSync(file, "a");
|
|
19141
|
+
} catch {
|
|
19142
|
+
return void 0;
|
|
19143
|
+
}
|
|
19144
|
+
}
|
|
19145
|
+
function logDaemonStartup(kind, detail) {
|
|
19146
|
+
try {
|
|
19147
|
+
const file = DAEMON_STARTUP_LOG();
|
|
19148
|
+
const dir = import_path38.default.dirname(file);
|
|
19149
|
+
if (!import_fs39.default.existsSync(dir)) import_fs39.default.mkdirSync(dir, { recursive: true });
|
|
19150
|
+
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-startup:${kind}${detail ? ` ${detail}` : ""}
|
|
19151
|
+
`;
|
|
19152
|
+
import_fs39.default.appendFileSync(file, line, "utf-8");
|
|
19153
|
+
} catch {
|
|
19154
|
+
}
|
|
19155
|
+
}
|
|
19156
|
+
var import_fs39, import_path38, import_os36, DAEMON_STARTUP_LOG, MAX_STARTUP_LOG_BYTES;
|
|
19157
|
+
var init_startup_log = __esm({
|
|
19158
|
+
"src/daemon/startup-log.ts"() {
|
|
19159
|
+
"use strict";
|
|
19160
|
+
import_fs39 = __toESM(require("fs"));
|
|
19161
|
+
import_path38 = __toESM(require("path"));
|
|
19162
|
+
import_os36 = __toESM(require("os"));
|
|
19163
|
+
DAEMON_STARTUP_LOG = () => import_path38.default.join(import_os36.default.homedir(), ".node9", "daemon-startup.log");
|
|
19164
|
+
MAX_STARTUP_LOG_BYTES = 256 * 1024;
|
|
19165
|
+
}
|
|
19166
|
+
});
|
|
19167
|
+
|
|
18958
19168
|
// src/daemon/server.ts
|
|
18959
19169
|
function startDaemon() {
|
|
18960
|
-
|
|
18961
|
-
|
|
18962
|
-
|
|
18963
|
-
|
|
18964
|
-
|
|
18965
|
-
|
|
18966
|
-
|
|
18967
|
-
|
|
19170
|
+
try {
|
|
19171
|
+
startCostSync();
|
|
19172
|
+
startCloudSync();
|
|
19173
|
+
startForensicBroadcast();
|
|
19174
|
+
startAuditShipper();
|
|
19175
|
+
startDlpScanner();
|
|
19176
|
+
startMcpReconciler();
|
|
19177
|
+
startHookHeal();
|
|
19178
|
+
loadInsightCounts();
|
|
19179
|
+
} catch (err2) {
|
|
19180
|
+
const stack = err2 instanceof Error ? err2.stack ?? err2.message : String(err2);
|
|
19181
|
+
console.error("\n\u{1F6D1} Node9 daemon startup failed:\n" + stack);
|
|
19182
|
+
logDaemonStartup("startup-throw", err2 instanceof Error ? err2.message : String(err2));
|
|
19183
|
+
process.exit(1);
|
|
19184
|
+
}
|
|
18968
19185
|
const internalToken = (0, import_crypto11.randomUUID)();
|
|
18969
19186
|
const validToken = (req) => req.headers["x-node9-internal"] === internalToken || req.headers["x-node9-token"] === internalToken;
|
|
18970
19187
|
const IDLE_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
|
|
@@ -18976,7 +19193,7 @@ function startDaemon() {
|
|
|
18976
19193
|
idleTimer = setTimeout(() => {
|
|
18977
19194
|
if (autoStarted) {
|
|
18978
19195
|
try {
|
|
18979
|
-
|
|
19196
|
+
import_fs40.default.unlinkSync(DAEMON_PID_FILE);
|
|
18980
19197
|
} catch {
|
|
18981
19198
|
}
|
|
18982
19199
|
}
|
|
@@ -19121,7 +19338,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
19121
19338
|
mcpServer: entry.mcpServer
|
|
19122
19339
|
});
|
|
19123
19340
|
}
|
|
19124
|
-
const projectCwd = typeof cwd === "string" &&
|
|
19341
|
+
const projectCwd = typeof cwd === "string" && import_path39.default.isAbsolute(cwd) ? cwd : void 0;
|
|
19125
19342
|
const projectConfig = getConfig(projectCwd);
|
|
19126
19343
|
const browserEnabled = projectConfig.settings.approvers?.browser !== false;
|
|
19127
19344
|
const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
|
|
@@ -19413,8 +19630,8 @@ data: ${JSON.stringify(item.data)}
|
|
|
19413
19630
|
if (!validToken(req)) return res.writeHead(403).end();
|
|
19414
19631
|
const periodParam = reqUrl.searchParams.get("period") || "7d";
|
|
19415
19632
|
const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
|
|
19416
|
-
const logPath =
|
|
19417
|
-
if (!
|
|
19633
|
+
const logPath = import_path39.default.join(import_os37.default.homedir(), ".node9", "audit.log");
|
|
19634
|
+
if (!import_fs40.default.existsSync(logPath)) {
|
|
19418
19635
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
19419
19636
|
return res.end(
|
|
19420
19637
|
JSON.stringify({
|
|
@@ -19427,7 +19644,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
19427
19644
|
);
|
|
19428
19645
|
}
|
|
19429
19646
|
try {
|
|
19430
|
-
const raw =
|
|
19647
|
+
const raw = import_fs40.default.readFileSync(logPath, "utf-8");
|
|
19431
19648
|
const allEntries = raw.split("\n").flatMap((line) => {
|
|
19432
19649
|
if (!line.trim()) return [];
|
|
19433
19650
|
try {
|
|
@@ -19810,14 +20027,15 @@ data: ${JSON.stringify(item.data)}
|
|
|
19810
20027
|
server.on("error", (e) => {
|
|
19811
20028
|
if (e.code === "EADDRINUSE") {
|
|
19812
20029
|
try {
|
|
19813
|
-
if (
|
|
19814
|
-
const { pid } = JSON.parse(
|
|
20030
|
+
if (import_fs40.default.existsSync(DAEMON_PID_FILE)) {
|
|
20031
|
+
const { pid } = JSON.parse(import_fs40.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
19815
20032
|
process.kill(pid, 0);
|
|
20033
|
+
logDaemonStartup("port-in-use", `another daemon (pid ${pid}) owns :${DAEMON_PORT}`);
|
|
19816
20034
|
return process.exit(0);
|
|
19817
20035
|
}
|
|
19818
20036
|
} catch {
|
|
19819
20037
|
try {
|
|
19820
|
-
|
|
20038
|
+
import_fs40.default.unlinkSync(DAEMON_PID_FILE);
|
|
19821
20039
|
} catch {
|
|
19822
20040
|
}
|
|
19823
20041
|
server.listen(DAEMON_PORT, DAEMON_HOST);
|
|
@@ -19866,6 +20084,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
19866
20084
|
});
|
|
19867
20085
|
return;
|
|
19868
20086
|
}
|
|
20087
|
+
logDaemonStartup("bind-failed", e.message);
|
|
19869
20088
|
console.error(import_chalk6.default.red("\n\u{1F6D1} Node9 Daemon Error:"), e.message);
|
|
19870
20089
|
process.exit(1);
|
|
19871
20090
|
});
|
|
@@ -19889,14 +20108,14 @@ data: ${JSON.stringify(item.data)}
|
|
|
19889
20108
|
}
|
|
19890
20109
|
startActivitySocket();
|
|
19891
20110
|
}
|
|
19892
|
-
var import_http3,
|
|
20111
|
+
var import_http3, import_fs40, import_path39, import_os37, import_crypto11, import_child_process2, import_chalk6;
|
|
19893
20112
|
var init_server = __esm({
|
|
19894
20113
|
"src/daemon/server.ts"() {
|
|
19895
20114
|
"use strict";
|
|
19896
20115
|
import_http3 = __toESM(require("http"));
|
|
19897
|
-
|
|
19898
|
-
|
|
19899
|
-
|
|
20116
|
+
import_fs40 = __toESM(require("fs"));
|
|
20117
|
+
import_path39 = __toESM(require("path"));
|
|
20118
|
+
import_os37 = __toESM(require("os"));
|
|
19900
20119
|
import_crypto11 = require("crypto");
|
|
19901
20120
|
import_child_process2 = require("child_process");
|
|
19902
20121
|
import_chalk6 = __toESM(require("chalk"));
|
|
@@ -19911,6 +20130,7 @@ var init_server = __esm({
|
|
|
19911
20130
|
init_dlp_scanner();
|
|
19912
20131
|
init_mcp_reconciler();
|
|
19913
20132
|
init_hook_heal();
|
|
20133
|
+
init_startup_log();
|
|
19914
20134
|
init_mcp_tools();
|
|
19915
20135
|
}
|
|
19916
20136
|
});
|
|
@@ -19919,8 +20139,8 @@ var init_server = __esm({
|
|
|
19919
20139
|
function resolveNode9Binary() {
|
|
19920
20140
|
try {
|
|
19921
20141
|
const script = process.argv[1];
|
|
19922
|
-
if (typeof script === "string" &&
|
|
19923
|
-
return
|
|
20142
|
+
if (typeof script === "string" && import_path40.default.isAbsolute(script) && import_fs41.default.existsSync(script)) {
|
|
20143
|
+
return import_fs41.default.realpathSync(script);
|
|
19924
20144
|
}
|
|
19925
20145
|
} catch {
|
|
19926
20146
|
}
|
|
@@ -19938,11 +20158,11 @@ function xmlEscape(s) {
|
|
|
19938
20158
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
19939
20159
|
}
|
|
19940
20160
|
function launchdPlist(binaryPath) {
|
|
19941
|
-
const logDir =
|
|
20161
|
+
const logDir = import_path40.default.join(import_os38.default.homedir(), ".node9");
|
|
19942
20162
|
const nodePath = xmlEscape(process.execPath);
|
|
19943
20163
|
const scriptPath = xmlEscape(binaryPath);
|
|
19944
|
-
const outLog = xmlEscape(
|
|
19945
|
-
const errLog = xmlEscape(
|
|
20164
|
+
const outLog = xmlEscape(import_path40.default.join(logDir, "daemon.log"));
|
|
20165
|
+
const errLog = xmlEscape(import_path40.default.join(logDir, "daemon-error.log"));
|
|
19946
20166
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
19947
20167
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
19948
20168
|
<plist version="1.0">
|
|
@@ -19975,9 +20195,9 @@ function launchdPlist(binaryPath) {
|
|
|
19975
20195
|
`;
|
|
19976
20196
|
}
|
|
19977
20197
|
function installLaunchd(binaryPath) {
|
|
19978
|
-
const dir =
|
|
19979
|
-
if (!
|
|
19980
|
-
|
|
20198
|
+
const dir = import_path40.default.dirname(LAUNCHD_PLIST);
|
|
20199
|
+
if (!import_fs41.default.existsSync(dir)) import_fs41.default.mkdirSync(dir, { recursive: true });
|
|
20200
|
+
import_fs41.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
|
|
19981
20201
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
|
|
19982
20202
|
const r = (0, import_child_process3.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
|
|
19983
20203
|
encoding: "utf8",
|
|
@@ -19988,13 +20208,13 @@ function installLaunchd(binaryPath) {
|
|
|
19988
20208
|
}
|
|
19989
20209
|
}
|
|
19990
20210
|
function uninstallLaunchd() {
|
|
19991
|
-
if (
|
|
20211
|
+
if (import_fs41.default.existsSync(LAUNCHD_PLIST)) {
|
|
19992
20212
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
|
|
19993
|
-
|
|
20213
|
+
import_fs41.default.unlinkSync(LAUNCHD_PLIST);
|
|
19994
20214
|
}
|
|
19995
20215
|
}
|
|
19996
20216
|
function isLaunchdInstalled() {
|
|
19997
|
-
return
|
|
20217
|
+
return import_fs41.default.existsSync(LAUNCHD_PLIST);
|
|
19998
20218
|
}
|
|
19999
20219
|
function systemdUnit(binaryPath) {
|
|
20000
20220
|
return `[Unit]
|
|
@@ -20013,12 +20233,12 @@ WantedBy=default.target
|
|
|
20013
20233
|
`;
|
|
20014
20234
|
}
|
|
20015
20235
|
function installSystemd(binaryPath) {
|
|
20016
|
-
if (!
|
|
20017
|
-
|
|
20236
|
+
if (!import_fs41.default.existsSync(SYSTEMD_UNIT_DIR)) {
|
|
20237
|
+
import_fs41.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
|
|
20018
20238
|
}
|
|
20019
|
-
|
|
20239
|
+
import_fs41.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
|
|
20020
20240
|
try {
|
|
20021
|
-
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger",
|
|
20241
|
+
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger", import_os38.default.userInfo().username], { timeout: 3e3 });
|
|
20022
20242
|
} catch {
|
|
20023
20243
|
}
|
|
20024
20244
|
const reload = (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], {
|
|
@@ -20038,23 +20258,23 @@ function installSystemd(binaryPath) {
|
|
|
20038
20258
|
}
|
|
20039
20259
|
}
|
|
20040
20260
|
function uninstallSystemd() {
|
|
20041
|
-
if (
|
|
20261
|
+
if (import_fs41.default.existsSync(SYSTEMD_UNIT)) {
|
|
20042
20262
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
|
|
20043
20263
|
encoding: "utf8",
|
|
20044
20264
|
timeout: 5e3
|
|
20045
20265
|
});
|
|
20046
20266
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
|
|
20047
|
-
|
|
20267
|
+
import_fs41.default.unlinkSync(SYSTEMD_UNIT);
|
|
20048
20268
|
}
|
|
20049
20269
|
}
|
|
20050
20270
|
function isSystemdInstalled() {
|
|
20051
|
-
return
|
|
20271
|
+
return import_fs41.default.existsSync(SYSTEMD_UNIT);
|
|
20052
20272
|
}
|
|
20053
20273
|
function stopRunningDaemon() {
|
|
20054
|
-
const pidFile =
|
|
20055
|
-
if (!
|
|
20274
|
+
const pidFile = import_path40.default.join(import_os38.default.homedir(), ".node9", "daemon.pid");
|
|
20275
|
+
if (!import_fs41.default.existsSync(pidFile)) return;
|
|
20056
20276
|
try {
|
|
20057
|
-
const data = JSON.parse(
|
|
20277
|
+
const data = JSON.parse(import_fs41.default.readFileSync(pidFile, "utf-8"));
|
|
20058
20278
|
const pid = data.pid;
|
|
20059
20279
|
const MAX_PID2 = 4194304;
|
|
20060
20280
|
if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
|
|
@@ -20074,7 +20294,7 @@ function stopRunningDaemon() {
|
|
|
20074
20294
|
}
|
|
20075
20295
|
}
|
|
20076
20296
|
try {
|
|
20077
|
-
|
|
20297
|
+
import_fs41.default.unlinkSync(pidFile);
|
|
20078
20298
|
} catch {
|
|
20079
20299
|
}
|
|
20080
20300
|
} catch {
|
|
@@ -20144,26 +20364,95 @@ function isDaemonServiceInstalled() {
|
|
|
20144
20364
|
if (process.platform === "linux") return isSystemdInstalled();
|
|
20145
20365
|
return false;
|
|
20146
20366
|
}
|
|
20147
|
-
|
|
20367
|
+
function autostartRepairDecision(opts) {
|
|
20368
|
+
if (!opts.autoStartDaemon) return "skip";
|
|
20369
|
+
if (process.platform !== "linux" && process.platform !== "darwin") return "unsupported";
|
|
20370
|
+
if (!opts.installed) return "skip";
|
|
20371
|
+
return opts.enabled ? "ok" : "repair";
|
|
20372
|
+
}
|
|
20373
|
+
function enableDaemonServiceQuiet() {
|
|
20374
|
+
try {
|
|
20375
|
+
if (process.platform === "linux") {
|
|
20376
|
+
const r = (0, import_child_process3.spawnSync)("systemctl", ["--user", "enable", "node9-daemon"], {
|
|
20377
|
+
encoding: "utf8",
|
|
20378
|
+
timeout: 3e3
|
|
20379
|
+
});
|
|
20380
|
+
return r.status === 0;
|
|
20381
|
+
}
|
|
20382
|
+
return process.platform === "darwin";
|
|
20383
|
+
} catch {
|
|
20384
|
+
return false;
|
|
20385
|
+
}
|
|
20386
|
+
}
|
|
20387
|
+
function ensureAutostartHealthy(autoStartDaemon) {
|
|
20388
|
+
const decision = autostartRepairDecision({
|
|
20389
|
+
installed: isDaemonServiceInstalled(),
|
|
20390
|
+
enabled: isDaemonServiceEnabled(),
|
|
20391
|
+
autoStartDaemon
|
|
20392
|
+
});
|
|
20393
|
+
if (decision === "repair") return enableDaemonServiceQuiet() ? "repaired" : "skipped";
|
|
20394
|
+
return decision === "ok" ? "ok" : decision === "unsupported" ? "unsupported" : "skipped";
|
|
20395
|
+
}
|
|
20396
|
+
function autostartAdvice(opts) {
|
|
20397
|
+
const installable = process.platform === "linux" || process.platform === "darwin";
|
|
20398
|
+
if (!opts.cloudEnabled || !installable) return null;
|
|
20399
|
+
const installHint = process.platform === "linux" ? "Run: systemctl --user enable --now node9-daemon (or: node9 daemon install)" : "Run: node9 daemon install";
|
|
20400
|
+
if (opts.installed && !opts.enabled) {
|
|
20401
|
+
return {
|
|
20402
|
+
level: "warn",
|
|
20403
|
+
message: "Daemon autostart is INSTALLED but DISABLED \u2014 it will NOT survive a reboot, so cloud policy can silently go stale.",
|
|
20404
|
+
hint: installHint
|
|
20405
|
+
};
|
|
20406
|
+
}
|
|
20407
|
+
if (!opts.installed) {
|
|
20408
|
+
return {
|
|
20409
|
+
level: "warn",
|
|
20410
|
+
message: "No daemon autostart installed \u2014 the daemon only runs when an agent happens to spawn it; cloud policy may lag.",
|
|
20411
|
+
hint: installHint
|
|
20412
|
+
};
|
|
20413
|
+
}
|
|
20414
|
+
return null;
|
|
20415
|
+
}
|
|
20416
|
+
function isDaemonServiceEnabled() {
|
|
20417
|
+
try {
|
|
20418
|
+
if (process.platform === "linux") {
|
|
20419
|
+
const r = (0, import_child_process3.spawnSync)("systemctl", ["--user", "is-enabled", "node9-daemon"], {
|
|
20420
|
+
encoding: "utf8",
|
|
20421
|
+
timeout: 3e3
|
|
20422
|
+
});
|
|
20423
|
+
return r.status === 0 && (r.stdout ?? "").trim() === "enabled";
|
|
20424
|
+
}
|
|
20425
|
+
if (process.platform === "darwin") {
|
|
20426
|
+
const r = (0, import_child_process3.spawnSync)("launchctl", ["list", LAUNCHD_LABEL], {
|
|
20427
|
+
encoding: "utf8",
|
|
20428
|
+
timeout: 3e3
|
|
20429
|
+
});
|
|
20430
|
+
return r.status === 0;
|
|
20431
|
+
}
|
|
20432
|
+
} catch {
|
|
20433
|
+
}
|
|
20434
|
+
return false;
|
|
20435
|
+
}
|
|
20436
|
+
var import_fs41, import_path40, import_os38, import_child_process3, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
|
|
20148
20437
|
var init_service = __esm({
|
|
20149
20438
|
"src/daemon/service.ts"() {
|
|
20150
20439
|
"use strict";
|
|
20151
|
-
|
|
20152
|
-
|
|
20153
|
-
|
|
20440
|
+
import_fs41 = __toESM(require("fs"));
|
|
20441
|
+
import_path40 = __toESM(require("path"));
|
|
20442
|
+
import_os38 = __toESM(require("os"));
|
|
20154
20443
|
import_child_process3 = require("child_process");
|
|
20155
20444
|
LAUNCHD_LABEL = "ai.node9.daemon";
|
|
20156
|
-
LAUNCHD_PLIST =
|
|
20157
|
-
SYSTEMD_UNIT_DIR =
|
|
20158
|
-
SYSTEMD_UNIT =
|
|
20445
|
+
LAUNCHD_PLIST = import_path40.default.join(import_os38.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
20446
|
+
SYSTEMD_UNIT_DIR = import_path40.default.join(import_os38.default.homedir(), ".config", "systemd", "user");
|
|
20447
|
+
SYSTEMD_UNIT = import_path40.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
|
|
20159
20448
|
}
|
|
20160
20449
|
});
|
|
20161
20450
|
|
|
20162
20451
|
// src/daemon/index.ts
|
|
20163
20452
|
function stopDaemon() {
|
|
20164
|
-
if (!
|
|
20453
|
+
if (!import_fs42.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk7.default.yellow("Not running."));
|
|
20165
20454
|
try {
|
|
20166
|
-
const data = JSON.parse(
|
|
20455
|
+
const data = JSON.parse(import_fs42.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
20167
20456
|
const pid = data.pid;
|
|
20168
20457
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
20169
20458
|
console.log(import_chalk7.default.gray("Cleaned up invalid PID file."));
|
|
@@ -20175,7 +20464,7 @@ function stopDaemon() {
|
|
|
20175
20464
|
console.log(import_chalk7.default.gray("Cleaned up stale PID file."));
|
|
20176
20465
|
} finally {
|
|
20177
20466
|
try {
|
|
20178
|
-
|
|
20467
|
+
import_fs42.default.unlinkSync(DAEMON_PID_FILE);
|
|
20179
20468
|
} catch {
|
|
20180
20469
|
}
|
|
20181
20470
|
}
|
|
@@ -20184,9 +20473,9 @@ function daemonStatus() {
|
|
|
20184
20473
|
const serviceInstalled = isDaemonServiceInstalled();
|
|
20185
20474
|
const serviceLabel = serviceInstalled ? import_chalk7.default.green("installed (starts on login)") : import_chalk7.default.yellow("not installed \u2014 run: node9 daemon install");
|
|
20186
20475
|
let processStatus;
|
|
20187
|
-
if (
|
|
20476
|
+
if (import_fs42.default.existsSync(DAEMON_PID_FILE)) {
|
|
20188
20477
|
try {
|
|
20189
|
-
const data = JSON.parse(
|
|
20478
|
+
const data = JSON.parse(import_fs42.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
20190
20479
|
const pid = data.pid;
|
|
20191
20480
|
const port = data.port;
|
|
20192
20481
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
@@ -20208,11 +20497,11 @@ function daemonStatus() {
|
|
|
20208
20497
|
console.log(` Service : ${serviceLabel}
|
|
20209
20498
|
`);
|
|
20210
20499
|
}
|
|
20211
|
-
var
|
|
20500
|
+
var import_fs42, import_chalk7, MAX_PID;
|
|
20212
20501
|
var init_daemon2 = __esm({
|
|
20213
20502
|
"src/daemon/index.ts"() {
|
|
20214
20503
|
"use strict";
|
|
20215
|
-
|
|
20504
|
+
import_fs42 = __toESM(require("fs"));
|
|
20216
20505
|
import_chalk7 = __toESM(require("chalk"));
|
|
20217
20506
|
init_server();
|
|
20218
20507
|
init_state2();
|
|
@@ -21331,14 +21620,14 @@ var require_util = __commonJS({
|
|
|
21331
21620
|
}
|
|
21332
21621
|
const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
|
|
21333
21622
|
let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
|
|
21334
|
-
let
|
|
21623
|
+
let path71 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
|
|
21335
21624
|
if (origin[origin.length - 1] === "/") {
|
|
21336
21625
|
origin = origin.slice(0, origin.length - 1);
|
|
21337
21626
|
}
|
|
21338
|
-
if (
|
|
21339
|
-
|
|
21627
|
+
if (path71 && path71[0] !== "/") {
|
|
21628
|
+
path71 = `/${path71}`;
|
|
21340
21629
|
}
|
|
21341
|
-
return new URL(`${origin}${
|
|
21630
|
+
return new URL(`${origin}${path71}`);
|
|
21342
21631
|
}
|
|
21343
21632
|
if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
|
|
21344
21633
|
throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
|
|
@@ -22159,9 +22448,9 @@ var require_diagnostics = __commonJS({
|
|
|
22159
22448
|
"undici:client:sendHeaders",
|
|
22160
22449
|
(evt) => {
|
|
22161
22450
|
const {
|
|
22162
|
-
request: { method, path:
|
|
22451
|
+
request: { method, path: path71, origin }
|
|
22163
22452
|
} = evt;
|
|
22164
|
-
debugLog("sending request to %s %s%s", method, origin,
|
|
22453
|
+
debugLog("sending request to %s %s%s", method, origin, path71);
|
|
22165
22454
|
}
|
|
22166
22455
|
);
|
|
22167
22456
|
}
|
|
@@ -22179,14 +22468,14 @@ var require_diagnostics = __commonJS({
|
|
|
22179
22468
|
"undici:request:headers",
|
|
22180
22469
|
(evt) => {
|
|
22181
22470
|
const {
|
|
22182
|
-
request: { method, path:
|
|
22471
|
+
request: { method, path: path71, origin },
|
|
22183
22472
|
response: { statusCode }
|
|
22184
22473
|
} = evt;
|
|
22185
22474
|
debugLog(
|
|
22186
22475
|
"received response to %s %s%s - HTTP %d",
|
|
22187
22476
|
method,
|
|
22188
22477
|
origin,
|
|
22189
|
-
|
|
22478
|
+
path71,
|
|
22190
22479
|
statusCode
|
|
22191
22480
|
);
|
|
22192
22481
|
}
|
|
@@ -22195,23 +22484,23 @@ var require_diagnostics = __commonJS({
|
|
|
22195
22484
|
"undici:request:trailers",
|
|
22196
22485
|
(evt) => {
|
|
22197
22486
|
const {
|
|
22198
|
-
request: { method, path:
|
|
22487
|
+
request: { method, path: path71, origin }
|
|
22199
22488
|
} = evt;
|
|
22200
|
-
debugLog("trailers received from %s %s%s", method, origin,
|
|
22489
|
+
debugLog("trailers received from %s %s%s", method, origin, path71);
|
|
22201
22490
|
}
|
|
22202
22491
|
);
|
|
22203
22492
|
diagnosticsChannel.subscribe(
|
|
22204
22493
|
"undici:request:error",
|
|
22205
22494
|
(evt) => {
|
|
22206
22495
|
const {
|
|
22207
|
-
request: { method, path:
|
|
22496
|
+
request: { method, path: path71, origin },
|
|
22208
22497
|
error
|
|
22209
22498
|
} = evt;
|
|
22210
22499
|
debugLog(
|
|
22211
22500
|
"request to %s %s%s errored - %s",
|
|
22212
22501
|
method,
|
|
22213
22502
|
origin,
|
|
22214
|
-
|
|
22503
|
+
path71,
|
|
22215
22504
|
error.message
|
|
22216
22505
|
);
|
|
22217
22506
|
}
|
|
@@ -22314,7 +22603,7 @@ var require_request = __commonJS({
|
|
|
22314
22603
|
var kHandler = /* @__PURE__ */ Symbol("handler");
|
|
22315
22604
|
var Request = class {
|
|
22316
22605
|
constructor(origin, {
|
|
22317
|
-
path:
|
|
22606
|
+
path: path71,
|
|
22318
22607
|
method,
|
|
22319
22608
|
body,
|
|
22320
22609
|
headers,
|
|
@@ -22331,11 +22620,11 @@ var require_request = __commonJS({
|
|
|
22331
22620
|
maxRedirections,
|
|
22332
22621
|
typeOfService
|
|
22333
22622
|
}, handler) {
|
|
22334
|
-
if (typeof
|
|
22623
|
+
if (typeof path71 !== "string") {
|
|
22335
22624
|
throw new InvalidArgumentError("path must be a string");
|
|
22336
|
-
} else if (
|
|
22625
|
+
} else if (path71[0] !== "/" && !(path71.startsWith("http://") || path71.startsWith("https://")) && method !== "CONNECT") {
|
|
22337
22626
|
throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
|
|
22338
|
-
} else if (invalidPathRegex.test(
|
|
22627
|
+
} else if (invalidPathRegex.test(path71)) {
|
|
22339
22628
|
throw new InvalidArgumentError("invalid request path");
|
|
22340
22629
|
}
|
|
22341
22630
|
if (typeof method !== "string") {
|
|
@@ -22410,7 +22699,7 @@ var require_request = __commonJS({
|
|
|
22410
22699
|
this.completed = false;
|
|
22411
22700
|
this.aborted = false;
|
|
22412
22701
|
this.upgrade = upgrade || null;
|
|
22413
|
-
this.path = query ? serializePathWithQuery(
|
|
22702
|
+
this.path = query ? serializePathWithQuery(path71, query) : path71;
|
|
22414
22703
|
this.origin = origin;
|
|
22415
22704
|
this.protocol = getProtocolFromUrlString(origin);
|
|
22416
22705
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
|
|
@@ -27449,7 +27738,7 @@ var require_client_h1 = __commonJS({
|
|
|
27449
27738
|
return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
|
|
27450
27739
|
}
|
|
27451
27740
|
function writeH1(client, request2) {
|
|
27452
|
-
const { method, path:
|
|
27741
|
+
const { method, path: path71, host, upgrade, blocking, reset } = request2;
|
|
27453
27742
|
let { body, headers, contentLength } = request2;
|
|
27454
27743
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
|
|
27455
27744
|
if (util.isFormDataLike(body)) {
|
|
@@ -27518,7 +27807,7 @@ var require_client_h1 = __commonJS({
|
|
|
27518
27807
|
if (socket.setTypeOfService) {
|
|
27519
27808
|
socket.setTypeOfService(request2.typeOfService);
|
|
27520
27809
|
}
|
|
27521
|
-
let header = `${method} ${
|
|
27810
|
+
let header = `${method} ${path71} HTTP/1.1\r
|
|
27522
27811
|
`;
|
|
27523
27812
|
if (typeof host === "string") {
|
|
27524
27813
|
header += `host: ${host}\r
|
|
@@ -28171,7 +28460,7 @@ var require_client_h2 = __commonJS({
|
|
|
28171
28460
|
function writeH2(client, request2) {
|
|
28172
28461
|
const requestTimeout = request2.bodyTimeout ?? client[kBodyTimeout];
|
|
28173
28462
|
const session = client[kHTTP2Session];
|
|
28174
|
-
const { method, path:
|
|
28463
|
+
const { method, path: path71, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
|
|
28175
28464
|
let { body } = request2;
|
|
28176
28465
|
if (upgrade != null && upgrade !== "websocket") {
|
|
28177
28466
|
util.errorRequest(client, request2, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
|
|
@@ -28239,7 +28528,7 @@ var require_client_h2 = __commonJS({
|
|
|
28239
28528
|
}
|
|
28240
28529
|
headers[HTTP2_HEADER_METHOD] = "CONNECT";
|
|
28241
28530
|
headers[HTTP2_HEADER_PROTOCOL] = "websocket";
|
|
28242
|
-
headers[HTTP2_HEADER_PATH] =
|
|
28531
|
+
headers[HTTP2_HEADER_PATH] = path71;
|
|
28243
28532
|
if (protocol === "ws:" || protocol === "wss:") {
|
|
28244
28533
|
headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
|
|
28245
28534
|
} else {
|
|
@@ -28280,7 +28569,7 @@ var require_client_h2 = __commonJS({
|
|
|
28280
28569
|
stream.setTimeout(requestTimeout);
|
|
28281
28570
|
return true;
|
|
28282
28571
|
}
|
|
28283
|
-
headers[HTTP2_HEADER_PATH] =
|
|
28572
|
+
headers[HTTP2_HEADER_PATH] = path71;
|
|
28284
28573
|
headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
|
|
28285
28574
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
|
|
28286
28575
|
if (body && typeof body.read === "function") {
|
|
@@ -30582,10 +30871,10 @@ var require_proxy_agent = __commonJS({
|
|
|
30582
30871
|
};
|
|
30583
30872
|
const {
|
|
30584
30873
|
origin,
|
|
30585
|
-
path:
|
|
30874
|
+
path: path71 = "/",
|
|
30586
30875
|
headers = {}
|
|
30587
30876
|
} = opts;
|
|
30588
|
-
opts.path = origin +
|
|
30877
|
+
opts.path = origin + path71;
|
|
30589
30878
|
if (!("host" in headers) && !("Host" in headers)) {
|
|
30590
30879
|
const { host } = new URL(origin);
|
|
30591
30880
|
headers.host = host;
|
|
@@ -32648,20 +32937,20 @@ var require_mock_utils = __commonJS({
|
|
|
32648
32937
|
}
|
|
32649
32938
|
return normalizedQp;
|
|
32650
32939
|
}
|
|
32651
|
-
function safeUrl(
|
|
32652
|
-
if (typeof
|
|
32653
|
-
return
|
|
32940
|
+
function safeUrl(path71) {
|
|
32941
|
+
if (typeof path71 !== "string") {
|
|
32942
|
+
return path71;
|
|
32654
32943
|
}
|
|
32655
|
-
const pathSegments =
|
|
32944
|
+
const pathSegments = path71.split("?", 3);
|
|
32656
32945
|
if (pathSegments.length !== 2) {
|
|
32657
|
-
return
|
|
32946
|
+
return path71;
|
|
32658
32947
|
}
|
|
32659
32948
|
const qp = new URLSearchParams(pathSegments.pop());
|
|
32660
32949
|
qp.sort();
|
|
32661
32950
|
return [...pathSegments, qp.toString()].join("?");
|
|
32662
32951
|
}
|
|
32663
|
-
function matchKey(mockDispatch2, { path:
|
|
32664
|
-
const pathMatch = matchValue(mockDispatch2.path,
|
|
32952
|
+
function matchKey(mockDispatch2, { path: path71, method, body, headers }) {
|
|
32953
|
+
const pathMatch = matchValue(mockDispatch2.path, path71);
|
|
32665
32954
|
const methodMatch = matchValue(mockDispatch2.method, method);
|
|
32666
32955
|
const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
|
|
32667
32956
|
const headersMatch = matchHeaders(mockDispatch2, headers);
|
|
@@ -32686,8 +32975,8 @@ var require_mock_utils = __commonJS({
|
|
|
32686
32975
|
const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
|
|
32687
32976
|
const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
|
|
32688
32977
|
const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
|
|
32689
|
-
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path:
|
|
32690
|
-
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(
|
|
32978
|
+
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path71, ignoreTrailingSlash }) => {
|
|
32979
|
+
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path71)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path71), resolvedPath);
|
|
32691
32980
|
});
|
|
32692
32981
|
if (matchedMockDispatches.length === 0) {
|
|
32693
32982
|
throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
|
|
@@ -32726,19 +33015,19 @@ var require_mock_utils = __commonJS({
|
|
|
32726
33015
|
mockDispatches.splice(index, 1);
|
|
32727
33016
|
}
|
|
32728
33017
|
}
|
|
32729
|
-
function removeTrailingSlash(
|
|
32730
|
-
while (
|
|
32731
|
-
|
|
33018
|
+
function removeTrailingSlash(path71) {
|
|
33019
|
+
while (path71.endsWith("/")) {
|
|
33020
|
+
path71 = path71.slice(0, -1);
|
|
32732
33021
|
}
|
|
32733
|
-
if (
|
|
32734
|
-
|
|
33022
|
+
if (path71.length === 0) {
|
|
33023
|
+
path71 = "/";
|
|
32735
33024
|
}
|
|
32736
|
-
return
|
|
33025
|
+
return path71;
|
|
32737
33026
|
}
|
|
32738
33027
|
function buildKey(opts) {
|
|
32739
|
-
const { path:
|
|
33028
|
+
const { path: path71, method, body, headers, query } = opts;
|
|
32740
33029
|
return {
|
|
32741
|
-
path:
|
|
33030
|
+
path: path71,
|
|
32742
33031
|
method,
|
|
32743
33032
|
body,
|
|
32744
33033
|
headers,
|
|
@@ -33428,10 +33717,10 @@ var require_pending_interceptors_formatter = __commonJS({
|
|
|
33428
33717
|
}
|
|
33429
33718
|
format(pendingInterceptors) {
|
|
33430
33719
|
const withPrettyHeaders = pendingInterceptors.map(
|
|
33431
|
-
({ method, path:
|
|
33720
|
+
({ method, path: path71, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
33432
33721
|
Method: method,
|
|
33433
33722
|
Origin: origin,
|
|
33434
|
-
Path:
|
|
33723
|
+
Path: path71,
|
|
33435
33724
|
"Status code": statusCode,
|
|
33436
33725
|
Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
|
|
33437
33726
|
Invocations: timesInvoked,
|
|
@@ -33513,9 +33802,9 @@ var require_mock_agent = __commonJS({
|
|
|
33513
33802
|
const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
|
|
33514
33803
|
const dispatchOpts = { ...opts };
|
|
33515
33804
|
if (acceptNonStandardSearchParameters && dispatchOpts.path) {
|
|
33516
|
-
const [
|
|
33805
|
+
const [path71, searchParams] = dispatchOpts.path.split("?");
|
|
33517
33806
|
const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
|
|
33518
|
-
dispatchOpts.path = `${
|
|
33807
|
+
dispatchOpts.path = `${path71}?${normalizedSearchParams}`;
|
|
33519
33808
|
}
|
|
33520
33809
|
return this[kAgent].dispatch(dispatchOpts, handler);
|
|
33521
33810
|
}
|
|
@@ -33916,12 +34205,12 @@ var require_snapshot_recorder = __commonJS({
|
|
|
33916
34205
|
* @return {Promise<void>} - Resolves when snapshots are loaded
|
|
33917
34206
|
*/
|
|
33918
34207
|
async loadSnapshots(filePath) {
|
|
33919
|
-
const
|
|
33920
|
-
if (!
|
|
34208
|
+
const path71 = filePath || this.#snapshotPath;
|
|
34209
|
+
if (!path71) {
|
|
33921
34210
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
33922
34211
|
}
|
|
33923
34212
|
try {
|
|
33924
|
-
const data = await readFile(resolve2(
|
|
34213
|
+
const data = await readFile(resolve2(path71), "utf8");
|
|
33925
34214
|
const parsed = JSON.parse(data);
|
|
33926
34215
|
if (Array.isArray(parsed)) {
|
|
33927
34216
|
this.#snapshots.clear();
|
|
@@ -33935,7 +34224,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
33935
34224
|
if (error.code === "ENOENT") {
|
|
33936
34225
|
this.#snapshots.clear();
|
|
33937
34226
|
} else {
|
|
33938
|
-
throw new UndiciError(`Failed to load snapshots from ${
|
|
34227
|
+
throw new UndiciError(`Failed to load snapshots from ${path71}`, { cause: error });
|
|
33939
34228
|
}
|
|
33940
34229
|
}
|
|
33941
34230
|
}
|
|
@@ -33946,11 +34235,11 @@ var require_snapshot_recorder = __commonJS({
|
|
|
33946
34235
|
* @returns {Promise<void>} - Resolves when snapshots are saved
|
|
33947
34236
|
*/
|
|
33948
34237
|
async saveSnapshots(filePath) {
|
|
33949
|
-
const
|
|
33950
|
-
if (!
|
|
34238
|
+
const path71 = filePath || this.#snapshotPath;
|
|
34239
|
+
if (!path71) {
|
|
33951
34240
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
33952
34241
|
}
|
|
33953
|
-
const resolvedPath = resolve2(
|
|
34242
|
+
const resolvedPath = resolve2(path71);
|
|
33954
34243
|
await mkdir(dirname2(resolvedPath), { recursive: true });
|
|
33955
34244
|
const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
|
|
33956
34245
|
hash,
|
|
@@ -34575,15 +34864,15 @@ var require_redirect_handler = __commonJS({
|
|
|
34575
34864
|
return;
|
|
34576
34865
|
}
|
|
34577
34866
|
const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
|
|
34578
|
-
const
|
|
34579
|
-
const redirectUrlString = `${origin}${
|
|
34867
|
+
const path71 = search ? `${pathname}${search}` : pathname;
|
|
34868
|
+
const redirectUrlString = `${origin}${path71}`;
|
|
34580
34869
|
for (const historyUrl of this.history) {
|
|
34581
34870
|
if (historyUrl.toString() === redirectUrlString) {
|
|
34582
34871
|
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.`);
|
|
34583
34872
|
}
|
|
34584
34873
|
}
|
|
34585
34874
|
this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
|
|
34586
|
-
this.opts.path =
|
|
34875
|
+
this.opts.path = path71;
|
|
34587
34876
|
this.opts.origin = origin;
|
|
34588
34877
|
this.opts.query = null;
|
|
34589
34878
|
}
|
|
@@ -40790,11 +41079,11 @@ var require_fetch = __commonJS({
|
|
|
40790
41079
|
function dispatch({ body }) {
|
|
40791
41080
|
const url = requestCurrentURL(request2);
|
|
40792
41081
|
const agent = fetchParams.controller.dispatcher;
|
|
40793
|
-
const
|
|
41082
|
+
const path71 = url.pathname + url.search;
|
|
40794
41083
|
const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
|
|
40795
41084
|
return new Promise((resolve2, reject) => agent.dispatch(
|
|
40796
41085
|
{
|
|
40797
|
-
path: hasTrailingQuestionMark ? `${
|
|
41086
|
+
path: hasTrailingQuestionMark ? `${path71}?` : path71,
|
|
40798
41087
|
origin: url.origin,
|
|
40799
41088
|
method: request2.method,
|
|
40800
41089
|
body: agent.isMockActive ? request2.body && (request2.body.source || request2.body.stream) : body,
|
|
@@ -41725,9 +42014,9 @@ var require_util4 = __commonJS({
|
|
|
41725
42014
|
}
|
|
41726
42015
|
}
|
|
41727
42016
|
}
|
|
41728
|
-
function validateCookiePath(
|
|
41729
|
-
for (let i = 0; i <
|
|
41730
|
-
const code =
|
|
42017
|
+
function validateCookiePath(path71) {
|
|
42018
|
+
for (let i = 0; i < path71.length; ++i) {
|
|
42019
|
+
const code = path71.charCodeAt(i);
|
|
41731
42020
|
if (code < 32 || // exclude CTLs (0-31)
|
|
41732
42021
|
code === 127 || // DEL
|
|
41733
42022
|
code === 59) {
|
|
@@ -44897,11 +45186,11 @@ var require_undici = __commonJS({
|
|
|
44897
45186
|
if (typeof opts.path !== "string") {
|
|
44898
45187
|
throw new InvalidArgumentError("invalid opts.path");
|
|
44899
45188
|
}
|
|
44900
|
-
let
|
|
45189
|
+
let path71 = opts.path;
|
|
44901
45190
|
if (!opts.path.startsWith("/")) {
|
|
44902
|
-
|
|
45191
|
+
path71 = `/${path71}`;
|
|
44903
45192
|
}
|
|
44904
|
-
url = new URL(util.parseOrigin(url).origin +
|
|
45193
|
+
url = new URL(util.parseOrigin(url).origin + path71);
|
|
44905
45194
|
} else {
|
|
44906
45195
|
if (!opts) {
|
|
44907
45196
|
opts = typeof url === "object" ? url : {};
|
|
@@ -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 = import_path67.default.join(import_os60.default.homedir(), ".claude", "projects");
|
|
45332
|
+
if (!import_fs70.default.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 import_fs70.default.readdirSync(projectsDir)) {
|
|
45337
|
+
const dirPath = import_path67.default.join(projectsDir, dir);
|
|
45049
45338
|
try {
|
|
45050
|
-
if (!
|
|
45051
|
-
for (const file of
|
|
45339
|
+
if (!import_fs70.default.statSync(dirPath).isDirectory()) continue;
|
|
45340
|
+
for (const file of import_fs70.default.readdirSync(dirPath)) {
|
|
45052
45341
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
45053
|
-
const filePath =
|
|
45342
|
+
const filePath = import_path67.default.join(dirPath, file);
|
|
45054
45343
|
try {
|
|
45055
|
-
const mtime =
|
|
45344
|
+
const mtime = import_fs70.default.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 = import_fs70.default.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(import_os60.default.homedir(), "~");
|
|
45132
45421
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
45133
45422
|
return `${import_chalk40.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk40.default.white.bold(toolName)} ${import_chalk40.default.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 (import_fs70.default.existsSync(PID_FILE)) {
|
|
45171
45460
|
try {
|
|
45172
|
-
const { port } = JSON.parse(
|
|
45461
|
+
const { port } = JSON.parse(import_fs70.default.readFileSync(PID_FILE, "utf-8"));
|
|
45173
45462
|
pidPort = port;
|
|
45174
45463
|
} catch {
|
|
45175
45464
|
console.error(import_chalk40.default.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 = import_path67.default.join(import_os60.default.homedir(), ".node9", "config.json");
|
|
45329
45618
|
try {
|
|
45330
|
-
const raw = JSON.parse(
|
|
45619
|
+
const raw = JSON.parse(import_fs70.default.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 = import_path67.default.join(import_os60.default.homedir(), ".node9", "config.json");
|
|
45347
45636
|
try {
|
|
45348
|
-
const raw = JSON.parse(
|
|
45637
|
+
const raw = JSON.parse(import_fs70.default.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
|
+
import_fs70.default.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
|
+
import_fs70.default.appendFileSync(
|
|
45816
|
+
import_path67.default.join(import_os60.default.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 = import_path67.default.join(import_os60.default.homedir(), ".node9", "audit.log");
|
|
45592
45881
|
try {
|
|
45593
|
-
const unackedDlp =
|
|
45882
|
+
const unackedDlp = import_fs70.default.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 = import_fs70.default.statSync(auditLog).mtimeMs;
|
|
45634
45923
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
45635
45924
|
console.log("");
|
|
45636
45925
|
console.log(
|
|
@@ -45815,20 +46104,20 @@ async function startTail(options = {}) {
|
|
|
45815
46104
|
process.exit(1);
|
|
45816
46105
|
});
|
|
45817
46106
|
}
|
|
45818
|
-
var import_http5, import_chalk40,
|
|
46107
|
+
var import_http5, import_chalk40, import_fs70, import_os60, import_path67, import_readline6, import_child_process14, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
45819
46108
|
var init_tail = __esm({
|
|
45820
46109
|
"src/tui/tail.ts"() {
|
|
45821
46110
|
"use strict";
|
|
45822
46111
|
import_http5 = __toESM(require("http"));
|
|
45823
46112
|
import_chalk40 = __toESM(require("chalk"));
|
|
45824
|
-
|
|
45825
|
-
|
|
45826
|
-
|
|
46113
|
+
import_fs70 = __toESM(require("fs"));
|
|
46114
|
+
import_os60 = __toESM(require("os"));
|
|
46115
|
+
import_path67 = __toESM(require("path"));
|
|
45827
46116
|
import_readline6 = __toESM(require("readline"));
|
|
45828
46117
|
import_child_process14 = require("child_process");
|
|
45829
46118
|
init_daemon2();
|
|
45830
46119
|
init_daemon();
|
|
45831
|
-
PID_FILE =
|
|
46120
|
+
PID_FILE = import_path67.default.join(import_os60.default.homedir(), ".node9", "daemon.pid");
|
|
45832
46121
|
ICONS = {
|
|
45833
46122
|
bash: "\u{1F4BB}",
|
|
45834
46123
|
shell: "\u{1F4BB}",
|
|
@@ -45950,9 +46239,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
45950
46239
|
return ` (${m}m left)`;
|
|
45951
46240
|
}
|
|
45952
46241
|
function safeReadJson(filePath) {
|
|
45953
|
-
if (!
|
|
46242
|
+
if (!import_fs71.default.existsSync(filePath)) return null;
|
|
45954
46243
|
try {
|
|
45955
|
-
return JSON.parse(
|
|
46244
|
+
return JSON.parse(import_fs71.default.readFileSync(filePath, "utf-8"));
|
|
45956
46245
|
} catch {
|
|
45957
46246
|
return null;
|
|
45958
46247
|
}
|
|
@@ -45973,12 +46262,12 @@ function countHooksInFile(filePath) {
|
|
|
45973
46262
|
return Object.keys(cfg.hooks).length;
|
|
45974
46263
|
}
|
|
45975
46264
|
function countRulesInDir(rulesDir) {
|
|
45976
|
-
if (!
|
|
46265
|
+
if (!import_fs71.default.existsSync(rulesDir)) return 0;
|
|
45977
46266
|
let count = 0;
|
|
45978
46267
|
try {
|
|
45979
|
-
for (const entry of
|
|
46268
|
+
for (const entry of import_fs71.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
45980
46269
|
if (entry.isDirectory()) {
|
|
45981
|
-
count += countRulesInDir(
|
|
46270
|
+
count += countRulesInDir(import_path68.default.join(rulesDir, entry.name));
|
|
45982
46271
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
45983
46272
|
count++;
|
|
45984
46273
|
}
|
|
@@ -45989,46 +46278,46 @@ function countRulesInDir(rulesDir) {
|
|
|
45989
46278
|
}
|
|
45990
46279
|
function isSamePath(a, b) {
|
|
45991
46280
|
try {
|
|
45992
|
-
return
|
|
46281
|
+
return import_path68.default.resolve(a) === import_path68.default.resolve(b);
|
|
45993
46282
|
} catch {
|
|
45994
46283
|
return false;
|
|
45995
46284
|
}
|
|
45996
46285
|
}
|
|
45997
46286
|
function countConfigs(cwd) {
|
|
45998
|
-
const homeDir2 =
|
|
45999
|
-
const claudeDir =
|
|
46287
|
+
const homeDir2 = import_os61.default.homedir();
|
|
46288
|
+
const claudeDir = import_path68.default.join(homeDir2, ".claude");
|
|
46000
46289
|
let claudeMdCount = 0;
|
|
46001
46290
|
let rulesCount = 0;
|
|
46002
46291
|
let hooksCount = 0;
|
|
46003
46292
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
46004
46293
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
46005
|
-
if (
|
|
46006
|
-
rulesCount += countRulesInDir(
|
|
46007
|
-
const userSettings =
|
|
46294
|
+
if (import_fs71.default.existsSync(import_path68.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
46295
|
+
rulesCount += countRulesInDir(import_path68.default.join(claudeDir, "rules"));
|
|
46296
|
+
const userSettings = import_path68.default.join(claudeDir, "settings.json");
|
|
46008
46297
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
46009
46298
|
hooksCount += countHooksInFile(userSettings);
|
|
46010
|
-
const userClaudeJson =
|
|
46299
|
+
const userClaudeJson = import_path68.default.join(homeDir2, ".claude.json");
|
|
46011
46300
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
46012
46301
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
46013
46302
|
userMcpServers.delete(name);
|
|
46014
46303
|
}
|
|
46015
46304
|
if (cwd) {
|
|
46016
|
-
if (
|
|
46017
|
-
if (
|
|
46018
|
-
const projectClaudeDir =
|
|
46305
|
+
if (import_fs71.default.existsSync(import_path68.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
46306
|
+
if (import_fs71.default.existsSync(import_path68.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
46307
|
+
const projectClaudeDir = import_path68.default.join(cwd, ".claude");
|
|
46019
46308
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
46020
46309
|
if (!overlapsUserScope) {
|
|
46021
|
-
if (
|
|
46022
|
-
rulesCount += countRulesInDir(
|
|
46023
|
-
const projSettings =
|
|
46310
|
+
if (import_fs71.default.existsSync(import_path68.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
46311
|
+
rulesCount += countRulesInDir(import_path68.default.join(projectClaudeDir, "rules"));
|
|
46312
|
+
const projSettings = import_path68.default.join(projectClaudeDir, "settings.json");
|
|
46024
46313
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
46025
46314
|
hooksCount += countHooksInFile(projSettings);
|
|
46026
46315
|
}
|
|
46027
|
-
if (
|
|
46028
|
-
const localSettings =
|
|
46316
|
+
if (import_fs71.default.existsSync(import_path68.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
46317
|
+
const localSettings = import_path68.default.join(projectClaudeDir, "settings.local.json");
|
|
46029
46318
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
46030
46319
|
hooksCount += countHooksInFile(localSettings);
|
|
46031
|
-
const mcpJsonServers = getMcpServerNames(
|
|
46320
|
+
const mcpJsonServers = getMcpServerNames(import_path68.default.join(cwd, ".mcp.json"));
|
|
46032
46321
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
46033
46322
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
46034
46323
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -46061,12 +46350,12 @@ function readActiveShieldsHud() {
|
|
|
46061
46350
|
return shieldsCache.value;
|
|
46062
46351
|
}
|
|
46063
46352
|
try {
|
|
46064
|
-
const shieldsPath =
|
|
46065
|
-
if (!
|
|
46353
|
+
const shieldsPath = import_path68.default.join(import_os61.default.homedir(), ".node9", "shields.json");
|
|
46354
|
+
if (!import_fs71.default.existsSync(shieldsPath)) {
|
|
46066
46355
|
shieldsCache = { value: [], ts: now };
|
|
46067
46356
|
return [];
|
|
46068
46357
|
}
|
|
46069
|
-
const parsed = JSON.parse(
|
|
46358
|
+
const parsed = JSON.parse(import_fs71.default.readFileSync(shieldsPath, "utf-8"));
|
|
46070
46359
|
if (!Array.isArray(parsed.active)) {
|
|
46071
46360
|
shieldsCache = { value: [], ts: now };
|
|
46072
46361
|
return [];
|
|
@@ -46168,17 +46457,17 @@ function renderContextLine(stdin) {
|
|
|
46168
46457
|
async function main() {
|
|
46169
46458
|
try {
|
|
46170
46459
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
46171
|
-
if (
|
|
46460
|
+
if (import_fs71.default.existsSync(import_path68.default.join(import_os61.default.homedir(), ".node9", "hud-debug"))) {
|
|
46172
46461
|
try {
|
|
46173
|
-
const logPath =
|
|
46462
|
+
const logPath = import_path68.default.join(import_os61.default.homedir(), ".node9", "hud-debug.log");
|
|
46174
46463
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
46175
46464
|
let size = 0;
|
|
46176
46465
|
try {
|
|
46177
|
-
size =
|
|
46466
|
+
size = import_fs71.default.statSync(logPath).size;
|
|
46178
46467
|
} catch {
|
|
46179
46468
|
}
|
|
46180
46469
|
if (size < MAX_LOG_SIZE) {
|
|
46181
|
-
|
|
46470
|
+
import_fs71.default.appendFileSync(
|
|
46182
46471
|
logPath,
|
|
46183
46472
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
46184
46473
|
);
|
|
@@ -46199,11 +46488,11 @@ async function main() {
|
|
|
46199
46488
|
try {
|
|
46200
46489
|
const cwd = stdin.cwd ?? process.cwd();
|
|
46201
46490
|
for (const configPath of [
|
|
46202
|
-
|
|
46203
|
-
|
|
46491
|
+
import_path68.default.join(cwd, "node9.config.json"),
|
|
46492
|
+
import_path68.default.join(import_os61.default.homedir(), ".node9", "config.json")
|
|
46204
46493
|
]) {
|
|
46205
|
-
if (!
|
|
46206
|
-
const cfg = JSON.parse(
|
|
46494
|
+
if (!import_fs71.default.existsSync(configPath)) continue;
|
|
46495
|
+
const cfg = JSON.parse(import_fs71.default.readFileSync(configPath, "utf-8"));
|
|
46207
46496
|
const hud = cfg.settings?.hud;
|
|
46208
46497
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
46209
46498
|
}
|
|
@@ -46221,13 +46510,13 @@ async function main() {
|
|
|
46221
46510
|
renderOffline();
|
|
46222
46511
|
}
|
|
46223
46512
|
}
|
|
46224
|
-
var
|
|
46513
|
+
var import_fs71, import_path68, import_os61, import_http6, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
|
|
46225
46514
|
var init_hud = __esm({
|
|
46226
46515
|
"src/cli/hud.ts"() {
|
|
46227
46516
|
"use strict";
|
|
46228
|
-
|
|
46229
|
-
|
|
46230
|
-
|
|
46517
|
+
import_fs71 = __toESM(require("fs"));
|
|
46518
|
+
import_path68 = __toESM(require("path"));
|
|
46519
|
+
import_os61 = __toESM(require("os"));
|
|
46231
46520
|
import_http6 = __toESM(require("http"));
|
|
46232
46521
|
init_daemon();
|
|
46233
46522
|
RESET3 = "\x1B[0m";
|
|
@@ -46349,9 +46638,9 @@ function writeCredentialsAndConfig(apiKey, opts = {}) {
|
|
|
46349
46638
|
// src/cli.ts
|
|
46350
46639
|
init_daemon2();
|
|
46351
46640
|
var import_chalk41 = __toESM(require("chalk"));
|
|
46352
|
-
var
|
|
46353
|
-
var
|
|
46354
|
-
var
|
|
46641
|
+
var import_fs72 = __toESM(require("fs"));
|
|
46642
|
+
var import_path69 = __toESM(require("path"));
|
|
46643
|
+
var import_os62 = __toESM(require("os"));
|
|
46355
46644
|
var import_child_process15 = require("child_process");
|
|
46356
46645
|
var import_prompts2 = require("@inquirer/prompts");
|
|
46357
46646
|
|
|
@@ -46538,26 +46827,48 @@ async function runProxy(targetCommand) {
|
|
|
46538
46827
|
|
|
46539
46828
|
// src/cli/daemon-starter.ts
|
|
46540
46829
|
var import_child_process5 = require("child_process");
|
|
46541
|
-
var
|
|
46542
|
-
var
|
|
46830
|
+
var import_path41 = __toESM(require("path"));
|
|
46831
|
+
var import_fs43 = __toESM(require("fs"));
|
|
46832
|
+
var import_os39 = __toESM(require("os"));
|
|
46543
46833
|
init_daemon();
|
|
46834
|
+
init_startup_log();
|
|
46544
46835
|
function isTestingMode() {
|
|
46545
46836
|
return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
|
|
46546
46837
|
}
|
|
46838
|
+
var SKIP_STAMP = () => import_path41.default.join(import_os39.default.homedir(), ".node9", ".autostart-skip-stamp");
|
|
46839
|
+
var SKIP_THROTTLE_MS = 60 * 60 * 1e3;
|
|
46840
|
+
function logAutostartSkipThrottled(reason) {
|
|
46841
|
+
try {
|
|
46842
|
+
const stamp = SKIP_STAMP();
|
|
46843
|
+
try {
|
|
46844
|
+
if (Date.now() - import_fs43.default.statSync(stamp).mtimeMs < SKIP_THROTTLE_MS) return;
|
|
46845
|
+
} catch {
|
|
46846
|
+
}
|
|
46847
|
+
import_fs43.default.writeFileSync(stamp, "", "utf-8");
|
|
46848
|
+
import_fs43.default.appendFileSync(
|
|
46849
|
+
import_path41.default.join(import_os39.default.homedir(), ".node9", "hook-debug.log"),
|
|
46850
|
+
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-skip: ${reason}
|
|
46851
|
+
`,
|
|
46852
|
+
"utf-8"
|
|
46853
|
+
);
|
|
46854
|
+
} catch {
|
|
46855
|
+
}
|
|
46856
|
+
}
|
|
46547
46857
|
async function autoStartDaemonAndWait() {
|
|
46548
46858
|
if (isTestingMode()) return false;
|
|
46549
|
-
if (!
|
|
46859
|
+
if (!import_path41.default.isAbsolute(process.argv[1])) return false;
|
|
46550
46860
|
let resolvedArgv1;
|
|
46551
46861
|
try {
|
|
46552
|
-
resolvedArgv1 =
|
|
46862
|
+
resolvedArgv1 = import_fs43.default.realpathSync(process.argv[1]);
|
|
46553
46863
|
} catch {
|
|
46554
46864
|
return false;
|
|
46555
46865
|
}
|
|
46556
46866
|
if (!resolvedArgv1.endsWith(".js")) return false;
|
|
46867
|
+
const startupFd = openStartupLogFd();
|
|
46557
46868
|
try {
|
|
46558
46869
|
const child = (0, import_child_process5.spawn)(process.execPath, [resolvedArgv1, "daemon"], {
|
|
46559
46870
|
detached: true,
|
|
46560
|
-
stdio: "ignore",
|
|
46871
|
+
stdio: ["ignore", "ignore", startupFd ?? "ignore"],
|
|
46561
46872
|
env: {
|
|
46562
46873
|
...process.env,
|
|
46563
46874
|
NODE9_AUTO_STARTED: "1"
|
|
@@ -46570,30 +46881,41 @@ async function autoStartDaemonAndWait() {
|
|
|
46570
46881
|
if (await isDaemonReachable()) return true;
|
|
46571
46882
|
}
|
|
46572
46883
|
} catch {
|
|
46884
|
+
} finally {
|
|
46885
|
+
if (startupFd !== void 0) {
|
|
46886
|
+
try {
|
|
46887
|
+
import_fs43.default.closeSync(startupFd);
|
|
46888
|
+
} catch {
|
|
46889
|
+
}
|
|
46890
|
+
}
|
|
46573
46891
|
}
|
|
46574
46892
|
return false;
|
|
46575
46893
|
}
|
|
46576
46894
|
|
|
46895
|
+
// src/cli.ts
|
|
46896
|
+
init_service();
|
|
46897
|
+
|
|
46577
46898
|
// src/cli/commands/check.ts
|
|
46578
46899
|
var import_chalk9 = __toESM(require("chalk"));
|
|
46579
|
-
var
|
|
46900
|
+
var import_fs47 = __toESM(require("fs"));
|
|
46580
46901
|
var import_child_process7 = require("child_process");
|
|
46581
|
-
var
|
|
46582
|
-
var
|
|
46902
|
+
var import_path45 = __toESM(require("path"));
|
|
46903
|
+
var import_os43 = __toESM(require("os"));
|
|
46583
46904
|
init_orchestrator();
|
|
46584
46905
|
init_state();
|
|
46585
46906
|
init_daemon();
|
|
46907
|
+
init_startup_log();
|
|
46586
46908
|
init_config();
|
|
46587
46909
|
init_policy();
|
|
46588
46910
|
|
|
46589
46911
|
// src/undo.ts
|
|
46590
46912
|
var import_child_process6 = require("child_process");
|
|
46591
46913
|
var import_crypto12 = __toESM(require("crypto"));
|
|
46592
|
-
var
|
|
46914
|
+
var import_fs44 = __toESM(require("fs"));
|
|
46593
46915
|
var import_net3 = __toESM(require("net"));
|
|
46594
|
-
var
|
|
46595
|
-
var
|
|
46596
|
-
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
46916
|
+
var import_path42 = __toESM(require("path"));
|
|
46917
|
+
var import_os40 = __toESM(require("os"));
|
|
46918
|
+
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path42.default.join(import_os40.default.tmpdir(), "node9-activity.sock");
|
|
46597
46919
|
function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
46598
46920
|
try {
|
|
46599
46921
|
const payload = JSON.stringify({
|
|
@@ -46613,22 +46935,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
|
46613
46935
|
} catch {
|
|
46614
46936
|
}
|
|
46615
46937
|
}
|
|
46616
|
-
var SNAPSHOT_STACK_PATH =
|
|
46617
|
-
var UNDO_LATEST_PATH =
|
|
46938
|
+
var SNAPSHOT_STACK_PATH = import_path42.default.join(import_os40.default.homedir(), ".node9", "snapshots.json");
|
|
46939
|
+
var UNDO_LATEST_PATH = import_path42.default.join(import_os40.default.homedir(), ".node9", "undo_latest.txt");
|
|
46618
46940
|
var MAX_SNAPSHOTS = 10;
|
|
46619
46941
|
var GIT_TIMEOUT = 15e3;
|
|
46620
46942
|
function readStack() {
|
|
46621
46943
|
try {
|
|
46622
|
-
if (
|
|
46623
|
-
return JSON.parse(
|
|
46944
|
+
if (import_fs44.default.existsSync(SNAPSHOT_STACK_PATH))
|
|
46945
|
+
return JSON.parse(import_fs44.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
|
|
46624
46946
|
} catch {
|
|
46625
46947
|
}
|
|
46626
46948
|
return [];
|
|
46627
46949
|
}
|
|
46628
46950
|
function writeStack(stack) {
|
|
46629
|
-
const dir =
|
|
46630
|
-
if (!
|
|
46631
|
-
|
|
46951
|
+
const dir = import_path42.default.dirname(SNAPSHOT_STACK_PATH);
|
|
46952
|
+
if (!import_fs44.default.existsSync(dir)) import_fs44.default.mkdirSync(dir, { recursive: true });
|
|
46953
|
+
import_fs44.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
|
|
46632
46954
|
}
|
|
46633
46955
|
function extractFilePath(args) {
|
|
46634
46956
|
if (!args || typeof args !== "object") return null;
|
|
@@ -46648,12 +46970,12 @@ function buildArgsSummary(tool, args) {
|
|
|
46648
46970
|
return "";
|
|
46649
46971
|
}
|
|
46650
46972
|
function findProjectRoot(filePath) {
|
|
46651
|
-
let dir =
|
|
46973
|
+
let dir = import_path42.default.dirname(filePath);
|
|
46652
46974
|
while (true) {
|
|
46653
|
-
if (
|
|
46975
|
+
if (import_fs44.default.existsSync(import_path42.default.join(dir, ".git")) || import_fs44.default.existsSync(import_path42.default.join(dir, "package.json"))) {
|
|
46654
46976
|
return dir;
|
|
46655
46977
|
}
|
|
46656
|
-
const parent =
|
|
46978
|
+
const parent = import_path42.default.dirname(dir);
|
|
46657
46979
|
if (parent === dir) return process.cwd();
|
|
46658
46980
|
dir = parent;
|
|
46659
46981
|
}
|
|
@@ -46661,7 +46983,7 @@ function findProjectRoot(filePath) {
|
|
|
46661
46983
|
function normalizeCwdForHash(cwd) {
|
|
46662
46984
|
let normalized;
|
|
46663
46985
|
try {
|
|
46664
|
-
normalized =
|
|
46986
|
+
normalized = import_fs44.default.realpathSync(cwd);
|
|
46665
46987
|
} catch {
|
|
46666
46988
|
normalized = cwd;
|
|
46667
46989
|
}
|
|
@@ -46671,16 +46993,16 @@ function normalizeCwdForHash(cwd) {
|
|
|
46671
46993
|
}
|
|
46672
46994
|
function getShadowRepoDir(cwd) {
|
|
46673
46995
|
const hash = import_crypto12.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
|
|
46674
|
-
return
|
|
46996
|
+
return import_path42.default.join(import_os40.default.homedir(), ".node9", "snapshots", hash);
|
|
46675
46997
|
}
|
|
46676
46998
|
function cleanOrphanedIndexFiles(shadowDir) {
|
|
46677
46999
|
try {
|
|
46678
47000
|
const cutoff = Date.now() - 6e4;
|
|
46679
|
-
for (const f of
|
|
47001
|
+
for (const f of import_fs44.default.readdirSync(shadowDir)) {
|
|
46680
47002
|
if (f.startsWith("index_")) {
|
|
46681
|
-
const fp =
|
|
47003
|
+
const fp = import_path42.default.join(shadowDir, f);
|
|
46682
47004
|
try {
|
|
46683
|
-
if (
|
|
47005
|
+
if (import_fs44.default.statSync(fp).mtimeMs < cutoff) import_fs44.default.unlinkSync(fp);
|
|
46684
47006
|
} catch {
|
|
46685
47007
|
}
|
|
46686
47008
|
}
|
|
@@ -46692,7 +47014,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
|
|
|
46692
47014
|
const hardcoded = [".git", ".node9"];
|
|
46693
47015
|
const lines = [...hardcoded, ...ignorePaths].join("\n");
|
|
46694
47016
|
try {
|
|
46695
|
-
|
|
47017
|
+
import_fs44.default.writeFileSync(import_path42.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
|
|
46696
47018
|
} catch {
|
|
46697
47019
|
}
|
|
46698
47020
|
}
|
|
@@ -46705,25 +47027,25 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
46705
47027
|
timeout: 3e3
|
|
46706
47028
|
});
|
|
46707
47029
|
if (check.status === 0) {
|
|
46708
|
-
const ptPath =
|
|
47030
|
+
const ptPath = import_path42.default.join(shadowDir, "project-path.txt");
|
|
46709
47031
|
try {
|
|
46710
|
-
const stored =
|
|
47032
|
+
const stored = import_fs44.default.readFileSync(ptPath, "utf8").trim();
|
|
46711
47033
|
if (stored === normalizedCwd) return true;
|
|
46712
47034
|
if (process.env.NODE9_DEBUG === "1")
|
|
46713
47035
|
console.error(
|
|
46714
47036
|
`[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
|
|
46715
47037
|
);
|
|
46716
|
-
|
|
47038
|
+
import_fs44.default.rmSync(shadowDir, { recursive: true, force: true });
|
|
46717
47039
|
} catch {
|
|
46718
47040
|
try {
|
|
46719
|
-
|
|
47041
|
+
import_fs44.default.writeFileSync(ptPath, normalizedCwd, "utf8");
|
|
46720
47042
|
} catch {
|
|
46721
47043
|
}
|
|
46722
47044
|
return true;
|
|
46723
47045
|
}
|
|
46724
47046
|
}
|
|
46725
47047
|
try {
|
|
46726
|
-
|
|
47048
|
+
import_fs44.default.mkdirSync(shadowDir, { recursive: true });
|
|
46727
47049
|
} catch {
|
|
46728
47050
|
}
|
|
46729
47051
|
const init = (0, import_child_process6.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
|
|
@@ -46732,7 +47054,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
46732
47054
|
if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
|
|
46733
47055
|
return false;
|
|
46734
47056
|
}
|
|
46735
|
-
const configFile =
|
|
47057
|
+
const configFile = import_path42.default.join(shadowDir, "config");
|
|
46736
47058
|
(0, import_child_process6.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
|
|
46737
47059
|
timeout: 3e3
|
|
46738
47060
|
});
|
|
@@ -46740,7 +47062,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
46740
47062
|
timeout: 3e3
|
|
46741
47063
|
});
|
|
46742
47064
|
try {
|
|
46743
|
-
|
|
47065
|
+
import_fs44.default.writeFileSync(import_path42.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
|
|
46744
47066
|
} catch {
|
|
46745
47067
|
}
|
|
46746
47068
|
return true;
|
|
@@ -46763,12 +47085,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
46763
47085
|
let indexFile = null;
|
|
46764
47086
|
try {
|
|
46765
47087
|
const rawFilePath = extractFilePath(args);
|
|
46766
|
-
const absFilePath = rawFilePath &&
|
|
47088
|
+
const absFilePath = rawFilePath && import_path42.default.isAbsolute(rawFilePath) ? rawFilePath : null;
|
|
46767
47089
|
const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
|
|
46768
47090
|
const shadowDir = getShadowRepoDir(cwd);
|
|
46769
47091
|
if (!ensureShadowRepo(shadowDir, cwd)) return null;
|
|
46770
47092
|
writeShadowExcludes(shadowDir, ignorePaths);
|
|
46771
|
-
indexFile =
|
|
47093
|
+
indexFile = import_path42.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
|
|
46772
47094
|
const shadowEnv = {
|
|
46773
47095
|
...process.env,
|
|
46774
47096
|
GIT_DIR: shadowDir,
|
|
@@ -46840,7 +47162,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
46840
47162
|
writeStack(stack);
|
|
46841
47163
|
const entry = stack[stack.length - 1];
|
|
46842
47164
|
notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
|
|
46843
|
-
|
|
47165
|
+
import_fs44.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
|
|
46844
47166
|
if (shouldGc) {
|
|
46845
47167
|
(0, import_child_process6.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
|
|
46846
47168
|
}
|
|
@@ -46851,7 +47173,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
46851
47173
|
} finally {
|
|
46852
47174
|
if (indexFile) {
|
|
46853
47175
|
try {
|
|
46854
|
-
|
|
47176
|
+
import_fs44.default.unlinkSync(indexFile);
|
|
46855
47177
|
} catch {
|
|
46856
47178
|
}
|
|
46857
47179
|
}
|
|
@@ -46927,9 +47249,9 @@ function applyUndo(hash, cwd) {
|
|
|
46927
47249
|
timeout: GIT_TIMEOUT
|
|
46928
47250
|
}).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
|
|
46929
47251
|
for (const file of [...tracked, ...untracked]) {
|
|
46930
|
-
const fullPath =
|
|
46931
|
-
if (!snapshotFiles.has(file) &&
|
|
46932
|
-
|
|
47252
|
+
const fullPath = import_path42.default.join(dir, file);
|
|
47253
|
+
if (!snapshotFiles.has(file) && import_fs44.default.existsSync(fullPath)) {
|
|
47254
|
+
import_fs44.default.unlinkSync(fullPath);
|
|
46933
47255
|
}
|
|
46934
47256
|
}
|
|
46935
47257
|
return true;
|
|
@@ -46939,12 +47261,12 @@ function applyUndo(hash, cwd) {
|
|
|
46939
47261
|
}
|
|
46940
47262
|
|
|
46941
47263
|
// src/skill-pin.ts
|
|
46942
|
-
var
|
|
46943
|
-
var
|
|
46944
|
-
var
|
|
47264
|
+
var import_fs45 = __toESM(require("fs"));
|
|
47265
|
+
var import_path43 = __toESM(require("path"));
|
|
47266
|
+
var import_os41 = __toESM(require("os"));
|
|
46945
47267
|
var import_crypto13 = __toESM(require("crypto"));
|
|
46946
47268
|
function getPinsFilePath2() {
|
|
46947
|
-
return
|
|
47269
|
+
return import_path43.default.join(import_os41.default.homedir(), ".node9", "skill-pins.json");
|
|
46948
47270
|
}
|
|
46949
47271
|
var MAX_FILES = 5e3;
|
|
46950
47272
|
var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
@@ -46958,18 +47280,18 @@ function walkDir(root) {
|
|
|
46958
47280
|
if (out.length >= MAX_FILES) return;
|
|
46959
47281
|
let entries;
|
|
46960
47282
|
try {
|
|
46961
|
-
entries =
|
|
47283
|
+
entries = import_fs45.default.readdirSync(dir, { withFileTypes: true });
|
|
46962
47284
|
} catch {
|
|
46963
47285
|
return;
|
|
46964
47286
|
}
|
|
46965
47287
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
46966
47288
|
for (const entry of entries) {
|
|
46967
47289
|
if (out.length >= MAX_FILES) return;
|
|
46968
|
-
const full =
|
|
46969
|
-
const rel = relDir ?
|
|
47290
|
+
const full = import_path43.default.join(dir, entry.name);
|
|
47291
|
+
const rel = relDir ? import_path43.default.posix.join(relDir, entry.name) : entry.name;
|
|
46970
47292
|
let lst;
|
|
46971
47293
|
try {
|
|
46972
|
-
lst =
|
|
47294
|
+
lst = import_fs45.default.lstatSync(full);
|
|
46973
47295
|
} catch {
|
|
46974
47296
|
continue;
|
|
46975
47297
|
}
|
|
@@ -46981,7 +47303,7 @@ function walkDir(root) {
|
|
|
46981
47303
|
if (!lst.isFile()) continue;
|
|
46982
47304
|
if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
|
|
46983
47305
|
try {
|
|
46984
|
-
const buf =
|
|
47306
|
+
const buf = import_fs45.default.readFileSync(full);
|
|
46985
47307
|
totalBytes += buf.length;
|
|
46986
47308
|
out.push({ rel, hash: sha256Bytes(buf) });
|
|
46987
47309
|
} catch {
|
|
@@ -46995,14 +47317,14 @@ function walkDir(root) {
|
|
|
46995
47317
|
function hashSkillRoot(absPath) {
|
|
46996
47318
|
let lst;
|
|
46997
47319
|
try {
|
|
46998
|
-
lst =
|
|
47320
|
+
lst = import_fs45.default.lstatSync(absPath);
|
|
46999
47321
|
} catch {
|
|
47000
47322
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
47001
47323
|
}
|
|
47002
47324
|
if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
|
|
47003
47325
|
if (lst.isFile()) {
|
|
47004
47326
|
try {
|
|
47005
|
-
return { exists: true, contentHash: sha256Bytes(
|
|
47327
|
+
return { exists: true, contentHash: sha256Bytes(import_fs45.default.readFileSync(absPath)), fileCount: 1 };
|
|
47006
47328
|
} catch {
|
|
47007
47329
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
47008
47330
|
}
|
|
@@ -47020,7 +47342,7 @@ function getRootKey(absPath) {
|
|
|
47020
47342
|
function readSkillPinsSafe() {
|
|
47021
47343
|
const filePath = getPinsFilePath2();
|
|
47022
47344
|
try {
|
|
47023
|
-
const raw =
|
|
47345
|
+
const raw = import_fs45.default.readFileSync(filePath, "utf-8");
|
|
47024
47346
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
47025
47347
|
const parsed = JSON.parse(raw);
|
|
47026
47348
|
if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
|
|
@@ -47040,10 +47362,10 @@ function readSkillPins() {
|
|
|
47040
47362
|
}
|
|
47041
47363
|
function writeSkillPins(data) {
|
|
47042
47364
|
const filePath = getPinsFilePath2();
|
|
47043
|
-
|
|
47365
|
+
import_fs45.default.mkdirSync(import_path43.default.dirname(filePath), { recursive: true });
|
|
47044
47366
|
const tmp = `${filePath}.${import_crypto13.default.randomBytes(6).toString("hex")}.tmp`;
|
|
47045
|
-
|
|
47046
|
-
|
|
47367
|
+
import_fs45.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
47368
|
+
import_fs45.default.renameSync(tmp, filePath);
|
|
47047
47369
|
}
|
|
47048
47370
|
function removePin2(rootKey) {
|
|
47049
47371
|
const pins = readSkillPins();
|
|
@@ -47087,36 +47409,36 @@ function verifyAndPinRoots(roots) {
|
|
|
47087
47409
|
return { kind: "verified" };
|
|
47088
47410
|
}
|
|
47089
47411
|
function defaultSkillRoots(_cwd) {
|
|
47090
|
-
const marketplaces =
|
|
47412
|
+
const marketplaces = import_path43.default.join(import_os41.default.homedir(), ".claude", "plugins", "marketplaces");
|
|
47091
47413
|
const roots = [];
|
|
47092
47414
|
let registries;
|
|
47093
47415
|
try {
|
|
47094
|
-
registries =
|
|
47416
|
+
registries = import_fs45.default.readdirSync(marketplaces, { withFileTypes: true });
|
|
47095
47417
|
} catch {
|
|
47096
47418
|
return [];
|
|
47097
47419
|
}
|
|
47098
47420
|
for (const registry of registries) {
|
|
47099
47421
|
if (!registry.isDirectory()) continue;
|
|
47100
|
-
const pluginsDir =
|
|
47422
|
+
const pluginsDir = import_path43.default.join(marketplaces, registry.name, "plugins");
|
|
47101
47423
|
let plugins;
|
|
47102
47424
|
try {
|
|
47103
|
-
plugins =
|
|
47425
|
+
plugins = import_fs45.default.readdirSync(pluginsDir, { withFileTypes: true });
|
|
47104
47426
|
} catch {
|
|
47105
47427
|
continue;
|
|
47106
47428
|
}
|
|
47107
47429
|
for (const plugin of plugins) {
|
|
47108
47430
|
if (!plugin.isDirectory()) continue;
|
|
47109
|
-
roots.push(
|
|
47431
|
+
roots.push(import_path43.default.join(pluginsDir, plugin.name));
|
|
47110
47432
|
}
|
|
47111
47433
|
}
|
|
47112
47434
|
return roots;
|
|
47113
47435
|
}
|
|
47114
47436
|
function resolveUserSkillRoot(entry, cwd) {
|
|
47115
47437
|
if (!entry) return null;
|
|
47116
|
-
if (entry.startsWith("~/") || entry === "~") return
|
|
47117
|
-
if (
|
|
47118
|
-
if (!cwd || !
|
|
47119
|
-
return
|
|
47438
|
+
if (entry.startsWith("~/") || entry === "~") return import_path43.default.join(import_os41.default.homedir(), entry.slice(1));
|
|
47439
|
+
if (import_path43.default.isAbsolute(entry)) return entry;
|
|
47440
|
+
if (!cwd || !import_path43.default.isAbsolute(cwd)) return null;
|
|
47441
|
+
return import_path43.default.join(cwd, entry);
|
|
47120
47442
|
}
|
|
47121
47443
|
|
|
47122
47444
|
// src/cli/commands/check.ts
|
|
@@ -47124,12 +47446,12 @@ init_dlp();
|
|
|
47124
47446
|
init_audit();
|
|
47125
47447
|
|
|
47126
47448
|
// src/review-pending.ts
|
|
47127
|
-
var
|
|
47128
|
-
var
|
|
47129
|
-
var
|
|
47449
|
+
var import_fs46 = __toESM(require("fs"));
|
|
47450
|
+
var import_os42 = __toESM(require("os"));
|
|
47451
|
+
var import_path44 = __toESM(require("path"));
|
|
47130
47452
|
init_hasher();
|
|
47131
47453
|
function storePath() {
|
|
47132
|
-
return process.env.NODE9_PENDING_STORE ||
|
|
47454
|
+
return process.env.NODE9_PENDING_STORE || import_path44.default.join(import_os42.default.homedir(), ".node9", "pending-reviews.json");
|
|
47133
47455
|
}
|
|
47134
47456
|
var TTL_MS2 = 6 * 60 * 60 * 1e3;
|
|
47135
47457
|
var MAX_ENTRIES = 500;
|
|
@@ -47146,7 +47468,7 @@ function reviewCorrelationKey(payload) {
|
|
|
47146
47468
|
}
|
|
47147
47469
|
function read() {
|
|
47148
47470
|
try {
|
|
47149
|
-
const parsed = JSON.parse(
|
|
47471
|
+
const parsed = JSON.parse(import_fs46.default.readFileSync(storePath(), "utf-8"));
|
|
47150
47472
|
if (parsed && Array.isArray(parsed.entries)) return parsed;
|
|
47151
47473
|
} catch {
|
|
47152
47474
|
}
|
|
@@ -47155,11 +47477,11 @@ function read() {
|
|
|
47155
47477
|
function write(store) {
|
|
47156
47478
|
try {
|
|
47157
47479
|
const p = storePath();
|
|
47158
|
-
const dir =
|
|
47159
|
-
if (!
|
|
47480
|
+
const dir = import_path44.default.dirname(p);
|
|
47481
|
+
if (!import_fs46.default.existsSync(dir)) import_fs46.default.mkdirSync(dir, { recursive: true });
|
|
47160
47482
|
const tmp = `${p}.${process.pid}.tmp`;
|
|
47161
|
-
|
|
47162
|
-
|
|
47483
|
+
import_fs46.default.writeFileSync(tmp, JSON.stringify(store));
|
|
47484
|
+
import_fs46.default.renameSync(tmp, p);
|
|
47163
47485
|
} catch {
|
|
47164
47486
|
}
|
|
47165
47487
|
}
|
|
@@ -47272,9 +47594,9 @@ function registerCheckCommand(program2) {
|
|
|
47272
47594
|
} catch (err2) {
|
|
47273
47595
|
const tempConfig = getConfig();
|
|
47274
47596
|
if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
|
|
47275
|
-
const logPath =
|
|
47597
|
+
const logPath = import_path45.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
|
|
47276
47598
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
47277
|
-
|
|
47599
|
+
import_fs47.default.appendFileSync(
|
|
47278
47600
|
logPath,
|
|
47279
47601
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
|
|
47280
47602
|
RAW: ${raw}
|
|
@@ -47287,14 +47609,14 @@ RAW: ${raw}
|
|
|
47287
47609
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
47288
47610
|
if (process.env.NODE9_DEBUG === "1") {
|
|
47289
47611
|
try {
|
|
47290
|
-
const logPath =
|
|
47291
|
-
if (!
|
|
47292
|
-
|
|
47612
|
+
const logPath = import_path45.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
|
|
47613
|
+
if (!import_fs47.default.existsSync(import_path45.default.dirname(logPath)))
|
|
47614
|
+
import_fs47.default.mkdirSync(import_path45.default.dirname(logPath), { recursive: true });
|
|
47293
47615
|
const sanitized = JSON.stringify({
|
|
47294
47616
|
...payload,
|
|
47295
47617
|
prompt: `<redacted, ${prompt.length} bytes>`
|
|
47296
47618
|
});
|
|
47297
|
-
|
|
47619
|
+
import_fs47.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
|
|
47298
47620
|
`);
|
|
47299
47621
|
} catch {
|
|
47300
47622
|
}
|
|
@@ -47315,8 +47637,8 @@ RAW: ${raw}
|
|
|
47315
47637
|
);
|
|
47316
47638
|
const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
|
|
47317
47639
|
try {
|
|
47318
|
-
const ttyFd =
|
|
47319
|
-
|
|
47640
|
+
const ttyFd = import_fs47.default.openSync("/dev/tty", "w");
|
|
47641
|
+
import_fs47.default.writeSync(
|
|
47320
47642
|
ttyFd,
|
|
47321
47643
|
import_chalk9.default.bgRed.white.bold(`
|
|
47322
47644
|
\u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
|
|
@@ -47326,7 +47648,7 @@ RAW: ${raw}
|
|
|
47326
47648
|
|
|
47327
47649
|
`)
|
|
47328
47650
|
);
|
|
47329
|
-
|
|
47651
|
+
import_fs47.default.closeSync(ttyFd);
|
|
47330
47652
|
} catch {
|
|
47331
47653
|
}
|
|
47332
47654
|
const isCodex = agent2 === "Codex";
|
|
@@ -47345,16 +47667,17 @@ RAW: ${raw}
|
|
|
47345
47667
|
process.exit(2);
|
|
47346
47668
|
}
|
|
47347
47669
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
47348
|
-
const safeCwdForConfig = typeof payloadCwd === "string" &&
|
|
47670
|
+
const safeCwdForConfig = typeof payloadCwd === "string" && import_path45.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
47349
47671
|
const config = getConfig(safeCwdForConfig);
|
|
47350
|
-
|
|
47672
|
+
const daemonDown = !isDaemonRunning();
|
|
47673
|
+
if (config.settings.autoStartDaemon && daemonDown && !process.env.NODE9_NO_AUTO_DAEMON) {
|
|
47351
47674
|
try {
|
|
47352
47675
|
const scriptPath = process.argv[1];
|
|
47353
|
-
if (typeof scriptPath !== "string" || !
|
|
47676
|
+
if (typeof scriptPath !== "string" || !import_path45.default.isAbsolute(scriptPath))
|
|
47354
47677
|
throw new Error("node9: argv[1] is not an absolute path");
|
|
47355
|
-
const resolvedScript =
|
|
47356
|
-
const packageDist =
|
|
47357
|
-
if (!resolvedScript.startsWith(packageDist +
|
|
47678
|
+
const resolvedScript = import_fs47.default.realpathSync(scriptPath);
|
|
47679
|
+
const packageDist = import_fs47.default.realpathSync(import_path45.default.resolve(__dirname, "../.."));
|
|
47680
|
+
if (!resolvedScript.startsWith(packageDist + import_path45.default.sep) && resolvedScript !== packageDist)
|
|
47358
47681
|
throw new Error(
|
|
47359
47682
|
`node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
|
|
47360
47683
|
);
|
|
@@ -47369,17 +47692,27 @@ RAW: ${raw}
|
|
|
47369
47692
|
]) {
|
|
47370
47693
|
delete safeEnv[key];
|
|
47371
47694
|
}
|
|
47372
|
-
const
|
|
47373
|
-
|
|
47374
|
-
|
|
47375
|
-
|
|
47376
|
-
|
|
47377
|
-
|
|
47695
|
+
const startupFd = openStartupLogFd();
|
|
47696
|
+
try {
|
|
47697
|
+
const d = (0, import_child_process7.spawn)(process.execPath, [scriptPath, "daemon"], {
|
|
47698
|
+
detached: true,
|
|
47699
|
+
stdio: ["ignore", "ignore", startupFd ?? "ignore"],
|
|
47700
|
+
env: { ...safeEnv, NODE9_AUTO_STARTED: "1" }
|
|
47701
|
+
});
|
|
47702
|
+
d.unref();
|
|
47703
|
+
} finally {
|
|
47704
|
+
if (startupFd !== void 0) {
|
|
47705
|
+
try {
|
|
47706
|
+
import_fs47.default.closeSync(startupFd);
|
|
47707
|
+
} catch {
|
|
47708
|
+
}
|
|
47709
|
+
}
|
|
47710
|
+
}
|
|
47378
47711
|
} catch (spawnErr) {
|
|
47379
|
-
const logPath =
|
|
47712
|
+
const logPath = import_path45.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
|
|
47380
47713
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
47381
47714
|
try {
|
|
47382
|
-
|
|
47715
|
+
import_fs47.default.appendFileSync(
|
|
47383
47716
|
logPath,
|
|
47384
47717
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
|
|
47385
47718
|
`
|
|
@@ -47387,12 +47720,16 @@ RAW: ${raw}
|
|
|
47387
47720
|
} catch {
|
|
47388
47721
|
}
|
|
47389
47722
|
}
|
|
47723
|
+
} else if (daemonDown && !isTestingMode()) {
|
|
47724
|
+
logAutostartSkipThrottled(
|
|
47725
|
+
!config.settings.autoStartDaemon ? "autoStartDaemon=false" : process.env.NODE9_NO_AUTO_DAEMON ? "NODE9_NO_AUTO_DAEMON" : "unknown"
|
|
47726
|
+
);
|
|
47390
47727
|
}
|
|
47391
47728
|
if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
|
|
47392
|
-
const logPath =
|
|
47393
|
-
if (!
|
|
47394
|
-
|
|
47395
|
-
|
|
47729
|
+
const logPath = import_path45.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
|
|
47730
|
+
if (!import_fs47.default.existsSync(import_path45.default.dirname(logPath)))
|
|
47731
|
+
import_fs47.default.mkdirSync(import_path45.default.dirname(logPath), { recursive: true });
|
|
47732
|
+
import_fs47.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
|
|
47396
47733
|
`);
|
|
47397
47734
|
}
|
|
47398
47735
|
const rawToolName = sanitize2(extractToolName(payload));
|
|
@@ -47406,8 +47743,8 @@ RAW: ${raw}
|
|
|
47406
47743
|
const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
|
|
47407
47744
|
let ttyFd = null;
|
|
47408
47745
|
try {
|
|
47409
|
-
ttyFd =
|
|
47410
|
-
const writeTty = (line) =>
|
|
47746
|
+
ttyFd = import_fs47.default.openSync("/dev/tty", "w");
|
|
47747
|
+
const writeTty = (line) => import_fs47.default.writeSync(ttyFd, line + "\n");
|
|
47411
47748
|
if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
|
|
47412
47749
|
writeTty(import_chalk9.default.bgRed.white.bold(`
|
|
47413
47750
|
\u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
|
|
@@ -47426,7 +47763,7 @@ RAW: ${raw}
|
|
|
47426
47763
|
} finally {
|
|
47427
47764
|
if (ttyFd !== null)
|
|
47428
47765
|
try {
|
|
47429
|
-
|
|
47766
|
+
import_fs47.default.closeSync(ttyFd);
|
|
47430
47767
|
} catch {
|
|
47431
47768
|
}
|
|
47432
47769
|
}
|
|
@@ -47483,8 +47820,8 @@ RAW: ${raw}
|
|
|
47483
47820
|
} catch {
|
|
47484
47821
|
}
|
|
47485
47822
|
try {
|
|
47486
|
-
const ttyFd =
|
|
47487
|
-
|
|
47823
|
+
const ttyFd = import_fs47.default.openSync("/dev/tty", "w");
|
|
47824
|
+
import_fs47.default.writeSync(
|
|
47488
47825
|
ttyFd,
|
|
47489
47826
|
import_chalk9.default.yellow(
|
|
47490
47827
|
`
|
|
@@ -47492,7 +47829,7 @@ RAW: ${raw}
|
|
|
47492
47829
|
`
|
|
47493
47830
|
)
|
|
47494
47831
|
);
|
|
47495
|
-
|
|
47832
|
+
import_fs47.default.closeSync(ttyFd);
|
|
47496
47833
|
} catch {
|
|
47497
47834
|
}
|
|
47498
47835
|
if (agent === "GitHub Copilot") {
|
|
@@ -47524,17 +47861,17 @@ RAW: ${raw}
|
|
|
47524
47861
|
const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
|
|
47525
47862
|
if (skillPinCfg.enabled && safeSessionId) {
|
|
47526
47863
|
try {
|
|
47527
|
-
const sessionsDir =
|
|
47528
|
-
const flagPath =
|
|
47864
|
+
const sessionsDir = import_path45.default.join(import_os43.default.homedir(), ".node9", "skill-sessions");
|
|
47865
|
+
const flagPath = import_path45.default.join(sessionsDir, `${safeSessionId}.json`);
|
|
47529
47866
|
let flag = null;
|
|
47530
47867
|
try {
|
|
47531
|
-
flag = JSON.parse(
|
|
47868
|
+
flag = JSON.parse(import_fs47.default.readFileSync(flagPath, "utf-8"));
|
|
47532
47869
|
} catch {
|
|
47533
47870
|
}
|
|
47534
47871
|
const writeFlag = (data2) => {
|
|
47535
47872
|
try {
|
|
47536
|
-
|
|
47537
|
-
|
|
47873
|
+
import_fs47.default.mkdirSync(sessionsDir, { recursive: true });
|
|
47874
|
+
import_fs47.default.writeFileSync(
|
|
47538
47875
|
flagPath,
|
|
47539
47876
|
JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
47540
47877
|
{ mode: 384 }
|
|
@@ -47545,8 +47882,8 @@ RAW: ${raw}
|
|
|
47545
47882
|
const sendSkillWarn = (detail, recoveryCmd) => {
|
|
47546
47883
|
let ttyFd = null;
|
|
47547
47884
|
try {
|
|
47548
|
-
ttyFd =
|
|
47549
|
-
const w = (line) =>
|
|
47885
|
+
ttyFd = import_fs47.default.openSync("/dev/tty", "w");
|
|
47886
|
+
const w = (line) => import_fs47.default.writeSync(ttyFd, line + "\n");
|
|
47550
47887
|
w(import_chalk9.default.yellow(`
|
|
47551
47888
|
\u26A0\uFE0F Node9: installed skill drift detected`));
|
|
47552
47889
|
w(import_chalk9.default.gray(` ${detail}`));
|
|
@@ -47561,7 +47898,7 @@ RAW: ${raw}
|
|
|
47561
47898
|
} finally {
|
|
47562
47899
|
if (ttyFd !== null)
|
|
47563
47900
|
try {
|
|
47564
|
-
|
|
47901
|
+
import_fs47.default.closeSync(ttyFd);
|
|
47565
47902
|
} catch {
|
|
47566
47903
|
}
|
|
47567
47904
|
}
|
|
@@ -47577,7 +47914,7 @@ RAW: ${raw}
|
|
|
47577
47914
|
return;
|
|
47578
47915
|
}
|
|
47579
47916
|
if (!flag || flag.state !== "verified" && flag.state !== "warned") {
|
|
47580
|
-
const absoluteCwd = typeof payloadCwd === "string" &&
|
|
47917
|
+
const absoluteCwd = typeof payloadCwd === "string" && import_path45.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
47581
47918
|
const extraRoots = skillPinCfg.roots;
|
|
47582
47919
|
const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
|
|
47583
47920
|
const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
|
|
@@ -47618,10 +47955,10 @@ RAW: ${raw}
|
|
|
47618
47955
|
}
|
|
47619
47956
|
try {
|
|
47620
47957
|
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
47621
|
-
for (const name of
|
|
47622
|
-
const p =
|
|
47958
|
+
for (const name of import_fs47.default.readdirSync(sessionsDir)) {
|
|
47959
|
+
const p = import_path45.default.join(sessionsDir, name);
|
|
47623
47960
|
try {
|
|
47624
|
-
if (
|
|
47961
|
+
if (import_fs47.default.statSync(p).mtimeMs < cutoff) import_fs47.default.unlinkSync(p);
|
|
47625
47962
|
} catch {
|
|
47626
47963
|
}
|
|
47627
47964
|
}
|
|
@@ -47631,9 +47968,9 @@ RAW: ${raw}
|
|
|
47631
47968
|
} catch (err2) {
|
|
47632
47969
|
if (process.env.NODE9_DEBUG === "1") {
|
|
47633
47970
|
try {
|
|
47634
|
-
const dbg =
|
|
47971
|
+
const dbg = import_path45.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
|
|
47635
47972
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
47636
|
-
|
|
47973
|
+
import_fs47.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
|
|
47637
47974
|
`);
|
|
47638
47975
|
} catch {
|
|
47639
47976
|
}
|
|
@@ -47643,7 +47980,7 @@ RAW: ${raw}
|
|
|
47643
47980
|
if (shouldSnapshot(toolName, toolInput, config)) {
|
|
47644
47981
|
await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
|
|
47645
47982
|
}
|
|
47646
|
-
const safeCwdForAuth = typeof payloadCwd === "string" &&
|
|
47983
|
+
const safeCwdForAuth = typeof payloadCwd === "string" && import_path45.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
47647
47984
|
const askMode = resolveAskMode(agent, opts, config);
|
|
47648
47985
|
const result = await authorizeHeadless(toolName, toolInput, meta, {
|
|
47649
47986
|
cwd: safeCwdForAuth,
|
|
@@ -47661,12 +47998,12 @@ RAW: ${raw}
|
|
|
47661
47998
|
}
|
|
47662
47999
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
|
|
47663
48000
|
try {
|
|
47664
|
-
const tty =
|
|
47665
|
-
|
|
48001
|
+
const tty = import_fs47.default.openSync("/dev/tty", "w");
|
|
48002
|
+
import_fs47.default.writeSync(
|
|
47666
48003
|
tty,
|
|
47667
48004
|
import_chalk9.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
|
|
47668
48005
|
);
|
|
47669
|
-
|
|
48006
|
+
import_fs47.default.closeSync(tty);
|
|
47670
48007
|
} catch {
|
|
47671
48008
|
}
|
|
47672
48009
|
const daemonReady = await autoStartDaemonAndWait();
|
|
@@ -47693,9 +48030,9 @@ RAW: ${raw}
|
|
|
47693
48030
|
});
|
|
47694
48031
|
} catch (err2) {
|
|
47695
48032
|
if (process.env.NODE9_DEBUG === "1") {
|
|
47696
|
-
const logPath =
|
|
48033
|
+
const logPath = import_path45.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
|
|
47697
48034
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
47698
|
-
|
|
48035
|
+
import_fs47.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
|
|
47699
48036
|
`);
|
|
47700
48037
|
}
|
|
47701
48038
|
process.exit(0);
|
|
@@ -47729,9 +48066,9 @@ RAW: ${raw}
|
|
|
47729
48066
|
}
|
|
47730
48067
|
|
|
47731
48068
|
// src/cli/commands/log.ts
|
|
47732
|
-
var
|
|
47733
|
-
var
|
|
47734
|
-
var
|
|
48069
|
+
var import_fs48 = __toESM(require("fs"));
|
|
48070
|
+
var import_path46 = __toESM(require("path"));
|
|
48071
|
+
var import_os44 = __toESM(require("os"));
|
|
47735
48072
|
init_audit();
|
|
47736
48073
|
init_config();
|
|
47737
48074
|
init_daemon();
|
|
@@ -47841,10 +48178,10 @@ function registerLogCommand(program2) {
|
|
|
47841
48178
|
if (rawToolName !== tool) entry.agentToolName = rawToolName;
|
|
47842
48179
|
const payloadSessionId = payload.session_id ?? payload.conversationId;
|
|
47843
48180
|
if (payloadSessionId) entry.sessionId = payloadSessionId;
|
|
47844
|
-
const logPath =
|
|
47845
|
-
if (!
|
|
47846
|
-
|
|
47847
|
-
|
|
48181
|
+
const logPath = import_path46.default.join(import_os44.default.homedir(), ".node9", "audit.log");
|
|
48182
|
+
if (!import_fs48.default.existsSync(import_path46.default.dirname(logPath)))
|
|
48183
|
+
import_fs48.default.mkdirSync(import_path46.default.dirname(logPath), { recursive: true });
|
|
48184
|
+
import_fs48.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
47848
48185
|
if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
|
|
47849
48186
|
const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
47850
48187
|
if (command) {
|
|
@@ -47878,7 +48215,7 @@ function registerLogCommand(program2) {
|
|
|
47878
48215
|
}
|
|
47879
48216
|
}
|
|
47880
48217
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
47881
|
-
const safeCwd = typeof payloadCwd === "string" &&
|
|
48218
|
+
const safeCwd = typeof payloadCwd === "string" && import_path46.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
47882
48219
|
const config = getConfig(safeCwd);
|
|
47883
48220
|
{
|
|
47884
48221
|
const toolOutput = payload.tool_response?.output;
|
|
@@ -47955,9 +48292,9 @@ function registerLogCommand(program2) {
|
|
|
47955
48292
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
47956
48293
|
process.stderr.write(`[Node9] audit log error: ${msg}
|
|
47957
48294
|
`);
|
|
47958
|
-
const debugPath =
|
|
48295
|
+
const debugPath = import_path46.default.join(import_os44.default.homedir(), ".node9", "hook-debug.log");
|
|
47959
48296
|
try {
|
|
47960
|
-
|
|
48297
|
+
import_fs48.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
|
|
47961
48298
|
`);
|
|
47962
48299
|
} catch {
|
|
47963
48300
|
}
|
|
@@ -47982,15 +48319,15 @@ function registerLogCommand(program2) {
|
|
|
47982
48319
|
|
|
47983
48320
|
// src/cli/commands/shield.ts
|
|
47984
48321
|
var import_chalk10 = __toESM(require("chalk"));
|
|
47985
|
-
var
|
|
47986
|
-
var
|
|
47987
|
-
var
|
|
48322
|
+
var import_fs50 = __toESM(require("fs"));
|
|
48323
|
+
var import_path48 = __toESM(require("path"));
|
|
48324
|
+
var import_os45 = __toESM(require("os"));
|
|
47988
48325
|
init_shields();
|
|
47989
48326
|
init_build();
|
|
47990
48327
|
|
|
47991
48328
|
// src/shields/create.ts
|
|
47992
|
-
var
|
|
47993
|
-
var
|
|
48329
|
+
var import_fs49 = __toESM(require("fs"));
|
|
48330
|
+
var import_path47 = __toESM(require("path"));
|
|
47994
48331
|
init_dist();
|
|
47995
48332
|
init_shields();
|
|
47996
48333
|
init_audit();
|
|
@@ -48010,8 +48347,8 @@ function createShield(def, opts = {}) {
|
|
|
48010
48347
|
error: `"${name}" is a built-in shield \u2014 choose a different name (a user shield with this name would shadow the built-in).`
|
|
48011
48348
|
};
|
|
48012
48349
|
}
|
|
48013
|
-
const filePath =
|
|
48014
|
-
if (!opts.overwrite &&
|
|
48350
|
+
const filePath = import_path47.default.join(USER_SHIELDS_DIR_PATH, `${name}.json`);
|
|
48351
|
+
if (!opts.overwrite && import_fs49.default.existsSync(filePath)) {
|
|
48015
48352
|
return {
|
|
48016
48353
|
ok: false,
|
|
48017
48354
|
error: `Shield "${name}" already exists at ${filePath}. Pass --overwrite to replace it.`
|
|
@@ -48076,8 +48413,8 @@ var COMMUNITY_INDEX_URL = "https://raw.githubusercontent.com/node9ai/node9-proxy
|
|
|
48076
48413
|
function readCloudShields() {
|
|
48077
48414
|
const out = /* @__PURE__ */ new Set();
|
|
48078
48415
|
try {
|
|
48079
|
-
const file =
|
|
48080
|
-
const raw = JSON.parse(
|
|
48416
|
+
const file = import_path48.default.join(import_os45.default.homedir(), ".node9", "rules-cache.json");
|
|
48417
|
+
const raw = JSON.parse(import_fs50.default.readFileSync(file, "utf-8"));
|
|
48081
48418
|
for (const r of raw.rules ?? []) {
|
|
48082
48419
|
const rule = r;
|
|
48083
48420
|
const fromSource = rule.source?.startsWith("SHIELD:") ? rule.source.slice("SHIELD:".length).toLowerCase() : void 0;
|
|
@@ -48394,7 +48731,7 @@ function registerShieldCommand(program2) {
|
|
|
48394
48731
|
if (opts.fromFile) {
|
|
48395
48732
|
let raw;
|
|
48396
48733
|
try {
|
|
48397
|
-
raw = JSON.parse(
|
|
48734
|
+
raw = JSON.parse(import_fs50.default.readFileSync(opts.fromFile, "utf-8"));
|
|
48398
48735
|
} catch (err2) {
|
|
48399
48736
|
console.error(
|
|
48400
48737
|
import_chalk10.default.red(`
|
|
@@ -48514,16 +48851,33 @@ function registerConfigShowCommand(program2) {
|
|
|
48514
48851
|
|
|
48515
48852
|
// src/cli/commands/doctor.ts
|
|
48516
48853
|
var import_chalk11 = __toESM(require("chalk"));
|
|
48517
|
-
var
|
|
48518
|
-
var
|
|
48519
|
-
var
|
|
48854
|
+
var import_fs51 = __toESM(require("fs"));
|
|
48855
|
+
var import_path49 = __toESM(require("path"));
|
|
48856
|
+
var import_os46 = __toESM(require("os"));
|
|
48520
48857
|
var import_child_process8 = require("child_process");
|
|
48521
48858
|
init_daemon();
|
|
48522
48859
|
init_config();
|
|
48523
48860
|
init_agent_wiring();
|
|
48861
|
+
init_sync();
|
|
48862
|
+
init_service();
|
|
48863
|
+
|
|
48864
|
+
// src/lib/relative-time.ts
|
|
48865
|
+
function agoLabel(iso, now = Date.now()) {
|
|
48866
|
+
const ms = now - new Date(iso).getTime();
|
|
48867
|
+
if (!Number.isFinite(ms) || ms < 0) return "just now";
|
|
48868
|
+
const min = Math.floor(ms / 6e4);
|
|
48869
|
+
if (min < 1) return "just now";
|
|
48870
|
+
if (min < 60) return `${min} min ago`;
|
|
48871
|
+
const hr = Math.floor(min / 60);
|
|
48872
|
+
if (hr < 24) return `${hr} hour${hr === 1 ? "" : "s"} ago`;
|
|
48873
|
+
const d = Math.floor(hr / 24);
|
|
48874
|
+
return `${d} day${d === 1 ? "" : "s"} ago`;
|
|
48875
|
+
}
|
|
48876
|
+
|
|
48877
|
+
// src/cli/commands/doctor.ts
|
|
48524
48878
|
function registerDoctorCommand(program2, version2) {
|
|
48525
48879
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
|
|
48526
|
-
const homeDir2 =
|
|
48880
|
+
const homeDir2 = import_os46.default.homedir();
|
|
48527
48881
|
let failures = 0;
|
|
48528
48882
|
function pass(msg) {
|
|
48529
48883
|
console.log(import_chalk11.default.green(" \u2705 ") + msg);
|
|
@@ -48569,10 +48923,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48569
48923
|
);
|
|
48570
48924
|
}
|
|
48571
48925
|
section("Configuration");
|
|
48572
|
-
const globalConfigPath =
|
|
48573
|
-
if (
|
|
48926
|
+
const globalConfigPath = import_path49.default.join(homeDir2, ".node9", "config.json");
|
|
48927
|
+
if (import_fs51.default.existsSync(globalConfigPath)) {
|
|
48574
48928
|
try {
|
|
48575
|
-
JSON.parse(
|
|
48929
|
+
JSON.parse(import_fs51.default.readFileSync(globalConfigPath, "utf-8"));
|
|
48576
48930
|
pass("~/.node9/config.json found and valid");
|
|
48577
48931
|
} catch {
|
|
48578
48932
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -48580,10 +48934,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48580
48934
|
} else {
|
|
48581
48935
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
48582
48936
|
}
|
|
48583
|
-
const projectConfigPath =
|
|
48584
|
-
if (
|
|
48937
|
+
const projectConfigPath = import_path49.default.join(process.cwd(), "node9.config.json");
|
|
48938
|
+
if (import_fs51.default.existsSync(projectConfigPath)) {
|
|
48585
48939
|
try {
|
|
48586
|
-
JSON.parse(
|
|
48940
|
+
JSON.parse(import_fs51.default.readFileSync(projectConfigPath, "utf-8"));
|
|
48587
48941
|
pass("node9.config.json found and valid (project)");
|
|
48588
48942
|
} catch {
|
|
48589
48943
|
fail(
|
|
@@ -48592,8 +48946,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48592
48946
|
);
|
|
48593
48947
|
}
|
|
48594
48948
|
}
|
|
48595
|
-
const credsPath =
|
|
48596
|
-
if (
|
|
48949
|
+
const credsPath = import_path49.default.join(homeDir2, ".node9", "credentials.json");
|
|
48950
|
+
if (import_fs51.default.existsSync(credsPath)) {
|
|
48597
48951
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
48598
48952
|
} else {
|
|
48599
48953
|
warn(
|
|
@@ -48633,11 +48987,31 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48633
48987
|
"Run: node9 daemon --background"
|
|
48634
48988
|
);
|
|
48635
48989
|
}
|
|
48990
|
+
const autostart = autostartAdvice({
|
|
48991
|
+
installed: isDaemonServiceInstalled(),
|
|
48992
|
+
enabled: isDaemonServiceEnabled(),
|
|
48993
|
+
cloudEnabled: !!getConfig().settings.approvers?.cloud
|
|
48994
|
+
});
|
|
48995
|
+
if (autostart) warn(autostart.message, autostart.hint);
|
|
48996
|
+
if (import_fs51.default.existsSync(import_path49.default.join(import_os46.default.homedir(), ".node9", "credentials.json")) && getConfig().settings.approvers?.cloud) {
|
|
48997
|
+
section("Policy sync");
|
|
48998
|
+
const health = readSyncHealth();
|
|
48999
|
+
if (isPolicyStale(Date.now(), health)) {
|
|
49000
|
+
const when = health.lastCheckedAt ? `last reached the cloud ${agoLabel(health.lastCheckedAt)}` : "never reached the cloud";
|
|
49001
|
+
const fails = health.consecutiveFailures > 0 ? ` (${health.consecutiveFailures} consecutive failure${health.consecutiveFailures === 1 ? "" : "s"}${health.lastError ? `: ${health.lastError}` : ""})` : "";
|
|
49002
|
+
warn(
|
|
49003
|
+
`Cloud policy is STALE \u2014 ${when}${fails}. The cached policy is still enforced, but changes from the dashboard are not reaching this machine.`,
|
|
49004
|
+
"Run: node9 policy sync (and ensure the daemon autostarts: systemctl --user enable --now node9-daemon)"
|
|
49005
|
+
);
|
|
49006
|
+
} else if (health.lastCheckedAt) {
|
|
49007
|
+
pass(`Cloud policy fresh \u2014 last synced ${agoLabel(health.lastCheckedAt)}`);
|
|
49008
|
+
}
|
|
49009
|
+
}
|
|
48636
49010
|
section("Cloud audit shipping");
|
|
48637
49011
|
try {
|
|
48638
49012
|
const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
|
|
48639
49013
|
const cfg = getConfig();
|
|
48640
|
-
const creds =
|
|
49014
|
+
const creds = import_fs51.default.existsSync(import_path49.default.join(import_os46.default.homedir(), ".node9", "credentials.json"));
|
|
48641
49015
|
if (!creds) {
|
|
48642
49016
|
warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
|
|
48643
49017
|
} else if (!cfg.settings.approvers.cloud) {
|
|
@@ -48687,9 +49061,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48687
49061
|
|
|
48688
49062
|
// src/cli/commands/audit.ts
|
|
48689
49063
|
var import_chalk12 = __toESM(require("chalk"));
|
|
48690
|
-
var
|
|
48691
|
-
var
|
|
48692
|
-
var
|
|
49064
|
+
var import_fs52 = __toESM(require("fs"));
|
|
49065
|
+
var import_path50 = __toESM(require("path"));
|
|
49066
|
+
var import_os47 = __toESM(require("os"));
|
|
48693
49067
|
function formatRelativeTime(timestamp) {
|
|
48694
49068
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
48695
49069
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -48702,14 +49076,14 @@ function formatRelativeTime(timestamp) {
|
|
|
48702
49076
|
}
|
|
48703
49077
|
function registerAuditCommand(program2) {
|
|
48704
49078
|
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) => {
|
|
48705
|
-
const logPath =
|
|
48706
|
-
if (!
|
|
49079
|
+
const logPath = import_path50.default.join(import_os47.default.homedir(), ".node9", "audit.log");
|
|
49080
|
+
if (!import_fs52.default.existsSync(logPath)) {
|
|
48707
49081
|
console.log(
|
|
48708
49082
|
import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
48709
49083
|
);
|
|
48710
49084
|
return;
|
|
48711
49085
|
}
|
|
48712
|
-
const raw =
|
|
49086
|
+
const raw = import_fs52.default.readFileSync(logPath, "utf-8");
|
|
48713
49087
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
48714
49088
|
let entries = lines.flatMap((line) => {
|
|
48715
49089
|
try {
|
|
@@ -48765,9 +49139,9 @@ function registerAuditCommand(program2) {
|
|
|
48765
49139
|
var import_chalk13 = __toESM(require("chalk"));
|
|
48766
49140
|
|
|
48767
49141
|
// src/cli/aggregate/report-audit.ts
|
|
48768
|
-
var
|
|
48769
|
-
var
|
|
48770
|
-
var
|
|
49142
|
+
var import_fs53 = __toESM(require("fs"));
|
|
49143
|
+
var import_os48 = __toESM(require("os"));
|
|
49144
|
+
var import_path51 = __toESM(require("path"));
|
|
48771
49145
|
init_costSync();
|
|
48772
49146
|
init_litellm();
|
|
48773
49147
|
init_cost_codex();
|
|
@@ -48850,8 +49224,8 @@ function getDateRange(period, now) {
|
|
|
48850
49224
|
}
|
|
48851
49225
|
}
|
|
48852
49226
|
function parseAuditLog(logPath) {
|
|
48853
|
-
if (!
|
|
48854
|
-
const raw =
|
|
49227
|
+
if (!import_fs53.default.existsSync(logPath)) return [];
|
|
49228
|
+
const raw = import_fs53.default.readFileSync(logPath, "utf-8");
|
|
48855
49229
|
return raw.split("\n").flatMap((line) => {
|
|
48856
49230
|
if (!line.trim()) return [];
|
|
48857
49231
|
try {
|
|
@@ -48898,25 +49272,25 @@ function freezeClaudeCost(acc) {
|
|
|
48898
49272
|
};
|
|
48899
49273
|
}
|
|
48900
49274
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
48901
|
-
const projPath =
|
|
49275
|
+
const projPath = import_path51.default.join(projectsDir, proj);
|
|
48902
49276
|
let files;
|
|
48903
49277
|
try {
|
|
48904
|
-
const stat =
|
|
49278
|
+
const stat = import_fs53.default.statSync(projPath);
|
|
48905
49279
|
if (!stat.isDirectory()) return;
|
|
48906
|
-
files =
|
|
49280
|
+
files = import_fs53.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
48907
49281
|
} catch {
|
|
48908
49282
|
return;
|
|
48909
49283
|
}
|
|
48910
49284
|
const startMs = start.getTime();
|
|
48911
49285
|
for (const file of files) {
|
|
48912
|
-
const filePath =
|
|
49286
|
+
const filePath = import_path51.default.join(projPath, file);
|
|
48913
49287
|
try {
|
|
48914
|
-
if (
|
|
49288
|
+
if (import_fs53.default.statSync(filePath).mtimeMs < startMs) continue;
|
|
48915
49289
|
} catch {
|
|
48916
49290
|
continue;
|
|
48917
49291
|
}
|
|
48918
49292
|
try {
|
|
48919
|
-
const raw =
|
|
49293
|
+
const raw = import_fs53.default.readFileSync(filePath, "utf-8");
|
|
48920
49294
|
for (const line of raw.split("\n")) {
|
|
48921
49295
|
if (!line.trim()) continue;
|
|
48922
49296
|
let entry;
|
|
@@ -48966,10 +49340,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
48966
49340
|
}
|
|
48967
49341
|
function loadClaudeCost(start, end, projectsDir) {
|
|
48968
49342
|
const acc = emptyClaudeCostAccumulator();
|
|
48969
|
-
if (!
|
|
49343
|
+
if (!import_fs53.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
48970
49344
|
let dirs;
|
|
48971
49345
|
try {
|
|
48972
|
-
dirs =
|
|
49346
|
+
dirs = import_fs53.default.readdirSync(projectsDir);
|
|
48973
49347
|
} catch {
|
|
48974
49348
|
return freezeClaudeCost(acc);
|
|
48975
49349
|
}
|
|
@@ -48981,7 +49355,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
48981
49355
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
48982
49356
|
let lines;
|
|
48983
49357
|
try {
|
|
48984
|
-
lines =
|
|
49358
|
+
lines = import_fs53.default.readFileSync(filePath, "utf-8").split("\n");
|
|
48985
49359
|
} catch {
|
|
48986
49360
|
return;
|
|
48987
49361
|
}
|
|
@@ -49036,31 +49410,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
49036
49410
|
}
|
|
49037
49411
|
function listCodexSessionFiles2(sessionsBase) {
|
|
49038
49412
|
const jsonlFiles = [];
|
|
49039
|
-
if (!
|
|
49413
|
+
if (!import_fs53.default.existsSync(sessionsBase)) return jsonlFiles;
|
|
49040
49414
|
try {
|
|
49041
|
-
for (const year of
|
|
49042
|
-
const yearPath =
|
|
49415
|
+
for (const year of import_fs53.default.readdirSync(sessionsBase)) {
|
|
49416
|
+
const yearPath = import_path51.default.join(sessionsBase, year);
|
|
49043
49417
|
try {
|
|
49044
|
-
if (!
|
|
49418
|
+
if (!import_fs53.default.statSync(yearPath).isDirectory()) continue;
|
|
49045
49419
|
} catch {
|
|
49046
49420
|
continue;
|
|
49047
49421
|
}
|
|
49048
|
-
for (const month of
|
|
49049
|
-
const monthPath =
|
|
49422
|
+
for (const month of import_fs53.default.readdirSync(yearPath)) {
|
|
49423
|
+
const monthPath = import_path51.default.join(yearPath, month);
|
|
49050
49424
|
try {
|
|
49051
|
-
if (!
|
|
49425
|
+
if (!import_fs53.default.statSync(monthPath).isDirectory()) continue;
|
|
49052
49426
|
} catch {
|
|
49053
49427
|
continue;
|
|
49054
49428
|
}
|
|
49055
|
-
for (const day of
|
|
49056
|
-
const dayPath =
|
|
49429
|
+
for (const day of import_fs53.default.readdirSync(monthPath)) {
|
|
49430
|
+
const dayPath = import_path51.default.join(monthPath, day);
|
|
49057
49431
|
try {
|
|
49058
|
-
if (!
|
|
49432
|
+
if (!import_fs53.default.statSync(dayPath).isDirectory()) continue;
|
|
49059
49433
|
} catch {
|
|
49060
49434
|
continue;
|
|
49061
49435
|
}
|
|
49062
|
-
for (const file of
|
|
49063
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
49436
|
+
for (const file of import_fs53.default.readdirSync(dayPath)) {
|
|
49437
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path51.default.join(dayPath, file));
|
|
49064
49438
|
}
|
|
49065
49439
|
}
|
|
49066
49440
|
}
|
|
@@ -49125,13 +49499,13 @@ function freezeGeminiCost(acc) {
|
|
|
49125
49499
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
49126
49500
|
const startMs = start.getTime();
|
|
49127
49501
|
try {
|
|
49128
|
-
if (
|
|
49502
|
+
if (import_fs53.default.statSync(filePath).mtimeMs < startMs) return;
|
|
49129
49503
|
} catch {
|
|
49130
49504
|
return;
|
|
49131
49505
|
}
|
|
49132
49506
|
let raw;
|
|
49133
49507
|
try {
|
|
49134
|
-
raw =
|
|
49508
|
+
raw = import_fs53.default.readFileSync(filePath, "utf-8");
|
|
49135
49509
|
} catch {
|
|
49136
49510
|
return;
|
|
49137
49511
|
}
|
|
@@ -49180,30 +49554,30 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
|
|
|
49180
49554
|
const out = [];
|
|
49181
49555
|
let dirs;
|
|
49182
49556
|
try {
|
|
49183
|
-
if (!
|
|
49184
|
-
dirs =
|
|
49557
|
+
if (!import_fs53.default.statSync(geminiTmpDir2).isDirectory()) return out;
|
|
49558
|
+
dirs = import_fs53.default.readdirSync(geminiTmpDir2);
|
|
49185
49559
|
} catch {
|
|
49186
49560
|
return out;
|
|
49187
49561
|
}
|
|
49188
49562
|
for (const proj of dirs) {
|
|
49189
|
-
const chatsDir =
|
|
49563
|
+
const chatsDir = import_path51.default.join(geminiTmpDir2, proj, "chats");
|
|
49190
49564
|
let files;
|
|
49191
49565
|
try {
|
|
49192
|
-
if (!
|
|
49193
|
-
files =
|
|
49566
|
+
if (!import_fs53.default.statSync(chatsDir).isDirectory()) continue;
|
|
49567
|
+
files = import_fs53.default.readdirSync(chatsDir);
|
|
49194
49568
|
} catch {
|
|
49195
49569
|
continue;
|
|
49196
49570
|
}
|
|
49197
49571
|
for (const f of files) {
|
|
49198
49572
|
if (!f.endsWith(".jsonl")) continue;
|
|
49199
|
-
out.push({ projectKey: proj, file:
|
|
49573
|
+
out.push({ projectKey: proj, file: import_path51.default.join(chatsDir, f) });
|
|
49200
49574
|
}
|
|
49201
49575
|
}
|
|
49202
49576
|
return out;
|
|
49203
49577
|
}
|
|
49204
49578
|
function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
49205
49579
|
const acc = emptyGeminiAccumulator();
|
|
49206
|
-
if (!
|
|
49580
|
+
if (!import_fs53.default.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
|
|
49207
49581
|
for (const { projectKey, file } of listGeminiSessionFiles2(geminiTmpDir2)) {
|
|
49208
49582
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
49209
49583
|
}
|
|
@@ -49221,11 +49595,11 @@ function dimensionOfBlock(checkedBy, ruleName) {
|
|
|
49221
49595
|
}
|
|
49222
49596
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
49223
49597
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
49224
|
-
const auditLogPath = opts.auditLogPath ??
|
|
49225
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
49226
|
-
const codexSessionsDir2 = opts.codexSessionsDir ??
|
|
49227
|
-
const geminiTmpDir2 = opts.geminiTmpDir ??
|
|
49228
|
-
const hasAuditFile =
|
|
49598
|
+
const auditLogPath = opts.auditLogPath ?? import_path51.default.join(import_os48.default.homedir(), ".node9", "audit.log");
|
|
49599
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? import_path51.default.join(import_os48.default.homedir(), ".claude", "projects");
|
|
49600
|
+
const codexSessionsDir2 = opts.codexSessionsDir ?? import_path51.default.join(import_os48.default.homedir(), ".codex", "sessions");
|
|
49601
|
+
const geminiTmpDir2 = opts.geminiTmpDir ?? import_path51.default.join(import_os48.default.homedir(), ".gemini", "tmp");
|
|
49602
|
+
const hasAuditFile = import_fs53.default.existsSync(auditLogPath);
|
|
49229
49603
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
49230
49604
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
49231
49605
|
const { start, end } = getDateRange(period, now);
|
|
@@ -50016,12 +50390,14 @@ function registerDaemonCommand(program2) {
|
|
|
50016
50390
|
|
|
50017
50391
|
// src/cli/commands/status.ts
|
|
50018
50392
|
var import_chalk15 = __toESM(require("chalk"));
|
|
50019
|
-
var
|
|
50020
|
-
var
|
|
50021
|
-
var
|
|
50393
|
+
var import_fs54 = __toESM(require("fs"));
|
|
50394
|
+
var import_path52 = __toESM(require("path"));
|
|
50395
|
+
var import_os49 = __toESM(require("os"));
|
|
50022
50396
|
init_core();
|
|
50023
50397
|
init_daemon();
|
|
50024
50398
|
init_agent_wiring();
|
|
50399
|
+
init_sync();
|
|
50400
|
+
init_service();
|
|
50025
50401
|
function printAgentSection(label2, hookPairs, wrapped) {
|
|
50026
50402
|
console.log(import_chalk15.default.bold(` ${label2}`));
|
|
50027
50403
|
for (const { name, present } of hookPairs) {
|
|
@@ -50050,6 +50426,15 @@ function registerStatusCommand(program2) {
|
|
|
50050
50426
|
console.log("");
|
|
50051
50427
|
if (creds && settings.approvers.cloud) {
|
|
50052
50428
|
console.log(import_chalk15.default.green(" \u25CF Agent mode") + import_chalk15.default.gray(" \u2014 cloud team policy enforced"));
|
|
50429
|
+
const health = readSyncHealth();
|
|
50430
|
+
if (isPolicyStale(Date.now(), health)) {
|
|
50431
|
+
const when = health.lastCheckedAt ? `last synced ${agoLabel(health.lastCheckedAt)}` : "never synced";
|
|
50432
|
+
const fails = health.consecutiveFailures > 0 ? ` \xB7 ${health.consecutiveFailures} failed attempt${health.consecutiveFailures === 1 ? "" : "s"}${health.lastError ? ` (${health.lastError})` : ""}` : "";
|
|
50433
|
+
console.log(import_chalk15.default.yellow(" \u26A0 Policy sync STALE") + import_chalk15.default.gray(` \u2014 ${when}${fails}`));
|
|
50434
|
+
console.log(import_chalk15.default.gray(" the cached policy is still enforced \u2014 run: node9 doctor"));
|
|
50435
|
+
} else if (health.lastCheckedAt) {
|
|
50436
|
+
console.log(import_chalk15.default.gray(` \u21B3 policy synced ${agoLabel(health.lastCheckedAt)}`));
|
|
50437
|
+
}
|
|
50053
50438
|
} else if (creds && !settings.approvers.cloud) {
|
|
50054
50439
|
console.log(
|
|
50055
50440
|
import_chalk15.default.blue(" \u25CF Privacy mode \u{1F6E1}\uFE0F") + import_chalk15.default.gray(" \u2014 all decisions stay on this machine")
|
|
@@ -50067,6 +50452,16 @@ function registerStatusCommand(program2) {
|
|
|
50067
50452
|
} else {
|
|
50068
50453
|
console.log(import_chalk15.default.gray(" \u25CB Daemon stopped"));
|
|
50069
50454
|
}
|
|
50455
|
+
const autostart = autostartAdvice({
|
|
50456
|
+
installed: isDaemonServiceInstalled(),
|
|
50457
|
+
enabled: isDaemonServiceEnabled(),
|
|
50458
|
+
cloudEnabled: !!(creds && settings.approvers.cloud)
|
|
50459
|
+
});
|
|
50460
|
+
if (autostart) {
|
|
50461
|
+
console.log(
|
|
50462
|
+
import_chalk15.default.yellow(" \u26A0 daemon autostart not active") + import_chalk15.default.gray(" \u2014 won't survive reboot; run: node9 doctor")
|
|
50463
|
+
);
|
|
50464
|
+
}
|
|
50070
50465
|
if (settings.enableUndo) {
|
|
50071
50466
|
console.log(
|
|
50072
50467
|
import_chalk15.default.magenta(" \u25CF Undo Engine") + import_chalk15.default.gray(` \u2192 Auto-snapshotting Git repos on AI change`)
|
|
@@ -50075,20 +50470,20 @@ function registerStatusCommand(program2) {
|
|
|
50075
50470
|
console.log("");
|
|
50076
50471
|
const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
|
|
50077
50472
|
console.log(` Mode: ${modeLabel}`);
|
|
50078
|
-
const projectConfig =
|
|
50079
|
-
const globalConfig =
|
|
50473
|
+
const projectConfig = import_path52.default.join(process.cwd(), "node9.config.json");
|
|
50474
|
+
const globalConfig = import_path52.default.join(import_os49.default.homedir(), ".node9", "config.json");
|
|
50080
50475
|
console.log(
|
|
50081
|
-
` Local: ${
|
|
50476
|
+
` Local: ${import_fs54.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
|
|
50082
50477
|
);
|
|
50083
50478
|
console.log(
|
|
50084
|
-
` Global: ${
|
|
50479
|
+
` Global: ${import_fs54.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
|
|
50085
50480
|
);
|
|
50086
50481
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
50087
50482
|
console.log(
|
|
50088
50483
|
` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
50089
50484
|
);
|
|
50090
50485
|
}
|
|
50091
|
-
const wiring = getAgentWiring(
|
|
50486
|
+
const wiring = getAgentWiring(import_os49.default.homedir()).filter((a) => a.present);
|
|
50092
50487
|
if (wiring.length > 0) {
|
|
50093
50488
|
console.log("");
|
|
50094
50489
|
console.log(import_chalk15.default.bold(" Agent Wiring:"));
|
|
@@ -50123,14 +50518,15 @@ function registerStatusCommand(program2) {
|
|
|
50123
50518
|
|
|
50124
50519
|
// src/cli/commands/init.ts
|
|
50125
50520
|
var import_chalk16 = __toESM(require("chalk"));
|
|
50126
|
-
var
|
|
50127
|
-
var
|
|
50128
|
-
var
|
|
50521
|
+
var import_fs55 = __toESM(require("fs"));
|
|
50522
|
+
var import_path53 = __toESM(require("path"));
|
|
50523
|
+
var import_os50 = __toESM(require("os"));
|
|
50129
50524
|
var import_https6 = __toESM(require("https"));
|
|
50130
50525
|
init_core();
|
|
50131
50526
|
init_setup();
|
|
50132
50527
|
init_shields();
|
|
50133
50528
|
init_service();
|
|
50529
|
+
init_core();
|
|
50134
50530
|
var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
|
|
50135
50531
|
function buildTelemetryPayload(agents, firstInstall) {
|
|
50136
50532
|
return {
|
|
@@ -50215,16 +50611,16 @@ function registerInitCommand(program2) {
|
|
|
50215
50611
|
}
|
|
50216
50612
|
console.log("");
|
|
50217
50613
|
}
|
|
50218
|
-
const configPath =
|
|
50219
|
-
const isFirstInstall = !
|
|
50220
|
-
if (
|
|
50614
|
+
const configPath = import_path53.default.join(import_os50.default.homedir(), ".node9", "config.json");
|
|
50615
|
+
const isFirstInstall = !import_fs55.default.existsSync(configPath);
|
|
50616
|
+
if (import_fs55.default.existsSync(configPath) && !options.force) {
|
|
50221
50617
|
try {
|
|
50222
|
-
const existing = JSON.parse(
|
|
50618
|
+
const existing = JSON.parse(import_fs55.default.readFileSync(configPath, "utf-8"));
|
|
50223
50619
|
const settings = existing.settings ?? {};
|
|
50224
50620
|
if (settings.mode !== chosenMode) {
|
|
50225
50621
|
settings.mode = chosenMode;
|
|
50226
50622
|
existing.settings = settings;
|
|
50227
|
-
|
|
50623
|
+
import_fs55.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
50228
50624
|
console.log(import_chalk16.default.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
50229
50625
|
} else {
|
|
50230
50626
|
console.log(import_chalk16.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -50237,9 +50633,9 @@ function registerInitCommand(program2) {
|
|
|
50237
50633
|
...DEFAULT_CONFIG,
|
|
50238
50634
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
50239
50635
|
};
|
|
50240
|
-
const dir =
|
|
50241
|
-
if (!
|
|
50242
|
-
|
|
50636
|
+
const dir = import_path53.default.dirname(configPath);
|
|
50637
|
+
if (!import_fs55.default.existsSync(dir)) import_fs55.default.mkdirSync(dir, { recursive: true });
|
|
50638
|
+
import_fs55.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
50243
50639
|
console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
|
|
50244
50640
|
console.log(import_chalk16.default.gray(` Mode: ${chosenMode}`));
|
|
50245
50641
|
}
|
|
@@ -50291,8 +50687,13 @@ function registerInitCommand(program2) {
|
|
|
50291
50687
|
console.log(import_chalk16.default.gray(" You can try again later with: node9 daemon install"));
|
|
50292
50688
|
}
|
|
50293
50689
|
}
|
|
50690
|
+
} else if (isDaemonServiceEnabled()) {
|
|
50691
|
+
console.log(import_chalk16.default.green(" \u2713 Daemon login service already installed & enabled"));
|
|
50294
50692
|
} else {
|
|
50295
|
-
|
|
50693
|
+
const healed = ensureAutostartHealthy(!!getConfig().settings.autoStartDaemon);
|
|
50694
|
+
console.log(
|
|
50695
|
+
healed === "repaired" ? import_chalk16.default.green(" \u2713 Re-enabled daemon login service (was installed but disabled)") : import_chalk16.default.gray(" \xB7 Daemon login service is disabled (autostart off) \u2014 left as-is")
|
|
50696
|
+
);
|
|
50296
50697
|
}
|
|
50297
50698
|
if (!isTestingMode()) {
|
|
50298
50699
|
process.stdout.write(import_chalk16.default.dim(" Starting daemon..."));
|
|
@@ -50334,14 +50735,14 @@ function registerInitCommand(program2) {
|
|
|
50334
50735
|
|
|
50335
50736
|
// src/cli/commands/heal.ts
|
|
50336
50737
|
var import_chalk17 = __toESM(require("chalk"));
|
|
50337
|
-
var
|
|
50738
|
+
var import_fs56 = __toESM(require("fs"));
|
|
50338
50739
|
init_agent_wiring();
|
|
50339
50740
|
init_setup();
|
|
50340
50741
|
init_hook_baseline();
|
|
50341
50742
|
var hasHookSurface = (a) => a.hooks.length > 0;
|
|
50342
50743
|
function backupForHeal(file) {
|
|
50343
50744
|
try {
|
|
50344
|
-
if (file &&
|
|
50745
|
+
if (file && import_fs56.default.existsSync(file)) import_fs56.default.copyFileSync(file, `${file}.node9-heal-bak`);
|
|
50345
50746
|
} catch {
|
|
50346
50747
|
}
|
|
50347
50748
|
}
|
|
@@ -50508,7 +50909,7 @@ function registerConnectCommand(program2) {
|
|
|
50508
50909
|
}
|
|
50509
50910
|
|
|
50510
50911
|
// src/cli/commands/undo.ts
|
|
50511
|
-
var
|
|
50912
|
+
var import_path54 = __toESM(require("path"));
|
|
50512
50913
|
var import_chalk20 = __toESM(require("chalk"));
|
|
50513
50914
|
|
|
50514
50915
|
// src/tui/undo-navigator.ts
|
|
@@ -50667,7 +51068,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
50667
51068
|
let dir = startDir;
|
|
50668
51069
|
while (true) {
|
|
50669
51070
|
if (cwds.has(dir)) return dir;
|
|
50670
|
-
const parent =
|
|
51071
|
+
const parent = import_path54.default.dirname(dir);
|
|
50671
51072
|
if (parent === dir) return null;
|
|
50672
51073
|
dir = parent;
|
|
50673
51074
|
}
|
|
@@ -50835,7 +51236,7 @@ function normalizeClientName(name) {
|
|
|
50835
51236
|
const sanitized = sanitize4(name).slice(0, 40);
|
|
50836
51237
|
return sanitized.length > 0 ? sanitized : void 0;
|
|
50837
51238
|
}
|
|
50838
|
-
function reportPinMismatchToCloud(serverKey, agent) {
|
|
51239
|
+
function reportPinMismatchToCloud(serverKey, serverLabel, agent) {
|
|
50839
51240
|
try {
|
|
50840
51241
|
const creds = getCredentials();
|
|
50841
51242
|
if (!creds) return;
|
|
@@ -50844,18 +51245,18 @@ function reportPinMismatchToCloud(serverKey, agent) {
|
|
|
50844
51245
|
{ serverKey, reason: "tool-pin-mismatch" },
|
|
50845
51246
|
"mcp-pin-mismatch",
|
|
50846
51247
|
creds,
|
|
50847
|
-
{ mcpServer:
|
|
51248
|
+
{ mcpServer: serverLabel, agent },
|
|
50848
51249
|
void 0,
|
|
50849
51250
|
false,
|
|
50850
51251
|
{
|
|
50851
51252
|
ruleName: "MCP tool definitions changed (possible rug pull)",
|
|
50852
|
-
ruleDescription: `The MCP server "${
|
|
51253
|
+
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}`
|
|
50853
51254
|
}
|
|
50854
51255
|
);
|
|
50855
51256
|
} catch {
|
|
50856
51257
|
}
|
|
50857
51258
|
}
|
|
50858
|
-
function reportInventoryToCloud(serverKey, toolCount, agent) {
|
|
51259
|
+
function reportInventoryToCloud(serverKey, serverLabel, toolCount, agent) {
|
|
50859
51260
|
try {
|
|
50860
51261
|
const creds = getCredentials();
|
|
50861
51262
|
if (!creds) return;
|
|
@@ -50864,7 +51265,7 @@ function reportInventoryToCloud(serverKey, toolCount, agent) {
|
|
|
50864
51265
|
{ serverKey, toolCount },
|
|
50865
51266
|
"mcp-discovered",
|
|
50866
51267
|
creds,
|
|
50867
|
-
{ mcpServer:
|
|
51268
|
+
{ mcpServer: serverLabel, agent },
|
|
50868
51269
|
void 0,
|
|
50869
51270
|
false,
|
|
50870
51271
|
{ mcpToolCount: toolCount }
|
|
@@ -50872,7 +51273,7 @@ function reportInventoryToCloud(serverKey, toolCount, agent) {
|
|
|
50872
51273
|
} catch {
|
|
50873
51274
|
}
|
|
50874
51275
|
}
|
|
50875
|
-
function reportLargeResponseToCloud(serverKey, responseBytes, agent) {
|
|
51276
|
+
function reportLargeResponseToCloud(serverKey, serverLabel, responseBytes, agent) {
|
|
50876
51277
|
try {
|
|
50877
51278
|
const creds = getCredentials();
|
|
50878
51279
|
if (!creds) return;
|
|
@@ -50881,7 +51282,7 @@ function reportLargeResponseToCloud(serverKey, responseBytes, agent) {
|
|
|
50881
51282
|
{ serverKey, responseBytes },
|
|
50882
51283
|
"mcp-large-response",
|
|
50883
51284
|
creds,
|
|
50884
|
-
{ mcpServer:
|
|
51285
|
+
{ mcpServer: serverLabel, agent },
|
|
50885
51286
|
void 0,
|
|
50886
51287
|
false,
|
|
50887
51288
|
{ mcpResponseBytes: responseBytes }
|
|
@@ -51118,7 +51519,12 @@ async function runMcpGateway(upstreamCommand, configName) {
|
|
|
51118
51519
|
const currentHash = hashToolDefinitions(tools);
|
|
51119
51520
|
const pinStatus = checkPin(serverKey, currentHash, gatewayCwd);
|
|
51120
51521
|
const token = getInternalToken();
|
|
51121
|
-
reportInventoryToCloud(
|
|
51522
|
+
reportInventoryToCloud(
|
|
51523
|
+
serverKey,
|
|
51524
|
+
resolveServerLabel("", serverKey, upstreamCommand, configName),
|
|
51525
|
+
tools.length,
|
|
51526
|
+
clientName
|
|
51527
|
+
);
|
|
51122
51528
|
if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
|
|
51123
51529
|
const toolSummary = tools.map((t) => ({ name: t.name, description: t.description }));
|
|
51124
51530
|
fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/mcp/discovered`, {
|
|
@@ -51190,7 +51596,11 @@ async function runMcpGateway(upstreamCommand, configName) {
|
|
|
51190
51596
|
console.error(import_chalk21.default.red(" Session quarantined \u2014 all tool calls blocked."));
|
|
51191
51597
|
console.error(import_chalk21.default.yellow(` Run: node9 mcp pin update ${serverKey}
|
|
51192
51598
|
`));
|
|
51193
|
-
reportPinMismatchToCloud(
|
|
51599
|
+
reportPinMismatchToCloud(
|
|
51600
|
+
serverKey,
|
|
51601
|
+
resolveServerLabel("", serverKey, upstreamCommand, configName),
|
|
51602
|
+
clientName
|
|
51603
|
+
);
|
|
51194
51604
|
const errorResponse = {
|
|
51195
51605
|
jsonrpc: "2.0",
|
|
51196
51606
|
id: parsed.id,
|
|
@@ -51236,7 +51646,12 @@ async function runMcpGateway(upstreamCommand, configName) {
|
|
|
51236
51646
|
`\u26A1 Node9: Large MCP response from '${toolName}' (${(line.length / 1024).toFixed(0)}KB) \u2014 context window enlarged`
|
|
51237
51647
|
)
|
|
51238
51648
|
);
|
|
51239
|
-
reportLargeResponseToCloud(
|
|
51649
|
+
reportLargeResponseToCloud(
|
|
51650
|
+
serverKey,
|
|
51651
|
+
resolveServerLabel("", serverKey, upstreamCommand, configName),
|
|
51652
|
+
line.length,
|
|
51653
|
+
clientName
|
|
51654
|
+
);
|
|
51240
51655
|
if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
|
|
51241
51656
|
const token = getInternalToken();
|
|
51242
51657
|
fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/mcp/large-response`, {
|
|
@@ -51287,18 +51702,18 @@ function registerMcpGatewayCommand(program2) {
|
|
|
51287
51702
|
|
|
51288
51703
|
// src/mcp-server/index.ts
|
|
51289
51704
|
var import_readline5 = __toESM(require("readline"));
|
|
51290
|
-
var
|
|
51291
|
-
var
|
|
51292
|
-
var
|
|
51705
|
+
var import_fs58 = __toESM(require("fs"));
|
|
51706
|
+
var import_os52 = __toESM(require("os"));
|
|
51707
|
+
var import_path56 = __toESM(require("path"));
|
|
51293
51708
|
var import_child_process11 = require("child_process");
|
|
51294
51709
|
init_core();
|
|
51295
51710
|
init_daemon();
|
|
51296
51711
|
init_shields();
|
|
51297
51712
|
|
|
51298
51713
|
// src/auth/egress-config.ts
|
|
51299
|
-
var
|
|
51300
|
-
var
|
|
51301
|
-
var
|
|
51714
|
+
var import_fs57 = __toESM(require("fs"));
|
|
51715
|
+
var import_os51 = __toESM(require("os"));
|
|
51716
|
+
var import_path55 = __toESM(require("path"));
|
|
51302
51717
|
var DEFAULT_EGRESS = {
|
|
51303
51718
|
enabled: false,
|
|
51304
51719
|
mode: "review",
|
|
@@ -51307,12 +51722,12 @@ var DEFAULT_EGRESS = {
|
|
|
51307
51722
|
allowPrivate: true
|
|
51308
51723
|
};
|
|
51309
51724
|
function egressConfigPath() {
|
|
51310
|
-
return
|
|
51725
|
+
return import_path55.default.join(import_os51.default.homedir(), ".node9", "config.json");
|
|
51311
51726
|
}
|
|
51312
51727
|
function readEgressRawConfig() {
|
|
51313
51728
|
let text;
|
|
51314
51729
|
try {
|
|
51315
|
-
text =
|
|
51730
|
+
text = import_fs57.default.readFileSync(egressConfigPath(), "utf8");
|
|
51316
51731
|
} catch (err2) {
|
|
51317
51732
|
if (err2.code === "ENOENT") return {};
|
|
51318
51733
|
throw err2;
|
|
@@ -51327,8 +51742,8 @@ function readEgressRawConfig() {
|
|
|
51327
51742
|
}
|
|
51328
51743
|
function writeEgressRawConfig(config) {
|
|
51329
51744
|
const p = egressConfigPath();
|
|
51330
|
-
|
|
51331
|
-
|
|
51745
|
+
import_fs57.default.mkdirSync(import_path55.default.dirname(p), { recursive: true });
|
|
51746
|
+
import_fs57.default.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
51332
51747
|
}
|
|
51333
51748
|
function applyEgress(config, change) {
|
|
51334
51749
|
const policy = config.policy = config.policy ?? {};
|
|
@@ -51713,13 +52128,13 @@ function handleStatus() {
|
|
|
51713
52128
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
51714
52129
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
51715
52130
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
51716
|
-
const projectConfig =
|
|
51717
|
-
const globalConfig =
|
|
52131
|
+
const projectConfig = import_path56.default.join(process.cwd(), "node9.config.json");
|
|
52132
|
+
const globalConfig = import_path56.default.join(import_os52.default.homedir(), ".node9", "config.json");
|
|
51718
52133
|
lines.push(
|
|
51719
|
-
`Project config (node9.config.json): ${
|
|
52134
|
+
`Project config (node9.config.json): ${import_fs58.default.existsSync(projectConfig) ? "present" : "not found"}`
|
|
51720
52135
|
);
|
|
51721
52136
|
lines.push(
|
|
51722
|
-
`Global config (~/.node9/config.json): ${
|
|
52137
|
+
`Global config (~/.node9/config.json): ${import_fs58.default.existsSync(globalConfig) ? "present" : "not found"}`
|
|
51723
52138
|
);
|
|
51724
52139
|
return lines.join("\n");
|
|
51725
52140
|
}
|
|
@@ -51825,21 +52240,21 @@ function handleEgressDeny(args) {
|
|
|
51825
52240
|
addEgressHost("deny", host);
|
|
51826
52241
|
return `Denied egress to ${host} (deny always wins over allow).`;
|
|
51827
52242
|
}
|
|
51828
|
-
var GLOBAL_CONFIG_PATH =
|
|
52243
|
+
var GLOBAL_CONFIG_PATH = import_path56.default.join(import_os52.default.homedir(), ".node9", "config.json");
|
|
51829
52244
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
51830
52245
|
function readGlobalConfigRaw() {
|
|
51831
52246
|
try {
|
|
51832
|
-
if (
|
|
51833
|
-
return JSON.parse(
|
|
52247
|
+
if (import_fs58.default.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
52248
|
+
return JSON.parse(import_fs58.default.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
|
|
51834
52249
|
}
|
|
51835
52250
|
} catch {
|
|
51836
52251
|
}
|
|
51837
52252
|
return {};
|
|
51838
52253
|
}
|
|
51839
52254
|
function writeGlobalConfigRaw(data) {
|
|
51840
|
-
const dir =
|
|
51841
|
-
if (!
|
|
51842
|
-
|
|
52255
|
+
const dir = import_path56.default.dirname(GLOBAL_CONFIG_PATH);
|
|
52256
|
+
if (!import_fs58.default.existsSync(dir)) import_fs58.default.mkdirSync(dir, { recursive: true });
|
|
52257
|
+
import_fs58.default.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
|
|
51843
52258
|
}
|
|
51844
52259
|
function handleApproverList() {
|
|
51845
52260
|
const config = getConfig();
|
|
@@ -51883,9 +52298,9 @@ function handleApproverSet(args) {
|
|
|
51883
52298
|
function handleAuditGet(args) {
|
|
51884
52299
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
51885
52300
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
51886
|
-
const auditPath =
|
|
51887
|
-
if (!
|
|
51888
|
-
const rawLines =
|
|
52301
|
+
const auditPath = import_path56.default.join(import_os52.default.homedir(), ".node9", "audit.log");
|
|
52302
|
+
if (!import_fs58.default.existsSync(auditPath)) return "No audit log found.";
|
|
52303
|
+
const rawLines = import_fs58.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
51889
52304
|
const parsed = [];
|
|
51890
52305
|
for (const line of rawLines) {
|
|
51891
52306
|
try {
|
|
@@ -52259,7 +52674,7 @@ function registerTrustCommand(program2) {
|
|
|
52259
52674
|
// src/cli/commands/mcp-pin.ts
|
|
52260
52675
|
var import_chalk24 = __toESM(require("chalk"));
|
|
52261
52676
|
init_mcp_pin();
|
|
52262
|
-
var
|
|
52677
|
+
var import_fs59 = __toESM(require("fs"));
|
|
52263
52678
|
|
|
52264
52679
|
// src/cli/commands/mcp-gateway-cmd.ts
|
|
52265
52680
|
var import_chalk23 = __toESM(require("chalk"));
|
|
@@ -52466,7 +52881,7 @@ function registerMcpPinCommand(program2) {
|
|
|
52466
52881
|
let repoCorrupt = false;
|
|
52467
52882
|
if (found.source === "repo") {
|
|
52468
52883
|
try {
|
|
52469
|
-
const raw =
|
|
52884
|
+
const raw = import_fs59.default.readFileSync(found.path, "utf-8");
|
|
52470
52885
|
const parsed = JSON.parse(raw);
|
|
52471
52886
|
repoEntries = parsed.servers ?? {};
|
|
52472
52887
|
} catch {
|
|
@@ -52966,8 +53381,8 @@ function registerPostureCommand(program2) {
|
|
|
52966
53381
|
var import_chalk30 = __toESM(require("chalk"));
|
|
52967
53382
|
|
|
52968
53383
|
// src/ci-check/fetch.ts
|
|
52969
|
-
var
|
|
52970
|
-
var
|
|
53384
|
+
var import_fs60 = __toESM(require("fs"));
|
|
53385
|
+
var import_path57 = __toESM(require("path"));
|
|
52971
53386
|
var import_node_child_process = require("child_process");
|
|
52972
53387
|
var import_undici = __toESM(require_undici());
|
|
52973
53388
|
var cachedGhToken;
|
|
@@ -53051,7 +53466,7 @@ function parseRepoUrl(input) {
|
|
|
53051
53466
|
function isLocalPath(input) {
|
|
53052
53467
|
if (input.startsWith(".") || input.startsWith("/") || input.startsWith("~")) return true;
|
|
53053
53468
|
try {
|
|
53054
|
-
return
|
|
53469
|
+
return import_fs60.default.existsSync(input) && import_fs60.default.statSync(input).isDirectory();
|
|
53055
53470
|
} catch {
|
|
53056
53471
|
return false;
|
|
53057
53472
|
}
|
|
@@ -53166,10 +53581,10 @@ function readLocalTree(dir) {
|
|
|
53166
53581
|
const files = [];
|
|
53167
53582
|
const notes = [];
|
|
53168
53583
|
const add = (rel) => {
|
|
53169
|
-
const abs =
|
|
53584
|
+
const abs = import_path57.default.join(root, rel);
|
|
53170
53585
|
try {
|
|
53171
|
-
if (
|
|
53172
|
-
files.push({ path: rel, content:
|
|
53586
|
+
if (import_fs60.default.existsSync(abs) && import_fs60.default.statSync(abs).isFile()) {
|
|
53587
|
+
files.push({ path: rel, content: import_fs60.default.readFileSync(abs, "utf8") });
|
|
53173
53588
|
}
|
|
53174
53589
|
} catch {
|
|
53175
53590
|
}
|
|
@@ -53189,7 +53604,7 @@ function readLocalTree(dir) {
|
|
|
53189
53604
|
dirsVisited++;
|
|
53190
53605
|
let entries;
|
|
53191
53606
|
try {
|
|
53192
|
-
entries =
|
|
53607
|
+
entries = import_fs60.default.readdirSync(import_path57.default.join(root, relDir), { withFileTypes: true });
|
|
53193
53608
|
} catch {
|
|
53194
53609
|
return;
|
|
53195
53610
|
}
|
|
@@ -53210,11 +53625,11 @@ function readLocalTree(dir) {
|
|
|
53210
53625
|
`repo is large \u2014 some agent-surface files may be INCOMPLETE (capped at ${MAX_SURFACE_FILES} files / ${MAX_DIRS} dirs).`
|
|
53211
53626
|
);
|
|
53212
53627
|
for (const rel of matches) collect(rel);
|
|
53213
|
-
const wfDir =
|
|
53628
|
+
const wfDir = import_path57.default.join(root, WORKFLOW_DIR);
|
|
53214
53629
|
try {
|
|
53215
|
-
if (
|
|
53216
|
-
for (const name of
|
|
53217
|
-
if (/\.ya?ml$/.test(name)) add(
|
|
53630
|
+
if (import_fs60.default.existsSync(wfDir)) {
|
|
53631
|
+
for (const name of import_fs60.default.readdirSync(wfDir)) {
|
|
53632
|
+
if (/\.ya?ml$/.test(name)) add(import_path57.default.join(WORKFLOW_DIR, name));
|
|
53218
53633
|
}
|
|
53219
53634
|
}
|
|
53220
53635
|
} catch {
|
|
@@ -53487,7 +53902,7 @@ function severityFromScore(score) {
|
|
|
53487
53902
|
if (score >= 1) return "advisory";
|
|
53488
53903
|
return null;
|
|
53489
53904
|
}
|
|
53490
|
-
function analyzeWorkflow(
|
|
53905
|
+
function analyzeWorkflow(path71, content) {
|
|
53491
53906
|
let raw;
|
|
53492
53907
|
try {
|
|
53493
53908
|
raw = (0, import_yaml.parse)(content) ?? {};
|
|
@@ -53608,7 +54023,7 @@ function analyzeWorkflow(path70, content) {
|
|
|
53608
54023
|
dimension: "workflows",
|
|
53609
54024
|
severity,
|
|
53610
54025
|
title,
|
|
53611
|
-
file:
|
|
54026
|
+
file: path71,
|
|
53612
54027
|
signals,
|
|
53613
54028
|
mitigations: mitigations.length ? mitigations : void 0,
|
|
53614
54029
|
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."
|
|
@@ -53684,7 +54099,7 @@ function evalAgentJob(job, wf, raw, untrustedTrigger, reusable) {
|
|
|
53684
54099
|
if (reusable && !loadedGun && SEVERITY_RANK2[severity] > SEVERITY_RANK2.medium) severity = "medium";
|
|
53685
54100
|
return { severity, secrets, injectable, canReadEnv };
|
|
53686
54101
|
}
|
|
53687
|
-
function analyzeWorkflowSecrets(
|
|
54102
|
+
function analyzeWorkflowSecrets(path71, content) {
|
|
53688
54103
|
let raw;
|
|
53689
54104
|
try {
|
|
53690
54105
|
raw = (0, import_yaml.parse)(content) ?? {};
|
|
@@ -53704,7 +54119,7 @@ function analyzeWorkflowSecrets(path70, content) {
|
|
|
53704
54119
|
dimension: "data",
|
|
53705
54120
|
severity: worst.severity,
|
|
53706
54121
|
title: worst.severity === "advisory" ? "Secrets reachable by the agent \u2014 hardening" : "Exfiltratable secrets reachable by an injectable agent",
|
|
53707
|
-
file:
|
|
54122
|
+
file: path71,
|
|
53708
54123
|
signals: [
|
|
53709
54124
|
`agent can reach: ${worst.secrets.map((s) => s.name).join(", ")}`,
|
|
53710
54125
|
worst.injectable ? "the agent is externally triggerable (untrusted trigger, no gate)" : "gated / not externally triggerable \u2014 latent risk only",
|
|
@@ -53731,7 +54146,7 @@ function hookCommands(hooks) {
|
|
|
53731
54146
|
}
|
|
53732
54147
|
return out;
|
|
53733
54148
|
}
|
|
53734
|
-
function analyzeAgentConfig(
|
|
54149
|
+
function analyzeAgentConfig(path71, content) {
|
|
53735
54150
|
let cfg;
|
|
53736
54151
|
try {
|
|
53737
54152
|
cfg = JSON.parse(content);
|
|
@@ -53750,7 +54165,7 @@ function analyzeAgentConfig(path70, content) {
|
|
|
53750
54165
|
dimension: "toolRules",
|
|
53751
54166
|
severity: high ? "high" : "medium",
|
|
53752
54167
|
title: high ? "Agent hook runs UNPINNED/remote third-party code on every action" : "Agent hook runs third-party code in the agent hot path",
|
|
53753
|
-
file:
|
|
54168
|
+
file: path71,
|
|
53754
54169
|
signals: [
|
|
53755
54170
|
`hook command: \`${cmd.slice(0, 120)}\``,
|
|
53756
54171
|
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"
|
|
@@ -53770,7 +54185,7 @@ function analyzeAgentConfig(path70, content) {
|
|
|
53770
54185
|
dimension: "toolRules",
|
|
53771
54186
|
severity: hasBackstop ? "medium" : "high",
|
|
53772
54187
|
title: hasBackstop ? "Committed agent config pre-authorizes broad tools" : "Committed agent config pre-authorizes broad tools with no deny backstop",
|
|
53773
|
-
file:
|
|
54188
|
+
file: path71,
|
|
53774
54189
|
signals: [
|
|
53775
54190
|
`broad allow(s): ${broad.slice(0, 5).join(", ")}`,
|
|
53776
54191
|
hasBackstop ? "a `deny` list backstops the broad allow" : "no `deny` entry covers Bash/Write/Edit \u2014 every contributor is pre-authorized for catastrophic tools"
|
|
@@ -53783,16 +54198,16 @@ function analyzeAgentConfig(path70, content) {
|
|
|
53783
54198
|
|
|
53784
54199
|
// src/ci-check/mcp.ts
|
|
53785
54200
|
init_dist();
|
|
53786
|
-
function analyzeMcp(
|
|
54201
|
+
function analyzeMcp(path71, content) {
|
|
53787
54202
|
let cfg;
|
|
53788
54203
|
try {
|
|
53789
54204
|
cfg = JSON.parse(content);
|
|
53790
54205
|
} catch {
|
|
53791
54206
|
return [];
|
|
53792
54207
|
}
|
|
53793
|
-
return analyzeMcpServers(cfg.mcpServers ?? {},
|
|
54208
|
+
return analyzeMcpServers(cfg.mcpServers ?? {}, path71);
|
|
53794
54209
|
}
|
|
53795
|
-
function analyzeMcpServers(servers,
|
|
54210
|
+
function analyzeMcpServers(servers, path71) {
|
|
53796
54211
|
const findings = [];
|
|
53797
54212
|
for (const [name, srv] of Object.entries(servers ?? {})) {
|
|
53798
54213
|
if (!srv || srv.disabled) continue;
|
|
@@ -53803,7 +54218,7 @@ function analyzeMcpServers(servers, path70) {
|
|
|
53803
54218
|
dimension: "mcp",
|
|
53804
54219
|
severity: "medium",
|
|
53805
54220
|
title: `MCP server "${name}" runs an unpinned executable`,
|
|
53806
|
-
file:
|
|
54221
|
+
file: path71,
|
|
53807
54222
|
signals: [`\`${argv.slice(0, 120)}\` \u2014 unversioned/@latest npx`],
|
|
53808
54223
|
fix: "Pin the MCP server package to an exact version so a PR (or a registry compromise) can\u2019t swap the toolchain."
|
|
53809
54224
|
});
|
|
@@ -53817,7 +54232,7 @@ function analyzeMcpServers(servers, path70) {
|
|
|
53817
54232
|
dimension: "mcp",
|
|
53818
54233
|
severity: "high",
|
|
53819
54234
|
title: `MCP server "${name}" has an inline credential`,
|
|
53820
|
-
file:
|
|
54235
|
+
file: path71,
|
|
53821
54236
|
signals: [
|
|
53822
54237
|
`env.${k} matches ${hit.patternName} \u2014 agent-reachable secret committed to the repo`
|
|
53823
54238
|
],
|
|
@@ -53831,7 +54246,7 @@ function analyzeMcpServers(servers, path70) {
|
|
|
53831
54246
|
|
|
53832
54247
|
// src/ci-check/codex.ts
|
|
53833
54248
|
var import_smol_toml5 = require("smol-toml");
|
|
53834
|
-
function analyzeCodexConfig(
|
|
54249
|
+
function analyzeCodexConfig(path71, content) {
|
|
53835
54250
|
let cfg;
|
|
53836
54251
|
try {
|
|
53837
54252
|
cfg = (0, import_smol_toml5.parse)(content);
|
|
@@ -53839,7 +54254,7 @@ function analyzeCodexConfig(path70, content) {
|
|
|
53839
54254
|
return [];
|
|
53840
54255
|
}
|
|
53841
54256
|
const findings = [];
|
|
53842
|
-
findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {},
|
|
54257
|
+
findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {}, path71));
|
|
53843
54258
|
const sandbox = typeof cfg.sandbox_mode === "string" ? cfg.sandbox_mode : "";
|
|
53844
54259
|
const approval = typeof cfg.approval_policy === "string" ? cfg.approval_policy : "";
|
|
53845
54260
|
const fullAccess = /danger-full-access/i.test(sandbox);
|
|
@@ -53854,7 +54269,7 @@ function analyzeCodexConfig(path70, content) {
|
|
|
53854
54269
|
dimension: "toolRules",
|
|
53855
54270
|
severity: fullAccess ? "high" : "medium",
|
|
53856
54271
|
title: fullAccess ? "Codex config grants a full-access sandbox" : "Codex config never requires approval",
|
|
53857
|
-
file:
|
|
54272
|
+
file: path71,
|
|
53858
54273
|
signals,
|
|
53859
54274
|
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.'
|
|
53860
54275
|
});
|
|
@@ -53910,10 +54325,10 @@ function decodeSuspiciousBase64(text) {
|
|
|
53910
54325
|
}
|
|
53911
54326
|
return out;
|
|
53912
54327
|
}
|
|
53913
|
-
function mk(severity, title, signals, fix,
|
|
53914
|
-
return { check: "CI-6", dimension: "instructions", severity, title, file:
|
|
54328
|
+
function mk(severity, title, signals, fix, path71) {
|
|
54329
|
+
return { check: "CI-6", dimension: "instructions", severity, title, file: path71, signals, fix };
|
|
53915
54330
|
}
|
|
53916
|
-
function analyzeInstructionFile(
|
|
54331
|
+
function analyzeInstructionFile(path71, content) {
|
|
53917
54332
|
const findings = [];
|
|
53918
54333
|
const decoded = decodeSuspiciousBase64(content);
|
|
53919
54334
|
if (TAG_CHARS.test(content))
|
|
@@ -53925,7 +54340,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
53925
54340
|
"contains Unicode tag characters (U+E0000\u2013E007F) \u2014 an invisible instruction-smuggling channel with no legitimate use in text"
|
|
53926
54341
|
],
|
|
53927
54342
|
"Remove the tag characters. Instruction files must be plain, reviewable text.",
|
|
53928
|
-
|
|
54343
|
+
path71
|
|
53929
54344
|
)
|
|
53930
54345
|
);
|
|
53931
54346
|
if (BIDI_OVERRIDE.test(content))
|
|
@@ -53937,7 +54352,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
53937
54352
|
"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"
|
|
53938
54353
|
],
|
|
53939
54354
|
"Remove the bidi override characters.",
|
|
53940
|
-
|
|
54355
|
+
path71
|
|
53941
54356
|
)
|
|
53942
54357
|
);
|
|
53943
54358
|
else if (BIDI_EMBED_ISOLATE.test(content))
|
|
@@ -53949,7 +54364,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
53949
54364
|
"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"
|
|
53950
54365
|
],
|
|
53951
54366
|
"Confirm the bidi marks are legitimate RTL formatting; remove otherwise.",
|
|
53952
|
-
|
|
54367
|
+
path71
|
|
53953
54368
|
)
|
|
53954
54369
|
);
|
|
53955
54370
|
const zw = suspiciousZeroWidth(content);
|
|
@@ -53963,7 +54378,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
53963
54378
|
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)"
|
|
53964
54379
|
],
|
|
53965
54380
|
"Remove the zero-width characters. Instruction files must be plain, reviewable text.",
|
|
53966
|
-
|
|
54381
|
+
path71
|
|
53967
54382
|
)
|
|
53968
54383
|
);
|
|
53969
54384
|
}
|
|
@@ -53979,7 +54394,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
53979
54394
|
`contains a prompt-override / role-impersonation directive (\`${m[0].slice(0, 60).trim()}\`)${ovEnc ? " \u2014 concealed in a base64 blob" : ""}`
|
|
53980
54395
|
],
|
|
53981
54396
|
"Remove the override text. An instruction file should not tell the agent to ignore its own rules.",
|
|
53982
|
-
|
|
54397
|
+
path71
|
|
53983
54398
|
)
|
|
53984
54399
|
);
|
|
53985
54400
|
}
|
|
@@ -53991,7 +54406,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
53991
54406
|
"Instruction directs the agent to fetch and run remote code",
|
|
53992
54407
|
[`\`${fo[0].slice(0, 70).trim()}\` \u2014 fetch-and-obey, outside an install/setup section`],
|
|
53993
54408
|
"Do not instruct the agent to pipe remote content into a shell; pin and vendor scripts instead.",
|
|
53994
|
-
|
|
54409
|
+
path71
|
|
53995
54410
|
)
|
|
53996
54411
|
);
|
|
53997
54412
|
}
|
|
@@ -54003,7 +54418,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
54003
54418
|
"Instruction points the agent at credential material",
|
|
54004
54419
|
[`references \`${sp[0].slice(0, 50).trim()}\` \u2014 directs the agent toward secrets`],
|
|
54005
54420
|
"Do not reference credential files or paths in agent instructions.",
|
|
54006
|
-
|
|
54421
|
+
path71
|
|
54007
54422
|
)
|
|
54008
54423
|
);
|
|
54009
54424
|
}
|
|
@@ -54015,7 +54430,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
54015
54430
|
"Instruction directs the agent to send data to an external endpoint",
|
|
54016
54431
|
[`\`${ex[0].slice(0, 70).trim()}\` \u2014 possible exfiltration directive`],
|
|
54017
54432
|
"Remove external post/upload directives from agent instructions.",
|
|
54018
|
-
|
|
54433
|
+
path71
|
|
54019
54434
|
)
|
|
54020
54435
|
);
|
|
54021
54436
|
}
|
|
@@ -54315,19 +54730,19 @@ function registerEgressCommand(program2) {
|
|
|
54315
54730
|
var import_chalk32 = __toESM(require("chalk"));
|
|
54316
54731
|
|
|
54317
54732
|
// src/shields/jail.ts
|
|
54318
|
-
var
|
|
54319
|
-
var
|
|
54320
|
-
var
|
|
54733
|
+
var import_fs61 = __toESM(require("fs"));
|
|
54734
|
+
var import_os53 = __toESM(require("os"));
|
|
54735
|
+
var import_path58 = __toESM(require("path"));
|
|
54321
54736
|
init_build();
|
|
54322
54737
|
init_shields();
|
|
54323
54738
|
var USER_JAIL_SHIELD = "user-jail";
|
|
54324
54739
|
function jailStorePath() {
|
|
54325
|
-
return
|
|
54740
|
+
return import_path58.default.join(import_os53.default.homedir(), ".node9", "jail-paths.json");
|
|
54326
54741
|
}
|
|
54327
54742
|
function readJailPaths() {
|
|
54328
54743
|
let text;
|
|
54329
54744
|
try {
|
|
54330
|
-
text =
|
|
54745
|
+
text = import_fs61.default.readFileSync(jailStorePath(), "utf8");
|
|
54331
54746
|
} catch (err2) {
|
|
54332
54747
|
if (err2.code === "ENOENT") return [];
|
|
54333
54748
|
throw err2;
|
|
@@ -54345,8 +54760,8 @@ function readJailPaths() {
|
|
|
54345
54760
|
}
|
|
54346
54761
|
function writeJailPaths(paths) {
|
|
54347
54762
|
const p = jailStorePath();
|
|
54348
|
-
|
|
54349
|
-
|
|
54763
|
+
import_fs61.default.mkdirSync(import_path58.default.dirname(p), { recursive: true });
|
|
54764
|
+
import_fs61.default.writeFileSync(p, JSON.stringify({ paths }, null, 2) + "\n", { mode: 384 });
|
|
54350
54765
|
}
|
|
54351
54766
|
function addJailPath(rawPath, verdict) {
|
|
54352
54767
|
const norm = rawPath.trim();
|
|
@@ -54368,14 +54783,14 @@ function removeJailPath(rawPath) {
|
|
|
54368
54783
|
return { removed, paths: after };
|
|
54369
54784
|
}
|
|
54370
54785
|
function regenerateUserJail(paths) {
|
|
54371
|
-
const file =
|
|
54786
|
+
const file = import_path58.default.join(USER_SHIELDS_DIR_PATH, `${USER_JAIL_SHIELD}.json`);
|
|
54372
54787
|
if (paths.length === 0) {
|
|
54373
54788
|
const active2 = readActiveShields();
|
|
54374
54789
|
if (active2.includes(USER_JAIL_SHIELD)) {
|
|
54375
54790
|
writeActiveShields(active2.filter((s) => s !== USER_JAIL_SHIELD));
|
|
54376
54791
|
}
|
|
54377
54792
|
try {
|
|
54378
|
-
|
|
54793
|
+
import_fs61.default.rmSync(file, { force: true });
|
|
54379
54794
|
} catch {
|
|
54380
54795
|
}
|
|
54381
54796
|
return;
|
|
@@ -54489,14 +54904,14 @@ function registerJailCommand(program2) {
|
|
|
54489
54904
|
|
|
54490
54905
|
// src/cli/commands/sandbox.ts
|
|
54491
54906
|
var import_chalk33 = __toESM(require("chalk"));
|
|
54492
|
-
var
|
|
54493
|
-
var
|
|
54907
|
+
var import_fs64 = __toESM(require("fs"));
|
|
54908
|
+
var import_path61 = __toESM(require("path"));
|
|
54494
54909
|
var import_child_process13 = require("child_process");
|
|
54495
54910
|
init_config();
|
|
54496
54911
|
|
|
54497
54912
|
// src/sandbox/config.ts
|
|
54498
|
-
var
|
|
54499
|
-
var
|
|
54913
|
+
var import_fs62 = __toESM(require("fs"));
|
|
54914
|
+
var import_path59 = __toESM(require("path"));
|
|
54500
54915
|
var import_yaml2 = require("yaml");
|
|
54501
54916
|
var SANDBOX_CONFIG_FILE = "node9.sandbox.yaml";
|
|
54502
54917
|
var FORBIDDEN_ENV = /* @__PURE__ */ new Set(["NODE9_API_KEY", "NODE9_API_URL"]);
|
|
@@ -54569,16 +54984,16 @@ function scaffoldSandboxYaml(agent) {
|
|
|
54569
54984
|
return header + (0, import_yaml2.stringify)(defaultSandboxConfig(agent));
|
|
54570
54985
|
}
|
|
54571
54986
|
function sandboxConfigPath(cwd = process.cwd()) {
|
|
54572
|
-
return
|
|
54987
|
+
return import_path59.default.join(cwd, SANDBOX_CONFIG_FILE);
|
|
54573
54988
|
}
|
|
54574
54989
|
function loadSandboxConfig(cwd = process.cwd(), fallbackAgent = "claude") {
|
|
54575
54990
|
const p = sandboxConfigPath(cwd);
|
|
54576
|
-
if (!
|
|
54991
|
+
if (!import_fs62.default.existsSync(p)) {
|
|
54577
54992
|
throw new Error(`sandbox: ${SANDBOX_CONFIG_FILE} not found \u2014 run \`node9 sandbox new\` first.`);
|
|
54578
54993
|
}
|
|
54579
54994
|
let raw;
|
|
54580
54995
|
try {
|
|
54581
|
-
raw = (0, import_yaml2.parse)(
|
|
54996
|
+
raw = (0, import_yaml2.parse)(import_fs62.default.readFileSync(p, "utf-8"));
|
|
54582
54997
|
} catch (err2) {
|
|
54583
54998
|
throw new Error(
|
|
54584
54999
|
`sandbox: ${SANDBOX_CONFIG_FILE} is not valid YAML \u2014 ${err2.message}`
|
|
@@ -54636,14 +55051,14 @@ function compileAllowlist(input) {
|
|
|
54636
55051
|
init_templates();
|
|
54637
55052
|
|
|
54638
55053
|
// src/sandbox/runtime.ts
|
|
54639
|
-
var
|
|
54640
|
-
var
|
|
54641
|
-
var
|
|
55054
|
+
var import_fs63 = __toESM(require("fs"));
|
|
55055
|
+
var import_os54 = __toESM(require("os"));
|
|
55056
|
+
var import_path60 = __toESM(require("path"));
|
|
54642
55057
|
var import_crypto14 = __toESM(require("crypto"));
|
|
54643
55058
|
var import_child_process12 = require("child_process");
|
|
54644
55059
|
init_templates();
|
|
54645
55060
|
function sandboxDataDir(cwd = process.cwd()) {
|
|
54646
|
-
return
|
|
55061
|
+
return import_path60.default.join(cwd, ".node9", "sandbox", "data");
|
|
54647
55062
|
}
|
|
54648
55063
|
function detectEngine(engine) {
|
|
54649
55064
|
const r = (0, import_child_process12.spawnSync)(engine, ["--version"], { encoding: "utf-8" });
|
|
@@ -54654,7 +55069,7 @@ function detectEngine(engine) {
|
|
|
54654
55069
|
}
|
|
54655
55070
|
function agentCredentialsMount(agent) {
|
|
54656
55071
|
const rel = agent === "codex" ? ".codex/auth.json" : ".claude/.credentials.json";
|
|
54657
|
-
return { hostPath:
|
|
55072
|
+
return { hostPath: import_path60.default.join(import_os54.default.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
|
|
54658
55073
|
}
|
|
54659
55074
|
function buildRunArgs(opts) {
|
|
54660
55075
|
const { config, workspaceHostPath, dataHostPath, allowlistHostPath, agentArgs } = opts;
|
|
@@ -54664,7 +55079,7 @@ function buildRunArgs(opts) {
|
|
|
54664
55079
|
args.push("-v", `${allowlistHostPath}:${ALLOWED_DOMAINS_PATH}:ro`);
|
|
54665
55080
|
if (config.node9.mountAgentCredentials) {
|
|
54666
55081
|
const creds = agentCredentialsMount(config.agent);
|
|
54667
|
-
if (
|
|
55082
|
+
if (import_fs63.default.existsSync(creds.hostPath)) {
|
|
54668
55083
|
args.push("-v", `${creds.hostPath}:${creds.target}`);
|
|
54669
55084
|
}
|
|
54670
55085
|
}
|
|
@@ -54682,30 +55097,30 @@ function imageContentHash(dockerfile, entrypoint) {
|
|
|
54682
55097
|
return import_crypto14.default.createHash("sha256").update(dockerfile).update("\0").update(entrypoint).digest("hex").slice(0, 16);
|
|
54683
55098
|
}
|
|
54684
55099
|
function sandboxBuildDir(cwd = process.cwd()) {
|
|
54685
|
-
return
|
|
55100
|
+
return import_path60.default.join(cwd, ".node9", "sandbox", "build");
|
|
54686
55101
|
}
|
|
54687
55102
|
function writeBuildContext(cwd, dockerfile, entrypoint) {
|
|
54688
55103
|
const dir = sandboxBuildDir(cwd);
|
|
54689
|
-
|
|
54690
|
-
|
|
54691
|
-
|
|
55104
|
+
import_fs63.default.mkdirSync(dir, { recursive: true });
|
|
55105
|
+
import_fs63.default.writeFileSync(import_path60.default.join(dir, "Dockerfile"), dockerfile);
|
|
55106
|
+
import_fs63.default.writeFileSync(import_path60.default.join(dir, "entrypoint.sh"), entrypoint);
|
|
54692
55107
|
return dir;
|
|
54693
55108
|
}
|
|
54694
55109
|
function writeAllowlist(cwd, hosts) {
|
|
54695
|
-
const dir =
|
|
54696
|
-
|
|
54697
|
-
const p =
|
|
54698
|
-
|
|
55110
|
+
const dir = import_path60.default.join(cwd, ".node9", "sandbox");
|
|
55111
|
+
import_fs63.default.mkdirSync(dir, { recursive: true });
|
|
55112
|
+
const p = import_path60.default.join(dir, "allowed-domains.txt");
|
|
55113
|
+
import_fs63.default.writeFileSync(p, hosts.join("\n") + "\n");
|
|
54699
55114
|
return p;
|
|
54700
55115
|
}
|
|
54701
55116
|
function resolveHomePath(p) {
|
|
54702
|
-
return p.startsWith("~") ?
|
|
55117
|
+
return p.startsWith("~") ? import_path60.default.join(import_os54.default.homedir(), p.slice(1)) : import_path60.default.resolve(p);
|
|
54703
55118
|
}
|
|
54704
55119
|
|
|
54705
55120
|
// src/cli/commands/sandbox.ts
|
|
54706
55121
|
function seedDataDirConfig(dataDir, sandbox) {
|
|
54707
|
-
|
|
54708
|
-
const configPath =
|
|
55122
|
+
import_fs64.default.mkdirSync(dataDir, { recursive: true });
|
|
55123
|
+
const configPath = import_path61.default.join(dataDir, "config.json");
|
|
54709
55124
|
const seed = {
|
|
54710
55125
|
settings: {
|
|
54711
55126
|
approvers: {
|
|
@@ -54716,7 +55131,7 @@ function seedDataDirConfig(dataDir, sandbox) {
|
|
|
54716
55131
|
}
|
|
54717
55132
|
}
|
|
54718
55133
|
};
|
|
54719
|
-
|
|
55134
|
+
import_fs64.default.writeFileSync(configPath, JSON.stringify(seed, null, 2), { mode: 384 });
|
|
54720
55135
|
}
|
|
54721
55136
|
function registerSandboxCommand(program2, version2) {
|
|
54722
55137
|
const node9Version2 = pinnedNode9Version(version2);
|
|
@@ -54724,13 +55139,13 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54724
55139
|
cmd.command("new").description(`Scaffold ${SANDBOX_CONFIG_FILE} in this project`).option("--agent <agent>", "claude (default) or codex", "claude").action((opts) => {
|
|
54725
55140
|
const agent = opts.agent === "codex" ? "codex" : "claude";
|
|
54726
55141
|
const p = sandboxConfigPath();
|
|
54727
|
-
if (
|
|
55142
|
+
if (import_fs64.default.existsSync(p)) {
|
|
54728
55143
|
console.log(
|
|
54729
55144
|
import_chalk33.default.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
|
|
54730
55145
|
);
|
|
54731
55146
|
return;
|
|
54732
55147
|
}
|
|
54733
|
-
|
|
55148
|
+
import_fs64.default.writeFileSync(p, scaffoldSandboxYaml(agent));
|
|
54734
55149
|
console.log(
|
|
54735
55150
|
import_chalk33.default.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + import_chalk33.default.dim(` (agent: ${agent})`)
|
|
54736
55151
|
);
|
|
@@ -54770,8 +55185,8 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54770
55185
|
const buildDir = writeBuildContext(cwd, dockerfile, entrypoint);
|
|
54771
55186
|
const hash = imageContentHash(dockerfile, entrypoint);
|
|
54772
55187
|
const image = sandbox.runtime.image;
|
|
54773
|
-
const hashFile =
|
|
54774
|
-
const lastHash =
|
|
55188
|
+
const hashFile = import_path61.default.join(sandboxBuildDir(cwd), ".image-hash");
|
|
55189
|
+
const lastHash = import_fs64.default.existsSync(hashFile) ? import_fs64.default.readFileSync(hashFile, "utf-8").trim() : "";
|
|
54775
55190
|
const imageExists = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
|
|
54776
55191
|
const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
|
|
54777
55192
|
if (needBuild) {
|
|
@@ -54783,7 +55198,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54783
55198
|
console.error(import_chalk33.default.red(" build failed."));
|
|
54784
55199
|
process.exit(b.status ?? 1);
|
|
54785
55200
|
}
|
|
54786
|
-
|
|
55201
|
+
import_fs64.default.writeFileSync(hashFile, hash);
|
|
54787
55202
|
}
|
|
54788
55203
|
const dataDir = sandboxDataDir(cwd);
|
|
54789
55204
|
seedDataDirConfig(dataDir, sandbox);
|
|
@@ -54797,7 +55212,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54797
55212
|
});
|
|
54798
55213
|
if (sandbox.node9.mountAgentCredentials) {
|
|
54799
55214
|
const creds = agentCredentialsMount(sandbox.agent);
|
|
54800
|
-
if (
|
|
55215
|
+
if (import_fs64.default.existsSync(creds.hostPath)) {
|
|
54801
55216
|
console.log(import_chalk33.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
|
|
54802
55217
|
} else {
|
|
54803
55218
|
console.log(
|
|
@@ -54813,20 +55228,20 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54813
55228
|
process.exit(r.status ?? 0);
|
|
54814
55229
|
});
|
|
54815
55230
|
cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
|
|
54816
|
-
const auditPath =
|
|
54817
|
-
if (!
|
|
55231
|
+
const auditPath = import_path61.default.join(sandboxDataDir(), "audit.log");
|
|
55232
|
+
if (!import_fs64.default.existsSync(auditPath)) {
|
|
54818
55233
|
console.log(import_chalk33.default.dim(" no sandbox audit yet."));
|
|
54819
55234
|
return;
|
|
54820
55235
|
}
|
|
54821
55236
|
(0, import_child_process13.spawnSync)("tail", ["-f", auditPath], { stdio: "inherit" });
|
|
54822
55237
|
});
|
|
54823
55238
|
cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
|
|
54824
|
-
const auditPath =
|
|
54825
|
-
if (!
|
|
55239
|
+
const auditPath = import_path61.default.join(sandboxDataDir(), "audit.log");
|
|
55240
|
+
if (!import_fs64.default.existsSync(auditPath)) {
|
|
54826
55241
|
console.log(import_chalk33.default.dim(" no sandbox audit yet."));
|
|
54827
55242
|
return;
|
|
54828
55243
|
}
|
|
54829
|
-
process.stdout.write(
|
|
55244
|
+
process.stdout.write(import_fs64.default.readFileSync(auditPath, "utf-8"));
|
|
54830
55245
|
});
|
|
54831
55246
|
cmd.command("clean").description("Remove the sandbox image, build context, and data").action(() => {
|
|
54832
55247
|
const cwd = process.cwd();
|
|
@@ -54840,16 +55255,16 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54840
55255
|
stdio: "ignore"
|
|
54841
55256
|
});
|
|
54842
55257
|
}
|
|
54843
|
-
|
|
55258
|
+
import_fs64.default.rmSync(import_path61.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
|
|
54844
55259
|
console.log(import_chalk33.default.green(" \u2713 sandbox image + build + data removed."));
|
|
54845
55260
|
});
|
|
54846
55261
|
}
|
|
54847
55262
|
|
|
54848
55263
|
// src/cli/commands/sessions.ts
|
|
54849
55264
|
var import_chalk34 = __toESM(require("chalk"));
|
|
54850
|
-
var
|
|
54851
|
-
var
|
|
54852
|
-
var
|
|
55265
|
+
var import_fs65 = __toESM(require("fs"));
|
|
55266
|
+
var import_path62 = __toESM(require("path"));
|
|
55267
|
+
var import_os55 = __toESM(require("os"));
|
|
54853
55268
|
init_scan_summary();
|
|
54854
55269
|
init_litellm();
|
|
54855
55270
|
init_cost_gemini();
|
|
@@ -54870,10 +55285,10 @@ function encodeProjectPath(projectPath) {
|
|
|
54870
55285
|
}
|
|
54871
55286
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
54872
55287
|
const encoded = encodeProjectPath(projectPath);
|
|
54873
|
-
return
|
|
55288
|
+
return import_path62.default.join(import_os55.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
54874
55289
|
}
|
|
54875
55290
|
function projectLabel(projectPath) {
|
|
54876
|
-
return projectPath.replace(
|
|
55291
|
+
return projectPath.replace(import_os55.default.homedir(), "~");
|
|
54877
55292
|
}
|
|
54878
55293
|
function parseHistoryLines(lines) {
|
|
54879
55294
|
const entries = [];
|
|
@@ -54942,10 +55357,10 @@ function parseSessionLines(lines) {
|
|
|
54942
55357
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
54943
55358
|
}
|
|
54944
55359
|
function loadAuditEntries(auditPath) {
|
|
54945
|
-
const aPath = auditPath ??
|
|
55360
|
+
const aPath = auditPath ?? import_path62.default.join(import_os55.default.homedir(), ".node9", "audit.log");
|
|
54946
55361
|
let raw;
|
|
54947
55362
|
try {
|
|
54948
|
-
raw =
|
|
55363
|
+
raw = import_fs65.default.readFileSync(aPath, "utf-8");
|
|
54949
55364
|
} catch {
|
|
54950
55365
|
return [];
|
|
54951
55366
|
}
|
|
@@ -54981,8 +55396,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
54981
55396
|
return result;
|
|
54982
55397
|
}
|
|
54983
55398
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
54984
|
-
const tmpDir =
|
|
54985
|
-
if (!
|
|
55399
|
+
const tmpDir = import_path62.default.join(import_os55.default.homedir(), ".gemini", "tmp");
|
|
55400
|
+
if (!import_fs65.default.existsSync(tmpDir)) return [];
|
|
54986
55401
|
const cutoff = days !== null ? (() => {
|
|
54987
55402
|
const d = /* @__PURE__ */ new Date();
|
|
54988
55403
|
d.setDate(d.getDate() - days);
|
|
@@ -54991,35 +55406,35 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
54991
55406
|
})() : null;
|
|
54992
55407
|
let slugDirs;
|
|
54993
55408
|
try {
|
|
54994
|
-
slugDirs =
|
|
55409
|
+
slugDirs = import_fs65.default.readdirSync(tmpDir);
|
|
54995
55410
|
} catch {
|
|
54996
55411
|
return [];
|
|
54997
55412
|
}
|
|
54998
55413
|
const summaries = [];
|
|
54999
55414
|
for (const slug2 of slugDirs) {
|
|
55000
|
-
const slugPath =
|
|
55415
|
+
const slugPath = import_path62.default.join(tmpDir, slug2);
|
|
55001
55416
|
try {
|
|
55002
|
-
if (!
|
|
55417
|
+
if (!import_fs65.default.statSync(slugPath).isDirectory()) continue;
|
|
55003
55418
|
} catch {
|
|
55004
55419
|
continue;
|
|
55005
55420
|
}
|
|
55006
|
-
let projectRoot =
|
|
55421
|
+
let projectRoot = import_path62.default.join(import_os55.default.homedir(), slug2);
|
|
55007
55422
|
try {
|
|
55008
|
-
projectRoot =
|
|
55423
|
+
projectRoot = import_fs65.default.readFileSync(import_path62.default.join(slugPath, ".project_root"), "utf-8").trim();
|
|
55009
55424
|
} catch {
|
|
55010
55425
|
}
|
|
55011
|
-
const chatsDir =
|
|
55012
|
-
if (!
|
|
55426
|
+
const chatsDir = import_path62.default.join(slugPath, "chats");
|
|
55427
|
+
if (!import_fs65.default.existsSync(chatsDir)) continue;
|
|
55013
55428
|
let chatFiles;
|
|
55014
55429
|
try {
|
|
55015
|
-
chatFiles =
|
|
55430
|
+
chatFiles = import_fs65.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
55016
55431
|
} catch {
|
|
55017
55432
|
continue;
|
|
55018
55433
|
}
|
|
55019
55434
|
for (const chatFile of chatFiles) {
|
|
55020
55435
|
let raw;
|
|
55021
55436
|
try {
|
|
55022
|
-
raw =
|
|
55437
|
+
raw = import_fs65.default.readFileSync(import_path62.default.join(chatsDir, chatFile), "utf-8");
|
|
55023
55438
|
} catch {
|
|
55024
55439
|
continue;
|
|
55025
55440
|
}
|
|
@@ -55099,8 +55514,8 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
55099
55514
|
return summaries;
|
|
55100
55515
|
}
|
|
55101
55516
|
function buildCodexSessions(days, allAuditEntries) {
|
|
55102
|
-
const sessionsBase =
|
|
55103
|
-
if (!
|
|
55517
|
+
const sessionsBase = import_path62.default.join(import_os55.default.homedir(), ".codex", "sessions");
|
|
55518
|
+
if (!import_fs65.default.existsSync(sessionsBase)) return [];
|
|
55104
55519
|
const cutoff = days !== null ? (() => {
|
|
55105
55520
|
const d = /* @__PURE__ */ new Date();
|
|
55106
55521
|
d.setDate(d.getDate() - days);
|
|
@@ -55109,29 +55524,29 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
55109
55524
|
})() : null;
|
|
55110
55525
|
const jsonlFiles = [];
|
|
55111
55526
|
try {
|
|
55112
|
-
for (const year of
|
|
55113
|
-
const yearPath =
|
|
55527
|
+
for (const year of import_fs65.default.readdirSync(sessionsBase)) {
|
|
55528
|
+
const yearPath = import_path62.default.join(sessionsBase, year);
|
|
55114
55529
|
try {
|
|
55115
|
-
if (!
|
|
55530
|
+
if (!import_fs65.default.statSync(yearPath).isDirectory()) continue;
|
|
55116
55531
|
} catch {
|
|
55117
55532
|
continue;
|
|
55118
55533
|
}
|
|
55119
|
-
for (const month of
|
|
55120
|
-
const monthPath =
|
|
55534
|
+
for (const month of import_fs65.default.readdirSync(yearPath)) {
|
|
55535
|
+
const monthPath = import_path62.default.join(yearPath, month);
|
|
55121
55536
|
try {
|
|
55122
|
-
if (!
|
|
55537
|
+
if (!import_fs65.default.statSync(monthPath).isDirectory()) continue;
|
|
55123
55538
|
} catch {
|
|
55124
55539
|
continue;
|
|
55125
55540
|
}
|
|
55126
|
-
for (const day of
|
|
55127
|
-
const dayPath =
|
|
55541
|
+
for (const day of import_fs65.default.readdirSync(monthPath)) {
|
|
55542
|
+
const dayPath = import_path62.default.join(monthPath, day);
|
|
55128
55543
|
try {
|
|
55129
|
-
if (!
|
|
55544
|
+
if (!import_fs65.default.statSync(dayPath).isDirectory()) continue;
|
|
55130
55545
|
} catch {
|
|
55131
55546
|
continue;
|
|
55132
55547
|
}
|
|
55133
|
-
for (const file of
|
|
55134
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
55548
|
+
for (const file of import_fs65.default.readdirSync(dayPath)) {
|
|
55549
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path62.default.join(dayPath, file));
|
|
55135
55550
|
}
|
|
55136
55551
|
}
|
|
55137
55552
|
}
|
|
@@ -55143,7 +55558,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
55143
55558
|
for (const filePath of jsonlFiles) {
|
|
55144
55559
|
let lines;
|
|
55145
55560
|
try {
|
|
55146
|
-
lines =
|
|
55561
|
+
lines = import_fs65.default.readFileSync(filePath, "utf-8").split("\n");
|
|
55147
55562
|
} catch {
|
|
55148
55563
|
continue;
|
|
55149
55564
|
}
|
|
@@ -55229,10 +55644,10 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
55229
55644
|
return summaries;
|
|
55230
55645
|
}
|
|
55231
55646
|
function buildSessions(days, historyPath) {
|
|
55232
|
-
const hPath = historyPath ??
|
|
55647
|
+
const hPath = historyPath ?? import_path62.default.join(import_os55.default.homedir(), ".claude", "history.jsonl");
|
|
55233
55648
|
let historyRaw = "";
|
|
55234
55649
|
try {
|
|
55235
|
-
historyRaw =
|
|
55650
|
+
historyRaw = import_fs65.default.readFileSync(hPath, "utf-8");
|
|
55236
55651
|
} catch {
|
|
55237
55652
|
}
|
|
55238
55653
|
const cutoff = days !== null ? (() => {
|
|
@@ -55256,7 +55671,7 @@ function buildSessions(days, historyPath) {
|
|
|
55256
55671
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
55257
55672
|
let sessionLines = [];
|
|
55258
55673
|
try {
|
|
55259
|
-
sessionLines =
|
|
55674
|
+
sessionLines = import_fs65.default.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
55260
55675
|
} catch {
|
|
55261
55676
|
}
|
|
55262
55677
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -55650,12 +56065,12 @@ function registerSessionTaintCommand(program2) {
|
|
|
55650
56065
|
|
|
55651
56066
|
// src/cli/commands/skill-pin.ts
|
|
55652
56067
|
var import_chalk36 = __toESM(require("chalk"));
|
|
55653
|
-
var
|
|
55654
|
-
var
|
|
55655
|
-
var
|
|
56068
|
+
var import_fs66 = __toESM(require("fs"));
|
|
56069
|
+
var import_os56 = __toESM(require("os"));
|
|
56070
|
+
var import_path63 = __toESM(require("path"));
|
|
55656
56071
|
function wipeSkillSessions() {
|
|
55657
56072
|
try {
|
|
55658
|
-
|
|
56073
|
+
import_fs66.default.rmSync(import_path63.default.join(import_os56.default.homedir(), ".node9", "skill-sessions"), {
|
|
55659
56074
|
recursive: true,
|
|
55660
56075
|
force: true
|
|
55661
56076
|
});
|
|
@@ -55737,15 +56152,15 @@ function registerSkillPinCommand(program2) {
|
|
|
55737
56152
|
}
|
|
55738
56153
|
|
|
55739
56154
|
// src/cli/commands/decisions.ts
|
|
55740
|
-
var
|
|
55741
|
-
var
|
|
55742
|
-
var
|
|
56155
|
+
var import_fs67 = __toESM(require("fs"));
|
|
56156
|
+
var import_os57 = __toESM(require("os"));
|
|
56157
|
+
var import_path64 = __toESM(require("path"));
|
|
55743
56158
|
var import_chalk37 = __toESM(require("chalk"));
|
|
55744
|
-
var DECISIONS_FILE2 =
|
|
56159
|
+
var DECISIONS_FILE2 = import_path64.default.join(import_os57.default.homedir(), ".node9", "decisions.json");
|
|
55745
56160
|
function readDecisions() {
|
|
55746
56161
|
try {
|
|
55747
|
-
if (!
|
|
55748
|
-
const raw =
|
|
56162
|
+
if (!import_fs67.default.existsSync(DECISIONS_FILE2)) return {};
|
|
56163
|
+
const raw = import_fs67.default.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
55749
56164
|
const parsed = JSON.parse(raw);
|
|
55750
56165
|
const out = {};
|
|
55751
56166
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -55757,11 +56172,11 @@ function readDecisions() {
|
|
|
55757
56172
|
}
|
|
55758
56173
|
}
|
|
55759
56174
|
function writeDecisions(d) {
|
|
55760
|
-
const dir =
|
|
55761
|
-
if (!
|
|
56175
|
+
const dir = import_path64.default.dirname(DECISIONS_FILE2);
|
|
56176
|
+
if (!import_fs67.default.existsSync(dir)) import_fs67.default.mkdirSync(dir, { recursive: true });
|
|
55762
56177
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
55763
|
-
|
|
55764
|
-
|
|
56178
|
+
import_fs67.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
56179
|
+
import_fs67.default.renameSync(tmp, DECISIONS_FILE2);
|
|
55765
56180
|
}
|
|
55766
56181
|
function registerDecisionsCommand(program2) {
|
|
55767
56182
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -55818,18 +56233,18 @@ Persistent decisions (${entries.length})
|
|
|
55818
56233
|
|
|
55819
56234
|
// src/cli/commands/dlp.ts
|
|
55820
56235
|
var import_chalk38 = __toESM(require("chalk"));
|
|
55821
|
-
var
|
|
55822
|
-
var
|
|
55823
|
-
var
|
|
55824
|
-
var AUDIT_LOG =
|
|
55825
|
-
var RESOLVED_FILE =
|
|
56236
|
+
var import_fs68 = __toESM(require("fs"));
|
|
56237
|
+
var import_path65 = __toESM(require("path"));
|
|
56238
|
+
var import_os58 = __toESM(require("os"));
|
|
56239
|
+
var AUDIT_LOG = import_path65.default.join(import_os58.default.homedir(), ".node9", "audit.log");
|
|
56240
|
+
var RESOLVED_FILE = import_path65.default.join(import_os58.default.homedir(), ".node9", "dlp-resolved.json");
|
|
55826
56241
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
55827
56242
|
function stripAnsi(s) {
|
|
55828
56243
|
return s.replace(ANSI_RE, "");
|
|
55829
56244
|
}
|
|
55830
56245
|
function loadResolved() {
|
|
55831
56246
|
try {
|
|
55832
|
-
const raw = JSON.parse(
|
|
56247
|
+
const raw = JSON.parse(import_fs68.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
55833
56248
|
return new Set(raw);
|
|
55834
56249
|
} catch {
|
|
55835
56250
|
return /* @__PURE__ */ new Set();
|
|
@@ -55837,13 +56252,13 @@ function loadResolved() {
|
|
|
55837
56252
|
}
|
|
55838
56253
|
function saveResolved(resolved) {
|
|
55839
56254
|
try {
|
|
55840
|
-
|
|
56255
|
+
import_fs68.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
55841
56256
|
} catch {
|
|
55842
56257
|
}
|
|
55843
56258
|
}
|
|
55844
56259
|
function loadDlpFindings() {
|
|
55845
|
-
if (!
|
|
55846
|
-
return
|
|
56260
|
+
if (!import_fs68.default.existsSync(AUDIT_LOG)) return [];
|
|
56261
|
+
return import_fs68.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
55847
56262
|
if (!line.trim()) return [];
|
|
55848
56263
|
try {
|
|
55849
56264
|
const e = JSON.parse(line);
|
|
@@ -55941,15 +56356,15 @@ function registerDlpCommand(program2) {
|
|
|
55941
56356
|
|
|
55942
56357
|
// src/cli/commands/mask.ts
|
|
55943
56358
|
var import_chalk39 = __toESM(require("chalk"));
|
|
55944
|
-
var
|
|
55945
|
-
var
|
|
55946
|
-
var
|
|
56359
|
+
var import_fs69 = __toESM(require("fs"));
|
|
56360
|
+
var import_path66 = __toESM(require("path"));
|
|
56361
|
+
var import_os59 = __toESM(require("os"));
|
|
55947
56362
|
init_dlp();
|
|
55948
56363
|
function findJsonlFiles(dir) {
|
|
55949
56364
|
const results = [];
|
|
55950
|
-
if (!
|
|
55951
|
-
for (const entry of
|
|
55952
|
-
const full =
|
|
56365
|
+
if (!import_fs69.default.existsSync(dir)) return results;
|
|
56366
|
+
for (const entry of import_fs69.default.readdirSync(dir, { withFileTypes: true })) {
|
|
56367
|
+
const full = import_path66.default.join(dir, entry.name);
|
|
55953
56368
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
55954
56369
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
55955
56370
|
}
|
|
@@ -55992,7 +56407,7 @@ function redactJson(obj) {
|
|
|
55992
56407
|
function processFile(filePath, dryRun) {
|
|
55993
56408
|
let raw;
|
|
55994
56409
|
try {
|
|
55995
|
-
raw =
|
|
56410
|
+
raw = import_fs69.default.readFileSync(filePath, "utf-8");
|
|
55996
56411
|
} catch {
|
|
55997
56412
|
return { redactedLines: 0, patterns: [] };
|
|
55998
56413
|
}
|
|
@@ -56024,14 +56439,14 @@ function processFile(filePath, dryRun) {
|
|
|
56024
56439
|
}
|
|
56025
56440
|
}
|
|
56026
56441
|
if (!dryRun && redactedLines > 0) {
|
|
56027
|
-
|
|
56442
|
+
import_fs69.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
56028
56443
|
}
|
|
56029
56444
|
return { redactedLines, patterns };
|
|
56030
56445
|
}
|
|
56031
56446
|
function processJsonFile(filePath, dryRun) {
|
|
56032
56447
|
let raw;
|
|
56033
56448
|
try {
|
|
56034
|
-
raw =
|
|
56449
|
+
raw = import_fs69.default.readFileSync(filePath, "utf-8");
|
|
56035
56450
|
} catch {
|
|
56036
56451
|
return { redactedLines: 0, patterns: [] };
|
|
56037
56452
|
}
|
|
@@ -56044,15 +56459,15 @@ function processJsonFile(filePath, dryRun) {
|
|
|
56044
56459
|
const { value, modified, found } = redactJson(parsed);
|
|
56045
56460
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
56046
56461
|
if (!dryRun) {
|
|
56047
|
-
|
|
56462
|
+
import_fs69.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
56048
56463
|
}
|
|
56049
56464
|
return { redactedLines: 1, patterns: found };
|
|
56050
56465
|
}
|
|
56051
56466
|
function findJsonFiles(dir) {
|
|
56052
56467
|
const results = [];
|
|
56053
|
-
if (!
|
|
56054
|
-
for (const entry of
|
|
56055
|
-
const full =
|
|
56468
|
+
if (!import_fs69.default.existsSync(dir)) return results;
|
|
56469
|
+
for (const entry of import_fs69.default.readdirSync(dir, { withFileTypes: true })) {
|
|
56470
|
+
const full = import_path66.default.join(dir, entry.name);
|
|
56056
56471
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
56057
56472
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
56058
56473
|
}
|
|
@@ -56061,9 +56476,9 @@ function findJsonFiles(dir) {
|
|
|
56061
56476
|
function registerMaskCommand(program2) {
|
|
56062
56477
|
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) => {
|
|
56063
56478
|
const dryRun = !!options.dryRun;
|
|
56064
|
-
const home =
|
|
56065
|
-
const claudeDir =
|
|
56066
|
-
const geminiDir =
|
|
56479
|
+
const home = import_os59.default.homedir();
|
|
56480
|
+
const claudeDir = import_path66.default.join(home, ".claude", "projects");
|
|
56481
|
+
const geminiDir = import_path66.default.join(home, ".gemini", "tmp");
|
|
56067
56482
|
const allFiles = [
|
|
56068
56483
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
56069
56484
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -56071,7 +56486,7 @@ function registerMaskCommand(program2) {
|
|
|
56071
56486
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
56072
56487
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
56073
56488
|
try {
|
|
56074
|
-
return
|
|
56489
|
+
return import_fs69.default.statSync(f.path).mtime >= cutoff;
|
|
56075
56490
|
} catch {
|
|
56076
56491
|
return false;
|
|
56077
56492
|
}
|
|
@@ -56127,7 +56542,7 @@ function registerMaskCommand(program2) {
|
|
|
56127
56542
|
// src/cli.ts
|
|
56128
56543
|
init_blast();
|
|
56129
56544
|
var { version } = JSON.parse(
|
|
56130
|
-
|
|
56545
|
+
import_fs72.default.readFileSync(import_path69.default.join(__dirname, "../package.json"), "utf-8")
|
|
56131
56546
|
);
|
|
56132
56547
|
var program = new import_commander.Command();
|
|
56133
56548
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
@@ -56153,6 +56568,11 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
56153
56568
|
} else {
|
|
56154
56569
|
console.log(import_chalk41.default.green(`\u2705 Logged in \u2014 agent mode`));
|
|
56155
56570
|
console.log(import_chalk41.default.gray(` Team policy enforced for all calls via Node9 cloud.`));
|
|
56571
|
+
if (!isTestingMode()) {
|
|
56572
|
+
const healed = ensureAutostartHealthy(!!getConfig().settings.autoStartDaemon);
|
|
56573
|
+
if (healed === "repaired")
|
|
56574
|
+
console.log(import_chalk41.default.green(` \u2713 Re-enabled daemon autostart (survives reboot)`));
|
|
56575
|
+
}
|
|
56156
56576
|
}
|
|
56157
56577
|
});
|
|
56158
56578
|
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) => {
|
|
@@ -56301,15 +56721,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
56301
56721
|
} catch {
|
|
56302
56722
|
}
|
|
56303
56723
|
if (options.purge) {
|
|
56304
|
-
const node9Dir =
|
|
56305
|
-
if (
|
|
56724
|
+
const node9Dir = import_path69.default.join(import_os62.default.homedir(), ".node9");
|
|
56725
|
+
if (import_fs72.default.existsSync(node9Dir)) {
|
|
56306
56726
|
const confirmed = await (0, import_prompts2.confirm)({
|
|
56307
56727
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
56308
56728
|
default: false
|
|
56309
56729
|
});
|
|
56310
56730
|
if (confirmed) {
|
|
56311
|
-
|
|
56312
|
-
if (
|
|
56731
|
+
import_fs72.default.rmSync(node9Dir, { recursive: true });
|
|
56732
|
+
if (import_fs72.default.existsSync(node9Dir)) {
|
|
56313
56733
|
console.error(
|
|
56314
56734
|
import_chalk41.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
56315
56735
|
);
|
|
@@ -56434,7 +56854,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
56434
56854
|
});
|
|
56435
56855
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
56436
56856
|
try {
|
|
56437
|
-
const dashboardPath =
|
|
56857
|
+
const dashboardPath = import_path69.default.join(__dirname, "dashboard.mjs");
|
|
56438
56858
|
const dynamicImport = new Function("id", "return import(id)");
|
|
56439
56859
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
56440
56860
|
await mod.startMonitor();
|
|
@@ -56472,14 +56892,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
56472
56892
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
56473
56893
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
56474
56894
|
if (subcommand === "debug") {
|
|
56475
|
-
const flagFile =
|
|
56895
|
+
const flagFile = import_path69.default.join(import_os62.default.homedir(), ".node9", "hud-debug");
|
|
56476
56896
|
if (state === "on") {
|
|
56477
|
-
|
|
56478
|
-
|
|
56897
|
+
import_fs72.default.mkdirSync(import_path69.default.dirname(flagFile), { recursive: true });
|
|
56898
|
+
import_fs72.default.writeFileSync(flagFile, "");
|
|
56479
56899
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
56480
56900
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
56481
56901
|
} else if (state === "off") {
|
|
56482
|
-
if (
|
|
56902
|
+
if (import_fs72.default.existsSync(flagFile)) import_fs72.default.unlinkSync(flagFile);
|
|
56483
56903
|
console.log("HUD debug logging disabled.");
|
|
56484
56904
|
} else {
|
|
56485
56905
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -56602,9 +57022,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
56602
57022
|
const isCheckHook = process.argv[2] === "check";
|
|
56603
57023
|
if (isCheckHook) {
|
|
56604
57024
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
56605
|
-
const logPath =
|
|
57025
|
+
const logPath = import_path69.default.join(import_os62.default.homedir(), ".node9", "hook-debug.log");
|
|
56606
57026
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
56607
|
-
|
|
57027
|
+
import_fs72.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
56608
57028
|
`);
|
|
56609
57029
|
}
|
|
56610
57030
|
process.exit(0);
|