@node9/proxy 1.64.0 → 1.65.1
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 +1064 -792
- package/dist/cli.mjs +1044 -772
- package/dist/dashboard.mjs +2 -1
- package/dist/index.js +25 -10
- package/dist/index.mjs +25 -10
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -248,8 +248,8 @@ function sanitizeConfig(raw) {
|
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
const lines = result.error.issues.map((issue) => {
|
|
251
|
-
const
|
|
252
|
-
return ` \u2022 ${
|
|
251
|
+
const path72 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
252
|
+
return ` \u2022 ${path72}: ${issue.message}`;
|
|
253
253
|
});
|
|
254
254
|
return {
|
|
255
255
|
sanitized,
|
|
@@ -1465,9 +1465,9 @@ function matchesPattern(text, patterns) {
|
|
|
1465
1465
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
1466
1466
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
1467
1467
|
}
|
|
1468
|
-
function getNestedValue(obj,
|
|
1468
|
+
function getNestedValue(obj, path72) {
|
|
1469
1469
|
if (!obj || typeof obj !== "object") return null;
|
|
1470
|
-
const segments =
|
|
1470
|
+
const segments = path72.split(".");
|
|
1471
1471
|
for (const seg of segments) {
|
|
1472
1472
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
1473
1473
|
}
|
|
@@ -4619,6 +4619,7 @@ function getActiveEnvironment(config) {
|
|
|
4619
4619
|
}
|
|
4620
4620
|
function readRulesCacheResilient(cacheFile) {
|
|
4621
4621
|
let existed = false;
|
|
4622
|
+
let sawReadError = false;
|
|
4622
4623
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
4623
4624
|
let content;
|
|
4624
4625
|
try {
|
|
@@ -4626,30 +4627,39 @@ function readRulesCacheResilient(cacheFile) {
|
|
|
4626
4627
|
existed = true;
|
|
4627
4628
|
} catch (err2) {
|
|
4628
4629
|
if (err2.code === "ENOENT") return {};
|
|
4630
|
+
sawReadError = true;
|
|
4629
4631
|
continue;
|
|
4630
4632
|
}
|
|
4631
4633
|
try {
|
|
4632
|
-
|
|
4634
|
+
const parsed = JSON.parse(content);
|
|
4635
|
+
lastParsedRulesCache = parsed;
|
|
4636
|
+
return parsed;
|
|
4633
4637
|
} catch {
|
|
4634
4638
|
}
|
|
4635
4639
|
}
|
|
4636
|
-
if (existed) {
|
|
4640
|
+
if (existed || sawReadError) {
|
|
4637
4641
|
const backup = path4.join(path4.dirname(cacheFile), "rules-cache.last-good.json");
|
|
4638
4642
|
if (backup !== cacheFile) {
|
|
4639
4643
|
try {
|
|
4640
4644
|
const raw = JSON.parse(fs4.readFileSync(backup, "utf-8"));
|
|
4641
4645
|
logCacheReadIssue(cacheFile, "RULES_CACHE_CORRUPT_USED_BACKUP");
|
|
4646
|
+
lastParsedRulesCache = raw;
|
|
4642
4647
|
return raw;
|
|
4643
4648
|
} catch {
|
|
4644
4649
|
}
|
|
4645
4650
|
}
|
|
4651
|
+
if (lastParsedRulesCache) {
|
|
4652
|
+
logCacheReadIssue(cacheFile, "RULES_CACHE_USED_MEMORY");
|
|
4653
|
+
return lastParsedRulesCache;
|
|
4654
|
+
}
|
|
4646
4655
|
logCacheReadIssue(cacheFile, "RULES_CACHE_UNREADABLE");
|
|
4647
4656
|
}
|
|
4648
4657
|
return {};
|
|
4649
4658
|
}
|
|
4650
4659
|
function logCacheReadIssue(cacheFile, kind) {
|
|
4651
|
-
|
|
4652
|
-
|
|
4660
|
+
const now = Date.now();
|
|
4661
|
+
if (now - cacheReadLastLoggedAt < CACHE_LOG_REARM_MS) return;
|
|
4662
|
+
cacheReadLastLoggedAt = now;
|
|
4653
4663
|
try {
|
|
4654
4664
|
fs4.appendFileSync(
|
|
4655
4665
|
path4.join(os4.homedir(), ".node9", "hook-debug.log"),
|
|
@@ -4900,10 +4910,10 @@ function getConfig(cwd) {
|
|
|
4900
4910
|
}
|
|
4901
4911
|
if (Array.isArray(mc.jailPaths)) {
|
|
4902
4912
|
for (const jp of mc.jailPaths) {
|
|
4903
|
-
const
|
|
4904
|
-
if (!
|
|
4913
|
+
const path72 = typeof jp?.path === "string" ? jp.path.trim() : "";
|
|
4914
|
+
if (!path72) continue;
|
|
4905
4915
|
const verdict = jp?.verdict === "review" ? "review" : "block";
|
|
4906
|
-
for (const r of pathRules(
|
|
4916
|
+
for (const r of pathRules(path72, verdict, "org-managed jail")) {
|
|
4907
4917
|
mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
|
|
4908
4918
|
}
|
|
4909
4919
|
}
|
|
@@ -5056,7 +5066,7 @@ ${error.replace("Invalid config:\n", "")}
|
|
|
5056
5066
|
}
|
|
5057
5067
|
return sanitized;
|
|
5058
5068
|
}
|
|
5059
|
-
var DANGEROUS_WORDS, DEFAULT_CONFIG, ADVISORY_SMART_RULES, cachedConfig,
|
|
5069
|
+
var DANGEROUS_WORDS, DEFAULT_CONFIG, ADVISORY_SMART_RULES, cachedConfig, lastParsedRulesCache, CACHE_LOG_REARM_MS, cacheReadLastLoggedAt;
|
|
5060
5070
|
var init_config = __esm({
|
|
5061
5071
|
"src/config/index.ts"() {
|
|
5062
5072
|
"use strict";
|
|
@@ -5343,7 +5353,9 @@ var init_config = __esm({
|
|
|
5343
5353
|
}
|
|
5344
5354
|
];
|
|
5345
5355
|
cachedConfig = null;
|
|
5346
|
-
|
|
5356
|
+
lastParsedRulesCache = null;
|
|
5357
|
+
CACHE_LOG_REARM_MS = 5 * 60 * 1e3;
|
|
5358
|
+
cacheReadLastLoggedAt = 0;
|
|
5347
5359
|
}
|
|
5348
5360
|
});
|
|
5349
5361
|
|
|
@@ -6064,6 +6076,18 @@ async function isDaemonReachable(timeoutMs = 500) {
|
|
|
6064
6076
|
return false;
|
|
6065
6077
|
}
|
|
6066
6078
|
}
|
|
6079
|
+
async function probeDaemonHealth(timeoutMs = 800) {
|
|
6080
|
+
try {
|
|
6081
|
+
const res = await fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/health`, {
|
|
6082
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
6083
|
+
});
|
|
6084
|
+
if (!res.ok) return { kind: "no-health" };
|
|
6085
|
+
const j = await res.json().catch(() => null);
|
|
6086
|
+
return j && typeof j === "object" ? { kind: "health", health: j } : { kind: "no-health" };
|
|
6087
|
+
} catch {
|
|
6088
|
+
return { kind: "unreachable" };
|
|
6089
|
+
}
|
|
6090
|
+
}
|
|
6067
6091
|
async function daemonHasInteractiveApprover(timeoutMs = 400) {
|
|
6068
6092
|
try {
|
|
6069
6093
|
const res = await fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/approver`, {
|
|
@@ -7035,6 +7059,7 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
7035
7059
|
let riskMetadata;
|
|
7036
7060
|
let statefulRecoveryCommand;
|
|
7037
7061
|
let localSmartRuleMatched = false;
|
|
7062
|
+
let hardBlockDowngraded = false;
|
|
7038
7063
|
let taintWarning = null;
|
|
7039
7064
|
if (isNetworkTool(toolName, args)) {
|
|
7040
7065
|
const filePaths = extractFilePaths(toolName, args);
|
|
@@ -7276,6 +7301,7 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
7276
7301
|
return { approved: true, checkedBy: "local-policy" };
|
|
7277
7302
|
}
|
|
7278
7303
|
if (policyResult.decision === "block") {
|
|
7304
|
+
hardBlockDowngraded = true;
|
|
7279
7305
|
const daemonUp = isDaemonRunning();
|
|
7280
7306
|
let humanApproverReachable = false;
|
|
7281
7307
|
if (!policyResult.dependsOnStatePredicates?.length && daemonUp && !isTestEnv2) {
|
|
@@ -7349,7 +7375,8 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
7349
7375
|
explainableLabel = policyResult.blockedByLabel || "Local Config";
|
|
7350
7376
|
policyMatchedField = policyResult.matchedField;
|
|
7351
7377
|
policyMatchedWord = policyResult.matchedWord;
|
|
7352
|
-
if (policyResult.ruleName || policyResult.tier === 7
|
|
7378
|
+
if (policyResult.ruleName || policyResult.tier === 7 || hardBlockDowngraded)
|
|
7379
|
+
localSmartRuleMatched = true;
|
|
7353
7380
|
if (policyResult.ruleDescription) policyRuleDescription = policyResult.ruleDescription;
|
|
7354
7381
|
else if (policyResult.reason) policyRuleDescription = policyResult.reason;
|
|
7355
7382
|
riskMetadata = computeRiskMetadata(
|
|
@@ -7361,7 +7388,7 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
7361
7388
|
policyResult.ruleName
|
|
7362
7389
|
);
|
|
7363
7390
|
if (policyRuleDescription) riskMetadata.ruleDescription = policyRuleDescription.slice(0, 200);
|
|
7364
|
-
const persistent = policyResult.ruleName || policyResult.tier === 7 ? null : getPersistentDecision(toolName);
|
|
7391
|
+
const persistent = policyResult.ruleName || policyResult.tier === 7 || hardBlockDowngraded ? null : getPersistentDecision(toolName);
|
|
7365
7392
|
if (persistent === "allow" && !appPermReview) {
|
|
7366
7393
|
if (!isManual) appendLocalAudit(toolName, args, "allow", "persistent", meta, hashAuditArgs);
|
|
7367
7394
|
return { approved: true, checkedBy: "persistent" };
|
|
@@ -7394,7 +7421,7 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
7394
7421
|
return { approved: true };
|
|
7395
7422
|
}
|
|
7396
7423
|
}
|
|
7397
|
-
if (!taintWarning && !appPermReview && getActiveTrustSession(toolName, args)) {
|
|
7424
|
+
if (!taintWarning && !appPermReview && !hardBlockDowngraded && getActiveTrustSession(toolName, args)) {
|
|
7398
7425
|
if (!isManual) appendLocalAudit(toolName, args, "allow", "trust", meta, hashAuditArgs);
|
|
7399
7426
|
return { approved: true, checkedBy: "trust" };
|
|
7400
7427
|
}
|
|
@@ -7434,7 +7461,7 @@ ${appPermReview}`
|
|
|
7434
7461
|
}
|
|
7435
7462
|
}
|
|
7436
7463
|
const cloudEnforcedForDefer = approvers.cloud && !!creds?.apiKey;
|
|
7437
|
-
if (options?.deferReview && !taintWarning && !appPermReview && !cloudEnforcedForDefer) {
|
|
7464
|
+
if (options?.deferReview && !hardBlockDowngraded && !taintWarning && !appPermReview && !cloudEnforcedForDefer) {
|
|
7438
7465
|
return {
|
|
7439
7466
|
approved: false,
|
|
7440
7467
|
review: true,
|
|
@@ -7458,7 +7485,7 @@ ${appPermReview}`
|
|
|
7458
7485
|
forceReview
|
|
7459
7486
|
);
|
|
7460
7487
|
if (!initResult.pending) {
|
|
7461
|
-
if (initResult.shadowMode && !appPermReview) {
|
|
7488
|
+
if (initResult.shadowMode && !localSmartRuleMatched && !options?.localSmartRuleMatched && !appPermReview) {
|
|
7462
7489
|
return { approved: true, checkedBy: "cloud" };
|
|
7463
7490
|
}
|
|
7464
7491
|
if (!localSmartRuleMatched && !options?.localSmartRuleMatched && !appPermReview) {
|
|
@@ -15482,6 +15509,73 @@ var init_scan = __esm({
|
|
|
15482
15509
|
}
|
|
15483
15510
|
});
|
|
15484
15511
|
|
|
15512
|
+
// src/daemon/build-id.ts
|
|
15513
|
+
import fs27 from "fs";
|
|
15514
|
+
import path29 from "path";
|
|
15515
|
+
function readOwnVersion() {
|
|
15516
|
+
for (const rel of ["../package.json", "../../package.json"]) {
|
|
15517
|
+
try {
|
|
15518
|
+
const raw = fs27.readFileSync(path29.join(__dirname, rel), "utf-8");
|
|
15519
|
+
const v = JSON.parse(raw).version;
|
|
15520
|
+
if (typeof v === "string" && v.length > 0) return v;
|
|
15521
|
+
} catch {
|
|
15522
|
+
}
|
|
15523
|
+
}
|
|
15524
|
+
return "0.0.0";
|
|
15525
|
+
}
|
|
15526
|
+
function computeBuildId(entry = process.argv[1] ?? "") {
|
|
15527
|
+
let mtimeMs = 0;
|
|
15528
|
+
try {
|
|
15529
|
+
if (entry) mtimeMs = fs27.statSync(entry).mtimeMs;
|
|
15530
|
+
} catch {
|
|
15531
|
+
}
|
|
15532
|
+
return { version: readOwnVersion(), mtimeMs };
|
|
15533
|
+
}
|
|
15534
|
+
function buildIdString(b) {
|
|
15535
|
+
return `${b.version}+${Math.round(b.mtimeMs)}`;
|
|
15536
|
+
}
|
|
15537
|
+
function parseBuildId(s) {
|
|
15538
|
+
if (typeof s !== "string") return null;
|
|
15539
|
+
const at = s.lastIndexOf("+");
|
|
15540
|
+
if (at <= 0) return null;
|
|
15541
|
+
const version2 = s.slice(0, at);
|
|
15542
|
+
const mtimeMs = Number(s.slice(at + 1));
|
|
15543
|
+
if (!/^\d+(\.\d+){2}/.test(version2) || !Number.isFinite(mtimeMs) || mtimeMs < 0) return null;
|
|
15544
|
+
return { version: version2, mtimeMs };
|
|
15545
|
+
}
|
|
15546
|
+
function compareVersion(a, b) {
|
|
15547
|
+
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
15548
|
+
const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
|
|
15549
|
+
for (let i = 0; i < 3; i++) {
|
|
15550
|
+
const d = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
15551
|
+
if (d !== 0) return d;
|
|
15552
|
+
}
|
|
15553
|
+
return 0;
|
|
15554
|
+
}
|
|
15555
|
+
function compareBuild(a, b) {
|
|
15556
|
+
const v = compareVersion(a.version, b.version);
|
|
15557
|
+
if (v !== 0) return v;
|
|
15558
|
+
return a.mtimeMs - b.mtimeMs;
|
|
15559
|
+
}
|
|
15560
|
+
function describeBuildDrift(running, installed) {
|
|
15561
|
+
const mine = buildIdString(installed);
|
|
15562
|
+
if (running === null) return null;
|
|
15563
|
+
if (running === "no-health") {
|
|
15564
|
+
return `running daemon predates the installed build (no /health \u2014 older than v${installed.version}) \u2014 it is enforcing OLD code`;
|
|
15565
|
+
}
|
|
15566
|
+
const theirs = typeof running.buildId === "string" ? running.buildId : null;
|
|
15567
|
+
if (!theirs || theirs === mine) return null;
|
|
15568
|
+
const theirVersion = typeof running.version === "string" ? running.version : "unknown";
|
|
15569
|
+
return `running daemon is v${theirVersion} (build ${theirs}) but installed is v${installed.version} (build ${mine}) \u2014 it is enforcing a different build`;
|
|
15570
|
+
}
|
|
15571
|
+
var CURRENT_BUILD;
|
|
15572
|
+
var init_build_id = __esm({
|
|
15573
|
+
"src/daemon/build-id.ts"() {
|
|
15574
|
+
"use strict";
|
|
15575
|
+
CURRENT_BUILD = parseBuildId(process.env.NODE9_BUILD_ID_OVERRIDE) ?? computeBuildId();
|
|
15576
|
+
}
|
|
15577
|
+
});
|
|
15578
|
+
|
|
15485
15579
|
// src/daemon/suggestion-tracker.ts
|
|
15486
15580
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
15487
15581
|
function extractPath(args) {
|
|
@@ -15573,8 +15667,8 @@ var init_suggestion_tracker = __esm({
|
|
|
15573
15667
|
});
|
|
15574
15668
|
|
|
15575
15669
|
// src/daemon/taint-store.ts
|
|
15576
|
-
import
|
|
15577
|
-
import
|
|
15670
|
+
import fs28 from "fs";
|
|
15671
|
+
import path30 from "path";
|
|
15578
15672
|
var DEFAULT_TTL_MS, TaintStore, SESSION_TAINT_TTL_MS, SessionTaintStore;
|
|
15579
15673
|
var init_taint_store = __esm({
|
|
15580
15674
|
"src/daemon/taint-store.ts"() {
|
|
@@ -15644,9 +15738,9 @@ var init_taint_store = __esm({
|
|
|
15644
15738
|
/** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
|
|
15645
15739
|
_resolve(filePath) {
|
|
15646
15740
|
try {
|
|
15647
|
-
return
|
|
15741
|
+
return fs28.realpathSync.native(path30.resolve(filePath));
|
|
15648
15742
|
} catch {
|
|
15649
|
-
return
|
|
15743
|
+
return path30.resolve(filePath);
|
|
15650
15744
|
}
|
|
15651
15745
|
}
|
|
15652
15746
|
};
|
|
@@ -15811,14 +15905,14 @@ var init_session_history = __esm({
|
|
|
15811
15905
|
|
|
15812
15906
|
// src/daemon/state.ts
|
|
15813
15907
|
import net2 from "net";
|
|
15814
|
-
import
|
|
15815
|
-
import
|
|
15908
|
+
import fs29 from "fs";
|
|
15909
|
+
import path31 from "path";
|
|
15816
15910
|
import os26 from "os";
|
|
15817
15911
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
15818
15912
|
function loadInsightCounts() {
|
|
15819
15913
|
try {
|
|
15820
|
-
if (!
|
|
15821
|
-
const data = JSON.parse(
|
|
15914
|
+
if (!fs29.existsSync(INSIGHT_COUNTS_FILE)) return;
|
|
15915
|
+
const data = JSON.parse(fs29.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
|
|
15822
15916
|
for (const [tool, count] of Object.entries(data)) {
|
|
15823
15917
|
if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
|
|
15824
15918
|
}
|
|
@@ -15857,23 +15951,23 @@ function markRejectionHandlerRegistered() {
|
|
|
15857
15951
|
daemonRejectionHandlerRegistered = true;
|
|
15858
15952
|
}
|
|
15859
15953
|
function atomicWriteSync2(filePath, data, options) {
|
|
15860
|
-
const dir =
|
|
15861
|
-
if (!
|
|
15954
|
+
const dir = path31.dirname(filePath);
|
|
15955
|
+
if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
|
|
15862
15956
|
const tmpPath = `${filePath}.${randomUUID3()}.tmp`;
|
|
15863
15957
|
try {
|
|
15864
|
-
|
|
15958
|
+
fs29.writeFileSync(tmpPath, data, options);
|
|
15865
15959
|
} catch (err2) {
|
|
15866
15960
|
try {
|
|
15867
|
-
|
|
15961
|
+
fs29.unlinkSync(tmpPath);
|
|
15868
15962
|
} catch {
|
|
15869
15963
|
}
|
|
15870
15964
|
throw err2;
|
|
15871
15965
|
}
|
|
15872
15966
|
try {
|
|
15873
|
-
|
|
15967
|
+
fs29.renameSync(tmpPath, filePath);
|
|
15874
15968
|
} catch (err2) {
|
|
15875
15969
|
try {
|
|
15876
|
-
|
|
15970
|
+
fs29.unlinkSync(tmpPath);
|
|
15877
15971
|
} catch {
|
|
15878
15972
|
}
|
|
15879
15973
|
throw err2;
|
|
@@ -15897,16 +15991,16 @@ function appendAuditLog(data) {
|
|
|
15897
15991
|
decision: data.decision,
|
|
15898
15992
|
source: "daemon"
|
|
15899
15993
|
};
|
|
15900
|
-
const dir =
|
|
15901
|
-
if (!
|
|
15902
|
-
|
|
15994
|
+
const dir = path31.dirname(AUDIT_LOG_FILE);
|
|
15995
|
+
if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
|
|
15996
|
+
fs29.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
15903
15997
|
} catch {
|
|
15904
15998
|
}
|
|
15905
15999
|
}
|
|
15906
16000
|
function getAuditHistory(limit = 20) {
|
|
15907
16001
|
try {
|
|
15908
|
-
if (!
|
|
15909
|
-
const lines =
|
|
16002
|
+
if (!fs29.existsSync(AUDIT_LOG_FILE)) return [];
|
|
16003
|
+
const lines = fs29.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
|
|
15910
16004
|
if (lines.length === 1 && lines[0] === "") return [];
|
|
15911
16005
|
return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
|
|
15912
16006
|
} catch {
|
|
@@ -15915,7 +16009,7 @@ function getAuditHistory(limit = 20) {
|
|
|
15915
16009
|
}
|
|
15916
16010
|
function getOrgName() {
|
|
15917
16011
|
try {
|
|
15918
|
-
if (
|
|
16012
|
+
if (fs29.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
|
|
15919
16013
|
} catch {
|
|
15920
16014
|
}
|
|
15921
16015
|
return null;
|
|
@@ -15923,8 +16017,8 @@ function getOrgName() {
|
|
|
15923
16017
|
function writeGlobalSetting(key, value) {
|
|
15924
16018
|
let config = {};
|
|
15925
16019
|
try {
|
|
15926
|
-
if (
|
|
15927
|
-
config = JSON.parse(
|
|
16020
|
+
if (fs29.existsSync(GLOBAL_CONFIG_FILE)) {
|
|
16021
|
+
config = JSON.parse(fs29.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
|
|
15928
16022
|
}
|
|
15929
16023
|
} catch {
|
|
15930
16024
|
}
|
|
@@ -15936,8 +16030,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
15936
16030
|
try {
|
|
15937
16031
|
let trust = { entries: [] };
|
|
15938
16032
|
try {
|
|
15939
|
-
if (
|
|
15940
|
-
trust = JSON.parse(
|
|
16033
|
+
if (fs29.existsSync(TRUST_FILE2))
|
|
16034
|
+
trust = JSON.parse(fs29.readFileSync(TRUST_FILE2, "utf-8"));
|
|
15941
16035
|
} catch {
|
|
15942
16036
|
}
|
|
15943
16037
|
trust.entries = trust.entries.filter(
|
|
@@ -15954,8 +16048,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
15954
16048
|
}
|
|
15955
16049
|
function readPersistentDecisions() {
|
|
15956
16050
|
try {
|
|
15957
|
-
if (
|
|
15958
|
-
return JSON.parse(
|
|
16051
|
+
if (fs29.existsSync(DECISIONS_FILE)) {
|
|
16052
|
+
return JSON.parse(fs29.readFileSync(DECISIONS_FILE, "utf-8"));
|
|
15959
16053
|
}
|
|
15960
16054
|
} catch {
|
|
15961
16055
|
}
|
|
@@ -15983,7 +16077,7 @@ function estimateToolCost(tool, args) {
|
|
|
15983
16077
|
const filePath = a.file_path ?? a.path;
|
|
15984
16078
|
if (filePath) {
|
|
15985
16079
|
try {
|
|
15986
|
-
const bytes =
|
|
16080
|
+
const bytes = fs29.statSync(filePath).size;
|
|
15987
16081
|
return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
|
|
15988
16082
|
} catch {
|
|
15989
16083
|
}
|
|
@@ -16057,7 +16151,7 @@ function abandonPending() {
|
|
|
16057
16151
|
});
|
|
16058
16152
|
if (autoStarted) {
|
|
16059
16153
|
try {
|
|
16060
|
-
|
|
16154
|
+
fs29.unlinkSync(DAEMON_PID_FILE);
|
|
16061
16155
|
} catch {
|
|
16062
16156
|
}
|
|
16063
16157
|
setTimeout(() => {
|
|
@@ -16068,8 +16162,8 @@ function abandonPending() {
|
|
|
16068
16162
|
}
|
|
16069
16163
|
function logActivitySocket(msg) {
|
|
16070
16164
|
try {
|
|
16071
|
-
|
|
16072
|
-
|
|
16165
|
+
fs29.appendFileSync(
|
|
16166
|
+
path31.join(homeDir, ".node9", "hook-debug.log"),
|
|
16073
16167
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
|
|
16074
16168
|
`
|
|
16075
16169
|
);
|
|
@@ -16091,13 +16185,13 @@ function shouldRebind(now = Date.now()) {
|
|
|
16091
16185
|
function startActivitySocket() {
|
|
16092
16186
|
bindActivitySocket();
|
|
16093
16187
|
activityHealthInterval = setInterval(() => {
|
|
16094
|
-
if (!
|
|
16188
|
+
if (!fs29.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
|
|
16095
16189
|
}, ACTIVITY_HEALTH_PROBE_MS);
|
|
16096
16190
|
activityHealthInterval.unref();
|
|
16097
16191
|
process.on("exit", () => {
|
|
16098
16192
|
if (activityHealthInterval) clearInterval(activityHealthInterval);
|
|
16099
16193
|
try {
|
|
16100
|
-
|
|
16194
|
+
fs29.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
16101
16195
|
} catch {
|
|
16102
16196
|
}
|
|
16103
16197
|
});
|
|
@@ -16125,7 +16219,7 @@ function attemptRebind(reason) {
|
|
|
16125
16219
|
}
|
|
16126
16220
|
function bindActivitySocket() {
|
|
16127
16221
|
try {
|
|
16128
|
-
|
|
16222
|
+
fs29.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
16129
16223
|
} catch {
|
|
16130
16224
|
}
|
|
16131
16225
|
const ACTIVITY_MAX_BYTES = 1024 * 1024;
|
|
@@ -16239,13 +16333,13 @@ var init_state2 = __esm({
|
|
|
16239
16333
|
init_session_counters();
|
|
16240
16334
|
init_session_history();
|
|
16241
16335
|
homeDir = os26.homedir();
|
|
16242
|
-
DAEMON_PID_FILE =
|
|
16243
|
-
DECISIONS_FILE =
|
|
16244
|
-
AUDIT_LOG_FILE =
|
|
16245
|
-
TRUST_FILE2 =
|
|
16246
|
-
GLOBAL_CONFIG_FILE =
|
|
16247
|
-
CREDENTIALS_FILE =
|
|
16248
|
-
INSIGHT_COUNTS_FILE =
|
|
16336
|
+
DAEMON_PID_FILE = path31.join(homeDir, ".node9", "daemon.pid");
|
|
16337
|
+
DECISIONS_FILE = path31.join(homeDir, ".node9", "decisions.json");
|
|
16338
|
+
AUDIT_LOG_FILE = path31.join(homeDir, ".node9", "audit.log");
|
|
16339
|
+
TRUST_FILE2 = path31.join(homeDir, ".node9", "trust.json");
|
|
16340
|
+
GLOBAL_CONFIG_FILE = path31.join(homeDir, ".node9", "config.json");
|
|
16341
|
+
CREDENTIALS_FILE = path31.join(homeDir, ".node9", "credentials.json");
|
|
16342
|
+
INSIGHT_COUNTS_FILE = path31.join(homeDir, ".node9", "insight-counts.json");
|
|
16249
16343
|
pending = /* @__PURE__ */ new Map();
|
|
16250
16344
|
sseClients = /* @__PURE__ */ new Set();
|
|
16251
16345
|
suggestionTracker = new SuggestionTracker(3);
|
|
@@ -16263,7 +16357,7 @@ var init_state2 = __esm({
|
|
|
16263
16357
|
"2h": 2 * 60 * 6e4
|
|
16264
16358
|
};
|
|
16265
16359
|
autoStarted = process.env.NODE9_AUTO_STARTED === "1";
|
|
16266
|
-
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
16360
|
+
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path31.join(os26.tmpdir(), "node9-activity.sock");
|
|
16267
16361
|
ACTIVITY_RING_SIZE = 100;
|
|
16268
16362
|
activityRing = [];
|
|
16269
16363
|
LARGE_RESPONSE_RING_SIZE = 20;
|
|
@@ -16302,20 +16396,20 @@ var init_state2 = __esm({
|
|
|
16302
16396
|
});
|
|
16303
16397
|
|
|
16304
16398
|
// src/posture/secrets.ts
|
|
16305
|
-
import
|
|
16306
|
-
import
|
|
16399
|
+
import fs30 from "fs";
|
|
16400
|
+
import path32 from "path";
|
|
16307
16401
|
import os27 from "os";
|
|
16308
16402
|
function displayPath(p, home) {
|
|
16309
16403
|
if (p === home) return "~";
|
|
16310
|
-
const prefix = home.endsWith(
|
|
16311
|
-
if (p.startsWith(prefix)) return "~" +
|
|
16404
|
+
const prefix = home.endsWith(path32.sep) ? home : home + path32.sep;
|
|
16405
|
+
if (p.startsWith(prefix)) return "~" + path32.sep + p.slice(prefix.length);
|
|
16312
16406
|
return p;
|
|
16313
16407
|
}
|
|
16314
16408
|
function safeRead(file) {
|
|
16315
16409
|
try {
|
|
16316
|
-
const stat =
|
|
16410
|
+
const stat = fs30.statSync(file);
|
|
16317
16411
|
if (!stat.isFile() || stat.size === 0 || stat.size > MAX_FILE_BYTES) return null;
|
|
16318
|
-
return
|
|
16412
|
+
return fs30.readFileSync(file, "utf8");
|
|
16319
16413
|
} catch {
|
|
16320
16414
|
return null;
|
|
16321
16415
|
}
|
|
@@ -16323,8 +16417,8 @@ function safeRead(file) {
|
|
|
16323
16417
|
function candidateFiles(home, cwd) {
|
|
16324
16418
|
const files = /* @__PURE__ */ new Set();
|
|
16325
16419
|
try {
|
|
16326
|
-
for (const name of
|
|
16327
|
-
if (name === ".env" || name.startsWith(".env.")) files.add(
|
|
16420
|
+
for (const name of fs30.readdirSync(cwd)) {
|
|
16421
|
+
if (name === ".env" || name.startsWith(".env.")) files.add(path32.join(cwd, name));
|
|
16328
16422
|
}
|
|
16329
16423
|
} catch {
|
|
16330
16424
|
}
|
|
@@ -16332,17 +16426,17 @@ function candidateFiles(home, cwd) {
|
|
|
16332
16426
|
if (spec.hookFile) files.add(spec.hookFile(home));
|
|
16333
16427
|
if (spec.mcpFile) files.add(spec.mcpFile(home));
|
|
16334
16428
|
}
|
|
16335
|
-
files.add(
|
|
16429
|
+
files.add(path32.join(home, ".env"));
|
|
16336
16430
|
return [...files];
|
|
16337
16431
|
}
|
|
16338
16432
|
function credentialMaterial(home) {
|
|
16339
16433
|
return [
|
|
16340
|
-
|
|
16341
|
-
|
|
16342
|
-
|
|
16343
|
-
|
|
16344
|
-
|
|
16345
|
-
|
|
16434
|
+
path32.join(home, ".ssh", "id_rsa"),
|
|
16435
|
+
path32.join(home, ".ssh", "id_dsa"),
|
|
16436
|
+
path32.join(home, ".ssh", "id_ecdsa"),
|
|
16437
|
+
path32.join(home, ".ssh", "id_ed25519"),
|
|
16438
|
+
path32.join(home, ".aws", "credentials"),
|
|
16439
|
+
path32.join(home, ".config", "gcloud", "application_default_credentials.json")
|
|
16346
16440
|
];
|
|
16347
16441
|
}
|
|
16348
16442
|
function checkSecrets(ctx) {
|
|
@@ -16379,7 +16473,7 @@ function checkSecrets(ctx) {
|
|
|
16379
16473
|
const credPaths = [];
|
|
16380
16474
|
for (const file of credentialMaterial(home)) {
|
|
16381
16475
|
try {
|
|
16382
|
-
if (
|
|
16476
|
+
if (fs30.statSync(file).isFile()) {
|
|
16383
16477
|
creds.push(displayPath(file, home));
|
|
16384
16478
|
credPaths.push(file);
|
|
16385
16479
|
}
|
|
@@ -16535,10 +16629,10 @@ var init_templates = __esm({
|
|
|
16535
16629
|
});
|
|
16536
16630
|
|
|
16537
16631
|
// src/posture/egress.ts
|
|
16538
|
-
import
|
|
16632
|
+
import fs31 from "fs";
|
|
16539
16633
|
function sandboxEgressWallActive() {
|
|
16540
16634
|
try {
|
|
16541
|
-
return
|
|
16635
|
+
return fs31.existsSync(ALLOWED_DOMAINS_PATH);
|
|
16542
16636
|
} catch {
|
|
16543
16637
|
return false;
|
|
16544
16638
|
}
|
|
@@ -16660,23 +16754,23 @@ var init_gate = __esm({
|
|
|
16660
16754
|
});
|
|
16661
16755
|
|
|
16662
16756
|
// src/posture/supply-chain.ts
|
|
16663
|
-
import
|
|
16757
|
+
import fs32 from "fs";
|
|
16664
16758
|
import os28 from "os";
|
|
16665
|
-
import
|
|
16759
|
+
import path33 from "path";
|
|
16666
16760
|
import { parse as parseToml3 } from "smol-toml";
|
|
16667
16761
|
function isNode9Managed(command, args = []) {
|
|
16668
16762
|
if (!command) return false;
|
|
16669
|
-
if (
|
|
16670
|
-
if (PACKAGE_RUNNERS.has(
|
|
16671
|
-
return args.some((a) => a === "node9" ||
|
|
16763
|
+
if (path33.basename(command).toLowerCase() === "node9") return true;
|
|
16764
|
+
if (PACKAGE_RUNNERS.has(path33.basename(command).toLowerCase())) {
|
|
16765
|
+
return args.some((a) => a === "node9" || path33.basename(a).toLowerCase() === "node9");
|
|
16672
16766
|
}
|
|
16673
16767
|
return false;
|
|
16674
16768
|
}
|
|
16675
16769
|
function readServers(file, format, agent) {
|
|
16676
16770
|
try {
|
|
16677
|
-
const stat =
|
|
16771
|
+
const stat = fs32.statSync(file);
|
|
16678
16772
|
if (!stat.isFile() || stat.size > MAX_CONFIG_BYTES) return [];
|
|
16679
|
-
const text =
|
|
16773
|
+
const text = fs32.readFileSync(file, "utf8");
|
|
16680
16774
|
const map = format === "toml" ? parseToml3(text)?.mcp_servers : JSON.parse(text)?.mcpServers;
|
|
16681
16775
|
if (!map || typeof map !== "object") return [];
|
|
16682
16776
|
return Object.entries(map).map(([name, v]) => ({
|
|
@@ -16788,11 +16882,11 @@ var init_privilege = __esm({
|
|
|
16788
16882
|
});
|
|
16789
16883
|
|
|
16790
16884
|
// src/posture/containment.ts
|
|
16791
|
-
import
|
|
16885
|
+
import fs33 from "fs";
|
|
16792
16886
|
function inContainer() {
|
|
16793
|
-
if (
|
|
16887
|
+
if (fs33.existsSync("/.dockerenv") || fs33.existsSync("/run/.containerenv")) return true;
|
|
16794
16888
|
try {
|
|
16795
|
-
const cgroup =
|
|
16889
|
+
const cgroup = fs33.readFileSync("/proc/1/cgroup", "utf8");
|
|
16796
16890
|
if (/docker|kubepods|containerd|lxc|libpod/.test(cgroup)) return true;
|
|
16797
16891
|
} catch {
|
|
16798
16892
|
}
|
|
@@ -16838,7 +16932,7 @@ var init_containment = __esm({
|
|
|
16838
16932
|
});
|
|
16839
16933
|
|
|
16840
16934
|
// src/posture/inbound.ts
|
|
16841
|
-
import
|
|
16935
|
+
import fs34 from "fs";
|
|
16842
16936
|
function buildNetworkFix(labels) {
|
|
16843
16937
|
const shielded = [
|
|
16844
16938
|
...new Map(
|
|
@@ -16896,7 +16990,7 @@ function collectListeners() {
|
|
|
16896
16990
|
const byPort = /* @__PURE__ */ new Map();
|
|
16897
16991
|
for (const file of ["/proc/net/tcp", "/proc/net/tcp6"]) {
|
|
16898
16992
|
try {
|
|
16899
|
-
for (const l of parseListeners(
|
|
16993
|
+
for (const l of parseListeners(fs34.readFileSync(file, "utf8"))) {
|
|
16900
16994
|
if (!byPort.has(l.port)) byPort.set(l.port, l);
|
|
16901
16995
|
}
|
|
16902
16996
|
} catch {
|
|
@@ -16908,11 +17002,11 @@ function readProc(pid) {
|
|
|
16908
17002
|
let comm = "unknown";
|
|
16909
17003
|
let cmdline = "";
|
|
16910
17004
|
try {
|
|
16911
|
-
comm =
|
|
17005
|
+
comm = fs34.readFileSync(`/proc/${pid}/comm`, "utf8").trim().replace(/-MainThread$/, "") || "unknown";
|
|
16912
17006
|
} catch {
|
|
16913
17007
|
}
|
|
16914
17008
|
try {
|
|
16915
|
-
cmdline =
|
|
17009
|
+
cmdline = fs34.readFileSync(`/proc/${pid}/cmdline`).toString().replace(/\0/g, " ").trim();
|
|
16916
17010
|
} catch {
|
|
16917
17011
|
}
|
|
16918
17012
|
return { comm, cmdline };
|
|
@@ -16922,21 +17016,21 @@ function resolveProcesses(inodes) {
|
|
|
16922
17016
|
if (inodes.size === 0) return map;
|
|
16923
17017
|
let pids;
|
|
16924
17018
|
try {
|
|
16925
|
-
pids =
|
|
17019
|
+
pids = fs34.readdirSync("/proc").filter((d) => /^\d+$/.test(d));
|
|
16926
17020
|
} catch {
|
|
16927
17021
|
return map;
|
|
16928
17022
|
}
|
|
16929
17023
|
for (const pid of pids) {
|
|
16930
17024
|
let fds;
|
|
16931
17025
|
try {
|
|
16932
|
-
fds =
|
|
17026
|
+
fds = fs34.readdirSync(`/proc/${pid}/fd`);
|
|
16933
17027
|
} catch {
|
|
16934
17028
|
continue;
|
|
16935
17029
|
}
|
|
16936
17030
|
for (const fd of fds) {
|
|
16937
17031
|
let link;
|
|
16938
17032
|
try {
|
|
16939
|
-
link =
|
|
17033
|
+
link = fs34.readlinkSync(`/proc/${pid}/fd/${fd}`);
|
|
16940
17034
|
} catch {
|
|
16941
17035
|
continue;
|
|
16942
17036
|
}
|
|
@@ -17085,7 +17179,7 @@ var init_coverage = __esm({
|
|
|
17085
17179
|
});
|
|
17086
17180
|
|
|
17087
17181
|
// src/posture/governance.ts
|
|
17088
|
-
import
|
|
17182
|
+
import path34 from "path";
|
|
17089
17183
|
function checkData(ctx) {
|
|
17090
17184
|
const dlp = getConfig(ctx.cwd).policy.dlp;
|
|
17091
17185
|
if (!dlp?.enabled) {
|
|
@@ -17230,7 +17324,7 @@ var init_governance = __esm({
|
|
|
17230
17324
|
"src/posture/governance.ts"() {
|
|
17231
17325
|
"use strict";
|
|
17232
17326
|
init_config();
|
|
17233
|
-
jailProbePath = (home) =>
|
|
17327
|
+
jailProbePath = (home) => path34.join(home, ".aws", "credentials");
|
|
17234
17328
|
}
|
|
17235
17329
|
});
|
|
17236
17330
|
|
|
@@ -17697,8 +17791,8 @@ var init_mcp_cmd = __esm({
|
|
|
17697
17791
|
});
|
|
17698
17792
|
|
|
17699
17793
|
// src/daemon/mcp-tools.ts
|
|
17700
|
-
import
|
|
17701
|
-
import
|
|
17794
|
+
import fs35 from "fs";
|
|
17795
|
+
import path35 from "path";
|
|
17702
17796
|
import os31 from "os";
|
|
17703
17797
|
function deriveServerName(cmd) {
|
|
17704
17798
|
if (!cmd || typeof cmd !== "string") return "MCP Server";
|
|
@@ -17725,13 +17819,13 @@ function deriveServerName(cmd) {
|
|
|
17725
17819
|
return strip(base) || "MCP Server";
|
|
17726
17820
|
}
|
|
17727
17821
|
function getMcpToolsFile() {
|
|
17728
|
-
return
|
|
17822
|
+
return path35.join(os31.homedir(), ".node9", "mcp-tools.json");
|
|
17729
17823
|
}
|
|
17730
17824
|
function readMcpToolsConfig() {
|
|
17731
17825
|
try {
|
|
17732
17826
|
const file = getMcpToolsFile();
|
|
17733
|
-
if (!
|
|
17734
|
-
const raw =
|
|
17827
|
+
if (!fs35.existsSync(file)) return {};
|
|
17828
|
+
const raw = fs35.readFileSync(file, "utf-8");
|
|
17735
17829
|
return JSON.parse(raw);
|
|
17736
17830
|
} catch {
|
|
17737
17831
|
return {};
|
|
@@ -17740,11 +17834,11 @@ function readMcpToolsConfig() {
|
|
|
17740
17834
|
function writeMcpToolsConfig(config) {
|
|
17741
17835
|
try {
|
|
17742
17836
|
const file = getMcpToolsFile();
|
|
17743
|
-
const dir =
|
|
17744
|
-
if (!
|
|
17837
|
+
const dir = path35.dirname(file);
|
|
17838
|
+
if (!fs35.existsSync(dir)) fs35.mkdirSync(dir, { recursive: true });
|
|
17745
17839
|
const tmpPath = `${file}.${os31.hostname()}.${process.pid}.tmp`;
|
|
17746
|
-
|
|
17747
|
-
|
|
17840
|
+
fs35.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
|
|
17841
|
+
fs35.renameSync(tmpPath, file);
|
|
17748
17842
|
} catch (e) {
|
|
17749
17843
|
console.error("Failed to write mcp-tools.json", e);
|
|
17750
17844
|
}
|
|
@@ -17799,7 +17893,7 @@ var init_mcp_tools = __esm({
|
|
|
17799
17893
|
});
|
|
17800
17894
|
|
|
17801
17895
|
// src/mcp-wrap.ts
|
|
17802
|
-
import
|
|
17896
|
+
import fs36 from "fs";
|
|
17803
17897
|
import os32 from "os";
|
|
17804
17898
|
import { parse as parseToml4, stringify as stringifyToml2 } from "smol-toml";
|
|
17805
17899
|
function isNode9Command(command) {
|
|
@@ -17872,11 +17966,11 @@ function inventoryServerKeys(inv) {
|
|
|
17872
17966
|
function writeMcpEntry(mcpFile, format, name, entry) {
|
|
17873
17967
|
const key = format === "toml" ? "mcp_servers" : "mcpServers";
|
|
17874
17968
|
let root = {};
|
|
17875
|
-
if (
|
|
17876
|
-
const raw =
|
|
17969
|
+
if (fs36.existsSync(mcpFile)) {
|
|
17970
|
+
const raw = fs36.readFileSync(mcpFile, "utf-8");
|
|
17877
17971
|
root = format === "toml" ? parseToml4(raw) : JSON.parse(raw);
|
|
17878
17972
|
const bak = `${mcpFile}.node9-bak`;
|
|
17879
|
-
if (!
|
|
17973
|
+
if (!fs36.existsSync(bak)) fs36.writeFileSync(bak, raw, { mode: 384 });
|
|
17880
17974
|
}
|
|
17881
17975
|
const existing = root[key];
|
|
17882
17976
|
const servers = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
|
|
@@ -17884,8 +17978,8 @@ function writeMcpEntry(mcpFile, format, name, entry) {
|
|
|
17884
17978
|
root[key] = servers;
|
|
17885
17979
|
const serialized = format === "toml" ? stringifyToml2(root) : JSON.stringify(root, null, 2);
|
|
17886
17980
|
const tmp = `${mcpFile}.${process.pid}.tmp`;
|
|
17887
|
-
|
|
17888
|
-
|
|
17981
|
+
fs36.writeFileSync(tmp, serialized, { mode: 384 });
|
|
17982
|
+
fs36.renameSync(tmp, mcpFile);
|
|
17889
17983
|
}
|
|
17890
17984
|
var init_mcp_wrap = __esm({
|
|
17891
17985
|
"src/mcp-wrap.ts"() {
|
|
@@ -18012,10 +18106,10 @@ var init_ship2 = __esm({
|
|
|
18012
18106
|
});
|
|
18013
18107
|
|
|
18014
18108
|
// src/daemon/sync.ts
|
|
18015
|
-
import
|
|
18109
|
+
import fs37 from "fs";
|
|
18016
18110
|
import https4 from "https";
|
|
18017
18111
|
import os33 from "os";
|
|
18018
|
-
import
|
|
18112
|
+
import path36 from "path";
|
|
18019
18113
|
function emptySignals3() {
|
|
18020
18114
|
return {
|
|
18021
18115
|
dlpFindings: 0,
|
|
@@ -18060,8 +18154,8 @@ function readCredentials() {
|
|
|
18060
18154
|
};
|
|
18061
18155
|
}
|
|
18062
18156
|
try {
|
|
18063
|
-
const credPath =
|
|
18064
|
-
const creds = JSON.parse(
|
|
18157
|
+
const credPath = path36.join(os33.homedir(), ".node9", "credentials.json");
|
|
18158
|
+
const creds = JSON.parse(fs37.readFileSync(credPath, "utf-8"));
|
|
18065
18159
|
const profileName = process.env.NODE9_PROFILE ?? "default";
|
|
18066
18160
|
const profile = creds[profileName];
|
|
18067
18161
|
if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
|
|
@@ -18087,7 +18181,7 @@ function readCredentials() {
|
|
|
18087
18181
|
}
|
|
18088
18182
|
function readCachedEtag() {
|
|
18089
18183
|
try {
|
|
18090
|
-
const raw = JSON.parse(
|
|
18184
|
+
const raw = JSON.parse(fs37.readFileSync(rulesCacheFile(), "utf-8"));
|
|
18091
18185
|
return typeof raw.etag === "string" ? raw.etag : void 0;
|
|
18092
18186
|
} catch {
|
|
18093
18187
|
return void 0;
|
|
@@ -18095,7 +18189,7 @@ function readCachedEtag() {
|
|
|
18095
18189
|
}
|
|
18096
18190
|
function readCachedSyncIntervalHours() {
|
|
18097
18191
|
try {
|
|
18098
|
-
const raw = JSON.parse(
|
|
18192
|
+
const raw = JSON.parse(fs37.readFileSync(rulesCacheFile(), "utf-8"));
|
|
18099
18193
|
return typeof raw.syncIntervalHours === "number" ? raw.syncIntervalHours : void 0;
|
|
18100
18194
|
} catch {
|
|
18101
18195
|
return void 0;
|
|
@@ -18112,7 +18206,7 @@ function effectiveSyncIntervalMs() {
|
|
|
18112
18206
|
}
|
|
18113
18207
|
function readSyncHealth() {
|
|
18114
18208
|
try {
|
|
18115
|
-
const raw = JSON.parse(
|
|
18209
|
+
const raw = JSON.parse(fs37.readFileSync(syncHealthFile(), "utf-8"));
|
|
18116
18210
|
return {
|
|
18117
18211
|
lastCheckedAt: typeof raw.lastCheckedAt === "string" ? raw.lastCheckedAt : void 0,
|
|
18118
18212
|
lastChangedAt: typeof raw.lastChangedAt === "string" ? raw.lastChangedAt : void 0,
|
|
@@ -18127,17 +18221,17 @@ function readSyncHealth() {
|
|
|
18127
18221
|
function writeSyncHealth(h) {
|
|
18128
18222
|
try {
|
|
18129
18223
|
const file = syncHealthFile();
|
|
18130
|
-
const dir =
|
|
18131
|
-
if (!
|
|
18224
|
+
const dir = path36.dirname(file);
|
|
18225
|
+
if (!fs37.existsSync(dir)) fs37.mkdirSync(dir, { recursive: true });
|
|
18132
18226
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
18133
|
-
|
|
18134
|
-
|
|
18227
|
+
fs37.writeFileSync(tmp, JSON.stringify(h, null, 2) + "\n", "utf-8");
|
|
18228
|
+
fs37.renameSync(tmp, file);
|
|
18135
18229
|
} catch {
|
|
18136
18230
|
}
|
|
18137
18231
|
}
|
|
18138
18232
|
function readCacheFetchedAt() {
|
|
18139
18233
|
try {
|
|
18140
|
-
const raw = JSON.parse(
|
|
18234
|
+
const raw = JSON.parse(fs37.readFileSync(rulesCacheFile(), "utf-8"));
|
|
18141
18235
|
return typeof raw.fetchedAt === "string" ? raw.fetchedAt : void 0;
|
|
18142
18236
|
} catch {
|
|
18143
18237
|
return void 0;
|
|
@@ -18323,8 +18417,24 @@ function extractManagedConfig(body) {
|
|
|
18323
18417
|
}
|
|
18324
18418
|
return out.mode !== void 0 || out.egress !== void 0 || out.dlp !== void 0 || out.approvers !== void 0 || out.reviewChannel !== void 0 || out.approvalTimeoutMs !== void 0 || out.injectionScan !== void 0 || out.loopDetection !== void 0 || out.skillPinning !== void 0 || out.jailPaths !== void 0 || out.trustedHosts !== void 0 || out.appPermissions !== void 0 ? out : void 0;
|
|
18325
18419
|
}
|
|
18420
|
+
function sweepStaleTmp(target) {
|
|
18421
|
+
try {
|
|
18422
|
+
const dir = path36.dirname(target);
|
|
18423
|
+
const prefix = `${path36.basename(target)}.`;
|
|
18424
|
+
for (const name of fs37.readdirSync(dir)) {
|
|
18425
|
+
if (!name.startsWith(prefix) || !name.endsWith(".tmp")) continue;
|
|
18426
|
+
const full = path36.join(dir, name);
|
|
18427
|
+
try {
|
|
18428
|
+
if (Date.now() - fs37.statSync(full).mtimeMs > 5 * 60 * 1e3) fs37.unlinkSync(full);
|
|
18429
|
+
} catch {
|
|
18430
|
+
}
|
|
18431
|
+
}
|
|
18432
|
+
} catch {
|
|
18433
|
+
}
|
|
18434
|
+
}
|
|
18326
18435
|
function writeCache2(cache) {
|
|
18327
18436
|
const data = JSON.stringify(cache, null, 2) + "\n";
|
|
18437
|
+
sweepStaleTmp(rulesCacheFile());
|
|
18328
18438
|
atomicWriteSync2(rulesCacheFile(), data, "utf-8");
|
|
18329
18439
|
try {
|
|
18330
18440
|
atomicWriteSync2(rulesCacheBackupFile(), data, "utf-8");
|
|
@@ -18571,7 +18681,7 @@ async function runCloudSync() {
|
|
|
18571
18681
|
}
|
|
18572
18682
|
function getCloudSyncStatus() {
|
|
18573
18683
|
try {
|
|
18574
|
-
const raw = JSON.parse(
|
|
18684
|
+
const raw = JSON.parse(fs37.readFileSync(rulesCacheFile(), "utf-8"));
|
|
18575
18685
|
if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
|
|
18576
18686
|
return {
|
|
18577
18687
|
cached: true,
|
|
@@ -18588,7 +18698,7 @@ function getCloudSyncStatus() {
|
|
|
18588
18698
|
}
|
|
18589
18699
|
function getCloudRules() {
|
|
18590
18700
|
try {
|
|
18591
|
-
const raw = JSON.parse(
|
|
18701
|
+
const raw = JSON.parse(fs37.readFileSync(rulesCacheFile(), "utf-8"));
|
|
18592
18702
|
return Array.isArray(raw.rules) ? raw.rules : null;
|
|
18593
18703
|
} catch {
|
|
18594
18704
|
return null;
|
|
@@ -18653,13 +18763,13 @@ var init_sync = __esm({
|
|
|
18653
18763
|
loop: "loops",
|
|
18654
18764
|
"long-output-redacted": "longOutputRedactions"
|
|
18655
18765
|
};
|
|
18656
|
-
rulesCacheFile = () =>
|
|
18657
|
-
rulesCacheBackupFile = () =>
|
|
18766
|
+
rulesCacheFile = () => path36.join(os33.homedir(), ".node9", "rules-cache.json");
|
|
18767
|
+
rulesCacheBackupFile = () => path36.join(os33.homedir(), ".node9", "rules-cache.last-good.json");
|
|
18658
18768
|
DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept/policies/sync";
|
|
18659
18769
|
DEFAULT_INTERVAL_HOURS = 5;
|
|
18660
18770
|
MIN_INTERVAL_SECONDS = 15;
|
|
18661
18771
|
MAX_INTERVAL_SECONDS = 24 * 60 * 60;
|
|
18662
|
-
syncHealthFile = () =>
|
|
18772
|
+
syncHealthFile = () => path36.join(os33.homedir(), ".node9", "sync-health.json");
|
|
18663
18773
|
STALE_MIN_MS = 3 * 60 * 60 * 1e3;
|
|
18664
18774
|
STALE_MAX_MS = 24 * 60 * 60 * 1e3;
|
|
18665
18775
|
STALE_FACTOR = 3;
|
|
@@ -18682,26 +18792,26 @@ __export(audit_shipper_exports, {
|
|
|
18682
18792
|
startAuditShipper: () => startAuditShipper,
|
|
18683
18793
|
writeWatermark: () => writeWatermark
|
|
18684
18794
|
});
|
|
18685
|
-
import
|
|
18686
|
-
import
|
|
18795
|
+
import fs38 from "fs";
|
|
18796
|
+
import path37 from "path";
|
|
18687
18797
|
import os34 from "os";
|
|
18688
18798
|
import crypto5 from "crypto";
|
|
18689
18799
|
function fileSignature(filePath) {
|
|
18690
|
-
const fd =
|
|
18800
|
+
const fd = fs38.openSync(filePath, "r");
|
|
18691
18801
|
try {
|
|
18692
18802
|
const buf = Buffer.alloc(512);
|
|
18693
|
-
const read2 =
|
|
18803
|
+
const read2 = fs38.readSync(fd, buf, 0, 512, 0);
|
|
18694
18804
|
const slice = buf.subarray(0, read2);
|
|
18695
18805
|
const nl = slice.indexOf(10);
|
|
18696
18806
|
const firstLine = nl === -1 ? slice : slice.subarray(0, nl);
|
|
18697
18807
|
return crypto5.createHash("sha256").update(firstLine).digest("hex").slice(0, 16);
|
|
18698
18808
|
} finally {
|
|
18699
|
-
|
|
18809
|
+
fs38.closeSync(fd);
|
|
18700
18810
|
}
|
|
18701
18811
|
}
|
|
18702
18812
|
function readWatermark(watermarkPath) {
|
|
18703
18813
|
try {
|
|
18704
|
-
const raw = JSON.parse(
|
|
18814
|
+
const raw = JSON.parse(fs38.readFileSync(watermarkPath, "utf-8"));
|
|
18705
18815
|
if (typeof raw.fileSig === "string" && typeof raw.offset === "number" && raw.offset >= 0)
|
|
18706
18816
|
return raw;
|
|
18707
18817
|
} catch {
|
|
@@ -18710,8 +18820,8 @@ function readWatermark(watermarkPath) {
|
|
|
18710
18820
|
}
|
|
18711
18821
|
function writeWatermark(watermarkPath, wm) {
|
|
18712
18822
|
const tmp = `${watermarkPath}.tmp`;
|
|
18713
|
-
|
|
18714
|
-
|
|
18823
|
+
fs38.writeFileSync(tmp, JSON.stringify(wm));
|
|
18824
|
+
fs38.renameSync(tmp, watermarkPath);
|
|
18715
18825
|
}
|
|
18716
18826
|
function buildWireRows(chunk2) {
|
|
18717
18827
|
const lastNl = chunk2.lastIndexOf(10);
|
|
@@ -18789,11 +18899,11 @@ async function shipOnce(deps = {}) {
|
|
|
18789
18899
|
if (!creds?.apiKey) return { status: "no-creds", shipped: 0 };
|
|
18790
18900
|
const endpoint = buildBatchEndpoint(creds.apiUrl);
|
|
18791
18901
|
if (!endpoint) return { status: "no-creds", shipped: 0 };
|
|
18792
|
-
if (!
|
|
18902
|
+
if (!fs38.existsSync(auditLogPath)) return { status: "idle", shipped: 0 };
|
|
18793
18903
|
let shipped = 0;
|
|
18794
18904
|
try {
|
|
18795
18905
|
for (let chunkN = 0; chunkN < MAX_CHUNKS_PER_TICK; chunkN++) {
|
|
18796
|
-
const size =
|
|
18906
|
+
const size = fs38.statSync(auditLogPath).size;
|
|
18797
18907
|
if (size === 0) break;
|
|
18798
18908
|
const sig = fileSignature(auditLogPath);
|
|
18799
18909
|
const wm = readWatermark(watermarkPath);
|
|
@@ -18801,12 +18911,12 @@ async function shipOnce(deps = {}) {
|
|
|
18801
18911
|
if (offset >= size) break;
|
|
18802
18912
|
const toRead = Math.min(size - offset, MAX_CHUNK_BYTES);
|
|
18803
18913
|
const buf = Buffer.alloc(toRead);
|
|
18804
|
-
const fd =
|
|
18914
|
+
const fd = fs38.openSync(auditLogPath, "r");
|
|
18805
18915
|
let read2;
|
|
18806
18916
|
try {
|
|
18807
|
-
read2 =
|
|
18917
|
+
read2 = fs38.readSync(fd, buf, 0, toRead, offset);
|
|
18808
18918
|
} finally {
|
|
18809
|
-
|
|
18919
|
+
fs38.closeSync(fd);
|
|
18810
18920
|
}
|
|
18811
18921
|
const { rows, consumed } = buildWireRows(buf.subarray(0, read2));
|
|
18812
18922
|
if (consumed === 0) break;
|
|
@@ -18853,8 +18963,8 @@ async function shipOnce(deps = {}) {
|
|
|
18853
18963
|
}
|
|
18854
18964
|
function shipLagBytes(auditLogPath = LOCAL_AUDIT_LOG, watermarkPath = AUDIT_SHIP_WATERMARK) {
|
|
18855
18965
|
try {
|
|
18856
|
-
if (!
|
|
18857
|
-
const size =
|
|
18966
|
+
if (!fs38.existsSync(auditLogPath)) return 0;
|
|
18967
|
+
const size = fs38.statSync(auditLogPath).size;
|
|
18858
18968
|
const wm = readWatermark(watermarkPath);
|
|
18859
18969
|
if (!wm) return size;
|
|
18860
18970
|
if (wm.fileSig !== fileSignature(auditLogPath)) return size;
|
|
@@ -18885,7 +18995,7 @@ var init_audit_shipper = __esm({
|
|
|
18885
18995
|
init_config();
|
|
18886
18996
|
init_sync();
|
|
18887
18997
|
init_cloud();
|
|
18888
|
-
AUDIT_SHIP_WATERMARK =
|
|
18998
|
+
AUDIT_SHIP_WATERMARK = path37.join(os34.homedir(), ".node9", "audit-ship.json");
|
|
18889
18999
|
DEFAULT_INTERVAL_MS = 2e4;
|
|
18890
19000
|
MAX_BATCH = 500;
|
|
18891
19001
|
MAX_CHUNK_BYTES = 4 * 1024 * 1024;
|
|
@@ -18944,12 +19054,12 @@ var init_decision = __esm({
|
|
|
18944
19054
|
});
|
|
18945
19055
|
|
|
18946
19056
|
// src/daemon/dlp-scanner.ts
|
|
18947
|
-
import
|
|
18948
|
-
import
|
|
19057
|
+
import fs39 from "fs";
|
|
19058
|
+
import path38 from "path";
|
|
18949
19059
|
import os35 from "os";
|
|
18950
19060
|
function loadIndex() {
|
|
18951
19061
|
try {
|
|
18952
|
-
const raw = JSON.parse(
|
|
19062
|
+
const raw = JSON.parse(fs39.readFileSync(INDEX_FILE, "utf-8"));
|
|
18953
19063
|
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
18954
19064
|
const r = raw;
|
|
18955
19065
|
if (r.offsets && typeof r.offsets === "object") return r.offsets;
|
|
@@ -18961,63 +19071,63 @@ function loadIndex() {
|
|
|
18961
19071
|
}
|
|
18962
19072
|
function saveIndex(index) {
|
|
18963
19073
|
try {
|
|
18964
|
-
|
|
19074
|
+
fs39.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
|
|
18965
19075
|
} catch {
|
|
18966
19076
|
}
|
|
18967
19077
|
}
|
|
18968
19078
|
function appendAuditEntry(entry) {
|
|
18969
19079
|
try {
|
|
18970
|
-
|
|
19080
|
+
fs39.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
18971
19081
|
} catch {
|
|
18972
19082
|
}
|
|
18973
19083
|
}
|
|
18974
19084
|
function runDlpScan() {
|
|
18975
|
-
if (!
|
|
19085
|
+
if (!fs39.existsSync(PROJECTS_DIR2)) return;
|
|
18976
19086
|
const index = loadIndex();
|
|
18977
19087
|
const seenThisPass = /* @__PURE__ */ new Set();
|
|
18978
19088
|
const newFindings = [];
|
|
18979
19089
|
let updated = false;
|
|
18980
19090
|
let projDirs;
|
|
18981
19091
|
try {
|
|
18982
|
-
projDirs =
|
|
19092
|
+
projDirs = fs39.readdirSync(PROJECTS_DIR2);
|
|
18983
19093
|
} catch {
|
|
18984
19094
|
return;
|
|
18985
19095
|
}
|
|
18986
19096
|
for (const proj of projDirs) {
|
|
18987
|
-
const projPath =
|
|
19097
|
+
const projPath = path38.join(PROJECTS_DIR2, proj);
|
|
18988
19098
|
try {
|
|
18989
|
-
if (!
|
|
18990
|
-
const real =
|
|
18991
|
-
if (!real.startsWith(PROJECTS_DIR2 +
|
|
19099
|
+
if (!fs39.lstatSync(projPath).isDirectory()) continue;
|
|
19100
|
+
const real = fs39.realpathSync(projPath);
|
|
19101
|
+
if (!real.startsWith(PROJECTS_DIR2 + path38.sep) && real !== PROJECTS_DIR2) continue;
|
|
18992
19102
|
} catch {
|
|
18993
19103
|
continue;
|
|
18994
19104
|
}
|
|
18995
19105
|
let files;
|
|
18996
19106
|
try {
|
|
18997
|
-
files =
|
|
19107
|
+
files = fs39.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
18998
19108
|
} catch {
|
|
18999
19109
|
continue;
|
|
19000
19110
|
}
|
|
19001
19111
|
for (const file of files) {
|
|
19002
|
-
const filePath =
|
|
19112
|
+
const filePath = path38.join(projPath, file);
|
|
19003
19113
|
const lastOffset = index[filePath] ?? 0;
|
|
19004
19114
|
let size;
|
|
19005
19115
|
try {
|
|
19006
|
-
size =
|
|
19116
|
+
size = fs39.statSync(filePath).size;
|
|
19007
19117
|
} catch {
|
|
19008
19118
|
continue;
|
|
19009
19119
|
}
|
|
19010
19120
|
if (size <= lastOffset) continue;
|
|
19011
19121
|
let fd;
|
|
19012
19122
|
try {
|
|
19013
|
-
fd =
|
|
19123
|
+
fd = fs39.openSync(filePath, "r");
|
|
19014
19124
|
} catch {
|
|
19015
19125
|
continue;
|
|
19016
19126
|
}
|
|
19017
19127
|
try {
|
|
19018
19128
|
const chunkSize = size - lastOffset;
|
|
19019
19129
|
const buf = Buffer.alloc(chunkSize);
|
|
19020
|
-
|
|
19130
|
+
fs39.readSync(fd, buf, 0, chunkSize, lastOffset);
|
|
19021
19131
|
const chunk2 = buf.toString("utf-8");
|
|
19022
19132
|
for (const line of chunk2.split("\n")) {
|
|
19023
19133
|
if (!line.trim()) continue;
|
|
@@ -19064,7 +19174,7 @@ function runDlpScan() {
|
|
|
19064
19174
|
updated = true;
|
|
19065
19175
|
} finally {
|
|
19066
19176
|
try {
|
|
19067
|
-
|
|
19177
|
+
fs39.closeSync(fd);
|
|
19068
19178
|
} catch {
|
|
19069
19179
|
}
|
|
19070
19180
|
}
|
|
@@ -19112,14 +19222,14 @@ var init_dlp_scanner = __esm({
|
|
|
19112
19222
|
init_dlp();
|
|
19113
19223
|
init_native();
|
|
19114
19224
|
init_state2();
|
|
19115
|
-
INDEX_FILE =
|
|
19116
|
-
PROJECTS_DIR2 =
|
|
19225
|
+
INDEX_FILE = path38.join(os35.homedir(), ".node9", "dlp-index.json");
|
|
19226
|
+
PROJECTS_DIR2 = path38.join(os35.homedir(), ".claude", "projects");
|
|
19117
19227
|
}
|
|
19118
19228
|
});
|
|
19119
19229
|
|
|
19120
19230
|
// src/daemon/mcp-reconciler.ts
|
|
19121
|
-
import
|
|
19122
|
-
import
|
|
19231
|
+
import fs40 from "fs";
|
|
19232
|
+
import path39 from "path";
|
|
19123
19233
|
import os36 from "os";
|
|
19124
19234
|
import crypto6 from "crypto";
|
|
19125
19235
|
function idKey(e) {
|
|
@@ -19128,7 +19238,7 @@ function idKey(e) {
|
|
|
19128
19238
|
}
|
|
19129
19239
|
function loadBaseline() {
|
|
19130
19240
|
try {
|
|
19131
|
-
const raw = JSON.parse(
|
|
19241
|
+
const raw = JSON.parse(fs40.readFileSync(BASELINE_FILE2, "utf-8"));
|
|
19132
19242
|
return new Set(Array.isArray(raw) ? raw : []);
|
|
19133
19243
|
} catch {
|
|
19134
19244
|
return /* @__PURE__ */ new Set();
|
|
@@ -19136,7 +19246,7 @@ function loadBaseline() {
|
|
|
19136
19246
|
}
|
|
19137
19247
|
function saveBaseline(keys) {
|
|
19138
19248
|
try {
|
|
19139
|
-
|
|
19249
|
+
fs40.writeFileSync(BASELINE_FILE2, JSON.stringify([...keys].slice(-BASELINE_CAP)), {
|
|
19140
19250
|
mode: 384
|
|
19141
19251
|
});
|
|
19142
19252
|
} catch {
|
|
@@ -19324,7 +19434,7 @@ var init_mcp_reconciler = __esm({
|
|
|
19324
19434
|
init_cloud();
|
|
19325
19435
|
init_audit();
|
|
19326
19436
|
init_mcp_pin();
|
|
19327
|
-
BASELINE_FILE2 =
|
|
19437
|
+
BASELINE_FILE2 = path39.join(os36.homedir(), ".node9", "mcp-baseline.json");
|
|
19328
19438
|
BASELINE_CAP = 500;
|
|
19329
19439
|
DEFAULT_INTERVAL_MIN = 60;
|
|
19330
19440
|
DEFAULT_STALE_DAYS = 7;
|
|
@@ -19399,22 +19509,22 @@ var init_hook_heal = __esm({
|
|
|
19399
19509
|
});
|
|
19400
19510
|
|
|
19401
19511
|
// src/daemon/startup-log.ts
|
|
19402
|
-
import
|
|
19403
|
-
import
|
|
19512
|
+
import fs41 from "fs";
|
|
19513
|
+
import path40 from "path";
|
|
19404
19514
|
import os37 from "os";
|
|
19405
19515
|
function capStartupLog(file) {
|
|
19406
19516
|
try {
|
|
19407
|
-
if (
|
|
19517
|
+
if (fs41.statSync(file).size > MAX_STARTUP_LOG_BYTES) fs41.truncateSync(file);
|
|
19408
19518
|
} catch {
|
|
19409
19519
|
}
|
|
19410
19520
|
}
|
|
19411
19521
|
function openStartupLogFd() {
|
|
19412
19522
|
try {
|
|
19413
19523
|
const file = DAEMON_STARTUP_LOG();
|
|
19414
|
-
const dir =
|
|
19415
|
-
if (!
|
|
19524
|
+
const dir = path40.dirname(file);
|
|
19525
|
+
if (!fs41.existsSync(dir)) fs41.mkdirSync(dir, { recursive: true });
|
|
19416
19526
|
capStartupLog(file);
|
|
19417
|
-
return
|
|
19527
|
+
return fs41.openSync(file, "a");
|
|
19418
19528
|
} catch {
|
|
19419
19529
|
return void 0;
|
|
19420
19530
|
}
|
|
@@ -19430,18 +19540,18 @@ function recordStartupState(outcome, kind, detail) {
|
|
|
19430
19540
|
}
|
|
19431
19541
|
}
|
|
19432
19542
|
const file = DAEMON_STARTUP_STATE();
|
|
19433
|
-
const dir =
|
|
19434
|
-
if (!
|
|
19543
|
+
const dir = path40.dirname(file);
|
|
19544
|
+
if (!fs41.existsSync(dir)) fs41.mkdirSync(dir, { recursive: true });
|
|
19435
19545
|
const state = { outcome, at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
19436
19546
|
if (kind) state.kind = kind;
|
|
19437
19547
|
if (detail) state.detail = detail.slice(0, MAX_DETAIL);
|
|
19438
19548
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
19439
19549
|
try {
|
|
19440
|
-
|
|
19441
|
-
|
|
19550
|
+
fs41.writeFileSync(tmp, JSON.stringify(state), "utf-8");
|
|
19551
|
+
fs41.renameSync(tmp, file);
|
|
19442
19552
|
} catch (err2) {
|
|
19443
19553
|
try {
|
|
19444
|
-
|
|
19554
|
+
fs41.unlinkSync(tmp);
|
|
19445
19555
|
} catch {
|
|
19446
19556
|
}
|
|
19447
19557
|
throw err2;
|
|
@@ -19451,7 +19561,7 @@ function recordStartupState(outcome, kind, detail) {
|
|
|
19451
19561
|
}
|
|
19452
19562
|
function readStartupState() {
|
|
19453
19563
|
try {
|
|
19454
|
-
const raw =
|
|
19564
|
+
const raw = fs41.readFileSync(DAEMON_STARTUP_STATE(), "utf-8");
|
|
19455
19565
|
const s = JSON.parse(raw);
|
|
19456
19566
|
if (!s || typeof s.outcome !== "string" || typeof s.at !== "string") return null;
|
|
19457
19567
|
return s;
|
|
@@ -19486,11 +19596,11 @@ function readStartupCause(maxAgeMs = 24 * 60 * 60 * 1e3) {
|
|
|
19486
19596
|
function logDaemonStartup(kind, detail) {
|
|
19487
19597
|
try {
|
|
19488
19598
|
const file = DAEMON_STARTUP_LOG();
|
|
19489
|
-
const dir =
|
|
19490
|
-
if (!
|
|
19599
|
+
const dir = path40.dirname(file);
|
|
19600
|
+
if (!fs41.existsSync(dir)) fs41.mkdirSync(dir, { recursive: true });
|
|
19491
19601
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-startup:${kind}${detail ? ` ${detail}` : ""}
|
|
19492
19602
|
`;
|
|
19493
|
-
|
|
19603
|
+
fs41.appendFileSync(file, line, "utf-8");
|
|
19494
19604
|
} catch {
|
|
19495
19605
|
}
|
|
19496
19606
|
}
|
|
@@ -19498,9 +19608,9 @@ var DAEMON_STARTUP_LOG, MAX_STARTUP_LOG_BYTES, DAEMON_STARTUP_STATE, MAX_DETAIL,
|
|
|
19498
19608
|
var init_startup_log = __esm({
|
|
19499
19609
|
"src/daemon/startup-log.ts"() {
|
|
19500
19610
|
"use strict";
|
|
19501
|
-
DAEMON_STARTUP_LOG = () =>
|
|
19611
|
+
DAEMON_STARTUP_LOG = () => path40.join(os37.homedir(), ".node9", "daemon-startup.log");
|
|
19502
19612
|
MAX_STARTUP_LOG_BYTES = 256 * 1024;
|
|
19503
|
-
DAEMON_STARTUP_STATE = () =>
|
|
19613
|
+
DAEMON_STARTUP_STATE = () => path40.join(os37.homedir(), ".node9", "daemon-startup-state.json");
|
|
19504
19614
|
MAX_DETAIL = 200;
|
|
19505
19615
|
STARTING_GRACE_MS = 90 * 1e3;
|
|
19506
19616
|
}
|
|
@@ -19508,8 +19618,8 @@ var init_startup_log = __esm({
|
|
|
19508
19618
|
|
|
19509
19619
|
// src/daemon/server.ts
|
|
19510
19620
|
import http3 from "http";
|
|
19511
|
-
import
|
|
19512
|
-
import
|
|
19621
|
+
import fs42 from "fs";
|
|
19622
|
+
import path41 from "path";
|
|
19513
19623
|
import os38 from "os";
|
|
19514
19624
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
19515
19625
|
import { spawnSync } from "child_process";
|
|
@@ -19603,6 +19713,7 @@ function startDaemon() {
|
|
|
19603
19713
|
}
|
|
19604
19714
|
const internalToken = randomUUID4();
|
|
19605
19715
|
const validToken = (req) => req.headers["x-node9-internal"] === internalToken || req.headers["x-node9-token"] === internalToken;
|
|
19716
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
19606
19717
|
const IDLE_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
|
|
19607
19718
|
const watchMode = process.env.NODE9_WATCH_MODE === "1";
|
|
19608
19719
|
let idleTimer;
|
|
@@ -19612,7 +19723,7 @@ function startDaemon() {
|
|
|
19612
19723
|
idleTimer = setTimeout(() => {
|
|
19613
19724
|
if (autoStarted) {
|
|
19614
19725
|
try {
|
|
19615
|
-
|
|
19726
|
+
fs42.unlinkSync(DAEMON_PID_FILE);
|
|
19616
19727
|
} catch {
|
|
19617
19728
|
}
|
|
19618
19729
|
}
|
|
@@ -19757,7 +19868,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
19757
19868
|
mcpServer: entry.mcpServer
|
|
19758
19869
|
});
|
|
19759
19870
|
}
|
|
19760
|
-
const projectCwd = typeof cwd === "string" &&
|
|
19871
|
+
const projectCwd = typeof cwd === "string" && path41.isAbsolute(cwd) ? cwd : void 0;
|
|
19761
19872
|
const projectConfig = getConfig(projectCwd);
|
|
19762
19873
|
const browserEnabled = projectConfig.settings.approvers?.browser !== false;
|
|
19763
19874
|
const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
|
|
@@ -19975,6 +20086,35 @@ data: ${JSON.stringify(item.data)}
|
|
|
19975
20086
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
19976
20087
|
return res.end(JSON.stringify({ interactive: hasInteractiveClient() }));
|
|
19977
20088
|
}
|
|
20089
|
+
if (req.method === "POST" && pathname === "/shutdown") {
|
|
20090
|
+
if (!validToken(req)) {
|
|
20091
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
20092
|
+
return res.end(JSON.stringify({ error: "unauthorized" }));
|
|
20093
|
+
}
|
|
20094
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
20095
|
+
res.end(JSON.stringify({ ok: true }));
|
|
20096
|
+
logDaemonStartup("shutdown", "yielding on authenticated /shutdown (takeover or restart)");
|
|
20097
|
+
setImmediate(() => {
|
|
20098
|
+
try {
|
|
20099
|
+
server.close();
|
|
20100
|
+
} catch {
|
|
20101
|
+
}
|
|
20102
|
+
process.exit(0);
|
|
20103
|
+
});
|
|
20104
|
+
return;
|
|
20105
|
+
}
|
|
20106
|
+
if (req.method === "GET" && pathname === "/health") {
|
|
20107
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
20108
|
+
return res.end(
|
|
20109
|
+
JSON.stringify({
|
|
20110
|
+
version: CURRENT_BUILD.version,
|
|
20111
|
+
buildId: buildIdString(CURRENT_BUILD),
|
|
20112
|
+
pid: process.pid,
|
|
20113
|
+
startedAt,
|
|
20114
|
+
autoStarted
|
|
20115
|
+
})
|
|
20116
|
+
);
|
|
20117
|
+
}
|
|
19978
20118
|
if (req.method === "GET" && pathname === "/state/check") {
|
|
19979
20119
|
const predicatesParam = reqUrl.searchParams.get("predicates") ?? "";
|
|
19980
20120
|
const predicates = predicatesParam.split(",").filter(Boolean);
|
|
@@ -20053,8 +20193,8 @@ data: ${JSON.stringify(item.data)}
|
|
|
20053
20193
|
if (!validToken(req)) return res.writeHead(403).end();
|
|
20054
20194
|
const periodParam = reqUrl.searchParams.get("period") || "7d";
|
|
20055
20195
|
const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
|
|
20056
|
-
const logPath =
|
|
20057
|
-
if (!
|
|
20196
|
+
const logPath = path41.join(os38.homedir(), ".node9", "audit.log");
|
|
20197
|
+
if (!fs42.existsSync(logPath)) {
|
|
20058
20198
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
20059
20199
|
return res.end(
|
|
20060
20200
|
JSON.stringify({
|
|
@@ -20067,7 +20207,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
20067
20207
|
);
|
|
20068
20208
|
}
|
|
20069
20209
|
try {
|
|
20070
|
-
const raw =
|
|
20210
|
+
const raw = fs42.readFileSync(logPath, "utf-8");
|
|
20071
20211
|
const allEntries = raw.split("\n").flatMap((line) => {
|
|
20072
20212
|
if (!line.trim()) return [];
|
|
20073
20213
|
try {
|
|
@@ -20382,34 +20522,114 @@ data: ${JSON.stringify(item.data)}
|
|
|
20382
20522
|
setDaemonServer(server);
|
|
20383
20523
|
let bindAttempts = 0;
|
|
20384
20524
|
const MAX_BIND_ATTEMPTS = 3;
|
|
20525
|
+
let tookDownHolder = false;
|
|
20385
20526
|
function retryListen() {
|
|
20386
20527
|
if (++bindAttempts >= MAX_BIND_ATTEMPTS) {
|
|
20528
|
+
if (tookDownHolder) {
|
|
20529
|
+
logDaemonStartup(
|
|
20530
|
+
"takeover-bind-failed",
|
|
20531
|
+
`shut down the previous daemon but could not bind :${DAEMON_PORT} \u2014 the port was taken during handover`
|
|
20532
|
+
);
|
|
20533
|
+
recordStartupState(
|
|
20534
|
+
"failed",
|
|
20535
|
+
"takeover-bind-failed",
|
|
20536
|
+
`took over :${DAEMON_PORT} but could not rebind (the port was claimed during handover) \u2014 no daemon is serving; run: node9 daemon restart`
|
|
20537
|
+
);
|
|
20538
|
+
} else {
|
|
20539
|
+
logDaemonStartup(
|
|
20540
|
+
"port-unavailable",
|
|
20541
|
+
`:${DAEMON_PORT} is held by something that is not a node9 daemon`
|
|
20542
|
+
);
|
|
20543
|
+
recordStartupState(
|
|
20544
|
+
"failed",
|
|
20545
|
+
"port-unavailable",
|
|
20546
|
+
`:${DAEMON_PORT} is held by another process that is not a node9 daemon \u2014 free the port, then: node9 daemon --background`
|
|
20547
|
+
);
|
|
20548
|
+
}
|
|
20549
|
+
return process.exit(0);
|
|
20550
|
+
}
|
|
20551
|
+
server.listen(DAEMON_PORT, DAEMON_HOST);
|
|
20552
|
+
}
|
|
20553
|
+
async function decideAgainstHolder(holderPid, holderToken) {
|
|
20554
|
+
let holderBuildId = null;
|
|
20555
|
+
try {
|
|
20556
|
+
const res = await fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/health`, {
|
|
20557
|
+
signal: AbortSignal.timeout(800)
|
|
20558
|
+
});
|
|
20559
|
+
if (res.ok) {
|
|
20560
|
+
const j = await res.json().catch(() => null);
|
|
20561
|
+
if (j && typeof j.buildId === "string") holderBuildId = j.buildId;
|
|
20562
|
+
}
|
|
20563
|
+
} catch {
|
|
20564
|
+
}
|
|
20565
|
+
const holderBuild = holderBuildId ? parseBuildId(holderBuildId) : null;
|
|
20566
|
+
if (holderBuild && compareBuild(CURRENT_BUILD, holderBuild) > 0 && holderToken) {
|
|
20567
|
+
try {
|
|
20568
|
+
const r = await fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/shutdown`, {
|
|
20569
|
+
method: "POST",
|
|
20570
|
+
headers: { "x-node9-internal": holderToken },
|
|
20571
|
+
signal: AbortSignal.timeout(2e3)
|
|
20572
|
+
});
|
|
20573
|
+
if (r.ok) {
|
|
20574
|
+
for (let i = 0; i < 10; i++) {
|
|
20575
|
+
await new Promise((resolve2) => setTimeout(resolve2, 200));
|
|
20576
|
+
const stillUp = await fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/health`, {
|
|
20577
|
+
signal: AbortSignal.timeout(300)
|
|
20578
|
+
}).then(
|
|
20579
|
+
() => true,
|
|
20580
|
+
() => false
|
|
20581
|
+
);
|
|
20582
|
+
if (!stillUp) break;
|
|
20583
|
+
}
|
|
20584
|
+
logDaemonStartup(
|
|
20585
|
+
"takeover",
|
|
20586
|
+
`took over :${DAEMON_PORT} from older build ${holderBuildId} (pid ${holderPid})`
|
|
20587
|
+
);
|
|
20588
|
+
tookDownHolder = true;
|
|
20589
|
+
retryListen();
|
|
20590
|
+
return;
|
|
20591
|
+
}
|
|
20592
|
+
recordStartupState(
|
|
20593
|
+
"failed",
|
|
20594
|
+
"version-skew-unauthenticated",
|
|
20595
|
+
`an older-build daemon (${holderBuildId}) holds :${DAEMON_PORT} but could not be authenticated for takeover \u2014 run: node9 daemon restart`
|
|
20596
|
+
);
|
|
20597
|
+
logDaemonStartup("port-in-use", `older build on :${DAEMON_PORT}, /shutdown refused`);
|
|
20598
|
+
return process.exit(0);
|
|
20599
|
+
} catch {
|
|
20600
|
+
}
|
|
20601
|
+
}
|
|
20602
|
+
if (holderBuild && compareBuild(holderBuild, CURRENT_BUILD) > 0) {
|
|
20387
20603
|
logDaemonStartup(
|
|
20388
|
-
"port-
|
|
20389
|
-
|
|
20390
|
-
);
|
|
20391
|
-
recordStartupState(
|
|
20392
|
-
"failed",
|
|
20393
|
-
"port-unavailable",
|
|
20394
|
-
`:${DAEMON_PORT} is held by another process that is not a node9 daemon \u2014 free the port, then: node9 daemon --background`
|
|
20604
|
+
"port-in-use",
|
|
20605
|
+
`a NEWER daemon (${holderBuildId}, pid ${holderPid}) owns :${DAEMON_PORT} \u2014 yielding`
|
|
20395
20606
|
);
|
|
20607
|
+
recordStartupState("ok-elsewhere", "newer-daemon-running");
|
|
20396
20608
|
return process.exit(0);
|
|
20397
20609
|
}
|
|
20398
|
-
|
|
20610
|
+
logDaemonStartup("port-in-use", `another daemon (pid ${holderPid}) owns :${DAEMON_PORT}`);
|
|
20611
|
+
recordStartupState("ok-elsewhere");
|
|
20612
|
+
return process.exit(0);
|
|
20399
20613
|
}
|
|
20400
20614
|
server.on("error", (e) => {
|
|
20401
20615
|
if (e.code === "EADDRINUSE") {
|
|
20402
20616
|
try {
|
|
20403
|
-
if (
|
|
20404
|
-
const
|
|
20617
|
+
if (fs42.existsSync(DAEMON_PID_FILE)) {
|
|
20618
|
+
const parsed = JSON.parse(fs42.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
20619
|
+
const pid = parsed.pid;
|
|
20620
|
+
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > 4194304) {
|
|
20621
|
+
throw new Error("invalid pid in daemon.pid");
|
|
20622
|
+
}
|
|
20405
20623
|
process.kill(pid, 0);
|
|
20406
|
-
|
|
20407
|
-
|
|
20408
|
-
|
|
20624
|
+
void decideAgainstHolder(
|
|
20625
|
+
pid,
|
|
20626
|
+
typeof parsed.internalToken === "string" ? parsed.internalToken : null
|
|
20627
|
+
);
|
|
20628
|
+
return;
|
|
20409
20629
|
}
|
|
20410
20630
|
} catch {
|
|
20411
20631
|
try {
|
|
20412
|
-
|
|
20632
|
+
fs42.unlinkSync(DAEMON_PID_FILE);
|
|
20413
20633
|
} catch {
|
|
20414
20634
|
}
|
|
20415
20635
|
retryListen();
|
|
@@ -20444,7 +20664,12 @@ data: ${JSON.stringify(item.data)}
|
|
|
20444
20664
|
process.kill(orphanPid, 0);
|
|
20445
20665
|
atomicWriteSync2(
|
|
20446
20666
|
DAEMON_PID_FILE,
|
|
20447
|
-
JSON.stringify({
|
|
20667
|
+
JSON.stringify({
|
|
20668
|
+
pid: orphanPid,
|
|
20669
|
+
port: DAEMON_PORT,
|
|
20670
|
+
internalToken: null,
|
|
20671
|
+
autoStarted
|
|
20672
|
+
}),
|
|
20448
20673
|
{ mode: 384 }
|
|
20449
20674
|
);
|
|
20450
20675
|
adopted = true;
|
|
@@ -20492,7 +20717,15 @@ data: ${JSON.stringify(item.data)}
|
|
|
20492
20717
|
server.listen(DAEMON_PORT, DAEMON_HOST, () => {
|
|
20493
20718
|
atomicWriteSync2(
|
|
20494
20719
|
DAEMON_PID_FILE,
|
|
20495
|
-
JSON.stringify({
|
|
20720
|
+
JSON.stringify({
|
|
20721
|
+
pid: process.pid,
|
|
20722
|
+
port: DAEMON_PORT,
|
|
20723
|
+
internalToken,
|
|
20724
|
+
autoStarted,
|
|
20725
|
+
version: CURRENT_BUILD.version,
|
|
20726
|
+
buildId: buildIdString(CURRENT_BUILD),
|
|
20727
|
+
startedAt
|
|
20728
|
+
}),
|
|
20496
20729
|
{ mode: 384 }
|
|
20497
20730
|
);
|
|
20498
20731
|
console.error(chalk6.green(`\u{1F6E1}\uFE0F Node9 Guard LIVE on 127.0.0.1:${DAEMON_PORT}`));
|
|
@@ -20510,6 +20743,7 @@ var init_server = __esm({
|
|
|
20510
20743
|
init_core();
|
|
20511
20744
|
init_scan();
|
|
20512
20745
|
init_scan_summary();
|
|
20746
|
+
init_build_id();
|
|
20513
20747
|
init_state2();
|
|
20514
20748
|
init_state();
|
|
20515
20749
|
init_costSync();
|
|
@@ -20525,15 +20759,15 @@ var init_server = __esm({
|
|
|
20525
20759
|
});
|
|
20526
20760
|
|
|
20527
20761
|
// src/daemon/service.ts
|
|
20528
|
-
import
|
|
20529
|
-
import
|
|
20762
|
+
import fs43 from "fs";
|
|
20763
|
+
import path42 from "path";
|
|
20530
20764
|
import os39 from "os";
|
|
20531
20765
|
import { spawnSync as spawnSync2, execFileSync } from "child_process";
|
|
20532
20766
|
function resolveNode9Binary() {
|
|
20533
20767
|
try {
|
|
20534
20768
|
const script = process.argv[1];
|
|
20535
|
-
if (typeof script === "string" &&
|
|
20536
|
-
return
|
|
20769
|
+
if (typeof script === "string" && path42.isAbsolute(script) && fs43.existsSync(script)) {
|
|
20770
|
+
return fs43.realpathSync(script);
|
|
20537
20771
|
}
|
|
20538
20772
|
} catch {
|
|
20539
20773
|
}
|
|
@@ -20551,11 +20785,11 @@ function xmlEscape(s) {
|
|
|
20551
20785
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
20552
20786
|
}
|
|
20553
20787
|
function launchdPlist(binaryPath) {
|
|
20554
|
-
const logDir =
|
|
20788
|
+
const logDir = path42.join(os39.homedir(), ".node9");
|
|
20555
20789
|
const nodePath = xmlEscape(process.execPath);
|
|
20556
20790
|
const scriptPath = xmlEscape(binaryPath);
|
|
20557
|
-
const outLog = xmlEscape(
|
|
20558
|
-
const errLog = xmlEscape(
|
|
20791
|
+
const outLog = xmlEscape(path42.join(logDir, "daemon.log"));
|
|
20792
|
+
const errLog = xmlEscape(path42.join(logDir, "daemon-error.log"));
|
|
20559
20793
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
20560
20794
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
20561
20795
|
<plist version="1.0">
|
|
@@ -20588,9 +20822,9 @@ function launchdPlist(binaryPath) {
|
|
|
20588
20822
|
`;
|
|
20589
20823
|
}
|
|
20590
20824
|
function installLaunchd(binaryPath) {
|
|
20591
|
-
const dir =
|
|
20592
|
-
if (!
|
|
20593
|
-
|
|
20825
|
+
const dir = path42.dirname(LAUNCHD_PLIST);
|
|
20826
|
+
if (!fs43.existsSync(dir)) fs43.mkdirSync(dir, { recursive: true });
|
|
20827
|
+
fs43.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
|
|
20594
20828
|
spawnSync2("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
|
|
20595
20829
|
const r = spawnSync2("launchctl", ["load", "-w", LAUNCHD_PLIST], {
|
|
20596
20830
|
encoding: "utf8",
|
|
@@ -20601,13 +20835,13 @@ function installLaunchd(binaryPath) {
|
|
|
20601
20835
|
}
|
|
20602
20836
|
}
|
|
20603
20837
|
function uninstallLaunchd() {
|
|
20604
|
-
if (
|
|
20838
|
+
if (fs43.existsSync(LAUNCHD_PLIST)) {
|
|
20605
20839
|
spawnSync2("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
|
|
20606
|
-
|
|
20840
|
+
fs43.unlinkSync(LAUNCHD_PLIST);
|
|
20607
20841
|
}
|
|
20608
20842
|
}
|
|
20609
20843
|
function isLaunchdInstalled() {
|
|
20610
|
-
return
|
|
20844
|
+
return fs43.existsSync(LAUNCHD_PLIST);
|
|
20611
20845
|
}
|
|
20612
20846
|
function systemdUnit(binaryPath) {
|
|
20613
20847
|
return `[Unit]
|
|
@@ -20626,10 +20860,10 @@ WantedBy=default.target
|
|
|
20626
20860
|
`;
|
|
20627
20861
|
}
|
|
20628
20862
|
function installSystemd(binaryPath) {
|
|
20629
|
-
if (!
|
|
20630
|
-
|
|
20863
|
+
if (!fs43.existsSync(SYSTEMD_UNIT_DIR)) {
|
|
20864
|
+
fs43.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
|
|
20631
20865
|
}
|
|
20632
|
-
|
|
20866
|
+
fs43.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
|
|
20633
20867
|
try {
|
|
20634
20868
|
execFileSync("loginctl", ["enable-linger", os39.userInfo().username], { timeout: 3e3 });
|
|
20635
20869
|
} catch {
|
|
@@ -20651,23 +20885,23 @@ function installSystemd(binaryPath) {
|
|
|
20651
20885
|
}
|
|
20652
20886
|
}
|
|
20653
20887
|
function uninstallSystemd() {
|
|
20654
|
-
if (
|
|
20888
|
+
if (fs43.existsSync(SYSTEMD_UNIT)) {
|
|
20655
20889
|
spawnSync2("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
|
|
20656
20890
|
encoding: "utf8",
|
|
20657
20891
|
timeout: 5e3
|
|
20658
20892
|
});
|
|
20659
20893
|
spawnSync2("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
|
|
20660
|
-
|
|
20894
|
+
fs43.unlinkSync(SYSTEMD_UNIT);
|
|
20661
20895
|
}
|
|
20662
20896
|
}
|
|
20663
20897
|
function isSystemdInstalled() {
|
|
20664
|
-
return
|
|
20898
|
+
return fs43.existsSync(SYSTEMD_UNIT);
|
|
20665
20899
|
}
|
|
20666
20900
|
function stopRunningDaemon() {
|
|
20667
|
-
const pidFile =
|
|
20668
|
-
if (!
|
|
20901
|
+
const pidFile = path42.join(os39.homedir(), ".node9", "daemon.pid");
|
|
20902
|
+
if (!fs43.existsSync(pidFile)) return;
|
|
20669
20903
|
try {
|
|
20670
|
-
const data = JSON.parse(
|
|
20904
|
+
const data = JSON.parse(fs43.readFileSync(pidFile, "utf-8"));
|
|
20671
20905
|
const pid = data.pid;
|
|
20672
20906
|
const MAX_PID2 = 4194304;
|
|
20673
20907
|
if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
|
|
@@ -20687,7 +20921,7 @@ function stopRunningDaemon() {
|
|
|
20687
20921
|
}
|
|
20688
20922
|
}
|
|
20689
20923
|
try {
|
|
20690
|
-
|
|
20924
|
+
fs43.unlinkSync(pidFile);
|
|
20691
20925
|
} catch {
|
|
20692
20926
|
}
|
|
20693
20927
|
} catch {
|
|
@@ -20831,19 +21065,19 @@ var init_service = __esm({
|
|
|
20831
21065
|
"src/daemon/service.ts"() {
|
|
20832
21066
|
"use strict";
|
|
20833
21067
|
LAUNCHD_LABEL = "ai.node9.daemon";
|
|
20834
|
-
LAUNCHD_PLIST =
|
|
20835
|
-
SYSTEMD_UNIT_DIR =
|
|
20836
|
-
SYSTEMD_UNIT =
|
|
21068
|
+
LAUNCHD_PLIST = path42.join(os39.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
21069
|
+
SYSTEMD_UNIT_DIR = path42.join(os39.homedir(), ".config", "systemd", "user");
|
|
21070
|
+
SYSTEMD_UNIT = path42.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
|
|
20837
21071
|
}
|
|
20838
21072
|
});
|
|
20839
21073
|
|
|
20840
21074
|
// src/daemon/index.ts
|
|
20841
|
-
import
|
|
21075
|
+
import fs44 from "fs";
|
|
20842
21076
|
import chalk7 from "chalk";
|
|
20843
21077
|
function stopDaemon() {
|
|
20844
|
-
if (!
|
|
21078
|
+
if (!fs44.existsSync(DAEMON_PID_FILE)) return console.log(chalk7.yellow("Not running."));
|
|
20845
21079
|
try {
|
|
20846
|
-
const data = JSON.parse(
|
|
21080
|
+
const data = JSON.parse(fs44.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
20847
21081
|
const pid = data.pid;
|
|
20848
21082
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
20849
21083
|
console.log(chalk7.gray("Cleaned up invalid PID file."));
|
|
@@ -20855,7 +21089,7 @@ function stopDaemon() {
|
|
|
20855
21089
|
console.log(chalk7.gray("Cleaned up stale PID file."));
|
|
20856
21090
|
} finally {
|
|
20857
21091
|
try {
|
|
20858
|
-
|
|
21092
|
+
fs44.unlinkSync(DAEMON_PID_FILE);
|
|
20859
21093
|
} catch {
|
|
20860
21094
|
}
|
|
20861
21095
|
}
|
|
@@ -20864,9 +21098,9 @@ function daemonStatus() {
|
|
|
20864
21098
|
const serviceInstalled = isDaemonServiceInstalled();
|
|
20865
21099
|
const serviceLabel = serviceInstalled ? chalk7.green("installed (starts on login)") : chalk7.yellow("not installed \u2014 run: node9 daemon install");
|
|
20866
21100
|
let processStatus;
|
|
20867
|
-
if (
|
|
21101
|
+
if (fs44.existsSync(DAEMON_PID_FILE)) {
|
|
20868
21102
|
try {
|
|
20869
|
-
const data = JSON.parse(
|
|
21103
|
+
const data = JSON.parse(fs44.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
20870
21104
|
const pid = data.pid;
|
|
20871
21105
|
const port = data.port;
|
|
20872
21106
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
@@ -22009,14 +22243,14 @@ var require_util = __commonJS({
|
|
|
22009
22243
|
}
|
|
22010
22244
|
const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
|
|
22011
22245
|
let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
|
|
22012
|
-
let
|
|
22246
|
+
let path72 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
|
|
22013
22247
|
if (origin[origin.length - 1] === "/") {
|
|
22014
22248
|
origin = origin.slice(0, origin.length - 1);
|
|
22015
22249
|
}
|
|
22016
|
-
if (
|
|
22017
|
-
|
|
22250
|
+
if (path72 && path72[0] !== "/") {
|
|
22251
|
+
path72 = `/${path72}`;
|
|
22018
22252
|
}
|
|
22019
|
-
return new URL(`${origin}${
|
|
22253
|
+
return new URL(`${origin}${path72}`);
|
|
22020
22254
|
}
|
|
22021
22255
|
if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
|
|
22022
22256
|
throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
|
|
@@ -22837,9 +23071,9 @@ var require_diagnostics = __commonJS({
|
|
|
22837
23071
|
"undici:client:sendHeaders",
|
|
22838
23072
|
(evt) => {
|
|
22839
23073
|
const {
|
|
22840
|
-
request: { method, path:
|
|
23074
|
+
request: { method, path: path72, origin }
|
|
22841
23075
|
} = evt;
|
|
22842
|
-
debugLog("sending request to %s %s%s", method, origin,
|
|
23076
|
+
debugLog("sending request to %s %s%s", method, origin, path72);
|
|
22843
23077
|
}
|
|
22844
23078
|
);
|
|
22845
23079
|
}
|
|
@@ -22857,14 +23091,14 @@ var require_diagnostics = __commonJS({
|
|
|
22857
23091
|
"undici:request:headers",
|
|
22858
23092
|
(evt) => {
|
|
22859
23093
|
const {
|
|
22860
|
-
request: { method, path:
|
|
23094
|
+
request: { method, path: path72, origin },
|
|
22861
23095
|
response: { statusCode }
|
|
22862
23096
|
} = evt;
|
|
22863
23097
|
debugLog(
|
|
22864
23098
|
"received response to %s %s%s - HTTP %d",
|
|
22865
23099
|
method,
|
|
22866
23100
|
origin,
|
|
22867
|
-
|
|
23101
|
+
path72,
|
|
22868
23102
|
statusCode
|
|
22869
23103
|
);
|
|
22870
23104
|
}
|
|
@@ -22873,23 +23107,23 @@ var require_diagnostics = __commonJS({
|
|
|
22873
23107
|
"undici:request:trailers",
|
|
22874
23108
|
(evt) => {
|
|
22875
23109
|
const {
|
|
22876
|
-
request: { method, path:
|
|
23110
|
+
request: { method, path: path72, origin }
|
|
22877
23111
|
} = evt;
|
|
22878
|
-
debugLog("trailers received from %s %s%s", method, origin,
|
|
23112
|
+
debugLog("trailers received from %s %s%s", method, origin, path72);
|
|
22879
23113
|
}
|
|
22880
23114
|
);
|
|
22881
23115
|
diagnosticsChannel.subscribe(
|
|
22882
23116
|
"undici:request:error",
|
|
22883
23117
|
(evt) => {
|
|
22884
23118
|
const {
|
|
22885
|
-
request: { method, path:
|
|
23119
|
+
request: { method, path: path72, origin },
|
|
22886
23120
|
error
|
|
22887
23121
|
} = evt;
|
|
22888
23122
|
debugLog(
|
|
22889
23123
|
"request to %s %s%s errored - %s",
|
|
22890
23124
|
method,
|
|
22891
23125
|
origin,
|
|
22892
|
-
|
|
23126
|
+
path72,
|
|
22893
23127
|
error.message
|
|
22894
23128
|
);
|
|
22895
23129
|
}
|
|
@@ -22992,7 +23226,7 @@ var require_request = __commonJS({
|
|
|
22992
23226
|
var kHandler = /* @__PURE__ */ Symbol("handler");
|
|
22993
23227
|
var Request = class {
|
|
22994
23228
|
constructor(origin, {
|
|
22995
|
-
path:
|
|
23229
|
+
path: path72,
|
|
22996
23230
|
method,
|
|
22997
23231
|
body,
|
|
22998
23232
|
headers,
|
|
@@ -23009,11 +23243,11 @@ var require_request = __commonJS({
|
|
|
23009
23243
|
maxRedirections,
|
|
23010
23244
|
typeOfService
|
|
23011
23245
|
}, handler) {
|
|
23012
|
-
if (typeof
|
|
23246
|
+
if (typeof path72 !== "string") {
|
|
23013
23247
|
throw new InvalidArgumentError("path must be a string");
|
|
23014
|
-
} else if (
|
|
23248
|
+
} else if (path72[0] !== "/" && !(path72.startsWith("http://") || path72.startsWith("https://")) && method !== "CONNECT") {
|
|
23015
23249
|
throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
|
|
23016
|
-
} else if (invalidPathRegex.test(
|
|
23250
|
+
} else if (invalidPathRegex.test(path72)) {
|
|
23017
23251
|
throw new InvalidArgumentError("invalid request path");
|
|
23018
23252
|
}
|
|
23019
23253
|
if (typeof method !== "string") {
|
|
@@ -23088,7 +23322,7 @@ var require_request = __commonJS({
|
|
|
23088
23322
|
this.completed = false;
|
|
23089
23323
|
this.aborted = false;
|
|
23090
23324
|
this.upgrade = upgrade || null;
|
|
23091
|
-
this.path = query ? serializePathWithQuery(
|
|
23325
|
+
this.path = query ? serializePathWithQuery(path72, query) : path72;
|
|
23092
23326
|
this.origin = origin;
|
|
23093
23327
|
this.protocol = getProtocolFromUrlString(origin);
|
|
23094
23328
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
|
|
@@ -28127,7 +28361,7 @@ var require_client_h1 = __commonJS({
|
|
|
28127
28361
|
return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
|
|
28128
28362
|
}
|
|
28129
28363
|
function writeH1(client, request2) {
|
|
28130
|
-
const { method, path:
|
|
28364
|
+
const { method, path: path72, host, upgrade, blocking, reset } = request2;
|
|
28131
28365
|
let { body, headers, contentLength } = request2;
|
|
28132
28366
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
|
|
28133
28367
|
if (util.isFormDataLike(body)) {
|
|
@@ -28196,7 +28430,7 @@ var require_client_h1 = __commonJS({
|
|
|
28196
28430
|
if (socket.setTypeOfService) {
|
|
28197
28431
|
socket.setTypeOfService(request2.typeOfService);
|
|
28198
28432
|
}
|
|
28199
|
-
let header = `${method} ${
|
|
28433
|
+
let header = `${method} ${path72} HTTP/1.1\r
|
|
28200
28434
|
`;
|
|
28201
28435
|
if (typeof host === "string") {
|
|
28202
28436
|
header += `host: ${host}\r
|
|
@@ -28849,7 +29083,7 @@ var require_client_h2 = __commonJS({
|
|
|
28849
29083
|
function writeH2(client, request2) {
|
|
28850
29084
|
const requestTimeout = request2.bodyTimeout ?? client[kBodyTimeout];
|
|
28851
29085
|
const session = client[kHTTP2Session];
|
|
28852
|
-
const { method, path:
|
|
29086
|
+
const { method, path: path72, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
|
|
28853
29087
|
let { body } = request2;
|
|
28854
29088
|
if (upgrade != null && upgrade !== "websocket") {
|
|
28855
29089
|
util.errorRequest(client, request2, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
|
|
@@ -28917,7 +29151,7 @@ var require_client_h2 = __commonJS({
|
|
|
28917
29151
|
}
|
|
28918
29152
|
headers[HTTP2_HEADER_METHOD] = "CONNECT";
|
|
28919
29153
|
headers[HTTP2_HEADER_PROTOCOL] = "websocket";
|
|
28920
|
-
headers[HTTP2_HEADER_PATH] =
|
|
29154
|
+
headers[HTTP2_HEADER_PATH] = path72;
|
|
28921
29155
|
if (protocol === "ws:" || protocol === "wss:") {
|
|
28922
29156
|
headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
|
|
28923
29157
|
} else {
|
|
@@ -28958,7 +29192,7 @@ var require_client_h2 = __commonJS({
|
|
|
28958
29192
|
stream.setTimeout(requestTimeout);
|
|
28959
29193
|
return true;
|
|
28960
29194
|
}
|
|
28961
|
-
headers[HTTP2_HEADER_PATH] =
|
|
29195
|
+
headers[HTTP2_HEADER_PATH] = path72;
|
|
28962
29196
|
headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
|
|
28963
29197
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
|
|
28964
29198
|
if (body && typeof body.read === "function") {
|
|
@@ -31260,10 +31494,10 @@ var require_proxy_agent = __commonJS({
|
|
|
31260
31494
|
};
|
|
31261
31495
|
const {
|
|
31262
31496
|
origin,
|
|
31263
|
-
path:
|
|
31497
|
+
path: path72 = "/",
|
|
31264
31498
|
headers = {}
|
|
31265
31499
|
} = opts;
|
|
31266
|
-
opts.path = origin +
|
|
31500
|
+
opts.path = origin + path72;
|
|
31267
31501
|
if (!("host" in headers) && !("Host" in headers)) {
|
|
31268
31502
|
const { host } = new URL(origin);
|
|
31269
31503
|
headers.host = host;
|
|
@@ -33326,20 +33560,20 @@ var require_mock_utils = __commonJS({
|
|
|
33326
33560
|
}
|
|
33327
33561
|
return normalizedQp;
|
|
33328
33562
|
}
|
|
33329
|
-
function safeUrl(
|
|
33330
|
-
if (typeof
|
|
33331
|
-
return
|
|
33563
|
+
function safeUrl(path72) {
|
|
33564
|
+
if (typeof path72 !== "string") {
|
|
33565
|
+
return path72;
|
|
33332
33566
|
}
|
|
33333
|
-
const pathSegments =
|
|
33567
|
+
const pathSegments = path72.split("?", 3);
|
|
33334
33568
|
if (pathSegments.length !== 2) {
|
|
33335
|
-
return
|
|
33569
|
+
return path72;
|
|
33336
33570
|
}
|
|
33337
33571
|
const qp = new URLSearchParams(pathSegments.pop());
|
|
33338
33572
|
qp.sort();
|
|
33339
33573
|
return [...pathSegments, qp.toString()].join("?");
|
|
33340
33574
|
}
|
|
33341
|
-
function matchKey(mockDispatch2, { path:
|
|
33342
|
-
const pathMatch = matchValue(mockDispatch2.path,
|
|
33575
|
+
function matchKey(mockDispatch2, { path: path72, method, body, headers }) {
|
|
33576
|
+
const pathMatch = matchValue(mockDispatch2.path, path72);
|
|
33343
33577
|
const methodMatch = matchValue(mockDispatch2.method, method);
|
|
33344
33578
|
const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
|
|
33345
33579
|
const headersMatch = matchHeaders(mockDispatch2, headers);
|
|
@@ -33364,8 +33598,8 @@ var require_mock_utils = __commonJS({
|
|
|
33364
33598
|
const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
|
|
33365
33599
|
const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
|
|
33366
33600
|
const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
|
|
33367
|
-
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path:
|
|
33368
|
-
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(
|
|
33601
|
+
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path72, ignoreTrailingSlash }) => {
|
|
33602
|
+
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path72)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path72), resolvedPath);
|
|
33369
33603
|
});
|
|
33370
33604
|
if (matchedMockDispatches.length === 0) {
|
|
33371
33605
|
throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
|
|
@@ -33404,19 +33638,19 @@ var require_mock_utils = __commonJS({
|
|
|
33404
33638
|
mockDispatches.splice(index, 1);
|
|
33405
33639
|
}
|
|
33406
33640
|
}
|
|
33407
|
-
function removeTrailingSlash(
|
|
33408
|
-
while (
|
|
33409
|
-
|
|
33641
|
+
function removeTrailingSlash(path72) {
|
|
33642
|
+
while (path72.endsWith("/")) {
|
|
33643
|
+
path72 = path72.slice(0, -1);
|
|
33410
33644
|
}
|
|
33411
|
-
if (
|
|
33412
|
-
|
|
33645
|
+
if (path72.length === 0) {
|
|
33646
|
+
path72 = "/";
|
|
33413
33647
|
}
|
|
33414
|
-
return
|
|
33648
|
+
return path72;
|
|
33415
33649
|
}
|
|
33416
33650
|
function buildKey(opts) {
|
|
33417
|
-
const { path:
|
|
33651
|
+
const { path: path72, method, body, headers, query } = opts;
|
|
33418
33652
|
return {
|
|
33419
|
-
path:
|
|
33653
|
+
path: path72,
|
|
33420
33654
|
method,
|
|
33421
33655
|
body,
|
|
33422
33656
|
headers,
|
|
@@ -34106,10 +34340,10 @@ var require_pending_interceptors_formatter = __commonJS({
|
|
|
34106
34340
|
}
|
|
34107
34341
|
format(pendingInterceptors) {
|
|
34108
34342
|
const withPrettyHeaders = pendingInterceptors.map(
|
|
34109
|
-
({ method, path:
|
|
34343
|
+
({ method, path: path72, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
34110
34344
|
Method: method,
|
|
34111
34345
|
Origin: origin,
|
|
34112
|
-
Path:
|
|
34346
|
+
Path: path72,
|
|
34113
34347
|
"Status code": statusCode,
|
|
34114
34348
|
Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
|
|
34115
34349
|
Invocations: timesInvoked,
|
|
@@ -34191,9 +34425,9 @@ var require_mock_agent = __commonJS({
|
|
|
34191
34425
|
const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
|
|
34192
34426
|
const dispatchOpts = { ...opts };
|
|
34193
34427
|
if (acceptNonStandardSearchParameters && dispatchOpts.path) {
|
|
34194
|
-
const [
|
|
34428
|
+
const [path72, searchParams] = dispatchOpts.path.split("?");
|
|
34195
34429
|
const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
|
|
34196
|
-
dispatchOpts.path = `${
|
|
34430
|
+
dispatchOpts.path = `${path72}?${normalizedSearchParams}`;
|
|
34197
34431
|
}
|
|
34198
34432
|
return this[kAgent].dispatch(dispatchOpts, handler);
|
|
34199
34433
|
}
|
|
@@ -34594,12 +34828,12 @@ var require_snapshot_recorder = __commonJS({
|
|
|
34594
34828
|
* @return {Promise<void>} - Resolves when snapshots are loaded
|
|
34595
34829
|
*/
|
|
34596
34830
|
async loadSnapshots(filePath) {
|
|
34597
|
-
const
|
|
34598
|
-
if (!
|
|
34831
|
+
const path72 = filePath || this.#snapshotPath;
|
|
34832
|
+
if (!path72) {
|
|
34599
34833
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
34600
34834
|
}
|
|
34601
34835
|
try {
|
|
34602
|
-
const data = await readFile(resolve2(
|
|
34836
|
+
const data = await readFile(resolve2(path72), "utf8");
|
|
34603
34837
|
const parsed = JSON.parse(data);
|
|
34604
34838
|
if (Array.isArray(parsed)) {
|
|
34605
34839
|
this.#snapshots.clear();
|
|
@@ -34613,7 +34847,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
34613
34847
|
if (error.code === "ENOENT") {
|
|
34614
34848
|
this.#snapshots.clear();
|
|
34615
34849
|
} else {
|
|
34616
|
-
throw new UndiciError(`Failed to load snapshots from ${
|
|
34850
|
+
throw new UndiciError(`Failed to load snapshots from ${path72}`, { cause: error });
|
|
34617
34851
|
}
|
|
34618
34852
|
}
|
|
34619
34853
|
}
|
|
@@ -34624,11 +34858,11 @@ var require_snapshot_recorder = __commonJS({
|
|
|
34624
34858
|
* @returns {Promise<void>} - Resolves when snapshots are saved
|
|
34625
34859
|
*/
|
|
34626
34860
|
async saveSnapshots(filePath) {
|
|
34627
|
-
const
|
|
34628
|
-
if (!
|
|
34861
|
+
const path72 = filePath || this.#snapshotPath;
|
|
34862
|
+
if (!path72) {
|
|
34629
34863
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
34630
34864
|
}
|
|
34631
|
-
const resolvedPath = resolve2(
|
|
34865
|
+
const resolvedPath = resolve2(path72);
|
|
34632
34866
|
await mkdir(dirname2(resolvedPath), { recursive: true });
|
|
34633
34867
|
const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
|
|
34634
34868
|
hash,
|
|
@@ -35253,15 +35487,15 @@ var require_redirect_handler = __commonJS({
|
|
|
35253
35487
|
return;
|
|
35254
35488
|
}
|
|
35255
35489
|
const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
|
|
35256
|
-
const
|
|
35257
|
-
const redirectUrlString = `${origin}${
|
|
35490
|
+
const path72 = search ? `${pathname}${search}` : pathname;
|
|
35491
|
+
const redirectUrlString = `${origin}${path72}`;
|
|
35258
35492
|
for (const historyUrl of this.history) {
|
|
35259
35493
|
if (historyUrl.toString() === redirectUrlString) {
|
|
35260
35494
|
throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
|
|
35261
35495
|
}
|
|
35262
35496
|
}
|
|
35263
35497
|
this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
|
|
35264
|
-
this.opts.path =
|
|
35498
|
+
this.opts.path = path72;
|
|
35265
35499
|
this.opts.origin = origin;
|
|
35266
35500
|
this.opts.query = null;
|
|
35267
35501
|
}
|
|
@@ -41468,11 +41702,11 @@ var require_fetch = __commonJS({
|
|
|
41468
41702
|
function dispatch({ body }) {
|
|
41469
41703
|
const url = requestCurrentURL(request2);
|
|
41470
41704
|
const agent = fetchParams.controller.dispatcher;
|
|
41471
|
-
const
|
|
41705
|
+
const path72 = url.pathname + url.search;
|
|
41472
41706
|
const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
|
|
41473
41707
|
return new Promise((resolve2, reject) => agent.dispatch(
|
|
41474
41708
|
{
|
|
41475
|
-
path: hasTrailingQuestionMark ? `${
|
|
41709
|
+
path: hasTrailingQuestionMark ? `${path72}?` : path72,
|
|
41476
41710
|
origin: url.origin,
|
|
41477
41711
|
method: request2.method,
|
|
41478
41712
|
body: agent.isMockActive ? request2.body && (request2.body.source || request2.body.stream) : body,
|
|
@@ -42403,9 +42637,9 @@ var require_util4 = __commonJS({
|
|
|
42403
42637
|
}
|
|
42404
42638
|
}
|
|
42405
42639
|
}
|
|
42406
|
-
function validateCookiePath(
|
|
42407
|
-
for (let i = 0; i <
|
|
42408
|
-
const code =
|
|
42640
|
+
function validateCookiePath(path72) {
|
|
42641
|
+
for (let i = 0; i < path72.length; ++i) {
|
|
42642
|
+
const code = path72.charCodeAt(i);
|
|
42409
42643
|
if (code < 32 || // exclude CTLs (0-31)
|
|
42410
42644
|
code === 127 || // DEL
|
|
42411
42645
|
code === 59) {
|
|
@@ -45575,11 +45809,11 @@ var require_undici = __commonJS({
|
|
|
45575
45809
|
if (typeof opts.path !== "string") {
|
|
45576
45810
|
throw new InvalidArgumentError("invalid opts.path");
|
|
45577
45811
|
}
|
|
45578
|
-
let
|
|
45812
|
+
let path72 = opts.path;
|
|
45579
45813
|
if (!opts.path.startsWith("/")) {
|
|
45580
|
-
|
|
45814
|
+
path72 = `/${path72}`;
|
|
45581
45815
|
}
|
|
45582
|
-
url = new URL(util.parseOrigin(url).origin +
|
|
45816
|
+
url = new URL(util.parseOrigin(url).origin + path72);
|
|
45583
45817
|
} else {
|
|
45584
45818
|
if (!opts) {
|
|
45585
45819
|
opts = typeof url === "object" ? url : {};
|
|
@@ -45692,17 +45926,21 @@ ${captureLines}` : capture.stack;
|
|
|
45692
45926
|
var tail_exports = {};
|
|
45693
45927
|
__export(tail_exports, {
|
|
45694
45928
|
agentLabel: () => agentLabel,
|
|
45929
|
+
eventsUrl: () => eventsUrl,
|
|
45695
45930
|
sessionTag: () => sessionTag,
|
|
45696
45931
|
shortenPathSummary: () => shortenPathSummary,
|
|
45697
45932
|
startTail: () => startTail
|
|
45698
45933
|
});
|
|
45699
45934
|
import http5 from "http";
|
|
45700
45935
|
import chalk40 from "chalk";
|
|
45701
|
-
import
|
|
45936
|
+
import fs73 from "fs";
|
|
45702
45937
|
import os61 from "os";
|
|
45703
|
-
import
|
|
45938
|
+
import path69 from "path";
|
|
45704
45939
|
import readline6 from "readline";
|
|
45705
45940
|
import { spawn as spawn8 } from "child_process";
|
|
45941
|
+
function eventsUrl(port, canApprove) {
|
|
45942
|
+
return `http://127.0.0.1:${port}/events${canApprove ? "?capabilities=input" : ""}`;
|
|
45943
|
+
}
|
|
45706
45944
|
function shortenPathSummary(s) {
|
|
45707
45945
|
if (!s || !s.startsWith("/")) return s;
|
|
45708
45946
|
const parts = s.split("/").filter(Boolean);
|
|
@@ -45724,20 +45962,20 @@ function getModelContextLimit(model) {
|
|
|
45724
45962
|
return 2e5;
|
|
45725
45963
|
}
|
|
45726
45964
|
function readSessionUsage() {
|
|
45727
|
-
const projectsDir =
|
|
45728
|
-
if (!
|
|
45965
|
+
const projectsDir = path69.join(os61.homedir(), ".claude", "projects");
|
|
45966
|
+
if (!fs73.existsSync(projectsDir)) return null;
|
|
45729
45967
|
let latestFile = null;
|
|
45730
45968
|
let latestMtime = 0;
|
|
45731
45969
|
try {
|
|
45732
|
-
for (const dir of
|
|
45733
|
-
const dirPath =
|
|
45970
|
+
for (const dir of fs73.readdirSync(projectsDir)) {
|
|
45971
|
+
const dirPath = path69.join(projectsDir, dir);
|
|
45734
45972
|
try {
|
|
45735
|
-
if (!
|
|
45736
|
-
for (const file of
|
|
45973
|
+
if (!fs73.statSync(dirPath).isDirectory()) continue;
|
|
45974
|
+
for (const file of fs73.readdirSync(dirPath)) {
|
|
45737
45975
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
45738
|
-
const filePath =
|
|
45976
|
+
const filePath = path69.join(dirPath, file);
|
|
45739
45977
|
try {
|
|
45740
|
-
const mtime =
|
|
45978
|
+
const mtime = fs73.statSync(filePath).mtimeMs;
|
|
45741
45979
|
if (mtime > latestMtime) {
|
|
45742
45980
|
latestMtime = mtime;
|
|
45743
45981
|
latestFile = filePath;
|
|
@@ -45752,7 +45990,7 @@ function readSessionUsage() {
|
|
|
45752
45990
|
}
|
|
45753
45991
|
if (!latestFile) return null;
|
|
45754
45992
|
try {
|
|
45755
|
-
const lines =
|
|
45993
|
+
const lines = fs73.readFileSync(latestFile, "utf-8").split("\n");
|
|
45756
45994
|
let lastModel = "";
|
|
45757
45995
|
let lastInput = 0;
|
|
45758
45996
|
let lastOutput = 0;
|
|
@@ -45852,9 +46090,9 @@ function renderPending(activity) {
|
|
|
45852
46090
|
}
|
|
45853
46091
|
async function ensureDaemon() {
|
|
45854
46092
|
let pidPort = null;
|
|
45855
|
-
if (
|
|
46093
|
+
if (fs73.existsSync(PID_FILE)) {
|
|
45856
46094
|
try {
|
|
45857
|
-
const { port } = JSON.parse(
|
|
46095
|
+
const { port } = JSON.parse(fs73.readFileSync(PID_FILE, "utf-8"));
|
|
45858
46096
|
pidPort = port;
|
|
45859
46097
|
} catch {
|
|
45860
46098
|
console.error(chalk40.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -45880,7 +46118,7 @@ async function ensureDaemon() {
|
|
|
45880
46118
|
child.unref();
|
|
45881
46119
|
if (startupFd !== void 0) {
|
|
45882
46120
|
try {
|
|
45883
|
-
|
|
46121
|
+
fs73.closeSync(startupFd);
|
|
45884
46122
|
} catch {
|
|
45885
46123
|
}
|
|
45886
46124
|
}
|
|
@@ -46019,9 +46257,9 @@ function buildRecoveryCardLines(req) {
|
|
|
46019
46257
|
];
|
|
46020
46258
|
}
|
|
46021
46259
|
function readApproversFromDisk() {
|
|
46022
|
-
const configPath =
|
|
46260
|
+
const configPath = path69.join(os61.homedir(), ".node9", "config.json");
|
|
46023
46261
|
try {
|
|
46024
|
-
const raw = JSON.parse(
|
|
46262
|
+
const raw = JSON.parse(fs73.readFileSync(configPath, "utf-8"));
|
|
46025
46263
|
const settings = raw.settings ?? {};
|
|
46026
46264
|
return settings.approvers ?? {};
|
|
46027
46265
|
} catch {
|
|
@@ -46037,15 +46275,15 @@ function approverStatusLine() {
|
|
|
46037
46275
|
return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
46038
46276
|
}
|
|
46039
46277
|
function toggleApprover(channel) {
|
|
46040
|
-
const configPath =
|
|
46278
|
+
const configPath = path69.join(os61.homedir(), ".node9", "config.json");
|
|
46041
46279
|
try {
|
|
46042
|
-
const raw = JSON.parse(
|
|
46280
|
+
const raw = JSON.parse(fs73.readFileSync(configPath, "utf-8"));
|
|
46043
46281
|
const settings = raw.settings ?? {};
|
|
46044
46282
|
const approvers = settings.approvers ?? {};
|
|
46045
46283
|
approvers[channel] = approvers[channel] === false;
|
|
46046
46284
|
settings.approvers = approvers;
|
|
46047
46285
|
raw.settings = settings;
|
|
46048
|
-
|
|
46286
|
+
fs73.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
46049
46287
|
} catch (err2) {
|
|
46050
46288
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
46051
46289
|
`);
|
|
@@ -46217,8 +46455,8 @@ async function startTail(options = {}) {
|
|
|
46217
46455
|
}
|
|
46218
46456
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
46219
46457
|
try {
|
|
46220
|
-
|
|
46221
|
-
|
|
46458
|
+
fs73.appendFileSync(
|
|
46459
|
+
path69.join(os61.homedir(), ".node9", "hook-debug.log"),
|
|
46222
46460
|
`[tail] POST /decision failed: ${String(err2)}
|
|
46223
46461
|
`
|
|
46224
46462
|
);
|
|
@@ -46282,9 +46520,9 @@ async function startTail(options = {}) {
|
|
|
46282
46520
|
};
|
|
46283
46521
|
process.stdin.on("keypress", onKeypress);
|
|
46284
46522
|
}
|
|
46285
|
-
const auditLog =
|
|
46523
|
+
const auditLog = path69.join(os61.homedir(), ".node9", "audit.log");
|
|
46286
46524
|
try {
|
|
46287
|
-
const unackedDlp =
|
|
46525
|
+
const unackedDlp = fs73.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
46288
46526
|
if (unackedDlp > 0) {
|
|
46289
46527
|
console.log("");
|
|
46290
46528
|
console.log(
|
|
@@ -46324,7 +46562,7 @@ async function startTail(options = {}) {
|
|
|
46324
46562
|
if (stallWarned) return;
|
|
46325
46563
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
46326
46564
|
try {
|
|
46327
|
-
const auditMtime =
|
|
46565
|
+
const auditMtime = fs73.statSync(auditLog).mtimeMs;
|
|
46328
46566
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
46329
46567
|
console.log("");
|
|
46330
46568
|
console.log(
|
|
@@ -46337,7 +46575,7 @@ async function startTail(options = {}) {
|
|
|
46337
46575
|
}
|
|
46338
46576
|
}, STALL_THRESHOLD_MS / 2);
|
|
46339
46577
|
stallWatchdog.unref();
|
|
46340
|
-
const sseUrl =
|
|
46578
|
+
const sseUrl = eventsUrl(port, canApprove);
|
|
46341
46579
|
const req = http5.get(
|
|
46342
46580
|
sseUrl,
|
|
46343
46581
|
{
|
|
@@ -46516,7 +46754,7 @@ var init_tail = __esm({
|
|
|
46516
46754
|
init_startup_log();
|
|
46517
46755
|
init_daemon2();
|
|
46518
46756
|
init_daemon();
|
|
46519
|
-
PID_FILE =
|
|
46757
|
+
PID_FILE = path69.join(os61.homedir(), ".node9", "daemon.pid");
|
|
46520
46758
|
ICONS = {
|
|
46521
46759
|
bash: "\u{1F4BB}",
|
|
46522
46760
|
shell: "\u{1F4BB}",
|
|
@@ -46564,8 +46802,8 @@ __export(hud_exports, {
|
|
|
46564
46802
|
main: () => main,
|
|
46565
46803
|
renderEnvironmentLine: () => renderEnvironmentLine
|
|
46566
46804
|
});
|
|
46567
|
-
import
|
|
46568
|
-
import
|
|
46805
|
+
import fs74 from "fs";
|
|
46806
|
+
import path70 from "path";
|
|
46569
46807
|
import os62 from "os";
|
|
46570
46808
|
import http6 from "http";
|
|
46571
46809
|
async function readStdin() {
|
|
@@ -46642,9 +46880,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
46642
46880
|
return ` (${m}m left)`;
|
|
46643
46881
|
}
|
|
46644
46882
|
function safeReadJson(filePath) {
|
|
46645
|
-
if (!
|
|
46883
|
+
if (!fs74.existsSync(filePath)) return null;
|
|
46646
46884
|
try {
|
|
46647
|
-
return JSON.parse(
|
|
46885
|
+
return JSON.parse(fs74.readFileSync(filePath, "utf-8"));
|
|
46648
46886
|
} catch {
|
|
46649
46887
|
return null;
|
|
46650
46888
|
}
|
|
@@ -46665,12 +46903,12 @@ function countHooksInFile(filePath) {
|
|
|
46665
46903
|
return Object.keys(cfg.hooks).length;
|
|
46666
46904
|
}
|
|
46667
46905
|
function countRulesInDir(rulesDir) {
|
|
46668
|
-
if (!
|
|
46906
|
+
if (!fs74.existsSync(rulesDir)) return 0;
|
|
46669
46907
|
let count = 0;
|
|
46670
46908
|
try {
|
|
46671
|
-
for (const entry of
|
|
46909
|
+
for (const entry of fs74.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
46672
46910
|
if (entry.isDirectory()) {
|
|
46673
|
-
count += countRulesInDir(
|
|
46911
|
+
count += countRulesInDir(path70.join(rulesDir, entry.name));
|
|
46674
46912
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
46675
46913
|
count++;
|
|
46676
46914
|
}
|
|
@@ -46681,46 +46919,46 @@ function countRulesInDir(rulesDir) {
|
|
|
46681
46919
|
}
|
|
46682
46920
|
function isSamePath(a, b) {
|
|
46683
46921
|
try {
|
|
46684
|
-
return
|
|
46922
|
+
return path70.resolve(a) === path70.resolve(b);
|
|
46685
46923
|
} catch {
|
|
46686
46924
|
return false;
|
|
46687
46925
|
}
|
|
46688
46926
|
}
|
|
46689
46927
|
function countConfigs(cwd) {
|
|
46690
46928
|
const homeDir2 = os62.homedir();
|
|
46691
|
-
const claudeDir =
|
|
46929
|
+
const claudeDir = path70.join(homeDir2, ".claude");
|
|
46692
46930
|
let claudeMdCount = 0;
|
|
46693
46931
|
let rulesCount = 0;
|
|
46694
46932
|
let hooksCount = 0;
|
|
46695
46933
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
46696
46934
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
46697
|
-
if (
|
|
46698
|
-
rulesCount += countRulesInDir(
|
|
46699
|
-
const userSettings =
|
|
46935
|
+
if (fs74.existsSync(path70.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
46936
|
+
rulesCount += countRulesInDir(path70.join(claudeDir, "rules"));
|
|
46937
|
+
const userSettings = path70.join(claudeDir, "settings.json");
|
|
46700
46938
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
46701
46939
|
hooksCount += countHooksInFile(userSettings);
|
|
46702
|
-
const userClaudeJson =
|
|
46940
|
+
const userClaudeJson = path70.join(homeDir2, ".claude.json");
|
|
46703
46941
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
46704
46942
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
46705
46943
|
userMcpServers.delete(name);
|
|
46706
46944
|
}
|
|
46707
46945
|
if (cwd) {
|
|
46708
|
-
if (
|
|
46709
|
-
if (
|
|
46710
|
-
const projectClaudeDir =
|
|
46946
|
+
if (fs74.existsSync(path70.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
46947
|
+
if (fs74.existsSync(path70.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
46948
|
+
const projectClaudeDir = path70.join(cwd, ".claude");
|
|
46711
46949
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
46712
46950
|
if (!overlapsUserScope) {
|
|
46713
|
-
if (
|
|
46714
|
-
rulesCount += countRulesInDir(
|
|
46715
|
-
const projSettings =
|
|
46951
|
+
if (fs74.existsSync(path70.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
46952
|
+
rulesCount += countRulesInDir(path70.join(projectClaudeDir, "rules"));
|
|
46953
|
+
const projSettings = path70.join(projectClaudeDir, "settings.json");
|
|
46716
46954
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
46717
46955
|
hooksCount += countHooksInFile(projSettings);
|
|
46718
46956
|
}
|
|
46719
|
-
if (
|
|
46720
|
-
const localSettings =
|
|
46957
|
+
if (fs74.existsSync(path70.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
46958
|
+
const localSettings = path70.join(projectClaudeDir, "settings.local.json");
|
|
46721
46959
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
46722
46960
|
hooksCount += countHooksInFile(localSettings);
|
|
46723
|
-
const mcpJsonServers = getMcpServerNames(
|
|
46961
|
+
const mcpJsonServers = getMcpServerNames(path70.join(cwd, ".mcp.json"));
|
|
46724
46962
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
46725
46963
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
46726
46964
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -46753,12 +46991,12 @@ function readActiveShieldsHud() {
|
|
|
46753
46991
|
return shieldsCache.value;
|
|
46754
46992
|
}
|
|
46755
46993
|
try {
|
|
46756
|
-
const shieldsPath =
|
|
46757
|
-
if (!
|
|
46994
|
+
const shieldsPath = path70.join(os62.homedir(), ".node9", "shields.json");
|
|
46995
|
+
if (!fs74.existsSync(shieldsPath)) {
|
|
46758
46996
|
shieldsCache = { value: [], ts: now };
|
|
46759
46997
|
return [];
|
|
46760
46998
|
}
|
|
46761
|
-
const parsed = JSON.parse(
|
|
46999
|
+
const parsed = JSON.parse(fs74.readFileSync(shieldsPath, "utf-8"));
|
|
46762
47000
|
if (!Array.isArray(parsed.active)) {
|
|
46763
47001
|
shieldsCache = { value: [], ts: now };
|
|
46764
47002
|
return [];
|
|
@@ -46860,17 +47098,17 @@ function renderContextLine(stdin) {
|
|
|
46860
47098
|
async function main() {
|
|
46861
47099
|
try {
|
|
46862
47100
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
46863
|
-
if (
|
|
47101
|
+
if (fs74.existsSync(path70.join(os62.homedir(), ".node9", "hud-debug"))) {
|
|
46864
47102
|
try {
|
|
46865
|
-
const logPath =
|
|
47103
|
+
const logPath = path70.join(os62.homedir(), ".node9", "hud-debug.log");
|
|
46866
47104
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
46867
47105
|
let size = 0;
|
|
46868
47106
|
try {
|
|
46869
|
-
size =
|
|
47107
|
+
size = fs74.statSync(logPath).size;
|
|
46870
47108
|
} catch {
|
|
46871
47109
|
}
|
|
46872
47110
|
if (size < MAX_LOG_SIZE) {
|
|
46873
|
-
|
|
47111
|
+
fs74.appendFileSync(
|
|
46874
47112
|
logPath,
|
|
46875
47113
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
46876
47114
|
);
|
|
@@ -46891,11 +47129,11 @@ async function main() {
|
|
|
46891
47129
|
try {
|
|
46892
47130
|
const cwd = stdin.cwd ?? process.cwd();
|
|
46893
47131
|
for (const configPath of [
|
|
46894
|
-
|
|
46895
|
-
|
|
47132
|
+
path70.join(cwd, "node9.config.json"),
|
|
47133
|
+
path70.join(os62.homedir(), ".node9", "config.json")
|
|
46896
47134
|
]) {
|
|
46897
|
-
if (!
|
|
46898
|
-
const cfg = JSON.parse(
|
|
47135
|
+
if (!fs74.existsSync(configPath)) continue;
|
|
47136
|
+
const cfg = JSON.parse(fs74.readFileSync(configPath, "utf-8"));
|
|
46899
47137
|
const hud = cfg.settings?.hud;
|
|
46900
47138
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
46901
47139
|
}
|
|
@@ -47037,8 +47275,8 @@ function writeCredentialsAndConfig(apiKey, opts = {}) {
|
|
|
47037
47275
|
// src/cli.ts
|
|
47038
47276
|
init_daemon2();
|
|
47039
47277
|
import chalk41 from "chalk";
|
|
47040
|
-
import
|
|
47041
|
-
import
|
|
47278
|
+
import fs75 from "fs";
|
|
47279
|
+
import path71 from "path";
|
|
47042
47280
|
import os63 from "os";
|
|
47043
47281
|
import { spawn as spawn9 } from "child_process";
|
|
47044
47282
|
import { confirm as confirm2 } from "@inquirer/prompts";
|
|
@@ -47228,26 +47466,26 @@ async function runProxy(targetCommand) {
|
|
|
47228
47466
|
init_daemon();
|
|
47229
47467
|
init_startup_log();
|
|
47230
47468
|
import { spawn as spawn3 } from "child_process";
|
|
47231
|
-
import
|
|
47232
|
-
import
|
|
47469
|
+
import path43 from "path";
|
|
47470
|
+
import fs45 from "fs";
|
|
47233
47471
|
import os40 from "os";
|
|
47234
47472
|
function isTestingMode() {
|
|
47235
47473
|
return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
|
|
47236
47474
|
}
|
|
47237
|
-
var SKIP_STAMP = () =>
|
|
47475
|
+
var SKIP_STAMP = () => path43.join(os40.homedir(), ".node9", ".autostart-skip-stamp");
|
|
47238
47476
|
var SKIP_THROTTLE_MS = 60 * 60 * 1e3;
|
|
47239
47477
|
function logAutostartSkipThrottled(reason) {
|
|
47240
47478
|
try {
|
|
47241
47479
|
const stamp = SKIP_STAMP();
|
|
47242
47480
|
try {
|
|
47243
|
-
if (Date.now() -
|
|
47481
|
+
if (Date.now() - fs45.statSync(stamp).mtimeMs < SKIP_THROTTLE_MS) return;
|
|
47244
47482
|
} catch {
|
|
47245
47483
|
}
|
|
47246
|
-
const dir =
|
|
47247
|
-
if (!
|
|
47248
|
-
|
|
47249
|
-
|
|
47250
|
-
|
|
47484
|
+
const dir = path43.join(os40.homedir(), ".node9");
|
|
47485
|
+
if (!fs45.existsSync(dir)) fs45.mkdirSync(dir, { recursive: true });
|
|
47486
|
+
fs45.writeFileSync(stamp, "", "utf-8");
|
|
47487
|
+
fs45.appendFileSync(
|
|
47488
|
+
path43.join(dir, "hook-debug.log"),
|
|
47251
47489
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-skip: ${reason}
|
|
47252
47490
|
`,
|
|
47253
47491
|
"utf-8"
|
|
@@ -47256,11 +47494,20 @@ function logAutostartSkipThrottled(reason) {
|
|
|
47256
47494
|
}
|
|
47257
47495
|
}
|
|
47258
47496
|
async function autoStartDaemonAndWait() {
|
|
47497
|
+
let alreadyServing = false;
|
|
47498
|
+
try {
|
|
47499
|
+
alreadyServing = await isDaemonReachable();
|
|
47500
|
+
} catch {
|
|
47501
|
+
}
|
|
47502
|
+
if (alreadyServing) {
|
|
47503
|
+
logAutostartSkipThrottled("already-serving");
|
|
47504
|
+
return true;
|
|
47505
|
+
}
|
|
47259
47506
|
if (isTestingMode()) return false;
|
|
47260
|
-
if (!
|
|
47507
|
+
if (!path43.isAbsolute(process.argv[1])) return false;
|
|
47261
47508
|
let resolvedArgv1;
|
|
47262
47509
|
try {
|
|
47263
|
-
resolvedArgv1 =
|
|
47510
|
+
resolvedArgv1 = fs45.realpathSync(process.argv[1]);
|
|
47264
47511
|
} catch {
|
|
47265
47512
|
return false;
|
|
47266
47513
|
}
|
|
@@ -47298,7 +47545,7 @@ async function autoStartDaemonAndWait() {
|
|
|
47298
47545
|
} finally {
|
|
47299
47546
|
if (startupFd !== void 0) {
|
|
47300
47547
|
try {
|
|
47301
|
-
|
|
47548
|
+
fs45.closeSync(startupFd);
|
|
47302
47549
|
} catch {
|
|
47303
47550
|
}
|
|
47304
47551
|
}
|
|
@@ -47317,19 +47564,19 @@ init_startup_log();
|
|
|
47317
47564
|
init_config();
|
|
47318
47565
|
init_policy();
|
|
47319
47566
|
import chalk9 from "chalk";
|
|
47320
|
-
import
|
|
47567
|
+
import fs49 from "fs";
|
|
47321
47568
|
import { spawn as spawn5 } from "child_process";
|
|
47322
|
-
import
|
|
47569
|
+
import path47 from "path";
|
|
47323
47570
|
import os44 from "os";
|
|
47324
47571
|
|
|
47325
47572
|
// src/undo.ts
|
|
47326
47573
|
import { spawnSync as spawnSync3, spawn as spawn4 } from "child_process";
|
|
47327
47574
|
import crypto7 from "crypto";
|
|
47328
|
-
import
|
|
47575
|
+
import fs46 from "fs";
|
|
47329
47576
|
import net3 from "net";
|
|
47330
|
-
import
|
|
47577
|
+
import path44 from "path";
|
|
47331
47578
|
import os41 from "os";
|
|
47332
|
-
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
47579
|
+
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path44.join(os41.tmpdir(), "node9-activity.sock");
|
|
47333
47580
|
function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
47334
47581
|
try {
|
|
47335
47582
|
const payload = JSON.stringify({
|
|
@@ -47349,22 +47596,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
|
47349
47596
|
} catch {
|
|
47350
47597
|
}
|
|
47351
47598
|
}
|
|
47352
|
-
var SNAPSHOT_STACK_PATH =
|
|
47353
|
-
var UNDO_LATEST_PATH =
|
|
47599
|
+
var SNAPSHOT_STACK_PATH = path44.join(os41.homedir(), ".node9", "snapshots.json");
|
|
47600
|
+
var UNDO_LATEST_PATH = path44.join(os41.homedir(), ".node9", "undo_latest.txt");
|
|
47354
47601
|
var MAX_SNAPSHOTS = 10;
|
|
47355
47602
|
var GIT_TIMEOUT = 15e3;
|
|
47356
47603
|
function readStack() {
|
|
47357
47604
|
try {
|
|
47358
|
-
if (
|
|
47359
|
-
return JSON.parse(
|
|
47605
|
+
if (fs46.existsSync(SNAPSHOT_STACK_PATH))
|
|
47606
|
+
return JSON.parse(fs46.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
|
|
47360
47607
|
} catch {
|
|
47361
47608
|
}
|
|
47362
47609
|
return [];
|
|
47363
47610
|
}
|
|
47364
47611
|
function writeStack(stack) {
|
|
47365
|
-
const dir =
|
|
47366
|
-
if (!
|
|
47367
|
-
|
|
47612
|
+
const dir = path44.dirname(SNAPSHOT_STACK_PATH);
|
|
47613
|
+
if (!fs46.existsSync(dir)) fs46.mkdirSync(dir, { recursive: true });
|
|
47614
|
+
fs46.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
|
|
47368
47615
|
}
|
|
47369
47616
|
function extractFilePath(args) {
|
|
47370
47617
|
if (!args || typeof args !== "object") return null;
|
|
@@ -47384,12 +47631,12 @@ function buildArgsSummary(tool, args) {
|
|
|
47384
47631
|
return "";
|
|
47385
47632
|
}
|
|
47386
47633
|
function findProjectRoot(filePath) {
|
|
47387
|
-
let dir =
|
|
47634
|
+
let dir = path44.dirname(filePath);
|
|
47388
47635
|
while (true) {
|
|
47389
|
-
if (
|
|
47636
|
+
if (fs46.existsSync(path44.join(dir, ".git")) || fs46.existsSync(path44.join(dir, "package.json"))) {
|
|
47390
47637
|
return dir;
|
|
47391
47638
|
}
|
|
47392
|
-
const parent =
|
|
47639
|
+
const parent = path44.dirname(dir);
|
|
47393
47640
|
if (parent === dir) return process.cwd();
|
|
47394
47641
|
dir = parent;
|
|
47395
47642
|
}
|
|
@@ -47397,7 +47644,7 @@ function findProjectRoot(filePath) {
|
|
|
47397
47644
|
function normalizeCwdForHash(cwd) {
|
|
47398
47645
|
let normalized;
|
|
47399
47646
|
try {
|
|
47400
|
-
normalized =
|
|
47647
|
+
normalized = fs46.realpathSync(cwd);
|
|
47401
47648
|
} catch {
|
|
47402
47649
|
normalized = cwd;
|
|
47403
47650
|
}
|
|
@@ -47407,16 +47654,16 @@ function normalizeCwdForHash(cwd) {
|
|
|
47407
47654
|
}
|
|
47408
47655
|
function getShadowRepoDir(cwd) {
|
|
47409
47656
|
const hash = crypto7.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
|
|
47410
|
-
return
|
|
47657
|
+
return path44.join(os41.homedir(), ".node9", "snapshots", hash);
|
|
47411
47658
|
}
|
|
47412
47659
|
function cleanOrphanedIndexFiles(shadowDir) {
|
|
47413
47660
|
try {
|
|
47414
47661
|
const cutoff = Date.now() - 6e4;
|
|
47415
|
-
for (const f of
|
|
47662
|
+
for (const f of fs46.readdirSync(shadowDir)) {
|
|
47416
47663
|
if (f.startsWith("index_")) {
|
|
47417
|
-
const fp =
|
|
47664
|
+
const fp = path44.join(shadowDir, f);
|
|
47418
47665
|
try {
|
|
47419
|
-
if (
|
|
47666
|
+
if (fs46.statSync(fp).mtimeMs < cutoff) fs46.unlinkSync(fp);
|
|
47420
47667
|
} catch {
|
|
47421
47668
|
}
|
|
47422
47669
|
}
|
|
@@ -47428,7 +47675,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
|
|
|
47428
47675
|
const hardcoded = [".git", ".node9"];
|
|
47429
47676
|
const lines = [...hardcoded, ...ignorePaths].join("\n");
|
|
47430
47677
|
try {
|
|
47431
|
-
|
|
47678
|
+
fs46.writeFileSync(path44.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
|
|
47432
47679
|
} catch {
|
|
47433
47680
|
}
|
|
47434
47681
|
}
|
|
@@ -47441,25 +47688,25 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
47441
47688
|
timeout: 3e3
|
|
47442
47689
|
});
|
|
47443
47690
|
if (check.status === 0) {
|
|
47444
|
-
const ptPath =
|
|
47691
|
+
const ptPath = path44.join(shadowDir, "project-path.txt");
|
|
47445
47692
|
try {
|
|
47446
|
-
const stored =
|
|
47693
|
+
const stored = fs46.readFileSync(ptPath, "utf8").trim();
|
|
47447
47694
|
if (stored === normalizedCwd) return true;
|
|
47448
47695
|
if (process.env.NODE9_DEBUG === "1")
|
|
47449
47696
|
console.error(
|
|
47450
47697
|
`[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
|
|
47451
47698
|
);
|
|
47452
|
-
|
|
47699
|
+
fs46.rmSync(shadowDir, { recursive: true, force: true });
|
|
47453
47700
|
} catch {
|
|
47454
47701
|
try {
|
|
47455
|
-
|
|
47702
|
+
fs46.writeFileSync(ptPath, normalizedCwd, "utf8");
|
|
47456
47703
|
} catch {
|
|
47457
47704
|
}
|
|
47458
47705
|
return true;
|
|
47459
47706
|
}
|
|
47460
47707
|
}
|
|
47461
47708
|
try {
|
|
47462
|
-
|
|
47709
|
+
fs46.mkdirSync(shadowDir, { recursive: true });
|
|
47463
47710
|
} catch {
|
|
47464
47711
|
}
|
|
47465
47712
|
const init = spawnSync3("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
|
|
@@ -47468,7 +47715,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
47468
47715
|
if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
|
|
47469
47716
|
return false;
|
|
47470
47717
|
}
|
|
47471
|
-
const configFile =
|
|
47718
|
+
const configFile = path44.join(shadowDir, "config");
|
|
47472
47719
|
spawnSync3("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
|
|
47473
47720
|
timeout: 3e3
|
|
47474
47721
|
});
|
|
@@ -47476,7 +47723,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
47476
47723
|
timeout: 3e3
|
|
47477
47724
|
});
|
|
47478
47725
|
try {
|
|
47479
|
-
|
|
47726
|
+
fs46.writeFileSync(path44.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
|
|
47480
47727
|
} catch {
|
|
47481
47728
|
}
|
|
47482
47729
|
return true;
|
|
@@ -47499,12 +47746,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
47499
47746
|
let indexFile = null;
|
|
47500
47747
|
try {
|
|
47501
47748
|
const rawFilePath = extractFilePath(args);
|
|
47502
|
-
const absFilePath = rawFilePath &&
|
|
47749
|
+
const absFilePath = rawFilePath && path44.isAbsolute(rawFilePath) ? rawFilePath : null;
|
|
47503
47750
|
const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
|
|
47504
47751
|
const shadowDir = getShadowRepoDir(cwd);
|
|
47505
47752
|
if (!ensureShadowRepo(shadowDir, cwd)) return null;
|
|
47506
47753
|
writeShadowExcludes(shadowDir, ignorePaths);
|
|
47507
|
-
indexFile =
|
|
47754
|
+
indexFile = path44.join(shadowDir, `index_${process.pid}_${Date.now()}`);
|
|
47508
47755
|
const shadowEnv = {
|
|
47509
47756
|
...process.env,
|
|
47510
47757
|
GIT_DIR: shadowDir,
|
|
@@ -47576,7 +47823,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
47576
47823
|
writeStack(stack);
|
|
47577
47824
|
const entry = stack[stack.length - 1];
|
|
47578
47825
|
notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
|
|
47579
|
-
|
|
47826
|
+
fs46.writeFileSync(UNDO_LATEST_PATH, commitHash);
|
|
47580
47827
|
if (shouldGc) {
|
|
47581
47828
|
spawn4("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
|
|
47582
47829
|
}
|
|
@@ -47587,7 +47834,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
47587
47834
|
} finally {
|
|
47588
47835
|
if (indexFile) {
|
|
47589
47836
|
try {
|
|
47590
|
-
|
|
47837
|
+
fs46.unlinkSync(indexFile);
|
|
47591
47838
|
} catch {
|
|
47592
47839
|
}
|
|
47593
47840
|
}
|
|
@@ -47663,9 +47910,9 @@ function applyUndo(hash, cwd) {
|
|
|
47663
47910
|
timeout: GIT_TIMEOUT
|
|
47664
47911
|
}).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
|
|
47665
47912
|
for (const file of [...tracked, ...untracked]) {
|
|
47666
|
-
const fullPath =
|
|
47667
|
-
if (!snapshotFiles.has(file) &&
|
|
47668
|
-
|
|
47913
|
+
const fullPath = path44.join(dir, file);
|
|
47914
|
+
if (!snapshotFiles.has(file) && fs46.existsSync(fullPath)) {
|
|
47915
|
+
fs46.unlinkSync(fullPath);
|
|
47669
47916
|
}
|
|
47670
47917
|
}
|
|
47671
47918
|
return true;
|
|
@@ -47675,12 +47922,12 @@ function applyUndo(hash, cwd) {
|
|
|
47675
47922
|
}
|
|
47676
47923
|
|
|
47677
47924
|
// src/skill-pin.ts
|
|
47678
|
-
import
|
|
47679
|
-
import
|
|
47925
|
+
import fs47 from "fs";
|
|
47926
|
+
import path45 from "path";
|
|
47680
47927
|
import os42 from "os";
|
|
47681
47928
|
import crypto8 from "crypto";
|
|
47682
47929
|
function getPinsFilePath2() {
|
|
47683
|
-
return
|
|
47930
|
+
return path45.join(os42.homedir(), ".node9", "skill-pins.json");
|
|
47684
47931
|
}
|
|
47685
47932
|
var MAX_FILES = 5e3;
|
|
47686
47933
|
var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
@@ -47694,18 +47941,18 @@ function walkDir(root) {
|
|
|
47694
47941
|
if (out.length >= MAX_FILES) return;
|
|
47695
47942
|
let entries;
|
|
47696
47943
|
try {
|
|
47697
|
-
entries =
|
|
47944
|
+
entries = fs47.readdirSync(dir, { withFileTypes: true });
|
|
47698
47945
|
} catch {
|
|
47699
47946
|
return;
|
|
47700
47947
|
}
|
|
47701
47948
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
47702
47949
|
for (const entry of entries) {
|
|
47703
47950
|
if (out.length >= MAX_FILES) return;
|
|
47704
|
-
const full =
|
|
47705
|
-
const rel = relDir ?
|
|
47951
|
+
const full = path45.join(dir, entry.name);
|
|
47952
|
+
const rel = relDir ? path45.posix.join(relDir, entry.name) : entry.name;
|
|
47706
47953
|
let lst;
|
|
47707
47954
|
try {
|
|
47708
|
-
lst =
|
|
47955
|
+
lst = fs47.lstatSync(full);
|
|
47709
47956
|
} catch {
|
|
47710
47957
|
continue;
|
|
47711
47958
|
}
|
|
@@ -47717,7 +47964,7 @@ function walkDir(root) {
|
|
|
47717
47964
|
if (!lst.isFile()) continue;
|
|
47718
47965
|
if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
|
|
47719
47966
|
try {
|
|
47720
|
-
const buf =
|
|
47967
|
+
const buf = fs47.readFileSync(full);
|
|
47721
47968
|
totalBytes += buf.length;
|
|
47722
47969
|
out.push({ rel, hash: sha256Bytes(buf) });
|
|
47723
47970
|
} catch {
|
|
@@ -47731,14 +47978,14 @@ function walkDir(root) {
|
|
|
47731
47978
|
function hashSkillRoot(absPath) {
|
|
47732
47979
|
let lst;
|
|
47733
47980
|
try {
|
|
47734
|
-
lst =
|
|
47981
|
+
lst = fs47.lstatSync(absPath);
|
|
47735
47982
|
} catch {
|
|
47736
47983
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
47737
47984
|
}
|
|
47738
47985
|
if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
|
|
47739
47986
|
if (lst.isFile()) {
|
|
47740
47987
|
try {
|
|
47741
|
-
return { exists: true, contentHash: sha256Bytes(
|
|
47988
|
+
return { exists: true, contentHash: sha256Bytes(fs47.readFileSync(absPath)), fileCount: 1 };
|
|
47742
47989
|
} catch {
|
|
47743
47990
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
47744
47991
|
}
|
|
@@ -47756,7 +48003,7 @@ function getRootKey(absPath) {
|
|
|
47756
48003
|
function readSkillPinsSafe() {
|
|
47757
48004
|
const filePath = getPinsFilePath2();
|
|
47758
48005
|
try {
|
|
47759
|
-
const raw =
|
|
48006
|
+
const raw = fs47.readFileSync(filePath, "utf-8");
|
|
47760
48007
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
47761
48008
|
const parsed = JSON.parse(raw);
|
|
47762
48009
|
if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
|
|
@@ -47776,10 +48023,10 @@ function readSkillPins() {
|
|
|
47776
48023
|
}
|
|
47777
48024
|
function writeSkillPins(data) {
|
|
47778
48025
|
const filePath = getPinsFilePath2();
|
|
47779
|
-
|
|
48026
|
+
fs47.mkdirSync(path45.dirname(filePath), { recursive: true });
|
|
47780
48027
|
const tmp = `${filePath}.${crypto8.randomBytes(6).toString("hex")}.tmp`;
|
|
47781
|
-
|
|
47782
|
-
|
|
48028
|
+
fs47.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
48029
|
+
fs47.renameSync(tmp, filePath);
|
|
47783
48030
|
}
|
|
47784
48031
|
function removePin2(rootKey) {
|
|
47785
48032
|
const pins = readSkillPins();
|
|
@@ -47823,36 +48070,36 @@ function verifyAndPinRoots(roots) {
|
|
|
47823
48070
|
return { kind: "verified" };
|
|
47824
48071
|
}
|
|
47825
48072
|
function defaultSkillRoots(_cwd) {
|
|
47826
|
-
const marketplaces =
|
|
48073
|
+
const marketplaces = path45.join(os42.homedir(), ".claude", "plugins", "marketplaces");
|
|
47827
48074
|
const roots = [];
|
|
47828
48075
|
let registries;
|
|
47829
48076
|
try {
|
|
47830
|
-
registries =
|
|
48077
|
+
registries = fs47.readdirSync(marketplaces, { withFileTypes: true });
|
|
47831
48078
|
} catch {
|
|
47832
48079
|
return [];
|
|
47833
48080
|
}
|
|
47834
48081
|
for (const registry of registries) {
|
|
47835
48082
|
if (!registry.isDirectory()) continue;
|
|
47836
|
-
const pluginsDir =
|
|
48083
|
+
const pluginsDir = path45.join(marketplaces, registry.name, "plugins");
|
|
47837
48084
|
let plugins;
|
|
47838
48085
|
try {
|
|
47839
|
-
plugins =
|
|
48086
|
+
plugins = fs47.readdirSync(pluginsDir, { withFileTypes: true });
|
|
47840
48087
|
} catch {
|
|
47841
48088
|
continue;
|
|
47842
48089
|
}
|
|
47843
48090
|
for (const plugin of plugins) {
|
|
47844
48091
|
if (!plugin.isDirectory()) continue;
|
|
47845
|
-
roots.push(
|
|
48092
|
+
roots.push(path45.join(pluginsDir, plugin.name));
|
|
47846
48093
|
}
|
|
47847
48094
|
}
|
|
47848
48095
|
return roots;
|
|
47849
48096
|
}
|
|
47850
48097
|
function resolveUserSkillRoot(entry, cwd) {
|
|
47851
48098
|
if (!entry) return null;
|
|
47852
|
-
if (entry.startsWith("~/") || entry === "~") return
|
|
47853
|
-
if (
|
|
47854
|
-
if (!cwd || !
|
|
47855
|
-
return
|
|
48099
|
+
if (entry.startsWith("~/") || entry === "~") return path45.join(os42.homedir(), entry.slice(1));
|
|
48100
|
+
if (path45.isAbsolute(entry)) return entry;
|
|
48101
|
+
if (!cwd || !path45.isAbsolute(cwd)) return null;
|
|
48102
|
+
return path45.join(cwd, entry);
|
|
47856
48103
|
}
|
|
47857
48104
|
|
|
47858
48105
|
// src/cli/commands/check.ts
|
|
@@ -47861,11 +48108,11 @@ init_audit();
|
|
|
47861
48108
|
|
|
47862
48109
|
// src/review-pending.ts
|
|
47863
48110
|
init_hasher();
|
|
47864
|
-
import
|
|
48111
|
+
import fs48 from "fs";
|
|
47865
48112
|
import os43 from "os";
|
|
47866
|
-
import
|
|
48113
|
+
import path46 from "path";
|
|
47867
48114
|
function storePath() {
|
|
47868
|
-
return process.env.NODE9_PENDING_STORE ||
|
|
48115
|
+
return process.env.NODE9_PENDING_STORE || path46.join(os43.homedir(), ".node9", "pending-reviews.json");
|
|
47869
48116
|
}
|
|
47870
48117
|
var TTL_MS2 = 6 * 60 * 60 * 1e3;
|
|
47871
48118
|
var MAX_ENTRIES = 500;
|
|
@@ -47882,7 +48129,7 @@ function reviewCorrelationKey(payload) {
|
|
|
47882
48129
|
}
|
|
47883
48130
|
function read() {
|
|
47884
48131
|
try {
|
|
47885
|
-
const parsed = JSON.parse(
|
|
48132
|
+
const parsed = JSON.parse(fs48.readFileSync(storePath(), "utf-8"));
|
|
47886
48133
|
if (parsed && Array.isArray(parsed.entries)) return parsed;
|
|
47887
48134
|
} catch {
|
|
47888
48135
|
}
|
|
@@ -47891,11 +48138,11 @@ function read() {
|
|
|
47891
48138
|
function write(store) {
|
|
47892
48139
|
try {
|
|
47893
48140
|
const p = storePath();
|
|
47894
|
-
const dir =
|
|
47895
|
-
if (!
|
|
48141
|
+
const dir = path46.dirname(p);
|
|
48142
|
+
if (!fs48.existsSync(dir)) fs48.mkdirSync(dir, { recursive: true });
|
|
47896
48143
|
const tmp = `${p}.${process.pid}.tmp`;
|
|
47897
|
-
|
|
47898
|
-
|
|
48144
|
+
fs48.writeFileSync(tmp, JSON.stringify(store));
|
|
48145
|
+
fs48.renameSync(tmp, p);
|
|
47899
48146
|
} catch {
|
|
47900
48147
|
}
|
|
47901
48148
|
}
|
|
@@ -48008,9 +48255,9 @@ function registerCheckCommand(program2) {
|
|
|
48008
48255
|
} catch (err2) {
|
|
48009
48256
|
const tempConfig = getConfig();
|
|
48010
48257
|
if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
|
|
48011
|
-
const logPath =
|
|
48258
|
+
const logPath = path47.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
48012
48259
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
48013
|
-
|
|
48260
|
+
fs49.appendFileSync(
|
|
48014
48261
|
logPath,
|
|
48015
48262
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
|
|
48016
48263
|
RAW: ${raw}
|
|
@@ -48023,14 +48270,14 @@ RAW: ${raw}
|
|
|
48023
48270
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
48024
48271
|
if (process.env.NODE9_DEBUG === "1") {
|
|
48025
48272
|
try {
|
|
48026
|
-
const logPath =
|
|
48027
|
-
if (!
|
|
48028
|
-
|
|
48273
|
+
const logPath = path47.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
48274
|
+
if (!fs49.existsSync(path47.dirname(logPath)))
|
|
48275
|
+
fs49.mkdirSync(path47.dirname(logPath), { recursive: true });
|
|
48029
48276
|
const sanitized = JSON.stringify({
|
|
48030
48277
|
...payload,
|
|
48031
48278
|
prompt: `<redacted, ${prompt.length} bytes>`
|
|
48032
48279
|
});
|
|
48033
|
-
|
|
48280
|
+
fs49.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
|
|
48034
48281
|
`);
|
|
48035
48282
|
} catch {
|
|
48036
48283
|
}
|
|
@@ -48051,8 +48298,8 @@ RAW: ${raw}
|
|
|
48051
48298
|
);
|
|
48052
48299
|
const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
|
|
48053
48300
|
try {
|
|
48054
|
-
const ttyFd =
|
|
48055
|
-
|
|
48301
|
+
const ttyFd = fs49.openSync("/dev/tty", "w");
|
|
48302
|
+
fs49.writeSync(
|
|
48056
48303
|
ttyFd,
|
|
48057
48304
|
chalk9.bgRed.white.bold(`
|
|
48058
48305
|
\u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
|
|
@@ -48062,7 +48309,7 @@ RAW: ${raw}
|
|
|
48062
48309
|
|
|
48063
48310
|
`)
|
|
48064
48311
|
);
|
|
48065
|
-
|
|
48312
|
+
fs49.closeSync(ttyFd);
|
|
48066
48313
|
} catch {
|
|
48067
48314
|
}
|
|
48068
48315
|
const isCodex = agent2 === "Codex";
|
|
@@ -48081,17 +48328,17 @@ RAW: ${raw}
|
|
|
48081
48328
|
process.exit(2);
|
|
48082
48329
|
}
|
|
48083
48330
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
48084
|
-
const safeCwdForConfig = typeof payloadCwd === "string" &&
|
|
48331
|
+
const safeCwdForConfig = typeof payloadCwd === "string" && path47.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
48085
48332
|
const config = getConfig(safeCwdForConfig);
|
|
48086
48333
|
const daemonDown = !isDaemonRunning();
|
|
48087
48334
|
if (config.settings.autoStartDaemon && daemonDown && !process.env.NODE9_NO_AUTO_DAEMON) {
|
|
48088
48335
|
try {
|
|
48089
48336
|
const scriptPath = process.argv[1];
|
|
48090
|
-
if (typeof scriptPath !== "string" || !
|
|
48337
|
+
if (typeof scriptPath !== "string" || !path47.isAbsolute(scriptPath))
|
|
48091
48338
|
throw new Error("node9: argv[1] is not an absolute path");
|
|
48092
|
-
const resolvedScript =
|
|
48093
|
-
const packageDist =
|
|
48094
|
-
if (!resolvedScript.startsWith(packageDist +
|
|
48339
|
+
const resolvedScript = fs49.realpathSync(scriptPath);
|
|
48340
|
+
const packageDist = fs49.realpathSync(path47.resolve(__dirname, "../.."));
|
|
48341
|
+
if (!resolvedScript.startsWith(packageDist + path47.sep) && resolvedScript !== packageDist)
|
|
48095
48342
|
throw new Error(
|
|
48096
48343
|
`node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
|
|
48097
48344
|
);
|
|
@@ -48121,17 +48368,17 @@ RAW: ${raw}
|
|
|
48121
48368
|
} finally {
|
|
48122
48369
|
if (startupFd !== void 0) {
|
|
48123
48370
|
try {
|
|
48124
|
-
|
|
48371
|
+
fs49.closeSync(startupFd);
|
|
48125
48372
|
} catch {
|
|
48126
48373
|
}
|
|
48127
48374
|
}
|
|
48128
48375
|
}
|
|
48129
48376
|
} catch (spawnErr) {
|
|
48130
|
-
const logPath =
|
|
48377
|
+
const logPath = path47.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
48131
48378
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
48132
48379
|
recordStartupState("failed", "spawn-aborted", msg);
|
|
48133
48380
|
try {
|
|
48134
|
-
|
|
48381
|
+
fs49.appendFileSync(
|
|
48135
48382
|
logPath,
|
|
48136
48383
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
|
|
48137
48384
|
`
|
|
@@ -48145,10 +48392,10 @@ RAW: ${raw}
|
|
|
48145
48392
|
);
|
|
48146
48393
|
}
|
|
48147
48394
|
if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
|
|
48148
|
-
const logPath =
|
|
48149
|
-
if (!
|
|
48150
|
-
|
|
48151
|
-
|
|
48395
|
+
const logPath = path47.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
48396
|
+
if (!fs49.existsSync(path47.dirname(logPath)))
|
|
48397
|
+
fs49.mkdirSync(path47.dirname(logPath), { recursive: true });
|
|
48398
|
+
fs49.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
|
|
48152
48399
|
`);
|
|
48153
48400
|
}
|
|
48154
48401
|
const rawToolName = sanitize2(extractToolName(payload));
|
|
@@ -48162,8 +48409,8 @@ RAW: ${raw}
|
|
|
48162
48409
|
const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
|
|
48163
48410
|
let ttyFd = null;
|
|
48164
48411
|
try {
|
|
48165
|
-
ttyFd =
|
|
48166
|
-
const writeTty = (line) =>
|
|
48412
|
+
ttyFd = fs49.openSync("/dev/tty", "w");
|
|
48413
|
+
const writeTty = (line) => fs49.writeSync(ttyFd, line + "\n");
|
|
48167
48414
|
if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
|
|
48168
48415
|
writeTty(chalk9.bgRed.white.bold(`
|
|
48169
48416
|
\u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
|
|
@@ -48182,7 +48429,7 @@ RAW: ${raw}
|
|
|
48182
48429
|
} finally {
|
|
48183
48430
|
if (ttyFd !== null)
|
|
48184
48431
|
try {
|
|
48185
|
-
|
|
48432
|
+
fs49.closeSync(ttyFd);
|
|
48186
48433
|
} catch {
|
|
48187
48434
|
}
|
|
48188
48435
|
}
|
|
@@ -48239,8 +48486,8 @@ RAW: ${raw}
|
|
|
48239
48486
|
} catch {
|
|
48240
48487
|
}
|
|
48241
48488
|
try {
|
|
48242
|
-
const ttyFd =
|
|
48243
|
-
|
|
48489
|
+
const ttyFd = fs49.openSync("/dev/tty", "w");
|
|
48490
|
+
fs49.writeSync(
|
|
48244
48491
|
ttyFd,
|
|
48245
48492
|
chalk9.yellow(
|
|
48246
48493
|
`
|
|
@@ -48248,7 +48495,7 @@ RAW: ${raw}
|
|
|
48248
48495
|
`
|
|
48249
48496
|
)
|
|
48250
48497
|
);
|
|
48251
|
-
|
|
48498
|
+
fs49.closeSync(ttyFd);
|
|
48252
48499
|
} catch {
|
|
48253
48500
|
}
|
|
48254
48501
|
if (agent === "GitHub Copilot") {
|
|
@@ -48280,17 +48527,17 @@ RAW: ${raw}
|
|
|
48280
48527
|
const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
|
|
48281
48528
|
if (skillPinCfg.enabled && safeSessionId) {
|
|
48282
48529
|
try {
|
|
48283
|
-
const sessionsDir =
|
|
48284
|
-
const flagPath =
|
|
48530
|
+
const sessionsDir = path47.join(os44.homedir(), ".node9", "skill-sessions");
|
|
48531
|
+
const flagPath = path47.join(sessionsDir, `${safeSessionId}.json`);
|
|
48285
48532
|
let flag = null;
|
|
48286
48533
|
try {
|
|
48287
|
-
flag = JSON.parse(
|
|
48534
|
+
flag = JSON.parse(fs49.readFileSync(flagPath, "utf-8"));
|
|
48288
48535
|
} catch {
|
|
48289
48536
|
}
|
|
48290
48537
|
const writeFlag = (data2) => {
|
|
48291
48538
|
try {
|
|
48292
|
-
|
|
48293
|
-
|
|
48539
|
+
fs49.mkdirSync(sessionsDir, { recursive: true });
|
|
48540
|
+
fs49.writeFileSync(
|
|
48294
48541
|
flagPath,
|
|
48295
48542
|
JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
48296
48543
|
{ mode: 384 }
|
|
@@ -48301,8 +48548,8 @@ RAW: ${raw}
|
|
|
48301
48548
|
const sendSkillWarn = (detail, recoveryCmd) => {
|
|
48302
48549
|
let ttyFd = null;
|
|
48303
48550
|
try {
|
|
48304
|
-
ttyFd =
|
|
48305
|
-
const w = (line) =>
|
|
48551
|
+
ttyFd = fs49.openSync("/dev/tty", "w");
|
|
48552
|
+
const w = (line) => fs49.writeSync(ttyFd, line + "\n");
|
|
48306
48553
|
w(chalk9.yellow(`
|
|
48307
48554
|
\u26A0\uFE0F Node9: installed skill drift detected`));
|
|
48308
48555
|
w(chalk9.gray(` ${detail}`));
|
|
@@ -48317,7 +48564,7 @@ RAW: ${raw}
|
|
|
48317
48564
|
} finally {
|
|
48318
48565
|
if (ttyFd !== null)
|
|
48319
48566
|
try {
|
|
48320
|
-
|
|
48567
|
+
fs49.closeSync(ttyFd);
|
|
48321
48568
|
} catch {
|
|
48322
48569
|
}
|
|
48323
48570
|
}
|
|
@@ -48333,7 +48580,7 @@ RAW: ${raw}
|
|
|
48333
48580
|
return;
|
|
48334
48581
|
}
|
|
48335
48582
|
if (!flag || flag.state !== "verified" && flag.state !== "warned") {
|
|
48336
|
-
const absoluteCwd = typeof payloadCwd === "string" &&
|
|
48583
|
+
const absoluteCwd = typeof payloadCwd === "string" && path47.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
48337
48584
|
const extraRoots = skillPinCfg.roots;
|
|
48338
48585
|
const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
|
|
48339
48586
|
const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
|
|
@@ -48374,10 +48621,10 @@ RAW: ${raw}
|
|
|
48374
48621
|
}
|
|
48375
48622
|
try {
|
|
48376
48623
|
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
48377
|
-
for (const name of
|
|
48378
|
-
const p =
|
|
48624
|
+
for (const name of fs49.readdirSync(sessionsDir)) {
|
|
48625
|
+
const p = path47.join(sessionsDir, name);
|
|
48379
48626
|
try {
|
|
48380
|
-
if (
|
|
48627
|
+
if (fs49.statSync(p).mtimeMs < cutoff) fs49.unlinkSync(p);
|
|
48381
48628
|
} catch {
|
|
48382
48629
|
}
|
|
48383
48630
|
}
|
|
@@ -48387,9 +48634,9 @@ RAW: ${raw}
|
|
|
48387
48634
|
} catch (err2) {
|
|
48388
48635
|
if (process.env.NODE9_DEBUG === "1") {
|
|
48389
48636
|
try {
|
|
48390
|
-
const dbg =
|
|
48637
|
+
const dbg = path47.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
48391
48638
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
48392
|
-
|
|
48639
|
+
fs49.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
|
|
48393
48640
|
`);
|
|
48394
48641
|
} catch {
|
|
48395
48642
|
}
|
|
@@ -48399,7 +48646,7 @@ RAW: ${raw}
|
|
|
48399
48646
|
if (shouldSnapshot(toolName, toolInput, config)) {
|
|
48400
48647
|
await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
|
|
48401
48648
|
}
|
|
48402
|
-
const safeCwdForAuth = typeof payloadCwd === "string" &&
|
|
48649
|
+
const safeCwdForAuth = typeof payloadCwd === "string" && path47.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
48403
48650
|
const askMode = resolveAskMode(agent, opts, config);
|
|
48404
48651
|
const result = await authorizeHeadless(toolName, toolInput, meta, {
|
|
48405
48652
|
cwd: safeCwdForAuth,
|
|
@@ -48417,12 +48664,12 @@ RAW: ${raw}
|
|
|
48417
48664
|
}
|
|
48418
48665
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
|
|
48419
48666
|
try {
|
|
48420
|
-
const tty =
|
|
48421
|
-
|
|
48667
|
+
const tty = fs49.openSync("/dev/tty", "w");
|
|
48668
|
+
fs49.writeSync(
|
|
48422
48669
|
tty,
|
|
48423
48670
|
chalk9.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
|
|
48424
48671
|
);
|
|
48425
|
-
|
|
48672
|
+
fs49.closeSync(tty);
|
|
48426
48673
|
} catch {
|
|
48427
48674
|
}
|
|
48428
48675
|
const daemonReady = await autoStartDaemonAndWait();
|
|
@@ -48449,9 +48696,9 @@ RAW: ${raw}
|
|
|
48449
48696
|
});
|
|
48450
48697
|
} catch (err2) {
|
|
48451
48698
|
if (process.env.NODE9_DEBUG === "1") {
|
|
48452
|
-
const logPath =
|
|
48699
|
+
const logPath = path47.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
48453
48700
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
48454
|
-
|
|
48701
|
+
fs49.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
|
|
48455
48702
|
`);
|
|
48456
48703
|
}
|
|
48457
48704
|
process.exit(0);
|
|
@@ -48487,8 +48734,8 @@ RAW: ${raw}
|
|
|
48487
48734
|
// src/cli/commands/log.ts
|
|
48488
48735
|
init_audit();
|
|
48489
48736
|
init_config();
|
|
48490
|
-
import
|
|
48491
|
-
import
|
|
48737
|
+
import fs50 from "fs";
|
|
48738
|
+
import path48 from "path";
|
|
48492
48739
|
import os45 from "os";
|
|
48493
48740
|
init_daemon();
|
|
48494
48741
|
init_dlp();
|
|
@@ -48597,10 +48844,10 @@ function registerLogCommand(program2) {
|
|
|
48597
48844
|
if (rawToolName !== tool) entry.agentToolName = rawToolName;
|
|
48598
48845
|
const payloadSessionId = payload.session_id ?? payload.conversationId;
|
|
48599
48846
|
if (payloadSessionId) entry.sessionId = payloadSessionId;
|
|
48600
|
-
const logPath =
|
|
48601
|
-
if (!
|
|
48602
|
-
|
|
48603
|
-
|
|
48847
|
+
const logPath = path48.join(os45.homedir(), ".node9", "audit.log");
|
|
48848
|
+
if (!fs50.existsSync(path48.dirname(logPath)))
|
|
48849
|
+
fs50.mkdirSync(path48.dirname(logPath), { recursive: true });
|
|
48850
|
+
fs50.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
48604
48851
|
if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
|
|
48605
48852
|
const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
48606
48853
|
if (command) {
|
|
@@ -48634,7 +48881,7 @@ function registerLogCommand(program2) {
|
|
|
48634
48881
|
}
|
|
48635
48882
|
}
|
|
48636
48883
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
48637
|
-
const safeCwd = typeof payloadCwd === "string" &&
|
|
48884
|
+
const safeCwd = typeof payloadCwd === "string" && path48.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
48638
48885
|
const config = getConfig(safeCwd);
|
|
48639
48886
|
{
|
|
48640
48887
|
const toolOutput = payload.tool_response?.output;
|
|
@@ -48711,9 +48958,9 @@ function registerLogCommand(program2) {
|
|
|
48711
48958
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
48712
48959
|
process.stderr.write(`[Node9] audit log error: ${msg}
|
|
48713
48960
|
`);
|
|
48714
|
-
const debugPath =
|
|
48961
|
+
const debugPath = path48.join(os45.homedir(), ".node9", "hook-debug.log");
|
|
48715
48962
|
try {
|
|
48716
|
-
|
|
48963
|
+
fs50.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
|
|
48717
48964
|
`);
|
|
48718
48965
|
} catch {
|
|
48719
48966
|
}
|
|
@@ -48740,16 +48987,16 @@ function registerLogCommand(program2) {
|
|
|
48740
48987
|
init_shields();
|
|
48741
48988
|
init_build();
|
|
48742
48989
|
import chalk10 from "chalk";
|
|
48743
|
-
import
|
|
48744
|
-
import
|
|
48990
|
+
import fs52 from "fs";
|
|
48991
|
+
import path50 from "path";
|
|
48745
48992
|
import os46 from "os";
|
|
48746
48993
|
|
|
48747
48994
|
// src/shields/create.ts
|
|
48748
48995
|
init_dist();
|
|
48749
48996
|
init_shields();
|
|
48750
48997
|
init_audit();
|
|
48751
|
-
import
|
|
48752
|
-
import
|
|
48998
|
+
import fs51 from "fs";
|
|
48999
|
+
import path49 from "path";
|
|
48753
49000
|
function builtinNames() {
|
|
48754
49001
|
const names = /* @__PURE__ */ new Set();
|
|
48755
49002
|
for (const def of Object.values(BUILTIN_SHIELDS)) {
|
|
@@ -48766,8 +49013,8 @@ function createShield(def, opts = {}) {
|
|
|
48766
49013
|
error: `"${name}" is a built-in shield \u2014 choose a different name (a user shield with this name would shadow the built-in).`
|
|
48767
49014
|
};
|
|
48768
49015
|
}
|
|
48769
|
-
const filePath =
|
|
48770
|
-
if (!opts.overwrite &&
|
|
49016
|
+
const filePath = path49.join(USER_SHIELDS_DIR_PATH, `${name}.json`);
|
|
49017
|
+
if (!opts.overwrite && fs51.existsSync(filePath)) {
|
|
48771
49018
|
return {
|
|
48772
49019
|
ok: false,
|
|
48773
49020
|
error: `Shield "${name}" already exists at ${filePath}. Pass --overwrite to replace it.`
|
|
@@ -48832,8 +49079,8 @@ var COMMUNITY_INDEX_URL = "https://raw.githubusercontent.com/node9ai/node9-proxy
|
|
|
48832
49079
|
function readCloudShields() {
|
|
48833
49080
|
const out = /* @__PURE__ */ new Set();
|
|
48834
49081
|
try {
|
|
48835
|
-
const file =
|
|
48836
|
-
const raw = JSON.parse(
|
|
49082
|
+
const file = path50.join(os46.homedir(), ".node9", "rules-cache.json");
|
|
49083
|
+
const raw = JSON.parse(fs52.readFileSync(file, "utf-8"));
|
|
48837
49084
|
for (const r of raw.rules ?? []) {
|
|
48838
49085
|
const rule = r;
|
|
48839
49086
|
const fromSource = rule.source?.startsWith("SHIELD:") ? rule.source.slice("SHIELD:".length).toLowerCase() : void 0;
|
|
@@ -49150,7 +49397,7 @@ function registerShieldCommand(program2) {
|
|
|
49150
49397
|
if (opts.fromFile) {
|
|
49151
49398
|
let raw;
|
|
49152
49399
|
try {
|
|
49153
|
-
raw = JSON.parse(
|
|
49400
|
+
raw = JSON.parse(fs52.readFileSync(opts.fromFile, "utf-8"));
|
|
49154
49401
|
} catch (err2) {
|
|
49155
49402
|
console.error(
|
|
49156
49403
|
chalk10.red(`
|
|
@@ -49270,13 +49517,14 @@ function registerConfigShowCommand(program2) {
|
|
|
49270
49517
|
|
|
49271
49518
|
// src/cli/commands/doctor.ts
|
|
49272
49519
|
init_daemon();
|
|
49520
|
+
init_build_id();
|
|
49273
49521
|
init_config();
|
|
49274
49522
|
init_agent_wiring();
|
|
49275
49523
|
init_sync();
|
|
49276
49524
|
init_service();
|
|
49277
49525
|
import chalk11 from "chalk";
|
|
49278
|
-
import
|
|
49279
|
-
import
|
|
49526
|
+
import fs53 from "fs";
|
|
49527
|
+
import path51 from "path";
|
|
49280
49528
|
import os47 from "os";
|
|
49281
49529
|
import { execSync } from "child_process";
|
|
49282
49530
|
|
|
@@ -49343,10 +49591,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
49343
49591
|
);
|
|
49344
49592
|
}
|
|
49345
49593
|
section("Configuration");
|
|
49346
|
-
const globalConfigPath =
|
|
49347
|
-
if (
|
|
49594
|
+
const globalConfigPath = path51.join(homeDir2, ".node9", "config.json");
|
|
49595
|
+
if (fs53.existsSync(globalConfigPath)) {
|
|
49348
49596
|
try {
|
|
49349
|
-
JSON.parse(
|
|
49597
|
+
JSON.parse(fs53.readFileSync(globalConfigPath, "utf-8"));
|
|
49350
49598
|
pass("~/.node9/config.json found and valid");
|
|
49351
49599
|
} catch {
|
|
49352
49600
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -49354,10 +49602,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
49354
49602
|
} else {
|
|
49355
49603
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
49356
49604
|
}
|
|
49357
|
-
const projectConfigPath =
|
|
49358
|
-
if (
|
|
49605
|
+
const projectConfigPath = path51.join(process.cwd(), "node9.config.json");
|
|
49606
|
+
if (fs53.existsSync(projectConfigPath)) {
|
|
49359
49607
|
try {
|
|
49360
|
-
JSON.parse(
|
|
49608
|
+
JSON.parse(fs53.readFileSync(projectConfigPath, "utf-8"));
|
|
49361
49609
|
pass("node9.config.json found and valid (project)");
|
|
49362
49610
|
} catch {
|
|
49363
49611
|
fail(
|
|
@@ -49366,8 +49614,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
49366
49614
|
);
|
|
49367
49615
|
}
|
|
49368
49616
|
}
|
|
49369
|
-
const credsPath =
|
|
49370
|
-
if (
|
|
49617
|
+
const credsPath = path51.join(homeDir2, ".node9", "credentials.json");
|
|
49618
|
+
if (fs53.existsSync(credsPath)) {
|
|
49371
49619
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
49372
49620
|
} else {
|
|
49373
49621
|
warn(
|
|
@@ -49401,6 +49649,17 @@ function registerDoctorCommand(program2, version2) {
|
|
|
49401
49649
|
pass(
|
|
49402
49650
|
`Daemon running on ${DAEMON_HOST}:${DAEMON_PORT} \u2014 terminal & native approvals enabled`
|
|
49403
49651
|
);
|
|
49652
|
+
const probe = await probeDaemonHealth();
|
|
49653
|
+
const drift = describeBuildDrift(
|
|
49654
|
+
probe.kind === "health" ? probe.health : probe.kind === "no-health" ? "no-health" : null,
|
|
49655
|
+
CURRENT_BUILD
|
|
49656
|
+
);
|
|
49657
|
+
if (drift) {
|
|
49658
|
+
warn(
|
|
49659
|
+
drift,
|
|
49660
|
+
"Stop the running daemon (pid in ~/.node9/daemon.pid), then: node9 daemon --background"
|
|
49661
|
+
);
|
|
49662
|
+
}
|
|
49404
49663
|
} else {
|
|
49405
49664
|
warn(
|
|
49406
49665
|
"Daemon not running \u2014 terminal & native approvals unavailable",
|
|
@@ -49422,7 +49681,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
49422
49681
|
cloudEnabled: !!getConfig().settings.approvers?.cloud
|
|
49423
49682
|
});
|
|
49424
49683
|
if (autostart) warn(autostart.message, autostart.hint);
|
|
49425
|
-
if (
|
|
49684
|
+
if (fs53.existsSync(path51.join(os47.homedir(), ".node9", "credentials.json")) && getConfig().settings.approvers?.cloud) {
|
|
49426
49685
|
section("Policy sync");
|
|
49427
49686
|
const health = readSyncHealth();
|
|
49428
49687
|
if (isPolicyStale(Date.now(), health)) {
|
|
@@ -49440,7 +49699,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
49440
49699
|
try {
|
|
49441
49700
|
const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
|
|
49442
49701
|
const cfg = getConfig();
|
|
49443
|
-
const creds =
|
|
49702
|
+
const creds = fs53.existsSync(path51.join(os47.homedir(), ".node9", "credentials.json"));
|
|
49444
49703
|
if (!creds) {
|
|
49445
49704
|
warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
|
|
49446
49705
|
} else if (!cfg.settings.approvers.cloud) {
|
|
@@ -49491,8 +49750,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
49491
49750
|
// src/cli/commands/audit.ts
|
|
49492
49751
|
init_decision();
|
|
49493
49752
|
import chalk12 from "chalk";
|
|
49494
|
-
import
|
|
49495
|
-
import
|
|
49753
|
+
import fs54 from "fs";
|
|
49754
|
+
import path52 from "path";
|
|
49496
49755
|
import os48 from "os";
|
|
49497
49756
|
function formatRelativeTime(timestamp) {
|
|
49498
49757
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
@@ -49506,14 +49765,14 @@ function formatRelativeTime(timestamp) {
|
|
|
49506
49765
|
}
|
|
49507
49766
|
function registerAuditCommand(program2) {
|
|
49508
49767
|
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) => {
|
|
49509
|
-
const logPath =
|
|
49510
|
-
if (!
|
|
49768
|
+
const logPath = path52.join(os48.homedir(), ".node9", "audit.log");
|
|
49769
|
+
if (!fs54.existsSync(logPath)) {
|
|
49511
49770
|
console.log(
|
|
49512
49771
|
chalk12.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
49513
49772
|
);
|
|
49514
49773
|
return;
|
|
49515
49774
|
}
|
|
49516
|
-
const raw =
|
|
49775
|
+
const raw = fs54.readFileSync(logPath, "utf-8");
|
|
49517
49776
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
49518
49777
|
let entries = lines.flatMap((line) => {
|
|
49519
49778
|
try {
|
|
@@ -49579,9 +49838,9 @@ init_costSync();
|
|
|
49579
49838
|
init_litellm();
|
|
49580
49839
|
init_cost_codex();
|
|
49581
49840
|
init_decision();
|
|
49582
|
-
import
|
|
49841
|
+
import fs55 from "fs";
|
|
49583
49842
|
import os49 from "os";
|
|
49584
|
-
import
|
|
49843
|
+
import path53 from "path";
|
|
49585
49844
|
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;
|
|
49586
49845
|
function buildTestTimestamps(allEntries) {
|
|
49587
49846
|
const testTs = /* @__PURE__ */ new Set();
|
|
@@ -49661,8 +49920,8 @@ function getDateRange(period, now) {
|
|
|
49661
49920
|
}
|
|
49662
49921
|
}
|
|
49663
49922
|
function parseAuditLog(logPath) {
|
|
49664
|
-
if (!
|
|
49665
|
-
const raw =
|
|
49923
|
+
if (!fs55.existsSync(logPath)) return [];
|
|
49924
|
+
const raw = fs55.readFileSync(logPath, "utf-8");
|
|
49666
49925
|
return raw.split("\n").flatMap((line) => {
|
|
49667
49926
|
if (!line.trim()) return [];
|
|
49668
49927
|
try {
|
|
@@ -49716,25 +49975,25 @@ function freezeClaudeCost(acc) {
|
|
|
49716
49975
|
};
|
|
49717
49976
|
}
|
|
49718
49977
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
49719
|
-
const projPath =
|
|
49978
|
+
const projPath = path53.join(projectsDir, proj);
|
|
49720
49979
|
let files;
|
|
49721
49980
|
try {
|
|
49722
|
-
const stat =
|
|
49981
|
+
const stat = fs55.statSync(projPath);
|
|
49723
49982
|
if (!stat.isDirectory()) return;
|
|
49724
|
-
files =
|
|
49983
|
+
files = fs55.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
49725
49984
|
} catch {
|
|
49726
49985
|
return;
|
|
49727
49986
|
}
|
|
49728
49987
|
const startMs = start.getTime();
|
|
49729
49988
|
for (const file of files) {
|
|
49730
|
-
const filePath =
|
|
49989
|
+
const filePath = path53.join(projPath, file);
|
|
49731
49990
|
try {
|
|
49732
|
-
if (
|
|
49991
|
+
if (fs55.statSync(filePath).mtimeMs < startMs) continue;
|
|
49733
49992
|
} catch {
|
|
49734
49993
|
continue;
|
|
49735
49994
|
}
|
|
49736
49995
|
try {
|
|
49737
|
-
const raw =
|
|
49996
|
+
const raw = fs55.readFileSync(filePath, "utf-8");
|
|
49738
49997
|
for (const line of raw.split("\n")) {
|
|
49739
49998
|
if (!line.trim()) continue;
|
|
49740
49999
|
let entry;
|
|
@@ -49784,10 +50043,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
49784
50043
|
}
|
|
49785
50044
|
function loadClaudeCost(start, end, projectsDir) {
|
|
49786
50045
|
const acc = emptyClaudeCostAccumulator();
|
|
49787
|
-
if (!
|
|
50046
|
+
if (!fs55.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
49788
50047
|
let dirs;
|
|
49789
50048
|
try {
|
|
49790
|
-
dirs =
|
|
50049
|
+
dirs = fs55.readdirSync(projectsDir);
|
|
49791
50050
|
} catch {
|
|
49792
50051
|
return freezeClaudeCost(acc);
|
|
49793
50052
|
}
|
|
@@ -49799,7 +50058,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
49799
50058
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
49800
50059
|
let lines;
|
|
49801
50060
|
try {
|
|
49802
|
-
lines =
|
|
50061
|
+
lines = fs55.readFileSync(filePath, "utf-8").split("\n");
|
|
49803
50062
|
} catch {
|
|
49804
50063
|
return;
|
|
49805
50064
|
}
|
|
@@ -49854,31 +50113,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
49854
50113
|
}
|
|
49855
50114
|
function listCodexSessionFiles2(sessionsBase) {
|
|
49856
50115
|
const jsonlFiles = [];
|
|
49857
|
-
if (!
|
|
50116
|
+
if (!fs55.existsSync(sessionsBase)) return jsonlFiles;
|
|
49858
50117
|
try {
|
|
49859
|
-
for (const year of
|
|
49860
|
-
const yearPath =
|
|
50118
|
+
for (const year of fs55.readdirSync(sessionsBase)) {
|
|
50119
|
+
const yearPath = path53.join(sessionsBase, year);
|
|
49861
50120
|
try {
|
|
49862
|
-
if (!
|
|
50121
|
+
if (!fs55.statSync(yearPath).isDirectory()) continue;
|
|
49863
50122
|
} catch {
|
|
49864
50123
|
continue;
|
|
49865
50124
|
}
|
|
49866
|
-
for (const month of
|
|
49867
|
-
const monthPath =
|
|
50125
|
+
for (const month of fs55.readdirSync(yearPath)) {
|
|
50126
|
+
const monthPath = path53.join(yearPath, month);
|
|
49868
50127
|
try {
|
|
49869
|
-
if (!
|
|
50128
|
+
if (!fs55.statSync(monthPath).isDirectory()) continue;
|
|
49870
50129
|
} catch {
|
|
49871
50130
|
continue;
|
|
49872
50131
|
}
|
|
49873
|
-
for (const day of
|
|
49874
|
-
const dayPath =
|
|
50132
|
+
for (const day of fs55.readdirSync(monthPath)) {
|
|
50133
|
+
const dayPath = path53.join(monthPath, day);
|
|
49875
50134
|
try {
|
|
49876
|
-
if (!
|
|
50135
|
+
if (!fs55.statSync(dayPath).isDirectory()) continue;
|
|
49877
50136
|
} catch {
|
|
49878
50137
|
continue;
|
|
49879
50138
|
}
|
|
49880
|
-
for (const file of
|
|
49881
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
50139
|
+
for (const file of fs55.readdirSync(dayPath)) {
|
|
50140
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path53.join(dayPath, file));
|
|
49882
50141
|
}
|
|
49883
50142
|
}
|
|
49884
50143
|
}
|
|
@@ -49943,13 +50202,13 @@ function freezeGeminiCost(acc) {
|
|
|
49943
50202
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
49944
50203
|
const startMs = start.getTime();
|
|
49945
50204
|
try {
|
|
49946
|
-
if (
|
|
50205
|
+
if (fs55.statSync(filePath).mtimeMs < startMs) return;
|
|
49947
50206
|
} catch {
|
|
49948
50207
|
return;
|
|
49949
50208
|
}
|
|
49950
50209
|
let raw;
|
|
49951
50210
|
try {
|
|
49952
|
-
raw =
|
|
50211
|
+
raw = fs55.readFileSync(filePath, "utf-8");
|
|
49953
50212
|
} catch {
|
|
49954
50213
|
return;
|
|
49955
50214
|
}
|
|
@@ -49998,30 +50257,30 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
|
|
|
49998
50257
|
const out = [];
|
|
49999
50258
|
let dirs;
|
|
50000
50259
|
try {
|
|
50001
|
-
if (!
|
|
50002
|
-
dirs =
|
|
50260
|
+
if (!fs55.statSync(geminiTmpDir2).isDirectory()) return out;
|
|
50261
|
+
dirs = fs55.readdirSync(geminiTmpDir2);
|
|
50003
50262
|
} catch {
|
|
50004
50263
|
return out;
|
|
50005
50264
|
}
|
|
50006
50265
|
for (const proj of dirs) {
|
|
50007
|
-
const chatsDir =
|
|
50266
|
+
const chatsDir = path53.join(geminiTmpDir2, proj, "chats");
|
|
50008
50267
|
let files;
|
|
50009
50268
|
try {
|
|
50010
|
-
if (!
|
|
50011
|
-
files =
|
|
50269
|
+
if (!fs55.statSync(chatsDir).isDirectory()) continue;
|
|
50270
|
+
files = fs55.readdirSync(chatsDir);
|
|
50012
50271
|
} catch {
|
|
50013
50272
|
continue;
|
|
50014
50273
|
}
|
|
50015
50274
|
for (const f of files) {
|
|
50016
50275
|
if (!f.endsWith(".jsonl")) continue;
|
|
50017
|
-
out.push({ projectKey: proj, file:
|
|
50276
|
+
out.push({ projectKey: proj, file: path53.join(chatsDir, f) });
|
|
50018
50277
|
}
|
|
50019
50278
|
}
|
|
50020
50279
|
return out;
|
|
50021
50280
|
}
|
|
50022
50281
|
function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
50023
50282
|
const acc = emptyGeminiAccumulator();
|
|
50024
|
-
if (!
|
|
50283
|
+
if (!fs55.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
|
|
50025
50284
|
for (const { projectKey, file } of listGeminiSessionFiles2(geminiTmpDir2)) {
|
|
50026
50285
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
50027
50286
|
}
|
|
@@ -50039,11 +50298,11 @@ function dimensionOfBlock(checkedBy, ruleName) {
|
|
|
50039
50298
|
}
|
|
50040
50299
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
50041
50300
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
50042
|
-
const auditLogPath = opts.auditLogPath ??
|
|
50043
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
50044
|
-
const codexSessionsDir2 = opts.codexSessionsDir ??
|
|
50045
|
-
const geminiTmpDir2 = opts.geminiTmpDir ??
|
|
50046
|
-
const hasAuditFile =
|
|
50301
|
+
const auditLogPath = opts.auditLogPath ?? path53.join(os49.homedir(), ".node9", "audit.log");
|
|
50302
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? path53.join(os49.homedir(), ".claude", "projects");
|
|
50303
|
+
const codexSessionsDir2 = opts.codexSessionsDir ?? path53.join(os49.homedir(), ".codex", "sessions");
|
|
50304
|
+
const geminiTmpDir2 = opts.geminiTmpDir ?? path53.join(os49.homedir(), ".gemini", "tmp");
|
|
50305
|
+
const hasAuditFile = fs55.existsSync(auditLogPath);
|
|
50047
50306
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
50048
50307
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
50049
50308
|
const { start, end } = getDateRange(period, now);
|
|
@@ -50750,11 +51009,12 @@ function renderTerminalReport(data, responseDlpEntries, excludeTests) {
|
|
|
50750
51009
|
}
|
|
50751
51010
|
|
|
50752
51011
|
// src/cli/commands/daemon-cmd.ts
|
|
51012
|
+
init_daemon();
|
|
50753
51013
|
init_startup_log();
|
|
50754
51014
|
init_daemon2();
|
|
50755
51015
|
import chalk14 from "chalk";
|
|
50756
51016
|
import { spawn as spawn6 } from "child_process";
|
|
50757
|
-
import
|
|
51017
|
+
import fs56 from "fs";
|
|
50758
51018
|
var VALID_ACTIONS = "start | stop | restart | status | install | uninstall";
|
|
50759
51019
|
function registerDaemonCommand(program2) {
|
|
50760
51020
|
program2.command("daemon").description("Manage the local approval daemon").argument("[action]", `${VALID_ACTIONS} (default: start)`).option("-b, --background", "Start the daemon in the background (detached)").option(
|
|
@@ -50791,7 +51051,10 @@ function registerDaemonCommand(program2) {
|
|
|
50791
51051
|
if (cmd === "stop") return stopDaemon();
|
|
50792
51052
|
if (cmd === "restart") {
|
|
50793
51053
|
stopDaemon();
|
|
50794
|
-
|
|
51054
|
+
for (let i = 0; i < 15; i++) {
|
|
51055
|
+
if (!await isDaemonReachable(300)) break;
|
|
51056
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
51057
|
+
}
|
|
50795
51058
|
const restartFd = openStartupLogFd();
|
|
50796
51059
|
recordStartupState("starting");
|
|
50797
51060
|
const child = spawn6(process.execPath, [process.argv[1], "daemon"], {
|
|
@@ -50806,7 +51069,7 @@ function registerDaemonCommand(program2) {
|
|
|
50806
51069
|
child.unref();
|
|
50807
51070
|
if (restartFd !== void 0) {
|
|
50808
51071
|
try {
|
|
50809
|
-
|
|
51072
|
+
fs56.closeSync(restartFd);
|
|
50810
51073
|
} catch {
|
|
50811
51074
|
}
|
|
50812
51075
|
}
|
|
@@ -50857,7 +51120,7 @@ function registerDaemonCommand(program2) {
|
|
|
50857
51120
|
} finally {
|
|
50858
51121
|
if (startupFd !== void 0) {
|
|
50859
51122
|
try {
|
|
50860
|
-
|
|
51123
|
+
fs56.closeSync(startupFd);
|
|
50861
51124
|
} catch {
|
|
50862
51125
|
}
|
|
50863
51126
|
}
|
|
@@ -50872,12 +51135,13 @@ function registerDaemonCommand(program2) {
|
|
|
50872
51135
|
// src/cli/commands/status.ts
|
|
50873
51136
|
init_core();
|
|
50874
51137
|
init_daemon();
|
|
51138
|
+
init_build_id();
|
|
50875
51139
|
init_agent_wiring();
|
|
50876
51140
|
init_sync();
|
|
50877
51141
|
init_service();
|
|
50878
51142
|
import chalk15 from "chalk";
|
|
50879
|
-
import
|
|
50880
|
-
import
|
|
51143
|
+
import fs57 from "fs";
|
|
51144
|
+
import path54 from "path";
|
|
50881
51145
|
import os50 from "os";
|
|
50882
51146
|
function printAgentSection(label2, hookPairs, wrapped) {
|
|
50883
51147
|
console.log(chalk15.bold(` ${label2}`));
|
|
@@ -50899,7 +51163,7 @@ function printAgentSection(label2, hookPairs, wrapped) {
|
|
|
50899
51163
|
}
|
|
50900
51164
|
}
|
|
50901
51165
|
function registerStatusCommand(program2) {
|
|
50902
|
-
program2.command("status").description("Show current Node9 mode, policy source, and persistent decisions").action(() => {
|
|
51166
|
+
program2.command("status").description("Show current Node9 mode, policy source, and persistent decisions").action(async () => {
|
|
50903
51167
|
const creds = getCredentials();
|
|
50904
51168
|
const daemonRunning = isDaemonRunning();
|
|
50905
51169
|
const mergedConfig = getConfig();
|
|
@@ -50930,6 +51194,14 @@ function registerStatusCommand(program2) {
|
|
|
50930
51194
|
console.log(
|
|
50931
51195
|
chalk15.green(" \u25CF Daemon running") + chalk15.gray(` \u2192 http://127.0.0.1:${DAEMON_PORT}/`)
|
|
50932
51196
|
);
|
|
51197
|
+
const probe = await probeDaemonHealth();
|
|
51198
|
+
const drift = describeBuildDrift(
|
|
51199
|
+
probe.kind === "health" ? probe.health : probe.kind === "no-health" ? "no-health" : null,
|
|
51200
|
+
CURRENT_BUILD
|
|
51201
|
+
);
|
|
51202
|
+
if (drift) {
|
|
51203
|
+
console.log(chalk15.yellow(` \u26A0 ${drift}`) + chalk15.gray(" \u2014 run: node9 doctor"));
|
|
51204
|
+
}
|
|
50933
51205
|
} else {
|
|
50934
51206
|
console.log(chalk15.gray(" \u25CB Daemon stopped"));
|
|
50935
51207
|
}
|
|
@@ -50951,13 +51223,13 @@ function registerStatusCommand(program2) {
|
|
|
50951
51223
|
console.log("");
|
|
50952
51224
|
const modeLabel = settings.mode === "audit" ? chalk15.blue("audit") : settings.mode === "strict" ? chalk15.red("strict") : chalk15.white("standard");
|
|
50953
51225
|
console.log(` Mode: ${modeLabel}`);
|
|
50954
|
-
const projectConfig =
|
|
50955
|
-
const globalConfig =
|
|
51226
|
+
const projectConfig = path54.join(process.cwd(), "node9.config.json");
|
|
51227
|
+
const globalConfig = path54.join(os50.homedir(), ".node9", "config.json");
|
|
50956
51228
|
console.log(
|
|
50957
|
-
` Local: ${
|
|
51229
|
+
` Local: ${fs57.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
|
|
50958
51230
|
);
|
|
50959
51231
|
console.log(
|
|
50960
|
-
` Global: ${
|
|
51232
|
+
` Global: ${fs57.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
|
|
50961
51233
|
);
|
|
50962
51234
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
50963
51235
|
console.log(
|
|
@@ -51004,8 +51276,8 @@ init_shields();
|
|
|
51004
51276
|
init_service();
|
|
51005
51277
|
init_core();
|
|
51006
51278
|
import chalk16 from "chalk";
|
|
51007
|
-
import
|
|
51008
|
-
import
|
|
51279
|
+
import fs58 from "fs";
|
|
51280
|
+
import path55 from "path";
|
|
51009
51281
|
import os51 from "os";
|
|
51010
51282
|
import https6 from "https";
|
|
51011
51283
|
var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
|
|
@@ -51092,16 +51364,16 @@ function registerInitCommand(program2) {
|
|
|
51092
51364
|
}
|
|
51093
51365
|
console.log("");
|
|
51094
51366
|
}
|
|
51095
|
-
const configPath =
|
|
51096
|
-
const isFirstInstall = !
|
|
51097
|
-
if (
|
|
51367
|
+
const configPath = path55.join(os51.homedir(), ".node9", "config.json");
|
|
51368
|
+
const isFirstInstall = !fs58.existsSync(configPath);
|
|
51369
|
+
if (fs58.existsSync(configPath) && !options.force) {
|
|
51098
51370
|
try {
|
|
51099
|
-
const existing = JSON.parse(
|
|
51371
|
+
const existing = JSON.parse(fs58.readFileSync(configPath, "utf-8"));
|
|
51100
51372
|
const settings = existing.settings ?? {};
|
|
51101
51373
|
if (settings.mode !== chosenMode) {
|
|
51102
51374
|
settings.mode = chosenMode;
|
|
51103
51375
|
existing.settings = settings;
|
|
51104
|
-
|
|
51376
|
+
fs58.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
51105
51377
|
console.log(chalk16.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
51106
51378
|
} else {
|
|
51107
51379
|
console.log(chalk16.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -51114,9 +51386,9 @@ function registerInitCommand(program2) {
|
|
|
51114
51386
|
...DEFAULT_CONFIG,
|
|
51115
51387
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
51116
51388
|
};
|
|
51117
|
-
const dir =
|
|
51118
|
-
if (!
|
|
51119
|
-
|
|
51389
|
+
const dir = path55.dirname(configPath);
|
|
51390
|
+
if (!fs58.existsSync(dir)) fs58.mkdirSync(dir, { recursive: true });
|
|
51391
|
+
fs58.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
51120
51392
|
console.log(chalk16.green(`\u2705 Config created: ${configPath}`));
|
|
51121
51393
|
console.log(chalk16.gray(` Mode: ${chosenMode}`));
|
|
51122
51394
|
}
|
|
@@ -51219,11 +51491,11 @@ init_agent_wiring();
|
|
|
51219
51491
|
init_setup();
|
|
51220
51492
|
init_hook_baseline();
|
|
51221
51493
|
import chalk17 from "chalk";
|
|
51222
|
-
import
|
|
51494
|
+
import fs59 from "fs";
|
|
51223
51495
|
var hasHookSurface = (a) => a.hooks.length > 0;
|
|
51224
51496
|
function backupForHeal(file) {
|
|
51225
51497
|
try {
|
|
51226
|
-
if (file &&
|
|
51498
|
+
if (file && fs59.existsSync(file)) fs59.copyFileSync(file, `${file}.node9-heal-bak`);
|
|
51227
51499
|
} catch {
|
|
51228
51500
|
}
|
|
51229
51501
|
}
|
|
@@ -51390,7 +51662,7 @@ function registerConnectCommand(program2) {
|
|
|
51390
51662
|
}
|
|
51391
51663
|
|
|
51392
51664
|
// src/cli/commands/undo.ts
|
|
51393
|
-
import
|
|
51665
|
+
import path56 from "path";
|
|
51394
51666
|
import chalk20 from "chalk";
|
|
51395
51667
|
|
|
51396
51668
|
// src/tui/undo-navigator.ts
|
|
@@ -51549,7 +51821,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
51549
51821
|
let dir = startDir;
|
|
51550
51822
|
while (true) {
|
|
51551
51823
|
if (cwds.has(dir)) return dir;
|
|
51552
|
-
const parent =
|
|
51824
|
+
const parent = path56.dirname(dir);
|
|
51553
51825
|
if (parent === dir) return null;
|
|
51554
51826
|
dir = parent;
|
|
51555
51827
|
}
|
|
@@ -52183,9 +52455,9 @@ function registerMcpGatewayCommand(program2) {
|
|
|
52183
52455
|
|
|
52184
52456
|
// src/mcp-server/index.ts
|
|
52185
52457
|
import readline5 from "readline";
|
|
52186
|
-
import
|
|
52458
|
+
import fs61 from "fs";
|
|
52187
52459
|
import os53 from "os";
|
|
52188
|
-
import
|
|
52460
|
+
import path58 from "path";
|
|
52189
52461
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
52190
52462
|
init_decision();
|
|
52191
52463
|
init_core();
|
|
@@ -52193,9 +52465,9 @@ init_daemon();
|
|
|
52193
52465
|
init_shields();
|
|
52194
52466
|
|
|
52195
52467
|
// src/auth/egress-config.ts
|
|
52196
|
-
import
|
|
52468
|
+
import fs60 from "fs";
|
|
52197
52469
|
import os52 from "os";
|
|
52198
|
-
import
|
|
52470
|
+
import path57 from "path";
|
|
52199
52471
|
var DEFAULT_EGRESS = {
|
|
52200
52472
|
enabled: false,
|
|
52201
52473
|
mode: "review",
|
|
@@ -52204,12 +52476,12 @@ var DEFAULT_EGRESS = {
|
|
|
52204
52476
|
allowPrivate: true
|
|
52205
52477
|
};
|
|
52206
52478
|
function egressConfigPath() {
|
|
52207
|
-
return
|
|
52479
|
+
return path57.join(os52.homedir(), ".node9", "config.json");
|
|
52208
52480
|
}
|
|
52209
52481
|
function readEgressRawConfig() {
|
|
52210
52482
|
let text;
|
|
52211
52483
|
try {
|
|
52212
|
-
text =
|
|
52484
|
+
text = fs60.readFileSync(egressConfigPath(), "utf8");
|
|
52213
52485
|
} catch (err2) {
|
|
52214
52486
|
if (err2.code === "ENOENT") return {};
|
|
52215
52487
|
throw err2;
|
|
@@ -52224,8 +52496,8 @@ function readEgressRawConfig() {
|
|
|
52224
52496
|
}
|
|
52225
52497
|
function writeEgressRawConfig(config) {
|
|
52226
52498
|
const p = egressConfigPath();
|
|
52227
|
-
|
|
52228
|
-
|
|
52499
|
+
fs60.mkdirSync(path57.dirname(p), { recursive: true });
|
|
52500
|
+
fs60.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
52229
52501
|
}
|
|
52230
52502
|
function applyEgress(config, change) {
|
|
52231
52503
|
const policy = config.policy = config.policy ?? {};
|
|
@@ -52610,13 +52882,13 @@ function handleStatus() {
|
|
|
52610
52882
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
52611
52883
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
52612
52884
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
52613
|
-
const projectConfig =
|
|
52614
|
-
const globalConfig =
|
|
52885
|
+
const projectConfig = path58.join(process.cwd(), "node9.config.json");
|
|
52886
|
+
const globalConfig = path58.join(os53.homedir(), ".node9", "config.json");
|
|
52615
52887
|
lines.push(
|
|
52616
|
-
`Project config (node9.config.json): ${
|
|
52888
|
+
`Project config (node9.config.json): ${fs61.existsSync(projectConfig) ? "present" : "not found"}`
|
|
52617
52889
|
);
|
|
52618
52890
|
lines.push(
|
|
52619
|
-
`Global config (~/.node9/config.json): ${
|
|
52891
|
+
`Global config (~/.node9/config.json): ${fs61.existsSync(globalConfig) ? "present" : "not found"}`
|
|
52620
52892
|
);
|
|
52621
52893
|
return lines.join("\n");
|
|
52622
52894
|
}
|
|
@@ -52722,21 +52994,21 @@ function handleEgressDeny(args) {
|
|
|
52722
52994
|
addEgressHost("deny", host);
|
|
52723
52995
|
return `Denied egress to ${host} (deny always wins over allow).`;
|
|
52724
52996
|
}
|
|
52725
|
-
var GLOBAL_CONFIG_PATH =
|
|
52997
|
+
var GLOBAL_CONFIG_PATH = path58.join(os53.homedir(), ".node9", "config.json");
|
|
52726
52998
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
52727
52999
|
function readGlobalConfigRaw() {
|
|
52728
53000
|
try {
|
|
52729
|
-
if (
|
|
52730
|
-
return JSON.parse(
|
|
53001
|
+
if (fs61.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
53002
|
+
return JSON.parse(fs61.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
|
|
52731
53003
|
}
|
|
52732
53004
|
} catch {
|
|
52733
53005
|
}
|
|
52734
53006
|
return {};
|
|
52735
53007
|
}
|
|
52736
53008
|
function writeGlobalConfigRaw(data) {
|
|
52737
|
-
const dir =
|
|
52738
|
-
if (!
|
|
52739
|
-
|
|
53009
|
+
const dir = path58.dirname(GLOBAL_CONFIG_PATH);
|
|
53010
|
+
if (!fs61.existsSync(dir)) fs61.mkdirSync(dir, { recursive: true });
|
|
53011
|
+
fs61.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
|
|
52740
53012
|
}
|
|
52741
53013
|
function handleApproverList() {
|
|
52742
53014
|
const config = getConfig();
|
|
@@ -52780,9 +53052,9 @@ function handleApproverSet(args) {
|
|
|
52780
53052
|
function handleAuditGet(args) {
|
|
52781
53053
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
52782
53054
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
52783
|
-
const auditPath =
|
|
52784
|
-
if (!
|
|
52785
|
-
const rawLines =
|
|
53055
|
+
const auditPath = path58.join(os53.homedir(), ".node9", "audit.log");
|
|
53056
|
+
if (!fs61.existsSync(auditPath)) return "No audit log found.";
|
|
53057
|
+
const rawLines = fs61.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
52786
53058
|
const wanted = filter === "block" ? "deny" : filter;
|
|
52787
53059
|
const parsed = [];
|
|
52788
53060
|
for (const line of rawLines) {
|
|
@@ -53158,7 +53430,7 @@ function registerTrustCommand(program2) {
|
|
|
53158
53430
|
// src/cli/commands/mcp-pin.ts
|
|
53159
53431
|
init_mcp_pin();
|
|
53160
53432
|
import chalk24 from "chalk";
|
|
53161
|
-
import
|
|
53433
|
+
import fs62 from "fs";
|
|
53162
53434
|
|
|
53163
53435
|
// src/cli/commands/mcp-gateway-cmd.ts
|
|
53164
53436
|
init_mcp_wrap();
|
|
@@ -53366,7 +53638,7 @@ function registerMcpPinCommand(program2) {
|
|
|
53366
53638
|
let repoCorrupt = false;
|
|
53367
53639
|
if (found.source === "repo") {
|
|
53368
53640
|
try {
|
|
53369
|
-
const raw =
|
|
53641
|
+
const raw = fs62.readFileSync(found.path, "utf-8");
|
|
53370
53642
|
const parsed = JSON.parse(raw);
|
|
53371
53643
|
repoEntries = parsed.servers ?? {};
|
|
53372
53644
|
} catch {
|
|
@@ -53960,8 +54232,8 @@ import chalk30 from "chalk";
|
|
|
53960
54232
|
|
|
53961
54233
|
// src/ci-check/fetch.ts
|
|
53962
54234
|
var import_undici = __toESM(require_undici());
|
|
53963
|
-
import
|
|
53964
|
-
import
|
|
54235
|
+
import fs63 from "fs";
|
|
54236
|
+
import path59 from "path";
|
|
53965
54237
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
53966
54238
|
var cachedGhToken;
|
|
53967
54239
|
function resolveGitHubToken() {
|
|
@@ -54044,7 +54316,7 @@ function parseRepoUrl(input) {
|
|
|
54044
54316
|
function isLocalPath(input) {
|
|
54045
54317
|
if (input.startsWith(".") || input.startsWith("/") || input.startsWith("~")) return true;
|
|
54046
54318
|
try {
|
|
54047
|
-
return
|
|
54319
|
+
return fs63.existsSync(input) && fs63.statSync(input).isDirectory();
|
|
54048
54320
|
} catch {
|
|
54049
54321
|
return false;
|
|
54050
54322
|
}
|
|
@@ -54159,10 +54431,10 @@ function readLocalTree(dir) {
|
|
|
54159
54431
|
const files = [];
|
|
54160
54432
|
const notes = [];
|
|
54161
54433
|
const add = (rel) => {
|
|
54162
|
-
const abs =
|
|
54434
|
+
const abs = path59.join(root, rel);
|
|
54163
54435
|
try {
|
|
54164
|
-
if (
|
|
54165
|
-
files.push({ path: rel, content:
|
|
54436
|
+
if (fs63.existsSync(abs) && fs63.statSync(abs).isFile()) {
|
|
54437
|
+
files.push({ path: rel, content: fs63.readFileSync(abs, "utf8") });
|
|
54166
54438
|
}
|
|
54167
54439
|
} catch {
|
|
54168
54440
|
}
|
|
@@ -54182,7 +54454,7 @@ function readLocalTree(dir) {
|
|
|
54182
54454
|
dirsVisited++;
|
|
54183
54455
|
let entries;
|
|
54184
54456
|
try {
|
|
54185
|
-
entries =
|
|
54457
|
+
entries = fs63.readdirSync(path59.join(root, relDir), { withFileTypes: true });
|
|
54186
54458
|
} catch {
|
|
54187
54459
|
return;
|
|
54188
54460
|
}
|
|
@@ -54203,11 +54475,11 @@ function readLocalTree(dir) {
|
|
|
54203
54475
|
`repo is large \u2014 some agent-surface files may be INCOMPLETE (capped at ${MAX_SURFACE_FILES} files / ${MAX_DIRS} dirs).`
|
|
54204
54476
|
);
|
|
54205
54477
|
for (const rel of matches) collect(rel);
|
|
54206
|
-
const wfDir =
|
|
54478
|
+
const wfDir = path59.join(root, WORKFLOW_DIR);
|
|
54207
54479
|
try {
|
|
54208
|
-
if (
|
|
54209
|
-
for (const name of
|
|
54210
|
-
if (/\.ya?ml$/.test(name)) add(
|
|
54480
|
+
if (fs63.existsSync(wfDir)) {
|
|
54481
|
+
for (const name of fs63.readdirSync(wfDir)) {
|
|
54482
|
+
if (/\.ya?ml$/.test(name)) add(path59.join(WORKFLOW_DIR, name));
|
|
54211
54483
|
}
|
|
54212
54484
|
}
|
|
54213
54485
|
} catch {
|
|
@@ -54512,7 +54784,7 @@ function severityFromScore(score) {
|
|
|
54512
54784
|
if (score >= 1) return "advisory";
|
|
54513
54785
|
return null;
|
|
54514
54786
|
}
|
|
54515
|
-
function analyzeWorkflow(
|
|
54787
|
+
function analyzeWorkflow(path72, content) {
|
|
54516
54788
|
let raw;
|
|
54517
54789
|
try {
|
|
54518
54790
|
raw = parseYaml(content) ?? {};
|
|
@@ -54638,7 +54910,7 @@ function analyzeWorkflow(path71, content) {
|
|
|
54638
54910
|
dimension: "workflows",
|
|
54639
54911
|
severity,
|
|
54640
54912
|
title,
|
|
54641
|
-
file:
|
|
54913
|
+
file: path72,
|
|
54642
54914
|
signals,
|
|
54643
54915
|
mitigations: mitigations.length ? mitigations : void 0,
|
|
54644
54916
|
fix: head === "root" && privileged ? "Do not check out the untrusted PR head into the workspace root under a privileged trigger (pull_request_target/workflow_run) \u2014 check out the base ref, or isolate the head in a subdir (--add-dir). Add an actor gate and scope the agent tools." : head === "root" ? "This runs under `pull_request` (fork PRs get a read-only token), so the head checkout is low-risk today \u2014 keep it on `pull_request` (not `pull_request_target`) and keep the actor gate + scoped tools." : "Add/verify an actor gate, scope the agent tools to read-only, and env-deny secrets. See Anthropic\u2019s claude-code-action security doc."
|
|
@@ -54714,7 +54986,7 @@ function evalAgentJob(job, wf, raw, untrustedTrigger, reusable) {
|
|
|
54714
54986
|
if (reusable && !loadedGun && SEVERITY_RANK2[severity] > SEVERITY_RANK2.medium) severity = "medium";
|
|
54715
54987
|
return { severity, secrets, injectable, canReadEnv };
|
|
54716
54988
|
}
|
|
54717
|
-
function analyzeWorkflowSecrets(
|
|
54989
|
+
function analyzeWorkflowSecrets(path72, content) {
|
|
54718
54990
|
let raw;
|
|
54719
54991
|
try {
|
|
54720
54992
|
raw = parseYaml(content) ?? {};
|
|
@@ -54734,7 +55006,7 @@ function analyzeWorkflowSecrets(path71, content) {
|
|
|
54734
55006
|
dimension: "data",
|
|
54735
55007
|
severity: worst.severity,
|
|
54736
55008
|
title: worst.severity === "advisory" ? "Secrets reachable by the agent \u2014 hardening" : "Exfiltratable secrets reachable by an injectable agent",
|
|
54737
|
-
file:
|
|
55009
|
+
file: path72,
|
|
54738
55010
|
signals: [
|
|
54739
55011
|
`agent can reach: ${worst.secrets.map((s) => s.name).join(", ")}`,
|
|
54740
55012
|
worst.injectable ? "the agent is externally triggerable (untrusted trigger, no gate)" : "gated / not externally triggerable \u2014 latent risk only",
|
|
@@ -54761,7 +55033,7 @@ function hookCommands(hooks) {
|
|
|
54761
55033
|
}
|
|
54762
55034
|
return out;
|
|
54763
55035
|
}
|
|
54764
|
-
function analyzeAgentConfig(
|
|
55036
|
+
function analyzeAgentConfig(path72, content) {
|
|
54765
55037
|
let cfg;
|
|
54766
55038
|
try {
|
|
54767
55039
|
cfg = JSON.parse(content);
|
|
@@ -54780,7 +55052,7 @@ function analyzeAgentConfig(path71, content) {
|
|
|
54780
55052
|
dimension: "toolRules",
|
|
54781
55053
|
severity: high ? "high" : "medium",
|
|
54782
55054
|
title: high ? "Agent hook runs UNPINNED/remote third-party code on every action" : "Agent hook runs third-party code in the agent hot path",
|
|
54783
|
-
file:
|
|
55055
|
+
file: path72,
|
|
54784
55056
|
signals: [
|
|
54785
55057
|
`hook command: \`${cmd.slice(0, 120)}\``,
|
|
54786
55058
|
remoteExec ? "fetch-and-run (curl|wget / pipe-to-shell) \u2014 unpinnable remote code execution on every contributor" : unpinned ? "unpinned \u2014 a compromised/yanked package = code execution on every contributor" : "pinned, but still a standing supply-chain dependency in the agent hot path"
|
|
@@ -54800,7 +55072,7 @@ function analyzeAgentConfig(path71, content) {
|
|
|
54800
55072
|
dimension: "toolRules",
|
|
54801
55073
|
severity: hasBackstop ? "medium" : "high",
|
|
54802
55074
|
title: hasBackstop ? "Committed agent config pre-authorizes broad tools" : "Committed agent config pre-authorizes broad tools with no deny backstop",
|
|
54803
|
-
file:
|
|
55075
|
+
file: path72,
|
|
54804
55076
|
signals: [
|
|
54805
55077
|
`broad allow(s): ${broad.slice(0, 5).join(", ")}`,
|
|
54806
55078
|
hasBackstop ? "a `deny` list backstops the broad allow" : "no `deny` entry covers Bash/Write/Edit \u2014 every contributor is pre-authorized for catastrophic tools"
|
|
@@ -54813,16 +55085,16 @@ function analyzeAgentConfig(path71, content) {
|
|
|
54813
55085
|
|
|
54814
55086
|
// src/ci-check/mcp.ts
|
|
54815
55087
|
init_dist();
|
|
54816
|
-
function analyzeMcp(
|
|
55088
|
+
function analyzeMcp(path72, content) {
|
|
54817
55089
|
let cfg;
|
|
54818
55090
|
try {
|
|
54819
55091
|
cfg = JSON.parse(content);
|
|
54820
55092
|
} catch {
|
|
54821
55093
|
return [];
|
|
54822
55094
|
}
|
|
54823
|
-
return analyzeMcpServers(cfg.mcpServers ?? {},
|
|
55095
|
+
return analyzeMcpServers(cfg.mcpServers ?? {}, path72);
|
|
54824
55096
|
}
|
|
54825
|
-
function analyzeMcpServers(servers,
|
|
55097
|
+
function analyzeMcpServers(servers, path72) {
|
|
54826
55098
|
const findings = [];
|
|
54827
55099
|
for (const [name, srv] of Object.entries(servers ?? {})) {
|
|
54828
55100
|
if (!srv || srv.disabled) continue;
|
|
@@ -54833,7 +55105,7 @@ function analyzeMcpServers(servers, path71) {
|
|
|
54833
55105
|
dimension: "mcp",
|
|
54834
55106
|
severity: "medium",
|
|
54835
55107
|
title: `MCP server "${name}" runs an unpinned executable`,
|
|
54836
|
-
file:
|
|
55108
|
+
file: path72,
|
|
54837
55109
|
signals: [`\`${argv.slice(0, 120)}\` \u2014 unversioned/@latest npx`],
|
|
54838
55110
|
fix: "Pin the MCP server package to an exact version so a PR (or a registry compromise) can\u2019t swap the toolchain."
|
|
54839
55111
|
});
|
|
@@ -54847,7 +55119,7 @@ function analyzeMcpServers(servers, path71) {
|
|
|
54847
55119
|
dimension: "mcp",
|
|
54848
55120
|
severity: "high",
|
|
54849
55121
|
title: `MCP server "${name}" has an inline credential`,
|
|
54850
|
-
file:
|
|
55122
|
+
file: path72,
|
|
54851
55123
|
signals: [
|
|
54852
55124
|
`env.${k} matches ${hit.patternName} \u2014 agent-reachable secret committed to the repo`
|
|
54853
55125
|
],
|
|
@@ -54861,7 +55133,7 @@ function analyzeMcpServers(servers, path71) {
|
|
|
54861
55133
|
|
|
54862
55134
|
// src/ci-check/codex.ts
|
|
54863
55135
|
import { parse as parseToml5 } from "smol-toml";
|
|
54864
|
-
function analyzeCodexConfig(
|
|
55136
|
+
function analyzeCodexConfig(path72, content) {
|
|
54865
55137
|
let cfg;
|
|
54866
55138
|
try {
|
|
54867
55139
|
cfg = parseToml5(content);
|
|
@@ -54869,7 +55141,7 @@ function analyzeCodexConfig(path71, content) {
|
|
|
54869
55141
|
return [];
|
|
54870
55142
|
}
|
|
54871
55143
|
const findings = [];
|
|
54872
|
-
findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {},
|
|
55144
|
+
findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {}, path72));
|
|
54873
55145
|
const sandbox = typeof cfg.sandbox_mode === "string" ? cfg.sandbox_mode : "";
|
|
54874
55146
|
const approval = typeof cfg.approval_policy === "string" ? cfg.approval_policy : "";
|
|
54875
55147
|
const fullAccess = /danger-full-access/i.test(sandbox);
|
|
@@ -54884,7 +55156,7 @@ function analyzeCodexConfig(path71, content) {
|
|
|
54884
55156
|
dimension: "toolRules",
|
|
54885
55157
|
severity: fullAccess ? "high" : "medium",
|
|
54886
55158
|
title: fullAccess ? "Codex config grants a full-access sandbox" : "Codex config never requires approval",
|
|
54887
|
-
file:
|
|
55159
|
+
file: path72,
|
|
54888
55160
|
signals,
|
|
54889
55161
|
fix: 'Commit a least-privilege Codex config: prefer `sandbox_mode = "read-only"` (or `"workspace-write"`) and `approval_policy = "on-request"`/`"on-failure"`. A repo-committed config applies to every contributor who runs Codex here.'
|
|
54890
55162
|
});
|
|
@@ -54940,10 +55212,10 @@ function decodeSuspiciousBase64(text) {
|
|
|
54940
55212
|
}
|
|
54941
55213
|
return out;
|
|
54942
55214
|
}
|
|
54943
|
-
function mk(severity, title, signals, fix,
|
|
54944
|
-
return { check: "CI-6", dimension: "instructions", severity, title, file:
|
|
55215
|
+
function mk(severity, title, signals, fix, path72) {
|
|
55216
|
+
return { check: "CI-6", dimension: "instructions", severity, title, file: path72, signals, fix };
|
|
54945
55217
|
}
|
|
54946
|
-
function analyzeInstructionFile(
|
|
55218
|
+
function analyzeInstructionFile(path72, content) {
|
|
54947
55219
|
const findings = [];
|
|
54948
55220
|
const decoded = decodeSuspiciousBase64(content);
|
|
54949
55221
|
if (TAG_CHARS.test(content))
|
|
@@ -54955,7 +55227,7 @@ function analyzeInstructionFile(path71, content) {
|
|
|
54955
55227
|
"contains Unicode tag characters (U+E0000\u2013E007F) \u2014 an invisible instruction-smuggling channel with no legitimate use in text"
|
|
54956
55228
|
],
|
|
54957
55229
|
"Remove the tag characters. Instruction files must be plain, reviewable text.",
|
|
54958
|
-
|
|
55230
|
+
path72
|
|
54959
55231
|
)
|
|
54960
55232
|
);
|
|
54961
55233
|
if (BIDI_OVERRIDE.test(content))
|
|
@@ -54967,7 +55239,7 @@ function analyzeInstructionFile(path71, content) {
|
|
|
54967
55239
|
"contains a bidi override (U+202D/U+202E) \u2014 a Trojan-Source technique that visually reorders text so a human reads something different from what the agent parses"
|
|
54968
55240
|
],
|
|
54969
55241
|
"Remove the bidi override characters.",
|
|
54970
|
-
|
|
55242
|
+
path72
|
|
54971
55243
|
)
|
|
54972
55244
|
);
|
|
54973
55245
|
else if (BIDI_EMBED_ISOLATE.test(content))
|
|
@@ -54979,7 +55251,7 @@ function analyzeInstructionFile(path71, content) {
|
|
|
54979
55251
|
"contains bidi embed/isolate characters (U+202A\u2013202C / U+2066\u20132069) \u2014 legitimate in right-to-left text, but confirm they are not being used to hide or reorder instructions"
|
|
54980
55252
|
],
|
|
54981
55253
|
"Confirm the bidi marks are legitimate RTL formatting; remove otherwise.",
|
|
54982
|
-
|
|
55254
|
+
path72
|
|
54983
55255
|
)
|
|
54984
55256
|
);
|
|
54985
55257
|
const zw = suspiciousZeroWidth(content);
|
|
@@ -54993,7 +55265,7 @@ function analyzeInstructionFile(path71, content) {
|
|
|
54993
55265
|
revealed ? "a zero-width character conceals a prompt-override directive that only appears once the hidden characters are stripped" : "a zero-width character splits a visible Latin word \u2014 a concealment technique (hides text from human review while the agent reads it as contiguous)"
|
|
54994
55266
|
],
|
|
54995
55267
|
"Remove the zero-width characters. Instruction files must be plain, reviewable text.",
|
|
54996
|
-
|
|
55268
|
+
path72
|
|
54997
55269
|
)
|
|
54998
55270
|
);
|
|
54999
55271
|
}
|
|
@@ -55009,7 +55281,7 @@ function analyzeInstructionFile(path71, content) {
|
|
|
55009
55281
|
`contains a prompt-override / role-impersonation directive (\`${m[0].slice(0, 60).trim()}\`)${ovEnc ? " \u2014 concealed in a base64 blob" : ""}`
|
|
55010
55282
|
],
|
|
55011
55283
|
"Remove the override text. An instruction file should not tell the agent to ignore its own rules.",
|
|
55012
|
-
|
|
55284
|
+
path72
|
|
55013
55285
|
)
|
|
55014
55286
|
);
|
|
55015
55287
|
}
|
|
@@ -55021,7 +55293,7 @@ function analyzeInstructionFile(path71, content) {
|
|
|
55021
55293
|
"Instruction directs the agent to fetch and run remote code",
|
|
55022
55294
|
[`\`${fo[0].slice(0, 70).trim()}\` \u2014 fetch-and-obey, outside an install/setup section`],
|
|
55023
55295
|
"Do not instruct the agent to pipe remote content into a shell; pin and vendor scripts instead.",
|
|
55024
|
-
|
|
55296
|
+
path72
|
|
55025
55297
|
)
|
|
55026
55298
|
);
|
|
55027
55299
|
}
|
|
@@ -55033,7 +55305,7 @@ function analyzeInstructionFile(path71, content) {
|
|
|
55033
55305
|
"Instruction points the agent at credential material",
|
|
55034
55306
|
[`references \`${sp[0].slice(0, 50).trim()}\` \u2014 directs the agent toward secrets`],
|
|
55035
55307
|
"Do not reference credential files or paths in agent instructions.",
|
|
55036
|
-
|
|
55308
|
+
path72
|
|
55037
55309
|
)
|
|
55038
55310
|
);
|
|
55039
55311
|
}
|
|
@@ -55045,7 +55317,7 @@ function analyzeInstructionFile(path71, content) {
|
|
|
55045
55317
|
"Instruction directs the agent to send data to an external endpoint",
|
|
55046
55318
|
[`\`${ex[0].slice(0, 70).trim()}\` \u2014 possible exfiltration directive`],
|
|
55047
55319
|
"Remove external post/upload directives from agent instructions.",
|
|
55048
|
-
|
|
55320
|
+
path72
|
|
55049
55321
|
)
|
|
55050
55322
|
);
|
|
55051
55323
|
}
|
|
@@ -55347,17 +55619,17 @@ import chalk32 from "chalk";
|
|
|
55347
55619
|
// src/shields/jail.ts
|
|
55348
55620
|
init_build();
|
|
55349
55621
|
init_shields();
|
|
55350
|
-
import
|
|
55622
|
+
import fs64 from "fs";
|
|
55351
55623
|
import os54 from "os";
|
|
55352
|
-
import
|
|
55624
|
+
import path60 from "path";
|
|
55353
55625
|
var USER_JAIL_SHIELD = "user-jail";
|
|
55354
55626
|
function jailStorePath() {
|
|
55355
|
-
return
|
|
55627
|
+
return path60.join(os54.homedir(), ".node9", "jail-paths.json");
|
|
55356
55628
|
}
|
|
55357
55629
|
function readJailPaths() {
|
|
55358
55630
|
let text;
|
|
55359
55631
|
try {
|
|
55360
|
-
text =
|
|
55632
|
+
text = fs64.readFileSync(jailStorePath(), "utf8");
|
|
55361
55633
|
} catch (err2) {
|
|
55362
55634
|
if (err2.code === "ENOENT") return [];
|
|
55363
55635
|
throw err2;
|
|
@@ -55375,8 +55647,8 @@ function readJailPaths() {
|
|
|
55375
55647
|
}
|
|
55376
55648
|
function writeJailPaths(paths) {
|
|
55377
55649
|
const p = jailStorePath();
|
|
55378
|
-
|
|
55379
|
-
|
|
55650
|
+
fs64.mkdirSync(path60.dirname(p), { recursive: true });
|
|
55651
|
+
fs64.writeFileSync(p, JSON.stringify({ paths }, null, 2) + "\n", { mode: 384 });
|
|
55380
55652
|
}
|
|
55381
55653
|
function addJailPath(rawPath, verdict) {
|
|
55382
55654
|
const norm = rawPath.trim();
|
|
@@ -55398,14 +55670,14 @@ function removeJailPath(rawPath) {
|
|
|
55398
55670
|
return { removed, paths: after };
|
|
55399
55671
|
}
|
|
55400
55672
|
function regenerateUserJail(paths) {
|
|
55401
|
-
const file =
|
|
55673
|
+
const file = path60.join(USER_SHIELDS_DIR_PATH, `${USER_JAIL_SHIELD}.json`);
|
|
55402
55674
|
if (paths.length === 0) {
|
|
55403
55675
|
const active2 = readActiveShields();
|
|
55404
55676
|
if (active2.includes(USER_JAIL_SHIELD)) {
|
|
55405
55677
|
writeActiveShields(active2.filter((s) => s !== USER_JAIL_SHIELD));
|
|
55406
55678
|
}
|
|
55407
55679
|
try {
|
|
55408
|
-
|
|
55680
|
+
fs64.rmSync(file, { force: true });
|
|
55409
55681
|
} catch {
|
|
55410
55682
|
}
|
|
55411
55683
|
return;
|
|
@@ -55520,13 +55792,13 @@ function registerJailCommand(program2) {
|
|
|
55520
55792
|
// src/cli/commands/sandbox.ts
|
|
55521
55793
|
init_config();
|
|
55522
55794
|
import chalk33 from "chalk";
|
|
55523
|
-
import
|
|
55524
|
-
import
|
|
55795
|
+
import fs67 from "fs";
|
|
55796
|
+
import path63 from "path";
|
|
55525
55797
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
55526
55798
|
|
|
55527
55799
|
// src/sandbox/config.ts
|
|
55528
|
-
import
|
|
55529
|
-
import
|
|
55800
|
+
import fs65 from "fs";
|
|
55801
|
+
import path61 from "path";
|
|
55530
55802
|
import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
|
|
55531
55803
|
var SANDBOX_CONFIG_FILE = "node9.sandbox.yaml";
|
|
55532
55804
|
var FORBIDDEN_ENV = /* @__PURE__ */ new Set(["NODE9_API_KEY", "NODE9_API_URL"]);
|
|
@@ -55599,16 +55871,16 @@ function scaffoldSandboxYaml(agent) {
|
|
|
55599
55871
|
return header + stringifyYaml(defaultSandboxConfig(agent));
|
|
55600
55872
|
}
|
|
55601
55873
|
function sandboxConfigPath(cwd = process.cwd()) {
|
|
55602
|
-
return
|
|
55874
|
+
return path61.join(cwd, SANDBOX_CONFIG_FILE);
|
|
55603
55875
|
}
|
|
55604
55876
|
function loadSandboxConfig(cwd = process.cwd(), fallbackAgent = "claude") {
|
|
55605
55877
|
const p = sandboxConfigPath(cwd);
|
|
55606
|
-
if (!
|
|
55878
|
+
if (!fs65.existsSync(p)) {
|
|
55607
55879
|
throw new Error(`sandbox: ${SANDBOX_CONFIG_FILE} not found \u2014 run \`node9 sandbox new\` first.`);
|
|
55608
55880
|
}
|
|
55609
55881
|
let raw;
|
|
55610
55882
|
try {
|
|
55611
|
-
raw = parseYaml2(
|
|
55883
|
+
raw = parseYaml2(fs65.readFileSync(p, "utf-8"));
|
|
55612
55884
|
} catch (err2) {
|
|
55613
55885
|
throw new Error(
|
|
55614
55886
|
`sandbox: ${SANDBOX_CONFIG_FILE} is not valid YAML \u2014 ${err2.message}`
|
|
@@ -55667,13 +55939,13 @@ init_templates();
|
|
|
55667
55939
|
|
|
55668
55940
|
// src/sandbox/runtime.ts
|
|
55669
55941
|
init_templates();
|
|
55670
|
-
import
|
|
55942
|
+
import fs66 from "fs";
|
|
55671
55943
|
import os55 from "os";
|
|
55672
|
-
import
|
|
55944
|
+
import path62 from "path";
|
|
55673
55945
|
import crypto9 from "crypto";
|
|
55674
55946
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
55675
55947
|
function sandboxDataDir(cwd = process.cwd()) {
|
|
55676
|
-
return
|
|
55948
|
+
return path62.join(cwd, ".node9", "sandbox", "data");
|
|
55677
55949
|
}
|
|
55678
55950
|
function detectEngine(engine) {
|
|
55679
55951
|
const r = spawnSync5(engine, ["--version"], { encoding: "utf-8" });
|
|
@@ -55684,7 +55956,7 @@ function detectEngine(engine) {
|
|
|
55684
55956
|
}
|
|
55685
55957
|
function agentCredentialsMount(agent) {
|
|
55686
55958
|
const rel = agent === "codex" ? ".codex/auth.json" : ".claude/.credentials.json";
|
|
55687
|
-
return { hostPath:
|
|
55959
|
+
return { hostPath: path62.join(os55.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
|
|
55688
55960
|
}
|
|
55689
55961
|
function buildRunArgs(opts) {
|
|
55690
55962
|
const { config, workspaceHostPath, dataHostPath, allowlistHostPath, agentArgs } = opts;
|
|
@@ -55694,7 +55966,7 @@ function buildRunArgs(opts) {
|
|
|
55694
55966
|
args.push("-v", `${allowlistHostPath}:${ALLOWED_DOMAINS_PATH}:ro`);
|
|
55695
55967
|
if (config.node9.mountAgentCredentials) {
|
|
55696
55968
|
const creds = agentCredentialsMount(config.agent);
|
|
55697
|
-
if (
|
|
55969
|
+
if (fs66.existsSync(creds.hostPath)) {
|
|
55698
55970
|
args.push("-v", `${creds.hostPath}:${creds.target}`);
|
|
55699
55971
|
}
|
|
55700
55972
|
}
|
|
@@ -55712,30 +55984,30 @@ function imageContentHash(dockerfile, entrypoint) {
|
|
|
55712
55984
|
return crypto9.createHash("sha256").update(dockerfile).update("\0").update(entrypoint).digest("hex").slice(0, 16);
|
|
55713
55985
|
}
|
|
55714
55986
|
function sandboxBuildDir(cwd = process.cwd()) {
|
|
55715
|
-
return
|
|
55987
|
+
return path62.join(cwd, ".node9", "sandbox", "build");
|
|
55716
55988
|
}
|
|
55717
55989
|
function writeBuildContext(cwd, dockerfile, entrypoint) {
|
|
55718
55990
|
const dir = sandboxBuildDir(cwd);
|
|
55719
|
-
|
|
55720
|
-
|
|
55721
|
-
|
|
55991
|
+
fs66.mkdirSync(dir, { recursive: true });
|
|
55992
|
+
fs66.writeFileSync(path62.join(dir, "Dockerfile"), dockerfile);
|
|
55993
|
+
fs66.writeFileSync(path62.join(dir, "entrypoint.sh"), entrypoint);
|
|
55722
55994
|
return dir;
|
|
55723
55995
|
}
|
|
55724
55996
|
function writeAllowlist(cwd, hosts) {
|
|
55725
|
-
const dir =
|
|
55726
|
-
|
|
55727
|
-
const p =
|
|
55728
|
-
|
|
55997
|
+
const dir = path62.join(cwd, ".node9", "sandbox");
|
|
55998
|
+
fs66.mkdirSync(dir, { recursive: true });
|
|
55999
|
+
const p = path62.join(dir, "allowed-domains.txt");
|
|
56000
|
+
fs66.writeFileSync(p, hosts.join("\n") + "\n");
|
|
55729
56001
|
return p;
|
|
55730
56002
|
}
|
|
55731
56003
|
function resolveHomePath(p) {
|
|
55732
|
-
return p.startsWith("~") ?
|
|
56004
|
+
return p.startsWith("~") ? path62.join(os55.homedir(), p.slice(1)) : path62.resolve(p);
|
|
55733
56005
|
}
|
|
55734
56006
|
|
|
55735
56007
|
// src/cli/commands/sandbox.ts
|
|
55736
56008
|
function seedDataDirConfig(dataDir, sandbox) {
|
|
55737
|
-
|
|
55738
|
-
const configPath =
|
|
56009
|
+
fs67.mkdirSync(dataDir, { recursive: true });
|
|
56010
|
+
const configPath = path63.join(dataDir, "config.json");
|
|
55739
56011
|
const seed = {
|
|
55740
56012
|
settings: {
|
|
55741
56013
|
approvers: {
|
|
@@ -55746,7 +56018,7 @@ function seedDataDirConfig(dataDir, sandbox) {
|
|
|
55746
56018
|
}
|
|
55747
56019
|
}
|
|
55748
56020
|
};
|
|
55749
|
-
|
|
56021
|
+
fs67.writeFileSync(configPath, JSON.stringify(seed, null, 2), { mode: 384 });
|
|
55750
56022
|
}
|
|
55751
56023
|
function registerSandboxCommand(program2, version2) {
|
|
55752
56024
|
const node9Version2 = pinnedNode9Version(version2);
|
|
@@ -55754,13 +56026,13 @@ function registerSandboxCommand(program2, version2) {
|
|
|
55754
56026
|
cmd.command("new").description(`Scaffold ${SANDBOX_CONFIG_FILE} in this project`).option("--agent <agent>", "claude (default) or codex", "claude").action((opts) => {
|
|
55755
56027
|
const agent = opts.agent === "codex" ? "codex" : "claude";
|
|
55756
56028
|
const p = sandboxConfigPath();
|
|
55757
|
-
if (
|
|
56029
|
+
if (fs67.existsSync(p)) {
|
|
55758
56030
|
console.log(
|
|
55759
56031
|
chalk33.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
|
|
55760
56032
|
);
|
|
55761
56033
|
return;
|
|
55762
56034
|
}
|
|
55763
|
-
|
|
56035
|
+
fs67.writeFileSync(p, scaffoldSandboxYaml(agent));
|
|
55764
56036
|
console.log(
|
|
55765
56037
|
chalk33.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + chalk33.dim(` (agent: ${agent})`)
|
|
55766
56038
|
);
|
|
@@ -55800,8 +56072,8 @@ function registerSandboxCommand(program2, version2) {
|
|
|
55800
56072
|
const buildDir = writeBuildContext(cwd, dockerfile, entrypoint);
|
|
55801
56073
|
const hash = imageContentHash(dockerfile, entrypoint);
|
|
55802
56074
|
const image = sandbox.runtime.image;
|
|
55803
|
-
const hashFile =
|
|
55804
|
-
const lastHash =
|
|
56075
|
+
const hashFile = path63.join(sandboxBuildDir(cwd), ".image-hash");
|
|
56076
|
+
const lastHash = fs67.existsSync(hashFile) ? fs67.readFileSync(hashFile, "utf-8").trim() : "";
|
|
55805
56077
|
const imageExists = spawnSync6(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
|
|
55806
56078
|
const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
|
|
55807
56079
|
if (needBuild) {
|
|
@@ -55813,7 +56085,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
55813
56085
|
console.error(chalk33.red(" build failed."));
|
|
55814
56086
|
process.exit(b.status ?? 1);
|
|
55815
56087
|
}
|
|
55816
|
-
|
|
56088
|
+
fs67.writeFileSync(hashFile, hash);
|
|
55817
56089
|
}
|
|
55818
56090
|
const dataDir = sandboxDataDir(cwd);
|
|
55819
56091
|
seedDataDirConfig(dataDir, sandbox);
|
|
@@ -55827,7 +56099,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
55827
56099
|
});
|
|
55828
56100
|
if (sandbox.node9.mountAgentCredentials) {
|
|
55829
56101
|
const creds = agentCredentialsMount(sandbox.agent);
|
|
55830
|
-
if (
|
|
56102
|
+
if (fs67.existsSync(creds.hostPath)) {
|
|
55831
56103
|
console.log(chalk33.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
|
|
55832
56104
|
} else {
|
|
55833
56105
|
console.log(
|
|
@@ -55843,20 +56115,20 @@ function registerSandboxCommand(program2, version2) {
|
|
|
55843
56115
|
process.exit(r.status ?? 0);
|
|
55844
56116
|
});
|
|
55845
56117
|
cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
|
|
55846
|
-
const auditPath =
|
|
55847
|
-
if (!
|
|
56118
|
+
const auditPath = path63.join(sandboxDataDir(), "audit.log");
|
|
56119
|
+
if (!fs67.existsSync(auditPath)) {
|
|
55848
56120
|
console.log(chalk33.dim(" no sandbox audit yet."));
|
|
55849
56121
|
return;
|
|
55850
56122
|
}
|
|
55851
56123
|
spawnSync6("tail", ["-f", auditPath], { stdio: "inherit" });
|
|
55852
56124
|
});
|
|
55853
56125
|
cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
|
|
55854
|
-
const auditPath =
|
|
55855
|
-
if (!
|
|
56126
|
+
const auditPath = path63.join(sandboxDataDir(), "audit.log");
|
|
56127
|
+
if (!fs67.existsSync(auditPath)) {
|
|
55856
56128
|
console.log(chalk33.dim(" no sandbox audit yet."));
|
|
55857
56129
|
return;
|
|
55858
56130
|
}
|
|
55859
|
-
process.stdout.write(
|
|
56131
|
+
process.stdout.write(fs67.readFileSync(auditPath, "utf-8"));
|
|
55860
56132
|
});
|
|
55861
56133
|
cmd.command("clean").description("Remove the sandbox image, build context, and data").action(() => {
|
|
55862
56134
|
const cwd = process.cwd();
|
|
@@ -55870,7 +56142,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
55870
56142
|
stdio: "ignore"
|
|
55871
56143
|
});
|
|
55872
56144
|
}
|
|
55873
|
-
|
|
56145
|
+
fs67.rmSync(path63.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
|
|
55874
56146
|
console.log(chalk33.green(" \u2713 sandbox image + build + data removed."));
|
|
55875
56147
|
});
|
|
55876
56148
|
}
|
|
@@ -55882,8 +56154,8 @@ init_litellm();
|
|
|
55882
56154
|
init_cost_gemini();
|
|
55883
56155
|
init_cost_codex();
|
|
55884
56156
|
import chalk34 from "chalk";
|
|
55885
|
-
import
|
|
55886
|
-
import
|
|
56157
|
+
import fs68 from "fs";
|
|
56158
|
+
import path64 from "path";
|
|
55887
56159
|
import os56 from "os";
|
|
55888
56160
|
function modelPrice(model) {
|
|
55889
56161
|
const t = pricingFor(model);
|
|
@@ -55901,7 +56173,7 @@ function encodeProjectPath(projectPath) {
|
|
|
55901
56173
|
}
|
|
55902
56174
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
55903
56175
|
const encoded = encodeProjectPath(projectPath);
|
|
55904
|
-
return
|
|
56176
|
+
return path64.join(os56.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
55905
56177
|
}
|
|
55906
56178
|
function projectLabel(projectPath) {
|
|
55907
56179
|
return projectPath.replace(os56.homedir(), "~");
|
|
@@ -55973,10 +56245,10 @@ function parseSessionLines(lines) {
|
|
|
55973
56245
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
55974
56246
|
}
|
|
55975
56247
|
function loadAuditEntries(auditPath) {
|
|
55976
|
-
const aPath = auditPath ??
|
|
56248
|
+
const aPath = auditPath ?? path64.join(os56.homedir(), ".node9", "audit.log");
|
|
55977
56249
|
let raw;
|
|
55978
56250
|
try {
|
|
55979
|
-
raw =
|
|
56251
|
+
raw = fs68.readFileSync(aPath, "utf-8");
|
|
55980
56252
|
} catch {
|
|
55981
56253
|
return [];
|
|
55982
56254
|
}
|
|
@@ -56012,8 +56284,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
56012
56284
|
return result;
|
|
56013
56285
|
}
|
|
56014
56286
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
56015
|
-
const tmpDir =
|
|
56016
|
-
if (!
|
|
56287
|
+
const tmpDir = path64.join(os56.homedir(), ".gemini", "tmp");
|
|
56288
|
+
if (!fs68.existsSync(tmpDir)) return [];
|
|
56017
56289
|
const cutoff = days !== null ? (() => {
|
|
56018
56290
|
const d = /* @__PURE__ */ new Date();
|
|
56019
56291
|
d.setDate(d.getDate() - days);
|
|
@@ -56022,35 +56294,35 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
56022
56294
|
})() : null;
|
|
56023
56295
|
let slugDirs;
|
|
56024
56296
|
try {
|
|
56025
|
-
slugDirs =
|
|
56297
|
+
slugDirs = fs68.readdirSync(tmpDir);
|
|
56026
56298
|
} catch {
|
|
56027
56299
|
return [];
|
|
56028
56300
|
}
|
|
56029
56301
|
const summaries = [];
|
|
56030
56302
|
for (const slug2 of slugDirs) {
|
|
56031
|
-
const slugPath =
|
|
56303
|
+
const slugPath = path64.join(tmpDir, slug2);
|
|
56032
56304
|
try {
|
|
56033
|
-
if (!
|
|
56305
|
+
if (!fs68.statSync(slugPath).isDirectory()) continue;
|
|
56034
56306
|
} catch {
|
|
56035
56307
|
continue;
|
|
56036
56308
|
}
|
|
56037
|
-
let projectRoot =
|
|
56309
|
+
let projectRoot = path64.join(os56.homedir(), slug2);
|
|
56038
56310
|
try {
|
|
56039
|
-
projectRoot =
|
|
56311
|
+
projectRoot = fs68.readFileSync(path64.join(slugPath, ".project_root"), "utf-8").trim();
|
|
56040
56312
|
} catch {
|
|
56041
56313
|
}
|
|
56042
|
-
const chatsDir =
|
|
56043
|
-
if (!
|
|
56314
|
+
const chatsDir = path64.join(slugPath, "chats");
|
|
56315
|
+
if (!fs68.existsSync(chatsDir)) continue;
|
|
56044
56316
|
let chatFiles;
|
|
56045
56317
|
try {
|
|
56046
|
-
chatFiles =
|
|
56318
|
+
chatFiles = fs68.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
56047
56319
|
} catch {
|
|
56048
56320
|
continue;
|
|
56049
56321
|
}
|
|
56050
56322
|
for (const chatFile of chatFiles) {
|
|
56051
56323
|
let raw;
|
|
56052
56324
|
try {
|
|
56053
|
-
raw =
|
|
56325
|
+
raw = fs68.readFileSync(path64.join(chatsDir, chatFile), "utf-8");
|
|
56054
56326
|
} catch {
|
|
56055
56327
|
continue;
|
|
56056
56328
|
}
|
|
@@ -56130,8 +56402,8 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
56130
56402
|
return summaries;
|
|
56131
56403
|
}
|
|
56132
56404
|
function buildCodexSessions(days, allAuditEntries) {
|
|
56133
|
-
const sessionsBase =
|
|
56134
|
-
if (!
|
|
56405
|
+
const sessionsBase = path64.join(os56.homedir(), ".codex", "sessions");
|
|
56406
|
+
if (!fs68.existsSync(sessionsBase)) return [];
|
|
56135
56407
|
const cutoff = days !== null ? (() => {
|
|
56136
56408
|
const d = /* @__PURE__ */ new Date();
|
|
56137
56409
|
d.setDate(d.getDate() - days);
|
|
@@ -56140,29 +56412,29 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
56140
56412
|
})() : null;
|
|
56141
56413
|
const jsonlFiles = [];
|
|
56142
56414
|
try {
|
|
56143
|
-
for (const year of
|
|
56144
|
-
const yearPath =
|
|
56415
|
+
for (const year of fs68.readdirSync(sessionsBase)) {
|
|
56416
|
+
const yearPath = path64.join(sessionsBase, year);
|
|
56145
56417
|
try {
|
|
56146
|
-
if (!
|
|
56418
|
+
if (!fs68.statSync(yearPath).isDirectory()) continue;
|
|
56147
56419
|
} catch {
|
|
56148
56420
|
continue;
|
|
56149
56421
|
}
|
|
56150
|
-
for (const month of
|
|
56151
|
-
const monthPath =
|
|
56422
|
+
for (const month of fs68.readdirSync(yearPath)) {
|
|
56423
|
+
const monthPath = path64.join(yearPath, month);
|
|
56152
56424
|
try {
|
|
56153
|
-
if (!
|
|
56425
|
+
if (!fs68.statSync(monthPath).isDirectory()) continue;
|
|
56154
56426
|
} catch {
|
|
56155
56427
|
continue;
|
|
56156
56428
|
}
|
|
56157
|
-
for (const day of
|
|
56158
|
-
const dayPath =
|
|
56429
|
+
for (const day of fs68.readdirSync(monthPath)) {
|
|
56430
|
+
const dayPath = path64.join(monthPath, day);
|
|
56159
56431
|
try {
|
|
56160
|
-
if (!
|
|
56432
|
+
if (!fs68.statSync(dayPath).isDirectory()) continue;
|
|
56161
56433
|
} catch {
|
|
56162
56434
|
continue;
|
|
56163
56435
|
}
|
|
56164
|
-
for (const file of
|
|
56165
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
56436
|
+
for (const file of fs68.readdirSync(dayPath)) {
|
|
56437
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path64.join(dayPath, file));
|
|
56166
56438
|
}
|
|
56167
56439
|
}
|
|
56168
56440
|
}
|
|
@@ -56174,7 +56446,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
56174
56446
|
for (const filePath of jsonlFiles) {
|
|
56175
56447
|
let lines;
|
|
56176
56448
|
try {
|
|
56177
|
-
lines =
|
|
56449
|
+
lines = fs68.readFileSync(filePath, "utf-8").split("\n");
|
|
56178
56450
|
} catch {
|
|
56179
56451
|
continue;
|
|
56180
56452
|
}
|
|
@@ -56260,10 +56532,10 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
56260
56532
|
return summaries;
|
|
56261
56533
|
}
|
|
56262
56534
|
function buildSessions(days, historyPath) {
|
|
56263
|
-
const hPath = historyPath ??
|
|
56535
|
+
const hPath = historyPath ?? path64.join(os56.homedir(), ".claude", "history.jsonl");
|
|
56264
56536
|
let historyRaw = "";
|
|
56265
56537
|
try {
|
|
56266
|
-
historyRaw =
|
|
56538
|
+
historyRaw = fs68.readFileSync(hPath, "utf-8");
|
|
56267
56539
|
} catch {
|
|
56268
56540
|
}
|
|
56269
56541
|
const cutoff = days !== null ? (() => {
|
|
@@ -56287,7 +56559,7 @@ function buildSessions(days, historyPath) {
|
|
|
56287
56559
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
56288
56560
|
let sessionLines = [];
|
|
56289
56561
|
try {
|
|
56290
|
-
sessionLines =
|
|
56562
|
+
sessionLines = fs68.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
56291
56563
|
} catch {
|
|
56292
56564
|
}
|
|
56293
56565
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -56681,12 +56953,12 @@ function registerSessionTaintCommand(program2) {
|
|
|
56681
56953
|
|
|
56682
56954
|
// src/cli/commands/skill-pin.ts
|
|
56683
56955
|
import chalk36 from "chalk";
|
|
56684
|
-
import
|
|
56956
|
+
import fs69 from "fs";
|
|
56685
56957
|
import os57 from "os";
|
|
56686
|
-
import
|
|
56958
|
+
import path65 from "path";
|
|
56687
56959
|
function wipeSkillSessions() {
|
|
56688
56960
|
try {
|
|
56689
|
-
|
|
56961
|
+
fs69.rmSync(path65.join(os57.homedir(), ".node9", "skill-sessions"), {
|
|
56690
56962
|
recursive: true,
|
|
56691
56963
|
force: true
|
|
56692
56964
|
});
|
|
@@ -56768,15 +57040,15 @@ function registerSkillPinCommand(program2) {
|
|
|
56768
57040
|
}
|
|
56769
57041
|
|
|
56770
57042
|
// src/cli/commands/decisions.ts
|
|
56771
|
-
import
|
|
57043
|
+
import fs70 from "fs";
|
|
56772
57044
|
import os58 from "os";
|
|
56773
|
-
import
|
|
57045
|
+
import path66 from "path";
|
|
56774
57046
|
import chalk37 from "chalk";
|
|
56775
|
-
var DECISIONS_FILE2 =
|
|
57047
|
+
var DECISIONS_FILE2 = path66.join(os58.homedir(), ".node9", "decisions.json");
|
|
56776
57048
|
function readDecisions() {
|
|
56777
57049
|
try {
|
|
56778
|
-
if (!
|
|
56779
|
-
const raw =
|
|
57050
|
+
if (!fs70.existsSync(DECISIONS_FILE2)) return {};
|
|
57051
|
+
const raw = fs70.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
56780
57052
|
const parsed = JSON.parse(raw);
|
|
56781
57053
|
const out = {};
|
|
56782
57054
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -56788,11 +57060,11 @@ function readDecisions() {
|
|
|
56788
57060
|
}
|
|
56789
57061
|
}
|
|
56790
57062
|
function writeDecisions(d) {
|
|
56791
|
-
const dir =
|
|
56792
|
-
if (!
|
|
57063
|
+
const dir = path66.dirname(DECISIONS_FILE2);
|
|
57064
|
+
if (!fs70.existsSync(dir)) fs70.mkdirSync(dir, { recursive: true });
|
|
56793
57065
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
56794
|
-
|
|
56795
|
-
|
|
57066
|
+
fs70.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
57067
|
+
fs70.renameSync(tmp, DECISIONS_FILE2);
|
|
56796
57068
|
}
|
|
56797
57069
|
function registerDecisionsCommand(program2) {
|
|
56798
57070
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -56849,18 +57121,18 @@ Persistent decisions (${entries.length})
|
|
|
56849
57121
|
|
|
56850
57122
|
// src/cli/commands/dlp.ts
|
|
56851
57123
|
import chalk38 from "chalk";
|
|
56852
|
-
import
|
|
56853
|
-
import
|
|
57124
|
+
import fs71 from "fs";
|
|
57125
|
+
import path67 from "path";
|
|
56854
57126
|
import os59 from "os";
|
|
56855
|
-
var AUDIT_LOG =
|
|
56856
|
-
var RESOLVED_FILE =
|
|
57127
|
+
var AUDIT_LOG = path67.join(os59.homedir(), ".node9", "audit.log");
|
|
57128
|
+
var RESOLVED_FILE = path67.join(os59.homedir(), ".node9", "dlp-resolved.json");
|
|
56857
57129
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
56858
57130
|
function stripAnsi(s) {
|
|
56859
57131
|
return s.replace(ANSI_RE, "");
|
|
56860
57132
|
}
|
|
56861
57133
|
function loadResolved() {
|
|
56862
57134
|
try {
|
|
56863
|
-
const raw = JSON.parse(
|
|
57135
|
+
const raw = JSON.parse(fs71.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
56864
57136
|
return new Set(raw);
|
|
56865
57137
|
} catch {
|
|
56866
57138
|
return /* @__PURE__ */ new Set();
|
|
@@ -56868,13 +57140,13 @@ function loadResolved() {
|
|
|
56868
57140
|
}
|
|
56869
57141
|
function saveResolved(resolved) {
|
|
56870
57142
|
try {
|
|
56871
|
-
|
|
57143
|
+
fs71.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
56872
57144
|
} catch {
|
|
56873
57145
|
}
|
|
56874
57146
|
}
|
|
56875
57147
|
function loadDlpFindings() {
|
|
56876
|
-
if (!
|
|
56877
|
-
return
|
|
57148
|
+
if (!fs71.existsSync(AUDIT_LOG)) return [];
|
|
57149
|
+
return fs71.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
56878
57150
|
if (!line.trim()) return [];
|
|
56879
57151
|
try {
|
|
56880
57152
|
const e = JSON.parse(line);
|
|
@@ -56973,14 +57245,14 @@ function registerDlpCommand(program2) {
|
|
|
56973
57245
|
// src/cli/commands/mask.ts
|
|
56974
57246
|
init_dlp();
|
|
56975
57247
|
import chalk39 from "chalk";
|
|
56976
|
-
import
|
|
56977
|
-
import
|
|
57248
|
+
import fs72 from "fs";
|
|
57249
|
+
import path68 from "path";
|
|
56978
57250
|
import os60 from "os";
|
|
56979
57251
|
function findJsonlFiles(dir) {
|
|
56980
57252
|
const results = [];
|
|
56981
|
-
if (!
|
|
56982
|
-
for (const entry of
|
|
56983
|
-
const full =
|
|
57253
|
+
if (!fs72.existsSync(dir)) return results;
|
|
57254
|
+
for (const entry of fs72.readdirSync(dir, { withFileTypes: true })) {
|
|
57255
|
+
const full = path68.join(dir, entry.name);
|
|
56984
57256
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
56985
57257
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
56986
57258
|
}
|
|
@@ -57023,7 +57295,7 @@ function redactJson(obj) {
|
|
|
57023
57295
|
function processFile(filePath, dryRun) {
|
|
57024
57296
|
let raw;
|
|
57025
57297
|
try {
|
|
57026
|
-
raw =
|
|
57298
|
+
raw = fs72.readFileSync(filePath, "utf-8");
|
|
57027
57299
|
} catch {
|
|
57028
57300
|
return { redactedLines: 0, patterns: [] };
|
|
57029
57301
|
}
|
|
@@ -57055,14 +57327,14 @@ function processFile(filePath, dryRun) {
|
|
|
57055
57327
|
}
|
|
57056
57328
|
}
|
|
57057
57329
|
if (!dryRun && redactedLines > 0) {
|
|
57058
|
-
|
|
57330
|
+
fs72.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
57059
57331
|
}
|
|
57060
57332
|
return { redactedLines, patterns };
|
|
57061
57333
|
}
|
|
57062
57334
|
function processJsonFile(filePath, dryRun) {
|
|
57063
57335
|
let raw;
|
|
57064
57336
|
try {
|
|
57065
|
-
raw =
|
|
57337
|
+
raw = fs72.readFileSync(filePath, "utf-8");
|
|
57066
57338
|
} catch {
|
|
57067
57339
|
return { redactedLines: 0, patterns: [] };
|
|
57068
57340
|
}
|
|
@@ -57075,15 +57347,15 @@ function processJsonFile(filePath, dryRun) {
|
|
|
57075
57347
|
const { value, modified, found } = redactJson(parsed);
|
|
57076
57348
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
57077
57349
|
if (!dryRun) {
|
|
57078
|
-
|
|
57350
|
+
fs72.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
57079
57351
|
}
|
|
57080
57352
|
return { redactedLines: 1, patterns: found };
|
|
57081
57353
|
}
|
|
57082
57354
|
function findJsonFiles(dir) {
|
|
57083
57355
|
const results = [];
|
|
57084
|
-
if (!
|
|
57085
|
-
for (const entry of
|
|
57086
|
-
const full =
|
|
57356
|
+
if (!fs72.existsSync(dir)) return results;
|
|
57357
|
+
for (const entry of fs72.readdirSync(dir, { withFileTypes: true })) {
|
|
57358
|
+
const full = path68.join(dir, entry.name);
|
|
57087
57359
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
57088
57360
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
57089
57361
|
}
|
|
@@ -57093,8 +57365,8 @@ function registerMaskCommand(program2) {
|
|
|
57093
57365
|
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) => {
|
|
57094
57366
|
const dryRun = !!options.dryRun;
|
|
57095
57367
|
const home = os60.homedir();
|
|
57096
|
-
const claudeDir =
|
|
57097
|
-
const geminiDir =
|
|
57368
|
+
const claudeDir = path68.join(home, ".claude", "projects");
|
|
57369
|
+
const geminiDir = path68.join(home, ".gemini", "tmp");
|
|
57098
57370
|
const allFiles = [
|
|
57099
57371
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
57100
57372
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -57102,7 +57374,7 @@ function registerMaskCommand(program2) {
|
|
|
57102
57374
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
57103
57375
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
57104
57376
|
try {
|
|
57105
|
-
return
|
|
57377
|
+
return fs72.statSync(f.path).mtime >= cutoff;
|
|
57106
57378
|
} catch {
|
|
57107
57379
|
return false;
|
|
57108
57380
|
}
|
|
@@ -57158,7 +57430,7 @@ function registerMaskCommand(program2) {
|
|
|
57158
57430
|
// src/cli.ts
|
|
57159
57431
|
init_blast();
|
|
57160
57432
|
var { version } = JSON.parse(
|
|
57161
|
-
|
|
57433
|
+
fs75.readFileSync(path71.join(__dirname, "../package.json"), "utf-8")
|
|
57162
57434
|
);
|
|
57163
57435
|
var program = new Command();
|
|
57164
57436
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
@@ -57337,15 +57609,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
57337
57609
|
} catch {
|
|
57338
57610
|
}
|
|
57339
57611
|
if (options.purge) {
|
|
57340
|
-
const node9Dir =
|
|
57341
|
-
if (
|
|
57612
|
+
const node9Dir = path71.join(os63.homedir(), ".node9");
|
|
57613
|
+
if (fs75.existsSync(node9Dir)) {
|
|
57342
57614
|
const confirmed = await confirm2({
|
|
57343
57615
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
57344
57616
|
default: false
|
|
57345
57617
|
});
|
|
57346
57618
|
if (confirmed) {
|
|
57347
|
-
|
|
57348
|
-
if (
|
|
57619
|
+
fs75.rmSync(node9Dir, { recursive: true });
|
|
57620
|
+
if (fs75.existsSync(node9Dir)) {
|
|
57349
57621
|
console.error(
|
|
57350
57622
|
chalk41.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
57351
57623
|
);
|
|
@@ -57470,7 +57742,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
57470
57742
|
});
|
|
57471
57743
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
57472
57744
|
try {
|
|
57473
|
-
const dashboardPath =
|
|
57745
|
+
const dashboardPath = path71.join(__dirname, "dashboard.mjs");
|
|
57474
57746
|
const dynamicImport = new Function("id", "return import(id)");
|
|
57475
57747
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
57476
57748
|
await mod.startMonitor();
|
|
@@ -57508,14 +57780,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
57508
57780
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
57509
57781
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
57510
57782
|
if (subcommand === "debug") {
|
|
57511
|
-
const flagFile =
|
|
57783
|
+
const flagFile = path71.join(os63.homedir(), ".node9", "hud-debug");
|
|
57512
57784
|
if (state === "on") {
|
|
57513
|
-
|
|
57514
|
-
|
|
57785
|
+
fs75.mkdirSync(path71.dirname(flagFile), { recursive: true });
|
|
57786
|
+
fs75.writeFileSync(flagFile, "");
|
|
57515
57787
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
57516
57788
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
57517
57789
|
} else if (state === "off") {
|
|
57518
|
-
if (
|
|
57790
|
+
if (fs75.existsSync(flagFile)) fs75.unlinkSync(flagFile);
|
|
57519
57791
|
console.log("HUD debug logging disabled.");
|
|
57520
57792
|
} else {
|
|
57521
57793
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -57638,9 +57910,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
57638
57910
|
const isCheckHook = process.argv[2] === "check";
|
|
57639
57911
|
if (isCheckHook) {
|
|
57640
57912
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
57641
|
-
const logPath =
|
|
57913
|
+
const logPath = path71.join(os63.homedir(), ".node9", "hook-debug.log");
|
|
57642
57914
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
57643
|
-
|
|
57915
|
+
fs75.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
57644
57916
|
`);
|
|
57645
57917
|
}
|
|
57646
57918
|
process.exit(0);
|