@astrasyncai/verification-gateway 3.9.0 → 3.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/adapter-interface/interface.d.mts +3 -2
  2. package/dist/adapter-interface/interface.d.ts +3 -2
  3. package/dist/adapters/express.d.mts +3 -2
  4. package/dist/adapters/express.d.ts +3 -2
  5. package/dist/adapters/express.js +151 -2
  6. package/dist/adapters/express.js.map +1 -1
  7. package/dist/adapters/express.mjs +151 -2
  8. package/dist/adapters/express.mjs.map +1 -1
  9. package/dist/adapters/mcp.d.mts +2 -1
  10. package/dist/adapters/mcp.d.ts +2 -1
  11. package/dist/adapters/mcp.js +1 -1
  12. package/dist/adapters/mcp.js.map +1 -1
  13. package/dist/adapters/mcp.mjs +1 -1
  14. package/dist/adapters/mcp.mjs.map +1 -1
  15. package/dist/adapters/nextjs.d.mts +3 -2
  16. package/dist/adapters/nextjs.d.ts +3 -2
  17. package/dist/adapters/nextjs.js +151 -2
  18. package/dist/adapters/nextjs.js.map +1 -1
  19. package/dist/adapters/nextjs.mjs +151 -2
  20. package/dist/adapters/nextjs.mjs.map +1 -1
  21. package/dist/adapters/sdk.d.mts +3 -2
  22. package/dist/adapters/sdk.d.ts +3 -2
  23. package/dist/adapters/sdk.js +1 -1
  24. package/dist/adapters/sdk.js.map +1 -1
  25. package/dist/adapters/sdk.mjs +1 -1
  26. package/dist/adapters/sdk.mjs.map +1 -1
  27. package/dist/agent/index.d.mts +3 -2
  28. package/dist/agent/index.d.ts +3 -2
  29. package/dist/bin/astrasync-claude-hook.js +276 -25
  30. package/dist/bin/astrasync-guard.js +258 -23
  31. package/dist/bin/astrasync.js +282 -24
  32. package/dist/browser/background.js +257 -22
  33. package/dist/browser/background.js.map +1 -1
  34. package/dist/browser/background.mjs +257 -22
  35. package/dist/browser/background.mjs.map +1 -1
  36. package/dist/browser/browser-adapter.d.mts +3 -2
  37. package/dist/browser/browser-adapter.d.ts +3 -2
  38. package/dist/claude-code/claude-code-adapter.d.mts +3 -2
  39. package/dist/claude-code/claude-code-adapter.d.ts +3 -2
  40. package/dist/cli/index.d.mts +3 -2
  41. package/dist/cli/index.d.ts +3 -2
  42. package/dist/cursor/cursor-adapter.d.mts +3 -2
  43. package/dist/cursor/cursor-adapter.d.ts +3 -2
  44. package/dist/cursor/extension.d.mts +3 -2
  45. package/dist/cursor/extension.d.ts +3 -2
  46. package/dist/cursor/extension.js +257 -22
  47. package/dist/cursor/extension.js.map +1 -1
  48. package/dist/cursor/extension.mjs +257 -22
  49. package/dist/cursor/extension.mjs.map +1 -1
  50. package/dist/edge-config.d.mts +2 -1
  51. package/dist/edge-config.d.ts +2 -1
  52. package/dist/{express-sGXhDdd0.d.ts → express-ClNtDhhc.d.ts} +1 -1
  53. package/dist/{express-DXUyvv7t.d.mts → express-DCXa1oqj.d.mts} +1 -1
  54. package/dist/gateway/gateway.d.mts +29 -3
  55. package/dist/gateway/gateway.d.ts +29 -3
  56. package/dist/gateway/gateway.js +257 -22
  57. package/dist/gateway/gateway.js.map +1 -1
  58. package/dist/gateway/gateway.mjs +257 -22
  59. package/dist/gateway/gateway.mjs.map +1 -1
  60. package/dist/git-trigger/git-hooks.d.mts +3 -2
  61. package/dist/git-trigger/git-hooks.d.ts +3 -2
  62. package/dist/{index-Dalih3EB.d.mts → index-BrNKDmiR.d.mts} +1 -1
  63. package/dist/{index-C61VL_OW.d.ts → index-CfHurO1P.d.ts} +1 -1
  64. package/dist/{index-CMg-vjEK.d.ts → index-D2ztkumS.d.ts} +1 -1
  65. package/dist/{index-DmmdehNu.d.mts → index-Dr_XiN65.d.mts} +1 -1
  66. package/dist/index.d.mts +10 -9
  67. package/dist/index.d.ts +10 -9
  68. package/dist/index.js +218 -11
  69. package/dist/index.js.map +1 -1
  70. package/dist/index.mjs +211 -11
  71. package/dist/index.mjs.map +1 -1
  72. package/dist/local-evaluator/evaluator.d.mts +3 -2
  73. package/dist/local-evaluator/evaluator.d.ts +3 -2
  74. package/dist/local-evaluator/evaluator.js +165 -7
  75. package/dist/local-evaluator/evaluator.js.map +1 -1
  76. package/dist/local-evaluator/evaluator.mjs +165 -7
  77. package/dist/local-evaluator/evaluator.mjs.map +1 -1
  78. package/dist/metadata-capture.d.mts +87 -0
  79. package/dist/metadata-capture.d.ts +87 -0
  80. package/dist/metadata-capture.js +184 -0
  81. package/dist/metadata-capture.js.map +1 -0
  82. package/dist/metadata-capture.mjs +154 -0
  83. package/dist/metadata-capture.mjs.map +1 -0
  84. package/dist/{nextjs-DwUW-Nm1.d.ts → nextjs-CEBVBsdi.d.ts} +1 -1
  85. package/dist/{nextjs-F_2pbPIA.d.mts → nextjs-DcQIk6Zj.d.mts} +1 -1
  86. package/dist/platform-signatures.d.mts +60 -10
  87. package/dist/platform-signatures.d.ts +60 -10
  88. package/dist/platform-signatures.js +37 -10
  89. package/dist/platform-signatures.js.map +1 -1
  90. package/dist/platform-signatures.mjs +35 -9
  91. package/dist/platform-signatures.mjs.map +1 -1
  92. package/dist/{sdk-Clob2-0A.d.mts → sdk-CZkbSOeO.d.mts} +1 -1
  93. package/dist/{sdk-CfHANs4A.d.ts → sdk-H0JCLW2y.d.ts} +1 -1
  94. package/dist/transport/index.d.mts +3 -2
  95. package/dist/transport/index.d.ts +3 -2
  96. package/dist/{types-ACMsV07B.d.mts → types-9tns4wyl.d.ts} +12 -0
  97. package/dist/{types-DmSDgPpG.d.ts → types-BV6abBnF.d.mts} +7 -1
  98. package/dist/{types-BtqUvK8v.d.mts → types-C23_uaY8.d.ts} +7 -1
  99. package/dist/{types-ACMsV07B.d.ts → types-sy3tq8lp.d.mts} +12 -0
  100. package/dist/ui/index.d.mts +2 -1
  101. package/dist/ui/index.d.ts +2 -1
  102. package/dist/verify.d.mts +8 -1
  103. package/dist/verify.d.ts +8 -1
  104. package/dist/verify.js +1 -1
  105. package/dist/verify.js.map +1 -1
  106. package/dist/verify.mjs +1 -1
  107. package/dist/verify.mjs.map +1 -1
  108. package/package.json +6 -1
