@intutic/sync-daemon 2.2.0 → 2.4.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 (235) hide show
  1. package/README.md +1 -1
  2. package/dist/agentReporter.d.ts +23 -11
  3. package/dist/agentReporter.d.ts.map +1 -1
  4. package/dist/agentReporter.js +20 -13
  5. package/dist/agentReporter.js.map +1 -1
  6. package/dist/configReader.d.ts +1 -3
  7. package/dist/configReader.d.ts.map +1 -1
  8. package/dist/configReader.js +0 -2
  9. package/dist/configReader.js.map +1 -1
  10. package/dist/configWriter.d.ts +11 -12
  11. package/dist/configWriter.d.ts.map +1 -1
  12. package/dist/configWriter.js +35 -58
  13. package/dist/configWriter.js.map +1 -1
  14. package/dist/disconnect/harnesses.d.ts +0 -2
  15. package/dist/disconnect/harnesses.d.ts.map +1 -1
  16. package/dist/disconnect/harnesses.js +157 -80
  17. package/dist/disconnect/harnesses.js.map +1 -1
  18. package/dist/disconnect/index.d.ts.map +1 -1
  19. package/dist/disconnect/index.js +11 -1
  20. package/dist/disconnect/index.js.map +1 -1
  21. package/dist/disconnect/mcp.d.ts +21 -0
  22. package/dist/disconnect/mcp.d.ts.map +1 -1
  23. package/dist/disconnect/mcp.js +71 -0
  24. package/dist/disconnect/mcp.js.map +1 -1
  25. package/dist/disconnect/recognise.d.ts +2 -2
  26. package/dist/disconnect/recognise.d.ts.map +1 -1
  27. package/dist/disconnect/recognise.js +15 -5
  28. package/dist/disconnect/recognise.js.map +1 -1
  29. package/dist/harness/aiderConfigMerger.d.ts +28 -8
  30. package/dist/harness/aiderConfigMerger.d.ts.map +1 -1
  31. package/dist/harness/aiderConfigMerger.js +59 -11
  32. package/dist/harness/aiderConfigMerger.js.map +1 -1
  33. package/dist/harness/antigravityCliHooks.d.ts +61 -0
  34. package/dist/harness/antigravityCliHooks.d.ts.map +1 -0
  35. package/dist/harness/antigravityCliHooks.js +207 -0
  36. package/dist/harness/antigravityCliHooks.js.map +1 -0
  37. package/dist/harness/antigravityHooks.d.ts +12 -2
  38. package/dist/harness/antigravityHooks.d.ts.map +1 -1
  39. package/dist/harness/antigravityHooks.js +36 -16
  40. package/dist/harness/antigravityHooks.js.map +1 -1
  41. package/dist/harness/antigravityProducts.d.ts +40 -0
  42. package/dist/harness/antigravityProducts.d.ts.map +1 -0
  43. package/dist/harness/antigravityProducts.js +109 -0
  44. package/dist/harness/antigravityProducts.js.map +1 -0
  45. package/dist/harness/claudeAgentsMd.d.ts +29 -0
  46. package/dist/harness/claudeAgentsMd.d.ts.map +1 -0
  47. package/dist/harness/claudeAgentsMd.js +80 -0
  48. package/dist/harness/claudeAgentsMd.js.map +1 -0
  49. package/dist/harness/claudeCodeHooks.d.ts +6 -5
  50. package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
  51. package/dist/harness/claudeCodeHooks.js +98 -24
  52. package/dist/harness/claudeCodeHooks.js.map +1 -1
  53. package/dist/harness/clineHooks.d.ts +0 -1
  54. package/dist/harness/clineHooks.d.ts.map +1 -1
  55. package/dist/harness/clineHooks.js +10 -4
  56. package/dist/harness/clineHooks.js.map +1 -1
  57. package/dist/harness/codexHooks.d.ts +2 -0
  58. package/dist/harness/codexHooks.d.ts.map +1 -1
  59. package/dist/harness/codexHooks.js +12 -4
  60. package/dist/harness/codexHooks.js.map +1 -1
  61. package/dist/harness/cursorHooks.d.ts +5 -2
  62. package/dist/harness/cursorHooks.d.ts.map +1 -1
  63. package/dist/harness/cursorHooks.js +9 -3
  64. package/dist/harness/cursorHooks.js.map +1 -1
  65. package/dist/harness/dshHooks.d.ts +5 -5
  66. package/dist/harness/dshHooks.d.ts.map +1 -1
  67. package/dist/harness/dshHooks.js +5 -5
  68. package/dist/harness/gateArtifacts.d.ts +35 -0
  69. package/dist/harness/gateArtifacts.d.ts.map +1 -0
  70. package/dist/harness/gateArtifacts.js +88 -0
  71. package/dist/harness/gateArtifacts.js.map +1 -0
  72. package/dist/harness/gateBody.d.ts +186 -69
  73. package/dist/harness/gateBody.d.ts.map +1 -1
  74. package/dist/harness/gateBody.js +820 -182
  75. package/dist/harness/gateBody.js.map +1 -1
  76. package/dist/harness/gateSightings.d.ts +47 -0
  77. package/dist/harness/gateSightings.d.ts.map +1 -0
  78. package/dist/harness/gateSightings.js +159 -0
  79. package/dist/harness/gateSightings.js.map +1 -0
  80. package/dist/harness/githubCopilotHooks.d.ts.map +1 -1
  81. package/dist/harness/githubCopilotHooks.js +7 -1
  82. package/dist/harness/githubCopilotHooks.js.map +1 -1
  83. package/dist/harness/gooseHardener.d.ts +0 -1
  84. package/dist/harness/gooseHardener.d.ts.map +1 -1
  85. package/dist/harness/gooseHardener.js +1 -1
  86. package/dist/harness/gooseHardener.js.map +1 -1
  87. package/dist/harness/gooseHooks.d.ts +14 -1
  88. package/dist/harness/gooseHooks.d.ts.map +1 -1
  89. package/dist/harness/gooseHooks.js +55 -29
  90. package/dist/harness/gooseHooks.js.map +1 -1
  91. package/dist/harness/grokHooks.d.ts +2 -2
  92. package/dist/harness/grokHooks.d.ts.map +1 -1
  93. package/dist/harness/grokHooks.js +11 -6
  94. package/dist/harness/grokHooks.js.map +1 -1
  95. package/dist/harness/hermesHooks.d.ts +18 -8
  96. package/dist/harness/hermesHooks.d.ts.map +1 -1
  97. package/dist/harness/hermesHooks.js +48 -17
  98. package/dist/harness/hermesHooks.js.map +1 -1
  99. package/dist/harness/mcpAutoWrite.d.ts +24 -9
  100. package/dist/harness/mcpAutoWrite.d.ts.map +1 -1
  101. package/dist/harness/mcpAutoWrite.js +218 -25
  102. package/dist/harness/mcpAutoWrite.js.map +1 -1
  103. package/dist/harness/museHooks.d.ts +3 -3
  104. package/dist/harness/museHooks.d.ts.map +1 -1
  105. package/dist/harness/museHooks.js +9 -5
  106. package/dist/harness/museHooks.js.map +1 -1
  107. package/dist/harness/n8nHooks.d.ts +0 -1
  108. package/dist/harness/n8nHooks.d.ts.map +1 -1
  109. package/dist/harness/n8nHooks.js +4 -1
  110. package/dist/harness/n8nHooks.js.map +1 -1
  111. package/dist/harness/openCodeHooks.d.ts +2 -2
  112. package/dist/harness/openCodeHooks.d.ts.map +1 -1
  113. package/dist/harness/openCodeHooks.js +7 -3
  114. package/dist/harness/openCodeHooks.js.map +1 -1
  115. package/dist/harness/openWebuiHooks.d.ts +0 -1
  116. package/dist/harness/openWebuiHooks.d.ts.map +1 -1
  117. package/dist/harness/openWebuiHooks.js +5 -1
  118. package/dist/harness/openWebuiHooks.js.map +1 -1
  119. package/dist/harness/openclawHooks.d.ts +70 -18
  120. package/dist/harness/openclawHooks.d.ts.map +1 -1
  121. package/dist/harness/openclawHooks.js +213 -161
  122. package/dist/harness/openclawHooks.js.map +1 -1
  123. package/dist/harness/openhandsHooks.d.ts +24 -10
  124. package/dist/harness/openhandsHooks.d.ts.map +1 -1
  125. package/dist/harness/openhandsHooks.js +49 -48
  126. package/dist/harness/openhandsHooks.js.map +1 -1
  127. package/dist/harness/piHooks.d.ts +52 -17
  128. package/dist/harness/piHooks.d.ts.map +1 -1
  129. package/dist/harness/piHooks.js +177 -166
  130. package/dist/harness/piHooks.js.map +1 -1
  131. package/dist/harness/protectedPaths.d.ts +107 -25
  132. package/dist/harness/protectedPaths.d.ts.map +1 -1
  133. package/dist/harness/protectedPaths.js +342 -48
  134. package/dist/harness/protectedPaths.js.map +1 -1
  135. package/dist/harness/rulesSection.d.ts +62 -0
  136. package/dist/harness/rulesSection.d.ts.map +1 -0
  137. package/dist/harness/rulesSection.js +145 -0
  138. package/dist/harness/rulesSection.js.map +1 -0
  139. package/dist/harness/windsurfHooks.d.ts +0 -1
  140. package/dist/harness/windsurfHooks.d.ts.map +1 -1
  141. package/dist/harness/windsurfHooks.js +4 -1
  142. package/dist/harness/windsurfHooks.js.map +1 -1
  143. package/dist/index.d.ts +12 -8
  144. package/dist/index.d.ts.map +1 -1
  145. package/dist/index.js +11 -9
  146. package/dist/index.js.map +1 -1
  147. package/dist/inventory.d.ts +53 -0
  148. package/dist/inventory.d.ts.map +1 -0
  149. package/dist/inventory.js +133 -0
  150. package/dist/inventory.js.map +1 -0
  151. package/dist/lib/complianceProbes.d.ts +2 -1
  152. package/dist/lib/complianceProbes.d.ts.map +1 -1
  153. package/dist/lib/complianceProbes.js +1 -1
  154. package/dist/lib/complianceProbes.js.map +1 -1
  155. package/dist/lib/decisionsDigest.d.ts +34 -16
  156. package/dist/lib/decisionsDigest.d.ts.map +1 -1
  157. package/dist/lib/decisionsDigest.js +105 -46
  158. package/dist/lib/decisionsDigest.js.map +1 -1
  159. package/dist/lib/egressPolicy.d.ts +2 -2
  160. package/dist/lib/egressPolicy.js +2 -2
  161. package/dist/lib/mcpRegistryPy.d.ts +11 -0
  162. package/dist/lib/mcpRegistryPy.d.ts.map +1 -0
  163. package/dist/lib/mcpRegistryPy.js +173 -0
  164. package/dist/lib/mcpRegistryPy.js.map +1 -0
  165. package/dist/lib/phrasesPy.d.ts +11 -0
  166. package/dist/lib/phrasesPy.d.ts.map +1 -0
  167. package/dist/lib/phrasesPy.js +351 -0
  168. package/dist/lib/phrasesPy.js.map +1 -0
  169. package/dist/lib/policySnapshot.d.ts +46 -10
  170. package/dist/lib/policySnapshot.d.ts.map +1 -1
  171. package/dist/lib/policySnapshot.js +136 -47
  172. package/dist/lib/policySnapshot.js.map +1 -1
  173. package/dist/lib/processPoller.d.ts.map +1 -1
  174. package/dist/lib/processPoller.js +9 -2
  175. package/dist/lib/processPoller.js.map +1 -1
  176. package/dist/lib/regexLinearity.d.ts +43 -0
  177. package/dist/lib/regexLinearity.d.ts.map +1 -0
  178. package/dist/lib/regexLinearity.js +275 -0
  179. package/dist/lib/regexLinearity.js.map +1 -0
  180. package/dist/lib/runtimeEnv.d.ts +1 -3
  181. package/dist/lib/runtimeEnv.d.ts.map +1 -1
  182. package/dist/lib/runtimeEnv.js +0 -2
  183. package/dist/lib/runtimeEnv.js.map +1 -1
  184. package/dist/lib/sequencePy.d.ts +10 -0
  185. package/dist/lib/sequencePy.d.ts.map +1 -0
  186. package/dist/lib/sequencePy.js +102 -0
  187. package/dist/lib/sequencePy.js.map +1 -0
  188. package/dist/sessionReporter.d.ts +17 -11
  189. package/dist/sessionReporter.d.ts.map +1 -1
  190. package/dist/sessionReporter.js +36 -23
  191. package/dist/sessionReporter.js.map +1 -1
  192. package/dist/skillWriter.d.ts +23 -5
  193. package/dist/skillWriter.d.ts.map +1 -1
  194. package/dist/skillWriter.js +159 -16
  195. package/dist/skillWriter.js.map +1 -1
  196. package/dist/syncCycle.d.ts.map +1 -1
  197. package/dist/syncCycle.js +21 -9
  198. package/dist/syncCycle.js.map +1 -1
  199. package/dist/trajectoryMonitor.d.ts +1 -3
  200. package/dist/trajectoryMonitor.d.ts.map +1 -1
  201. package/dist/trajectoryMonitor.js +1 -4
  202. package/dist/trajectoryMonitor.js.map +1 -1
  203. package/dist/watcher/driftWatcher.d.ts +0 -1
  204. package/dist/watcher/driftWatcher.d.ts.map +1 -1
  205. package/dist/watcher/driftWatcher.js +1 -2
  206. package/dist/watcher/driftWatcher.js.map +1 -1
  207. package/dist/watcher/settingsGuard.d.ts +33 -7
  208. package/dist/watcher/settingsGuard.d.ts.map +1 -1
  209. package/dist/watcher/settingsGuard.js +373 -61
  210. package/dist/watcher/settingsGuard.js.map +1 -1
  211. package/dist/watcher/vscodeHookSettings.d.ts +30 -0
  212. package/dist/watcher/vscodeHookSettings.d.ts.map +1 -0
  213. package/dist/watcher/vscodeHookSettings.js +170 -0
  214. package/dist/watcher/vscodeHookSettings.js.map +1 -0
  215. package/dist/wsClient.d.ts +0 -1
  216. package/dist/wsClient.d.ts.map +1 -1
  217. package/dist/wsClient.js +0 -1
  218. package/dist/wsClient.js.map +1 -1
  219. package/package.json +5 -5
  220. package/dist/harness/claudeDesktopHooks.d.ts +0 -33
  221. package/dist/harness/claudeDesktopHooks.d.ts.map +0 -1
  222. package/dist/harness/claudeDesktopHooks.js +0 -256
  223. package/dist/harness/claudeDesktopHooks.js.map +0 -1
  224. package/dist/harness/continueHooks.d.ts +0 -63
  225. package/dist/harness/continueHooks.d.ts.map +0 -1
  226. package/dist/harness/continueHooks.js +0 -250
  227. package/dist/harness/continueHooks.js.map +0 -1
  228. package/dist/harness/gateKind.d.ts +0 -164
  229. package/dist/harness/gateKind.d.ts.map +0 -1
  230. package/dist/harness/gateKind.js +0 -144
  231. package/dist/harness/gateKind.js.map +0 -1
  232. package/dist/harness/rooCodeHooks.d.ts +0 -31
  233. package/dist/harness/rooCodeHooks.d.ts.map +0 -1
  234. package/dist/harness/rooCodeHooks.js +0 -281
  235. package/dist/harness/rooCodeHooks.js.map +0 -1
