@node9/proxy 1.61.1 → 1.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +935 -621
- package/dist/cli.mjs +929 -615
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -248,8 +248,8 @@ function sanitizeConfig(raw) {
|
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
const lines = result.error.issues.map((issue) => {
|
|
251
|
-
const
|
|
252
|
-
return ` \u2022 ${
|
|
251
|
+
const path71 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
252
|
+
return ` \u2022 ${path71}: ${issue.message}`;
|
|
253
253
|
});
|
|
254
254
|
return {
|
|
255
255
|
sanitized,
|
|
@@ -1464,9 +1464,9 @@ function matchesPattern(text, patterns) {
|
|
|
1464
1464
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
1465
1465
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
1466
1466
|
}
|
|
1467
|
-
function getNestedValue(obj,
|
|
1467
|
+
function getNestedValue(obj, path71) {
|
|
1468
1468
|
if (!obj || typeof obj !== "object") return null;
|
|
1469
|
-
const segments =
|
|
1469
|
+
const segments = path71.split(".");
|
|
1470
1470
|
for (const seg of segments) {
|
|
1471
1471
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
1472
1472
|
}
|
|
@@ -4849,10 +4849,10 @@ function getConfig(cwd) {
|
|
|
4849
4849
|
}
|
|
4850
4850
|
if (Array.isArray(mc.jailPaths)) {
|
|
4851
4851
|
for (const jp of mc.jailPaths) {
|
|
4852
|
-
const
|
|
4853
|
-
if (!
|
|
4852
|
+
const path71 = typeof jp?.path === "string" ? jp.path.trim() : "";
|
|
4853
|
+
if (!path71) continue;
|
|
4854
4854
|
const verdict = jp?.verdict === "review" ? "review" : "block";
|
|
4855
|
-
for (const r of pathRules(
|
|
4855
|
+
for (const r of pathRules(path71, verdict, "org-managed jail")) {
|
|
4856
4856
|
mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
|
|
4857
4857
|
}
|
|
4858
4858
|
}
|
|
@@ -17963,6 +17963,66 @@ function pickSyncIntervalMs(cloudHours, localSettings) {
|
|
|
17963
17963
|
function effectiveSyncIntervalMs() {
|
|
17964
17964
|
return pickSyncIntervalMs(readCachedSyncIntervalHours(), getConfig().settings);
|
|
17965
17965
|
}
|
|
17966
|
+
function readSyncHealth() {
|
|
17967
|
+
try {
|
|
17968
|
+
const raw = JSON.parse(fs36.readFileSync(syncHealthFile(), "utf-8"));
|
|
17969
|
+
return {
|
|
17970
|
+
lastCheckedAt: typeof raw.lastCheckedAt === "string" ? raw.lastCheckedAt : void 0,
|
|
17971
|
+
lastChangedAt: typeof raw.lastChangedAt === "string" ? raw.lastChangedAt : void 0,
|
|
17972
|
+
lastError: typeof raw.lastError === "string" ? raw.lastError : void 0,
|
|
17973
|
+
lastErrorAt: typeof raw.lastErrorAt === "string" ? raw.lastErrorAt : void 0,
|
|
17974
|
+
consecutiveFailures: typeof raw.consecutiveFailures === "number" && raw.consecutiveFailures >= 0 ? raw.consecutiveFailures : 0
|
|
17975
|
+
};
|
|
17976
|
+
} catch {
|
|
17977
|
+
return { consecutiveFailures: 0 };
|
|
17978
|
+
}
|
|
17979
|
+
}
|
|
17980
|
+
function writeSyncHealth(h) {
|
|
17981
|
+
try {
|
|
17982
|
+
const file = syncHealthFile();
|
|
17983
|
+
const dir = path35.dirname(file);
|
|
17984
|
+
if (!fs36.existsSync(dir)) fs36.mkdirSync(dir, { recursive: true });
|
|
17985
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
17986
|
+
fs36.writeFileSync(tmp, JSON.stringify(h, null, 2) + "\n", "utf-8");
|
|
17987
|
+
fs36.renameSync(tmp, file);
|
|
17988
|
+
} catch {
|
|
17989
|
+
}
|
|
17990
|
+
}
|
|
17991
|
+
function readCacheFetchedAt() {
|
|
17992
|
+
try {
|
|
17993
|
+
const raw = JSON.parse(fs36.readFileSync(rulesCacheFile(), "utf-8"));
|
|
17994
|
+
return typeof raw.fetchedAt === "string" ? raw.fetchedAt : void 0;
|
|
17995
|
+
} catch {
|
|
17996
|
+
return void 0;
|
|
17997
|
+
}
|
|
17998
|
+
}
|
|
17999
|
+
function recordSyncHealth(result) {
|
|
18000
|
+
const h = readSyncHealth();
|
|
18001
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
18002
|
+
if (result.ok) {
|
|
18003
|
+
h.lastCheckedAt = now;
|
|
18004
|
+
if (result.changed) h.lastChangedAt = now;
|
|
18005
|
+
h.consecutiveFailures = 0;
|
|
18006
|
+
h.lastError = void 0;
|
|
18007
|
+
h.lastErrorAt = void 0;
|
|
18008
|
+
} else {
|
|
18009
|
+
h.consecutiveFailures += 1;
|
|
18010
|
+
h.lastError = result.error;
|
|
18011
|
+
h.lastErrorAt = now;
|
|
18012
|
+
}
|
|
18013
|
+
writeSyncHealth(h);
|
|
18014
|
+
}
|
|
18015
|
+
function stalenessThresholdMs(intervalMs) {
|
|
18016
|
+
return Math.min(STALE_MAX_MS, Math.max(STALE_MIN_MS, intervalMs * STALE_FACTOR));
|
|
18017
|
+
}
|
|
18018
|
+
function isPolicyStale(nowMs = Date.now(), health) {
|
|
18019
|
+
const h = health ?? readSyncHealth();
|
|
18020
|
+
const lastKnownGood = h.lastCheckedAt ?? readCacheFetchedAt();
|
|
18021
|
+
if (!lastKnownGood) return false;
|
|
18022
|
+
const last = Date.parse(lastKnownGood);
|
|
18023
|
+
if (Number.isNaN(last)) return false;
|
|
18024
|
+
return nowMs - last > stalenessThresholdMs(effectiveSyncIntervalMs());
|
|
18025
|
+
}
|
|
17966
18026
|
function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
|
|
17967
18027
|
const parsed = new URL(apiUrl);
|
|
17968
18028
|
const headers = {
|
|
@@ -18127,6 +18187,7 @@ async function syncOnce() {
|
|
|
18127
18187
|
try {
|
|
18128
18188
|
const result = await fetchCloudPolicy(creds.apiKey, creds.apiUrl, readCachedEtag());
|
|
18129
18189
|
if (result.kind === "unchanged") {
|
|
18190
|
+
recordSyncHealth({ ok: true });
|
|
18130
18191
|
} else {
|
|
18131
18192
|
const cache = {
|
|
18132
18193
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -18140,8 +18201,19 @@ async function syncOnce() {
|
|
|
18140
18201
|
managedConfig: extractManagedConfig(result.body)
|
|
18141
18202
|
};
|
|
18142
18203
|
writeCache2(cache);
|
|
18204
|
+
recordSyncHealth({ ok: true, changed: true });
|
|
18205
|
+
}
|
|
18206
|
+
} catch (err2) {
|
|
18207
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
18208
|
+
recordSyncHealth({ ok: false, error: msg });
|
|
18209
|
+
try {
|
|
18210
|
+
appendToLog(HOOK_DEBUG_LOG, {
|
|
18211
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18212
|
+
kind: "policy-sync-error",
|
|
18213
|
+
error: msg
|
|
18214
|
+
});
|
|
18215
|
+
} catch {
|
|
18143
18216
|
}
|
|
18144
|
-
} catch {
|
|
18145
18217
|
}
|
|
18146
18218
|
if (process.env.NODE9_BLAST_DISABLE !== "1") {
|
|
18147
18219
|
void pushBlastSnapshot(creds);
|
|
@@ -18317,6 +18389,7 @@ async function runCloudSync() {
|
|
|
18317
18389
|
const result = await fetchCloudPolicy(creds.apiKey, creds.apiUrl, readCachedEtag());
|
|
18318
18390
|
if (result.kind === "unchanged") {
|
|
18319
18391
|
const status = getCloudSyncStatus();
|
|
18392
|
+
recordSyncHealth({ ok: true });
|
|
18320
18393
|
maybePushBlast();
|
|
18321
18394
|
return status.cached ? { ok: true, rules: status.rules, fetchedAt: status.fetchedAt, unchanged: true } : { ok: true, rules: 0, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), unchanged: true };
|
|
18322
18395
|
}
|
|
@@ -18332,11 +18405,14 @@ async function runCloudSync() {
|
|
|
18332
18405
|
managedConfig: extractManagedConfig(result.body)
|
|
18333
18406
|
};
|
|
18334
18407
|
writeCache2(cache);
|
|
18408
|
+
recordSyncHealth({ ok: true, changed: true });
|
|
18335
18409
|
maybePushBlast();
|
|
18336
18410
|
return { ok: true, rules: cache.rules.length, fetchedAt: cache.fetchedAt };
|
|
18337
18411
|
} catch (err2) {
|
|
18412
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
18413
|
+
recordSyncHealth({ ok: false, error: msg });
|
|
18338
18414
|
maybePushBlast();
|
|
18339
|
-
return { ok: false, reason:
|
|
18415
|
+
return { ok: false, reason: msg };
|
|
18340
18416
|
}
|
|
18341
18417
|
}
|
|
18342
18418
|
function getCloudSyncStatus() {
|
|
@@ -18393,7 +18469,7 @@ function startForensicBroadcast() {
|
|
|
18393
18469
|
const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
|
|
18394
18470
|
recurring.unref();
|
|
18395
18471
|
}
|
|
18396
|
-
var FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL2, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
|
|
18472
|
+
var FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL2, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, syncHealthFile, STALE_MIN_MS, STALE_MAX_MS, STALE_FACTOR, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
|
|
18397
18473
|
var init_sync = __esm({
|
|
18398
18474
|
"src/daemon/sync.ts"() {
|
|
18399
18475
|
"use strict";
|
|
@@ -18427,6 +18503,10 @@ var init_sync = __esm({
|
|
|
18427
18503
|
DEFAULT_INTERVAL_HOURS = 5;
|
|
18428
18504
|
MIN_INTERVAL_SECONDS = 15;
|
|
18429
18505
|
MAX_INTERVAL_SECONDS = 24 * 60 * 60;
|
|
18506
|
+
syncHealthFile = () => path35.join(os33.homedir(), ".node9", "sync-health.json");
|
|
18507
|
+
STALE_MIN_MS = 3 * 60 * 60 * 1e3;
|
|
18508
|
+
STALE_MAX_MS = 24 * 60 * 60 * 1e3;
|
|
18509
|
+
STALE_FACTOR = 3;
|
|
18430
18510
|
FORENSIC_BROADCAST_INTERVAL_MS = 3e4;
|
|
18431
18511
|
FORENSIC_INITIAL_DELAY_MS = 5e3;
|
|
18432
18512
|
forensicBroadcastOffsets = /* @__PURE__ */ new Map();
|
|
@@ -19041,23 +19121,68 @@ var init_hook_heal = __esm({
|
|
|
19041
19121
|
}
|
|
19042
19122
|
});
|
|
19043
19123
|
|
|
19044
|
-
// src/daemon/
|
|
19045
|
-
import http3 from "http";
|
|
19124
|
+
// src/daemon/startup-log.ts
|
|
19046
19125
|
import fs40 from "fs";
|
|
19047
19126
|
import path39 from "path";
|
|
19048
19127
|
import os37 from "os";
|
|
19128
|
+
function openStartupLogFd() {
|
|
19129
|
+
try {
|
|
19130
|
+
const file = DAEMON_STARTUP_LOG();
|
|
19131
|
+
const dir = path39.dirname(file);
|
|
19132
|
+
if (!fs40.existsSync(dir)) fs40.mkdirSync(dir, { recursive: true });
|
|
19133
|
+
try {
|
|
19134
|
+
if (fs40.statSync(file).size > MAX_STARTUP_LOG_BYTES) fs40.truncateSync(file);
|
|
19135
|
+
} catch {
|
|
19136
|
+
}
|
|
19137
|
+
return fs40.openSync(file, "a");
|
|
19138
|
+
} catch {
|
|
19139
|
+
return void 0;
|
|
19140
|
+
}
|
|
19141
|
+
}
|
|
19142
|
+
function logDaemonStartup(kind, detail) {
|
|
19143
|
+
try {
|
|
19144
|
+
const file = DAEMON_STARTUP_LOG();
|
|
19145
|
+
const dir = path39.dirname(file);
|
|
19146
|
+
if (!fs40.existsSync(dir)) fs40.mkdirSync(dir, { recursive: true });
|
|
19147
|
+
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-startup:${kind}${detail ? ` ${detail}` : ""}
|
|
19148
|
+
`;
|
|
19149
|
+
fs40.appendFileSync(file, line, "utf-8");
|
|
19150
|
+
} catch {
|
|
19151
|
+
}
|
|
19152
|
+
}
|
|
19153
|
+
var DAEMON_STARTUP_LOG, MAX_STARTUP_LOG_BYTES;
|
|
19154
|
+
var init_startup_log = __esm({
|
|
19155
|
+
"src/daemon/startup-log.ts"() {
|
|
19156
|
+
"use strict";
|
|
19157
|
+
DAEMON_STARTUP_LOG = () => path39.join(os37.homedir(), ".node9", "daemon-startup.log");
|
|
19158
|
+
MAX_STARTUP_LOG_BYTES = 256 * 1024;
|
|
19159
|
+
}
|
|
19160
|
+
});
|
|
19161
|
+
|
|
19162
|
+
// src/daemon/server.ts
|
|
19163
|
+
import http3 from "http";
|
|
19164
|
+
import fs41 from "fs";
|
|
19165
|
+
import path40 from "path";
|
|
19166
|
+
import os38 from "os";
|
|
19049
19167
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
19050
19168
|
import { spawnSync } from "child_process";
|
|
19051
19169
|
import chalk6 from "chalk";
|
|
19052
19170
|
function startDaemon() {
|
|
19053
|
-
|
|
19054
|
-
|
|
19055
|
-
|
|
19056
|
-
|
|
19057
|
-
|
|
19058
|
-
|
|
19059
|
-
|
|
19060
|
-
|
|
19171
|
+
try {
|
|
19172
|
+
startCostSync();
|
|
19173
|
+
startCloudSync();
|
|
19174
|
+
startForensicBroadcast();
|
|
19175
|
+
startAuditShipper();
|
|
19176
|
+
startDlpScanner();
|
|
19177
|
+
startMcpReconciler();
|
|
19178
|
+
startHookHeal();
|
|
19179
|
+
loadInsightCounts();
|
|
19180
|
+
} catch (err2) {
|
|
19181
|
+
const stack = err2 instanceof Error ? err2.stack ?? err2.message : String(err2);
|
|
19182
|
+
console.error("\n\u{1F6D1} Node9 daemon startup failed:\n" + stack);
|
|
19183
|
+
logDaemonStartup("startup-throw", err2 instanceof Error ? err2.message : String(err2));
|
|
19184
|
+
process.exit(1);
|
|
19185
|
+
}
|
|
19061
19186
|
const internalToken = randomUUID4();
|
|
19062
19187
|
const validToken = (req) => req.headers["x-node9-internal"] === internalToken || req.headers["x-node9-token"] === internalToken;
|
|
19063
19188
|
const IDLE_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
|
|
@@ -19069,7 +19194,7 @@ function startDaemon() {
|
|
|
19069
19194
|
idleTimer = setTimeout(() => {
|
|
19070
19195
|
if (autoStarted) {
|
|
19071
19196
|
try {
|
|
19072
|
-
|
|
19197
|
+
fs41.unlinkSync(DAEMON_PID_FILE);
|
|
19073
19198
|
} catch {
|
|
19074
19199
|
}
|
|
19075
19200
|
}
|
|
@@ -19214,7 +19339,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
19214
19339
|
mcpServer: entry.mcpServer
|
|
19215
19340
|
});
|
|
19216
19341
|
}
|
|
19217
|
-
const projectCwd = typeof cwd === "string" &&
|
|
19342
|
+
const projectCwd = typeof cwd === "string" && path40.isAbsolute(cwd) ? cwd : void 0;
|
|
19218
19343
|
const projectConfig = getConfig(projectCwd);
|
|
19219
19344
|
const browserEnabled = projectConfig.settings.approvers?.browser !== false;
|
|
19220
19345
|
const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
|
|
@@ -19506,8 +19631,8 @@ data: ${JSON.stringify(item.data)}
|
|
|
19506
19631
|
if (!validToken(req)) return res.writeHead(403).end();
|
|
19507
19632
|
const periodParam = reqUrl.searchParams.get("period") || "7d";
|
|
19508
19633
|
const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
|
|
19509
|
-
const logPath =
|
|
19510
|
-
if (!
|
|
19634
|
+
const logPath = path40.join(os38.homedir(), ".node9", "audit.log");
|
|
19635
|
+
if (!fs41.existsSync(logPath)) {
|
|
19511
19636
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
19512
19637
|
return res.end(
|
|
19513
19638
|
JSON.stringify({
|
|
@@ -19520,7 +19645,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
19520
19645
|
);
|
|
19521
19646
|
}
|
|
19522
19647
|
try {
|
|
19523
|
-
const raw =
|
|
19648
|
+
const raw = fs41.readFileSync(logPath, "utf-8");
|
|
19524
19649
|
const allEntries = raw.split("\n").flatMap((line) => {
|
|
19525
19650
|
if (!line.trim()) return [];
|
|
19526
19651
|
try {
|
|
@@ -19903,14 +20028,15 @@ data: ${JSON.stringify(item.data)}
|
|
|
19903
20028
|
server.on("error", (e) => {
|
|
19904
20029
|
if (e.code === "EADDRINUSE") {
|
|
19905
20030
|
try {
|
|
19906
|
-
if (
|
|
19907
|
-
const { pid } = JSON.parse(
|
|
20031
|
+
if (fs41.existsSync(DAEMON_PID_FILE)) {
|
|
20032
|
+
const { pid } = JSON.parse(fs41.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
19908
20033
|
process.kill(pid, 0);
|
|
20034
|
+
logDaemonStartup("port-in-use", `another daemon (pid ${pid}) owns :${DAEMON_PORT}`);
|
|
19909
20035
|
return process.exit(0);
|
|
19910
20036
|
}
|
|
19911
20037
|
} catch {
|
|
19912
20038
|
try {
|
|
19913
|
-
|
|
20039
|
+
fs41.unlinkSync(DAEMON_PID_FILE);
|
|
19914
20040
|
} catch {
|
|
19915
20041
|
}
|
|
19916
20042
|
server.listen(DAEMON_PORT, DAEMON_HOST);
|
|
@@ -19959,6 +20085,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
19959
20085
|
});
|
|
19960
20086
|
return;
|
|
19961
20087
|
}
|
|
20088
|
+
logDaemonStartup("bind-failed", e.message);
|
|
19962
20089
|
console.error(chalk6.red("\n\u{1F6D1} Node9 Daemon Error:"), e.message);
|
|
19963
20090
|
process.exit(1);
|
|
19964
20091
|
});
|
|
@@ -19996,20 +20123,21 @@ var init_server = __esm({
|
|
|
19996
20123
|
init_dlp_scanner();
|
|
19997
20124
|
init_mcp_reconciler();
|
|
19998
20125
|
init_hook_heal();
|
|
20126
|
+
init_startup_log();
|
|
19999
20127
|
init_mcp_tools();
|
|
20000
20128
|
}
|
|
20001
20129
|
});
|
|
20002
20130
|
|
|
20003
20131
|
// src/daemon/service.ts
|
|
20004
|
-
import
|
|
20005
|
-
import
|
|
20006
|
-
import
|
|
20132
|
+
import fs42 from "fs";
|
|
20133
|
+
import path41 from "path";
|
|
20134
|
+
import os39 from "os";
|
|
20007
20135
|
import { spawnSync as spawnSync2, execFileSync } from "child_process";
|
|
20008
20136
|
function resolveNode9Binary() {
|
|
20009
20137
|
try {
|
|
20010
20138
|
const script = process.argv[1];
|
|
20011
|
-
if (typeof script === "string" &&
|
|
20012
|
-
return
|
|
20139
|
+
if (typeof script === "string" && path41.isAbsolute(script) && fs42.existsSync(script)) {
|
|
20140
|
+
return fs42.realpathSync(script);
|
|
20013
20141
|
}
|
|
20014
20142
|
} catch {
|
|
20015
20143
|
}
|
|
@@ -20027,11 +20155,11 @@ function xmlEscape(s) {
|
|
|
20027
20155
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
20028
20156
|
}
|
|
20029
20157
|
function launchdPlist(binaryPath) {
|
|
20030
|
-
const logDir =
|
|
20158
|
+
const logDir = path41.join(os39.homedir(), ".node9");
|
|
20031
20159
|
const nodePath = xmlEscape(process.execPath);
|
|
20032
20160
|
const scriptPath = xmlEscape(binaryPath);
|
|
20033
|
-
const outLog = xmlEscape(
|
|
20034
|
-
const errLog = xmlEscape(
|
|
20161
|
+
const outLog = xmlEscape(path41.join(logDir, "daemon.log"));
|
|
20162
|
+
const errLog = xmlEscape(path41.join(logDir, "daemon-error.log"));
|
|
20035
20163
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
20036
20164
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
20037
20165
|
<plist version="1.0">
|
|
@@ -20064,9 +20192,9 @@ function launchdPlist(binaryPath) {
|
|
|
20064
20192
|
`;
|
|
20065
20193
|
}
|
|
20066
20194
|
function installLaunchd(binaryPath) {
|
|
20067
|
-
const dir =
|
|
20068
|
-
if (!
|
|
20069
|
-
|
|
20195
|
+
const dir = path41.dirname(LAUNCHD_PLIST);
|
|
20196
|
+
if (!fs42.existsSync(dir)) fs42.mkdirSync(dir, { recursive: true });
|
|
20197
|
+
fs42.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
|
|
20070
20198
|
spawnSync2("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
|
|
20071
20199
|
const r = spawnSync2("launchctl", ["load", "-w", LAUNCHD_PLIST], {
|
|
20072
20200
|
encoding: "utf8",
|
|
@@ -20077,13 +20205,13 @@ function installLaunchd(binaryPath) {
|
|
|
20077
20205
|
}
|
|
20078
20206
|
}
|
|
20079
20207
|
function uninstallLaunchd() {
|
|
20080
|
-
if (
|
|
20208
|
+
if (fs42.existsSync(LAUNCHD_PLIST)) {
|
|
20081
20209
|
spawnSync2("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
|
|
20082
|
-
|
|
20210
|
+
fs42.unlinkSync(LAUNCHD_PLIST);
|
|
20083
20211
|
}
|
|
20084
20212
|
}
|
|
20085
20213
|
function isLaunchdInstalled() {
|
|
20086
|
-
return
|
|
20214
|
+
return fs42.existsSync(LAUNCHD_PLIST);
|
|
20087
20215
|
}
|
|
20088
20216
|
function systemdUnit(binaryPath) {
|
|
20089
20217
|
return `[Unit]
|
|
@@ -20102,12 +20230,12 @@ WantedBy=default.target
|
|
|
20102
20230
|
`;
|
|
20103
20231
|
}
|
|
20104
20232
|
function installSystemd(binaryPath) {
|
|
20105
|
-
if (!
|
|
20106
|
-
|
|
20233
|
+
if (!fs42.existsSync(SYSTEMD_UNIT_DIR)) {
|
|
20234
|
+
fs42.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
|
|
20107
20235
|
}
|
|
20108
|
-
|
|
20236
|
+
fs42.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
|
|
20109
20237
|
try {
|
|
20110
|
-
execFileSync("loginctl", ["enable-linger",
|
|
20238
|
+
execFileSync("loginctl", ["enable-linger", os39.userInfo().username], { timeout: 3e3 });
|
|
20111
20239
|
} catch {
|
|
20112
20240
|
}
|
|
20113
20241
|
const reload = spawnSync2("systemctl", ["--user", "daemon-reload"], {
|
|
@@ -20127,23 +20255,23 @@ function installSystemd(binaryPath) {
|
|
|
20127
20255
|
}
|
|
20128
20256
|
}
|
|
20129
20257
|
function uninstallSystemd() {
|
|
20130
|
-
if (
|
|
20258
|
+
if (fs42.existsSync(SYSTEMD_UNIT)) {
|
|
20131
20259
|
spawnSync2("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
|
|
20132
20260
|
encoding: "utf8",
|
|
20133
20261
|
timeout: 5e3
|
|
20134
20262
|
});
|
|
20135
20263
|
spawnSync2("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
|
|
20136
|
-
|
|
20264
|
+
fs42.unlinkSync(SYSTEMD_UNIT);
|
|
20137
20265
|
}
|
|
20138
20266
|
}
|
|
20139
20267
|
function isSystemdInstalled() {
|
|
20140
|
-
return
|
|
20268
|
+
return fs42.existsSync(SYSTEMD_UNIT);
|
|
20141
20269
|
}
|
|
20142
20270
|
function stopRunningDaemon() {
|
|
20143
|
-
const pidFile =
|
|
20144
|
-
if (!
|
|
20271
|
+
const pidFile = path41.join(os39.homedir(), ".node9", "daemon.pid");
|
|
20272
|
+
if (!fs42.existsSync(pidFile)) return;
|
|
20145
20273
|
try {
|
|
20146
|
-
const data = JSON.parse(
|
|
20274
|
+
const data = JSON.parse(fs42.readFileSync(pidFile, "utf-8"));
|
|
20147
20275
|
const pid = data.pid;
|
|
20148
20276
|
const MAX_PID2 = 4194304;
|
|
20149
20277
|
if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
|
|
@@ -20163,7 +20291,7 @@ function stopRunningDaemon() {
|
|
|
20163
20291
|
}
|
|
20164
20292
|
}
|
|
20165
20293
|
try {
|
|
20166
|
-
|
|
20294
|
+
fs42.unlinkSync(pidFile);
|
|
20167
20295
|
} catch {
|
|
20168
20296
|
}
|
|
20169
20297
|
} catch {
|
|
@@ -20233,24 +20361,93 @@ function isDaemonServiceInstalled() {
|
|
|
20233
20361
|
if (process.platform === "linux") return isSystemdInstalled();
|
|
20234
20362
|
return false;
|
|
20235
20363
|
}
|
|
20364
|
+
function autostartRepairDecision(opts) {
|
|
20365
|
+
if (!opts.autoStartDaemon) return "skip";
|
|
20366
|
+
if (process.platform !== "linux" && process.platform !== "darwin") return "unsupported";
|
|
20367
|
+
if (!opts.installed) return "skip";
|
|
20368
|
+
return opts.enabled ? "ok" : "repair";
|
|
20369
|
+
}
|
|
20370
|
+
function enableDaemonServiceQuiet() {
|
|
20371
|
+
try {
|
|
20372
|
+
if (process.platform === "linux") {
|
|
20373
|
+
const r = spawnSync2("systemctl", ["--user", "enable", "node9-daemon"], {
|
|
20374
|
+
encoding: "utf8",
|
|
20375
|
+
timeout: 3e3
|
|
20376
|
+
});
|
|
20377
|
+
return r.status === 0;
|
|
20378
|
+
}
|
|
20379
|
+
return process.platform === "darwin";
|
|
20380
|
+
} catch {
|
|
20381
|
+
return false;
|
|
20382
|
+
}
|
|
20383
|
+
}
|
|
20384
|
+
function ensureAutostartHealthy(autoStartDaemon) {
|
|
20385
|
+
const decision = autostartRepairDecision({
|
|
20386
|
+
installed: isDaemonServiceInstalled(),
|
|
20387
|
+
enabled: isDaemonServiceEnabled(),
|
|
20388
|
+
autoStartDaemon
|
|
20389
|
+
});
|
|
20390
|
+
if (decision === "repair") return enableDaemonServiceQuiet() ? "repaired" : "skipped";
|
|
20391
|
+
return decision === "ok" ? "ok" : decision === "unsupported" ? "unsupported" : "skipped";
|
|
20392
|
+
}
|
|
20393
|
+
function autostartAdvice(opts) {
|
|
20394
|
+
const installable = process.platform === "linux" || process.platform === "darwin";
|
|
20395
|
+
if (!opts.cloudEnabled || !installable) return null;
|
|
20396
|
+
const installHint = process.platform === "linux" ? "Run: systemctl --user enable --now node9-daemon (or: node9 daemon install)" : "Run: node9 daemon install";
|
|
20397
|
+
if (opts.installed && !opts.enabled) {
|
|
20398
|
+
return {
|
|
20399
|
+
level: "warn",
|
|
20400
|
+
message: "Daemon autostart is INSTALLED but DISABLED \u2014 it will NOT survive a reboot, so cloud policy can silently go stale.",
|
|
20401
|
+
hint: installHint
|
|
20402
|
+
};
|
|
20403
|
+
}
|
|
20404
|
+
if (!opts.installed) {
|
|
20405
|
+
return {
|
|
20406
|
+
level: "warn",
|
|
20407
|
+
message: "No daemon autostart installed \u2014 the daemon only runs when an agent happens to spawn it; cloud policy may lag.",
|
|
20408
|
+
hint: installHint
|
|
20409
|
+
};
|
|
20410
|
+
}
|
|
20411
|
+
return null;
|
|
20412
|
+
}
|
|
20413
|
+
function isDaemonServiceEnabled() {
|
|
20414
|
+
try {
|
|
20415
|
+
if (process.platform === "linux") {
|
|
20416
|
+
const r = spawnSync2("systemctl", ["--user", "is-enabled", "node9-daemon"], {
|
|
20417
|
+
encoding: "utf8",
|
|
20418
|
+
timeout: 3e3
|
|
20419
|
+
});
|
|
20420
|
+
return r.status === 0 && (r.stdout ?? "").trim() === "enabled";
|
|
20421
|
+
}
|
|
20422
|
+
if (process.platform === "darwin") {
|
|
20423
|
+
const r = spawnSync2("launchctl", ["list", LAUNCHD_LABEL], {
|
|
20424
|
+
encoding: "utf8",
|
|
20425
|
+
timeout: 3e3
|
|
20426
|
+
});
|
|
20427
|
+
return r.status === 0;
|
|
20428
|
+
}
|
|
20429
|
+
} catch {
|
|
20430
|
+
}
|
|
20431
|
+
return false;
|
|
20432
|
+
}
|
|
20236
20433
|
var LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
|
|
20237
20434
|
var init_service = __esm({
|
|
20238
20435
|
"src/daemon/service.ts"() {
|
|
20239
20436
|
"use strict";
|
|
20240
20437
|
LAUNCHD_LABEL = "ai.node9.daemon";
|
|
20241
|
-
LAUNCHD_PLIST =
|
|
20242
|
-
SYSTEMD_UNIT_DIR =
|
|
20243
|
-
SYSTEMD_UNIT =
|
|
20438
|
+
LAUNCHD_PLIST = path41.join(os39.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
20439
|
+
SYSTEMD_UNIT_DIR = path41.join(os39.homedir(), ".config", "systemd", "user");
|
|
20440
|
+
SYSTEMD_UNIT = path41.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
|
|
20244
20441
|
}
|
|
20245
20442
|
});
|
|
20246
20443
|
|
|
20247
20444
|
// src/daemon/index.ts
|
|
20248
|
-
import
|
|
20445
|
+
import fs43 from "fs";
|
|
20249
20446
|
import chalk7 from "chalk";
|
|
20250
20447
|
function stopDaemon() {
|
|
20251
|
-
if (!
|
|
20448
|
+
if (!fs43.existsSync(DAEMON_PID_FILE)) return console.log(chalk7.yellow("Not running."));
|
|
20252
20449
|
try {
|
|
20253
|
-
const data = JSON.parse(
|
|
20450
|
+
const data = JSON.parse(fs43.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
20254
20451
|
const pid = data.pid;
|
|
20255
20452
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
20256
20453
|
console.log(chalk7.gray("Cleaned up invalid PID file."));
|
|
@@ -20262,7 +20459,7 @@ function stopDaemon() {
|
|
|
20262
20459
|
console.log(chalk7.gray("Cleaned up stale PID file."));
|
|
20263
20460
|
} finally {
|
|
20264
20461
|
try {
|
|
20265
|
-
|
|
20462
|
+
fs43.unlinkSync(DAEMON_PID_FILE);
|
|
20266
20463
|
} catch {
|
|
20267
20464
|
}
|
|
20268
20465
|
}
|
|
@@ -20271,9 +20468,9 @@ function daemonStatus() {
|
|
|
20271
20468
|
const serviceInstalled = isDaemonServiceInstalled();
|
|
20272
20469
|
const serviceLabel = serviceInstalled ? chalk7.green("installed (starts on login)") : chalk7.yellow("not installed \u2014 run: node9 daemon install");
|
|
20273
20470
|
let processStatus;
|
|
20274
|
-
if (
|
|
20471
|
+
if (fs43.existsSync(DAEMON_PID_FILE)) {
|
|
20275
20472
|
try {
|
|
20276
|
-
const data = JSON.parse(
|
|
20473
|
+
const data = JSON.parse(fs43.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
20277
20474
|
const pid = data.pid;
|
|
20278
20475
|
const port = data.port;
|
|
20279
20476
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
@@ -21416,14 +21613,14 @@ var require_util = __commonJS({
|
|
|
21416
21613
|
}
|
|
21417
21614
|
const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
|
|
21418
21615
|
let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
|
|
21419
|
-
let
|
|
21616
|
+
let path71 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
|
|
21420
21617
|
if (origin[origin.length - 1] === "/") {
|
|
21421
21618
|
origin = origin.slice(0, origin.length - 1);
|
|
21422
21619
|
}
|
|
21423
|
-
if (
|
|
21424
|
-
|
|
21620
|
+
if (path71 && path71[0] !== "/") {
|
|
21621
|
+
path71 = `/${path71}`;
|
|
21425
21622
|
}
|
|
21426
|
-
return new URL(`${origin}${
|
|
21623
|
+
return new URL(`${origin}${path71}`);
|
|
21427
21624
|
}
|
|
21428
21625
|
if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
|
|
21429
21626
|
throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
|
|
@@ -22244,9 +22441,9 @@ var require_diagnostics = __commonJS({
|
|
|
22244
22441
|
"undici:client:sendHeaders",
|
|
22245
22442
|
(evt) => {
|
|
22246
22443
|
const {
|
|
22247
|
-
request: { method, path:
|
|
22444
|
+
request: { method, path: path71, origin }
|
|
22248
22445
|
} = evt;
|
|
22249
|
-
debugLog("sending request to %s %s%s", method, origin,
|
|
22446
|
+
debugLog("sending request to %s %s%s", method, origin, path71);
|
|
22250
22447
|
}
|
|
22251
22448
|
);
|
|
22252
22449
|
}
|
|
@@ -22264,14 +22461,14 @@ var require_diagnostics = __commonJS({
|
|
|
22264
22461
|
"undici:request:headers",
|
|
22265
22462
|
(evt) => {
|
|
22266
22463
|
const {
|
|
22267
|
-
request: { method, path:
|
|
22464
|
+
request: { method, path: path71, origin },
|
|
22268
22465
|
response: { statusCode }
|
|
22269
22466
|
} = evt;
|
|
22270
22467
|
debugLog(
|
|
22271
22468
|
"received response to %s %s%s - HTTP %d",
|
|
22272
22469
|
method,
|
|
22273
22470
|
origin,
|
|
22274
|
-
|
|
22471
|
+
path71,
|
|
22275
22472
|
statusCode
|
|
22276
22473
|
);
|
|
22277
22474
|
}
|
|
@@ -22280,23 +22477,23 @@ var require_diagnostics = __commonJS({
|
|
|
22280
22477
|
"undici:request:trailers",
|
|
22281
22478
|
(evt) => {
|
|
22282
22479
|
const {
|
|
22283
|
-
request: { method, path:
|
|
22480
|
+
request: { method, path: path71, origin }
|
|
22284
22481
|
} = evt;
|
|
22285
|
-
debugLog("trailers received from %s %s%s", method, origin,
|
|
22482
|
+
debugLog("trailers received from %s %s%s", method, origin, path71);
|
|
22286
22483
|
}
|
|
22287
22484
|
);
|
|
22288
22485
|
diagnosticsChannel.subscribe(
|
|
22289
22486
|
"undici:request:error",
|
|
22290
22487
|
(evt) => {
|
|
22291
22488
|
const {
|
|
22292
|
-
request: { method, path:
|
|
22489
|
+
request: { method, path: path71, origin },
|
|
22293
22490
|
error
|
|
22294
22491
|
} = evt;
|
|
22295
22492
|
debugLog(
|
|
22296
22493
|
"request to %s %s%s errored - %s",
|
|
22297
22494
|
method,
|
|
22298
22495
|
origin,
|
|
22299
|
-
|
|
22496
|
+
path71,
|
|
22300
22497
|
error.message
|
|
22301
22498
|
);
|
|
22302
22499
|
}
|
|
@@ -22399,7 +22596,7 @@ var require_request = __commonJS({
|
|
|
22399
22596
|
var kHandler = /* @__PURE__ */ Symbol("handler");
|
|
22400
22597
|
var Request = class {
|
|
22401
22598
|
constructor(origin, {
|
|
22402
|
-
path:
|
|
22599
|
+
path: path71,
|
|
22403
22600
|
method,
|
|
22404
22601
|
body,
|
|
22405
22602
|
headers,
|
|
@@ -22416,11 +22613,11 @@ var require_request = __commonJS({
|
|
|
22416
22613
|
maxRedirections,
|
|
22417
22614
|
typeOfService
|
|
22418
22615
|
}, handler) {
|
|
22419
|
-
if (typeof
|
|
22616
|
+
if (typeof path71 !== "string") {
|
|
22420
22617
|
throw new InvalidArgumentError("path must be a string");
|
|
22421
|
-
} else if (
|
|
22618
|
+
} else if (path71[0] !== "/" && !(path71.startsWith("http://") || path71.startsWith("https://")) && method !== "CONNECT") {
|
|
22422
22619
|
throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
|
|
22423
|
-
} else if (invalidPathRegex.test(
|
|
22620
|
+
} else if (invalidPathRegex.test(path71)) {
|
|
22424
22621
|
throw new InvalidArgumentError("invalid request path");
|
|
22425
22622
|
}
|
|
22426
22623
|
if (typeof method !== "string") {
|
|
@@ -22495,7 +22692,7 @@ var require_request = __commonJS({
|
|
|
22495
22692
|
this.completed = false;
|
|
22496
22693
|
this.aborted = false;
|
|
22497
22694
|
this.upgrade = upgrade || null;
|
|
22498
|
-
this.path = query ? serializePathWithQuery(
|
|
22695
|
+
this.path = query ? serializePathWithQuery(path71, query) : path71;
|
|
22499
22696
|
this.origin = origin;
|
|
22500
22697
|
this.protocol = getProtocolFromUrlString(origin);
|
|
22501
22698
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
|
|
@@ -27534,7 +27731,7 @@ var require_client_h1 = __commonJS({
|
|
|
27534
27731
|
return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
|
|
27535
27732
|
}
|
|
27536
27733
|
function writeH1(client, request2) {
|
|
27537
|
-
const { method, path:
|
|
27734
|
+
const { method, path: path71, host, upgrade, blocking, reset } = request2;
|
|
27538
27735
|
let { body, headers, contentLength } = request2;
|
|
27539
27736
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
|
|
27540
27737
|
if (util.isFormDataLike(body)) {
|
|
@@ -27603,7 +27800,7 @@ var require_client_h1 = __commonJS({
|
|
|
27603
27800
|
if (socket.setTypeOfService) {
|
|
27604
27801
|
socket.setTypeOfService(request2.typeOfService);
|
|
27605
27802
|
}
|
|
27606
|
-
let header = `${method} ${
|
|
27803
|
+
let header = `${method} ${path71} HTTP/1.1\r
|
|
27607
27804
|
`;
|
|
27608
27805
|
if (typeof host === "string") {
|
|
27609
27806
|
header += `host: ${host}\r
|
|
@@ -28256,7 +28453,7 @@ var require_client_h2 = __commonJS({
|
|
|
28256
28453
|
function writeH2(client, request2) {
|
|
28257
28454
|
const requestTimeout = request2.bodyTimeout ?? client[kBodyTimeout];
|
|
28258
28455
|
const session = client[kHTTP2Session];
|
|
28259
|
-
const { method, path:
|
|
28456
|
+
const { method, path: path71, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
|
|
28260
28457
|
let { body } = request2;
|
|
28261
28458
|
if (upgrade != null && upgrade !== "websocket") {
|
|
28262
28459
|
util.errorRequest(client, request2, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
|
|
@@ -28324,7 +28521,7 @@ var require_client_h2 = __commonJS({
|
|
|
28324
28521
|
}
|
|
28325
28522
|
headers[HTTP2_HEADER_METHOD] = "CONNECT";
|
|
28326
28523
|
headers[HTTP2_HEADER_PROTOCOL] = "websocket";
|
|
28327
|
-
headers[HTTP2_HEADER_PATH] =
|
|
28524
|
+
headers[HTTP2_HEADER_PATH] = path71;
|
|
28328
28525
|
if (protocol === "ws:" || protocol === "wss:") {
|
|
28329
28526
|
headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
|
|
28330
28527
|
} else {
|
|
@@ -28365,7 +28562,7 @@ var require_client_h2 = __commonJS({
|
|
|
28365
28562
|
stream.setTimeout(requestTimeout);
|
|
28366
28563
|
return true;
|
|
28367
28564
|
}
|
|
28368
|
-
headers[HTTP2_HEADER_PATH] =
|
|
28565
|
+
headers[HTTP2_HEADER_PATH] = path71;
|
|
28369
28566
|
headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
|
|
28370
28567
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
|
|
28371
28568
|
if (body && typeof body.read === "function") {
|
|
@@ -30667,10 +30864,10 @@ var require_proxy_agent = __commonJS({
|
|
|
30667
30864
|
};
|
|
30668
30865
|
const {
|
|
30669
30866
|
origin,
|
|
30670
|
-
path:
|
|
30867
|
+
path: path71 = "/",
|
|
30671
30868
|
headers = {}
|
|
30672
30869
|
} = opts;
|
|
30673
|
-
opts.path = origin +
|
|
30870
|
+
opts.path = origin + path71;
|
|
30674
30871
|
if (!("host" in headers) && !("Host" in headers)) {
|
|
30675
30872
|
const { host } = new URL(origin);
|
|
30676
30873
|
headers.host = host;
|
|
@@ -32733,20 +32930,20 @@ var require_mock_utils = __commonJS({
|
|
|
32733
32930
|
}
|
|
32734
32931
|
return normalizedQp;
|
|
32735
32932
|
}
|
|
32736
|
-
function safeUrl(
|
|
32737
|
-
if (typeof
|
|
32738
|
-
return
|
|
32933
|
+
function safeUrl(path71) {
|
|
32934
|
+
if (typeof path71 !== "string") {
|
|
32935
|
+
return path71;
|
|
32739
32936
|
}
|
|
32740
|
-
const pathSegments =
|
|
32937
|
+
const pathSegments = path71.split("?", 3);
|
|
32741
32938
|
if (pathSegments.length !== 2) {
|
|
32742
|
-
return
|
|
32939
|
+
return path71;
|
|
32743
32940
|
}
|
|
32744
32941
|
const qp = new URLSearchParams(pathSegments.pop());
|
|
32745
32942
|
qp.sort();
|
|
32746
32943
|
return [...pathSegments, qp.toString()].join("?");
|
|
32747
32944
|
}
|
|
32748
|
-
function matchKey(mockDispatch2, { path:
|
|
32749
|
-
const pathMatch = matchValue(mockDispatch2.path,
|
|
32945
|
+
function matchKey(mockDispatch2, { path: path71, method, body, headers }) {
|
|
32946
|
+
const pathMatch = matchValue(mockDispatch2.path, path71);
|
|
32750
32947
|
const methodMatch = matchValue(mockDispatch2.method, method);
|
|
32751
32948
|
const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
|
|
32752
32949
|
const headersMatch = matchHeaders(mockDispatch2, headers);
|
|
@@ -32771,8 +32968,8 @@ var require_mock_utils = __commonJS({
|
|
|
32771
32968
|
const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
|
|
32772
32969
|
const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
|
|
32773
32970
|
const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
|
|
32774
|
-
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path:
|
|
32775
|
-
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(
|
|
32971
|
+
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path71, ignoreTrailingSlash }) => {
|
|
32972
|
+
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path71)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path71), resolvedPath);
|
|
32776
32973
|
});
|
|
32777
32974
|
if (matchedMockDispatches.length === 0) {
|
|
32778
32975
|
throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
|
|
@@ -32811,19 +33008,19 @@ var require_mock_utils = __commonJS({
|
|
|
32811
33008
|
mockDispatches.splice(index, 1);
|
|
32812
33009
|
}
|
|
32813
33010
|
}
|
|
32814
|
-
function removeTrailingSlash(
|
|
32815
|
-
while (
|
|
32816
|
-
|
|
33011
|
+
function removeTrailingSlash(path71) {
|
|
33012
|
+
while (path71.endsWith("/")) {
|
|
33013
|
+
path71 = path71.slice(0, -1);
|
|
32817
33014
|
}
|
|
32818
|
-
if (
|
|
32819
|
-
|
|
33015
|
+
if (path71.length === 0) {
|
|
33016
|
+
path71 = "/";
|
|
32820
33017
|
}
|
|
32821
|
-
return
|
|
33018
|
+
return path71;
|
|
32822
33019
|
}
|
|
32823
33020
|
function buildKey(opts) {
|
|
32824
|
-
const { path:
|
|
33021
|
+
const { path: path71, method, body, headers, query } = opts;
|
|
32825
33022
|
return {
|
|
32826
|
-
path:
|
|
33023
|
+
path: path71,
|
|
32827
33024
|
method,
|
|
32828
33025
|
body,
|
|
32829
33026
|
headers,
|
|
@@ -33513,10 +33710,10 @@ var require_pending_interceptors_formatter = __commonJS({
|
|
|
33513
33710
|
}
|
|
33514
33711
|
format(pendingInterceptors) {
|
|
33515
33712
|
const withPrettyHeaders = pendingInterceptors.map(
|
|
33516
|
-
({ method, path:
|
|
33713
|
+
({ method, path: path71, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
33517
33714
|
Method: method,
|
|
33518
33715
|
Origin: origin,
|
|
33519
|
-
Path:
|
|
33716
|
+
Path: path71,
|
|
33520
33717
|
"Status code": statusCode,
|
|
33521
33718
|
Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
|
|
33522
33719
|
Invocations: timesInvoked,
|
|
@@ -33598,9 +33795,9 @@ var require_mock_agent = __commonJS({
|
|
|
33598
33795
|
const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
|
|
33599
33796
|
const dispatchOpts = { ...opts };
|
|
33600
33797
|
if (acceptNonStandardSearchParameters && dispatchOpts.path) {
|
|
33601
|
-
const [
|
|
33798
|
+
const [path71, searchParams] = dispatchOpts.path.split("?");
|
|
33602
33799
|
const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
|
|
33603
|
-
dispatchOpts.path = `${
|
|
33800
|
+
dispatchOpts.path = `${path71}?${normalizedSearchParams}`;
|
|
33604
33801
|
}
|
|
33605
33802
|
return this[kAgent].dispatch(dispatchOpts, handler);
|
|
33606
33803
|
}
|
|
@@ -34001,12 +34198,12 @@ var require_snapshot_recorder = __commonJS({
|
|
|
34001
34198
|
* @return {Promise<void>} - Resolves when snapshots are loaded
|
|
34002
34199
|
*/
|
|
34003
34200
|
async loadSnapshots(filePath) {
|
|
34004
|
-
const
|
|
34005
|
-
if (!
|
|
34201
|
+
const path71 = filePath || this.#snapshotPath;
|
|
34202
|
+
if (!path71) {
|
|
34006
34203
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
34007
34204
|
}
|
|
34008
34205
|
try {
|
|
34009
|
-
const data = await readFile(resolve2(
|
|
34206
|
+
const data = await readFile(resolve2(path71), "utf8");
|
|
34010
34207
|
const parsed = JSON.parse(data);
|
|
34011
34208
|
if (Array.isArray(parsed)) {
|
|
34012
34209
|
this.#snapshots.clear();
|
|
@@ -34020,7 +34217,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
34020
34217
|
if (error.code === "ENOENT") {
|
|
34021
34218
|
this.#snapshots.clear();
|
|
34022
34219
|
} else {
|
|
34023
|
-
throw new UndiciError(`Failed to load snapshots from ${
|
|
34220
|
+
throw new UndiciError(`Failed to load snapshots from ${path71}`, { cause: error });
|
|
34024
34221
|
}
|
|
34025
34222
|
}
|
|
34026
34223
|
}
|
|
@@ -34031,11 +34228,11 @@ var require_snapshot_recorder = __commonJS({
|
|
|
34031
34228
|
* @returns {Promise<void>} - Resolves when snapshots are saved
|
|
34032
34229
|
*/
|
|
34033
34230
|
async saveSnapshots(filePath) {
|
|
34034
|
-
const
|
|
34035
|
-
if (!
|
|
34231
|
+
const path71 = filePath || this.#snapshotPath;
|
|
34232
|
+
if (!path71) {
|
|
34036
34233
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
34037
34234
|
}
|
|
34038
|
-
const resolvedPath = resolve2(
|
|
34235
|
+
const resolvedPath = resolve2(path71);
|
|
34039
34236
|
await mkdir(dirname2(resolvedPath), { recursive: true });
|
|
34040
34237
|
const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
|
|
34041
34238
|
hash,
|
|
@@ -34660,15 +34857,15 @@ var require_redirect_handler = __commonJS({
|
|
|
34660
34857
|
return;
|
|
34661
34858
|
}
|
|
34662
34859
|
const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
|
|
34663
|
-
const
|
|
34664
|
-
const redirectUrlString = `${origin}${
|
|
34860
|
+
const path71 = search ? `${pathname}${search}` : pathname;
|
|
34861
|
+
const redirectUrlString = `${origin}${path71}`;
|
|
34665
34862
|
for (const historyUrl of this.history) {
|
|
34666
34863
|
if (historyUrl.toString() === redirectUrlString) {
|
|
34667
34864
|
throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
|
|
34668
34865
|
}
|
|
34669
34866
|
}
|
|
34670
34867
|
this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
|
|
34671
|
-
this.opts.path =
|
|
34868
|
+
this.opts.path = path71;
|
|
34672
34869
|
this.opts.origin = origin;
|
|
34673
34870
|
this.opts.query = null;
|
|
34674
34871
|
}
|
|
@@ -40875,11 +41072,11 @@ var require_fetch = __commonJS({
|
|
|
40875
41072
|
function dispatch({ body }) {
|
|
40876
41073
|
const url = requestCurrentURL(request2);
|
|
40877
41074
|
const agent = fetchParams.controller.dispatcher;
|
|
40878
|
-
const
|
|
41075
|
+
const path71 = url.pathname + url.search;
|
|
40879
41076
|
const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
|
|
40880
41077
|
return new Promise((resolve2, reject) => agent.dispatch(
|
|
40881
41078
|
{
|
|
40882
|
-
path: hasTrailingQuestionMark ? `${
|
|
41079
|
+
path: hasTrailingQuestionMark ? `${path71}?` : path71,
|
|
40883
41080
|
origin: url.origin,
|
|
40884
41081
|
method: request2.method,
|
|
40885
41082
|
body: agent.isMockActive ? request2.body && (request2.body.source || request2.body.stream) : body,
|
|
@@ -41810,9 +42007,9 @@ var require_util4 = __commonJS({
|
|
|
41810
42007
|
}
|
|
41811
42008
|
}
|
|
41812
42009
|
}
|
|
41813
|
-
function validateCookiePath(
|
|
41814
|
-
for (let i = 0; i <
|
|
41815
|
-
const code =
|
|
42010
|
+
function validateCookiePath(path71) {
|
|
42011
|
+
for (let i = 0; i < path71.length; ++i) {
|
|
42012
|
+
const code = path71.charCodeAt(i);
|
|
41816
42013
|
if (code < 32 || // exclude CTLs (0-31)
|
|
41817
42014
|
code === 127 || // DEL
|
|
41818
42015
|
code === 59) {
|
|
@@ -44982,11 +45179,11 @@ var require_undici = __commonJS({
|
|
|
44982
45179
|
if (typeof opts.path !== "string") {
|
|
44983
45180
|
throw new InvalidArgumentError("invalid opts.path");
|
|
44984
45181
|
}
|
|
44985
|
-
let
|
|
45182
|
+
let path71 = opts.path;
|
|
44986
45183
|
if (!opts.path.startsWith("/")) {
|
|
44987
|
-
|
|
45184
|
+
path71 = `/${path71}`;
|
|
44988
45185
|
}
|
|
44989
|
-
url = new URL(util.parseOrigin(url).origin +
|
|
45186
|
+
url = new URL(util.parseOrigin(url).origin + path71);
|
|
44990
45187
|
} else {
|
|
44991
45188
|
if (!opts) {
|
|
44992
45189
|
opts = typeof url === "object" ? url : {};
|
|
@@ -45105,9 +45302,9 @@ __export(tail_exports, {
|
|
|
45105
45302
|
});
|
|
45106
45303
|
import http5 from "http";
|
|
45107
45304
|
import chalk40 from "chalk";
|
|
45108
|
-
import
|
|
45109
|
-
import
|
|
45110
|
-
import
|
|
45305
|
+
import fs71 from "fs";
|
|
45306
|
+
import os61 from "os";
|
|
45307
|
+
import path68 from "path";
|
|
45111
45308
|
import readline6 from "readline";
|
|
45112
45309
|
import { spawn as spawn8 } from "child_process";
|
|
45113
45310
|
function shortenPathSummary(s) {
|
|
@@ -45131,20 +45328,20 @@ function getModelContextLimit(model) {
|
|
|
45131
45328
|
return 2e5;
|
|
45132
45329
|
}
|
|
45133
45330
|
function readSessionUsage() {
|
|
45134
|
-
const projectsDir =
|
|
45135
|
-
if (!
|
|
45331
|
+
const projectsDir = path68.join(os61.homedir(), ".claude", "projects");
|
|
45332
|
+
if (!fs71.existsSync(projectsDir)) return null;
|
|
45136
45333
|
let latestFile = null;
|
|
45137
45334
|
let latestMtime = 0;
|
|
45138
45335
|
try {
|
|
45139
|
-
for (const dir of
|
|
45140
|
-
const dirPath =
|
|
45336
|
+
for (const dir of fs71.readdirSync(projectsDir)) {
|
|
45337
|
+
const dirPath = path68.join(projectsDir, dir);
|
|
45141
45338
|
try {
|
|
45142
|
-
if (!
|
|
45143
|
-
for (const file of
|
|
45339
|
+
if (!fs71.statSync(dirPath).isDirectory()) continue;
|
|
45340
|
+
for (const file of fs71.readdirSync(dirPath)) {
|
|
45144
45341
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
45145
|
-
const filePath =
|
|
45342
|
+
const filePath = path68.join(dirPath, file);
|
|
45146
45343
|
try {
|
|
45147
|
-
const mtime =
|
|
45344
|
+
const mtime = fs71.statSync(filePath).mtimeMs;
|
|
45148
45345
|
if (mtime > latestMtime) {
|
|
45149
45346
|
latestMtime = mtime;
|
|
45150
45347
|
latestFile = filePath;
|
|
@@ -45159,7 +45356,7 @@ function readSessionUsage() {
|
|
|
45159
45356
|
}
|
|
45160
45357
|
if (!latestFile) return null;
|
|
45161
45358
|
try {
|
|
45162
|
-
const lines =
|
|
45359
|
+
const lines = fs71.readFileSync(latestFile, "utf-8").split("\n");
|
|
45163
45360
|
let lastModel = "";
|
|
45164
45361
|
let lastInput = 0;
|
|
45165
45362
|
let lastOutput = 0;
|
|
@@ -45220,7 +45417,7 @@ function formatBase(activity) {
|
|
|
45220
45417
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
45221
45418
|
const icon = getIcon(activity.tool);
|
|
45222
45419
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
45223
|
-
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(
|
|
45420
|
+
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(os61.homedir(), "~");
|
|
45224
45421
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
45225
45422
|
return `${chalk40.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${chalk40.white.bold(toolName)} ${chalk40.dim(argsPreview)}`;
|
|
45226
45423
|
}
|
|
@@ -45259,9 +45456,9 @@ function renderPending(activity) {
|
|
|
45259
45456
|
}
|
|
45260
45457
|
async function ensureDaemon() {
|
|
45261
45458
|
let pidPort = null;
|
|
45262
|
-
if (
|
|
45459
|
+
if (fs71.existsSync(PID_FILE)) {
|
|
45263
45460
|
try {
|
|
45264
|
-
const { port } = JSON.parse(
|
|
45461
|
+
const { port } = JSON.parse(fs71.readFileSync(PID_FILE, "utf-8"));
|
|
45265
45462
|
pidPort = port;
|
|
45266
45463
|
} catch {
|
|
45267
45464
|
console.error(chalk40.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -45417,9 +45614,9 @@ function buildRecoveryCardLines(req) {
|
|
|
45417
45614
|
];
|
|
45418
45615
|
}
|
|
45419
45616
|
function readApproversFromDisk() {
|
|
45420
|
-
const configPath =
|
|
45617
|
+
const configPath = path68.join(os61.homedir(), ".node9", "config.json");
|
|
45421
45618
|
try {
|
|
45422
|
-
const raw = JSON.parse(
|
|
45619
|
+
const raw = JSON.parse(fs71.readFileSync(configPath, "utf-8"));
|
|
45423
45620
|
const settings = raw.settings ?? {};
|
|
45424
45621
|
return settings.approvers ?? {};
|
|
45425
45622
|
} catch {
|
|
@@ -45435,15 +45632,15 @@ function approverStatusLine() {
|
|
|
45435
45632
|
return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
45436
45633
|
}
|
|
45437
45634
|
function toggleApprover(channel) {
|
|
45438
|
-
const configPath =
|
|
45635
|
+
const configPath = path68.join(os61.homedir(), ".node9", "config.json");
|
|
45439
45636
|
try {
|
|
45440
|
-
const raw = JSON.parse(
|
|
45637
|
+
const raw = JSON.parse(fs71.readFileSync(configPath, "utf-8"));
|
|
45441
45638
|
const settings = raw.settings ?? {};
|
|
45442
45639
|
const approvers = settings.approvers ?? {};
|
|
45443
45640
|
approvers[channel] = approvers[channel] === false;
|
|
45444
45641
|
settings.approvers = approvers;
|
|
45445
45642
|
raw.settings = settings;
|
|
45446
|
-
|
|
45643
|
+
fs71.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
45447
45644
|
} catch (err2) {
|
|
45448
45645
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
45449
45646
|
`);
|
|
@@ -45615,8 +45812,8 @@ async function startTail(options = {}) {
|
|
|
45615
45812
|
}
|
|
45616
45813
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
45617
45814
|
try {
|
|
45618
|
-
|
|
45619
|
-
|
|
45815
|
+
fs71.appendFileSync(
|
|
45816
|
+
path68.join(os61.homedir(), ".node9", "hook-debug.log"),
|
|
45620
45817
|
`[tail] POST /decision failed: ${String(err2)}
|
|
45621
45818
|
`
|
|
45622
45819
|
);
|
|
@@ -45680,9 +45877,9 @@ async function startTail(options = {}) {
|
|
|
45680
45877
|
};
|
|
45681
45878
|
process.stdin.on("keypress", onKeypress);
|
|
45682
45879
|
}
|
|
45683
|
-
const auditLog =
|
|
45880
|
+
const auditLog = path68.join(os61.homedir(), ".node9", "audit.log");
|
|
45684
45881
|
try {
|
|
45685
|
-
const unackedDlp =
|
|
45882
|
+
const unackedDlp = fs71.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
45686
45883
|
if (unackedDlp > 0) {
|
|
45687
45884
|
console.log("");
|
|
45688
45885
|
console.log(
|
|
@@ -45722,7 +45919,7 @@ async function startTail(options = {}) {
|
|
|
45722
45919
|
if (stallWarned) return;
|
|
45723
45920
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
45724
45921
|
try {
|
|
45725
|
-
const auditMtime =
|
|
45922
|
+
const auditMtime = fs71.statSync(auditLog).mtimeMs;
|
|
45726
45923
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
45727
45924
|
console.log("");
|
|
45728
45925
|
console.log(
|
|
@@ -45913,7 +46110,7 @@ var init_tail = __esm({
|
|
|
45913
46110
|
"use strict";
|
|
45914
46111
|
init_daemon2();
|
|
45915
46112
|
init_daemon();
|
|
45916
|
-
PID_FILE =
|
|
46113
|
+
PID_FILE = path68.join(os61.homedir(), ".node9", "daemon.pid");
|
|
45917
46114
|
ICONS = {
|
|
45918
46115
|
bash: "\u{1F4BB}",
|
|
45919
46116
|
shell: "\u{1F4BB}",
|
|
@@ -45961,9 +46158,9 @@ __export(hud_exports, {
|
|
|
45961
46158
|
main: () => main,
|
|
45962
46159
|
renderEnvironmentLine: () => renderEnvironmentLine
|
|
45963
46160
|
});
|
|
45964
|
-
import
|
|
45965
|
-
import
|
|
45966
|
-
import
|
|
46161
|
+
import fs72 from "fs";
|
|
46162
|
+
import path69 from "path";
|
|
46163
|
+
import os62 from "os";
|
|
45967
46164
|
import http6 from "http";
|
|
45968
46165
|
async function readStdin() {
|
|
45969
46166
|
const chunks = [];
|
|
@@ -46039,9 +46236,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
46039
46236
|
return ` (${m}m left)`;
|
|
46040
46237
|
}
|
|
46041
46238
|
function safeReadJson(filePath) {
|
|
46042
|
-
if (!
|
|
46239
|
+
if (!fs72.existsSync(filePath)) return null;
|
|
46043
46240
|
try {
|
|
46044
|
-
return JSON.parse(
|
|
46241
|
+
return JSON.parse(fs72.readFileSync(filePath, "utf-8"));
|
|
46045
46242
|
} catch {
|
|
46046
46243
|
return null;
|
|
46047
46244
|
}
|
|
@@ -46062,12 +46259,12 @@ function countHooksInFile(filePath) {
|
|
|
46062
46259
|
return Object.keys(cfg.hooks).length;
|
|
46063
46260
|
}
|
|
46064
46261
|
function countRulesInDir(rulesDir) {
|
|
46065
|
-
if (!
|
|
46262
|
+
if (!fs72.existsSync(rulesDir)) return 0;
|
|
46066
46263
|
let count = 0;
|
|
46067
46264
|
try {
|
|
46068
|
-
for (const entry of
|
|
46265
|
+
for (const entry of fs72.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
46069
46266
|
if (entry.isDirectory()) {
|
|
46070
|
-
count += countRulesInDir(
|
|
46267
|
+
count += countRulesInDir(path69.join(rulesDir, entry.name));
|
|
46071
46268
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
46072
46269
|
count++;
|
|
46073
46270
|
}
|
|
@@ -46078,46 +46275,46 @@ function countRulesInDir(rulesDir) {
|
|
|
46078
46275
|
}
|
|
46079
46276
|
function isSamePath(a, b) {
|
|
46080
46277
|
try {
|
|
46081
|
-
return
|
|
46278
|
+
return path69.resolve(a) === path69.resolve(b);
|
|
46082
46279
|
} catch {
|
|
46083
46280
|
return false;
|
|
46084
46281
|
}
|
|
46085
46282
|
}
|
|
46086
46283
|
function countConfigs(cwd) {
|
|
46087
|
-
const homeDir2 =
|
|
46088
|
-
const claudeDir =
|
|
46284
|
+
const homeDir2 = os62.homedir();
|
|
46285
|
+
const claudeDir = path69.join(homeDir2, ".claude");
|
|
46089
46286
|
let claudeMdCount = 0;
|
|
46090
46287
|
let rulesCount = 0;
|
|
46091
46288
|
let hooksCount = 0;
|
|
46092
46289
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
46093
46290
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
46094
|
-
if (
|
|
46095
|
-
rulesCount += countRulesInDir(
|
|
46096
|
-
const userSettings =
|
|
46291
|
+
if (fs72.existsSync(path69.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
46292
|
+
rulesCount += countRulesInDir(path69.join(claudeDir, "rules"));
|
|
46293
|
+
const userSettings = path69.join(claudeDir, "settings.json");
|
|
46097
46294
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
46098
46295
|
hooksCount += countHooksInFile(userSettings);
|
|
46099
|
-
const userClaudeJson =
|
|
46296
|
+
const userClaudeJson = path69.join(homeDir2, ".claude.json");
|
|
46100
46297
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
46101
46298
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
46102
46299
|
userMcpServers.delete(name);
|
|
46103
46300
|
}
|
|
46104
46301
|
if (cwd) {
|
|
46105
|
-
if (
|
|
46106
|
-
if (
|
|
46107
|
-
const projectClaudeDir =
|
|
46302
|
+
if (fs72.existsSync(path69.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
46303
|
+
if (fs72.existsSync(path69.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
46304
|
+
const projectClaudeDir = path69.join(cwd, ".claude");
|
|
46108
46305
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
46109
46306
|
if (!overlapsUserScope) {
|
|
46110
|
-
if (
|
|
46111
|
-
rulesCount += countRulesInDir(
|
|
46112
|
-
const projSettings =
|
|
46307
|
+
if (fs72.existsSync(path69.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
46308
|
+
rulesCount += countRulesInDir(path69.join(projectClaudeDir, "rules"));
|
|
46309
|
+
const projSettings = path69.join(projectClaudeDir, "settings.json");
|
|
46113
46310
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
46114
46311
|
hooksCount += countHooksInFile(projSettings);
|
|
46115
46312
|
}
|
|
46116
|
-
if (
|
|
46117
|
-
const localSettings =
|
|
46313
|
+
if (fs72.existsSync(path69.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
46314
|
+
const localSettings = path69.join(projectClaudeDir, "settings.local.json");
|
|
46118
46315
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
46119
46316
|
hooksCount += countHooksInFile(localSettings);
|
|
46120
|
-
const mcpJsonServers = getMcpServerNames(
|
|
46317
|
+
const mcpJsonServers = getMcpServerNames(path69.join(cwd, ".mcp.json"));
|
|
46121
46318
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
46122
46319
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
46123
46320
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -46150,12 +46347,12 @@ function readActiveShieldsHud() {
|
|
|
46150
46347
|
return shieldsCache.value;
|
|
46151
46348
|
}
|
|
46152
46349
|
try {
|
|
46153
|
-
const shieldsPath =
|
|
46154
|
-
if (!
|
|
46350
|
+
const shieldsPath = path69.join(os62.homedir(), ".node9", "shields.json");
|
|
46351
|
+
if (!fs72.existsSync(shieldsPath)) {
|
|
46155
46352
|
shieldsCache = { value: [], ts: now };
|
|
46156
46353
|
return [];
|
|
46157
46354
|
}
|
|
46158
|
-
const parsed = JSON.parse(
|
|
46355
|
+
const parsed = JSON.parse(fs72.readFileSync(shieldsPath, "utf-8"));
|
|
46159
46356
|
if (!Array.isArray(parsed.active)) {
|
|
46160
46357
|
shieldsCache = { value: [], ts: now };
|
|
46161
46358
|
return [];
|
|
@@ -46257,17 +46454,17 @@ function renderContextLine(stdin) {
|
|
|
46257
46454
|
async function main() {
|
|
46258
46455
|
try {
|
|
46259
46456
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
46260
|
-
if (
|
|
46457
|
+
if (fs72.existsSync(path69.join(os62.homedir(), ".node9", "hud-debug"))) {
|
|
46261
46458
|
try {
|
|
46262
|
-
const logPath =
|
|
46459
|
+
const logPath = path69.join(os62.homedir(), ".node9", "hud-debug.log");
|
|
46263
46460
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
46264
46461
|
let size = 0;
|
|
46265
46462
|
try {
|
|
46266
|
-
size =
|
|
46463
|
+
size = fs72.statSync(logPath).size;
|
|
46267
46464
|
} catch {
|
|
46268
46465
|
}
|
|
46269
46466
|
if (size < MAX_LOG_SIZE) {
|
|
46270
|
-
|
|
46467
|
+
fs72.appendFileSync(
|
|
46271
46468
|
logPath,
|
|
46272
46469
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
46273
46470
|
);
|
|
@@ -46288,11 +46485,11 @@ async function main() {
|
|
|
46288
46485
|
try {
|
|
46289
46486
|
const cwd = stdin.cwd ?? process.cwd();
|
|
46290
46487
|
for (const configPath of [
|
|
46291
|
-
|
|
46292
|
-
|
|
46488
|
+
path69.join(cwd, "node9.config.json"),
|
|
46489
|
+
path69.join(os62.homedir(), ".node9", "config.json")
|
|
46293
46490
|
]) {
|
|
46294
|
-
if (!
|
|
46295
|
-
const cfg = JSON.parse(
|
|
46491
|
+
if (!fs72.existsSync(configPath)) continue;
|
|
46492
|
+
const cfg = JSON.parse(fs72.readFileSync(configPath, "utf-8"));
|
|
46296
46493
|
const hud = cfg.settings?.hud;
|
|
46297
46494
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
46298
46495
|
}
|
|
@@ -46434,9 +46631,9 @@ function writeCredentialsAndConfig(apiKey, opts = {}) {
|
|
|
46434
46631
|
// src/cli.ts
|
|
46435
46632
|
init_daemon2();
|
|
46436
46633
|
import chalk41 from "chalk";
|
|
46437
|
-
import
|
|
46438
|
-
import
|
|
46439
|
-
import
|
|
46634
|
+
import fs73 from "fs";
|
|
46635
|
+
import path70 from "path";
|
|
46636
|
+
import os63 from "os";
|
|
46440
46637
|
import { spawn as spawn9 } from "child_process";
|
|
46441
46638
|
import { confirm as confirm2 } from "@inquirer/prompts";
|
|
46442
46639
|
|
|
@@ -46623,26 +46820,48 @@ async function runProxy(targetCommand) {
|
|
|
46623
46820
|
|
|
46624
46821
|
// src/cli/daemon-starter.ts
|
|
46625
46822
|
init_daemon();
|
|
46823
|
+
init_startup_log();
|
|
46626
46824
|
import { spawn as spawn3 } from "child_process";
|
|
46627
|
-
import
|
|
46628
|
-
import
|
|
46825
|
+
import path42 from "path";
|
|
46826
|
+
import fs44 from "fs";
|
|
46827
|
+
import os40 from "os";
|
|
46629
46828
|
function isTestingMode() {
|
|
46630
46829
|
return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
|
|
46631
46830
|
}
|
|
46831
|
+
var SKIP_STAMP = () => path42.join(os40.homedir(), ".node9", ".autostart-skip-stamp");
|
|
46832
|
+
var SKIP_THROTTLE_MS = 60 * 60 * 1e3;
|
|
46833
|
+
function logAutostartSkipThrottled(reason) {
|
|
46834
|
+
try {
|
|
46835
|
+
const stamp = SKIP_STAMP();
|
|
46836
|
+
try {
|
|
46837
|
+
if (Date.now() - fs44.statSync(stamp).mtimeMs < SKIP_THROTTLE_MS) return;
|
|
46838
|
+
} catch {
|
|
46839
|
+
}
|
|
46840
|
+
fs44.writeFileSync(stamp, "", "utf-8");
|
|
46841
|
+
fs44.appendFileSync(
|
|
46842
|
+
path42.join(os40.homedir(), ".node9", "hook-debug.log"),
|
|
46843
|
+
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-skip: ${reason}
|
|
46844
|
+
`,
|
|
46845
|
+
"utf-8"
|
|
46846
|
+
);
|
|
46847
|
+
} catch {
|
|
46848
|
+
}
|
|
46849
|
+
}
|
|
46632
46850
|
async function autoStartDaemonAndWait() {
|
|
46633
46851
|
if (isTestingMode()) return false;
|
|
46634
|
-
if (!
|
|
46852
|
+
if (!path42.isAbsolute(process.argv[1])) return false;
|
|
46635
46853
|
let resolvedArgv1;
|
|
46636
46854
|
try {
|
|
46637
|
-
resolvedArgv1 =
|
|
46855
|
+
resolvedArgv1 = fs44.realpathSync(process.argv[1]);
|
|
46638
46856
|
} catch {
|
|
46639
46857
|
return false;
|
|
46640
46858
|
}
|
|
46641
46859
|
if (!resolvedArgv1.endsWith(".js")) return false;
|
|
46860
|
+
const startupFd = openStartupLogFd();
|
|
46642
46861
|
try {
|
|
46643
46862
|
const child = spawn3(process.execPath, [resolvedArgv1, "daemon"], {
|
|
46644
46863
|
detached: true,
|
|
46645
|
-
stdio: "ignore",
|
|
46864
|
+
stdio: ["ignore", "ignore", startupFd ?? "ignore"],
|
|
46646
46865
|
env: {
|
|
46647
46866
|
...process.env,
|
|
46648
46867
|
NODE9_AUTO_STARTED: "1"
|
|
@@ -46655,30 +46874,41 @@ async function autoStartDaemonAndWait() {
|
|
|
46655
46874
|
if (await isDaemonReachable()) return true;
|
|
46656
46875
|
}
|
|
46657
46876
|
} catch {
|
|
46877
|
+
} finally {
|
|
46878
|
+
if (startupFd !== void 0) {
|
|
46879
|
+
try {
|
|
46880
|
+
fs44.closeSync(startupFd);
|
|
46881
|
+
} catch {
|
|
46882
|
+
}
|
|
46883
|
+
}
|
|
46658
46884
|
}
|
|
46659
46885
|
return false;
|
|
46660
46886
|
}
|
|
46661
46887
|
|
|
46888
|
+
// src/cli.ts
|
|
46889
|
+
init_service();
|
|
46890
|
+
|
|
46662
46891
|
// src/cli/commands/check.ts
|
|
46663
46892
|
init_orchestrator();
|
|
46664
46893
|
init_state();
|
|
46665
46894
|
init_daemon();
|
|
46895
|
+
init_startup_log();
|
|
46666
46896
|
init_config();
|
|
46667
46897
|
init_policy();
|
|
46668
46898
|
import chalk9 from "chalk";
|
|
46669
|
-
import
|
|
46899
|
+
import fs48 from "fs";
|
|
46670
46900
|
import { spawn as spawn5 } from "child_process";
|
|
46671
|
-
import
|
|
46672
|
-
import
|
|
46901
|
+
import path46 from "path";
|
|
46902
|
+
import os44 from "os";
|
|
46673
46903
|
|
|
46674
46904
|
// src/undo.ts
|
|
46675
46905
|
import { spawnSync as spawnSync3, spawn as spawn4 } from "child_process";
|
|
46676
46906
|
import crypto7 from "crypto";
|
|
46677
|
-
import
|
|
46907
|
+
import fs45 from "fs";
|
|
46678
46908
|
import net3 from "net";
|
|
46679
|
-
import
|
|
46680
|
-
import
|
|
46681
|
-
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
46909
|
+
import path43 from "path";
|
|
46910
|
+
import os41 from "os";
|
|
46911
|
+
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path43.join(os41.tmpdir(), "node9-activity.sock");
|
|
46682
46912
|
function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
46683
46913
|
try {
|
|
46684
46914
|
const payload = JSON.stringify({
|
|
@@ -46698,22 +46928,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
|
46698
46928
|
} catch {
|
|
46699
46929
|
}
|
|
46700
46930
|
}
|
|
46701
|
-
var SNAPSHOT_STACK_PATH =
|
|
46702
|
-
var UNDO_LATEST_PATH =
|
|
46931
|
+
var SNAPSHOT_STACK_PATH = path43.join(os41.homedir(), ".node9", "snapshots.json");
|
|
46932
|
+
var UNDO_LATEST_PATH = path43.join(os41.homedir(), ".node9", "undo_latest.txt");
|
|
46703
46933
|
var MAX_SNAPSHOTS = 10;
|
|
46704
46934
|
var GIT_TIMEOUT = 15e3;
|
|
46705
46935
|
function readStack() {
|
|
46706
46936
|
try {
|
|
46707
|
-
if (
|
|
46708
|
-
return JSON.parse(
|
|
46937
|
+
if (fs45.existsSync(SNAPSHOT_STACK_PATH))
|
|
46938
|
+
return JSON.parse(fs45.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
|
|
46709
46939
|
} catch {
|
|
46710
46940
|
}
|
|
46711
46941
|
return [];
|
|
46712
46942
|
}
|
|
46713
46943
|
function writeStack(stack) {
|
|
46714
|
-
const dir =
|
|
46715
|
-
if (!
|
|
46716
|
-
|
|
46944
|
+
const dir = path43.dirname(SNAPSHOT_STACK_PATH);
|
|
46945
|
+
if (!fs45.existsSync(dir)) fs45.mkdirSync(dir, { recursive: true });
|
|
46946
|
+
fs45.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
|
|
46717
46947
|
}
|
|
46718
46948
|
function extractFilePath(args) {
|
|
46719
46949
|
if (!args || typeof args !== "object") return null;
|
|
@@ -46733,12 +46963,12 @@ function buildArgsSummary(tool, args) {
|
|
|
46733
46963
|
return "";
|
|
46734
46964
|
}
|
|
46735
46965
|
function findProjectRoot(filePath) {
|
|
46736
|
-
let dir =
|
|
46966
|
+
let dir = path43.dirname(filePath);
|
|
46737
46967
|
while (true) {
|
|
46738
|
-
if (
|
|
46968
|
+
if (fs45.existsSync(path43.join(dir, ".git")) || fs45.existsSync(path43.join(dir, "package.json"))) {
|
|
46739
46969
|
return dir;
|
|
46740
46970
|
}
|
|
46741
|
-
const parent =
|
|
46971
|
+
const parent = path43.dirname(dir);
|
|
46742
46972
|
if (parent === dir) return process.cwd();
|
|
46743
46973
|
dir = parent;
|
|
46744
46974
|
}
|
|
@@ -46746,7 +46976,7 @@ function findProjectRoot(filePath) {
|
|
|
46746
46976
|
function normalizeCwdForHash(cwd) {
|
|
46747
46977
|
let normalized;
|
|
46748
46978
|
try {
|
|
46749
|
-
normalized =
|
|
46979
|
+
normalized = fs45.realpathSync(cwd);
|
|
46750
46980
|
} catch {
|
|
46751
46981
|
normalized = cwd;
|
|
46752
46982
|
}
|
|
@@ -46756,16 +46986,16 @@ function normalizeCwdForHash(cwd) {
|
|
|
46756
46986
|
}
|
|
46757
46987
|
function getShadowRepoDir(cwd) {
|
|
46758
46988
|
const hash = crypto7.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
|
|
46759
|
-
return
|
|
46989
|
+
return path43.join(os41.homedir(), ".node9", "snapshots", hash);
|
|
46760
46990
|
}
|
|
46761
46991
|
function cleanOrphanedIndexFiles(shadowDir) {
|
|
46762
46992
|
try {
|
|
46763
46993
|
const cutoff = Date.now() - 6e4;
|
|
46764
|
-
for (const f of
|
|
46994
|
+
for (const f of fs45.readdirSync(shadowDir)) {
|
|
46765
46995
|
if (f.startsWith("index_")) {
|
|
46766
|
-
const fp =
|
|
46996
|
+
const fp = path43.join(shadowDir, f);
|
|
46767
46997
|
try {
|
|
46768
|
-
if (
|
|
46998
|
+
if (fs45.statSync(fp).mtimeMs < cutoff) fs45.unlinkSync(fp);
|
|
46769
46999
|
} catch {
|
|
46770
47000
|
}
|
|
46771
47001
|
}
|
|
@@ -46777,7 +47007,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
|
|
|
46777
47007
|
const hardcoded = [".git", ".node9"];
|
|
46778
47008
|
const lines = [...hardcoded, ...ignorePaths].join("\n");
|
|
46779
47009
|
try {
|
|
46780
|
-
|
|
47010
|
+
fs45.writeFileSync(path43.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
|
|
46781
47011
|
} catch {
|
|
46782
47012
|
}
|
|
46783
47013
|
}
|
|
@@ -46790,25 +47020,25 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
46790
47020
|
timeout: 3e3
|
|
46791
47021
|
});
|
|
46792
47022
|
if (check.status === 0) {
|
|
46793
|
-
const ptPath =
|
|
47023
|
+
const ptPath = path43.join(shadowDir, "project-path.txt");
|
|
46794
47024
|
try {
|
|
46795
|
-
const stored =
|
|
47025
|
+
const stored = fs45.readFileSync(ptPath, "utf8").trim();
|
|
46796
47026
|
if (stored === normalizedCwd) return true;
|
|
46797
47027
|
if (process.env.NODE9_DEBUG === "1")
|
|
46798
47028
|
console.error(
|
|
46799
47029
|
`[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
|
|
46800
47030
|
);
|
|
46801
|
-
|
|
47031
|
+
fs45.rmSync(shadowDir, { recursive: true, force: true });
|
|
46802
47032
|
} catch {
|
|
46803
47033
|
try {
|
|
46804
|
-
|
|
47034
|
+
fs45.writeFileSync(ptPath, normalizedCwd, "utf8");
|
|
46805
47035
|
} catch {
|
|
46806
47036
|
}
|
|
46807
47037
|
return true;
|
|
46808
47038
|
}
|
|
46809
47039
|
}
|
|
46810
47040
|
try {
|
|
46811
|
-
|
|
47041
|
+
fs45.mkdirSync(shadowDir, { recursive: true });
|
|
46812
47042
|
} catch {
|
|
46813
47043
|
}
|
|
46814
47044
|
const init = spawnSync3("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
|
|
@@ -46817,7 +47047,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
46817
47047
|
if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
|
|
46818
47048
|
return false;
|
|
46819
47049
|
}
|
|
46820
|
-
const configFile =
|
|
47050
|
+
const configFile = path43.join(shadowDir, "config");
|
|
46821
47051
|
spawnSync3("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
|
|
46822
47052
|
timeout: 3e3
|
|
46823
47053
|
});
|
|
@@ -46825,7 +47055,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
46825
47055
|
timeout: 3e3
|
|
46826
47056
|
});
|
|
46827
47057
|
try {
|
|
46828
|
-
|
|
47058
|
+
fs45.writeFileSync(path43.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
|
|
46829
47059
|
} catch {
|
|
46830
47060
|
}
|
|
46831
47061
|
return true;
|
|
@@ -46848,12 +47078,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
46848
47078
|
let indexFile = null;
|
|
46849
47079
|
try {
|
|
46850
47080
|
const rawFilePath = extractFilePath(args);
|
|
46851
|
-
const absFilePath = rawFilePath &&
|
|
47081
|
+
const absFilePath = rawFilePath && path43.isAbsolute(rawFilePath) ? rawFilePath : null;
|
|
46852
47082
|
const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
|
|
46853
47083
|
const shadowDir = getShadowRepoDir(cwd);
|
|
46854
47084
|
if (!ensureShadowRepo(shadowDir, cwd)) return null;
|
|
46855
47085
|
writeShadowExcludes(shadowDir, ignorePaths);
|
|
46856
|
-
indexFile =
|
|
47086
|
+
indexFile = path43.join(shadowDir, `index_${process.pid}_${Date.now()}`);
|
|
46857
47087
|
const shadowEnv = {
|
|
46858
47088
|
...process.env,
|
|
46859
47089
|
GIT_DIR: shadowDir,
|
|
@@ -46925,7 +47155,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
46925
47155
|
writeStack(stack);
|
|
46926
47156
|
const entry = stack[stack.length - 1];
|
|
46927
47157
|
notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
|
|
46928
|
-
|
|
47158
|
+
fs45.writeFileSync(UNDO_LATEST_PATH, commitHash);
|
|
46929
47159
|
if (shouldGc) {
|
|
46930
47160
|
spawn4("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
|
|
46931
47161
|
}
|
|
@@ -46936,7 +47166,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
46936
47166
|
} finally {
|
|
46937
47167
|
if (indexFile) {
|
|
46938
47168
|
try {
|
|
46939
|
-
|
|
47169
|
+
fs45.unlinkSync(indexFile);
|
|
46940
47170
|
} catch {
|
|
46941
47171
|
}
|
|
46942
47172
|
}
|
|
@@ -47012,9 +47242,9 @@ function applyUndo(hash, cwd) {
|
|
|
47012
47242
|
timeout: GIT_TIMEOUT
|
|
47013
47243
|
}).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
|
|
47014
47244
|
for (const file of [...tracked, ...untracked]) {
|
|
47015
|
-
const fullPath =
|
|
47016
|
-
if (!snapshotFiles.has(file) &&
|
|
47017
|
-
|
|
47245
|
+
const fullPath = path43.join(dir, file);
|
|
47246
|
+
if (!snapshotFiles.has(file) && fs45.existsSync(fullPath)) {
|
|
47247
|
+
fs45.unlinkSync(fullPath);
|
|
47018
47248
|
}
|
|
47019
47249
|
}
|
|
47020
47250
|
return true;
|
|
@@ -47024,12 +47254,12 @@ function applyUndo(hash, cwd) {
|
|
|
47024
47254
|
}
|
|
47025
47255
|
|
|
47026
47256
|
// src/skill-pin.ts
|
|
47027
|
-
import
|
|
47028
|
-
import
|
|
47029
|
-
import
|
|
47257
|
+
import fs46 from "fs";
|
|
47258
|
+
import path44 from "path";
|
|
47259
|
+
import os42 from "os";
|
|
47030
47260
|
import crypto8 from "crypto";
|
|
47031
47261
|
function getPinsFilePath2() {
|
|
47032
|
-
return
|
|
47262
|
+
return path44.join(os42.homedir(), ".node9", "skill-pins.json");
|
|
47033
47263
|
}
|
|
47034
47264
|
var MAX_FILES = 5e3;
|
|
47035
47265
|
var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
@@ -47043,18 +47273,18 @@ function walkDir(root) {
|
|
|
47043
47273
|
if (out.length >= MAX_FILES) return;
|
|
47044
47274
|
let entries;
|
|
47045
47275
|
try {
|
|
47046
|
-
entries =
|
|
47276
|
+
entries = fs46.readdirSync(dir, { withFileTypes: true });
|
|
47047
47277
|
} catch {
|
|
47048
47278
|
return;
|
|
47049
47279
|
}
|
|
47050
47280
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
47051
47281
|
for (const entry of entries) {
|
|
47052
47282
|
if (out.length >= MAX_FILES) return;
|
|
47053
|
-
const full =
|
|
47054
|
-
const rel = relDir ?
|
|
47283
|
+
const full = path44.join(dir, entry.name);
|
|
47284
|
+
const rel = relDir ? path44.posix.join(relDir, entry.name) : entry.name;
|
|
47055
47285
|
let lst;
|
|
47056
47286
|
try {
|
|
47057
|
-
lst =
|
|
47287
|
+
lst = fs46.lstatSync(full);
|
|
47058
47288
|
} catch {
|
|
47059
47289
|
continue;
|
|
47060
47290
|
}
|
|
@@ -47066,7 +47296,7 @@ function walkDir(root) {
|
|
|
47066
47296
|
if (!lst.isFile()) continue;
|
|
47067
47297
|
if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
|
|
47068
47298
|
try {
|
|
47069
|
-
const buf =
|
|
47299
|
+
const buf = fs46.readFileSync(full);
|
|
47070
47300
|
totalBytes += buf.length;
|
|
47071
47301
|
out.push({ rel, hash: sha256Bytes(buf) });
|
|
47072
47302
|
} catch {
|
|
@@ -47080,14 +47310,14 @@ function walkDir(root) {
|
|
|
47080
47310
|
function hashSkillRoot(absPath) {
|
|
47081
47311
|
let lst;
|
|
47082
47312
|
try {
|
|
47083
|
-
lst =
|
|
47313
|
+
lst = fs46.lstatSync(absPath);
|
|
47084
47314
|
} catch {
|
|
47085
47315
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
47086
47316
|
}
|
|
47087
47317
|
if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
|
|
47088
47318
|
if (lst.isFile()) {
|
|
47089
47319
|
try {
|
|
47090
|
-
return { exists: true, contentHash: sha256Bytes(
|
|
47320
|
+
return { exists: true, contentHash: sha256Bytes(fs46.readFileSync(absPath)), fileCount: 1 };
|
|
47091
47321
|
} catch {
|
|
47092
47322
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
47093
47323
|
}
|
|
@@ -47105,7 +47335,7 @@ function getRootKey(absPath) {
|
|
|
47105
47335
|
function readSkillPinsSafe() {
|
|
47106
47336
|
const filePath = getPinsFilePath2();
|
|
47107
47337
|
try {
|
|
47108
|
-
const raw =
|
|
47338
|
+
const raw = fs46.readFileSync(filePath, "utf-8");
|
|
47109
47339
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
47110
47340
|
const parsed = JSON.parse(raw);
|
|
47111
47341
|
if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
|
|
@@ -47125,10 +47355,10 @@ function readSkillPins() {
|
|
|
47125
47355
|
}
|
|
47126
47356
|
function writeSkillPins(data) {
|
|
47127
47357
|
const filePath = getPinsFilePath2();
|
|
47128
|
-
|
|
47358
|
+
fs46.mkdirSync(path44.dirname(filePath), { recursive: true });
|
|
47129
47359
|
const tmp = `${filePath}.${crypto8.randomBytes(6).toString("hex")}.tmp`;
|
|
47130
|
-
|
|
47131
|
-
|
|
47360
|
+
fs46.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
47361
|
+
fs46.renameSync(tmp, filePath);
|
|
47132
47362
|
}
|
|
47133
47363
|
function removePin2(rootKey) {
|
|
47134
47364
|
const pins = readSkillPins();
|
|
@@ -47172,36 +47402,36 @@ function verifyAndPinRoots(roots) {
|
|
|
47172
47402
|
return { kind: "verified" };
|
|
47173
47403
|
}
|
|
47174
47404
|
function defaultSkillRoots(_cwd) {
|
|
47175
|
-
const marketplaces =
|
|
47405
|
+
const marketplaces = path44.join(os42.homedir(), ".claude", "plugins", "marketplaces");
|
|
47176
47406
|
const roots = [];
|
|
47177
47407
|
let registries;
|
|
47178
47408
|
try {
|
|
47179
|
-
registries =
|
|
47409
|
+
registries = fs46.readdirSync(marketplaces, { withFileTypes: true });
|
|
47180
47410
|
} catch {
|
|
47181
47411
|
return [];
|
|
47182
47412
|
}
|
|
47183
47413
|
for (const registry of registries) {
|
|
47184
47414
|
if (!registry.isDirectory()) continue;
|
|
47185
|
-
const pluginsDir =
|
|
47415
|
+
const pluginsDir = path44.join(marketplaces, registry.name, "plugins");
|
|
47186
47416
|
let plugins;
|
|
47187
47417
|
try {
|
|
47188
|
-
plugins =
|
|
47418
|
+
plugins = fs46.readdirSync(pluginsDir, { withFileTypes: true });
|
|
47189
47419
|
} catch {
|
|
47190
47420
|
continue;
|
|
47191
47421
|
}
|
|
47192
47422
|
for (const plugin of plugins) {
|
|
47193
47423
|
if (!plugin.isDirectory()) continue;
|
|
47194
|
-
roots.push(
|
|
47424
|
+
roots.push(path44.join(pluginsDir, plugin.name));
|
|
47195
47425
|
}
|
|
47196
47426
|
}
|
|
47197
47427
|
return roots;
|
|
47198
47428
|
}
|
|
47199
47429
|
function resolveUserSkillRoot(entry, cwd) {
|
|
47200
47430
|
if (!entry) return null;
|
|
47201
|
-
if (entry.startsWith("~/") || entry === "~") return
|
|
47202
|
-
if (
|
|
47203
|
-
if (!cwd || !
|
|
47204
|
-
return
|
|
47431
|
+
if (entry.startsWith("~/") || entry === "~") return path44.join(os42.homedir(), entry.slice(1));
|
|
47432
|
+
if (path44.isAbsolute(entry)) return entry;
|
|
47433
|
+
if (!cwd || !path44.isAbsolute(cwd)) return null;
|
|
47434
|
+
return path44.join(cwd, entry);
|
|
47205
47435
|
}
|
|
47206
47436
|
|
|
47207
47437
|
// src/cli/commands/check.ts
|
|
@@ -47210,11 +47440,11 @@ init_audit();
|
|
|
47210
47440
|
|
|
47211
47441
|
// src/review-pending.ts
|
|
47212
47442
|
init_hasher();
|
|
47213
|
-
import
|
|
47214
|
-
import
|
|
47215
|
-
import
|
|
47443
|
+
import fs47 from "fs";
|
|
47444
|
+
import os43 from "os";
|
|
47445
|
+
import path45 from "path";
|
|
47216
47446
|
function storePath() {
|
|
47217
|
-
return process.env.NODE9_PENDING_STORE ||
|
|
47447
|
+
return process.env.NODE9_PENDING_STORE || path45.join(os43.homedir(), ".node9", "pending-reviews.json");
|
|
47218
47448
|
}
|
|
47219
47449
|
var TTL_MS2 = 6 * 60 * 60 * 1e3;
|
|
47220
47450
|
var MAX_ENTRIES = 500;
|
|
@@ -47231,7 +47461,7 @@ function reviewCorrelationKey(payload) {
|
|
|
47231
47461
|
}
|
|
47232
47462
|
function read() {
|
|
47233
47463
|
try {
|
|
47234
|
-
const parsed = JSON.parse(
|
|
47464
|
+
const parsed = JSON.parse(fs47.readFileSync(storePath(), "utf-8"));
|
|
47235
47465
|
if (parsed && Array.isArray(parsed.entries)) return parsed;
|
|
47236
47466
|
} catch {
|
|
47237
47467
|
}
|
|
@@ -47240,11 +47470,11 @@ function read() {
|
|
|
47240
47470
|
function write(store) {
|
|
47241
47471
|
try {
|
|
47242
47472
|
const p = storePath();
|
|
47243
|
-
const dir =
|
|
47244
|
-
if (!
|
|
47473
|
+
const dir = path45.dirname(p);
|
|
47474
|
+
if (!fs47.existsSync(dir)) fs47.mkdirSync(dir, { recursive: true });
|
|
47245
47475
|
const tmp = `${p}.${process.pid}.tmp`;
|
|
47246
|
-
|
|
47247
|
-
|
|
47476
|
+
fs47.writeFileSync(tmp, JSON.stringify(store));
|
|
47477
|
+
fs47.renameSync(tmp, p);
|
|
47248
47478
|
} catch {
|
|
47249
47479
|
}
|
|
47250
47480
|
}
|
|
@@ -47357,9 +47587,9 @@ function registerCheckCommand(program2) {
|
|
|
47357
47587
|
} catch (err2) {
|
|
47358
47588
|
const tempConfig = getConfig();
|
|
47359
47589
|
if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
|
|
47360
|
-
const logPath =
|
|
47590
|
+
const logPath = path46.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
47361
47591
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
47362
|
-
|
|
47592
|
+
fs48.appendFileSync(
|
|
47363
47593
|
logPath,
|
|
47364
47594
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
|
|
47365
47595
|
RAW: ${raw}
|
|
@@ -47372,14 +47602,14 @@ RAW: ${raw}
|
|
|
47372
47602
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
47373
47603
|
if (process.env.NODE9_DEBUG === "1") {
|
|
47374
47604
|
try {
|
|
47375
|
-
const logPath =
|
|
47376
|
-
if (!
|
|
47377
|
-
|
|
47605
|
+
const logPath = path46.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
47606
|
+
if (!fs48.existsSync(path46.dirname(logPath)))
|
|
47607
|
+
fs48.mkdirSync(path46.dirname(logPath), { recursive: true });
|
|
47378
47608
|
const sanitized = JSON.stringify({
|
|
47379
47609
|
...payload,
|
|
47380
47610
|
prompt: `<redacted, ${prompt.length} bytes>`
|
|
47381
47611
|
});
|
|
47382
|
-
|
|
47612
|
+
fs48.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
|
|
47383
47613
|
`);
|
|
47384
47614
|
} catch {
|
|
47385
47615
|
}
|
|
@@ -47400,8 +47630,8 @@ RAW: ${raw}
|
|
|
47400
47630
|
);
|
|
47401
47631
|
const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
|
|
47402
47632
|
try {
|
|
47403
|
-
const ttyFd =
|
|
47404
|
-
|
|
47633
|
+
const ttyFd = fs48.openSync("/dev/tty", "w");
|
|
47634
|
+
fs48.writeSync(
|
|
47405
47635
|
ttyFd,
|
|
47406
47636
|
chalk9.bgRed.white.bold(`
|
|
47407
47637
|
\u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
|
|
@@ -47411,7 +47641,7 @@ RAW: ${raw}
|
|
|
47411
47641
|
|
|
47412
47642
|
`)
|
|
47413
47643
|
);
|
|
47414
|
-
|
|
47644
|
+
fs48.closeSync(ttyFd);
|
|
47415
47645
|
} catch {
|
|
47416
47646
|
}
|
|
47417
47647
|
const isCodex = agent2 === "Codex";
|
|
@@ -47430,16 +47660,17 @@ RAW: ${raw}
|
|
|
47430
47660
|
process.exit(2);
|
|
47431
47661
|
}
|
|
47432
47662
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
47433
|
-
const safeCwdForConfig = typeof payloadCwd === "string" &&
|
|
47663
|
+
const safeCwdForConfig = typeof payloadCwd === "string" && path46.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
47434
47664
|
const config = getConfig(safeCwdForConfig);
|
|
47435
|
-
|
|
47665
|
+
const daemonDown = !isDaemonRunning();
|
|
47666
|
+
if (config.settings.autoStartDaemon && daemonDown && !process.env.NODE9_NO_AUTO_DAEMON) {
|
|
47436
47667
|
try {
|
|
47437
47668
|
const scriptPath = process.argv[1];
|
|
47438
|
-
if (typeof scriptPath !== "string" || !
|
|
47669
|
+
if (typeof scriptPath !== "string" || !path46.isAbsolute(scriptPath))
|
|
47439
47670
|
throw new Error("node9: argv[1] is not an absolute path");
|
|
47440
|
-
const resolvedScript =
|
|
47441
|
-
const packageDist =
|
|
47442
|
-
if (!resolvedScript.startsWith(packageDist +
|
|
47671
|
+
const resolvedScript = fs48.realpathSync(scriptPath);
|
|
47672
|
+
const packageDist = fs48.realpathSync(path46.resolve(__dirname, "../.."));
|
|
47673
|
+
if (!resolvedScript.startsWith(packageDist + path46.sep) && resolvedScript !== packageDist)
|
|
47443
47674
|
throw new Error(
|
|
47444
47675
|
`node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
|
|
47445
47676
|
);
|
|
@@ -47454,17 +47685,27 @@ RAW: ${raw}
|
|
|
47454
47685
|
]) {
|
|
47455
47686
|
delete safeEnv[key];
|
|
47456
47687
|
}
|
|
47457
|
-
const
|
|
47458
|
-
|
|
47459
|
-
|
|
47460
|
-
|
|
47461
|
-
|
|
47462
|
-
|
|
47688
|
+
const startupFd = openStartupLogFd();
|
|
47689
|
+
try {
|
|
47690
|
+
const d = spawn5(process.execPath, [scriptPath, "daemon"], {
|
|
47691
|
+
detached: true,
|
|
47692
|
+
stdio: ["ignore", "ignore", startupFd ?? "ignore"],
|
|
47693
|
+
env: { ...safeEnv, NODE9_AUTO_STARTED: "1" }
|
|
47694
|
+
});
|
|
47695
|
+
d.unref();
|
|
47696
|
+
} finally {
|
|
47697
|
+
if (startupFd !== void 0) {
|
|
47698
|
+
try {
|
|
47699
|
+
fs48.closeSync(startupFd);
|
|
47700
|
+
} catch {
|
|
47701
|
+
}
|
|
47702
|
+
}
|
|
47703
|
+
}
|
|
47463
47704
|
} catch (spawnErr) {
|
|
47464
|
-
const logPath =
|
|
47705
|
+
const logPath = path46.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
47465
47706
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
47466
47707
|
try {
|
|
47467
|
-
|
|
47708
|
+
fs48.appendFileSync(
|
|
47468
47709
|
logPath,
|
|
47469
47710
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
|
|
47470
47711
|
`
|
|
@@ -47472,12 +47713,16 @@ RAW: ${raw}
|
|
|
47472
47713
|
} catch {
|
|
47473
47714
|
}
|
|
47474
47715
|
}
|
|
47716
|
+
} else if (daemonDown && !isTestingMode()) {
|
|
47717
|
+
logAutostartSkipThrottled(
|
|
47718
|
+
!config.settings.autoStartDaemon ? "autoStartDaemon=false" : process.env.NODE9_NO_AUTO_DAEMON ? "NODE9_NO_AUTO_DAEMON" : "unknown"
|
|
47719
|
+
);
|
|
47475
47720
|
}
|
|
47476
47721
|
if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
|
|
47477
|
-
const logPath =
|
|
47478
|
-
if (!
|
|
47479
|
-
|
|
47480
|
-
|
|
47722
|
+
const logPath = path46.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
47723
|
+
if (!fs48.existsSync(path46.dirname(logPath)))
|
|
47724
|
+
fs48.mkdirSync(path46.dirname(logPath), { recursive: true });
|
|
47725
|
+
fs48.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
|
|
47481
47726
|
`);
|
|
47482
47727
|
}
|
|
47483
47728
|
const rawToolName = sanitize2(extractToolName(payload));
|
|
@@ -47491,8 +47736,8 @@ RAW: ${raw}
|
|
|
47491
47736
|
const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
|
|
47492
47737
|
let ttyFd = null;
|
|
47493
47738
|
try {
|
|
47494
|
-
ttyFd =
|
|
47495
|
-
const writeTty = (line) =>
|
|
47739
|
+
ttyFd = fs48.openSync("/dev/tty", "w");
|
|
47740
|
+
const writeTty = (line) => fs48.writeSync(ttyFd, line + "\n");
|
|
47496
47741
|
if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
|
|
47497
47742
|
writeTty(chalk9.bgRed.white.bold(`
|
|
47498
47743
|
\u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
|
|
@@ -47511,7 +47756,7 @@ RAW: ${raw}
|
|
|
47511
47756
|
} finally {
|
|
47512
47757
|
if (ttyFd !== null)
|
|
47513
47758
|
try {
|
|
47514
|
-
|
|
47759
|
+
fs48.closeSync(ttyFd);
|
|
47515
47760
|
} catch {
|
|
47516
47761
|
}
|
|
47517
47762
|
}
|
|
@@ -47568,8 +47813,8 @@ RAW: ${raw}
|
|
|
47568
47813
|
} catch {
|
|
47569
47814
|
}
|
|
47570
47815
|
try {
|
|
47571
|
-
const ttyFd =
|
|
47572
|
-
|
|
47816
|
+
const ttyFd = fs48.openSync("/dev/tty", "w");
|
|
47817
|
+
fs48.writeSync(
|
|
47573
47818
|
ttyFd,
|
|
47574
47819
|
chalk9.yellow(
|
|
47575
47820
|
`
|
|
@@ -47577,7 +47822,7 @@ RAW: ${raw}
|
|
|
47577
47822
|
`
|
|
47578
47823
|
)
|
|
47579
47824
|
);
|
|
47580
|
-
|
|
47825
|
+
fs48.closeSync(ttyFd);
|
|
47581
47826
|
} catch {
|
|
47582
47827
|
}
|
|
47583
47828
|
if (agent === "GitHub Copilot") {
|
|
@@ -47609,17 +47854,17 @@ RAW: ${raw}
|
|
|
47609
47854
|
const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
|
|
47610
47855
|
if (skillPinCfg.enabled && safeSessionId) {
|
|
47611
47856
|
try {
|
|
47612
|
-
const sessionsDir =
|
|
47613
|
-
const flagPath =
|
|
47857
|
+
const sessionsDir = path46.join(os44.homedir(), ".node9", "skill-sessions");
|
|
47858
|
+
const flagPath = path46.join(sessionsDir, `${safeSessionId}.json`);
|
|
47614
47859
|
let flag = null;
|
|
47615
47860
|
try {
|
|
47616
|
-
flag = JSON.parse(
|
|
47861
|
+
flag = JSON.parse(fs48.readFileSync(flagPath, "utf-8"));
|
|
47617
47862
|
} catch {
|
|
47618
47863
|
}
|
|
47619
47864
|
const writeFlag = (data2) => {
|
|
47620
47865
|
try {
|
|
47621
|
-
|
|
47622
|
-
|
|
47866
|
+
fs48.mkdirSync(sessionsDir, { recursive: true });
|
|
47867
|
+
fs48.writeFileSync(
|
|
47623
47868
|
flagPath,
|
|
47624
47869
|
JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
47625
47870
|
{ mode: 384 }
|
|
@@ -47630,8 +47875,8 @@ RAW: ${raw}
|
|
|
47630
47875
|
const sendSkillWarn = (detail, recoveryCmd) => {
|
|
47631
47876
|
let ttyFd = null;
|
|
47632
47877
|
try {
|
|
47633
|
-
ttyFd =
|
|
47634
|
-
const w = (line) =>
|
|
47878
|
+
ttyFd = fs48.openSync("/dev/tty", "w");
|
|
47879
|
+
const w = (line) => fs48.writeSync(ttyFd, line + "\n");
|
|
47635
47880
|
w(chalk9.yellow(`
|
|
47636
47881
|
\u26A0\uFE0F Node9: installed skill drift detected`));
|
|
47637
47882
|
w(chalk9.gray(` ${detail}`));
|
|
@@ -47646,7 +47891,7 @@ RAW: ${raw}
|
|
|
47646
47891
|
} finally {
|
|
47647
47892
|
if (ttyFd !== null)
|
|
47648
47893
|
try {
|
|
47649
|
-
|
|
47894
|
+
fs48.closeSync(ttyFd);
|
|
47650
47895
|
} catch {
|
|
47651
47896
|
}
|
|
47652
47897
|
}
|
|
@@ -47662,7 +47907,7 @@ RAW: ${raw}
|
|
|
47662
47907
|
return;
|
|
47663
47908
|
}
|
|
47664
47909
|
if (!flag || flag.state !== "verified" && flag.state !== "warned") {
|
|
47665
|
-
const absoluteCwd = typeof payloadCwd === "string" &&
|
|
47910
|
+
const absoluteCwd = typeof payloadCwd === "string" && path46.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
47666
47911
|
const extraRoots = skillPinCfg.roots;
|
|
47667
47912
|
const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
|
|
47668
47913
|
const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
|
|
@@ -47703,10 +47948,10 @@ RAW: ${raw}
|
|
|
47703
47948
|
}
|
|
47704
47949
|
try {
|
|
47705
47950
|
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
47706
|
-
for (const name of
|
|
47707
|
-
const p =
|
|
47951
|
+
for (const name of fs48.readdirSync(sessionsDir)) {
|
|
47952
|
+
const p = path46.join(sessionsDir, name);
|
|
47708
47953
|
try {
|
|
47709
|
-
if (
|
|
47954
|
+
if (fs48.statSync(p).mtimeMs < cutoff) fs48.unlinkSync(p);
|
|
47710
47955
|
} catch {
|
|
47711
47956
|
}
|
|
47712
47957
|
}
|
|
@@ -47716,9 +47961,9 @@ RAW: ${raw}
|
|
|
47716
47961
|
} catch (err2) {
|
|
47717
47962
|
if (process.env.NODE9_DEBUG === "1") {
|
|
47718
47963
|
try {
|
|
47719
|
-
const dbg =
|
|
47964
|
+
const dbg = path46.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
47720
47965
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
47721
|
-
|
|
47966
|
+
fs48.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
|
|
47722
47967
|
`);
|
|
47723
47968
|
} catch {
|
|
47724
47969
|
}
|
|
@@ -47728,7 +47973,7 @@ RAW: ${raw}
|
|
|
47728
47973
|
if (shouldSnapshot(toolName, toolInput, config)) {
|
|
47729
47974
|
await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
|
|
47730
47975
|
}
|
|
47731
|
-
const safeCwdForAuth = typeof payloadCwd === "string" &&
|
|
47976
|
+
const safeCwdForAuth = typeof payloadCwd === "string" && path46.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
47732
47977
|
const askMode = resolveAskMode(agent, opts, config);
|
|
47733
47978
|
const result = await authorizeHeadless(toolName, toolInput, meta, {
|
|
47734
47979
|
cwd: safeCwdForAuth,
|
|
@@ -47746,12 +47991,12 @@ RAW: ${raw}
|
|
|
47746
47991
|
}
|
|
47747
47992
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
|
|
47748
47993
|
try {
|
|
47749
|
-
const tty =
|
|
47750
|
-
|
|
47994
|
+
const tty = fs48.openSync("/dev/tty", "w");
|
|
47995
|
+
fs48.writeSync(
|
|
47751
47996
|
tty,
|
|
47752
47997
|
chalk9.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
|
|
47753
47998
|
);
|
|
47754
|
-
|
|
47999
|
+
fs48.closeSync(tty);
|
|
47755
48000
|
} catch {
|
|
47756
48001
|
}
|
|
47757
48002
|
const daemonReady = await autoStartDaemonAndWait();
|
|
@@ -47778,9 +48023,9 @@ RAW: ${raw}
|
|
|
47778
48023
|
});
|
|
47779
48024
|
} catch (err2) {
|
|
47780
48025
|
if (process.env.NODE9_DEBUG === "1") {
|
|
47781
|
-
const logPath =
|
|
48026
|
+
const logPath = path46.join(os44.homedir(), ".node9", "hook-debug.log");
|
|
47782
48027
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
47783
|
-
|
|
48028
|
+
fs48.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
|
|
47784
48029
|
`);
|
|
47785
48030
|
}
|
|
47786
48031
|
process.exit(0);
|
|
@@ -47816,9 +48061,9 @@ RAW: ${raw}
|
|
|
47816
48061
|
// src/cli/commands/log.ts
|
|
47817
48062
|
init_audit();
|
|
47818
48063
|
init_config();
|
|
47819
|
-
import
|
|
47820
|
-
import
|
|
47821
|
-
import
|
|
48064
|
+
import fs49 from "fs";
|
|
48065
|
+
import path47 from "path";
|
|
48066
|
+
import os45 from "os";
|
|
47822
48067
|
init_daemon();
|
|
47823
48068
|
init_dlp();
|
|
47824
48069
|
|
|
@@ -47926,10 +48171,10 @@ function registerLogCommand(program2) {
|
|
|
47926
48171
|
if (rawToolName !== tool) entry.agentToolName = rawToolName;
|
|
47927
48172
|
const payloadSessionId = payload.session_id ?? payload.conversationId;
|
|
47928
48173
|
if (payloadSessionId) entry.sessionId = payloadSessionId;
|
|
47929
|
-
const logPath =
|
|
47930
|
-
if (!
|
|
47931
|
-
|
|
47932
|
-
|
|
48174
|
+
const logPath = path47.join(os45.homedir(), ".node9", "audit.log");
|
|
48175
|
+
if (!fs49.existsSync(path47.dirname(logPath)))
|
|
48176
|
+
fs49.mkdirSync(path47.dirname(logPath), { recursive: true });
|
|
48177
|
+
fs49.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
47933
48178
|
if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
|
|
47934
48179
|
const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
47935
48180
|
if (command) {
|
|
@@ -47963,7 +48208,7 @@ function registerLogCommand(program2) {
|
|
|
47963
48208
|
}
|
|
47964
48209
|
}
|
|
47965
48210
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
47966
|
-
const safeCwd = typeof payloadCwd === "string" &&
|
|
48211
|
+
const safeCwd = typeof payloadCwd === "string" && path47.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
47967
48212
|
const config = getConfig(safeCwd);
|
|
47968
48213
|
{
|
|
47969
48214
|
const toolOutput = payload.tool_response?.output;
|
|
@@ -48040,9 +48285,9 @@ function registerLogCommand(program2) {
|
|
|
48040
48285
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
48041
48286
|
process.stderr.write(`[Node9] audit log error: ${msg}
|
|
48042
48287
|
`);
|
|
48043
|
-
const debugPath =
|
|
48288
|
+
const debugPath = path47.join(os45.homedir(), ".node9", "hook-debug.log");
|
|
48044
48289
|
try {
|
|
48045
|
-
|
|
48290
|
+
fs49.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
|
|
48046
48291
|
`);
|
|
48047
48292
|
} catch {
|
|
48048
48293
|
}
|
|
@@ -48069,16 +48314,16 @@ function registerLogCommand(program2) {
|
|
|
48069
48314
|
init_shields();
|
|
48070
48315
|
init_build();
|
|
48071
48316
|
import chalk10 from "chalk";
|
|
48072
|
-
import
|
|
48073
|
-
import
|
|
48074
|
-
import
|
|
48317
|
+
import fs51 from "fs";
|
|
48318
|
+
import path49 from "path";
|
|
48319
|
+
import os46 from "os";
|
|
48075
48320
|
|
|
48076
48321
|
// src/shields/create.ts
|
|
48077
48322
|
init_dist();
|
|
48078
48323
|
init_shields();
|
|
48079
48324
|
init_audit();
|
|
48080
|
-
import
|
|
48081
|
-
import
|
|
48325
|
+
import fs50 from "fs";
|
|
48326
|
+
import path48 from "path";
|
|
48082
48327
|
function builtinNames() {
|
|
48083
48328
|
const names = /* @__PURE__ */ new Set();
|
|
48084
48329
|
for (const def of Object.values(BUILTIN_SHIELDS)) {
|
|
@@ -48095,8 +48340,8 @@ function createShield(def, opts = {}) {
|
|
|
48095
48340
|
error: `"${name}" is a built-in shield \u2014 choose a different name (a user shield with this name would shadow the built-in).`
|
|
48096
48341
|
};
|
|
48097
48342
|
}
|
|
48098
|
-
const filePath =
|
|
48099
|
-
if (!opts.overwrite &&
|
|
48343
|
+
const filePath = path48.join(USER_SHIELDS_DIR_PATH, `${name}.json`);
|
|
48344
|
+
if (!opts.overwrite && fs50.existsSync(filePath)) {
|
|
48100
48345
|
return {
|
|
48101
48346
|
ok: false,
|
|
48102
48347
|
error: `Shield "${name}" already exists at ${filePath}. Pass --overwrite to replace it.`
|
|
@@ -48161,8 +48406,8 @@ var COMMUNITY_INDEX_URL = "https://raw.githubusercontent.com/node9ai/node9-proxy
|
|
|
48161
48406
|
function readCloudShields() {
|
|
48162
48407
|
const out = /* @__PURE__ */ new Set();
|
|
48163
48408
|
try {
|
|
48164
|
-
const file =
|
|
48165
|
-
const raw = JSON.parse(
|
|
48409
|
+
const file = path49.join(os46.homedir(), ".node9", "rules-cache.json");
|
|
48410
|
+
const raw = JSON.parse(fs51.readFileSync(file, "utf-8"));
|
|
48166
48411
|
for (const r of raw.rules ?? []) {
|
|
48167
48412
|
const rule = r;
|
|
48168
48413
|
const fromSource = rule.source?.startsWith("SHIELD:") ? rule.source.slice("SHIELD:".length).toLowerCase() : void 0;
|
|
@@ -48479,7 +48724,7 @@ function registerShieldCommand(program2) {
|
|
|
48479
48724
|
if (opts.fromFile) {
|
|
48480
48725
|
let raw;
|
|
48481
48726
|
try {
|
|
48482
|
-
raw = JSON.parse(
|
|
48727
|
+
raw = JSON.parse(fs51.readFileSync(opts.fromFile, "utf-8"));
|
|
48483
48728
|
} catch (err2) {
|
|
48484
48729
|
console.error(
|
|
48485
48730
|
chalk10.red(`
|
|
@@ -48601,14 +48846,31 @@ function registerConfigShowCommand(program2) {
|
|
|
48601
48846
|
init_daemon();
|
|
48602
48847
|
init_config();
|
|
48603
48848
|
init_agent_wiring();
|
|
48849
|
+
init_sync();
|
|
48850
|
+
init_service();
|
|
48604
48851
|
import chalk11 from "chalk";
|
|
48605
|
-
import
|
|
48606
|
-
import
|
|
48607
|
-
import
|
|
48852
|
+
import fs52 from "fs";
|
|
48853
|
+
import path50 from "path";
|
|
48854
|
+
import os47 from "os";
|
|
48608
48855
|
import { execSync } from "child_process";
|
|
48856
|
+
|
|
48857
|
+
// src/lib/relative-time.ts
|
|
48858
|
+
function agoLabel(iso, now = Date.now()) {
|
|
48859
|
+
const ms = now - new Date(iso).getTime();
|
|
48860
|
+
if (!Number.isFinite(ms) || ms < 0) return "just now";
|
|
48861
|
+
const min = Math.floor(ms / 6e4);
|
|
48862
|
+
if (min < 1) return "just now";
|
|
48863
|
+
if (min < 60) return `${min} min ago`;
|
|
48864
|
+
const hr = Math.floor(min / 60);
|
|
48865
|
+
if (hr < 24) return `${hr} hour${hr === 1 ? "" : "s"} ago`;
|
|
48866
|
+
const d = Math.floor(hr / 24);
|
|
48867
|
+
return `${d} day${d === 1 ? "" : "s"} ago`;
|
|
48868
|
+
}
|
|
48869
|
+
|
|
48870
|
+
// src/cli/commands/doctor.ts
|
|
48609
48871
|
function registerDoctorCommand(program2, version2) {
|
|
48610
48872
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
|
|
48611
|
-
const homeDir2 =
|
|
48873
|
+
const homeDir2 = os47.homedir();
|
|
48612
48874
|
let failures = 0;
|
|
48613
48875
|
function pass(msg) {
|
|
48614
48876
|
console.log(chalk11.green(" \u2705 ") + msg);
|
|
@@ -48654,10 +48916,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48654
48916
|
);
|
|
48655
48917
|
}
|
|
48656
48918
|
section("Configuration");
|
|
48657
|
-
const globalConfigPath =
|
|
48658
|
-
if (
|
|
48919
|
+
const globalConfigPath = path50.join(homeDir2, ".node9", "config.json");
|
|
48920
|
+
if (fs52.existsSync(globalConfigPath)) {
|
|
48659
48921
|
try {
|
|
48660
|
-
JSON.parse(
|
|
48922
|
+
JSON.parse(fs52.readFileSync(globalConfigPath, "utf-8"));
|
|
48661
48923
|
pass("~/.node9/config.json found and valid");
|
|
48662
48924
|
} catch {
|
|
48663
48925
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -48665,10 +48927,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48665
48927
|
} else {
|
|
48666
48928
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
48667
48929
|
}
|
|
48668
|
-
const projectConfigPath =
|
|
48669
|
-
if (
|
|
48930
|
+
const projectConfigPath = path50.join(process.cwd(), "node9.config.json");
|
|
48931
|
+
if (fs52.existsSync(projectConfigPath)) {
|
|
48670
48932
|
try {
|
|
48671
|
-
JSON.parse(
|
|
48933
|
+
JSON.parse(fs52.readFileSync(projectConfigPath, "utf-8"));
|
|
48672
48934
|
pass("node9.config.json found and valid (project)");
|
|
48673
48935
|
} catch {
|
|
48674
48936
|
fail(
|
|
@@ -48677,8 +48939,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48677
48939
|
);
|
|
48678
48940
|
}
|
|
48679
48941
|
}
|
|
48680
|
-
const credsPath =
|
|
48681
|
-
if (
|
|
48942
|
+
const credsPath = path50.join(homeDir2, ".node9", "credentials.json");
|
|
48943
|
+
if (fs52.existsSync(credsPath)) {
|
|
48682
48944
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
48683
48945
|
} else {
|
|
48684
48946
|
warn(
|
|
@@ -48718,11 +48980,31 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48718
48980
|
"Run: node9 daemon --background"
|
|
48719
48981
|
);
|
|
48720
48982
|
}
|
|
48983
|
+
const autostart = autostartAdvice({
|
|
48984
|
+
installed: isDaemonServiceInstalled(),
|
|
48985
|
+
enabled: isDaemonServiceEnabled(),
|
|
48986
|
+
cloudEnabled: !!getConfig().settings.approvers?.cloud
|
|
48987
|
+
});
|
|
48988
|
+
if (autostart) warn(autostart.message, autostart.hint);
|
|
48989
|
+
if (fs52.existsSync(path50.join(os47.homedir(), ".node9", "credentials.json")) && getConfig().settings.approvers?.cloud) {
|
|
48990
|
+
section("Policy sync");
|
|
48991
|
+
const health = readSyncHealth();
|
|
48992
|
+
if (isPolicyStale(Date.now(), health)) {
|
|
48993
|
+
const when = health.lastCheckedAt ? `last reached the cloud ${agoLabel(health.lastCheckedAt)}` : "never reached the cloud";
|
|
48994
|
+
const fails = health.consecutiveFailures > 0 ? ` (${health.consecutiveFailures} consecutive failure${health.consecutiveFailures === 1 ? "" : "s"}${health.lastError ? `: ${health.lastError}` : ""})` : "";
|
|
48995
|
+
warn(
|
|
48996
|
+
`Cloud policy is STALE \u2014 ${when}${fails}. The cached policy is still enforced, but changes from the dashboard are not reaching this machine.`,
|
|
48997
|
+
"Run: node9 policy sync (and ensure the daemon autostarts: systemctl --user enable --now node9-daemon)"
|
|
48998
|
+
);
|
|
48999
|
+
} else if (health.lastCheckedAt) {
|
|
49000
|
+
pass(`Cloud policy fresh \u2014 last synced ${agoLabel(health.lastCheckedAt)}`);
|
|
49001
|
+
}
|
|
49002
|
+
}
|
|
48721
49003
|
section("Cloud audit shipping");
|
|
48722
49004
|
try {
|
|
48723
49005
|
const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
|
|
48724
49006
|
const cfg = getConfig();
|
|
48725
|
-
const creds =
|
|
49007
|
+
const creds = fs52.existsSync(path50.join(os47.homedir(), ".node9", "credentials.json"));
|
|
48726
49008
|
if (!creds) {
|
|
48727
49009
|
warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
|
|
48728
49010
|
} else if (!cfg.settings.approvers.cloud) {
|
|
@@ -48772,9 +49054,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
48772
49054
|
|
|
48773
49055
|
// src/cli/commands/audit.ts
|
|
48774
49056
|
import chalk12 from "chalk";
|
|
48775
|
-
import
|
|
48776
|
-
import
|
|
48777
|
-
import
|
|
49057
|
+
import fs53 from "fs";
|
|
49058
|
+
import path51 from "path";
|
|
49059
|
+
import os48 from "os";
|
|
48778
49060
|
function formatRelativeTime(timestamp) {
|
|
48779
49061
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
48780
49062
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -48787,14 +49069,14 @@ function formatRelativeTime(timestamp) {
|
|
|
48787
49069
|
}
|
|
48788
49070
|
function registerAuditCommand(program2) {
|
|
48789
49071
|
program2.command("audit").description("View local execution audit log").option("--tail <n>", "Number of entries to show", "20").option("--tool <pattern>", "Filter by tool name (substring match)").option("--deny", "Show only denied actions").option("--json", "Output raw JSON").action((options) => {
|
|
48790
|
-
const logPath =
|
|
48791
|
-
if (!
|
|
49072
|
+
const logPath = path51.join(os48.homedir(), ".node9", "audit.log");
|
|
49073
|
+
if (!fs53.existsSync(logPath)) {
|
|
48792
49074
|
console.log(
|
|
48793
49075
|
chalk12.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
48794
49076
|
);
|
|
48795
49077
|
return;
|
|
48796
49078
|
}
|
|
48797
|
-
const raw =
|
|
49079
|
+
const raw = fs53.readFileSync(logPath, "utf-8");
|
|
48798
49080
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
48799
49081
|
let entries = lines.flatMap((line) => {
|
|
48800
49082
|
try {
|
|
@@ -48853,9 +49135,9 @@ import chalk13 from "chalk";
|
|
|
48853
49135
|
init_costSync();
|
|
48854
49136
|
init_litellm();
|
|
48855
49137
|
init_cost_codex();
|
|
48856
|
-
import
|
|
48857
|
-
import
|
|
48858
|
-
import
|
|
49138
|
+
import fs54 from "fs";
|
|
49139
|
+
import os49 from "os";
|
|
49140
|
+
import path52 from "path";
|
|
48859
49141
|
var TEST_COMMAND_RE3 = /(?:^|\s)(npm\s+(?:run\s+)?test|npx\s+(?:vitest|jest|mocha)|yarn\s+(?:run\s+)?test|pnpm\s+(?:run\s+)?test|vitest|jest|mocha|pytest|py\.test|cargo\s+test|go\s+test|bundle\s+exec\s+rspec|rspec|phpunit|dotnet\s+test)\b/i;
|
|
48860
49142
|
function buildTestTimestamps(allEntries) {
|
|
48861
49143
|
const testTs = /* @__PURE__ */ new Set();
|
|
@@ -48935,8 +49217,8 @@ function getDateRange(period, now) {
|
|
|
48935
49217
|
}
|
|
48936
49218
|
}
|
|
48937
49219
|
function parseAuditLog(logPath) {
|
|
48938
|
-
if (!
|
|
48939
|
-
const raw =
|
|
49220
|
+
if (!fs54.existsSync(logPath)) return [];
|
|
49221
|
+
const raw = fs54.readFileSync(logPath, "utf-8");
|
|
48940
49222
|
return raw.split("\n").flatMap((line) => {
|
|
48941
49223
|
if (!line.trim()) return [];
|
|
48942
49224
|
try {
|
|
@@ -48983,25 +49265,25 @@ function freezeClaudeCost(acc) {
|
|
|
48983
49265
|
};
|
|
48984
49266
|
}
|
|
48985
49267
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
48986
|
-
const projPath =
|
|
49268
|
+
const projPath = path52.join(projectsDir, proj);
|
|
48987
49269
|
let files;
|
|
48988
49270
|
try {
|
|
48989
|
-
const stat =
|
|
49271
|
+
const stat = fs54.statSync(projPath);
|
|
48990
49272
|
if (!stat.isDirectory()) return;
|
|
48991
|
-
files =
|
|
49273
|
+
files = fs54.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
48992
49274
|
} catch {
|
|
48993
49275
|
return;
|
|
48994
49276
|
}
|
|
48995
49277
|
const startMs = start.getTime();
|
|
48996
49278
|
for (const file of files) {
|
|
48997
|
-
const filePath =
|
|
49279
|
+
const filePath = path52.join(projPath, file);
|
|
48998
49280
|
try {
|
|
48999
|
-
if (
|
|
49281
|
+
if (fs54.statSync(filePath).mtimeMs < startMs) continue;
|
|
49000
49282
|
} catch {
|
|
49001
49283
|
continue;
|
|
49002
49284
|
}
|
|
49003
49285
|
try {
|
|
49004
|
-
const raw =
|
|
49286
|
+
const raw = fs54.readFileSync(filePath, "utf-8");
|
|
49005
49287
|
for (const line of raw.split("\n")) {
|
|
49006
49288
|
if (!line.trim()) continue;
|
|
49007
49289
|
let entry;
|
|
@@ -49051,10 +49333,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
49051
49333
|
}
|
|
49052
49334
|
function loadClaudeCost(start, end, projectsDir) {
|
|
49053
49335
|
const acc = emptyClaudeCostAccumulator();
|
|
49054
|
-
if (!
|
|
49336
|
+
if (!fs54.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
49055
49337
|
let dirs;
|
|
49056
49338
|
try {
|
|
49057
|
-
dirs =
|
|
49339
|
+
dirs = fs54.readdirSync(projectsDir);
|
|
49058
49340
|
} catch {
|
|
49059
49341
|
return freezeClaudeCost(acc);
|
|
49060
49342
|
}
|
|
@@ -49066,7 +49348,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
49066
49348
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
49067
49349
|
let lines;
|
|
49068
49350
|
try {
|
|
49069
|
-
lines =
|
|
49351
|
+
lines = fs54.readFileSync(filePath, "utf-8").split("\n");
|
|
49070
49352
|
} catch {
|
|
49071
49353
|
return;
|
|
49072
49354
|
}
|
|
@@ -49121,31 +49403,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
49121
49403
|
}
|
|
49122
49404
|
function listCodexSessionFiles2(sessionsBase) {
|
|
49123
49405
|
const jsonlFiles = [];
|
|
49124
|
-
if (!
|
|
49406
|
+
if (!fs54.existsSync(sessionsBase)) return jsonlFiles;
|
|
49125
49407
|
try {
|
|
49126
|
-
for (const year of
|
|
49127
|
-
const yearPath =
|
|
49408
|
+
for (const year of fs54.readdirSync(sessionsBase)) {
|
|
49409
|
+
const yearPath = path52.join(sessionsBase, year);
|
|
49128
49410
|
try {
|
|
49129
|
-
if (!
|
|
49411
|
+
if (!fs54.statSync(yearPath).isDirectory()) continue;
|
|
49130
49412
|
} catch {
|
|
49131
49413
|
continue;
|
|
49132
49414
|
}
|
|
49133
|
-
for (const month of
|
|
49134
|
-
const monthPath =
|
|
49415
|
+
for (const month of fs54.readdirSync(yearPath)) {
|
|
49416
|
+
const monthPath = path52.join(yearPath, month);
|
|
49135
49417
|
try {
|
|
49136
|
-
if (!
|
|
49418
|
+
if (!fs54.statSync(monthPath).isDirectory()) continue;
|
|
49137
49419
|
} catch {
|
|
49138
49420
|
continue;
|
|
49139
49421
|
}
|
|
49140
|
-
for (const day of
|
|
49141
|
-
const dayPath =
|
|
49422
|
+
for (const day of fs54.readdirSync(monthPath)) {
|
|
49423
|
+
const dayPath = path52.join(monthPath, day);
|
|
49142
49424
|
try {
|
|
49143
|
-
if (!
|
|
49425
|
+
if (!fs54.statSync(dayPath).isDirectory()) continue;
|
|
49144
49426
|
} catch {
|
|
49145
49427
|
continue;
|
|
49146
49428
|
}
|
|
49147
|
-
for (const file of
|
|
49148
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
49429
|
+
for (const file of fs54.readdirSync(dayPath)) {
|
|
49430
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path52.join(dayPath, file));
|
|
49149
49431
|
}
|
|
49150
49432
|
}
|
|
49151
49433
|
}
|
|
@@ -49210,13 +49492,13 @@ function freezeGeminiCost(acc) {
|
|
|
49210
49492
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
49211
49493
|
const startMs = start.getTime();
|
|
49212
49494
|
try {
|
|
49213
|
-
if (
|
|
49495
|
+
if (fs54.statSync(filePath).mtimeMs < startMs) return;
|
|
49214
49496
|
} catch {
|
|
49215
49497
|
return;
|
|
49216
49498
|
}
|
|
49217
49499
|
let raw;
|
|
49218
49500
|
try {
|
|
49219
|
-
raw =
|
|
49501
|
+
raw = fs54.readFileSync(filePath, "utf-8");
|
|
49220
49502
|
} catch {
|
|
49221
49503
|
return;
|
|
49222
49504
|
}
|
|
@@ -49265,30 +49547,30 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
|
|
|
49265
49547
|
const out = [];
|
|
49266
49548
|
let dirs;
|
|
49267
49549
|
try {
|
|
49268
|
-
if (!
|
|
49269
|
-
dirs =
|
|
49550
|
+
if (!fs54.statSync(geminiTmpDir2).isDirectory()) return out;
|
|
49551
|
+
dirs = fs54.readdirSync(geminiTmpDir2);
|
|
49270
49552
|
} catch {
|
|
49271
49553
|
return out;
|
|
49272
49554
|
}
|
|
49273
49555
|
for (const proj of dirs) {
|
|
49274
|
-
const chatsDir =
|
|
49556
|
+
const chatsDir = path52.join(geminiTmpDir2, proj, "chats");
|
|
49275
49557
|
let files;
|
|
49276
49558
|
try {
|
|
49277
|
-
if (!
|
|
49278
|
-
files =
|
|
49559
|
+
if (!fs54.statSync(chatsDir).isDirectory()) continue;
|
|
49560
|
+
files = fs54.readdirSync(chatsDir);
|
|
49279
49561
|
} catch {
|
|
49280
49562
|
continue;
|
|
49281
49563
|
}
|
|
49282
49564
|
for (const f of files) {
|
|
49283
49565
|
if (!f.endsWith(".jsonl")) continue;
|
|
49284
|
-
out.push({ projectKey: proj, file:
|
|
49566
|
+
out.push({ projectKey: proj, file: path52.join(chatsDir, f) });
|
|
49285
49567
|
}
|
|
49286
49568
|
}
|
|
49287
49569
|
return out;
|
|
49288
49570
|
}
|
|
49289
49571
|
function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
49290
49572
|
const acc = emptyGeminiAccumulator();
|
|
49291
|
-
if (!
|
|
49573
|
+
if (!fs54.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
|
|
49292
49574
|
for (const { projectKey, file } of listGeminiSessionFiles2(geminiTmpDir2)) {
|
|
49293
49575
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
49294
49576
|
}
|
|
@@ -49306,11 +49588,11 @@ function dimensionOfBlock(checkedBy, ruleName) {
|
|
|
49306
49588
|
}
|
|
49307
49589
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
49308
49590
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
49309
|
-
const auditLogPath = opts.auditLogPath ??
|
|
49310
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
49311
|
-
const codexSessionsDir2 = opts.codexSessionsDir ??
|
|
49312
|
-
const geminiTmpDir2 = opts.geminiTmpDir ??
|
|
49313
|
-
const hasAuditFile =
|
|
49591
|
+
const auditLogPath = opts.auditLogPath ?? path52.join(os49.homedir(), ".node9", "audit.log");
|
|
49592
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? path52.join(os49.homedir(), ".claude", "projects");
|
|
49593
|
+
const codexSessionsDir2 = opts.codexSessionsDir ?? path52.join(os49.homedir(), ".codex", "sessions");
|
|
49594
|
+
const geminiTmpDir2 = opts.geminiTmpDir ?? path52.join(os49.homedir(), ".gemini", "tmp");
|
|
49595
|
+
const hasAuditFile = fs54.existsSync(auditLogPath);
|
|
49314
49596
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
49315
49597
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
49316
49598
|
const { start, end } = getDateRange(period, now);
|
|
@@ -50103,10 +50385,12 @@ function registerDaemonCommand(program2) {
|
|
|
50103
50385
|
init_core();
|
|
50104
50386
|
init_daemon();
|
|
50105
50387
|
init_agent_wiring();
|
|
50388
|
+
init_sync();
|
|
50389
|
+
init_service();
|
|
50106
50390
|
import chalk15 from "chalk";
|
|
50107
|
-
import
|
|
50108
|
-
import
|
|
50109
|
-
import
|
|
50391
|
+
import fs55 from "fs";
|
|
50392
|
+
import path53 from "path";
|
|
50393
|
+
import os50 from "os";
|
|
50110
50394
|
function printAgentSection(label2, hookPairs, wrapped) {
|
|
50111
50395
|
console.log(chalk15.bold(` ${label2}`));
|
|
50112
50396
|
for (const { name, present } of hookPairs) {
|
|
@@ -50135,6 +50419,15 @@ function registerStatusCommand(program2) {
|
|
|
50135
50419
|
console.log("");
|
|
50136
50420
|
if (creds && settings.approvers.cloud) {
|
|
50137
50421
|
console.log(chalk15.green(" \u25CF Agent mode") + chalk15.gray(" \u2014 cloud team policy enforced"));
|
|
50422
|
+
const health = readSyncHealth();
|
|
50423
|
+
if (isPolicyStale(Date.now(), health)) {
|
|
50424
|
+
const when = health.lastCheckedAt ? `last synced ${agoLabel(health.lastCheckedAt)}` : "never synced";
|
|
50425
|
+
const fails = health.consecutiveFailures > 0 ? ` \xB7 ${health.consecutiveFailures} failed attempt${health.consecutiveFailures === 1 ? "" : "s"}${health.lastError ? ` (${health.lastError})` : ""}` : "";
|
|
50426
|
+
console.log(chalk15.yellow(" \u26A0 Policy sync STALE") + chalk15.gray(` \u2014 ${when}${fails}`));
|
|
50427
|
+
console.log(chalk15.gray(" the cached policy is still enforced \u2014 run: node9 doctor"));
|
|
50428
|
+
} else if (health.lastCheckedAt) {
|
|
50429
|
+
console.log(chalk15.gray(` \u21B3 policy synced ${agoLabel(health.lastCheckedAt)}`));
|
|
50430
|
+
}
|
|
50138
50431
|
} else if (creds && !settings.approvers.cloud) {
|
|
50139
50432
|
console.log(
|
|
50140
50433
|
chalk15.blue(" \u25CF Privacy mode \u{1F6E1}\uFE0F") + chalk15.gray(" \u2014 all decisions stay on this machine")
|
|
@@ -50152,6 +50445,16 @@ function registerStatusCommand(program2) {
|
|
|
50152
50445
|
} else {
|
|
50153
50446
|
console.log(chalk15.gray(" \u25CB Daemon stopped"));
|
|
50154
50447
|
}
|
|
50448
|
+
const autostart = autostartAdvice({
|
|
50449
|
+
installed: isDaemonServiceInstalled(),
|
|
50450
|
+
enabled: isDaemonServiceEnabled(),
|
|
50451
|
+
cloudEnabled: !!(creds && settings.approvers.cloud)
|
|
50452
|
+
});
|
|
50453
|
+
if (autostart) {
|
|
50454
|
+
console.log(
|
|
50455
|
+
chalk15.yellow(" \u26A0 daemon autostart not active") + chalk15.gray(" \u2014 won't survive reboot; run: node9 doctor")
|
|
50456
|
+
);
|
|
50457
|
+
}
|
|
50155
50458
|
if (settings.enableUndo) {
|
|
50156
50459
|
console.log(
|
|
50157
50460
|
chalk15.magenta(" \u25CF Undo Engine") + chalk15.gray(` \u2192 Auto-snapshotting Git repos on AI change`)
|
|
@@ -50160,20 +50463,20 @@ function registerStatusCommand(program2) {
|
|
|
50160
50463
|
console.log("");
|
|
50161
50464
|
const modeLabel = settings.mode === "audit" ? chalk15.blue("audit") : settings.mode === "strict" ? chalk15.red("strict") : chalk15.white("standard");
|
|
50162
50465
|
console.log(` Mode: ${modeLabel}`);
|
|
50163
|
-
const projectConfig =
|
|
50164
|
-
const globalConfig =
|
|
50466
|
+
const projectConfig = path53.join(process.cwd(), "node9.config.json");
|
|
50467
|
+
const globalConfig = path53.join(os50.homedir(), ".node9", "config.json");
|
|
50165
50468
|
console.log(
|
|
50166
|
-
` Local: ${
|
|
50469
|
+
` Local: ${fs55.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
|
|
50167
50470
|
);
|
|
50168
50471
|
console.log(
|
|
50169
|
-
` Global: ${
|
|
50472
|
+
` Global: ${fs55.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
|
|
50170
50473
|
);
|
|
50171
50474
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
50172
50475
|
console.log(
|
|
50173
50476
|
` Sandbox: ${chalk15.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
50174
50477
|
);
|
|
50175
50478
|
}
|
|
50176
|
-
const wiring = getAgentWiring(
|
|
50479
|
+
const wiring = getAgentWiring(os50.homedir()).filter((a) => a.present);
|
|
50177
50480
|
if (wiring.length > 0) {
|
|
50178
50481
|
console.log("");
|
|
50179
50482
|
console.log(chalk15.bold(" Agent Wiring:"));
|
|
@@ -50211,10 +50514,11 @@ init_core();
|
|
|
50211
50514
|
init_setup();
|
|
50212
50515
|
init_shields();
|
|
50213
50516
|
init_service();
|
|
50517
|
+
init_core();
|
|
50214
50518
|
import chalk16 from "chalk";
|
|
50215
|
-
import
|
|
50216
|
-
import
|
|
50217
|
-
import
|
|
50519
|
+
import fs56 from "fs";
|
|
50520
|
+
import path54 from "path";
|
|
50521
|
+
import os51 from "os";
|
|
50218
50522
|
import https6 from "https";
|
|
50219
50523
|
var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
|
|
50220
50524
|
function buildTelemetryPayload(agents, firstInstall) {
|
|
@@ -50300,16 +50604,16 @@ function registerInitCommand(program2) {
|
|
|
50300
50604
|
}
|
|
50301
50605
|
console.log("");
|
|
50302
50606
|
}
|
|
50303
|
-
const configPath =
|
|
50304
|
-
const isFirstInstall = !
|
|
50305
|
-
if (
|
|
50607
|
+
const configPath = path54.join(os51.homedir(), ".node9", "config.json");
|
|
50608
|
+
const isFirstInstall = !fs56.existsSync(configPath);
|
|
50609
|
+
if (fs56.existsSync(configPath) && !options.force) {
|
|
50306
50610
|
try {
|
|
50307
|
-
const existing = JSON.parse(
|
|
50611
|
+
const existing = JSON.parse(fs56.readFileSync(configPath, "utf-8"));
|
|
50308
50612
|
const settings = existing.settings ?? {};
|
|
50309
50613
|
if (settings.mode !== chosenMode) {
|
|
50310
50614
|
settings.mode = chosenMode;
|
|
50311
50615
|
existing.settings = settings;
|
|
50312
|
-
|
|
50616
|
+
fs56.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
50313
50617
|
console.log(chalk16.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
50314
50618
|
} else {
|
|
50315
50619
|
console.log(chalk16.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -50322,9 +50626,9 @@ function registerInitCommand(program2) {
|
|
|
50322
50626
|
...DEFAULT_CONFIG,
|
|
50323
50627
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
50324
50628
|
};
|
|
50325
|
-
const dir =
|
|
50326
|
-
if (!
|
|
50327
|
-
|
|
50629
|
+
const dir = path54.dirname(configPath);
|
|
50630
|
+
if (!fs56.existsSync(dir)) fs56.mkdirSync(dir, { recursive: true });
|
|
50631
|
+
fs56.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
50328
50632
|
console.log(chalk16.green(`\u2705 Config created: ${configPath}`));
|
|
50329
50633
|
console.log(chalk16.gray(` Mode: ${chosenMode}`));
|
|
50330
50634
|
}
|
|
@@ -50376,8 +50680,13 @@ function registerInitCommand(program2) {
|
|
|
50376
50680
|
console.log(chalk16.gray(" You can try again later with: node9 daemon install"));
|
|
50377
50681
|
}
|
|
50378
50682
|
}
|
|
50683
|
+
} else if (isDaemonServiceEnabled()) {
|
|
50684
|
+
console.log(chalk16.green(" \u2713 Daemon login service already installed & enabled"));
|
|
50379
50685
|
} else {
|
|
50380
|
-
|
|
50686
|
+
const healed = ensureAutostartHealthy(!!getConfig().settings.autoStartDaemon);
|
|
50687
|
+
console.log(
|
|
50688
|
+
healed === "repaired" ? chalk16.green(" \u2713 Re-enabled daemon login service (was installed but disabled)") : chalk16.gray(" \xB7 Daemon login service is disabled (autostart off) \u2014 left as-is")
|
|
50689
|
+
);
|
|
50381
50690
|
}
|
|
50382
50691
|
if (!isTestingMode()) {
|
|
50383
50692
|
process.stdout.write(chalk16.dim(" Starting daemon..."));
|
|
@@ -50422,11 +50731,11 @@ init_agent_wiring();
|
|
|
50422
50731
|
init_setup();
|
|
50423
50732
|
init_hook_baseline();
|
|
50424
50733
|
import chalk17 from "chalk";
|
|
50425
|
-
import
|
|
50734
|
+
import fs57 from "fs";
|
|
50426
50735
|
var hasHookSurface = (a) => a.hooks.length > 0;
|
|
50427
50736
|
function backupForHeal(file) {
|
|
50428
50737
|
try {
|
|
50429
|
-
if (file &&
|
|
50738
|
+
if (file && fs57.existsSync(file)) fs57.copyFileSync(file, `${file}.node9-heal-bak`);
|
|
50430
50739
|
} catch {
|
|
50431
50740
|
}
|
|
50432
50741
|
}
|
|
@@ -50593,7 +50902,7 @@ function registerConnectCommand(program2) {
|
|
|
50593
50902
|
}
|
|
50594
50903
|
|
|
50595
50904
|
// src/cli/commands/undo.ts
|
|
50596
|
-
import
|
|
50905
|
+
import path55 from "path";
|
|
50597
50906
|
import chalk20 from "chalk";
|
|
50598
50907
|
|
|
50599
50908
|
// src/tui/undo-navigator.ts
|
|
@@ -50752,7 +51061,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
50752
51061
|
let dir = startDir;
|
|
50753
51062
|
while (true) {
|
|
50754
51063
|
if (cwds.has(dir)) return dir;
|
|
50755
|
-
const parent =
|
|
51064
|
+
const parent = path55.dirname(dir);
|
|
50756
51065
|
if (parent === dir) return null;
|
|
50757
51066
|
dir = parent;
|
|
50758
51067
|
}
|
|
@@ -51386,18 +51695,18 @@ function registerMcpGatewayCommand(program2) {
|
|
|
51386
51695
|
|
|
51387
51696
|
// src/mcp-server/index.ts
|
|
51388
51697
|
import readline5 from "readline";
|
|
51389
|
-
import
|
|
51390
|
-
import
|
|
51391
|
-
import
|
|
51698
|
+
import fs59 from "fs";
|
|
51699
|
+
import os53 from "os";
|
|
51700
|
+
import path57 from "path";
|
|
51392
51701
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
51393
51702
|
init_core();
|
|
51394
51703
|
init_daemon();
|
|
51395
51704
|
init_shields();
|
|
51396
51705
|
|
|
51397
51706
|
// src/auth/egress-config.ts
|
|
51398
|
-
import
|
|
51399
|
-
import
|
|
51400
|
-
import
|
|
51707
|
+
import fs58 from "fs";
|
|
51708
|
+
import os52 from "os";
|
|
51709
|
+
import path56 from "path";
|
|
51401
51710
|
var DEFAULT_EGRESS = {
|
|
51402
51711
|
enabled: false,
|
|
51403
51712
|
mode: "review",
|
|
@@ -51406,12 +51715,12 @@ var DEFAULT_EGRESS = {
|
|
|
51406
51715
|
allowPrivate: true
|
|
51407
51716
|
};
|
|
51408
51717
|
function egressConfigPath() {
|
|
51409
|
-
return
|
|
51718
|
+
return path56.join(os52.homedir(), ".node9", "config.json");
|
|
51410
51719
|
}
|
|
51411
51720
|
function readEgressRawConfig() {
|
|
51412
51721
|
let text;
|
|
51413
51722
|
try {
|
|
51414
|
-
text =
|
|
51723
|
+
text = fs58.readFileSync(egressConfigPath(), "utf8");
|
|
51415
51724
|
} catch (err2) {
|
|
51416
51725
|
if (err2.code === "ENOENT") return {};
|
|
51417
51726
|
throw err2;
|
|
@@ -51426,8 +51735,8 @@ function readEgressRawConfig() {
|
|
|
51426
51735
|
}
|
|
51427
51736
|
function writeEgressRawConfig(config) {
|
|
51428
51737
|
const p = egressConfigPath();
|
|
51429
|
-
|
|
51430
|
-
|
|
51738
|
+
fs58.mkdirSync(path56.dirname(p), { recursive: true });
|
|
51739
|
+
fs58.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
51431
51740
|
}
|
|
51432
51741
|
function applyEgress(config, change) {
|
|
51433
51742
|
const policy = config.policy = config.policy ?? {};
|
|
@@ -51812,13 +52121,13 @@ function handleStatus() {
|
|
|
51812
52121
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
51813
52122
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
51814
52123
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
51815
|
-
const projectConfig =
|
|
51816
|
-
const globalConfig =
|
|
52124
|
+
const projectConfig = path57.join(process.cwd(), "node9.config.json");
|
|
52125
|
+
const globalConfig = path57.join(os53.homedir(), ".node9", "config.json");
|
|
51817
52126
|
lines.push(
|
|
51818
|
-
`Project config (node9.config.json): ${
|
|
52127
|
+
`Project config (node9.config.json): ${fs59.existsSync(projectConfig) ? "present" : "not found"}`
|
|
51819
52128
|
);
|
|
51820
52129
|
lines.push(
|
|
51821
|
-
`Global config (~/.node9/config.json): ${
|
|
52130
|
+
`Global config (~/.node9/config.json): ${fs59.existsSync(globalConfig) ? "present" : "not found"}`
|
|
51822
52131
|
);
|
|
51823
52132
|
return lines.join("\n");
|
|
51824
52133
|
}
|
|
@@ -51924,21 +52233,21 @@ function handleEgressDeny(args) {
|
|
|
51924
52233
|
addEgressHost("deny", host);
|
|
51925
52234
|
return `Denied egress to ${host} (deny always wins over allow).`;
|
|
51926
52235
|
}
|
|
51927
|
-
var GLOBAL_CONFIG_PATH =
|
|
52236
|
+
var GLOBAL_CONFIG_PATH = path57.join(os53.homedir(), ".node9", "config.json");
|
|
51928
52237
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
51929
52238
|
function readGlobalConfigRaw() {
|
|
51930
52239
|
try {
|
|
51931
|
-
if (
|
|
51932
|
-
return JSON.parse(
|
|
52240
|
+
if (fs59.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
52241
|
+
return JSON.parse(fs59.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
|
|
51933
52242
|
}
|
|
51934
52243
|
} catch {
|
|
51935
52244
|
}
|
|
51936
52245
|
return {};
|
|
51937
52246
|
}
|
|
51938
52247
|
function writeGlobalConfigRaw(data) {
|
|
51939
|
-
const dir =
|
|
51940
|
-
if (!
|
|
51941
|
-
|
|
52248
|
+
const dir = path57.dirname(GLOBAL_CONFIG_PATH);
|
|
52249
|
+
if (!fs59.existsSync(dir)) fs59.mkdirSync(dir, { recursive: true });
|
|
52250
|
+
fs59.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
|
|
51942
52251
|
}
|
|
51943
52252
|
function handleApproverList() {
|
|
51944
52253
|
const config = getConfig();
|
|
@@ -51982,9 +52291,9 @@ function handleApproverSet(args) {
|
|
|
51982
52291
|
function handleAuditGet(args) {
|
|
51983
52292
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
51984
52293
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
51985
|
-
const auditPath =
|
|
51986
|
-
if (!
|
|
51987
|
-
const rawLines =
|
|
52294
|
+
const auditPath = path57.join(os53.homedir(), ".node9", "audit.log");
|
|
52295
|
+
if (!fs59.existsSync(auditPath)) return "No audit log found.";
|
|
52296
|
+
const rawLines = fs59.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
51988
52297
|
const parsed = [];
|
|
51989
52298
|
for (const line of rawLines) {
|
|
51990
52299
|
try {
|
|
@@ -52358,7 +52667,7 @@ function registerTrustCommand(program2) {
|
|
|
52358
52667
|
// src/cli/commands/mcp-pin.ts
|
|
52359
52668
|
init_mcp_pin();
|
|
52360
52669
|
import chalk24 from "chalk";
|
|
52361
|
-
import
|
|
52670
|
+
import fs60 from "fs";
|
|
52362
52671
|
|
|
52363
52672
|
// src/cli/commands/mcp-gateway-cmd.ts
|
|
52364
52673
|
init_mcp_wrap();
|
|
@@ -52565,7 +52874,7 @@ function registerMcpPinCommand(program2) {
|
|
|
52565
52874
|
let repoCorrupt = false;
|
|
52566
52875
|
if (found.source === "repo") {
|
|
52567
52876
|
try {
|
|
52568
|
-
const raw =
|
|
52877
|
+
const raw = fs60.readFileSync(found.path, "utf-8");
|
|
52569
52878
|
const parsed = JSON.parse(raw);
|
|
52570
52879
|
repoEntries = parsed.servers ?? {};
|
|
52571
52880
|
} catch {
|
|
@@ -53066,8 +53375,8 @@ import chalk30 from "chalk";
|
|
|
53066
53375
|
|
|
53067
53376
|
// src/ci-check/fetch.ts
|
|
53068
53377
|
var import_undici = __toESM(require_undici());
|
|
53069
|
-
import
|
|
53070
|
-
import
|
|
53378
|
+
import fs61 from "fs";
|
|
53379
|
+
import path58 from "path";
|
|
53071
53380
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
53072
53381
|
var cachedGhToken;
|
|
53073
53382
|
function resolveGitHubToken() {
|
|
@@ -53150,7 +53459,7 @@ function parseRepoUrl(input) {
|
|
|
53150
53459
|
function isLocalPath(input) {
|
|
53151
53460
|
if (input.startsWith(".") || input.startsWith("/") || input.startsWith("~")) return true;
|
|
53152
53461
|
try {
|
|
53153
|
-
return
|
|
53462
|
+
return fs61.existsSync(input) && fs61.statSync(input).isDirectory();
|
|
53154
53463
|
} catch {
|
|
53155
53464
|
return false;
|
|
53156
53465
|
}
|
|
@@ -53265,10 +53574,10 @@ function readLocalTree(dir) {
|
|
|
53265
53574
|
const files = [];
|
|
53266
53575
|
const notes = [];
|
|
53267
53576
|
const add = (rel) => {
|
|
53268
|
-
const abs =
|
|
53577
|
+
const abs = path58.join(root, rel);
|
|
53269
53578
|
try {
|
|
53270
|
-
if (
|
|
53271
|
-
files.push({ path: rel, content:
|
|
53579
|
+
if (fs61.existsSync(abs) && fs61.statSync(abs).isFile()) {
|
|
53580
|
+
files.push({ path: rel, content: fs61.readFileSync(abs, "utf8") });
|
|
53272
53581
|
}
|
|
53273
53582
|
} catch {
|
|
53274
53583
|
}
|
|
@@ -53288,7 +53597,7 @@ function readLocalTree(dir) {
|
|
|
53288
53597
|
dirsVisited++;
|
|
53289
53598
|
let entries;
|
|
53290
53599
|
try {
|
|
53291
|
-
entries =
|
|
53600
|
+
entries = fs61.readdirSync(path58.join(root, relDir), { withFileTypes: true });
|
|
53292
53601
|
} catch {
|
|
53293
53602
|
return;
|
|
53294
53603
|
}
|
|
@@ -53309,11 +53618,11 @@ function readLocalTree(dir) {
|
|
|
53309
53618
|
`repo is large \u2014 some agent-surface files may be INCOMPLETE (capped at ${MAX_SURFACE_FILES} files / ${MAX_DIRS} dirs).`
|
|
53310
53619
|
);
|
|
53311
53620
|
for (const rel of matches) collect(rel);
|
|
53312
|
-
const wfDir =
|
|
53621
|
+
const wfDir = path58.join(root, WORKFLOW_DIR);
|
|
53313
53622
|
try {
|
|
53314
|
-
if (
|
|
53315
|
-
for (const name of
|
|
53316
|
-
if (/\.ya?ml$/.test(name)) add(
|
|
53623
|
+
if (fs61.existsSync(wfDir)) {
|
|
53624
|
+
for (const name of fs61.readdirSync(wfDir)) {
|
|
53625
|
+
if (/\.ya?ml$/.test(name)) add(path58.join(WORKFLOW_DIR, name));
|
|
53317
53626
|
}
|
|
53318
53627
|
}
|
|
53319
53628
|
} catch {
|
|
@@ -53586,7 +53895,7 @@ function severityFromScore(score) {
|
|
|
53586
53895
|
if (score >= 1) return "advisory";
|
|
53587
53896
|
return null;
|
|
53588
53897
|
}
|
|
53589
|
-
function analyzeWorkflow(
|
|
53898
|
+
function analyzeWorkflow(path71, content) {
|
|
53590
53899
|
let raw;
|
|
53591
53900
|
try {
|
|
53592
53901
|
raw = parseYaml(content) ?? {};
|
|
@@ -53707,7 +54016,7 @@ function analyzeWorkflow(path70, content) {
|
|
|
53707
54016
|
dimension: "workflows",
|
|
53708
54017
|
severity,
|
|
53709
54018
|
title,
|
|
53710
|
-
file:
|
|
54019
|
+
file: path71,
|
|
53711
54020
|
signals,
|
|
53712
54021
|
mitigations: mitigations.length ? mitigations : void 0,
|
|
53713
54022
|
fix: head === "root" && privileged ? "Do not check out the untrusted PR head into the workspace root under a privileged trigger (pull_request_target/workflow_run) \u2014 check out the base ref, or isolate the head in a subdir (--add-dir). Add an actor gate and scope the agent tools." : head === "root" ? "This runs under `pull_request` (fork PRs get a read-only token), so the head checkout is low-risk today \u2014 keep it on `pull_request` (not `pull_request_target`) and keep the actor gate + scoped tools." : "Add/verify an actor gate, scope the agent tools to read-only, and env-deny secrets. See Anthropic\u2019s claude-code-action security doc."
|
|
@@ -53783,7 +54092,7 @@ function evalAgentJob(job, wf, raw, untrustedTrigger, reusable) {
|
|
|
53783
54092
|
if (reusable && !loadedGun && SEVERITY_RANK2[severity] > SEVERITY_RANK2.medium) severity = "medium";
|
|
53784
54093
|
return { severity, secrets, injectable, canReadEnv };
|
|
53785
54094
|
}
|
|
53786
|
-
function analyzeWorkflowSecrets(
|
|
54095
|
+
function analyzeWorkflowSecrets(path71, content) {
|
|
53787
54096
|
let raw;
|
|
53788
54097
|
try {
|
|
53789
54098
|
raw = parseYaml(content) ?? {};
|
|
@@ -53803,7 +54112,7 @@ function analyzeWorkflowSecrets(path70, content) {
|
|
|
53803
54112
|
dimension: "data",
|
|
53804
54113
|
severity: worst.severity,
|
|
53805
54114
|
title: worst.severity === "advisory" ? "Secrets reachable by the agent \u2014 hardening" : "Exfiltratable secrets reachable by an injectable agent",
|
|
53806
|
-
file:
|
|
54115
|
+
file: path71,
|
|
53807
54116
|
signals: [
|
|
53808
54117
|
`agent can reach: ${worst.secrets.map((s) => s.name).join(", ")}`,
|
|
53809
54118
|
worst.injectable ? "the agent is externally triggerable (untrusted trigger, no gate)" : "gated / not externally triggerable \u2014 latent risk only",
|
|
@@ -53830,7 +54139,7 @@ function hookCommands(hooks) {
|
|
|
53830
54139
|
}
|
|
53831
54140
|
return out;
|
|
53832
54141
|
}
|
|
53833
|
-
function analyzeAgentConfig(
|
|
54142
|
+
function analyzeAgentConfig(path71, content) {
|
|
53834
54143
|
let cfg;
|
|
53835
54144
|
try {
|
|
53836
54145
|
cfg = JSON.parse(content);
|
|
@@ -53849,7 +54158,7 @@ function analyzeAgentConfig(path70, content) {
|
|
|
53849
54158
|
dimension: "toolRules",
|
|
53850
54159
|
severity: high ? "high" : "medium",
|
|
53851
54160
|
title: high ? "Agent hook runs UNPINNED/remote third-party code on every action" : "Agent hook runs third-party code in the agent hot path",
|
|
53852
|
-
file:
|
|
54161
|
+
file: path71,
|
|
53853
54162
|
signals: [
|
|
53854
54163
|
`hook command: \`${cmd.slice(0, 120)}\``,
|
|
53855
54164
|
remoteExec ? "fetch-and-run (curl|wget / pipe-to-shell) \u2014 unpinnable remote code execution on every contributor" : unpinned ? "unpinned \u2014 a compromised/yanked package = code execution on every contributor" : "pinned, but still a standing supply-chain dependency in the agent hot path"
|
|
@@ -53869,7 +54178,7 @@ function analyzeAgentConfig(path70, content) {
|
|
|
53869
54178
|
dimension: "toolRules",
|
|
53870
54179
|
severity: hasBackstop ? "medium" : "high",
|
|
53871
54180
|
title: hasBackstop ? "Committed agent config pre-authorizes broad tools" : "Committed agent config pre-authorizes broad tools with no deny backstop",
|
|
53872
|
-
file:
|
|
54181
|
+
file: path71,
|
|
53873
54182
|
signals: [
|
|
53874
54183
|
`broad allow(s): ${broad.slice(0, 5).join(", ")}`,
|
|
53875
54184
|
hasBackstop ? "a `deny` list backstops the broad allow" : "no `deny` entry covers Bash/Write/Edit \u2014 every contributor is pre-authorized for catastrophic tools"
|
|
@@ -53882,16 +54191,16 @@ function analyzeAgentConfig(path70, content) {
|
|
|
53882
54191
|
|
|
53883
54192
|
// src/ci-check/mcp.ts
|
|
53884
54193
|
init_dist();
|
|
53885
|
-
function analyzeMcp(
|
|
54194
|
+
function analyzeMcp(path71, content) {
|
|
53886
54195
|
let cfg;
|
|
53887
54196
|
try {
|
|
53888
54197
|
cfg = JSON.parse(content);
|
|
53889
54198
|
} catch {
|
|
53890
54199
|
return [];
|
|
53891
54200
|
}
|
|
53892
|
-
return analyzeMcpServers(cfg.mcpServers ?? {},
|
|
54201
|
+
return analyzeMcpServers(cfg.mcpServers ?? {}, path71);
|
|
53893
54202
|
}
|
|
53894
|
-
function analyzeMcpServers(servers,
|
|
54203
|
+
function analyzeMcpServers(servers, path71) {
|
|
53895
54204
|
const findings = [];
|
|
53896
54205
|
for (const [name, srv] of Object.entries(servers ?? {})) {
|
|
53897
54206
|
if (!srv || srv.disabled) continue;
|
|
@@ -53902,7 +54211,7 @@ function analyzeMcpServers(servers, path70) {
|
|
|
53902
54211
|
dimension: "mcp",
|
|
53903
54212
|
severity: "medium",
|
|
53904
54213
|
title: `MCP server "${name}" runs an unpinned executable`,
|
|
53905
|
-
file:
|
|
54214
|
+
file: path71,
|
|
53906
54215
|
signals: [`\`${argv.slice(0, 120)}\` \u2014 unversioned/@latest npx`],
|
|
53907
54216
|
fix: "Pin the MCP server package to an exact version so a PR (or a registry compromise) can\u2019t swap the toolchain."
|
|
53908
54217
|
});
|
|
@@ -53916,7 +54225,7 @@ function analyzeMcpServers(servers, path70) {
|
|
|
53916
54225
|
dimension: "mcp",
|
|
53917
54226
|
severity: "high",
|
|
53918
54227
|
title: `MCP server "${name}" has an inline credential`,
|
|
53919
|
-
file:
|
|
54228
|
+
file: path71,
|
|
53920
54229
|
signals: [
|
|
53921
54230
|
`env.${k} matches ${hit.patternName} \u2014 agent-reachable secret committed to the repo`
|
|
53922
54231
|
],
|
|
@@ -53930,7 +54239,7 @@ function analyzeMcpServers(servers, path70) {
|
|
|
53930
54239
|
|
|
53931
54240
|
// src/ci-check/codex.ts
|
|
53932
54241
|
import { parse as parseToml5 } from "smol-toml";
|
|
53933
|
-
function analyzeCodexConfig(
|
|
54242
|
+
function analyzeCodexConfig(path71, content) {
|
|
53934
54243
|
let cfg;
|
|
53935
54244
|
try {
|
|
53936
54245
|
cfg = parseToml5(content);
|
|
@@ -53938,7 +54247,7 @@ function analyzeCodexConfig(path70, content) {
|
|
|
53938
54247
|
return [];
|
|
53939
54248
|
}
|
|
53940
54249
|
const findings = [];
|
|
53941
|
-
findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {},
|
|
54250
|
+
findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {}, path71));
|
|
53942
54251
|
const sandbox = typeof cfg.sandbox_mode === "string" ? cfg.sandbox_mode : "";
|
|
53943
54252
|
const approval = typeof cfg.approval_policy === "string" ? cfg.approval_policy : "";
|
|
53944
54253
|
const fullAccess = /danger-full-access/i.test(sandbox);
|
|
@@ -53953,7 +54262,7 @@ function analyzeCodexConfig(path70, content) {
|
|
|
53953
54262
|
dimension: "toolRules",
|
|
53954
54263
|
severity: fullAccess ? "high" : "medium",
|
|
53955
54264
|
title: fullAccess ? "Codex config grants a full-access sandbox" : "Codex config never requires approval",
|
|
53956
|
-
file:
|
|
54265
|
+
file: path71,
|
|
53957
54266
|
signals,
|
|
53958
54267
|
fix: 'Commit a least-privilege Codex config: prefer `sandbox_mode = "read-only"` (or `"workspace-write"`) and `approval_policy = "on-request"`/`"on-failure"`. A repo-committed config applies to every contributor who runs Codex here.'
|
|
53959
54268
|
});
|
|
@@ -54009,10 +54318,10 @@ function decodeSuspiciousBase64(text) {
|
|
|
54009
54318
|
}
|
|
54010
54319
|
return out;
|
|
54011
54320
|
}
|
|
54012
|
-
function mk(severity, title, signals, fix,
|
|
54013
|
-
return { check: "CI-6", dimension: "instructions", severity, title, file:
|
|
54321
|
+
function mk(severity, title, signals, fix, path71) {
|
|
54322
|
+
return { check: "CI-6", dimension: "instructions", severity, title, file: path71, signals, fix };
|
|
54014
54323
|
}
|
|
54015
|
-
function analyzeInstructionFile(
|
|
54324
|
+
function analyzeInstructionFile(path71, content) {
|
|
54016
54325
|
const findings = [];
|
|
54017
54326
|
const decoded = decodeSuspiciousBase64(content);
|
|
54018
54327
|
if (TAG_CHARS.test(content))
|
|
@@ -54024,7 +54333,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
54024
54333
|
"contains Unicode tag characters (U+E0000\u2013E007F) \u2014 an invisible instruction-smuggling channel with no legitimate use in text"
|
|
54025
54334
|
],
|
|
54026
54335
|
"Remove the tag characters. Instruction files must be plain, reviewable text.",
|
|
54027
|
-
|
|
54336
|
+
path71
|
|
54028
54337
|
)
|
|
54029
54338
|
);
|
|
54030
54339
|
if (BIDI_OVERRIDE.test(content))
|
|
@@ -54036,7 +54345,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
54036
54345
|
"contains a bidi override (U+202D/U+202E) \u2014 a Trojan-Source technique that visually reorders text so a human reads something different from what the agent parses"
|
|
54037
54346
|
],
|
|
54038
54347
|
"Remove the bidi override characters.",
|
|
54039
|
-
|
|
54348
|
+
path71
|
|
54040
54349
|
)
|
|
54041
54350
|
);
|
|
54042
54351
|
else if (BIDI_EMBED_ISOLATE.test(content))
|
|
@@ -54048,7 +54357,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
54048
54357
|
"contains bidi embed/isolate characters (U+202A\u2013202C / U+2066\u20132069) \u2014 legitimate in right-to-left text, but confirm they are not being used to hide or reorder instructions"
|
|
54049
54358
|
],
|
|
54050
54359
|
"Confirm the bidi marks are legitimate RTL formatting; remove otherwise.",
|
|
54051
|
-
|
|
54360
|
+
path71
|
|
54052
54361
|
)
|
|
54053
54362
|
);
|
|
54054
54363
|
const zw = suspiciousZeroWidth(content);
|
|
@@ -54062,7 +54371,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
54062
54371
|
revealed ? "a zero-width character conceals a prompt-override directive that only appears once the hidden characters are stripped" : "a zero-width character splits a visible Latin word \u2014 a concealment technique (hides text from human review while the agent reads it as contiguous)"
|
|
54063
54372
|
],
|
|
54064
54373
|
"Remove the zero-width characters. Instruction files must be plain, reviewable text.",
|
|
54065
|
-
|
|
54374
|
+
path71
|
|
54066
54375
|
)
|
|
54067
54376
|
);
|
|
54068
54377
|
}
|
|
@@ -54078,7 +54387,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
54078
54387
|
`contains a prompt-override / role-impersonation directive (\`${m[0].slice(0, 60).trim()}\`)${ovEnc ? " \u2014 concealed in a base64 blob" : ""}`
|
|
54079
54388
|
],
|
|
54080
54389
|
"Remove the override text. An instruction file should not tell the agent to ignore its own rules.",
|
|
54081
|
-
|
|
54390
|
+
path71
|
|
54082
54391
|
)
|
|
54083
54392
|
);
|
|
54084
54393
|
}
|
|
@@ -54090,7 +54399,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
54090
54399
|
"Instruction directs the agent to fetch and run remote code",
|
|
54091
54400
|
[`\`${fo[0].slice(0, 70).trim()}\` \u2014 fetch-and-obey, outside an install/setup section`],
|
|
54092
54401
|
"Do not instruct the agent to pipe remote content into a shell; pin and vendor scripts instead.",
|
|
54093
|
-
|
|
54402
|
+
path71
|
|
54094
54403
|
)
|
|
54095
54404
|
);
|
|
54096
54405
|
}
|
|
@@ -54102,7 +54411,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
54102
54411
|
"Instruction points the agent at credential material",
|
|
54103
54412
|
[`references \`${sp[0].slice(0, 50).trim()}\` \u2014 directs the agent toward secrets`],
|
|
54104
54413
|
"Do not reference credential files or paths in agent instructions.",
|
|
54105
|
-
|
|
54414
|
+
path71
|
|
54106
54415
|
)
|
|
54107
54416
|
);
|
|
54108
54417
|
}
|
|
@@ -54114,7 +54423,7 @@ function analyzeInstructionFile(path70, content) {
|
|
|
54114
54423
|
"Instruction directs the agent to send data to an external endpoint",
|
|
54115
54424
|
[`\`${ex[0].slice(0, 70).trim()}\` \u2014 possible exfiltration directive`],
|
|
54116
54425
|
"Remove external post/upload directives from agent instructions.",
|
|
54117
|
-
|
|
54426
|
+
path71
|
|
54118
54427
|
)
|
|
54119
54428
|
);
|
|
54120
54429
|
}
|
|
@@ -54416,17 +54725,17 @@ import chalk32 from "chalk";
|
|
|
54416
54725
|
// src/shields/jail.ts
|
|
54417
54726
|
init_build();
|
|
54418
54727
|
init_shields();
|
|
54419
|
-
import
|
|
54420
|
-
import
|
|
54421
|
-
import
|
|
54728
|
+
import fs62 from "fs";
|
|
54729
|
+
import os54 from "os";
|
|
54730
|
+
import path59 from "path";
|
|
54422
54731
|
var USER_JAIL_SHIELD = "user-jail";
|
|
54423
54732
|
function jailStorePath() {
|
|
54424
|
-
return
|
|
54733
|
+
return path59.join(os54.homedir(), ".node9", "jail-paths.json");
|
|
54425
54734
|
}
|
|
54426
54735
|
function readJailPaths() {
|
|
54427
54736
|
let text;
|
|
54428
54737
|
try {
|
|
54429
|
-
text =
|
|
54738
|
+
text = fs62.readFileSync(jailStorePath(), "utf8");
|
|
54430
54739
|
} catch (err2) {
|
|
54431
54740
|
if (err2.code === "ENOENT") return [];
|
|
54432
54741
|
throw err2;
|
|
@@ -54444,8 +54753,8 @@ function readJailPaths() {
|
|
|
54444
54753
|
}
|
|
54445
54754
|
function writeJailPaths(paths) {
|
|
54446
54755
|
const p = jailStorePath();
|
|
54447
|
-
|
|
54448
|
-
|
|
54756
|
+
fs62.mkdirSync(path59.dirname(p), { recursive: true });
|
|
54757
|
+
fs62.writeFileSync(p, JSON.stringify({ paths }, null, 2) + "\n", { mode: 384 });
|
|
54449
54758
|
}
|
|
54450
54759
|
function addJailPath(rawPath, verdict) {
|
|
54451
54760
|
const norm = rawPath.trim();
|
|
@@ -54467,14 +54776,14 @@ function removeJailPath(rawPath) {
|
|
|
54467
54776
|
return { removed, paths: after };
|
|
54468
54777
|
}
|
|
54469
54778
|
function regenerateUserJail(paths) {
|
|
54470
|
-
const file =
|
|
54779
|
+
const file = path59.join(USER_SHIELDS_DIR_PATH, `${USER_JAIL_SHIELD}.json`);
|
|
54471
54780
|
if (paths.length === 0) {
|
|
54472
54781
|
const active2 = readActiveShields();
|
|
54473
54782
|
if (active2.includes(USER_JAIL_SHIELD)) {
|
|
54474
54783
|
writeActiveShields(active2.filter((s) => s !== USER_JAIL_SHIELD));
|
|
54475
54784
|
}
|
|
54476
54785
|
try {
|
|
54477
|
-
|
|
54786
|
+
fs62.rmSync(file, { force: true });
|
|
54478
54787
|
} catch {
|
|
54479
54788
|
}
|
|
54480
54789
|
return;
|
|
@@ -54589,13 +54898,13 @@ function registerJailCommand(program2) {
|
|
|
54589
54898
|
// src/cli/commands/sandbox.ts
|
|
54590
54899
|
init_config();
|
|
54591
54900
|
import chalk33 from "chalk";
|
|
54592
|
-
import
|
|
54593
|
-
import
|
|
54901
|
+
import fs65 from "fs";
|
|
54902
|
+
import path62 from "path";
|
|
54594
54903
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
54595
54904
|
|
|
54596
54905
|
// src/sandbox/config.ts
|
|
54597
|
-
import
|
|
54598
|
-
import
|
|
54906
|
+
import fs63 from "fs";
|
|
54907
|
+
import path60 from "path";
|
|
54599
54908
|
import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
|
|
54600
54909
|
var SANDBOX_CONFIG_FILE = "node9.sandbox.yaml";
|
|
54601
54910
|
var FORBIDDEN_ENV = /* @__PURE__ */ new Set(["NODE9_API_KEY", "NODE9_API_URL"]);
|
|
@@ -54668,16 +54977,16 @@ function scaffoldSandboxYaml(agent) {
|
|
|
54668
54977
|
return header + stringifyYaml(defaultSandboxConfig(agent));
|
|
54669
54978
|
}
|
|
54670
54979
|
function sandboxConfigPath(cwd = process.cwd()) {
|
|
54671
|
-
return
|
|
54980
|
+
return path60.join(cwd, SANDBOX_CONFIG_FILE);
|
|
54672
54981
|
}
|
|
54673
54982
|
function loadSandboxConfig(cwd = process.cwd(), fallbackAgent = "claude") {
|
|
54674
54983
|
const p = sandboxConfigPath(cwd);
|
|
54675
|
-
if (!
|
|
54984
|
+
if (!fs63.existsSync(p)) {
|
|
54676
54985
|
throw new Error(`sandbox: ${SANDBOX_CONFIG_FILE} not found \u2014 run \`node9 sandbox new\` first.`);
|
|
54677
54986
|
}
|
|
54678
54987
|
let raw;
|
|
54679
54988
|
try {
|
|
54680
|
-
raw = parseYaml2(
|
|
54989
|
+
raw = parseYaml2(fs63.readFileSync(p, "utf-8"));
|
|
54681
54990
|
} catch (err2) {
|
|
54682
54991
|
throw new Error(
|
|
54683
54992
|
`sandbox: ${SANDBOX_CONFIG_FILE} is not valid YAML \u2014 ${err2.message}`
|
|
@@ -54736,13 +55045,13 @@ init_templates();
|
|
|
54736
55045
|
|
|
54737
55046
|
// src/sandbox/runtime.ts
|
|
54738
55047
|
init_templates();
|
|
54739
|
-
import
|
|
54740
|
-
import
|
|
54741
|
-
import
|
|
55048
|
+
import fs64 from "fs";
|
|
55049
|
+
import os55 from "os";
|
|
55050
|
+
import path61 from "path";
|
|
54742
55051
|
import crypto9 from "crypto";
|
|
54743
55052
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
54744
55053
|
function sandboxDataDir(cwd = process.cwd()) {
|
|
54745
|
-
return
|
|
55054
|
+
return path61.join(cwd, ".node9", "sandbox", "data");
|
|
54746
55055
|
}
|
|
54747
55056
|
function detectEngine(engine) {
|
|
54748
55057
|
const r = spawnSync5(engine, ["--version"], { encoding: "utf-8" });
|
|
@@ -54753,7 +55062,7 @@ function detectEngine(engine) {
|
|
|
54753
55062
|
}
|
|
54754
55063
|
function agentCredentialsMount(agent) {
|
|
54755
55064
|
const rel = agent === "codex" ? ".codex/auth.json" : ".claude/.credentials.json";
|
|
54756
|
-
return { hostPath:
|
|
55065
|
+
return { hostPath: path61.join(os55.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
|
|
54757
55066
|
}
|
|
54758
55067
|
function buildRunArgs(opts) {
|
|
54759
55068
|
const { config, workspaceHostPath, dataHostPath, allowlistHostPath, agentArgs } = opts;
|
|
@@ -54763,7 +55072,7 @@ function buildRunArgs(opts) {
|
|
|
54763
55072
|
args.push("-v", `${allowlistHostPath}:${ALLOWED_DOMAINS_PATH}:ro`);
|
|
54764
55073
|
if (config.node9.mountAgentCredentials) {
|
|
54765
55074
|
const creds = agentCredentialsMount(config.agent);
|
|
54766
|
-
if (
|
|
55075
|
+
if (fs64.existsSync(creds.hostPath)) {
|
|
54767
55076
|
args.push("-v", `${creds.hostPath}:${creds.target}`);
|
|
54768
55077
|
}
|
|
54769
55078
|
}
|
|
@@ -54781,30 +55090,30 @@ function imageContentHash(dockerfile, entrypoint) {
|
|
|
54781
55090
|
return crypto9.createHash("sha256").update(dockerfile).update("\0").update(entrypoint).digest("hex").slice(0, 16);
|
|
54782
55091
|
}
|
|
54783
55092
|
function sandboxBuildDir(cwd = process.cwd()) {
|
|
54784
|
-
return
|
|
55093
|
+
return path61.join(cwd, ".node9", "sandbox", "build");
|
|
54785
55094
|
}
|
|
54786
55095
|
function writeBuildContext(cwd, dockerfile, entrypoint) {
|
|
54787
55096
|
const dir = sandboxBuildDir(cwd);
|
|
54788
|
-
|
|
54789
|
-
|
|
54790
|
-
|
|
55097
|
+
fs64.mkdirSync(dir, { recursive: true });
|
|
55098
|
+
fs64.writeFileSync(path61.join(dir, "Dockerfile"), dockerfile);
|
|
55099
|
+
fs64.writeFileSync(path61.join(dir, "entrypoint.sh"), entrypoint);
|
|
54791
55100
|
return dir;
|
|
54792
55101
|
}
|
|
54793
55102
|
function writeAllowlist(cwd, hosts) {
|
|
54794
|
-
const dir =
|
|
54795
|
-
|
|
54796
|
-
const p =
|
|
54797
|
-
|
|
55103
|
+
const dir = path61.join(cwd, ".node9", "sandbox");
|
|
55104
|
+
fs64.mkdirSync(dir, { recursive: true });
|
|
55105
|
+
const p = path61.join(dir, "allowed-domains.txt");
|
|
55106
|
+
fs64.writeFileSync(p, hosts.join("\n") + "\n");
|
|
54798
55107
|
return p;
|
|
54799
55108
|
}
|
|
54800
55109
|
function resolveHomePath(p) {
|
|
54801
|
-
return p.startsWith("~") ?
|
|
55110
|
+
return p.startsWith("~") ? path61.join(os55.homedir(), p.slice(1)) : path61.resolve(p);
|
|
54802
55111
|
}
|
|
54803
55112
|
|
|
54804
55113
|
// src/cli/commands/sandbox.ts
|
|
54805
55114
|
function seedDataDirConfig(dataDir, sandbox) {
|
|
54806
|
-
|
|
54807
|
-
const configPath =
|
|
55115
|
+
fs65.mkdirSync(dataDir, { recursive: true });
|
|
55116
|
+
const configPath = path62.join(dataDir, "config.json");
|
|
54808
55117
|
const seed = {
|
|
54809
55118
|
settings: {
|
|
54810
55119
|
approvers: {
|
|
@@ -54815,7 +55124,7 @@ function seedDataDirConfig(dataDir, sandbox) {
|
|
|
54815
55124
|
}
|
|
54816
55125
|
}
|
|
54817
55126
|
};
|
|
54818
|
-
|
|
55127
|
+
fs65.writeFileSync(configPath, JSON.stringify(seed, null, 2), { mode: 384 });
|
|
54819
55128
|
}
|
|
54820
55129
|
function registerSandboxCommand(program2, version2) {
|
|
54821
55130
|
const node9Version2 = pinnedNode9Version(version2);
|
|
@@ -54823,13 +55132,13 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54823
55132
|
cmd.command("new").description(`Scaffold ${SANDBOX_CONFIG_FILE} in this project`).option("--agent <agent>", "claude (default) or codex", "claude").action((opts) => {
|
|
54824
55133
|
const agent = opts.agent === "codex" ? "codex" : "claude";
|
|
54825
55134
|
const p = sandboxConfigPath();
|
|
54826
|
-
if (
|
|
55135
|
+
if (fs65.existsSync(p)) {
|
|
54827
55136
|
console.log(
|
|
54828
55137
|
chalk33.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
|
|
54829
55138
|
);
|
|
54830
55139
|
return;
|
|
54831
55140
|
}
|
|
54832
|
-
|
|
55141
|
+
fs65.writeFileSync(p, scaffoldSandboxYaml(agent));
|
|
54833
55142
|
console.log(
|
|
54834
55143
|
chalk33.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + chalk33.dim(` (agent: ${agent})`)
|
|
54835
55144
|
);
|
|
@@ -54869,8 +55178,8 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54869
55178
|
const buildDir = writeBuildContext(cwd, dockerfile, entrypoint);
|
|
54870
55179
|
const hash = imageContentHash(dockerfile, entrypoint);
|
|
54871
55180
|
const image = sandbox.runtime.image;
|
|
54872
|
-
const hashFile =
|
|
54873
|
-
const lastHash =
|
|
55181
|
+
const hashFile = path62.join(sandboxBuildDir(cwd), ".image-hash");
|
|
55182
|
+
const lastHash = fs65.existsSync(hashFile) ? fs65.readFileSync(hashFile, "utf-8").trim() : "";
|
|
54874
55183
|
const imageExists = spawnSync6(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
|
|
54875
55184
|
const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
|
|
54876
55185
|
if (needBuild) {
|
|
@@ -54882,7 +55191,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54882
55191
|
console.error(chalk33.red(" build failed."));
|
|
54883
55192
|
process.exit(b.status ?? 1);
|
|
54884
55193
|
}
|
|
54885
|
-
|
|
55194
|
+
fs65.writeFileSync(hashFile, hash);
|
|
54886
55195
|
}
|
|
54887
55196
|
const dataDir = sandboxDataDir(cwd);
|
|
54888
55197
|
seedDataDirConfig(dataDir, sandbox);
|
|
@@ -54896,7 +55205,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54896
55205
|
});
|
|
54897
55206
|
if (sandbox.node9.mountAgentCredentials) {
|
|
54898
55207
|
const creds = agentCredentialsMount(sandbox.agent);
|
|
54899
|
-
if (
|
|
55208
|
+
if (fs65.existsSync(creds.hostPath)) {
|
|
54900
55209
|
console.log(chalk33.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
|
|
54901
55210
|
} else {
|
|
54902
55211
|
console.log(
|
|
@@ -54912,20 +55221,20 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54912
55221
|
process.exit(r.status ?? 0);
|
|
54913
55222
|
});
|
|
54914
55223
|
cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
|
|
54915
|
-
const auditPath =
|
|
54916
|
-
if (!
|
|
55224
|
+
const auditPath = path62.join(sandboxDataDir(), "audit.log");
|
|
55225
|
+
if (!fs65.existsSync(auditPath)) {
|
|
54917
55226
|
console.log(chalk33.dim(" no sandbox audit yet."));
|
|
54918
55227
|
return;
|
|
54919
55228
|
}
|
|
54920
55229
|
spawnSync6("tail", ["-f", auditPath], { stdio: "inherit" });
|
|
54921
55230
|
});
|
|
54922
55231
|
cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
|
|
54923
|
-
const auditPath =
|
|
54924
|
-
if (!
|
|
55232
|
+
const auditPath = path62.join(sandboxDataDir(), "audit.log");
|
|
55233
|
+
if (!fs65.existsSync(auditPath)) {
|
|
54925
55234
|
console.log(chalk33.dim(" no sandbox audit yet."));
|
|
54926
55235
|
return;
|
|
54927
55236
|
}
|
|
54928
|
-
process.stdout.write(
|
|
55237
|
+
process.stdout.write(fs65.readFileSync(auditPath, "utf-8"));
|
|
54929
55238
|
});
|
|
54930
55239
|
cmd.command("clean").description("Remove the sandbox image, build context, and data").action(() => {
|
|
54931
55240
|
const cwd = process.cwd();
|
|
@@ -54939,7 +55248,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
54939
55248
|
stdio: "ignore"
|
|
54940
55249
|
});
|
|
54941
55250
|
}
|
|
54942
|
-
|
|
55251
|
+
fs65.rmSync(path62.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
|
|
54943
55252
|
console.log(chalk33.green(" \u2713 sandbox image + build + data removed."));
|
|
54944
55253
|
});
|
|
54945
55254
|
}
|
|
@@ -54950,9 +55259,9 @@ init_litellm();
|
|
|
54950
55259
|
init_cost_gemini();
|
|
54951
55260
|
init_cost_codex();
|
|
54952
55261
|
import chalk34 from "chalk";
|
|
54953
|
-
import
|
|
54954
|
-
import
|
|
54955
|
-
import
|
|
55262
|
+
import fs66 from "fs";
|
|
55263
|
+
import path63 from "path";
|
|
55264
|
+
import os56 from "os";
|
|
54956
55265
|
function modelPrice(model) {
|
|
54957
55266
|
const t = pricingFor(model);
|
|
54958
55267
|
if (!t) return null;
|
|
@@ -54969,10 +55278,10 @@ function encodeProjectPath(projectPath) {
|
|
|
54969
55278
|
}
|
|
54970
55279
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
54971
55280
|
const encoded = encodeProjectPath(projectPath);
|
|
54972
|
-
return
|
|
55281
|
+
return path63.join(os56.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
54973
55282
|
}
|
|
54974
55283
|
function projectLabel(projectPath) {
|
|
54975
|
-
return projectPath.replace(
|
|
55284
|
+
return projectPath.replace(os56.homedir(), "~");
|
|
54976
55285
|
}
|
|
54977
55286
|
function parseHistoryLines(lines) {
|
|
54978
55287
|
const entries = [];
|
|
@@ -55041,10 +55350,10 @@ function parseSessionLines(lines) {
|
|
|
55041
55350
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
55042
55351
|
}
|
|
55043
55352
|
function loadAuditEntries(auditPath) {
|
|
55044
|
-
const aPath = auditPath ??
|
|
55353
|
+
const aPath = auditPath ?? path63.join(os56.homedir(), ".node9", "audit.log");
|
|
55045
55354
|
let raw;
|
|
55046
55355
|
try {
|
|
55047
|
-
raw =
|
|
55356
|
+
raw = fs66.readFileSync(aPath, "utf-8");
|
|
55048
55357
|
} catch {
|
|
55049
55358
|
return [];
|
|
55050
55359
|
}
|
|
@@ -55080,8 +55389,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
55080
55389
|
return result;
|
|
55081
55390
|
}
|
|
55082
55391
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
55083
|
-
const tmpDir =
|
|
55084
|
-
if (!
|
|
55392
|
+
const tmpDir = path63.join(os56.homedir(), ".gemini", "tmp");
|
|
55393
|
+
if (!fs66.existsSync(tmpDir)) return [];
|
|
55085
55394
|
const cutoff = days !== null ? (() => {
|
|
55086
55395
|
const d = /* @__PURE__ */ new Date();
|
|
55087
55396
|
d.setDate(d.getDate() - days);
|
|
@@ -55090,35 +55399,35 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
55090
55399
|
})() : null;
|
|
55091
55400
|
let slugDirs;
|
|
55092
55401
|
try {
|
|
55093
|
-
slugDirs =
|
|
55402
|
+
slugDirs = fs66.readdirSync(tmpDir);
|
|
55094
55403
|
} catch {
|
|
55095
55404
|
return [];
|
|
55096
55405
|
}
|
|
55097
55406
|
const summaries = [];
|
|
55098
55407
|
for (const slug2 of slugDirs) {
|
|
55099
|
-
const slugPath =
|
|
55408
|
+
const slugPath = path63.join(tmpDir, slug2);
|
|
55100
55409
|
try {
|
|
55101
|
-
if (!
|
|
55410
|
+
if (!fs66.statSync(slugPath).isDirectory()) continue;
|
|
55102
55411
|
} catch {
|
|
55103
55412
|
continue;
|
|
55104
55413
|
}
|
|
55105
|
-
let projectRoot =
|
|
55414
|
+
let projectRoot = path63.join(os56.homedir(), slug2);
|
|
55106
55415
|
try {
|
|
55107
|
-
projectRoot =
|
|
55416
|
+
projectRoot = fs66.readFileSync(path63.join(slugPath, ".project_root"), "utf-8").trim();
|
|
55108
55417
|
} catch {
|
|
55109
55418
|
}
|
|
55110
|
-
const chatsDir =
|
|
55111
|
-
if (!
|
|
55419
|
+
const chatsDir = path63.join(slugPath, "chats");
|
|
55420
|
+
if (!fs66.existsSync(chatsDir)) continue;
|
|
55112
55421
|
let chatFiles;
|
|
55113
55422
|
try {
|
|
55114
|
-
chatFiles =
|
|
55423
|
+
chatFiles = fs66.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
55115
55424
|
} catch {
|
|
55116
55425
|
continue;
|
|
55117
55426
|
}
|
|
55118
55427
|
for (const chatFile of chatFiles) {
|
|
55119
55428
|
let raw;
|
|
55120
55429
|
try {
|
|
55121
|
-
raw =
|
|
55430
|
+
raw = fs66.readFileSync(path63.join(chatsDir, chatFile), "utf-8");
|
|
55122
55431
|
} catch {
|
|
55123
55432
|
continue;
|
|
55124
55433
|
}
|
|
@@ -55198,8 +55507,8 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
55198
55507
|
return summaries;
|
|
55199
55508
|
}
|
|
55200
55509
|
function buildCodexSessions(days, allAuditEntries) {
|
|
55201
|
-
const sessionsBase =
|
|
55202
|
-
if (!
|
|
55510
|
+
const sessionsBase = path63.join(os56.homedir(), ".codex", "sessions");
|
|
55511
|
+
if (!fs66.existsSync(sessionsBase)) return [];
|
|
55203
55512
|
const cutoff = days !== null ? (() => {
|
|
55204
55513
|
const d = /* @__PURE__ */ new Date();
|
|
55205
55514
|
d.setDate(d.getDate() - days);
|
|
@@ -55208,29 +55517,29 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
55208
55517
|
})() : null;
|
|
55209
55518
|
const jsonlFiles = [];
|
|
55210
55519
|
try {
|
|
55211
|
-
for (const year of
|
|
55212
|
-
const yearPath =
|
|
55520
|
+
for (const year of fs66.readdirSync(sessionsBase)) {
|
|
55521
|
+
const yearPath = path63.join(sessionsBase, year);
|
|
55213
55522
|
try {
|
|
55214
|
-
if (!
|
|
55523
|
+
if (!fs66.statSync(yearPath).isDirectory()) continue;
|
|
55215
55524
|
} catch {
|
|
55216
55525
|
continue;
|
|
55217
55526
|
}
|
|
55218
|
-
for (const month of
|
|
55219
|
-
const monthPath =
|
|
55527
|
+
for (const month of fs66.readdirSync(yearPath)) {
|
|
55528
|
+
const monthPath = path63.join(yearPath, month);
|
|
55220
55529
|
try {
|
|
55221
|
-
if (!
|
|
55530
|
+
if (!fs66.statSync(monthPath).isDirectory()) continue;
|
|
55222
55531
|
} catch {
|
|
55223
55532
|
continue;
|
|
55224
55533
|
}
|
|
55225
|
-
for (const day of
|
|
55226
|
-
const dayPath =
|
|
55534
|
+
for (const day of fs66.readdirSync(monthPath)) {
|
|
55535
|
+
const dayPath = path63.join(monthPath, day);
|
|
55227
55536
|
try {
|
|
55228
|
-
if (!
|
|
55537
|
+
if (!fs66.statSync(dayPath).isDirectory()) continue;
|
|
55229
55538
|
} catch {
|
|
55230
55539
|
continue;
|
|
55231
55540
|
}
|
|
55232
|
-
for (const file of
|
|
55233
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
55541
|
+
for (const file of fs66.readdirSync(dayPath)) {
|
|
55542
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path63.join(dayPath, file));
|
|
55234
55543
|
}
|
|
55235
55544
|
}
|
|
55236
55545
|
}
|
|
@@ -55242,7 +55551,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
55242
55551
|
for (const filePath of jsonlFiles) {
|
|
55243
55552
|
let lines;
|
|
55244
55553
|
try {
|
|
55245
|
-
lines =
|
|
55554
|
+
lines = fs66.readFileSync(filePath, "utf-8").split("\n");
|
|
55246
55555
|
} catch {
|
|
55247
55556
|
continue;
|
|
55248
55557
|
}
|
|
@@ -55328,10 +55637,10 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
55328
55637
|
return summaries;
|
|
55329
55638
|
}
|
|
55330
55639
|
function buildSessions(days, historyPath) {
|
|
55331
|
-
const hPath = historyPath ??
|
|
55640
|
+
const hPath = historyPath ?? path63.join(os56.homedir(), ".claude", "history.jsonl");
|
|
55332
55641
|
let historyRaw = "";
|
|
55333
55642
|
try {
|
|
55334
|
-
historyRaw =
|
|
55643
|
+
historyRaw = fs66.readFileSync(hPath, "utf-8");
|
|
55335
55644
|
} catch {
|
|
55336
55645
|
}
|
|
55337
55646
|
const cutoff = days !== null ? (() => {
|
|
@@ -55355,7 +55664,7 @@ function buildSessions(days, historyPath) {
|
|
|
55355
55664
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
55356
55665
|
let sessionLines = [];
|
|
55357
55666
|
try {
|
|
55358
|
-
sessionLines =
|
|
55667
|
+
sessionLines = fs66.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
55359
55668
|
} catch {
|
|
55360
55669
|
}
|
|
55361
55670
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -55749,12 +56058,12 @@ function registerSessionTaintCommand(program2) {
|
|
|
55749
56058
|
|
|
55750
56059
|
// src/cli/commands/skill-pin.ts
|
|
55751
56060
|
import chalk36 from "chalk";
|
|
55752
|
-
import
|
|
55753
|
-
import
|
|
55754
|
-
import
|
|
56061
|
+
import fs67 from "fs";
|
|
56062
|
+
import os57 from "os";
|
|
56063
|
+
import path64 from "path";
|
|
55755
56064
|
function wipeSkillSessions() {
|
|
55756
56065
|
try {
|
|
55757
|
-
|
|
56066
|
+
fs67.rmSync(path64.join(os57.homedir(), ".node9", "skill-sessions"), {
|
|
55758
56067
|
recursive: true,
|
|
55759
56068
|
force: true
|
|
55760
56069
|
});
|
|
@@ -55836,15 +56145,15 @@ function registerSkillPinCommand(program2) {
|
|
|
55836
56145
|
}
|
|
55837
56146
|
|
|
55838
56147
|
// src/cli/commands/decisions.ts
|
|
55839
|
-
import
|
|
55840
|
-
import
|
|
55841
|
-
import
|
|
56148
|
+
import fs68 from "fs";
|
|
56149
|
+
import os58 from "os";
|
|
56150
|
+
import path65 from "path";
|
|
55842
56151
|
import chalk37 from "chalk";
|
|
55843
|
-
var DECISIONS_FILE2 =
|
|
56152
|
+
var DECISIONS_FILE2 = path65.join(os58.homedir(), ".node9", "decisions.json");
|
|
55844
56153
|
function readDecisions() {
|
|
55845
56154
|
try {
|
|
55846
|
-
if (!
|
|
55847
|
-
const raw =
|
|
56155
|
+
if (!fs68.existsSync(DECISIONS_FILE2)) return {};
|
|
56156
|
+
const raw = fs68.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
55848
56157
|
const parsed = JSON.parse(raw);
|
|
55849
56158
|
const out = {};
|
|
55850
56159
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -55856,11 +56165,11 @@ function readDecisions() {
|
|
|
55856
56165
|
}
|
|
55857
56166
|
}
|
|
55858
56167
|
function writeDecisions(d) {
|
|
55859
|
-
const dir =
|
|
55860
|
-
if (!
|
|
56168
|
+
const dir = path65.dirname(DECISIONS_FILE2);
|
|
56169
|
+
if (!fs68.existsSync(dir)) fs68.mkdirSync(dir, { recursive: true });
|
|
55861
56170
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
55862
|
-
|
|
55863
|
-
|
|
56171
|
+
fs68.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
56172
|
+
fs68.renameSync(tmp, DECISIONS_FILE2);
|
|
55864
56173
|
}
|
|
55865
56174
|
function registerDecisionsCommand(program2) {
|
|
55866
56175
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -55917,18 +56226,18 @@ Persistent decisions (${entries.length})
|
|
|
55917
56226
|
|
|
55918
56227
|
// src/cli/commands/dlp.ts
|
|
55919
56228
|
import chalk38 from "chalk";
|
|
55920
|
-
import
|
|
55921
|
-
import
|
|
55922
|
-
import
|
|
55923
|
-
var AUDIT_LOG =
|
|
55924
|
-
var RESOLVED_FILE =
|
|
56229
|
+
import fs69 from "fs";
|
|
56230
|
+
import path66 from "path";
|
|
56231
|
+
import os59 from "os";
|
|
56232
|
+
var AUDIT_LOG = path66.join(os59.homedir(), ".node9", "audit.log");
|
|
56233
|
+
var RESOLVED_FILE = path66.join(os59.homedir(), ".node9", "dlp-resolved.json");
|
|
55925
56234
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
55926
56235
|
function stripAnsi(s) {
|
|
55927
56236
|
return s.replace(ANSI_RE, "");
|
|
55928
56237
|
}
|
|
55929
56238
|
function loadResolved() {
|
|
55930
56239
|
try {
|
|
55931
|
-
const raw = JSON.parse(
|
|
56240
|
+
const raw = JSON.parse(fs69.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
55932
56241
|
return new Set(raw);
|
|
55933
56242
|
} catch {
|
|
55934
56243
|
return /* @__PURE__ */ new Set();
|
|
@@ -55936,13 +56245,13 @@ function loadResolved() {
|
|
|
55936
56245
|
}
|
|
55937
56246
|
function saveResolved(resolved) {
|
|
55938
56247
|
try {
|
|
55939
|
-
|
|
56248
|
+
fs69.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
55940
56249
|
} catch {
|
|
55941
56250
|
}
|
|
55942
56251
|
}
|
|
55943
56252
|
function loadDlpFindings() {
|
|
55944
|
-
if (!
|
|
55945
|
-
return
|
|
56253
|
+
if (!fs69.existsSync(AUDIT_LOG)) return [];
|
|
56254
|
+
return fs69.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
55946
56255
|
if (!line.trim()) return [];
|
|
55947
56256
|
try {
|
|
55948
56257
|
const e = JSON.parse(line);
|
|
@@ -56041,14 +56350,14 @@ function registerDlpCommand(program2) {
|
|
|
56041
56350
|
// src/cli/commands/mask.ts
|
|
56042
56351
|
init_dlp();
|
|
56043
56352
|
import chalk39 from "chalk";
|
|
56044
|
-
import
|
|
56045
|
-
import
|
|
56046
|
-
import
|
|
56353
|
+
import fs70 from "fs";
|
|
56354
|
+
import path67 from "path";
|
|
56355
|
+
import os60 from "os";
|
|
56047
56356
|
function findJsonlFiles(dir) {
|
|
56048
56357
|
const results = [];
|
|
56049
|
-
if (!
|
|
56050
|
-
for (const entry of
|
|
56051
|
-
const full =
|
|
56358
|
+
if (!fs70.existsSync(dir)) return results;
|
|
56359
|
+
for (const entry of fs70.readdirSync(dir, { withFileTypes: true })) {
|
|
56360
|
+
const full = path67.join(dir, entry.name);
|
|
56052
56361
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
56053
56362
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
56054
56363
|
}
|
|
@@ -56091,7 +56400,7 @@ function redactJson(obj) {
|
|
|
56091
56400
|
function processFile(filePath, dryRun) {
|
|
56092
56401
|
let raw;
|
|
56093
56402
|
try {
|
|
56094
|
-
raw =
|
|
56403
|
+
raw = fs70.readFileSync(filePath, "utf-8");
|
|
56095
56404
|
} catch {
|
|
56096
56405
|
return { redactedLines: 0, patterns: [] };
|
|
56097
56406
|
}
|
|
@@ -56123,14 +56432,14 @@ function processFile(filePath, dryRun) {
|
|
|
56123
56432
|
}
|
|
56124
56433
|
}
|
|
56125
56434
|
if (!dryRun && redactedLines > 0) {
|
|
56126
|
-
|
|
56435
|
+
fs70.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
56127
56436
|
}
|
|
56128
56437
|
return { redactedLines, patterns };
|
|
56129
56438
|
}
|
|
56130
56439
|
function processJsonFile(filePath, dryRun) {
|
|
56131
56440
|
let raw;
|
|
56132
56441
|
try {
|
|
56133
|
-
raw =
|
|
56442
|
+
raw = fs70.readFileSync(filePath, "utf-8");
|
|
56134
56443
|
} catch {
|
|
56135
56444
|
return { redactedLines: 0, patterns: [] };
|
|
56136
56445
|
}
|
|
@@ -56143,15 +56452,15 @@ function processJsonFile(filePath, dryRun) {
|
|
|
56143
56452
|
const { value, modified, found } = redactJson(parsed);
|
|
56144
56453
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
56145
56454
|
if (!dryRun) {
|
|
56146
|
-
|
|
56455
|
+
fs70.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
56147
56456
|
}
|
|
56148
56457
|
return { redactedLines: 1, patterns: found };
|
|
56149
56458
|
}
|
|
56150
56459
|
function findJsonFiles(dir) {
|
|
56151
56460
|
const results = [];
|
|
56152
|
-
if (!
|
|
56153
|
-
for (const entry of
|
|
56154
|
-
const full =
|
|
56461
|
+
if (!fs70.existsSync(dir)) return results;
|
|
56462
|
+
for (const entry of fs70.readdirSync(dir, { withFileTypes: true })) {
|
|
56463
|
+
const full = path67.join(dir, entry.name);
|
|
56155
56464
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
56156
56465
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
56157
56466
|
}
|
|
@@ -56160,9 +56469,9 @@ function findJsonFiles(dir) {
|
|
|
56160
56469
|
function registerMaskCommand(program2) {
|
|
56161
56470
|
program2.command("mask").description("Redact plaintext secrets from local AI session history files").option("--dry-run", "show what would be redacted without making changes").option("--all", "scan all history (default: last 30 days)").action(async (options) => {
|
|
56162
56471
|
const dryRun = !!options.dryRun;
|
|
56163
|
-
const home =
|
|
56164
|
-
const claudeDir =
|
|
56165
|
-
const geminiDir =
|
|
56472
|
+
const home = os60.homedir();
|
|
56473
|
+
const claudeDir = path67.join(home, ".claude", "projects");
|
|
56474
|
+
const geminiDir = path67.join(home, ".gemini", "tmp");
|
|
56166
56475
|
const allFiles = [
|
|
56167
56476
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
56168
56477
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -56170,7 +56479,7 @@ function registerMaskCommand(program2) {
|
|
|
56170
56479
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
56171
56480
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
56172
56481
|
try {
|
|
56173
|
-
return
|
|
56482
|
+
return fs70.statSync(f.path).mtime >= cutoff;
|
|
56174
56483
|
} catch {
|
|
56175
56484
|
return false;
|
|
56176
56485
|
}
|
|
@@ -56226,7 +56535,7 @@ function registerMaskCommand(program2) {
|
|
|
56226
56535
|
// src/cli.ts
|
|
56227
56536
|
init_blast();
|
|
56228
56537
|
var { version } = JSON.parse(
|
|
56229
|
-
|
|
56538
|
+
fs73.readFileSync(path70.join(__dirname, "../package.json"), "utf-8")
|
|
56230
56539
|
);
|
|
56231
56540
|
var program = new Command();
|
|
56232
56541
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
@@ -56252,6 +56561,11 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
56252
56561
|
} else {
|
|
56253
56562
|
console.log(chalk41.green(`\u2705 Logged in \u2014 agent mode`));
|
|
56254
56563
|
console.log(chalk41.gray(` Team policy enforced for all calls via Node9 cloud.`));
|
|
56564
|
+
if (!isTestingMode()) {
|
|
56565
|
+
const healed = ensureAutostartHealthy(!!getConfig().settings.autoStartDaemon);
|
|
56566
|
+
if (healed === "repaired")
|
|
56567
|
+
console.log(chalk41.green(` \u2713 Re-enabled daemon autostart (survives reboot)`));
|
|
56568
|
+
}
|
|
56255
56569
|
}
|
|
56256
56570
|
});
|
|
56257
56571
|
program.command("signup").description("Create your node9 account / open the dashboard in your browser").option("--login", "Open the login page instead of signup").action((options) => {
|
|
@@ -56400,15 +56714,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
56400
56714
|
} catch {
|
|
56401
56715
|
}
|
|
56402
56716
|
if (options.purge) {
|
|
56403
|
-
const node9Dir =
|
|
56404
|
-
if (
|
|
56717
|
+
const node9Dir = path70.join(os63.homedir(), ".node9");
|
|
56718
|
+
if (fs73.existsSync(node9Dir)) {
|
|
56405
56719
|
const confirmed = await confirm2({
|
|
56406
56720
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
56407
56721
|
default: false
|
|
56408
56722
|
});
|
|
56409
56723
|
if (confirmed) {
|
|
56410
|
-
|
|
56411
|
-
if (
|
|
56724
|
+
fs73.rmSync(node9Dir, { recursive: true });
|
|
56725
|
+
if (fs73.existsSync(node9Dir)) {
|
|
56412
56726
|
console.error(
|
|
56413
56727
|
chalk41.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
56414
56728
|
);
|
|
@@ -56533,7 +56847,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
56533
56847
|
});
|
|
56534
56848
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
56535
56849
|
try {
|
|
56536
|
-
const dashboardPath =
|
|
56850
|
+
const dashboardPath = path70.join(__dirname, "dashboard.mjs");
|
|
56537
56851
|
const dynamicImport = new Function("id", "return import(id)");
|
|
56538
56852
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
56539
56853
|
await mod.startMonitor();
|
|
@@ -56571,14 +56885,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
56571
56885
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
56572
56886
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
56573
56887
|
if (subcommand === "debug") {
|
|
56574
|
-
const flagFile =
|
|
56888
|
+
const flagFile = path70.join(os63.homedir(), ".node9", "hud-debug");
|
|
56575
56889
|
if (state === "on") {
|
|
56576
|
-
|
|
56577
|
-
|
|
56890
|
+
fs73.mkdirSync(path70.dirname(flagFile), { recursive: true });
|
|
56891
|
+
fs73.writeFileSync(flagFile, "");
|
|
56578
56892
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
56579
56893
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
56580
56894
|
} else if (state === "off") {
|
|
56581
|
-
if (
|
|
56895
|
+
if (fs73.existsSync(flagFile)) fs73.unlinkSync(flagFile);
|
|
56582
56896
|
console.log("HUD debug logging disabled.");
|
|
56583
56897
|
} else {
|
|
56584
56898
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -56701,9 +57015,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
56701
57015
|
const isCheckHook = process.argv[2] === "check";
|
|
56702
57016
|
if (isCheckHook) {
|
|
56703
57017
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
56704
|
-
const logPath =
|
|
57018
|
+
const logPath = path70.join(os63.homedir(), ".node9", "hook-debug.log");
|
|
56705
57019
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
56706
|
-
|
|
57020
|
+
fs73.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
56707
57021
|
`);
|
|
56708
57022
|
}
|
|
56709
57023
|
process.exit(0);
|