@node9/proxy 1.31.0 → 1.33.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 +1344 -855
- package/dist/cli.mjs +1329 -840
- package/dist/dashboard.mjs +78 -15
- package/dist/index.js +86 -17
- package/dist/index.mjs +86 -17
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -140,6 +140,9 @@ function appendLocalAudit(toolName, args, decision, checkedBy, meta, auditHashAr
|
|
|
140
140
|
const agentToolNameField = meta?.agentToolName ? { agentToolName: meta.agentToolName } : {};
|
|
141
141
|
const dlpFields = meta?.dlpPattern ? { dlpPattern: meta.dlpPattern, dlpSample: meta.dlpSample } : {};
|
|
142
142
|
const cloudLinkField = meta?.cloudRequestId ? { cloudRequestId: meta.cloudRequestId } : {};
|
|
143
|
+
const workingDirField = meta?.workingDir ? { workingDir: meta.workingDir } : {};
|
|
144
|
+
const shell = process.env.SHELL ? import_path.default.basename(process.env.SHELL) : void 0;
|
|
145
|
+
const shellTypeField = shell ? { shellType: shell } : {};
|
|
143
146
|
appendToLog(LOCAL_AUDIT_LOG, {
|
|
144
147
|
// eid first: the outbox shipper dedups on it, and a fixed leading field
|
|
145
148
|
// makes the JSONL easy to eyeball.
|
|
@@ -153,11 +156,14 @@ function appendLocalAudit(toolName, args, decision, checkedBy, meta, auditHashAr
|
|
|
153
156
|
...ruleNameField,
|
|
154
157
|
...dlpFields,
|
|
155
158
|
...cloudLinkField,
|
|
159
|
+
...workingDirField,
|
|
160
|
+
...shellTypeField,
|
|
156
161
|
...testRun,
|
|
157
162
|
agent: meta?.agent,
|
|
158
163
|
mcpServer: meta?.mcpServer,
|
|
159
164
|
sessionId: meta?.sessionId,
|
|
160
|
-
hostname: import_os.default.hostname()
|
|
165
|
+
hostname: import_os.default.hostname(),
|
|
166
|
+
platform: import_os.default.platform()
|
|
161
167
|
});
|
|
162
168
|
}
|
|
163
169
|
function appendConfigAudit(entry) {
|
|
@@ -200,8 +206,8 @@ function sanitizeConfig(raw) {
|
|
|
200
206
|
}
|
|
201
207
|
}
|
|
202
208
|
const lines = result.error.issues.map((issue) => {
|
|
203
|
-
const
|
|
204
|
-
return ` \u2022 ${
|
|
209
|
+
const path54 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
210
|
+
return ` \u2022 ${path54}: ${issue.message}`;
|
|
205
211
|
});
|
|
206
212
|
return {
|
|
207
213
|
sanitized,
|
|
@@ -548,6 +554,8 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
548
554
|
if (f === PARSE_FAIL) return command;
|
|
549
555
|
try {
|
|
550
556
|
const strips = [];
|
|
557
|
+
const rewrites = [];
|
|
558
|
+
const msgSpans = /* @__PURE__ */ new Set();
|
|
551
559
|
syntax.Walk(f, (node) => {
|
|
552
560
|
if (!node) return false;
|
|
553
561
|
const n = node;
|
|
@@ -563,25 +571,46 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
563
571
|
if (nextParts.length !== 1) continue;
|
|
564
572
|
const quotedNode = nextParts[0];
|
|
565
573
|
const nt = syntax.NodeType(quotedNode);
|
|
574
|
+
const markStrip = () => {
|
|
575
|
+
const s = next.Pos().Offset();
|
|
576
|
+
const e = next.End().Offset();
|
|
577
|
+
strips.push([s, e]);
|
|
578
|
+
msgSpans.add(`${s}:${e}`);
|
|
579
|
+
};
|
|
566
580
|
if (nt === "SglQuoted") {
|
|
567
|
-
|
|
581
|
+
markStrip();
|
|
568
582
|
} else if (nt === "DblQuoted") {
|
|
569
583
|
const innerParts = quotedNode.Parts || [];
|
|
570
584
|
const allLit = innerParts.length === 0 || innerParts.every((p) => syntax.NodeType(p) === "Lit");
|
|
571
585
|
if (allLit) {
|
|
572
|
-
|
|
586
|
+
markStrip();
|
|
573
587
|
} else if (innerParts.every((p) => isCatHeredocOrLit(p))) {
|
|
574
|
-
|
|
588
|
+
markStrip();
|
|
575
589
|
}
|
|
576
590
|
}
|
|
577
591
|
}
|
|
592
|
+
for (const arg of args) {
|
|
593
|
+
const s = arg.Pos().Offset();
|
|
594
|
+
const e = arg.End().Offset();
|
|
595
|
+
if (msgSpans.has(`${s}:${e}`)) continue;
|
|
596
|
+
const resolved = resolveWordLiteral(arg);
|
|
597
|
+
if (resolved === null) continue;
|
|
598
|
+
const source = command.slice(s, e);
|
|
599
|
+
if (resolved === source) continue;
|
|
600
|
+
if (resolved === "" || /\s/.test(resolved)) continue;
|
|
601
|
+
rewrites.push([s, e, resolved]);
|
|
602
|
+
}
|
|
578
603
|
return true;
|
|
579
604
|
});
|
|
580
|
-
|
|
581
|
-
|
|
605
|
+
const edits = [
|
|
606
|
+
...strips.map(([s, e]) => [s, e, '""']),
|
|
607
|
+
...rewrites
|
|
608
|
+
];
|
|
609
|
+
if (edits.length === 0) return command;
|
|
610
|
+
edits.sort((a, b) => b[0] - a[0]);
|
|
582
611
|
let result = command;
|
|
583
|
-
for (const [
|
|
584
|
-
result = result.slice(0,
|
|
612
|
+
for (const [s, e, rep] of edits) {
|
|
613
|
+
result = result.slice(0, s) + rep + result.slice(e);
|
|
585
614
|
}
|
|
586
615
|
return result;
|
|
587
616
|
} catch {
|
|
@@ -643,6 +672,17 @@ function detectDangerousShellExec(command) {
|
|
|
643
672
|
function isBashTool(toolName) {
|
|
644
673
|
return BASH_TOOL_NAMES.has(toolName.toLowerCase());
|
|
645
674
|
}
|
|
675
|
+
function analyzeSqlDestructive(command) {
|
|
676
|
+
if (!SQL_DDL_RE.test(command)) return null;
|
|
677
|
+
const { actions } = analyzeShellCommand(command);
|
|
678
|
+
if (!actions.some((a) => SQL_DB_CLIS.has(a))) return null;
|
|
679
|
+
return {
|
|
680
|
+
ruleName: "review-drop-truncate-shell",
|
|
681
|
+
verdict: "review",
|
|
682
|
+
reason: "SQL DDL destructive statement inside a shell command",
|
|
683
|
+
description: "The AI wants to drop or truncate a database table via the shell. This permanently deletes the table structure or all its data."
|
|
684
|
+
};
|
|
685
|
+
}
|
|
646
686
|
function isProtectedHomePath(rawPath) {
|
|
647
687
|
let p = rawPath.replace(/^\$HOME[\\/]?|^\$\{HOME\}[\\/]?/, "~/");
|
|
648
688
|
let underHome = false;
|
|
@@ -804,19 +844,20 @@ function extractShellDestinations(command) {
|
|
|
804
844
|
return out;
|
|
805
845
|
}
|
|
806
846
|
function analyzeFsOperation(command) {
|
|
807
|
-
|
|
808
|
-
if (
|
|
809
|
-
|
|
810
|
-
fsOpCache.
|
|
811
|
-
fsOpCache.
|
|
847
|
+
const normalized = normalizeCommandForPolicy(command);
|
|
848
|
+
if (!FS_OP_PRESCREEN_RE.test(normalized)) return null;
|
|
849
|
+
if (fsOpCache.has(normalized)) {
|
|
850
|
+
const hit = fsOpCache.get(normalized) ?? null;
|
|
851
|
+
fsOpCache.delete(normalized);
|
|
852
|
+
fsOpCache.set(normalized, hit);
|
|
812
853
|
return hit;
|
|
813
854
|
}
|
|
814
|
-
const computed = analyzeFsOperationImpl(
|
|
855
|
+
const computed = analyzeFsOperationImpl(normalized);
|
|
815
856
|
if (fsOpCache.size >= FS_OP_CACHE_MAX) {
|
|
816
857
|
const oldest = fsOpCache.keys().next().value;
|
|
817
858
|
if (oldest !== void 0) fsOpCache.delete(oldest);
|
|
818
859
|
}
|
|
819
|
-
fsOpCache.set(
|
|
860
|
+
fsOpCache.set(normalized, computed);
|
|
820
861
|
return computed;
|
|
821
862
|
}
|
|
822
863
|
function analyzeFsOperationImpl(command) {
|
|
@@ -1215,9 +1256,9 @@ function matchesPattern(text, patterns) {
|
|
|
1215
1256
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
1216
1257
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
1217
1258
|
}
|
|
1218
|
-
function getNestedValue(obj,
|
|
1259
|
+
function getNestedValue(obj, path54) {
|
|
1219
1260
|
if (!obj || typeof obj !== "object") return null;
|
|
1220
|
-
const segments =
|
|
1261
|
+
const segments = path54.split(".");
|
|
1221
1262
|
for (const seg of segments) {
|
|
1222
1263
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
1223
1264
|
}
|
|
@@ -1357,6 +1398,17 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
1357
1398
|
ruleDescription: fsVerdict.reason
|
|
1358
1399
|
};
|
|
1359
1400
|
}
|
|
1401
|
+
const sqlVerdict = analyzeSqlDestructive(bashCommand);
|
|
1402
|
+
if (sqlVerdict) {
|
|
1403
|
+
return {
|
|
1404
|
+
decision: sqlVerdict.verdict,
|
|
1405
|
+
blockedByLabel: `Node9 (AST): ${sqlVerdict.ruleName}`,
|
|
1406
|
+
reason: sqlVerdict.reason,
|
|
1407
|
+
tier: 2,
|
|
1408
|
+
ruleName: sqlVerdict.ruleName,
|
|
1409
|
+
ruleDescription: sqlVerdict.description
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1360
1412
|
}
|
|
1361
1413
|
if (config.policy.smartRules.length > 0) {
|
|
1362
1414
|
const matchedRule = config.policy.smartRules.find(
|
|
@@ -1937,7 +1989,7 @@ function extractCanonicalFindings(call, ctx) {
|
|
|
1937
1989
|
})
|
|
1938
1990
|
);
|
|
1939
1991
|
}
|
|
1940
|
-
if (DESTRUCTIVE_OP_RE.test(command)) {
|
|
1992
|
+
if (command !== null && DESTRUCTIVE_OP_RE.test(normalizeCommandForPolicy(command))) {
|
|
1941
1993
|
out.push(
|
|
1942
1994
|
makeFinding({
|
|
1943
1995
|
type: "destructive-op",
|
|
@@ -2089,7 +2141,7 @@ function* stringValues(obj, depth = 0) {
|
|
|
2089
2141
|
}
|
|
2090
2142
|
for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
|
|
2091
2143
|
}
|
|
2092
|
-
var import_safe_regex2, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto3, 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, 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, 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;
|
|
2144
|
+
var import_safe_regex2, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto3, 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, 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, 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;
|
|
2093
2145
|
var init_dist = __esm({
|
|
2094
2146
|
"packages/policy-engine/dist/index.mjs"() {
|
|
2095
2147
|
"use strict";
|
|
@@ -2707,8 +2759,24 @@ var init_dist = __esm({
|
|
|
2707
2759
|
"shield:project-jail:block-read-ssh",
|
|
2708
2760
|
"shield:project-jail:block-read-aws",
|
|
2709
2761
|
"shield:project-jail:block-read-env",
|
|
2710
|
-
"shield:project-jail:review-read-credentials"
|
|
2762
|
+
"shield:project-jail:review-read-credentials",
|
|
2763
|
+
// SQL-DDL is now owned by the AST detector (analyzeSqlDestructive) so the
|
|
2764
|
+
// raw-regex smart rule is suppressed for bash — its cond1 read a grep
|
|
2765
|
+
// alternation's `|` as a shell pipe (`grep "…|mysql…"` → false positive).
|
|
2766
|
+
"review-drop-truncate-shell"
|
|
2767
|
+
]);
|
|
2768
|
+
SQL_DB_CLIS = /* @__PURE__ */ new Set([
|
|
2769
|
+
"psql",
|
|
2770
|
+
"mysql",
|
|
2771
|
+
"mariadb",
|
|
2772
|
+
"sqlite3",
|
|
2773
|
+
"sqlplus",
|
|
2774
|
+
"cockroach",
|
|
2775
|
+
"clickhouse-client",
|
|
2776
|
+
"mongo",
|
|
2777
|
+
"mongosh"
|
|
2711
2778
|
]);
|
|
2779
|
+
SQL_DDL_RE = /\b(DROP|TRUNCATE)\s+(TABLE|DATABASE|SCHEMA|INDEX)\b/i;
|
|
2712
2780
|
NET_BINARIES = /* @__PURE__ */ new Set(["curl", "wget", "scp", "ssh", "nc", "ncat", "netcat"]);
|
|
2713
2781
|
VALUE_FLAGS = {
|
|
2714
2782
|
curl: /* @__PURE__ */ new Set([
|
|
@@ -3747,7 +3815,7 @@ var init_dist = __esm({
|
|
|
3747
3815
|
REALTIME_PII_PATTERNS = ["SSN", "Credit Card"];
|
|
3748
3816
|
MAX_PII_SCAN_BYTES = 1e5;
|
|
3749
3817
|
LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
|
|
3750
|
-
CANONICAL_EXTRACTOR_VERSION = "canonical-
|
|
3818
|
+
CANONICAL_EXTRACTOR_VERSION = "canonical-v6";
|
|
3751
3819
|
DEDUPE_PREVIEW_LEN = 120;
|
|
3752
3820
|
TERMINAL_ESCAPE_RE = // eslint-disable-next-line no-control-regex
|
|
3753
3821
|
/\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
@@ -6079,7 +6147,8 @@ async function authorizeHeadless(toolName, args, meta, options) {
|
|
|
6079
6147
|
}
|
|
6080
6148
|
return _authorizeHeadlessCore(toolName, args, meta, options);
|
|
6081
6149
|
}
|
|
6082
|
-
async function _authorizeHeadlessCore(toolName, args,
|
|
6150
|
+
async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
6151
|
+
const meta = options?.cwd && !metaArg?.workingDir ? { ...metaArg, workingDir: options.cwd } : metaArg;
|
|
6083
6152
|
if (process.env.NODE9_PAUSED === "1") return { approved: true, checkedBy: "paused" };
|
|
6084
6153
|
const pauseState = checkPause();
|
|
6085
6154
|
if (pauseState.paused) return { approved: true, checkedBy: "paused" };
|
|
@@ -7235,7 +7304,7 @@ function writeJson(filePath, data) {
|
|
|
7235
7304
|
}
|
|
7236
7305
|
function isNode9Hook(cmd) {
|
|
7237
7306
|
if (!cmd) return false;
|
|
7238
|
-
return /(?:^|[\s/\\"])node9 (?:check|log)/.test(cmd) || /(?:^|[\s/\\
|
|
7307
|
+
return /(?:^|[\s/\\"])node9"? (?:check|log)/.test(cmd) || /(?:^|[\s/\\])cli\.js"? (?:check|log)/.test(cmd);
|
|
7239
7308
|
}
|
|
7240
7309
|
function teardownClaude() {
|
|
7241
7310
|
const homeDir2 = import_os12.default.homedir();
|
|
@@ -10027,43 +10096,102 @@ var init_litellm = __esm({
|
|
|
10027
10096
|
});
|
|
10028
10097
|
|
|
10029
10098
|
// src/cost-codex.ts
|
|
10030
|
-
function
|
|
10031
|
-
return import_path19.default.join(import_os16.default.homedir(), ".codex", "
|
|
10032
|
-
}
|
|
10033
|
-
function
|
|
10034
|
-
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
const
|
|
10038
|
-
|
|
10039
|
-
|
|
10040
|
-
|
|
10041
|
-
|
|
10042
|
-
|
|
10043
|
-
|
|
10044
|
-
|
|
10045
|
-
|
|
10046
|
-
|
|
10047
|
-
|
|
10048
|
-
|
|
10049
|
-
|
|
10050
|
-
|
|
10051
|
-
|
|
10052
|
-
|
|
10099
|
+
function codexSessionsDir() {
|
|
10100
|
+
return import_path19.default.join(import_os16.default.homedir(), ".codex", "sessions");
|
|
10101
|
+
}
|
|
10102
|
+
function codexPriceFor(model) {
|
|
10103
|
+
return pricingFor(model) ?? CODEX_FALLBACK;
|
|
10104
|
+
}
|
|
10105
|
+
function listCodexSessionFiles(base) {
|
|
10106
|
+
const out = [];
|
|
10107
|
+
for (const y of safeReaddir(base)) {
|
|
10108
|
+
const yp = import_path19.default.join(base, y);
|
|
10109
|
+
if (!isDir(yp)) continue;
|
|
10110
|
+
for (const m of safeReaddir(yp)) {
|
|
10111
|
+
const mp = import_path19.default.join(yp, m);
|
|
10112
|
+
if (!isDir(mp)) continue;
|
|
10113
|
+
for (const d of safeReaddir(mp)) {
|
|
10114
|
+
const dp = import_path19.default.join(mp, d);
|
|
10115
|
+
if (!isDir(dp)) continue;
|
|
10116
|
+
for (const f of safeReaddir(dp)) {
|
|
10117
|
+
if (f.endsWith(".jsonl")) out.push(import_path19.default.join(dp, f));
|
|
10118
|
+
}
|
|
10119
|
+
}
|
|
10120
|
+
}
|
|
10121
|
+
}
|
|
10122
|
+
return out;
|
|
10123
|
+
}
|
|
10124
|
+
function safeReaddir(dir) {
|
|
10125
|
+
try {
|
|
10126
|
+
return import_fs17.default.readdirSync(dir);
|
|
10127
|
+
} catch {
|
|
10128
|
+
return [];
|
|
10129
|
+
}
|
|
10130
|
+
}
|
|
10131
|
+
function isDir(p) {
|
|
10132
|
+
try {
|
|
10133
|
+
return import_fs17.default.statSync(p).isDirectory();
|
|
10134
|
+
} catch {
|
|
10135
|
+
return false;
|
|
10136
|
+
}
|
|
10137
|
+
}
|
|
10138
|
+
function parseCodexSession(lines) {
|
|
10139
|
+
let sessionStart2 = "";
|
|
10140
|
+
let runId = "";
|
|
10141
|
+
let cwd = "";
|
|
10142
|
+
let model = "";
|
|
10143
|
+
let input = 0;
|
|
10144
|
+
let cached = 0;
|
|
10145
|
+
let output = 0;
|
|
10146
|
+
let sawUsage = false;
|
|
10147
|
+
for (const raw of lines) {
|
|
10148
|
+
if (!raw.trim()) continue;
|
|
10149
|
+
let entry;
|
|
10150
|
+
try {
|
|
10151
|
+
entry = JSON.parse(raw);
|
|
10152
|
+
} catch {
|
|
10153
|
+
continue;
|
|
10154
|
+
}
|
|
10155
|
+
const p = entry.payload ?? {};
|
|
10156
|
+
if (entry.type === "session_meta") {
|
|
10157
|
+
if (!sessionStart2 && typeof p["timestamp"] === "string") sessionStart2 = p["timestamp"];
|
|
10158
|
+
if (!runId && typeof p["id"] === "string") runId = p["id"];
|
|
10159
|
+
if (!cwd && typeof p["cwd"] === "string") cwd = p["cwd"];
|
|
10160
|
+
continue;
|
|
10161
|
+
}
|
|
10162
|
+
if (entry.type === "turn_context") {
|
|
10163
|
+
if (typeof p["model"] === "string") model = p["model"];
|
|
10164
|
+
if (!cwd && typeof p["cwd"] === "string") cwd = p["cwd"];
|
|
10165
|
+
continue;
|
|
10166
|
+
}
|
|
10167
|
+
if (entry.type === "event_msg" && p["type"] === "token_count") {
|
|
10168
|
+
const info = p["info"] ?? {};
|
|
10169
|
+
const usage = info["total_token_usage"] ?? {};
|
|
10170
|
+
if (typeof usage["input_tokens"] === "number") input = usage["input_tokens"];
|
|
10171
|
+
if (typeof usage["cached_input_tokens"] === "number") cached = usage["cached_input_tokens"];
|
|
10172
|
+
if (typeof usage["output_tokens"] === "number") output = usage["output_tokens"];
|
|
10173
|
+
sawUsage = true;
|
|
10174
|
+
}
|
|
10175
|
+
}
|
|
10176
|
+
if (!sessionStart2 || !sawUsage) return null;
|
|
10177
|
+
const nonCached = Math.max(0, input - cached);
|
|
10178
|
+
if (nonCached === 0 && output === 0 && cached === 0) return null;
|
|
10179
|
+
const norm = normalizeModel(model || "gpt-5");
|
|
10180
|
+
const [pin, pout, , pcr] = codexPriceFor(model || "gpt-5");
|
|
10181
|
+
const costUSD = nonCached * pin + output * pout + cached * pcr;
|
|
10053
10182
|
return {
|
|
10054
|
-
date,
|
|
10183
|
+
date: sessionStart2.slice(0, 10),
|
|
10055
10184
|
model: norm,
|
|
10056
|
-
workingDir:
|
|
10057
|
-
// Codex span carries no cwd — attribution is by runId (thread)
|
|
10185
|
+
workingDir: cwd,
|
|
10058
10186
|
runId,
|
|
10059
10187
|
costUSD,
|
|
10060
|
-
inputTokens,
|
|
10188
|
+
inputTokens: nonCached,
|
|
10061
10189
|
outputTokens: output,
|
|
10062
10190
|
cacheReadTokens: cached,
|
|
10063
10191
|
cacheWriteTokens: 0
|
|
10064
10192
|
};
|
|
10065
10193
|
}
|
|
10066
|
-
var import_fs17, import_os16, import_path19,
|
|
10194
|
+
var import_fs17, import_os16, import_path19, CODEX_FALLBACK, codexSource;
|
|
10067
10195
|
var init_cost_codex = __esm({
|
|
10068
10196
|
"src/cost-codex.ts"() {
|
|
10069
10197
|
"use strict";
|
|
@@ -10071,42 +10199,32 @@ var init_cost_codex = __esm({
|
|
|
10071
10199
|
import_os16 = __toESM(require("os"));
|
|
10072
10200
|
import_path19 = __toESM(require("path"));
|
|
10073
10201
|
init_litellm();
|
|
10074
|
-
|
|
10075
|
-
RE_CACHED = /token_usage\.cached_input_tokens=(\d+)/;
|
|
10076
|
-
RE_NON_CACHED = /token_usage\.non_cached_input_tokens=(\d+)/;
|
|
10077
|
-
RE_OUTPUT = /token_usage\.output_tokens=(\d+)/;
|
|
10078
|
-
RE_MODEL = /\bmodel=([^\s}]+)/;
|
|
10079
|
-
RE_THREAD = /\bthread\.id=([0-9a-fA-F-]+)/;
|
|
10080
|
-
RE_DATE = /^(\d{4}-\d{2}-\d{2})T/;
|
|
10202
|
+
CODEX_FALLBACK = [5e-6, 15e-6, 0, 25e-7];
|
|
10081
10203
|
codexSource = {
|
|
10082
10204
|
id: "codex",
|
|
10083
10205
|
available() {
|
|
10084
10206
|
try {
|
|
10085
|
-
return import_fs17.default.existsSync(
|
|
10207
|
+
return import_fs17.default.existsSync(codexSessionsDir());
|
|
10086
10208
|
} catch {
|
|
10087
10209
|
return false;
|
|
10088
10210
|
}
|
|
10089
10211
|
},
|
|
10090
10212
|
collect(sinceMs) {
|
|
10091
|
-
const
|
|
10092
|
-
let content;
|
|
10093
|
-
try {
|
|
10094
|
-
if (sinceMs !== void 0 && import_fs17.default.statSync(file).mtimeMs < sinceMs) return [];
|
|
10095
|
-
content = import_fs17.default.readFileSync(file, "utf8");
|
|
10096
|
-
} catch {
|
|
10097
|
-
return [];
|
|
10098
|
-
}
|
|
10213
|
+
const base = codexSessionsDir();
|
|
10099
10214
|
const combined = /* @__PURE__ */ new Map();
|
|
10100
|
-
for (const
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
10104
|
-
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10215
|
+
for (const file of listCodexSessionFiles(base)) {
|
|
10216
|
+
try {
|
|
10217
|
+
if (sinceMs !== void 0 && import_fs17.default.statSync(file).mtimeMs < sinceMs) continue;
|
|
10218
|
+
} catch {
|
|
10219
|
+
continue;
|
|
10220
|
+
}
|
|
10221
|
+
let content;
|
|
10222
|
+
try {
|
|
10223
|
+
content = import_fs17.default.readFileSync(file, "utf8");
|
|
10224
|
+
} catch {
|
|
10225
|
+
continue;
|
|
10108
10226
|
}
|
|
10109
|
-
const e =
|
|
10227
|
+
const e = parseCodexSession(content.split("\n"));
|
|
10110
10228
|
if (!e) continue;
|
|
10111
10229
|
const key = `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
|
|
10112
10230
|
const prev = combined.get(key);
|
|
@@ -10126,15 +10244,286 @@ var init_cost_codex = __esm({
|
|
|
10126
10244
|
}
|
|
10127
10245
|
});
|
|
10128
10246
|
|
|
10247
|
+
// src/cost-gemini.ts
|
|
10248
|
+
function geminiTmpDir() {
|
|
10249
|
+
return import_path20.default.join(import_os17.default.homedir(), ".gemini", "tmp");
|
|
10250
|
+
}
|
|
10251
|
+
function geminiPriceFor(model) {
|
|
10252
|
+
let tuple = pricingFor(model);
|
|
10253
|
+
if (!tuple && /^gemini-/i.test(model)) {
|
|
10254
|
+
for (const proxy of GEMINI_FALLBACK_MODELS) {
|
|
10255
|
+
tuple = pricingFor(proxy);
|
|
10256
|
+
if (tuple) break;
|
|
10257
|
+
}
|
|
10258
|
+
}
|
|
10259
|
+
if (!tuple) return null;
|
|
10260
|
+
return { input: tuple[0], output: tuple[1], cacheRead: tuple[3] || tuple[0] };
|
|
10261
|
+
}
|
|
10262
|
+
function safeReaddir2(dir) {
|
|
10263
|
+
try {
|
|
10264
|
+
return import_fs18.default.readdirSync(dir);
|
|
10265
|
+
} catch {
|
|
10266
|
+
return [];
|
|
10267
|
+
}
|
|
10268
|
+
}
|
|
10269
|
+
function isDir2(p) {
|
|
10270
|
+
try {
|
|
10271
|
+
return import_fs18.default.statSync(p).isDirectory();
|
|
10272
|
+
} catch {
|
|
10273
|
+
return false;
|
|
10274
|
+
}
|
|
10275
|
+
}
|
|
10276
|
+
function listGeminiSessionFiles(base) {
|
|
10277
|
+
const out = [];
|
|
10278
|
+
for (const project of safeReaddir2(base)) {
|
|
10279
|
+
const chats = import_path20.default.join(base, project, "chats");
|
|
10280
|
+
if (!isDir2(chats)) continue;
|
|
10281
|
+
for (const f of safeReaddir2(chats)) {
|
|
10282
|
+
if (f.startsWith("session-") && f.endsWith(".jsonl")) {
|
|
10283
|
+
out.push({ file: import_path20.default.join(chats, f), project });
|
|
10284
|
+
}
|
|
10285
|
+
}
|
|
10286
|
+
}
|
|
10287
|
+
return out;
|
|
10288
|
+
}
|
|
10289
|
+
function parseGeminiSession(lines, project) {
|
|
10290
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
10291
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
10292
|
+
let runId = "";
|
|
10293
|
+
for (const raw of lines) {
|
|
10294
|
+
if (!raw.trim()) continue;
|
|
10295
|
+
let obj;
|
|
10296
|
+
try {
|
|
10297
|
+
obj = JSON.parse(raw);
|
|
10298
|
+
} catch {
|
|
10299
|
+
continue;
|
|
10300
|
+
}
|
|
10301
|
+
if (typeof obj.sessionId === "string" && !runId) runId = obj.sessionId;
|
|
10302
|
+
if (!obj.tokens || !obj.model || !obj.timestamp) continue;
|
|
10303
|
+
if (obj.id) {
|
|
10304
|
+
if (seenIds.has(obj.id)) continue;
|
|
10305
|
+
seenIds.add(obj.id);
|
|
10306
|
+
}
|
|
10307
|
+
const price = geminiPriceFor(obj.model);
|
|
10308
|
+
if (!price) continue;
|
|
10309
|
+
const inp = obj.tokens.input ?? 0;
|
|
10310
|
+
const out = obj.tokens.output ?? 0;
|
|
10311
|
+
const cached = Math.min(obj.tokens.cached ?? 0, inp);
|
|
10312
|
+
const fresh = Math.max(0, inp - cached);
|
|
10313
|
+
const cost = fresh * price.input + cached * price.cacheRead + out * price.output;
|
|
10314
|
+
const date = obj.timestamp.slice(0, 10);
|
|
10315
|
+
const model = normalizeModel(obj.model);
|
|
10316
|
+
const key = `${date}::${model}`;
|
|
10317
|
+
const prev = byKey.get(key);
|
|
10318
|
+
if (prev) {
|
|
10319
|
+
prev.costUSD += cost;
|
|
10320
|
+
prev.inputTokens += fresh;
|
|
10321
|
+
prev.outputTokens += out;
|
|
10322
|
+
prev.cacheReadTokens += cached;
|
|
10323
|
+
} else {
|
|
10324
|
+
byKey.set(key, {
|
|
10325
|
+
date,
|
|
10326
|
+
model,
|
|
10327
|
+
workingDir: project,
|
|
10328
|
+
runId,
|
|
10329
|
+
costUSD: cost,
|
|
10330
|
+
inputTokens: fresh,
|
|
10331
|
+
outputTokens: out,
|
|
10332
|
+
cacheReadTokens: cached,
|
|
10333
|
+
cacheWriteTokens: 0
|
|
10334
|
+
});
|
|
10335
|
+
}
|
|
10336
|
+
}
|
|
10337
|
+
if (runId) for (const e of byKey.values()) e.runId = runId;
|
|
10338
|
+
return [...byKey.values()];
|
|
10339
|
+
}
|
|
10340
|
+
var import_fs18, import_os17, import_path20, GEMINI_FALLBACK_MODELS, geminiSource;
|
|
10341
|
+
var init_cost_gemini = __esm({
|
|
10342
|
+
"src/cost-gemini.ts"() {
|
|
10343
|
+
"use strict";
|
|
10344
|
+
import_fs18 = __toESM(require("fs"));
|
|
10345
|
+
import_os17 = __toESM(require("os"));
|
|
10346
|
+
import_path20 = __toESM(require("path"));
|
|
10347
|
+
init_litellm();
|
|
10348
|
+
GEMINI_FALLBACK_MODELS = ["gemini-2.5-flash", "gemini-2.0-flash"];
|
|
10349
|
+
geminiSource = {
|
|
10350
|
+
id: "gemini",
|
|
10351
|
+
available() {
|
|
10352
|
+
try {
|
|
10353
|
+
return import_fs18.default.existsSync(geminiTmpDir());
|
|
10354
|
+
} catch {
|
|
10355
|
+
return false;
|
|
10356
|
+
}
|
|
10357
|
+
},
|
|
10358
|
+
collect(sinceMs) {
|
|
10359
|
+
const combined = /* @__PURE__ */ new Map();
|
|
10360
|
+
for (const { file, project } of listGeminiSessionFiles(geminiTmpDir())) {
|
|
10361
|
+
try {
|
|
10362
|
+
if (sinceMs !== void 0 && import_fs18.default.statSync(file).mtimeMs < sinceMs) continue;
|
|
10363
|
+
} catch {
|
|
10364
|
+
continue;
|
|
10365
|
+
}
|
|
10366
|
+
let content;
|
|
10367
|
+
try {
|
|
10368
|
+
content = import_fs18.default.readFileSync(file, "utf8");
|
|
10369
|
+
} catch {
|
|
10370
|
+
continue;
|
|
10371
|
+
}
|
|
10372
|
+
for (const e of parseGeminiSession(content.split("\n"), project)) {
|
|
10373
|
+
const key = `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
|
|
10374
|
+
const prev = combined.get(key);
|
|
10375
|
+
if (prev) {
|
|
10376
|
+
prev.costUSD += e.costUSD;
|
|
10377
|
+
prev.inputTokens += e.inputTokens;
|
|
10378
|
+
prev.outputTokens += e.outputTokens;
|
|
10379
|
+
prev.cacheReadTokens += e.cacheReadTokens;
|
|
10380
|
+
prev.cacheWriteTokens += e.cacheWriteTokens;
|
|
10381
|
+
} else {
|
|
10382
|
+
combined.set(key, { ...e });
|
|
10383
|
+
}
|
|
10384
|
+
}
|
|
10385
|
+
}
|
|
10386
|
+
return [...combined.values()];
|
|
10387
|
+
}
|
|
10388
|
+
};
|
|
10389
|
+
}
|
|
10390
|
+
});
|
|
10391
|
+
|
|
10392
|
+
// src/cost-copilot.ts
|
|
10393
|
+
function copilotSessionsDir() {
|
|
10394
|
+
return import_path21.default.join(import_os18.default.homedir(), ".copilot", "session-state");
|
|
10395
|
+
}
|
|
10396
|
+
function safeReaddir3(dir) {
|
|
10397
|
+
try {
|
|
10398
|
+
return import_fs19.default.readdirSync(dir);
|
|
10399
|
+
} catch {
|
|
10400
|
+
return [];
|
|
10401
|
+
}
|
|
10402
|
+
}
|
|
10403
|
+
function priceTokens(model, u) {
|
|
10404
|
+
const tuple = pricingFor(model);
|
|
10405
|
+
if (!tuple || !u) return 0;
|
|
10406
|
+
const [pin, pout, pcw, pcr] = tuple;
|
|
10407
|
+
return (u.inputTokens ?? 0) * pin + (u.outputTokens ?? 0) * pout + (u.cacheWriteTokens ?? 0) * pcw + (u.cacheReadTokens ?? 0) * pcr;
|
|
10408
|
+
}
|
|
10409
|
+
function parseCopilotSession(lines) {
|
|
10410
|
+
let sessionId = "";
|
|
10411
|
+
let cwd = "";
|
|
10412
|
+
let startDate = "";
|
|
10413
|
+
let shutdownDate = "";
|
|
10414
|
+
let modelMetrics = null;
|
|
10415
|
+
for (const raw of lines) {
|
|
10416
|
+
if (!raw.trim()) continue;
|
|
10417
|
+
let o;
|
|
10418
|
+
try {
|
|
10419
|
+
o = JSON.parse(raw);
|
|
10420
|
+
} catch {
|
|
10421
|
+
continue;
|
|
10422
|
+
}
|
|
10423
|
+
const d = o.data ?? {};
|
|
10424
|
+
if (o.type === "session.start") {
|
|
10425
|
+
if (typeof d["sessionId"] === "string") sessionId = d["sessionId"];
|
|
10426
|
+
if (typeof d["startTime"] === "string") startDate = d["startTime"];
|
|
10427
|
+
const ctx = d["context"] ?? {};
|
|
10428
|
+
if (typeof ctx["cwd"] === "string") cwd = ctx["cwd"];
|
|
10429
|
+
} else if (o.type === "session.shutdown") {
|
|
10430
|
+
if (d["modelMetrics"] && typeof d["modelMetrics"] === "object") {
|
|
10431
|
+
modelMetrics = d["modelMetrics"];
|
|
10432
|
+
}
|
|
10433
|
+
if (typeof o.timestamp === "string") shutdownDate = o.timestamp;
|
|
10434
|
+
}
|
|
10435
|
+
}
|
|
10436
|
+
if (!modelMetrics) return [];
|
|
10437
|
+
const date = (startDate || shutdownDate).slice(0, 10);
|
|
10438
|
+
if (!date) return [];
|
|
10439
|
+
const rows = [];
|
|
10440
|
+
for (const [rawModel, m] of Object.entries(modelMetrics)) {
|
|
10441
|
+
const u = m.usage ?? {};
|
|
10442
|
+
const inputTokens = u.inputTokens ?? 0;
|
|
10443
|
+
const outputTokens = u.outputTokens ?? 0;
|
|
10444
|
+
const cacheReadTokens = u.cacheReadTokens ?? 0;
|
|
10445
|
+
const cacheWriteTokens = u.cacheWriteTokens ?? 0;
|
|
10446
|
+
if (inputTokens === 0 && outputTokens === 0 && cacheReadTokens === 0 && cacheWriteTokens === 0) {
|
|
10447
|
+
continue;
|
|
10448
|
+
}
|
|
10449
|
+
const model = normalizeModel(rawModel);
|
|
10450
|
+
const costUSD = typeof m.requests?.cost === "number" && m.requests.cost > 0 ? m.requests.cost : priceTokens(rawModel, u);
|
|
10451
|
+
rows.push({
|
|
10452
|
+
date,
|
|
10453
|
+
model,
|
|
10454
|
+
workingDir: cwd,
|
|
10455
|
+
runId: sessionId,
|
|
10456
|
+
costUSD,
|
|
10457
|
+
inputTokens,
|
|
10458
|
+
outputTokens,
|
|
10459
|
+
cacheReadTokens,
|
|
10460
|
+
cacheWriteTokens
|
|
10461
|
+
});
|
|
10462
|
+
}
|
|
10463
|
+
return rows;
|
|
10464
|
+
}
|
|
10465
|
+
var import_fs19, import_os18, import_path21, copilotSource;
|
|
10466
|
+
var init_cost_copilot = __esm({
|
|
10467
|
+
"src/cost-copilot.ts"() {
|
|
10468
|
+
"use strict";
|
|
10469
|
+
import_fs19 = __toESM(require("fs"));
|
|
10470
|
+
import_os18 = __toESM(require("os"));
|
|
10471
|
+
import_path21 = __toESM(require("path"));
|
|
10472
|
+
init_litellm();
|
|
10473
|
+
copilotSource = {
|
|
10474
|
+
id: "copilot",
|
|
10475
|
+
available() {
|
|
10476
|
+
try {
|
|
10477
|
+
return import_fs19.default.existsSync(copilotSessionsDir());
|
|
10478
|
+
} catch {
|
|
10479
|
+
return false;
|
|
10480
|
+
}
|
|
10481
|
+
},
|
|
10482
|
+
collect(sinceMs) {
|
|
10483
|
+
const base = copilotSessionsDir();
|
|
10484
|
+
const combined = /* @__PURE__ */ new Map();
|
|
10485
|
+
for (const sid of safeReaddir3(base)) {
|
|
10486
|
+
const file = import_path21.default.join(base, sid, "events.jsonl");
|
|
10487
|
+
try {
|
|
10488
|
+
if (sinceMs !== void 0 && import_fs19.default.statSync(file).mtimeMs < sinceMs) continue;
|
|
10489
|
+
} catch {
|
|
10490
|
+
continue;
|
|
10491
|
+
}
|
|
10492
|
+
let content;
|
|
10493
|
+
try {
|
|
10494
|
+
content = import_fs19.default.readFileSync(file, "utf8");
|
|
10495
|
+
} catch {
|
|
10496
|
+
continue;
|
|
10497
|
+
}
|
|
10498
|
+
for (const e of parseCopilotSession(content.split("\n"))) {
|
|
10499
|
+
const key = `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
|
|
10500
|
+
const prev = combined.get(key);
|
|
10501
|
+
if (prev) {
|
|
10502
|
+
prev.costUSD += e.costUSD;
|
|
10503
|
+
prev.inputTokens += e.inputTokens;
|
|
10504
|
+
prev.outputTokens += e.outputTokens;
|
|
10505
|
+
prev.cacheReadTokens += e.cacheReadTokens;
|
|
10506
|
+
prev.cacheWriteTokens += e.cacheWriteTokens;
|
|
10507
|
+
} else {
|
|
10508
|
+
combined.set(key, { ...e });
|
|
10509
|
+
}
|
|
10510
|
+
}
|
|
10511
|
+
}
|
|
10512
|
+
return [...combined.values()];
|
|
10513
|
+
}
|
|
10514
|
+
};
|
|
10515
|
+
}
|
|
10516
|
+
});
|
|
10517
|
+
|
|
10129
10518
|
// src/costSync.ts
|
|
10130
10519
|
function decodeProjectDirName(dirName) {
|
|
10131
10520
|
return dirName.replace(/-/g, "/");
|
|
10132
10521
|
}
|
|
10133
10522
|
function parseJSONLFile(filePath, fallbackWorkingDir) {
|
|
10134
|
-
const runId =
|
|
10523
|
+
const runId = import_path22.default.basename(filePath, ".jsonl");
|
|
10135
10524
|
let content;
|
|
10136
10525
|
try {
|
|
10137
|
-
content =
|
|
10526
|
+
content = import_fs20.default.readFileSync(filePath, "utf8");
|
|
10138
10527
|
} catch {
|
|
10139
10528
|
return /* @__PURE__ */ new Map();
|
|
10140
10529
|
}
|
|
@@ -10218,6 +10607,45 @@ function collectEntries(sinceMs) {
|
|
|
10218
10607
|
}
|
|
10219
10608
|
return [...combined.values()];
|
|
10220
10609
|
}
|
|
10610
|
+
function chunk(arr, size) {
|
|
10611
|
+
if (size <= 0) return arr.length ? [arr] : [];
|
|
10612
|
+
const out = [];
|
|
10613
|
+
for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size));
|
|
10614
|
+
return out;
|
|
10615
|
+
}
|
|
10616
|
+
async function postCostBatches(apiUrl, apiKey, machineId, entries) {
|
|
10617
|
+
for (const batch of chunk(entries, COST_BATCH_SIZE)) {
|
|
10618
|
+
try {
|
|
10619
|
+
const res = await fetch(`${apiUrl}/cost-sync`, {
|
|
10620
|
+
method: "POST",
|
|
10621
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
|
|
10622
|
+
body: JSON.stringify({ machineId, entries: batch }),
|
|
10623
|
+
signal: AbortSignal.timeout(15e3)
|
|
10624
|
+
});
|
|
10625
|
+
if (!res.ok) {
|
|
10626
|
+
import_fs20.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
|
|
10627
|
+
`);
|
|
10628
|
+
} else {
|
|
10629
|
+
let stored;
|
|
10630
|
+
try {
|
|
10631
|
+
const respBody = typeof res.json === "function" ? await res.json() : null;
|
|
10632
|
+
stored = respBody?.stored;
|
|
10633
|
+
} catch {
|
|
10634
|
+
}
|
|
10635
|
+
if (typeof stored === "number" && stored < batch.length) {
|
|
10636
|
+
import_fs20.default.appendFileSync(
|
|
10637
|
+
HOOK_DEBUG_LOG,
|
|
10638
|
+
`[cost-sync] dropped ${batch.length - stored} of ${batch.length} rows
|
|
10639
|
+
`
|
|
10640
|
+
);
|
|
10641
|
+
}
|
|
10642
|
+
}
|
|
10643
|
+
} catch (err2) {
|
|
10644
|
+
import_fs20.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
|
|
10645
|
+
`);
|
|
10646
|
+
}
|
|
10647
|
+
}
|
|
10648
|
+
}
|
|
10221
10649
|
async function syncCost() {
|
|
10222
10650
|
const creds = getCredentials();
|
|
10223
10651
|
if (!creds?.apiKey || !creds?.apiUrl) return;
|
|
@@ -10226,25 +10654,11 @@ async function syncCost() {
|
|
|
10226
10654
|
if (entries.length === 0) return;
|
|
10227
10655
|
let username = "unknown";
|
|
10228
10656
|
try {
|
|
10229
|
-
username =
|
|
10657
|
+
username = import_os19.default.userInfo().username;
|
|
10230
10658
|
} catch {
|
|
10231
10659
|
}
|
|
10232
|
-
const machineId = `${
|
|
10233
|
-
|
|
10234
|
-
const res = await fetch(`${creds.apiUrl}/cost-sync`, {
|
|
10235
|
-
method: "POST",
|
|
10236
|
-
headers: { "Content-Type": "application/json", Authorization: `Bearer ${creds.apiKey}` },
|
|
10237
|
-
body: JSON.stringify({ machineId, entries }),
|
|
10238
|
-
signal: AbortSignal.timeout(15e3)
|
|
10239
|
-
});
|
|
10240
|
-
if (!res.ok) {
|
|
10241
|
-
import_fs18.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
|
|
10242
|
-
`);
|
|
10243
|
-
}
|
|
10244
|
-
} catch (err2) {
|
|
10245
|
-
import_fs18.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
|
|
10246
|
-
`);
|
|
10247
|
-
}
|
|
10660
|
+
const machineId = `${import_os19.default.hostname()}:${username}`;
|
|
10661
|
+
await postCostBatches(creds.apiUrl, creds.apiKey, machineId, entries);
|
|
10248
10662
|
}
|
|
10249
10663
|
function startCostSync() {
|
|
10250
10664
|
syncCost().catch(() => {
|
|
@@ -10255,52 +10669,54 @@ function startCostSync() {
|
|
|
10255
10669
|
}, SYNC_INTERVAL_MS);
|
|
10256
10670
|
timer.unref();
|
|
10257
10671
|
}
|
|
10258
|
-
var
|
|
10672
|
+
var import_fs20, import_path22, import_os19, SYNC_INTERVAL_MS, claudeSource, COST_SOURCES, COST_BATCH_SIZE;
|
|
10259
10673
|
var init_costSync = __esm({
|
|
10260
10674
|
"src/costSync.ts"() {
|
|
10261
10675
|
"use strict";
|
|
10262
|
-
|
|
10263
|
-
|
|
10264
|
-
|
|
10676
|
+
import_fs20 = __toESM(require("fs"));
|
|
10677
|
+
import_path22 = __toESM(require("path"));
|
|
10678
|
+
import_os19 = __toESM(require("os"));
|
|
10265
10679
|
init_config();
|
|
10266
10680
|
init_audit();
|
|
10267
10681
|
init_litellm();
|
|
10268
10682
|
init_cost_codex();
|
|
10683
|
+
init_cost_gemini();
|
|
10684
|
+
init_cost_copilot();
|
|
10269
10685
|
SYNC_INTERVAL_MS = 10 * 60 * 1e3;
|
|
10270
10686
|
claudeSource = {
|
|
10271
10687
|
id: "claude",
|
|
10272
10688
|
available() {
|
|
10273
|
-
return
|
|
10689
|
+
return import_fs20.default.existsSync(import_path22.default.join(import_os19.default.homedir(), ".claude", "projects"));
|
|
10274
10690
|
},
|
|
10275
10691
|
collect(sinceMs) {
|
|
10276
|
-
const projectsDir =
|
|
10277
|
-
if (!
|
|
10692
|
+
const projectsDir = import_path22.default.join(import_os19.default.homedir(), ".claude", "projects");
|
|
10693
|
+
if (!import_fs20.default.existsSync(projectsDir)) return [];
|
|
10278
10694
|
const combined = /* @__PURE__ */ new Map();
|
|
10279
10695
|
let dirs;
|
|
10280
10696
|
try {
|
|
10281
|
-
dirs =
|
|
10697
|
+
dirs = import_fs20.default.readdirSync(projectsDir);
|
|
10282
10698
|
} catch {
|
|
10283
10699
|
return [];
|
|
10284
10700
|
}
|
|
10285
10701
|
for (const dir of dirs) {
|
|
10286
|
-
const dirPath =
|
|
10702
|
+
const dirPath = import_path22.default.join(projectsDir, dir);
|
|
10287
10703
|
try {
|
|
10288
|
-
if (!
|
|
10704
|
+
if (!import_fs20.default.statSync(dirPath).isDirectory()) continue;
|
|
10289
10705
|
} catch {
|
|
10290
10706
|
continue;
|
|
10291
10707
|
}
|
|
10292
10708
|
let files;
|
|
10293
10709
|
try {
|
|
10294
|
-
files =
|
|
10710
|
+
files = import_fs20.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
10295
10711
|
} catch {
|
|
10296
10712
|
continue;
|
|
10297
10713
|
}
|
|
10298
10714
|
const fallbackWorkingDir = decodeProjectDirName(dir);
|
|
10299
10715
|
for (const file of files) {
|
|
10300
|
-
const filePath =
|
|
10716
|
+
const filePath = import_path22.default.join(dirPath, file);
|
|
10301
10717
|
if (sinceMs !== void 0) {
|
|
10302
10718
|
try {
|
|
10303
|
-
if (
|
|
10719
|
+
if (import_fs20.default.statSync(filePath).mtimeMs < sinceMs) continue;
|
|
10304
10720
|
} catch {
|
|
10305
10721
|
continue;
|
|
10306
10722
|
}
|
|
@@ -10323,7 +10739,8 @@ var init_costSync = __esm({
|
|
|
10323
10739
|
return [...combined.values()];
|
|
10324
10740
|
}
|
|
10325
10741
|
};
|
|
10326
|
-
COST_SOURCES = [claudeSource, codexSource];
|
|
10742
|
+
COST_SOURCES = [claudeSource, codexSource, geminiSource, copilotSource];
|
|
10743
|
+
COST_BATCH_SIZE = 200;
|
|
10327
10744
|
}
|
|
10328
10745
|
});
|
|
10329
10746
|
|
|
@@ -10350,7 +10767,7 @@ function freshWatermark() {
|
|
|
10350
10767
|
function loadWatermark() {
|
|
10351
10768
|
let raw;
|
|
10352
10769
|
try {
|
|
10353
|
-
raw =
|
|
10770
|
+
raw = import_fs21.default.readFileSync(WATERMARK_FILE(), "utf-8");
|
|
10354
10771
|
} catch {
|
|
10355
10772
|
return { status: "fresh", wm: freshWatermark() };
|
|
10356
10773
|
}
|
|
@@ -10402,28 +10819,28 @@ function loadWatermark() {
|
|
|
10402
10819
|
function saveWatermark(wm) {
|
|
10403
10820
|
if (wm.schemaVersion > WATERMARK_SCHEMA_VERSION) return;
|
|
10404
10821
|
const target = WATERMARK_FILE();
|
|
10405
|
-
const dir =
|
|
10406
|
-
if (!
|
|
10822
|
+
const dir = import_path23.default.dirname(target);
|
|
10823
|
+
if (!import_fs21.default.existsSync(dir)) import_fs21.default.mkdirSync(dir, { recursive: true });
|
|
10407
10824
|
const tmp = target + ".tmp";
|
|
10408
|
-
|
|
10409
|
-
|
|
10825
|
+
import_fs21.default.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
|
|
10826
|
+
import_fs21.default.renameSync(tmp, target);
|
|
10410
10827
|
}
|
|
10411
10828
|
function listJsonlFiles() {
|
|
10412
10829
|
const root = PROJECTS_DIR();
|
|
10413
|
-
if (!
|
|
10830
|
+
if (!import_fs21.default.existsSync(root)) return [];
|
|
10414
10831
|
const out = [];
|
|
10415
|
-
for (const entry of
|
|
10832
|
+
for (const entry of import_fs21.default.readdirSync(root, { withFileTypes: true })) {
|
|
10416
10833
|
if (!entry.isDirectory()) continue;
|
|
10417
|
-
const projectDir =
|
|
10834
|
+
const projectDir = import_path23.default.join(root, entry.name);
|
|
10418
10835
|
let inner;
|
|
10419
10836
|
try {
|
|
10420
|
-
inner =
|
|
10837
|
+
inner = import_fs21.default.readdirSync(projectDir, { withFileTypes: true });
|
|
10421
10838
|
} catch {
|
|
10422
10839
|
continue;
|
|
10423
10840
|
}
|
|
10424
10841
|
for (const file of inner) {
|
|
10425
10842
|
if (file.isFile() && file.name.endsWith(".jsonl")) {
|
|
10426
|
-
out.push(
|
|
10843
|
+
out.push(import_path23.default.join(projectDir, file.name));
|
|
10427
10844
|
}
|
|
10428
10845
|
}
|
|
10429
10846
|
}
|
|
@@ -10431,7 +10848,7 @@ function listJsonlFiles() {
|
|
|
10431
10848
|
}
|
|
10432
10849
|
function fileSize(p) {
|
|
10433
10850
|
try {
|
|
10434
|
-
return
|
|
10851
|
+
return import_fs21.default.statSync(p).size;
|
|
10435
10852
|
} catch {
|
|
10436
10853
|
return 0;
|
|
10437
10854
|
}
|
|
@@ -10439,7 +10856,7 @@ function fileSize(p) {
|
|
|
10439
10856
|
async function scanDelta(filePath, fromByte, onLine) {
|
|
10440
10857
|
const size = fileSize(filePath);
|
|
10441
10858
|
if (size <= fromByte) return fromByte;
|
|
10442
|
-
const stream =
|
|
10859
|
+
const stream = import_fs21.default.createReadStream(filePath, {
|
|
10443
10860
|
start: fromByte,
|
|
10444
10861
|
end: size - 1,
|
|
10445
10862
|
highWaterMark: 64 * 1024
|
|
@@ -10551,7 +10968,7 @@ async function tickForensicBroadcast(offsets) {
|
|
|
10551
10968
|
continue;
|
|
10552
10969
|
}
|
|
10553
10970
|
if (size <= offset) continue;
|
|
10554
|
-
const sessionId =
|
|
10971
|
+
const sessionId = import_path23.default.basename(file, ".jsonl");
|
|
10555
10972
|
const newOffset = await scanDelta(file, offset, (obj, lineIndex) => {
|
|
10556
10973
|
out.push(...extractFindingsFromLine(obj, sessionId, lineIndex));
|
|
10557
10974
|
});
|
|
@@ -10610,7 +11027,7 @@ function emptyTick(uploadAs) {
|
|
|
10610
11027
|
function readRawWatermarkPreservingOffsets() {
|
|
10611
11028
|
let raw;
|
|
10612
11029
|
try {
|
|
10613
|
-
raw =
|
|
11030
|
+
raw = import_fs21.default.readFileSync(WATERMARK_FILE(), "utf-8");
|
|
10614
11031
|
} catch {
|
|
10615
11032
|
return null;
|
|
10616
11033
|
}
|
|
@@ -10644,13 +11061,13 @@ async function runActualTick(wm) {
|
|
|
10644
11061
|
if (!known) {
|
|
10645
11062
|
let mtimeMs = 0;
|
|
10646
11063
|
try {
|
|
10647
|
-
mtimeMs =
|
|
11064
|
+
mtimeMs = import_fs21.default.statSync(filePath).mtime.getTime();
|
|
10648
11065
|
} catch {
|
|
10649
11066
|
continue;
|
|
10650
11067
|
}
|
|
10651
11068
|
if (mtimeMs >= watermarkCreatedAt) {
|
|
10652
11069
|
filesNew++;
|
|
10653
|
-
const sessionId2 =
|
|
11070
|
+
const sessionId2 = import_path23.default.basename(filePath, ".jsonl");
|
|
10654
11071
|
const newScannedTo2 = await scanDelta(filePath, 0, (obj, lineIndex) => {
|
|
10655
11072
|
totalToolCalls++;
|
|
10656
11073
|
toolCallsBySession[sessionId2] = (toolCallsBySession[sessionId2] ?? 0) + 1;
|
|
@@ -10668,7 +11085,7 @@ async function runActualTick(wm) {
|
|
|
10668
11085
|
filesSkipped++;
|
|
10669
11086
|
continue;
|
|
10670
11087
|
}
|
|
10671
|
-
const sessionId =
|
|
11088
|
+
const sessionId = import_path23.default.basename(filePath, ".jsonl");
|
|
10672
11089
|
const newScannedTo = await scanDelta(filePath, known.scannedTo, (obj, lineIndex) => {
|
|
10673
11090
|
totalToolCalls++;
|
|
10674
11091
|
toolCallsBySession[sessionId] = (toolCallsBySession[sessionId] ?? 0) + 1;
|
|
@@ -10690,18 +11107,18 @@ async function runActualTick(wm) {
|
|
|
10690
11107
|
schemaFuture: false
|
|
10691
11108
|
};
|
|
10692
11109
|
}
|
|
10693
|
-
var
|
|
11110
|
+
var import_fs21, import_os20, import_path23, import_readline, PROJECTS_DIR, WATERMARK_FILE, MAX_LINE_BYTES, WATERMARK_SCHEMA_VERSION, LONG_OUTPUT_THRESHOLD_BYTES2;
|
|
10694
11111
|
var init_scan_watermark = __esm({
|
|
10695
11112
|
"src/daemon/scan-watermark.ts"() {
|
|
10696
11113
|
"use strict";
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
|
|
11114
|
+
import_fs21 = __toESM(require("fs"));
|
|
11115
|
+
import_os20 = __toESM(require("os"));
|
|
11116
|
+
import_path23 = __toESM(require("path"));
|
|
10700
11117
|
import_readline = __toESM(require("readline"));
|
|
10701
11118
|
init_dlp();
|
|
10702
11119
|
init_dist();
|
|
10703
|
-
PROJECTS_DIR = () =>
|
|
10704
|
-
WATERMARK_FILE = () =>
|
|
11120
|
+
PROJECTS_DIR = () => import_path23.default.join(import_os20.default.homedir(), ".claude", "projects");
|
|
11121
|
+
WATERMARK_FILE = () => import_path23.default.join(import_os20.default.homedir(), ".node9", "scan-watermark.json");
|
|
10705
11122
|
MAX_LINE_BYTES = 2 * 1024 * 1024;
|
|
10706
11123
|
WATERMARK_SCHEMA_VERSION = 2;
|
|
10707
11124
|
LONG_OUTPUT_THRESHOLD_BYTES2 = LONG_OUTPUT_THRESHOLD_BYTES;
|
|
@@ -10750,40 +11167,40 @@ function parseSinceCutoff(raw, now = /* @__PURE__ */ new Date()) {
|
|
|
10750
11167
|
return now.getTime() - 90 * 864e5;
|
|
10751
11168
|
}
|
|
10752
11169
|
function* iterateJsonlFiles(cutoffMs) {
|
|
10753
|
-
const projectsDir =
|
|
11170
|
+
const projectsDir = import_path24.default.join(import_os21.default.homedir(), ".claude", "projects");
|
|
10754
11171
|
let dirs;
|
|
10755
11172
|
try {
|
|
10756
|
-
dirs =
|
|
11173
|
+
dirs = import_fs22.default.readdirSync(projectsDir);
|
|
10757
11174
|
} catch {
|
|
10758
11175
|
return;
|
|
10759
11176
|
}
|
|
10760
11177
|
for (const dir of dirs) {
|
|
10761
|
-
const dirPath =
|
|
11178
|
+
const dirPath = import_path24.default.join(projectsDir, dir);
|
|
10762
11179
|
let stats;
|
|
10763
11180
|
try {
|
|
10764
|
-
stats =
|
|
11181
|
+
stats = import_fs22.default.statSync(dirPath);
|
|
10765
11182
|
} catch {
|
|
10766
11183
|
continue;
|
|
10767
11184
|
}
|
|
10768
11185
|
if (!stats.isDirectory()) continue;
|
|
10769
11186
|
let files;
|
|
10770
11187
|
try {
|
|
10771
|
-
files =
|
|
11188
|
+
files = import_fs22.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
10772
11189
|
} catch {
|
|
10773
11190
|
continue;
|
|
10774
11191
|
}
|
|
10775
11192
|
for (const file of files) {
|
|
10776
|
-
const filePath =
|
|
11193
|
+
const filePath = import_path24.default.join(dirPath, file);
|
|
10777
11194
|
let mtime = 0;
|
|
10778
11195
|
try {
|
|
10779
|
-
mtime =
|
|
11196
|
+
mtime = import_fs22.default.statSync(filePath).mtimeMs;
|
|
10780
11197
|
} catch {
|
|
10781
11198
|
continue;
|
|
10782
11199
|
}
|
|
10783
11200
|
if (mtime < cutoffMs) continue;
|
|
10784
11201
|
yield {
|
|
10785
11202
|
filePath,
|
|
10786
|
-
sessionId:
|
|
11203
|
+
sessionId: import_path24.default.basename(file, ".jsonl"),
|
|
10787
11204
|
projectDir: dir
|
|
10788
11205
|
};
|
|
10789
11206
|
}
|
|
@@ -10837,7 +11254,9 @@ async function runUploadHistory(opts) {
|
|
|
10837
11254
|
let filesScanned = 0;
|
|
10838
11255
|
let linesParsed = 0;
|
|
10839
11256
|
let linesSkipped = 0;
|
|
10840
|
-
const dailyEntries =
|
|
11257
|
+
const dailyEntries = collectEntries(cutoffMs).filter(
|
|
11258
|
+
(e) => cutoffMs === 0 || Date.parse(e.date + "T00:00:00Z") >= cutoffMs
|
|
11259
|
+
);
|
|
10841
11260
|
const liveLoopCfg = getConfig().policy.loopDetection;
|
|
10842
11261
|
const loopCfg = {
|
|
10843
11262
|
enabled: liveLoopCfg.enabled,
|
|
@@ -10849,7 +11268,7 @@ async function runUploadHistory(opts) {
|
|
|
10849
11268
|
filesScanned++;
|
|
10850
11269
|
let content;
|
|
10851
11270
|
try {
|
|
10852
|
-
content =
|
|
11271
|
+
content = import_fs22.default.readFileSync(filePath, "utf8");
|
|
10853
11272
|
} catch {
|
|
10854
11273
|
continue;
|
|
10855
11274
|
}
|
|
@@ -10899,14 +11318,6 @@ async function runUploadHistory(opts) {
|
|
|
10899
11318
|
if (sf) findings.push(sf);
|
|
10900
11319
|
}
|
|
10901
11320
|
}
|
|
10902
|
-
const fallbackWorkingDir = decodeProjectDirName(projectDir);
|
|
10903
|
-
const dailyMap = parseJSONLFile(filePath, fallbackWorkingDir);
|
|
10904
|
-
for (const entry of dailyMap.values()) {
|
|
10905
|
-
if (cutoffMs > 0 && Date.parse(entry.date + "T00:00:00Z") < cutoffMs) {
|
|
10906
|
-
continue;
|
|
10907
|
-
}
|
|
10908
|
-
dailyEntries.push(entry);
|
|
10909
|
-
}
|
|
10910
11321
|
}
|
|
10911
11322
|
if (filesScanned === 0) {
|
|
10912
11323
|
console.log(import_chalk4.default.yellow(" No JSONL files found in window. Nothing to upload."));
|
|
@@ -10931,10 +11342,10 @@ async function runUploadHistory(opts) {
|
|
|
10931
11342
|
const costUrl = creds.apiUrl.endsWith("/policies/sync") ? creds.apiUrl.replace(/\/policies\/sync$/, "/cost-sync") : `${creds.apiUrl.replace(/\/$/, "")}/cost-sync`;
|
|
10932
11343
|
let username = "unknown";
|
|
10933
11344
|
try {
|
|
10934
|
-
username =
|
|
11345
|
+
username = import_os21.default.userInfo().username;
|
|
10935
11346
|
} catch {
|
|
10936
11347
|
}
|
|
10937
|
-
const machineId = `${
|
|
11348
|
+
const machineId = `${import_os21.default.hostname()}:${username}`;
|
|
10938
11349
|
await postJson(costUrl, creds.apiKey, {
|
|
10939
11350
|
machineId,
|
|
10940
11351
|
entries: dailyEntries
|
|
@@ -10984,14 +11395,14 @@ async function postJson(url, apiKey, body) {
|
|
|
10984
11395
|
req.end();
|
|
10985
11396
|
});
|
|
10986
11397
|
}
|
|
10987
|
-
var
|
|
11398
|
+
var import_fs22, import_https, import_os21, import_path24, import_chalk4, FINDING_TO_SIGNAL2;
|
|
10988
11399
|
var init_scan_upload_history = __esm({
|
|
10989
11400
|
"src/scan-upload-history.ts"() {
|
|
10990
11401
|
"use strict";
|
|
10991
|
-
|
|
11402
|
+
import_fs22 = __toESM(require("fs"));
|
|
10992
11403
|
import_https = __toESM(require("https"));
|
|
10993
|
-
|
|
10994
|
-
|
|
11404
|
+
import_os21 = __toESM(require("os"));
|
|
11405
|
+
import_path24 = __toESM(require("path"));
|
|
10995
11406
|
import_chalk4 = __toESM(require("chalk"));
|
|
10996
11407
|
init_dist();
|
|
10997
11408
|
init_config();
|
|
@@ -11237,14 +11648,14 @@ function buildRuleSources() {
|
|
|
11237
11648
|
}
|
|
11238
11649
|
function countScanFiles() {
|
|
11239
11650
|
let total = 0;
|
|
11240
|
-
const claudeDir =
|
|
11241
|
-
if (
|
|
11651
|
+
const claudeDir = import_path25.default.join(import_os22.default.homedir(), ".claude", "projects");
|
|
11652
|
+
if (import_fs23.default.existsSync(claudeDir)) {
|
|
11242
11653
|
try {
|
|
11243
|
-
for (const proj of
|
|
11244
|
-
const p =
|
|
11654
|
+
for (const proj of import_fs23.default.readdirSync(claudeDir)) {
|
|
11655
|
+
const p = import_path25.default.join(claudeDir, proj);
|
|
11245
11656
|
try {
|
|
11246
|
-
if (!
|
|
11247
|
-
total +=
|
|
11657
|
+
if (!import_fs23.default.statSync(p).isDirectory()) continue;
|
|
11658
|
+
total += import_fs23.default.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
|
|
11248
11659
|
} catch {
|
|
11249
11660
|
continue;
|
|
11250
11661
|
}
|
|
@@ -11252,17 +11663,17 @@ function countScanFiles() {
|
|
|
11252
11663
|
} catch {
|
|
11253
11664
|
}
|
|
11254
11665
|
}
|
|
11255
|
-
const geminiDir =
|
|
11256
|
-
if (
|
|
11666
|
+
const geminiDir = import_path25.default.join(import_os22.default.homedir(), ".gemini", "tmp");
|
|
11667
|
+
if (import_fs23.default.existsSync(geminiDir)) {
|
|
11257
11668
|
try {
|
|
11258
|
-
for (const slug of
|
|
11259
|
-
const p =
|
|
11669
|
+
for (const slug of import_fs23.default.readdirSync(geminiDir)) {
|
|
11670
|
+
const p = import_path25.default.join(geminiDir, slug);
|
|
11260
11671
|
try {
|
|
11261
|
-
if (!
|
|
11262
|
-
const chatsDir =
|
|
11263
|
-
if (
|
|
11672
|
+
if (!import_fs23.default.statSync(p).isDirectory()) continue;
|
|
11673
|
+
const chatsDir = import_path25.default.join(p, "chats");
|
|
11674
|
+
if (import_fs23.default.existsSync(chatsDir)) {
|
|
11264
11675
|
try {
|
|
11265
|
-
total +=
|
|
11676
|
+
total += import_fs23.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
|
|
11266
11677
|
} catch {
|
|
11267
11678
|
}
|
|
11268
11679
|
}
|
|
@@ -11274,15 +11685,15 @@ function countScanFiles() {
|
|
|
11274
11685
|
}
|
|
11275
11686
|
}
|
|
11276
11687
|
for (const surface of ["antigravity-cli", "antigravity-ide"]) {
|
|
11277
|
-
const brainDir =
|
|
11278
|
-
if (!
|
|
11688
|
+
const brainDir = import_path25.default.join(import_os22.default.homedir(), ".gemini", surface, "brain");
|
|
11689
|
+
if (!import_fs23.default.existsSync(brainDir)) continue;
|
|
11279
11690
|
try {
|
|
11280
|
-
for (const conv of
|
|
11281
|
-
const convPath =
|
|
11691
|
+
for (const conv of import_fs23.default.readdirSync(brainDir)) {
|
|
11692
|
+
const convPath = import_path25.default.join(brainDir, conv);
|
|
11282
11693
|
try {
|
|
11283
|
-
if (!
|
|
11284
|
-
const logsDir =
|
|
11285
|
-
if (
|
|
11694
|
+
if (!import_fs23.default.statSync(convPath).isDirectory()) continue;
|
|
11695
|
+
const logsDir = import_path25.default.join(convPath, ".system_generated", "logs");
|
|
11696
|
+
if (import_fs23.default.existsSync(import_path25.default.join(logsDir, "transcript_full.jsonl")) || import_fs23.default.existsSync(import_path25.default.join(logsDir, "transcript.jsonl"))) {
|
|
11286
11697
|
total += 1;
|
|
11287
11698
|
}
|
|
11288
11699
|
} catch {
|
|
@@ -11292,31 +11703,31 @@ function countScanFiles() {
|
|
|
11292
11703
|
} catch {
|
|
11293
11704
|
}
|
|
11294
11705
|
}
|
|
11295
|
-
const copilotDir =
|
|
11296
|
-
if (
|
|
11706
|
+
const copilotDir = import_path25.default.join(import_os22.default.homedir(), ".copilot", "session-state");
|
|
11707
|
+
if (import_fs23.default.existsSync(copilotDir)) {
|
|
11297
11708
|
try {
|
|
11298
|
-
for (const sid of
|
|
11299
|
-
if (
|
|
11709
|
+
for (const sid of import_fs23.default.readdirSync(copilotDir)) {
|
|
11710
|
+
if (import_fs23.default.existsSync(import_path25.default.join(copilotDir, sid, "events.jsonl"))) total += 1;
|
|
11300
11711
|
}
|
|
11301
11712
|
} catch {
|
|
11302
11713
|
}
|
|
11303
11714
|
}
|
|
11304
|
-
const codexDir =
|
|
11305
|
-
if (
|
|
11715
|
+
const codexDir = import_path25.default.join(import_os22.default.homedir(), ".codex", "sessions");
|
|
11716
|
+
if (import_fs23.default.existsSync(codexDir)) {
|
|
11306
11717
|
try {
|
|
11307
|
-
for (const year of
|
|
11308
|
-
const yp =
|
|
11718
|
+
for (const year of import_fs23.default.readdirSync(codexDir)) {
|
|
11719
|
+
const yp = import_path25.default.join(codexDir, year);
|
|
11309
11720
|
try {
|
|
11310
|
-
if (!
|
|
11311
|
-
for (const month of
|
|
11312
|
-
const mp =
|
|
11721
|
+
if (!import_fs23.default.statSync(yp).isDirectory()) continue;
|
|
11722
|
+
for (const month of import_fs23.default.readdirSync(yp)) {
|
|
11723
|
+
const mp = import_path25.default.join(yp, month);
|
|
11313
11724
|
try {
|
|
11314
|
-
if (!
|
|
11315
|
-
for (const day of
|
|
11316
|
-
const dp =
|
|
11725
|
+
if (!import_fs23.default.statSync(mp).isDirectory()) continue;
|
|
11726
|
+
for (const day of import_fs23.default.readdirSync(mp)) {
|
|
11727
|
+
const dp = import_path25.default.join(mp, day);
|
|
11317
11728
|
try {
|
|
11318
|
-
if (!
|
|
11319
|
-
total +=
|
|
11729
|
+
if (!import_fs23.default.statSync(dp).isDirectory()) continue;
|
|
11730
|
+
total += import_fs23.default.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
|
|
11320
11731
|
} catch {
|
|
11321
11732
|
continue;
|
|
11322
11733
|
}
|
|
@@ -11352,7 +11763,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
11352
11763
|
const sessionId = file.replace(/\.jsonl$/, "");
|
|
11353
11764
|
let raw;
|
|
11354
11765
|
try {
|
|
11355
|
-
raw =
|
|
11766
|
+
raw = import_fs23.default.readFileSync(import_path25.default.join(projPath, file), "utf-8");
|
|
11356
11767
|
} catch {
|
|
11357
11768
|
return;
|
|
11358
11769
|
}
|
|
@@ -11404,7 +11815,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
11404
11815
|
if (block.type !== "tool_result") continue;
|
|
11405
11816
|
const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
|
|
11406
11817
|
if (filePath) {
|
|
11407
|
-
const ext =
|
|
11818
|
+
const ext = import_path25.default.extname(filePath).toLowerCase();
|
|
11408
11819
|
if (CODE_EXTENSIONS.has(ext)) continue;
|
|
11409
11820
|
}
|
|
11410
11821
|
const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
|
|
@@ -11461,7 +11872,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
11461
11872
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
11462
11873
|
if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
|
|
11463
11874
|
const inputFilePath = typeof input.file_path === "string" ? input.file_path : "";
|
|
11464
|
-
const inputFileExt = inputFilePath ?
|
|
11875
|
+
const inputFileExt = inputFilePath ? import_path25.default.extname(inputFilePath).toLowerCase() : "";
|
|
11465
11876
|
if (CODE_EXTENSIONS.has(inputFileExt)) continue;
|
|
11466
11877
|
const dlpMatch = scanArgs(input);
|
|
11467
11878
|
if (dlpMatch) {
|
|
@@ -11558,19 +11969,19 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
11558
11969
|
}
|
|
11559
11970
|
}
|
|
11560
11971
|
function processClaudeProject(proj, projectsDir, ruleSources, startDate, result, dedup, onProgress, onLine) {
|
|
11561
|
-
const projPath =
|
|
11972
|
+
const projPath = import_path25.default.join(projectsDir, proj);
|
|
11562
11973
|
try {
|
|
11563
|
-
if (!
|
|
11974
|
+
if (!import_fs23.default.statSync(projPath).isDirectory()) return;
|
|
11564
11975
|
} catch {
|
|
11565
11976
|
return;
|
|
11566
11977
|
}
|
|
11567
|
-
const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(
|
|
11978
|
+
const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(import_os22.default.homedir(), "~")).slice(
|
|
11568
11979
|
0,
|
|
11569
11980
|
40
|
|
11570
11981
|
);
|
|
11571
11982
|
let files;
|
|
11572
11983
|
try {
|
|
11573
|
-
files =
|
|
11984
|
+
files = import_fs23.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
11574
11985
|
} catch {
|
|
11575
11986
|
return;
|
|
11576
11987
|
}
|
|
@@ -11604,12 +12015,12 @@ function emptyClaudeScan() {
|
|
|
11604
12015
|
};
|
|
11605
12016
|
}
|
|
11606
12017
|
function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
11607
|
-
const projectsDir =
|
|
12018
|
+
const projectsDir = import_path25.default.join(import_os22.default.homedir(), ".claude", "projects");
|
|
11608
12019
|
const result = emptyClaudeScan();
|
|
11609
|
-
if (!
|
|
12020
|
+
if (!import_fs23.default.existsSync(projectsDir)) return result;
|
|
11610
12021
|
let projDirs;
|
|
11611
12022
|
try {
|
|
11612
|
-
projDirs =
|
|
12023
|
+
projDirs = import_fs23.default.readdirSync(projectsDir);
|
|
11613
12024
|
} catch {
|
|
11614
12025
|
return result;
|
|
11615
12026
|
}
|
|
@@ -11630,7 +12041,7 @@ function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
|
11630
12041
|
return result;
|
|
11631
12042
|
}
|
|
11632
12043
|
function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
11633
|
-
const tmpDir =
|
|
12044
|
+
const tmpDir = import_path25.default.join(import_os22.default.homedir(), ".gemini", "tmp");
|
|
11634
12045
|
const result = {
|
|
11635
12046
|
filesScanned: 0,
|
|
11636
12047
|
sessions: 0,
|
|
@@ -11645,33 +12056,33 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
11645
12056
|
sessionsWithEarlySecrets: 0
|
|
11646
12057
|
};
|
|
11647
12058
|
const dedup = emptyScanDedup();
|
|
11648
|
-
if (!
|
|
12059
|
+
if (!import_fs23.default.existsSync(tmpDir)) return result;
|
|
11649
12060
|
let slugDirs;
|
|
11650
12061
|
try {
|
|
11651
|
-
slugDirs =
|
|
12062
|
+
slugDirs = import_fs23.default.readdirSync(tmpDir);
|
|
11652
12063
|
} catch {
|
|
11653
12064
|
return result;
|
|
11654
12065
|
}
|
|
11655
12066
|
const ruleSources = buildRuleSources();
|
|
11656
12067
|
for (const slug of slugDirs) {
|
|
11657
|
-
const slugPath =
|
|
12068
|
+
const slugPath = import_path25.default.join(tmpDir, slug);
|
|
11658
12069
|
try {
|
|
11659
|
-
if (!
|
|
12070
|
+
if (!import_fs23.default.statSync(slugPath).isDirectory()) continue;
|
|
11660
12071
|
} catch {
|
|
11661
12072
|
continue;
|
|
11662
12073
|
}
|
|
11663
12074
|
let projLabel = stripTerminalEscapes(slug).slice(0, 40);
|
|
11664
12075
|
try {
|
|
11665
12076
|
projLabel = stripTerminalEscapes(
|
|
11666
|
-
|
|
11667
|
-
).replace(
|
|
12077
|
+
import_fs23.default.readFileSync(import_path25.default.join(slugPath, ".project_root"), "utf-8").trim()
|
|
12078
|
+
).replace(import_os22.default.homedir(), "~").slice(0, 40);
|
|
11668
12079
|
} catch {
|
|
11669
12080
|
}
|
|
11670
|
-
const chatsDir =
|
|
11671
|
-
if (!
|
|
12081
|
+
const chatsDir = import_path25.default.join(slugPath, "chats");
|
|
12082
|
+
if (!import_fs23.default.existsSync(chatsDir)) continue;
|
|
11672
12083
|
let chatFiles;
|
|
11673
12084
|
try {
|
|
11674
|
-
chatFiles =
|
|
12085
|
+
chatFiles = import_fs23.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
11675
12086
|
} catch {
|
|
11676
12087
|
continue;
|
|
11677
12088
|
}
|
|
@@ -11681,7 +12092,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
11681
12092
|
const sessionId = chatFile.replace(/\.json$/, "");
|
|
11682
12093
|
let raw;
|
|
11683
12094
|
try {
|
|
11684
|
-
raw =
|
|
12095
|
+
raw = import_fs23.default.readFileSync(import_path25.default.join(chatsDir, chatFile), "utf-8");
|
|
11685
12096
|
} catch {
|
|
11686
12097
|
continue;
|
|
11687
12098
|
}
|
|
@@ -11843,13 +12254,13 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
11843
12254
|
return result;
|
|
11844
12255
|
}
|
|
11845
12256
|
function antigravityBrainDirs() {
|
|
11846
|
-
return ["antigravity-cli", "antigravity-ide"].map((surface) =>
|
|
12257
|
+
return ["antigravity-cli", "antigravity-ide"].map((surface) => import_path25.default.join(import_os22.default.homedir(), ".gemini", surface, "brain")).filter((p) => import_fs23.default.existsSync(p));
|
|
11847
12258
|
}
|
|
11848
12259
|
function antigravityTranscriptPath(convPath) {
|
|
11849
|
-
const logsDir =
|
|
12260
|
+
const logsDir = import_path25.default.join(convPath, ".system_generated", "logs");
|
|
11850
12261
|
for (const name of ["transcript_full.jsonl", "transcript.jsonl"]) {
|
|
11851
|
-
const p =
|
|
11852
|
-
if (
|
|
12262
|
+
const p = import_path25.default.join(logsDir, name);
|
|
12263
|
+
if (import_fs23.default.existsSync(p)) return p;
|
|
11853
12264
|
}
|
|
11854
12265
|
return null;
|
|
11855
12266
|
}
|
|
@@ -11875,14 +12286,14 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
11875
12286
|
for (const brainDir of brainDirs) {
|
|
11876
12287
|
let convDirs;
|
|
11877
12288
|
try {
|
|
11878
|
-
convDirs =
|
|
12289
|
+
convDirs = import_fs23.default.readdirSync(brainDir);
|
|
11879
12290
|
} catch {
|
|
11880
12291
|
continue;
|
|
11881
12292
|
}
|
|
11882
12293
|
for (const conv of convDirs) {
|
|
11883
|
-
const convPath =
|
|
12294
|
+
const convPath = import_path25.default.join(brainDir, conv);
|
|
11884
12295
|
try {
|
|
11885
|
-
if (!
|
|
12296
|
+
if (!import_fs23.default.statSync(convPath).isDirectory()) continue;
|
|
11886
12297
|
} catch {
|
|
11887
12298
|
continue;
|
|
11888
12299
|
}
|
|
@@ -11892,7 +12303,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
11892
12303
|
onProgress?.(result.filesScanned);
|
|
11893
12304
|
let raw;
|
|
11894
12305
|
try {
|
|
11895
|
-
raw =
|
|
12306
|
+
raw = import_fs23.default.readFileSync(transcriptFile, "utf-8");
|
|
11896
12307
|
} catch {
|
|
11897
12308
|
continue;
|
|
11898
12309
|
}
|
|
@@ -11949,7 +12360,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
11949
12360
|
result.bashCalls++;
|
|
11950
12361
|
const cwd = String(input.cwd ?? "");
|
|
11951
12362
|
if (cwd && projLabel === conv.slice(0, 8)) {
|
|
11952
|
-
projLabel = stripTerminalEscapes(cwd).replace(
|
|
12363
|
+
projLabel = stripTerminalEscapes(cwd).replace(import_os22.default.homedir(), "~").slice(0, 40);
|
|
11953
12364
|
}
|
|
11954
12365
|
}
|
|
11955
12366
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
@@ -12049,7 +12460,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
12049
12460
|
return result;
|
|
12050
12461
|
}
|
|
12051
12462
|
function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
12052
|
-
const sessionDir =
|
|
12463
|
+
const sessionDir = import_path25.default.join(import_os22.default.homedir(), ".copilot", "session-state");
|
|
12053
12464
|
const result = {
|
|
12054
12465
|
filesScanned: 0,
|
|
12055
12466
|
sessions: 0,
|
|
@@ -12065,22 +12476,22 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
|
12065
12476
|
sessionsWithEarlySecrets: 0
|
|
12066
12477
|
};
|
|
12067
12478
|
const dedup = emptyScanDedup();
|
|
12068
|
-
if (!
|
|
12479
|
+
if (!import_fs23.default.existsSync(sessionDir)) return result;
|
|
12069
12480
|
let sessionIds;
|
|
12070
12481
|
try {
|
|
12071
|
-
sessionIds =
|
|
12482
|
+
sessionIds = import_fs23.default.readdirSync(sessionDir);
|
|
12072
12483
|
} catch {
|
|
12073
12484
|
return result;
|
|
12074
12485
|
}
|
|
12075
12486
|
const ruleSources = buildRuleSources();
|
|
12076
12487
|
for (const sessionId of sessionIds) {
|
|
12077
|
-
const eventsPath =
|
|
12078
|
-
if (!
|
|
12488
|
+
const eventsPath = import_path25.default.join(sessionDir, sessionId, "events.jsonl");
|
|
12489
|
+
if (!import_fs23.default.existsSync(eventsPath)) continue;
|
|
12079
12490
|
result.filesScanned++;
|
|
12080
12491
|
onProgress?.(result.filesScanned);
|
|
12081
12492
|
let raw;
|
|
12082
12493
|
try {
|
|
12083
|
-
raw =
|
|
12494
|
+
raw = import_fs23.default.readFileSync(eventsPath, "utf-8");
|
|
12084
12495
|
} catch {
|
|
12085
12496
|
continue;
|
|
12086
12497
|
}
|
|
@@ -12100,7 +12511,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
|
12100
12511
|
if (ev.type === "session.start") {
|
|
12101
12512
|
const cwd = ev.data?.context?.cwd;
|
|
12102
12513
|
if (typeof cwd === "string" && cwd) {
|
|
12103
|
-
projLabel = stripTerminalEscapes(cwd).replace(
|
|
12514
|
+
projLabel = stripTerminalEscapes(cwd).replace(import_os22.default.homedir(), "~").slice(0, 40);
|
|
12104
12515
|
}
|
|
12105
12516
|
continue;
|
|
12106
12517
|
}
|
|
@@ -12232,7 +12643,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
|
12232
12643
|
return result;
|
|
12233
12644
|
}
|
|
12234
12645
|
function scanCodexHistory(startDate, onProgress, onLine) {
|
|
12235
|
-
const sessionsBase =
|
|
12646
|
+
const sessionsBase = import_path25.default.join(import_os22.default.homedir(), ".codex", "sessions");
|
|
12236
12647
|
const result = {
|
|
12237
12648
|
filesScanned: 0,
|
|
12238
12649
|
sessions: 0,
|
|
@@ -12247,32 +12658,32 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
12247
12658
|
sessionsWithEarlySecrets: 0
|
|
12248
12659
|
};
|
|
12249
12660
|
const dedup = emptyScanDedup();
|
|
12250
|
-
if (!
|
|
12661
|
+
if (!import_fs23.default.existsSync(sessionsBase)) return result;
|
|
12251
12662
|
const jsonlFiles = [];
|
|
12252
12663
|
try {
|
|
12253
|
-
for (const year of
|
|
12254
|
-
const yearPath =
|
|
12664
|
+
for (const year of import_fs23.default.readdirSync(sessionsBase)) {
|
|
12665
|
+
const yearPath = import_path25.default.join(sessionsBase, year);
|
|
12255
12666
|
try {
|
|
12256
|
-
if (!
|
|
12667
|
+
if (!import_fs23.default.statSync(yearPath).isDirectory()) continue;
|
|
12257
12668
|
} catch {
|
|
12258
12669
|
continue;
|
|
12259
12670
|
}
|
|
12260
|
-
for (const month of
|
|
12261
|
-
const monthPath =
|
|
12671
|
+
for (const month of import_fs23.default.readdirSync(yearPath)) {
|
|
12672
|
+
const monthPath = import_path25.default.join(yearPath, month);
|
|
12262
12673
|
try {
|
|
12263
|
-
if (!
|
|
12674
|
+
if (!import_fs23.default.statSync(monthPath).isDirectory()) continue;
|
|
12264
12675
|
} catch {
|
|
12265
12676
|
continue;
|
|
12266
12677
|
}
|
|
12267
|
-
for (const day of
|
|
12268
|
-
const dayPath =
|
|
12678
|
+
for (const day of import_fs23.default.readdirSync(monthPath)) {
|
|
12679
|
+
const dayPath = import_path25.default.join(monthPath, day);
|
|
12269
12680
|
try {
|
|
12270
|
-
if (!
|
|
12681
|
+
if (!import_fs23.default.statSync(dayPath).isDirectory()) continue;
|
|
12271
12682
|
} catch {
|
|
12272
12683
|
continue;
|
|
12273
12684
|
}
|
|
12274
|
-
for (const file of
|
|
12275
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
12685
|
+
for (const file of import_fs23.default.readdirSync(dayPath)) {
|
|
12686
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path25.default.join(dayPath, file));
|
|
12276
12687
|
}
|
|
12277
12688
|
}
|
|
12278
12689
|
}
|
|
@@ -12286,7 +12697,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
12286
12697
|
onProgress?.(result.filesScanned);
|
|
12287
12698
|
let lines;
|
|
12288
12699
|
try {
|
|
12289
|
-
lines =
|
|
12700
|
+
lines = import_fs23.default.readFileSync(filePath, "utf-8").split("\n");
|
|
12290
12701
|
} catch {
|
|
12291
12702
|
continue;
|
|
12292
12703
|
}
|
|
@@ -12312,7 +12723,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
12312
12723
|
sessionId = String(payload["id"] ?? filePath);
|
|
12313
12724
|
startTime = String(payload["timestamp"] ?? "");
|
|
12314
12725
|
const cwd = String(payload["cwd"] ?? "");
|
|
12315
|
-
projLabel = stripTerminalEscapes(cwd.replace(
|
|
12726
|
+
projLabel = stripTerminalEscapes(cwd.replace(import_os22.default.homedir(), "~")).slice(0, 40);
|
|
12316
12727
|
continue;
|
|
12317
12728
|
}
|
|
12318
12729
|
if (entry.type === "event_msg" && payload["type"] === "token_count") {
|
|
@@ -12465,17 +12876,17 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
12465
12876
|
return result;
|
|
12466
12877
|
}
|
|
12467
12878
|
function scanShellConfig() {
|
|
12468
|
-
const home =
|
|
12879
|
+
const home = import_os22.default.homedir();
|
|
12469
12880
|
const configFiles = [".zshrc", ".bashrc", ".bash_profile", ".profile"].map(
|
|
12470
|
-
(f) =>
|
|
12881
|
+
(f) => import_path25.default.join(home, f)
|
|
12471
12882
|
);
|
|
12472
12883
|
const findings = [];
|
|
12473
12884
|
const seen = /* @__PURE__ */ new Set();
|
|
12474
12885
|
for (const filePath of configFiles) {
|
|
12475
|
-
if (!
|
|
12886
|
+
if (!import_fs23.default.existsSync(filePath)) continue;
|
|
12476
12887
|
let lines;
|
|
12477
12888
|
try {
|
|
12478
|
-
lines =
|
|
12889
|
+
lines = import_fs23.default.readFileSync(filePath, "utf-8").split("\n");
|
|
12479
12890
|
} catch {
|
|
12480
12891
|
continue;
|
|
12481
12892
|
}
|
|
@@ -13281,7 +13692,7 @@ function registerScanCommand(program2) {
|
|
|
13281
13692
|
if (!drillDown) {
|
|
13282
13693
|
const useInk2 = !options.classic;
|
|
13283
13694
|
if (useInk2) {
|
|
13284
|
-
const scanInkPath =
|
|
13695
|
+
const scanInkPath = import_path25.default.join(__dirname, "scan-ink.mjs");
|
|
13285
13696
|
const dynamicImport = new Function("id", "return import(id)");
|
|
13286
13697
|
const mod = await dynamicImport(`file://${scanInkPath}`);
|
|
13287
13698
|
const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
|
|
@@ -13506,14 +13917,14 @@ function registerScanCommand(program2) {
|
|
|
13506
13917
|
}
|
|
13507
13918
|
);
|
|
13508
13919
|
}
|
|
13509
|
-
var import_chalk5,
|
|
13920
|
+
var import_chalk5, import_fs23, import_path25, import_os22, import_string_width2, CLAUDE_PRICING, GEMINI_PRICING, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS, FIXTURE_TOKEN_PATTERNS, TERMINAL_ESCAPE_RE2, LOOP_TOOLS, LOOP_THRESHOLD, LOOP_TIMESPAN_THRESHOLD_MS, STUCK_TOOLS_MIN_WASTE, STUCK_TOOLS_LIMIT, RECURRING_SESSION_THRESHOLD, STALE_AGE_DAYS, classifyRuleSeverity2, narrativeRuleLabel2;
|
|
13510
13921
|
var init_scan = __esm({
|
|
13511
13922
|
"src/cli/commands/scan.ts"() {
|
|
13512
13923
|
"use strict";
|
|
13513
13924
|
import_chalk5 = __toESM(require("chalk"));
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
|
|
13925
|
+
import_fs23 = __toESM(require("fs"));
|
|
13926
|
+
import_path25 = __toESM(require("path"));
|
|
13927
|
+
import_os22 = __toESM(require("os"));
|
|
13517
13928
|
init_shields();
|
|
13518
13929
|
init_config();
|
|
13519
13930
|
init_policy();
|
|
@@ -13707,12 +14118,12 @@ var init_suggestion_tracker = __esm({
|
|
|
13707
14118
|
});
|
|
13708
14119
|
|
|
13709
14120
|
// src/daemon/taint-store.ts
|
|
13710
|
-
var
|
|
14121
|
+
var import_fs24, import_path26, DEFAULT_TTL_MS, TaintStore;
|
|
13711
14122
|
var init_taint_store = __esm({
|
|
13712
14123
|
"src/daemon/taint-store.ts"() {
|
|
13713
14124
|
"use strict";
|
|
13714
|
-
|
|
13715
|
-
|
|
14125
|
+
import_fs24 = __toESM(require("fs"));
|
|
14126
|
+
import_path26 = __toESM(require("path"));
|
|
13716
14127
|
DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
13717
14128
|
TaintStore = class {
|
|
13718
14129
|
records = /* @__PURE__ */ new Map();
|
|
@@ -13777,9 +14188,9 @@ var init_taint_store = __esm({
|
|
|
13777
14188
|
/** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
|
|
13778
14189
|
_resolve(filePath) {
|
|
13779
14190
|
try {
|
|
13780
|
-
return
|
|
14191
|
+
return import_fs24.default.realpathSync.native(import_path26.default.resolve(filePath));
|
|
13781
14192
|
} catch {
|
|
13782
|
-
return
|
|
14193
|
+
return import_path26.default.resolve(filePath);
|
|
13783
14194
|
}
|
|
13784
14195
|
}
|
|
13785
14196
|
};
|
|
@@ -13897,8 +14308,8 @@ var init_session_history = __esm({
|
|
|
13897
14308
|
// src/daemon/state.ts
|
|
13898
14309
|
function loadInsightCounts() {
|
|
13899
14310
|
try {
|
|
13900
|
-
if (!
|
|
13901
|
-
const data = JSON.parse(
|
|
14311
|
+
if (!import_fs25.default.existsSync(INSIGHT_COUNTS_FILE)) return;
|
|
14312
|
+
const data = JSON.parse(import_fs25.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
|
|
13902
14313
|
for (const [tool, count] of Object.entries(data)) {
|
|
13903
14314
|
if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
|
|
13904
14315
|
}
|
|
@@ -13937,23 +14348,23 @@ function markRejectionHandlerRegistered() {
|
|
|
13937
14348
|
daemonRejectionHandlerRegistered = true;
|
|
13938
14349
|
}
|
|
13939
14350
|
function atomicWriteSync2(filePath, data, options) {
|
|
13940
|
-
const dir =
|
|
13941
|
-
if (!
|
|
14351
|
+
const dir = import_path27.default.dirname(filePath);
|
|
14352
|
+
if (!import_fs25.default.existsSync(dir)) import_fs25.default.mkdirSync(dir, { recursive: true });
|
|
13942
14353
|
const tmpPath = `${filePath}.${(0, import_crypto8.randomUUID)()}.tmp`;
|
|
13943
14354
|
try {
|
|
13944
|
-
|
|
14355
|
+
import_fs25.default.writeFileSync(tmpPath, data, options);
|
|
13945
14356
|
} catch (err2) {
|
|
13946
14357
|
try {
|
|
13947
|
-
|
|
14358
|
+
import_fs25.default.unlinkSync(tmpPath);
|
|
13948
14359
|
} catch {
|
|
13949
14360
|
}
|
|
13950
14361
|
throw err2;
|
|
13951
14362
|
}
|
|
13952
14363
|
try {
|
|
13953
|
-
|
|
14364
|
+
import_fs25.default.renameSync(tmpPath, filePath);
|
|
13954
14365
|
} catch (err2) {
|
|
13955
14366
|
try {
|
|
13956
|
-
|
|
14367
|
+
import_fs25.default.unlinkSync(tmpPath);
|
|
13957
14368
|
} catch {
|
|
13958
14369
|
}
|
|
13959
14370
|
throw err2;
|
|
@@ -13977,16 +14388,16 @@ function appendAuditLog(data) {
|
|
|
13977
14388
|
decision: data.decision,
|
|
13978
14389
|
source: "daemon"
|
|
13979
14390
|
};
|
|
13980
|
-
const dir =
|
|
13981
|
-
if (!
|
|
13982
|
-
|
|
14391
|
+
const dir = import_path27.default.dirname(AUDIT_LOG_FILE);
|
|
14392
|
+
if (!import_fs25.default.existsSync(dir)) import_fs25.default.mkdirSync(dir, { recursive: true });
|
|
14393
|
+
import_fs25.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
13983
14394
|
} catch {
|
|
13984
14395
|
}
|
|
13985
14396
|
}
|
|
13986
14397
|
function getAuditHistory(limit = 20) {
|
|
13987
14398
|
try {
|
|
13988
|
-
if (!
|
|
13989
|
-
const lines =
|
|
14399
|
+
if (!import_fs25.default.existsSync(AUDIT_LOG_FILE)) return [];
|
|
14400
|
+
const lines = import_fs25.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
|
|
13990
14401
|
if (lines.length === 1 && lines[0] === "") return [];
|
|
13991
14402
|
return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
|
|
13992
14403
|
} catch {
|
|
@@ -13995,7 +14406,7 @@ function getAuditHistory(limit = 20) {
|
|
|
13995
14406
|
}
|
|
13996
14407
|
function getOrgName() {
|
|
13997
14408
|
try {
|
|
13998
|
-
if (
|
|
14409
|
+
if (import_fs25.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
|
|
13999
14410
|
} catch {
|
|
14000
14411
|
}
|
|
14001
14412
|
return null;
|
|
@@ -14003,8 +14414,8 @@ function getOrgName() {
|
|
|
14003
14414
|
function writeGlobalSetting(key, value) {
|
|
14004
14415
|
let config = {};
|
|
14005
14416
|
try {
|
|
14006
|
-
if (
|
|
14007
|
-
config = JSON.parse(
|
|
14417
|
+
if (import_fs25.default.existsSync(GLOBAL_CONFIG_FILE)) {
|
|
14418
|
+
config = JSON.parse(import_fs25.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
|
|
14008
14419
|
}
|
|
14009
14420
|
} catch {
|
|
14010
14421
|
}
|
|
@@ -14016,8 +14427,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
14016
14427
|
try {
|
|
14017
14428
|
let trust = { entries: [] };
|
|
14018
14429
|
try {
|
|
14019
|
-
if (
|
|
14020
|
-
trust = JSON.parse(
|
|
14430
|
+
if (import_fs25.default.existsSync(TRUST_FILE2))
|
|
14431
|
+
trust = JSON.parse(import_fs25.default.readFileSync(TRUST_FILE2, "utf-8"));
|
|
14021
14432
|
} catch {
|
|
14022
14433
|
}
|
|
14023
14434
|
trust.entries = trust.entries.filter(
|
|
@@ -14034,8 +14445,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
14034
14445
|
}
|
|
14035
14446
|
function readPersistentDecisions() {
|
|
14036
14447
|
try {
|
|
14037
|
-
if (
|
|
14038
|
-
return JSON.parse(
|
|
14448
|
+
if (import_fs25.default.existsSync(DECISIONS_FILE)) {
|
|
14449
|
+
return JSON.parse(import_fs25.default.readFileSync(DECISIONS_FILE, "utf-8"));
|
|
14039
14450
|
}
|
|
14040
14451
|
} catch {
|
|
14041
14452
|
}
|
|
@@ -14052,7 +14463,7 @@ function writePersistentDecision(toolName, decision) {
|
|
|
14052
14463
|
function readBody(req) {
|
|
14053
14464
|
return new Promise((resolve) => {
|
|
14054
14465
|
let body = "";
|
|
14055
|
-
req.on("data", (
|
|
14466
|
+
req.on("data", (chunk2) => body += chunk2);
|
|
14056
14467
|
req.on("end", () => resolve(body));
|
|
14057
14468
|
});
|
|
14058
14469
|
}
|
|
@@ -14063,7 +14474,7 @@ function estimateToolCost(tool, args) {
|
|
|
14063
14474
|
const filePath = a.file_path ?? a.path;
|
|
14064
14475
|
if (filePath) {
|
|
14065
14476
|
try {
|
|
14066
|
-
const bytes =
|
|
14477
|
+
const bytes = import_fs25.default.statSync(filePath).size;
|
|
14067
14478
|
return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
|
|
14068
14479
|
} catch {
|
|
14069
14480
|
}
|
|
@@ -14134,7 +14545,7 @@ function abandonPending() {
|
|
|
14134
14545
|
});
|
|
14135
14546
|
if (autoStarted) {
|
|
14136
14547
|
try {
|
|
14137
|
-
|
|
14548
|
+
import_fs25.default.unlinkSync(DAEMON_PID_FILE);
|
|
14138
14549
|
} catch {
|
|
14139
14550
|
}
|
|
14140
14551
|
setTimeout(() => {
|
|
@@ -14145,8 +14556,8 @@ function abandonPending() {
|
|
|
14145
14556
|
}
|
|
14146
14557
|
function logActivitySocket(msg) {
|
|
14147
14558
|
try {
|
|
14148
|
-
|
|
14149
|
-
|
|
14559
|
+
import_fs25.default.appendFileSync(
|
|
14560
|
+
import_path27.default.join(homeDir, ".node9", "hook-debug.log"),
|
|
14150
14561
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
|
|
14151
14562
|
`
|
|
14152
14563
|
);
|
|
@@ -14168,13 +14579,13 @@ function shouldRebind(now = Date.now()) {
|
|
|
14168
14579
|
function startActivitySocket() {
|
|
14169
14580
|
bindActivitySocket();
|
|
14170
14581
|
activityHealthInterval = setInterval(() => {
|
|
14171
|
-
if (!
|
|
14582
|
+
if (!import_fs25.default.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
|
|
14172
14583
|
}, ACTIVITY_HEALTH_PROBE_MS);
|
|
14173
14584
|
activityHealthInterval.unref();
|
|
14174
14585
|
process.on("exit", () => {
|
|
14175
14586
|
if (activityHealthInterval) clearInterval(activityHealthInterval);
|
|
14176
14587
|
try {
|
|
14177
|
-
|
|
14588
|
+
import_fs25.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
14178
14589
|
} catch {
|
|
14179
14590
|
}
|
|
14180
14591
|
});
|
|
@@ -14202,20 +14613,20 @@ function attemptRebind(reason) {
|
|
|
14202
14613
|
}
|
|
14203
14614
|
function bindActivitySocket() {
|
|
14204
14615
|
try {
|
|
14205
|
-
|
|
14616
|
+
import_fs25.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
14206
14617
|
} catch {
|
|
14207
14618
|
}
|
|
14208
14619
|
const ACTIVITY_MAX_BYTES = 1024 * 1024;
|
|
14209
14620
|
const unixServer = import_net2.default.createServer((socket) => {
|
|
14210
14621
|
const chunks = [];
|
|
14211
14622
|
let bytesReceived = 0;
|
|
14212
|
-
socket.on("data", (
|
|
14213
|
-
bytesReceived +=
|
|
14623
|
+
socket.on("data", (chunk2) => {
|
|
14624
|
+
bytesReceived += chunk2.length;
|
|
14214
14625
|
if (bytesReceived > ACTIVITY_MAX_BYTES) {
|
|
14215
14626
|
socket.destroy();
|
|
14216
14627
|
return;
|
|
14217
14628
|
}
|
|
14218
|
-
chunks.push(
|
|
14629
|
+
chunks.push(chunk2);
|
|
14219
14630
|
});
|
|
14220
14631
|
socket.on("end", () => {
|
|
14221
14632
|
try {
|
|
@@ -14306,28 +14717,28 @@ function bindActivitySocket() {
|
|
|
14306
14717
|
});
|
|
14307
14718
|
activitySocketServer = unixServer;
|
|
14308
14719
|
}
|
|
14309
|
-
var import_net2,
|
|
14720
|
+
var import_net2, import_fs25, import_path27, import_os23, import_crypto8, homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, pending, sseClients, suggestionTracker, taintStore, insightCounts, _abandonTimer, _hadBrowserClient, _daemonServer, daemonRejectionHandlerRegistered, AUTO_DENY_MS, TRUST_DURATIONS, autoStarted, ACTIVITY_SOCKET_PATH2, ACTIVITY_RING_SIZE, activityRing, LARGE_RESPONSE_RING_SIZE, largeResponseRing, cachedScanResult, cachedScanTs, SCAN_CACHE_TTL_MS, SECRET_KEY_RE, INPUT_PRICE_PER_1M, OUTPUT_PRICE_PER_1M, BYTES_PER_TOKEN, CRITICAL_FORENSIC_CATEGORIES, WRITE_TOOL_NAMES, ACTIVITY_REBIND_MAX_ATTEMPTS, ACTIVITY_REBIND_WINDOW_MS, ACTIVITY_HEALTH_PROBE_MS, activitySocketServer, activityHealthInterval, activityRebindAttempts, activityCircuitTripped;
|
|
14310
14721
|
var init_state2 = __esm({
|
|
14311
14722
|
"src/daemon/state.ts"() {
|
|
14312
14723
|
"use strict";
|
|
14313
14724
|
import_net2 = __toESM(require("net"));
|
|
14314
|
-
|
|
14315
|
-
|
|
14316
|
-
|
|
14725
|
+
import_fs25 = __toESM(require("fs"));
|
|
14726
|
+
import_path27 = __toESM(require("path"));
|
|
14727
|
+
import_os23 = __toESM(require("os"));
|
|
14317
14728
|
import_crypto8 = require("crypto");
|
|
14318
14729
|
init_daemon();
|
|
14319
14730
|
init_suggestion_tracker();
|
|
14320
14731
|
init_taint_store();
|
|
14321
14732
|
init_session_counters();
|
|
14322
14733
|
init_session_history();
|
|
14323
|
-
homeDir =
|
|
14324
|
-
DAEMON_PID_FILE =
|
|
14325
|
-
DECISIONS_FILE =
|
|
14326
|
-
AUDIT_LOG_FILE =
|
|
14327
|
-
TRUST_FILE2 =
|
|
14328
|
-
GLOBAL_CONFIG_FILE =
|
|
14329
|
-
CREDENTIALS_FILE =
|
|
14330
|
-
INSIGHT_COUNTS_FILE =
|
|
14734
|
+
homeDir = import_os23.default.homedir();
|
|
14735
|
+
DAEMON_PID_FILE = import_path27.default.join(homeDir, ".node9", "daemon.pid");
|
|
14736
|
+
DECISIONS_FILE = import_path27.default.join(homeDir, ".node9", "decisions.json");
|
|
14737
|
+
AUDIT_LOG_FILE = import_path27.default.join(homeDir, ".node9", "audit.log");
|
|
14738
|
+
TRUST_FILE2 = import_path27.default.join(homeDir, ".node9", "trust.json");
|
|
14739
|
+
GLOBAL_CONFIG_FILE = import_path27.default.join(homeDir, ".node9", "config.json");
|
|
14740
|
+
CREDENTIALS_FILE = import_path27.default.join(homeDir, ".node9", "credentials.json");
|
|
14741
|
+
INSIGHT_COUNTS_FILE = import_path27.default.join(homeDir, ".node9", "insight-counts.json");
|
|
14331
14742
|
pending = /* @__PURE__ */ new Map();
|
|
14332
14743
|
sseClients = /* @__PURE__ */ new Set();
|
|
14333
14744
|
suggestionTracker = new SuggestionTracker(3);
|
|
@@ -14344,7 +14755,7 @@ var init_state2 = __esm({
|
|
|
14344
14755
|
"2h": 2 * 60 * 6e4
|
|
14345
14756
|
};
|
|
14346
14757
|
autoStarted = process.env.NODE9_AUTO_STARTED === "1";
|
|
14347
|
-
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
14758
|
+
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path27.default.join(import_os23.default.tmpdir(), "node9-activity.sock");
|
|
14348
14759
|
ACTIVITY_RING_SIZE = 100;
|
|
14349
14760
|
activityRing = [];
|
|
14350
14761
|
LARGE_RESPONSE_RING_SIZE = 20;
|
|
@@ -14422,8 +14833,8 @@ function readCredentials() {
|
|
|
14422
14833
|
};
|
|
14423
14834
|
}
|
|
14424
14835
|
try {
|
|
14425
|
-
const credPath =
|
|
14426
|
-
const creds = JSON.parse(
|
|
14836
|
+
const credPath = import_path28.default.join(import_os24.default.homedir(), ".node9", "credentials.json");
|
|
14837
|
+
const creds = JSON.parse(import_fs26.default.readFileSync(credPath, "utf-8"));
|
|
14427
14838
|
const profileName = process.env.NODE9_PROFILE ?? "default";
|
|
14428
14839
|
const profile = creds[profileName];
|
|
14429
14840
|
if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
|
|
@@ -14449,7 +14860,7 @@ function readCredentials() {
|
|
|
14449
14860
|
}
|
|
14450
14861
|
function readCachedEtag() {
|
|
14451
14862
|
try {
|
|
14452
|
-
const raw = JSON.parse(
|
|
14863
|
+
const raw = JSON.parse(import_fs26.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
14453
14864
|
return typeof raw.etag === "string" ? raw.etag : void 0;
|
|
14454
14865
|
} catch {
|
|
14455
14866
|
return void 0;
|
|
@@ -14479,7 +14890,7 @@ function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
|
|
|
14479
14890
|
return;
|
|
14480
14891
|
}
|
|
14481
14892
|
const chunks = [];
|
|
14482
|
-
res.on("data", (
|
|
14893
|
+
res.on("data", (chunk2) => chunks.push(chunk2));
|
|
14483
14894
|
res.on("end", () => {
|
|
14484
14895
|
if (res.statusCode !== 200) {
|
|
14485
14896
|
reject(new Error(`API returned ${res.statusCode ?? "unknown"}`));
|
|
@@ -14510,9 +14921,9 @@ function extractRules(body) {
|
|
|
14510
14921
|
return [];
|
|
14511
14922
|
}
|
|
14512
14923
|
function writeCache2(cache) {
|
|
14513
|
-
const dir =
|
|
14514
|
-
if (!
|
|
14515
|
-
|
|
14924
|
+
const dir = import_path28.default.dirname(rulesCacheFile());
|
|
14925
|
+
if (!import_fs26.default.existsSync(dir)) import_fs26.default.mkdirSync(dir, { recursive: true });
|
|
14926
|
+
import_fs26.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
|
|
14516
14927
|
}
|
|
14517
14928
|
async function syncOnce() {
|
|
14518
14929
|
const creds = readCredentials();
|
|
@@ -14669,7 +15080,7 @@ async function runCloudSync() {
|
|
|
14669
15080
|
}
|
|
14670
15081
|
function getCloudSyncStatus() {
|
|
14671
15082
|
try {
|
|
14672
|
-
const raw = JSON.parse(
|
|
15083
|
+
const raw = JSON.parse(import_fs26.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
14673
15084
|
if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
|
|
14674
15085
|
return {
|
|
14675
15086
|
cached: true,
|
|
@@ -14686,7 +15097,7 @@ function getCloudSyncStatus() {
|
|
|
14686
15097
|
}
|
|
14687
15098
|
function getCloudRules() {
|
|
14688
15099
|
try {
|
|
14689
|
-
const raw = JSON.parse(
|
|
15100
|
+
const raw = JSON.parse(import_fs26.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
14690
15101
|
return Array.isArray(raw.rules) ? raw.rules : null;
|
|
14691
15102
|
} catch {
|
|
14692
15103
|
return null;
|
|
@@ -14720,14 +15131,14 @@ function startForensicBroadcast() {
|
|
|
14720
15131
|
const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
|
|
14721
15132
|
recurring.unref();
|
|
14722
15133
|
}
|
|
14723
|
-
var
|
|
15134
|
+
var import_fs26, import_https2, import_os24, import_path28, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
|
|
14724
15135
|
var init_sync = __esm({
|
|
14725
15136
|
"src/daemon/sync.ts"() {
|
|
14726
15137
|
"use strict";
|
|
14727
|
-
|
|
15138
|
+
import_fs26 = __toESM(require("fs"));
|
|
14728
15139
|
import_https2 = __toESM(require("https"));
|
|
14729
|
-
|
|
14730
|
-
|
|
15140
|
+
import_os24 = __toESM(require("os"));
|
|
15141
|
+
import_path28 = __toESM(require("path"));
|
|
14731
15142
|
init_config();
|
|
14732
15143
|
init_blast();
|
|
14733
15144
|
init_dist();
|
|
@@ -14746,7 +15157,7 @@ var init_sync = __esm({
|
|
|
14746
15157
|
loop: "loops",
|
|
14747
15158
|
"long-output-redacted": "longOutputRedactions"
|
|
14748
15159
|
};
|
|
14749
|
-
rulesCacheFile = () =>
|
|
15160
|
+
rulesCacheFile = () => import_path28.default.join(import_os24.default.homedir(), ".node9", "rules-cache.json");
|
|
14750
15161
|
DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
|
|
14751
15162
|
DEFAULT_INTERVAL_HOURS = 5;
|
|
14752
15163
|
MIN_INTERVAL_HOURS = 1;
|
|
@@ -14770,21 +15181,21 @@ __export(audit_shipper_exports, {
|
|
|
14770
15181
|
writeWatermark: () => writeWatermark
|
|
14771
15182
|
});
|
|
14772
15183
|
function fileSignature(filePath) {
|
|
14773
|
-
const fd =
|
|
15184
|
+
const fd = import_fs27.default.openSync(filePath, "r");
|
|
14774
15185
|
try {
|
|
14775
15186
|
const buf = Buffer.alloc(512);
|
|
14776
|
-
const read =
|
|
15187
|
+
const read = import_fs27.default.readSync(fd, buf, 0, 512, 0);
|
|
14777
15188
|
const slice = buf.subarray(0, read);
|
|
14778
15189
|
const nl = slice.indexOf(10);
|
|
14779
15190
|
const firstLine = nl === -1 ? slice : slice.subarray(0, nl);
|
|
14780
15191
|
return import_crypto9.default.createHash("sha256").update(firstLine).digest("hex").slice(0, 16);
|
|
14781
15192
|
} finally {
|
|
14782
|
-
|
|
15193
|
+
import_fs27.default.closeSync(fd);
|
|
14783
15194
|
}
|
|
14784
15195
|
}
|
|
14785
15196
|
function readWatermark(watermarkPath) {
|
|
14786
15197
|
try {
|
|
14787
|
-
const raw = JSON.parse(
|
|
15198
|
+
const raw = JSON.parse(import_fs27.default.readFileSync(watermarkPath, "utf-8"));
|
|
14788
15199
|
if (typeof raw.fileSig === "string" && typeof raw.offset === "number" && raw.offset >= 0)
|
|
14789
15200
|
return raw;
|
|
14790
15201
|
} catch {
|
|
@@ -14793,13 +15204,13 @@ function readWatermark(watermarkPath) {
|
|
|
14793
15204
|
}
|
|
14794
15205
|
function writeWatermark(watermarkPath, wm) {
|
|
14795
15206
|
const tmp = `${watermarkPath}.tmp`;
|
|
14796
|
-
|
|
14797
|
-
|
|
15207
|
+
import_fs27.default.writeFileSync(tmp, JSON.stringify(wm));
|
|
15208
|
+
import_fs27.default.renameSync(tmp, watermarkPath);
|
|
14798
15209
|
}
|
|
14799
|
-
function buildWireRows(
|
|
14800
|
-
const lastNl =
|
|
15210
|
+
function buildWireRows(chunk2) {
|
|
15211
|
+
const lastNl = chunk2.lastIndexOf(10);
|
|
14801
15212
|
if (lastNl === -1) return { rows: [], consumed: 0 };
|
|
14802
|
-
const complete =
|
|
15213
|
+
const complete = chunk2.subarray(0, lastNl + 1);
|
|
14803
15214
|
const rows = [];
|
|
14804
15215
|
for (const line of complete.toString("utf-8").split("\n")) {
|
|
14805
15216
|
if (!line.trim()) continue;
|
|
@@ -14833,7 +15244,10 @@ function buildWireRows(chunk) {
|
|
|
14833
15244
|
...typeof parsed.sessionId === "string" ? { sessionId: parsed.sessionId } : {},
|
|
14834
15245
|
...typeof parsed.dlpPattern === "string" ? { dlpPattern: parsed.dlpPattern } : {},
|
|
14835
15246
|
...typeof parsed.dlpSample === "string" ? { dlpSample: parsed.dlpSample } : {},
|
|
14836
|
-
...cloudRequestId ? { cloudRequestId } : {}
|
|
15247
|
+
...cloudRequestId ? { cloudRequestId } : {},
|
|
15248
|
+
...typeof parsed.workingDir === "string" ? { workingDir: parsed.workingDir } : {},
|
|
15249
|
+
...typeof parsed.platform === "string" ? { platform: parsed.platform } : {},
|
|
15250
|
+
...typeof parsed.shellType === "string" ? { shellType: parsed.shellType } : {}
|
|
14837
15251
|
});
|
|
14838
15252
|
}
|
|
14839
15253
|
return { rows, consumed: lastNl + 1 };
|
|
@@ -14862,11 +15276,11 @@ async function shipOnce(deps = {}) {
|
|
|
14862
15276
|
if (!creds?.apiKey) return { status: "no-creds", shipped: 0 };
|
|
14863
15277
|
const endpoint = buildBatchEndpoint(creds.apiUrl);
|
|
14864
15278
|
if (!endpoint) return { status: "no-creds", shipped: 0 };
|
|
14865
|
-
if (!
|
|
15279
|
+
if (!import_fs27.default.existsSync(auditLogPath)) return { status: "idle", shipped: 0 };
|
|
14866
15280
|
let shipped = 0;
|
|
14867
15281
|
try {
|
|
14868
15282
|
for (let chunkN = 0; chunkN < MAX_CHUNKS_PER_TICK; chunkN++) {
|
|
14869
|
-
const size =
|
|
15283
|
+
const size = import_fs27.default.statSync(auditLogPath).size;
|
|
14870
15284
|
if (size === 0) break;
|
|
14871
15285
|
const sig = fileSignature(auditLogPath);
|
|
14872
15286
|
const wm = readWatermark(watermarkPath);
|
|
@@ -14874,12 +15288,12 @@ async function shipOnce(deps = {}) {
|
|
|
14874
15288
|
if (offset >= size) break;
|
|
14875
15289
|
const toRead = Math.min(size - offset, MAX_CHUNK_BYTES);
|
|
14876
15290
|
const buf = Buffer.alloc(toRead);
|
|
14877
|
-
const fd =
|
|
15291
|
+
const fd = import_fs27.default.openSync(auditLogPath, "r");
|
|
14878
15292
|
let read;
|
|
14879
15293
|
try {
|
|
14880
|
-
read =
|
|
15294
|
+
read = import_fs27.default.readSync(fd, buf, 0, toRead, offset);
|
|
14881
15295
|
} finally {
|
|
14882
|
-
|
|
15296
|
+
import_fs27.default.closeSync(fd);
|
|
14883
15297
|
}
|
|
14884
15298
|
const { rows, consumed } = buildWireRows(buf.subarray(0, read));
|
|
14885
15299
|
if (consumed === 0) break;
|
|
@@ -14926,8 +15340,8 @@ async function shipOnce(deps = {}) {
|
|
|
14926
15340
|
}
|
|
14927
15341
|
function shipLagBytes(auditLogPath = LOCAL_AUDIT_LOG, watermarkPath = AUDIT_SHIP_WATERMARK) {
|
|
14928
15342
|
try {
|
|
14929
|
-
if (!
|
|
14930
|
-
const size =
|
|
15343
|
+
if (!import_fs27.default.existsSync(auditLogPath)) return 0;
|
|
15344
|
+
const size = import_fs27.default.statSync(auditLogPath).size;
|
|
14931
15345
|
const wm = readWatermark(watermarkPath);
|
|
14932
15346
|
if (!wm) return size;
|
|
14933
15347
|
if (wm.fileSig !== fileSignature(auditLogPath)) return size;
|
|
@@ -14950,19 +15364,19 @@ function startAuditShipper() {
|
|
|
14950
15364
|
setTimeout(() => void shipOnce(), 3e3);
|
|
14951
15365
|
setInterval(() => void shipOnce(), intervalMs);
|
|
14952
15366
|
}
|
|
14953
|
-
var
|
|
15367
|
+
var import_fs27, import_path29, import_os25, import_crypto9, AUDIT_SHIP_WATERMARK, DEFAULT_INTERVAL_MS, MAX_BATCH, MAX_CHUNK_BYTES, MAX_CHUNKS_PER_TICK, FETCH_TIMEOUT_MS, SKIP_CHECKED_BY, shipperStarted;
|
|
14954
15368
|
var init_audit_shipper = __esm({
|
|
14955
15369
|
"src/daemon/audit-shipper.ts"() {
|
|
14956
15370
|
"use strict";
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
15371
|
+
import_fs27 = __toESM(require("fs"));
|
|
15372
|
+
import_path29 = __toESM(require("path"));
|
|
15373
|
+
import_os25 = __toESM(require("os"));
|
|
14960
15374
|
import_crypto9 = __toESM(require("crypto"));
|
|
14961
15375
|
init_audit();
|
|
14962
15376
|
init_config();
|
|
14963
15377
|
init_sync();
|
|
14964
15378
|
init_cloud();
|
|
14965
|
-
AUDIT_SHIP_WATERMARK =
|
|
15379
|
+
AUDIT_SHIP_WATERMARK = import_path29.default.join(import_os25.default.homedir(), ".node9", "audit-ship.json");
|
|
14966
15380
|
DEFAULT_INTERVAL_MS = 2e4;
|
|
14967
15381
|
MAX_BATCH = 500;
|
|
14968
15382
|
MAX_CHUNK_BYTES = 4 * 1024 * 1024;
|
|
@@ -14976,70 +15390,70 @@ var init_audit_shipper = __esm({
|
|
|
14976
15390
|
// src/daemon/dlp-scanner.ts
|
|
14977
15391
|
function loadIndex() {
|
|
14978
15392
|
try {
|
|
14979
|
-
return JSON.parse(
|
|
15393
|
+
return JSON.parse(import_fs28.default.readFileSync(INDEX_FILE, "utf-8"));
|
|
14980
15394
|
} catch {
|
|
14981
15395
|
return {};
|
|
14982
15396
|
}
|
|
14983
15397
|
}
|
|
14984
15398
|
function saveIndex(index) {
|
|
14985
15399
|
try {
|
|
14986
|
-
|
|
15400
|
+
import_fs28.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
|
|
14987
15401
|
} catch {
|
|
14988
15402
|
}
|
|
14989
15403
|
}
|
|
14990
15404
|
function appendAuditEntry(entry) {
|
|
14991
15405
|
try {
|
|
14992
|
-
|
|
15406
|
+
import_fs28.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
14993
15407
|
} catch {
|
|
14994
15408
|
}
|
|
14995
15409
|
}
|
|
14996
15410
|
function runDlpScan() {
|
|
14997
|
-
if (!
|
|
15411
|
+
if (!import_fs28.default.existsSync(PROJECTS_DIR2)) return;
|
|
14998
15412
|
const index = loadIndex();
|
|
14999
15413
|
let updated = false;
|
|
15000
15414
|
let projDirs;
|
|
15001
15415
|
try {
|
|
15002
|
-
projDirs =
|
|
15416
|
+
projDirs = import_fs28.default.readdirSync(PROJECTS_DIR2);
|
|
15003
15417
|
} catch {
|
|
15004
15418
|
return;
|
|
15005
15419
|
}
|
|
15006
15420
|
for (const proj of projDirs) {
|
|
15007
|
-
const projPath =
|
|
15421
|
+
const projPath = import_path30.default.join(PROJECTS_DIR2, proj);
|
|
15008
15422
|
try {
|
|
15009
|
-
if (!
|
|
15010
|
-
const real =
|
|
15011
|
-
if (!real.startsWith(PROJECTS_DIR2 +
|
|
15423
|
+
if (!import_fs28.default.lstatSync(projPath).isDirectory()) continue;
|
|
15424
|
+
const real = import_fs28.default.realpathSync(projPath);
|
|
15425
|
+
if (!real.startsWith(PROJECTS_DIR2 + import_path30.default.sep) && real !== PROJECTS_DIR2) continue;
|
|
15012
15426
|
} catch {
|
|
15013
15427
|
continue;
|
|
15014
15428
|
}
|
|
15015
15429
|
let files;
|
|
15016
15430
|
try {
|
|
15017
|
-
files =
|
|
15431
|
+
files = import_fs28.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
15018
15432
|
} catch {
|
|
15019
15433
|
continue;
|
|
15020
15434
|
}
|
|
15021
15435
|
for (const file of files) {
|
|
15022
|
-
const filePath =
|
|
15436
|
+
const filePath = import_path30.default.join(projPath, file);
|
|
15023
15437
|
const lastOffset = index[filePath] ?? 0;
|
|
15024
15438
|
let size;
|
|
15025
15439
|
try {
|
|
15026
|
-
size =
|
|
15440
|
+
size = import_fs28.default.statSync(filePath).size;
|
|
15027
15441
|
} catch {
|
|
15028
15442
|
continue;
|
|
15029
15443
|
}
|
|
15030
15444
|
if (size <= lastOffset) continue;
|
|
15031
15445
|
let fd;
|
|
15032
15446
|
try {
|
|
15033
|
-
fd =
|
|
15447
|
+
fd = import_fs28.default.openSync(filePath, "r");
|
|
15034
15448
|
} catch {
|
|
15035
15449
|
continue;
|
|
15036
15450
|
}
|
|
15037
15451
|
try {
|
|
15038
15452
|
const chunkSize = size - lastOffset;
|
|
15039
15453
|
const buf = Buffer.alloc(chunkSize);
|
|
15040
|
-
|
|
15041
|
-
const
|
|
15042
|
-
for (const line of
|
|
15454
|
+
import_fs28.default.readSync(fd, buf, 0, chunkSize, lastOffset);
|
|
15455
|
+
const chunk2 = buf.toString("utf-8");
|
|
15456
|
+
for (const line of chunk2.split("\n")) {
|
|
15043
15457
|
if (!line.trim()) continue;
|
|
15044
15458
|
let entry;
|
|
15045
15459
|
try {
|
|
@@ -15057,7 +15471,7 @@ function runDlpScan() {
|
|
|
15057
15471
|
if (typeof text !== "string") continue;
|
|
15058
15472
|
const match = scanText(text);
|
|
15059
15473
|
if (!match) continue;
|
|
15060
|
-
const projLabel = decodeURIComponent(proj).replace(
|
|
15474
|
+
const projLabel = decodeURIComponent(proj).replace(import_os26.default.homedir(), "~").slice(0, 40);
|
|
15061
15475
|
const ts = entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
15062
15476
|
appendAuditEntry({
|
|
15063
15477
|
ts,
|
|
@@ -15082,7 +15496,7 @@ Run: node9 report --period 30d`
|
|
|
15082
15496
|
updated = true;
|
|
15083
15497
|
} finally {
|
|
15084
15498
|
try {
|
|
15085
|
-
|
|
15499
|
+
import_fs28.default.closeSync(fd);
|
|
15086
15500
|
} catch {
|
|
15087
15501
|
}
|
|
15088
15502
|
}
|
|
@@ -15108,30 +15522,30 @@ function startDlpScanner() {
|
|
|
15108
15522
|
);
|
|
15109
15523
|
timer.unref();
|
|
15110
15524
|
}
|
|
15111
|
-
var
|
|
15525
|
+
var import_fs28, import_path30, import_os26, INDEX_FILE, PROJECTS_DIR2;
|
|
15112
15526
|
var init_dlp_scanner = __esm({
|
|
15113
15527
|
"src/daemon/dlp-scanner.ts"() {
|
|
15114
15528
|
"use strict";
|
|
15115
|
-
|
|
15116
|
-
|
|
15117
|
-
|
|
15529
|
+
import_fs28 = __toESM(require("fs"));
|
|
15530
|
+
import_path30 = __toESM(require("path"));
|
|
15531
|
+
import_os26 = __toESM(require("os"));
|
|
15118
15532
|
init_dlp();
|
|
15119
15533
|
init_native();
|
|
15120
15534
|
init_state2();
|
|
15121
|
-
INDEX_FILE =
|
|
15122
|
-
PROJECTS_DIR2 =
|
|
15535
|
+
INDEX_FILE = import_path30.default.join(import_os26.default.homedir(), ".node9", "dlp-index.json");
|
|
15536
|
+
PROJECTS_DIR2 = import_path30.default.join(import_os26.default.homedir(), ".claude", "projects");
|
|
15123
15537
|
}
|
|
15124
15538
|
});
|
|
15125
15539
|
|
|
15126
15540
|
// src/daemon/mcp-tools.ts
|
|
15127
15541
|
function getMcpToolsFile() {
|
|
15128
|
-
return
|
|
15542
|
+
return import_path31.default.join(import_os27.default.homedir(), ".node9", "mcp-tools.json");
|
|
15129
15543
|
}
|
|
15130
15544
|
function readMcpToolsConfig() {
|
|
15131
15545
|
try {
|
|
15132
15546
|
const file = getMcpToolsFile();
|
|
15133
|
-
if (!
|
|
15134
|
-
const raw =
|
|
15547
|
+
if (!import_fs29.default.existsSync(file)) return {};
|
|
15548
|
+
const raw = import_fs29.default.readFileSync(file, "utf-8");
|
|
15135
15549
|
return JSON.parse(raw);
|
|
15136
15550
|
} catch {
|
|
15137
15551
|
return {};
|
|
@@ -15140,11 +15554,11 @@ function readMcpToolsConfig() {
|
|
|
15140
15554
|
function writeMcpToolsConfig(config) {
|
|
15141
15555
|
try {
|
|
15142
15556
|
const file = getMcpToolsFile();
|
|
15143
|
-
const dir =
|
|
15144
|
-
if (!
|
|
15145
|
-
const tmpPath = `${file}.${
|
|
15146
|
-
|
|
15147
|
-
|
|
15557
|
+
const dir = import_path31.default.dirname(file);
|
|
15558
|
+
if (!import_fs29.default.existsSync(dir)) import_fs29.default.mkdirSync(dir, { recursive: true });
|
|
15559
|
+
const tmpPath = `${file}.${import_os27.default.hostname()}.${process.pid}.tmp`;
|
|
15560
|
+
import_fs29.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
|
|
15561
|
+
import_fs29.default.renameSync(tmpPath, file);
|
|
15148
15562
|
} catch (e) {
|
|
15149
15563
|
console.error("Failed to write mcp-tools.json", e);
|
|
15150
15564
|
}
|
|
@@ -15183,13 +15597,13 @@ function approveServer(serverKey, disabledTools) {
|
|
|
15183
15597
|
writeMcpToolsConfig(config);
|
|
15184
15598
|
}
|
|
15185
15599
|
}
|
|
15186
|
-
var
|
|
15600
|
+
var import_fs29, import_path31, import_os27;
|
|
15187
15601
|
var init_mcp_tools = __esm({
|
|
15188
15602
|
"src/daemon/mcp-tools.ts"() {
|
|
15189
15603
|
"use strict";
|
|
15190
|
-
|
|
15191
|
-
|
|
15192
|
-
|
|
15604
|
+
import_fs29 = __toESM(require("fs"));
|
|
15605
|
+
import_path31 = __toESM(require("path"));
|
|
15606
|
+
import_os27 = __toESM(require("os"));
|
|
15193
15607
|
}
|
|
15194
15608
|
});
|
|
15195
15609
|
|
|
@@ -15212,7 +15626,7 @@ function startDaemon() {
|
|
|
15212
15626
|
idleTimer = setTimeout(() => {
|
|
15213
15627
|
if (autoStarted) {
|
|
15214
15628
|
try {
|
|
15215
|
-
|
|
15629
|
+
import_fs30.default.unlinkSync(DAEMON_PID_FILE);
|
|
15216
15630
|
} catch {
|
|
15217
15631
|
}
|
|
15218
15632
|
}
|
|
@@ -15357,7 +15771,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
15357
15771
|
mcpServer: entry.mcpServer
|
|
15358
15772
|
});
|
|
15359
15773
|
}
|
|
15360
|
-
const projectCwd = typeof cwd === "string" &&
|
|
15774
|
+
const projectCwd = typeof cwd === "string" && import_path32.default.isAbsolute(cwd) ? cwd : void 0;
|
|
15361
15775
|
const projectConfig = getConfig(projectCwd);
|
|
15362
15776
|
const browserEnabled = projectConfig.settings.approvers?.browser !== false;
|
|
15363
15777
|
const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
|
|
@@ -15649,8 +16063,8 @@ data: ${JSON.stringify(item.data)}
|
|
|
15649
16063
|
if (!validToken(req)) return res.writeHead(403).end();
|
|
15650
16064
|
const periodParam = reqUrl.searchParams.get("period") || "7d";
|
|
15651
16065
|
const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
|
|
15652
|
-
const logPath =
|
|
15653
|
-
if (!
|
|
16066
|
+
const logPath = import_path32.default.join(import_os28.default.homedir(), ".node9", "audit.log");
|
|
16067
|
+
if (!import_fs30.default.existsSync(logPath)) {
|
|
15654
16068
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
15655
16069
|
return res.end(
|
|
15656
16070
|
JSON.stringify({
|
|
@@ -15663,7 +16077,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
15663
16077
|
);
|
|
15664
16078
|
}
|
|
15665
16079
|
try {
|
|
15666
|
-
const raw =
|
|
16080
|
+
const raw = import_fs30.default.readFileSync(logPath, "utf-8");
|
|
15667
16081
|
const allEntries = raw.split("\n").flatMap((line) => {
|
|
15668
16082
|
if (!line.trim()) return [];
|
|
15669
16083
|
try {
|
|
@@ -15986,14 +16400,14 @@ data: ${JSON.stringify(item.data)}
|
|
|
15986
16400
|
server.on("error", (e) => {
|
|
15987
16401
|
if (e.code === "EADDRINUSE") {
|
|
15988
16402
|
try {
|
|
15989
|
-
if (
|
|
15990
|
-
const { pid } = JSON.parse(
|
|
16403
|
+
if (import_fs30.default.existsSync(DAEMON_PID_FILE)) {
|
|
16404
|
+
const { pid } = JSON.parse(import_fs30.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
15991
16405
|
process.kill(pid, 0);
|
|
15992
16406
|
return process.exit(0);
|
|
15993
16407
|
}
|
|
15994
16408
|
} catch {
|
|
15995
16409
|
try {
|
|
15996
|
-
|
|
16410
|
+
import_fs30.default.unlinkSync(DAEMON_PID_FILE);
|
|
15997
16411
|
} catch {
|
|
15998
16412
|
}
|
|
15999
16413
|
server.listen(DAEMON_PORT, DAEMON_HOST);
|
|
@@ -16065,14 +16479,14 @@ data: ${JSON.stringify(item.data)}
|
|
|
16065
16479
|
}
|
|
16066
16480
|
startActivitySocket();
|
|
16067
16481
|
}
|
|
16068
|
-
var import_http,
|
|
16482
|
+
var import_http, import_fs30, import_path32, import_os28, import_crypto10, import_child_process2, import_chalk6;
|
|
16069
16483
|
var init_server = __esm({
|
|
16070
16484
|
"src/daemon/server.ts"() {
|
|
16071
16485
|
"use strict";
|
|
16072
16486
|
import_http = __toESM(require("http"));
|
|
16073
|
-
|
|
16074
|
-
|
|
16075
|
-
|
|
16487
|
+
import_fs30 = __toESM(require("fs"));
|
|
16488
|
+
import_path32 = __toESM(require("path"));
|
|
16489
|
+
import_os28 = __toESM(require("os"));
|
|
16076
16490
|
import_crypto10 = require("crypto");
|
|
16077
16491
|
import_child_process2 = require("child_process");
|
|
16078
16492
|
import_chalk6 = __toESM(require("chalk"));
|
|
@@ -16093,8 +16507,8 @@ var init_server = __esm({
|
|
|
16093
16507
|
function resolveNode9Binary() {
|
|
16094
16508
|
try {
|
|
16095
16509
|
const script = process.argv[1];
|
|
16096
|
-
if (typeof script === "string" &&
|
|
16097
|
-
return
|
|
16510
|
+
if (typeof script === "string" && import_path33.default.isAbsolute(script) && import_fs31.default.existsSync(script)) {
|
|
16511
|
+
return import_fs31.default.realpathSync(script);
|
|
16098
16512
|
}
|
|
16099
16513
|
} catch {
|
|
16100
16514
|
}
|
|
@@ -16112,11 +16526,11 @@ function xmlEscape(s) {
|
|
|
16112
16526
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
16113
16527
|
}
|
|
16114
16528
|
function launchdPlist(binaryPath) {
|
|
16115
|
-
const logDir =
|
|
16529
|
+
const logDir = import_path33.default.join(import_os29.default.homedir(), ".node9");
|
|
16116
16530
|
const nodePath = xmlEscape(process.execPath);
|
|
16117
16531
|
const scriptPath = xmlEscape(binaryPath);
|
|
16118
|
-
const outLog = xmlEscape(
|
|
16119
|
-
const errLog = xmlEscape(
|
|
16532
|
+
const outLog = xmlEscape(import_path33.default.join(logDir, "daemon.log"));
|
|
16533
|
+
const errLog = xmlEscape(import_path33.default.join(logDir, "daemon-error.log"));
|
|
16120
16534
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
16121
16535
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
16122
16536
|
<plist version="1.0">
|
|
@@ -16149,9 +16563,9 @@ function launchdPlist(binaryPath) {
|
|
|
16149
16563
|
`;
|
|
16150
16564
|
}
|
|
16151
16565
|
function installLaunchd(binaryPath) {
|
|
16152
|
-
const dir =
|
|
16153
|
-
if (!
|
|
16154
|
-
|
|
16566
|
+
const dir = import_path33.default.dirname(LAUNCHD_PLIST);
|
|
16567
|
+
if (!import_fs31.default.existsSync(dir)) import_fs31.default.mkdirSync(dir, { recursive: true });
|
|
16568
|
+
import_fs31.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
|
|
16155
16569
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
|
|
16156
16570
|
const r = (0, import_child_process3.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
|
|
16157
16571
|
encoding: "utf8",
|
|
@@ -16162,13 +16576,13 @@ function installLaunchd(binaryPath) {
|
|
|
16162
16576
|
}
|
|
16163
16577
|
}
|
|
16164
16578
|
function uninstallLaunchd() {
|
|
16165
|
-
if (
|
|
16579
|
+
if (import_fs31.default.existsSync(LAUNCHD_PLIST)) {
|
|
16166
16580
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
|
|
16167
|
-
|
|
16581
|
+
import_fs31.default.unlinkSync(LAUNCHD_PLIST);
|
|
16168
16582
|
}
|
|
16169
16583
|
}
|
|
16170
16584
|
function isLaunchdInstalled() {
|
|
16171
|
-
return
|
|
16585
|
+
return import_fs31.default.existsSync(LAUNCHD_PLIST);
|
|
16172
16586
|
}
|
|
16173
16587
|
function systemdUnit(binaryPath) {
|
|
16174
16588
|
return `[Unit]
|
|
@@ -16187,12 +16601,12 @@ WantedBy=default.target
|
|
|
16187
16601
|
`;
|
|
16188
16602
|
}
|
|
16189
16603
|
function installSystemd(binaryPath) {
|
|
16190
|
-
if (!
|
|
16191
|
-
|
|
16604
|
+
if (!import_fs31.default.existsSync(SYSTEMD_UNIT_DIR)) {
|
|
16605
|
+
import_fs31.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
|
|
16192
16606
|
}
|
|
16193
|
-
|
|
16607
|
+
import_fs31.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
|
|
16194
16608
|
try {
|
|
16195
|
-
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger",
|
|
16609
|
+
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger", import_os29.default.userInfo().username], { timeout: 3e3 });
|
|
16196
16610
|
} catch {
|
|
16197
16611
|
}
|
|
16198
16612
|
const reload = (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], {
|
|
@@ -16212,23 +16626,23 @@ function installSystemd(binaryPath) {
|
|
|
16212
16626
|
}
|
|
16213
16627
|
}
|
|
16214
16628
|
function uninstallSystemd() {
|
|
16215
|
-
if (
|
|
16629
|
+
if (import_fs31.default.existsSync(SYSTEMD_UNIT)) {
|
|
16216
16630
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
|
|
16217
16631
|
encoding: "utf8",
|
|
16218
16632
|
timeout: 5e3
|
|
16219
16633
|
});
|
|
16220
16634
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
|
|
16221
|
-
|
|
16635
|
+
import_fs31.default.unlinkSync(SYSTEMD_UNIT);
|
|
16222
16636
|
}
|
|
16223
16637
|
}
|
|
16224
16638
|
function isSystemdInstalled() {
|
|
16225
|
-
return
|
|
16639
|
+
return import_fs31.default.existsSync(SYSTEMD_UNIT);
|
|
16226
16640
|
}
|
|
16227
16641
|
function stopRunningDaemon() {
|
|
16228
|
-
const pidFile =
|
|
16229
|
-
if (!
|
|
16642
|
+
const pidFile = import_path33.default.join(import_os29.default.homedir(), ".node9", "daemon.pid");
|
|
16643
|
+
if (!import_fs31.default.existsSync(pidFile)) return;
|
|
16230
16644
|
try {
|
|
16231
|
-
const data = JSON.parse(
|
|
16645
|
+
const data = JSON.parse(import_fs31.default.readFileSync(pidFile, "utf-8"));
|
|
16232
16646
|
const pid = data.pid;
|
|
16233
16647
|
const MAX_PID2 = 4194304;
|
|
16234
16648
|
if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
|
|
@@ -16248,7 +16662,7 @@ function stopRunningDaemon() {
|
|
|
16248
16662
|
}
|
|
16249
16663
|
}
|
|
16250
16664
|
try {
|
|
16251
|
-
|
|
16665
|
+
import_fs31.default.unlinkSync(pidFile);
|
|
16252
16666
|
} catch {
|
|
16253
16667
|
}
|
|
16254
16668
|
} catch {
|
|
@@ -16318,26 +16732,26 @@ function isDaemonServiceInstalled() {
|
|
|
16318
16732
|
if (process.platform === "linux") return isSystemdInstalled();
|
|
16319
16733
|
return false;
|
|
16320
16734
|
}
|
|
16321
|
-
var
|
|
16735
|
+
var import_fs31, import_path33, import_os29, import_child_process3, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
|
|
16322
16736
|
var init_service = __esm({
|
|
16323
16737
|
"src/daemon/service.ts"() {
|
|
16324
16738
|
"use strict";
|
|
16325
|
-
|
|
16326
|
-
|
|
16327
|
-
|
|
16739
|
+
import_fs31 = __toESM(require("fs"));
|
|
16740
|
+
import_path33 = __toESM(require("path"));
|
|
16741
|
+
import_os29 = __toESM(require("os"));
|
|
16328
16742
|
import_child_process3 = require("child_process");
|
|
16329
16743
|
LAUNCHD_LABEL = "ai.node9.daemon";
|
|
16330
|
-
LAUNCHD_PLIST =
|
|
16331
|
-
SYSTEMD_UNIT_DIR =
|
|
16332
|
-
SYSTEMD_UNIT =
|
|
16744
|
+
LAUNCHD_PLIST = import_path33.default.join(import_os29.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
16745
|
+
SYSTEMD_UNIT_DIR = import_path33.default.join(import_os29.default.homedir(), ".config", "systemd", "user");
|
|
16746
|
+
SYSTEMD_UNIT = import_path33.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
|
|
16333
16747
|
}
|
|
16334
16748
|
});
|
|
16335
16749
|
|
|
16336
16750
|
// src/daemon/index.ts
|
|
16337
16751
|
function stopDaemon() {
|
|
16338
|
-
if (!
|
|
16752
|
+
if (!import_fs32.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk7.default.yellow("Not running."));
|
|
16339
16753
|
try {
|
|
16340
|
-
const data = JSON.parse(
|
|
16754
|
+
const data = JSON.parse(import_fs32.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
16341
16755
|
const pid = data.pid;
|
|
16342
16756
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
16343
16757
|
console.log(import_chalk7.default.gray("Cleaned up invalid PID file."));
|
|
@@ -16349,7 +16763,7 @@ function stopDaemon() {
|
|
|
16349
16763
|
console.log(import_chalk7.default.gray("Cleaned up stale PID file."));
|
|
16350
16764
|
} finally {
|
|
16351
16765
|
try {
|
|
16352
|
-
|
|
16766
|
+
import_fs32.default.unlinkSync(DAEMON_PID_FILE);
|
|
16353
16767
|
} catch {
|
|
16354
16768
|
}
|
|
16355
16769
|
}
|
|
@@ -16358,9 +16772,9 @@ function daemonStatus() {
|
|
|
16358
16772
|
const serviceInstalled = isDaemonServiceInstalled();
|
|
16359
16773
|
const serviceLabel = serviceInstalled ? import_chalk7.default.green("installed (starts on login)") : import_chalk7.default.yellow("not installed \u2014 run: node9 daemon install");
|
|
16360
16774
|
let processStatus;
|
|
16361
|
-
if (
|
|
16775
|
+
if (import_fs32.default.existsSync(DAEMON_PID_FILE)) {
|
|
16362
16776
|
try {
|
|
16363
|
-
const data = JSON.parse(
|
|
16777
|
+
const data = JSON.parse(import_fs32.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
16364
16778
|
const pid = data.pid;
|
|
16365
16779
|
const port = data.port;
|
|
16366
16780
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
@@ -16382,11 +16796,11 @@ function daemonStatus() {
|
|
|
16382
16796
|
console.log(` Service : ${serviceLabel}
|
|
16383
16797
|
`);
|
|
16384
16798
|
}
|
|
16385
|
-
var
|
|
16799
|
+
var import_fs32, import_chalk7, MAX_PID;
|
|
16386
16800
|
var init_daemon2 = __esm({
|
|
16387
16801
|
"src/daemon/index.ts"() {
|
|
16388
16802
|
"use strict";
|
|
16389
|
-
|
|
16803
|
+
import_fs32 = __toESM(require("fs"));
|
|
16390
16804
|
import_chalk7 = __toESM(require("chalk"));
|
|
16391
16805
|
init_server();
|
|
16392
16806
|
init_state2();
|
|
@@ -16426,20 +16840,20 @@ function getModelContextLimit(model) {
|
|
|
16426
16840
|
return 2e5;
|
|
16427
16841
|
}
|
|
16428
16842
|
function readSessionUsage() {
|
|
16429
|
-
const projectsDir =
|
|
16430
|
-
if (!
|
|
16843
|
+
const projectsDir = import_path51.default.join(import_os45.default.homedir(), ".claude", "projects");
|
|
16844
|
+
if (!import_fs50.default.existsSync(projectsDir)) return null;
|
|
16431
16845
|
let latestFile = null;
|
|
16432
16846
|
let latestMtime = 0;
|
|
16433
16847
|
try {
|
|
16434
|
-
for (const dir of
|
|
16435
|
-
const dirPath =
|
|
16848
|
+
for (const dir of import_fs50.default.readdirSync(projectsDir)) {
|
|
16849
|
+
const dirPath = import_path51.default.join(projectsDir, dir);
|
|
16436
16850
|
try {
|
|
16437
|
-
if (!
|
|
16438
|
-
for (const file of
|
|
16851
|
+
if (!import_fs50.default.statSync(dirPath).isDirectory()) continue;
|
|
16852
|
+
for (const file of import_fs50.default.readdirSync(dirPath)) {
|
|
16439
16853
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
16440
|
-
const filePath =
|
|
16854
|
+
const filePath = import_path51.default.join(dirPath, file);
|
|
16441
16855
|
try {
|
|
16442
|
-
const mtime =
|
|
16856
|
+
const mtime = import_fs50.default.statSync(filePath).mtimeMs;
|
|
16443
16857
|
if (mtime > latestMtime) {
|
|
16444
16858
|
latestMtime = mtime;
|
|
16445
16859
|
latestFile = filePath;
|
|
@@ -16454,7 +16868,7 @@ function readSessionUsage() {
|
|
|
16454
16868
|
}
|
|
16455
16869
|
if (!latestFile) return null;
|
|
16456
16870
|
try {
|
|
16457
|
-
const lines =
|
|
16871
|
+
const lines = import_fs50.default.readFileSync(latestFile, "utf-8").split("\n");
|
|
16458
16872
|
let lastModel = "";
|
|
16459
16873
|
let lastInput = 0;
|
|
16460
16874
|
let lastOutput = 0;
|
|
@@ -16515,7 +16929,7 @@ function formatBase(activity) {
|
|
|
16515
16929
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
16516
16930
|
const icon = getIcon(activity.tool);
|
|
16517
16931
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
16518
|
-
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(
|
|
16932
|
+
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os45.default.homedir(), "~");
|
|
16519
16933
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
16520
16934
|
return `${import_chalk29.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk29.default.white.bold(toolName)} ${import_chalk29.default.dim(argsPreview)}`;
|
|
16521
16935
|
}
|
|
@@ -16554,9 +16968,9 @@ function renderPending(activity) {
|
|
|
16554
16968
|
}
|
|
16555
16969
|
async function ensureDaemon() {
|
|
16556
16970
|
let pidPort = null;
|
|
16557
|
-
if (
|
|
16971
|
+
if (import_fs50.default.existsSync(PID_FILE)) {
|
|
16558
16972
|
try {
|
|
16559
|
-
const { port } = JSON.parse(
|
|
16973
|
+
const { port } = JSON.parse(import_fs50.default.readFileSync(PID_FILE, "utf-8"));
|
|
16560
16974
|
pidPort = port;
|
|
16561
16975
|
} catch {
|
|
16562
16976
|
console.error(import_chalk29.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -16712,9 +17126,9 @@ function buildRecoveryCardLines(req) {
|
|
|
16712
17126
|
];
|
|
16713
17127
|
}
|
|
16714
17128
|
function readApproversFromDisk() {
|
|
16715
|
-
const configPath =
|
|
17129
|
+
const configPath = import_path51.default.join(import_os45.default.homedir(), ".node9", "config.json");
|
|
16716
17130
|
try {
|
|
16717
|
-
const raw = JSON.parse(
|
|
17131
|
+
const raw = JSON.parse(import_fs50.default.readFileSync(configPath, "utf-8"));
|
|
16718
17132
|
const settings = raw.settings ?? {};
|
|
16719
17133
|
return settings.approvers ?? {};
|
|
16720
17134
|
} catch {
|
|
@@ -16730,15 +17144,15 @@ function approverStatusLine() {
|
|
|
16730
17144
|
return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
16731
17145
|
}
|
|
16732
17146
|
function toggleApprover(channel) {
|
|
16733
|
-
const configPath =
|
|
17147
|
+
const configPath = import_path51.default.join(import_os45.default.homedir(), ".node9", "config.json");
|
|
16734
17148
|
try {
|
|
16735
|
-
const raw = JSON.parse(
|
|
17149
|
+
const raw = JSON.parse(import_fs50.default.readFileSync(configPath, "utf-8"));
|
|
16736
17150
|
const settings = raw.settings ?? {};
|
|
16737
17151
|
const approvers = settings.approvers ?? {};
|
|
16738
17152
|
approvers[channel] = approvers[channel] === false;
|
|
16739
17153
|
settings.approvers = approvers;
|
|
16740
17154
|
raw.settings = settings;
|
|
16741
|
-
|
|
17155
|
+
import_fs50.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
16742
17156
|
} catch (err2) {
|
|
16743
17157
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
16744
17158
|
`);
|
|
@@ -16910,8 +17324,8 @@ async function startTail(options = {}) {
|
|
|
16910
17324
|
}
|
|
16911
17325
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
16912
17326
|
try {
|
|
16913
|
-
|
|
16914
|
-
|
|
17327
|
+
import_fs50.default.appendFileSync(
|
|
17328
|
+
import_path51.default.join(import_os45.default.homedir(), ".node9", "hook-debug.log"),
|
|
16915
17329
|
`[tail] POST /decision failed: ${String(err2)}
|
|
16916
17330
|
`
|
|
16917
17331
|
);
|
|
@@ -16975,9 +17389,9 @@ async function startTail(options = {}) {
|
|
|
16975
17389
|
};
|
|
16976
17390
|
process.stdin.on("keypress", onKeypress);
|
|
16977
17391
|
}
|
|
16978
|
-
const auditLog =
|
|
17392
|
+
const auditLog = import_path51.default.join(import_os45.default.homedir(), ".node9", "audit.log");
|
|
16979
17393
|
try {
|
|
16980
|
-
const unackedDlp =
|
|
17394
|
+
const unackedDlp = import_fs50.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
16981
17395
|
if (unackedDlp > 0) {
|
|
16982
17396
|
console.log("");
|
|
16983
17397
|
console.log(
|
|
@@ -17017,7 +17431,7 @@ async function startTail(options = {}) {
|
|
|
17017
17431
|
if (stallWarned) return;
|
|
17018
17432
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
17019
17433
|
try {
|
|
17020
|
-
const auditMtime =
|
|
17434
|
+
const auditMtime = import_fs50.default.statSync(auditLog).mtimeMs;
|
|
17021
17435
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
17022
17436
|
console.log("");
|
|
17023
17437
|
console.log(
|
|
@@ -17202,20 +17616,20 @@ async function startTail(options = {}) {
|
|
|
17202
17616
|
process.exit(1);
|
|
17203
17617
|
});
|
|
17204
17618
|
}
|
|
17205
|
-
var import_http2, import_chalk29,
|
|
17619
|
+
var import_http2, import_chalk29, import_fs50, import_os45, import_path51, import_readline6, import_child_process12, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
17206
17620
|
var init_tail = __esm({
|
|
17207
17621
|
"src/tui/tail.ts"() {
|
|
17208
17622
|
"use strict";
|
|
17209
17623
|
import_http2 = __toESM(require("http"));
|
|
17210
17624
|
import_chalk29 = __toESM(require("chalk"));
|
|
17211
|
-
|
|
17212
|
-
|
|
17213
|
-
|
|
17625
|
+
import_fs50 = __toESM(require("fs"));
|
|
17626
|
+
import_os45 = __toESM(require("os"));
|
|
17627
|
+
import_path51 = __toESM(require("path"));
|
|
17214
17628
|
import_readline6 = __toESM(require("readline"));
|
|
17215
17629
|
import_child_process12 = require("child_process");
|
|
17216
17630
|
init_daemon2();
|
|
17217
17631
|
init_daemon();
|
|
17218
|
-
PID_FILE =
|
|
17632
|
+
PID_FILE = import_path51.default.join(import_os45.default.homedir(), ".node9", "daemon.pid");
|
|
17219
17633
|
ICONS = {
|
|
17220
17634
|
bash: "\u{1F4BB}",
|
|
17221
17635
|
shell: "\u{1F4BB}",
|
|
@@ -17265,8 +17679,8 @@ __export(hud_exports, {
|
|
|
17265
17679
|
});
|
|
17266
17680
|
async function readStdin() {
|
|
17267
17681
|
const chunks = [];
|
|
17268
|
-
for await (const
|
|
17269
|
-
chunks.push(
|
|
17682
|
+
for await (const chunk2 of process.stdin) {
|
|
17683
|
+
chunks.push(chunk2);
|
|
17270
17684
|
}
|
|
17271
17685
|
const raw = Buffer.concat(chunks).toString("utf-8").trim();
|
|
17272
17686
|
if (!raw) return {};
|
|
@@ -17337,9 +17751,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
17337
17751
|
return ` (${m}m left)`;
|
|
17338
17752
|
}
|
|
17339
17753
|
function safeReadJson(filePath) {
|
|
17340
|
-
if (!
|
|
17754
|
+
if (!import_fs51.default.existsSync(filePath)) return null;
|
|
17341
17755
|
try {
|
|
17342
|
-
return JSON.parse(
|
|
17756
|
+
return JSON.parse(import_fs51.default.readFileSync(filePath, "utf-8"));
|
|
17343
17757
|
} catch {
|
|
17344
17758
|
return null;
|
|
17345
17759
|
}
|
|
@@ -17360,12 +17774,12 @@ function countHooksInFile(filePath) {
|
|
|
17360
17774
|
return Object.keys(cfg.hooks).length;
|
|
17361
17775
|
}
|
|
17362
17776
|
function countRulesInDir(rulesDir) {
|
|
17363
|
-
if (!
|
|
17777
|
+
if (!import_fs51.default.existsSync(rulesDir)) return 0;
|
|
17364
17778
|
let count = 0;
|
|
17365
17779
|
try {
|
|
17366
|
-
for (const entry of
|
|
17780
|
+
for (const entry of import_fs51.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
17367
17781
|
if (entry.isDirectory()) {
|
|
17368
|
-
count += countRulesInDir(
|
|
17782
|
+
count += countRulesInDir(import_path52.default.join(rulesDir, entry.name));
|
|
17369
17783
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
17370
17784
|
count++;
|
|
17371
17785
|
}
|
|
@@ -17376,46 +17790,46 @@ function countRulesInDir(rulesDir) {
|
|
|
17376
17790
|
}
|
|
17377
17791
|
function isSamePath(a, b) {
|
|
17378
17792
|
try {
|
|
17379
|
-
return
|
|
17793
|
+
return import_path52.default.resolve(a) === import_path52.default.resolve(b);
|
|
17380
17794
|
} catch {
|
|
17381
17795
|
return false;
|
|
17382
17796
|
}
|
|
17383
17797
|
}
|
|
17384
17798
|
function countConfigs(cwd) {
|
|
17385
|
-
const homeDir2 =
|
|
17386
|
-
const claudeDir =
|
|
17799
|
+
const homeDir2 = import_os46.default.homedir();
|
|
17800
|
+
const claudeDir = import_path52.default.join(homeDir2, ".claude");
|
|
17387
17801
|
let claudeMdCount = 0;
|
|
17388
17802
|
let rulesCount = 0;
|
|
17389
17803
|
let hooksCount = 0;
|
|
17390
17804
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
17391
17805
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
17392
|
-
if (
|
|
17393
|
-
rulesCount += countRulesInDir(
|
|
17394
|
-
const userSettings =
|
|
17806
|
+
if (import_fs51.default.existsSync(import_path52.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
17807
|
+
rulesCount += countRulesInDir(import_path52.default.join(claudeDir, "rules"));
|
|
17808
|
+
const userSettings = import_path52.default.join(claudeDir, "settings.json");
|
|
17395
17809
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
17396
17810
|
hooksCount += countHooksInFile(userSettings);
|
|
17397
|
-
const userClaudeJson =
|
|
17811
|
+
const userClaudeJson = import_path52.default.join(homeDir2, ".claude.json");
|
|
17398
17812
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
17399
17813
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
17400
17814
|
userMcpServers.delete(name);
|
|
17401
17815
|
}
|
|
17402
17816
|
if (cwd) {
|
|
17403
|
-
if (
|
|
17404
|
-
if (
|
|
17405
|
-
const projectClaudeDir =
|
|
17817
|
+
if (import_fs51.default.existsSync(import_path52.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
17818
|
+
if (import_fs51.default.existsSync(import_path52.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
17819
|
+
const projectClaudeDir = import_path52.default.join(cwd, ".claude");
|
|
17406
17820
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
17407
17821
|
if (!overlapsUserScope) {
|
|
17408
|
-
if (
|
|
17409
|
-
rulesCount += countRulesInDir(
|
|
17410
|
-
const projSettings =
|
|
17822
|
+
if (import_fs51.default.existsSync(import_path52.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
17823
|
+
rulesCount += countRulesInDir(import_path52.default.join(projectClaudeDir, "rules"));
|
|
17824
|
+
const projSettings = import_path52.default.join(projectClaudeDir, "settings.json");
|
|
17411
17825
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
17412
17826
|
hooksCount += countHooksInFile(projSettings);
|
|
17413
17827
|
}
|
|
17414
|
-
if (
|
|
17415
|
-
const localSettings =
|
|
17828
|
+
if (import_fs51.default.existsSync(import_path52.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
17829
|
+
const localSettings = import_path52.default.join(projectClaudeDir, "settings.local.json");
|
|
17416
17830
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
17417
17831
|
hooksCount += countHooksInFile(localSettings);
|
|
17418
|
-
const mcpJsonServers = getMcpServerNames(
|
|
17832
|
+
const mcpJsonServers = getMcpServerNames(import_path52.default.join(cwd, ".mcp.json"));
|
|
17419
17833
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
17420
17834
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
17421
17835
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -17448,12 +17862,12 @@ function readActiveShieldsHud() {
|
|
|
17448
17862
|
return shieldsCache.value;
|
|
17449
17863
|
}
|
|
17450
17864
|
try {
|
|
17451
|
-
const shieldsPath =
|
|
17452
|
-
if (!
|
|
17865
|
+
const shieldsPath = import_path52.default.join(import_os46.default.homedir(), ".node9", "shields.json");
|
|
17866
|
+
if (!import_fs51.default.existsSync(shieldsPath)) {
|
|
17453
17867
|
shieldsCache = { value: [], ts: now };
|
|
17454
17868
|
return [];
|
|
17455
17869
|
}
|
|
17456
|
-
const parsed = JSON.parse(
|
|
17870
|
+
const parsed = JSON.parse(import_fs51.default.readFileSync(shieldsPath, "utf-8"));
|
|
17457
17871
|
if (!Array.isArray(parsed.active)) {
|
|
17458
17872
|
shieldsCache = { value: [], ts: now };
|
|
17459
17873
|
return [];
|
|
@@ -17555,17 +17969,17 @@ function renderContextLine(stdin) {
|
|
|
17555
17969
|
async function main() {
|
|
17556
17970
|
try {
|
|
17557
17971
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
17558
|
-
if (
|
|
17972
|
+
if (import_fs51.default.existsSync(import_path52.default.join(import_os46.default.homedir(), ".node9", "hud-debug"))) {
|
|
17559
17973
|
try {
|
|
17560
|
-
const logPath =
|
|
17974
|
+
const logPath = import_path52.default.join(import_os46.default.homedir(), ".node9", "hud-debug.log");
|
|
17561
17975
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
17562
17976
|
let size = 0;
|
|
17563
17977
|
try {
|
|
17564
|
-
size =
|
|
17978
|
+
size = import_fs51.default.statSync(logPath).size;
|
|
17565
17979
|
} catch {
|
|
17566
17980
|
}
|
|
17567
17981
|
if (size < MAX_LOG_SIZE) {
|
|
17568
|
-
|
|
17982
|
+
import_fs51.default.appendFileSync(
|
|
17569
17983
|
logPath,
|
|
17570
17984
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
17571
17985
|
);
|
|
@@ -17586,11 +18000,11 @@ async function main() {
|
|
|
17586
18000
|
try {
|
|
17587
18001
|
const cwd = stdin.cwd ?? process.cwd();
|
|
17588
18002
|
for (const configPath of [
|
|
17589
|
-
|
|
17590
|
-
|
|
18003
|
+
import_path52.default.join(cwd, "node9.config.json"),
|
|
18004
|
+
import_path52.default.join(import_os46.default.homedir(), ".node9", "config.json")
|
|
17591
18005
|
]) {
|
|
17592
|
-
if (!
|
|
17593
|
-
const cfg = JSON.parse(
|
|
18006
|
+
if (!import_fs51.default.existsSync(configPath)) continue;
|
|
18007
|
+
const cfg = JSON.parse(import_fs51.default.readFileSync(configPath, "utf-8"));
|
|
17594
18008
|
const hud = cfg.settings?.hud;
|
|
17595
18009
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
17596
18010
|
}
|
|
@@ -17608,13 +18022,13 @@ async function main() {
|
|
|
17608
18022
|
renderOffline();
|
|
17609
18023
|
}
|
|
17610
18024
|
}
|
|
17611
|
-
var
|
|
18025
|
+
var import_fs51, import_path52, import_os46, import_http3, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
|
|
17612
18026
|
var init_hud = __esm({
|
|
17613
18027
|
"src/cli/hud.ts"() {
|
|
17614
18028
|
"use strict";
|
|
17615
|
-
|
|
17616
|
-
|
|
17617
|
-
|
|
18029
|
+
import_fs51 = __toESM(require("fs"));
|
|
18030
|
+
import_path52 = __toESM(require("path"));
|
|
18031
|
+
import_os46 = __toESM(require("os"));
|
|
17618
18032
|
import_http3 = __toESM(require("http"));
|
|
17619
18033
|
init_daemon();
|
|
17620
18034
|
RESET3 = "\x1B[0m";
|
|
@@ -17641,9 +18055,9 @@ init_core();
|
|
|
17641
18055
|
init_setup();
|
|
17642
18056
|
init_daemon2();
|
|
17643
18057
|
var import_chalk30 = __toESM(require("chalk"));
|
|
17644
|
-
var
|
|
17645
|
-
var
|
|
17646
|
-
var
|
|
18058
|
+
var import_fs52 = __toESM(require("fs"));
|
|
18059
|
+
var import_path53 = __toESM(require("path"));
|
|
18060
|
+
var import_os47 = __toESM(require("os"));
|
|
17647
18061
|
var import_prompts2 = require("@inquirer/prompts");
|
|
17648
18062
|
|
|
17649
18063
|
// src/utils/duration.ts
|
|
@@ -17825,18 +18239,18 @@ async function runProxy(targetCommand) {
|
|
|
17825
18239
|
|
|
17826
18240
|
// src/cli/daemon-starter.ts
|
|
17827
18241
|
var import_child_process5 = require("child_process");
|
|
17828
|
-
var
|
|
17829
|
-
var
|
|
18242
|
+
var import_path34 = __toESM(require("path"));
|
|
18243
|
+
var import_fs33 = __toESM(require("fs"));
|
|
17830
18244
|
init_daemon();
|
|
17831
18245
|
function isTestingMode() {
|
|
17832
18246
|
return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
|
|
17833
18247
|
}
|
|
17834
18248
|
async function autoStartDaemonAndWait() {
|
|
17835
18249
|
if (isTestingMode()) return false;
|
|
17836
|
-
if (!
|
|
18250
|
+
if (!import_path34.default.isAbsolute(process.argv[1])) return false;
|
|
17837
18251
|
let resolvedArgv1;
|
|
17838
18252
|
try {
|
|
17839
|
-
resolvedArgv1 =
|
|
18253
|
+
resolvedArgv1 = import_fs33.default.realpathSync(process.argv[1]);
|
|
17840
18254
|
} catch {
|
|
17841
18255
|
return false;
|
|
17842
18256
|
}
|
|
@@ -17863,10 +18277,10 @@ async function autoStartDaemonAndWait() {
|
|
|
17863
18277
|
|
|
17864
18278
|
// src/cli/commands/check.ts
|
|
17865
18279
|
var import_chalk9 = __toESM(require("chalk"));
|
|
17866
|
-
var
|
|
18280
|
+
var import_fs36 = __toESM(require("fs"));
|
|
17867
18281
|
var import_child_process7 = require("child_process");
|
|
17868
|
-
var
|
|
17869
|
-
var
|
|
18282
|
+
var import_path37 = __toESM(require("path"));
|
|
18283
|
+
var import_os32 = __toESM(require("os"));
|
|
17870
18284
|
init_orchestrator();
|
|
17871
18285
|
init_daemon();
|
|
17872
18286
|
init_config();
|
|
@@ -17875,11 +18289,11 @@ init_policy();
|
|
|
17875
18289
|
// src/undo.ts
|
|
17876
18290
|
var import_child_process6 = require("child_process");
|
|
17877
18291
|
var import_crypto11 = __toESM(require("crypto"));
|
|
17878
|
-
var
|
|
18292
|
+
var import_fs34 = __toESM(require("fs"));
|
|
17879
18293
|
var import_net3 = __toESM(require("net"));
|
|
17880
|
-
var
|
|
17881
|
-
var
|
|
17882
|
-
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
18294
|
+
var import_path35 = __toESM(require("path"));
|
|
18295
|
+
var import_os30 = __toESM(require("os"));
|
|
18296
|
+
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path35.default.join(import_os30.default.tmpdir(), "node9-activity.sock");
|
|
17883
18297
|
function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
17884
18298
|
try {
|
|
17885
18299
|
const payload = JSON.stringify({
|
|
@@ -17899,22 +18313,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
|
17899
18313
|
} catch {
|
|
17900
18314
|
}
|
|
17901
18315
|
}
|
|
17902
|
-
var SNAPSHOT_STACK_PATH =
|
|
17903
|
-
var UNDO_LATEST_PATH =
|
|
18316
|
+
var SNAPSHOT_STACK_PATH = import_path35.default.join(import_os30.default.homedir(), ".node9", "snapshots.json");
|
|
18317
|
+
var UNDO_LATEST_PATH = import_path35.default.join(import_os30.default.homedir(), ".node9", "undo_latest.txt");
|
|
17904
18318
|
var MAX_SNAPSHOTS = 10;
|
|
17905
18319
|
var GIT_TIMEOUT = 15e3;
|
|
17906
18320
|
function readStack() {
|
|
17907
18321
|
try {
|
|
17908
|
-
if (
|
|
17909
|
-
return JSON.parse(
|
|
18322
|
+
if (import_fs34.default.existsSync(SNAPSHOT_STACK_PATH))
|
|
18323
|
+
return JSON.parse(import_fs34.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
|
|
17910
18324
|
} catch {
|
|
17911
18325
|
}
|
|
17912
18326
|
return [];
|
|
17913
18327
|
}
|
|
17914
18328
|
function writeStack(stack) {
|
|
17915
|
-
const dir =
|
|
17916
|
-
if (!
|
|
17917
|
-
|
|
18329
|
+
const dir = import_path35.default.dirname(SNAPSHOT_STACK_PATH);
|
|
18330
|
+
if (!import_fs34.default.existsSync(dir)) import_fs34.default.mkdirSync(dir, { recursive: true });
|
|
18331
|
+
import_fs34.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
|
|
17918
18332
|
}
|
|
17919
18333
|
function extractFilePath(args) {
|
|
17920
18334
|
if (!args || typeof args !== "object") return null;
|
|
@@ -17934,12 +18348,12 @@ function buildArgsSummary(tool, args) {
|
|
|
17934
18348
|
return "";
|
|
17935
18349
|
}
|
|
17936
18350
|
function findProjectRoot(filePath) {
|
|
17937
|
-
let dir =
|
|
18351
|
+
let dir = import_path35.default.dirname(filePath);
|
|
17938
18352
|
while (true) {
|
|
17939
|
-
if (
|
|
18353
|
+
if (import_fs34.default.existsSync(import_path35.default.join(dir, ".git")) || import_fs34.default.existsSync(import_path35.default.join(dir, "package.json"))) {
|
|
17940
18354
|
return dir;
|
|
17941
18355
|
}
|
|
17942
|
-
const parent =
|
|
18356
|
+
const parent = import_path35.default.dirname(dir);
|
|
17943
18357
|
if (parent === dir) return process.cwd();
|
|
17944
18358
|
dir = parent;
|
|
17945
18359
|
}
|
|
@@ -17947,7 +18361,7 @@ function findProjectRoot(filePath) {
|
|
|
17947
18361
|
function normalizeCwdForHash(cwd) {
|
|
17948
18362
|
let normalized;
|
|
17949
18363
|
try {
|
|
17950
|
-
normalized =
|
|
18364
|
+
normalized = import_fs34.default.realpathSync(cwd);
|
|
17951
18365
|
} catch {
|
|
17952
18366
|
normalized = cwd;
|
|
17953
18367
|
}
|
|
@@ -17957,16 +18371,16 @@ function normalizeCwdForHash(cwd) {
|
|
|
17957
18371
|
}
|
|
17958
18372
|
function getShadowRepoDir(cwd) {
|
|
17959
18373
|
const hash = import_crypto11.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
|
|
17960
|
-
return
|
|
18374
|
+
return import_path35.default.join(import_os30.default.homedir(), ".node9", "snapshots", hash);
|
|
17961
18375
|
}
|
|
17962
18376
|
function cleanOrphanedIndexFiles(shadowDir) {
|
|
17963
18377
|
try {
|
|
17964
18378
|
const cutoff = Date.now() - 6e4;
|
|
17965
|
-
for (const f of
|
|
18379
|
+
for (const f of import_fs34.default.readdirSync(shadowDir)) {
|
|
17966
18380
|
if (f.startsWith("index_")) {
|
|
17967
|
-
const fp =
|
|
18381
|
+
const fp = import_path35.default.join(shadowDir, f);
|
|
17968
18382
|
try {
|
|
17969
|
-
if (
|
|
18383
|
+
if (import_fs34.default.statSync(fp).mtimeMs < cutoff) import_fs34.default.unlinkSync(fp);
|
|
17970
18384
|
} catch {
|
|
17971
18385
|
}
|
|
17972
18386
|
}
|
|
@@ -17978,7 +18392,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
|
|
|
17978
18392
|
const hardcoded = [".git", ".node9"];
|
|
17979
18393
|
const lines = [...hardcoded, ...ignorePaths].join("\n");
|
|
17980
18394
|
try {
|
|
17981
|
-
|
|
18395
|
+
import_fs34.default.writeFileSync(import_path35.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
|
|
17982
18396
|
} catch {
|
|
17983
18397
|
}
|
|
17984
18398
|
}
|
|
@@ -17991,25 +18405,25 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
17991
18405
|
timeout: 3e3
|
|
17992
18406
|
});
|
|
17993
18407
|
if (check.status === 0) {
|
|
17994
|
-
const ptPath =
|
|
18408
|
+
const ptPath = import_path35.default.join(shadowDir, "project-path.txt");
|
|
17995
18409
|
try {
|
|
17996
|
-
const stored =
|
|
18410
|
+
const stored = import_fs34.default.readFileSync(ptPath, "utf8").trim();
|
|
17997
18411
|
if (stored === normalizedCwd) return true;
|
|
17998
18412
|
if (process.env.NODE9_DEBUG === "1")
|
|
17999
18413
|
console.error(
|
|
18000
18414
|
`[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
|
|
18001
18415
|
);
|
|
18002
|
-
|
|
18416
|
+
import_fs34.default.rmSync(shadowDir, { recursive: true, force: true });
|
|
18003
18417
|
} catch {
|
|
18004
18418
|
try {
|
|
18005
|
-
|
|
18419
|
+
import_fs34.default.writeFileSync(ptPath, normalizedCwd, "utf8");
|
|
18006
18420
|
} catch {
|
|
18007
18421
|
}
|
|
18008
18422
|
return true;
|
|
18009
18423
|
}
|
|
18010
18424
|
}
|
|
18011
18425
|
try {
|
|
18012
|
-
|
|
18426
|
+
import_fs34.default.mkdirSync(shadowDir, { recursive: true });
|
|
18013
18427
|
} catch {
|
|
18014
18428
|
}
|
|
18015
18429
|
const init = (0, import_child_process6.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
|
|
@@ -18018,7 +18432,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
18018
18432
|
if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
|
|
18019
18433
|
return false;
|
|
18020
18434
|
}
|
|
18021
|
-
const configFile =
|
|
18435
|
+
const configFile = import_path35.default.join(shadowDir, "config");
|
|
18022
18436
|
(0, import_child_process6.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
|
|
18023
18437
|
timeout: 3e3
|
|
18024
18438
|
});
|
|
@@ -18026,7 +18440,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
18026
18440
|
timeout: 3e3
|
|
18027
18441
|
});
|
|
18028
18442
|
try {
|
|
18029
|
-
|
|
18443
|
+
import_fs34.default.writeFileSync(import_path35.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
|
|
18030
18444
|
} catch {
|
|
18031
18445
|
}
|
|
18032
18446
|
return true;
|
|
@@ -18049,12 +18463,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
18049
18463
|
let indexFile = null;
|
|
18050
18464
|
try {
|
|
18051
18465
|
const rawFilePath = extractFilePath(args);
|
|
18052
|
-
const absFilePath = rawFilePath &&
|
|
18466
|
+
const absFilePath = rawFilePath && import_path35.default.isAbsolute(rawFilePath) ? rawFilePath : null;
|
|
18053
18467
|
const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
|
|
18054
18468
|
const shadowDir = getShadowRepoDir(cwd);
|
|
18055
18469
|
if (!ensureShadowRepo(shadowDir, cwd)) return null;
|
|
18056
18470
|
writeShadowExcludes(shadowDir, ignorePaths);
|
|
18057
|
-
indexFile =
|
|
18471
|
+
indexFile = import_path35.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
|
|
18058
18472
|
const shadowEnv = {
|
|
18059
18473
|
...process.env,
|
|
18060
18474
|
GIT_DIR: shadowDir,
|
|
@@ -18126,7 +18540,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
18126
18540
|
writeStack(stack);
|
|
18127
18541
|
const entry = stack[stack.length - 1];
|
|
18128
18542
|
notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
|
|
18129
|
-
|
|
18543
|
+
import_fs34.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
|
|
18130
18544
|
if (shouldGc) {
|
|
18131
18545
|
(0, import_child_process6.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
|
|
18132
18546
|
}
|
|
@@ -18137,7 +18551,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
18137
18551
|
} finally {
|
|
18138
18552
|
if (indexFile) {
|
|
18139
18553
|
try {
|
|
18140
|
-
|
|
18554
|
+
import_fs34.default.unlinkSync(indexFile);
|
|
18141
18555
|
} catch {
|
|
18142
18556
|
}
|
|
18143
18557
|
}
|
|
@@ -18213,9 +18627,9 @@ function applyUndo(hash, cwd) {
|
|
|
18213
18627
|
timeout: GIT_TIMEOUT
|
|
18214
18628
|
}).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
|
|
18215
18629
|
for (const file of [...tracked, ...untracked]) {
|
|
18216
|
-
const fullPath =
|
|
18217
|
-
if (!snapshotFiles.has(file) &&
|
|
18218
|
-
|
|
18630
|
+
const fullPath = import_path35.default.join(dir, file);
|
|
18631
|
+
if (!snapshotFiles.has(file) && import_fs34.default.existsSync(fullPath)) {
|
|
18632
|
+
import_fs34.default.unlinkSync(fullPath);
|
|
18219
18633
|
}
|
|
18220
18634
|
}
|
|
18221
18635
|
return true;
|
|
@@ -18225,12 +18639,12 @@ function applyUndo(hash, cwd) {
|
|
|
18225
18639
|
}
|
|
18226
18640
|
|
|
18227
18641
|
// src/skill-pin.ts
|
|
18228
|
-
var
|
|
18229
|
-
var
|
|
18230
|
-
var
|
|
18642
|
+
var import_fs35 = __toESM(require("fs"));
|
|
18643
|
+
var import_path36 = __toESM(require("path"));
|
|
18644
|
+
var import_os31 = __toESM(require("os"));
|
|
18231
18645
|
var import_crypto12 = __toESM(require("crypto"));
|
|
18232
18646
|
function getPinsFilePath2() {
|
|
18233
|
-
return
|
|
18647
|
+
return import_path36.default.join(import_os31.default.homedir(), ".node9", "skill-pins.json");
|
|
18234
18648
|
}
|
|
18235
18649
|
var MAX_FILES = 5e3;
|
|
18236
18650
|
var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
@@ -18244,18 +18658,18 @@ function walkDir(root) {
|
|
|
18244
18658
|
if (out.length >= MAX_FILES) return;
|
|
18245
18659
|
let entries;
|
|
18246
18660
|
try {
|
|
18247
|
-
entries =
|
|
18661
|
+
entries = import_fs35.default.readdirSync(dir, { withFileTypes: true });
|
|
18248
18662
|
} catch {
|
|
18249
18663
|
return;
|
|
18250
18664
|
}
|
|
18251
18665
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
18252
18666
|
for (const entry of entries) {
|
|
18253
18667
|
if (out.length >= MAX_FILES) return;
|
|
18254
|
-
const full =
|
|
18255
|
-
const rel = relDir ?
|
|
18668
|
+
const full = import_path36.default.join(dir, entry.name);
|
|
18669
|
+
const rel = relDir ? import_path36.default.posix.join(relDir, entry.name) : entry.name;
|
|
18256
18670
|
let lst;
|
|
18257
18671
|
try {
|
|
18258
|
-
lst =
|
|
18672
|
+
lst = import_fs35.default.lstatSync(full);
|
|
18259
18673
|
} catch {
|
|
18260
18674
|
continue;
|
|
18261
18675
|
}
|
|
@@ -18267,7 +18681,7 @@ function walkDir(root) {
|
|
|
18267
18681
|
if (!lst.isFile()) continue;
|
|
18268
18682
|
if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
|
|
18269
18683
|
try {
|
|
18270
|
-
const buf =
|
|
18684
|
+
const buf = import_fs35.default.readFileSync(full);
|
|
18271
18685
|
totalBytes += buf.length;
|
|
18272
18686
|
out.push({ rel, hash: sha256Bytes(buf) });
|
|
18273
18687
|
} catch {
|
|
@@ -18281,14 +18695,14 @@ function walkDir(root) {
|
|
|
18281
18695
|
function hashSkillRoot(absPath) {
|
|
18282
18696
|
let lst;
|
|
18283
18697
|
try {
|
|
18284
|
-
lst =
|
|
18698
|
+
lst = import_fs35.default.lstatSync(absPath);
|
|
18285
18699
|
} catch {
|
|
18286
18700
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
18287
18701
|
}
|
|
18288
18702
|
if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
|
|
18289
18703
|
if (lst.isFile()) {
|
|
18290
18704
|
try {
|
|
18291
|
-
return { exists: true, contentHash: sha256Bytes(
|
|
18705
|
+
return { exists: true, contentHash: sha256Bytes(import_fs35.default.readFileSync(absPath)), fileCount: 1 };
|
|
18292
18706
|
} catch {
|
|
18293
18707
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
18294
18708
|
}
|
|
@@ -18306,7 +18720,7 @@ function getRootKey(absPath) {
|
|
|
18306
18720
|
function readSkillPinsSafe() {
|
|
18307
18721
|
const filePath = getPinsFilePath2();
|
|
18308
18722
|
try {
|
|
18309
|
-
const raw =
|
|
18723
|
+
const raw = import_fs35.default.readFileSync(filePath, "utf-8");
|
|
18310
18724
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
18311
18725
|
const parsed = JSON.parse(raw);
|
|
18312
18726
|
if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
|
|
@@ -18326,10 +18740,10 @@ function readSkillPins() {
|
|
|
18326
18740
|
}
|
|
18327
18741
|
function writeSkillPins(data) {
|
|
18328
18742
|
const filePath = getPinsFilePath2();
|
|
18329
|
-
|
|
18743
|
+
import_fs35.default.mkdirSync(import_path36.default.dirname(filePath), { recursive: true });
|
|
18330
18744
|
const tmp = `${filePath}.${import_crypto12.default.randomBytes(6).toString("hex")}.tmp`;
|
|
18331
|
-
|
|
18332
|
-
|
|
18745
|
+
import_fs35.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
18746
|
+
import_fs35.default.renameSync(tmp, filePath);
|
|
18333
18747
|
}
|
|
18334
18748
|
function removePin2(rootKey) {
|
|
18335
18749
|
const pins = readSkillPins();
|
|
@@ -18373,36 +18787,36 @@ function verifyAndPinRoots(roots) {
|
|
|
18373
18787
|
return { kind: "verified" };
|
|
18374
18788
|
}
|
|
18375
18789
|
function defaultSkillRoots(_cwd) {
|
|
18376
|
-
const marketplaces =
|
|
18790
|
+
const marketplaces = import_path36.default.join(import_os31.default.homedir(), ".claude", "plugins", "marketplaces");
|
|
18377
18791
|
const roots = [];
|
|
18378
18792
|
let registries;
|
|
18379
18793
|
try {
|
|
18380
|
-
registries =
|
|
18794
|
+
registries = import_fs35.default.readdirSync(marketplaces, { withFileTypes: true });
|
|
18381
18795
|
} catch {
|
|
18382
18796
|
return [];
|
|
18383
18797
|
}
|
|
18384
18798
|
for (const registry of registries) {
|
|
18385
18799
|
if (!registry.isDirectory()) continue;
|
|
18386
|
-
const pluginsDir =
|
|
18800
|
+
const pluginsDir = import_path36.default.join(marketplaces, registry.name, "plugins");
|
|
18387
18801
|
let plugins;
|
|
18388
18802
|
try {
|
|
18389
|
-
plugins =
|
|
18803
|
+
plugins = import_fs35.default.readdirSync(pluginsDir, { withFileTypes: true });
|
|
18390
18804
|
} catch {
|
|
18391
18805
|
continue;
|
|
18392
18806
|
}
|
|
18393
18807
|
for (const plugin of plugins) {
|
|
18394
18808
|
if (!plugin.isDirectory()) continue;
|
|
18395
|
-
roots.push(
|
|
18809
|
+
roots.push(import_path36.default.join(pluginsDir, plugin.name));
|
|
18396
18810
|
}
|
|
18397
18811
|
}
|
|
18398
18812
|
return roots;
|
|
18399
18813
|
}
|
|
18400
18814
|
function resolveUserSkillRoot(entry, cwd) {
|
|
18401
18815
|
if (!entry) return null;
|
|
18402
|
-
if (entry.startsWith("~/") || entry === "~") return
|
|
18403
|
-
if (
|
|
18404
|
-
if (!cwd || !
|
|
18405
|
-
return
|
|
18816
|
+
if (entry.startsWith("~/") || entry === "~") return import_path36.default.join(import_os31.default.homedir(), entry.slice(1));
|
|
18817
|
+
if (import_path36.default.isAbsolute(entry)) return entry;
|
|
18818
|
+
if (!cwd || !import_path36.default.isAbsolute(cwd)) return null;
|
|
18819
|
+
return import_path36.default.join(cwd, entry);
|
|
18406
18820
|
}
|
|
18407
18821
|
|
|
18408
18822
|
// src/cli/commands/check.ts
|
|
@@ -18471,9 +18885,9 @@ function registerCheckCommand(program2) {
|
|
|
18471
18885
|
} catch (err2) {
|
|
18472
18886
|
const tempConfig = getConfig();
|
|
18473
18887
|
if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
|
|
18474
|
-
const logPath =
|
|
18888
|
+
const logPath = import_path37.default.join(import_os32.default.homedir(), ".node9", "hook-debug.log");
|
|
18475
18889
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
18476
|
-
|
|
18890
|
+
import_fs36.default.appendFileSync(
|
|
18477
18891
|
logPath,
|
|
18478
18892
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
|
|
18479
18893
|
RAW: ${raw}
|
|
@@ -18486,14 +18900,14 @@ RAW: ${raw}
|
|
|
18486
18900
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
18487
18901
|
if (process.env.NODE9_DEBUG === "1") {
|
|
18488
18902
|
try {
|
|
18489
|
-
const logPath =
|
|
18490
|
-
if (!
|
|
18491
|
-
|
|
18903
|
+
const logPath = import_path37.default.join(import_os32.default.homedir(), ".node9", "hook-debug.log");
|
|
18904
|
+
if (!import_fs36.default.existsSync(import_path37.default.dirname(logPath)))
|
|
18905
|
+
import_fs36.default.mkdirSync(import_path37.default.dirname(logPath), { recursive: true });
|
|
18492
18906
|
const sanitized = JSON.stringify({
|
|
18493
18907
|
...payload,
|
|
18494
18908
|
prompt: `<redacted, ${prompt.length} bytes>`
|
|
18495
18909
|
});
|
|
18496
|
-
|
|
18910
|
+
import_fs36.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
|
|
18497
18911
|
`);
|
|
18498
18912
|
} catch {
|
|
18499
18913
|
}
|
|
@@ -18513,8 +18927,8 @@ RAW: ${raw}
|
|
|
18513
18927
|
);
|
|
18514
18928
|
const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
|
|
18515
18929
|
try {
|
|
18516
|
-
const ttyFd =
|
|
18517
|
-
|
|
18930
|
+
const ttyFd = import_fs36.default.openSync("/dev/tty", "w");
|
|
18931
|
+
import_fs36.default.writeSync(
|
|
18518
18932
|
ttyFd,
|
|
18519
18933
|
import_chalk9.default.bgRed.white.bold(`
|
|
18520
18934
|
\u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
|
|
@@ -18524,7 +18938,7 @@ RAW: ${raw}
|
|
|
18524
18938
|
|
|
18525
18939
|
`)
|
|
18526
18940
|
);
|
|
18527
|
-
|
|
18941
|
+
import_fs36.default.closeSync(ttyFd);
|
|
18528
18942
|
} catch {
|
|
18529
18943
|
}
|
|
18530
18944
|
const isCodex = agent2 === "Codex";
|
|
@@ -18543,16 +18957,16 @@ RAW: ${raw}
|
|
|
18543
18957
|
process.exit(2);
|
|
18544
18958
|
}
|
|
18545
18959
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
18546
|
-
const safeCwdForConfig = typeof payloadCwd === "string" &&
|
|
18960
|
+
const safeCwdForConfig = typeof payloadCwd === "string" && import_path37.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
18547
18961
|
const config = getConfig(safeCwdForConfig);
|
|
18548
18962
|
if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
|
|
18549
18963
|
try {
|
|
18550
18964
|
const scriptPath = process.argv[1];
|
|
18551
|
-
if (typeof scriptPath !== "string" || !
|
|
18965
|
+
if (typeof scriptPath !== "string" || !import_path37.default.isAbsolute(scriptPath))
|
|
18552
18966
|
throw new Error("node9: argv[1] is not an absolute path");
|
|
18553
|
-
const resolvedScript =
|
|
18554
|
-
const packageDist =
|
|
18555
|
-
if (!resolvedScript.startsWith(packageDist +
|
|
18967
|
+
const resolvedScript = import_fs36.default.realpathSync(scriptPath);
|
|
18968
|
+
const packageDist = import_fs36.default.realpathSync(import_path37.default.resolve(__dirname, "../.."));
|
|
18969
|
+
if (!resolvedScript.startsWith(packageDist + import_path37.default.sep) && resolvedScript !== packageDist)
|
|
18556
18970
|
throw new Error(
|
|
18557
18971
|
`node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
|
|
18558
18972
|
);
|
|
@@ -18574,10 +18988,10 @@ RAW: ${raw}
|
|
|
18574
18988
|
});
|
|
18575
18989
|
d.unref();
|
|
18576
18990
|
} catch (spawnErr) {
|
|
18577
|
-
const logPath =
|
|
18991
|
+
const logPath = import_path37.default.join(import_os32.default.homedir(), ".node9", "hook-debug.log");
|
|
18578
18992
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
18579
18993
|
try {
|
|
18580
|
-
|
|
18994
|
+
import_fs36.default.appendFileSync(
|
|
18581
18995
|
logPath,
|
|
18582
18996
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
|
|
18583
18997
|
`
|
|
@@ -18587,10 +19001,10 @@ RAW: ${raw}
|
|
|
18587
19001
|
}
|
|
18588
19002
|
}
|
|
18589
19003
|
if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
|
|
18590
|
-
const logPath =
|
|
18591
|
-
if (!
|
|
18592
|
-
|
|
18593
|
-
|
|
19004
|
+
const logPath = import_path37.default.join(import_os32.default.homedir(), ".node9", "hook-debug.log");
|
|
19005
|
+
if (!import_fs36.default.existsSync(import_path37.default.dirname(logPath)))
|
|
19006
|
+
import_fs36.default.mkdirSync(import_path37.default.dirname(logPath), { recursive: true });
|
|
19007
|
+
import_fs36.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
|
|
18594
19008
|
`);
|
|
18595
19009
|
}
|
|
18596
19010
|
const rawToolName = sanitize2(extractToolName(payload));
|
|
@@ -18604,8 +19018,8 @@ RAW: ${raw}
|
|
|
18604
19018
|
const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
|
|
18605
19019
|
let ttyFd = null;
|
|
18606
19020
|
try {
|
|
18607
|
-
ttyFd =
|
|
18608
|
-
const writeTty = (line) =>
|
|
19021
|
+
ttyFd = import_fs36.default.openSync("/dev/tty", "w");
|
|
19022
|
+
const writeTty = (line) => import_fs36.default.writeSync(ttyFd, line + "\n");
|
|
18609
19023
|
if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
|
|
18610
19024
|
writeTty(import_chalk9.default.bgRed.white.bold(`
|
|
18611
19025
|
\u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
|
|
@@ -18624,7 +19038,7 @@ RAW: ${raw}
|
|
|
18624
19038
|
} finally {
|
|
18625
19039
|
if (ttyFd !== null)
|
|
18626
19040
|
try {
|
|
18627
|
-
|
|
19041
|
+
import_fs36.default.closeSync(ttyFd);
|
|
18628
19042
|
} catch {
|
|
18629
19043
|
}
|
|
18630
19044
|
}
|
|
@@ -18675,17 +19089,17 @@ RAW: ${raw}
|
|
|
18675
19089
|
const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
|
|
18676
19090
|
if (skillPinCfg.enabled && safeSessionId) {
|
|
18677
19091
|
try {
|
|
18678
|
-
const sessionsDir =
|
|
18679
|
-
const flagPath =
|
|
19092
|
+
const sessionsDir = import_path37.default.join(import_os32.default.homedir(), ".node9", "skill-sessions");
|
|
19093
|
+
const flagPath = import_path37.default.join(sessionsDir, `${safeSessionId}.json`);
|
|
18680
19094
|
let flag = null;
|
|
18681
19095
|
try {
|
|
18682
|
-
flag = JSON.parse(
|
|
19096
|
+
flag = JSON.parse(import_fs36.default.readFileSync(flagPath, "utf-8"));
|
|
18683
19097
|
} catch {
|
|
18684
19098
|
}
|
|
18685
19099
|
const writeFlag = (data2) => {
|
|
18686
19100
|
try {
|
|
18687
|
-
|
|
18688
|
-
|
|
19101
|
+
import_fs36.default.mkdirSync(sessionsDir, { recursive: true });
|
|
19102
|
+
import_fs36.default.writeFileSync(
|
|
18689
19103
|
flagPath,
|
|
18690
19104
|
JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
18691
19105
|
{ mode: 384 }
|
|
@@ -18696,8 +19110,8 @@ RAW: ${raw}
|
|
|
18696
19110
|
const sendSkillWarn = (detail, recoveryCmd) => {
|
|
18697
19111
|
let ttyFd = null;
|
|
18698
19112
|
try {
|
|
18699
|
-
ttyFd =
|
|
18700
|
-
const w = (line) =>
|
|
19113
|
+
ttyFd = import_fs36.default.openSync("/dev/tty", "w");
|
|
19114
|
+
const w = (line) => import_fs36.default.writeSync(ttyFd, line + "\n");
|
|
18701
19115
|
w(import_chalk9.default.yellow(`
|
|
18702
19116
|
\u26A0\uFE0F Node9: installed skill drift detected`));
|
|
18703
19117
|
w(import_chalk9.default.gray(` ${detail}`));
|
|
@@ -18712,7 +19126,7 @@ RAW: ${raw}
|
|
|
18712
19126
|
} finally {
|
|
18713
19127
|
if (ttyFd !== null)
|
|
18714
19128
|
try {
|
|
18715
|
-
|
|
19129
|
+
import_fs36.default.closeSync(ttyFd);
|
|
18716
19130
|
} catch {
|
|
18717
19131
|
}
|
|
18718
19132
|
}
|
|
@@ -18728,7 +19142,7 @@ RAW: ${raw}
|
|
|
18728
19142
|
return;
|
|
18729
19143
|
}
|
|
18730
19144
|
if (!flag || flag.state !== "verified" && flag.state !== "warned") {
|
|
18731
|
-
const absoluteCwd = typeof payloadCwd === "string" &&
|
|
19145
|
+
const absoluteCwd = typeof payloadCwd === "string" && import_path37.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
18732
19146
|
const extraRoots = skillPinCfg.roots;
|
|
18733
19147
|
const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
|
|
18734
19148
|
const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
|
|
@@ -18769,10 +19183,10 @@ RAW: ${raw}
|
|
|
18769
19183
|
}
|
|
18770
19184
|
try {
|
|
18771
19185
|
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
18772
|
-
for (const name of
|
|
18773
|
-
const p =
|
|
19186
|
+
for (const name of import_fs36.default.readdirSync(sessionsDir)) {
|
|
19187
|
+
const p = import_path37.default.join(sessionsDir, name);
|
|
18774
19188
|
try {
|
|
18775
|
-
if (
|
|
19189
|
+
if (import_fs36.default.statSync(p).mtimeMs < cutoff) import_fs36.default.unlinkSync(p);
|
|
18776
19190
|
} catch {
|
|
18777
19191
|
}
|
|
18778
19192
|
}
|
|
@@ -18782,9 +19196,9 @@ RAW: ${raw}
|
|
|
18782
19196
|
} catch (err2) {
|
|
18783
19197
|
if (process.env.NODE9_DEBUG === "1") {
|
|
18784
19198
|
try {
|
|
18785
|
-
const dbg =
|
|
19199
|
+
const dbg = import_path37.default.join(import_os32.default.homedir(), ".node9", "hook-debug.log");
|
|
18786
19200
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
18787
|
-
|
|
19201
|
+
import_fs36.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
|
|
18788
19202
|
`);
|
|
18789
19203
|
} catch {
|
|
18790
19204
|
}
|
|
@@ -18794,7 +19208,7 @@ RAW: ${raw}
|
|
|
18794
19208
|
if (shouldSnapshot(toolName, toolInput, config)) {
|
|
18795
19209
|
await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
|
|
18796
19210
|
}
|
|
18797
|
-
const safeCwdForAuth = typeof payloadCwd === "string" &&
|
|
19211
|
+
const safeCwdForAuth = typeof payloadCwd === "string" && import_path37.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
18798
19212
|
const result = await authorizeHeadless(toolName, toolInput, meta, {
|
|
18799
19213
|
cwd: safeCwdForAuth
|
|
18800
19214
|
});
|
|
@@ -18806,12 +19220,12 @@ RAW: ${raw}
|
|
|
18806
19220
|
}
|
|
18807
19221
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
|
|
18808
19222
|
try {
|
|
18809
|
-
const tty =
|
|
18810
|
-
|
|
19223
|
+
const tty = import_fs36.default.openSync("/dev/tty", "w");
|
|
19224
|
+
import_fs36.default.writeSync(
|
|
18811
19225
|
tty,
|
|
18812
19226
|
import_chalk9.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
|
|
18813
19227
|
);
|
|
18814
|
-
|
|
19228
|
+
import_fs36.default.closeSync(tty);
|
|
18815
19229
|
} catch {
|
|
18816
19230
|
}
|
|
18817
19231
|
const daemonReady = await autoStartDaemonAndWait();
|
|
@@ -18838,9 +19252,9 @@ RAW: ${raw}
|
|
|
18838
19252
|
});
|
|
18839
19253
|
} catch (err2) {
|
|
18840
19254
|
if (process.env.NODE9_DEBUG === "1") {
|
|
18841
|
-
const logPath =
|
|
19255
|
+
const logPath = import_path37.default.join(import_os32.default.homedir(), ".node9", "hook-debug.log");
|
|
18842
19256
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
18843
|
-
|
|
19257
|
+
import_fs36.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
|
|
18844
19258
|
`);
|
|
18845
19259
|
}
|
|
18846
19260
|
process.exit(0);
|
|
@@ -18860,8 +19274,8 @@ RAW: ${raw}
|
|
|
18860
19274
|
await processPayload(raw);
|
|
18861
19275
|
};
|
|
18862
19276
|
process.stdin.setEncoding("utf-8");
|
|
18863
|
-
process.stdin.on("data", (
|
|
18864
|
-
raw +=
|
|
19277
|
+
process.stdin.on("data", (chunk2) => {
|
|
19278
|
+
raw += chunk2;
|
|
18865
19279
|
if (inactivityTimer) clearTimeout(inactivityTimer);
|
|
18866
19280
|
inactivityTimer = setTimeout(() => void done(), 2e3);
|
|
18867
19281
|
});
|
|
@@ -18874,9 +19288,9 @@ RAW: ${raw}
|
|
|
18874
19288
|
}
|
|
18875
19289
|
|
|
18876
19290
|
// src/cli/commands/log.ts
|
|
18877
|
-
var
|
|
18878
|
-
var
|
|
18879
|
-
var
|
|
19291
|
+
var import_fs37 = __toESM(require("fs"));
|
|
19292
|
+
var import_path38 = __toESM(require("path"));
|
|
19293
|
+
var import_os33 = __toESM(require("os"));
|
|
18880
19294
|
init_audit();
|
|
18881
19295
|
init_config();
|
|
18882
19296
|
init_daemon();
|
|
@@ -18971,10 +19385,10 @@ function registerLogCommand(program2) {
|
|
|
18971
19385
|
if (rawToolName !== tool) entry.agentToolName = rawToolName;
|
|
18972
19386
|
const payloadSessionId = payload.session_id ?? payload.conversationId;
|
|
18973
19387
|
if (payloadSessionId) entry.sessionId = payloadSessionId;
|
|
18974
|
-
const logPath =
|
|
18975
|
-
if (!
|
|
18976
|
-
|
|
18977
|
-
|
|
19388
|
+
const logPath = import_path38.default.join(import_os33.default.homedir(), ".node9", "audit.log");
|
|
19389
|
+
if (!import_fs37.default.existsSync(import_path38.default.dirname(logPath)))
|
|
19390
|
+
import_fs37.default.mkdirSync(import_path38.default.dirname(logPath), { recursive: true });
|
|
19391
|
+
import_fs37.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
18978
19392
|
if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
|
|
18979
19393
|
const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
18980
19394
|
if (command) {
|
|
@@ -19008,7 +19422,7 @@ function registerLogCommand(program2) {
|
|
|
19008
19422
|
}
|
|
19009
19423
|
}
|
|
19010
19424
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
19011
|
-
const safeCwd = typeof payloadCwd === "string" &&
|
|
19425
|
+
const safeCwd = typeof payloadCwd === "string" && import_path38.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
19012
19426
|
const config = getConfig(safeCwd);
|
|
19013
19427
|
if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
|
|
19014
19428
|
const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
@@ -19029,9 +19443,9 @@ function registerLogCommand(program2) {
|
|
|
19029
19443
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
19030
19444
|
process.stderr.write(`[Node9] audit log error: ${msg}
|
|
19031
19445
|
`);
|
|
19032
|
-
const debugPath =
|
|
19446
|
+
const debugPath = import_path38.default.join(import_os33.default.homedir(), ".node9", "hook-debug.log");
|
|
19033
19447
|
try {
|
|
19034
|
-
|
|
19448
|
+
import_fs37.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
|
|
19035
19449
|
`);
|
|
19036
19450
|
} catch {
|
|
19037
19451
|
}
|
|
@@ -19043,7 +19457,7 @@ function registerLogCommand(program2) {
|
|
|
19043
19457
|
} else {
|
|
19044
19458
|
let raw = "";
|
|
19045
19459
|
process.stdin.setEncoding("utf-8");
|
|
19046
|
-
process.stdin.on("data", (
|
|
19460
|
+
process.stdin.on("data", (chunk2) => raw += chunk2);
|
|
19047
19461
|
process.stdin.on("end", () => {
|
|
19048
19462
|
void logPayload(raw);
|
|
19049
19463
|
});
|
|
@@ -19071,7 +19485,7 @@ function httpsFetch(url) {
|
|
|
19071
19485
|
return;
|
|
19072
19486
|
}
|
|
19073
19487
|
const chunks = [];
|
|
19074
|
-
res.on("data", (
|
|
19488
|
+
res.on("data", (chunk2) => chunks.push(chunk2));
|
|
19075
19489
|
res.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
|
|
19076
19490
|
res.on("error", reject);
|
|
19077
19491
|
}).on("error", reject);
|
|
@@ -19431,15 +19845,15 @@ function registerConfigShowCommand(program2) {
|
|
|
19431
19845
|
|
|
19432
19846
|
// src/cli/commands/doctor.ts
|
|
19433
19847
|
var import_chalk11 = __toESM(require("chalk"));
|
|
19434
|
-
var
|
|
19435
|
-
var
|
|
19436
|
-
var
|
|
19848
|
+
var import_fs38 = __toESM(require("fs"));
|
|
19849
|
+
var import_path39 = __toESM(require("path"));
|
|
19850
|
+
var import_os34 = __toESM(require("os"));
|
|
19437
19851
|
var import_child_process8 = require("child_process");
|
|
19438
19852
|
init_daemon();
|
|
19439
19853
|
init_config();
|
|
19440
19854
|
function registerDoctorCommand(program2, version2) {
|
|
19441
19855
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
|
|
19442
|
-
const homeDir2 =
|
|
19856
|
+
const homeDir2 = import_os34.default.homedir();
|
|
19443
19857
|
let failures = 0;
|
|
19444
19858
|
function pass(msg) {
|
|
19445
19859
|
console.log(import_chalk11.default.green(" \u2705 ") + msg);
|
|
@@ -19488,10 +19902,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19488
19902
|
);
|
|
19489
19903
|
}
|
|
19490
19904
|
section("Configuration");
|
|
19491
|
-
const globalConfigPath =
|
|
19492
|
-
if (
|
|
19905
|
+
const globalConfigPath = import_path39.default.join(homeDir2, ".node9", "config.json");
|
|
19906
|
+
if (import_fs38.default.existsSync(globalConfigPath)) {
|
|
19493
19907
|
try {
|
|
19494
|
-
JSON.parse(
|
|
19908
|
+
JSON.parse(import_fs38.default.readFileSync(globalConfigPath, "utf-8"));
|
|
19495
19909
|
pass("~/.node9/config.json found and valid");
|
|
19496
19910
|
} catch {
|
|
19497
19911
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -19499,10 +19913,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19499
19913
|
} else {
|
|
19500
19914
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
19501
19915
|
}
|
|
19502
|
-
const projectConfigPath =
|
|
19503
|
-
if (
|
|
19916
|
+
const projectConfigPath = import_path39.default.join(process.cwd(), "node9.config.json");
|
|
19917
|
+
if (import_fs38.default.existsSync(projectConfigPath)) {
|
|
19504
19918
|
try {
|
|
19505
|
-
JSON.parse(
|
|
19919
|
+
JSON.parse(import_fs38.default.readFileSync(projectConfigPath, "utf-8"));
|
|
19506
19920
|
pass("node9.config.json found and valid (project)");
|
|
19507
19921
|
} catch {
|
|
19508
19922
|
fail(
|
|
@@ -19511,8 +19925,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19511
19925
|
);
|
|
19512
19926
|
}
|
|
19513
19927
|
}
|
|
19514
|
-
const credsPath =
|
|
19515
|
-
if (
|
|
19928
|
+
const credsPath = import_path39.default.join(homeDir2, ".node9", "credentials.json");
|
|
19929
|
+
if (import_fs38.default.existsSync(credsPath)) {
|
|
19516
19930
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
19517
19931
|
} else {
|
|
19518
19932
|
warn(
|
|
@@ -19521,10 +19935,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19521
19935
|
);
|
|
19522
19936
|
}
|
|
19523
19937
|
section("Agent Hooks");
|
|
19524
|
-
const claudeSettingsPath =
|
|
19525
|
-
if (
|
|
19938
|
+
const claudeSettingsPath = import_path39.default.join(homeDir2, ".claude", "settings.json");
|
|
19939
|
+
if (import_fs38.default.existsSync(claudeSettingsPath)) {
|
|
19526
19940
|
try {
|
|
19527
|
-
const cs = JSON.parse(
|
|
19941
|
+
const cs = JSON.parse(import_fs38.default.readFileSync(claudeSettingsPath, "utf-8"));
|
|
19528
19942
|
const hasHook = cs.hooks?.PreToolUse?.some(
|
|
19529
19943
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
19530
19944
|
);
|
|
@@ -19540,10 +19954,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19540
19954
|
} else {
|
|
19541
19955
|
warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
|
|
19542
19956
|
}
|
|
19543
|
-
const geminiSettingsPath =
|
|
19544
|
-
if (
|
|
19957
|
+
const geminiSettingsPath = import_path39.default.join(homeDir2, ".gemini", "settings.json");
|
|
19958
|
+
if (import_fs38.default.existsSync(geminiSettingsPath)) {
|
|
19545
19959
|
try {
|
|
19546
|
-
const gs = JSON.parse(
|
|
19960
|
+
const gs = JSON.parse(import_fs38.default.readFileSync(geminiSettingsPath, "utf-8"));
|
|
19547
19961
|
const hasHook = gs.hooks?.BeforeTool?.some(
|
|
19548
19962
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
19549
19963
|
);
|
|
@@ -19559,10 +19973,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19559
19973
|
} else {
|
|
19560
19974
|
warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
|
|
19561
19975
|
}
|
|
19562
|
-
const cursorHooksPath =
|
|
19563
|
-
if (
|
|
19976
|
+
const cursorHooksPath = import_path39.default.join(homeDir2, ".cursor", "hooks.json");
|
|
19977
|
+
if (import_fs38.default.existsSync(cursorHooksPath)) {
|
|
19564
19978
|
try {
|
|
19565
|
-
const cur = JSON.parse(
|
|
19979
|
+
const cur = JSON.parse(import_fs38.default.readFileSync(cursorHooksPath, "utf-8"));
|
|
19566
19980
|
const hasHook = cur.hooks?.preToolUse?.some(
|
|
19567
19981
|
(h) => h.command?.includes("node9") || h.command?.includes("cli.js")
|
|
19568
19982
|
);
|
|
@@ -19593,7 +20007,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19593
20007
|
try {
|
|
19594
20008
|
const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
|
|
19595
20009
|
const cfg = getConfig();
|
|
19596
|
-
const creds =
|
|
20010
|
+
const creds = import_fs38.default.existsSync(import_path39.default.join(import_os34.default.homedir(), ".node9", "credentials.json"));
|
|
19597
20011
|
if (!creds) {
|
|
19598
20012
|
warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
|
|
19599
20013
|
} else if (!cfg.settings.approvers.cloud) {
|
|
@@ -19643,9 +20057,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19643
20057
|
|
|
19644
20058
|
// src/cli/commands/audit.ts
|
|
19645
20059
|
var import_chalk12 = __toESM(require("chalk"));
|
|
19646
|
-
var
|
|
19647
|
-
var
|
|
19648
|
-
var
|
|
20060
|
+
var import_fs39 = __toESM(require("fs"));
|
|
20061
|
+
var import_path40 = __toESM(require("path"));
|
|
20062
|
+
var import_os35 = __toESM(require("os"));
|
|
19649
20063
|
function formatRelativeTime(timestamp) {
|
|
19650
20064
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
19651
20065
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -19658,14 +20072,14 @@ function formatRelativeTime(timestamp) {
|
|
|
19658
20072
|
}
|
|
19659
20073
|
function registerAuditCommand(program2) {
|
|
19660
20074
|
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) => {
|
|
19661
|
-
const logPath =
|
|
19662
|
-
if (!
|
|
20075
|
+
const logPath = import_path40.default.join(import_os35.default.homedir(), ".node9", "audit.log");
|
|
20076
|
+
if (!import_fs39.default.existsSync(logPath)) {
|
|
19663
20077
|
console.log(
|
|
19664
20078
|
import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
19665
20079
|
);
|
|
19666
20080
|
return;
|
|
19667
20081
|
}
|
|
19668
|
-
const raw =
|
|
20082
|
+
const raw = import_fs39.default.readFileSync(logPath, "utf-8");
|
|
19669
20083
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
19670
20084
|
let entries = lines.flatMap((line) => {
|
|
19671
20085
|
try {
|
|
@@ -19721,9 +20135,9 @@ function registerAuditCommand(program2) {
|
|
|
19721
20135
|
var import_chalk13 = __toESM(require("chalk"));
|
|
19722
20136
|
|
|
19723
20137
|
// src/cli/aggregate/report-audit.ts
|
|
19724
|
-
var
|
|
19725
|
-
var
|
|
19726
|
-
var
|
|
20138
|
+
var import_fs40 = __toESM(require("fs"));
|
|
20139
|
+
var import_os36 = __toESM(require("os"));
|
|
20140
|
+
var import_path41 = __toESM(require("path"));
|
|
19727
20141
|
init_costSync();
|
|
19728
20142
|
init_litellm();
|
|
19729
20143
|
var TEST_COMMAND_RE3 = /(?:^|\s)(npm\s+(?:run\s+)?test|npx\s+(?:vitest|jest|mocha)|yarn\s+(?:run\s+)?test|pnpm\s+(?:run\s+)?test|vitest|jest|mocha|pytest|py\.test|cargo\s+test|go\s+test|bundle\s+exec\s+rspec|rspec|phpunit|dotnet\s+test)\b/i;
|
|
@@ -19805,8 +20219,8 @@ function getDateRange(period, now) {
|
|
|
19805
20219
|
}
|
|
19806
20220
|
}
|
|
19807
20221
|
function parseAuditLog(logPath) {
|
|
19808
|
-
if (!
|
|
19809
|
-
const raw =
|
|
20222
|
+
if (!import_fs40.default.existsSync(logPath)) return [];
|
|
20223
|
+
const raw = import_fs40.default.readFileSync(logPath, "utf-8");
|
|
19810
20224
|
return raw.split("\n").flatMap((line) => {
|
|
19811
20225
|
if (!line.trim()) return [];
|
|
19812
20226
|
try {
|
|
@@ -19866,25 +20280,25 @@ function freezeClaudeCost(acc) {
|
|
|
19866
20280
|
};
|
|
19867
20281
|
}
|
|
19868
20282
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
19869
|
-
const projPath =
|
|
20283
|
+
const projPath = import_path41.default.join(projectsDir, proj);
|
|
19870
20284
|
let files;
|
|
19871
20285
|
try {
|
|
19872
|
-
const stat =
|
|
20286
|
+
const stat = import_fs40.default.statSync(projPath);
|
|
19873
20287
|
if (!stat.isDirectory()) return;
|
|
19874
|
-
files =
|
|
20288
|
+
files = import_fs40.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
19875
20289
|
} catch {
|
|
19876
20290
|
return;
|
|
19877
20291
|
}
|
|
19878
20292
|
const startMs = start.getTime();
|
|
19879
20293
|
for (const file of files) {
|
|
19880
|
-
const filePath =
|
|
20294
|
+
const filePath = import_path41.default.join(projPath, file);
|
|
19881
20295
|
try {
|
|
19882
|
-
if (
|
|
20296
|
+
if (import_fs40.default.statSync(filePath).mtimeMs < startMs) continue;
|
|
19883
20297
|
} catch {
|
|
19884
20298
|
continue;
|
|
19885
20299
|
}
|
|
19886
20300
|
try {
|
|
19887
|
-
const raw =
|
|
20301
|
+
const raw = import_fs40.default.readFileSync(filePath, "utf-8");
|
|
19888
20302
|
for (const line of raw.split("\n")) {
|
|
19889
20303
|
if (!line.trim()) continue;
|
|
19890
20304
|
let entry;
|
|
@@ -19934,10 +20348,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
19934
20348
|
}
|
|
19935
20349
|
function loadClaudeCost(start, end, projectsDir) {
|
|
19936
20350
|
const acc = emptyClaudeCostAccumulator();
|
|
19937
|
-
if (!
|
|
20351
|
+
if (!import_fs40.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
19938
20352
|
let dirs;
|
|
19939
20353
|
try {
|
|
19940
|
-
dirs =
|
|
20354
|
+
dirs = import_fs40.default.readdirSync(projectsDir);
|
|
19941
20355
|
} catch {
|
|
19942
20356
|
return freezeClaudeCost(acc);
|
|
19943
20357
|
}
|
|
@@ -19949,7 +20363,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
19949
20363
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
19950
20364
|
let lines;
|
|
19951
20365
|
try {
|
|
19952
|
-
lines =
|
|
20366
|
+
lines = import_fs40.default.readFileSync(filePath, "utf-8").split("\n");
|
|
19953
20367
|
} catch {
|
|
19954
20368
|
return;
|
|
19955
20369
|
}
|
|
@@ -19992,33 +20406,33 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
19992
20406
|
const dateKey = sessionStart2.slice(0, 10);
|
|
19993
20407
|
acc.byDay.set(dateKey, (acc.byDay.get(dateKey) ?? 0) + cost);
|
|
19994
20408
|
}
|
|
19995
|
-
function
|
|
20409
|
+
function listCodexSessionFiles2(sessionsBase) {
|
|
19996
20410
|
const jsonlFiles = [];
|
|
19997
|
-
if (!
|
|
20411
|
+
if (!import_fs40.default.existsSync(sessionsBase)) return jsonlFiles;
|
|
19998
20412
|
try {
|
|
19999
|
-
for (const year of
|
|
20000
|
-
const yearPath =
|
|
20413
|
+
for (const year of import_fs40.default.readdirSync(sessionsBase)) {
|
|
20414
|
+
const yearPath = import_path41.default.join(sessionsBase, year);
|
|
20001
20415
|
try {
|
|
20002
|
-
if (!
|
|
20416
|
+
if (!import_fs40.default.statSync(yearPath).isDirectory()) continue;
|
|
20003
20417
|
} catch {
|
|
20004
20418
|
continue;
|
|
20005
20419
|
}
|
|
20006
|
-
for (const month of
|
|
20007
|
-
const monthPath =
|
|
20420
|
+
for (const month of import_fs40.default.readdirSync(yearPath)) {
|
|
20421
|
+
const monthPath = import_path41.default.join(yearPath, month);
|
|
20008
20422
|
try {
|
|
20009
|
-
if (!
|
|
20423
|
+
if (!import_fs40.default.statSync(monthPath).isDirectory()) continue;
|
|
20010
20424
|
} catch {
|
|
20011
20425
|
continue;
|
|
20012
20426
|
}
|
|
20013
|
-
for (const day of
|
|
20014
|
-
const dayPath =
|
|
20427
|
+
for (const day of import_fs40.default.readdirSync(monthPath)) {
|
|
20428
|
+
const dayPath = import_path41.default.join(monthPath, day);
|
|
20015
20429
|
try {
|
|
20016
|
-
if (!
|
|
20430
|
+
if (!import_fs40.default.statSync(dayPath).isDirectory()) continue;
|
|
20017
20431
|
} catch {
|
|
20018
20432
|
continue;
|
|
20019
20433
|
}
|
|
20020
|
-
for (const file of
|
|
20021
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
20434
|
+
for (const file of import_fs40.default.readdirSync(dayPath)) {
|
|
20435
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path41.default.join(dayPath, file));
|
|
20022
20436
|
}
|
|
20023
20437
|
}
|
|
20024
20438
|
}
|
|
@@ -20030,17 +20444,17 @@ function listCodexSessionFiles(sessionsBase) {
|
|
|
20030
20444
|
}
|
|
20031
20445
|
function loadCodexCost(start, end, sessionsBase) {
|
|
20032
20446
|
const acc = { total: 0, toolCalls: 0, byDay: /* @__PURE__ */ new Map() };
|
|
20033
|
-
const files =
|
|
20447
|
+
const files = listCodexSessionFiles2(sessionsBase);
|
|
20034
20448
|
for (const filePath of files) {
|
|
20035
20449
|
processCodexCostFile(filePath, start, end, acc);
|
|
20036
20450
|
}
|
|
20037
20451
|
return { total: acc.total, byDay: acc.byDay, toolCalls: acc.toolCalls };
|
|
20038
20452
|
}
|
|
20039
|
-
var
|
|
20040
|
-
function
|
|
20453
|
+
var GEMINI_FALLBACK_MODELS2 = ["gemini-2.5-flash", "gemini-2.0-flash"];
|
|
20454
|
+
function geminiPriceFor2(model) {
|
|
20041
20455
|
let tuple = pricingFor(model);
|
|
20042
20456
|
if (!tuple && /^gemini-/i.test(model)) {
|
|
20043
|
-
for (const proxy of
|
|
20457
|
+
for (const proxy of GEMINI_FALLBACK_MODELS2) {
|
|
20044
20458
|
tuple = pricingFor(proxy);
|
|
20045
20459
|
if (tuple) break;
|
|
20046
20460
|
}
|
|
@@ -20071,13 +20485,13 @@ function freezeGeminiCost(acc) {
|
|
|
20071
20485
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
20072
20486
|
const startMs = start.getTime();
|
|
20073
20487
|
try {
|
|
20074
|
-
if (
|
|
20488
|
+
if (import_fs40.default.statSync(filePath).mtimeMs < startMs) return;
|
|
20075
20489
|
} catch {
|
|
20076
20490
|
return;
|
|
20077
20491
|
}
|
|
20078
20492
|
let raw;
|
|
20079
20493
|
try {
|
|
20080
|
-
raw =
|
|
20494
|
+
raw = import_fs40.default.readFileSync(filePath, "utf-8");
|
|
20081
20495
|
} catch {
|
|
20082
20496
|
return;
|
|
20083
20497
|
}
|
|
@@ -20098,7 +20512,7 @@ function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
|
20098
20512
|
}
|
|
20099
20513
|
const ts = new Date(entry.timestamp);
|
|
20100
20514
|
if (ts < start || ts > end) continue;
|
|
20101
|
-
const price =
|
|
20515
|
+
const price = geminiPriceFor2(entry.model);
|
|
20102
20516
|
if (!price) continue;
|
|
20103
20517
|
const inp = entry.tokens.input ?? 0;
|
|
20104
20518
|
const out = entry.tokens.output ?? 0;
|
|
@@ -20122,46 +20536,46 @@ function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
|
20122
20536
|
acc.byProject.set(projectKey, rollup);
|
|
20123
20537
|
}
|
|
20124
20538
|
}
|
|
20125
|
-
function
|
|
20539
|
+
function listGeminiSessionFiles2(geminiTmpDir2) {
|
|
20126
20540
|
const out = [];
|
|
20127
20541
|
let dirs;
|
|
20128
20542
|
try {
|
|
20129
|
-
if (!
|
|
20130
|
-
dirs =
|
|
20543
|
+
if (!import_fs40.default.statSync(geminiTmpDir2).isDirectory()) return out;
|
|
20544
|
+
dirs = import_fs40.default.readdirSync(geminiTmpDir2);
|
|
20131
20545
|
} catch {
|
|
20132
20546
|
return out;
|
|
20133
20547
|
}
|
|
20134
20548
|
for (const proj of dirs) {
|
|
20135
|
-
const chatsDir =
|
|
20549
|
+
const chatsDir = import_path41.default.join(geminiTmpDir2, proj, "chats");
|
|
20136
20550
|
let files;
|
|
20137
20551
|
try {
|
|
20138
|
-
if (!
|
|
20139
|
-
files =
|
|
20552
|
+
if (!import_fs40.default.statSync(chatsDir).isDirectory()) continue;
|
|
20553
|
+
files = import_fs40.default.readdirSync(chatsDir);
|
|
20140
20554
|
} catch {
|
|
20141
20555
|
continue;
|
|
20142
20556
|
}
|
|
20143
20557
|
for (const f of files) {
|
|
20144
20558
|
if (!f.endsWith(".jsonl")) continue;
|
|
20145
|
-
out.push({ projectKey: proj, file:
|
|
20559
|
+
out.push({ projectKey: proj, file: import_path41.default.join(chatsDir, f) });
|
|
20146
20560
|
}
|
|
20147
20561
|
}
|
|
20148
20562
|
return out;
|
|
20149
20563
|
}
|
|
20150
|
-
function loadGeminiCost(start, end,
|
|
20564
|
+
function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
20151
20565
|
const acc = emptyGeminiAccumulator();
|
|
20152
|
-
if (!
|
|
20153
|
-
for (const { projectKey, file } of
|
|
20566
|
+
if (!import_fs40.default.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
|
|
20567
|
+
for (const { projectKey, file } of listGeminiSessionFiles2(geminiTmpDir2)) {
|
|
20154
20568
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
20155
20569
|
}
|
|
20156
20570
|
return freezeGeminiCost(acc);
|
|
20157
20571
|
}
|
|
20158
20572
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
20159
20573
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
20160
|
-
const auditLogPath = opts.auditLogPath ??
|
|
20161
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
20162
|
-
const
|
|
20163
|
-
const
|
|
20164
|
-
const hasAuditFile =
|
|
20574
|
+
const auditLogPath = opts.auditLogPath ?? import_path41.default.join(import_os36.default.homedir(), ".node9", "audit.log");
|
|
20575
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? import_path41.default.join(import_os36.default.homedir(), ".claude", "projects");
|
|
20576
|
+
const codexSessionsDir2 = opts.codexSessionsDir ?? import_path41.default.join(import_os36.default.homedir(), ".codex", "sessions");
|
|
20577
|
+
const geminiTmpDir2 = opts.geminiTmpDir ?? import_path41.default.join(import_os36.default.homedir(), ".gemini", "tmp");
|
|
20578
|
+
const hasAuditFile = import_fs40.default.existsSync(auditLogPath);
|
|
20165
20579
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
20166
20580
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
20167
20581
|
const { start, end } = getDateRange(period, now);
|
|
@@ -20178,8 +20592,8 @@ function aggregateReportFromAudit(period, opts = {}) {
|
|
|
20178
20592
|
};
|
|
20179
20593
|
});
|
|
20180
20594
|
const claudeCost = opts.preloadedClaudeCost ?? loadClaudeCost(start, end, claudeProjectsDir);
|
|
20181
|
-
const codexCost = opts.preloadedCodexCost ?? loadCodexCost(start, end,
|
|
20182
|
-
const geminiCost = opts.preloadedGeminiCost ?? loadGeminiCost(start, end,
|
|
20595
|
+
const codexCost = opts.preloadedCodexCost ?? loadCodexCost(start, end, codexSessionsDir2);
|
|
20596
|
+
const geminiCost = opts.preloadedGeminiCost ?? loadGeminiCost(start, end, geminiTmpDir2);
|
|
20183
20597
|
for (const [day, c] of codexCost.byDay) {
|
|
20184
20598
|
claudeCost.byDay.set(day, (claudeCost.byDay.get(day) ?? 0) + c);
|
|
20185
20599
|
}
|
|
@@ -20857,21 +21271,48 @@ function registerDaemonCommand(program2) {
|
|
|
20857
21271
|
|
|
20858
21272
|
// src/cli/commands/status.ts
|
|
20859
21273
|
var import_chalk15 = __toESM(require("chalk"));
|
|
20860
|
-
var
|
|
20861
|
-
var
|
|
20862
|
-
var
|
|
21274
|
+
var import_fs41 = __toESM(require("fs"));
|
|
21275
|
+
var import_path42 = __toESM(require("path"));
|
|
21276
|
+
var import_os37 = __toESM(require("os"));
|
|
21277
|
+
var yaml2 = __toESM(require("yaml"));
|
|
20863
21278
|
init_core();
|
|
20864
21279
|
init_daemon();
|
|
21280
|
+
init_setup();
|
|
21281
|
+
function readHermesHooks(configPath) {
|
|
21282
|
+
if (!import_fs41.default.existsSync(configPath)) return null;
|
|
21283
|
+
let raw;
|
|
21284
|
+
try {
|
|
21285
|
+
raw = import_fs41.default.readFileSync(configPath, "utf-8");
|
|
21286
|
+
} catch {
|
|
21287
|
+
return null;
|
|
21288
|
+
}
|
|
21289
|
+
try {
|
|
21290
|
+
const cfg = yaml2.parse(raw);
|
|
21291
|
+
const has = (event) => (cfg?.hooks?.[event] ?? []).some(
|
|
21292
|
+
(e) => typeof e?.command === "string" && isNode9Hook(e.command)
|
|
21293
|
+
);
|
|
21294
|
+
return { pre: has("pre_tool_call"), post: has("post_tool_call") };
|
|
21295
|
+
} catch {
|
|
21296
|
+
console.error(
|
|
21297
|
+
import_chalk15.default.yellow(
|
|
21298
|
+
` \u26A0\uFE0F Hermes config.yaml at ${configPath} is not valid YAML \u2014 showing as unwired.`
|
|
21299
|
+
)
|
|
21300
|
+
);
|
|
21301
|
+
return { pre: false, post: false };
|
|
21302
|
+
}
|
|
21303
|
+
}
|
|
20865
21304
|
function readJson2(filePath) {
|
|
20866
21305
|
try {
|
|
20867
|
-
if (
|
|
21306
|
+
if (import_fs41.default.existsSync(filePath)) return JSON.parse(import_fs41.default.readFileSync(filePath, "utf-8"));
|
|
20868
21307
|
} catch {
|
|
20869
21308
|
}
|
|
20870
21309
|
return null;
|
|
20871
21310
|
}
|
|
20872
|
-
function
|
|
20873
|
-
|
|
20874
|
-
|
|
21311
|
+
function matchersHaveNode9Hook(matchers) {
|
|
21312
|
+
return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
|
|
21313
|
+
}
|
|
21314
|
+
function flatHaveNode9Hook(entries) {
|
|
21315
|
+
return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
|
|
20875
21316
|
}
|
|
20876
21317
|
function wrappedMcpServers(servers) {
|
|
20877
21318
|
if (!servers) return [];
|
|
@@ -20886,6 +21327,7 @@ function printAgentSection(label, hookPairs, wrapped) {
|
|
|
20886
21327
|
console.log(import_chalk15.default.red(` \u2717 ${name}`) + import_chalk15.default.gray(" (not wired)"));
|
|
20887
21328
|
}
|
|
20888
21329
|
}
|
|
21330
|
+
if (wrapped === null) return;
|
|
20889
21331
|
if (wrapped.length > 0) {
|
|
20890
21332
|
console.log(import_chalk15.default.cyan(` MCP proxied:`));
|
|
20891
21333
|
for (const entry of wrapped) {
|
|
@@ -20929,40 +21371,51 @@ function registerStatusCommand(program2) {
|
|
|
20929
21371
|
console.log("");
|
|
20930
21372
|
const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
|
|
20931
21373
|
console.log(` Mode: ${modeLabel}`);
|
|
20932
|
-
const projectConfig =
|
|
20933
|
-
const globalConfig =
|
|
21374
|
+
const projectConfig = import_path42.default.join(process.cwd(), "node9.config.json");
|
|
21375
|
+
const globalConfig = import_path42.default.join(import_os37.default.homedir(), ".node9", "config.json");
|
|
20934
21376
|
console.log(
|
|
20935
|
-
` Local: ${
|
|
21377
|
+
` Local: ${import_fs41.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
|
|
20936
21378
|
);
|
|
20937
21379
|
console.log(
|
|
20938
|
-
` Global: ${
|
|
21380
|
+
` Global: ${import_fs41.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
|
|
20939
21381
|
);
|
|
20940
21382
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
20941
21383
|
console.log(
|
|
20942
21384
|
` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
20943
21385
|
);
|
|
20944
21386
|
}
|
|
20945
|
-
const homeDir2 =
|
|
21387
|
+
const homeDir2 = import_os37.default.homedir();
|
|
20946
21388
|
const claudeSettings = readJson2(
|
|
20947
|
-
|
|
21389
|
+
import_path42.default.join(homeDir2, ".claude", "settings.json")
|
|
20948
21390
|
);
|
|
20949
|
-
const claudeConfig = readJson2(
|
|
21391
|
+
const claudeConfig = readJson2(import_path42.default.join(homeDir2, ".claude.json"));
|
|
20950
21392
|
const geminiSettings = readJson2(
|
|
20951
|
-
|
|
21393
|
+
import_path42.default.join(homeDir2, ".gemini", "settings.json")
|
|
21394
|
+
);
|
|
21395
|
+
const cursorConfig = readJson2(import_path42.default.join(homeDir2, ".cursor", "mcp.json"));
|
|
21396
|
+
const antigravityHooks = readJson2(
|
|
21397
|
+
import_path42.default.join(homeDir2, ".gemini", "config", "hooks.json")
|
|
21398
|
+
);
|
|
21399
|
+
const antigravityMcp = readJson2(
|
|
21400
|
+
import_path42.default.join(homeDir2, ".gemini", "config", "mcp_config.json")
|
|
21401
|
+
);
|
|
21402
|
+
const antigravityPresent = antigravityHooks !== null || import_fs41.default.existsSync(import_path42.default.join(homeDir2, ".gemini", "antigravity-cli")) || import_fs41.default.existsSync(import_path42.default.join(homeDir2, ".gemini", "antigravity-ide"));
|
|
21403
|
+
const copilotHooks = readJson2(
|
|
21404
|
+
import_path42.default.join(homeDir2, ".copilot", "hooks", "node9.json")
|
|
20952
21405
|
);
|
|
20953
|
-
const
|
|
20954
|
-
|
|
21406
|
+
const copilotMcp = readJson2(
|
|
21407
|
+
import_path42.default.join(homeDir2, ".copilot", "mcp-config.json")
|
|
21408
|
+
);
|
|
21409
|
+
const copilotPresent = import_fs41.default.existsSync(import_path42.default.join(homeDir2, ".copilot"));
|
|
21410
|
+
const hermesHooks = readHermesHooks(hermesConfigPath(homeDir2));
|
|
21411
|
+
const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig || antigravityPresent || copilotPresent || hermesHooks;
|
|
20955
21412
|
if (agentFound) {
|
|
20956
21413
|
console.log("");
|
|
20957
21414
|
console.log(import_chalk15.default.bold(" Agent Wiring:"));
|
|
20958
21415
|
console.log("");
|
|
20959
21416
|
if (claudeSettings || claudeConfig) {
|
|
20960
|
-
const preHook = claudeSettings?.hooks?.PreToolUse
|
|
20961
|
-
|
|
20962
|
-
) ?? false;
|
|
20963
|
-
const postHook = claudeSettings?.hooks?.PostToolUse?.some(
|
|
20964
|
-
(m) => m.hooks.some((h) => isNode9Hook2(h.command))
|
|
20965
|
-
) ?? false;
|
|
21417
|
+
const preHook = matchersHaveNode9Hook(claudeSettings?.hooks?.PreToolUse);
|
|
21418
|
+
const postHook = matchersHaveNode9Hook(claudeSettings?.hooks?.PostToolUse);
|
|
20966
21419
|
printAgentSection(
|
|
20967
21420
|
"Claude Code",
|
|
20968
21421
|
[
|
|
@@ -20974,12 +21427,8 @@ function registerStatusCommand(program2) {
|
|
|
20974
21427
|
console.log("");
|
|
20975
21428
|
}
|
|
20976
21429
|
if (geminiSettings) {
|
|
20977
|
-
const beforeHook = geminiSettings.hooks?.BeforeTool
|
|
20978
|
-
|
|
20979
|
-
) ?? false;
|
|
20980
|
-
const afterHook = geminiSettings.hooks?.AfterTool?.some(
|
|
20981
|
-
(m) => m.hooks.some((h) => isNode9Hook2(h.command))
|
|
20982
|
-
) ?? false;
|
|
21430
|
+
const beforeHook = matchersHaveNode9Hook(geminiSettings.hooks?.BeforeTool);
|
|
21431
|
+
const afterHook = matchersHaveNode9Hook(geminiSettings.hooks?.AfterTool);
|
|
20983
21432
|
printAgentSection(
|
|
20984
21433
|
"Gemini CLI",
|
|
20985
21434
|
[
|
|
@@ -20990,10 +21439,50 @@ function registerStatusCommand(program2) {
|
|
|
20990
21439
|
);
|
|
20991
21440
|
console.log("");
|
|
20992
21441
|
}
|
|
21442
|
+
if (antigravityPresent) {
|
|
21443
|
+
const preHook = matchersHaveNode9Hook(antigravityHooks?.hooks?.PreToolUse);
|
|
21444
|
+
const postHook = matchersHaveNode9Hook(antigravityHooks?.hooks?.PostToolUse);
|
|
21445
|
+
printAgentSection(
|
|
21446
|
+
"Antigravity",
|
|
21447
|
+
[
|
|
21448
|
+
{ name: "PreToolUse (node9 check)", present: preHook },
|
|
21449
|
+
{ name: "PostToolUse (node9 log)", present: postHook }
|
|
21450
|
+
],
|
|
21451
|
+
wrappedMcpServers(antigravityMcp?.mcpServers)
|
|
21452
|
+
);
|
|
21453
|
+
console.log("");
|
|
21454
|
+
}
|
|
21455
|
+
if (copilotPresent) {
|
|
21456
|
+
const preHook = flatHaveNode9Hook(copilotHooks?.hooks?.PreToolUse);
|
|
21457
|
+
const postHook = flatHaveNode9Hook(copilotHooks?.hooks?.PostToolUse);
|
|
21458
|
+
const promptHook = flatHaveNode9Hook(copilotHooks?.hooks?.UserPromptSubmit);
|
|
21459
|
+
printAgentSection(
|
|
21460
|
+
"GitHub Copilot",
|
|
21461
|
+
[
|
|
21462
|
+
{ name: "PreToolUse (node9 check)", present: preHook },
|
|
21463
|
+
{ name: "PostToolUse (node9 log)", present: postHook },
|
|
21464
|
+
{ name: "UserPromptSubmit (node9 check)", present: promptHook }
|
|
21465
|
+
],
|
|
21466
|
+
wrappedMcpServers(copilotMcp?.mcpServers)
|
|
21467
|
+
);
|
|
21468
|
+
console.log("");
|
|
21469
|
+
}
|
|
20993
21470
|
if (cursorConfig) {
|
|
20994
21471
|
printAgentSection("Cursor", [], wrappedMcpServers(cursorConfig.mcpServers));
|
|
20995
21472
|
console.log("");
|
|
20996
21473
|
}
|
|
21474
|
+
if (hermesHooks) {
|
|
21475
|
+
printAgentSection(
|
|
21476
|
+
"Hermes Agent",
|
|
21477
|
+
[
|
|
21478
|
+
{ name: "pre_tool_call (node9 check)", present: hermesHooks.pre },
|
|
21479
|
+
{ name: "post_tool_call (node9 log)", present: hermesHooks.post }
|
|
21480
|
+
],
|
|
21481
|
+
null
|
|
21482
|
+
// Hermes has no MCP surface
|
|
21483
|
+
);
|
|
21484
|
+
console.log("");
|
|
21485
|
+
}
|
|
20997
21486
|
}
|
|
20998
21487
|
const pauseState = checkPause();
|
|
20999
21488
|
if (pauseState.paused) {
|
|
@@ -21009,9 +21498,9 @@ function registerStatusCommand(program2) {
|
|
|
21009
21498
|
|
|
21010
21499
|
// src/cli/commands/init.ts
|
|
21011
21500
|
var import_chalk16 = __toESM(require("chalk"));
|
|
21012
|
-
var
|
|
21013
|
-
var
|
|
21014
|
-
var
|
|
21501
|
+
var import_fs42 = __toESM(require("fs"));
|
|
21502
|
+
var import_path43 = __toESM(require("path"));
|
|
21503
|
+
var import_os38 = __toESM(require("os"));
|
|
21015
21504
|
var import_https4 = __toESM(require("https"));
|
|
21016
21505
|
init_core();
|
|
21017
21506
|
init_setup();
|
|
@@ -21101,16 +21590,16 @@ function registerInitCommand(program2) {
|
|
|
21101
21590
|
}
|
|
21102
21591
|
console.log("");
|
|
21103
21592
|
}
|
|
21104
|
-
const configPath =
|
|
21105
|
-
const isFirstInstall = !
|
|
21106
|
-
if (
|
|
21593
|
+
const configPath = import_path43.default.join(import_os38.default.homedir(), ".node9", "config.json");
|
|
21594
|
+
const isFirstInstall = !import_fs42.default.existsSync(configPath);
|
|
21595
|
+
if (import_fs42.default.existsSync(configPath) && !options.force) {
|
|
21107
21596
|
try {
|
|
21108
|
-
const existing = JSON.parse(
|
|
21597
|
+
const existing = JSON.parse(import_fs42.default.readFileSync(configPath, "utf-8"));
|
|
21109
21598
|
const settings = existing.settings ?? {};
|
|
21110
21599
|
if (settings.mode !== chosenMode) {
|
|
21111
21600
|
settings.mode = chosenMode;
|
|
21112
21601
|
existing.settings = settings;
|
|
21113
|
-
|
|
21602
|
+
import_fs42.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
21114
21603
|
console.log(import_chalk16.default.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
21115
21604
|
} else {
|
|
21116
21605
|
console.log(import_chalk16.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -21123,9 +21612,9 @@ function registerInitCommand(program2) {
|
|
|
21123
21612
|
...DEFAULT_CONFIG,
|
|
21124
21613
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
21125
21614
|
};
|
|
21126
|
-
const dir =
|
|
21127
|
-
if (!
|
|
21128
|
-
|
|
21615
|
+
const dir = import_path43.default.dirname(configPath);
|
|
21616
|
+
if (!import_fs42.default.existsSync(dir)) import_fs42.default.mkdirSync(dir, { recursive: true });
|
|
21617
|
+
import_fs42.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
21129
21618
|
console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
|
|
21130
21619
|
console.log(import_chalk16.default.gray(` Mode: ${chosenMode}`));
|
|
21131
21620
|
}
|
|
@@ -21230,7 +21719,7 @@ function registerInitCommand(program2) {
|
|
|
21230
21719
|
}
|
|
21231
21720
|
|
|
21232
21721
|
// src/cli/commands/undo.ts
|
|
21233
|
-
var
|
|
21722
|
+
var import_path44 = __toESM(require("path"));
|
|
21234
21723
|
var import_chalk18 = __toESM(require("chalk"));
|
|
21235
21724
|
|
|
21236
21725
|
// src/tui/undo-navigator.ts
|
|
@@ -21389,7 +21878,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
21389
21878
|
let dir = startDir;
|
|
21390
21879
|
while (true) {
|
|
21391
21880
|
if (cwds.has(dir)) return dir;
|
|
21392
|
-
const parent =
|
|
21881
|
+
const parent = import_path44.default.dirname(dir);
|
|
21393
21882
|
if (parent === dir) return null;
|
|
21394
21883
|
dir = parent;
|
|
21395
21884
|
}
|
|
@@ -21965,9 +22454,9 @@ function registerMcpGatewayCommand(program2) {
|
|
|
21965
22454
|
|
|
21966
22455
|
// src/mcp-server/index.ts
|
|
21967
22456
|
var import_readline5 = __toESM(require("readline"));
|
|
21968
|
-
var
|
|
21969
|
-
var
|
|
21970
|
-
var
|
|
22457
|
+
var import_fs43 = __toESM(require("fs"));
|
|
22458
|
+
var import_os39 = __toESM(require("os"));
|
|
22459
|
+
var import_path45 = __toESM(require("path"));
|
|
21971
22460
|
var import_child_process11 = require("child_process");
|
|
21972
22461
|
init_core();
|
|
21973
22462
|
init_daemon();
|
|
@@ -22218,13 +22707,13 @@ function handleStatus() {
|
|
|
22218
22707
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
22219
22708
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
22220
22709
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
22221
|
-
const projectConfig =
|
|
22222
|
-
const globalConfig =
|
|
22710
|
+
const projectConfig = import_path45.default.join(process.cwd(), "node9.config.json");
|
|
22711
|
+
const globalConfig = import_path45.default.join(import_os39.default.homedir(), ".node9", "config.json");
|
|
22223
22712
|
lines.push(
|
|
22224
|
-
`Project config (node9.config.json): ${
|
|
22713
|
+
`Project config (node9.config.json): ${import_fs43.default.existsSync(projectConfig) ? "present" : "not found"}`
|
|
22225
22714
|
);
|
|
22226
22715
|
lines.push(
|
|
22227
|
-
`Global config (~/.node9/config.json): ${
|
|
22716
|
+
`Global config (~/.node9/config.json): ${import_fs43.default.existsSync(globalConfig) ? "present" : "not found"}`
|
|
22228
22717
|
);
|
|
22229
22718
|
return lines.join("\n");
|
|
22230
22719
|
}
|
|
@@ -22298,21 +22787,21 @@ function handleShieldDisable(args) {
|
|
|
22298
22787
|
writeActiveShields(active.filter((s) => s !== name));
|
|
22299
22788
|
return `Shield "${name}" disabled.`;
|
|
22300
22789
|
}
|
|
22301
|
-
var GLOBAL_CONFIG_PATH =
|
|
22790
|
+
var GLOBAL_CONFIG_PATH = import_path45.default.join(import_os39.default.homedir(), ".node9", "config.json");
|
|
22302
22791
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
22303
22792
|
function readGlobalConfigRaw() {
|
|
22304
22793
|
try {
|
|
22305
|
-
if (
|
|
22306
|
-
return JSON.parse(
|
|
22794
|
+
if (import_fs43.default.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
22795
|
+
return JSON.parse(import_fs43.default.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
|
|
22307
22796
|
}
|
|
22308
22797
|
} catch {
|
|
22309
22798
|
}
|
|
22310
22799
|
return {};
|
|
22311
22800
|
}
|
|
22312
22801
|
function writeGlobalConfigRaw(data) {
|
|
22313
|
-
const dir =
|
|
22314
|
-
if (!
|
|
22315
|
-
|
|
22802
|
+
const dir = import_path45.default.dirname(GLOBAL_CONFIG_PATH);
|
|
22803
|
+
if (!import_fs43.default.existsSync(dir)) import_fs43.default.mkdirSync(dir, { recursive: true });
|
|
22804
|
+
import_fs43.default.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
|
|
22316
22805
|
}
|
|
22317
22806
|
function handleApproverList() {
|
|
22318
22807
|
const config = getConfig();
|
|
@@ -22356,9 +22845,9 @@ function handleApproverSet(args) {
|
|
|
22356
22845
|
function handleAuditGet(args) {
|
|
22357
22846
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
22358
22847
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
22359
|
-
const auditPath =
|
|
22360
|
-
if (!
|
|
22361
|
-
const rawLines =
|
|
22848
|
+
const auditPath = import_path45.default.join(import_os39.default.homedir(), ".node9", "audit.log");
|
|
22849
|
+
if (!import_fs43.default.existsSync(auditPath)) return "No audit log found.";
|
|
22850
|
+
const rawLines = import_fs43.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
22362
22851
|
const parsed = [];
|
|
22363
22852
|
for (const line of rawLines) {
|
|
22364
22853
|
try {
|
|
@@ -22693,7 +23182,7 @@ function registerTrustCommand(program2) {
|
|
|
22693
23182
|
// src/cli/commands/mcp-pin.ts
|
|
22694
23183
|
var import_chalk21 = __toESM(require("chalk"));
|
|
22695
23184
|
init_mcp_pin();
|
|
22696
|
-
var
|
|
23185
|
+
var import_fs44 = __toESM(require("fs"));
|
|
22697
23186
|
function registerMcpPinCommand(program2) {
|
|
22698
23187
|
const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
|
|
22699
23188
|
const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
|
|
@@ -22704,7 +23193,7 @@ function registerMcpPinCommand(program2) {
|
|
|
22704
23193
|
let repoCorrupt = false;
|
|
22705
23194
|
if (found.source === "repo") {
|
|
22706
23195
|
try {
|
|
22707
|
-
const raw =
|
|
23196
|
+
const raw = import_fs44.default.readFileSync(found.path, "utf-8");
|
|
22708
23197
|
const parsed = JSON.parse(raw);
|
|
22709
23198
|
repoEntries = parsed.servers ?? {};
|
|
22710
23199
|
} catch {
|
|
@@ -23017,9 +23506,9 @@ init_scan();
|
|
|
23017
23506
|
|
|
23018
23507
|
// src/cli/commands/sessions.ts
|
|
23019
23508
|
var import_chalk24 = __toESM(require("chalk"));
|
|
23020
|
-
var
|
|
23021
|
-
var
|
|
23022
|
-
var
|
|
23509
|
+
var import_fs45 = __toESM(require("fs"));
|
|
23510
|
+
var import_path46 = __toESM(require("path"));
|
|
23511
|
+
var import_os40 = __toESM(require("os"));
|
|
23023
23512
|
init_scan_summary();
|
|
23024
23513
|
var CLAUDE_PRICING3 = {
|
|
23025
23514
|
"claude-opus-4-6": { i: 5e-6, o: 25e-6, cw: 625e-8, cr: 5e-7 },
|
|
@@ -23061,10 +23550,10 @@ function encodeProjectPath(projectPath) {
|
|
|
23061
23550
|
}
|
|
23062
23551
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
23063
23552
|
const encoded = encodeProjectPath(projectPath);
|
|
23064
|
-
return
|
|
23553
|
+
return import_path46.default.join(import_os40.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
23065
23554
|
}
|
|
23066
23555
|
function projectLabel(projectPath) {
|
|
23067
|
-
return projectPath.replace(
|
|
23556
|
+
return projectPath.replace(import_os40.default.homedir(), "~");
|
|
23068
23557
|
}
|
|
23069
23558
|
function parseHistoryLines(lines) {
|
|
23070
23559
|
const entries = [];
|
|
@@ -23133,10 +23622,10 @@ function parseSessionLines(lines) {
|
|
|
23133
23622
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
23134
23623
|
}
|
|
23135
23624
|
function loadAuditEntries(auditPath) {
|
|
23136
|
-
const aPath = auditPath ??
|
|
23625
|
+
const aPath = auditPath ?? import_path46.default.join(import_os40.default.homedir(), ".node9", "audit.log");
|
|
23137
23626
|
let raw;
|
|
23138
23627
|
try {
|
|
23139
|
-
raw =
|
|
23628
|
+
raw = import_fs45.default.readFileSync(aPath, "utf-8");
|
|
23140
23629
|
} catch {
|
|
23141
23630
|
return [];
|
|
23142
23631
|
}
|
|
@@ -23172,8 +23661,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
23172
23661
|
return result;
|
|
23173
23662
|
}
|
|
23174
23663
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
23175
|
-
const tmpDir =
|
|
23176
|
-
if (!
|
|
23664
|
+
const tmpDir = import_path46.default.join(import_os40.default.homedir(), ".gemini", "tmp");
|
|
23665
|
+
if (!import_fs45.default.existsSync(tmpDir)) return [];
|
|
23177
23666
|
const cutoff = days !== null ? (() => {
|
|
23178
23667
|
const d = /* @__PURE__ */ new Date();
|
|
23179
23668
|
d.setDate(d.getDate() - days);
|
|
@@ -23182,35 +23671,35 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
23182
23671
|
})() : null;
|
|
23183
23672
|
let slugDirs;
|
|
23184
23673
|
try {
|
|
23185
|
-
slugDirs =
|
|
23674
|
+
slugDirs = import_fs45.default.readdirSync(tmpDir);
|
|
23186
23675
|
} catch {
|
|
23187
23676
|
return [];
|
|
23188
23677
|
}
|
|
23189
23678
|
const summaries = [];
|
|
23190
23679
|
for (const slug of slugDirs) {
|
|
23191
|
-
const slugPath =
|
|
23680
|
+
const slugPath = import_path46.default.join(tmpDir, slug);
|
|
23192
23681
|
try {
|
|
23193
|
-
if (!
|
|
23682
|
+
if (!import_fs45.default.statSync(slugPath).isDirectory()) continue;
|
|
23194
23683
|
} catch {
|
|
23195
23684
|
continue;
|
|
23196
23685
|
}
|
|
23197
|
-
let projectRoot =
|
|
23686
|
+
let projectRoot = import_path46.default.join(import_os40.default.homedir(), slug);
|
|
23198
23687
|
try {
|
|
23199
|
-
projectRoot =
|
|
23688
|
+
projectRoot = import_fs45.default.readFileSync(import_path46.default.join(slugPath, ".project_root"), "utf-8").trim();
|
|
23200
23689
|
} catch {
|
|
23201
23690
|
}
|
|
23202
|
-
const chatsDir =
|
|
23203
|
-
if (!
|
|
23691
|
+
const chatsDir = import_path46.default.join(slugPath, "chats");
|
|
23692
|
+
if (!import_fs45.default.existsSync(chatsDir)) continue;
|
|
23204
23693
|
let chatFiles;
|
|
23205
23694
|
try {
|
|
23206
|
-
chatFiles =
|
|
23695
|
+
chatFiles = import_fs45.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
23207
23696
|
} catch {
|
|
23208
23697
|
continue;
|
|
23209
23698
|
}
|
|
23210
23699
|
for (const chatFile of chatFiles) {
|
|
23211
23700
|
let raw;
|
|
23212
23701
|
try {
|
|
23213
|
-
raw =
|
|
23702
|
+
raw = import_fs45.default.readFileSync(import_path46.default.join(chatsDir, chatFile), "utf-8");
|
|
23214
23703
|
} catch {
|
|
23215
23704
|
continue;
|
|
23216
23705
|
}
|
|
@@ -23290,8 +23779,8 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
23290
23779
|
return summaries;
|
|
23291
23780
|
}
|
|
23292
23781
|
function buildCodexSessions(days, allAuditEntries) {
|
|
23293
|
-
const sessionsBase =
|
|
23294
|
-
if (!
|
|
23782
|
+
const sessionsBase = import_path46.default.join(import_os40.default.homedir(), ".codex", "sessions");
|
|
23783
|
+
if (!import_fs45.default.existsSync(sessionsBase)) return [];
|
|
23295
23784
|
const cutoff = days !== null ? (() => {
|
|
23296
23785
|
const d = /* @__PURE__ */ new Date();
|
|
23297
23786
|
d.setDate(d.getDate() - days);
|
|
@@ -23300,29 +23789,29 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
23300
23789
|
})() : null;
|
|
23301
23790
|
const jsonlFiles = [];
|
|
23302
23791
|
try {
|
|
23303
|
-
for (const year of
|
|
23304
|
-
const yearPath =
|
|
23792
|
+
for (const year of import_fs45.default.readdirSync(sessionsBase)) {
|
|
23793
|
+
const yearPath = import_path46.default.join(sessionsBase, year);
|
|
23305
23794
|
try {
|
|
23306
|
-
if (!
|
|
23795
|
+
if (!import_fs45.default.statSync(yearPath).isDirectory()) continue;
|
|
23307
23796
|
} catch {
|
|
23308
23797
|
continue;
|
|
23309
23798
|
}
|
|
23310
|
-
for (const month of
|
|
23311
|
-
const monthPath =
|
|
23799
|
+
for (const month of import_fs45.default.readdirSync(yearPath)) {
|
|
23800
|
+
const monthPath = import_path46.default.join(yearPath, month);
|
|
23312
23801
|
try {
|
|
23313
|
-
if (!
|
|
23802
|
+
if (!import_fs45.default.statSync(monthPath).isDirectory()) continue;
|
|
23314
23803
|
} catch {
|
|
23315
23804
|
continue;
|
|
23316
23805
|
}
|
|
23317
|
-
for (const day of
|
|
23318
|
-
const dayPath =
|
|
23806
|
+
for (const day of import_fs45.default.readdirSync(monthPath)) {
|
|
23807
|
+
const dayPath = import_path46.default.join(monthPath, day);
|
|
23319
23808
|
try {
|
|
23320
|
-
if (!
|
|
23809
|
+
if (!import_fs45.default.statSync(dayPath).isDirectory()) continue;
|
|
23321
23810
|
} catch {
|
|
23322
23811
|
continue;
|
|
23323
23812
|
}
|
|
23324
|
-
for (const file of
|
|
23325
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
23813
|
+
for (const file of import_fs45.default.readdirSync(dayPath)) {
|
|
23814
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path46.default.join(dayPath, file));
|
|
23326
23815
|
}
|
|
23327
23816
|
}
|
|
23328
23817
|
}
|
|
@@ -23334,7 +23823,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
23334
23823
|
for (const filePath of jsonlFiles) {
|
|
23335
23824
|
let lines;
|
|
23336
23825
|
try {
|
|
23337
|
-
lines =
|
|
23826
|
+
lines = import_fs45.default.readFileSync(filePath, "utf-8").split("\n");
|
|
23338
23827
|
} catch {
|
|
23339
23828
|
continue;
|
|
23340
23829
|
}
|
|
@@ -23412,10 +23901,10 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
23412
23901
|
return summaries;
|
|
23413
23902
|
}
|
|
23414
23903
|
function buildSessions(days, historyPath) {
|
|
23415
|
-
const hPath = historyPath ??
|
|
23904
|
+
const hPath = historyPath ?? import_path46.default.join(import_os40.default.homedir(), ".claude", "history.jsonl");
|
|
23416
23905
|
let historyRaw;
|
|
23417
23906
|
try {
|
|
23418
|
-
historyRaw =
|
|
23907
|
+
historyRaw = import_fs45.default.readFileSync(hPath, "utf-8");
|
|
23419
23908
|
} catch {
|
|
23420
23909
|
return [];
|
|
23421
23910
|
}
|
|
@@ -23440,7 +23929,7 @@ function buildSessions(days, historyPath) {
|
|
|
23440
23929
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
23441
23930
|
let sessionLines = [];
|
|
23442
23931
|
try {
|
|
23443
|
-
sessionLines =
|
|
23932
|
+
sessionLines = import_fs45.default.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
23444
23933
|
} catch {
|
|
23445
23934
|
}
|
|
23446
23935
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -23708,8 +24197,8 @@ function registerSessionsCommand(program2) {
|
|
|
23708
24197
|
console.log("");
|
|
23709
24198
|
console.log(import_chalk24.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk24.default.dim(" \u2014 what your AI agent did"));
|
|
23710
24199
|
console.log("");
|
|
23711
|
-
const historyPath =
|
|
23712
|
-
if (!
|
|
24200
|
+
const historyPath = import_path46.default.join(import_os40.default.homedir(), ".claude", "history.jsonl");
|
|
24201
|
+
if (!import_fs45.default.existsSync(historyPath)) {
|
|
23713
24202
|
console.log(import_chalk24.default.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
|
|
23714
24203
|
console.log(import_chalk24.default.gray(" Install Claude Code, run a few sessions, then try again.\n"));
|
|
23715
24204
|
return;
|
|
@@ -23746,12 +24235,12 @@ function registerSessionsCommand(program2) {
|
|
|
23746
24235
|
|
|
23747
24236
|
// src/cli/commands/skill-pin.ts
|
|
23748
24237
|
var import_chalk25 = __toESM(require("chalk"));
|
|
23749
|
-
var
|
|
23750
|
-
var
|
|
23751
|
-
var
|
|
24238
|
+
var import_fs46 = __toESM(require("fs"));
|
|
24239
|
+
var import_os41 = __toESM(require("os"));
|
|
24240
|
+
var import_path47 = __toESM(require("path"));
|
|
23752
24241
|
function wipeSkillSessions() {
|
|
23753
24242
|
try {
|
|
23754
|
-
|
|
24243
|
+
import_fs46.default.rmSync(import_path47.default.join(import_os41.default.homedir(), ".node9", "skill-sessions"), {
|
|
23755
24244
|
recursive: true,
|
|
23756
24245
|
force: true
|
|
23757
24246
|
});
|
|
@@ -23833,15 +24322,15 @@ function registerSkillPinCommand(program2) {
|
|
|
23833
24322
|
}
|
|
23834
24323
|
|
|
23835
24324
|
// src/cli/commands/decisions.ts
|
|
23836
|
-
var
|
|
23837
|
-
var
|
|
23838
|
-
var
|
|
24325
|
+
var import_fs47 = __toESM(require("fs"));
|
|
24326
|
+
var import_os42 = __toESM(require("os"));
|
|
24327
|
+
var import_path48 = __toESM(require("path"));
|
|
23839
24328
|
var import_chalk26 = __toESM(require("chalk"));
|
|
23840
|
-
var DECISIONS_FILE2 =
|
|
24329
|
+
var DECISIONS_FILE2 = import_path48.default.join(import_os42.default.homedir(), ".node9", "decisions.json");
|
|
23841
24330
|
function readDecisions() {
|
|
23842
24331
|
try {
|
|
23843
|
-
if (!
|
|
23844
|
-
const raw =
|
|
24332
|
+
if (!import_fs47.default.existsSync(DECISIONS_FILE2)) return {};
|
|
24333
|
+
const raw = import_fs47.default.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
23845
24334
|
const parsed = JSON.parse(raw);
|
|
23846
24335
|
const out = {};
|
|
23847
24336
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -23853,11 +24342,11 @@ function readDecisions() {
|
|
|
23853
24342
|
}
|
|
23854
24343
|
}
|
|
23855
24344
|
function writeDecisions(d) {
|
|
23856
|
-
const dir =
|
|
23857
|
-
if (!
|
|
24345
|
+
const dir = import_path48.default.dirname(DECISIONS_FILE2);
|
|
24346
|
+
if (!import_fs47.default.existsSync(dir)) import_fs47.default.mkdirSync(dir, { recursive: true });
|
|
23858
24347
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
23859
|
-
|
|
23860
|
-
|
|
24348
|
+
import_fs47.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
24349
|
+
import_fs47.default.renameSync(tmp, DECISIONS_FILE2);
|
|
23861
24350
|
}
|
|
23862
24351
|
function registerDecisionsCommand(program2) {
|
|
23863
24352
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -23914,18 +24403,18 @@ Persistent decisions (${entries.length})
|
|
|
23914
24403
|
|
|
23915
24404
|
// src/cli/commands/dlp.ts
|
|
23916
24405
|
var import_chalk27 = __toESM(require("chalk"));
|
|
23917
|
-
var
|
|
23918
|
-
var
|
|
23919
|
-
var
|
|
23920
|
-
var AUDIT_LOG =
|
|
23921
|
-
var RESOLVED_FILE =
|
|
24406
|
+
var import_fs48 = __toESM(require("fs"));
|
|
24407
|
+
var import_path49 = __toESM(require("path"));
|
|
24408
|
+
var import_os43 = __toESM(require("os"));
|
|
24409
|
+
var AUDIT_LOG = import_path49.default.join(import_os43.default.homedir(), ".node9", "audit.log");
|
|
24410
|
+
var RESOLVED_FILE = import_path49.default.join(import_os43.default.homedir(), ".node9", "dlp-resolved.json");
|
|
23922
24411
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
23923
24412
|
function stripAnsi(s) {
|
|
23924
24413
|
return s.replace(ANSI_RE, "");
|
|
23925
24414
|
}
|
|
23926
24415
|
function loadResolved() {
|
|
23927
24416
|
try {
|
|
23928
|
-
const raw = JSON.parse(
|
|
24417
|
+
const raw = JSON.parse(import_fs48.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
23929
24418
|
return new Set(raw);
|
|
23930
24419
|
} catch {
|
|
23931
24420
|
return /* @__PURE__ */ new Set();
|
|
@@ -23933,13 +24422,13 @@ function loadResolved() {
|
|
|
23933
24422
|
}
|
|
23934
24423
|
function saveResolved(resolved) {
|
|
23935
24424
|
try {
|
|
23936
|
-
|
|
24425
|
+
import_fs48.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
23937
24426
|
} catch {
|
|
23938
24427
|
}
|
|
23939
24428
|
}
|
|
23940
24429
|
function loadDlpFindings() {
|
|
23941
|
-
if (!
|
|
23942
|
-
return
|
|
24430
|
+
if (!import_fs48.default.existsSync(AUDIT_LOG)) return [];
|
|
24431
|
+
return import_fs48.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
23943
24432
|
if (!line.trim()) return [];
|
|
23944
24433
|
try {
|
|
23945
24434
|
const e = JSON.parse(line);
|
|
@@ -24037,15 +24526,15 @@ function registerDlpCommand(program2) {
|
|
|
24037
24526
|
|
|
24038
24527
|
// src/cli/commands/mask.ts
|
|
24039
24528
|
var import_chalk28 = __toESM(require("chalk"));
|
|
24040
|
-
var
|
|
24041
|
-
var
|
|
24042
|
-
var
|
|
24529
|
+
var import_fs49 = __toESM(require("fs"));
|
|
24530
|
+
var import_path50 = __toESM(require("path"));
|
|
24531
|
+
var import_os44 = __toESM(require("os"));
|
|
24043
24532
|
init_dlp();
|
|
24044
24533
|
function findJsonlFiles(dir) {
|
|
24045
24534
|
const results = [];
|
|
24046
|
-
if (!
|
|
24047
|
-
for (const entry of
|
|
24048
|
-
const full =
|
|
24535
|
+
if (!import_fs49.default.existsSync(dir)) return results;
|
|
24536
|
+
for (const entry of import_fs49.default.readdirSync(dir, { withFileTypes: true })) {
|
|
24537
|
+
const full = import_path50.default.join(dir, entry.name);
|
|
24049
24538
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
24050
24539
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
24051
24540
|
}
|
|
@@ -24088,7 +24577,7 @@ function redactJson(obj) {
|
|
|
24088
24577
|
function processFile(filePath, dryRun) {
|
|
24089
24578
|
let raw;
|
|
24090
24579
|
try {
|
|
24091
|
-
raw =
|
|
24580
|
+
raw = import_fs49.default.readFileSync(filePath, "utf-8");
|
|
24092
24581
|
} catch {
|
|
24093
24582
|
return { redactedLines: 0, patterns: [] };
|
|
24094
24583
|
}
|
|
@@ -24120,14 +24609,14 @@ function processFile(filePath, dryRun) {
|
|
|
24120
24609
|
}
|
|
24121
24610
|
}
|
|
24122
24611
|
if (!dryRun && redactedLines > 0) {
|
|
24123
|
-
|
|
24612
|
+
import_fs49.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
24124
24613
|
}
|
|
24125
24614
|
return { redactedLines, patterns };
|
|
24126
24615
|
}
|
|
24127
24616
|
function processJsonFile(filePath, dryRun) {
|
|
24128
24617
|
let raw;
|
|
24129
24618
|
try {
|
|
24130
|
-
raw =
|
|
24619
|
+
raw = import_fs49.default.readFileSync(filePath, "utf-8");
|
|
24131
24620
|
} catch {
|
|
24132
24621
|
return { redactedLines: 0, patterns: [] };
|
|
24133
24622
|
}
|
|
@@ -24140,15 +24629,15 @@ function processJsonFile(filePath, dryRun) {
|
|
|
24140
24629
|
const { value, modified, found } = redactJson(parsed);
|
|
24141
24630
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
24142
24631
|
if (!dryRun) {
|
|
24143
|
-
|
|
24632
|
+
import_fs49.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
24144
24633
|
}
|
|
24145
24634
|
return { redactedLines: 1, patterns: found };
|
|
24146
24635
|
}
|
|
24147
24636
|
function findJsonFiles(dir) {
|
|
24148
24637
|
const results = [];
|
|
24149
|
-
if (!
|
|
24150
|
-
for (const entry of
|
|
24151
|
-
const full =
|
|
24638
|
+
if (!import_fs49.default.existsSync(dir)) return results;
|
|
24639
|
+
for (const entry of import_fs49.default.readdirSync(dir, { withFileTypes: true })) {
|
|
24640
|
+
const full = import_path50.default.join(dir, entry.name);
|
|
24152
24641
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
24153
24642
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
24154
24643
|
}
|
|
@@ -24157,9 +24646,9 @@ function findJsonFiles(dir) {
|
|
|
24157
24646
|
function registerMaskCommand(program2) {
|
|
24158
24647
|
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) => {
|
|
24159
24648
|
const dryRun = !!options.dryRun;
|
|
24160
|
-
const home =
|
|
24161
|
-
const claudeDir =
|
|
24162
|
-
const geminiDir =
|
|
24649
|
+
const home = import_os44.default.homedir();
|
|
24650
|
+
const claudeDir = import_path50.default.join(home, ".claude", "projects");
|
|
24651
|
+
const geminiDir = import_path50.default.join(home, ".gemini", "tmp");
|
|
24163
24652
|
const allFiles = [
|
|
24164
24653
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
24165
24654
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -24167,7 +24656,7 @@ function registerMaskCommand(program2) {
|
|
|
24167
24656
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
24168
24657
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
24169
24658
|
try {
|
|
24170
|
-
return
|
|
24659
|
+
return import_fs49.default.statSync(f.path).mtime >= cutoff;
|
|
24171
24660
|
} catch {
|
|
24172
24661
|
return false;
|
|
24173
24662
|
}
|
|
@@ -24223,20 +24712,20 @@ function registerMaskCommand(program2) {
|
|
|
24223
24712
|
// src/cli.ts
|
|
24224
24713
|
init_blast();
|
|
24225
24714
|
var { version } = JSON.parse(
|
|
24226
|
-
|
|
24715
|
+
import_fs52.default.readFileSync(import_path53.default.join(__dirname, "../package.json"), "utf-8")
|
|
24227
24716
|
);
|
|
24228
24717
|
var program = new import_commander.Command();
|
|
24229
24718
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
24230
24719
|
program.command("login").argument("<apiKey>").option("--local", "Save key for audit/logging only \u2014 local config still controls all decisions").option("--profile <name>", 'Save as a named profile (default: "default")').action((apiKey, options) => {
|
|
24231
24720
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
24232
|
-
const credPath =
|
|
24233
|
-
if (!
|
|
24234
|
-
|
|
24721
|
+
const credPath = import_path53.default.join(import_os47.default.homedir(), ".node9", "credentials.json");
|
|
24722
|
+
if (!import_fs52.default.existsSync(import_path53.default.dirname(credPath)))
|
|
24723
|
+
import_fs52.default.mkdirSync(import_path53.default.dirname(credPath), { recursive: true });
|
|
24235
24724
|
const profileName = options.profile || "default";
|
|
24236
24725
|
let existingCreds = {};
|
|
24237
24726
|
try {
|
|
24238
|
-
if (
|
|
24239
|
-
const raw = JSON.parse(
|
|
24727
|
+
if (import_fs52.default.existsSync(credPath)) {
|
|
24728
|
+
const raw = JSON.parse(import_fs52.default.readFileSync(credPath, "utf-8"));
|
|
24240
24729
|
if (raw.apiKey) {
|
|
24241
24730
|
existingCreds = {
|
|
24242
24731
|
default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
|
|
@@ -24248,14 +24737,14 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
24248
24737
|
} catch {
|
|
24249
24738
|
}
|
|
24250
24739
|
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
24251
|
-
|
|
24740
|
+
import_fs52.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
24252
24741
|
let effectiveCloud = null;
|
|
24253
24742
|
if (profileName === "default") {
|
|
24254
|
-
const configPath =
|
|
24743
|
+
const configPath = import_path53.default.join(import_os47.default.homedir(), ".node9", "config.json");
|
|
24255
24744
|
let config = {};
|
|
24256
24745
|
try {
|
|
24257
|
-
if (
|
|
24258
|
-
config = JSON.parse(
|
|
24746
|
+
if (import_fs52.default.existsSync(configPath))
|
|
24747
|
+
config = JSON.parse(import_fs52.default.readFileSync(configPath, "utf-8"));
|
|
24259
24748
|
} catch {
|
|
24260
24749
|
}
|
|
24261
24750
|
if (!config.settings || typeof config.settings !== "object") config.settings = {};
|
|
@@ -24270,9 +24759,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
24270
24759
|
approvers.cloud = false;
|
|
24271
24760
|
}
|
|
24272
24761
|
s.approvers = approvers;
|
|
24273
|
-
if (!
|
|
24274
|
-
|
|
24275
|
-
|
|
24762
|
+
if (!import_fs52.default.existsSync(import_path53.default.dirname(configPath)))
|
|
24763
|
+
import_fs52.default.mkdirSync(import_path53.default.dirname(configPath), { recursive: true });
|
|
24764
|
+
import_fs52.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
24276
24765
|
effectiveCloud = approvers.cloud === true;
|
|
24277
24766
|
}
|
|
24278
24767
|
if (options.profile && profileName !== "default") {
|
|
@@ -24431,15 +24920,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
24431
24920
|
}
|
|
24432
24921
|
}
|
|
24433
24922
|
if (options.purge) {
|
|
24434
|
-
const node9Dir =
|
|
24435
|
-
if (
|
|
24923
|
+
const node9Dir = import_path53.default.join(import_os47.default.homedir(), ".node9");
|
|
24924
|
+
if (import_fs52.default.existsSync(node9Dir)) {
|
|
24436
24925
|
const confirmed = await (0, import_prompts2.confirm)({
|
|
24437
24926
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
24438
24927
|
default: false
|
|
24439
24928
|
});
|
|
24440
24929
|
if (confirmed) {
|
|
24441
|
-
|
|
24442
|
-
if (
|
|
24930
|
+
import_fs52.default.rmSync(node9Dir, { recursive: true });
|
|
24931
|
+
if (import_fs52.default.existsSync(node9Dir)) {
|
|
24443
24932
|
console.error(
|
|
24444
24933
|
import_chalk30.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
24445
24934
|
);
|
|
@@ -24554,7 +25043,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
24554
25043
|
});
|
|
24555
25044
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
24556
25045
|
try {
|
|
24557
|
-
const dashboardPath =
|
|
25046
|
+
const dashboardPath = import_path53.default.join(__dirname, "dashboard.mjs");
|
|
24558
25047
|
const dynamicImport = new Function("id", "return import(id)");
|
|
24559
25048
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
24560
25049
|
await mod.startMonitor();
|
|
@@ -24592,14 +25081,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
24592
25081
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
24593
25082
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
24594
25083
|
if (subcommand === "debug") {
|
|
24595
|
-
const flagFile =
|
|
25084
|
+
const flagFile = import_path53.default.join(import_os47.default.homedir(), ".node9", "hud-debug");
|
|
24596
25085
|
if (state === "on") {
|
|
24597
|
-
|
|
24598
|
-
|
|
25086
|
+
import_fs52.default.mkdirSync(import_path53.default.dirname(flagFile), { recursive: true });
|
|
25087
|
+
import_fs52.default.writeFileSync(flagFile, "");
|
|
24599
25088
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
24600
25089
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
24601
25090
|
} else if (state === "off") {
|
|
24602
|
-
if (
|
|
25091
|
+
if (import_fs52.default.existsSync(flagFile)) import_fs52.default.unlinkSync(flagFile);
|
|
24603
25092
|
console.log("HUD debug logging disabled.");
|
|
24604
25093
|
} else {
|
|
24605
25094
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -24716,9 +25205,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
24716
25205
|
const isCheckHook = process.argv[2] === "check";
|
|
24717
25206
|
if (isCheckHook) {
|
|
24718
25207
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
24719
|
-
const logPath =
|
|
25208
|
+
const logPath = import_path53.default.join(import_os47.default.homedir(), ".node9", "hook-debug.log");
|
|
24720
25209
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
24721
|
-
|
|
25210
|
+
import_fs52.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
24722
25211
|
`);
|
|
24723
25212
|
}
|
|
24724
25213
|
process.exit(0);
|