@@ -0,0 +1,207 @@
1
+ /**
2
+ * antigravityCliHooks.ts — Google Antigravity governance hook injection.
3
+ *
4
+ * Antigravity (the 2.0 desktop app, the IDE and Antigravity CLI, which
5
+ * replaced Gemini CLI for individual users in 2026) runs command hooks from
6
+ * `<workspace>/.agents/hooks.json` and `~/.gemini/config/hooks.json`
7
+ * (https://antigravity.google/docs/hooks/). This module:
8
+ *
9
+ * 1. Writes the gate script to `.intutic/hooks/antigravity-cli-check.js`.
10
+ * 2. Merges an `intutic-governance` entry into `~/.gemini/config/hooks.json`,
11
+ * keeping every other hook in the file. A file that is not a plain JSON
12
+ * object is left alone and reported.
13
+ *
14
+ * # The hook contract, from the documentation
15
+ *
16
+ * The file's top-level keys are hook names; each maps event names to
17
+ * handlers. `PreToolUse` takes `{matcher, hooks: [{type, command, timeout?}]}`
18
+ * entries, where a matcher of `"*"` applies to every tool. The command gets
19
+ * `{toolCall: {name, args}, conversationId, workspacePaths, ...}` on stdin,
20
+ * camelCase, with Antigravity's own tool names (`run_command` with
21
+ * `CommandLine`, `write_to_file` and `replace_file_content` with
22
+ * `TargetFile`). It refuses a call by printing
23
+ * `{"decision":"deny","reason":"..."}` on stdout — the same shape as Grok
24
+ * Build's, so the gate uses the `stdout-decision-deny` contract.
25
+ *
26
+ * On an allowed call the gate prints `{}`: a JSON object, which every hook
27
+ * must print, with no decision in it, so Antigravity's own permission
28
+ * settings decide. The documented values all change what the user sees:
29
+ * `allow` is documented to auto-approve the call past the permission prompts
30
+ * the user configured, `ask` and `force_ask` to prompt, and
31
+ * `deny_unless_prior_grant` to refuse what was never granted. The
32
+ * documentation marks `decision` as required without saying how a result
33
+ * without one is read, so it was read from Antigravity itself (2.21.1, its
34
+ * `language_server`): `decision` is an optional string, `{}` parses to an
35
+ * empty one, and an empty decision is the lowest-ranked result when several
36
+ * hooks answer (deny > force_ask > deny_unless_prior_grant > ask >
37
+ * auto_approve > allow > none), so it never overrides another hook, and the
38
+ * permission check skips it, leaving the call to the user's own permission
39
+ * settings. A decision Antigravity does not know is reported as an error.
40
+ *
41
+ * HLD §3.14 — Three-Tier Defense Cascade (Tier 1 Native Gating)
42
+ * @module
43
+ */
44
+ import * as fs from 'node:fs/promises';
45
+ import * as path from 'node:path';
46
+ import * as os from 'node:os';
47
+ import { createLogger } from '@intutic/logger';
48
+ import { keepOriginal } from '../disconnect/originals.js';
49
+ import { newIso } from '@intutic/id';
50
+ import { HOOK_TIMEOUT_SECONDS } from '@intutic/shared-types';
51
+ import { emitJsGate, emitJsFailClosedPrelude } from './gateBody.js';
52
+ import { readJsonObjectForMerge } from './jsonMergeTarget.js';
53
+ const log = createLogger('sync-antigravity-cli-hooks');
54
+ /** The key Intutic owns in Antigravity's hooks file. */
55
+ export const ANTIGRAVITY_HOOK_NAME = 'intutic-governance';
56
+ /** The gate script's file name in `.intutic/hooks/`. */
57
+ export const ANTIGRAVITY_CLI_GATE = 'antigravity-cli-check.js';
58
+ /** `~/.gemini/config/hooks.json`, resolved at call time so a moved HOME is honoured. */
59
+ export function antigravityHooksPath() {
60
+ return path.join(os.homedir(), '.gemini', 'config', 'hooks.json');
61
+ }
62
+ /** The `intutic-governance` entry for Antigravity's hooks file. */
63
+ export function buildAntigravityHookEntry(hookScriptPath) {
64
+ return {
65
+ enabled: true,
66
+ PreToolUse: [
67
+ {
68
+ // Every tool: the gate decides from the arguments, so a tool name
69
+ // nobody anticipated is still evaluated.
70
+ matcher: '*',
71
+ hooks: [{ type: 'command', command: `node ${JSON.stringify(hookScriptPath)}`, timeout: HOOK_TIMEOUT_SECONDS }],
72
+ },
73
+ ],
74
+ };
75
+ }
76
+ function buildHookScript(proxyUrl, workspaceRoot, workspaceId) {
77
+ const hookEventsLog = path.join(workspaceRoot, '.intutic', 'events', 'hook-events.jsonl');
78
+ return `#!/usr/bin/env node
79
+ /**
80
+ * Intutic Antigravity governance gate.
81
+ * Auto-generated by intutic sync-daemon. DO NOT EDIT.
82
+ * Proxy: ${proxyUrl}
83
+ * Generated: ${newIso()}
84
+ */
85
+ ${emitJsFailClosedPrelude({ harness: 'antigravity', contract: 'stdout-decision-deny', documentedFieldsOnly: true })}
86
+ const fs = require('fs');
87
+ const crypto = require('crypto');
88
+ const https = require('https');
89
+
90
+ // Runtime credentials
91
+ const _runtimeEnvPath = require('path').join(require('os').homedir(), '.intutic', 'env', 'runtime.env');
92
+ let _intuticHost = 'https://api.intutic.ai', _intuticKey = '', _intuticWsId = ${JSON.stringify(workspaceId)};
93
+ try {
94
+ fs.readFileSync(_runtimeEnvPath, 'utf-8').split('\\n').forEach(line => {
95
+ const eq = line.indexOf('='); if (eq < 0) return;
96
+ const k = line.slice(0, eq).trim(), v = line.slice(eq + 1).trim();
97
+ if (k === 'INTUTIC_HOST' && v) _intuticHost = v;
98
+ if (k === 'INTUTIC_API_KEY' && v) _intuticKey = v;
99
+ if (k === 'INTUTIC_WORKSPACE_ID' && v) _intuticWsId = v;
100
+ });
101
+ } catch {}
102
+
103
+ ${emitJsGate({ harness: 'antigravity', contract: 'stdout-decision-deny', documentedFieldsOnly: true })}
104
+
105
+ let _intuticSessionId = '';
106
+ function logEvent(verdict, toolName, reason) {
107
+ try {
108
+ const ts = new Date().toISOString();
109
+ const incidentId = crypto.createHash('sha1').update(ts + toolName + _intuticWsId).digest('hex').slice(0, 16);
110
+ // The event's id: random, made once here, and resent with the line it is
111
+ // written into, so the control plane processes the event once.
112
+ const eventId = crypto.randomBytes(16).toString('hex');
113
+ const entry = JSON.stringify({
114
+ event: verdict,
115
+ toolName, reason: reason || '',
116
+ workspaceId: _intuticWsId,
117
+ harnessType: 'antigravity',
118
+ timestamp: ts,
119
+ incidentId,
120
+ eventId,
121
+ ...(_intuticSessionId ? { sessionId: _intuticSessionId } : {}),
122
+ }) + '\\n';
123
+ fs.appendFileSync(${JSON.stringify(hookEventsLog)}, entry, { flag: 'a' });
124
+ if (_intuticKey) {
125
+ try {
126
+ const body = JSON.stringify({ events: [JSON.parse(entry)] });
127
+ const urlObj = new URL('/api/v1/hook-events', _intuticHost);
128
+ const mod = urlObj.protocol === 'https:' ? https : require('http');
129
+ const req = mod.request({ hostname: urlObj.hostname, port: urlObj.port || 443, path: urlObj.pathname, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body), 'Authorization': 'Bearer ' + _intuticKey } });
130
+ req.on('error', () => { /* fire-and-forget */ });
131
+ req.write(body); req.end();
132
+ } catch { /* never crash the hook */ }
133
+ }
134
+ } catch { /* never crash the hook */ }
135
+ }
136
+
137
+ let raw = '';
138
+ process.stdin.on('data', (c) => { raw += c; });
139
+ process.stdin.on('end', () => {
140
+ try {
141
+ const ctx = JSON.parse(raw);
142
+ _intuticSessionId = ctx.conversationId || ctx.session_id || '';
143
+ // Antigravity sends {toolCall: {name, args}}; the Claude-Code-shaped
144
+ // fields are read too, so the shared gate test matrix drives this gate
145
+ // with the payload it sends every other one.
146
+ intuticGuardEnvelope(ctx, ['toolCall', 'tool_name', 'tool_input'], logEvent);
147
+ const call = (ctx.toolCall && typeof ctx.toolCall === 'object') ? ctx.toolCall : {};
148
+ const toolName = call.name || ctx.tool_name || 'tool';
149
+ const input = call.args || ctx.tool_input || {};
150
+
151
+ const targetPath = input.TargetFile || input.AbsolutePath || input.path || input.file_path ||
152
+ input.filePath || input.target || '';
153
+ const command = input.CommandLine || input.command || input.cmd || '';
154
+
155
+ intuticGate(toolName, targetPath, command, logEvent, _intuticWsId, input);
156
+
157
+ // Allow: a result with no decision in it, so the user's own permission
158
+ // settings decide (see the module doc).
159
+ logEvent('tool_allowed', toolName, '');
160
+ process.stdout.write('{}\\n');
161
+ process.exit(0);
162
+ } catch (err) {
163
+ // Fail CLOSED — the stdout-decision-deny contract, even on a crash inside
164
+ // this handler (the module-level prelude above covers crashes outside it).
165
+ const errMsg = String(err);
166
+ process.stderr.write('[Intutic Governance] Hook error (fail-closed): ' + errMsg + '\\n');
167
+ logEvent('tool_blocked', 'unknown', errMsg);
168
+ process.stdout.write(JSON.stringify({ decision: 'deny', reason: '[Intutic Governance] Hook error (fail-closed): ' + errMsg + ' (refusal code GATE_CRASHED)' }) + '\\n');
169
+ process.exit(0);
170
+ }
171
+ });
172
+ `;
173
+ }
174
+ /**
175
+ * Write the Antigravity gate script and merge its registration into
176
+ * `~/.gemini/config/hooks.json`.
177
+ *
178
+ * @param workspaceRoot - Absolute workspace root path.
179
+ * @param proxyUrl - Intutic proxy URL written into the script header.
180
+ * @param workspaceId - Workspace ID embedded in every hook event payload.
181
+ */
182
+ export async function writeAntigravityCliHooks(workspaceRoot, proxyUrl, workspaceId = '') {
183
+ const hookScriptDir = path.join(workspaceRoot, '.intutic', 'hooks');
184
+ const hooksFile = antigravityHooksPath();
185
+ await keepOriginal(hooksFile, workspaceRoot);
186
+ await Promise.all([
187
+ fs.mkdir(hookScriptDir, { recursive: true }),
188
+ fs.mkdir(path.join(workspaceRoot, '.intutic', 'events'), { recursive: true }),
189
+ fs.mkdir(path.dirname(hooksFile), { recursive: true }),
190
+ ]);
191
+ const hookScriptPath = path.join(hookScriptDir, ANTIGRAVITY_CLI_GATE);
192
+ const tmpScript = hookScriptPath + '.intutic-tmp';
193
+ await fs.writeFile(tmpScript, buildHookScript(proxyUrl, workspaceRoot, workspaceId), 'utf-8');
194
+ await fs.rename(tmpScript, hookScriptPath);
195
+ await fs.chmod(hookScriptPath, 0o755);
196
+ log.info({ action: 'antigravity_cli_hook_script_written', path: hookScriptPath }, 'Antigravity hook script written');
197
+ const existing = await readJsonObjectForMerge(hooksFile);
198
+ if (existing === null)
199
+ return;
200
+ // Only Intutic's own key is replaced; every hook the user registered stays.
201
+ const merged = { ...existing, [ANTIGRAVITY_HOOK_NAME]: buildAntigravityHookEntry(hookScriptPath) };
202
+ const tmp = hooksFile + '.intutic-tmp';
203
+ await fs.writeFile(tmp, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
204
+ await fs.rename(tmp, hooksFile);
205
+ log.info({ action: 'antigravity_cli_hooks_written', path: hooksFile }, 'Merged Intutic PreToolUse hook into ~/.gemini/config/hooks.json');
206
+ }
207
+ //# sourceMappingURL=antigravityCliHooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"antigravityCliHooks.js","sourceRoot":"","sources":["../../src/harness/antigravityCliHooks.ts"],"names":[],"mappings":"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"}
@@ -25,14 +25,24 @@
25
25
  *
26
26
  * Hook events:
27
27
  * Every block/allow is appended to `.intutic/events/hook-events.jsonl`
28
- * and drained to the control plane via FSEvents-driven drain.
28
+ * and drained to the control plane via FSEvents-driven drain, under the
29
+ * gate id `gemini-cli` rather than the harness id: the Antigravity gate
30
+ * reports as `antigravity`, so liveness, the AI inventory and SIEM can tell
31
+ * the two products apart (gateIdentity.ts in @intutic/shared-types).
29
32
  *
30
- * LLD #14 — Phase 3 cross-harness defence (Gap 3)
31
33
  * HLD §3.14 — Three-Tier Defense Cascade (Tier 1 Native Gating)
32
34
  * HLD §3.x — Gemini CLI / Antigravity harness
33
35
  *
34
36
  * @module
35
37
  */
38
+ /**
39
+ * The `BeforeTool` entry that registers the gate: a catch-all matcher, since
40
+ * the gate decides from the arguments and a tool name nobody anticipated is
41
+ * still evaluated. Shared with the MDM manifest, so the two cannot drift.
42
+ * Gemini CLI's \`timeout\` is in milliseconds (default 60 000), and it runs a
43
+ * call whose hook times out; the gate refuses at its own deadline inside it.
44
+ */
45
+ export declare function buildGeminiBeforeToolEntry(hookScriptPath: string): Record<string, unknown>;
36
46
  /**
37
47
  * Write the Antigravity (Gemini CLI) governance hook script and merge
38
48
  * hook configuration into `~/.gemini/settings.json`.
@@ -1 +1 @@
1
- {"version":3,"file":"antigravityHooks.d.ts","sourceRoot":"","sources":["../../src/harness/antigravityHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAyFH;;;;;;;;;;GAUG;AACH,wBAAsB,qBAAqB,CACzC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CA2Ef"}
1
+ {"version":3,"file":"antigravityHooks.d.ts","sourceRoot":"","sources":["../../src/harness/antigravityHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AA4FH;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAU1F;AAQD;;;;;;;;;;GAUG;AACH,wBAAsB,qBAAqB,CACzC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CAmEf"}
@@ -25,9 +25,11 @@
25
25
  *
26
26
  * Hook events:
27
27
  * Every block/allow is appended to `.intutic/events/hook-events.jsonl`
28
- * and drained to the control plane via FSEvents-driven drain.
28
+ * and drained to the control plane via FSEvents-driven drain, under the
29
+ * gate id `gemini-cli` rather than the harness id: the Antigravity gate
30
+ * reports as `antigravity`, so liveness, the AI inventory and SIEM can tell
31
+ * the two products apart (gateIdentity.ts in @intutic/shared-types).
29
32
  *
30
- * LLD #14 — Phase 3 cross-harness defence (Gap 3)
31
33
  * HLD §3.14 — Three-Tier Defense Cascade (Tier 1 Native Gating)
32
34
  * HLD §3.x — Gemini CLI / Antigravity harness
33
35
  *
@@ -39,7 +41,8 @@ import * as os from 'node:os';
39
41
  import { createLogger } from '@intutic/logger';
40
42
  import { keepOriginal } from '../disconnect/originals.js';
41
43
  import { newIso } from '@intutic/id';
42
- import { emitShellGate, SHELL_EXTRACT, SHELL_FAIL_CLOSED } from './gateBody.js';
44
+ import { GEMINI_CLI_GATE_ID, HOOK_TIMEOUT_SECONDS } from '@intutic/shared-types';
45
+ import { emitShellGate, SHELL_EXTRACT, emitShellFailClosed } from './gateBody.js';
43
46
  import { readJsonObjectForMerge } from './jsonMergeTarget.js';
44
47
  const log = createLogger('sync-antigravity-hooks');
45
48
  /** Governance-sensitive paths that the hook gate protects. */
@@ -53,7 +56,7 @@ function buildAntigravityCheckScript(proxyUrl, workspaceRoot, workspaceId) {
53
56
  # Generated: ${newIso()}
54
57
  # Workspace: ${workspaceId}
55
58
  set -euo pipefail
56
- ${SHELL_FAIL_CLOSED}
59
+ ${emitShellFailClosed(GEMINI_CLI_GATE_ID)}
57
60
  INPUT="$(cat)"
58
61
  ${SHELL_EXTRACT}
59
62
 
@@ -93,7 +96,11 @@ log_event() {
93
96
  ws="\${ws//\\\\/\\\\\\\\}"; ws="\${ws//\\"/\\\\\\"}"; ws="\${ws//[\$'\\x01'-\$'\\x1f']/ }"
94
97
  local ts; ts="\$(date -u +%Y-%m-%dT%H:%M:%SZ)"
95
98
  local incident_id; incident_id="\$(printf '%s' "\${ts}\${tool}\${INTUTIC_WORKSPACE_ID}" | sha1sum 2>/dev/null | cut -c1-16 || echo \"\$(date +%s)\")"
96
- local entry="{\\"event\\":\\"\${verdict}\\",\\"toolName\\":\\"\${tool}\\",\\"reason\\":\\"\${reason}\\",\\"workspaceId\\":\\"\${ws}\\",\\"harnessType\\":\\"antigravity\\",\\"timestamp\\":\\"\${ts}\\",\\"incidentId\\":\\"\${incident_id}\\"}"
99
+ # The event's id: random, made once here, and resent with the line it is
100
+ # written into, so the control plane processes the event once.
101
+ local event_id; event_id="\$(od -An -N16 -tx1 /dev/urandom 2>/dev/null | tr -d ' \\n' || true)"
102
+ [ -n "\$event_id" ] || event_id="\$(date +%s)\$\$\${RANDOM}\${RANDOM}\${RANDOM}"
103
+ local entry="{\\"event\\":\\"\${verdict}\\",\\"toolName\\":\\"\${tool}\\",\\"reason\\":\\"\${reason}\\",\\"workspaceId\\":\\"\${ws}\\",\\"harnessType\\":\\"${GEMINI_CLI_GATE_ID}\\",\\"timestamp\\":\\"\${ts}\\",\\"incidentId\\":\\"\${incident_id}\\",\\"eventId\\":\\"\${event_id}\\"}"
97
104
  printf '%s\\n' "\$entry" >> "\$HOOK_EVENTS_LOG" 2>/dev/null || true
98
105
  if [ -n "\$INTUTIC_API_KEY" ]; then
99
106
  curl -s -o /dev/null --max-time 3 -X POST \\
@@ -104,11 +111,32 @@ log_event() {
104
111
  fi
105
112
  }
106
113
 
107
- ${emitShellGate({ harness: "antigravity" })}
114
+ ${emitShellGate({ harness: GEMINI_CLI_GATE_ID })}
108
115
  log_event "tool_allowed" "$TOOL_NAME" ""
109
116
  exit 0
110
117
  `;
111
118
  }
119
+ /**
120
+ * The `BeforeTool` entry that registers the gate: a catch-all matcher, since
121
+ * the gate decides from the arguments and a tool name nobody anticipated is
122
+ * still evaluated. Shared with the MDM manifest, so the two cannot drift.
123
+ * Gemini CLI's \`timeout\` is in milliseconds (default 60 000), and it runs a
124
+ * call whose hook times out; the gate refuses at its own deadline inside it.
125
+ */
126
+ export function buildGeminiBeforeToolEntry(hookScriptPath) {
127
+ return {
128
+ matcher: '.*',
129
+ hooks: [{
130
+ name: 'intutic-governance',
131
+ type: 'command',
132
+ command: geminiGateCommand(hookScriptPath),
133
+ timeout: HOOK_TIMEOUT_SECONDS * 1000,
134
+ }],
135
+ };
136
+ }
137
+ function geminiGateCommand(hookScriptPath) {
138
+ return `bash ${JSON.stringify(hookScriptPath)}`;
139
+ }
112
140
  // ─── Main export ──────────────────────────────────────────────────────────────
113
141
  /**
114
142
  * Write the Antigravity (Gemini CLI) governance hook script and merge
@@ -154,7 +182,7 @@ export async function writeAntigravityHooks(workspaceRoot, proxyUrl, workspaceId
154
182
  const existingBeforeTool = Array.isArray(keptHooks.BeforeTool) ? keptHooks.BeforeTool : [];
155
183
  // De-duplicated by command, so repeated syncs replace this entry rather than
156
184
  // stacking copies, and every hook the user registered is kept.
157
- const intuticCmd = `bash ${JSON.stringify(hookScriptPath)}`;
185
+ const intuticCmd = geminiGateCommand(hookScriptPath);
158
186
  const filtered = existingBeforeTool.filter((entry) => {
159
187
  if (typeof entry !== 'object' || entry === null)
160
188
  return true;
@@ -166,15 +194,7 @@ export async function writeAntigravityHooks(workspaceRoot, proxyUrl, workspaceId
166
194
  ...existingSettings,
167
195
  hooks: {
168
196
  ...keptHooks,
169
- BeforeTool: [
170
- ...filtered,
171
- {
172
- // Catch-all: the gate decides from the arguments, so a tool name
173
- // nobody anticipated is still evaluated.
174
- matcher: '.*',
175
- hooks: [{ name: 'intutic-governance', type: 'command', command: intuticCmd }],
176
- },
177
- ],
197
+ BeforeTool: [...filtered, buildGeminiBeforeToolEntry(hookScriptPath)],
178
198
  },
179
199
  };
180
200
  const tmpSettings = geminiSettings + '.intutic-tmp';
@@ -1 +1 @@
1
- {"version":3,"file":"antigravityHooks.js","sourceRoot":"","sources":["../../src/harness/antigravityHooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"antigravityHooks.js","sourceRoot":"","sources":["../../src/harness/antigravityHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAChF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAE7D,MAAM,GAAG,GAAG,YAAY,CAAC,wBAAwB,CAAC,CAAA;AAGlD,8DAA8D;AAC9D,iFAAiF;AAEjF,SAAS,2BAA2B,CAClC,QAAgB,EAChB,aAAqB,EACrB,WAAmB;IAEnB,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAA;IACzF,OAAO;;;WAGE,QAAQ;eACJ,MAAM,EAAE;eACR,WAAW;;EAExB,mBAAmB,CAAC,kBAAkB,CAAC;;EAEvC,aAAa;;kBAEG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC;;;;;;;;;;uBAUxB,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gKA8B8G,kBAAkB;;;;;;;;;;;EAWhL,aAAa,CAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC;;;CAG/C,CAAA;AACD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B,CAAC,cAAsB;IAC/D,OAAO;QACL,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,CAAC;gBACN,IAAI,EAAE,oBAAoB;gBAC1B,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,iBAAiB,CAAC,cAAc,CAAC;gBAC1C,OAAO,EAAE,oBAAoB,GAAG,IAAI;aACrC,CAAC;KACH,CAAA;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,cAAsB;IAC/C,OAAO,QAAQ,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,CAAA;AACjD,CAAC;AAED,iFAAiF;AAEjF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,aAAqB,EACrB,QAAgB,EAChB,WAAW,GAAG,EAAE;IAEhB,8EAA8E;IAE9E,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;IACnE,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAA;IACpE,oEAAoE;IACpE,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,eAAe,CAAC,CAAA;IAE1E,MAAM,YAAY,CAAC,cAAc,EAAE,aAAa,CAAC,CAAA;IACjD,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC5C,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC5C,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;KAC5D,CAAC,CAAA;IAEF,8EAA8E;IAE9E,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAA;IACvE,MAAM,SAAS,GAAG,cAAc,GAAG,cAAc,CAAA;IACjD,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,2BAA2B,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,CAAA;IACzG,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,cAAc,CAAC,CAAA;IAC1C,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAA;IAErC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,iCAAiC,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,iCAAiC,CAAC,CAAA;IAEhH,6EAA6E;IAE7E,MAAM,gBAAgB,GAAG,MAAM,sBAAsB,CAAC,cAAc,CAAC,CAAA;IACrE,IAAI,gBAAgB,KAAK,IAAI;QAAE,OAAM;IAErC,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,KAAK,KAAK,QAAQ,IAAI,gBAAgB,CAAC,KAAK,KAAK,IAAI;QAClG,CAAC,CAAC,gBAAgB,CAAC,KAAK;QACxB,CAAC,CAAC,EAAE,CAA4B,CAAA;IAClC,uEAAuE;IACvE,uEAAuE;IACvE,MAAM,SAAS,GAA4B,EAAE,GAAG,aAAa,EAAE,CAAA;IAC/D,OAAO,SAAS,CAAC,OAAO,CAAA;IACxB,MAAM,kBAAkB,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAE,SAAS,CAAC,UAAwB,CAAC,CAAC,CAAC,EAAE,CAAA;IAEzG,6EAA6E;IAC7E,+DAA+D;IAC/D,MAAM,UAAU,GAAG,iBAAiB,CAAC,cAAc,CAAC,CAAA;IACpD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC,KAAc,EAAE,EAAE;QAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,IAAI,CAAA;QAC5D,MAAM,KAAK,GAAK,KAAiC,CAAC,KAAmB,IAAI,EAAE,CAAA;QAC3E,OAAO,CAAC,CACN,KAAK,CAAC,MAAM,GAAG,CAAC;YAChB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAK,CAA6B,CAAC,OAAO,KAAK,UAAU,CAAC,CAC1H,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,MAAM,cAAc,GAAG;QACrB,GAAG,gBAAgB;QACnB,KAAK,EAAE;YACL,GAAG,SAAS;YACZ,UAAU,EAAE,CAAC,GAAG,QAAQ,EAAE,0BAA0B,CAAC,cAAc,CAAC,CAAC;SACtE;KACF,CAAA;IAED,MAAM,WAAW,GAAG,cAAc,GAAG,cAAc,CAAA;IACnD,MAAM,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAA;IACxF,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,CAAA;IAE5C,GAAG,CAAC,IAAI,CACN,EAAE,MAAM,EAAE,8BAA8B,EAAE,IAAI,EAAE,cAAc,EAAE,EAChE,6DAA6D,CAC9D,CAAA;AACH,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * antigravityProducts.ts — which of the two Google products behind the
3
+ * `antigravity` harness are on this machine.
4
+ *
5
+ * The harness installs two gates: Google Antigravity's (`PreToolUse` in
6
+ * `~/.gemini/config/hooks.json`) and Gemini CLI's (`BeforeTool` in
7
+ * `~/.gemini/settings.json`). Each reports under its own gate id
8
+ * (`gateIdentitiesOf` in `@intutic/shared-types`), and this says which of
9
+ * them to expect: the agent report registers a gate for each product found,
10
+ * so the silent-gate check does not wait on a gate whose product is absent,
11
+ * and the AI inventory lists each product with its own gate file and last
12
+ * event. The CLI's harness detection uses the same answer, so a machine with
13
+ * only Gemini CLI installed is detected too.
14
+ *
15
+ * - Antigravity: its app-data directories under `~/.gemini` (the 2.0 app, the
16
+ * CLI and the IDE), a project `.agents/hooks.json`, or `antigravity` on PATH.
17
+ * - Gemini CLI: `gemini` on PATH, a project `.gemini` directory, or a
18
+ * `~/.gemini/settings.json` holding a setting of its own. Intutic writes
19
+ * `hooks` and its own `intutic` MCP server into that file, so a file with
20
+ * nothing else in it is Intutic's and says nothing about Gemini CLI.
21
+ *
22
+ * @module
23
+ */
24
+ export interface ProductProbeOptions {
25
+ home?: string;
26
+ /** The PATH to search; defaults to this process's. */
27
+ path?: string;
28
+ }
29
+ /**
30
+ * The gate ids of the `antigravity` harness whose products are on this
31
+ * machine: `antigravity`, `gemini-cli`, both, or neither.
32
+ */
33
+ export declare function antigravityGateIdentities(workspaceRoot: string, opts?: ProductProbeOptions): Promise<string[]>;
34
+ /**
35
+ * The gate ids a configured harness reports under on this machine: for
36
+ * `antigravity`, the products found, or the harness id itself when neither is
37
+ * (a configured harness is never dropped); for any other harness, its own id.
38
+ */
39
+ export declare function presentGateIdentities(harness: string, workspaceRoot: string, opts?: ProductProbeOptions): Promise<string[]>;
40
+ //# sourceMappingURL=antigravityProducts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"antigravityProducts.d.ts","sourceRoot":"","sources":["../../src/harness/antigravityProducts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAOH,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AA+DD;;;GAGG;AACH,wBAAsB,yBAAyB,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,GAAE,mBAAwB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAQxH;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,GAAE,mBAAwB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAIrI"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * antigravityProducts.ts — which of the two Google products behind the
3
+ * `antigravity` harness are on this machine.
4
+ *
5
+ * The harness installs two gates: Google Antigravity's (`PreToolUse` in
6
+ * `~/.gemini/config/hooks.json`) and Gemini CLI's (`BeforeTool` in
7
+ * `~/.gemini/settings.json`). Each reports under its own gate id
8
+ * (`gateIdentitiesOf` in `@intutic/shared-types`), and this says which of
9
+ * them to expect: the agent report registers a gate for each product found,
10
+ * so the silent-gate check does not wait on a gate whose product is absent,
11
+ * and the AI inventory lists each product with its own gate file and last
12
+ * event. The CLI's harness detection uses the same answer, so a machine with
13
+ * only Gemini CLI installed is detected too.
14
+ *
15
+ * - Antigravity: its app-data directories under `~/.gemini` (the 2.0 app, the
16
+ * CLI and the IDE), a project `.agents/hooks.json`, or `antigravity` on PATH.
17
+ * - Gemini CLI: `gemini` on PATH, a project `.gemini` directory, or a
18
+ * `~/.gemini/settings.json` holding a setting of its own. Intutic writes
19
+ * `hooks` and its own `intutic` MCP server into that file, so a file with
20
+ * nothing else in it is Intutic's and says nothing about Gemini CLI.
21
+ *
22
+ * @module
23
+ */
24
+ import * as node_fs from 'node:fs/promises';
25
+ import * as node_path from 'node:path';
26
+ import { homedir } from 'node:os';
27
+ import { GEMINI_CLI_GATE_ID } from '@intutic/shared-types';
28
+ async function exists(p) {
29
+ try {
30
+ await node_fs.access(p);
31
+ return true;
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
37
+ /** Whether an executable named `bin` is in one of PATH's directories. */
38
+ async function onPath(bin, pathEnv) {
39
+ const names = process.platform === 'win32' ? [`${bin}.cmd`, `${bin}.exe`, bin] : [bin];
40
+ for (const dir of pathEnv.split(node_path.delimiter)) {
41
+ if (!dir)
42
+ continue;
43
+ for (const name of names) {
44
+ try {
45
+ await node_fs.access(node_path.join(dir, name), node_fs.constants.X_OK);
46
+ return true;
47
+ }
48
+ catch {
49
+ // not here
50
+ }
51
+ }
52
+ }
53
+ return false;
54
+ }
55
+ /** Whether a setting is only what Intutic writes: the hooks, or an `mcpServers` holding no server but `intutic`. */
56
+ function intuticsOwn(key, value) {
57
+ if (key === 'hooks')
58
+ return true;
59
+ return key === 'mcpServers' && typeof value === 'object' && value !== null && Object.keys(value).every((name) => name === 'intutic');
60
+ }
61
+ /** Whether `~/.gemini/settings.json` holds any setting besides what Intutic writes. */
62
+ async function geminiSettingsInUse(home) {
63
+ try {
64
+ const parsed = JSON.parse(await node_fs.readFile(node_path.join(home, '.gemini', 'settings.json'), 'utf-8'));
65
+ return (typeof parsed === 'object' &&
66
+ parsed !== null &&
67
+ Object.entries(parsed).some(([key, value]) => !intuticsOwn(key, value)));
68
+ }
69
+ catch {
70
+ return false;
71
+ }
72
+ }
73
+ async function antigravityPresent(workspaceRoot, home, pathEnv) {
74
+ for (const dir of ['antigravity', 'antigravity-cli', 'antigravity-ide']) {
75
+ if (await exists(node_path.join(home, '.gemini', dir)))
76
+ return true;
77
+ }
78
+ return (await exists(node_path.join(workspaceRoot, '.agents', 'hooks.json'))) || onPath('antigravity', pathEnv);
79
+ }
80
+ async function geminiCliPresent(workspaceRoot, home, pathEnv) {
81
+ return ((await onPath('gemini', pathEnv)) ||
82
+ (await exists(node_path.join(workspaceRoot, '.gemini'))) ||
83
+ geminiSettingsInUse(home));
84
+ }
85
+ /**
86
+ * The gate ids of the `antigravity` harness whose products are on this
87
+ * machine: `antigravity`, `gemini-cli`, both, or neither.
88
+ */
89
+ export async function antigravityGateIdentities(workspaceRoot, opts = {}) {
90
+ const home = opts.home ?? homedir();
91
+ const pathEnv = opts.path ?? process.env.PATH ?? '';
92
+ const [antigravity, geminiCli] = await Promise.all([
93
+ antigravityPresent(workspaceRoot, home, pathEnv),
94
+ geminiCliPresent(workspaceRoot, home, pathEnv),
95
+ ]);
96
+ return [...(antigravity ? ['antigravity'] : []), ...(geminiCli ? [GEMINI_CLI_GATE_ID] : [])];
97
+ }
98
+ /**
99
+ * The gate ids a configured harness reports under on this machine: for
100
+ * `antigravity`, the products found, or the harness id itself when neither is
101
+ * (a configured harness is never dropped); for any other harness, its own id.
102
+ */
103
+ export async function presentGateIdentities(harness, workspaceRoot, opts = {}) {
104
+ if (harness !== 'antigravity')
105
+ return [harness];
106
+ const found = await antigravityGateIdentities(workspaceRoot, opts);
107
+ return found.length > 0 ? found : [harness];
108
+ }
109
+ //# sourceMappingURL=antigravityProducts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"antigravityProducts.js","sourceRoot":"","sources":["../../src/harness/antigravityProducts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * claudeAgentsMd.ts — whether Claude Code reads the workspace's `AGENTS.md`.
3
+ *
4
+ * Claude Code gets its rule sets and the decisions log from
5
+ * `.claude/rules/`, which it loads at launch whatever other instruction
6
+ * files exist. It also reads `AGENTS.md`, but only sometimes
7
+ * (https://code.claude.com/docs/en/memory#when-claude-code-reads-agentsmd):
8
+ *
9
+ * - under the default **Project instructions** setting,
10
+ * `claude-md-or-agents-md`, only when there is no `CLAUDE.md`,
11
+ * `.claude/CLAUDE.md` or `CLAUDE.local.md` in the working directory or a
12
+ * directory above it (`~/.claude/CLAUDE.md` does not count);
13
+ * - always under `claude-md-and-agents-md`, and never under `claude-md` or
14
+ * `managed-only`.
15
+ *
16
+ * The setting is honoured only from user, `--settings` or managed settings,
17
+ * under `pluginConfigs["cc-plugin-agents-md@builtin"].options.instructionFiles`
18
+ * (`agents-md@builtin` before v2.1.285); a project's settings cannot change
19
+ * it. This reads the user's `~/.claude/settings.json`.
20
+ *
21
+ * When Claude Code reads `AGENTS.md`, whatever Intutic puts there for the
22
+ * other harnesses reaches Claude Code too, so the writers leave it out of
23
+ * `.claude/rules/` to keep Claude Code from reading it twice.
24
+ *
25
+ * @module
26
+ */
27
+ /** Whether Claude Code, started in `workspaceRoot`, reads its `AGENTS.md`. */
28
+ export declare function claudeCodeReadsAgentsMd(workspaceRoot: string): Promise<boolean>;
29
+ //# sourceMappingURL=claudeAgentsMd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claudeAgentsMd.d.ts","sourceRoot":"","sources":["../../src/harness/claudeAgentsMd.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAgDH,8EAA8E;AAC9E,wBAAsB,uBAAuB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAKrF"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * claudeAgentsMd.ts — whether Claude Code reads the workspace's `AGENTS.md`.
3
+ *
4
+ * Claude Code gets its rule sets and the decisions log from
5
+ * `.claude/rules/`, which it loads at launch whatever other instruction
6
+ * files exist. It also reads `AGENTS.md`, but only sometimes
7
+ * (https://code.claude.com/docs/en/memory#when-claude-code-reads-agentsmd):
8
+ *
9
+ * - under the default **Project instructions** setting,
10
+ * `claude-md-or-agents-md`, only when there is no `CLAUDE.md`,
11
+ * `.claude/CLAUDE.md` or `CLAUDE.local.md` in the working directory or a
12
+ * directory above it (`~/.claude/CLAUDE.md` does not count);
13
+ * - always under `claude-md-and-agents-md`, and never under `claude-md` or
14
+ * `managed-only`.
15
+ *
16
+ * The setting is honoured only from user, `--settings` or managed settings,
17
+ * under `pluginConfigs["cc-plugin-agents-md@builtin"].options.instructionFiles`
18
+ * (`agents-md@builtin` before v2.1.285); a project's settings cannot change
19
+ * it. This reads the user's `~/.claude/settings.json`.
20
+ *
21
+ * When Claude Code reads `AGENTS.md`, whatever Intutic puts there for the
22
+ * other harnesses reaches Claude Code too, so the writers leave it out of
23
+ * `.claude/rules/` to keep Claude Code from reading it twice.
24
+ *
25
+ * @module
26
+ */
27
+ import * as fs from 'node:fs/promises';
28
+ import * as os from 'node:os';
29
+ import * as path from 'node:path';
30
+ const PLUGIN_IDS = ['cc-plugin-agents-md@builtin', 'agents-md@builtin'];
31
+ /** The Project instructions value in the user's settings; undefined when unset. */
32
+ async function instructionFilesSetting() {
33
+ try {
34
+ const settings = JSON.parse(await fs.readFile(path.join(os.homedir(), '.claude', 'settings.json'), 'utf-8'));
35
+ for (const id of PLUGIN_IDS) {
36
+ const value = settings.pluginConfigs?.[id]?.options?.instructionFiles;
37
+ if (typeof value === 'string')
38
+ return value;
39
+ }
40
+ }
41
+ catch {
42
+ // No user settings, or not JSON: the default applies.
43
+ }
44
+ return undefined;
45
+ }
46
+ async function exists(file) {
47
+ try {
48
+ await fs.access(file);
49
+ return true;
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ }
55
+ /** Whether a `CLAUDE.md`, `.claude/CLAUDE.md` or `CLAUDE.local.md` is in `dir` or above it, the user's own `~/.claude/CLAUDE.md` aside. */
56
+ async function claudeMdOnPath(dir) {
57
+ const userFile = path.join(os.homedir(), '.claude', 'CLAUDE.md');
58
+ let current = path.resolve(dir);
59
+ for (;;) {
60
+ for (const name of ['CLAUDE.md', path.join('.claude', 'CLAUDE.md'), 'CLAUDE.local.md']) {
61
+ const file = path.join(current, name);
62
+ if (file !== userFile && (await exists(file)))
63
+ return true;
64
+ }
65
+ const parent = path.dirname(current);
66
+ if (parent === current)
67
+ return false;
68
+ current = parent;
69
+ }
70
+ }
71
+ /** Whether Claude Code, started in `workspaceRoot`, reads its `AGENTS.md`. */
72
+ export async function claudeCodeReadsAgentsMd(workspaceRoot) {
73
+ const setting = await instructionFilesSetting();
74
+ if (setting === 'claude-md-and-agents-md')
75
+ return true;
76
+ if (setting === 'claude-md' || setting === 'managed-only')
77
+ return false;
78
+ return !(await claudeMdOnPath(workspaceRoot));
79
+ }
80
+ //# sourceMappingURL=claudeAgentsMd.js.map