@@ -4543,7 +4543,9 @@ var init_types = __esm({
4543
4543
  "git push",
4544
4544
  "npm publish",
4545
4545
  "docker",
4546
- "kubectl"
4546
+ "kubectl",
4547
+ "gh pr create",
4548
+ "gh pr merge"
4547
4549
  ];
4548
4550
  SENSITIVE_PATHS = [
4549
4551
  ".ssh",
@@ -4564,12 +4566,178 @@ var init_types = __esm({
4564
4566
  }
4565
4567
  });
4566
4568
 
4569
+ // src/local-evaluator/command-matcher.ts
4570
+ function buildRiskList(entries) {
4571
+ const singleWord = /* @__PURE__ */ new Set();
4572
+ const multiWord = [];
4573
+ for (const entry of entries) {
4574
+ const words = entry.toLowerCase().trim().split(/\s+/);
4575
+ if (words.length === 1) singleWord.add(words[0]);
4576
+ else multiWord.push(words);
4577
+ }
4578
+ multiWord.sort((a, b) => b.length - a.length);
4579
+ return { singleWord, multiWord };
4580
+ }
4581
+ function stripHeredocBodies(text) {
4582
+ const lines = text.split("\n");
4583
+ const kept = [];
4584
+ let terminator = null;
4585
+ for (const line of lines) {
4586
+ if (terminator !== null) {
4587
+ if (line.trim() === terminator) terminator = null;
4588
+ continue;
4589
+ }
4590
+ kept.push(line);
4591
+ const heredoc = line.match(/<<-?\s*['"]?(\w+)['"]?/);
4592
+ if (heredoc) terminator = heredoc[1];
4593
+ }
4594
+ return kept.join("\n");
4595
+ }
4596
+ function extractDollarSubstitutions(text, collect) {
4597
+ let result = text;
4598
+ let start = result.indexOf("$(");
4599
+ let iterations = 0;
4600
+ while (start !== -1 && iterations < 50) {
4601
+ iterations++;
4602
+ let depth = 0;
4603
+ let end = result.length;
4604
+ for (let i = start + 1; i < result.length; i++) {
4605
+ if (result[i] === "(") depth++;
4606
+ else if (result[i] === ")") {
4607
+ depth--;
4608
+ if (depth === 0) {
4609
+ end = i;
4610
+ break;
4611
+ }
4612
+ }
4613
+ }
4614
+ collect(result.slice(start + 2, end));
4615
+ result = `${result.slice(0, start)} ${result.slice(Math.min(end + 1, result.length))}`;
4616
+ start = result.indexOf("$(");
4617
+ }
4618
+ return result;
4619
+ }
4620
+ function extractBacktickSubstitutions(text, collect) {
4621
+ if (!text.includes("`")) return text;
4622
+ const chunks = text.split("`");
4623
+ const kept = [];
4624
+ for (let i = 0; i < chunks.length; i++) {
4625
+ if (i % 2 === 1) collect(chunks[i]);
4626
+ else kept.push(chunks[i]);
4627
+ }
4628
+ return kept.join(" ");
4629
+ }
4630
+ function basename(token) {
4631
+ const slash = token.lastIndexOf("/");
4632
+ return slash === -1 ? token : token.slice(slash + 1);
4633
+ }
4634
+ function matchSegment(segment, list) {
4635
+ const tokens = segment.split(/\s+/).filter((t) => /[a-z0-9]/.test(t));
4636
+ let i = 0;
4637
+ let hops = 0;
4638
+ while (i < tokens.length) {
4639
+ while (i < tokens.length && (tokens[i] === "export" || ASSIGN_RE.test(tokens[i]))) i++;
4640
+ if (i >= tokens.length) return null;
4641
+ const cmd = basename(tokens[i]);
4642
+ const significant = [cmd, ...tokens.slice(i + 1).filter((t) => !t.startsWith("-"))];
4643
+ for (const entry of list.multiWord) {
4644
+ if (entry.length <= significant.length && entry.every((w, j) => significant[j] === w)) {
4645
+ return entry.join(" ");
4646
+ }
4647
+ }
4648
+ if (list.singleWord.has(cmd)) return cmd;
4649
+ if (WRAPPERS.has(cmd) && hops < MAX_WRAPPER_HOPS) {
4650
+ hops++;
4651
+ i++;
4652
+ while (i < tokens.length && (tokens[i].startsWith("-") || ASSIGN_RE.test(tokens[i]))) i++;
4653
+ continue;
4654
+ }
4655
+ return null;
4656
+ }
4657
+ return null;
4658
+ }
4659
+ function collectMatches(command, list, matches, depth) {
4660
+ if (depth > MAX_RECURSION_DEPTH || command.length > MAX_COMMAND_LENGTH) return;
4661
+ let text = command.toLowerCase();
4662
+ text = stripHeredocBodies(text);
4663
+ const recurse = (inner) => collectMatches(inner, list, matches, depth + 1);
4664
+ text = extractDollarSubstitutions(text, recurse);
4665
+ text = extractBacktickSubstitutions(text, recurse);
4666
+ text = text.replace(/'[^']*'/g, " ").replace(/"[^"]*"/g, " ");
4667
+ text = text.replace(/(^|\s)#[^\n]*/g, " ");
4668
+ const segments = text.split(/\|\||&&|[;|&\n]|[({]/);
4669
+ for (const segment of segments) {
4670
+ const matched = matchSegment(segment, list);
4671
+ if (matched) matches.add(matched);
4672
+ }
4673
+ }
4674
+ function matchHighRiskCommands(command, highRiskCommands = HIGH_RISK_COMMANDS) {
4675
+ if (!command) return [];
4676
+ const matches = /* @__PURE__ */ new Set();
4677
+ collectMatches(command, buildRiskList(highRiskCommands), matches, 0);
4678
+ return [...matches];
4679
+ }
4680
+ function isLocalhostOnlyNetworkCommand(command) {
4681
+ const text = command.toLowerCase();
4682
+ const tokens = text.split(/\s+/).map((t) => t.replace(/^["'`]+|["'`,;)]+$/g, ""));
4683
+ let localCount = 0;
4684
+ for (const token of tokens) {
4685
+ let host = null;
4686
+ if (token.includes("://")) {
4687
+ let rest = token.slice(token.indexOf("://") + 3);
4688
+ const at = rest.indexOf("@");
4689
+ if (at !== -1) rest = rest.slice(at + 1);
4690
+ host = rest.split(/[/?#]/)[0];
4691
+ } else if (/^[a-z0-9.[\]:-]+:\d+(\/.*)?$/.test(token)) {
4692
+ host = token.split("/")[0];
4693
+ } else if (/^(localhost|127\.0\.0\.1|\[?::1\]?)(\/.*)?$/.test(token)) {
4694
+ host = token.split("/")[0];
4695
+ }
4696
+ if (host === null) continue;
4697
+ const bare = host.replace(/:\d+$/, "").replace(/^\[|\]$/g, "");
4698
+ if (LOCAL_HOST_RE.test(bare)) {
4699
+ localCount++;
4700
+ } else {
4701
+ return false;
4702
+ }
4703
+ }
4704
+ return localCount > 0;
4705
+ }
4706
+ var WRAPPERS, ASSIGN_RE, MAX_WRAPPER_HOPS, MAX_RECURSION_DEPTH, MAX_COMMAND_LENGTH, LOCAL_HOST_RE;
4707
+ var init_command_matcher = __esm({
4708
+ "src/local-evaluator/command-matcher.ts"() {
4709
+ "use strict";
4710
+ init_types();
4711
+ WRAPPERS = /* @__PURE__ */ new Set([
4712
+ "sudo",
4713
+ "doas",
4714
+ "env",
4715
+ "nohup",
4716
+ "time",
4717
+ "timeout",
4718
+ "nice",
4719
+ "ionice",
4720
+ "stdbuf",
4721
+ "xargs",
4722
+ "command",
4723
+ "exec",
4724
+ "builtin"
4725
+ ]);
4726
+ ASSIGN_RE = /^[a-z_][a-z0-9_]*=/;
4727
+ MAX_WRAPPER_HOPS = 4;
4728
+ MAX_RECURSION_DEPTH = 3;
4729
+ MAX_COMMAND_LENGTH = 1e5;
4730
+ LOCAL_HOST_RE = /^(localhost|127\.0\.0\.1|::1|[a-z0-9.-]*\.localhost)$/;
4731
+ }
4732
+ });
4733
+
4567
4734
  // src/local-evaluator/evaluator.ts
4568
4735
  var LocalEvaluator;
4569
4736
  var init_evaluator = __esm({
4570
4737
  "src/local-evaluator/evaluator.ts"() {
4571
4738
  "use strict";
4572
4739
  init_types();
4740
+ init_command_matcher();
4573
4741
  LocalEvaluator = class {
4574
4742
  constructor(policy) {
4575
4743
  this.requestCounts = /* @__PURE__ */ new Map();
@@ -4719,12 +4887,10 @@ var init_evaluator = __esm({
4719
4887
  return score;
4720
4888
  }
4721
4889
  if (context.purpose === "shell.exec" && context.target) {
4722
- const targetLower = context.target.toLowerCase();
4723
- for (const cmd of HIGH_RISK_COMMANDS) {
4724
- if (targetLower.startsWith(cmd) || targetLower.includes(` ${cmd} `) || targetLower.includes(` ${cmd}`)) {
4725
- score = Math.max(score, 80);
4726
- break;
4727
- }
4890
+ const matched = matchHighRiskCommands(context.target);
4891
+ const localProbeOnly = matched.length > 0 && matched.every((cmd) => cmd === "curl" || cmd === "wget") && isLocalhostOnlyNetworkCommand(context.target);
4892
+ if (matched.length > 0 && !localProbeOnly) {
4893
+ score = Math.max(score, 80);
4728
4894
  }
4729
4895
  }
4730
4896
  if ((context.purpose === "file.read" || context.purpose === "file.write" || context.purpose === "file.delete") && context.target) {
@@ -4823,7 +4989,7 @@ var SDK_VERSION;
4823
4989
  var init_version = __esm({
4824
4990
  "src/version.ts"() {
4825
4991
  "use strict";
4826
- SDK_VERSION = "3.9.0";
4992
+ SDK_VERSION = "3.10.1";
4827
4993
  }
4828
4994
  });
4829
4995
 
@@ -5299,6 +5465,15 @@ var init_pdlss_pre_check = __esm({
5299
5465
  }
5300
5466
  });
5301
5467
 
5468
+ // src/metadata-capture.ts
5469
+ var MAX_TOTAL_BYTES;
5470
+ var init_metadata_capture = __esm({
5471
+ "src/metadata-capture.ts"() {
5472
+ "use strict";
5473
+ MAX_TOTAL_BYTES = 16 * 1024;
5474
+ }
5475
+ });
5476
+
5302
5477
  // src/adapters/express.ts
5303
5478
  var DEFAULT_ROUTES_REFRESH_MS;
5304
5479
  var init_express = __esm({
@@ -5311,6 +5486,7 @@ var init_express = __esm({
5311
5486
  init_approval_gate();
5312
5487
  init_pdlss_pre_check();
5313
5488
  init_well_known();
5489
+ init_metadata_capture();
5314
5490
  DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
5315
5491
  }
5316
5492
  });
@@ -5324,6 +5500,7 @@ var init_nextjs = __esm({
5324
5500
  init_verify();
5325
5501
  init_http();
5326
5502
  init_pdlss_pre_check();
5503
+ init_metadata_capture();
5327
5504
  init_http_pdlss();
5328
5505
  init_approval_gate();
5329
5506
  DEFAULT_ROUTES_REFRESH_MS2 = 5 * 60 * 1e3;
@@ -5761,6 +5938,7 @@ var init_src = __esm({
5761
5938
  init_edge_config();
5762
5939
  init_platform_signatures();
5763
5940
  init_verify();
5941
+ init_metadata_capture();
5764
5942
  init_version();
5765
5943
  }
5766
5944
  });
@@ -5827,21 +6005,93 @@ var init_online = __esm({
5827
6005
  }
5828
6006
  });
5829
6007
 
6008
+ // src/gateway/redact.ts
6009
+ function redactSecrets(text) {
6010
+ let result = text;
6011
+ for (const { type: type2, re, replacement } of REDACTION_PATTERNS) {
6012
+ result = result.replace(re, replacement ?? marker(type2));
6013
+ }
6014
+ return result;
6015
+ }
6016
+ function redactDeep(value) {
6017
+ if (typeof value === "string") {
6018
+ return redactSecrets(value);
6019
+ }
6020
+ if (Array.isArray(value)) {
6021
+ return value.map((item) => redactDeep(item));
6022
+ }
6023
+ if (value !== null && typeof value === "object" && !(value instanceof Date)) {
6024
+ const out = {};
6025
+ for (const [k, v] of Object.entries(value)) {
6026
+ out[k] = redactDeep(v);
6027
+ }
6028
+ return out;
6029
+ }
6030
+ return value;
6031
+ }
6032
+ var marker, REDACTION_PATTERNS;
6033
+ var init_redact = __esm({
6034
+ "src/gateway/redact.ts"() {
6035
+ "use strict";
6036
+ marker = (type2) => `[REDACTED:${type2}]`;
6037
+ REDACTION_PATTERNS = [
6038
+ // Multi-line blocks first so later single-line patterns don't shred them.
6039
+ {
6040
+ type: "private-key",
6041
+ re: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z ]*PRIVATE KEY-----|$)/g
6042
+ },
6043
+ // URL userinfo credentials (https://user:pass@, x-access-token:ghp_…@).
6044
+ {
6045
+ type: "url-credentials",
6046
+ re: /([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+:[^\s/@]+@/gi,
6047
+ replacement: `$1${marker("url-credentials")}@`
6048
+ },
6049
+ // Known token formats.
6050
+ { type: "github-token", re: /\bgh[pousr]_[A-Za-z0-9]{20,255}\b/g },
6051
+ { type: "github-token", re: /\bgithub_pat_[A-Za-z0-9_]{20,255}\b/g },
6052
+ { type: "astrasync-key", re: /\bkya_[A-Fa-f0-9]{32,128}\b/g },
6053
+ { type: "openai-key", re: /\bsk-[A-Za-z0-9_-]{20,}\b/g },
6054
+ { type: "aws-access-key-id", re: /\bAKIA[0-9A-Z]{16}\b/g },
6055
+ { type: "jwt", re: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g },
6056
+ // Bearer/token headers.
6057
+ {
6058
+ type: "bearer-token",
6059
+ re: /\b(bearer\s+)[a-z0-9._~+/=-]{16,}/gi,
6060
+ replacement: `$1${marker("bearer-token")}`
6061
+ },
6062
+ // Generic KEY=value / key: value assignments with secret-ish names.
6063
+ {
6064
+ type: "assigned-secret",
6065
+ re: /\b((?:password|passwd|secret|token|api[_-]?key|apikey|access[_-]?key|client[_-]?secret|private[_-]?key)\s*[=:]\s*)(['"]?)[^\s'"&;]{8,}\2/gi,
6066
+ replacement: `$1$2${marker("assigned-secret")}$2`
6067
+ }
6068
+ ];
6069
+ }
6070
+ });
6071
+
5830
6072
  // src/gateway/modes/hybrid.ts
6073
+ function delay(ms) {
6074
+ return new Promise((resolve) => {
6075
+ const timer = setTimeout(() => resolve(FLUSH_TIMEOUT), ms);
6076
+ if (typeof timer.unref === "function") timer.unref();
6077
+ });
6078
+ }
5831
6079
  function verifyHybrid(evaluator, syncQueue, context) {
5832
6080
  const decision = evaluator.evaluate(context);
5833
6081
  syncQueue.enqueue(context, decision);
5834
6082
  return decision;
5835
6083
  }
5836
- var import_fs2, import_path, MAX_QUEUE_SIZE, MAX_RETRIES, HybridSyncQueue;
6084
+ var import_fs2, import_path, MAX_QUEUE_SIZE, MAX_RETRIES, FLUSH_TIMEOUT, HybridSyncQueue;
5837
6085
  var init_hybrid = __esm({
5838
6086
  "src/gateway/modes/hybrid.ts"() {
5839
6087
  "use strict";
5840
6088
  import_fs2 = require("fs");
5841
6089
  import_path = require("path");
5842
6090
  init_online();
6091
+ init_redact();
5843
6092
  MAX_QUEUE_SIZE = 1e3;
5844
6093
  MAX_RETRIES = 3;
6094
+ FLUSH_TIMEOUT = /* @__PURE__ */ Symbol("flush-timeout");
5845
6095
  HybridSyncQueue = class {
5846
6096
  constructor(config, persistPath) {
5847
6097
  this.queue = [];
@@ -5862,12 +6112,12 @@ var init_hybrid = __esm({
5862
6112
  /**
5863
6113
  * Stop periodic sync and flush remaining entries.
5864
6114
  */
5865
- async stop() {
6115
+ async stop(flushOptions = {}) {
5866
6116
  if (this.timer) {
5867
6117
  clearInterval(this.timer);
5868
6118
  this.timer = null;
5869
6119
  }
5870
- await this.flush();
6120
+ await this.flush(flushOptions);
5871
6121
  this.saveToDisk();
5872
6122
  }
5873
6123
  /**
@@ -5879,8 +6129,8 @@ var init_hybrid = __esm({
5879
6129
  }
5880
6130
  this.queue.push({
5881
6131
  id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
5882
- context,
5883
- decision,
6132
+ context: redactDeep(context),
6133
+ decision: redactDeep(decision),
5884
6134
  timestamp: /* @__PURE__ */ new Date(),
5885
6135
  retryCount: 0,
5886
6136
  status: "pending"
@@ -5890,16 +6140,21 @@ var init_hybrid = __esm({
5890
6140
  /**
5891
6141
  * Flush pending entries to the API.
5892
6142
  */
5893
- async flush() {
6143
+ async flush(options = {}) {
5894
6144
  if (this.processing) return;
5895
6145
  this.processing = true;
5896
6146
  try {
5897
6147
  const pending = this.queue.filter((e) => e.status === "pending");
5898
- for (const entry of pending) {
5899
- try {
5900
- await verifyOnline(this.config, entry.context);
6148
+ const batch = typeof options.limit === "number" ? pending.slice(0, options.limit) : pending;
6149
+ for (const entry of batch) {
6150
+ const attempt = verifyOnline(this.config, entry.context, this.config.agentId).then(() => "synced").catch(() => "error");
6151
+ const result = options.perEntryTimeoutMs ? await Promise.race([attempt, delay(options.perEntryTimeoutMs)]) : await attempt;
6152
+ if (result === FLUSH_TIMEOUT) {
6153
+ break;
6154
+ }
6155
+ if (result === "synced") {
5901
6156
  entry.status = "synced";
5902
- } catch {
6157
+ } else {
5903
6158
  entry.retryCount++;
5904
6159
  if (entry.retryCount >= MAX_RETRIES) {
5905
6160
  entry.status = "failed";
@@ -5958,6 +6213,7 @@ var init_trace_logger = __esm({
5958
6213
  "use strict";
5959
6214
  import_fs3 = require("fs");
5960
6215
  import_path2 = require("path");
6216
+ init_redact();
5961
6217
  MAX_FILE_SIZE = 10 * 1024 * 1024;
5962
6218
  MAX_FILES = 10;
5963
6219
  TraceLogger = class {
@@ -5977,8 +6233,8 @@ var init_trace_logger = __esm({
5977
6233
  id: this.generateId(),
5978
6234
  timestamp: /* @__PURE__ */ new Date(),
5979
6235
  type: "evaluation",
5980
- context,
5981
- decision
6236
+ context: redactDeep(context),
6237
+ decision: redactDeep(decision)
5982
6238
  });
5983
6239
  }
5984
6240
  /**
@@ -6106,10 +6362,12 @@ var init_gateway = __esm({
6106
6362
  }
6107
6363
  /**
6108
6364
  * Graceful shutdown. Flushes sync queue and cleans up resources.
6365
+ * Stateless callers (hooks) pass bounded flush options so sync never
6366
+ * sits on a tool call's critical path.
6109
6367
  */
6110
- async shutdown() {
6368
+ async shutdown(options) {
6111
6369
  if (this.syncQueue) {
6112
- await this.syncQueue.stop();
6370
+ await this.syncQueue.stop(options?.syncFlush ?? {});
6113
6371
  this.syncQueue = null;
6114
6372
  }
6115
6373
  this.evaluator = null;
@@ -6132,7 +6390,7 @@ var init_gateway = __esm({
6132
6390
  let decision;
6133
6391
  switch (this.config.mode) {
6134
6392
  case "online":
6135
- decision = await verifyOnline(this.config, context, astraId);
6393
+ decision = await verifyOnline(this.config, context, astraId ?? this.config.agentId);
6136
6394
  break;
6137
6395
  case "local":
6138
6396
  if (!this.evaluator) throw new Error("Local evaluator not initialized");
@@ -6700,7 +6958,7 @@ async function cmdUninstallHooks() {
6700
6958
  function resolveClaudeHookCommand() {
6701
6959
  const sibling = path.join(__dirname, "astrasync-claude-hook.js");
6702
6960
  if (fs.existsSync(sibling)) {
6703
- return `node "${sibling}"`;
6961
+ return `"${process.execPath}" "${sibling}"`;
6704
6962
  }
6705
6963
  return "astrasync-claude-hook";
6706
6964
  }