@cybedefend/vibedefend 1.7.0 → 1.8.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 (42) hide show
  1. package/README.md +22 -13
  2. package/dist/clients/antigravity.js +342 -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/clients/windsurf.js +20 -8
  7. package/dist/clients/windsurf.js.map +1 -1
  8. package/dist/hook-runner.js +930 -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 +345 -71
  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/install.js +17 -3
  36. package/dist/install.js.map +1 -1
  37. package/dist/json-file.js +6 -3
  38. package/dist/json-file.js.map +1 -1
  39. package/dist/shim.js +53 -3
  40. package/dist/utils.js +9 -0
  41. package/dist/utils.js.map +1 -1
  42. package/package.json +3 -2
@@ -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,220 @@ 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
+ if (action === "pre_run_command" || action === "post_run_command") {
5063
+ const command = typeof toolInfo.command_line === "string" ? toolInfo.command_line : "";
5064
+ const cwd = typeof toolInfo.cwd === "string" && toolInfo.cwd.length > 0 ? toolInfo.cwd : process.cwd();
5065
+ const filePaths = extractShellWriteTargets(command).map(
5066
+ (t) => resolveWriteTarget(cwd, t)
5067
+ );
5068
+ return {
5069
+ client: "windsurf",
5070
+ toolName: "Bash",
5071
+ filePath: filePaths[0] ?? "",
5072
+ filePaths,
5073
+ newContent: command,
5074
+ raw: input2
5075
+ };
5076
+ }
5077
+ const filePath = typeof toolInfo.file_path === "string" ? toolInfo.file_path : "";
5078
+ const newContent = joinStringField(toolInfo.edits, "new_string");
5079
+ let toolName = action;
5080
+ if (action === "pre_write_code" || action === "post_write_code") {
5081
+ toolName = "Write";
5082
+ } else if (action === "pre_read_code" || action === "post_read_code") {
5083
+ toolName = "Read";
4921
5084
  }
4922
5085
  return {
4923
- client: "unknown",
4924
- toolName: "",
4925
- filePath: "",
4926
- filePaths: [],
4927
- newContent: "",
5086
+ client: "windsurf",
5087
+ toolName,
5088
+ filePath,
5089
+ filePaths: filePath ? [filePath] : [],
5090
+ newContent,
4928
5091
  raw: input2
4929
5092
  };
4930
5093
  }
5094
+ function sniff(input2) {
5095
+ const client = detectClient(input2);
5096
+ switch (client) {
5097
+ case "antigravity":
5098
+ return extractAntigravityShape(input2);
5099
+ case "windsurf":
5100
+ return extractWindsurfShape(input2);
5101
+ case "unknown":
5102
+ return {
5103
+ client: "unknown",
5104
+ toolName: "",
5105
+ filePath: "",
5106
+ filePaths: [],
5107
+ newContent: "",
5108
+ raw: input2
5109
+ };
5110
+ default:
5111
+ return extractToolInputShape(input2, client);
5112
+ }
5113
+ }
4931
5114
  function hasIsoTimestamp(input2) {
4932
5115
  return typeof input2.timestamp === "string" && /^\d{4}-\d{2}-\d{2}T/.test(input2.timestamp);
4933
5116
  }
