@node9/proxy 1.0.7 → 1.0.8
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/LICENSE +183 -21
- package/README.md +1 -106
- package/dist/cli.js +278 -121
- package/dist/cli.mjs +278 -121
- package/dist/index.js +139 -31
- package/dist/index.mjs +139 -31
- package/package.json +4 -2
package/dist/index.mjs
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
import chalk2 from "chalk";
|
|
3
3
|
import { confirm } from "@inquirer/prompts";
|
|
4
4
|
import fs from "fs";
|
|
5
|
-
import
|
|
5
|
+
import path2 from "path";
|
|
6
6
|
import os from "os";
|
|
7
7
|
import pm from "picomatch";
|
|
8
8
|
import { parse } from "sh-syntax";
|
|
9
9
|
|
|
10
10
|
// src/ui/native.ts
|
|
11
11
|
import { spawn } from "child_process";
|
|
12
|
+
import path from "path";
|
|
12
13
|
import chalk from "chalk";
|
|
13
14
|
var isTestEnv = () => {
|
|
14
15
|
return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || !!process.env.VITEST || process.env.CI === "true" || !!process.env.CI || process.env.NODE9_TESTING === "1";
|
|
@@ -18,8 +19,29 @@ function smartTruncate(str, maxLen = 500) {
|
|
|
18
19
|
const edge = Math.floor(maxLen / 2) - 3;
|
|
19
20
|
return `${str.slice(0, edge)} ... ${str.slice(-edge)}`;
|
|
20
21
|
}
|
|
21
|
-
function
|
|
22
|
-
|
|
22
|
+
function extractContext(text, matchedWord) {
|
|
23
|
+
const lines = text.split("\n");
|
|
24
|
+
if (lines.length <= 7 || !matchedWord) return smartTruncate(text, 500);
|
|
25
|
+
const escaped = matchedWord.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26
|
+
const pattern = new RegExp(`\\b${escaped}\\b`, "i");
|
|
27
|
+
const allHits = lines.map((line, i) => ({ i, line })).filter(({ line }) => pattern.test(line));
|
|
28
|
+
if (allHits.length === 0) return smartTruncate(text, 500);
|
|
29
|
+
const nonComment = allHits.find(({ line }) => {
|
|
30
|
+
const trimmed = line.trim();
|
|
31
|
+
return !trimmed.startsWith("//") && !trimmed.startsWith("#");
|
|
32
|
+
});
|
|
33
|
+
const hitIndex = (nonComment ?? allHits[0]).i;
|
|
34
|
+
const start = Math.max(0, hitIndex - 3);
|
|
35
|
+
const end = Math.min(lines.length, hitIndex + 4);
|
|
36
|
+
const snippet = lines.slice(start, end).map((line, i) => `${start + i === hitIndex ? "\u{1F6D1} " : " "}${line}`).join("\n");
|
|
37
|
+
const head = start > 0 ? `... [${start} lines hidden] ...
|
|
38
|
+
` : "";
|
|
39
|
+
const tail = end < lines.length ? `
|
|
40
|
+
... [${lines.length - end} lines hidden] ...` : "";
|
|
41
|
+
return `${head}${snippet}${tail}`;
|
|
42
|
+
}
|
|
43
|
+
function formatArgs(args, matchedField, matchedWord) {
|
|
44
|
+
if (args === null || args === void 0) return { message: "(none)", intent: "EXEC" };
|
|
23
45
|
let parsed = args;
|
|
24
46
|
if (typeof args === "string") {
|
|
25
47
|
const trimmed = args.trim();
|
|
@@ -30,11 +52,39 @@ function formatArgs(args) {
|
|
|
30
52
|
parsed = args;
|
|
31
53
|
}
|
|
32
54
|
} else {
|
|
33
|
-
return smartTruncate(args, 600);
|
|
55
|
+
return { message: smartTruncate(args, 600), intent: "EXEC" };
|
|
34
56
|
}
|
|
35
57
|
}
|
|
36
58
|
if (typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
37
59
|
const obj = parsed;
|
|
60
|
+
if (obj.old_string !== void 0 && obj.new_string !== void 0) {
|
|
61
|
+
const file = obj.file_path ? path.basename(String(obj.file_path)) : "file";
|
|
62
|
+
const oldPreview = smartTruncate(String(obj.old_string), 120);
|
|
63
|
+
const newPreview = extractContext(String(obj.new_string), matchedWord);
|
|
64
|
+
return {
|
|
65
|
+
intent: "EDIT",
|
|
66
|
+
message: `\u{1F4DD} EDITING: ${file}
|
|
67
|
+
\u{1F4C2} PATH: ${obj.file_path}
|
|
68
|
+
|
|
69
|
+
--- REPLACING ---
|
|
70
|
+
${oldPreview}
|
|
71
|
+
|
|
72
|
+
+++ NEW CODE +++
|
|
73
|
+
${newPreview}`
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (matchedField && obj[matchedField] !== void 0) {
|
|
77
|
+
const otherKeys = Object.keys(obj).filter((k) => k !== matchedField);
|
|
78
|
+
const context = otherKeys.length > 0 ? `\u2699\uFE0F Context: ${otherKeys.map((k) => `${k}=${smartTruncate(typeof obj[k] === "object" ? JSON.stringify(obj[k]) : String(obj[k]), 30)}`).join(", ")}
|
|
79
|
+
|
|
80
|
+
` : "";
|
|
81
|
+
const content = extractContext(String(obj[matchedField]), matchedWord);
|
|
82
|
+
return {
|
|
83
|
+
intent: "EXEC",
|
|
84
|
+
message: `${context}\u{1F6D1} [${matchedField.toUpperCase()}]:
|
|
85
|
+
${content}`
|
|
86
|
+
};
|
|
87
|
+
}
|
|
38
88
|
const codeKeys = [
|
|
39
89
|
"command",
|
|
40
90
|
"cmd",
|
|
@@ -55,14 +105,18 @@ function formatArgs(args) {
|
|
|
55
105
|
if (foundKey) {
|
|
56
106
|
const val = obj[foundKey];
|
|
57
107
|
const str = typeof val === "string" ? val : JSON.stringify(val);
|
|
58
|
-
return
|
|
59
|
-
|
|
108
|
+
return {
|
|
109
|
+
intent: "EXEC",
|
|
110
|
+
message: `[${foundKey.toUpperCase()}]:
|
|
111
|
+
${smartTruncate(str, 500)}`
|
|
112
|
+
};
|
|
60
113
|
}
|
|
61
|
-
|
|
114
|
+
const msg = Object.entries(obj).slice(0, 5).map(
|
|
62
115
|
([k, v]) => ` ${k}: ${smartTruncate(typeof v === "string" ? v : JSON.stringify(v), 300)}`
|
|
63
116
|
).join("\n");
|
|
117
|
+
return { intent: "EXEC", message: msg };
|
|
64
118
|
}
|
|
65
|
-
return smartTruncate(JSON.stringify(parsed), 200);
|
|
119
|
+
return { intent: "EXEC", message: smartTruncate(JSON.stringify(parsed), 200) };
|
|
66
120
|
}
|
|
67
121
|
function sendDesktopNotification(title, body) {
|
|
68
122
|
if (isTestEnv()) return;
|
|
@@ -115,10 +169,11 @@ function buildPangoMessage(toolName, formattedArgs, agent, explainableLabel, loc
|
|
|
115
169
|
}
|
|
116
170
|
return lines.join("\n");
|
|
117
171
|
}
|
|
118
|
-
async function askNativePopup(toolName, args, agent, explainableLabel, locked = false, signal) {
|
|
172
|
+
async function askNativePopup(toolName, args, agent, explainableLabel, locked = false, signal, matchedField, matchedWord) {
|
|
119
173
|
if (isTestEnv()) return "deny";
|
|
120
|
-
const formattedArgs = formatArgs(args);
|
|
121
|
-
const
|
|
174
|
+
const { message: formattedArgs, intent } = formatArgs(args, matchedField, matchedWord);
|
|
175
|
+
const intentLabel = intent === "EDIT" ? "Code Edit" : "Action Approval";
|
|
176
|
+
const title = locked ? `\u26A1 Node9 \u2014 Locked` : `\u{1F6E1}\uFE0F Node9 \u2014 ${intentLabel}`;
|
|
122
177
|
const message = buildPlainMessage(toolName, formattedArgs, agent, explainableLabel, locked);
|
|
123
178
|
process.stderr.write(chalk.yellow(`
|
|
124
179
|
\u{1F6E1}\uFE0F Node9: Intercepted "${toolName}" \u2014 awaiting user...
|
|
@@ -196,10 +251,10 @@ end run`;
|
|
|
196
251
|
}
|
|
197
252
|
|
|
198
253
|
// src/core.ts
|
|
199
|
-
var PAUSED_FILE =
|
|
200
|
-
var TRUST_FILE =
|
|
201
|
-
var LOCAL_AUDIT_LOG =
|
|
202
|
-
var HOOK_DEBUG_LOG =
|
|
254
|
+
var PAUSED_FILE = path2.join(os.homedir(), ".node9", "PAUSED");
|
|
255
|
+
var TRUST_FILE = path2.join(os.homedir(), ".node9", "trust.json");
|
|
256
|
+
var LOCAL_AUDIT_LOG = path2.join(os.homedir(), ".node9", "audit.log");
|
|
257
|
+
var HOOK_DEBUG_LOG = path2.join(os.homedir(), ".node9", "hook-debug.log");
|
|
203
258
|
function checkPause() {
|
|
204
259
|
try {
|
|
205
260
|
if (!fs.existsSync(PAUSED_FILE)) return { paused: false };
|
|
@@ -217,7 +272,7 @@ function checkPause() {
|
|
|
217
272
|
}
|
|
218
273
|
}
|
|
219
274
|
function atomicWriteSync(filePath, data, options) {
|
|
220
|
-
const dir =
|
|
275
|
+
const dir = path2.dirname(filePath);
|
|
221
276
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
222
277
|
const tmpPath = `${filePath}.${os.hostname()}.${process.pid}.tmp`;
|
|
223
278
|
fs.writeFileSync(tmpPath, data, options);
|
|
@@ -258,7 +313,7 @@ function writeTrustSession(toolName, durationMs) {
|
|
|
258
313
|
}
|
|
259
314
|
function appendToLog(logPath, entry) {
|
|
260
315
|
try {
|
|
261
|
-
const dir =
|
|
316
|
+
const dir = path2.dirname(logPath);
|
|
262
317
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
263
318
|
fs.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
264
319
|
} catch {
|
|
@@ -302,9 +357,9 @@ function matchesPattern(text, patterns) {
|
|
|
302
357
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
303
358
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
304
359
|
}
|
|
305
|
-
function getNestedValue(obj,
|
|
360
|
+
function getNestedValue(obj, path3) {
|
|
306
361
|
if (!obj || typeof obj !== "object") return null;
|
|
307
|
-
return
|
|
362
|
+
return path3.split(".").reduce((prev, curr) => prev?.[curr], obj);
|
|
308
363
|
}
|
|
309
364
|
function evaluateSmartConditions(args, rule) {
|
|
310
365
|
if (!rule.conditions || rule.conditions.length === 0) return true;
|
|
@@ -493,6 +548,18 @@ var DEFAULT_CONFIG = {
|
|
|
493
548
|
"terminal.execute": "command",
|
|
494
549
|
"postgres:query": "sql"
|
|
495
550
|
},
|
|
551
|
+
snapshot: {
|
|
552
|
+
tools: [
|
|
553
|
+
"str_replace_based_edit_tool",
|
|
554
|
+
"write_file",
|
|
555
|
+
"edit_file",
|
|
556
|
+
"create_file",
|
|
557
|
+
"edit",
|
|
558
|
+
"replace"
|
|
559
|
+
],
|
|
560
|
+
onlyPaths: [],
|
|
561
|
+
ignorePaths: ["**/node_modules/**", "dist/**", "build/**", ".next/**", "**/*.log"]
|
|
562
|
+
},
|
|
496
563
|
rules: [
|
|
497
564
|
{
|
|
498
565
|
action: "rm",
|
|
@@ -528,7 +595,7 @@ var DEFAULT_CONFIG = {
|
|
|
528
595
|
var cachedConfig = null;
|
|
529
596
|
function getInternalToken() {
|
|
530
597
|
try {
|
|
531
|
-
const pidFile =
|
|
598
|
+
const pidFile = path2.join(os.homedir(), ".node9", "daemon.pid");
|
|
532
599
|
if (!fs.existsSync(pidFile)) return null;
|
|
533
600
|
const data = JSON.parse(fs.readFileSync(pidFile, "utf-8"));
|
|
534
601
|
process.kill(data.pid, 0);
|
|
@@ -632,9 +699,29 @@ async function evaluatePolicy(toolName, args, agent) {
|
|
|
632
699
|
})
|
|
633
700
|
);
|
|
634
701
|
if (isDangerous) {
|
|
702
|
+
let matchedField;
|
|
703
|
+
if (matchedDangerousWord && args && typeof args === "object" && !Array.isArray(args)) {
|
|
704
|
+
const obj = args;
|
|
705
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
706
|
+
if (typeof value === "string") {
|
|
707
|
+
try {
|
|
708
|
+
if (new RegExp(
|
|
709
|
+
`\\b${matchedDangerousWord.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`,
|
|
710
|
+
"i"
|
|
711
|
+
).test(value)) {
|
|
712
|
+
matchedField = key;
|
|
713
|
+
break;
|
|
714
|
+
}
|
|
715
|
+
} catch {
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
635
720
|
return {
|
|
636
721
|
decision: "review",
|
|
637
|
-
blockedByLabel: `Project/Global Config \u2014 dangerous word: "${matchedDangerousWord}"
|
|
722
|
+
blockedByLabel: `Project/Global Config \u2014 dangerous word: "${matchedDangerousWord}"`,
|
|
723
|
+
matchedWord: matchedDangerousWord,
|
|
724
|
+
matchedField
|
|
638
725
|
};
|
|
639
726
|
}
|
|
640
727
|
if (config.settings.mode === "strict") {
|
|
@@ -652,7 +739,7 @@ var DAEMON_PORT = 7391;
|
|
|
652
739
|
var DAEMON_HOST = "127.0.0.1";
|
|
653
740
|
function isDaemonRunning() {
|
|
654
741
|
try {
|
|
655
|
-
const pidFile =
|
|
742
|
+
const pidFile = path2.join(os.homedir(), ".node9", "daemon.pid");
|
|
656
743
|
if (!fs.existsSync(pidFile)) return false;
|
|
657
744
|
const { pid, port } = JSON.parse(fs.readFileSync(pidFile, "utf-8"));
|
|
658
745
|
if (port !== DAEMON_PORT) return false;
|
|
@@ -664,7 +751,7 @@ function isDaemonRunning() {
|
|
|
664
751
|
}
|
|
665
752
|
function getPersistentDecision(toolName) {
|
|
666
753
|
try {
|
|
667
|
-
const file =
|
|
754
|
+
const file = path2.join(os.homedir(), ".node9", "decisions.json");
|
|
668
755
|
if (!fs.existsSync(file)) return null;
|
|
669
756
|
const decisions = JSON.parse(fs.readFileSync(file, "utf-8"));
|
|
670
757
|
const d = decisions[toolName];
|
|
@@ -735,7 +822,7 @@ async function resolveViaDaemon(id, decision, internalToken) {
|
|
|
735
822
|
signal: AbortSignal.timeout(3e3)
|
|
736
823
|
});
|
|
737
824
|
}
|
|
738
|
-
async function authorizeHeadless(toolName, args, allowTerminalFallback = false, meta) {
|
|
825
|
+
async function authorizeHeadless(toolName, args, allowTerminalFallback = false, meta, options) {
|
|
739
826
|
if (process.env.NODE9_PAUSED === "1") return { approved: true, checkedBy: "paused" };
|
|
740
827
|
const pauseState = checkPause();
|
|
741
828
|
if (pauseState.paused) return { approved: true, checkedBy: "paused" };
|
|
@@ -755,6 +842,8 @@ async function authorizeHeadless(toolName, args, allowTerminalFallback = false,
|
|
|
755
842
|
}
|
|
756
843
|
const isManual = meta?.agent === "Terminal";
|
|
757
844
|
let explainableLabel = "Local Config";
|
|
845
|
+
let policyMatchedField;
|
|
846
|
+
let policyMatchedWord;
|
|
758
847
|
if (config.settings.mode === "audit") {
|
|
759
848
|
if (!isIgnoredTool(toolName)) {
|
|
760
849
|
const policyResult = await evaluatePolicy(toolName, args, meta?.agent);
|
|
@@ -790,6 +879,8 @@ async function authorizeHeadless(toolName, args, allowTerminalFallback = false,
|
|
|
790
879
|
};
|
|
791
880
|
}
|
|
792
881
|
explainableLabel = policyResult.blockedByLabel || "Local Config";
|
|
882
|
+
policyMatchedField = policyResult.matchedField;
|
|
883
|
+
policyMatchedWord = policyResult.matchedWord;
|
|
793
884
|
const persistent = getPersistentDecision(toolName);
|
|
794
885
|
if (persistent === "allow") {
|
|
795
886
|
if (creds?.apiKey) auditLocalAllow(toolName, args, "persistent", creds, meta);
|
|
@@ -882,7 +973,7 @@ async function authorizeHeadless(toolName, args, allowTerminalFallback = false,
|
|
|
882
973
|
racePromises.push(
|
|
883
974
|
(async () => {
|
|
884
975
|
try {
|
|
885
|
-
if (isDaemonRunning() && internalToken) {
|
|
976
|
+
if (isDaemonRunning() && internalToken && !options?.calledFromDaemon) {
|
|
886
977
|
viewerId = await notifyDaemonViewer(toolName, args, meta).catch(() => null);
|
|
887
978
|
}
|
|
888
979
|
const cloudResult = await pollNode9SaaS(cloudRequestId, creds, signal);
|
|
@@ -910,7 +1001,9 @@ async function authorizeHeadless(toolName, args, allowTerminalFallback = false,
|
|
|
910
1001
|
meta?.agent,
|
|
911
1002
|
explainableLabel,
|
|
912
1003
|
isRemoteLocked,
|
|
913
|
-
signal
|
|
1004
|
+
signal,
|
|
1005
|
+
policyMatchedField,
|
|
1006
|
+
policyMatchedWord
|
|
914
1007
|
);
|
|
915
1008
|
if (decision === "always_allow") {
|
|
916
1009
|
writeTrustSession(toolName, 36e5);
|
|
@@ -927,7 +1020,7 @@ async function authorizeHeadless(toolName, args, allowTerminalFallback = false,
|
|
|
927
1020
|
})()
|
|
928
1021
|
);
|
|
929
1022
|
}
|
|
930
|
-
if (approvers.browser && isDaemonRunning()) {
|
|
1023
|
+
if (approvers.browser && isDaemonRunning() && !options?.calledFromDaemon) {
|
|
931
1024
|
racePromises.push(
|
|
932
1025
|
(async () => {
|
|
933
1026
|
try {
|
|
@@ -1063,8 +1156,8 @@ REASON: Action blocked because no approval channels are available. (Native/Brows
|
|
|
1063
1156
|
}
|
|
1064
1157
|
function getConfig() {
|
|
1065
1158
|
if (cachedConfig) return cachedConfig;
|
|
1066
|
-
const globalPath =
|
|
1067
|
-
const projectPath =
|
|
1159
|
+
const globalPath = path2.join(os.homedir(), ".node9", "config.json");
|
|
1160
|
+
const projectPath = path2.join(process.cwd(), "node9.config.json");
|
|
1068
1161
|
const globalConfig = tryLoadConfig(globalPath);
|
|
1069
1162
|
const projectConfig = tryLoadConfig(projectPath);
|
|
1070
1163
|
const mergedSettings = {
|
|
@@ -1077,7 +1170,12 @@ function getConfig() {
|
|
|
1077
1170
|
ignoredTools: [...DEFAULT_CONFIG.policy.ignoredTools],
|
|
1078
1171
|
toolInspection: { ...DEFAULT_CONFIG.policy.toolInspection },
|
|
1079
1172
|
rules: [...DEFAULT_CONFIG.policy.rules],
|
|
1080
|
-
smartRules: [...DEFAULT_CONFIG.policy.smartRules]
|
|
1173
|
+
smartRules: [...DEFAULT_CONFIG.policy.smartRules],
|
|
1174
|
+
snapshot: {
|
|
1175
|
+
tools: [...DEFAULT_CONFIG.policy.snapshot.tools],
|
|
1176
|
+
onlyPaths: [...DEFAULT_CONFIG.policy.snapshot.onlyPaths],
|
|
1177
|
+
ignorePaths: [...DEFAULT_CONFIG.policy.snapshot.ignorePaths]
|
|
1178
|
+
}
|
|
1081
1179
|
};
|
|
1082
1180
|
const applyLayer = (source) => {
|
|
1083
1181
|
if (!source) return;
|
|
@@ -1089,6 +1187,7 @@ function getConfig() {
|
|
|
1089
1187
|
if (s.enableHookLogDebug !== void 0)
|
|
1090
1188
|
mergedSettings.enableHookLogDebug = s.enableHookLogDebug;
|
|
1091
1189
|
if (s.approvers) mergedSettings.approvers = { ...mergedSettings.approvers, ...s.approvers };
|
|
1190
|
+
if (s.approvalTimeoutMs !== void 0) mergedSettings.approvalTimeoutMs = s.approvalTimeoutMs;
|
|
1092
1191
|
if (s.environment !== void 0) mergedSettings.environment = s.environment;
|
|
1093
1192
|
if (p.sandboxPaths) mergedPolicy.sandboxPaths.push(...p.sandboxPaths);
|
|
1094
1193
|
if (p.ignoredTools) mergedPolicy.ignoredTools.push(...p.ignoredTools);
|
|
@@ -1097,6 +1196,12 @@ function getConfig() {
|
|
|
1097
1196
|
mergedPolicy.toolInspection = { ...mergedPolicy.toolInspection, ...p.toolInspection };
|
|
1098
1197
|
if (p.rules) mergedPolicy.rules.push(...p.rules);
|
|
1099
1198
|
if (p.smartRules) mergedPolicy.smartRules.push(...p.smartRules);
|
|
1199
|
+
if (p.snapshot) {
|
|
1200
|
+
const s2 = p.snapshot;
|
|
1201
|
+
if (s2.tools) mergedPolicy.snapshot.tools.push(...s2.tools);
|
|
1202
|
+
if (s2.onlyPaths) mergedPolicy.snapshot.onlyPaths.push(...s2.onlyPaths);
|
|
1203
|
+
if (s2.ignorePaths) mergedPolicy.snapshot.ignorePaths.push(...s2.ignorePaths);
|
|
1204
|
+
}
|
|
1100
1205
|
};
|
|
1101
1206
|
applyLayer(globalConfig);
|
|
1102
1207
|
applyLayer(projectConfig);
|
|
@@ -1104,6 +1209,9 @@ function getConfig() {
|
|
|
1104
1209
|
mergedPolicy.sandboxPaths = [...new Set(mergedPolicy.sandboxPaths)];
|
|
1105
1210
|
mergedPolicy.dangerousWords = [...new Set(mergedPolicy.dangerousWords)];
|
|
1106
1211
|
mergedPolicy.ignoredTools = [...new Set(mergedPolicy.ignoredTools)];
|
|
1212
|
+
mergedPolicy.snapshot.tools = [...new Set(mergedPolicy.snapshot.tools)];
|
|
1213
|
+
mergedPolicy.snapshot.onlyPaths = [...new Set(mergedPolicy.snapshot.onlyPaths)];
|
|
1214
|
+
mergedPolicy.snapshot.ignorePaths = [...new Set(mergedPolicy.snapshot.ignorePaths)];
|
|
1107
1215
|
cachedConfig = {
|
|
1108
1216
|
settings: mergedSettings,
|
|
1109
1217
|
policy: mergedPolicy,
|
|
@@ -1132,7 +1240,7 @@ function getCredentials() {
|
|
|
1132
1240
|
};
|
|
1133
1241
|
}
|
|
1134
1242
|
try {
|
|
1135
|
-
const credPath =
|
|
1243
|
+
const credPath = path2.join(os.homedir(), ".node9", "credentials.json");
|
|
1136
1244
|
if (fs.existsSync(credPath)) {
|
|
1137
1245
|
const creds = JSON.parse(fs.readFileSync(credPath, "utf-8"));
|
|
1138
1246
|
const profileName = process.env.NODE9_PROFILE || "default";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node9/proxy",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "The Sudo Command for AI Agents. Execution Security for Claude Code & MCP.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"hitl"
|
|
42
42
|
],
|
|
43
43
|
"author": "Nadav <nadav@node9.ai>",
|
|
44
|
-
"license": "
|
|
44
|
+
"license": "Apache-2.0",
|
|
45
45
|
"files": [
|
|
46
46
|
"dist",
|
|
47
47
|
"README.md",
|
|
@@ -73,6 +73,8 @@
|
|
|
73
73
|
"sh-syntax": "^0.5.8"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
+
"@anthropic-ai/sdk": "^0.78.0",
|
|
77
|
+
"@octokit/rest": "^22.0.1",
|
|
76
78
|
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
77
79
|
"@semantic-release/git": "^10.0.1",
|
|
78
80
|
"@semantic-release/github": "^12.0.6",
|