@node9/proxy 1.46.0 → 1.48.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 CHANGED
@@ -337,6 +337,11 @@ var init_config_schema = __esm({
337
337
  // must run them from the CLI. node9's threat model is the agent itself.
338
338
  mcpAllowWeakening: import_zod.z.boolean().optional(),
339
339
  cloudSyncIntervalHours: import_zod.z.number().positive().optional(),
340
+ // Seconds-granular override for the cloud policy sync cadence. Wins over
341
+ // cloudSyncIntervalHours when set. Lets you opt into fast apply (e.g. 20)
342
+ // for an incident; clamped to a 15s floor so it can't hammer the API.
343
+ // Unset → falls back to hours, then the 5h default.
344
+ cloudSyncIntervalSeconds: import_zod.z.number().positive().optional(),
340
345
  // Outbox shipper (audit.log → SaaS batch ingest). enabled defaults
341
346
  // to true; set false to fall back to local-only auditing.
342
347
  shipper: import_zod.z.object({
@@ -4410,6 +4415,7 @@ function getConfig(cwd) {
4410
4415
  };
4411
4416
  applyLayer(globalConfig);
4412
4417
  applyLayer(projectConfig);
4418
+ let cloudManagedShields = [];
4413
4419
  {
4414
4420
  const cacheFile = import_path3.default.join(import_os3.default.homedir(), ".node9", "rules-cache.json");
4415
4421
  try {
@@ -4417,6 +4423,9 @@ function getConfig(cwd) {
4417
4423
  if (Array.isArray(raw.rules) && raw.rules.length > 0) {
4418
4424
  applyLayer({ policy: { smartRules: raw.rules } });
4419
4425
  }
4426
+ if (Array.isArray(raw.shields)) {
4427
+ cloudManagedShields = raw.shields.filter((s) => typeof s === "string");
4428
+ }
4420
4429
  if (raw.panicMode === true) {
4421
4430
  mergedSettings.panicMode = true;
4422
4431
  }
@@ -4427,7 +4436,8 @@ function getConfig(cwd) {
4427
4436
  }
4428
4437
  }
4429
4438
  const shieldOverrides = readShieldOverrides();
4430
- for (const shieldName of readActiveShields()) {
4439
+ const activeShieldNames = [.../* @__PURE__ */ new Set([...readActiveShields(), ...cloudManagedShields])];
4440
+ for (const shieldName of activeShieldNames) {
4431
4441
  const shield = getShield(shieldName);
4432
4442
  if (!shield) continue;
4433
4443
  const existingRuleNames = new Set(mergedPolicy.smartRules.map((r) => r.name));
@@ -16777,6 +16787,11 @@ function buildSessionDeltas(findings, toolCallsBySession) {
16777
16787
  signals
16778
16788
  }));
16779
16789
  }
16790
+ function resolveSyncIntervalMs(settings) {
16791
+ const rawSeconds = settings.cloudSyncIntervalSeconds ?? (settings.cloudSyncIntervalHours ?? DEFAULT_INTERVAL_HOURS) * 3600;
16792
+ const clamped = Math.min(Math.max(rawSeconds, MIN_INTERVAL_SECONDS), MAX_INTERVAL_SECONDS);
16793
+ return clamped * 1e3;
16794
+ }
16780
16795
  function readCredentials() {
16781
16796
  if (process.env.NODE9_API_KEY) {
16782
16797
  return {
@@ -16872,6 +16887,9 @@ function extractRules(body) {
16872
16887
  if (Array.isArray(body.rules)) return body.rules;
16873
16888
  return [];
16874
16889
  }
16890
+ function extractShields(body) {
16891
+ return Array.isArray(body.shields) ? body.shields.filter((s) => typeof s === "string") : [];
16892
+ }
16875
16893
  function writeCache2(cache) {
16876
16894
  const dir = import_path31.default.dirname(rulesCacheFile());
16877
16895
  if (!import_fs32.default.existsSync(dir)) import_fs32.default.mkdirSync(dir, { recursive: true });
@@ -16891,7 +16909,8 @@ async function syncOnce() {
16891
16909
  panicMode: result.body.panicMode,
16892
16910
  shadowMode: result.body.shadowMode,
16893
16911
  syncIntervalHours: result.body.syncIntervalHours,
16894
- workspaceId: result.body.workspaceId
16912
+ workspaceId: result.body.workspaceId,
16913
+ shields: extractShields(result.body)
16895
16914
  };
16896
16915
  writeCache2(cache);
16897
16916
  }
@@ -17063,7 +17082,8 @@ async function runCloudSync() {
17063
17082
  panicMode: result.body.panicMode,
17064
17083
  shadowMode: result.body.shadowMode,
17065
17084
  syncIntervalHours: result.body.syncIntervalHours,
17066
- workspaceId: result.body.workspaceId
17085
+ workspaceId: result.body.workspaceId,
17086
+ shields: extractShields(result.body)
17067
17087
  };
17068
17088
  writeCache2(cache);
17069
17089
  maybePushBlast();
@@ -17099,9 +17119,7 @@ function getCloudRules() {
17099
17119
  }
17100
17120
  }
17101
17121
  function startCloudSync() {
17102
- const rawHours = getConfig().settings.cloudSyncIntervalHours ?? DEFAULT_INTERVAL_HOURS;
17103
- const intervalHours = Math.max(rawHours, MIN_INTERVAL_HOURS);
17104
- const intervalMs = intervalHours * 60 * 60 * 1e3;
17122
+ const intervalMs = resolveSyncIntervalMs(getConfig().settings);
17105
17123
  const initial = setTimeout(() => void syncOnce(), 3e4);
17106
17124
  initial.unref();
17107
17125
  const recurring = setInterval(() => void syncOnce(), intervalMs);
@@ -17126,7 +17144,7 @@ function startForensicBroadcast() {
17126
17144
  const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
17127
17145
  recurring.unref();
17128
17146
  }
17129
- var import_fs32, import_https4, import_os29, import_path31, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
17147
+ var import_fs32, import_https4, import_os29, import_path31, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
17130
17148
  var init_sync = __esm({
17131
17149
  "src/daemon/sync.ts"() {
17132
17150
  "use strict";
@@ -17160,7 +17178,8 @@ var init_sync = __esm({
17160
17178
  rulesCacheFile = () => import_path31.default.join(import_os29.default.homedir(), ".node9", "rules-cache.json");
17161
17179
  DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
17162
17180
  DEFAULT_INTERVAL_HOURS = 5;
17163
- MIN_INTERVAL_HOURS = 1;
17181
+ MIN_INTERVAL_SECONDS = 15;
17182
+ MAX_INTERVAL_SECONDS = 24 * 60 * 60;
17164
17183
  FORENSIC_BROADCAST_INTERVAL_MS = 3e4;
17165
17184
  FORENSIC_INITIAL_DELAY_MS = 5e3;
17166
17185
  forensicBroadcastOffsets = /* @__PURE__ */ new Map();
package/dist/cli.mjs CHANGED
@@ -315,6 +315,11 @@ var init_config_schema = __esm({
315
315
  // must run them from the CLI. node9's threat model is the agent itself.
316
316
  mcpAllowWeakening: z.boolean().optional(),
317
317
  cloudSyncIntervalHours: z.number().positive().optional(),
318
+ // Seconds-granular override for the cloud policy sync cadence. Wins over
319
+ // cloudSyncIntervalHours when set. Lets you opt into fast apply (e.g. 20)
320
+ // for an incident; clamped to a 15s floor so it can't hammer the API.
321
+ // Unset → falls back to hours, then the 5h default.
322
+ cloudSyncIntervalSeconds: z.number().positive().optional(),
318
323
  // Outbox shipper (audit.log → SaaS batch ingest). enabled defaults
319
324
  // to true; set false to fall back to local-only auditing.
320
325
  shipper: z.object({
@@ -4391,6 +4396,7 @@ function getConfig(cwd) {
4391
4396
  };
4392
4397
  applyLayer(globalConfig);
4393
4398
  applyLayer(projectConfig);
4399
+ let cloudManagedShields = [];
4394
4400
  {
4395
4401
  const cacheFile = path3.join(os3.homedir(), ".node9", "rules-cache.json");
4396
4402
  try {
@@ -4398,6 +4404,9 @@ function getConfig(cwd) {
4398
4404
  if (Array.isArray(raw.rules) && raw.rules.length > 0) {
4399
4405
  applyLayer({ policy: { smartRules: raw.rules } });
4400
4406
  }
4407
+ if (Array.isArray(raw.shields)) {
4408
+ cloudManagedShields = raw.shields.filter((s) => typeof s === "string");
4409
+ }
4401
4410
  if (raw.panicMode === true) {
4402
4411
  mergedSettings.panicMode = true;
4403
4412
  }
@@ -4408,7 +4417,8 @@ function getConfig(cwd) {
4408
4417
  }
4409
4418
  }
4410
4419
  const shieldOverrides = readShieldOverrides();
4411
- for (const shieldName of readActiveShields()) {
4420
+ const activeShieldNames = [.../* @__PURE__ */ new Set([...readActiveShields(), ...cloudManagedShields])];
4421
+ for (const shieldName of activeShieldNames) {
4412
4422
  const shield = getShield(shieldName);
4413
4423
  if (!shield) continue;
4414
4424
  const existingRuleNames = new Set(mergedPolicy.smartRules.map((r) => r.name));
@@ -16751,6 +16761,11 @@ function buildSessionDeltas(findings, toolCallsBySession) {
16751
16761
  signals
16752
16762
  }));
16753
16763
  }
16764
+ function resolveSyncIntervalMs(settings) {
16765
+ const rawSeconds = settings.cloudSyncIntervalSeconds ?? (settings.cloudSyncIntervalHours ?? DEFAULT_INTERVAL_HOURS) * 3600;
16766
+ const clamped = Math.min(Math.max(rawSeconds, MIN_INTERVAL_SECONDS), MAX_INTERVAL_SECONDS);
16767
+ return clamped * 1e3;
16768
+ }
16754
16769
  function readCredentials() {
16755
16770
  if (process.env.NODE9_API_KEY) {
16756
16771
  return {
@@ -16846,6 +16861,9 @@ function extractRules(body) {
16846
16861
  if (Array.isArray(body.rules)) return body.rules;
16847
16862
  return [];
16848
16863
  }
16864
+ function extractShields(body) {
16865
+ return Array.isArray(body.shields) ? body.shields.filter((s) => typeof s === "string") : [];
16866
+ }
16849
16867
  function writeCache2(cache) {
16850
16868
  const dir = path31.dirname(rulesCacheFile());
16851
16869
  if (!fs32.existsSync(dir)) fs32.mkdirSync(dir, { recursive: true });
@@ -16865,7 +16883,8 @@ async function syncOnce() {
16865
16883
  panicMode: result.body.panicMode,
16866
16884
  shadowMode: result.body.shadowMode,
16867
16885
  syncIntervalHours: result.body.syncIntervalHours,
16868
- workspaceId: result.body.workspaceId
16886
+ workspaceId: result.body.workspaceId,
16887
+ shields: extractShields(result.body)
16869
16888
  };
16870
16889
  writeCache2(cache);
16871
16890
  }
@@ -17037,7 +17056,8 @@ async function runCloudSync() {
17037
17056
  panicMode: result.body.panicMode,
17038
17057
  shadowMode: result.body.shadowMode,
17039
17058
  syncIntervalHours: result.body.syncIntervalHours,
17040
- workspaceId: result.body.workspaceId
17059
+ workspaceId: result.body.workspaceId,
17060
+ shields: extractShields(result.body)
17041
17061
  };
17042
17062
  writeCache2(cache);
17043
17063
  maybePushBlast();
@@ -17073,9 +17093,7 @@ function getCloudRules() {
17073
17093
  }
17074
17094
  }
17075
17095
  function startCloudSync() {
17076
- const rawHours = getConfig().settings.cloudSyncIntervalHours ?? DEFAULT_INTERVAL_HOURS;
17077
- const intervalHours = Math.max(rawHours, MIN_INTERVAL_HOURS);
17078
- const intervalMs = intervalHours * 60 * 60 * 1e3;
17096
+ const intervalMs = resolveSyncIntervalMs(getConfig().settings);
17079
17097
  const initial = setTimeout(() => void syncOnce(), 3e4);
17080
17098
  initial.unref();
17081
17099
  const recurring = setInterval(() => void syncOnce(), intervalMs);
@@ -17100,7 +17118,7 @@ function startForensicBroadcast() {
17100
17118
  const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
17101
17119
  recurring.unref();
17102
17120
  }
17103
- var FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
17121
+ var FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
17104
17122
  var init_sync = __esm({
17105
17123
  "src/daemon/sync.ts"() {
17106
17124
  "use strict";
@@ -17130,7 +17148,8 @@ var init_sync = __esm({
17130
17148
  rulesCacheFile = () => path31.join(os29.homedir(), ".node9", "rules-cache.json");
17131
17149
  DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
17132
17150
  DEFAULT_INTERVAL_HOURS = 5;
17133
- MIN_INTERVAL_HOURS = 1;
17151
+ MIN_INTERVAL_SECONDS = 15;
17152
+ MAX_INTERVAL_SECONDS = 24 * 60 * 60;
17134
17153
  FORENSIC_BROADCAST_INTERVAL_MS = 3e4;
17135
17154
  FORENSIC_INITIAL_DELAY_MS = 5e3;
17136
17155
  forensicBroadcastOffsets = /* @__PURE__ */ new Map();
@@ -2280,6 +2280,11 @@ var init_config_schema = __esm({
2280
2280
  // must run them from the CLI. node9's threat model is the agent itself.
2281
2281
  mcpAllowWeakening: z.boolean().optional(),
2282
2282
  cloudSyncIntervalHours: z.number().positive().optional(),
2283
+ // Seconds-granular override for the cloud policy sync cadence. Wins over
2284
+ // cloudSyncIntervalHours when set. Lets you opt into fast apply (e.g. 20)
2285
+ // for an incident; clamped to a 15s floor so it can't hammer the API.
2286
+ // Unset → falls back to hours, then the 5h default.
2287
+ cloudSyncIntervalSeconds: z.number().positive().optional(),
2283
2288
  // Outbox shipper (audit.log → SaaS batch ingest). enabled defaults
2284
2289
  // to true; set false to fall back to local-only auditing.
2285
2290
  shipper: z.object({
package/dist/index.js CHANGED
@@ -322,6 +322,11 @@ var ConfigFileSchema = import_zod.z.object({
322
322
  // must run them from the CLI. node9's threat model is the agent itself.
323
323
  mcpAllowWeakening: import_zod.z.boolean().optional(),
324
324
  cloudSyncIntervalHours: import_zod.z.number().positive().optional(),
325
+ // Seconds-granular override for the cloud policy sync cadence. Wins over
326
+ // cloudSyncIntervalHours when set. Lets you opt into fast apply (e.g. 20)
327
+ // for an incident; clamped to a 15s floor so it can't hammer the API.
328
+ // Unset → falls back to hours, then the 5h default.
329
+ cloudSyncIntervalSeconds: import_zod.z.number().positive().optional(),
325
330
  // Outbox shipper (audit.log → SaaS batch ingest). enabled defaults
326
331
  // to true; set false to fall back to local-only auditing.
327
332
  shipper: import_zod.z.object({
@@ -3942,6 +3947,7 @@ function getConfig(cwd) {
3942
3947
  };
3943
3948
  applyLayer(globalConfig);
3944
3949
  applyLayer(projectConfig);
3950
+ let cloudManagedShields = [];
3945
3951
  {
3946
3952
  const cacheFile = import_path3.default.join(import_os3.default.homedir(), ".node9", "rules-cache.json");
3947
3953
  try {
@@ -3949,6 +3955,9 @@ function getConfig(cwd) {
3949
3955
  if (Array.isArray(raw.rules) && raw.rules.length > 0) {
3950
3956
  applyLayer({ policy: { smartRules: raw.rules } });
3951
3957
  }
3958
+ if (Array.isArray(raw.shields)) {
3959
+ cloudManagedShields = raw.shields.filter((s) => typeof s === "string");
3960
+ }
3952
3961
  if (raw.panicMode === true) {
3953
3962
  mergedSettings.panicMode = true;
3954
3963
  }
@@ -3959,7 +3968,8 @@ function getConfig(cwd) {
3959
3968
  }
3960
3969
  }
3961
3970
  const shieldOverrides = readShieldOverrides();
3962
- for (const shieldName of readActiveShields()) {
3971
+ const activeShieldNames = [.../* @__PURE__ */ new Set([...readActiveShields(), ...cloudManagedShields])];
3972
+ for (const shieldName of activeShieldNames) {
3963
3973
  const shield = getShield(shieldName);
3964
3974
  if (!shield) continue;
3965
3975
  const existingRuleNames = new Set(mergedPolicy.smartRules.map((r) => r.name));
package/dist/index.mjs CHANGED
@@ -292,6 +292,11 @@ var ConfigFileSchema = z.object({
292
292
  // must run them from the CLI. node9's threat model is the agent itself.
293
293
  mcpAllowWeakening: z.boolean().optional(),
294
294
  cloudSyncIntervalHours: z.number().positive().optional(),
295
+ // Seconds-granular override for the cloud policy sync cadence. Wins over
296
+ // cloudSyncIntervalHours when set. Lets you opt into fast apply (e.g. 20)
297
+ // for an incident; clamped to a 15s floor so it can't hammer the API.
298
+ // Unset → falls back to hours, then the 5h default.
299
+ cloudSyncIntervalSeconds: z.number().positive().optional(),
295
300
  // Outbox shipper (audit.log → SaaS batch ingest). enabled defaults
296
301
  // to true; set false to fall back to local-only auditing.
297
302
  shipper: z.object({
@@ -3912,6 +3917,7 @@ function getConfig(cwd) {
3912
3917
  };
3913
3918
  applyLayer(globalConfig);
3914
3919
  applyLayer(projectConfig);
3920
+ let cloudManagedShields = [];
3915
3921
  {
3916
3922
  const cacheFile = path3.join(os3.homedir(), ".node9", "rules-cache.json");
3917
3923
  try {
@@ -3919,6 +3925,9 @@ function getConfig(cwd) {
3919
3925
  if (Array.isArray(raw.rules) && raw.rules.length > 0) {
3920
3926
  applyLayer({ policy: { smartRules: raw.rules } });
3921
3927
  }
3928
+ if (Array.isArray(raw.shields)) {
3929
+ cloudManagedShields = raw.shields.filter((s) => typeof s === "string");
3930
+ }
3922
3931
  if (raw.panicMode === true) {
3923
3932
  mergedSettings.panicMode = true;
3924
3933
  }
@@ -3929,7 +3938,8 @@ function getConfig(cwd) {
3929
3938
  }
3930
3939
  }
3931
3940
  const shieldOverrides = readShieldOverrides();
3932
- for (const shieldName of readActiveShields()) {
3941
+ const activeShieldNames = [.../* @__PURE__ */ new Set([...readActiveShields(), ...cloudManagedShields])];
3942
+ for (const shieldName of activeShieldNames) {
3933
3943
  const shield = getShield(shieldName);
3934
3944
  if (!shield) continue;
3935
3945
  const existingRuleNames = new Set(mergedPolicy.smartRules.map((r) => r.name));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/proxy",
3
- "version": "1.46.0",
3
+ "version": "1.48.0",
4
4
  "description": "The Sudo Command for AI Agents. Execution Security for Claude Code, Codex, Gemini, Cursor, Opencode, Pi, and any MCP server.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",