@node9/proxy 1.29.0 → 1.30.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 +845 -650
- package/dist/cli.mjs +817 -623
- package/dist/dashboard.mjs +9 -2
- package/dist/index.js +64 -149
- package/dist/index.mjs +61 -146
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -74,8 +74,13 @@ __export(audit_exports, {
|
|
|
74
74
|
appendHookDebug: () => appendHookDebug,
|
|
75
75
|
appendLocalAudit: () => appendLocalAudit,
|
|
76
76
|
appendToLog: () => appendToLog,
|
|
77
|
+
buildArgsPreview: () => buildArgsPreview,
|
|
78
|
+
generateEventId: () => generateEventId,
|
|
77
79
|
redactSecrets: () => redactSecrets
|
|
78
80
|
});
|
|
81
|
+
function generateEventId() {
|
|
82
|
+
return `${Date.now().toString(36)}-${import_crypto2.default.randomBytes(6).toString("hex")}`;
|
|
83
|
+
}
|
|
79
84
|
function isTestCall(toolName, args) {
|
|
80
85
|
if (toolName !== "Bash" && toolName !== "bash") return false;
|
|
81
86
|
const cmd = args?.command;
|
|
@@ -94,6 +99,17 @@ function redactSecrets(text) {
|
|
|
94
99
|
);
|
|
95
100
|
return redacted;
|
|
96
101
|
}
|
|
102
|
+
function buildArgsPreview(args) {
|
|
103
|
+
try {
|
|
104
|
+
const o = args && typeof args === "object" ? args : null;
|
|
105
|
+
const primary = o && (o.command ?? o.file_path ?? o.path ?? o.url ?? o.query);
|
|
106
|
+
const text = typeof primary === "string" ? primary : args ? JSON.stringify(args) : "";
|
|
107
|
+
if (!text) return void 0;
|
|
108
|
+
return redactSecrets(text).slice(0, 120);
|
|
109
|
+
} catch {
|
|
110
|
+
return void 0;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
97
113
|
function appendToLog(logPath, entry) {
|
|
98
114
|
try {
|
|
99
115
|
const dir = import_path.default.dirname(logPath);
|
|
@@ -116,11 +132,18 @@ function appendHookDebug(toolName, args, meta, auditHashArgsEnabled) {
|
|
|
116
132
|
});
|
|
117
133
|
}
|
|
118
134
|
function appendLocalAudit(toolName, args, decision, checkedBy, meta, auditHashArgsEnabled) {
|
|
119
|
-
const
|
|
135
|
+
const isDlpRow = checkedBy.toLowerCase().includes("dlp") || Boolean(meta?.dlpPattern);
|
|
136
|
+
const preview2 = auditHashArgsEnabled && !isDlpRow ? buildArgsPreview(args) : void 0;
|
|
137
|
+
const argsField = auditHashArgsEnabled ? { argsHash: hashArgs(args), ...preview2 ? { argsPreview: preview2 } : {} } : { args: args ? JSON.parse(redactSecrets(JSON.stringify(args))) : {} };
|
|
120
138
|
const testRun = isTestCall(toolName, args) || process.env.NODE9_TESTING === "1" ? { testRun: true } : {};
|
|
121
139
|
const ruleNameField = meta?.ruleName ? { ruleName: meta.ruleName } : {};
|
|
122
140
|
const agentToolNameField = meta?.agentToolName ? { agentToolName: meta.agentToolName } : {};
|
|
141
|
+
const dlpFields = meta?.dlpPattern ? { dlpPattern: meta.dlpPattern, dlpSample: meta.dlpSample } : {};
|
|
142
|
+
const cloudLinkField = meta?.cloudRequestId ? { cloudRequestId: meta.cloudRequestId } : {};
|
|
123
143
|
appendToLog(LOCAL_AUDIT_LOG, {
|
|
144
|
+
// eid first: the outbox shipper dedups on it, and a fixed leading field
|
|
145
|
+
// makes the JSONL easy to eyeball.
|
|
146
|
+
eid: generateEventId(),
|
|
124
147
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
125
148
|
tool: toolName,
|
|
126
149
|
...agentToolNameField,
|
|
@@ -128,6 +151,8 @@ function appendLocalAudit(toolName, args, decision, checkedBy, meta, auditHashAr
|
|
|
128
151
|
decision,
|
|
129
152
|
checkedBy,
|
|
130
153
|
...ruleNameField,
|
|
154
|
+
...dlpFields,
|
|
155
|
+
...cloudLinkField,
|
|
131
156
|
...testRun,
|
|
132
157
|
agent: meta?.agent,
|
|
133
158
|
mcpServer: meta?.mcpServer,
|
|
@@ -142,13 +167,14 @@ function appendConfigAudit(entry) {
|
|
|
142
167
|
hostname: import_os.default.hostname()
|
|
143
168
|
});
|
|
144
169
|
}
|
|
145
|
-
var import_fs, import_path, import_os, LOCAL_AUDIT_LOG, HOOK_DEBUG_LOG, TEST_COMMAND_RE;
|
|
170
|
+
var import_fs, import_path, import_os, import_crypto2, LOCAL_AUDIT_LOG, HOOK_DEBUG_LOG, TEST_COMMAND_RE;
|
|
146
171
|
var init_audit = __esm({
|
|
147
172
|
"src/audit/index.ts"() {
|
|
148
173
|
"use strict";
|
|
149
174
|
import_fs = __toESM(require("fs"));
|
|
150
175
|
import_path = __toESM(require("path"));
|
|
151
176
|
import_os = __toESM(require("os"));
|
|
177
|
+
import_crypto2 = __toESM(require("crypto"));
|
|
152
178
|
init_hasher();
|
|
153
179
|
LOCAL_AUDIT_LOG = import_path.default.join(import_os.default.homedir(), ".node9", "audit.log");
|
|
154
180
|
HOOK_DEBUG_LOG = import_path.default.join(import_os.default.homedir(), ".node9", "hook-debug.log");
|
|
@@ -174,8 +200,8 @@ function sanitizeConfig(raw) {
|
|
|
174
200
|
}
|
|
175
201
|
}
|
|
176
202
|
const lines = result.error.issues.map((issue) => {
|
|
177
|
-
const
|
|
178
|
-
return ` \u2022 ${
|
|
203
|
+
const path51 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
204
|
+
return ` \u2022 ${path51}: ${issue.message}`;
|
|
179
205
|
});
|
|
180
206
|
return {
|
|
181
207
|
sanitized,
|
|
@@ -261,7 +287,13 @@ var init_config_schema = __esm({
|
|
|
261
287
|
allowGlobalPause: import_zod.z.boolean().optional(),
|
|
262
288
|
auditHashArgs: import_zod.z.boolean().optional(),
|
|
263
289
|
agentPolicy: import_zod.z.enum(["require_approval", "block_on_rules"]).optional(),
|
|
264
|
-
cloudSyncIntervalHours: import_zod.z.number().positive().optional()
|
|
290
|
+
cloudSyncIntervalHours: import_zod.z.number().positive().optional(),
|
|
291
|
+
// Outbox shipper (audit.log → SaaS batch ingest). enabled defaults
|
|
292
|
+
// to true; set false to fall back to local-only auditing.
|
|
293
|
+
shipper: import_zod.z.object({
|
|
294
|
+
enabled: import_zod.z.boolean().optional(),
|
|
295
|
+
intervalSeconds: import_zod.z.number().min(5).optional()
|
|
296
|
+
}).optional()
|
|
265
297
|
}).optional(),
|
|
266
298
|
policy: import_zod.z.object({
|
|
267
299
|
sandboxPaths: import_zod.z.array(import_zod.z.string()).optional(),
|
|
@@ -1007,9 +1039,9 @@ function matchesPattern(text, patterns) {
|
|
|
1007
1039
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
1008
1040
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
1009
1041
|
}
|
|
1010
|
-
function getNestedValue(obj,
|
|
1042
|
+
function getNestedValue(obj, path51) {
|
|
1011
1043
|
if (!obj || typeof obj !== "object") return null;
|
|
1012
|
-
const segments =
|
|
1044
|
+
const segments = path51.split(".");
|
|
1013
1045
|
for (const seg of segments) {
|
|
1014
1046
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
1015
1047
|
}
|
|
@@ -1371,7 +1403,7 @@ function assertBuiltinShieldRegexesAreSafe() {
|
|
|
1371
1403
|
}
|
|
1372
1404
|
function computeArgsHash(args) {
|
|
1373
1405
|
const str = JSON.stringify(args ?? "");
|
|
1374
|
-
return
|
|
1406
|
+
return import_crypto3.default.createHash("sha256").update(str).digest("hex").slice(0, 16);
|
|
1375
1407
|
}
|
|
1376
1408
|
function evaluateLoopWindow(records, tool, args, threshold, windowMs, now) {
|
|
1377
1409
|
const hash = computeArgsHash(args);
|
|
@@ -1853,7 +1885,7 @@ function* stringValues(obj, depth = 0) {
|
|
|
1853
1885
|
}
|
|
1854
1886
|
for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
|
|
1855
1887
|
}
|
|
1856
|
-
var import_safe_regex2, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23,
|
|
1888
|
+
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, FS_OP_CACHE_MAX, fsOpCache, 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, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE;
|
|
1857
1889
|
var init_dist = __esm({
|
|
1858
1890
|
"packages/policy-engine/dist/index.mjs"() {
|
|
1859
1891
|
"use strict";
|
|
@@ -1862,7 +1894,7 @@ var init_dist = __esm({
|
|
|
1862
1894
|
import_picomatch = __toESM(require("picomatch"), 1);
|
|
1863
1895
|
import_safe_regex22 = __toESM(require("safe-regex2"), 1);
|
|
1864
1896
|
import_safe_regex23 = __toESM(require("safe-regex2"), 1);
|
|
1865
|
-
|
|
1897
|
+
import_crypto3 = __toESM(require("crypto"), 1);
|
|
1866
1898
|
ASSIGNMENT_CONTEXT_RE = /\b(?:password|passwd|secret|token|api[_-]?key|auth(?:_key|_token)?|credential|private[_-]?key|access[_-]?key|client[_-]?secret)\s*[=:]\s*/i;
|
|
1867
1899
|
DLP_STOPWORDS = [
|
|
1868
1900
|
"example",
|
|
@@ -3487,7 +3519,7 @@ function readShieldsFile() {
|
|
|
3487
3519
|
}
|
|
3488
3520
|
function writeShieldsFile(data) {
|
|
3489
3521
|
import_fs2.default.mkdirSync(import_path2.default.dirname(SHIELDS_STATE_FILE), { recursive: true });
|
|
3490
|
-
const tmp = `${SHIELDS_STATE_FILE}.${
|
|
3522
|
+
const tmp = `${SHIELDS_STATE_FILE}.${import_crypto4.default.randomBytes(6).toString("hex")}.tmp`;
|
|
3491
3523
|
const toWrite = { active: data.active };
|
|
3492
3524
|
if (data.overrides && Object.keys(data.overrides).length > 0) toWrite.overrides = data.overrides;
|
|
3493
3525
|
import_fs2.default.writeFileSync(tmp, JSON.stringify(toWrite, null, 2), { mode: 384 });
|
|
@@ -3577,18 +3609,18 @@ function installShield(name, shieldJson) {
|
|
|
3577
3609
|
}
|
|
3578
3610
|
import_fs2.default.mkdirSync(USER_SHIELDS_DIR, { recursive: true });
|
|
3579
3611
|
const filePath = import_path2.default.join(USER_SHIELDS_DIR, `${name}.json`);
|
|
3580
|
-
const tmp = `${filePath}.${
|
|
3612
|
+
const tmp = `${filePath}.${import_crypto4.default.randomBytes(6).toString("hex")}.tmp`;
|
|
3581
3613
|
import_fs2.default.writeFileSync(tmp, JSON.stringify(shieldJson, null, 2), { mode: 384 });
|
|
3582
3614
|
import_fs2.default.renameSync(tmp, filePath);
|
|
3583
3615
|
}
|
|
3584
|
-
var import_fs2, import_path2, import_os2,
|
|
3616
|
+
var import_fs2, import_path2, import_os2, import_crypto4, USER_SHIELDS_DIR, SHIELDS, SHIELDS_STATE_FILE, RULE_KEY_MIGRATIONS;
|
|
3585
3617
|
var init_shields = __esm({
|
|
3586
3618
|
"src/shields.ts"() {
|
|
3587
3619
|
"use strict";
|
|
3588
3620
|
import_fs2 = __toESM(require("fs"));
|
|
3589
3621
|
import_path2 = __toESM(require("path"));
|
|
3590
3622
|
import_os2 = __toESM(require("os"));
|
|
3591
|
-
|
|
3623
|
+
import_crypto4 = __toESM(require("crypto"));
|
|
3592
3624
|
init_dist();
|
|
3593
3625
|
init_dist();
|
|
3594
3626
|
USER_SHIELDS_DIR = import_path2.default.join(import_os2.default.homedir(), ".node9", "shields");
|
|
@@ -3676,7 +3708,8 @@ function getConfig(cwd) {
|
|
|
3676
3708
|
const projectConfig = tryLoadConfig(projectPath);
|
|
3677
3709
|
const mergedSettings = {
|
|
3678
3710
|
...DEFAULT_CONFIG.settings,
|
|
3679
|
-
approvers: { ...DEFAULT_CONFIG.settings.approvers }
|
|
3711
|
+
approvers: { ...DEFAULT_CONFIG.settings.approvers },
|
|
3712
|
+
shipper: { ...DEFAULT_CONFIG.settings.shipper }
|
|
3680
3713
|
};
|
|
3681
3714
|
const mergedPolicy = {
|
|
3682
3715
|
sandboxPaths: [...DEFAULT_CONFIG.policy.sandboxPaths],
|
|
@@ -3707,6 +3740,7 @@ function getConfig(cwd) {
|
|
|
3707
3740
|
if (s.enableHookLogDebug !== void 0)
|
|
3708
3741
|
mergedSettings.enableHookLogDebug = s.enableHookLogDebug;
|
|
3709
3742
|
if (s.approvers) mergedSettings.approvers = { ...mergedSettings.approvers, ...s.approvers };
|
|
3743
|
+
if (s.shipper) mergedSettings.shipper = { ...mergedSettings.shipper, ...s.shipper };
|
|
3710
3744
|
if (s.approvalTimeoutMs !== void 0) mergedSettings.approvalTimeoutMs = s.approvalTimeoutMs;
|
|
3711
3745
|
if (s.approvalTimeoutSeconds !== void 0 && s.approvalTimeoutMs === void 0)
|
|
3712
3746
|
mergedSettings.approvalTimeoutMs = s.approvalTimeoutSeconds * 1e3;
|
|
@@ -3907,7 +3941,8 @@ var init_config = __esm({
|
|
|
3907
3941
|
flightRecorder: true,
|
|
3908
3942
|
auditHashArgs: true,
|
|
3909
3943
|
approvers: { native: true, browser: false, cloud: false, terminal: true },
|
|
3910
|
-
cloudSyncIntervalHours: 5
|
|
3944
|
+
cloudSyncIntervalHours: 5,
|
|
3945
|
+
shipper: { enabled: true, intervalSeconds: 20 }
|
|
3911
3946
|
},
|
|
3912
3947
|
policy: {
|
|
3913
3948
|
sandboxPaths: ["/tmp/**", "**/sandbox/**", "**/test-results/**"],
|
|
@@ -5450,55 +5485,6 @@ function validateApiUrl(raw) {
|
|
|
5450
5485
|
}
|
|
5451
5486
|
return null;
|
|
5452
5487
|
}
|
|
5453
|
-
function auditLocalAllow(toolName, args, checkedBy, creds, meta, dlpInfo, containsSensitiveArgs = false, riskMetadata) {
|
|
5454
|
-
const validated = validateApiUrl(creds.apiUrl);
|
|
5455
|
-
if (!validated) {
|
|
5456
|
-
try {
|
|
5457
|
-
import_fs10.default.appendFileSync(
|
|
5458
|
-
HOOK_DEBUG_LOG,
|
|
5459
|
-
`[audit] refused to send: invalid apiUrl scheme/host (got "${String(creds.apiUrl).slice(0, 200)}")
|
|
5460
|
-
`
|
|
5461
|
-
);
|
|
5462
|
-
} catch {
|
|
5463
|
-
}
|
|
5464
|
-
return Promise.resolve();
|
|
5465
|
-
}
|
|
5466
|
-
const safeArgs = containsSensitiveArgs ? { tool: toolName, redacted: true } : args;
|
|
5467
|
-
const dlpSample = dlpInfo && typeof dlpInfo.redactedSample === "string" ? dlpInfo.redactedSample.slice(0, DLP_SAMPLE_MAX_LEN) : void 0;
|
|
5468
|
-
const dlpPattern = dlpInfo && typeof dlpInfo.pattern === "string" ? dlpInfo.pattern.slice(0, DLP_PATTERN_MAX_LEN) : void 0;
|
|
5469
|
-
const safeCheckedBy = KNOWN_CHECKED_BY.has(checkedBy) ? checkedBy : "unknown";
|
|
5470
|
-
const cleanedRiskMetadata = riskMetadata ? Object.fromEntries(
|
|
5471
|
-
Object.entries(riskMetadata).filter(([, v]) => typeof v === "string" && v.length > 0)
|
|
5472
|
-
) : void 0;
|
|
5473
|
-
const hasRiskMetadata = cleanedRiskMetadata && Object.keys(cleanedRiskMetadata).length > 0;
|
|
5474
|
-
return fetch(`${validated.toString().replace(/\/$/, "")}/audit`, {
|
|
5475
|
-
method: "POST",
|
|
5476
|
-
headers: { "Content-Type": "application/json", Authorization: `Bearer ${creds.apiKey}` },
|
|
5477
|
-
body: JSON.stringify({
|
|
5478
|
-
toolName,
|
|
5479
|
-
args: safeArgs,
|
|
5480
|
-
checkedBy: safeCheckedBy,
|
|
5481
|
-
...dlpInfo && { dlpPattern, dlpSample },
|
|
5482
|
-
...hasRiskMetadata && { riskMetadata: cleanedRiskMetadata },
|
|
5483
|
-
// session_id (Claude Code + Gemini CLI) groups all audit rows from one
|
|
5484
|
-
// agent run; transcript_path is the authoritative pointer to the
|
|
5485
|
-
// session log (survives Gemini resume drift). Both optional —
|
|
5486
|
-
// unsupported agents (MCP-mediated) leave them undefined.
|
|
5487
|
-
...meta?.sessionId && { runId: meta.sessionId },
|
|
5488
|
-
...meta?.transcriptPath && { transcriptPath: meta.transcriptPath },
|
|
5489
|
-
context: {
|
|
5490
|
-
agent: meta?.agent,
|
|
5491
|
-
mcpServer: meta?.mcpServer,
|
|
5492
|
-
hostname: import_os9.default.hostname(),
|
|
5493
|
-
cwd: process.cwd(),
|
|
5494
|
-
platform: import_os9.default.platform()
|
|
5495
|
-
}
|
|
5496
|
-
}),
|
|
5497
|
-
signal: AbortSignal.timeout(5e3)
|
|
5498
|
-
}).then(() => {
|
|
5499
|
-
}).catch(() => {
|
|
5500
|
-
});
|
|
5501
|
-
}
|
|
5502
5488
|
async function initNode9SaaS(toolName, args, creds, meta, riskMetadata, agentPolicy, forceReview) {
|
|
5503
5489
|
const controller = new AbortController();
|
|
5504
5490
|
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
@@ -5622,7 +5608,7 @@ async function resolveNode9SaaS(requestId, creds, approved, decidedBy) {
|
|
|
5622
5608
|
);
|
|
5623
5609
|
}
|
|
5624
5610
|
}
|
|
5625
|
-
var import_fs10, import_os9, import_path12
|
|
5611
|
+
var import_fs10, import_os9, import_path12;
|
|
5626
5612
|
var init_cloud = __esm({
|
|
5627
5613
|
"src/auth/cloud.ts"() {
|
|
5628
5614
|
"use strict";
|
|
@@ -5630,27 +5616,6 @@ var init_cloud = __esm({
|
|
|
5630
5616
|
import_os9 = __toESM(require("os"));
|
|
5631
5617
|
import_path12 = __toESM(require("path"));
|
|
5632
5618
|
init_audit();
|
|
5633
|
-
DLP_SAMPLE_MAX_LEN = 200;
|
|
5634
|
-
DLP_PATTERN_MAX_LEN = 100;
|
|
5635
|
-
KNOWN_CHECKED_BY = /* @__PURE__ */ new Set([
|
|
5636
|
-
"dlp-block",
|
|
5637
|
-
"observe-mode-dlp-would-block",
|
|
5638
|
-
"dlp-review-flagged",
|
|
5639
|
-
"loop-detected",
|
|
5640
|
-
"audit-mode",
|
|
5641
|
-
"local-policy",
|
|
5642
|
-
"smart-rule-block",
|
|
5643
|
-
// Smart-rule block was downgraded to review because the daemon was
|
|
5644
|
-
// running and we're not in CI. The block attempt is still recorded;
|
|
5645
|
-
// the user got a popup. Distinct from 'smart-rule-block' so the
|
|
5646
|
-
// dashboard can show "block rule overridden" separately from a hard
|
|
5647
|
-
// block that fired with no human in the loop.
|
|
5648
|
-
"smart-rule-block-override",
|
|
5649
|
-
"persistent",
|
|
5650
|
-
"trust",
|
|
5651
|
-
"observe-mode",
|
|
5652
|
-
"observe-mode-would-block"
|
|
5653
|
-
]);
|
|
5654
5619
|
}
|
|
5655
5620
|
});
|
|
5656
5621
|
|
|
@@ -5737,7 +5702,7 @@ function notifyActivity(data) {
|
|
|
5737
5702
|
}
|
|
5738
5703
|
async function authorizeHeadless(toolName, args, meta, options) {
|
|
5739
5704
|
if (!options?.calledFromDaemon) {
|
|
5740
|
-
const actId = (0,
|
|
5705
|
+
const actId = (0, import_crypto5.randomUUID)();
|
|
5741
5706
|
const actTs = Date.now();
|
|
5742
5707
|
const stripAnsi2 = (s) => s.replace(/\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g, "");
|
|
5743
5708
|
const sanitizedAgent = meta?.agent ? stripAnsi2(meta.agent).slice(0, 80) : void 0;
|
|
@@ -5832,17 +5797,11 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
5832
5797
|
args,
|
|
5833
5798
|
"deny",
|
|
5834
5799
|
isObserveMode ? "observe-mode-dlp-would-block" : "dlp-block",
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
toolName,
|
|
5841
|
-
args,
|
|
5842
|
-
isObserveMode ? "observe-mode-dlp-would-block" : "dlp-block",
|
|
5843
|
-
creds,
|
|
5844
|
-
meta,
|
|
5845
|
-
{ pattern: dlpMatch.patternName, redactedSample: dlpMatch.redactedSample },
|
|
5800
|
+
{
|
|
5801
|
+
...meta,
|
|
5802
|
+
dlpPattern: dlpMatch.patternName,
|
|
5803
|
+
dlpSample: dlpMatch.redactedSample
|
|
5804
|
+
},
|
|
5846
5805
|
true
|
|
5847
5806
|
);
|
|
5848
5807
|
if (isWriteTool(toolName) && filePath) {
|
|
@@ -5898,9 +5857,6 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
5898
5857
|
const policyResult = await evaluatePolicy2(toolName, args, meta?.agent, options?.cwd);
|
|
5899
5858
|
if (policyResult.decision === "review") {
|
|
5900
5859
|
appendLocalAudit(toolName, args, "allow", "audit-mode", meta, hashAuditArgs);
|
|
5901
|
-
if (approvers.cloud && creds?.apiKey) {
|
|
5902
|
-
await auditLocalAllow(toolName, args, "audit-mode", creds, meta);
|
|
5903
|
-
}
|
|
5904
5860
|
}
|
|
5905
5861
|
}
|
|
5906
5862
|
return { approved: true, checkedBy: "audit" };
|
|
@@ -5913,8 +5869,6 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
5913
5869
|
const reason = `It looks like you've called "${toolName}" ${loopResult.count} times with identical arguments in the last ${ld.windowSeconds}s. Are you stuck? Step back and reconsider your approach \u2014 what are you actually trying to accomplish, and is there a different way to get there?`;
|
|
5914
5870
|
if (!isManual)
|
|
5915
5871
|
appendLocalAudit(toolName, args, "deny", "loop-detected", meta, hashAuditArgs);
|
|
5916
|
-
if (approvers.cloud && creds?.apiKey)
|
|
5917
|
-
auditLocalAllow(toolName, args, "loop-detected", creds, meta, void 0, true);
|
|
5918
5872
|
return {
|
|
5919
5873
|
approved: false,
|
|
5920
5874
|
reason,
|
|
@@ -5933,15 +5887,15 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
5933
5887
|
};
|
|
5934
5888
|
}
|
|
5935
5889
|
if (policyResult.decision === "allow") {
|
|
5936
|
-
if (
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5890
|
+
if (!isManual)
|
|
5891
|
+
appendLocalAudit(
|
|
5892
|
+
toolName,
|
|
5893
|
+
args,
|
|
5894
|
+
"allow",
|
|
5895
|
+
"local-policy",
|
|
5896
|
+
{ ...meta, ruleName: policyResult.ruleName },
|
|
5897
|
+
hashAuditArgs
|
|
5898
|
+
);
|
|
5945
5899
|
return { approved: true, checkedBy: "local-policy" };
|
|
5946
5900
|
}
|
|
5947
5901
|
if (policyResult.decision === "block") {
|
|
@@ -5974,23 +5928,6 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
5974
5928
|
{ ...meta, ruleName: policyResult.ruleName },
|
|
5975
5929
|
hashAuditArgs
|
|
5976
5930
|
);
|
|
5977
|
-
if (approvers.cloud && creds?.apiKey)
|
|
5978
|
-
auditLocalAllow(
|
|
5979
|
-
toolName,
|
|
5980
|
-
args,
|
|
5981
|
-
"smart-rule-block-override",
|
|
5982
|
-
creds,
|
|
5983
|
-
meta,
|
|
5984
|
-
void 0,
|
|
5985
|
-
false,
|
|
5986
|
-
{
|
|
5987
|
-
ruleName: policyResult.ruleName,
|
|
5988
|
-
ruleDescription: policyResult.ruleDescription,
|
|
5989
|
-
blockedByLabel: policyResult.blockedByLabel,
|
|
5990
|
-
matchedField: policyResult.matchedField,
|
|
5991
|
-
matchedWord: policyResult.matchedWord
|
|
5992
|
-
}
|
|
5993
|
-
);
|
|
5994
5931
|
const baseLabel = policyResult.blockedByLabel || "Smart Rule";
|
|
5995
5932
|
const OVERRIDE_PREFIX = "\u26A0\uFE0F Override block rule: ";
|
|
5996
5933
|
if (!baseLabel.startsWith(OVERRIDE_PREFIX)) {
|
|
@@ -6015,14 +5952,6 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
6015
5952
|
{ ...meta, ruleName: policyResult.ruleName },
|
|
6016
5953
|
hashAuditArgs
|
|
6017
5954
|
);
|
|
6018
|
-
if (approvers.cloud && creds?.apiKey)
|
|
6019
|
-
auditLocalAllow(toolName, args, "smart-rule-block", creds, meta, void 0, false, {
|
|
6020
|
-
ruleName: policyResult.ruleName,
|
|
6021
|
-
ruleDescription: policyResult.ruleDescription,
|
|
6022
|
-
blockedByLabel: policyResult.blockedByLabel,
|
|
6023
|
-
matchedField: policyResult.matchedField,
|
|
6024
|
-
matchedWord: policyResult.matchedWord
|
|
6025
|
-
});
|
|
6026
5955
|
return {
|
|
6027
5956
|
approved: false,
|
|
6028
5957
|
reason: policyResult.reason ?? "Action explicitly blocked by Smart Policy.",
|
|
@@ -6051,8 +5980,6 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
6051
5980
|
if (policyRuleDescription) riskMetadata.ruleDescription = policyRuleDescription.slice(0, 200);
|
|
6052
5981
|
const persistent = policyResult.ruleName ? null : getPersistentDecision(toolName);
|
|
6053
5982
|
if (persistent === "allow") {
|
|
6054
|
-
if (approvers.cloud && creds?.apiKey)
|
|
6055
|
-
await auditLocalAllow(toolName, args, "persistent", creds, meta);
|
|
6056
5983
|
if (!isManual) appendLocalAudit(toolName, args, "allow", "persistent", meta, hashAuditArgs);
|
|
6057
5984
|
return { approved: true, checkedBy: "persistent" };
|
|
6058
5985
|
}
|
|
@@ -6085,8 +6012,6 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
6085
6012
|
}
|
|
6086
6013
|
}
|
|
6087
6014
|
if (!taintWarning && getActiveTrustSession(toolName, args)) {
|
|
6088
|
-
if (approvers.cloud && creds?.apiKey)
|
|
6089
|
-
await auditLocalAllow(toolName, args, "trust", creds, meta);
|
|
6090
6015
|
if (!isManual) appendLocalAudit(toolName, args, "allow", "trust", meta, hashAuditArgs);
|
|
6091
6016
|
return { approved: true, checkedBy: "trust" };
|
|
6092
6017
|
}
|
|
@@ -6331,18 +6256,23 @@ REASON: Action blocked because no approval channels are available. (Native/Brows
|
|
|
6331
6256
|
args,
|
|
6332
6257
|
finalResult.approved ? "allow" : "deny",
|
|
6333
6258
|
finalResult.checkedBy || finalResult.blockedBy || "unknown",
|
|
6334
|
-
|
|
6259
|
+
// cloudRequestId links this row to the BE-origin AuditLog row the
|
|
6260
|
+
// /intercept handshake created — the shipper hands it to the SaaS so
|
|
6261
|
+
// the BE enriches that row instead of inserting a duplicate. Matters
|
|
6262
|
+
// for EVERY racer outcome, not just cloud wins: a native-popup
|
|
6263
|
+
// decision on a cloud-pending request would otherwise count twice.
|
|
6264
|
+
cloudRequestId ? { ...meta, cloudRequestId } : meta,
|
|
6335
6265
|
hashAuditArgs
|
|
6336
6266
|
);
|
|
6337
6267
|
}
|
|
6338
6268
|
const enrichedResult = !finalResult.approved && policyRuleDescription && !finalResult.ruleDescription ? { ...finalResult, ruleDescription: policyRuleDescription } : finalResult;
|
|
6339
6269
|
return enrichedResult;
|
|
6340
6270
|
}
|
|
6341
|
-
var
|
|
6271
|
+
var import_crypto5, WRITE_TOOLS;
|
|
6342
6272
|
var init_orchestrator = __esm({
|
|
6343
6273
|
"src/auth/orchestrator.ts"() {
|
|
6344
6274
|
"use strict";
|
|
6345
|
-
|
|
6275
|
+
import_crypto5 = require("crypto");
|
|
6346
6276
|
init_native();
|
|
6347
6277
|
init_context_sniper();
|
|
6348
6278
|
init_dlp();
|
|
@@ -6412,10 +6342,10 @@ function hashToolDefinitions(tools) {
|
|
|
6412
6342
|
return nameA.localeCompare(nameB);
|
|
6413
6343
|
});
|
|
6414
6344
|
const canonical = JSON.stringify(sorted);
|
|
6415
|
-
return
|
|
6345
|
+
return import_crypto6.default.createHash("sha256").update(canonical).digest("hex");
|
|
6416
6346
|
}
|
|
6417
6347
|
function getServerKey(upstreamCommand) {
|
|
6418
|
-
return
|
|
6348
|
+
return import_crypto6.default.createHash("sha256").update(upstreamCommand).digest("hex").slice(0, 16);
|
|
6419
6349
|
}
|
|
6420
6350
|
function readPinsFile(filePath) {
|
|
6421
6351
|
try {
|
|
@@ -6446,7 +6376,7 @@ function readMcpPins() {
|
|
|
6446
6376
|
}
|
|
6447
6377
|
function writePinsFile(filePath, data) {
|
|
6448
6378
|
import_fs12.default.mkdirSync(import_path14.default.dirname(filePath), { recursive: true });
|
|
6449
|
-
const tmp = `${filePath}.${
|
|
6379
|
+
const tmp = `${filePath}.${import_crypto6.default.randomBytes(6).toString("hex")}.tmp`;
|
|
6450
6380
|
const isHome = filePath === getHomePinsFilePath();
|
|
6451
6381
|
import_fs12.default.writeFileSync(tmp, JSON.stringify(data, null, 2), isHome ? { mode: 384 } : {});
|
|
6452
6382
|
import_fs12.default.renameSync(tmp, filePath);
|
|
@@ -6529,14 +6459,14 @@ function promotePin(serverKey, cwd) {
|
|
|
6529
6459
|
writePinsFile(repoPath, repoPins);
|
|
6530
6460
|
return { repoPath, created };
|
|
6531
6461
|
}
|
|
6532
|
-
var import_fs12, import_path14, import_os11,
|
|
6462
|
+
var import_fs12, import_path14, import_os11, import_crypto6;
|
|
6533
6463
|
var init_mcp_pin = __esm({
|
|
6534
6464
|
"src/mcp-pin.ts"() {
|
|
6535
6465
|
"use strict";
|
|
6536
6466
|
import_fs12 = __toESM(require("fs"));
|
|
6537
6467
|
import_path14 = __toESM(require("path"));
|
|
6538
6468
|
import_os11 = __toESM(require("os"));
|
|
6539
|
-
|
|
6469
|
+
import_crypto6 = __toESM(require("crypto"));
|
|
6540
6470
|
}
|
|
6541
6471
|
});
|
|
6542
6472
|
|
|
@@ -13169,11 +13099,11 @@ function commonPathPrefix(paths) {
|
|
|
13169
13099
|
const prefix = common.join("/").replace(/\/?$/, "/");
|
|
13170
13100
|
return prefix.length > 1 ? prefix : null;
|
|
13171
13101
|
}
|
|
13172
|
-
var
|
|
13102
|
+
var import_crypto7, SuggestionTracker;
|
|
13173
13103
|
var init_suggestion_tracker = __esm({
|
|
13174
13104
|
"src/daemon/suggestion-tracker.ts"() {
|
|
13175
13105
|
"use strict";
|
|
13176
|
-
|
|
13106
|
+
import_crypto7 = require("crypto");
|
|
13177
13107
|
SuggestionTracker = class {
|
|
13178
13108
|
events = /* @__PURE__ */ new Map();
|
|
13179
13109
|
threshold;
|
|
@@ -13219,7 +13149,7 @@ var init_suggestion_tracker = __esm({
|
|
|
13219
13149
|
}
|
|
13220
13150
|
} : { type: "ignoredTool", toolName };
|
|
13221
13151
|
return {
|
|
13222
|
-
id: (0,
|
|
13152
|
+
id: (0, import_crypto7.randomUUID)(),
|
|
13223
13153
|
toolName,
|
|
13224
13154
|
allowCount: events.length,
|
|
13225
13155
|
suggestedRule,
|
|
@@ -13465,7 +13395,7 @@ function markRejectionHandlerRegistered() {
|
|
|
13465
13395
|
function atomicWriteSync2(filePath, data, options) {
|
|
13466
13396
|
const dir = import_path24.default.dirname(filePath);
|
|
13467
13397
|
if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
|
|
13468
|
-
const tmpPath = `${filePath}.${(0,
|
|
13398
|
+
const tmpPath = `${filePath}.${(0, import_crypto8.randomUUID)()}.tmp`;
|
|
13469
13399
|
try {
|
|
13470
13400
|
import_fs22.default.writeFileSync(tmpPath, data, options);
|
|
13471
13401
|
} catch (err2) {
|
|
@@ -13640,7 +13570,7 @@ function broadcastForensic(finding) {
|
|
|
13640
13570
|
const severity = CRITICAL_FORENSIC_CATEGORIES.has(finding.type) ? "critical" : "warning";
|
|
13641
13571
|
const event = {
|
|
13642
13572
|
type: "forensic",
|
|
13643
|
-
id: `fnd_${(0,
|
|
13573
|
+
id: `fnd_${(0, import_crypto8.randomUUID)()}`,
|
|
13644
13574
|
ts: Date.now(),
|
|
13645
13575
|
sessionId: finding.sessionId,
|
|
13646
13576
|
category: finding.type,
|
|
@@ -13832,7 +13762,7 @@ function bindActivitySocket() {
|
|
|
13832
13762
|
});
|
|
13833
13763
|
activitySocketServer = unixServer;
|
|
13834
13764
|
}
|
|
13835
|
-
var import_net2, import_fs22, import_path24, import_os20,
|
|
13765
|
+
var import_net2, import_fs22, import_path24, import_os20, 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;
|
|
13836
13766
|
var init_state2 = __esm({
|
|
13837
13767
|
"src/daemon/state.ts"() {
|
|
13838
13768
|
"use strict";
|
|
@@ -13840,7 +13770,7 @@ var init_state2 = __esm({
|
|
|
13840
13770
|
import_fs22 = __toESM(require("fs"));
|
|
13841
13771
|
import_path24 = __toESM(require("path"));
|
|
13842
13772
|
import_os20 = __toESM(require("os"));
|
|
13843
|
-
|
|
13773
|
+
import_crypto8 = require("crypto");
|
|
13844
13774
|
init_daemon();
|
|
13845
13775
|
init_suggestion_tracker();
|
|
13846
13776
|
init_taint_store();
|
|
@@ -14282,71 +14212,282 @@ var init_sync = __esm({
|
|
|
14282
14212
|
}
|
|
14283
14213
|
});
|
|
14284
14214
|
|
|
14215
|
+
// src/daemon/audit-shipper.ts
|
|
14216
|
+
var audit_shipper_exports = {};
|
|
14217
|
+
__export(audit_shipper_exports, {
|
|
14218
|
+
AUDIT_SHIP_WATERMARK: () => AUDIT_SHIP_WATERMARK,
|
|
14219
|
+
buildWireRows: () => buildWireRows,
|
|
14220
|
+
fileSignature: () => fileSignature,
|
|
14221
|
+
readWatermark: () => readWatermark,
|
|
14222
|
+
shipLagBytes: () => shipLagBytes,
|
|
14223
|
+
shipOnce: () => shipOnce,
|
|
14224
|
+
startAuditShipper: () => startAuditShipper,
|
|
14225
|
+
writeWatermark: () => writeWatermark
|
|
14226
|
+
});
|
|
14227
|
+
function fileSignature(filePath) {
|
|
14228
|
+
const fd = import_fs24.default.openSync(filePath, "r");
|
|
14229
|
+
try {
|
|
14230
|
+
const buf = Buffer.alloc(512);
|
|
14231
|
+
const read = import_fs24.default.readSync(fd, buf, 0, 512, 0);
|
|
14232
|
+
const slice = buf.subarray(0, read);
|
|
14233
|
+
const nl = slice.indexOf(10);
|
|
14234
|
+
const firstLine = nl === -1 ? slice : slice.subarray(0, nl);
|
|
14235
|
+
return import_crypto9.default.createHash("sha256").update(firstLine).digest("hex").slice(0, 16);
|
|
14236
|
+
} finally {
|
|
14237
|
+
import_fs24.default.closeSync(fd);
|
|
14238
|
+
}
|
|
14239
|
+
}
|
|
14240
|
+
function readWatermark(watermarkPath) {
|
|
14241
|
+
try {
|
|
14242
|
+
const raw = JSON.parse(import_fs24.default.readFileSync(watermarkPath, "utf-8"));
|
|
14243
|
+
if (typeof raw.fileSig === "string" && typeof raw.offset === "number" && raw.offset >= 0)
|
|
14244
|
+
return raw;
|
|
14245
|
+
} catch {
|
|
14246
|
+
}
|
|
14247
|
+
return null;
|
|
14248
|
+
}
|
|
14249
|
+
function writeWatermark(watermarkPath, wm) {
|
|
14250
|
+
const tmp = `${watermarkPath}.tmp`;
|
|
14251
|
+
import_fs24.default.writeFileSync(tmp, JSON.stringify(wm));
|
|
14252
|
+
import_fs24.default.renameSync(tmp, watermarkPath);
|
|
14253
|
+
}
|
|
14254
|
+
function buildWireRows(chunk) {
|
|
14255
|
+
const lastNl = chunk.lastIndexOf(10);
|
|
14256
|
+
if (lastNl === -1) return { rows: [], consumed: 0 };
|
|
14257
|
+
const complete = chunk.subarray(0, lastNl + 1);
|
|
14258
|
+
const rows = [];
|
|
14259
|
+
for (const line of complete.toString("utf-8").split("\n")) {
|
|
14260
|
+
if (!line.trim()) continue;
|
|
14261
|
+
let parsed;
|
|
14262
|
+
try {
|
|
14263
|
+
parsed = JSON.parse(line);
|
|
14264
|
+
} catch {
|
|
14265
|
+
continue;
|
|
14266
|
+
}
|
|
14267
|
+
if (typeof parsed.eid !== "string" || parsed.eid.length < 8) continue;
|
|
14268
|
+
if (typeof parsed.tool !== "string" || !parsed.tool) continue;
|
|
14269
|
+
if (parsed.decision !== "allow" && parsed.decision !== "deny") continue;
|
|
14270
|
+
if (typeof parsed.ts !== "string") continue;
|
|
14271
|
+
if (parsed.testRun === true) continue;
|
|
14272
|
+
const checkedBy = typeof parsed.checkedBy === "string" ? parsed.checkedBy : void 0;
|
|
14273
|
+
if (checkedBy && SKIP_CHECKED_BY.has(checkedBy)) continue;
|
|
14274
|
+
const cloudRequestId = typeof parsed.cloudRequestId === "string" ? parsed.cloudRequestId : void 0;
|
|
14275
|
+
if (checkedBy === "cloud" && !cloudRequestId) continue;
|
|
14276
|
+
rows.push({
|
|
14277
|
+
eid: parsed.eid,
|
|
14278
|
+
ts: parsed.ts,
|
|
14279
|
+
tool: parsed.tool,
|
|
14280
|
+
...parsed.args && typeof parsed.args === "object" ? { args: parsed.args } : {},
|
|
14281
|
+
...typeof parsed.argsHash === "string" ? { argsHash: parsed.argsHash } : {},
|
|
14282
|
+
...typeof parsed.argsPreview === "string" ? { argsPreview: parsed.argsPreview } : {},
|
|
14283
|
+
decision: parsed.decision,
|
|
14284
|
+
...checkedBy ? { checkedBy } : {},
|
|
14285
|
+
...typeof parsed.ruleName === "string" ? { ruleName: parsed.ruleName } : {},
|
|
14286
|
+
...typeof parsed.agent === "string" ? { agent: parsed.agent } : {},
|
|
14287
|
+
...typeof parsed.mcpServer === "string" ? { mcpServer: parsed.mcpServer } : {},
|
|
14288
|
+
...typeof parsed.sessionId === "string" ? { sessionId: parsed.sessionId } : {},
|
|
14289
|
+
...typeof parsed.dlpPattern === "string" ? { dlpPattern: parsed.dlpPattern } : {},
|
|
14290
|
+
...typeof parsed.dlpSample === "string" ? { dlpSample: parsed.dlpSample } : {},
|
|
14291
|
+
...cloudRequestId ? { cloudRequestId } : {}
|
|
14292
|
+
});
|
|
14293
|
+
}
|
|
14294
|
+
return { rows, consumed: lastNl + 1 };
|
|
14295
|
+
}
|
|
14296
|
+
async function shipOnce(deps = {}) {
|
|
14297
|
+
const auditLogPath = deps.auditLogPath ?? LOCAL_AUDIT_LOG;
|
|
14298
|
+
const watermarkPath = deps.watermarkPath ?? AUDIT_SHIP_WATERMARK;
|
|
14299
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
14300
|
+
let cloudEnabled = deps.cloudEnabled;
|
|
14301
|
+
if (cloudEnabled === void 0) {
|
|
14302
|
+
try {
|
|
14303
|
+
const settings = getConfig().settings;
|
|
14304
|
+
cloudEnabled = settings.shipper.enabled !== false && settings.approvers.cloud;
|
|
14305
|
+
} catch {
|
|
14306
|
+
cloudEnabled = false;
|
|
14307
|
+
}
|
|
14308
|
+
}
|
|
14309
|
+
if (!cloudEnabled) return { status: "disabled", shipped: 0 };
|
|
14310
|
+
const creds = deps.creds !== void 0 ? deps.creds : readCredentials();
|
|
14311
|
+
if (!creds?.apiKey) return { status: "no-creds", shipped: 0 };
|
|
14312
|
+
const validated = validateApiUrl(creds.apiUrl);
|
|
14313
|
+
if (!validated) return { status: "no-creds", shipped: 0 };
|
|
14314
|
+
const endpoint = `${validated.toString().replace(/\/$/, "")}/audit/batch`;
|
|
14315
|
+
if (!import_fs24.default.existsSync(auditLogPath)) return { status: "idle", shipped: 0 };
|
|
14316
|
+
let shipped = 0;
|
|
14317
|
+
try {
|
|
14318
|
+
for (let chunkN = 0; chunkN < MAX_CHUNKS_PER_TICK; chunkN++) {
|
|
14319
|
+
const size = import_fs24.default.statSync(auditLogPath).size;
|
|
14320
|
+
if (size === 0) break;
|
|
14321
|
+
const sig = fileSignature(auditLogPath);
|
|
14322
|
+
const wm = readWatermark(watermarkPath);
|
|
14323
|
+
const offset = wm && wm.fileSig === sig && wm.offset <= size ? wm.offset : 0;
|
|
14324
|
+
if (offset >= size) break;
|
|
14325
|
+
const toRead = Math.min(size - offset, MAX_CHUNK_BYTES);
|
|
14326
|
+
const buf = Buffer.alloc(toRead);
|
|
14327
|
+
const fd = import_fs24.default.openSync(auditLogPath, "r");
|
|
14328
|
+
let read;
|
|
14329
|
+
try {
|
|
14330
|
+
read = import_fs24.default.readSync(fd, buf, 0, toRead, offset);
|
|
14331
|
+
} finally {
|
|
14332
|
+
import_fs24.default.closeSync(fd);
|
|
14333
|
+
}
|
|
14334
|
+
const { rows, consumed } = buildWireRows(buf.subarray(0, read));
|
|
14335
|
+
if (consumed === 0) break;
|
|
14336
|
+
for (let i = 0; i < rows.length; i += MAX_BATCH) {
|
|
14337
|
+
const batch = rows.slice(i, i + MAX_BATCH);
|
|
14338
|
+
const controller = new AbortController();
|
|
14339
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
14340
|
+
try {
|
|
14341
|
+
const res = await fetchImpl(endpoint, {
|
|
14342
|
+
method: "POST",
|
|
14343
|
+
headers: {
|
|
14344
|
+
"Content-Type": "application/json",
|
|
14345
|
+
Authorization: `Bearer ${creds.apiKey}`
|
|
14346
|
+
},
|
|
14347
|
+
body: JSON.stringify({ rows: batch }),
|
|
14348
|
+
signal: controller.signal
|
|
14349
|
+
});
|
|
14350
|
+
if (!res.ok) throw new Error(`audit/batch HTTP ${res.status}`);
|
|
14351
|
+
} finally {
|
|
14352
|
+
clearTimeout(timer);
|
|
14353
|
+
}
|
|
14354
|
+
shipped += batch.length;
|
|
14355
|
+
}
|
|
14356
|
+
writeWatermark(watermarkPath, {
|
|
14357
|
+
fileSig: sig,
|
|
14358
|
+
offset: offset + consumed,
|
|
14359
|
+
lastEid: rows.length > 0 ? rows[rows.length - 1].eid : wm?.lastEid,
|
|
14360
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
14361
|
+
});
|
|
14362
|
+
if (consumed < toRead) break;
|
|
14363
|
+
}
|
|
14364
|
+
} catch (err2) {
|
|
14365
|
+
try {
|
|
14366
|
+
appendToLog(HOOK_DEBUG_LOG, {
|
|
14367
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14368
|
+
shipper: "error",
|
|
14369
|
+
message: err2.message
|
|
14370
|
+
});
|
|
14371
|
+
} catch {
|
|
14372
|
+
}
|
|
14373
|
+
return { status: "error", shipped };
|
|
14374
|
+
}
|
|
14375
|
+
return { status: shipped > 0 ? "shipped" : "idle", shipped };
|
|
14376
|
+
}
|
|
14377
|
+
function shipLagBytes(auditLogPath = LOCAL_AUDIT_LOG, watermarkPath = AUDIT_SHIP_WATERMARK) {
|
|
14378
|
+
try {
|
|
14379
|
+
if (!import_fs24.default.existsSync(auditLogPath)) return 0;
|
|
14380
|
+
const size = import_fs24.default.statSync(auditLogPath).size;
|
|
14381
|
+
const wm = readWatermark(watermarkPath);
|
|
14382
|
+
if (!wm) return size;
|
|
14383
|
+
if (wm.fileSig !== fileSignature(auditLogPath)) return size;
|
|
14384
|
+
return Math.max(0, size - wm.offset);
|
|
14385
|
+
} catch {
|
|
14386
|
+
return null;
|
|
14387
|
+
}
|
|
14388
|
+
}
|
|
14389
|
+
function startAuditShipper() {
|
|
14390
|
+
if (shipperStarted) return;
|
|
14391
|
+
shipperStarted = true;
|
|
14392
|
+
const intervalMs = (() => {
|
|
14393
|
+
try {
|
|
14394
|
+
const sec = getConfig().settings.shipper.intervalSeconds;
|
|
14395
|
+
return sec >= 5 ? sec * 1e3 : DEFAULT_INTERVAL_MS;
|
|
14396
|
+
} catch {
|
|
14397
|
+
return DEFAULT_INTERVAL_MS;
|
|
14398
|
+
}
|
|
14399
|
+
})();
|
|
14400
|
+
setTimeout(() => void shipOnce(), 3e3);
|
|
14401
|
+
setInterval(() => void shipOnce(), intervalMs);
|
|
14402
|
+
}
|
|
14403
|
+
var import_fs24, import_path26, import_os22, import_crypto9, AUDIT_SHIP_WATERMARK, DEFAULT_INTERVAL_MS, MAX_BATCH, MAX_CHUNK_BYTES, MAX_CHUNKS_PER_TICK, FETCH_TIMEOUT_MS, SKIP_CHECKED_BY, shipperStarted;
|
|
14404
|
+
var init_audit_shipper = __esm({
|
|
14405
|
+
"src/daemon/audit-shipper.ts"() {
|
|
14406
|
+
"use strict";
|
|
14407
|
+
import_fs24 = __toESM(require("fs"));
|
|
14408
|
+
import_path26 = __toESM(require("path"));
|
|
14409
|
+
import_os22 = __toESM(require("os"));
|
|
14410
|
+
import_crypto9 = __toESM(require("crypto"));
|
|
14411
|
+
init_audit();
|
|
14412
|
+
init_config();
|
|
14413
|
+
init_sync();
|
|
14414
|
+
init_cloud();
|
|
14415
|
+
AUDIT_SHIP_WATERMARK = import_path26.default.join(import_os22.default.homedir(), ".node9", "audit-ship.json");
|
|
14416
|
+
DEFAULT_INTERVAL_MS = 2e4;
|
|
14417
|
+
MAX_BATCH = 500;
|
|
14418
|
+
MAX_CHUNK_BYTES = 4 * 1024 * 1024;
|
|
14419
|
+
MAX_CHUNKS_PER_TICK = 10;
|
|
14420
|
+
FETCH_TIMEOUT_MS = 1e4;
|
|
14421
|
+
SKIP_CHECKED_BY = /* @__PURE__ */ new Set(["ignored"]);
|
|
14422
|
+
shipperStarted = false;
|
|
14423
|
+
}
|
|
14424
|
+
});
|
|
14425
|
+
|
|
14285
14426
|
// src/daemon/dlp-scanner.ts
|
|
14286
14427
|
function loadIndex() {
|
|
14287
14428
|
try {
|
|
14288
|
-
return JSON.parse(
|
|
14429
|
+
return JSON.parse(import_fs25.default.readFileSync(INDEX_FILE, "utf-8"));
|
|
14289
14430
|
} catch {
|
|
14290
14431
|
return {};
|
|
14291
14432
|
}
|
|
14292
14433
|
}
|
|
14293
14434
|
function saveIndex(index) {
|
|
14294
14435
|
try {
|
|
14295
|
-
|
|
14436
|
+
import_fs25.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
|
|
14296
14437
|
} catch {
|
|
14297
14438
|
}
|
|
14298
14439
|
}
|
|
14299
14440
|
function appendAuditEntry(entry) {
|
|
14300
14441
|
try {
|
|
14301
|
-
|
|
14442
|
+
import_fs25.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
14302
14443
|
} catch {
|
|
14303
14444
|
}
|
|
14304
14445
|
}
|
|
14305
14446
|
function runDlpScan() {
|
|
14306
|
-
if (!
|
|
14447
|
+
if (!import_fs25.default.existsSync(PROJECTS_DIR2)) return;
|
|
14307
14448
|
const index = loadIndex();
|
|
14308
14449
|
let updated = false;
|
|
14309
14450
|
let projDirs;
|
|
14310
14451
|
try {
|
|
14311
|
-
projDirs =
|
|
14452
|
+
projDirs = import_fs25.default.readdirSync(PROJECTS_DIR2);
|
|
14312
14453
|
} catch {
|
|
14313
14454
|
return;
|
|
14314
14455
|
}
|
|
14315
14456
|
for (const proj of projDirs) {
|
|
14316
|
-
const projPath =
|
|
14457
|
+
const projPath = import_path27.default.join(PROJECTS_DIR2, proj);
|
|
14317
14458
|
try {
|
|
14318
|
-
if (!
|
|
14319
|
-
const real =
|
|
14320
|
-
if (!real.startsWith(PROJECTS_DIR2 +
|
|
14459
|
+
if (!import_fs25.default.lstatSync(projPath).isDirectory()) continue;
|
|
14460
|
+
const real = import_fs25.default.realpathSync(projPath);
|
|
14461
|
+
if (!real.startsWith(PROJECTS_DIR2 + import_path27.default.sep) && real !== PROJECTS_DIR2) continue;
|
|
14321
14462
|
} catch {
|
|
14322
14463
|
continue;
|
|
14323
14464
|
}
|
|
14324
14465
|
let files;
|
|
14325
14466
|
try {
|
|
14326
|
-
files =
|
|
14467
|
+
files = import_fs25.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
14327
14468
|
} catch {
|
|
14328
14469
|
continue;
|
|
14329
14470
|
}
|
|
14330
14471
|
for (const file of files) {
|
|
14331
|
-
const filePath =
|
|
14472
|
+
const filePath = import_path27.default.join(projPath, file);
|
|
14332
14473
|
const lastOffset = index[filePath] ?? 0;
|
|
14333
14474
|
let size;
|
|
14334
14475
|
try {
|
|
14335
|
-
size =
|
|
14476
|
+
size = import_fs25.default.statSync(filePath).size;
|
|
14336
14477
|
} catch {
|
|
14337
14478
|
continue;
|
|
14338
14479
|
}
|
|
14339
14480
|
if (size <= lastOffset) continue;
|
|
14340
14481
|
let fd;
|
|
14341
14482
|
try {
|
|
14342
|
-
fd =
|
|
14483
|
+
fd = import_fs25.default.openSync(filePath, "r");
|
|
14343
14484
|
} catch {
|
|
14344
14485
|
continue;
|
|
14345
14486
|
}
|
|
14346
14487
|
try {
|
|
14347
14488
|
const chunkSize = size - lastOffset;
|
|
14348
14489
|
const buf = Buffer.alloc(chunkSize);
|
|
14349
|
-
|
|
14490
|
+
import_fs25.default.readSync(fd, buf, 0, chunkSize, lastOffset);
|
|
14350
14491
|
const chunk = buf.toString("utf-8");
|
|
14351
14492
|
for (const line of chunk.split("\n")) {
|
|
14352
14493
|
if (!line.trim()) continue;
|
|
@@ -14366,7 +14507,7 @@ function runDlpScan() {
|
|
|
14366
14507
|
if (typeof text !== "string") continue;
|
|
14367
14508
|
const match = scanText(text);
|
|
14368
14509
|
if (!match) continue;
|
|
14369
|
-
const projLabel = decodeURIComponent(proj).replace(
|
|
14510
|
+
const projLabel = decodeURIComponent(proj).replace(import_os23.default.homedir(), "~").slice(0, 40);
|
|
14370
14511
|
const ts = entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
14371
14512
|
appendAuditEntry({
|
|
14372
14513
|
ts,
|
|
@@ -14391,7 +14532,7 @@ Run: node9 report --period 30d`
|
|
|
14391
14532
|
updated = true;
|
|
14392
14533
|
} finally {
|
|
14393
14534
|
try {
|
|
14394
|
-
|
|
14535
|
+
import_fs25.default.closeSync(fd);
|
|
14395
14536
|
} catch {
|
|
14396
14537
|
}
|
|
14397
14538
|
}
|
|
@@ -14417,30 +14558,30 @@ function startDlpScanner() {
|
|
|
14417
14558
|
);
|
|
14418
14559
|
timer.unref();
|
|
14419
14560
|
}
|
|
14420
|
-
var
|
|
14561
|
+
var import_fs25, import_path27, import_os23, INDEX_FILE, PROJECTS_DIR2;
|
|
14421
14562
|
var init_dlp_scanner = __esm({
|
|
14422
14563
|
"src/daemon/dlp-scanner.ts"() {
|
|
14423
14564
|
"use strict";
|
|
14424
|
-
|
|
14425
|
-
|
|
14426
|
-
|
|
14565
|
+
import_fs25 = __toESM(require("fs"));
|
|
14566
|
+
import_path27 = __toESM(require("path"));
|
|
14567
|
+
import_os23 = __toESM(require("os"));
|
|
14427
14568
|
init_dlp();
|
|
14428
14569
|
init_native();
|
|
14429
14570
|
init_state2();
|
|
14430
|
-
INDEX_FILE =
|
|
14431
|
-
PROJECTS_DIR2 =
|
|
14571
|
+
INDEX_FILE = import_path27.default.join(import_os23.default.homedir(), ".node9", "dlp-index.json");
|
|
14572
|
+
PROJECTS_DIR2 = import_path27.default.join(import_os23.default.homedir(), ".claude", "projects");
|
|
14432
14573
|
}
|
|
14433
14574
|
});
|
|
14434
14575
|
|
|
14435
14576
|
// src/daemon/mcp-tools.ts
|
|
14436
14577
|
function getMcpToolsFile() {
|
|
14437
|
-
return
|
|
14578
|
+
return import_path28.default.join(import_os24.default.homedir(), ".node9", "mcp-tools.json");
|
|
14438
14579
|
}
|
|
14439
14580
|
function readMcpToolsConfig() {
|
|
14440
14581
|
try {
|
|
14441
14582
|
const file = getMcpToolsFile();
|
|
14442
|
-
if (!
|
|
14443
|
-
const raw =
|
|
14583
|
+
if (!import_fs26.default.existsSync(file)) return {};
|
|
14584
|
+
const raw = import_fs26.default.readFileSync(file, "utf-8");
|
|
14444
14585
|
return JSON.parse(raw);
|
|
14445
14586
|
} catch {
|
|
14446
14587
|
return {};
|
|
@@ -14449,11 +14590,11 @@ function readMcpToolsConfig() {
|
|
|
14449
14590
|
function writeMcpToolsConfig(config) {
|
|
14450
14591
|
try {
|
|
14451
14592
|
const file = getMcpToolsFile();
|
|
14452
|
-
const dir =
|
|
14453
|
-
if (!
|
|
14454
|
-
const tmpPath = `${file}.${
|
|
14455
|
-
|
|
14456
|
-
|
|
14593
|
+
const dir = import_path28.default.dirname(file);
|
|
14594
|
+
if (!import_fs26.default.existsSync(dir)) import_fs26.default.mkdirSync(dir, { recursive: true });
|
|
14595
|
+
const tmpPath = `${file}.${import_os24.default.hostname()}.${process.pid}.tmp`;
|
|
14596
|
+
import_fs26.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
|
|
14597
|
+
import_fs26.default.renameSync(tmpPath, file);
|
|
14457
14598
|
} catch (e) {
|
|
14458
14599
|
console.error("Failed to write mcp-tools.json", e);
|
|
14459
14600
|
}
|
|
@@ -14492,13 +14633,13 @@ function approveServer(serverKey, disabledTools) {
|
|
|
14492
14633
|
writeMcpToolsConfig(config);
|
|
14493
14634
|
}
|
|
14494
14635
|
}
|
|
14495
|
-
var
|
|
14636
|
+
var import_fs26, import_path28, import_os24;
|
|
14496
14637
|
var init_mcp_tools = __esm({
|
|
14497
14638
|
"src/daemon/mcp-tools.ts"() {
|
|
14498
14639
|
"use strict";
|
|
14499
|
-
|
|
14500
|
-
|
|
14501
|
-
|
|
14640
|
+
import_fs26 = __toESM(require("fs"));
|
|
14641
|
+
import_path28 = __toESM(require("path"));
|
|
14642
|
+
import_os24 = __toESM(require("os"));
|
|
14502
14643
|
}
|
|
14503
14644
|
});
|
|
14504
14645
|
|
|
@@ -14507,9 +14648,10 @@ function startDaemon() {
|
|
|
14507
14648
|
startCostSync();
|
|
14508
14649
|
startCloudSync();
|
|
14509
14650
|
startForensicBroadcast();
|
|
14651
|
+
startAuditShipper();
|
|
14510
14652
|
startDlpScanner();
|
|
14511
14653
|
loadInsightCounts();
|
|
14512
|
-
const internalToken = (0,
|
|
14654
|
+
const internalToken = (0, import_crypto10.randomUUID)();
|
|
14513
14655
|
const validToken = (req) => req.headers["x-node9-internal"] === internalToken || req.headers["x-node9-token"] === internalToken;
|
|
14514
14656
|
const IDLE_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
|
|
14515
14657
|
const watchMode = process.env.NODE9_WATCH_MODE === "1";
|
|
@@ -14520,7 +14662,7 @@ function startDaemon() {
|
|
|
14520
14662
|
idleTimer = setTimeout(() => {
|
|
14521
14663
|
if (autoStarted) {
|
|
14522
14664
|
try {
|
|
14523
|
-
|
|
14665
|
+
import_fs27.default.unlinkSync(DAEMON_PID_FILE);
|
|
14524
14666
|
} catch {
|
|
14525
14667
|
}
|
|
14526
14668
|
}
|
|
@@ -14621,7 +14763,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
14621
14763
|
cwd,
|
|
14622
14764
|
localSmartRuleMatched = false
|
|
14623
14765
|
} = JSON.parse(body);
|
|
14624
|
-
const id = fromCLI && typeof activityId === "string" && activityId || (0,
|
|
14766
|
+
const id = fromCLI && typeof activityId === "string" && activityId || (0, import_crypto10.randomUUID)();
|
|
14625
14767
|
const entry = {
|
|
14626
14768
|
id,
|
|
14627
14769
|
toolName,
|
|
@@ -14665,7 +14807,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
14665
14807
|
mcpServer: entry.mcpServer
|
|
14666
14808
|
});
|
|
14667
14809
|
}
|
|
14668
|
-
const projectCwd = typeof cwd === "string" &&
|
|
14810
|
+
const projectCwd = typeof cwd === "string" && import_path29.default.isAbsolute(cwd) ? cwd : void 0;
|
|
14669
14811
|
const projectConfig = getConfig(projectCwd);
|
|
14670
14812
|
const browserEnabled = projectConfig.settings.approvers?.browser !== false;
|
|
14671
14813
|
const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
|
|
@@ -14957,8 +15099,8 @@ data: ${JSON.stringify(item.data)}
|
|
|
14957
15099
|
if (!validToken(req)) return res.writeHead(403).end();
|
|
14958
15100
|
const periodParam = reqUrl.searchParams.get("period") || "7d";
|
|
14959
15101
|
const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
|
|
14960
|
-
const logPath =
|
|
14961
|
-
if (!
|
|
15102
|
+
const logPath = import_path29.default.join(import_os25.default.homedir(), ".node9", "audit.log");
|
|
15103
|
+
if (!import_fs27.default.existsSync(logPath)) {
|
|
14962
15104
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
14963
15105
|
return res.end(
|
|
14964
15106
|
JSON.stringify({
|
|
@@ -14971,7 +15113,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
14971
15113
|
);
|
|
14972
15114
|
}
|
|
14973
15115
|
try {
|
|
14974
|
-
const raw =
|
|
15116
|
+
const raw = import_fs27.default.readFileSync(logPath, "utf-8");
|
|
14975
15117
|
const allEntries = raw.split("\n").flatMap((line) => {
|
|
14976
15118
|
if (!line.trim()) return [];
|
|
14977
15119
|
try {
|
|
@@ -15206,7 +15348,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
15206
15348
|
args: { toolCount: tools.length, status },
|
|
15207
15349
|
decision: "mcp-discovered"
|
|
15208
15350
|
});
|
|
15209
|
-
const id = (0,
|
|
15351
|
+
const id = (0, import_crypto10.randomUUID)();
|
|
15210
15352
|
const entry = {
|
|
15211
15353
|
id,
|
|
15212
15354
|
type: "mcp-discovery",
|
|
@@ -15294,14 +15436,14 @@ data: ${JSON.stringify(item.data)}
|
|
|
15294
15436
|
server.on("error", (e) => {
|
|
15295
15437
|
if (e.code === "EADDRINUSE") {
|
|
15296
15438
|
try {
|
|
15297
|
-
if (
|
|
15298
|
-
const { pid } = JSON.parse(
|
|
15439
|
+
if (import_fs27.default.existsSync(DAEMON_PID_FILE)) {
|
|
15440
|
+
const { pid } = JSON.parse(import_fs27.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
15299
15441
|
process.kill(pid, 0);
|
|
15300
15442
|
return process.exit(0);
|
|
15301
15443
|
}
|
|
15302
15444
|
} catch {
|
|
15303
15445
|
try {
|
|
15304
|
-
|
|
15446
|
+
import_fs27.default.unlinkSync(DAEMON_PID_FILE);
|
|
15305
15447
|
} catch {
|
|
15306
15448
|
}
|
|
15307
15449
|
server.listen(DAEMON_PORT, DAEMON_HOST);
|
|
@@ -15373,15 +15515,15 @@ data: ${JSON.stringify(item.data)}
|
|
|
15373
15515
|
}
|
|
15374
15516
|
startActivitySocket();
|
|
15375
15517
|
}
|
|
15376
|
-
var import_http,
|
|
15518
|
+
var import_http, import_fs27, import_path29, import_os25, import_crypto10, import_child_process2, import_chalk6;
|
|
15377
15519
|
var init_server = __esm({
|
|
15378
15520
|
"src/daemon/server.ts"() {
|
|
15379
15521
|
"use strict";
|
|
15380
15522
|
import_http = __toESM(require("http"));
|
|
15381
|
-
|
|
15382
|
-
|
|
15383
|
-
|
|
15384
|
-
|
|
15523
|
+
import_fs27 = __toESM(require("fs"));
|
|
15524
|
+
import_path29 = __toESM(require("path"));
|
|
15525
|
+
import_os25 = __toESM(require("os"));
|
|
15526
|
+
import_crypto10 = require("crypto");
|
|
15385
15527
|
import_child_process2 = require("child_process");
|
|
15386
15528
|
import_chalk6 = __toESM(require("chalk"));
|
|
15387
15529
|
init_core();
|
|
@@ -15391,6 +15533,7 @@ var init_server = __esm({
|
|
|
15391
15533
|
init_state();
|
|
15392
15534
|
init_costSync();
|
|
15393
15535
|
init_sync();
|
|
15536
|
+
init_audit_shipper();
|
|
15394
15537
|
init_dlp_scanner();
|
|
15395
15538
|
init_mcp_tools();
|
|
15396
15539
|
}
|
|
@@ -15400,8 +15543,8 @@ var init_server = __esm({
|
|
|
15400
15543
|
function resolveNode9Binary() {
|
|
15401
15544
|
try {
|
|
15402
15545
|
const script = process.argv[1];
|
|
15403
|
-
if (typeof script === "string" &&
|
|
15404
|
-
return
|
|
15546
|
+
if (typeof script === "string" && import_path30.default.isAbsolute(script) && import_fs28.default.existsSync(script)) {
|
|
15547
|
+
return import_fs28.default.realpathSync(script);
|
|
15405
15548
|
}
|
|
15406
15549
|
} catch {
|
|
15407
15550
|
}
|
|
@@ -15419,11 +15562,11 @@ function xmlEscape(s) {
|
|
|
15419
15562
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
15420
15563
|
}
|
|
15421
15564
|
function launchdPlist(binaryPath) {
|
|
15422
|
-
const logDir =
|
|
15565
|
+
const logDir = import_path30.default.join(import_os26.default.homedir(), ".node9");
|
|
15423
15566
|
const nodePath = xmlEscape(process.execPath);
|
|
15424
15567
|
const scriptPath = xmlEscape(binaryPath);
|
|
15425
|
-
const outLog = xmlEscape(
|
|
15426
|
-
const errLog = xmlEscape(
|
|
15568
|
+
const outLog = xmlEscape(import_path30.default.join(logDir, "daemon.log"));
|
|
15569
|
+
const errLog = xmlEscape(import_path30.default.join(logDir, "daemon-error.log"));
|
|
15427
15570
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
15428
15571
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
15429
15572
|
<plist version="1.0">
|
|
@@ -15456,9 +15599,9 @@ function launchdPlist(binaryPath) {
|
|
|
15456
15599
|
`;
|
|
15457
15600
|
}
|
|
15458
15601
|
function installLaunchd(binaryPath) {
|
|
15459
|
-
const dir =
|
|
15460
|
-
if (!
|
|
15461
|
-
|
|
15602
|
+
const dir = import_path30.default.dirname(LAUNCHD_PLIST);
|
|
15603
|
+
if (!import_fs28.default.existsSync(dir)) import_fs28.default.mkdirSync(dir, { recursive: true });
|
|
15604
|
+
import_fs28.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
|
|
15462
15605
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
|
|
15463
15606
|
const r = (0, import_child_process3.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
|
|
15464
15607
|
encoding: "utf8",
|
|
@@ -15469,13 +15612,13 @@ function installLaunchd(binaryPath) {
|
|
|
15469
15612
|
}
|
|
15470
15613
|
}
|
|
15471
15614
|
function uninstallLaunchd() {
|
|
15472
|
-
if (
|
|
15615
|
+
if (import_fs28.default.existsSync(LAUNCHD_PLIST)) {
|
|
15473
15616
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
|
|
15474
|
-
|
|
15617
|
+
import_fs28.default.unlinkSync(LAUNCHD_PLIST);
|
|
15475
15618
|
}
|
|
15476
15619
|
}
|
|
15477
15620
|
function isLaunchdInstalled() {
|
|
15478
|
-
return
|
|
15621
|
+
return import_fs28.default.existsSync(LAUNCHD_PLIST);
|
|
15479
15622
|
}
|
|
15480
15623
|
function systemdUnit(binaryPath) {
|
|
15481
15624
|
return `[Unit]
|
|
@@ -15494,12 +15637,12 @@ WantedBy=default.target
|
|
|
15494
15637
|
`;
|
|
15495
15638
|
}
|
|
15496
15639
|
function installSystemd(binaryPath) {
|
|
15497
|
-
if (!
|
|
15498
|
-
|
|
15640
|
+
if (!import_fs28.default.existsSync(SYSTEMD_UNIT_DIR)) {
|
|
15641
|
+
import_fs28.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
|
|
15499
15642
|
}
|
|
15500
|
-
|
|
15643
|
+
import_fs28.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
|
|
15501
15644
|
try {
|
|
15502
|
-
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger",
|
|
15645
|
+
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger", import_os26.default.userInfo().username], { timeout: 3e3 });
|
|
15503
15646
|
} catch {
|
|
15504
15647
|
}
|
|
15505
15648
|
const reload = (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], {
|
|
@@ -15519,23 +15662,23 @@ function installSystemd(binaryPath) {
|
|
|
15519
15662
|
}
|
|
15520
15663
|
}
|
|
15521
15664
|
function uninstallSystemd() {
|
|
15522
|
-
if (
|
|
15665
|
+
if (import_fs28.default.existsSync(SYSTEMD_UNIT)) {
|
|
15523
15666
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
|
|
15524
15667
|
encoding: "utf8",
|
|
15525
15668
|
timeout: 5e3
|
|
15526
15669
|
});
|
|
15527
15670
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
|
|
15528
|
-
|
|
15671
|
+
import_fs28.default.unlinkSync(SYSTEMD_UNIT);
|
|
15529
15672
|
}
|
|
15530
15673
|
}
|
|
15531
15674
|
function isSystemdInstalled() {
|
|
15532
|
-
return
|
|
15675
|
+
return import_fs28.default.existsSync(SYSTEMD_UNIT);
|
|
15533
15676
|
}
|
|
15534
15677
|
function stopRunningDaemon() {
|
|
15535
|
-
const pidFile =
|
|
15536
|
-
if (!
|
|
15678
|
+
const pidFile = import_path30.default.join(import_os26.default.homedir(), ".node9", "daemon.pid");
|
|
15679
|
+
if (!import_fs28.default.existsSync(pidFile)) return;
|
|
15537
15680
|
try {
|
|
15538
|
-
const data = JSON.parse(
|
|
15681
|
+
const data = JSON.parse(import_fs28.default.readFileSync(pidFile, "utf-8"));
|
|
15539
15682
|
const pid = data.pid;
|
|
15540
15683
|
const MAX_PID2 = 4194304;
|
|
15541
15684
|
if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
|
|
@@ -15555,7 +15698,7 @@ function stopRunningDaemon() {
|
|
|
15555
15698
|
}
|
|
15556
15699
|
}
|
|
15557
15700
|
try {
|
|
15558
|
-
|
|
15701
|
+
import_fs28.default.unlinkSync(pidFile);
|
|
15559
15702
|
} catch {
|
|
15560
15703
|
}
|
|
15561
15704
|
} catch {
|
|
@@ -15625,26 +15768,26 @@ function isDaemonServiceInstalled() {
|
|
|
15625
15768
|
if (process.platform === "linux") return isSystemdInstalled();
|
|
15626
15769
|
return false;
|
|
15627
15770
|
}
|
|
15628
|
-
var
|
|
15771
|
+
var import_fs28, import_path30, import_os26, import_child_process3, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
|
|
15629
15772
|
var init_service = __esm({
|
|
15630
15773
|
"src/daemon/service.ts"() {
|
|
15631
15774
|
"use strict";
|
|
15632
|
-
|
|
15633
|
-
|
|
15634
|
-
|
|
15775
|
+
import_fs28 = __toESM(require("fs"));
|
|
15776
|
+
import_path30 = __toESM(require("path"));
|
|
15777
|
+
import_os26 = __toESM(require("os"));
|
|
15635
15778
|
import_child_process3 = require("child_process");
|
|
15636
15779
|
LAUNCHD_LABEL = "ai.node9.daemon";
|
|
15637
|
-
LAUNCHD_PLIST =
|
|
15638
|
-
SYSTEMD_UNIT_DIR =
|
|
15639
|
-
SYSTEMD_UNIT =
|
|
15780
|
+
LAUNCHD_PLIST = import_path30.default.join(import_os26.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
15781
|
+
SYSTEMD_UNIT_DIR = import_path30.default.join(import_os26.default.homedir(), ".config", "systemd", "user");
|
|
15782
|
+
SYSTEMD_UNIT = import_path30.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
|
|
15640
15783
|
}
|
|
15641
15784
|
});
|
|
15642
15785
|
|
|
15643
15786
|
// src/daemon/index.ts
|
|
15644
15787
|
function stopDaemon() {
|
|
15645
|
-
if (!
|
|
15788
|
+
if (!import_fs29.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk7.default.yellow("Not running."));
|
|
15646
15789
|
try {
|
|
15647
|
-
const data = JSON.parse(
|
|
15790
|
+
const data = JSON.parse(import_fs29.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
15648
15791
|
const pid = data.pid;
|
|
15649
15792
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
15650
15793
|
console.log(import_chalk7.default.gray("Cleaned up invalid PID file."));
|
|
@@ -15656,7 +15799,7 @@ function stopDaemon() {
|
|
|
15656
15799
|
console.log(import_chalk7.default.gray("Cleaned up stale PID file."));
|
|
15657
15800
|
} finally {
|
|
15658
15801
|
try {
|
|
15659
|
-
|
|
15802
|
+
import_fs29.default.unlinkSync(DAEMON_PID_FILE);
|
|
15660
15803
|
} catch {
|
|
15661
15804
|
}
|
|
15662
15805
|
}
|
|
@@ -15665,9 +15808,9 @@ function daemonStatus() {
|
|
|
15665
15808
|
const serviceInstalled = isDaemonServiceInstalled();
|
|
15666
15809
|
const serviceLabel = serviceInstalled ? import_chalk7.default.green("installed (starts on login)") : import_chalk7.default.yellow("not installed \u2014 run: node9 daemon install");
|
|
15667
15810
|
let processStatus;
|
|
15668
|
-
if (
|
|
15811
|
+
if (import_fs29.default.existsSync(DAEMON_PID_FILE)) {
|
|
15669
15812
|
try {
|
|
15670
|
-
const data = JSON.parse(
|
|
15813
|
+
const data = JSON.parse(import_fs29.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
15671
15814
|
const pid = data.pid;
|
|
15672
15815
|
const port = data.port;
|
|
15673
15816
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
@@ -15689,11 +15832,11 @@ function daemonStatus() {
|
|
|
15689
15832
|
console.log(` Service : ${serviceLabel}
|
|
15690
15833
|
`);
|
|
15691
15834
|
}
|
|
15692
|
-
var
|
|
15835
|
+
var import_fs29, import_chalk7, MAX_PID;
|
|
15693
15836
|
var init_daemon2 = __esm({
|
|
15694
15837
|
"src/daemon/index.ts"() {
|
|
15695
15838
|
"use strict";
|
|
15696
|
-
|
|
15839
|
+
import_fs29 = __toESM(require("fs"));
|
|
15697
15840
|
import_chalk7 = __toESM(require("chalk"));
|
|
15698
15841
|
init_server();
|
|
15699
15842
|
init_state2();
|
|
@@ -15733,20 +15876,20 @@ function getModelContextLimit(model) {
|
|
|
15733
15876
|
return 2e5;
|
|
15734
15877
|
}
|
|
15735
15878
|
function readSessionUsage() {
|
|
15736
|
-
const projectsDir =
|
|
15737
|
-
if (!
|
|
15879
|
+
const projectsDir = import_path48.default.join(import_os42.default.homedir(), ".claude", "projects");
|
|
15880
|
+
if (!import_fs47.default.existsSync(projectsDir)) return null;
|
|
15738
15881
|
let latestFile = null;
|
|
15739
15882
|
let latestMtime = 0;
|
|
15740
15883
|
try {
|
|
15741
|
-
for (const dir of
|
|
15742
|
-
const dirPath =
|
|
15884
|
+
for (const dir of import_fs47.default.readdirSync(projectsDir)) {
|
|
15885
|
+
const dirPath = import_path48.default.join(projectsDir, dir);
|
|
15743
15886
|
try {
|
|
15744
|
-
if (!
|
|
15745
|
-
for (const file of
|
|
15887
|
+
if (!import_fs47.default.statSync(dirPath).isDirectory()) continue;
|
|
15888
|
+
for (const file of import_fs47.default.readdirSync(dirPath)) {
|
|
15746
15889
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
15747
|
-
const filePath =
|
|
15890
|
+
const filePath = import_path48.default.join(dirPath, file);
|
|
15748
15891
|
try {
|
|
15749
|
-
const mtime =
|
|
15892
|
+
const mtime = import_fs47.default.statSync(filePath).mtimeMs;
|
|
15750
15893
|
if (mtime > latestMtime) {
|
|
15751
15894
|
latestMtime = mtime;
|
|
15752
15895
|
latestFile = filePath;
|
|
@@ -15761,7 +15904,7 @@ function readSessionUsage() {
|
|
|
15761
15904
|
}
|
|
15762
15905
|
if (!latestFile) return null;
|
|
15763
15906
|
try {
|
|
15764
|
-
const lines =
|
|
15907
|
+
const lines = import_fs47.default.readFileSync(latestFile, "utf-8").split("\n");
|
|
15765
15908
|
let lastModel = "";
|
|
15766
15909
|
let lastInput = 0;
|
|
15767
15910
|
let lastOutput = 0;
|
|
@@ -15822,7 +15965,7 @@ function formatBase(activity) {
|
|
|
15822
15965
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
15823
15966
|
const icon = getIcon(activity.tool);
|
|
15824
15967
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
15825
|
-
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(
|
|
15968
|
+
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os42.default.homedir(), "~");
|
|
15826
15969
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
15827
15970
|
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)}`;
|
|
15828
15971
|
}
|
|
@@ -15861,9 +16004,9 @@ function renderPending(activity) {
|
|
|
15861
16004
|
}
|
|
15862
16005
|
async function ensureDaemon() {
|
|
15863
16006
|
let pidPort = null;
|
|
15864
|
-
if (
|
|
16007
|
+
if (import_fs47.default.existsSync(PID_FILE)) {
|
|
15865
16008
|
try {
|
|
15866
|
-
const { port } = JSON.parse(
|
|
16009
|
+
const { port } = JSON.parse(import_fs47.default.readFileSync(PID_FILE, "utf-8"));
|
|
15867
16010
|
pidPort = port;
|
|
15868
16011
|
} catch {
|
|
15869
16012
|
console.error(import_chalk29.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -16019,9 +16162,9 @@ function buildRecoveryCardLines(req) {
|
|
|
16019
16162
|
];
|
|
16020
16163
|
}
|
|
16021
16164
|
function readApproversFromDisk() {
|
|
16022
|
-
const configPath =
|
|
16165
|
+
const configPath = import_path48.default.join(import_os42.default.homedir(), ".node9", "config.json");
|
|
16023
16166
|
try {
|
|
16024
|
-
const raw = JSON.parse(
|
|
16167
|
+
const raw = JSON.parse(import_fs47.default.readFileSync(configPath, "utf-8"));
|
|
16025
16168
|
const settings = raw.settings ?? {};
|
|
16026
16169
|
return settings.approvers ?? {};
|
|
16027
16170
|
} catch {
|
|
@@ -16037,15 +16180,15 @@ function approverStatusLine() {
|
|
|
16037
16180
|
return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
16038
16181
|
}
|
|
16039
16182
|
function toggleApprover(channel) {
|
|
16040
|
-
const configPath =
|
|
16183
|
+
const configPath = import_path48.default.join(import_os42.default.homedir(), ".node9", "config.json");
|
|
16041
16184
|
try {
|
|
16042
|
-
const raw = JSON.parse(
|
|
16185
|
+
const raw = JSON.parse(import_fs47.default.readFileSync(configPath, "utf-8"));
|
|
16043
16186
|
const settings = raw.settings ?? {};
|
|
16044
16187
|
const approvers = settings.approvers ?? {};
|
|
16045
16188
|
approvers[channel] = approvers[channel] === false;
|
|
16046
16189
|
settings.approvers = approvers;
|
|
16047
16190
|
raw.settings = settings;
|
|
16048
|
-
|
|
16191
|
+
import_fs47.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
16049
16192
|
} catch (err2) {
|
|
16050
16193
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
16051
16194
|
`);
|
|
@@ -16217,8 +16360,8 @@ async function startTail(options = {}) {
|
|
|
16217
16360
|
}
|
|
16218
16361
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
16219
16362
|
try {
|
|
16220
|
-
|
|
16221
|
-
|
|
16363
|
+
import_fs47.default.appendFileSync(
|
|
16364
|
+
import_path48.default.join(import_os42.default.homedir(), ".node9", "hook-debug.log"),
|
|
16222
16365
|
`[tail] POST /decision failed: ${String(err2)}
|
|
16223
16366
|
`
|
|
16224
16367
|
);
|
|
@@ -16282,9 +16425,9 @@ async function startTail(options = {}) {
|
|
|
16282
16425
|
};
|
|
16283
16426
|
process.stdin.on("keypress", onKeypress);
|
|
16284
16427
|
}
|
|
16285
|
-
const auditLog =
|
|
16428
|
+
const auditLog = import_path48.default.join(import_os42.default.homedir(), ".node9", "audit.log");
|
|
16286
16429
|
try {
|
|
16287
|
-
const unackedDlp =
|
|
16430
|
+
const unackedDlp = import_fs47.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
16288
16431
|
if (unackedDlp > 0) {
|
|
16289
16432
|
console.log("");
|
|
16290
16433
|
console.log(
|
|
@@ -16324,7 +16467,7 @@ async function startTail(options = {}) {
|
|
|
16324
16467
|
if (stallWarned) return;
|
|
16325
16468
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
16326
16469
|
try {
|
|
16327
|
-
const auditMtime =
|
|
16470
|
+
const auditMtime = import_fs47.default.statSync(auditLog).mtimeMs;
|
|
16328
16471
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
16329
16472
|
console.log("");
|
|
16330
16473
|
console.log(
|
|
@@ -16509,20 +16652,20 @@ async function startTail(options = {}) {
|
|
|
16509
16652
|
process.exit(1);
|
|
16510
16653
|
});
|
|
16511
16654
|
}
|
|
16512
|
-
var import_http2, import_chalk29,
|
|
16655
|
+
var import_http2, import_chalk29, import_fs47, import_os42, import_path48, 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;
|
|
16513
16656
|
var init_tail = __esm({
|
|
16514
16657
|
"src/tui/tail.ts"() {
|
|
16515
16658
|
"use strict";
|
|
16516
16659
|
import_http2 = __toESM(require("http"));
|
|
16517
16660
|
import_chalk29 = __toESM(require("chalk"));
|
|
16518
|
-
|
|
16519
|
-
|
|
16520
|
-
|
|
16661
|
+
import_fs47 = __toESM(require("fs"));
|
|
16662
|
+
import_os42 = __toESM(require("os"));
|
|
16663
|
+
import_path48 = __toESM(require("path"));
|
|
16521
16664
|
import_readline6 = __toESM(require("readline"));
|
|
16522
16665
|
import_child_process12 = require("child_process");
|
|
16523
16666
|
init_daemon2();
|
|
16524
16667
|
init_daemon();
|
|
16525
|
-
PID_FILE =
|
|
16668
|
+
PID_FILE = import_path48.default.join(import_os42.default.homedir(), ".node9", "daemon.pid");
|
|
16526
16669
|
ICONS = {
|
|
16527
16670
|
bash: "\u{1F4BB}",
|
|
16528
16671
|
shell: "\u{1F4BB}",
|
|
@@ -16644,9 +16787,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
16644
16787
|
return ` (${m}m left)`;
|
|
16645
16788
|
}
|
|
16646
16789
|
function safeReadJson(filePath) {
|
|
16647
|
-
if (!
|
|
16790
|
+
if (!import_fs48.default.existsSync(filePath)) return null;
|
|
16648
16791
|
try {
|
|
16649
|
-
return JSON.parse(
|
|
16792
|
+
return JSON.parse(import_fs48.default.readFileSync(filePath, "utf-8"));
|
|
16650
16793
|
} catch {
|
|
16651
16794
|
return null;
|
|
16652
16795
|
}
|
|
@@ -16667,12 +16810,12 @@ function countHooksInFile(filePath) {
|
|
|
16667
16810
|
return Object.keys(cfg.hooks).length;
|
|
16668
16811
|
}
|
|
16669
16812
|
function countRulesInDir(rulesDir) {
|
|
16670
|
-
if (!
|
|
16813
|
+
if (!import_fs48.default.existsSync(rulesDir)) return 0;
|
|
16671
16814
|
let count = 0;
|
|
16672
16815
|
try {
|
|
16673
|
-
for (const entry of
|
|
16816
|
+
for (const entry of import_fs48.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
16674
16817
|
if (entry.isDirectory()) {
|
|
16675
|
-
count += countRulesInDir(
|
|
16818
|
+
count += countRulesInDir(import_path49.default.join(rulesDir, entry.name));
|
|
16676
16819
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
16677
16820
|
count++;
|
|
16678
16821
|
}
|
|
@@ -16683,46 +16826,46 @@ function countRulesInDir(rulesDir) {
|
|
|
16683
16826
|
}
|
|
16684
16827
|
function isSamePath(a, b) {
|
|
16685
16828
|
try {
|
|
16686
|
-
return
|
|
16829
|
+
return import_path49.default.resolve(a) === import_path49.default.resolve(b);
|
|
16687
16830
|
} catch {
|
|
16688
16831
|
return false;
|
|
16689
16832
|
}
|
|
16690
16833
|
}
|
|
16691
16834
|
function countConfigs(cwd) {
|
|
16692
|
-
const homeDir2 =
|
|
16693
|
-
const claudeDir =
|
|
16835
|
+
const homeDir2 = import_os43.default.homedir();
|
|
16836
|
+
const claudeDir = import_path49.default.join(homeDir2, ".claude");
|
|
16694
16837
|
let claudeMdCount = 0;
|
|
16695
16838
|
let rulesCount = 0;
|
|
16696
16839
|
let hooksCount = 0;
|
|
16697
16840
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
16698
16841
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
16699
|
-
if (
|
|
16700
|
-
rulesCount += countRulesInDir(
|
|
16701
|
-
const userSettings =
|
|
16842
|
+
if (import_fs48.default.existsSync(import_path49.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
16843
|
+
rulesCount += countRulesInDir(import_path49.default.join(claudeDir, "rules"));
|
|
16844
|
+
const userSettings = import_path49.default.join(claudeDir, "settings.json");
|
|
16702
16845
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
16703
16846
|
hooksCount += countHooksInFile(userSettings);
|
|
16704
|
-
const userClaudeJson =
|
|
16847
|
+
const userClaudeJson = import_path49.default.join(homeDir2, ".claude.json");
|
|
16705
16848
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
16706
16849
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
16707
16850
|
userMcpServers.delete(name);
|
|
16708
16851
|
}
|
|
16709
16852
|
if (cwd) {
|
|
16710
|
-
if (
|
|
16711
|
-
if (
|
|
16712
|
-
const projectClaudeDir =
|
|
16853
|
+
if (import_fs48.default.existsSync(import_path49.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
16854
|
+
if (import_fs48.default.existsSync(import_path49.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
16855
|
+
const projectClaudeDir = import_path49.default.join(cwd, ".claude");
|
|
16713
16856
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
16714
16857
|
if (!overlapsUserScope) {
|
|
16715
|
-
if (
|
|
16716
|
-
rulesCount += countRulesInDir(
|
|
16717
|
-
const projSettings =
|
|
16858
|
+
if (import_fs48.default.existsSync(import_path49.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
16859
|
+
rulesCount += countRulesInDir(import_path49.default.join(projectClaudeDir, "rules"));
|
|
16860
|
+
const projSettings = import_path49.default.join(projectClaudeDir, "settings.json");
|
|
16718
16861
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
16719
16862
|
hooksCount += countHooksInFile(projSettings);
|
|
16720
16863
|
}
|
|
16721
|
-
if (
|
|
16722
|
-
const localSettings =
|
|
16864
|
+
if (import_fs48.default.existsSync(import_path49.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
16865
|
+
const localSettings = import_path49.default.join(projectClaudeDir, "settings.local.json");
|
|
16723
16866
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
16724
16867
|
hooksCount += countHooksInFile(localSettings);
|
|
16725
|
-
const mcpJsonServers = getMcpServerNames(
|
|
16868
|
+
const mcpJsonServers = getMcpServerNames(import_path49.default.join(cwd, ".mcp.json"));
|
|
16726
16869
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
16727
16870
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
16728
16871
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -16755,12 +16898,12 @@ function readActiveShieldsHud() {
|
|
|
16755
16898
|
return shieldsCache.value;
|
|
16756
16899
|
}
|
|
16757
16900
|
try {
|
|
16758
|
-
const shieldsPath =
|
|
16759
|
-
if (!
|
|
16901
|
+
const shieldsPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "shields.json");
|
|
16902
|
+
if (!import_fs48.default.existsSync(shieldsPath)) {
|
|
16760
16903
|
shieldsCache = { value: [], ts: now };
|
|
16761
16904
|
return [];
|
|
16762
16905
|
}
|
|
16763
|
-
const parsed = JSON.parse(
|
|
16906
|
+
const parsed = JSON.parse(import_fs48.default.readFileSync(shieldsPath, "utf-8"));
|
|
16764
16907
|
if (!Array.isArray(parsed.active)) {
|
|
16765
16908
|
shieldsCache = { value: [], ts: now };
|
|
16766
16909
|
return [];
|
|
@@ -16862,17 +17005,17 @@ function renderContextLine(stdin) {
|
|
|
16862
17005
|
async function main() {
|
|
16863
17006
|
try {
|
|
16864
17007
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
16865
|
-
if (
|
|
17008
|
+
if (import_fs48.default.existsSync(import_path49.default.join(import_os43.default.homedir(), ".node9", "hud-debug"))) {
|
|
16866
17009
|
try {
|
|
16867
|
-
const logPath =
|
|
17010
|
+
const logPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "hud-debug.log");
|
|
16868
17011
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
16869
17012
|
let size = 0;
|
|
16870
17013
|
try {
|
|
16871
|
-
size =
|
|
17014
|
+
size = import_fs48.default.statSync(logPath).size;
|
|
16872
17015
|
} catch {
|
|
16873
17016
|
}
|
|
16874
17017
|
if (size < MAX_LOG_SIZE) {
|
|
16875
|
-
|
|
17018
|
+
import_fs48.default.appendFileSync(
|
|
16876
17019
|
logPath,
|
|
16877
17020
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
16878
17021
|
);
|
|
@@ -16893,11 +17036,11 @@ async function main() {
|
|
|
16893
17036
|
try {
|
|
16894
17037
|
const cwd = stdin.cwd ?? process.cwd();
|
|
16895
17038
|
for (const configPath of [
|
|
16896
|
-
|
|
16897
|
-
|
|
17039
|
+
import_path49.default.join(cwd, "node9.config.json"),
|
|
17040
|
+
import_path49.default.join(import_os43.default.homedir(), ".node9", "config.json")
|
|
16898
17041
|
]) {
|
|
16899
|
-
if (!
|
|
16900
|
-
const cfg = JSON.parse(
|
|
17042
|
+
if (!import_fs48.default.existsSync(configPath)) continue;
|
|
17043
|
+
const cfg = JSON.parse(import_fs48.default.readFileSync(configPath, "utf-8"));
|
|
16901
17044
|
const hud = cfg.settings?.hud;
|
|
16902
17045
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
16903
17046
|
}
|
|
@@ -16915,13 +17058,13 @@ async function main() {
|
|
|
16915
17058
|
renderOffline();
|
|
16916
17059
|
}
|
|
16917
17060
|
}
|
|
16918
|
-
var
|
|
17061
|
+
var import_fs48, import_path49, import_os43, import_http3, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
|
|
16919
17062
|
var init_hud = __esm({
|
|
16920
17063
|
"src/cli/hud.ts"() {
|
|
16921
17064
|
"use strict";
|
|
16922
|
-
|
|
16923
|
-
|
|
16924
|
-
|
|
17065
|
+
import_fs48 = __toESM(require("fs"));
|
|
17066
|
+
import_path49 = __toESM(require("path"));
|
|
17067
|
+
import_os43 = __toESM(require("os"));
|
|
16925
17068
|
import_http3 = __toESM(require("http"));
|
|
16926
17069
|
init_daemon();
|
|
16927
17070
|
RESET3 = "\x1B[0m";
|
|
@@ -16948,9 +17091,9 @@ init_core();
|
|
|
16948
17091
|
init_setup();
|
|
16949
17092
|
init_daemon2();
|
|
16950
17093
|
var import_chalk30 = __toESM(require("chalk"));
|
|
16951
|
-
var
|
|
16952
|
-
var
|
|
16953
|
-
var
|
|
17094
|
+
var import_fs49 = __toESM(require("fs"));
|
|
17095
|
+
var import_path50 = __toESM(require("path"));
|
|
17096
|
+
var import_os44 = __toESM(require("os"));
|
|
16954
17097
|
var import_prompts2 = require("@inquirer/prompts");
|
|
16955
17098
|
|
|
16956
17099
|
// src/utils/duration.ts
|
|
@@ -17132,18 +17275,18 @@ async function runProxy(targetCommand) {
|
|
|
17132
17275
|
|
|
17133
17276
|
// src/cli/daemon-starter.ts
|
|
17134
17277
|
var import_child_process5 = require("child_process");
|
|
17135
|
-
var
|
|
17136
|
-
var
|
|
17278
|
+
var import_path31 = __toESM(require("path"));
|
|
17279
|
+
var import_fs30 = __toESM(require("fs"));
|
|
17137
17280
|
init_daemon();
|
|
17138
17281
|
function isTestingMode() {
|
|
17139
17282
|
return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
|
|
17140
17283
|
}
|
|
17141
17284
|
async function autoStartDaemonAndWait() {
|
|
17142
17285
|
if (isTestingMode()) return false;
|
|
17143
|
-
if (!
|
|
17286
|
+
if (!import_path31.default.isAbsolute(process.argv[1])) return false;
|
|
17144
17287
|
let resolvedArgv1;
|
|
17145
17288
|
try {
|
|
17146
|
-
resolvedArgv1 =
|
|
17289
|
+
resolvedArgv1 = import_fs30.default.realpathSync(process.argv[1]);
|
|
17147
17290
|
} catch {
|
|
17148
17291
|
return false;
|
|
17149
17292
|
}
|
|
@@ -17170,10 +17313,10 @@ async function autoStartDaemonAndWait() {
|
|
|
17170
17313
|
|
|
17171
17314
|
// src/cli/commands/check.ts
|
|
17172
17315
|
var import_chalk9 = __toESM(require("chalk"));
|
|
17173
|
-
var
|
|
17316
|
+
var import_fs33 = __toESM(require("fs"));
|
|
17174
17317
|
var import_child_process7 = require("child_process");
|
|
17175
|
-
var
|
|
17176
|
-
var
|
|
17318
|
+
var import_path34 = __toESM(require("path"));
|
|
17319
|
+
var import_os29 = __toESM(require("os"));
|
|
17177
17320
|
init_orchestrator();
|
|
17178
17321
|
init_daemon();
|
|
17179
17322
|
init_config();
|
|
@@ -17181,12 +17324,12 @@ init_policy();
|
|
|
17181
17324
|
|
|
17182
17325
|
// src/undo.ts
|
|
17183
17326
|
var import_child_process6 = require("child_process");
|
|
17184
|
-
var
|
|
17185
|
-
var
|
|
17327
|
+
var import_crypto11 = __toESM(require("crypto"));
|
|
17328
|
+
var import_fs31 = __toESM(require("fs"));
|
|
17186
17329
|
var import_net3 = __toESM(require("net"));
|
|
17187
|
-
var
|
|
17188
|
-
var
|
|
17189
|
-
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
17330
|
+
var import_path32 = __toESM(require("path"));
|
|
17331
|
+
var import_os27 = __toESM(require("os"));
|
|
17332
|
+
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path32.default.join(import_os27.default.tmpdir(), "node9-activity.sock");
|
|
17190
17333
|
function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
17191
17334
|
try {
|
|
17192
17335
|
const payload = JSON.stringify({
|
|
@@ -17206,22 +17349,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
|
17206
17349
|
} catch {
|
|
17207
17350
|
}
|
|
17208
17351
|
}
|
|
17209
|
-
var SNAPSHOT_STACK_PATH =
|
|
17210
|
-
var UNDO_LATEST_PATH =
|
|
17352
|
+
var SNAPSHOT_STACK_PATH = import_path32.default.join(import_os27.default.homedir(), ".node9", "snapshots.json");
|
|
17353
|
+
var UNDO_LATEST_PATH = import_path32.default.join(import_os27.default.homedir(), ".node9", "undo_latest.txt");
|
|
17211
17354
|
var MAX_SNAPSHOTS = 10;
|
|
17212
17355
|
var GIT_TIMEOUT = 15e3;
|
|
17213
17356
|
function readStack() {
|
|
17214
17357
|
try {
|
|
17215
|
-
if (
|
|
17216
|
-
return JSON.parse(
|
|
17358
|
+
if (import_fs31.default.existsSync(SNAPSHOT_STACK_PATH))
|
|
17359
|
+
return JSON.parse(import_fs31.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
|
|
17217
17360
|
} catch {
|
|
17218
17361
|
}
|
|
17219
17362
|
return [];
|
|
17220
17363
|
}
|
|
17221
17364
|
function writeStack(stack) {
|
|
17222
|
-
const dir =
|
|
17223
|
-
if (!
|
|
17224
|
-
|
|
17365
|
+
const dir = import_path32.default.dirname(SNAPSHOT_STACK_PATH);
|
|
17366
|
+
if (!import_fs31.default.existsSync(dir)) import_fs31.default.mkdirSync(dir, { recursive: true });
|
|
17367
|
+
import_fs31.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
|
|
17225
17368
|
}
|
|
17226
17369
|
function extractFilePath(args) {
|
|
17227
17370
|
if (!args || typeof args !== "object") return null;
|
|
@@ -17241,12 +17384,12 @@ function buildArgsSummary(tool, args) {
|
|
|
17241
17384
|
return "";
|
|
17242
17385
|
}
|
|
17243
17386
|
function findProjectRoot(filePath) {
|
|
17244
|
-
let dir =
|
|
17387
|
+
let dir = import_path32.default.dirname(filePath);
|
|
17245
17388
|
while (true) {
|
|
17246
|
-
if (
|
|
17389
|
+
if (import_fs31.default.existsSync(import_path32.default.join(dir, ".git")) || import_fs31.default.existsSync(import_path32.default.join(dir, "package.json"))) {
|
|
17247
17390
|
return dir;
|
|
17248
17391
|
}
|
|
17249
|
-
const parent =
|
|
17392
|
+
const parent = import_path32.default.dirname(dir);
|
|
17250
17393
|
if (parent === dir) return process.cwd();
|
|
17251
17394
|
dir = parent;
|
|
17252
17395
|
}
|
|
@@ -17254,7 +17397,7 @@ function findProjectRoot(filePath) {
|
|
|
17254
17397
|
function normalizeCwdForHash(cwd) {
|
|
17255
17398
|
let normalized;
|
|
17256
17399
|
try {
|
|
17257
|
-
normalized =
|
|
17400
|
+
normalized = import_fs31.default.realpathSync(cwd);
|
|
17258
17401
|
} catch {
|
|
17259
17402
|
normalized = cwd;
|
|
17260
17403
|
}
|
|
@@ -17263,17 +17406,17 @@ function normalizeCwdForHash(cwd) {
|
|
|
17263
17406
|
return normalized;
|
|
17264
17407
|
}
|
|
17265
17408
|
function getShadowRepoDir(cwd) {
|
|
17266
|
-
const hash =
|
|
17267
|
-
return
|
|
17409
|
+
const hash = import_crypto11.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
|
|
17410
|
+
return import_path32.default.join(import_os27.default.homedir(), ".node9", "snapshots", hash);
|
|
17268
17411
|
}
|
|
17269
17412
|
function cleanOrphanedIndexFiles(shadowDir) {
|
|
17270
17413
|
try {
|
|
17271
17414
|
const cutoff = Date.now() - 6e4;
|
|
17272
|
-
for (const f of
|
|
17415
|
+
for (const f of import_fs31.default.readdirSync(shadowDir)) {
|
|
17273
17416
|
if (f.startsWith("index_")) {
|
|
17274
|
-
const fp =
|
|
17417
|
+
const fp = import_path32.default.join(shadowDir, f);
|
|
17275
17418
|
try {
|
|
17276
|
-
if (
|
|
17419
|
+
if (import_fs31.default.statSync(fp).mtimeMs < cutoff) import_fs31.default.unlinkSync(fp);
|
|
17277
17420
|
} catch {
|
|
17278
17421
|
}
|
|
17279
17422
|
}
|
|
@@ -17285,7 +17428,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
|
|
|
17285
17428
|
const hardcoded = [".git", ".node9"];
|
|
17286
17429
|
const lines = [...hardcoded, ...ignorePaths].join("\n");
|
|
17287
17430
|
try {
|
|
17288
|
-
|
|
17431
|
+
import_fs31.default.writeFileSync(import_path32.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
|
|
17289
17432
|
} catch {
|
|
17290
17433
|
}
|
|
17291
17434
|
}
|
|
@@ -17298,25 +17441,25 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
17298
17441
|
timeout: 3e3
|
|
17299
17442
|
});
|
|
17300
17443
|
if (check.status === 0) {
|
|
17301
|
-
const ptPath =
|
|
17444
|
+
const ptPath = import_path32.default.join(shadowDir, "project-path.txt");
|
|
17302
17445
|
try {
|
|
17303
|
-
const stored =
|
|
17446
|
+
const stored = import_fs31.default.readFileSync(ptPath, "utf8").trim();
|
|
17304
17447
|
if (stored === normalizedCwd) return true;
|
|
17305
17448
|
if (process.env.NODE9_DEBUG === "1")
|
|
17306
17449
|
console.error(
|
|
17307
17450
|
`[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
|
|
17308
17451
|
);
|
|
17309
|
-
|
|
17452
|
+
import_fs31.default.rmSync(shadowDir, { recursive: true, force: true });
|
|
17310
17453
|
} catch {
|
|
17311
17454
|
try {
|
|
17312
|
-
|
|
17455
|
+
import_fs31.default.writeFileSync(ptPath, normalizedCwd, "utf8");
|
|
17313
17456
|
} catch {
|
|
17314
17457
|
}
|
|
17315
17458
|
return true;
|
|
17316
17459
|
}
|
|
17317
17460
|
}
|
|
17318
17461
|
try {
|
|
17319
|
-
|
|
17462
|
+
import_fs31.default.mkdirSync(shadowDir, { recursive: true });
|
|
17320
17463
|
} catch {
|
|
17321
17464
|
}
|
|
17322
17465
|
const init = (0, import_child_process6.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
|
|
@@ -17325,7 +17468,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
17325
17468
|
if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
|
|
17326
17469
|
return false;
|
|
17327
17470
|
}
|
|
17328
|
-
const configFile =
|
|
17471
|
+
const configFile = import_path32.default.join(shadowDir, "config");
|
|
17329
17472
|
(0, import_child_process6.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
|
|
17330
17473
|
timeout: 3e3
|
|
17331
17474
|
});
|
|
@@ -17333,7 +17476,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
17333
17476
|
timeout: 3e3
|
|
17334
17477
|
});
|
|
17335
17478
|
try {
|
|
17336
|
-
|
|
17479
|
+
import_fs31.default.writeFileSync(import_path32.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
|
|
17337
17480
|
} catch {
|
|
17338
17481
|
}
|
|
17339
17482
|
return true;
|
|
@@ -17356,12 +17499,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
17356
17499
|
let indexFile = null;
|
|
17357
17500
|
try {
|
|
17358
17501
|
const rawFilePath = extractFilePath(args);
|
|
17359
|
-
const absFilePath = rawFilePath &&
|
|
17502
|
+
const absFilePath = rawFilePath && import_path32.default.isAbsolute(rawFilePath) ? rawFilePath : null;
|
|
17360
17503
|
const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
|
|
17361
17504
|
const shadowDir = getShadowRepoDir(cwd);
|
|
17362
17505
|
if (!ensureShadowRepo(shadowDir, cwd)) return null;
|
|
17363
17506
|
writeShadowExcludes(shadowDir, ignorePaths);
|
|
17364
|
-
indexFile =
|
|
17507
|
+
indexFile = import_path32.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
|
|
17365
17508
|
const shadowEnv = {
|
|
17366
17509
|
...process.env,
|
|
17367
17510
|
GIT_DIR: shadowDir,
|
|
@@ -17433,7 +17576,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
17433
17576
|
writeStack(stack);
|
|
17434
17577
|
const entry = stack[stack.length - 1];
|
|
17435
17578
|
notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
|
|
17436
|
-
|
|
17579
|
+
import_fs31.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
|
|
17437
17580
|
if (shouldGc) {
|
|
17438
17581
|
(0, import_child_process6.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
|
|
17439
17582
|
}
|
|
@@ -17444,7 +17587,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
17444
17587
|
} finally {
|
|
17445
17588
|
if (indexFile) {
|
|
17446
17589
|
try {
|
|
17447
|
-
|
|
17590
|
+
import_fs31.default.unlinkSync(indexFile);
|
|
17448
17591
|
} catch {
|
|
17449
17592
|
}
|
|
17450
17593
|
}
|
|
@@ -17520,9 +17663,9 @@ function applyUndo(hash, cwd) {
|
|
|
17520
17663
|
timeout: GIT_TIMEOUT
|
|
17521
17664
|
}).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
|
|
17522
17665
|
for (const file of [...tracked, ...untracked]) {
|
|
17523
|
-
const fullPath =
|
|
17524
|
-
if (!snapshotFiles.has(file) &&
|
|
17525
|
-
|
|
17666
|
+
const fullPath = import_path32.default.join(dir, file);
|
|
17667
|
+
if (!snapshotFiles.has(file) && import_fs31.default.existsSync(fullPath)) {
|
|
17668
|
+
import_fs31.default.unlinkSync(fullPath);
|
|
17526
17669
|
}
|
|
17527
17670
|
}
|
|
17528
17671
|
return true;
|
|
@@ -17532,17 +17675,17 @@ function applyUndo(hash, cwd) {
|
|
|
17532
17675
|
}
|
|
17533
17676
|
|
|
17534
17677
|
// src/skill-pin.ts
|
|
17535
|
-
var
|
|
17536
|
-
var
|
|
17537
|
-
var
|
|
17538
|
-
var
|
|
17678
|
+
var import_fs32 = __toESM(require("fs"));
|
|
17679
|
+
var import_path33 = __toESM(require("path"));
|
|
17680
|
+
var import_os28 = __toESM(require("os"));
|
|
17681
|
+
var import_crypto12 = __toESM(require("crypto"));
|
|
17539
17682
|
function getPinsFilePath2() {
|
|
17540
|
-
return
|
|
17683
|
+
return import_path33.default.join(import_os28.default.homedir(), ".node9", "skill-pins.json");
|
|
17541
17684
|
}
|
|
17542
17685
|
var MAX_FILES = 5e3;
|
|
17543
17686
|
var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
17544
17687
|
function sha256Bytes(buf) {
|
|
17545
|
-
return
|
|
17688
|
+
return import_crypto12.default.createHash("sha256").update(buf).digest("hex");
|
|
17546
17689
|
}
|
|
17547
17690
|
function walkDir(root) {
|
|
17548
17691
|
const out = [];
|
|
@@ -17551,18 +17694,18 @@ function walkDir(root) {
|
|
|
17551
17694
|
if (out.length >= MAX_FILES) return;
|
|
17552
17695
|
let entries;
|
|
17553
17696
|
try {
|
|
17554
|
-
entries =
|
|
17697
|
+
entries = import_fs32.default.readdirSync(dir, { withFileTypes: true });
|
|
17555
17698
|
} catch {
|
|
17556
17699
|
return;
|
|
17557
17700
|
}
|
|
17558
17701
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
17559
17702
|
for (const entry of entries) {
|
|
17560
17703
|
if (out.length >= MAX_FILES) return;
|
|
17561
|
-
const full =
|
|
17562
|
-
const rel = relDir ?
|
|
17704
|
+
const full = import_path33.default.join(dir, entry.name);
|
|
17705
|
+
const rel = relDir ? import_path33.default.posix.join(relDir, entry.name) : entry.name;
|
|
17563
17706
|
let lst;
|
|
17564
17707
|
try {
|
|
17565
|
-
lst =
|
|
17708
|
+
lst = import_fs32.default.lstatSync(full);
|
|
17566
17709
|
} catch {
|
|
17567
17710
|
continue;
|
|
17568
17711
|
}
|
|
@@ -17574,7 +17717,7 @@ function walkDir(root) {
|
|
|
17574
17717
|
if (!lst.isFile()) continue;
|
|
17575
17718
|
if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
|
|
17576
17719
|
try {
|
|
17577
|
-
const buf =
|
|
17720
|
+
const buf = import_fs32.default.readFileSync(full);
|
|
17578
17721
|
totalBytes += buf.length;
|
|
17579
17722
|
out.push({ rel, hash: sha256Bytes(buf) });
|
|
17580
17723
|
} catch {
|
|
@@ -17588,32 +17731,32 @@ function walkDir(root) {
|
|
|
17588
17731
|
function hashSkillRoot(absPath) {
|
|
17589
17732
|
let lst;
|
|
17590
17733
|
try {
|
|
17591
|
-
lst =
|
|
17734
|
+
lst = import_fs32.default.lstatSync(absPath);
|
|
17592
17735
|
} catch {
|
|
17593
17736
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
17594
17737
|
}
|
|
17595
17738
|
if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
|
|
17596
17739
|
if (lst.isFile()) {
|
|
17597
17740
|
try {
|
|
17598
|
-
return { exists: true, contentHash: sha256Bytes(
|
|
17741
|
+
return { exists: true, contentHash: sha256Bytes(import_fs32.default.readFileSync(absPath)), fileCount: 1 };
|
|
17599
17742
|
} catch {
|
|
17600
17743
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
17601
17744
|
}
|
|
17602
17745
|
}
|
|
17603
17746
|
if (lst.isDirectory()) {
|
|
17604
17747
|
const entries = walkDir(absPath);
|
|
17605
|
-
const contentHash =
|
|
17748
|
+
const contentHash = import_crypto12.default.createHash("sha256").update(entries.join("\n")).digest("hex");
|
|
17606
17749
|
return { exists: true, contentHash, fileCount: entries.length };
|
|
17607
17750
|
}
|
|
17608
17751
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
17609
17752
|
}
|
|
17610
17753
|
function getRootKey(absPath) {
|
|
17611
|
-
return
|
|
17754
|
+
return import_crypto12.default.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
|
|
17612
17755
|
}
|
|
17613
17756
|
function readSkillPinsSafe() {
|
|
17614
17757
|
const filePath = getPinsFilePath2();
|
|
17615
17758
|
try {
|
|
17616
|
-
const raw =
|
|
17759
|
+
const raw = import_fs32.default.readFileSync(filePath, "utf-8");
|
|
17617
17760
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
17618
17761
|
const parsed = JSON.parse(raw);
|
|
17619
17762
|
if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
|
|
@@ -17633,10 +17776,10 @@ function readSkillPins() {
|
|
|
17633
17776
|
}
|
|
17634
17777
|
function writeSkillPins(data) {
|
|
17635
17778
|
const filePath = getPinsFilePath2();
|
|
17636
|
-
|
|
17637
|
-
const tmp = `${filePath}.${
|
|
17638
|
-
|
|
17639
|
-
|
|
17779
|
+
import_fs32.default.mkdirSync(import_path33.default.dirname(filePath), { recursive: true });
|
|
17780
|
+
const tmp = `${filePath}.${import_crypto12.default.randomBytes(6).toString("hex")}.tmp`;
|
|
17781
|
+
import_fs32.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
17782
|
+
import_fs32.default.renameSync(tmp, filePath);
|
|
17640
17783
|
}
|
|
17641
17784
|
function removePin2(rootKey) {
|
|
17642
17785
|
const pins = readSkillPins();
|
|
@@ -17680,36 +17823,36 @@ function verifyAndPinRoots(roots) {
|
|
|
17680
17823
|
return { kind: "verified" };
|
|
17681
17824
|
}
|
|
17682
17825
|
function defaultSkillRoots(_cwd) {
|
|
17683
|
-
const marketplaces =
|
|
17826
|
+
const marketplaces = import_path33.default.join(import_os28.default.homedir(), ".claude", "plugins", "marketplaces");
|
|
17684
17827
|
const roots = [];
|
|
17685
17828
|
let registries;
|
|
17686
17829
|
try {
|
|
17687
|
-
registries =
|
|
17830
|
+
registries = import_fs32.default.readdirSync(marketplaces, { withFileTypes: true });
|
|
17688
17831
|
} catch {
|
|
17689
17832
|
return [];
|
|
17690
17833
|
}
|
|
17691
17834
|
for (const registry of registries) {
|
|
17692
17835
|
if (!registry.isDirectory()) continue;
|
|
17693
|
-
const pluginsDir =
|
|
17836
|
+
const pluginsDir = import_path33.default.join(marketplaces, registry.name, "plugins");
|
|
17694
17837
|
let plugins;
|
|
17695
17838
|
try {
|
|
17696
|
-
plugins =
|
|
17839
|
+
plugins = import_fs32.default.readdirSync(pluginsDir, { withFileTypes: true });
|
|
17697
17840
|
} catch {
|
|
17698
17841
|
continue;
|
|
17699
17842
|
}
|
|
17700
17843
|
for (const plugin of plugins) {
|
|
17701
17844
|
if (!plugin.isDirectory()) continue;
|
|
17702
|
-
roots.push(
|
|
17845
|
+
roots.push(import_path33.default.join(pluginsDir, plugin.name));
|
|
17703
17846
|
}
|
|
17704
17847
|
}
|
|
17705
17848
|
return roots;
|
|
17706
17849
|
}
|
|
17707
17850
|
function resolveUserSkillRoot(entry, cwd) {
|
|
17708
17851
|
if (!entry) return null;
|
|
17709
|
-
if (entry.startsWith("~/") || entry === "~") return
|
|
17710
|
-
if (
|
|
17711
|
-
if (!cwd || !
|
|
17712
|
-
return
|
|
17852
|
+
if (entry.startsWith("~/") || entry === "~") return import_path33.default.join(import_os28.default.homedir(), entry.slice(1));
|
|
17853
|
+
if (import_path33.default.isAbsolute(entry)) return entry;
|
|
17854
|
+
if (!cwd || !import_path33.default.isAbsolute(cwd)) return null;
|
|
17855
|
+
return import_path33.default.join(cwd, entry);
|
|
17713
17856
|
}
|
|
17714
17857
|
|
|
17715
17858
|
// src/cli/commands/check.ts
|
|
@@ -17778,9 +17921,9 @@ function registerCheckCommand(program2) {
|
|
|
17778
17921
|
} catch (err2) {
|
|
17779
17922
|
const tempConfig = getConfig();
|
|
17780
17923
|
if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
|
|
17781
|
-
const logPath =
|
|
17924
|
+
const logPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "hook-debug.log");
|
|
17782
17925
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
17783
|
-
|
|
17926
|
+
import_fs33.default.appendFileSync(
|
|
17784
17927
|
logPath,
|
|
17785
17928
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
|
|
17786
17929
|
RAW: ${raw}
|
|
@@ -17793,14 +17936,14 @@ RAW: ${raw}
|
|
|
17793
17936
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
17794
17937
|
if (process.env.NODE9_DEBUG === "1") {
|
|
17795
17938
|
try {
|
|
17796
|
-
const logPath =
|
|
17797
|
-
if (!
|
|
17798
|
-
|
|
17939
|
+
const logPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "hook-debug.log");
|
|
17940
|
+
if (!import_fs33.default.existsSync(import_path34.default.dirname(logPath)))
|
|
17941
|
+
import_fs33.default.mkdirSync(import_path34.default.dirname(logPath), { recursive: true });
|
|
17799
17942
|
const sanitized = JSON.stringify({
|
|
17800
17943
|
...payload,
|
|
17801
17944
|
prompt: `<redacted, ${prompt.length} bytes>`
|
|
17802
17945
|
});
|
|
17803
|
-
|
|
17946
|
+
import_fs33.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
|
|
17804
17947
|
`);
|
|
17805
17948
|
} catch {
|
|
17806
17949
|
}
|
|
@@ -17820,8 +17963,8 @@ RAW: ${raw}
|
|
|
17820
17963
|
);
|
|
17821
17964
|
const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
|
|
17822
17965
|
try {
|
|
17823
|
-
const ttyFd =
|
|
17824
|
-
|
|
17966
|
+
const ttyFd = import_fs33.default.openSync("/dev/tty", "w");
|
|
17967
|
+
import_fs33.default.writeSync(
|
|
17825
17968
|
ttyFd,
|
|
17826
17969
|
import_chalk9.default.bgRed.white.bold(`
|
|
17827
17970
|
\u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
|
|
@@ -17831,7 +17974,7 @@ RAW: ${raw}
|
|
|
17831
17974
|
|
|
17832
17975
|
`)
|
|
17833
17976
|
);
|
|
17834
|
-
|
|
17977
|
+
import_fs33.default.closeSync(ttyFd);
|
|
17835
17978
|
} catch {
|
|
17836
17979
|
}
|
|
17837
17980
|
const isCodex = agent2 === "Codex";
|
|
@@ -17850,16 +17993,16 @@ RAW: ${raw}
|
|
|
17850
17993
|
process.exit(2);
|
|
17851
17994
|
}
|
|
17852
17995
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
17853
|
-
const safeCwdForConfig = typeof payloadCwd === "string" &&
|
|
17996
|
+
const safeCwdForConfig = typeof payloadCwd === "string" && import_path34.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
17854
17997
|
const config = getConfig(safeCwdForConfig);
|
|
17855
17998
|
if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
|
|
17856
17999
|
try {
|
|
17857
18000
|
const scriptPath = process.argv[1];
|
|
17858
|
-
if (typeof scriptPath !== "string" || !
|
|
18001
|
+
if (typeof scriptPath !== "string" || !import_path34.default.isAbsolute(scriptPath))
|
|
17859
18002
|
throw new Error("node9: argv[1] is not an absolute path");
|
|
17860
|
-
const resolvedScript =
|
|
17861
|
-
const packageDist =
|
|
17862
|
-
if (!resolvedScript.startsWith(packageDist +
|
|
18003
|
+
const resolvedScript = import_fs33.default.realpathSync(scriptPath);
|
|
18004
|
+
const packageDist = import_fs33.default.realpathSync(import_path34.default.resolve(__dirname, "../.."));
|
|
18005
|
+
if (!resolvedScript.startsWith(packageDist + import_path34.default.sep) && resolvedScript !== packageDist)
|
|
17863
18006
|
throw new Error(
|
|
17864
18007
|
`node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
|
|
17865
18008
|
);
|
|
@@ -17881,10 +18024,10 @@ RAW: ${raw}
|
|
|
17881
18024
|
});
|
|
17882
18025
|
d.unref();
|
|
17883
18026
|
} catch (spawnErr) {
|
|
17884
|
-
const logPath =
|
|
18027
|
+
const logPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "hook-debug.log");
|
|
17885
18028
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
17886
18029
|
try {
|
|
17887
|
-
|
|
18030
|
+
import_fs33.default.appendFileSync(
|
|
17888
18031
|
logPath,
|
|
17889
18032
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
|
|
17890
18033
|
`
|
|
@@ -17894,10 +18037,10 @@ RAW: ${raw}
|
|
|
17894
18037
|
}
|
|
17895
18038
|
}
|
|
17896
18039
|
if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
|
|
17897
|
-
const logPath =
|
|
17898
|
-
if (!
|
|
17899
|
-
|
|
17900
|
-
|
|
18040
|
+
const logPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "hook-debug.log");
|
|
18041
|
+
if (!import_fs33.default.existsSync(import_path34.default.dirname(logPath)))
|
|
18042
|
+
import_fs33.default.mkdirSync(import_path34.default.dirname(logPath), { recursive: true });
|
|
18043
|
+
import_fs33.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
|
|
17901
18044
|
`);
|
|
17902
18045
|
}
|
|
17903
18046
|
const rawToolName = sanitize2(extractToolName(payload));
|
|
@@ -17911,8 +18054,8 @@ RAW: ${raw}
|
|
|
17911
18054
|
const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
|
|
17912
18055
|
let ttyFd = null;
|
|
17913
18056
|
try {
|
|
17914
|
-
ttyFd =
|
|
17915
|
-
const writeTty = (line) =>
|
|
18057
|
+
ttyFd = import_fs33.default.openSync("/dev/tty", "w");
|
|
18058
|
+
const writeTty = (line) => import_fs33.default.writeSync(ttyFd, line + "\n");
|
|
17916
18059
|
if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
|
|
17917
18060
|
writeTty(import_chalk9.default.bgRed.white.bold(`
|
|
17918
18061
|
\u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
|
|
@@ -17931,7 +18074,7 @@ RAW: ${raw}
|
|
|
17931
18074
|
} finally {
|
|
17932
18075
|
if (ttyFd !== null)
|
|
17933
18076
|
try {
|
|
17934
|
-
|
|
18077
|
+
import_fs33.default.closeSync(ttyFd);
|
|
17935
18078
|
} catch {
|
|
17936
18079
|
}
|
|
17937
18080
|
}
|
|
@@ -17982,17 +18125,17 @@ RAW: ${raw}
|
|
|
17982
18125
|
const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
|
|
17983
18126
|
if (skillPinCfg.enabled && safeSessionId) {
|
|
17984
18127
|
try {
|
|
17985
|
-
const sessionsDir =
|
|
17986
|
-
const flagPath =
|
|
18128
|
+
const sessionsDir = import_path34.default.join(import_os29.default.homedir(), ".node9", "skill-sessions");
|
|
18129
|
+
const flagPath = import_path34.default.join(sessionsDir, `${safeSessionId}.json`);
|
|
17987
18130
|
let flag = null;
|
|
17988
18131
|
try {
|
|
17989
|
-
flag = JSON.parse(
|
|
18132
|
+
flag = JSON.parse(import_fs33.default.readFileSync(flagPath, "utf-8"));
|
|
17990
18133
|
} catch {
|
|
17991
18134
|
}
|
|
17992
18135
|
const writeFlag = (data2) => {
|
|
17993
18136
|
try {
|
|
17994
|
-
|
|
17995
|
-
|
|
18137
|
+
import_fs33.default.mkdirSync(sessionsDir, { recursive: true });
|
|
18138
|
+
import_fs33.default.writeFileSync(
|
|
17996
18139
|
flagPath,
|
|
17997
18140
|
JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
17998
18141
|
{ mode: 384 }
|
|
@@ -18003,8 +18146,8 @@ RAW: ${raw}
|
|
|
18003
18146
|
const sendSkillWarn = (detail, recoveryCmd) => {
|
|
18004
18147
|
let ttyFd = null;
|
|
18005
18148
|
try {
|
|
18006
|
-
ttyFd =
|
|
18007
|
-
const w = (line) =>
|
|
18149
|
+
ttyFd = import_fs33.default.openSync("/dev/tty", "w");
|
|
18150
|
+
const w = (line) => import_fs33.default.writeSync(ttyFd, line + "\n");
|
|
18008
18151
|
w(import_chalk9.default.yellow(`
|
|
18009
18152
|
\u26A0\uFE0F Node9: installed skill drift detected`));
|
|
18010
18153
|
w(import_chalk9.default.gray(` ${detail}`));
|
|
@@ -18019,7 +18162,7 @@ RAW: ${raw}
|
|
|
18019
18162
|
} finally {
|
|
18020
18163
|
if (ttyFd !== null)
|
|
18021
18164
|
try {
|
|
18022
|
-
|
|
18165
|
+
import_fs33.default.closeSync(ttyFd);
|
|
18023
18166
|
} catch {
|
|
18024
18167
|
}
|
|
18025
18168
|
}
|
|
@@ -18035,7 +18178,7 @@ RAW: ${raw}
|
|
|
18035
18178
|
return;
|
|
18036
18179
|
}
|
|
18037
18180
|
if (!flag || flag.state !== "verified" && flag.state !== "warned") {
|
|
18038
|
-
const absoluteCwd = typeof payloadCwd === "string" &&
|
|
18181
|
+
const absoluteCwd = typeof payloadCwd === "string" && import_path34.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
18039
18182
|
const extraRoots = skillPinCfg.roots;
|
|
18040
18183
|
const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
|
|
18041
18184
|
const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
|
|
@@ -18076,10 +18219,10 @@ RAW: ${raw}
|
|
|
18076
18219
|
}
|
|
18077
18220
|
try {
|
|
18078
18221
|
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
18079
|
-
for (const name of
|
|
18080
|
-
const p =
|
|
18222
|
+
for (const name of import_fs33.default.readdirSync(sessionsDir)) {
|
|
18223
|
+
const p = import_path34.default.join(sessionsDir, name);
|
|
18081
18224
|
try {
|
|
18082
|
-
if (
|
|
18225
|
+
if (import_fs33.default.statSync(p).mtimeMs < cutoff) import_fs33.default.unlinkSync(p);
|
|
18083
18226
|
} catch {
|
|
18084
18227
|
}
|
|
18085
18228
|
}
|
|
@@ -18089,9 +18232,9 @@ RAW: ${raw}
|
|
|
18089
18232
|
} catch (err2) {
|
|
18090
18233
|
if (process.env.NODE9_DEBUG === "1") {
|
|
18091
18234
|
try {
|
|
18092
|
-
const dbg =
|
|
18235
|
+
const dbg = import_path34.default.join(import_os29.default.homedir(), ".node9", "hook-debug.log");
|
|
18093
18236
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
18094
|
-
|
|
18237
|
+
import_fs33.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
|
|
18095
18238
|
`);
|
|
18096
18239
|
} catch {
|
|
18097
18240
|
}
|
|
@@ -18101,7 +18244,7 @@ RAW: ${raw}
|
|
|
18101
18244
|
if (shouldSnapshot(toolName, toolInput, config)) {
|
|
18102
18245
|
await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
|
|
18103
18246
|
}
|
|
18104
|
-
const safeCwdForAuth = typeof payloadCwd === "string" &&
|
|
18247
|
+
const safeCwdForAuth = typeof payloadCwd === "string" && import_path34.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
18105
18248
|
const result = await authorizeHeadless(toolName, toolInput, meta, {
|
|
18106
18249
|
cwd: safeCwdForAuth
|
|
18107
18250
|
});
|
|
@@ -18113,12 +18256,12 @@ RAW: ${raw}
|
|
|
18113
18256
|
}
|
|
18114
18257
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
|
|
18115
18258
|
try {
|
|
18116
|
-
const tty =
|
|
18117
|
-
|
|
18259
|
+
const tty = import_fs33.default.openSync("/dev/tty", "w");
|
|
18260
|
+
import_fs33.default.writeSync(
|
|
18118
18261
|
tty,
|
|
18119
18262
|
import_chalk9.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
|
|
18120
18263
|
);
|
|
18121
|
-
|
|
18264
|
+
import_fs33.default.closeSync(tty);
|
|
18122
18265
|
} catch {
|
|
18123
18266
|
}
|
|
18124
18267
|
const daemonReady = await autoStartDaemonAndWait();
|
|
@@ -18145,9 +18288,9 @@ RAW: ${raw}
|
|
|
18145
18288
|
});
|
|
18146
18289
|
} catch (err2) {
|
|
18147
18290
|
if (process.env.NODE9_DEBUG === "1") {
|
|
18148
|
-
const logPath =
|
|
18291
|
+
const logPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "hook-debug.log");
|
|
18149
18292
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
18150
|
-
|
|
18293
|
+
import_fs33.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
|
|
18151
18294
|
`);
|
|
18152
18295
|
}
|
|
18153
18296
|
process.exit(0);
|
|
@@ -18181,9 +18324,9 @@ RAW: ${raw}
|
|
|
18181
18324
|
}
|
|
18182
18325
|
|
|
18183
18326
|
// src/cli/commands/log.ts
|
|
18184
|
-
var
|
|
18185
|
-
var
|
|
18186
|
-
var
|
|
18327
|
+
var import_fs34 = __toESM(require("fs"));
|
|
18328
|
+
var import_path35 = __toESM(require("path"));
|
|
18329
|
+
var import_os30 = __toESM(require("os"));
|
|
18187
18330
|
init_audit();
|
|
18188
18331
|
init_config();
|
|
18189
18332
|
init_daemon();
|
|
@@ -18278,10 +18421,10 @@ function registerLogCommand(program2) {
|
|
|
18278
18421
|
if (rawToolName !== tool) entry.agentToolName = rawToolName;
|
|
18279
18422
|
const payloadSessionId = payload.session_id ?? payload.conversationId;
|
|
18280
18423
|
if (payloadSessionId) entry.sessionId = payloadSessionId;
|
|
18281
|
-
const logPath =
|
|
18282
|
-
if (!
|
|
18283
|
-
|
|
18284
|
-
|
|
18424
|
+
const logPath = import_path35.default.join(import_os30.default.homedir(), ".node9", "audit.log");
|
|
18425
|
+
if (!import_fs34.default.existsSync(import_path35.default.dirname(logPath)))
|
|
18426
|
+
import_fs34.default.mkdirSync(import_path35.default.dirname(logPath), { recursive: true });
|
|
18427
|
+
import_fs34.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
18285
18428
|
if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
|
|
18286
18429
|
const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
18287
18430
|
if (command) {
|
|
@@ -18315,7 +18458,7 @@ function registerLogCommand(program2) {
|
|
|
18315
18458
|
}
|
|
18316
18459
|
}
|
|
18317
18460
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
18318
|
-
const safeCwd = typeof payloadCwd === "string" &&
|
|
18461
|
+
const safeCwd = typeof payloadCwd === "string" && import_path35.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
18319
18462
|
const config = getConfig(safeCwd);
|
|
18320
18463
|
if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
|
|
18321
18464
|
const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
@@ -18336,9 +18479,9 @@ function registerLogCommand(program2) {
|
|
|
18336
18479
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
18337
18480
|
process.stderr.write(`[Node9] audit log error: ${msg}
|
|
18338
18481
|
`);
|
|
18339
|
-
const debugPath =
|
|
18482
|
+
const debugPath = import_path35.default.join(import_os30.default.homedir(), ".node9", "hook-debug.log");
|
|
18340
18483
|
try {
|
|
18341
|
-
|
|
18484
|
+
import_fs34.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
|
|
18342
18485
|
`);
|
|
18343
18486
|
} catch {
|
|
18344
18487
|
}
|
|
@@ -18738,14 +18881,15 @@ function registerConfigShowCommand(program2) {
|
|
|
18738
18881
|
|
|
18739
18882
|
// src/cli/commands/doctor.ts
|
|
18740
18883
|
var import_chalk11 = __toESM(require("chalk"));
|
|
18741
|
-
var
|
|
18742
|
-
var
|
|
18743
|
-
var
|
|
18884
|
+
var import_fs35 = __toESM(require("fs"));
|
|
18885
|
+
var import_path36 = __toESM(require("path"));
|
|
18886
|
+
var import_os31 = __toESM(require("os"));
|
|
18744
18887
|
var import_child_process8 = require("child_process");
|
|
18745
18888
|
init_daemon();
|
|
18889
|
+
init_config();
|
|
18746
18890
|
function registerDoctorCommand(program2, version2) {
|
|
18747
|
-
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(() => {
|
|
18748
|
-
const homeDir2 =
|
|
18891
|
+
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
|
|
18892
|
+
const homeDir2 = import_os31.default.homedir();
|
|
18749
18893
|
let failures = 0;
|
|
18750
18894
|
function pass(msg) {
|
|
18751
18895
|
console.log(import_chalk11.default.green(" \u2705 ") + msg);
|
|
@@ -18794,10 +18938,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
18794
18938
|
);
|
|
18795
18939
|
}
|
|
18796
18940
|
section("Configuration");
|
|
18797
|
-
const globalConfigPath =
|
|
18798
|
-
if (
|
|
18941
|
+
const globalConfigPath = import_path36.default.join(homeDir2, ".node9", "config.json");
|
|
18942
|
+
if (import_fs35.default.existsSync(globalConfigPath)) {
|
|
18799
18943
|
try {
|
|
18800
|
-
JSON.parse(
|
|
18944
|
+
JSON.parse(import_fs35.default.readFileSync(globalConfigPath, "utf-8"));
|
|
18801
18945
|
pass("~/.node9/config.json found and valid");
|
|
18802
18946
|
} catch {
|
|
18803
18947
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -18805,10 +18949,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
18805
18949
|
} else {
|
|
18806
18950
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
18807
18951
|
}
|
|
18808
|
-
const projectConfigPath =
|
|
18809
|
-
if (
|
|
18952
|
+
const projectConfigPath = import_path36.default.join(process.cwd(), "node9.config.json");
|
|
18953
|
+
if (import_fs35.default.existsSync(projectConfigPath)) {
|
|
18810
18954
|
try {
|
|
18811
|
-
JSON.parse(
|
|
18955
|
+
JSON.parse(import_fs35.default.readFileSync(projectConfigPath, "utf-8"));
|
|
18812
18956
|
pass("node9.config.json found and valid (project)");
|
|
18813
18957
|
} catch {
|
|
18814
18958
|
fail(
|
|
@@ -18817,8 +18961,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
18817
18961
|
);
|
|
18818
18962
|
}
|
|
18819
18963
|
}
|
|
18820
|
-
const credsPath =
|
|
18821
|
-
if (
|
|
18964
|
+
const credsPath = import_path36.default.join(homeDir2, ".node9", "credentials.json");
|
|
18965
|
+
if (import_fs35.default.existsSync(credsPath)) {
|
|
18822
18966
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
18823
18967
|
} else {
|
|
18824
18968
|
warn(
|
|
@@ -18827,10 +18971,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
18827
18971
|
);
|
|
18828
18972
|
}
|
|
18829
18973
|
section("Agent Hooks");
|
|
18830
|
-
const claudeSettingsPath =
|
|
18831
|
-
if (
|
|
18974
|
+
const claudeSettingsPath = import_path36.default.join(homeDir2, ".claude", "settings.json");
|
|
18975
|
+
if (import_fs35.default.existsSync(claudeSettingsPath)) {
|
|
18832
18976
|
try {
|
|
18833
|
-
const cs = JSON.parse(
|
|
18977
|
+
const cs = JSON.parse(import_fs35.default.readFileSync(claudeSettingsPath, "utf-8"));
|
|
18834
18978
|
const hasHook = cs.hooks?.PreToolUse?.some(
|
|
18835
18979
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
18836
18980
|
);
|
|
@@ -18846,10 +18990,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
18846
18990
|
} else {
|
|
18847
18991
|
warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
|
|
18848
18992
|
}
|
|
18849
|
-
const geminiSettingsPath =
|
|
18850
|
-
if (
|
|
18993
|
+
const geminiSettingsPath = import_path36.default.join(homeDir2, ".gemini", "settings.json");
|
|
18994
|
+
if (import_fs35.default.existsSync(geminiSettingsPath)) {
|
|
18851
18995
|
try {
|
|
18852
|
-
const gs = JSON.parse(
|
|
18996
|
+
const gs = JSON.parse(import_fs35.default.readFileSync(geminiSettingsPath, "utf-8"));
|
|
18853
18997
|
const hasHook = gs.hooks?.BeforeTool?.some(
|
|
18854
18998
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
18855
18999
|
);
|
|
@@ -18865,10 +19009,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
18865
19009
|
} else {
|
|
18866
19010
|
warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
|
|
18867
19011
|
}
|
|
18868
|
-
const cursorHooksPath =
|
|
18869
|
-
if (
|
|
19012
|
+
const cursorHooksPath = import_path36.default.join(homeDir2, ".cursor", "hooks.json");
|
|
19013
|
+
if (import_fs35.default.existsSync(cursorHooksPath)) {
|
|
18870
19014
|
try {
|
|
18871
|
-
const cur = JSON.parse(
|
|
19015
|
+
const cur = JSON.parse(import_fs35.default.readFileSync(cursorHooksPath, "utf-8"));
|
|
18872
19016
|
const hasHook = cur.hooks?.preToolUse?.some(
|
|
18873
19017
|
(h) => h.command?.includes("node9") || h.command?.includes("cli.js")
|
|
18874
19018
|
);
|
|
@@ -18895,6 +19039,47 @@ function registerDoctorCommand(program2, version2) {
|
|
|
18895
19039
|
"Run: node9 daemon --background"
|
|
18896
19040
|
);
|
|
18897
19041
|
}
|
|
19042
|
+
section("Cloud audit shipping");
|
|
19043
|
+
try {
|
|
19044
|
+
const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
|
|
19045
|
+
const cfg = getConfig();
|
|
19046
|
+
const creds = import_fs35.default.existsSync(import_path36.default.join(import_os31.default.homedir(), ".node9", "credentials.json"));
|
|
19047
|
+
if (!creds) {
|
|
19048
|
+
warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
|
|
19049
|
+
} else if (!cfg.settings.approvers.cloud) {
|
|
19050
|
+
warn(
|
|
19051
|
+
"Cloud approvals OFF (settings.approvers.cloud=false) \u2014 nothing syncs to the dashboard",
|
|
19052
|
+
"Privacy mode is a valid choice; set approvers.cloud=true to sync."
|
|
19053
|
+
);
|
|
19054
|
+
} else if (cfg.settings.shipper.enabled === false) {
|
|
19055
|
+
warn("Shipper disabled (settings.shipper.enabled=false) \u2014 audit rows stay local");
|
|
19056
|
+
} else {
|
|
19057
|
+
const lag = shipLagBytes2();
|
|
19058
|
+
const wm = readWatermark2(AUDIT_SHIP_WATERMARK2);
|
|
19059
|
+
if (lag === 0) {
|
|
19060
|
+
pass("Audit shipping caught up \u2014 dashboard matches the local log");
|
|
19061
|
+
} else if (wm && lag !== null) {
|
|
19062
|
+
const ageMin = Math.round((Date.now() - new Date(wm.updatedAt).getTime()) / 6e4);
|
|
19063
|
+
if (ageMin > 5 && !isDaemonRunning()) {
|
|
19064
|
+
warn(
|
|
19065
|
+
`${Math.round(lag / 1024)} KB of audit rows not shipped (last ship ${ageMin}m ago)`,
|
|
19066
|
+
"The daemon ships every ~20s \u2014 start it: node9 daemon --background"
|
|
19067
|
+
);
|
|
19068
|
+
} else {
|
|
19069
|
+
pass(
|
|
19070
|
+
`Shipping in progress \u2014 ${Math.round(lag / 1024)} KB queued, last ship ${ageMin}m ago`
|
|
19071
|
+
);
|
|
19072
|
+
}
|
|
19073
|
+
} else {
|
|
19074
|
+
warn(
|
|
19075
|
+
"Shipper has never run on this machine \u2014 dashboard may lag the local log",
|
|
19076
|
+
"Start the daemon: node9 daemon --background"
|
|
19077
|
+
);
|
|
19078
|
+
}
|
|
19079
|
+
}
|
|
19080
|
+
} catch (err2) {
|
|
19081
|
+
warn(`Shipping status unavailable: ${err2.message}`);
|
|
19082
|
+
}
|
|
18898
19083
|
console.log("");
|
|
18899
19084
|
if (failures === 0) {
|
|
18900
19085
|
console.log(import_chalk11.default.green.bold(" All checks passed. Node9 is ready.\n"));
|
|
@@ -18908,9 +19093,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
18908
19093
|
|
|
18909
19094
|
// src/cli/commands/audit.ts
|
|
18910
19095
|
var import_chalk12 = __toESM(require("chalk"));
|
|
18911
|
-
var
|
|
18912
|
-
var
|
|
18913
|
-
var
|
|
19096
|
+
var import_fs36 = __toESM(require("fs"));
|
|
19097
|
+
var import_path37 = __toESM(require("path"));
|
|
19098
|
+
var import_os32 = __toESM(require("os"));
|
|
18914
19099
|
function formatRelativeTime(timestamp) {
|
|
18915
19100
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
18916
19101
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -18923,14 +19108,14 @@ function formatRelativeTime(timestamp) {
|
|
|
18923
19108
|
}
|
|
18924
19109
|
function registerAuditCommand(program2) {
|
|
18925
19110
|
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) => {
|
|
18926
|
-
const logPath =
|
|
18927
|
-
if (!
|
|
19111
|
+
const logPath = import_path37.default.join(import_os32.default.homedir(), ".node9", "audit.log");
|
|
19112
|
+
if (!import_fs36.default.existsSync(logPath)) {
|
|
18928
19113
|
console.log(
|
|
18929
19114
|
import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
18930
19115
|
);
|
|
18931
19116
|
return;
|
|
18932
19117
|
}
|
|
18933
|
-
const raw =
|
|
19118
|
+
const raw = import_fs36.default.readFileSync(logPath, "utf-8");
|
|
18934
19119
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
18935
19120
|
let entries = lines.flatMap((line) => {
|
|
18936
19121
|
try {
|
|
@@ -18986,9 +19171,9 @@ function registerAuditCommand(program2) {
|
|
|
18986
19171
|
var import_chalk13 = __toESM(require("chalk"));
|
|
18987
19172
|
|
|
18988
19173
|
// src/cli/aggregate/report-audit.ts
|
|
18989
|
-
var
|
|
18990
|
-
var
|
|
18991
|
-
var
|
|
19174
|
+
var import_fs37 = __toESM(require("fs"));
|
|
19175
|
+
var import_os33 = __toESM(require("os"));
|
|
19176
|
+
var import_path38 = __toESM(require("path"));
|
|
18992
19177
|
init_costSync();
|
|
18993
19178
|
init_litellm();
|
|
18994
19179
|
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;
|
|
@@ -19070,8 +19255,8 @@ function getDateRange(period, now) {
|
|
|
19070
19255
|
}
|
|
19071
19256
|
}
|
|
19072
19257
|
function parseAuditLog(logPath) {
|
|
19073
|
-
if (!
|
|
19074
|
-
const raw =
|
|
19258
|
+
if (!import_fs37.default.existsSync(logPath)) return [];
|
|
19259
|
+
const raw = import_fs37.default.readFileSync(logPath, "utf-8");
|
|
19075
19260
|
return raw.split("\n").flatMap((line) => {
|
|
19076
19261
|
if (!line.trim()) return [];
|
|
19077
19262
|
try {
|
|
@@ -19131,25 +19316,25 @@ function freezeClaudeCost(acc) {
|
|
|
19131
19316
|
};
|
|
19132
19317
|
}
|
|
19133
19318
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
19134
|
-
const projPath =
|
|
19319
|
+
const projPath = import_path38.default.join(projectsDir, proj);
|
|
19135
19320
|
let files;
|
|
19136
19321
|
try {
|
|
19137
|
-
const stat =
|
|
19322
|
+
const stat = import_fs37.default.statSync(projPath);
|
|
19138
19323
|
if (!stat.isDirectory()) return;
|
|
19139
|
-
files =
|
|
19324
|
+
files = import_fs37.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
19140
19325
|
} catch {
|
|
19141
19326
|
return;
|
|
19142
19327
|
}
|
|
19143
19328
|
const startMs = start.getTime();
|
|
19144
19329
|
for (const file of files) {
|
|
19145
|
-
const filePath =
|
|
19330
|
+
const filePath = import_path38.default.join(projPath, file);
|
|
19146
19331
|
try {
|
|
19147
|
-
if (
|
|
19332
|
+
if (import_fs37.default.statSync(filePath).mtimeMs < startMs) continue;
|
|
19148
19333
|
} catch {
|
|
19149
19334
|
continue;
|
|
19150
19335
|
}
|
|
19151
19336
|
try {
|
|
19152
|
-
const raw =
|
|
19337
|
+
const raw = import_fs37.default.readFileSync(filePath, "utf-8");
|
|
19153
19338
|
for (const line of raw.split("\n")) {
|
|
19154
19339
|
if (!line.trim()) continue;
|
|
19155
19340
|
let entry;
|
|
@@ -19199,10 +19384,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
19199
19384
|
}
|
|
19200
19385
|
function loadClaudeCost(start, end, projectsDir) {
|
|
19201
19386
|
const acc = emptyClaudeCostAccumulator();
|
|
19202
|
-
if (!
|
|
19387
|
+
if (!import_fs37.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
19203
19388
|
let dirs;
|
|
19204
19389
|
try {
|
|
19205
|
-
dirs =
|
|
19390
|
+
dirs = import_fs37.default.readdirSync(projectsDir);
|
|
19206
19391
|
} catch {
|
|
19207
19392
|
return freezeClaudeCost(acc);
|
|
19208
19393
|
}
|
|
@@ -19214,7 +19399,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
19214
19399
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
19215
19400
|
let lines;
|
|
19216
19401
|
try {
|
|
19217
|
-
lines =
|
|
19402
|
+
lines = import_fs37.default.readFileSync(filePath, "utf-8").split("\n");
|
|
19218
19403
|
} catch {
|
|
19219
19404
|
return;
|
|
19220
19405
|
}
|
|
@@ -19259,31 +19444,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
19259
19444
|
}
|
|
19260
19445
|
function listCodexSessionFiles(sessionsBase) {
|
|
19261
19446
|
const jsonlFiles = [];
|
|
19262
|
-
if (!
|
|
19447
|
+
if (!import_fs37.default.existsSync(sessionsBase)) return jsonlFiles;
|
|
19263
19448
|
try {
|
|
19264
|
-
for (const year of
|
|
19265
|
-
const yearPath =
|
|
19449
|
+
for (const year of import_fs37.default.readdirSync(sessionsBase)) {
|
|
19450
|
+
const yearPath = import_path38.default.join(sessionsBase, year);
|
|
19266
19451
|
try {
|
|
19267
|
-
if (!
|
|
19452
|
+
if (!import_fs37.default.statSync(yearPath).isDirectory()) continue;
|
|
19268
19453
|
} catch {
|
|
19269
19454
|
continue;
|
|
19270
19455
|
}
|
|
19271
|
-
for (const month of
|
|
19272
|
-
const monthPath =
|
|
19456
|
+
for (const month of import_fs37.default.readdirSync(yearPath)) {
|
|
19457
|
+
const monthPath = import_path38.default.join(yearPath, month);
|
|
19273
19458
|
try {
|
|
19274
|
-
if (!
|
|
19459
|
+
if (!import_fs37.default.statSync(monthPath).isDirectory()) continue;
|
|
19275
19460
|
} catch {
|
|
19276
19461
|
continue;
|
|
19277
19462
|
}
|
|
19278
|
-
for (const day of
|
|
19279
|
-
const dayPath =
|
|
19463
|
+
for (const day of import_fs37.default.readdirSync(monthPath)) {
|
|
19464
|
+
const dayPath = import_path38.default.join(monthPath, day);
|
|
19280
19465
|
try {
|
|
19281
|
-
if (!
|
|
19466
|
+
if (!import_fs37.default.statSync(dayPath).isDirectory()) continue;
|
|
19282
19467
|
} catch {
|
|
19283
19468
|
continue;
|
|
19284
19469
|
}
|
|
19285
|
-
for (const file of
|
|
19286
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
19470
|
+
for (const file of import_fs37.default.readdirSync(dayPath)) {
|
|
19471
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path38.default.join(dayPath, file));
|
|
19287
19472
|
}
|
|
19288
19473
|
}
|
|
19289
19474
|
}
|
|
@@ -19336,13 +19521,13 @@ function freezeGeminiCost(acc) {
|
|
|
19336
19521
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
19337
19522
|
const startMs = start.getTime();
|
|
19338
19523
|
try {
|
|
19339
|
-
if (
|
|
19524
|
+
if (import_fs37.default.statSync(filePath).mtimeMs < startMs) return;
|
|
19340
19525
|
} catch {
|
|
19341
19526
|
return;
|
|
19342
19527
|
}
|
|
19343
19528
|
let raw;
|
|
19344
19529
|
try {
|
|
19345
|
-
raw =
|
|
19530
|
+
raw = import_fs37.default.readFileSync(filePath, "utf-8");
|
|
19346
19531
|
} catch {
|
|
19347
19532
|
return;
|
|
19348
19533
|
}
|
|
@@ -19391,30 +19576,30 @@ function listGeminiSessionFiles(geminiTmpDir) {
|
|
|
19391
19576
|
const out = [];
|
|
19392
19577
|
let dirs;
|
|
19393
19578
|
try {
|
|
19394
|
-
if (!
|
|
19395
|
-
dirs =
|
|
19579
|
+
if (!import_fs37.default.statSync(geminiTmpDir).isDirectory()) return out;
|
|
19580
|
+
dirs = import_fs37.default.readdirSync(geminiTmpDir);
|
|
19396
19581
|
} catch {
|
|
19397
19582
|
return out;
|
|
19398
19583
|
}
|
|
19399
19584
|
for (const proj of dirs) {
|
|
19400
|
-
const chatsDir =
|
|
19585
|
+
const chatsDir = import_path38.default.join(geminiTmpDir, proj, "chats");
|
|
19401
19586
|
let files;
|
|
19402
19587
|
try {
|
|
19403
|
-
if (!
|
|
19404
|
-
files =
|
|
19588
|
+
if (!import_fs37.default.statSync(chatsDir).isDirectory()) continue;
|
|
19589
|
+
files = import_fs37.default.readdirSync(chatsDir);
|
|
19405
19590
|
} catch {
|
|
19406
19591
|
continue;
|
|
19407
19592
|
}
|
|
19408
19593
|
for (const f of files) {
|
|
19409
19594
|
if (!f.endsWith(".jsonl")) continue;
|
|
19410
|
-
out.push({ projectKey: proj, file:
|
|
19595
|
+
out.push({ projectKey: proj, file: import_path38.default.join(chatsDir, f) });
|
|
19411
19596
|
}
|
|
19412
19597
|
}
|
|
19413
19598
|
return out;
|
|
19414
19599
|
}
|
|
19415
19600
|
function loadGeminiCost(start, end, geminiTmpDir) {
|
|
19416
19601
|
const acc = emptyGeminiAccumulator();
|
|
19417
|
-
if (!
|
|
19602
|
+
if (!import_fs37.default.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
|
|
19418
19603
|
for (const { projectKey, file } of listGeminiSessionFiles(geminiTmpDir)) {
|
|
19419
19604
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
19420
19605
|
}
|
|
@@ -19422,11 +19607,11 @@ function loadGeminiCost(start, end, geminiTmpDir) {
|
|
|
19422
19607
|
}
|
|
19423
19608
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
19424
19609
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
19425
|
-
const auditLogPath = opts.auditLogPath ??
|
|
19426
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
19427
|
-
const codexSessionsDir = opts.codexSessionsDir ??
|
|
19428
|
-
const geminiTmpDir = opts.geminiTmpDir ??
|
|
19429
|
-
const hasAuditFile =
|
|
19610
|
+
const auditLogPath = opts.auditLogPath ?? import_path38.default.join(import_os33.default.homedir(), ".node9", "audit.log");
|
|
19611
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? import_path38.default.join(import_os33.default.homedir(), ".claude", "projects");
|
|
19612
|
+
const codexSessionsDir = opts.codexSessionsDir ?? import_path38.default.join(import_os33.default.homedir(), ".codex", "sessions");
|
|
19613
|
+
const geminiTmpDir = opts.geminiTmpDir ?? import_path38.default.join(import_os33.default.homedir(), ".gemini", "tmp");
|
|
19614
|
+
const hasAuditFile = import_fs37.default.existsSync(auditLogPath);
|
|
19430
19615
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
19431
19616
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
19432
19617
|
const { start, end } = getDateRange(period, now);
|
|
@@ -20122,14 +20307,14 @@ function registerDaemonCommand(program2) {
|
|
|
20122
20307
|
|
|
20123
20308
|
// src/cli/commands/status.ts
|
|
20124
20309
|
var import_chalk15 = __toESM(require("chalk"));
|
|
20125
|
-
var
|
|
20126
|
-
var
|
|
20127
|
-
var
|
|
20310
|
+
var import_fs38 = __toESM(require("fs"));
|
|
20311
|
+
var import_path39 = __toESM(require("path"));
|
|
20312
|
+
var import_os34 = __toESM(require("os"));
|
|
20128
20313
|
init_core();
|
|
20129
20314
|
init_daemon();
|
|
20130
20315
|
function readJson2(filePath) {
|
|
20131
20316
|
try {
|
|
20132
|
-
if (
|
|
20317
|
+
if (import_fs38.default.existsSync(filePath)) return JSON.parse(import_fs38.default.readFileSync(filePath, "utf-8"));
|
|
20133
20318
|
} catch {
|
|
20134
20319
|
}
|
|
20135
20320
|
return null;
|
|
@@ -20194,28 +20379,28 @@ function registerStatusCommand(program2) {
|
|
|
20194
20379
|
console.log("");
|
|
20195
20380
|
const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
|
|
20196
20381
|
console.log(` Mode: ${modeLabel}`);
|
|
20197
|
-
const projectConfig =
|
|
20198
|
-
const globalConfig =
|
|
20382
|
+
const projectConfig = import_path39.default.join(process.cwd(), "node9.config.json");
|
|
20383
|
+
const globalConfig = import_path39.default.join(import_os34.default.homedir(), ".node9", "config.json");
|
|
20199
20384
|
console.log(
|
|
20200
|
-
` Local: ${
|
|
20385
|
+
` Local: ${import_fs38.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
|
|
20201
20386
|
);
|
|
20202
20387
|
console.log(
|
|
20203
|
-
` Global: ${
|
|
20388
|
+
` Global: ${import_fs38.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
|
|
20204
20389
|
);
|
|
20205
20390
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
20206
20391
|
console.log(
|
|
20207
20392
|
` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
20208
20393
|
);
|
|
20209
20394
|
}
|
|
20210
|
-
const homeDir2 =
|
|
20395
|
+
const homeDir2 = import_os34.default.homedir();
|
|
20211
20396
|
const claudeSettings = readJson2(
|
|
20212
|
-
|
|
20397
|
+
import_path39.default.join(homeDir2, ".claude", "settings.json")
|
|
20213
20398
|
);
|
|
20214
|
-
const claudeConfig = readJson2(
|
|
20399
|
+
const claudeConfig = readJson2(import_path39.default.join(homeDir2, ".claude.json"));
|
|
20215
20400
|
const geminiSettings = readJson2(
|
|
20216
|
-
|
|
20401
|
+
import_path39.default.join(homeDir2, ".gemini", "settings.json")
|
|
20217
20402
|
);
|
|
20218
|
-
const cursorConfig = readJson2(
|
|
20403
|
+
const cursorConfig = readJson2(import_path39.default.join(homeDir2, ".cursor", "mcp.json"));
|
|
20219
20404
|
const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig;
|
|
20220
20405
|
if (agentFound) {
|
|
20221
20406
|
console.log("");
|
|
@@ -20274,9 +20459,9 @@ function registerStatusCommand(program2) {
|
|
|
20274
20459
|
|
|
20275
20460
|
// src/cli/commands/init.ts
|
|
20276
20461
|
var import_chalk16 = __toESM(require("chalk"));
|
|
20277
|
-
var
|
|
20278
|
-
var
|
|
20279
|
-
var
|
|
20462
|
+
var import_fs39 = __toESM(require("fs"));
|
|
20463
|
+
var import_path40 = __toESM(require("path"));
|
|
20464
|
+
var import_os35 = __toESM(require("os"));
|
|
20280
20465
|
var import_https4 = __toESM(require("https"));
|
|
20281
20466
|
init_core();
|
|
20282
20467
|
init_setup();
|
|
@@ -20366,16 +20551,16 @@ function registerInitCommand(program2) {
|
|
|
20366
20551
|
}
|
|
20367
20552
|
console.log("");
|
|
20368
20553
|
}
|
|
20369
|
-
const configPath =
|
|
20370
|
-
const isFirstInstall = !
|
|
20371
|
-
if (
|
|
20554
|
+
const configPath = import_path40.default.join(import_os35.default.homedir(), ".node9", "config.json");
|
|
20555
|
+
const isFirstInstall = !import_fs39.default.existsSync(configPath);
|
|
20556
|
+
if (import_fs39.default.existsSync(configPath) && !options.force) {
|
|
20372
20557
|
try {
|
|
20373
|
-
const existing = JSON.parse(
|
|
20558
|
+
const existing = JSON.parse(import_fs39.default.readFileSync(configPath, "utf-8"));
|
|
20374
20559
|
const settings = existing.settings ?? {};
|
|
20375
20560
|
if (settings.mode !== chosenMode) {
|
|
20376
20561
|
settings.mode = chosenMode;
|
|
20377
20562
|
existing.settings = settings;
|
|
20378
|
-
|
|
20563
|
+
import_fs39.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
20379
20564
|
console.log(import_chalk16.default.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
20380
20565
|
} else {
|
|
20381
20566
|
console.log(import_chalk16.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -20388,9 +20573,9 @@ function registerInitCommand(program2) {
|
|
|
20388
20573
|
...DEFAULT_CONFIG,
|
|
20389
20574
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
20390
20575
|
};
|
|
20391
|
-
const dir =
|
|
20392
|
-
if (!
|
|
20393
|
-
|
|
20576
|
+
const dir = import_path40.default.dirname(configPath);
|
|
20577
|
+
if (!import_fs39.default.existsSync(dir)) import_fs39.default.mkdirSync(dir, { recursive: true });
|
|
20578
|
+
import_fs39.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
20394
20579
|
console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
|
|
20395
20580
|
console.log(import_chalk16.default.gray(` Mode: ${chosenMode}`));
|
|
20396
20581
|
}
|
|
@@ -20495,7 +20680,7 @@ function registerInitCommand(program2) {
|
|
|
20495
20680
|
}
|
|
20496
20681
|
|
|
20497
20682
|
// src/cli/commands/undo.ts
|
|
20498
|
-
var
|
|
20683
|
+
var import_path41 = __toESM(require("path"));
|
|
20499
20684
|
var import_chalk18 = __toESM(require("chalk"));
|
|
20500
20685
|
|
|
20501
20686
|
// src/tui/undo-navigator.ts
|
|
@@ -20654,7 +20839,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
20654
20839
|
let dir = startDir;
|
|
20655
20840
|
while (true) {
|
|
20656
20841
|
if (cwds.has(dir)) return dir;
|
|
20657
|
-
const parent =
|
|
20842
|
+
const parent = import_path41.default.dirname(dir);
|
|
20658
20843
|
if (parent === dir) return null;
|
|
20659
20844
|
dir = parent;
|
|
20660
20845
|
}
|
|
@@ -21230,9 +21415,9 @@ function registerMcpGatewayCommand(program2) {
|
|
|
21230
21415
|
|
|
21231
21416
|
// src/mcp-server/index.ts
|
|
21232
21417
|
var import_readline5 = __toESM(require("readline"));
|
|
21233
|
-
var
|
|
21234
|
-
var
|
|
21235
|
-
var
|
|
21418
|
+
var import_fs40 = __toESM(require("fs"));
|
|
21419
|
+
var import_os36 = __toESM(require("os"));
|
|
21420
|
+
var import_path42 = __toESM(require("path"));
|
|
21236
21421
|
var import_child_process11 = require("child_process");
|
|
21237
21422
|
init_core();
|
|
21238
21423
|
init_daemon();
|
|
@@ -21483,13 +21668,13 @@ function handleStatus() {
|
|
|
21483
21668
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
21484
21669
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
21485
21670
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
21486
|
-
const projectConfig =
|
|
21487
|
-
const globalConfig =
|
|
21671
|
+
const projectConfig = import_path42.default.join(process.cwd(), "node9.config.json");
|
|
21672
|
+
const globalConfig = import_path42.default.join(import_os36.default.homedir(), ".node9", "config.json");
|
|
21488
21673
|
lines.push(
|
|
21489
|
-
`Project config (node9.config.json): ${
|
|
21674
|
+
`Project config (node9.config.json): ${import_fs40.default.existsSync(projectConfig) ? "present" : "not found"}`
|
|
21490
21675
|
);
|
|
21491
21676
|
lines.push(
|
|
21492
|
-
`Global config (~/.node9/config.json): ${
|
|
21677
|
+
`Global config (~/.node9/config.json): ${import_fs40.default.existsSync(globalConfig) ? "present" : "not found"}`
|
|
21493
21678
|
);
|
|
21494
21679
|
return lines.join("\n");
|
|
21495
21680
|
}
|
|
@@ -21563,21 +21748,21 @@ function handleShieldDisable(args) {
|
|
|
21563
21748
|
writeActiveShields(active.filter((s) => s !== name));
|
|
21564
21749
|
return `Shield "${name}" disabled.`;
|
|
21565
21750
|
}
|
|
21566
|
-
var GLOBAL_CONFIG_PATH =
|
|
21751
|
+
var GLOBAL_CONFIG_PATH = import_path42.default.join(import_os36.default.homedir(), ".node9", "config.json");
|
|
21567
21752
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
21568
21753
|
function readGlobalConfigRaw() {
|
|
21569
21754
|
try {
|
|
21570
|
-
if (
|
|
21571
|
-
return JSON.parse(
|
|
21755
|
+
if (import_fs40.default.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
21756
|
+
return JSON.parse(import_fs40.default.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
|
|
21572
21757
|
}
|
|
21573
21758
|
} catch {
|
|
21574
21759
|
}
|
|
21575
21760
|
return {};
|
|
21576
21761
|
}
|
|
21577
21762
|
function writeGlobalConfigRaw(data) {
|
|
21578
|
-
const dir =
|
|
21579
|
-
if (!
|
|
21580
|
-
|
|
21763
|
+
const dir = import_path42.default.dirname(GLOBAL_CONFIG_PATH);
|
|
21764
|
+
if (!import_fs40.default.existsSync(dir)) import_fs40.default.mkdirSync(dir, { recursive: true });
|
|
21765
|
+
import_fs40.default.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
|
|
21581
21766
|
}
|
|
21582
21767
|
function handleApproverList() {
|
|
21583
21768
|
const config = getConfig();
|
|
@@ -21621,9 +21806,9 @@ function handleApproverSet(args) {
|
|
|
21621
21806
|
function handleAuditGet(args) {
|
|
21622
21807
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
21623
21808
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
21624
|
-
const auditPath =
|
|
21625
|
-
if (!
|
|
21626
|
-
const rawLines =
|
|
21809
|
+
const auditPath = import_path42.default.join(import_os36.default.homedir(), ".node9", "audit.log");
|
|
21810
|
+
if (!import_fs40.default.existsSync(auditPath)) return "No audit log found.";
|
|
21811
|
+
const rawLines = import_fs40.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
21627
21812
|
const parsed = [];
|
|
21628
21813
|
for (const line of rawLines) {
|
|
21629
21814
|
try {
|
|
@@ -21958,7 +22143,7 @@ function registerTrustCommand(program2) {
|
|
|
21958
22143
|
// src/cli/commands/mcp-pin.ts
|
|
21959
22144
|
var import_chalk21 = __toESM(require("chalk"));
|
|
21960
22145
|
init_mcp_pin();
|
|
21961
|
-
var
|
|
22146
|
+
var import_fs41 = __toESM(require("fs"));
|
|
21962
22147
|
function registerMcpPinCommand(program2) {
|
|
21963
22148
|
const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
|
|
21964
22149
|
const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
|
|
@@ -21969,7 +22154,7 @@ function registerMcpPinCommand(program2) {
|
|
|
21969
22154
|
let repoCorrupt = false;
|
|
21970
22155
|
if (found.source === "repo") {
|
|
21971
22156
|
try {
|
|
21972
|
-
const raw =
|
|
22157
|
+
const raw = import_fs41.default.readFileSync(found.path, "utf-8");
|
|
21973
22158
|
const parsed = JSON.parse(raw);
|
|
21974
22159
|
repoEntries = parsed.servers ?? {};
|
|
21975
22160
|
} catch {
|
|
@@ -22282,9 +22467,9 @@ init_scan();
|
|
|
22282
22467
|
|
|
22283
22468
|
// src/cli/commands/sessions.ts
|
|
22284
22469
|
var import_chalk24 = __toESM(require("chalk"));
|
|
22285
|
-
var
|
|
22286
|
-
var
|
|
22287
|
-
var
|
|
22470
|
+
var import_fs42 = __toESM(require("fs"));
|
|
22471
|
+
var import_path43 = __toESM(require("path"));
|
|
22472
|
+
var import_os37 = __toESM(require("os"));
|
|
22288
22473
|
init_scan_summary();
|
|
22289
22474
|
var CLAUDE_PRICING3 = {
|
|
22290
22475
|
"claude-opus-4-6": { i: 5e-6, o: 25e-6, cw: 625e-8, cr: 5e-7 },
|
|
@@ -22326,10 +22511,10 @@ function encodeProjectPath(projectPath) {
|
|
|
22326
22511
|
}
|
|
22327
22512
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
22328
22513
|
const encoded = encodeProjectPath(projectPath);
|
|
22329
|
-
return
|
|
22514
|
+
return import_path43.default.join(import_os37.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
22330
22515
|
}
|
|
22331
22516
|
function projectLabel(projectPath) {
|
|
22332
|
-
return projectPath.replace(
|
|
22517
|
+
return projectPath.replace(import_os37.default.homedir(), "~");
|
|
22333
22518
|
}
|
|
22334
22519
|
function parseHistoryLines(lines) {
|
|
22335
22520
|
const entries = [];
|
|
@@ -22398,10 +22583,10 @@ function parseSessionLines(lines) {
|
|
|
22398
22583
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
22399
22584
|
}
|
|
22400
22585
|
function loadAuditEntries(auditPath) {
|
|
22401
|
-
const aPath = auditPath ??
|
|
22586
|
+
const aPath = auditPath ?? import_path43.default.join(import_os37.default.homedir(), ".node9", "audit.log");
|
|
22402
22587
|
let raw;
|
|
22403
22588
|
try {
|
|
22404
|
-
raw =
|
|
22589
|
+
raw = import_fs42.default.readFileSync(aPath, "utf-8");
|
|
22405
22590
|
} catch {
|
|
22406
22591
|
return [];
|
|
22407
22592
|
}
|
|
@@ -22437,8 +22622,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
22437
22622
|
return result;
|
|
22438
22623
|
}
|
|
22439
22624
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
22440
|
-
const tmpDir =
|
|
22441
|
-
if (!
|
|
22625
|
+
const tmpDir = import_path43.default.join(import_os37.default.homedir(), ".gemini", "tmp");
|
|
22626
|
+
if (!import_fs42.default.existsSync(tmpDir)) return [];
|
|
22442
22627
|
const cutoff = days !== null ? (() => {
|
|
22443
22628
|
const d = /* @__PURE__ */ new Date();
|
|
22444
22629
|
d.setDate(d.getDate() - days);
|
|
@@ -22447,35 +22632,35 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
22447
22632
|
})() : null;
|
|
22448
22633
|
let slugDirs;
|
|
22449
22634
|
try {
|
|
22450
|
-
slugDirs =
|
|
22635
|
+
slugDirs = import_fs42.default.readdirSync(tmpDir);
|
|
22451
22636
|
} catch {
|
|
22452
22637
|
return [];
|
|
22453
22638
|
}
|
|
22454
22639
|
const summaries = [];
|
|
22455
22640
|
for (const slug of slugDirs) {
|
|
22456
|
-
const slugPath =
|
|
22641
|
+
const slugPath = import_path43.default.join(tmpDir, slug);
|
|
22457
22642
|
try {
|
|
22458
|
-
if (!
|
|
22643
|
+
if (!import_fs42.default.statSync(slugPath).isDirectory()) continue;
|
|
22459
22644
|
} catch {
|
|
22460
22645
|
continue;
|
|
22461
22646
|
}
|
|
22462
|
-
let projectRoot =
|
|
22647
|
+
let projectRoot = import_path43.default.join(import_os37.default.homedir(), slug);
|
|
22463
22648
|
try {
|
|
22464
|
-
projectRoot =
|
|
22649
|
+
projectRoot = import_fs42.default.readFileSync(import_path43.default.join(slugPath, ".project_root"), "utf-8").trim();
|
|
22465
22650
|
} catch {
|
|
22466
22651
|
}
|
|
22467
|
-
const chatsDir =
|
|
22468
|
-
if (!
|
|
22652
|
+
const chatsDir = import_path43.default.join(slugPath, "chats");
|
|
22653
|
+
if (!import_fs42.default.existsSync(chatsDir)) continue;
|
|
22469
22654
|
let chatFiles;
|
|
22470
22655
|
try {
|
|
22471
|
-
chatFiles =
|
|
22656
|
+
chatFiles = import_fs42.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
22472
22657
|
} catch {
|
|
22473
22658
|
continue;
|
|
22474
22659
|
}
|
|
22475
22660
|
for (const chatFile of chatFiles) {
|
|
22476
22661
|
let raw;
|
|
22477
22662
|
try {
|
|
22478
|
-
raw =
|
|
22663
|
+
raw = import_fs42.default.readFileSync(import_path43.default.join(chatsDir, chatFile), "utf-8");
|
|
22479
22664
|
} catch {
|
|
22480
22665
|
continue;
|
|
22481
22666
|
}
|
|
@@ -22555,8 +22740,8 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
22555
22740
|
return summaries;
|
|
22556
22741
|
}
|
|
22557
22742
|
function buildCodexSessions(days, allAuditEntries) {
|
|
22558
|
-
const sessionsBase =
|
|
22559
|
-
if (!
|
|
22743
|
+
const sessionsBase = import_path43.default.join(import_os37.default.homedir(), ".codex", "sessions");
|
|
22744
|
+
if (!import_fs42.default.existsSync(sessionsBase)) return [];
|
|
22560
22745
|
const cutoff = days !== null ? (() => {
|
|
22561
22746
|
const d = /* @__PURE__ */ new Date();
|
|
22562
22747
|
d.setDate(d.getDate() - days);
|
|
@@ -22565,29 +22750,29 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
22565
22750
|
})() : null;
|
|
22566
22751
|
const jsonlFiles = [];
|
|
22567
22752
|
try {
|
|
22568
|
-
for (const year of
|
|
22569
|
-
const yearPath =
|
|
22753
|
+
for (const year of import_fs42.default.readdirSync(sessionsBase)) {
|
|
22754
|
+
const yearPath = import_path43.default.join(sessionsBase, year);
|
|
22570
22755
|
try {
|
|
22571
|
-
if (!
|
|
22756
|
+
if (!import_fs42.default.statSync(yearPath).isDirectory()) continue;
|
|
22572
22757
|
} catch {
|
|
22573
22758
|
continue;
|
|
22574
22759
|
}
|
|
22575
|
-
for (const month of
|
|
22576
|
-
const monthPath =
|
|
22760
|
+
for (const month of import_fs42.default.readdirSync(yearPath)) {
|
|
22761
|
+
const monthPath = import_path43.default.join(yearPath, month);
|
|
22577
22762
|
try {
|
|
22578
|
-
if (!
|
|
22763
|
+
if (!import_fs42.default.statSync(monthPath).isDirectory()) continue;
|
|
22579
22764
|
} catch {
|
|
22580
22765
|
continue;
|
|
22581
22766
|
}
|
|
22582
|
-
for (const day of
|
|
22583
|
-
const dayPath =
|
|
22767
|
+
for (const day of import_fs42.default.readdirSync(monthPath)) {
|
|
22768
|
+
const dayPath = import_path43.default.join(monthPath, day);
|
|
22584
22769
|
try {
|
|
22585
|
-
if (!
|
|
22770
|
+
if (!import_fs42.default.statSync(dayPath).isDirectory()) continue;
|
|
22586
22771
|
} catch {
|
|
22587
22772
|
continue;
|
|
22588
22773
|
}
|
|
22589
|
-
for (const file of
|
|
22590
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
22774
|
+
for (const file of import_fs42.default.readdirSync(dayPath)) {
|
|
22775
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path43.default.join(dayPath, file));
|
|
22591
22776
|
}
|
|
22592
22777
|
}
|
|
22593
22778
|
}
|
|
@@ -22599,7 +22784,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
22599
22784
|
for (const filePath of jsonlFiles) {
|
|
22600
22785
|
let lines;
|
|
22601
22786
|
try {
|
|
22602
|
-
lines =
|
|
22787
|
+
lines = import_fs42.default.readFileSync(filePath, "utf-8").split("\n");
|
|
22603
22788
|
} catch {
|
|
22604
22789
|
continue;
|
|
22605
22790
|
}
|
|
@@ -22677,10 +22862,10 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
22677
22862
|
return summaries;
|
|
22678
22863
|
}
|
|
22679
22864
|
function buildSessions(days, historyPath) {
|
|
22680
|
-
const hPath = historyPath ??
|
|
22865
|
+
const hPath = historyPath ?? import_path43.default.join(import_os37.default.homedir(), ".claude", "history.jsonl");
|
|
22681
22866
|
let historyRaw;
|
|
22682
22867
|
try {
|
|
22683
|
-
historyRaw =
|
|
22868
|
+
historyRaw = import_fs42.default.readFileSync(hPath, "utf-8");
|
|
22684
22869
|
} catch {
|
|
22685
22870
|
return [];
|
|
22686
22871
|
}
|
|
@@ -22705,7 +22890,7 @@ function buildSessions(days, historyPath) {
|
|
|
22705
22890
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
22706
22891
|
let sessionLines = [];
|
|
22707
22892
|
try {
|
|
22708
|
-
sessionLines =
|
|
22893
|
+
sessionLines = import_fs42.default.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
22709
22894
|
} catch {
|
|
22710
22895
|
}
|
|
22711
22896
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -22973,8 +23158,8 @@ function registerSessionsCommand(program2) {
|
|
|
22973
23158
|
console.log("");
|
|
22974
23159
|
console.log(import_chalk24.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk24.default.dim(" \u2014 what your AI agent did"));
|
|
22975
23160
|
console.log("");
|
|
22976
|
-
const historyPath =
|
|
22977
|
-
if (!
|
|
23161
|
+
const historyPath = import_path43.default.join(import_os37.default.homedir(), ".claude", "history.jsonl");
|
|
23162
|
+
if (!import_fs42.default.existsSync(historyPath)) {
|
|
22978
23163
|
console.log(import_chalk24.default.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
|
|
22979
23164
|
console.log(import_chalk24.default.gray(" Install Claude Code, run a few sessions, then try again.\n"));
|
|
22980
23165
|
return;
|
|
@@ -23011,12 +23196,12 @@ function registerSessionsCommand(program2) {
|
|
|
23011
23196
|
|
|
23012
23197
|
// src/cli/commands/skill-pin.ts
|
|
23013
23198
|
var import_chalk25 = __toESM(require("chalk"));
|
|
23014
|
-
var
|
|
23015
|
-
var
|
|
23016
|
-
var
|
|
23199
|
+
var import_fs43 = __toESM(require("fs"));
|
|
23200
|
+
var import_os38 = __toESM(require("os"));
|
|
23201
|
+
var import_path44 = __toESM(require("path"));
|
|
23017
23202
|
function wipeSkillSessions() {
|
|
23018
23203
|
try {
|
|
23019
|
-
|
|
23204
|
+
import_fs43.default.rmSync(import_path44.default.join(import_os38.default.homedir(), ".node9", "skill-sessions"), {
|
|
23020
23205
|
recursive: true,
|
|
23021
23206
|
force: true
|
|
23022
23207
|
});
|
|
@@ -23098,15 +23283,15 @@ function registerSkillPinCommand(program2) {
|
|
|
23098
23283
|
}
|
|
23099
23284
|
|
|
23100
23285
|
// src/cli/commands/decisions.ts
|
|
23101
|
-
var
|
|
23102
|
-
var
|
|
23103
|
-
var
|
|
23286
|
+
var import_fs44 = __toESM(require("fs"));
|
|
23287
|
+
var import_os39 = __toESM(require("os"));
|
|
23288
|
+
var import_path45 = __toESM(require("path"));
|
|
23104
23289
|
var import_chalk26 = __toESM(require("chalk"));
|
|
23105
|
-
var DECISIONS_FILE2 =
|
|
23290
|
+
var DECISIONS_FILE2 = import_path45.default.join(import_os39.default.homedir(), ".node9", "decisions.json");
|
|
23106
23291
|
function readDecisions() {
|
|
23107
23292
|
try {
|
|
23108
|
-
if (!
|
|
23109
|
-
const raw =
|
|
23293
|
+
if (!import_fs44.default.existsSync(DECISIONS_FILE2)) return {};
|
|
23294
|
+
const raw = import_fs44.default.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
23110
23295
|
const parsed = JSON.parse(raw);
|
|
23111
23296
|
const out = {};
|
|
23112
23297
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -23118,11 +23303,11 @@ function readDecisions() {
|
|
|
23118
23303
|
}
|
|
23119
23304
|
}
|
|
23120
23305
|
function writeDecisions(d) {
|
|
23121
|
-
const dir =
|
|
23122
|
-
if (!
|
|
23306
|
+
const dir = import_path45.default.dirname(DECISIONS_FILE2);
|
|
23307
|
+
if (!import_fs44.default.existsSync(dir)) import_fs44.default.mkdirSync(dir, { recursive: true });
|
|
23123
23308
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
23124
|
-
|
|
23125
|
-
|
|
23309
|
+
import_fs44.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
23310
|
+
import_fs44.default.renameSync(tmp, DECISIONS_FILE2);
|
|
23126
23311
|
}
|
|
23127
23312
|
function registerDecisionsCommand(program2) {
|
|
23128
23313
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -23179,18 +23364,18 @@ Persistent decisions (${entries.length})
|
|
|
23179
23364
|
|
|
23180
23365
|
// src/cli/commands/dlp.ts
|
|
23181
23366
|
var import_chalk27 = __toESM(require("chalk"));
|
|
23182
|
-
var
|
|
23183
|
-
var
|
|
23184
|
-
var
|
|
23185
|
-
var AUDIT_LOG =
|
|
23186
|
-
var RESOLVED_FILE =
|
|
23367
|
+
var import_fs45 = __toESM(require("fs"));
|
|
23368
|
+
var import_path46 = __toESM(require("path"));
|
|
23369
|
+
var import_os40 = __toESM(require("os"));
|
|
23370
|
+
var AUDIT_LOG = import_path46.default.join(import_os40.default.homedir(), ".node9", "audit.log");
|
|
23371
|
+
var RESOLVED_FILE = import_path46.default.join(import_os40.default.homedir(), ".node9", "dlp-resolved.json");
|
|
23187
23372
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
23188
23373
|
function stripAnsi(s) {
|
|
23189
23374
|
return s.replace(ANSI_RE, "");
|
|
23190
23375
|
}
|
|
23191
23376
|
function loadResolved() {
|
|
23192
23377
|
try {
|
|
23193
|
-
const raw = JSON.parse(
|
|
23378
|
+
const raw = JSON.parse(import_fs45.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
23194
23379
|
return new Set(raw);
|
|
23195
23380
|
} catch {
|
|
23196
23381
|
return /* @__PURE__ */ new Set();
|
|
@@ -23198,13 +23383,13 @@ function loadResolved() {
|
|
|
23198
23383
|
}
|
|
23199
23384
|
function saveResolved(resolved) {
|
|
23200
23385
|
try {
|
|
23201
|
-
|
|
23386
|
+
import_fs45.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
23202
23387
|
} catch {
|
|
23203
23388
|
}
|
|
23204
23389
|
}
|
|
23205
23390
|
function loadDlpFindings() {
|
|
23206
|
-
if (!
|
|
23207
|
-
return
|
|
23391
|
+
if (!import_fs45.default.existsSync(AUDIT_LOG)) return [];
|
|
23392
|
+
return import_fs45.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
23208
23393
|
if (!line.trim()) return [];
|
|
23209
23394
|
try {
|
|
23210
23395
|
const e = JSON.parse(line);
|
|
@@ -23302,15 +23487,15 @@ function registerDlpCommand(program2) {
|
|
|
23302
23487
|
|
|
23303
23488
|
// src/cli/commands/mask.ts
|
|
23304
23489
|
var import_chalk28 = __toESM(require("chalk"));
|
|
23305
|
-
var
|
|
23306
|
-
var
|
|
23307
|
-
var
|
|
23490
|
+
var import_fs46 = __toESM(require("fs"));
|
|
23491
|
+
var import_path47 = __toESM(require("path"));
|
|
23492
|
+
var import_os41 = __toESM(require("os"));
|
|
23308
23493
|
init_dlp();
|
|
23309
23494
|
function findJsonlFiles(dir) {
|
|
23310
23495
|
const results = [];
|
|
23311
|
-
if (!
|
|
23312
|
-
for (const entry of
|
|
23313
|
-
const full =
|
|
23496
|
+
if (!import_fs46.default.existsSync(dir)) return results;
|
|
23497
|
+
for (const entry of import_fs46.default.readdirSync(dir, { withFileTypes: true })) {
|
|
23498
|
+
const full = import_path47.default.join(dir, entry.name);
|
|
23314
23499
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
23315
23500
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
23316
23501
|
}
|
|
@@ -23353,7 +23538,7 @@ function redactJson(obj) {
|
|
|
23353
23538
|
function processFile(filePath, dryRun) {
|
|
23354
23539
|
let raw;
|
|
23355
23540
|
try {
|
|
23356
|
-
raw =
|
|
23541
|
+
raw = import_fs46.default.readFileSync(filePath, "utf-8");
|
|
23357
23542
|
} catch {
|
|
23358
23543
|
return { redactedLines: 0, patterns: [] };
|
|
23359
23544
|
}
|
|
@@ -23385,14 +23570,14 @@ function processFile(filePath, dryRun) {
|
|
|
23385
23570
|
}
|
|
23386
23571
|
}
|
|
23387
23572
|
if (!dryRun && redactedLines > 0) {
|
|
23388
|
-
|
|
23573
|
+
import_fs46.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
23389
23574
|
}
|
|
23390
23575
|
return { redactedLines, patterns };
|
|
23391
23576
|
}
|
|
23392
23577
|
function processJsonFile(filePath, dryRun) {
|
|
23393
23578
|
let raw;
|
|
23394
23579
|
try {
|
|
23395
|
-
raw =
|
|
23580
|
+
raw = import_fs46.default.readFileSync(filePath, "utf-8");
|
|
23396
23581
|
} catch {
|
|
23397
23582
|
return { redactedLines: 0, patterns: [] };
|
|
23398
23583
|
}
|
|
@@ -23405,15 +23590,15 @@ function processJsonFile(filePath, dryRun) {
|
|
|
23405
23590
|
const { value, modified, found } = redactJson(parsed);
|
|
23406
23591
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
23407
23592
|
if (!dryRun) {
|
|
23408
|
-
|
|
23593
|
+
import_fs46.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
23409
23594
|
}
|
|
23410
23595
|
return { redactedLines: 1, patterns: found };
|
|
23411
23596
|
}
|
|
23412
23597
|
function findJsonFiles(dir) {
|
|
23413
23598
|
const results = [];
|
|
23414
|
-
if (!
|
|
23415
|
-
for (const entry of
|
|
23416
|
-
const full =
|
|
23599
|
+
if (!import_fs46.default.existsSync(dir)) return results;
|
|
23600
|
+
for (const entry of import_fs46.default.readdirSync(dir, { withFileTypes: true })) {
|
|
23601
|
+
const full = import_path47.default.join(dir, entry.name);
|
|
23417
23602
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
23418
23603
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
23419
23604
|
}
|
|
@@ -23422,9 +23607,9 @@ function findJsonFiles(dir) {
|
|
|
23422
23607
|
function registerMaskCommand(program2) {
|
|
23423
23608
|
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) => {
|
|
23424
23609
|
const dryRun = !!options.dryRun;
|
|
23425
|
-
const home =
|
|
23426
|
-
const claudeDir =
|
|
23427
|
-
const geminiDir =
|
|
23610
|
+
const home = import_os41.default.homedir();
|
|
23611
|
+
const claudeDir = import_path47.default.join(home, ".claude", "projects");
|
|
23612
|
+
const geminiDir = import_path47.default.join(home, ".gemini", "tmp");
|
|
23428
23613
|
const allFiles = [
|
|
23429
23614
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
23430
23615
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -23432,7 +23617,7 @@ function registerMaskCommand(program2) {
|
|
|
23432
23617
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
23433
23618
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
23434
23619
|
try {
|
|
23435
|
-
return
|
|
23620
|
+
return import_fs46.default.statSync(f.path).mtime >= cutoff;
|
|
23436
23621
|
} catch {
|
|
23437
23622
|
return false;
|
|
23438
23623
|
}
|
|
@@ -23488,20 +23673,20 @@ function registerMaskCommand(program2) {
|
|
|
23488
23673
|
// src/cli.ts
|
|
23489
23674
|
init_blast();
|
|
23490
23675
|
var { version } = JSON.parse(
|
|
23491
|
-
|
|
23676
|
+
import_fs49.default.readFileSync(import_path50.default.join(__dirname, "../package.json"), "utf-8")
|
|
23492
23677
|
);
|
|
23493
23678
|
var program = new import_commander.Command();
|
|
23494
23679
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
23495
23680
|
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) => {
|
|
23496
23681
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
23497
|
-
const credPath =
|
|
23498
|
-
if (!
|
|
23499
|
-
|
|
23682
|
+
const credPath = import_path50.default.join(import_os44.default.homedir(), ".node9", "credentials.json");
|
|
23683
|
+
if (!import_fs49.default.existsSync(import_path50.default.dirname(credPath)))
|
|
23684
|
+
import_fs49.default.mkdirSync(import_path50.default.dirname(credPath), { recursive: true });
|
|
23500
23685
|
const profileName = options.profile || "default";
|
|
23501
23686
|
let existingCreds = {};
|
|
23502
23687
|
try {
|
|
23503
|
-
if (
|
|
23504
|
-
const raw = JSON.parse(
|
|
23688
|
+
if (import_fs49.default.existsSync(credPath)) {
|
|
23689
|
+
const raw = JSON.parse(import_fs49.default.readFileSync(credPath, "utf-8"));
|
|
23505
23690
|
if (raw.apiKey) {
|
|
23506
23691
|
existingCreds = {
|
|
23507
23692
|
default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
|
|
@@ -23513,13 +23698,14 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
23513
23698
|
} catch {
|
|
23514
23699
|
}
|
|
23515
23700
|
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
23516
|
-
|
|
23701
|
+
import_fs49.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
23702
|
+
let effectiveCloud = null;
|
|
23517
23703
|
if (profileName === "default") {
|
|
23518
|
-
const configPath =
|
|
23704
|
+
const configPath = import_path50.default.join(import_os44.default.homedir(), ".node9", "config.json");
|
|
23519
23705
|
let config = {};
|
|
23520
23706
|
try {
|
|
23521
|
-
if (
|
|
23522
|
-
config = JSON.parse(
|
|
23707
|
+
if (import_fs49.default.existsSync(configPath))
|
|
23708
|
+
config = JSON.parse(import_fs49.default.readFileSync(configPath, "utf-8"));
|
|
23523
23709
|
} catch {
|
|
23524
23710
|
}
|
|
23525
23711
|
if (!config.settings || typeof config.settings !== "object") config.settings = {};
|
|
@@ -23534,16 +23720,25 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
23534
23720
|
approvers.cloud = false;
|
|
23535
23721
|
}
|
|
23536
23722
|
s.approvers = approvers;
|
|
23537
|
-
if (!
|
|
23538
|
-
|
|
23539
|
-
|
|
23723
|
+
if (!import_fs49.default.existsSync(import_path50.default.dirname(configPath)))
|
|
23724
|
+
import_fs49.default.mkdirSync(import_path50.default.dirname(configPath), { recursive: true });
|
|
23725
|
+
import_fs49.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
23726
|
+
effectiveCloud = approvers.cloud === true;
|
|
23540
23727
|
}
|
|
23541
23728
|
if (options.profile && profileName !== "default") {
|
|
23542
23729
|
console.log(import_chalk30.default.green(`\u2705 Profile "${profileName}" saved`));
|
|
23543
23730
|
console.log(import_chalk30.default.gray(` Switch to it per-session: NODE9_PROFILE=${profileName} claude`));
|
|
23544
|
-
} else if (options.local) {
|
|
23545
|
-
console.log(import_chalk30.default.green(`\u2705 Privacy mode \u{1F6E1}\uFE0F`));
|
|
23546
|
-
console.log(import_chalk30.default.gray(` All decisions stay on this machine.`));
|
|
23731
|
+
} else if (options.local || effectiveCloud === false) {
|
|
23732
|
+
console.log(import_chalk30.default.green(`\u2705 Key saved \u2014 Privacy mode \u{1F6E1}\uFE0F`));
|
|
23733
|
+
console.log(import_chalk30.default.gray(` All decisions stay on this machine. Nothing syncs to the cloud.`));
|
|
23734
|
+
if (!options.local) {
|
|
23735
|
+
console.log(
|
|
23736
|
+
import_chalk30.default.yellow(` Your config has cloud approvals OFF (settings.approvers.cloud).`)
|
|
23737
|
+
);
|
|
23738
|
+
console.log(
|
|
23739
|
+
import_chalk30.default.gray(` To enable team policy + dashboard sync: set it to true, or re-init.`)
|
|
23740
|
+
);
|
|
23741
|
+
}
|
|
23547
23742
|
} else {
|
|
23548
23743
|
console.log(import_chalk30.default.green(`\u2705 Logged in \u2014 agent mode`));
|
|
23549
23744
|
console.log(import_chalk30.default.gray(` Team policy enforced for all calls via Node9 cloud.`));
|
|
@@ -23686,15 +23881,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
23686
23881
|
}
|
|
23687
23882
|
}
|
|
23688
23883
|
if (options.purge) {
|
|
23689
|
-
const node9Dir =
|
|
23690
|
-
if (
|
|
23884
|
+
const node9Dir = import_path50.default.join(import_os44.default.homedir(), ".node9");
|
|
23885
|
+
if (import_fs49.default.existsSync(node9Dir)) {
|
|
23691
23886
|
const confirmed = await (0, import_prompts2.confirm)({
|
|
23692
23887
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
23693
23888
|
default: false
|
|
23694
23889
|
});
|
|
23695
23890
|
if (confirmed) {
|
|
23696
|
-
|
|
23697
|
-
if (
|
|
23891
|
+
import_fs49.default.rmSync(node9Dir, { recursive: true });
|
|
23892
|
+
if (import_fs49.default.existsSync(node9Dir)) {
|
|
23698
23893
|
console.error(
|
|
23699
23894
|
import_chalk30.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
23700
23895
|
);
|
|
@@ -23809,7 +24004,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
23809
24004
|
});
|
|
23810
24005
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
23811
24006
|
try {
|
|
23812
|
-
const dashboardPath =
|
|
24007
|
+
const dashboardPath = import_path50.default.join(__dirname, "dashboard.mjs");
|
|
23813
24008
|
const dynamicImport = new Function("id", "return import(id)");
|
|
23814
24009
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
23815
24010
|
await mod.startMonitor();
|
|
@@ -23847,14 +24042,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
23847
24042
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
23848
24043
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
23849
24044
|
if (subcommand === "debug") {
|
|
23850
|
-
const flagFile =
|
|
24045
|
+
const flagFile = import_path50.default.join(import_os44.default.homedir(), ".node9", "hud-debug");
|
|
23851
24046
|
if (state === "on") {
|
|
23852
|
-
|
|
23853
|
-
|
|
24047
|
+
import_fs49.default.mkdirSync(import_path50.default.dirname(flagFile), { recursive: true });
|
|
24048
|
+
import_fs49.default.writeFileSync(flagFile, "");
|
|
23854
24049
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
23855
24050
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
23856
24051
|
} else if (state === "off") {
|
|
23857
|
-
if (
|
|
24052
|
+
if (import_fs49.default.existsSync(flagFile)) import_fs49.default.unlinkSync(flagFile);
|
|
23858
24053
|
console.log("HUD debug logging disabled.");
|
|
23859
24054
|
} else {
|
|
23860
24055
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -23971,9 +24166,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
23971
24166
|
const isCheckHook = process.argv[2] === "check";
|
|
23972
24167
|
if (isCheckHook) {
|
|
23973
24168
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
23974
|
-
const logPath =
|
|
24169
|
+
const logPath = import_path50.default.join(import_os44.default.homedir(), ".node9", "hook-debug.log");
|
|
23975
24170
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
23976
|
-
|
|
24171
|
+
import_fs49.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
23977
24172
|
`);
|
|
23978
24173
|
}
|
|
23979
24174
|
process.exit(0);
|