@cybedefend/vibedefend 1.6.0 → 1.8.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.
Files changed (79) hide show
  1. package/README.md +24 -13
  2. package/dist/clients/antigravity.js +327 -0
  3. package/dist/clients/antigravity.js.map +1 -0
  4. package/dist/clients/registry.js +2 -0
  5. package/dist/clients/registry.js.map +1 -1
  6. package/dist/commands/mcp/proxy.js +67 -11
  7. package/dist/commands/mcp/proxy.js.map +1 -1
  8. package/dist/hook-runner.js +902 -227
  9. package/dist/hooks/install.js +1 -1
  10. package/dist/hooks/install.js.map +1 -1
  11. package/dist/hooks/runtime/antigravity-session.js +400 -0
  12. package/dist/hooks/runtime/antigravity-session.js.map +1 -0
  13. package/dist/hooks/runtime/emit.js +206 -0
  14. package/dist/hooks/runtime/emit.js.map +1 -1
  15. package/dist/hooks/runtime/exit-deadlock-guard.js +46 -0
  16. package/dist/hooks/runtime/exit-deadlock-guard.js.map +1 -0
  17. package/dist/hooks/runtime/fetch-rules.js +39 -3
  18. package/dist/hooks/runtime/fetch-rules.js.map +1 -1
  19. package/dist/hooks/runtime/pre-invocation.js +45 -0
  20. package/dist/hooks/runtime/pre-invocation.js.map +1 -0
  21. package/dist/hooks/runtime/runner-args.js +12 -0
  22. package/dist/hooks/runtime/runner-args.js.map +1 -0
  23. package/dist/hooks/runtime/session-activation.js +10 -4
  24. package/dist/hooks/runtime/session-activation.js.map +1 -1
  25. package/dist/hooks/runtime/session-review.js +42 -0
  26. package/dist/hooks/runtime/session-review.js.map +1 -1
  27. package/dist/hooks/runtime/session-start.js +21 -1
  28. package/dist/hooks/runtime/session-start.js.map +1 -1
  29. package/dist/hooks/runtime/sniff.js +325 -70
  30. package/dist/hooks/runtime/sniff.js.map +1 -1
  31. package/dist/hooks/runtime/work-dir.js +3 -0
  32. package/dist/hooks/runtime/work-dir.js.map +1 -1
  33. package/dist/hooks/shim.js +102 -5
  34. package/dist/hooks/shim.js.map +1 -1
  35. package/dist/json-file.js +6 -3
  36. package/dist/json-file.js.map +1 -1
  37. package/dist/mcp/proxy/audit.js.map +1 -1
  38. package/dist/mcp/proxy/inject.js +20 -5
  39. package/dist/mcp/proxy/inject.js.map +1 -1
  40. package/dist/mcp/proxy/intercept.js +26 -0
  41. package/dist/mcp/proxy/intercept.js.map +1 -1
  42. package/dist/mcp/proxy/paths.js +4 -0
  43. package/dist/mcp/proxy/paths.js.map +1 -1
  44. package/dist/mcp/proxy/proxy.js +12 -2
  45. package/dist/mcp/proxy/proxy.js.map +1 -1
  46. package/dist/mcp/proxy/serverCheckTimer.js +75 -0
  47. package/dist/mcp/proxy/serverCheckTimer.js.map +1 -0
  48. package/dist/mcp/proxy/sessionLifecycle.js +29 -0
  49. package/dist/mcp/proxy/sessionLifecycle.js.map +1 -0
  50. package/dist/mcp/proxy/verifyInterceptor.js +186 -27
  51. package/dist/mcp/proxy/verifyInterceptor.js.map +1 -1
  52. package/dist/mcp/report/buffer.js +351 -0
  53. package/dist/mcp/report/buffer.js.map +1 -0
  54. package/dist/mcp/report/coalesce.js +165 -0
  55. package/dist/mcp/report/coalesce.js.map +1 -0
  56. package/dist/mcp/report/constants.js +51 -0
  57. package/dist/mcp/report/constants.js.map +1 -0
  58. package/dist/mcp/report/project.js +83 -0
  59. package/dist/mcp/report/project.js.map +1 -0
  60. package/dist/mcp/report/reporter.js +443 -0
  61. package/dist/mcp/report/reporter.js.map +1 -0
  62. package/dist/mcp/report/types.js +3 -0
  63. package/dist/mcp/report/types.js.map +1 -0
  64. package/dist/mcp/report/validate.js +179 -0
  65. package/dist/mcp/report/validate.js.map +1 -0
  66. package/dist/mcp/verify/api.js +39 -0
  67. package/dist/mcp/verify/api.js.map +1 -1
  68. package/dist/mcp/verify/cache.js +18 -0
  69. package/dist/mcp/verify/cache.js.map +1 -1
  70. package/dist/mcp/verify/identity.js +120 -7
  71. package/dist/mcp/verify/identity.js.map +1 -1
  72. package/dist/mcp/verify/policy.js +2 -0
  73. package/dist/mcp/verify/policy.js.map +1 -1
  74. package/dist/mcp/verify/verifier.js +189 -32
  75. package/dist/mcp/verify/verifier.js.map +1 -1
  76. package/dist/shim.js +53 -3
  77. package/dist/utils.js +9 -0
  78. package/dist/utils.js.map +1 -1
  79. package/package.json +4 -3
@@ -4630,6 +4630,34 @@ var require_re22 = __commonJS({
4630
4630
  }
4631
4631
  });
4632
4632
 
4633
+ // src/hooks/runtime/exit-deadlock-guard.ts
4634
+ import { setFlagsFromString } from "node:v8";
4635
+
4636
+ // src/hooks/runtime/runner-args.ts
4637
+ function parseRunnerArgs(argv) {
4638
+ const subcommand = argv[0] ?? "";
4639
+ let client = null;
4640
+ for (let i = 1; i < argv.length - 1; i++) {
4641
+ if (argv[i] === "--client" && argv[i + 1] === "antigravity") {
4642
+ client = "antigravity";
4643
+ break;
4644
+ }
4645
+ }
4646
+ return { subcommand, client };
4647
+ }
4648
+
4649
+ // src/hooks/runtime/exit-deadlock-guard.ts
4650
+ function exitDeadlockFlags(argv) {
4651
+ if (parseRunnerArgs(argv).client !== "antigravity") return [];
4652
+ return ["--no-concurrent-sparkplug", "--no-maglev"];
4653
+ }
4654
+ for (const flag of exitDeadlockFlags(process.argv.slice(2))) {
4655
+ try {
4656
+ setFlagsFromString(flag);
4657
+ } catch {
4658
+ }
4659
+ }
4660
+
4633
4661
  // src/hooks/runtime/sniff.ts
4634
4662
  import { homedir } from "node:os";
4635
4663
  import { isAbsolute, resolve as resolvePath } from "node:path";
@@ -4869,65 +4897,205 @@ function filePathFromPatch(patch) {
4869
4897
  }
4870
4898
  return "";
4871
4899
  }