@@ -4955,9 +5138,7 @@ function extractToolInputShape(input2, client) {
4955
5138
  newContent = typeof toolInput.new_string === "string" ? toolInput.new_string : "";
4956
5139
  break;
4957
5140
  case "MultiEdit":
4958
- newContent = joinMultiEditNewStrings(
4959
- toolInput.edits
4960
- );
5141
+ newContent = joinStringField(toolInput.edits, "new_string");
4961
5142
  break;
4962
5143
  case "apply_patch": {
4963
5144
  const patch = typeof toolInput.patch === "string" ? toolInput.patch : typeof toolInput.command === "string" ? toolInput.command : "";
@@ -6184,9 +6365,15 @@ import { dirname as dirname4, isAbsolute as isAbsolute2, join as join6, resolve
6184
6365
  import { fileURLToPath } from "node:url";
6185
6366
 
6186
6367
  // src/hooks/runtime/emit.ts
6368
+ import { writeSync } from "node:fs";
6187
6369
  var ENVELOPE_CLIENTS = {
6188
6370
  SessionStart: /* @__PURE__ */ new Set(["codex"]),
6189
- PreToolUse: /* @__PURE__ */ new Set(["claude-code", "codex", "vscode"])
6371
+ PreToolUse: /* @__PURE__ */ new Set(["claude-code", "codex", "vscode"]),
6372
+ // Antigravity never reaches this generic envelope: it has its own shapes
6373
+ // per event, handled in `emitAntigravityContext` below. Kept as an empty
6374
+ // set (rather than omitted) so `ENVELOPE_CLIENTS[hookEventName]` stays a
6375
+ // total function over `ContextHookEvent`.
6376
+ PreInvocation: /* @__PURE__ */ new Set()
6190
6377
  };
6191
6378
  var NO_MODEL_CHANNEL = {
6192
6379
  PreToolUse: /* @__PURE__ */ new Set(["cursor"]),
@@ -6195,14 +6382,71 @@ var NO_MODEL_CHANNEL = {
6195
6382
  function hasModelChannel(client, event) {
6196
6383
  return !NO_MODEL_CHANNEL[event]?.has(client);
6197
6384
  }
6385
+ var antigravityWritten = false;
6386
+ function writeStdoutSync(text) {
6387
+ const buf = Buffer.from(text, "utf8");
6388
+ const deadline = Date.now() + 2e3;
6389
+ let pause;
6390
+ let offset = 0;
6391
+ while (offset < buf.length) {
6392
+ let written = 0;
6393
+ try {
6394
+ written = writeSync(1, buf, offset, buf.length - offset);
6395
+ } catch (e) {
6396
+ if (e?.code !== "EAGAIN") return;
6397
+ }
6398
+ offset += written;
6399
+ if (written > 0) continue;
6400
+ if (Date.now() >= deadline) return;
6401
+ pause ??= new Int32Array(new SharedArrayBuffer(4));
6402
+ Atomics.wait(pause, 0, 0, 5);
6403
+ }
6404
+ }
6405
+ var antigravityWriter = writeStdoutSync;
6406
+ function writeAntigravityPayload(payload) {
6407
+ if (antigravityWritten) return;
6408
+ antigravityWritten = true;
6409
+ antigravityWriter(JSON.stringify(payload) + "\n");
6410
+ }
6411
+ function emitAntigravityDecision(decision, reason) {
6412
+ writeAntigravityPayload({ decision, ...reason ? { reason } : {} });
6413
+ }
6414
+ var PRE_TOOL_USE_SUBCOMMANDS = /* @__PURE__ */ new Set([
6415
+ "fetch-rules",
6416
+ "guard-check",
6417
+ "pre-tool-use",
6418
+ "PreToolUse"
6419
+ ]);
6420
+ function finishAntigravityRun(subcommand) {
6421
+ const payload = PRE_TOOL_USE_SUBCOMMANDS.has(subcommand) ? { decision: "allow" } : {};
6422
+ writeAntigravityPayload(payload);
6423
+ }
6424
+ function emitAntigravityContext(body, hookEventName) {
6425
+ if (hookEventName === "PreToolUse") return;
6426
+ if (hookEventName === "SessionStart") {
6427
+ writeAntigravityPayload({
6428
+ injectSteps: [{ systemMessage: { systemMessage: body } }]
6429
+ });
6430
+ return;
6431
+ }
6432
+ writeAntigravityPayload({ injectSteps: [{ ephemeralMessage: body }] });
6433
+ }
6198
6434
  function emit(body, client) {
6199
6435
  if (!body) return;
6436
+ if (client === "antigravity") {
6437
+ writeAntigravityPayload({ injectSteps: [{ ephemeralMessage: body }] });
6438
+ return;
6439
+ }
6200
6440
  if (client === "cursor") return;
6201
6441
  process.stdout.write(body);
6202
6442
  if (!body.endsWith("\n")) process.stdout.write("\n");
6203
6443
  }
6204
6444
  function emitContext(body, client, hookEventName) {
6205
6445
  if (!body) return;
6446
+ if (client === "antigravity") {
6447
+ emitAntigravityContext(body, hookEventName);
6448
+ return;
6449
+ }
6206
6450
  if (!hasModelChannel(client, hookEventName)) return;
6207
6451
  if (client === "cursor" && hookEventName === "SessionStart") {
6208
6452
  writeJson({ additional_context: body });
@@ -6262,6 +6506,9 @@ function emitStop(body, client, reason) {
6262
6506
  case "cursor":
6263
6507
  writeJson({ followup_message: body });
6264
6508
  return;
6509
+ case "antigravity":
6510
+ writeAntigravityPayload({ decision: "continue", reason: body });
6511
+ return;
6265
6512
  default:
6266
6513
  emit(body, client);
6267
6514
  }
@@ -6330,7 +6577,7 @@ function defaultInactiveSessionStore(file2 = defaultStoreFile(), now = Date.now)
6330
6577
  };
6331
6578
  }
6332
6579
  function sessionIdOf(stdin) {
6333
- for (const key of ["session_id", "sessionId", "conversation_id", "trajectory_id"]) {
6580
+ for (const key of ["session_id", "sessionId", "conversation_id", "trajectory_id", "conversationId"]) {
6334
6581
  const v = stdin[key];
6335
6582
  if (typeof v === "string" && v.length > 0) return v;
6336
6583
  }
@@ -6343,6 +6590,9 @@ function sessionFolderOf(stdin, client, env = process.env) {
6343
6590
  if (Array.isArray(roots)) candidates.push(roots[0]);
6344
6591
  candidates.push(env.CURSOR_PROJECT_DIR);
6345
6592
  }
6593
+ if (client === "antigravity" && Array.isArray(stdin.workspacePaths)) {
6594
+ candidates.push(...stdin.workspacePaths);
6595
+ }
6346
6596
  candidates.push(stdin.cwd);
6347
6597
  for (const c of candidates) {
6348
6598
  const folder = absoluteFolder(c);
@@ -6453,10 +6703,260 @@ function projectDirForFile(file2, workDir) {
6453
6703
  return fileRoot;
6454
6704
  }
6455
6705
 
6706
+ // src/hooks/runtime/antigravity-session.ts
6707
+ import {
6708
+ appendFileSync,
6709
+ closeSync,
6710
+ constants,
6711
+ lstatSync,
6712
+ mkdirSync as mkdirSync6,
6713
+ openSync,
6714
+ readdirSync,
6715
+ readFileSync as readFileSync9,
6716
+ renameSync,
6717
+ rmSync,
6718
+ unlinkSync,
6719
+ utimesSync,
6720
+ writeFileSync as writeFileSync6,
6721
+ writeSync as writeSync2
6722
+ } from "node:fs";
6723
+ import { createHash as createHash2, randomBytes } from "node:crypto";
6724
+ import { homedir as homedir8 } from "node:os";
6725
+ import { join as join8 } from "node:path";
6726
+ var MAX_STASHED_CONTEXTS = 20;
6727
+ var DEFAULT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
6728
+ var STASH_NAME_RE = /^\d+-[0-9a-f]{8}\.md$/;
6729
+ var DIR_MODE = 448;
6730
+ var FILE_MODE = 384;
6731
+ function conversationKey(raw) {
6732
+ const id = raw.conversationId;
6733
+ if (typeof id !== "string" || id.length === 0 || id.length > 256) return null;
6734
+ return createHash2("sha256").update(id).digest("hex").slice(0, 32);
6735
+ }
6736
+ function antigravityStateDir() {
6737
+ return join8(homedir8(), ".cybedefend", "antigravity");
6738
+ }
6739
+ function keyDir(key, dir) {
6740
+ return join8(dir, key);
6741
+ }
6742
+ function isFinalStashName(name) {
6743
+ return STASH_NAME_RE.test(name);
6744
+ }
6745
+ function isUnsafePath(path) {
6746
+ try {
6747
+ return !lstatSync(path).isDirectory();
6748
+ } catch {
6749
+ return false;
6750
+ }
6751
+ }
6752
+ function isUnsafeFilePath(path) {
6753
+ try {
6754
+ return !lstatSync(path).isFile();
6755
+ } catch {
6756
+ return false;
6757
+ }
6758
+ }
6759
+ var NOFOLLOW_SUPPORTED = typeof constants.O_NOFOLLOW === "number";
6760
+ function appendLedgerLine(path, line) {
6761
+ if (NOFOLLOW_SUPPORTED) {
6762
+ const fd = openSync(
6763
+ path,
6764
+ constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW,
6765
+ FILE_MODE
6766
+ );
6767
+ try {
6768
+ writeSync2(fd, line, null, "utf8");
6769
+ } finally {
6770
+ closeSync(fd);
6771
+ }
6772
+ return;
6773
+ }
6774
+ if (isUnsafeFilePath(path)) return;
6775
+ appendFileSync(path, line, { mode: FILE_MODE });
6776
+ }
6777
+ function writeMarkerFile(path, content) {
6778
+ if (NOFOLLOW_SUPPORTED) {
6779
+ const fd = openSync(
6780
+ path,
6781
+ constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | constants.O_NOFOLLOW,
6782
+ FILE_MODE
6783
+ );
6784
+ try {
6785
+ writeSync2(fd, content, null, "utf8");
6786
+ } finally {
6787
+ closeSync(fd);
6788
+ }
6789
+ return;
6790
+ }
6791
+ if (isUnsafeFilePath(path)) return;
6792
+ writeFileSync6(path, content, { mode: FILE_MODE });
6793
+ }
6794
+ function ensureRealDir(path) {
6795
+ if (isUnsafePath(path)) return false;
6796
+ mkdirSync6(path, { recursive: true, mode: DIR_MODE });
6797
+ return true;
6798
+ }
6799
+ function ensureLiveKeyDir(key, dir, now) {
6800
+ const kd = keyDir(key, dir);
6801
+ if (!ensureRealDir(kd)) return null;
6802
+ try {
6803
+ const t = new Date(now);
6804
+ utimesSync(kd, t, t);
6805
+ } catch {
6806
+ }
6807
+ return kd;
6808
+ }
6809
+ function stashContext(key, body, dir = antigravityStateDir()) {
6810
+ let tmpPath;
6811
+ try {
6812
+ const now = Date.now();
6813
+ const kd = ensureLiveKeyDir(key, dir, now);
6814
+ if (!kd) return;
6815
+ const contextDir = join8(kd, "context");
6816
+ if (!ensureRealDir(contextDir)) return;
6817
+ const suffix = randomBytes(4).toString("hex");
6818
+ tmpPath = join8(contextDir, `.${now}-${suffix}.tmp`);
6819
+ writeFileSync6(tmpPath, body, { mode: FILE_MODE, flag: "wx" });
6820
+ const finalPath = join8(contextDir, `${now}-${suffix}.md`);
6821
+ renameSync(tmpPath, finalPath);
6822
+ tmpPath = void 0;
6823
+ const kept = readdirSync(contextDir).filter(isFinalStashName).sort();
6824
+ const excess = kept.length - MAX_STASHED_CONTEXTS;
6825
+ if (excess > 0) {
6826
+ for (const stale of kept.slice(0, excess)) {
6827
+ try {
6828
+ unlinkSync(join8(contextDir, stale));
6829
+ } catch {
6830
+ }
6831
+ }
6832
+ }
6833
+ } catch {
6834
+ if (tmpPath) {
6835
+ try {
6836
+ unlinkSync(tmpPath);
6837
+ } catch {
6838
+ }
6839
+ }
6840
+ }
6841
+ }
6842
+ function drainContext(key, dir = antigravityStateDir()) {
6843
+ try {
6844
+ const kd = keyDir(key, dir);
6845
+ if (isUnsafePath(kd)) return [];
6846
+ const contextDir = join8(kd, "context");
6847
+ if (isUnsafePath(contextDir)) return [];
6848
+ const entries = readdirSync(contextDir).filter(isFinalStashName).sort();
6849
+ const seen = /* @__PURE__ */ new Set();
6850
+ const bodies = [];
6851
+ for (const name of entries) {
6852
+ const filePath = join8(contextDir, name);
6853
+ try {
6854
+ const body = readFileSync9(filePath, "utf8");
6855
+ if (!seen.has(body)) {
6856
+ seen.add(body);
6857
+ bodies.push(body);
6858
+ }
6859
+ } catch {
6860
+ }
6861
+ try {
6862
+ unlinkSync(filePath);
6863
+ } catch {
6864
+ }
6865
+ }
6866
+ return bodies;
6867
+ } catch {
6868
+ return [];
6869
+ }
6870
+ }
6871
+ function recordEdit(key, file2, dir = antigravityStateDir()) {
6872
+ try {
6873
+ const now = Date.now();
6874
+ const kd = ensureLiveKeyDir(key, dir, now);
6875
+ if (!kd) return;
6876
+ appendLedgerLine(join8(kd, "edits.jsonl"), JSON.stringify({ f: file2 }) + "\n");
6877
+ } catch {
6878
+ }
6879
+ }
6880
+ function readEdits(key, dir = antigravityStateDir()) {
6881
+ try {
6882
+ const kd = keyDir(key, dir);
6883
+ if (isUnsafePath(kd)) return { count: 0, files: [] };
6884
+ const editsPath = join8(kd, "edits.jsonl");
6885
+ if (isUnsafeFilePath(editsPath)) return { count: 0, files: [] };
6886
+ const content = readFileSync9(editsPath, "utf8");
6887
+ let count = 0;
6888
+ const files = [];
6889
+ const seen = /* @__PURE__ */ new Set();
6890
+ for (const line of content.split("\n")) {
6891
+ const trimmed = line.trim();
6892
+ if (!trimmed) continue;
6893
+ let parsed;
6894
+ try {
6895
+ parsed = JSON.parse(trimmed);
6896
+ } catch {
6897
+ continue;
6898
+ }
6899
+ if (typeof parsed.f !== "string") continue;
6900
+ count++;
6901
+ if (!seen.has(parsed.f)) {
6902
+ seen.add(parsed.f);
6903
+ files.push(parsed.f);
6904
+ }
6905
+ }
6906
+ return { count, files };
6907
+ } catch {
6908
+ return { count: 0, files: [] };
6909
+ }
6910
+ }
6911
+ function markReviewed(key, dir = antigravityStateDir()) {
6912
+ try {
6913
+ const now = Date.now();
6914
+ const kd = ensureLiveKeyDir(key, dir, now);
6915
+ if (!kd) return;
6916
+ writeMarkerFile(join8(kd, "reviewed"), String(now));
6917
+ } catch {
6918
+ }
6919
+ }
6920
+ function isReviewed(key, dir = antigravityStateDir()) {
6921
+ try {
6922
+ const kd = keyDir(key, dir);
6923
+ if (isUnsafePath(kd)) return false;
6924
+ return lstatSync(join8(kd, "reviewed")).isFile();
6925
+ } catch {
6926
+ return false;
6927
+ }
6928
+ }
6929
+ function pruneStale(dir = antigravityStateDir(), now = Date.now(), maxAgeMs = DEFAULT_MAX_AGE_MS) {
6930
+ try {
6931
+ const entries = readdirSync(dir);
6932
+ for (const name of entries) {
6933
+ const entryPath = join8(dir, name);
6934
+ try {
6935
+ const { mtimeMs } = lstatSync(entryPath);
6936
+ if (now - mtimeMs > maxAgeMs) {
6937
+ rmSync(entryPath, { recursive: true, force: true });
6938
+ }
6939
+ } catch {
6940
+ }
6941
+ }
6942
+ } catch {
6943
+ }
6944
+ }
6945
+
6456
6946
  // src/hooks/runtime/fetch-rules.ts
6457
6947
  function emitPreToolUseContext(body, client) {
6458
6948
  emitContext(body, client, "PreToolUse");
6459
6949
  }
6950
+ function defaultEmit(stdin, stateDir) {
6951
+ return (body, client) => {
6952
+ if (client === "antigravity") {
6953
+ const key = conversationKey(stdin);
6954
+ if (key) stashContext(key, body, stateDir);
6955
+ return;
6956
+ }
6957
+ emitPreToolUseContext(body, client);
6958
+ };
6959
+ }
6460
6960
  var INTERESTED_TOOLS = /* @__PURE__ */ new Set([
6461
6961
  "Edit",
6462
6962
  "Write",
@@ -6471,13 +6971,17 @@ async function fetchRulesHook(deps = {}) {
6471
6971
  const resolveTok = deps.resolveTokenFn ?? resolveToken;
6472
6972
  const fetchRules = deps.fetchRulesFn ?? fetchBusinessRules;
6473
6973
  const fetchSecRules = deps.fetchSecurityRulesFn ?? fetchSecurityRules;
6474
- const emitFn = deps.emitFn ?? emitPreToolUseContext;
6475
6974
  const usageNotifier = deps.usageNotifier ?? makeUsageNotifier();
6476
6975
  const stdin = await readStdin();
6477
6976
  const event = sniff(stdin);
6977
+ const emitFn = deps.emitFn ?? defaultEmit(stdin, deps.antigravityStateDir);
6478
6978
  if (!INTERESTED_TOOLS.has(event.toolName)) return;
6479
6979
  if (!event.filePath) return;
6480
6980
  if (!hasModelChannel(event.client, "PreToolUse")) return;
6981
+ if (event.client === "antigravity" && (event.toolName === "Write" || event.toolName === "Edit" || event.toolName === "MultiEdit")) {
6982
+ const key = conversationKey(stdin);
6983
+ if (key) recordEdit(key, event.filePath, deps.antigravityStateDir);
6984
+ }
6481
6985
  const config2 = loadConfig();
6482
6986
  if (!config2) return;
6483
6987
  const folder = sessionFolderOf(stdin, event.client);
@@ -6626,9 +7130,9 @@ var DIRECT_PROPOSE_DIRECTIVES = {
6626
7130
 
6627
7131
  // src/hooks/runtime/self-update-check.ts
6628
7132
  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";
7133
+ import { existsSync as existsSync11, readFileSync as readFileSync10, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
7134
+ import { homedir as homedir9 } from "node:os";
7135
+ import { join as join9 } from "node:path";
6632
7136
 
6633
7137
  // src/hooks/runtime/semver.ts
6634
7138
  function parseVersion(input2) {
@@ -6706,9 +7210,9 @@ function isValidRegistryVersion(value) {
6706
7210
  }
6707
7211
  async function selfUpdateCheck(deps) {
6708
7212
  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");
7213
+ const dir = deps.cybeDir ?? join9(process.env.CYBEDEFEND_HOME ?? homedir9(), ".cybedefend");
7214
+ const throttlePath = join9(dir, "update-check.json");
7215
+ const logPath = join9(dir, "last-update.log");
6712
7216
  const installMode = deps.installMode ?? (deps.runnerSource ? detectInstallMode(deps.runnerSource) : detectInstallMode(resolveScriptPath()));
6713
7217
  const priorFailure = takeUpdateLogNotice(logPath);
6714
7218
  const throttle = readThrottle(throttlePath);
@@ -6742,7 +7246,7 @@ function applyOrNotify(deps, installMode, latest, logPath) {
6742
7246
  function readThrottle(path) {
6743
7247
  try {
6744
7248
  if (!existsSync11(path)) return null;
6745
- const data = JSON.parse(readFileSync9(path, "utf8"));
7249
+ const data = JSON.parse(readFileSync10(path, "utf8"));
6746
7250
  if (typeof data.lastCheckedAt !== "number") return null;
6747
7251
  return { lastCheckedAt: data.lastCheckedAt };
6748
7252
  } catch {
@@ -6752,7 +7256,7 @@ function readThrottle(path) {
6752
7256
  function writeThrottle(path, throttle) {
6753
7257
  try {
6754
7258
  ensureDirFor(path);
6755
- writeFileSync6(path, JSON.stringify(throttle) + "\n");
7259
+ writeFileSync7(path, JSON.stringify(throttle) + "\n");
6756
7260
  } catch {
6757
7261
  }
6758
7262
  }
@@ -6761,11 +7265,11 @@ function takeUpdateLogNotice(logPath) {
6761
7265
  if (!existsSync11(logPath)) return null;
6762
7266
  let parsed = {};
6763
7267
  try {
6764
- parsed = JSON.parse(readFileSync9(logPath, "utf8"));
7268
+ parsed = JSON.parse(readFileSync10(logPath, "utf8"));
6765
7269
  } catch {
6766
7270
  parsed = {};
6767
7271
  }
6768
- rmSync(logPath, { force: true });
7272
+ rmSync2(logPath, { force: true });
6769
7273
  if (typeof parsed.exitCode === "number" && parsed.exitCode !== 0) {
6770
7274
  return `\u26A0 vibedefend: last auto-update to ${parsed.to ?? "latest"} failed (exit ${parsed.exitCode}) \u2014 run \`vibedefend update --self\`.`;
6771
7275
  }
@@ -6836,18 +7340,18 @@ function pmCommand(mode, spec) {
6836
7340
 
6837
7341
  // src/hooks/runtime/hook-refresh-trigger.ts
6838
7342
  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";
7343
+ import { existsSync as existsSync12, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "node:fs";
7344
+ import { homedir as homedir10 } from "node:os";
7345
+ import { dirname as dirname6, join as join10 } from "node:path";
6842
7346
  function maybeRefreshStaleWiring(deps) {
6843
7347
  try {
6844
7348
  const { config: config2, runnerVersion } = deps;
6845
7349
  if (!config2.runnerSource || config2.installedVersion === runnerVersion) {
6846
7350
  return false;
6847
7351
  }
6848
- const cliEntry = join9(dirname6(dirname6(config2.runnerSource)), "bin", "vibedefend.js");
7352
+ const cliEntry = join10(dirname6(dirname6(config2.runnerSource)), "bin", "vibedefend.js");
6849
7353
  if (!(deps.exists ?? existsSync12)(cliEntry)) return false;
6850
- const markerPath = deps.markerPath ?? join9(process.env.CYBEDEFEND_HOME ?? homedir9(), ".cybedefend", "hook-refresh.json");
7354
+ const markerPath = deps.markerPath ?? join10(process.env.CYBEDEFEND_HOME ?? homedir10(), ".cybedefend", "hook-refresh.json");
6851
7355
  if (readMarkerVersion(markerPath) === runnerVersion) return false;
6852
7356
  (deps.spawnRefresh ?? defaultSpawnRefresh)(cliEntry);
6853
7357
  writeMarker(markerPath, runnerVersion);
@@ -6859,7 +7363,7 @@ function maybeRefreshStaleWiring(deps) {
6859
7363
  function readMarkerVersion(path) {
6860
7364
  try {
6861
7365
  if (!existsSync12(path)) return null;
6862
- const data = JSON.parse(readFileSync10(path, "utf8"));
7366
+ const data = JSON.parse(readFileSync11(path, "utf8"));
6863
7367
  return typeof data.version === "string" ? data.version : null;
6864
7368
  } catch {
6865
7369
  return null;
@@ -6868,7 +7372,7 @@ function readMarkerVersion(path) {
6868
7372
  function writeMarker(path, version2) {
6869
7373
  try {
6870
7374
  ensureDirFor(path);
6871
- writeFileSync7(path, JSON.stringify({ version: version2, spawnedAt: Date.now() }) + "\n");
7375
+ writeFileSync8(path, JSON.stringify({ version: version2, spawnedAt: Date.now() }) + "\n");
6872
7376
  } catch {
6873
7377
  }
6874
7378
  }
@@ -6882,18 +7386,18 @@ function defaultSpawnRefresh(cliEntry) {
6882
7386
  }
6883
7387
 
6884
7388
  // src/version.ts
6885
- import { readFileSync as readFileSync11 } from "node:fs";
7389
+ import { readFileSync as readFileSync12 } from "node:fs";
6886
7390
  import { fileURLToPath as fileURLToPath3 } from "node:url";
6887
- import { dirname as dirname7, join as join10 } from "node:path";
7391
+ import { dirname as dirname7, join as join11 } from "node:path";
6888
7392
  var PKG_NAME = "@cybedefend/vibedefend";
6889
7393
  function defaultPkgPath() {
6890
- return join10(dirname7(fileURLToPath3(import.meta.url)), "..", "package.json");
7394
+ return join11(dirname7(fileURLToPath3(import.meta.url)), "..", "package.json");
6891
7395
  }
6892
7396
  function readPackageMeta(opts = {}) {
6893
7397
  if (typeof opts.bakedVersion === "string" && opts.bakedVersion.length > 0) {
6894
7398
  return { name: PKG_NAME, version: opts.bakedVersion };
6895
7399
  }
6896
- const readFile = opts.readFile ?? ((p) => readFileSync11(p, "utf8"));
7400
+ const readFile = opts.readFile ?? ((p) => readFileSync12(p, "utf8"));
6897
7401
  const pkgPath = opts.pkgPath ?? defaultPkgPath();
6898
7402
  try {
6899
7403
  return JSON.parse(readFile(pkgPath));
@@ -6902,7 +7406,7 @@ function readPackageMeta(opts = {}) {
6902
7406
  }
6903
7407
  }
6904
7408
  var pkg = readPackageMeta({
6905
- bakedVersion: true ? "1.7.0" : void 0
7409
+ bakedVersion: true ? "1.8.1" : void 0
6906
7410
  });
6907
7411
 
6908
7412
  // src/hooks/runtime/session-start.ts
@@ -6946,6 +7450,9 @@ async function sessionStartHook(deps = {}) {
6946
7450
  }
6947
7451
  if (sessionId) sessionStore.clear(sessionId);
6948
7452
  const apiBase = process.env.CYBEDEFEND_API_BASE ?? configApiBase ?? config2.region.apiBase;
7453
+ if (event.client === "antigravity") {
7454
+ pruneStale(deps.antigravityStateDir);
7455
+ }
6949
7456
  if (process.env.CYBEDEFEND_DRY_RUN === "1") {
6950
7457
  emitFn(
6951
7458
  `## CybeDefend session bootstrap (dry-run, client=${event.client})
@@ -6998,7 +7505,12 @@ async function sessionStartHook(deps = {}) {
6998
7505
  " **before responding to the user request.**"
6999
7506
  );
7000
7507
  }
7001
- const HARD_ENFORCEMENT_CLIENTS = /* @__PURE__ */ new Set(["claude-code", "codex", "cursor"]);
7508
+ const HARD_ENFORCEMENT_CLIENTS = /* @__PURE__ */ new Set([
7509
+ "claude-code",
7510
+ "codex",
7511
+ "cursor",
7512
+ "antigravity"
7513
+ ]);
7002
7514
  lines.push("");
7003
7515
  if (HARD_ENFORCEMENT_CLIENTS.has(event.client)) {
7004
7516
  lines.push(
@@ -7036,23 +7548,23 @@ async function sessionStartHook(deps = {}) {
7036
7548
  }
7037
7549
 
7038
7550
  // src/hooks/runtime/session-review.ts
7039
- import { existsSync as existsSync14, readFileSync as readFileSync13 } from "node:fs";
7551
+ import { existsSync as existsSync14, readFileSync as readFileSync14 } from "node:fs";
7040
7552
 
7041
7553
  // 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";
7554
+ import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "node:fs";
7555
+ import { homedir as homedir11 } from "node:os";
7556
+ import { dirname as dirname8, join as join12 } from "node:path";
7045
7557
  var SESSIONS_CAP2 = 200;
7046
7558
  function defaultStoreFile2() {
7047
- const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join11(homedir10(), ".cybedefend");
7048
- return join11(dir, "review-sessions.json");
7559
+ const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join12(homedir11(), ".cybedefend");
7560
+ return join12(dir, "review-sessions.json");
7049
7561
  }
7050
7562
  var isCount = (n) => typeof n === "number" && Number.isInteger(n) && n >= 0;
7051
7563
  function defaultReviewSessionStore(file2 = defaultStoreFile2(), now = Date.now) {
7052
7564
  function load2() {
7053
7565
  if (!existsSync13(file2)) return {};
7054
7566
  try {
7055
- const parsed = JSON.parse(readFileSync12(file2, "utf8"));
7567
+ const parsed = JSON.parse(readFileSync13(file2, "utf8"));
7056
7568
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
7057
7569
  } catch {
7058
7570
  return {};
@@ -7060,8 +7572,8 @@ function defaultReviewSessionStore(file2 = defaultStoreFile2(), now = Date.now)
7060
7572
  }
7061
7573
  function save(map2) {
7062
7574
  try {
7063
- mkdirSync6(dirname8(file2), { recursive: true });
7064
- writeFileSync8(file2, JSON.stringify(map2) + "\n", "utf8");
7575
+ mkdirSync7(dirname8(file2), { recursive: true });
7576
+ writeFileSync9(file2, JSON.stringify(map2) + "\n", "utf8");
7065
7577
  } catch {
7066
7578
  }
7067
7579
  }
@@ -7171,6 +7683,32 @@ async function sessionReviewHook(deps = {}) {
7171
7683
  const config2 = loadConfig();
7172
7684
  if (!config2) return;
7173
7685
  if (!config2.hooks.enableSessionReview) return;
7686
+ if (event.client === "antigravity") {
7687
+ const key = conversationKey(stdin);
7688
+ const stateDir = deps.antigravityStateDir;
7689
+ if (!key || isReviewed(key, stateDir)) return;
7690
+ let { count, files } = readEdits(key, stateDir);
7691
+ if (process.env.CYBEDEFEND_DRY_RUN === "1") {
7692
+ count = parseInt(process.env.CYBEDEFEND_DRY_RUN_EDITS ?? "5", 10);
7693
+ }
7694
+ if (count === 0) return;
7695
+ if (count < resolveReviewThreshold(config2)) return;
7696
+ const folder2 = sessionFolderOf(stdin, "antigravity");
7697
+ if (isSessionInactive(stdin, { store: deps.sessionStore, cwd: folder2 })) return;
7698
+ const { projectId: projectId2 } = await (deps.resolveProject ?? resolveProjectIdWithApi)(folder2);
7699
+ if (!projectId2) return;
7700
+ const proposalMode2 = resolveProposalMode(config2);
7701
+ let body2 = composeReviewBody(count, "antigravity", "", proposalMode2);
7702
+ const withDiffScan2 = config2.hooks.enableDiffScan !== false;
7703
+ if (withDiffScan2) {
7704
+ body2 += "\n" + composeDiffScanBody(
7705
+ files.slice(0, CHANGED_FILES_MAX).map((f) => relativizePath(f, folder2))
7706
+ );
7707
+ }
7708
+ emitFn(body2, "antigravity", composeStopReason(withDiffScan2, proposalMode2));
7709
+ markReviewed(key, stateDir);
7710
+ return;
7711
+ }
7174
7712
  const transcript = loadTranscript(stdin, readTranscriptFile);
7175
7713
  const sessionId = sessionIdOf(stdin);
7176
7714
  const store = sessionId ? deps.reviewStore ?? defaultReviewSessionStore() : null;
@@ -7247,7 +7785,7 @@ function loadTranscript(stdin, readFile) {
7247
7785
  function defaultReadTranscript(path) {
7248
7786
  if (!existsSync14(path)) return null;
7249
7787
  try {
7250
- return readFileSync13(path, "utf8");
7788
+ return readFileSync14(path, "utf8");
7251
7789
  } catch {
7252
7790
  return null;
7253
7791
  }
@@ -7515,19 +8053,19 @@ async function preCompactHook(deps = {}) {
7515
8053
  }
7516
8054
 
7517
8055
  // 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";
8056
+ import { existsSync as existsSync15, mkdirSync as mkdirSync8, readFileSync as readFileSync15, writeFileSync as writeFileSync10 } from "node:fs";
8057
+ import { homedir as homedir12 } from "node:os";
8058
+ import { join as join13 } from "node:path";
7521
8059
  var SESSIONS_CAP3 = 100;
7522
8060
  function defaultSessionsFile() {
7523
- const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join12(homedir11(), ".cybedefend");
7524
- return join12(dir, "user-prompt-seen-sessions.json");
8061
+ const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join13(homedir12(), ".cybedefend");
8062
+ return join13(dir, "user-prompt-seen-sessions.json");
7525
8063
  }
7526
8064
  function defaultSessionTracker(file2 = defaultSessionsFile()) {
7527
8065
  function load2() {
7528
8066
  if (!existsSync15(file2)) return [];
7529
8067
  try {
7530
- const raw = readFileSync14(file2, "utf8");
8068
+ const raw = readFileSync15(file2, "utf8");
7531
8069
  const data = JSON.parse(raw);
7532
8070
  if (!Array.isArray(data.sessions)) return [];
7533
8071
  return data.sessions.filter((s) => typeof s === "string");
@@ -7544,8 +8082,8 @@ function defaultSessionTracker(file2 = defaultSessionsFile()) {
7544
8082
  if (existing.includes(sessionId)) return;
7545
8083
  const next = [...existing, sessionId].slice(-SESSIONS_CAP3);
7546
8084
  try {
7547
- mkdirSync7(join12(file2, ".."), { recursive: true });
7548
- writeFileSync9(file2, JSON.stringify({ sessions: next }), "utf8");
8085
+ mkdirSync8(join13(file2, ".."), { recursive: true });
8086
+ writeFileSync10(file2, JSON.stringify({ sessions: next }), "utf8");
7549
8087
  } catch {
7550
8088
  }
7551
8089
  }
@@ -7633,6 +8171,20 @@ async function userPromptSubmitHook(deps = {}) {
7633
8171
  }
7634
8172
  }
7635
8173
 
8174
+ // src/hooks/runtime/pre-invocation.ts
8175
+ var STASH_SEPARATOR = "\n\n---\n\n";
8176
+ async function preInvocationHook(deps = {}) {
8177
+ const readStdin = deps.readStdin ?? readStdinJson;
8178
+ const stdin = await readStdin();
8179
+ if (!isAntigravityEnvelope(stdin)) return;
8180
+ const key = conversationKey(stdin);
8181
+ if (!key) return;
8182
+ const dir = deps.stateDir ?? antigravityStateDir();
8183
+ const bodies = drainContext(key, dir);
8184
+ if (bodies.length === 0) return;
8185
+ emitContext(bodies.join(STASH_SEPARATOR), "antigravity", "PreInvocation");
8186
+ }
8187
+
7636
8188
  // src/guards-evaluator/glob.ts
7637
8189
  function expandHome(pattern, homeDir) {
7638
8190
  if (pattern === "~") return homeDir;
@@ -8364,7 +8916,7 @@ function buildCommandViews(raw) {
8364
8916
  }
8365
8917
 
8366
8918
  // src/guards-evaluator/redact.ts
8367
- import { createHash as createHash2 } from "node:crypto";
8919
+ import { createHash as createHash3 } from "node:crypto";
8368
8920
  var REDACTED = "[REDACTED]";
8369
8921
  var PATTERNS = [
8370
8922
  // 1. JWT — three base64url segments separated by dots
@@ -8476,7 +9028,7 @@ function redactScriptText(text) {
8476
9028
  return redactTarget(masked, Number.MAX_SAFE_INTEGER);
8477
9029
  }
8478
9030
  function hashTarget(text) {
8479
- return createHash2("sha256").update(text, "utf8").digest("hex");
9031
+ return createHash3("sha256").update(text, "utf8").digest("hex");
8480
9032
  }
8481
9033
 
8482
9034
  // src/guards-evaluator/evaluate.ts
@@ -11093,15 +11645,15 @@ function resolveCandidatePaths(rawPath, opts) {
11093
11645
  // src/hooks/runtime/session-writes.ts
11094
11646
  import {
11095
11647
  existsSync as existsSync17,
11096
- mkdirSync as mkdirSync8,
11097
- readFileSync as readFileSync16,
11098
- renameSync,
11648
+ mkdirSync as mkdirSync9,
11649
+ readFileSync as readFileSync17,
11650
+ renameSync as renameSync2,
11099
11651
  rmdirSync,
11100
11652
  statSync as statSync3,
11101
- writeFileSync as writeFileSync10
11653
+ writeFileSync as writeFileSync11
11102
11654
  } from "node:fs";
11103
- import { homedir as homedir12 } from "node:os";
11104
- import { join as join13, posix } from "node:path";
11655
+ import { homedir as homedir13 } from "node:os";
11656
+ import { join as join14, posix } from "node:path";
11105
11657
  var DEFAULT_MAX_PATHS = 500;
11106
11658
  var DEFAULT_SESSION_WRITES_TTL_MS = 4 * 60 * 60 * 1e3;
11107
11659
  var SESSION_WRITES_FILE = "guards-session-writes.json";
@@ -11115,7 +11667,7 @@ function withLock(lockDir, fn) {
11115
11667
  let held = false;
11116
11668
  while (!held) {
11117
11669
  try {
11118
- mkdirSync8(lockDir);
11670
+ mkdirSync9(lockDir);
11119
11671
  held = true;
11120
11672
  } catch {
11121
11673
  try {
@@ -11142,7 +11694,7 @@ function withLock(lockDir, fn) {
11142
11694
  }
11143
11695
  }
11144
11696
  function defaultDir() {
11145
- return process.env.CYBEDEFEND_BASELINE_DIR ?? join13(homedir12(), ".cybedefend");
11697
+ return process.env.CYBEDEFEND_BASELINE_DIR ?? join14(homedir13(), ".cybedefend");
11146
11698
  }
11147
11699
  function normalizePath(p) {
11148
11700
  if (typeof p !== "string") return "";
@@ -11177,14 +11729,14 @@ function coerce(raw) {
11177
11729
  }
11178
11730
  function makeSessionWritesStore(opts = {}) {
11179
11731
  const dir = opts.dir ?? defaultDir();
11180
- const file2 = join13(dir, SESSION_WRITES_FILE);
11732
+ const file2 = join14(dir, SESSION_WRITES_FILE);
11181
11733
  const now = opts.now ?? (() => Date.now());
11182
11734
  const maxPaths = typeof opts.maxPaths === "number" && opts.maxPaths > 0 ? Math.floor(opts.maxPaths) : DEFAULT_MAX_PATHS;
11183
11735
  const ttlMs = typeof opts.ttlMs === "number" && opts.ttlMs > 0 ? opts.ttlMs : DEFAULT_SESSION_WRITES_TTL_MS;
11184
11736
  function readAll() {
11185
11737
  if (!existsSync17(file2)) return {};
11186
11738
  try {
11187
- return coerce(JSON.parse(readFileSync16(file2, "utf8")));
11739
+ return coerce(JSON.parse(readFileSync17(file2, "utf8")));
11188
11740
  } catch {
11189
11741
  return {};
11190
11742
  }
@@ -11199,10 +11751,10 @@ function makeSessionWritesStore(opts = {}) {
11199
11751
  }
11200
11752
  function writeAll(all) {
11201
11753
  try {
11202
- if (!existsSync17(dir)) mkdirSync8(dir, { recursive: true });
11754
+ if (!existsSync17(dir)) mkdirSync9(dir, { recursive: true });
11203
11755
  const tmp = `${file2}.${process.pid}.tmp`;
11204
- writeFileSync10(tmp, JSON.stringify(all), "utf8");
11205
- renameSync(tmp, file2);
11756
+ writeFileSync11(tmp, JSON.stringify(all), "utf8");
11757
+ renameSync2(tmp, file2);
11206
11758
  } catch {
11207
11759
  }
11208
11760
  }
@@ -11212,7 +11764,7 @@ function makeSessionWritesStore(opts = {}) {
11212
11764
  const usable = paths.filter(isUsable);
11213
11765
  if (usable.length === 0) return;
11214
11766
  try {
11215
- if (!existsSync17(dir)) mkdirSync8(dir, { recursive: true });
11767
+ if (!existsSync17(dir)) mkdirSync9(dir, { recursive: true });
11216
11768
  withLock(`${file2}.lock`, () => {
11217
11769
  const t = now();
11218
11770
  const all = pruneExpired(readAll(), t);
@@ -11528,10 +12080,10 @@ function nearMiss(req, rule) {
11528
12080
  import { isAbsolute as isAbsolute6, resolve as resolvePath4 } from "node:path";
11529
12081
 
11530
12082
  // src/hooks/runtime/guard-rules-cache.ts
11531
- import { readFileSync as readFileSync17, writeFileSync as writeFileSync11, existsSync as existsSync18, mkdirSync as mkdirSync9 } from "node:fs";
12083
+ import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, existsSync as existsSync18, mkdirSync as mkdirSync10 } from "node:fs";
11532
12084
  import { dirname as dirname9 } from "node:path";
11533
- import { homedir as homedir13 } from "node:os";
11534
- import { join as join14 } from "node:path";
12085
+ import { homedir as homedir14 } from "node:os";
12086
+ import { join as join15 } from "node:path";
11535
12087
 
11536
12088
  // node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/external.js
11537
12089
  var external_exports = {};
@@ -31338,7 +31890,7 @@ function retryAfterOf(e) {
31338
31890
  }
31339
31891
 
31340
31892
  // src/hooks/runtime/retry-policy.ts
31341
- import { createHash as createHash3 } from "node:crypto";
31893
+ import { createHash as createHash4 } from "node:crypto";
31342
31894
  var UNAUTHORIZED_BACKOFF_MS = [
31343
31895
  6e4,
31344
31896
  5 * 6e4,
@@ -31364,12 +31916,12 @@ function unauthorizedBackoffMs(consecutive) {
31364
31916
  return UNAUTHORIZED_BACKOFF_MS[index];
31365
31917
  }
31366
31918
  function tokenFingerprint(token) {
31367
- return createHash3("sha256").update(token).digest("hex").slice(0, 16);
31919
+ return createHash4("sha256").update(token).digest("hex").slice(0, 16);
31368
31920
  }
31369
31921
 
31370
31922
  // src/hooks/runtime/guard-rules-cache.ts
31371
- var DEFAULT_CACHE_FILE = join14(
31372
- homedir13(),
31923
+ var DEFAULT_CACHE_FILE = join15(
31924
+ homedir14(),
31373
31925
  ".cybedefend",
31374
31926
  "guards-cache.json"
31375
31927
  );
@@ -31444,7 +31996,7 @@ function reportDroppedRules(dropped) {
31444
31996
  }
31445
31997
  function makeGuardRulesCache(opts) {
31446
31998
  const cacheFile = opts.cacheFile ?? DEFAULT_CACHE_FILE;
31447
- const failuresFile = opts.failuresFile ?? join14(dirname9(cacheFile), "guards-cache-failures.json");
31999
+ const failuresFile = opts.failuresFile ?? join15(dirname9(cacheFile), "guards-cache-failures.json");
31448
32000
  const staleSec = opts.staleSec ?? DEFAULT_STALE_SEC;
31449
32001
  const fetchFn = opts.fetchFn;
31450
32002
  const clock = opts.now ?? Date.now;
@@ -31549,7 +32101,7 @@ function makeGuardRulesCache(opts) {
31549
32101
  function readCache(projectId) {
31550
32102
  if (!existsSync18(cacheFile)) return null;
31551
32103
  try {
31552
- const raw = readFileSync17(cacheFile, "utf8");
32104
+ const raw = readFileSync18(cacheFile, "utf8");
31553
32105
  const data = JSON.parse(raw);
31554
32106
  if (data.projectId !== projectId) return null;
31555
32107
  return data;
@@ -31560,7 +32112,7 @@ function makeGuardRulesCache(opts) {
31560
32112
  function readFailures() {
31561
32113
  try {
31562
32114
  if (!existsSync18(failuresFile)) return {};
31563
- const parsed = JSON.parse(readFileSync17(failuresFile, "utf8"));
32115
+ const parsed = JSON.parse(readFileSync18(failuresFile, "utf8"));
31564
32116
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
31565
32117
  return {};
31566
32118
  }
@@ -31582,7 +32134,7 @@ function makeGuardRulesCache(opts) {
31582
32134
  if (now - f.at > FAILURE_RETENTION_MS) delete failures[projectId];
31583
32135
  }
31584
32136
  ensureDirFor2(failuresFile);
31585
- writeFileSync11(failuresFile, JSON.stringify(failures), "utf8");
32137
+ writeFileSync12(failuresFile, JSON.stringify(failures), "utf8");
31586
32138
  } catch {
31587
32139
  }
31588
32140
  }
@@ -31593,7 +32145,7 @@ function makeGuardRulesCache(opts) {
31593
32145
  function writeCache(entry) {
31594
32146
  try {
31595
32147
  ensureDirFor2(cacheFile);
31596
- writeFileSync11(cacheFile, JSON.stringify(entry), "utf8");
32148
+ writeFileSync12(cacheFile, JSON.stringify(entry), "utf8");
31597
32149
  } catch {
31598
32150
  }
31599
32151
  }
@@ -31602,7 +32154,7 @@ function makeGuardRulesCache(opts) {
31602
32154
  function ensureDirFor2(filePath) {
31603
32155
  const dir = dirname9(filePath);
31604
32156
  if (!existsSync18(dir)) {
31605
- mkdirSync9(dir, { recursive: true });
32157
+ mkdirSync10(dir, { recursive: true });
31606
32158
  }
31607
32159
  }
31608
32160
  var DEFAULT_TIMEOUT_MS2 = 8e3;
@@ -31742,11 +32294,11 @@ function detectPromptInjection(text) {
31742
32294
  }
31743
32295
 
31744
32296
  // 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(),
32297
+ import { readFileSync as readFileSync19, writeFileSync as writeFileSync13, existsSync as existsSync19, mkdirSync as mkdirSync11 } from "node:fs";
32298
+ import { dirname as dirname10, join as join16 } from "node:path";
32299
+ import { homedir as homedir15 } from "node:os";
32300
+ var DEFAULT_JUDGE_CACHE_FILE = join16(
32301
+ homedir15(),
31750
32302
  ".cybedefend",
31751
32303
  "guards-judge-cache.json"
31752
32304
  );
@@ -31759,7 +32311,7 @@ function makeJudgeCache(opts = {}) {
31759
32311
  function readAll() {
31760
32312
  if (!existsSync19(cacheFile)) return {};
31761
32313
  try {
31762
- return JSON.parse(readFileSync18(cacheFile, "utf8"));
32314
+ return JSON.parse(readFileSync19(cacheFile, "utf8"));
31763
32315
  } catch {
31764
32316
  return {};
31765
32317
  }
@@ -31783,7 +32335,7 @@ function makeJudgeCache(opts = {}) {
31783
32335
  for (const k of keys.slice(0, Math.max(0, keys.length - maxEntries))) delete all[k];
31784
32336
  }
31785
32337
  ensureDirFor3(cacheFile);
31786
- writeFileSync12(cacheFile, JSON.stringify(all), "utf8");
32338
+ writeFileSync13(cacheFile, JSON.stringify(all), "utf8");
31787
32339
  } catch {
31788
32340
  }
31789
32341
  }
@@ -31792,34 +32344,34 @@ function makeJudgeCache(opts = {}) {
31792
32344
  function ensureDirFor3(filePath) {
31793
32345
  const dir = dirname10(filePath);
31794
32346
  if (!existsSync19(dir)) {
31795
- mkdirSync10(dir, { recursive: true });
32347
+ mkdirSync11(dir, { recursive: true });
31796
32348
  }
31797
32349
  }
31798
32350
 
31799
32351
  // src/hooks/runtime/guard-check.ts
31800
32352
  import { spawn as spawn3 } from "node:child_process";
31801
- import { homedir as homedir17 } from "node:os";
31802
- import { join as join18 } from "node:path";
32353
+ import { homedir as homedir18 } from "node:os";
32354
+ import { join as join19 } from "node:path";
31803
32355
 
31804
32356
  // src/hooks/runtime/guard-violations-buffer.ts
31805
32357
  import {
31806
- appendFileSync,
31807
- closeSync as closeSync2,
32358
+ appendFileSync as appendFileSync2,
32359
+ closeSync as closeSync3,
31808
32360
  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,
32361
+ openSync as openSync3,
32362
+ readFileSync as readFileSync20,
32363
+ writeFileSync as writeFileSync14,
32364
+ writeSync as writeSync3,
32365
+ mkdirSync as mkdirSync12,
32366
+ rmSync as rmSync3,
31815
32367
  statSync as statSync4,
31816
- utimesSync
32368
+ utimesSync as utimesSync2
31817
32369
  } from "node:fs";
31818
32370
  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(),
32371
+ import { homedir as homedir16 } from "node:os";
32372
+ import { join as join17 } from "node:path";
32373
+ var DEFAULT_BUFFER_FILE = join17(
32374
+ homedir16(),
31823
32375
  ".cybedefend",
31824
32376
  "guards-violations-buffer.jsonl"
31825
32377
  );
@@ -31830,8 +32382,8 @@ var MAX_RECORD_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
31830
32382
  var FLUSH_LOCK_STALE_MS = 6e4;
31831
32383
  function makeViolationsBuffer(opts = {}) {
31832
32384
  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");
32385
+ const holdsFile = opts.holdsFile ?? join17(dirname11(bufferFile), "guards-violations-holds.json");
32386
+ const lockFile = opts.lockFile ?? join17(dirname11(bufferFile), "guards-violations-flush.lock");
31835
32387
  const now = opts.now ?? Date.now;
31836
32388
  function bufferViolation2(ctx, v) {
31837
32389
  const record2 = {
@@ -31841,7 +32393,7 @@ function makeViolationsBuffer(opts = {}) {
31841
32393
  };
31842
32394
  try {
31843
32395
  ensureDirFor4(bufferFile);
31844
- appendFileSync(bufferFile, JSON.stringify(record2) + "\n", "utf8");
32396
+ appendFileSync2(bufferFile, JSON.stringify(record2) + "\n", "utf8");
31845
32397
  } catch {
31846
32398
  }
31847
32399
  }
@@ -31923,7 +32475,7 @@ function makeViolationsBuffer(opts = {}) {
31923
32475
  writeHolds(holds);
31924
32476
  try {
31925
32477
  const serialised = failed.map((r) => JSON.stringify(r) + "\n").join("");
31926
- writeFileSync13(bufferFile, serialised + appendedSince(snapshot.bytes), "utf8");
32478
+ writeFileSync14(bufferFile, serialised + appendedSince(snapshot.bytes), "utf8");
31927
32479
  } catch {
31928
32480
  }
31929
32481
  }
@@ -31945,7 +32497,7 @@ function makeViolationsBuffer(opts = {}) {
31945
32497
  }
31946
32498
  function readBuffer() {
31947
32499
  try {
31948
- const raw = readFileSync19(bufferFile);
32500
+ const raw = readFileSync20(bufferFile);
31949
32501
  return { content: raw.toString("utf8"), bytes: raw.length };
31950
32502
  } catch {
31951
32503
  return null;
@@ -31953,7 +32505,7 @@ function makeViolationsBuffer(opts = {}) {
31953
32505
  }
31954
32506
  function appendedSince(bytes) {
31955
32507
  try {
31956
- const raw = readFileSync19(bufferFile);
32508
+ const raw = readFileSync20(bufferFile);
31957
32509
  return raw.length > bytes ? raw.subarray(bytes).toString("utf8") : "";
31958
32510
  } catch {
31959
32511
  return "";
@@ -31967,18 +32519,18 @@ function makeViolationsBuffer(opts = {}) {
31967
32519
  }
31968
32520
  for (let attempt = 0; attempt < 2; attempt++) {
31969
32521
  try {
31970
- const fd = openSync2(lockFile, "wx");
32522
+ const fd = openSync3(lockFile, "wx");
31971
32523
  try {
31972
- writeSync(fd, String(process.pid));
32524
+ writeSync3(fd, String(process.pid));
31973
32525
  } finally {
31974
- closeSync2(fd);
32526
+ closeSync3(fd);
31975
32527
  }
31976
32528
  return true;
31977
32529
  } catch (e) {
31978
32530
  if (e.code !== "EEXIST") return false;
31979
32531
  if (!lockIsStale()) return false;
31980
32532
  try {
31981
- rmSync2(lockFile, { force: true });
32533
+ rmSync3(lockFile, { force: true });
31982
32534
  } catch {
31983
32535
  return false;
31984
32536
  }
@@ -31996,26 +32548,26 @@ function makeViolationsBuffer(opts = {}) {
31996
32548
  function touchLock() {
31997
32549
  try {
31998
32550
  const t = /* @__PURE__ */ new Date();
31999
- utimesSync(lockFile, t, t);
32551
+ utimesSync2(lockFile, t, t);
32000
32552
  } catch {
32001
32553
  }
32002
32554
  }
32003
32555
  function releaseLock() {
32004
32556
  try {
32005
- rmSync2(lockFile, { force: true });
32557
+ rmSync3(lockFile, { force: true });
32006
32558
  } catch {
32007
32559
  }
32008
32560
  }
32009
32561
  function liftHolds() {
32010
32562
  try {
32011
- rmSync2(holdsFile, { force: true });
32563
+ rmSync3(holdsFile, { force: true });
32012
32564
  } catch {
32013
32565
  }
32014
32566
  }
32015
32567
  function readHolds() {
32016
32568
  try {
32017
32569
  if (!existsSync20(holdsFile)) return {};
32018
- const parsed = JSON.parse(readFileSync19(holdsFile, "utf8"));
32570
+ const parsed = JSON.parse(readFileSync20(holdsFile, "utf8"));
32019
32571
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
32020
32572
  return {};
32021
32573
  }
@@ -32040,11 +32592,11 @@ function makeViolationsBuffer(opts = {}) {
32040
32592
  function writeHolds(holds) {
32041
32593
  try {
32042
32594
  if (Object.keys(holds).length === 0) {
32043
- rmSync2(holdsFile, { force: true });
32595
+ rmSync3(holdsFile, { force: true });
32044
32596
  return;
32045
32597
  }
32046
32598
  ensureDirFor4(holdsFile);
32047
- writeFileSync13(holdsFile, JSON.stringify(holds), "utf8");
32599
+ writeFileSync14(holdsFile, JSON.stringify(holds), "utf8");
32048
32600
  } catch {
32049
32601
  }
32050
32602
  }
@@ -32077,7 +32629,7 @@ function capRecords(records, now) {
32077
32629
  function ensureDirFor4(filePath) {
32078
32630
  const dir = dirname11(filePath);
32079
32631
  if (!existsSync20(dir)) {
32080
- mkdirSync11(dir, { recursive: true });
32632
+ mkdirSync12(dir, { recursive: true });
32081
32633
  }
32082
32634
  }
32083
32635
  var _defaultBuffer = makeViolationsBuffer();
@@ -32086,9 +32638,9 @@ var flushViolations = _defaultBuffer.flushViolations.bind(_defaultBuffer);
32086
32638
  var liftViolationHolds = _defaultBuffer.liftHolds.bind(_defaultBuffer);
32087
32639
 
32088
32640
  // 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";
32641
+ import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync15 } from "node:fs";
32642
+ import { dirname as dirname12, join as join18 } from "node:path";
32643
+ import { homedir as homedir17 } from "node:os";
32092
32644
  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
32645
  var OWN_MCP_TOOL_RE = /^mcp__cybedefend(?:-[A-Za-z0-9_-]+)?__/;
32094
32646
  function isTargetlessTool(tool) {
@@ -32100,13 +32652,13 @@ function strictUnmappedPolicy() {
32100
32652
  }
32101
32653
  var MAX_TOOLS = 200;
32102
32654
  function defaultUnmappedToolsFile() {
32103
- const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join17(homedir16(), ".cybedefend");
32104
- return join17(dir, "guards-unmapped-tools.json");
32655
+ const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join18(homedir17(), ".cybedefend");
32656
+ return join18(dir, "guards-unmapped-tools.json");
32105
32657
  }
32106
32658
  function load(file2) {
32107
32659
  try {
32108
32660
  if (!existsSync21(file2)) return { tools: {} };
32109
- const parsed = JSON.parse(readFileSync20(file2, "utf8"));
32661
+ const parsed = JSON.parse(readFileSync21(file2, "utf8"));
32110
32662
  if (!parsed || typeof parsed !== "object" || typeof parsed.tools !== "object" || !parsed.tools) {
32111
32663
  return { tools: {} };
32112
32664
  }
@@ -32130,8 +32682,8 @@ function makeUnmappedToolTelemetry(file2 = defaultUnmappedToolsFile()) {
32130
32682
  if (names.length > MAX_TOOLS) {
32131
32683
  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
32684
  }
32133
- mkdirSync12(dirname12(file2), { recursive: true });
32134
- writeFileSync14(file2, JSON.stringify(data, null, 2) + "\n", "utf8");
32685
+ mkdirSync13(dirname12(file2), { recursive: true });
32686
+ writeFileSync15(file2, JSON.stringify(data, null, 2) + "\n", "utf8");
32135
32687
  } catch {
32136
32688
  }
32137
32689
  }
@@ -32171,9 +32723,16 @@ function extractWriteTargets(req, rawCommand) {
32171
32723
  }
32172
32724
  return [];
32173
32725
  }
32174
- function normalizeToolName(tool) {
32726
+ function normalizeToolName(tool, client) {
32175
32727
  if (!tool) return "";
32176
32728
  const t = (tool.split(/[\r\n]/, 1)[0] ?? "").trim();
32729
+ if (client === "antigravity") {
32730
+ if (/^view_file$/i.test(t)) return "Read";
32731
+ if (/^(write_to_file|write_file)$/i.test(t)) return "Write";
32732
+ if (/^(replace_file_content|edit_file)$/i.test(t)) return "Edit";
32733
+ if (/^multi_replace_file_content$/i.test(t)) return "MultiEdit";
32734
+ if (/^read_url_content$/i.test(t)) return "WebFetch";
32735
+ }
32177
32736
  if (/^(read|read_file|cat)$/i.test(t)) return "Read";
32178
32737
  if (/^(write|create_file|new_file)$/i.test(t)) return "Write";
32179
32738
  if (/^(edit|apply_patch|str_replace_editor)$/i.test(t)) return "Edit";
@@ -32189,11 +32748,11 @@ function appendDebugLog(entry) {
32189
32748
  try {
32190
32749
  const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? "";
32191
32750
  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");
32751
+ const { mkdirSync: mkdirSync14, appendFileSync: appendFileSync3 } = __require("node:fs");
32752
+ const { join: join20 } = __require("node:path");
32753
+ const dir = join20(homeDir, ".cybedefend");
32754
+ mkdirSync14(dir, { recursive: true });
32755
+ appendFileSync3(join20(dir, "hook-debug.log"), entry + "\n", "utf8");
32197
32756
  } catch {
32198
32757
  }
32199
32758
  }
@@ -32208,9 +32767,63 @@ function debugLog(entry) {
32208
32767
  }
32209
32768
  }
32210
32769
  var UNNAMED_TOOL = "<unnamed>";
32770
+ function sniffCaller(envelope) {
32771
+ try {
32772
+ return sniff(envelope);
32773
+ } catch {
32774
+ }
32775
+ let client = "unknown";
32776
+ try {
32777
+ client = detectClient(envelope);
32778
+ } catch {
32779
+ }
32780
+ const rawTool = client === "antigravity" && isRecord(envelope.toolCall) ? envelope.toolCall.name : envelope?.tool_name;
32781
+ return {
32782
+ client,
32783
+ toolName: typeof rawTool === "string" ? rawTool : "",
32784
+ filePath: "",
32785
+ filePaths: [],
32786
+ newContent: "",
32787
+ raw: envelope
32788
+ };
32789
+ }
32211
32790
  function argvToCommandLine(argv) {
32212
32791
  return argv.map((a) => /^[A-Za-z0-9_./=:@%+,-]+$/.test(a) ? a : `'${a.replace(/'/g, "'\\''")}'`).join(" ");
32213
32792
  }
32793
+ var MCP_SERVER_NAME_RE = /^[A-Za-z0-9]+(?:[-_][A-Za-z0-9]+)*$/;
32794
+ var MCP_SERVER_NAME_MAX = 64;
32795
+ var MCP_TOOL_NAME_RE = /^[A-Za-z0-9]+(?:[-_.][A-Za-z0-9]+)*$/;
32796
+ var MCP_TOOL_NAME_MAX = 128;
32797
+ function isRecord(v) {
32798
+ return typeof v === "object" && v !== null && !Array.isArray(v);
32799
+ }
32800
+ function readAntigravityCall(envelope) {
32801
+ const toolCall = isRecord(envelope.toolCall) ? envelope.toolCall : {};
32802
+ const args = isRecord(toolCall.args) ? toolCall.args : {};
32803
+ const str3 = (v) => typeof v === "string" ? v : void 0;
32804
+ const name = str3(toolCall.name);
32805
+ let tool = name;
32806
+ const server = str3(args.ServerName);
32807
+ const mcpTool = str3(args.ToolName);
32808
+ 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)) {
32809
+ tool = `mcp__${server}__${mcpTool}`;
32810
+ }
32811
+ const params = {};
32812
+ const filePath = antigravityFilePathArg(name ?? "", args);
32813
+ if (filePath) params.file_path = filePath;
32814
+ const command = str3(args.CommandLine);
32815
+ if (command !== void 0) params.command = command;
32816
+ const url2 = str3(args.Url);
32817
+ if (url2 !== void 0) params.url = url2;
32818
+ let classifiedTool;
32819
+ let extraFilePaths = [];
32820
+ if (name !== void 0 && filePath && !ANTIGRAVITY_KNOWN_TOOLS.has(name)) {
32821
+ classifiedTool = classifyUnknownAntigravityTool(args);
32822
+ extraFilePaths = antigravityAllPathArgs(args).filter((p) => p !== filePath);
32823
+ }
32824
+ const cwd = typeof args.Cwd === "string" && args.Cwd.length > 0 ? args.Cwd : sessionFolderOf(envelope, "antigravity");
32825
+ return { tool, classifiedTool, params, extraFilePaths, cwd, argKeys: Object.keys(args) };
32826
+ }
32214
32827
  function commandField(params) {
32215
32828
  const v = params.command;
32216
32829
  if (typeof v === "string") return v;
@@ -32219,40 +32832,67 @@ function commandField(params) {
32219
32832
  }
32220
32833
  return null;
32221
32834
  }
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 ?? {};
32835
+ function windsurfToolCall(envelope) {
32836
+ const ev = sniffCaller(envelope);
32837
+ switch (ev.toolName) {
32838
+ case "Bash":
32839
+ return { rawTool: ev.toolName, params: { command: ev.newContent } };
32840
+ case "Read":
32841
+ case "Write":
32842
+ return { rawTool: ev.toolName, params: { file_path: ev.filePath } };
32843
+ default:
32844
+ return { rawTool: ev.toolName, params: {} };
32845
+ }
32846
+ }
32847
+ function fileMapping(agent, tool, params, homeDir, cwd, rawTool, extraFilePaths) {
32848
+ const filePath = typeof params.file_path === "string" ? params.file_path : typeof params.path === "string" ? params.path : null;
32849
+ if (!filePath) return { kind: "unmapped", tool: rawTool ?? UNNAMED_TOOL };
32850
+ const request = {
32851
+ agent,
32852
+ tool,
32853
+ target: { type: "file", path: filePath },
32854
+ homeDir,
32855
+ cwd
32856
+ };
32857
+ if (extraFilePaths.length === 0) return { kind: "mapped", request };
32858
+ return {
32859
+ kind: "mapped",
32860
+ request,
32861
+ additionalRequests: extraFilePaths.map((path) => ({
32862
+ agent,
32863
+ tool,
32864
+ target: { type: "file", path },
32865
+ homeDir,
32866
+ cwd
32867
+ }))
32868
+ };
32869
+ }
32870
+ function mapEnvelope(envelope, agent = sniffCaller(envelope).client) {
32871
+ const antigravity = agent === "antigravity" ? readAntigravityCall(envelope) : null;
32872
+ const windsurf = agent === "windsurf" ? windsurfToolCall(envelope) : null;
32873
+ const rawTool = antigravity ? antigravity.tool : windsurf ? windsurf.rawTool : typeof envelope.tool_name === "string" ? envelope.tool_name : typeof envelope.tool === "string" ? envelope.tool : void 0;
32874
+ const params = antigravity ? antigravity.params : windsurf ? windsurf.params : envelope.tool_input ?? envelope.params ?? envelope.input ?? {};
32875
+ const loggedKeys = antigravity ? antigravity.argKeys : Object.keys(params);
32225
32876
  debugLog({
32226
32877
  event: "pre_map",
32227
32878
  raw_tool_name: rawTool ?? null,
32228
32879
  has_tool_input: "tool_input" in envelope,
32229
32880
  has_params: "params" in envelope,
32230
- param_keys: Object.keys(params).slice(0, 12)
32881
+ param_keys: loggedKeys.slice(0, 12)
32231
32882
  });
32232
32883
  const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? "/";
32233
- const cwd = process.cwd();
32234
- const tool = normalizeToolName(rawTool);
32884
+ const cwd = antigravity ? antigravity.cwd : process.cwd();
32885
+ const tool = antigravity?.classifiedTool ?? normalizeToolName(rawTool, agent);
32886
+ const extraFilePaths = antigravity?.extraFilePaths ?? [];
32235
32887
  switch (tool) {
32236
32888
  case "Read":
32237
32889
  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
- }
32890
+ case "Grep":
32891
+ return fileMapping(agent, tool, params, homeDir, cwd, rawTool, extraFilePaths);
32246
32892
  case "Write":
32247
32893
  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
- }
32894
+ case "MultiEdit":
32895
+ return fileMapping(agent, tool, params, homeDir, cwd, rawTool, extraFilePaths);
32256
32896
  case "Bash": {
32257
32897
  const command = commandField(params);
32258
32898
  if (!command) return { kind: "unmapped", tool: rawTool ?? UNNAMED_TOOL };
@@ -32334,7 +32974,7 @@ function mapEnvelope(envelope, agent = sniff(envelope).client) {
32334
32974
  JSON.stringify({
32335
32975
  ts: (/* @__PURE__ */ new Date()).toISOString(),
32336
32976
  tool_name: rawTool ?? null,
32337
- params_keys: Object.keys(params)
32977
+ params_keys: loggedKeys
32338
32978
  })
32339
32979
  );
32340
32980
  return { kind: "unmapped", tool: rawTool ?? UNNAMED_TOOL };
@@ -32383,6 +33023,9 @@ function stringifyTarget(t) {
32383
33023
  return `git ${t.subcommand}`;
32384
33024
  }
32385
33025
  }
33026
+ function verdictRank(v) {
33027
+ return v === "deny" ? 2 : v === "warn" ? 1 : 0;
33028
+ }
32386
33029
  async function consultJudge(judge, sessionId, cacheKey, input2, cache = { get: (k) => judge.cacheGet(k), set: (k, r) => judge.cacheSet(k, r) }) {
32387
33030
  const cached2 = cache.get(cacheKey);
32388
33031
  if (cached2) return { kind: "result", res: cached2 };
@@ -32601,6 +33244,14 @@ ${JSON.stringify(payload)}` : targetStr);
32601
33244
  }
32602
33245
  return { engine: "llm", outcome: "confirmed", model: res.model };
32603
33246
  }
33247
+ var SESSION_ID_MAX = 128;
33248
+ function antigravitySessionId(envelope) {
33249
+ const id = envelope.conversationId;
33250
+ return typeof id === "string" && id.length > 0 && id.length <= SESSION_ID_MAX ? id : void 0;
33251
+ }
33252
+ function denyExitCode(client) {
33253
+ return client === "antigravity" ? 0 : 2;
33254
+ }
32604
33255
  async function runCatchJudgeStep(args) {
32605
33256
  const {
32606
33257
  judge,
@@ -32660,7 +33311,7 @@ async function runCatchJudgeStep(args) {
32660
33311
  message
32661
33312
  };
32662
33313
  }
32663
- function emitUnverifiedBanner(reason) {
33314
+ function emitUnverifiedBanner(reason, client) {
32664
33315
  const banner = [
32665
33316
  "\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
33317
  "\u2588 VibeDefend Action Guards \u2014 UNVERIFIED \u2588",
@@ -32678,7 +33329,7 @@ function emitUnverifiedBanner(reason) {
32678
33329
  ].join("\n") + "\n";
32679
33330
  process.stderr.write(banner);
32680
33331
  const isCodex = typeof process.env.CODEX_SANDBOX !== "undefined" || typeof process.env.CODEX_AGENT !== "undefined";
32681
- if (isCodex) {
33332
+ if (isCodex && client !== "antigravity") {
32682
33333
  try {
32683
33334
  const ctx = JSON.stringify({
32684
33335
  additionalContext: `VibeDefend Action Guards UNVERIFIED \u2014 ${reason} Tool call allowed WITHOUT enforcement. Run \`vibedefend login\` to restore protection.`
@@ -32688,8 +33339,10 @@ function emitUnverifiedBanner(reason) {
32688
33339
  }
32689
33340
  }
32690
33341
  }
32691
- function sessionIdOf3(envelope) {
32692
- return typeof envelope.session_id === "string" ? envelope.session_id : typeof envelope.sessionId === "string" ? envelope.sessionId : void 0;
33342
+ function sessionIdOf3(envelope, client) {
33343
+ if (typeof envelope.session_id === "string") return envelope.session_id;
33344
+ if (typeof envelope.sessionId === "string") return envelope.sessionId;
33345
+ return client === "antigravity" ? antigravitySessionId(envelope) : void 0;
32693
33346
  }
32694
33347
  async function runPreToolUseGuardWith(opts) {
32695
33348
  const {
@@ -32702,21 +33355,22 @@ async function runPreToolUseGuardWith(opts) {
32702
33355
  if (!projectContext) return 0;
32703
33356
  if (rulesOutcome.kind === "unavailable") {
32704
33357
  emitUnverifiedBanner(
32705
- `Policy engine unreachable: ${rulesOutcome.reason}`
33358
+ `Policy engine unreachable: ${rulesOutcome.reason}`,
33359
+ sniffCaller(stdinEnvelope).client
32706
33360
  );
32707
33361
  return 0;
32708
33362
  }
32709
33363
  if (rulesOutcome.kind === "blocked") {
32710
33364
  const sentence = opts.usageNotifier?.notifyBlock(
32711
- sessionIdOf3(stdinEnvelope),
33365
+ sessionIdOf3(stdinEnvelope, sniffCaller(stdinEnvelope).client),
32712
33366
  rulesOutcome.block
32713
33367
  );
32714
- if (sentence) emitAgentMessage("warn", sentence);
33368
+ if (sentence) emitAgentMessage("warn", sentence, sniffCaller(stdinEnvelope).client);
32715
33369
  return 0;
32716
33370
  }
32717
33371
  const rules = rulesOutcome.rules;
32718
- const caller = sniff(stdinEnvelope);
32719
- const sessionId = sessionIdOf3(stdinEnvelope);
33372
+ const caller = sniffCaller(stdinEnvelope);
33373
+ const sessionId = sessionIdOf3(stdinEnvelope, caller.client);
32720
33374
  const mapping = mapEnvelope(stdinEnvelope, caller.client);
32721
33375
  if (mapping.kind === "targetless") return 0;
32722
33376
  if (mapping.kind === "unmapped") {
@@ -32731,9 +33385,10 @@ async function runPreToolUseGuardWith(opts) {
32731
33385
  if (strictUnmappedPolicy()) {
32732
33386
  emitAgentMessage(
32733
33387
  "deny",
32734
- `Tool "${mapping.tool}" is not evaluated by Action Guards and CYBEDEFEND_GUARDS_STRICT is on \u2014 blocked (strict mode).`
33388
+ `Tool "${mapping.tool}" is not evaluated by Action Guards and CYBEDEFEND_GUARDS_STRICT is on \u2014 blocked (strict mode).`,
33389
+ caller.client
32735
33390
  );
32736
- return 2;
33391
+ return denyExitCode(caller.client);
32737
33392
  }
32738
33393
  if (opts.unmapped.noticeOnce(sessionId, mapping.tool)) {
32739
33394
  process.stderr.write(
@@ -32744,12 +33399,24 @@ async function runPreToolUseGuardWith(opts) {
32744
33399
  return 0;
32745
33400
  }
32746
33401
  const partial2 = mapping.request;
32747
- const guardRequest = {
33402
+ let guardRequest = {
32748
33403
  ...partial2,
32749
33404
  projectId: projectContext.projectId,
32750
33405
  sessionId
32751
33406
  };
32752
33407
  let decision = evaluateFn(rules, guardRequest);
33408
+ for (const extra of mapping.additionalRequests ?? []) {
33409
+ const extraRequest = {
33410
+ ...extra,
33411
+ projectId: projectContext.projectId,
33412
+ sessionId
33413
+ };
33414
+ const extraDecision = evaluateFn(rules, extraRequest);
33415
+ if (verdictRank(extraDecision.verdict) > verdictRank(decision.verdict)) {
33416
+ decision = extraDecision;
33417
+ guardRequest = extraRequest;
33418
+ }
33419
+ }
32753
33420
  let hardenedTier = "small";
32754
33421
  let hardenedScripts = [];
32755
33422
  if (opts.hardenedCommandAnalysis && opts.sessionWrites && guardRequest.target.type === "file" && (guardRequest.tool === "Write" || guardRequest.tool === "Edit" || guardRequest.tool === "MultiEdit")) {
@@ -32904,20 +33571,28 @@ async function runPreToolUseGuardWith(opts) {
32904
33571
  matched_rule_ids: decision.matchedRuleIds
32905
33572
  });
32906
33573
  if (decision.verdict === "deny") {
32907
- emitAgentMessage("deny", decision.message ?? "Action blocked.");
32908
- return 2;
33574
+ emitAgentMessage("deny", decision.message ?? "Action blocked.", caller.client);
33575
+ return denyExitCode(caller.client);
32909
33576
  }
32910
33577
  if (decision.verdict === "warn") {
32911
- emitAgentMessage("warn", decision.message ?? "Action flagged.");
33578
+ emitAgentMessage("warn", decision.message ?? "Action flagged.", caller.client);
32912
33579
  return 0;
32913
33580
  }
32914
33581
  return 0;
32915
33582
  }
32916
- function emitAgentMessage(verdict, message) {
33583
+ var ANTIGRAVITY_DECISIONS = {
33584
+ deny: "deny",
33585
+ warn: "allow"
33586
+ };
33587
+ function emitAgentMessage(verdict, message, client) {
32917
33588
  const tag = verdict === "deny" ? "Action Guards" : "Action Guards \xB7 WARN";
32918
33589
  const fullMessage = `[VibeDefend ${tag}] ${message}`;
32919
33590
  process.stderr.write(fullMessage + "\n");
32920
33591
  try {
33592
+ if (client === "antigravity") {
33593
+ emitAntigravityDecision(ANTIGRAVITY_DECISIONS[verdict], fullMessage);
33594
+ return;
33595
+ }
32921
33596
  const payload = verdict === "deny" ? {
32922
33597
  // Claude Code legacy — the call, not the agent, is stopped.
32923
33598
  decision: "block",
@@ -32950,17 +33625,17 @@ function emitAgentMessage(verdict, message) {
32950
33625
  }
32951
33626
  function makeProductionJudgeDeps() {
32952
33627
  const cache = makeJudgeCache();
32953
- const warnDir = process.env.CYBEDEFEND_BASELINE_DIR ?? join18(homedir17(), ".cybedefend");
33628
+ const warnDir = process.env.CYBEDEFEND_BASELINE_DIR ?? join19(homedir18(), ".cybedefend");
32954
33629
  const scriptCache = makeJudgeCache({
32955
- cacheFile: join18(warnDir, "guards-judge-script-cache.json"),
33630
+ cacheFile: join19(warnDir, "guards-judge-script-cache.json"),
32956
33631
  ttlMs: SCRIPT_VERDICT_TTL_MS,
32957
33632
  maxEntries: SCRIPT_VERDICT_MAX_ENTRIES
32958
33633
  });
32959
33634
  const warnTracker = defaultSessionTracker(
32960
- join18(warnDir, "guards-judge-warned-sessions.json")
33635
+ join19(warnDir, "guards-judge-warned-sessions.json")
32961
33636
  );
32962
33637
  const blockedTracker = defaultSessionTracker(
32963
- join18(warnDir, "guards-judge-blocked-sessions.json")
33638
+ join19(warnDir, "guards-judge-blocked-sessions.json")
32964
33639
  );
32965
33640
  return {
32966
33641
  usage: {
@@ -32988,8 +33663,8 @@ function makeProductionJudgeDeps() {
32988
33663
  }
32989
33664
  function makeProductionUnmappedDeps() {
32990
33665
  const telemetry = makeUnmappedToolTelemetry();
32991
- const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join18(homedir17(), ".cybedefend");
32992
- const tracker = defaultSessionTracker(join18(dir, "guards-unmapped-notified.json"));
33666
+ const dir = process.env.CYBEDEFEND_BASELINE_DIR ?? join19(homedir18(), ".cybedefend");
33667
+ const tracker = defaultSessionTracker(join19(dir, "guards-unmapped-notified.json"));
32993
33668
  return {
32994
33669
  record: telemetry.record,
32995
33670
  noticeOnce: (sessionId, tool) => {
@@ -33043,7 +33718,8 @@ async function runPreToolUseGuard() {
33043
33718
  });
33044
33719
  if (!token && rulesOutcome.kind === "unavailable") {
33045
33720
  emitUnverifiedBanner(
33046
- "Not authenticated \u2014 run `vibedefend login` to restore Action Guards."
33721
+ "Not authenticated \u2014 run `vibedefend login` to restore Action Guards.",
33722
+ sniffCaller(envelope).client
33047
33723
  );
33048
33724
  return 0;
33049
33725
  }
@@ -33080,7 +33756,7 @@ async function runPreToolUseGuard() {
33080
33756
  scriptJudge: process.env.CYBEDEFEND_HARDENED_ANALYSIS !== "0" && process.env.CYBEDEFEND_SCRIPT_JUDGE !== "0",
33081
33757
  // Level 1 — real script reader + per-session write memory.
33082
33758
  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,
33759
+ sessionWrites: process.env.CYBEDEFEND_HARDENED_ANALYSIS !== "0" ? makeSessionWritesPort(sessionIdOf3(envelope, sniffCaller(envelope).client)) : void 0,
33084
33760
  resolvePaths: process.env.CYBEDEFEND_HARDENED_ANALYSIS !== "0" ? (rawPath, cwd, homeDir) => resolveCandidatePaths(rawPath, { cwd, homeDir }) : void 0,
33085
33761
  // The refusal sentence goes out through the agent-message channels
33086
33762
  // (stderr included), so this notifier itself writes nothing.
@@ -33177,7 +33853,31 @@ function toApiViolation(r) {
33177
33853
 
33178
33854
  // src/hooks/runtime/index.ts
33179
33855
  async function main() {
33180
- const subcommand = process.argv[2] ?? "";
33856
+ const { subcommand, client } = parseRunnerArgs(process.argv.slice(2));
33857
+ const isAntigravity = client === "antigravity";
33858
+ const finish = (code) => {
33859
+ if (isAntigravity) {
33860
+ finishAntigravityRun(subcommand);
33861
+ process.exit(0);
33862
+ }
33863
+ process.exit(code);
33864
+ };
33865
+ if (isAntigravity) {
33866
+ let crashed = false;
33867
+ const onCrash = (e) => {
33868
+ if (crashed) return;
33869
+ crashed = true;
33870
+ try {
33871
+ const msg = e instanceof Error ? e.stack || e.message : String(e);
33872
+ process.stderr.write(`[vibedefend hook] ${subcommand}: ${msg}
33873
+ `);
33874
+ } catch {
33875
+ }
33876
+ finish(0);
33877
+ };
33878
+ process.on("uncaughtException", onCrash);
33879
+ process.on("unhandledRejection", onCrash);
33880
+ }
33181
33881
  try {
33182
33882
  switch (subcommand) {
33183
33883
  case "fetch-rules":
@@ -33195,6 +33895,9 @@ async function main() {
33195
33895
  case "user-prompt-submit":
33196
33896
  await userPromptSubmitHook();
33197
33897
  break;
33898
+ case "pre-invocation":
33899
+ await preInvocationHook();
33900
+ break;
33198
33901
  case "flush-violations":
33199
33902
  await runViolationsFlush();
33200
33903
  break;
@@ -33202,21 +33905,21 @@ async function main() {
33202
33905
  case "pre-tool-use":
33203
33906
  case "PreToolUse": {
33204
33907
  const code = await runPreToolUseGuard();
33205
- process.exit(code);
33908
+ finish(code);
33206
33909
  return;
33207
33910
  }
33208
33911
  case "":
33209
33912
  case "--help":
33210
33913
  case "-h":
33211
33914
  process.stderr.write(
33212
- "Usage: hook-runner.js <fetch-rules|session-start|session-review|pre-compact|user-prompt-submit|guard-check>\n"
33915
+ "Usage: hook-runner.js <fetch-rules|session-start|session-review|pre-compact|user-prompt-submit|pre-invocation|guard-check> [--client antigravity]\n"
33213
33916
  );
33214
- process.exit(subcommand === "" ? 1 : 0);
33917
+ finish(subcommand === "" ? 1 : 0);
33215
33918
  return;
33216
33919
  default:
33217
33920
  process.stderr.write(`Unknown subcommand: ${subcommand}
33218
33921
  `);
33219
- process.exit(1);
33922
+ finish(1);
33220
33923
  return;
33221
33924
  }
33222
33925
  } catch (e) {
@@ -33224,6 +33927,6 @@ async function main() {
33224
33927
  process.stderr.write(`[vibedefend hook] ${subcommand}: ${msg}
33225
33928
  `);
33226
33929
  }
33227
- process.exit(0);
33930
+ finish(0);
33228
33931
  }
33229
33932
  main();