4872
- function joinMultiEditNewStrings(edits) {
4873
- if (!Array.isArray(edits)) return "";
4874
- return edits.map((e) => typeof e.new_string === "string" ? e.new_string : "").filter((s) => s.length > 0).join("\n---\n");
4900
+ function joinStringField(entries, field) {
4901
+ if (!Array.isArray(entries)) return "";
4902
+ return entries.map((e) => {
4903
+ if (typeof e !== "object" || e === null) return "";
4904
+ const value = e[field];
4905
+ return typeof value === "string" ? value : "";
4906
+ }).filter((s) => s.length > 0).join("\n---\n");
4907
+ }
4908
+ function isAntigravityEnvelope(input2) {
4909
+ return typeof input2.conversationId === "string" && Array.isArray(input2.workspacePaths);
4910
+ }
4911
+ var ANTIGRAVITY_PATH_ARGS = [
4912
+ "TargetFile",
4913
+ "AbsolutePath",
4914
+ "Path",
4915
+ "FilePath",
4916
+ "file_path",
4917
+ "path"
4918
+ ];
4919
+ var ANTIGRAVITY_OWN_PATH_ARG = /* @__PURE__ */ new Map([
4920
+ ["write_to_file", "TargetFile"],
4921
+ ["replace_file_content", "TargetFile"],
4922
+ ["multi_replace_file_content", "TargetFile"],
4923
+ ["view_file", "AbsolutePath"],
4924
+ ["write_file", "Path"],
4925
+ ["edit_file", "Path"],
4926
+ ["read_file", "Path"]
4927
+ ]);
4928
+ function antigravityFilePathArg(toolName, args) {
4929
+ const own2 = ANTIGRAVITY_OWN_PATH_ARG.get(toolName);
4930
+ for (const key of own2 === void 0 ? ANTIGRAVITY_PATH_ARGS : [own2, ...ANTIGRAVITY_PATH_ARGS]) {
4931
+ const value = args[key];
4932
+ if (typeof value === "string" && value.length > 0) return value;
4933
+ }
4934
+ return "";
4875
4935
  }
4876
- function joinWindsurfEdits(edits) {
4877
- return joinMultiEditNewStrings(edits);
4936
+ var ANTIGRAVITY_KNOWN_TOOLS = /* @__PURE__ */ new Set([
4937
+ ...ANTIGRAVITY_OWN_PATH_ARG.keys(),
4938
+ "run_command",
4939
+ "read_url_content",
4940
+ "call_mcp_tool"
4941
+ ]);
4942
+ var ANTIGRAVITY_CONTENT_KEY_RE = /content|replacement|chunk|edit|patch|diff/i;
4943
+ function classifyUnknownAntigravityTool(args) {
4944
+ const pathKeys = new Set(ANTIGRAVITY_PATH_ARGS);
4945
+ for (const key of Object.keys(args)) {
4946
+ if (pathKeys.has(key)) continue;
4947
+ if (ANTIGRAVITY_CONTENT_KEY_RE.test(key)) return "Write";
4948
+ }
4949
+ return "Read";
4950
+ }
4951
+ function unknownAntigravityContent(args) {
4952
+ const pathKeys = new Set(ANTIGRAVITY_PATH_ARGS);
4953
+ for (const key of Object.keys(args)) {
4954
+ if (pathKeys.has(key)) continue;
4955
+ if (!ANTIGRAVITY_CONTENT_KEY_RE.test(key)) continue;
4956
+ const value = args[key];
4957
+ if (typeof value === "string" && value.length > 0) return value;
4958
+ }
4959
+ return "";
4878
4960
  }
4879
- function sniff(input2) {
4880
- if (typeof input2.agent_action_name === "string") {
4881
- const action = input2.agent_action_name;
4882
- const toolInfo = input2.tool_info ?? {};
4883
- const filePath = typeof toolInfo.file_path === "string" ? toolInfo.file_path : "";
4884
- const newContent = joinWindsurfEdits(
4885
- toolInfo.edits
4886
- );
4887
- let toolName = action;
4888
- if (action === "pre_write_code" || action === "post_write_code") {
4889
- toolName = "Write";
4890
- } else if (action === "pre_read_code" || action === "post_read_code") {
4891
- toolName = "Read";
4961
+ function antigravityAllPathArgs(args) {
4962
+ const seen = /* @__PURE__ */ new Set();
4963
+ const out = [];
4964
+ for (const key of ANTIGRAVITY_PATH_ARGS) {
4965
+ const value = args[key];
4966
+ if (typeof value === "string" && value.length > 0 && !seen.has(value)) {
4967
+ seen.add(value);
4968
+ out.push(value);
4892
4969
  }
4970
+ }
4971
+ return out;
4972
+ }
4973
+ function resolveAntigravityTargetFile(value, w) {
4974
+ return value.length > 0 ? resolveWriteTarget(w, value) : "";
4975
+ }
4976
+ function stringArg(value) {
4977
+ return typeof value === "string" ? value : "";
4978
+ }
4979
+ function extractAntigravityShape(input2) {
4980
+ const workspacePaths = Array.isArray(input2.workspacePaths) ? input2.workspacePaths : [];
4981
+ const w = workspacePaths.find(
4982
+ (p) => typeof p === "string" && p.length > 0
4983
+ ) ?? process.cwd();
4984
+ const toolCall = typeof input2.toolCall === "object" && input2.toolCall !== null ? input2.toolCall : void 0;
4985
+ if (toolCall === void 0) {
4893
4986
  return {
4894
- client: "windsurf",
4895
- toolName,
4896
- filePath,
4897
- filePaths: filePath ? [filePath] : [],
4898
- newContent,
4987
+ client: "antigravity",
4988
+ toolName: "",
4989
+ filePath: "",
4990
+ filePaths: [],
4991
+ newContent: "",
4899
4992
  raw: input2
4900
4993
  };
4901
4994
  }
4902
- if ("hookEventName" in input2) {
4903
- return extractToolInputShape(input2, "vscode");
4995
+ const name = typeof toolCall.name === "string" ? toolCall.name : "";
4996
+ const args = toolCall.args ?? {};
4997
+ let toolName = name;
4998
+ let filePath = resolveAntigravityTargetFile(antigravityFilePathArg(name, args), w);
4999
+ let filePaths = [];
5000
+ let newContent = "";
5001
+ switch (name) {
5002
+ case "write_to_file":
5003
+ toolName = "Write";
5004
+ newContent = stringArg(args.CodeContent);
5005
+ break;
5006
+ case "write_file":
5007
+ toolName = "Write";
5008
+ newContent = stringArg(args.Content);
5009
+ break;
5010
+ case "replace_file_content":
5011
+ toolName = "Edit";
5012
+ newContent = stringArg(args.ReplacementContent);
5013
+ break;
5014
+ case "edit_file":
5015
+ toolName = "Edit";
5016
+ newContent = stringArg(args.Replacement);
5017
+ break;
5018
+ case "multi_replace_file_content":
5019
+ toolName = "MultiEdit";
5020
+ newContent = joinStringField(args.ReplacementChunks, "ReplacementContent");
5021
+ break;
5022
+ case "run_command": {
5023
+ toolName = "Bash";
5024
+ const command = typeof args.CommandLine === "string" ? args.CommandLine : "";
5025
+ newContent = command;
5026
+ const cwd = typeof args.Cwd === "string" && args.Cwd.length > 0 ? args.Cwd : w;
5027
+ filePaths = extractShellWriteTargets(command).map(
5028
+ (t) => resolveWriteTarget(cwd, t)
5029
+ );
5030
+ filePath = filePaths[0] ?? "";
5031
+ break;
5032
+ }
5033
+ default:
5034
+ if (name && filePath && !ANTIGRAVITY_KNOWN_TOOLS.has(name)) {
5035
+ if (classifyUnknownAntigravityTool(args) === "Write") {
5036
+ toolName = "Write";
5037
+ newContent = unknownAntigravityContent(args);
5038
+ }
5039
+ }
5040
+ break;
4904
5041
  }
5042
+ if (filePaths.length === 0 && filePath) filePaths = [filePath];
5043
+ return { client: "antigravity", toolName, filePath, filePaths, newContent, raw: input2 };
5044
+ }
5045
+ function detectClient(input2) {
5046
+ if (isAntigravityEnvelope(input2)) return "antigravity";
5047
+ if (typeof input2.agent_action_name === "string") return "windsurf";
5048
+ if ("hookEventName" in input2) return "vscode";
4905
5049
  if ("hook_event_name" in input2) {
4906
5050
  const evt = typeof input2.hook_event_name === "string" ? input2.hook_event_name : "";
4907
- let client;
4908
- if (/^[a-z]/.test(evt)) {
4909
- client = "cursor";
4910
- } else {
4911
- const toolName = typeof input2.tool_name === "string" ? input2.tool_name : "";
4912
- if (toolName === "apply_patch" || "turn_id" in input2) {
4913
- client = "codex";
4914
- } else if (hasIsoTimestamp(input2)) {
4915
- client = "vscode";
4916
- } else {
4917
- client = "claude-code";
4918
- }
4919
- }
4920
- return extractToolInputShape(input2, client);
5051
+ if (/^[a-z]/.test(evt)) return "cursor";
5052
+ const toolName = typeof input2.tool_name === "string" ? input2.tool_name : "";
5053
+ if (toolName === "apply_patch" || "turn_id" in input2) return "codex";
5054
+ if (hasIsoTimestamp(input2)) return "vscode";
5055
+ return "claude-code";
5056
+ }
5057
+ return "unknown";
5058
+ }
5059
+ function extractWindsurfShape(input2) {
5060
+ const action = input2.agent_action_name;
5061
+ const toolInfo = input2.tool_info ?? {};
5062
+ const filePath = typeof toolInfo.file_path === "string" ? toolInfo.file_path : "";
5063
+ const newContent = joinStringField(toolInfo.edits, "new_string");
5064
+ let toolName = action;
5065
+ if (action === "pre_write_code" || action === "post_write_code") {
5066
+ toolName = "Write";
5067
+ } else if (action === "pre_read_code" || action === "post_read_code") {
5068
+ toolName = "Read";
4921
5069
  }
4922
5070
  return {
4923
- client: "unknown",
4924
- toolName: "",
4925
- filePath: "",
4926
- filePaths: [],
4927
- newContent: "",
5071
+ client: "windsurf",
5072
+ toolName,
5073
+ filePath,
5074
+ filePaths: filePath ? [filePath] : [],
5075
+ newContent,
4928
5076
  raw: input2
4929
5077
  };
4930
5078
  }
5079
+ function sniff(input2) {
5080
+ const client = detectClient(input2);
5081
+ switch (client) {
5082
+ case "antigravity":
5083
+ return extractAntigravityShape(input2);
5084
+ case "windsurf":
5085
+ return extractWindsurfShape(input2);
5086
+ case "unknown":
5087
+ return {
5088
+ client: "unknown",
5089
+ toolName: "",
5090
+ filePath: "",
5091
+ filePaths: [],
5092
+ newContent: "",
5093
+ raw: input2
5094
+ };
5095
+ default:
5096
+ return extractToolInputShape(input2, client);
5097
+ }
5098
+ }
4931
5099
  function hasIsoTimestamp(input2) {
4932
5100
  return typeof input2.timestamp === "string" && /^\d{4}-\d{2}-\d{2}T/.test(input2.timestamp);
4933
5101
  }
@@ -4955,9 +5123,7 @@ function extractToolInputShape(input2, client) {
4955
5123
  newContent = typeof toolInput.new_string === "string" ? toolInput.new_string : "";
4956
5124
  break;
4957
5125
  case "MultiEdit":
4958
- newContent = joinMultiEditNewStrings(
4959
- toolInput.edits
4960
- );
5126
+ newContent = joinStringField(toolInput.edits, "new_string");
4961
5127
  break;
4962
5128
  case "apply_patch": {
4963
5129
  const patch = typeof toolInput.patch === "string" ? toolInput.patch : typeof toolInput.command === "string" ? toolInput.command : "";
@@ -6184,9 +6350,15 @@ import { dirname as dirname4, isAbsolute as isAbsolute2, join as join6, resolve
6184
6350
  import { fileURLToPath } from "node:url";
6185
6351
 
6186
6352
  // src/hooks/runtime/emit.ts
6353
+ import { writeSync } from "node:fs";
6187
6354
  var ENVELOPE_CLIENTS = {
6188
6355
  SessionStart: /* @__PURE__ */ new Set(["codex"]),
6189
- PreToolUse: /* @__PURE__ */ new Set(["claude-code", "codex", "vscode"])
6356
+ PreToolUse: /* @__PURE__ */ new Set(["claude-code", "codex", "vscode"]),
6357
+ // Antigravity never reaches this generic envelope: it has its own shapes
6358
+ // per event, handled in `emitAntigravityContext` below. Kept as an empty
6359
+ // set (rather than omitted) so `ENVELOPE_CLIENTS[hookEventName]` stays a
6360
+ // total function over `ContextHookEvent`.
6361
+ PreInvocation: /* @__PURE__ */ new Set()
6190
6362
  };
6191
6363
  var NO_MODEL_CHANNEL = {
6192
6364
  PreToolUse: /* @__PURE__ */ new Set(["cursor"]),
@@ -6195,14 +6367,71 @@ var NO_MODEL_CHANNEL = {
6195
6367
  function hasModelChannel(client, event) {
6196
6368
  return !NO_MODEL_CHANNEL[event]?.has(client);
6197
6369
  }
6370
+ var antigravityWritten = false;
6371
+ function writeStdoutSync(text) {
6372
+ const buf = Buffer.from(text, "utf8");
6373
+ const deadline = Date.now() + 2e3;
6374
+ let pause;
6375
+ let offset = 0;
6376
+ while (offset < buf.length) {
6377
+ let written = 0;
6378
+ try {
6379
+ written = writeSync(1, buf, offset, buf.length - offset);
6380
+ } catch (e) {
6381
+ if (e?.code !== "EAGAIN") return;
6382
+ }
6383
+ offset += written;
6384
+ if (written > 0) continue;
6385
+ if (Date.now() >= deadline) return;
6386
+ pause ??= new Int32Array(new SharedArrayBuffer(4));
6387
+ Atomics.wait(pause, 0, 0, 5);
6388
+ }
6389
+ }
6390
+ var antigravityWriter = writeStdoutSync;
6391
+ function writeAntigravityPayload(payload) {
6392
+ if (antigravityWritten) return;
6393
+ antigravityWritten = true;
6394
+ antigravityWriter(JSON.stringify(payload) + "\n");
6395
+ }
6396
+ function emitAntigravityDecision(decision, reason) {
6397
+ writeAntigravityPayload({ decision, ...reason ? { reason } : {} });
6398
+ }
6399
+ var PRE_TOOL_USE_SUBCOMMANDS = /* @__PURE__ */ new Set([
6400
+ "fetch-rules",
6401
+ "guard-check",
6402
+ "pre-tool-use",
6403
+ "PreToolUse"
6404
+ ]);
6405
+ function finishAntigravityRun(subcommand) {
6406
+ const payload = PRE_TOOL_USE_SUBCOMMANDS.has(subcommand) ? { decision: "allow" } : {};
6407
+ writeAntigravityPayload(payload);
6408
+ }
6409
+ function emitAntigravityContext(body, hookEventName) {
6410
+ if (hookEventName === "PreToolUse") return;
6411
+ if (hookEventName === "SessionStart") {
6412
+ writeAntigravityPayload({
6413
+ injectSteps: [{ systemMessage: { systemMessage: body } }]
6414
+ });
6415
+ return;
6416
+ }
6417
+ writeAntigravityPayload({ injectSteps: [{ ephemeralMessage: body }] });
6418
+ }
6198
6419
  function emit(body, client) {
6199
6420
  if (!body) return;
6421
+ if (client === "antigravity") {
6422
+ writeAntigravityPayload({ injectSteps: [{ ephemeralMessage: body }] });
6423
+ return;
6424
+ }
6200
6425
  if (client === "cursor") return;
6201
6426
  process.stdout.write(body);
6202
6427
  if (!body.endsWith("\n")) process.stdout.write("\n");
6203
6428
  }
6204
6429
  function emitContext(body, client, hookEventName) {
6205
6430
  if (!body) return;
6431
+ if (client === "antigravity") {
6432
+ emitAntigravityContext(body, hookEventName);
6433
+ return;
6434
+ }
6206
6435
  if (!hasModelChannel(client, hookEventName)) return;
6207
6436
  if (client === "cursor" && hookEventName === "SessionStart") {
6208
6437
  writeJson({ additional_context: body });
@@ -6262,6 +6491,9 @@ function emitStop(body, client, reason) {
6262
6491
  case "cursor":
6263
6492
  writeJson({ followup_message: body });
6264
6493
  return;
6494
+ case "antigravity":
6495
+ writeAntigravityPayload({ decision: "continue", reason: body });
6496
+ return;
6265
6497
  default:
6266
6498
  emit(body, client);
6267
6499
  }
@@ -6330,7 +6562,7 @@ function defaultInactiveSessionStore(file2 = defaultStoreFile(), now = Date.now)
6330
6562
  };
6331
6563
  }
6332
6564
  function sessionIdOf(stdin) {
6333
- for (const key of ["session_id", "sessionId", "conversation_id", "trajectory_id"]) {
6565
+ for (const key of ["session_id", "sessionId", "conversation_id", "trajectory_id", "conversationId"]) {
6334
6566
  const v = stdin[key];
6335
6567
  if (typeof v === "string" && v.length > 0) return v;
6336
6568
  }
@@ -6343,6 +6575,9 @@ function sessionFolderOf(stdin, client, env = process.env) {
6343
6575
  if (Array.isArray(roots)) candidates.push(roots[0]);
6344
6576
  candidates.push(env.CURSOR_PROJECT_DIR);
6345
6577
  }
6578
+ if (client === "antigravity" && Array.isArray(stdin.workspacePaths)) {
6579
+ candidates.push(...stdin.workspacePaths);
6580
+ }
6346
6581
  candidates.push(stdin.cwd);
6347
6582
  for (const c of candidates) {
6348
6583
  const folder = absoluteFolder(c);
@@ -6453,10 +6688,260 @@ function projectDirForFile(file2, workDir) {
6453
6688
  return fileRoot;
6454
6689
  }
6455
6690
 
6691
+ // src/hooks/runtime/antigravity-session.ts
6692
+ import {
6693
+ appendFileSync,
6694
+ closeSync,
6695
+ constants,
6696
+ lstatSync,
6697
+ mkdirSync as mkdirSync6,
6698
+ openSync,
6699
+ readdirSync,
6700
+ readFileSync as readFileSync9,
6701
+ renameSync,
6702
+ rmSync,
6703
+ unlinkSync,
6704
+ utimesSync,
6705
+ writeFileSync as writeFileSync6,
6706
+ writeSync as writeSync2
6707
+ } from "node:fs";
6708
+ import { createHash as createHash2, randomBytes } from "node:crypto";
6709
+ import { homedir as homedir8 } from "node:os";
6710
+ import { join as join8 } from "node:path";
6711
+ var MAX_STASHED_CONTEXTS = 20;
6712
+ var DEFAULT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
6713
+ var STASH_NAME_RE = /^\d+-[0-9a-f]{8}\.md$/;
6714
+ var DIR_MODE = 448;
6715
+ var FILE_MODE = 384;
6716
+ function conversationKey(raw) {
6717
+ const id = raw.conversationId;
6718
+ if (typeof id !== "string" || id.length === 0 || id.length > 256) return null;
6719
+ return createHash2("sha256").update(id).digest("hex").slice(0, 32);
6720
+ }
6721
+ function antigravityStateDir() {
6722
+ return join8(homedir8(), ".cybedefend", "antigravity");
6723
+ }
6724
+ function keyDir(key, dir) {
6725
+ return join8(dir, key);
6726
+ }
6727
+ function isFinalStashName(name) {
6728
+ return STASH_NAME_RE.test(name);
6729
+ }
6730
+ function isUnsafePath(path) {
6731
+ try {
6732
+ return !lstatSync(path).isDirectory();
6733
+ } catch {
6734
+ return false;
6735
+ }
6736
+ }
6737
+ function isUnsafeFilePath(path) {
6738
+ try {
6739
+ return !lstatSync(path).isFile();
6740
+ } catch {
6741
+ return false;
6742
+ }
6743
+ }
6744
+ var NOFOLLOW_SUPPORTED = typeof constants.O_NOFOLLOW === "number";
6745
+ function appendLedgerLine(path, line) {
6746
+ if (NOFOLLOW_SUPPORTED) {
6747
+ const fd = openSync(
6748
+ path,
6749
+ constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW,
6750
+ FILE_MODE
6751
+ );
6752
+ try {
6753
+ writeSync2(fd, line, null, "utf8");
6754
+ } finally {
6755
+ closeSync(fd);
6756
+ }
6757
+ return;
6758
+ }
6759
+ if (isUnsafeFilePath(path)) return;
6760
+ appendFileSync(path, line, { mode: FILE_MODE });
6761
+ }
6762
+ function writeMarkerFile(path, content) {
6763
+ if (NOFOLLOW_SUPPORTED) {
6764
+ const fd = openSync(
6765
+ path,
6766
+ constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | constants.O_NOFOLLOW,
6767
+ FILE_MODE
6768
+ );
6769
+ try {
6770
+ writeSync2(fd, content, null, "utf8");
6771
+ } finally {
6772
+ closeSync(fd);
6773
+ }
6774
+ return;
6775
+ }
6776
+ if (isUnsafeFilePath(path)) return;
6777
+ writeFileSync6(path, content, { mode: FILE_MODE });
6778
+ }
6779
+ function ensureRealDir(path) {
6780
+ if (isUnsafePath(path)) return false;
6781
+ mkdirSync6(path, { recursive: true, mode: DIR_MODE });
6782
+ return true;
6783
+ }
6784
+ function ensureLiveKeyDir(key, dir, now) {
6785
+ const kd = keyDir(key, dir);
6786
+ if (!ensureRealDir(kd)) return null;
6787
+ try {
6788
+ const t = new Date(now);
6789
+ utimesSync(kd, t, t);
6790
+ } catch {
6791
+ }
6792
+ return kd;
6793
+ }
6794
+ function stashContext(key, body, dir = antigravityStateDir()) {
6795
+ let tmpPath;
6796
+ try {
6797
+ const now = Date.now();
6798
+ const kd = ensureLiveKeyDir(key, dir, now);
6799
+ if (!kd) return;
6800
+ const contextDir = join8(kd, "context");
6801
+ if (!ensureRealDir(contextDir)) return;
6802
+ const suffix = randomBytes(4).toString("hex");
6803
+ tmpPath = join8(contextDir, `.${now}-${suffix}.tmp`);
6804
+ writeFileSync6(tmpPath, body, { mode: FILE_MODE, flag: "wx" });
6805
+ const finalPath = join8(contextDir, `${now}-${suffix}.md`);
6806
+ renameSync(tmpPath, finalPath);
6807
+ tmpPath = void 0;
6808
+ const kept = readdirSync(contextDir).filter(isFinalStashName).sort();
6809
+ const excess = kept.length - MAX_STASHED_CONTEXTS;
6810
+ if (excess > 0) {
6811
+ for (const stale of kept.slice(0, excess)) {
6812
+ try {
6813
+ unlinkSync(join8(contextDir, stale));
6814
+ } catch {
6815
+ }
6816
+ }
6817
+ }
6818
+ } catch {
6819
+ if (tmpPath) {
6820
+ try {
6821
+ unlinkSync(tmpPath);
6822
+ } catch {
6823
+ }
6824
+ }
6825
+ }
6826
+ }
6827
+ function drainContext(key, dir = antigravityStateDir()) {
6828
+ try {
6829
+ const kd = keyDir(key, dir);
6830
+ if (isUnsafePath(kd)) return [];
6831
+ const contextDir = join8(kd, "context");
6832
+ if (isUnsafePath(contextDir)) return [];
6833
+ const entries = readdirSync(contextDir).filter(isFinalStashName).sort();
6834
+ const seen = /* @__PURE__ */ new Set();
6835
+ const bodies = [];
6836
+ for (const name of entries) {
6837
+ const filePath = join8(contextDir, name);
6838
+ try {
6839
+ const body = readFileSync9(filePath, "utf8");
6840
+ if (!seen.has(body)) {
6841
+ seen.add(body);
6842
+ bodies.push(body);
6843
+ }
6844
+ } catch {
6845
+ }
6846
+ try {
6847
+ unlinkSync(filePath);
6848
+ } catch {
6849
+ }
6850
+ }
6851
+ return bodies;
6852
+ } catch {
6853
+ return [];
6854
+ }
6855
+ }
6856
+ function recordEdit(key, file2, dir = antigravityStateDir()) {
6857
+ try {
6858
+ const now = Date.now();
6859
+ const kd = ensureLiveKeyDir(key, dir, now);
6860
+ if (!kd) return;
6861
+ appendLedgerLine(join8(kd, "edits.jsonl"), JSON.stringify({ f: file2 }) + "\n");
6862
+ } catch {
6863
+ }
6864
+ }
6865
+ function readEdits(key, dir = antigravityStateDir()) {
6866
+ try {
6867
+ const kd = keyDir(key, dir);
6868
+ if (isUnsafePath(kd)) return { count: 0, files: [] };
6869
+ const editsPath = join8(kd, "edits.jsonl");
6870
+ if (isUnsafeFilePath(editsPath)) return { count: 0, files: [] };
6871
+ const content = readFileSync9(editsPath, "utf8");
6872
+ let count = 0;
6873
+ const files = [];
6874
+ const seen = /* @__PURE__ */ new Set();
6875
+ for (const line of content.split("\n")) {
6876
+ const trimmed = line.trim();
6877
+ if (!trimmed) continue;
6878
+ let parsed;
6879
+ try {
6880
+ parsed = JSON.parse(trimmed);
6881
+ } catch {
6882
+ continue;
6883
+ }
6884
+ if (typeof parsed.f !== "string") continue;
6885
+ count++;
6886
+ if (!seen.has(parsed.f)) {
6887
+ seen.add(parsed.f);
6888
+ files.push(parsed.f);
6889
+ }
6890
+ }
6891
+ return { count, files };
6892
+ } catch {
6893
+ return { count: 0, files: [] };
6894
+ }
6895
+ }
6896
+ function markReviewed(key, dir = antigravityStateDir()) {
6897
+ try {
6898
+ const now = Date.now();
6899
+ const kd = ensureLiveKeyDir(key, dir, now);
6900
+ if (!kd) return;
6901
+ writeMarkerFile(join8(kd, "reviewed"), String(now));
6902
+ } catch {
6903
+ }
6904
+ }
6905
+ function isReviewed(key, dir = antigravityStateDir()) {
6906
+ try {
6907
+ const kd = keyDir(key, dir);
6908
+ if (isUnsafePath(kd)) return false;
6909
+ return lstatSync(join8(kd, "reviewed")).isFile();
6910
+ } catch {
6911
+ return false;
6912
+ }
6913
+ }
6914
+ function pruneStale(dir = antigravityStateDir(), now = Date.now(), maxAgeMs = DEFAULT_MAX_AGE_MS) {
6915
+ try {
6916
+ const entries = readdirSync(dir);
6917
+ for (const name of entries) {
6918
+ const entryPath = join8(dir, name);
6919
+ try {
6920
+ const { mtimeMs } = lstatSync(entryPath);
6921
+ if (now - mtimeMs > maxAgeMs) {
6922
+ rmSync(entryPath, { recursive: true, force: true });
6923
+ }
6924
+ } catch {
6925
+ }
6926
+ }
6927
+ } catch {
6928
+ }
6929
+ }
6930
+
6456
6931
  // src/hooks/runtime/fetch-rules.ts
6457
6932
  function emitPreToolUseContext(body, client) {
6458
6933
  emitContext(body, client, "PreToolUse");
6459
6934
  }
6935
+ function defaultEmit(stdin, stateDir) {
6936
+ return (body, client) => {
6937
+ if (client === "antigravity") {
6938
+ const key = conversationKey(stdin);
6939
+ if (key) stashContext(key, body, stateDir);
6940
+ return;
6941
+ }
6942
+ emitPreToolUseContext(body, client);
6943
+ };
6944
+ }
6460
6945
  var INTERESTED_TOOLS = /* @__PURE__ */ new Set([
6461
6946
  "Edit",
6462
6947
  "Write",
@@ -6471,13 +6956,17 @@ async function fetchRulesHook(deps = {}) {
6471
6956
  const resolveTok = deps.resolveTokenFn ?? resolveToken;
6472
6957
  const fetchRules = deps.fetchRulesFn ?? fetchBusinessRules;
6473
6958
  const fetchSecRules = deps.fetchSecurityRulesFn ?? fetchSecurityRules;
6474
- const emitFn = deps.emitFn ?? emitPreToolUseContext;
6475
6959
  const usageNotifier = deps.usageNotifier ?? makeUsageNotifier();
6476
6960
  const stdin = await readStdin();
6477
6961
  const event = sniff(stdin);
6962
+ const emitFn = deps.emitFn ?? defaultEmit(stdin, deps.antigravityStateDir);
6478
6963
  if (!INTERESTED_TOOLS.has(event.toolName)) return;
6479
6964
  if (!event.filePath) return;
6480
6965
  if (!hasModelChannel(event.client, "PreToolUse")) return;
6966
+ if (event.client === "antigravity" && (event.toolName === "Write" || event.toolName === "Edit" || event.toolName === "MultiEdit")) {
6967
+ const key = conversationKey(stdin);
6968
+ if (key) recordEdit(key, event.filePath, deps.antigravityStateDir);
6969
+ }
6481
6970
  const config2 = loadConfig();
6482
6971
  if (!config2) return;
6483
6972
  const folder = sessionFolderOf(stdin, event.client);
@@ -6626,9 +7115,9 @@ var DIRECT_PROPOSE_DIRECTIVES = {
6626
7115
 
6627
7116
  // src/hooks/runtime/self-update-check.ts
6628
7117
  import { spawn } from "node:child_process";
6629
- import { existsSync as existsSync11, readFileSync as readFileSync9, rmSync, writeFileSync as writeFileSync6 } from "node:fs";
6630
- import { homedir as homedir8 } from "node:os";
6631
- import { join as join8 } from "node:path";
7118
+ import { existsSync as existsSync11, readFileSync as readFileSync10, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
7119
+ import { homedir as homedir9 } from "node:os";
7120
+ import { join as join9 } from "node:path";
6632
7121
 
6633
7122
  // src/hooks/runtime/semver.ts
6634
7123
  function parseVersion(input2) {
@@ -6706,9 +7195,9 @@ function isValidRegistryVersion(value) {
6706
7195
  }
6707
7196
  async function selfUpdateCheck(deps) {
6708
7197
  const now = deps.now ?? (() => Date.now());
6709
- const dir = deps.cybeDir ?? join8(process.env.CYBEDEFEND_HOME ?? homedir8(), ".cybedefend");
6710
- const throttlePath = join8(dir, "update-check.json");
6711
- const logPath = join8(dir, "last-update.log");
7198
+ const dir = deps.cybeDir ?? join9(process.env.CYBEDEFEND_HOME ?? homedir9(), ".cybedefend");
7199
+ const throttlePath = join9(dir, "update-check.json");
7200
+ const logPath = join9(dir, "last-update.log");
6712
7201
  const installMode = deps.installMode ?? (deps.runnerSource ? detectInstallMode(deps.runnerSource) : detectInstallMode(resolveScriptPath()));
6713
7202
  const priorFailure = takeUpdateLogNotice(logPath);
6714
7203
  const throttle = readThrottle(throttlePath);
@@ -6742,7 +7231,7 @@ function applyOrNotify(deps, installMode, latest, logPath) {
6742
7231
  function readThrottle(path) {
6743
7232
  try {
6744
7233
  if (!existsSync11(path)) return null;
6745
- const data = JSON.parse(readFileSync9(path, "utf8"));
7234
+ const data = JSON.parse(readFileSync10(path, "utf8"));
6746
7235
  if (typeof data.lastCheckedAt !== "number") return null;
6747
7236
  return { lastCheckedAt: data.lastCheckedAt };
6748
7237
  } catch {
@@ -6752,7 +7241,7 @@ function readThrottle(path) {
6752
7241
  function writeThrottle(path, throttle) {
6753
7242
  try {
6754
7243
  ensureDirFor(path);
6755
- writeFileSync6(path, JSON.stringify(throttle) + "\n");
7244
+ writeFileSync7(path, JSON.stringify(throttle) + "\n");
6756
7245
  } catch {
6757
7246
  }
6758
7247
  }
@@ -6761,11 +7250,11 @@ function takeUpdateLogNotice(logPath) {
6761
7250
  if (!existsSync11(logPath)) return null;
6762
7251
  let parsed = {};
6763
7252
  try {
6764
- parsed = JSON.parse(readFileSync9(logPath, "utf8"));
7253
+ parsed = JSON.parse(readFileSync10(logPath, "utf8"));
6765
7254
  } catch {
6766
7255
  parsed = {};
6767
7256
  }
6768
- rmSync(logPath, { force: true });
7257
+ rmSync2(logPath, { force: true });
6769
7258
  if (typeof parsed.exitCode === "number" && parsed.exitCode !== 0) {
6770
7259
  return `\u26A0 vibedefend: last auto-update to ${parsed.to ?? "latest"} failed (exit ${parsed.exitCode}) \u2014 run \`vibedefend update --self\`.`;
6771
7260
  }
@@ -6836,18 +7325,18 @@ function pmCommand(mode, spec) {
6836
7325
 
6837
7326
  // src/hooks/runtime/hook-refresh-trigger.ts
6838
7327
  import { spawn as spawn2 } from "node:child_process";
6839
- import { existsSync as existsSync12, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "node:fs";
6840
- import { homedir as homedir9 } from "node:os";
6841
- import { dirname as dirname6, join as join9 } from "node:path";
7328
+ import { existsSync as existsSync12, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "node:fs";
7329
+ import { homedir as homedir10 } from "node:os";
7330
+ import { dirname as dirname6, join as join10 } from "node:path";
6842
7331
  function maybeRefreshStaleWiring(deps) {
6843
7332
  try {
6844
7333
  const { config: config2, runnerVersion } = deps;
6845
7334
  if (!config2.runnerSource || config2.installedVersion === runnerVersion) {
6846
7335
  return false;
6847
7336
  }
6848
- const cliEntry = join9(dirname6(dirname6(config2.runnerSource)), "bin", "vibedefend.js");
7337
+ const cliEntry = join10(dirname6(dirname6(config2.runnerSource)), "bin", "vibedefend.js");
6849
7338
  if (!(deps.exists ?? existsSync12)(cliEntry)) return false;
6850
- const markerPath = deps.markerPath ?? join9(process.env.CYBEDEFEND_HOME ?? homedir9(), ".cybedefend", "hook-refresh.json");
7339
+ const markerPath = deps.markerPath ?? join10(process.env.CYBEDEFEND_HOME ?? homedir10(), ".cybedefend", "hook-refresh.json");
6851
7340
  if (readMarkerVersion(markerPath) === runnerVersion) return false;
6852
7341
  (deps.spawnRefresh ?? defaultSpawnRefresh)(cliEntry);
6853
7342
  writeMarker(markerPath, runnerVersion);
@@ -6859,7 +7348,7 @@ function maybeRefreshStaleWiring(deps) {
6859
7348
  function readMarkerVersion(path) {
6860
7349
  try {
6861
7350
  if (!existsSync12(path)) return null;
6862
- const data = JSON.parse(readFileSync10(path, "utf8"));
7351
+ const data = JSON.parse(readFileSync11(path, "utf8"));
6863
7352
  return typeof data.version === "string" ? data.version : null;
6864
7353
  } catch {
6865
7354
  return null;
@@ -6868,7 +7357,7 @@ function readMarkerVersion(path) {
6868
7357
  function writeMarker(path, version2) {
6869
7358
  try {
6870
7359
  ensureDirFor(path);
6871
- writeFileSync7(path, JSON.stringify({ version: version2, spawnedAt: Date.now() }) + "\n");
7360
+ writeFileSync8(path, JSON.stringify({ version: version2, spawnedAt: Date.now() }) + "\n");
6872
7361
  } catch {
6873
7362
  }
6874
7363
  }
@@ -6882,18 +7371,18 @@ function defaultSpawnRefresh(cliEntry) {
6882
7371
  }
6883
7372
 
6884
7373
  // src/version.ts
6885
- import { readFileSync as readFileSync11 } from "node:fs";
7374
+ import { readFileSync as readFileSync12 } from "node:fs";
6886
7375
  import { fileURLToPath as fileURLToPath3 } from "node:url";
6887
- import { dirname as dirname7, join as join10 } from "node:path";
7376
+ import { dirname as dirname7, join as join11 } from "node:path";
6888
7377
  var PKG_NAME = "@cybedefend/vibedefend";
6889
7378
  function defaultPkgPath() {
6890
- return join10(dirname7(fileURLToPath3(import.meta.url)), "..", "package.json");
7379
+ return join11(dirname7(fileURLToPath3(import.meta.url)), "..", "package.json");
6891
7380
  }
6892
7381
  function readPackageMeta(opts = {}) {
6893
7382
  if (typeof opts.bakedVersion === "string" && opts.bakedVersion.length > 0) {
6894
7383
  return { name: PKG_NAME, version: opts.bakedVersion };
6895
7384
  }
6896
- const readFile = opts.readFile ?? ((p) => readFileSync11(p, "utf8"));
7385
+ const readFile = opts.readFile ?? ((p) => readFileSync12(p, "utf8"));
6897
7386
  const pkgPath = opts.pkgPath ?? defaultPkgPath();
6898
7387
  try {
6899
7388
  return JSON.parse(readFile(pkgPath));
@@ -6902,7 +7391,7 @@ function readPackageMeta(opts = {}) {
6902
7391
  }
6903
7392
  }
6904
7393
  var pkg = readPackageMeta({
6905
- bakedVersion: true ? "1.6.0" : void 0
7394
+ bakedVersion: true ? "1.8.0" : void 0
6906
7395
  });
6907
7396
 
6908
7397
  // src/hooks/runtime/session-start.ts
@@ -6946,6 +7435,9 @@ async function sessionStartHook(deps = {}) {
6946
7435
  }
6947
7436
  if (sessionId) sessionStore.clear(sessionId);
6948
7437
  const apiBase = process.env.CYBEDEFEND_API_BASE ?? configApiBase ?? config2.region.apiBase;
7438
+ if (event.client === "antigravity") {
7439
+ pruneStale(deps.antigravityStateDir);
7440
+ }
6949
7441
  if (process.env.CYBEDEFEND_DRY_RUN === "1") {
6950
7442
  emitFn(
6951
7443
  `## CybeDefend session bootstrap (dry-run, client=${event.client})
@@ -6998,7 +7490,12 @@ async function sessionStartHook(deps = {}) {
6998
7490
  " **before responding to the user request.**"
6999
7491
  );
7000
7492
  }
7001
- const HARD_ENFORCEMENT_CLIENTS = /* @__PURE__ */ new Set(["claude-code", "codex", "cursor"]);
7493
+ const HARD_ENFORCEMENT_CLIENTS = /* @__PURE__ */ new Set([
7494
+ "claude-code",
7495
+ "codex",
7496
+ "cursor",
7497
+ "antigravity"
7498
+ ]);
7002
7499
  lines.push("");
7003
7500
  if (HARD_ENFORCEMENT_CLIENTS.has(event.client)) {
7004
7501
  lines.push(
@@ -7036,23 +7533,23 @@ async function sessionStartHook(deps = {}) {
7036
7533
  }
7037
7534
 
7038
7535
  // src/hooks/runtime/session-review.ts
7039
- import { existsSync as existsSync14, readFileSync as readFileSync13 } from "node:fs";
7536
+ import { existsSync as existsSync14, readFileSync as readFileSync14 } from "node:fs";
7040
7537
 
7041
7538
  // src/hooks/runtime/review-sessions.ts
7042
- import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "node:fs";
7043
- import { homedir as homedir10 } from "node:os";
7044
- import { dirname as dirname8, join as join11 } from "node:path";
7539
+ import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "node:fs";
7540
+ import { homedir as homedir11 } from "node:os";
7541
+ import { dirname as dirname8, join as join12 } from "node:path";
7045
7542
  var SESSIONS_CAP2 = 200;
7046
7543
  function defaultStoreFile2() {
7047
- const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join11(homedir10(), ".cybedefend");
7048
- return join11(dir, "review-sessions.json");
7544
+ const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join12(homedir11(), ".cybedefend");
7545
+ return join12(dir, "review-sessions.json");
7049
7546
  }
7050
7547
  var isCount = (n) => typeof n === "number" && Number.isInteger(n) && n >= 0;
7051
7548
  function defaultReviewSessionStore(file2 = defaultStoreFile2(), now = Date.now) {
7052
7549
  function load2() {
7053
7550
  if (!existsSync13(file2)) return {};
7054
7551
  try {
7055
- const parsed = JSON.parse(readFileSync12(file2, "utf8"));
7552
+ const parsed = JSON.parse(readFileSync13(file2, "utf8"));
7056
7553
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
7057
7554
  } catch {
7058
7555
  return {};
@@ -7060,8 +7557,8 @@ function defaultReviewSessionStore(file2 = defaultStoreFile2(), now = Date.now)
7060
7557
  }
7061
7558
  function save(map2) {
7062
7559
  try {
7063
- mkdirSync6(dirname8(file2), { recursive: true });
7064
- writeFileSync8(file2, JSON.stringify(map2) + "\n", "utf8");
7560
+ mkdirSync7(dirname8(file2), { recursive: true });
7561
+ writeFileSync9(file2, JSON.stringify(map2) + "\n", "utf8");
7065
7562
  } catch {
7066
7563
  }
7067
7564
  }
@@ -7171,6 +7668,32 @@ async function sessionReviewHook(deps = {}) {
7171
7668
  const config2 = loadConfig();
7172
7669
  if (!config2) return;
7173
7670
  if (!config2.hooks.enableSessionReview) return;
7671
+ if (event.client === "antigravity") {
7672
+ const key = conversationKey(stdin);
7673
+ const stateDir = deps.antigravityStateDir;
7674
+ if (!key || isReviewed(key, stateDir)) return;
7675
+ let { count, files } = readEdits(key, stateDir);
7676
+ if (process.env.CYBEDEFEND_DRY_RUN === "1") {
7677
+ count = parseInt(process.env.CYBEDEFEND_DRY_RUN_EDITS ?? "5", 10);
7678
+ }
7679
+ if (count === 0) return;
7680
+ if (count < resolveReviewThreshold(config2)) return;
7681
+ const folder2 = sessionFolderOf(stdin, "antigravity");
7682
+ if (isSessionInactive(stdin, { store: deps.sessionStore, cwd: folder2 })) return;
7683
+ const { projectId: projectId2 } = await (deps.resolveProject ?? resolveProjectIdWithApi)(folder2);
7684
+ if (!projectId2) return;
7685
+ const proposalMode2 = resolveProposalMode(config2);
7686
+ let body2 = composeReviewBody(count, "antigravity", "", proposalMode2);
7687
+ const withDiffScan2 = config2.hooks.enableDiffScan !== false;
7688
+ if (withDiffScan2) {
7689
+ body2 += "\n" + composeDiffScanBody(
7690
+ files.slice(0, CHANGED_FILES_MAX).map((f) => relativizePath(f, folder2))
7691
+ );
7692
+ }
7693
+ emitFn(body2, "antigravity", composeStopReason(withDiffScan2, proposalMode2));
7694
+ markReviewed(key, stateDir);
7695
+ return;
7696
+ }
7174
7697
  const transcript = loadTranscript(stdin, readTranscriptFile);
7175
7698
  const sessionId = sessionIdOf(stdin);
7176
7699
  const store = sessionId ? deps.reviewStore ?? defaultReviewSessionStore() : null;
@@ -7247,7 +7770,7 @@ function loadTranscript(stdin, readFile) {
7247
7770
  function defaultReadTranscript(path) {
7248
7771
  if (!existsSync14(path)) return null;
7249
7772
  try {
7250
- return readFileSync13(path, "utf8");
7773
+ return readFileSync14(path, "utf8");
7251
7774
  } catch {
7252
7775
  return null;
7253
7776
  }
@@ -7515,19 +8038,19 @@ async function preCompactHook(deps = {}) {
7515
8038
  }
7516
8039
 
7517
8040
  // src/hooks/runtime/user-prompt-submit.ts
7518
- import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "node:fs";
7519
- import { homedir as homedir11 } from "node:os";
7520
- import { join as join12 } from "node:path";
8041
+ import { existsSync as existsSync15, mkdirSync as mkdirSync8, readFileSync as readFileSync15, writeFileSync as writeFileSync10 } from "node:fs";
8042
+ import { homedir as homedir12 } from "node:os";
8043
+ import { join as join13 } from "node:path";
7521
8044
  var SESSIONS_CAP3 = 100;
7522
8045
  function defaultSessionsFile() {
7523
- const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join12(homedir11(), ".cybedefend");
7524
- return join12(dir, "user-prompt-seen-sessions.json");
8046
+ const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join13(homedir12(), ".cybedefend");
8047
+ return join13(dir, "user-prompt-seen-sessions.json");
7525
8048
  }
7526
8049
  function defaultSessionTracker(file2 = defaultSessionsFile()) {
7527
8050
  function load2() {
7528
8051
  if (!existsSync15(file2)) return [];
7529
8052
  try {
7530
- const raw = readFileSync14(file2, "utf8");
8053
+ const raw = readFileSync15(file2, "utf8");
7531
8054
  const data = JSON.parse(raw);
7532
8055
  if (!Array.isArray(data.sessions)) return [];
7533
8056
  return data.sessions.filter((s) => typeof s === "string");
@@ -7544,8 +8067,8 @@ function defaultSessionTracker(file2 = defaultSessionsFile()) {
7544
8067
  if (existing.includes(sessionId)) return;
7545
8068
  const next = [...existing, sessionId].slice(-SESSIONS_CAP3);
7546
8069
  try {
7547
- mkdirSync7(join12(file2, ".."), { recursive: true });
7548
- writeFileSync9(file2, JSON.stringify({ sessions: next }), "utf8");
8070
+ mkdirSync8(join13(file2, ".."), { recursive: true });
8071
+ writeFileSync10(file2, JSON.stringify({ sessions: next }), "utf8");
7549
8072
  } catch {
7550
8073
  }
7551
8074
  }
@@ -7633,6 +8156,20 @@ async function userPromptSubmitHook(deps = {}) {
7633
8156
  }
7634
8157
  }
7635
8158
 
8159
+ // src/hooks/runtime/pre-invocation.ts
8160
+ var STASH_SEPARATOR = "\n\n---\n\n";
8161
+ async function preInvocationHook(deps = {}) {
8162
+ const readStdin = deps.readStdin ?? readStdinJson;
8163
+ const stdin = await readStdin();
8164
+ if (!isAntigravityEnvelope(stdin)) return;
8165
+ const key = conversationKey(stdin);
8166
+ if (!key) return;
8167
+ const dir = deps.stateDir ?? antigravityStateDir();
8168
+ const bodies = drainContext(key, dir);
8169
+ if (bodies.length === 0) return;
8170
+ emitContext(bodies.join(STASH_SEPARATOR), "antigravity", "PreInvocation");
8171
+ }
8172
+
7636
8173
  // src/guards-evaluator/glob.ts
7637
8174
  function expandHome(pattern, homeDir) {
7638
8175
  if (pattern === "~") return homeDir;
@@ -8364,7 +8901,7 @@ function buildCommandViews(raw) {
8364
8901
  }
8365
8902
 
8366
8903
  // src/guards-evaluator/redact.ts
8367
- import { createHash as createHash2 } from "node:crypto";
8904
+ import { createHash as createHash3 } from "node:crypto";
8368
8905
  var REDACTED = "[REDACTED]";
8369
8906
  var PATTERNS = [
8370
8907
  // 1. JWT — three base64url segments separated by dots
@@ -8476,7 +9013,7 @@ function redactScriptText(text) {
8476
9013
  return redactTarget(masked, Number.MAX_SAFE_INTEGER);
8477
9014
  }
8478
9015
  function hashTarget(text) {
8479
- return createHash2("sha256").update(text, "utf8").digest("hex");
9016
+ return createHash3("sha256").update(text, "utf8").digest("hex");
8480
9017
  }
8481
9018
 
8482
9019
  // src/guards-evaluator/evaluate.ts
@@ -11093,15 +11630,15 @@ function resolveCandidatePaths(rawPath, opts) {
11093
11630
  // src/hooks/runtime/session-writes.ts
11094
11631
  import {
11095
11632
  existsSync as existsSync17,
11096
- mkdirSync as mkdirSync8,
11097
- readFileSync as readFileSync16,
11098
- renameSync,
11633
+ mkdirSync as mkdirSync9,
11634
+ readFileSync as readFileSync17,
11635
+ renameSync as renameSync2,
11099
11636
  rmdirSync,
11100
11637
  statSync as statSync3,
11101
- writeFileSync as writeFileSync10
11638
+ writeFileSync as writeFileSync11
11102
11639
  } from "node:fs";
11103
- import { homedir as homedir12 } from "node:os";
11104
- import { join as join13, posix } from "node:path";
11640
+ import { homedir as homedir13 } from "node:os";
11641
+ import { join as join14, posix } from "node:path";
11105
11642
  var DEFAULT_MAX_PATHS = 500;
11106
11643
  var DEFAULT_SESSION_WRITES_TTL_MS = 4 * 60 * 60 * 1e3;
11107
11644
  var SESSION_WRITES_FILE = "guards-session-writes.json";
@@ -11115,7 +11652,7 @@ function withLock(lockDir, fn) {
11115
11652
  let held = false;
11116
11653
  while (!held) {
11117
11654
  try {
11118
- mkdirSync8(lockDir);
11655
+ mkdirSync9(lockDir);
11119
11656
  held = true;
11120
11657
  } catch {
11121
11658
  try {
@@ -11142,7 +11679,7 @@ function withLock(lockDir, fn) {
11142
11679
  }
11143
11680
  }
11144
11681
  function defaultDir() {
11145
- return process.env.CYBEDEFEND_BASELINE_DIR ?? join13(homedir12(), ".cybedefend");
11682
+ return process.env.CYBEDEFEND_BASELINE_DIR ?? join14(homedir13(), ".cybedefend");
11146
11683
  }
11147
11684
  function normalizePath(p) {
11148
11685
  if (typeof p !== "string") return "";
@@ -11177,14 +11714,14 @@ function coerce(raw) {
11177
11714
  }
11178
11715
  function makeSessionWritesStore(opts = {}) {
11179
11716
  const dir = opts.dir ?? defaultDir();
11180
- const file2 = join13(dir, SESSION_WRITES_FILE);
11717
+ const file2 = join14(dir, SESSION_WRITES_FILE);
11181
11718
  const now = opts.now ?? (() => Date.now());
11182
11719
  const maxPaths = typeof opts.maxPaths === "number" && opts.maxPaths > 0 ? Math.floor(opts.maxPaths) : DEFAULT_MAX_PATHS;
11183
11720
  const ttlMs = typeof opts.ttlMs === "number" && opts.ttlMs > 0 ? opts.ttlMs : DEFAULT_SESSION_WRITES_TTL_MS;
11184
11721
  function readAll() {
11185
11722
  if (!existsSync17(file2)) return {};
11186
11723
  try {
11187
- return coerce(JSON.parse(readFileSync16(file2, "utf8")));
11724
+ return coerce(JSON.parse(readFileSync17(file2, "utf8")));
11188
11725
  } catch {
11189
11726
  return {};
11190
11727
  }
@@ -11199,10 +11736,10 @@ function makeSessionWritesStore(opts = {}) {
11199
11736
  }
11200
11737
  function writeAll(all) {
11201
11738
  try {
11202
- if (!existsSync17(dir)) mkdirSync8(dir, { recursive: true });
11739
+ if (!existsSync17(dir)) mkdirSync9(dir, { recursive: true });
11203
11740
  const tmp = `${file2}.${process.pid}.tmp`;
11204
- writeFileSync10(tmp, JSON.stringify(all), "utf8");
11205
- renameSync(tmp, file2);
11741
+ writeFileSync11(tmp, JSON.stringify(all), "utf8");
11742
+ renameSync2(tmp, file2);
11206
11743
  } catch {
11207
11744
  }
11208
11745
  }
@@ -11212,7 +11749,7 @@ function makeSessionWritesStore(opts = {}) {
11212
11749
  const usable = paths.filter(isUsable);
11213
11750
  if (usable.length === 0) return;
11214
11751
  try {
11215
- if (!existsSync17(dir)) mkdirSync8(dir, { recursive: true });
11752
+ if (!existsSync17(dir)) mkdirSync9(dir, { recursive: true });
11216
11753
  withLock(`${file2}.lock`, () => {
11217
11754
  const t = now();
11218
11755
  const all = pruneExpired(readAll(), t);
@@ -11528,10 +12065,10 @@ function nearMiss(req, rule) {
11528
12065
  import { isAbsolute as isAbsolute6, resolve as resolvePath4 } from "node:path";
11529
12066
 
11530
12067
  // src/hooks/runtime/guard-rules-cache.ts
11531
- import { readFileSync as readFileSync17, writeFileSync as writeFileSync11, existsSync as existsSync18, mkdirSync as mkdirSync9 } from "node:fs";
12068
+ import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, existsSync as existsSync18, mkdirSync as mkdirSync10 } from "node:fs";
11532
12069
  import { dirname as dirname9 } from "node:path";
11533
- import { homedir as homedir13 } from "node:os";
11534
- import { join as join14 } from "node:path";
12070
+ import { homedir as homedir14 } from "node:os";
12071
+ import { join as join15 } from "node:path";
11535
12072
 
11536
12073
  // node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/external.js
11537
12074
  var external_exports = {};
@@ -31338,7 +31875,7 @@ function retryAfterOf(e) {
31338
31875
  }
31339
31876
 
31340
31877
  // src/hooks/runtime/retry-policy.ts
31341
- import { createHash as createHash3 } from "node:crypto";
31878
+ import { createHash as createHash4 } from "node:crypto";
31342
31879
  var UNAUTHORIZED_BACKOFF_MS = [
31343
31880
  6e4,
31344
31881
  5 * 6e4,
@@ -31364,12 +31901,12 @@ function unauthorizedBackoffMs(consecutive) {
31364
31901
  return UNAUTHORIZED_BACKOFF_MS[index];
31365
31902
  }
31366
31903
  function tokenFingerprint(token) {
31367
- return createHash3("sha256").update(token).digest("hex").slice(0, 16);
31904
+ return createHash4("sha256").update(token).digest("hex").slice(0, 16);
31368
31905
  }
31369
31906
 
31370
31907
  // src/hooks/runtime/guard-rules-cache.ts
31371
- var DEFAULT_CACHE_FILE = join14(
31372
- homedir13(),
31908
+ var DEFAULT_CACHE_FILE = join15(
31909
+ homedir14(),
31373
31910
  ".cybedefend",
31374
31911
  "guards-cache.json"
31375
31912
  );
@@ -31444,7 +31981,7 @@ function reportDroppedRules(dropped) {
31444
31981
  }
31445
31982
  function makeGuardRulesCache(opts) {
31446
31983
  const cacheFile = opts.cacheFile ?? DEFAULT_CACHE_FILE;
31447
- const failuresFile = opts.failuresFile ?? join14(dirname9(cacheFile), "guards-cache-failures.json");
31984
+ const failuresFile = opts.failuresFile ?? join15(dirname9(cacheFile), "guards-cache-failures.json");
31448
31985
  const staleSec = opts.staleSec ?? DEFAULT_STALE_SEC;
31449
31986
  const fetchFn = opts.fetchFn;
31450
31987
  const clock = opts.now ?? Date.now;
@@ -31549,7 +32086,7 @@ function makeGuardRulesCache(opts) {
31549
32086
  function readCache(projectId) {
31550
32087
  if (!existsSync18(cacheFile)) return null;
31551
32088
  try {
31552
- const raw = readFileSync17(cacheFile, "utf8");
32089
+ const raw = readFileSync18(cacheFile, "utf8");
31553
32090
  const data = JSON.parse(raw);
31554
32091
  if (data.projectId !== projectId) return null;
31555
32092
  return data;
@@ -31560,7 +32097,7 @@ function makeGuardRulesCache(opts) {
31560
32097
  function readFailures() {
31561
32098
  try {
31562
32099
  if (!existsSync18(failuresFile)) return {};
31563
- const parsed = JSON.parse(readFileSync17(failuresFile, "utf8"));
32100
+ const parsed = JSON.parse(readFileSync18(failuresFile, "utf8"));
31564
32101
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
31565
32102
  return {};
31566
32103
  }
@@ -31582,7 +32119,7 @@ function makeGuardRulesCache(opts) {
31582
32119
  if (now - f.at > FAILURE_RETENTION_MS) delete failures[projectId];
31583
32120
  }
31584
32121
  ensureDirFor2(failuresFile);
31585
- writeFileSync11(failuresFile, JSON.stringify(failures), "utf8");
32122
+ writeFileSync12(failuresFile, JSON.stringify(failures), "utf8");
31586
32123
  } catch {
31587
32124
  }
31588
32125
  }
@@ -31593,7 +32130,7 @@ function makeGuardRulesCache(opts) {
31593
32130
  function writeCache(entry) {
31594
32131
  try {
31595
32132
  ensureDirFor2(cacheFile);
31596
- writeFileSync11(cacheFile, JSON.stringify(entry), "utf8");
32133
+ writeFileSync12(cacheFile, JSON.stringify(entry), "utf8");
31597
32134
  } catch {
31598
32135
  }
31599
32136
  }
@@ -31602,7 +32139,7 @@ function makeGuardRulesCache(opts) {
31602
32139
  function ensureDirFor2(filePath) {
31603
32140
  const dir = dirname9(filePath);
31604
32141
  if (!existsSync18(dir)) {
31605
- mkdirSync9(dir, { recursive: true });
32142
+ mkdirSync10(dir, { recursive: true });
31606
32143
  }
31607
32144
  }
31608
32145
  var DEFAULT_TIMEOUT_MS2 = 8e3;
@@ -31742,11 +32279,11 @@ function detectPromptInjection(text) {
31742
32279
  }
31743
32280
 
31744
32281
  // src/hooks/runtime/judge-cache.ts
31745
- import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, existsSync as existsSync19, mkdirSync as mkdirSync10 } from "node:fs";
31746
- import { dirname as dirname10, join as join15 } from "node:path";
31747
- import { homedir as homedir14 } from "node:os";
31748
- var DEFAULT_JUDGE_CACHE_FILE = join15(
31749
- homedir14(),
32282
+ import { readFileSync as readFileSync19, writeFileSync as writeFileSync13, existsSync as existsSync19, mkdirSync as mkdirSync11 } from "node:fs";
32283
+ import { dirname as dirname10, join as join16 } from "node:path";
32284
+ import { homedir as homedir15 } from "node:os";
32285
+ var DEFAULT_JUDGE_CACHE_FILE = join16(
32286
+ homedir15(),
31750
32287
  ".cybedefend",
31751
32288
  "guards-judge-cache.json"
31752
32289
  );
@@ -31759,7 +32296,7 @@ function makeJudgeCache(opts = {}) {
31759
32296
  function readAll() {
31760
32297
  if (!existsSync19(cacheFile)) return {};
31761
32298
  try {
31762
- return JSON.parse(readFileSync18(cacheFile, "utf8"));
32299
+ return JSON.parse(readFileSync19(cacheFile, "utf8"));
31763
32300
  } catch {
31764
32301
  return {};
31765
32302
  }
@@ -31783,7 +32320,7 @@ function makeJudgeCache(opts = {}) {
31783
32320
  for (const k of keys.slice(0, Math.max(0, keys.length - maxEntries))) delete all[k];
31784
32321
  }
31785
32322
  ensureDirFor3(cacheFile);
31786
- writeFileSync12(cacheFile, JSON.stringify(all), "utf8");
32323
+ writeFileSync13(cacheFile, JSON.stringify(all), "utf8");
31787
32324
  } catch {
31788
32325
  }
31789
32326
  }
@@ -31792,34 +32329,34 @@ function makeJudgeCache(opts = {}) {
31792
32329
  function ensureDirFor3(filePath) {
31793
32330
  const dir = dirname10(filePath);
31794
32331
  if (!existsSync19(dir)) {
31795
- mkdirSync10(dir, { recursive: true });
32332
+ mkdirSync11(dir, { recursive: true });
31796
32333
  }
31797
32334
  }
31798
32335
 
31799
32336
  // src/hooks/runtime/guard-check.ts
31800
32337
  import { spawn as spawn3 } from "node:child_process";
31801
- import { homedir as homedir17 } from "node:os";
31802
- import { join as join18 } from "node:path";
32338
+ import { homedir as homedir18 } from "node:os";
32339
+ import { join as join19 } from "node:path";
31803
32340
 
31804
32341
  // src/hooks/runtime/guard-violations-buffer.ts
31805
32342
  import {
31806
- appendFileSync,
31807
- closeSync as closeSync2,
32343
+ appendFileSync as appendFileSync2,
32344
+ closeSync as closeSync3,
31808
32345
  existsSync as existsSync20,
31809
- openSync as openSync2,
31810
- readFileSync as readFileSync19,
31811
- writeFileSync as writeFileSync13,
31812
- writeSync,
31813
- mkdirSync as mkdirSync11,
31814
- rmSync as rmSync2,
32346
+ openSync as openSync3,
32347
+ readFileSync as readFileSync20,
32348
+ writeFileSync as writeFileSync14,
32349
+ writeSync as writeSync3,
32350
+ mkdirSync as mkdirSync12,
32351
+ rmSync as rmSync3,
31815
32352
  statSync as statSync4,
31816
- utimesSync
32353
+ utimesSync as utimesSync2
31817
32354
  } from "node:fs";
31818
32355
  import { dirname as dirname11 } from "node:path";
31819
- import { homedir as homedir15 } from "node:os";
31820
- import { join as join16 } from "node:path";
31821
- var DEFAULT_BUFFER_FILE = join16(
31822
- homedir15(),
32356
+ import { homedir as homedir16 } from "node:os";
32357
+ import { join as join17 } from "node:path";
32358
+ var DEFAULT_BUFFER_FILE = join17(
32359
+ homedir16(),
31823
32360
  ".cybedefend",
31824
32361
  "guards-violations-buffer.jsonl"
31825
32362
  );
@@ -31830,8 +32367,8 @@ var MAX_RECORD_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
31830
32367
  var FLUSH_LOCK_STALE_MS = 6e4;
31831
32368
  function makeViolationsBuffer(opts = {}) {
31832
32369
  const bufferFile = opts.bufferFile ?? DEFAULT_BUFFER_FILE;
31833
- const holdsFile = opts.holdsFile ?? join16(dirname11(bufferFile), "guards-violations-holds.json");
31834
- const lockFile = opts.lockFile ?? join16(dirname11(bufferFile), "guards-violations-flush.lock");
32370
+ const holdsFile = opts.holdsFile ?? join17(dirname11(bufferFile), "guards-violations-holds.json");
32371
+ const lockFile = opts.lockFile ?? join17(dirname11(bufferFile), "guards-violations-flush.lock");
31835
32372
  const now = opts.now ?? Date.now;
31836
32373
  function bufferViolation2(ctx, v) {
31837
32374
  const record2 = {
@@ -31841,7 +32378,7 @@ function makeViolationsBuffer(opts = {}) {
31841
32378
  };
31842
32379
  try {
31843
32380
  ensureDirFor4(bufferFile);
31844
- appendFileSync(bufferFile, JSON.stringify(record2) + "\n", "utf8");
32381
+ appendFileSync2(bufferFile, JSON.stringify(record2) + "\n", "utf8");
31845
32382
  } catch {
31846
32383
  }
31847
32384
  }
@@ -31923,7 +32460,7 @@ function makeViolationsBuffer(opts = {}) {
31923
32460
  writeHolds(holds);
31924
32461
  try {
31925
32462
  const serialised = failed.map((r) => JSON.stringify(r) + "\n").join("");
31926
- writeFileSync13(bufferFile, serialised + appendedSince(snapshot.bytes), "utf8");
32463
+ writeFileSync14(bufferFile, serialised + appendedSince(snapshot.bytes), "utf8");
31927
32464
  } catch {
31928
32465
  }
31929
32466
  }
@@ -31945,7 +32482,7 @@ function makeViolationsBuffer(opts = {}) {
31945
32482
  }
31946
32483
  function readBuffer() {
31947
32484
  try {
31948
- const raw = readFileSync19(bufferFile);
32485
+ const raw = readFileSync20(bufferFile);
31949
32486
  return { content: raw.toString("utf8"), bytes: raw.length };
31950
32487
  } catch {
31951
32488
  return null;
@@ -31953,7 +32490,7 @@ function makeViolationsBuffer(opts = {}) {
31953
32490
  }
31954
32491
  function appendedSince(bytes) {
31955
32492
  try {
31956
- const raw = readFileSync19(bufferFile);
32493
+ const raw = readFileSync20(bufferFile);
31957
32494
  return raw.length > bytes ? raw.subarray(bytes).toString("utf8") : "";
31958
32495
  } catch {
31959
32496
  return "";
@@ -31967,18 +32504,18 @@ function makeViolationsBuffer(opts = {}) {
31967
32504
  }
31968
32505
  for (let attempt = 0; attempt < 2; attempt++) {
31969
32506
  try {
31970
- const fd = openSync2(lockFile, "wx");
32507
+ const fd = openSync3(lockFile, "wx");
31971
32508
  try {
31972
- writeSync(fd, String(process.pid));
32509
+ writeSync3(fd, String(process.pid));
31973
32510
  } finally {
31974
- closeSync2(fd);
32511
+ closeSync3(fd);
31975
32512
  }
31976
32513
  return true;
31977
32514
  } catch (e) {
31978
32515
  if (e.code !== "EEXIST") return false;
31979
32516
  if (!lockIsStale()) return false;
31980
32517
  try {
31981
- rmSync2(lockFile, { force: true });
32518
+ rmSync3(lockFile, { force: true });
31982
32519
  } catch {
31983
32520
  return false;
31984
32521
  }
@@ -31996,26 +32533,26 @@ function makeViolationsBuffer(opts = {}) {
31996
32533
  function touchLock() {
31997
32534
  try {
31998
32535
  const t = /* @__PURE__ */ new Date();
31999
- utimesSync(lockFile, t, t);
32536
+ utimesSync2(lockFile, t, t);
32000
32537
  } catch {
32001
32538
  }
32002
32539
  }
32003
32540
  function releaseLock() {
32004
32541
  try {
32005
- rmSync2(lockFile, { force: true });
32542
+ rmSync3(lockFile, { force: true });
32006
32543
  } catch {
32007
32544
  }
32008
32545
  }
32009
32546
  function liftHolds() {
32010
32547
  try {
32011
- rmSync2(holdsFile, { force: true });
32548
+ rmSync3(holdsFile, { force: true });
32012
32549
  } catch {
32013
32550
  }
32014
32551
  }
32015
32552
  function readHolds() {
32016
32553
  try {
32017
32554
  if (!existsSync20(holdsFile)) return {};
32018
- const parsed = JSON.parse(readFileSync19(holdsFile, "utf8"));
32555
+ const parsed = JSON.parse(readFileSync20(holdsFile, "utf8"));
32019
32556
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
32020
32557
  return {};
32021
32558
  }
@@ -32040,11 +32577,11 @@ function makeViolationsBuffer(opts = {}) {
32040
32577
  function writeHolds(holds) {
32041
32578
  try {
32042
32579
  if (Object.keys(holds).length === 0) {
32043
- rmSync2(holdsFile, { force: true });
32580
+ rmSync3(holdsFile, { force: true });
32044
32581
  return;
32045
32582
  }
32046
32583
  ensureDirFor4(holdsFile);
32047
- writeFileSync13(holdsFile, JSON.stringify(holds), "utf8");
32584
+ writeFileSync14(holdsFile, JSON.stringify(holds), "utf8");
32048
32585
  } catch {
32049
32586
  }
32050
32587
  }
@@ -32077,7 +32614,7 @@ function capRecords(records, now) {
32077
32614
  function ensureDirFor4(filePath) {
32078
32615
  const dir = dirname11(filePath);
32079
32616
  if (!existsSync20(dir)) {
32080
- mkdirSync11(dir, { recursive: true });
32617
+ mkdirSync12(dir, { recursive: true });
32081
32618
  }
32082
32619
  }
32083
32620
  var _defaultBuffer = makeViolationsBuffer();
@@ -32086,9 +32623,9 @@ var flushViolations = _defaultBuffer.flushViolations.bind(_defaultBuffer);
32086
32623
  var liftViolationHolds = _defaultBuffer.liftHolds.bind(_defaultBuffer);
32087
32624
 
32088
32625
  // src/hooks/runtime/unmapped-tools.ts
32089
- import { existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as readFileSync20, writeFileSync as writeFileSync14 } from "node:fs";
32090
- import { dirname as dirname12, join as join17 } from "node:path";
32091
- import { homedir as homedir16 } from "node:os";
32626
+ import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync15 } from "node:fs";
32627
+ import { dirname as dirname12, join as join18 } from "node:path";
32628
+ import { homedir as homedir17 } from "node:os";
32092
32629
  var TARGETLESS_TOOL_RE = /^(?:ToolSearch|TodoRead|TodoWrite|Task|Agent|AskUserQuestion|Skill|SlashCommand|EnterPlanMode|ExitPlanMode|EnterWorktree|ExitWorktree|BashOutput|KillShell|KillBash|Monitor|ListMcpResourcesTool|ReadMcpResourceTool|ReadMcpResourceDirTool|ScheduleWakeup|PushNotification|CronCreate|CronDelete|CronList|SendMessage|ListAgents|TaskOutput|TaskStop|ReportFindings|Workflow)$/;
32093
32630
  var OWN_MCP_TOOL_RE = /^mcp__cybedefend(?:-[A-Za-z0-9_-]+)?__/;
32094
32631
  function isTargetlessTool(tool) {
@@ -32100,13 +32637,13 @@ function strictUnmappedPolicy() {
32100
32637
  }
32101
32638
  var MAX_TOOLS = 200;
32102
32639
  function defaultUnmappedToolsFile() {
32103
- const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join17(homedir16(), ".cybedefend");
32104
- return join17(dir, "guards-unmapped-tools.json");
32640
+ const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join18(homedir17(), ".cybedefend");
32641
+ return join18(dir, "guards-unmapped-tools.json");
32105
32642
  }
32106
32643
  function load(file2) {
32107
32644
  try {
32108
32645
  if (!existsSync21(file2)) return { tools: {} };
32109
- const parsed = JSON.parse(readFileSync20(file2, "utf8"));
32646
+ const parsed = JSON.parse(readFileSync21(file2, "utf8"));
32110
32647
  if (!parsed || typeof parsed !== "object" || typeof parsed.tools !== "object" || !parsed.tools) {
32111
32648
  return { tools: {} };
32112
32649
  }
@@ -32130,8 +32667,8 @@ function makeUnmappedToolTelemetry(file2 = defaultUnmappedToolsFile()) {
32130
32667
  if (names.length > MAX_TOOLS) {
32131
32668
  names.sort((a, b) => data.tools[a].lastSeen.localeCompare(data.tools[b].lastSeen)).slice(0, names.length - MAX_TOOLS).forEach((n) => delete data.tools[n]);
32132
32669
  }
32133
- mkdirSync12(dirname12(file2), { recursive: true });
32134
- writeFileSync14(file2, JSON.stringify(data, null, 2) + "\n", "utf8");
32670
+ mkdirSync13(dirname12(file2), { recursive: true });
32671
+ writeFileSync15(file2, JSON.stringify(data, null, 2) + "\n", "utf8");
32135
32672
  } catch {
32136
32673
  }
32137
32674
  }
@@ -32171,9 +32708,16 @@ function extractWriteTargets(req, rawCommand) {
32171
32708
  }
32172
32709
  return [];
32173
32710
  }
32174
- function normalizeToolName(tool) {
32711
+ function normalizeToolName(tool, client) {
32175
32712
  if (!tool) return "";
32176
32713
  const t = (tool.split(/[\r\n]/, 1)[0] ?? "").trim();
32714
+ if (client === "antigravity") {
32715
+ if (/^view_file$/i.test(t)) return "Read";
32716
+ if (/^(write_to_file|write_file)$/i.test(t)) return "Write";
32717
+ if (/^(replace_file_content|edit_file)$/i.test(t)) return "Edit";
32718
+ if (/^multi_replace_file_content$/i.test(t)) return "MultiEdit";
32719
+ if (/^read_url_content$/i.test(t)) return "WebFetch";
32720
+ }
32177
32721
  if (/^(read|read_file|cat)$/i.test(t)) return "Read";
32178
32722
  if (/^(write|create_file|new_file)$/i.test(t)) return "Write";
32179
32723
  if (/^(edit|apply_patch|str_replace_editor)$/i.test(t)) return "Edit";
@@ -32189,11 +32733,11 @@ function appendDebugLog(entry) {
32189
32733
  try {
32190
32734
  const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? "";
32191
32735
  if (!homeDir) return;
32192
- const { mkdirSync: mkdirSync13, appendFileSync: appendFileSync2 } = __require("node:fs");
32193
- const { join: join19 } = __require("node:path");
32194
- const dir = join19(homeDir, ".cybedefend");
32195
- mkdirSync13(dir, { recursive: true });
32196
- appendFileSync2(join19(dir, "hook-debug.log"), entry + "\n", "utf8");
32736
+ const { mkdirSync: mkdirSync14, appendFileSync: appendFileSync3 } = __require("node:fs");
32737
+ const { join: join20 } = __require("node:path");
32738
+ const dir = join20(homeDir, ".cybedefend");
32739
+ mkdirSync14(dir, { recursive: true });
32740
+ appendFileSync3(join20(dir, "hook-debug.log"), entry + "\n", "utf8");
32197
32741
  } catch {
32198
32742
  }
32199
32743
  }
@@ -32208,9 +32752,63 @@ function debugLog(entry) {
32208
32752
  }
32209
32753
  }
32210
32754
  var UNNAMED_TOOL = "<unnamed>";
32755
+ function sniffCaller(envelope) {
32756
+ try {
32757
+ return sniff(envelope);
32758
+ } catch {
32759
+ }
32760
+ let client = "unknown";
32761
+ try {
32762
+ client = detectClient(envelope);
32763
+ } catch {
32764
+ }
32765
+ const rawTool = client === "antigravity" && isRecord(envelope.toolCall) ? envelope.toolCall.name : envelope?.tool_name;
32766
+ return {
32767
+ client,
32768
+ toolName: typeof rawTool === "string" ? rawTool : "",
32769
+ filePath: "",
32770
+ filePaths: [],
32771
+ newContent: "",
32772
+ raw: envelope
32773
+ };
32774
+ }
32211
32775
  function argvToCommandLine(argv) {
32212
32776
  return argv.map((a) => /^[A-Za-z0-9_./=:@%+,-]+$/.test(a) ? a : `'${a.replace(/'/g, "'\\''")}'`).join(" ");
32213
32777
  }
32778
+ var MCP_SERVER_NAME_RE = /^[A-Za-z0-9]+(?:[-_][A-Za-z0-9]+)*$/;
32779
+ var MCP_SERVER_NAME_MAX = 64;
32780
+ var MCP_TOOL_NAME_RE = /^[A-Za-z0-9]+(?:[-_.][A-Za-z0-9]+)*$/;
32781
+ var MCP_TOOL_NAME_MAX = 128;
32782
+ function isRecord(v) {
32783
+ return typeof v === "object" && v !== null && !Array.isArray(v);
32784
+ }
32785
+ function readAntigravityCall(envelope) {
32786
+ const toolCall = isRecord(envelope.toolCall) ? envelope.toolCall : {};
32787
+ const args = isRecord(toolCall.args) ? toolCall.args : {};
32788
+ const str3 = (v) => typeof v === "string" ? v : void 0;
32789
+ const name = str3(toolCall.name);
32790
+ let tool = name;
32791
+ const server = str3(args.ServerName);
32792
+ const mcpTool = str3(args.ToolName);
32793
+ if (tool === "call_mcp_tool" && server !== void 0 && mcpTool !== void 0 && server.length <= MCP_SERVER_NAME_MAX && MCP_SERVER_NAME_RE.test(server) && mcpTool.length <= MCP_TOOL_NAME_MAX && MCP_TOOL_NAME_RE.test(mcpTool)) {
32794
+ tool = `mcp__${server}__${mcpTool}`;
32795
+ }
32796
+ const params = {};
32797
+ const filePath = antigravityFilePathArg(name ?? "", args);
32798
+ if (filePath) params.file_path = filePath;
32799
+ const command = str3(args.CommandLine);
32800
+ if (command !== void 0) params.command = command;
32801
+ const url2 = str3(args.Url);
32802
+ if (url2 !== void 0) params.url = url2;
32803
+ let classifiedTool;
32804
+ let extraFilePaths = [];
32805
+ if (name !== void 0 && filePath && !ANTIGRAVITY_KNOWN_TOOLS.has(name)) {
32806
+ classifiedTool = classifyUnknownAntigravityTool(args);
32807
+ extraFilePaths = antigravityAllPathArgs(args).filter((p) => p !== filePath);
32808
+ }
32809
+ const cwd = typeof args.Cwd === "string" && args.Cwd.length > 0 ? args.Cwd : sessionFolderOf(envelope, "antigravity");
32810
+ return { tool, classifiedTool, params, extraFilePaths, cwd, argKeys: Object.keys(args) };
32811
+ }
32214
32812
  function commandField(params) {
32215
32813
  const v = params.command;
32216
32814
  if (typeof v === "string") return v;
@@ -32219,40 +32817,54 @@ function commandField(params) {
32219
32817
  }
32220
32818
  return null;
32221
32819
  }
32222
- function mapEnvelope(envelope, agent = sniff(envelope).client) {
32223
- const rawTool = typeof envelope.tool_name === "string" ? envelope.tool_name : typeof envelope.tool === "string" ? envelope.tool : void 0;
32224
- const params = envelope.tool_input ?? envelope.params ?? envelope.input ?? {};
32820
+ function fileMapping(agent, tool, params, homeDir, cwd, rawTool, extraFilePaths) {
32821
+ const filePath = typeof params.file_path === "string" ? params.file_path : typeof params.path === "string" ? params.path : null;
32822
+ if (!filePath) return { kind: "unmapped", tool: rawTool ?? UNNAMED_TOOL };
32823
+ const request = {
32824
+ agent,
32825
+ tool,
32826
+ target: { type: "file", path: filePath },
32827
+ homeDir,
32828
+ cwd
32829
+ };
32830
+ if (extraFilePaths.length === 0) return { kind: "mapped", request };
32831
+ return {
32832
+ kind: "mapped",
32833
+ request,
32834
+ additionalRequests: extraFilePaths.map((path) => ({
32835
+ agent,
32836
+ tool,
32837
+ target: { type: "file", path },
32838
+ homeDir,
32839
+ cwd
32840
+ }))
32841
+ };
32842
+ }
32843
+ function mapEnvelope(envelope, agent = sniffCaller(envelope).client) {
32844
+ const antigravity = agent === "antigravity" ? readAntigravityCall(envelope) : null;
32845
+ const rawTool = antigravity ? antigravity.tool : typeof envelope.tool_name === "string" ? envelope.tool_name : typeof envelope.tool === "string" ? envelope.tool : void 0;
32846
+ const params = antigravity ? antigravity.params : envelope.tool_input ?? envelope.params ?? envelope.input ?? {};
32847
+ const loggedKeys = antigravity ? antigravity.argKeys : Object.keys(params);
32225
32848
  debugLog({
32226
32849
  event: "pre_map",
32227
32850
  raw_tool_name: rawTool ?? null,
32228
32851
  has_tool_input: "tool_input" in envelope,
32229
32852
  has_params: "params" in envelope,
32230
- param_keys: Object.keys(params).slice(0, 12)
32853
+ param_keys: loggedKeys.slice(0, 12)
32231
32854
  });
32232
32855
  const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? "/";
32233
- const cwd = process.cwd();
32234
- const tool = normalizeToolName(rawTool);
32856
+ const cwd = antigravity ? antigravity.cwd : process.cwd();
32857
+ const tool = antigravity?.classifiedTool ?? normalizeToolName(rawTool, agent);
32858
+ const extraFilePaths = antigravity?.extraFilePaths ?? [];
32235
32859
  switch (tool) {
32236
32860
  case "Read":
32237
32861
  case "Glob":
32238
- case "Grep": {
32239
- const filePath = typeof params.file_path === "string" ? params.file_path : typeof params.path === "string" ? params.path : null;
32240
- if (!filePath) return { kind: "unmapped", tool: rawTool ?? UNNAMED_TOOL };
32241
- return {
32242
- kind: "mapped",
32243
- request: { agent, tool, target: { type: "file", path: filePath }, homeDir, cwd }
32244
- };
32245
- }
32862
+ case "Grep":
32863
+ return fileMapping(agent, tool, params, homeDir, cwd, rawTool, extraFilePaths);
32246
32864
  case "Write":
32247
32865
  case "Edit":
32248
- case "MultiEdit": {
32249
- const filePath = typeof params.file_path === "string" ? params.file_path : typeof params.path === "string" ? params.path : null;
32250
- if (!filePath) return { kind: "unmapped", tool: rawTool ?? UNNAMED_TOOL };
32251
- return {
32252
- kind: "mapped",
32253
- request: { agent, tool, target: { type: "file", path: filePath }, homeDir, cwd }
32254
- };
32255
- }
32866
+ case "MultiEdit":
32867
+ return fileMapping(agent, tool, params, homeDir, cwd, rawTool, extraFilePaths);
32256
32868
  case "Bash": {
32257
32869
  const command = commandField(params);
32258
32870
  if (!command) return { kind: "unmapped", tool: rawTool ?? UNNAMED_TOOL };
@@ -32334,7 +32946,7 @@ function mapEnvelope(envelope, agent = sniff(envelope).client) {
32334
32946
  JSON.stringify({
32335
32947
  ts: (/* @__PURE__ */ new Date()).toISOString(),
32336
32948
  tool_name: rawTool ?? null,
32337
- params_keys: Object.keys(params)
32949
+ params_keys: loggedKeys
32338
32950
  })
32339
32951
  );
32340
32952
  return { kind: "unmapped", tool: rawTool ?? UNNAMED_TOOL };
@@ -32383,6 +32995,9 @@ function stringifyTarget(t) {
32383
32995
  return `git ${t.subcommand}`;
32384
32996
  }
32385
32997
  }
32998
+ function verdictRank(v) {
32999
+ return v === "deny" ? 2 : v === "warn" ? 1 : 0;
33000
+ }
32386
33001
  async function consultJudge(judge, sessionId, cacheKey, input2, cache = { get: (k) => judge.cacheGet(k), set: (k, r) => judge.cacheSet(k, r) }) {
32387
33002
  const cached2 = cache.get(cacheKey);
32388
33003
  if (cached2) return { kind: "result", res: cached2 };
@@ -32601,6 +33216,14 @@ ${JSON.stringify(payload)}` : targetStr);
32601
33216
  }
32602
33217
  return { engine: "llm", outcome: "confirmed", model: res.model };
32603
33218
  }
33219
+ var SESSION_ID_MAX = 128;
33220
+ function antigravitySessionId(envelope) {
33221
+ const id = envelope.conversationId;
33222
+ return typeof id === "string" && id.length > 0 && id.length <= SESSION_ID_MAX ? id : void 0;
33223
+ }
33224
+ function denyExitCode(client) {
33225
+ return client === "antigravity" ? 0 : 2;
33226
+ }
32604
33227
  async function runCatchJudgeStep(args) {
32605
33228
  const {
32606
33229
  judge,
@@ -32660,7 +33283,7 @@ async function runCatchJudgeStep(args) {
32660
33283
  message
32661
33284
  };
32662
33285
  }
32663
- function emitUnverifiedBanner(reason) {
33286
+ function emitUnverifiedBanner(reason, client) {
32664
33287
  const banner = [
32665
33288
  "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588",
32666
33289
  "\u2588 VibeDefend Action Guards \u2014 UNVERIFIED \u2588",
@@ -32678,7 +33301,7 @@ function emitUnverifiedBanner(reason) {
32678
33301
  ].join("\n") + "\n";
32679
33302
  process.stderr.write(banner);
32680
33303
  const isCodex = typeof process.env.CODEX_SANDBOX !== "undefined" || typeof process.env.CODEX_AGENT !== "undefined";
32681
- if (isCodex) {
33304
+ if (isCodex && client !== "antigravity") {
32682
33305
  try {
32683
33306
  const ctx = JSON.stringify({
32684
33307
  additionalContext: `VibeDefend Action Guards UNVERIFIED \u2014 ${reason} Tool call allowed WITHOUT enforcement. Run \`vibedefend login\` to restore protection.`
@@ -32688,8 +33311,10 @@ function emitUnverifiedBanner(reason) {
32688
33311
  }
32689
33312
  }
32690
33313
  }
32691
- function sessionIdOf3(envelope) {
32692
- return typeof envelope.session_id === "string" ? envelope.session_id : typeof envelope.sessionId === "string" ? envelope.sessionId : void 0;
33314
+ function sessionIdOf3(envelope, client) {
33315
+ if (typeof envelope.session_id === "string") return envelope.session_id;
33316
+ if (typeof envelope.sessionId === "string") return envelope.sessionId;
33317
+ return client === "antigravity" ? antigravitySessionId(envelope) : void 0;
32693
33318
  }
32694
33319
  async function runPreToolUseGuardWith(opts) {
32695
33320
  const {
@@ -32702,21 +33327,22 @@ async function runPreToolUseGuardWith(opts) {
32702
33327
  if (!projectContext) return 0;
32703
33328
  if (rulesOutcome.kind === "unavailable") {
32704
33329
  emitUnverifiedBanner(
32705
- `Policy engine unreachable: ${rulesOutcome.reason}`
33330
+ `Policy engine unreachable: ${rulesOutcome.reason}`,
33331
+ sniffCaller(stdinEnvelope).client
32706
33332
  );
32707
33333
  return 0;
32708
33334
  }
32709
33335
  if (rulesOutcome.kind === "blocked") {
32710
33336
  const sentence = opts.usageNotifier?.notifyBlock(
32711
- sessionIdOf3(stdinEnvelope),
33337
+ sessionIdOf3(stdinEnvelope, sniffCaller(stdinEnvelope).client),
32712
33338
  rulesOutcome.block
32713
33339
  );
32714
- if (sentence) emitAgentMessage("warn", sentence);
33340
+ if (sentence) emitAgentMessage("warn", sentence, sniffCaller(stdinEnvelope).client);
32715
33341
  return 0;
32716
33342
  }
32717
33343
  const rules = rulesOutcome.rules;
32718
- const caller = sniff(stdinEnvelope);
32719
- const sessionId = sessionIdOf3(stdinEnvelope);
33344
+ const caller = sniffCaller(stdinEnvelope);
33345
+ const sessionId = sessionIdOf3(stdinEnvelope, caller.client);
32720
33346
  const mapping = mapEnvelope(stdinEnvelope, caller.client);
32721
33347
  if (mapping.kind === "targetless") return 0;
32722
33348
  if (mapping.kind === "unmapped") {
@@ -32731,9 +33357,10 @@ async function runPreToolUseGuardWith(opts) {
32731
33357
  if (strictUnmappedPolicy()) {
32732
33358
  emitAgentMessage(
32733
33359
  "deny",
32734
- `Tool "${mapping.tool}" is not evaluated by Action Guards and CYBEDEFEND_GUARDS_STRICT is on \u2014 blocked (strict mode).`
33360
+ `Tool "${mapping.tool}" is not evaluated by Action Guards and CYBEDEFEND_GUARDS_STRICT is on \u2014 blocked (strict mode).`,
33361
+ caller.client
32735
33362
  );
32736
- return 2;
33363
+ return denyExitCode(caller.client);
32737
33364
  }
32738
33365
  if (opts.unmapped.noticeOnce(sessionId, mapping.tool)) {
32739
33366
  process.stderr.write(
@@ -32744,12 +33371,24 @@ async function runPreToolUseGuardWith(opts) {
32744
33371
  return 0;
32745
33372
  }
32746
33373
  const partial2 = mapping.request;
32747
- const guardRequest = {
33374
+ let guardRequest = {
32748
33375
  ...partial2,
32749
33376
  projectId: projectContext.projectId,
32750
33377
  sessionId
32751
33378
  };
32752
33379
  let decision = evaluateFn(rules, guardRequest);
33380
+ for (const extra of mapping.additionalRequests ?? []) {
33381
+ const extraRequest = {
33382
+ ...extra,
33383
+ projectId: projectContext.projectId,
33384
+ sessionId
33385
+ };
33386
+ const extraDecision = evaluateFn(rules, extraRequest);
33387
+ if (verdictRank(extraDecision.verdict) > verdictRank(decision.verdict)) {
33388
+ decision = extraDecision;
33389
+ guardRequest = extraRequest;
33390
+ }
33391
+ }
32753
33392
  let hardenedTier = "small";
32754
33393
  let hardenedScripts = [];
32755
33394
  if (opts.hardenedCommandAnalysis && opts.sessionWrites && guardRequest.target.type === "file" && (guardRequest.tool === "Write" || guardRequest.tool === "Edit" || guardRequest.tool === "MultiEdit")) {
@@ -32904,20 +33543,28 @@ async function runPreToolUseGuardWith(opts) {
32904
33543
  matched_rule_ids: decision.matchedRuleIds
32905
33544
  });
32906
33545
  if (decision.verdict === "deny") {
32907
- emitAgentMessage("deny", decision.message ?? "Action blocked.");
32908
- return 2;
33546
+ emitAgentMessage("deny", decision.message ?? "Action blocked.", caller.client);
33547
+ return denyExitCode(caller.client);
32909
33548
  }
32910
33549
  if (decision.verdict === "warn") {
32911
- emitAgentMessage("warn", decision.message ?? "Action flagged.");
33550
+ emitAgentMessage("warn", decision.message ?? "Action flagged.", caller.client);
32912
33551
  return 0;
32913
33552
  }
32914
33553
  return 0;
32915
33554
  }
32916
- function emitAgentMessage(verdict, message) {
33555
+ var ANTIGRAVITY_DECISIONS = {
33556
+ deny: "deny",
33557
+ warn: "allow"
33558
+ };
33559
+ function emitAgentMessage(verdict, message, client) {
32917
33560
  const tag = verdict === "deny" ? "Action Guards" : "Action Guards \xB7 WARN";
32918
33561
  const fullMessage = `[VibeDefend ${tag}] ${message}`;
32919
33562
  process.stderr.write(fullMessage + "\n");
32920
33563
  try {
33564
+ if (client === "antigravity") {
33565
+ emitAntigravityDecision(ANTIGRAVITY_DECISIONS[verdict], fullMessage);
33566
+ return;
33567
+ }
32921
33568
  const payload = verdict === "deny" ? {
32922
33569
  // Claude Code legacy — the call, not the agent, is stopped.
32923
33570
  decision: "block",
@@ -32950,17 +33597,17 @@ function emitAgentMessage(verdict, message) {
32950
33597
  }
32951
33598
  function makeProductionJudgeDeps() {
32952
33599
  const cache = makeJudgeCache();
32953
- const warnDir = process.env.CYBEDEFEND_BASELINE_DIR ?? join18(homedir17(), ".cybedefend");
33600
+ const warnDir = process.env.CYBEDEFEND_BASELINE_DIR ?? join19(homedir18(), ".cybedefend");
32954
33601
  const scriptCache = makeJudgeCache({
32955
- cacheFile: join18(warnDir, "guards-judge-script-cache.json"),
33602
+ cacheFile: join19(warnDir, "guards-judge-script-cache.json"),
32956
33603
  ttlMs: SCRIPT_VERDICT_TTL_MS,
32957
33604
  maxEntries: SCRIPT_VERDICT_MAX_ENTRIES
32958
33605
  });
32959
33606
  const warnTracker = defaultSessionTracker(
32960
- join18(warnDir, "guards-judge-warned-sessions.json")
33607
+ join19(warnDir, "guards-judge-warned-sessions.json")
32961
33608
  );
32962
33609
  const blockedTracker = defaultSessionTracker(
32963
- join18(warnDir, "guards-judge-blocked-sessions.json")
33610
+ join19(warnDir, "guards-judge-blocked-sessions.json")
32964
33611
  );
32965
33612
  return {
32966
33613
  usage: {
@@ -32988,8 +33635,8 @@ function makeProductionJudgeDeps() {
32988
33635
  }
32989
33636
  function makeProductionUnmappedDeps() {
32990
33637
  const telemetry = makeUnmappedToolTelemetry();
32991
- const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join18(homedir17(), ".cybedefend");
32992
- const tracker = defaultSessionTracker(join18(dir, "guards-unmapped-notified.json"));
33638
+ const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join19(homedir18(), ".cybedefend");
33639
+ const tracker = defaultSessionTracker(join19(dir, "guards-unmapped-notified.json"));
32993
33640
  return {
32994
33641
  record: telemetry.record,
32995
33642
  noticeOnce: (sessionId, tool) => {
@@ -33043,7 +33690,8 @@ async function runPreToolUseGuard() {
33043
33690
  });
33044
33691
  if (!token && rulesOutcome.kind === "unavailable") {
33045
33692
  emitUnverifiedBanner(
33046
- "Not authenticated \u2014 run `vibedefend login` to restore Action Guards."
33693
+ "Not authenticated \u2014 run `vibedefend login` to restore Action Guards.",
33694
+ sniffCaller(envelope).client
33047
33695
  );
33048
33696
  return 0;
33049
33697
  }
@@ -33080,7 +33728,7 @@ async function runPreToolUseGuard() {
33080
33728
  scriptJudge: process.env.CYBEDEFEND_HARDENED_ANALYSIS !== "0" && process.env.CYBEDEFEND_SCRIPT_JUDGE !== "0",
33081
33729
  // Level 1 — real script reader + per-session write memory.
33082
33730
  scriptResolver: process.env.CYBEDEFEND_HARDENED_ANALYSIS !== "0" ? (command, cwd) => resolveExecutedScript(command, { cwd }) : void 0,
33083
- sessionWrites: process.env.CYBEDEFEND_HARDENED_ANALYSIS !== "0" ? makeSessionWritesPort(sessionIdOf3(envelope)) : void 0,
33731
+ sessionWrites: process.env.CYBEDEFEND_HARDENED_ANALYSIS !== "0" ? makeSessionWritesPort(sessionIdOf3(envelope, sniffCaller(envelope).client)) : void 0,
33084
33732
  resolvePaths: process.env.CYBEDEFEND_HARDENED_ANALYSIS !== "0" ? (rawPath, cwd, homeDir) => resolveCandidatePaths(rawPath, { cwd, homeDir }) : void 0,
33085
33733
  // The refusal sentence goes out through the agent-message channels
33086
33734
  // (stderr included), so this notifier itself writes nothing.
@@ -33177,7 +33825,31 @@ function toApiViolation(r) {
33177
33825
 
33178
33826
  // src/hooks/runtime/index.ts
33179
33827
  async function main() {
33180
- const subcommand = process.argv[2] ?? "";
33828
+ const { subcommand, client } = parseRunnerArgs(process.argv.slice(2));
33829
+ const isAntigravity = client === "antigravity";
33830
+ const finish = (code) => {
33831
+ if (isAntigravity) {
33832
+ finishAntigravityRun(subcommand);
33833
+ process.exit(0);
33834
+ }
33835
+ process.exit(code);
33836
+ };
33837
+ if (isAntigravity) {
33838
+ let crashed = false;
33839
+ const onCrash = (e) => {
33840
+ if (crashed) return;
33841
+ crashed = true;
33842
+ try {
33843
+ const msg = e instanceof Error ? e.stack || e.message : String(e);
33844
+ process.stderr.write(`[vibedefend hook] ${subcommand}: ${msg}
33845
+ `);
33846
+ } catch {
33847
+ }
33848
+ finish(0);
33849
+ };
33850
+ process.on("uncaughtException", onCrash);
33851
+ process.on("unhandledRejection", onCrash);
33852
+ }
33181
33853
  try {
33182
33854
  switch (subcommand) {
33183
33855
  case "fetch-rules":
@@ -33195,6 +33867,9 @@ async function main() {
33195
33867
  case "user-prompt-submit":
33196
33868
  await userPromptSubmitHook();
33197
33869
  break;
33870
+ case "pre-invocation":
33871
+ await preInvocationHook();
33872
+ break;
33198
33873
  case "flush-violations":
33199
33874
  await runViolationsFlush();
33200
33875
  break;
@@ -33202,21 +33877,21 @@ async function main() {
33202
33877
  case "pre-tool-use":
33203
33878
  case "PreToolUse": {
33204
33879
  const code = await runPreToolUseGuard();
33205
- process.exit(code);
33880
+ finish(code);
33206
33881
  return;
33207
33882
  }
33208
33883
  case "":
33209
33884
  case "--help":
33210
33885
  case "-h":
33211
33886
  process.stderr.write(
33212
- "Usage: hook-runner.js <fetch-rules|session-start|session-review|pre-compact|user-prompt-submit|guard-check>\n"
33887
+ "Usage: hook-runner.js <fetch-rules|session-start|session-review|pre-compact|user-prompt-submit|pre-invocation|guard-check> [--client antigravity]\n"
33213
33888
  );
33214
- process.exit(subcommand === "" ? 1 : 0);
33889
+ finish(subcommand === "" ? 1 : 0);
33215
33890
  return;
33216
33891
  default:
33217
33892
  process.stderr.write(`Unknown subcommand: ${subcommand}
33218
33893
  `);
33219
- process.exit(1);
33894
+ finish(1);
33220
33895
  return;
33221
33896
  }
33222
33897
  } catch (e) {
@@ -33224,6 +33899,6 @@ async function main() {
33224
33899
  process.stderr.write(`[vibedefend hook] ${subcommand}: ${msg}
33225
33900
  `);
33226
33901
  }
33227
- process.exit(0);
33902
+ finish(0);
33228
33903
  }
33229
33904
  main();