@intutic/sync-daemon 2.1.0 → 2.3.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 (288) hide show
  1. package/README.md +1 -1
  2. package/dist/agentReporter.d.ts +24 -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 +45 -25
  7. package/dist/configReader.d.ts.map +1 -1
  8. package/dist/configReader.js +70 -46
  9. package/dist/configReader.js.map +1 -1
  10. package/dist/configWriter.d.ts +32 -45
  11. package/dist/configWriter.d.ts.map +1 -1
  12. package/dist/configWriter.js +52 -686
  13. package/dist/configWriter.js.map +1 -1
  14. package/dist/disconnect/harnesses.d.ts +29 -0
  15. package/dist/disconnect/harnesses.d.ts.map +1 -0
  16. package/dist/disconnect/harnesses.js +805 -0
  17. package/dist/disconnect/harnesses.js.map +1 -0
  18. package/dist/disconnect/index.d.ts +25 -0
  19. package/dist/disconnect/index.d.ts.map +1 -0
  20. package/dist/disconnect/index.js +92 -0
  21. package/dist/disconnect/index.js.map +1 -0
  22. package/dist/disconnect/mcp.d.ts +81 -0
  23. package/dist/disconnect/mcp.d.ts.map +1 -0
  24. package/dist/disconnect/mcp.js +354 -0
  25. package/dist/disconnect/mcp.js.map +1 -0
  26. package/dist/disconnect/originals.d.ts +88 -0
  27. package/dist/disconnect/originals.d.ts.map +1 -0
  28. package/dist/disconnect/originals.js +257 -0
  29. package/dist/disconnect/originals.js.map +1 -0
  30. package/dist/disconnect/plan.d.ts +175 -0
  31. package/dist/disconnect/plan.d.ts.map +1 -0
  32. package/dist/disconnect/plan.js +580 -0
  33. package/dist/disconnect/plan.js.map +1 -0
  34. package/dist/disconnect/recognise.d.ts +43 -0
  35. package/dist/disconnect/recognise.d.ts.map +1 -0
  36. package/dist/disconnect/recognise.js +108 -0
  37. package/dist/disconnect/recognise.js.map +1 -0
  38. package/dist/disconnect/tomlLines.d.ts +39 -0
  39. package/dist/disconnect/tomlLines.d.ts.map +1 -0
  40. package/dist/disconnect/tomlLines.js +105 -0
  41. package/dist/disconnect/tomlLines.js.map +1 -0
  42. package/dist/harness/aiderConfigMerger.d.ts +29 -8
  43. package/dist/harness/aiderConfigMerger.d.ts.map +1 -1
  44. package/dist/harness/aiderConfigMerger.js +63 -12
  45. package/dist/harness/aiderConfigMerger.js.map +1 -1
  46. package/dist/harness/antigravityCliHooks.d.ts +61 -0
  47. package/dist/harness/antigravityCliHooks.d.ts.map +1 -0
  48. package/dist/harness/antigravityCliHooks.js +207 -0
  49. package/dist/harness/antigravityCliHooks.js.map +1 -0
  50. package/dist/harness/antigravityHooks.d.ts +12 -2
  51. package/dist/harness/antigravityHooks.d.ts.map +1 -1
  52. package/dist/harness/antigravityHooks.js +38 -16
  53. package/dist/harness/antigravityHooks.js.map +1 -1
  54. package/dist/harness/antigravityProducts.d.ts +40 -0
  55. package/dist/harness/antigravityProducts.d.ts.map +1 -0
  56. package/dist/harness/antigravityProducts.js +109 -0
  57. package/dist/harness/antigravityProducts.js.map +1 -0
  58. package/dist/harness/claudeAgentsMd.d.ts +29 -0
  59. package/dist/harness/claudeAgentsMd.d.ts.map +1 -0
  60. package/dist/harness/claudeAgentsMd.js +80 -0
  61. package/dist/harness/claudeAgentsMd.js.map +1 -0
  62. package/dist/harness/claudeCodeHooks.d.ts +6 -6
  63. package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
  64. package/dist/harness/claudeCodeHooks.js +115 -28
  65. package/dist/harness/claudeCodeHooks.js.map +1 -1
  66. package/dist/harness/claudeProjectApproval.d.ts +53 -0
  67. package/dist/harness/claudeProjectApproval.d.ts.map +1 -0
  68. package/dist/harness/claudeProjectApproval.js +159 -0
  69. package/dist/harness/claudeProjectApproval.js.map +1 -0
  70. package/dist/harness/clineHooks.d.ts +0 -1
  71. package/dist/harness/clineHooks.d.ts.map +1 -1
  72. package/dist/harness/clineHooks.js +13 -4
  73. package/dist/harness/clineHooks.js.map +1 -1
  74. package/dist/harness/codexConfigMerger.d.ts.map +1 -1
  75. package/dist/harness/codexConfigMerger.js +4 -0
  76. package/dist/harness/codexConfigMerger.js.map +1 -1
  77. package/dist/harness/codexHooks.d.ts +2 -0
  78. package/dist/harness/codexHooks.d.ts.map +1 -1
  79. package/dist/harness/codexHooks.js +15 -4
  80. package/dist/harness/codexHooks.js.map +1 -1
  81. package/dist/harness/continueConfigMerger.d.ts.map +1 -1
  82. package/dist/harness/continueConfigMerger.js +4 -0
  83. package/dist/harness/continueConfigMerger.js.map +1 -1
  84. package/dist/harness/cursorHooks.d.ts +5 -2
  85. package/dist/harness/cursorHooks.d.ts.map +1 -1
  86. package/dist/harness/cursorHooks.js +12 -3
  87. package/dist/harness/cursorHooks.js.map +1 -1
  88. package/dist/harness/dshHooks.d.ts +5 -5
  89. package/dist/harness/dshHooks.d.ts.map +1 -1
  90. package/dist/harness/dshHooks.js +12 -5
  91. package/dist/harness/dshHooks.js.map +1 -1
  92. package/dist/harness/gateArtifacts.d.ts +35 -0
  93. package/dist/harness/gateArtifacts.d.ts.map +1 -0
  94. package/dist/harness/gateArtifacts.js +88 -0
  95. package/dist/harness/gateArtifacts.js.map +1 -0
  96. package/dist/harness/gateBody.d.ts +195 -69
  97. package/dist/harness/gateBody.d.ts.map +1 -1
  98. package/dist/harness/gateBody.js +847 -182
  99. package/dist/harness/gateBody.js.map +1 -1
  100. package/dist/harness/gateSightings.d.ts +47 -0
  101. package/dist/harness/gateSightings.d.ts.map +1 -0
  102. package/dist/harness/gateSightings.js +159 -0
  103. package/dist/harness/gateSightings.js.map +1 -0
  104. package/dist/harness/githubCopilotHooks.d.ts.map +1 -1
  105. package/dist/harness/githubCopilotHooks.js +11 -10
  106. package/dist/harness/githubCopilotHooks.js.map +1 -1
  107. package/dist/harness/gooseHardener.d.ts +0 -1
  108. package/dist/harness/gooseHardener.d.ts.map +1 -1
  109. package/dist/harness/gooseHardener.js +1 -1
  110. package/dist/harness/gooseHardener.js.map +1 -1
  111. package/dist/harness/gooseHooks.d.ts +29 -1
  112. package/dist/harness/gooseHooks.d.ts.map +1 -1
  113. package/dist/harness/gooseHooks.js +107 -69
  114. package/dist/harness/gooseHooks.js.map +1 -1
  115. package/dist/harness/grokHooks.d.ts +2 -2
  116. package/dist/harness/grokHooks.d.ts.map +1 -1
  117. package/dist/harness/grokHooks.js +20 -18
  118. package/dist/harness/grokHooks.js.map +1 -1
  119. package/dist/harness/hermesHooks.d.ts +18 -8
  120. package/dist/harness/hermesHooks.d.ts.map +1 -1
  121. package/dist/harness/hermesHooks.js +55 -19
  122. package/dist/harness/hermesHooks.js.map +1 -1
  123. package/dist/harness/holdRedaction.d.ts +4 -1
  124. package/dist/harness/holdRedaction.d.ts.map +1 -1
  125. package/dist/harness/holdRedaction.js +32 -8
  126. package/dist/harness/holdRedaction.js.map +1 -1
  127. package/dist/harness/jetbrainsXmlConfig.d.ts +20 -0
  128. package/dist/harness/jetbrainsXmlConfig.d.ts.map +1 -1
  129. package/dist/harness/jetbrainsXmlConfig.js +39 -18
  130. package/dist/harness/jetbrainsXmlConfig.js.map +1 -1
  131. package/dist/harness/mcpAutoWrite.d.ts +62 -25
  132. package/dist/harness/mcpAutoWrite.d.ts.map +1 -1
  133. package/dist/harness/mcpAutoWrite.js +406 -95
  134. package/dist/harness/mcpAutoWrite.js.map +1 -1
  135. package/dist/harness/museHooks.d.ts +3 -3
  136. package/dist/harness/museHooks.d.ts.map +1 -1
  137. package/dist/harness/museHooks.js +15 -7
  138. package/dist/harness/museHooks.js.map +1 -1
  139. package/dist/harness/n8nHooks.d.ts +0 -1
  140. package/dist/harness/n8nHooks.d.ts.map +1 -1
  141. package/dist/harness/n8nHooks.js +4 -1
  142. package/dist/harness/n8nHooks.js.map +1 -1
  143. package/dist/harness/openCodeHooks.d.ts +2 -2
  144. package/dist/harness/openCodeHooks.d.ts.map +1 -1
  145. package/dist/harness/openCodeHooks.js +9 -8
  146. package/dist/harness/openCodeHooks.js.map +1 -1
  147. package/dist/harness/openWebuiHooks.d.ts +0 -1
  148. package/dist/harness/openWebuiHooks.d.ts.map +1 -1
  149. package/dist/harness/openWebuiHooks.js +11 -3
  150. package/dist/harness/openWebuiHooks.js.map +1 -1
  151. package/dist/harness/openclawHooks.d.ts +75 -18
  152. package/dist/harness/openclawHooks.d.ts.map +1 -1
  153. package/dist/harness/openclawHooks.js +214 -160
  154. package/dist/harness/openclawHooks.js.map +1 -1
  155. package/dist/harness/openhandsHooks.d.ts +37 -11
  156. package/dist/harness/openhandsHooks.d.ts.map +1 -1
  157. package/dist/harness/openhandsHooks.js +148 -97
  158. package/dist/harness/openhandsHooks.js.map +1 -1
  159. package/dist/harness/piHooks.d.ts +52 -17
  160. package/dist/harness/piHooks.d.ts.map +1 -1
  161. package/dist/harness/piHooks.js +177 -163
  162. package/dist/harness/piHooks.js.map +1 -1
  163. package/dist/harness/protectedPaths.d.ts +107 -25
  164. package/dist/harness/protectedPaths.d.ts.map +1 -1
  165. package/dist/harness/protectedPaths.js +342 -48
  166. package/dist/harness/protectedPaths.js.map +1 -1
  167. package/dist/harness/rulesSection.d.ts +62 -0
  168. package/dist/harness/rulesSection.d.ts.map +1 -0
  169. package/dist/harness/rulesSection.js +145 -0
  170. package/dist/harness/rulesSection.js.map +1 -0
  171. package/dist/harness/windsurfHooks.d.ts +18 -3
  172. package/dist/harness/windsurfHooks.d.ts.map +1 -1
  173. package/dist/harness/windsurfHooks.js +41 -8
  174. package/dist/harness/windsurfHooks.js.map +1 -1
  175. package/dist/harness/windsurfJetBrainsProxy.d.ts +1 -1
  176. package/dist/harness/windsurfJetBrainsProxy.d.ts.map +1 -1
  177. package/dist/harness/windsurfJetBrainsProxy.js +5 -1
  178. package/dist/harness/windsurfJetBrainsProxy.js.map +1 -1
  179. package/dist/index.d.ts +21 -20
  180. package/dist/index.d.ts.map +1 -1
  181. package/dist/index.js +19 -19
  182. package/dist/index.js.map +1 -1
  183. package/dist/inventory.d.ts +53 -0
  184. package/dist/inventory.d.ts.map +1 -0
  185. package/dist/inventory.js +133 -0
  186. package/dist/inventory.js.map +1 -0
  187. package/dist/lib/complianceProbes.d.ts +2 -1
  188. package/dist/lib/complianceProbes.d.ts.map +1 -1
  189. package/dist/lib/complianceProbes.js +1 -1
  190. package/dist/lib/complianceProbes.js.map +1 -1
  191. package/dist/lib/decisionsDigest.d.ts +35 -17
  192. package/dist/lib/decisionsDigest.d.ts.map +1 -1
  193. package/dist/lib/decisionsDigest.js +106 -47
  194. package/dist/lib/decisionsDigest.js.map +1 -1
  195. package/dist/lib/egressPolicy.d.ts +2 -2
  196. package/dist/lib/egressPolicy.js +2 -2
  197. package/dist/lib/mcpRegistryPy.d.ts +11 -0
  198. package/dist/lib/mcpRegistryPy.d.ts.map +1 -0
  199. package/dist/lib/mcpRegistryPy.js +173 -0
  200. package/dist/lib/mcpRegistryPy.js.map +1 -0
  201. package/dist/lib/phrasesPy.d.ts +11 -0
  202. package/dist/lib/phrasesPy.d.ts.map +1 -0
  203. package/dist/lib/phrasesPy.js +351 -0
  204. package/dist/lib/phrasesPy.js.map +1 -0
  205. package/dist/lib/policySnapshot.d.ts +63 -9
  206. package/dist/lib/policySnapshot.d.ts.map +1 -1
  207. package/dist/lib/policySnapshot.js +269 -45
  208. package/dist/lib/policySnapshot.js.map +1 -1
  209. package/dist/lib/processPoller.d.ts.map +1 -1
  210. package/dist/lib/processPoller.js +9 -2
  211. package/dist/lib/processPoller.js.map +1 -1
  212. package/dist/lib/regexLinearity.d.ts +43 -0
  213. package/dist/lib/regexLinearity.d.ts.map +1 -0
  214. package/dist/lib/regexLinearity.js +275 -0
  215. package/dist/lib/regexLinearity.js.map +1 -0
  216. package/dist/lib/runtimeEnv.d.ts +1 -3
  217. package/dist/lib/runtimeEnv.d.ts.map +1 -1
  218. package/dist/lib/runtimeEnv.js +0 -2
  219. package/dist/lib/runtimeEnv.js.map +1 -1
  220. package/dist/lib/sequencePy.d.ts +10 -0
  221. package/dist/lib/sequencePy.d.ts.map +1 -0
  222. package/dist/lib/sequencePy.js +102 -0
  223. package/dist/lib/sequencePy.js.map +1 -0
  224. package/dist/sessionReporter.d.ts +18 -12
  225. package/dist/sessionReporter.d.ts.map +1 -1
  226. package/dist/sessionReporter.js +37 -24
  227. package/dist/sessionReporter.js.map +1 -1
  228. package/dist/skillWriter.d.ts +23 -5
  229. package/dist/skillWriter.d.ts.map +1 -1
  230. package/dist/skillWriter.js +159 -16
  231. package/dist/skillWriter.js.map +1 -1
  232. package/dist/syncCycle.d.ts +142 -0
  233. package/dist/syncCycle.d.ts.map +1 -0
  234. package/dist/syncCycle.js +327 -0
  235. package/dist/syncCycle.js.map +1 -0
  236. package/dist/trajectoryMonitor.d.ts +2 -4
  237. package/dist/trajectoryMonitor.d.ts.map +1 -1
  238. package/dist/trajectoryMonitor.js +2 -5
  239. package/dist/trajectoryMonitor.js.map +1 -1
  240. package/dist/watcher/driftWatcher.d.ts +0 -1
  241. package/dist/watcher/driftWatcher.d.ts.map +1 -1
  242. package/dist/watcher/driftWatcher.js +1 -2
  243. package/dist/watcher/driftWatcher.js.map +1 -1
  244. package/dist/watcher/settingsGuard.d.ts +36 -7
  245. package/dist/watcher/settingsGuard.d.ts.map +1 -1
  246. package/dist/watcher/settingsGuard.js +397 -60
  247. package/dist/watcher/settingsGuard.js.map +1 -1
  248. package/dist/watcher/vscodeHookSettings.d.ts +30 -0
  249. package/dist/watcher/vscodeHookSettings.d.ts.map +1 -0
  250. package/dist/watcher/vscodeHookSettings.js +170 -0
  251. package/dist/watcher/vscodeHookSettings.js.map +1 -0
  252. package/dist/wsClient.d.ts +0 -1
  253. package/dist/wsClient.d.ts.map +1 -1
  254. package/dist/wsClient.js +0 -1
  255. package/dist/wsClient.js.map +1 -1
  256. package/package.json +5 -5
  257. package/dist/harness/claudeDesktopHooks.d.ts +0 -30
  258. package/dist/harness/claudeDesktopHooks.d.ts.map +0 -1
  259. package/dist/harness/claudeDesktopHooks.js +0 -254
  260. package/dist/harness/claudeDesktopHooks.js.map +0 -1
  261. package/dist/harness/continueHooks.d.ts +0 -63
  262. package/dist/harness/continueHooks.d.ts.map +0 -1
  263. package/dist/harness/continueHooks.js +0 -247
  264. package/dist/harness/continueHooks.js.map +0 -1
  265. package/dist/harness/gateKind.d.ts +0 -164
  266. package/dist/harness/gateKind.d.ts.map +0 -1
  267. package/dist/harness/gateKind.js +0 -144
  268. package/dist/harness/gateKind.js.map +0 -1
  269. package/dist/harness/rooCodeHooks.d.ts +0 -31
  270. package/dist/harness/rooCodeHooks.d.ts.map +0 -1
  271. package/dist/harness/rooCodeHooks.js +0 -286
  272. package/dist/harness/rooCodeHooks.js.map +0 -1
  273. package/dist/hashReporter.d.ts +0 -33
  274. package/dist/hashReporter.d.ts.map +0 -1
  275. package/dist/hashReporter.js +0 -69
  276. package/dist/hashReporter.js.map +0 -1
  277. package/dist/integrityStore.d.ts +0 -35
  278. package/dist/integrityStore.d.ts.map +0 -1
  279. package/dist/integrityStore.js +0 -71
  280. package/dist/integrityStore.js.map +0 -1
  281. package/dist/lib/gitWorktrees.d.ts +0 -140
  282. package/dist/lib/gitWorktrees.d.ts.map +0 -1
  283. package/dist/lib/gitWorktrees.js +0 -191
  284. package/dist/lib/gitWorktrees.js.map +0 -1
  285. package/dist/syncLoop.d.ts +0 -172
  286. package/dist/syncLoop.d.ts.map +0 -1
  287. package/dist/syncLoop.js +0 -878
  288. package/dist/syncLoop.js.map +0 -1
@@ -1,164 +0,0 @@
1
- /**
2
- * gateKind.ts — classifies each harness by HOW its tool calls get governed,
3
- * for `agentReporter.ts`'s `guardrails` facet.
4
- *
5
- * # Why this exists
6
- *
7
- * `collectAgentReport` used to report `hook_gate: true` unconditionally for
8
- * every harness, with the comment "the daemon writes the hook gate for every
9
- * harness it supports." That was already false for `langgraph` — which has
10
- * no on-disk hook, only the SDK-side `intutic_clawde.gate` — and for `aider`,
11
- * whose only NO_GATE-registered mechanism is a post-edit, /run-blind
12
- * pre-commit hook (see `aiderConfigMerger.ts`'s NO_GATE row in
13
- * `__tests__/harness/gateRegistry.ts`). Wave 1 adds eight more SDK-gated
14
- * harnesses, which would have made the lie eight times larger without this
15
- * fix.
16
- *
17
- * # What this does NOT do
18
- *
19
- * This does not verify that a user actually pip-installed `intutic-clawde`
20
- * and wired `guard_tools`/`IntuticMiddleware`/etc. into their process — the
21
- * daemon cannot observe another process's imports, the same way it cannot
22
- * observe whether a written hook file was left executable. It only reports
23
- * which MECHANISM this harness's governance model uses (a file the daemon
24
- * itself writes and can verify existence of, vs. an SDK the harness's own
25
- * process must import), matching the trust level `hook_gate: true` already
26
- * carried for file-based harnesses before this fix.
27
- *
28
- * # Keeping this in sync with the gate registry
29
- *
30
- * `services/sync-daemon/__tests__/harness/gateRegistry.ts` (the GATES/NO_GATE
31
- * completeness registry exercised by `generatedGateBehaviour.test.ts`) is the
32
- * authoritative decision per harness, but it is a test-only module (it
33
- * dynamically imports every writer's compiled `.js` from a temp build dir)
34
- * and must not be imported from daemon runtime code. `gateKind.test.ts`
35
- * cross-checks the two lists so this file cannot silently drift from that
36
- * registry's own NO_GATE rows: `file: null` harnesses split between 'sdk'
37
- * (LangGraph + the Python frameworks — the gate ships in intutic-clawde),
38
- * 'delegated' (xirp — the gate is whichever wrapped harness's own gate is
39
- * running), and 'bridge' (trueforge-server — the gate runs in a separate
40
- * Intutic-operated service, not in any process this repo's writers touch);
41
- * the one non-null row (aiderConfigMerger.ts, "no ... exists") is 'none'.
42
- *
43
- * @module
44
- */
45
- import { type HarnessType as HarnessTypeT } from '@intutic/shared-types';
46
- /**
47
- * `'hook'` — the daemon writes an on-disk hook/config file this harness
48
- * reads before running a tool call (the 19-harness majority).
49
- * `'sdk'` — the blocking gate ships in `intutic-clawde`, imported into
50
- * the harness's own Python process; no file for the daemon
51
- * to write or verify (LangGraph + the eight Wave/Wave-2
52
- * frameworks).
53
- * `'none'` — no enforcement point exists today at all (aider: its only
54
- * native hook is post-edit and /run-blind).
55
- * `'delegated'` — this harness has no gate mechanism of its own because it
56
- * does not run tools itself: it wraps OTHER harnesses that
57
- * are already `'hook'`- or `'sdk'`-gated, and a tool call
58
- * made inside it is governed by whichever wrapped harness's
59
- * own gate is running (Xirp, Agentic Orchestrator, and — a
60
- * different shape of the same idea — AgentCore Runtime,
61
- * which HOSTS a customer's already-gated framework code
62
- * rather than spawning it as a subprocess; see
63
- * gateRegistry.ts's NO_GATE rows for the reasoning this
64
- * precedent sets for future orchestrator/host-shaped
65
- * harnesses).
66
- * Every wrapped backend of the two orchestrators has a gate of
67
- * its own (Agentic Orchestrator's `opencode` backend since
68
- * TD-397 closed with `openCodeHooks.ts`), so `'delegated'`
69
- * claims exactly what happens. Distinct from
70
- * `'none'`: `'none'` means no enforcement point exists
71
- * ANYWHERE for this harness's tool calls; `'delegated'`
72
- * means one exists, just not one this harness's own row
73
- * owns or can be credited for independently — reporting it
74
- * as `'none'` would undercount real coverage, and reporting
75
- * it as `'hook'` would overclaim a file this daemon never
76
- * writes for the wrapping harness itself.
77
- * `'bridge'` — the gate runs OUT OF PROCESS, in an Intutic-operated
78
- * service reacting to the harness's own async
79
- * approval/event API, rather than a file this daemon writes
80
- * (`'hook'`), an SDK imported into the harness's own process
81
- * (`'sdk'`), no enforcement point at all (`'none'`), or
82
- * governance credited to a wrapped harness's own gate
83
- * (`'delegated'`) — a fifth, genuinely different shape.
84
- * TRUEFORGE_SERVER is the first and so far only member: a
85
- * TrueForge standalone/hosted server is a separate process
86
- * nobody embeds an Intutic gate into (unlike TRUEFORGE,
87
- * embedded mode, which IS `'sdk'`-gated — see that row's own
88
- * doc), so `services/trueforge-bridge` watches its turn/event
89
- * stream externally and answers pending approvals over HTTP.
90
- * Distinct from `'delegated'`: a delegated harness's tool
91
- * calls are governed by ANOTHER HARNESS's own gate running
92
- * in that other harness's process; a bridge-gated harness's
93
- * tool calls are governed by a service this repo ships and
94
- * operates, running in neither the harness's process nor any
95
- * other harness's. Distinct from `'sdk'`: no code from this
96
- * repo ever runs inside the governed harness's own process
97
- * at all — the harness's only obligation is to expose the
98
- * async approval API the bridge polls/subscribes to.
99
- */
100
- export type GateKind = 'hook' | 'sdk' | 'none' | 'delegated' | 'bridge';
101
- /**
102
- * Harnesses whose blocking gate ships SDK-side, in the harness's own
103
- * process — no on-disk hook/config file exists to point a gate at. Mirrors
104
- * the `file: null` NO_GATE rows in `gateRegistry.ts`.
105
- *
106
- * MASTRA, VERCEL_AI_SDK (T2), EVE (A2), and TRUEFORGE (embedded-library mode
107
- * only — see its own HarnessType doc) are the JS/TS-native members of this
108
- * family: their blocking gate ships in `@intutic/gate/mastra`/
109
- * `@intutic/gate/vercel`/`@intutic/gate/eve`/`@intutic/gate/trueforge`
110
- * (packages/gate-js) rather than `intutic-clawde`, but the shape is
111
- * identical — no on-disk hook/config file, tools run as plain callables in
112
- * the harness's own process (for eve, as per-tool/per-connection `approval`
113
- * policies attached in the agent directory's own TypeScript; for TrueForge,
114
- * as `intuticApprovalResponder()` answering `tool.approval_required`
115
- * pauses — see `@intutic/gate/trueforge`'s module doc for why that shape
116
- * differs from mastra/vercel's single-callback pattern).
117
- *
118
- * AI_SDK_HARNESS and AI_SDK_WORKFLOW (A3) are the same `@intutic/gate`
119
- * family with one nuance worth naming: the VETO still runs SDK-side in the
120
- * caller's own Node.js process (an approval responder / a `needsApproval`
121
- * function), which is what `'sdk'` classifies — but for AI_SDK_HARNESS the
122
- * tool EXECUTION it vetoes happens server-side in a Vercel Sandbox microVM,
123
- * and its built-in sandbox tools have no veto surface at all beyond
124
- * `permissionMode` (defaults to 'allow-all'). `'sdk'` describes where the
125
- * gate mechanism lives, not a claim that every tool the harness can run
126
- * passes through it — see gateRegistry.ts's NO_GATE rows for the honest
127
- * scope statement per harness.
128
- */
129
- export declare const SDK_GATED_HARNESSES: ReadonlySet<HarnessTypeT>;
130
- /**
131
- * Harnesses with no enforcement point at all today. Mirrors the
132
- * `aiderConfigMerger.ts` NO_GATE row: aider's only native hook
133
- * (`--git-commit-verify`) is opt-in, post-edit, and blind to `/run`.
134
- */
135
- export declare const NO_GATE_HARNESSES: ReadonlySet<HarnessTypeT>;
136
- /**
137
- * Harnesses that wrap OTHER already-gated harnesses instead of running tools
138
- * themselves — no gate of their own, but not ungoverned either. Mirrors the
139
- * `file: null` NO_GATE rows for `xirp` and `agentic-orchestrator` in
140
- * `gateRegistry.ts`. Xirp was the first entry of this shape; Agentic
141
- * Orchestrator (O3) is the second. O2 (QM) is expected to add a third, same
142
- * "wraps other harnesses" shape, in a concurrent phase not yet merged as of
143
- * this one.
144
- */
145
- export declare const DELEGATED_GATE_HARNESSES: ReadonlySet<HarnessTypeT>;
146
- /**
147
- * Harnesses whose blocking gate runs OUT OF PROCESS, in an Intutic-operated
148
- * service reacting to the harness's own async approval/event API — not a
149
- * file this daemon writes, and not an SDK imported into the harness's own
150
- * process (no process of ours runs inside the harness at all). Mirrors the
151
- * `file: null` NO_GATE row for `trueforge-server` in `gateRegistry.ts`.
152
- *
153
- * TRUEFORGE_SERVER (B3) is the first member: a TrueForge standalone/hosted
154
- * server has no in-process host to hang an SDK gate off of (contrast
155
- * TRUEFORGE, embedded mode, in `SDK_GATED_HARNESSES` above) — instead
156
- * `services/trueforge-bridge` watches its turn/event stream externally and
157
- * answers pending `tool.approval_required` pauses over HTTP. See the
158
- * `'bridge'` `GateKind` doc above for the full distinction from `'sdk'` and
159
- * `'delegated'`.
160
- */
161
- export declare const BRIDGE_GATED_HARNESSES: ReadonlySet<HarnessTypeT>;
162
- /** How this harness's tool calls get gated. Defaults to `'hook'`. */
163
- export declare function gateKindForHarness(type: HarnessTypeT): GateKind;
164
- //# sourceMappingURL=gateKind.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"gateKind.d.ts","sourceRoot":"","sources":["../../src/harness/gateKind.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAAe,KAAK,WAAW,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAErF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAA;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,YAAY,CAkBxD,CAAA;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,YAAY,CAAgC,CAAA;AAExF;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,EAAE,WAAW,CAAC,YAAY,CAO7D,CAAA;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,YAAY,CAA2C,CAAA;AAExG,qEAAqE;AACrE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,QAAQ,CAM/D"}
@@ -1,144 +0,0 @@
1
- /**
2
- * gateKind.ts — classifies each harness by HOW its tool calls get governed,
3
- * for `agentReporter.ts`'s `guardrails` facet.
4
- *
5
- * # Why this exists
6
- *
7
- * `collectAgentReport` used to report `hook_gate: true` unconditionally for
8
- * every harness, with the comment "the daemon writes the hook gate for every
9
- * harness it supports." That was already false for `langgraph` — which has
10
- * no on-disk hook, only the SDK-side `intutic_clawde.gate` — and for `aider`,
11
- * whose only NO_GATE-registered mechanism is a post-edit, /run-blind
12
- * pre-commit hook (see `aiderConfigMerger.ts`'s NO_GATE row in
13
- * `__tests__/harness/gateRegistry.ts`). Wave 1 adds eight more SDK-gated
14
- * harnesses, which would have made the lie eight times larger without this
15
- * fix.
16
- *
17
- * # What this does NOT do
18
- *
19
- * This does not verify that a user actually pip-installed `intutic-clawde`
20
- * and wired `guard_tools`/`IntuticMiddleware`/etc. into their process — the
21
- * daemon cannot observe another process's imports, the same way it cannot
22
- * observe whether a written hook file was left executable. It only reports
23
- * which MECHANISM this harness's governance model uses (a file the daemon
24
- * itself writes and can verify existence of, vs. an SDK the harness's own
25
- * process must import), matching the trust level `hook_gate: true` already
26
- * carried for file-based harnesses before this fix.
27
- *
28
- * # Keeping this in sync with the gate registry
29
- *
30
- * `services/sync-daemon/__tests__/harness/gateRegistry.ts` (the GATES/NO_GATE
31
- * completeness registry exercised by `generatedGateBehaviour.test.ts`) is the
32
- * authoritative decision per harness, but it is a test-only module (it
33
- * dynamically imports every writer's compiled `.js` from a temp build dir)
34
- * and must not be imported from daemon runtime code. `gateKind.test.ts`
35
- * cross-checks the two lists so this file cannot silently drift from that
36
- * registry's own NO_GATE rows: `file: null` harnesses split between 'sdk'
37
- * (LangGraph + the Python frameworks — the gate ships in intutic-clawde),
38
- * 'delegated' (xirp — the gate is whichever wrapped harness's own gate is
39
- * running), and 'bridge' (trueforge-server — the gate runs in a separate
40
- * Intutic-operated service, not in any process this repo's writers touch);
41
- * the one non-null row (aiderConfigMerger.ts, "no ... exists") is 'none'.
42
- *
43
- * @module
44
- */
45
- import { HarnessType } from '@intutic/shared-types';
46
- /**
47
- * Harnesses whose blocking gate ships SDK-side, in the harness's own
48
- * process — no on-disk hook/config file exists to point a gate at. Mirrors
49
- * the `file: null` NO_GATE rows in `gateRegistry.ts`.
50
- *
51
- * MASTRA, VERCEL_AI_SDK (T2), EVE (A2), and TRUEFORGE (embedded-library mode
52
- * only — see its own HarnessType doc) are the JS/TS-native members of this
53
- * family: their blocking gate ships in `@intutic/gate/mastra`/
54
- * `@intutic/gate/vercel`/`@intutic/gate/eve`/`@intutic/gate/trueforge`
55
- * (packages/gate-js) rather than `intutic-clawde`, but the shape is
56
- * identical — no on-disk hook/config file, tools run as plain callables in
57
- * the harness's own process (for eve, as per-tool/per-connection `approval`
58
- * policies attached in the agent directory's own TypeScript; for TrueForge,
59
- * as `intuticApprovalResponder()` answering `tool.approval_required`
60
- * pauses — see `@intutic/gate/trueforge`'s module doc for why that shape
61
- * differs from mastra/vercel's single-callback pattern).
62
- *
63
- * AI_SDK_HARNESS and AI_SDK_WORKFLOW (A3) are the same `@intutic/gate`
64
- * family with one nuance worth naming: the VETO still runs SDK-side in the
65
- * caller's own Node.js process (an approval responder / a `needsApproval`
66
- * function), which is what `'sdk'` classifies — but for AI_SDK_HARNESS the
67
- * tool EXECUTION it vetoes happens server-side in a Vercel Sandbox microVM,
68
- * and its built-in sandbox tools have no veto surface at all beyond
69
- * `permissionMode` (defaults to 'allow-all'). `'sdk'` describes where the
70
- * gate mechanism lives, not a claim that every tool the harness can run
71
- * passes through it — see gateRegistry.ts's NO_GATE rows for the honest
72
- * scope statement per harness.
73
- */
74
- export const SDK_GATED_HARNESSES = new Set([
75
- HarnessType.LANGGRAPH,
76
- HarnessType.LANGCHAIN,
77
- HarnessType.CREWAI,
78
- HarnessType.AUTOGEN,
79
- HarnessType.AG2,
80
- HarnessType.GOOGLE_ADK,
81
- HarnessType.OPENAI_AGENTS,
82
- HarnessType.PYDANTIC_AI,
83
- HarnessType.SMOLAGENTS,
84
- HarnessType.STRANDS,
85
- HarnessType.AGENT_FRAMEWORK,
86
- HarnessType.MASTRA,
87
- HarnessType.VERCEL_AI_SDK,
88
- HarnessType.EVE,
89
- HarnessType.TRUEFORGE,
90
- HarnessType.AI_SDK_HARNESS,
91
- HarnessType.AI_SDK_WORKFLOW,
92
- ]);
93
- /**
94
- * Harnesses with no enforcement point at all today. Mirrors the
95
- * `aiderConfigMerger.ts` NO_GATE row: aider's only native hook
96
- * (`--git-commit-verify`) is opt-in, post-edit, and blind to `/run`.
97
- */
98
- export const NO_GATE_HARNESSES = new Set([HarnessType.AIDER]);
99
- /**
100
- * Harnesses that wrap OTHER already-gated harnesses instead of running tools
101
- * themselves — no gate of their own, but not ungoverned either. Mirrors the
102
- * `file: null` NO_GATE rows for `xirp` and `agentic-orchestrator` in
103
- * `gateRegistry.ts`. Xirp was the first entry of this shape; Agentic
104
- * Orchestrator (O3) is the second. O2 (QM) is expected to add a third, same
105
- * "wraps other harnesses" shape, in a concurrent phase not yet merged as of
106
- * this one.
107
- */
108
- export const DELEGATED_GATE_HARNESSES = new Set([
109
- HarnessType.XIRP,
110
- HarnessType.AGENTIC_ORCHESTRATOR,
111
- // B2: AWS Bedrock AgentCore Runtime — hosts a customer's own framework
112
- // code unchanged; governed by whichever already-supported framework
113
- // adapter that code uses. See tools/cli/src/harness/agentcore.ts.
114
- HarnessType.AGENTCORE_RUNTIME,
115
- ]);
116
- /**
117
- * Harnesses whose blocking gate runs OUT OF PROCESS, in an Intutic-operated
118
- * service reacting to the harness's own async approval/event API — not a
119
- * file this daemon writes, and not an SDK imported into the harness's own
120
- * process (no process of ours runs inside the harness at all). Mirrors the
121
- * `file: null` NO_GATE row for `trueforge-server` in `gateRegistry.ts`.
122
- *
123
- * TRUEFORGE_SERVER (B3) is the first member: a TrueForge standalone/hosted
124
- * server has no in-process host to hang an SDK gate off of (contrast
125
- * TRUEFORGE, embedded mode, in `SDK_GATED_HARNESSES` above) — instead
126
- * `services/trueforge-bridge` watches its turn/event stream externally and
127
- * answers pending `tool.approval_required` pauses over HTTP. See the
128
- * `'bridge'` `GateKind` doc above for the full distinction from `'sdk'` and
129
- * `'delegated'`.
130
- */
131
- export const BRIDGE_GATED_HARNESSES = new Set([HarnessType.TRUEFORGE_SERVER]);
132
- /** How this harness's tool calls get gated. Defaults to `'hook'`. */
133
- export function gateKindForHarness(type) {
134
- if (SDK_GATED_HARNESSES.has(type))
135
- return 'sdk';
136
- if (NO_GATE_HARNESSES.has(type))
137
- return 'none';
138
- if (DELEGATED_GATE_HARNESSES.has(type))
139
- return 'delegated';
140
- if (BRIDGE_GATED_HARNESSES.has(type))
141
- return 'bridge';
142
- return 'hook';
143
- }
144
- //# sourceMappingURL=gateKind.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"gateKind.js","sourceRoot":"","sources":["../../src/harness/gateKind.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAAE,WAAW,EAAoC,MAAM,uBAAuB,CAAA;AA0DrF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAA8B,IAAI,GAAG,CAAC;IACpE,WAAW,CAAC,SAAS;IACrB,WAAW,CAAC,SAAS;IACrB,WAAW,CAAC,MAAM;IAClB,WAAW,CAAC,OAAO;IACnB,WAAW,CAAC,GAAG;IACf,WAAW,CAAC,UAAU;IACtB,WAAW,CAAC,aAAa;IACzB,WAAW,CAAC,WAAW;IACvB,WAAW,CAAC,UAAU;IACtB,WAAW,CAAC,OAAO;IACnB,WAAW,CAAC,eAAe;IAC3B,WAAW,CAAC,MAAM;IAClB,WAAW,CAAC,aAAa;IACzB,WAAW,CAAC,GAAG;IACf,WAAW,CAAC,SAAS;IACrB,WAAW,CAAC,cAAc;IAC1B,WAAW,CAAC,eAAe;CAC5B,CAAC,CAAA;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA8B,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAA;AAExF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAA8B,IAAI,GAAG,CAAC;IACzE,WAAW,CAAC,IAAI;IAChB,WAAW,CAAC,oBAAoB;IAChC,uEAAuE;IACvE,oEAAoE;IACpE,kEAAkE;IAClE,WAAW,CAAC,iBAAiB;CAC9B,CAAC,CAAA;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAA8B,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC,CAAA;AAExG,qEAAqE;AACrE,MAAM,UAAU,kBAAkB,CAAC,IAAkB;IACnD,IAAI,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IAC/C,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAA;IAC9C,IAAI,wBAAwB,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,WAAW,CAAA;IAC1D,IAAI,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAA;IACrD,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -1,31 +0,0 @@
1
- /**
2
- * rooCodeHooks.ts — Roo Code (ZooCode) governance hook generator.
3
- *
4
- * Roo Code uses `.roorules` for SOP rules and `.roomodes` for custom modes.
5
- * For hook interception, it reads hook config from `.roorules/hooks/hooks.json`.
6
- * The hook result format uses stdout JSON: {"cancel": true, "errorMessage": "..."}
7
- * rather than exit codes (unlike Claude Code's exit 2).
8
- *
9
- * Hook events are written via dual-path logEvent:
10
- * Path B (reliable) — synchronous append to .intutic/events/roo-hook-events.jsonl
11
- * Path A (telemetry) — fire-and-forget https.request to the control plane
12
- *
13
- * LLD #14 — Phase 3 cross-harness defence (Gap 3, WS-B)
14
- * HLD §3.14 — Three-Tier Defense Cascade (Tier 1 Native Gating)
15
- *
16
- * @module
17
- */
18
- /**
19
- * Write the Roo Code governance hook configuration:
20
- * 1. `.roorules` — SOP rules in Roo Code markdown format.
21
- * 2. `.roorules/hooks/hooks.json` — hook config pointing to the Node.js gate.
22
- * 3. `.intutic/hooks/roo-check.js` — Node.js dual-path hook (stdout cancel JSON).
23
- *
24
- * Safe to call repeatedly — uses atomic rename (`.intutic-tmp` → final path).
25
- *
26
- * @param workspaceRoot - Absolute workspace root path.
27
- * @param proxyUrl - Intutic proxy URL written into the hook script header.
28
- * @param workspaceId - Workspace ID embedded in every hook event payload.
29
- */
30
- export declare function writeRooCodeHooks(workspaceRoot: string, proxyUrl: string, workspaceId?: string): Promise<void>;
31
- //# sourceMappingURL=rooCodeHooks.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rooCodeHooks.d.ts","sourceRoot":"","sources":["../../src/harness/rooCodeHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAqNH;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CAuEf"}
@@ -1,286 +0,0 @@
1
- /**
2
- * rooCodeHooks.ts — Roo Code (ZooCode) governance hook generator.
3
- *
4
- * Roo Code uses `.roorules` for SOP rules and `.roomodes` for custom modes.
5
- * For hook interception, it reads hook config from `.roorules/hooks/hooks.json`.
6
- * The hook result format uses stdout JSON: {"cancel": true, "errorMessage": "..."}
7
- * rather than exit codes (unlike Claude Code's exit 2).
8
- *
9
- * Hook events are written via dual-path logEvent:
10
- * Path B (reliable) — synchronous append to .intutic/events/roo-hook-events.jsonl
11
- * Path A (telemetry) — fire-and-forget https.request to the control plane
12
- *
13
- * LLD #14 — Phase 3 cross-harness defence (Gap 3, WS-B)
14
- * HLD §3.14 — Three-Tier Defense Cascade (Tier 1 Native Gating)
15
- *
16
- * @module
17
- */
18
- import * as fs from 'node:fs/promises';
19
- import * as path from 'node:path';
20
- import * as os from 'node:os';
21
- import { createLogger } from '@intutic/logger';
22
- import { newIso } from '@intutic/id';
23
- import { emitJsGate, emitJsFailClosedPrelude } from './gateBody.js';
24
- import { UNIVERSAL_PROTECTED_PATHS } from './protectedPaths.js';
25
- const log = createLogger('sync-roo-code-hooks');
26
- /** Governance-sensitive paths that the hook gate protects. */
27
- // ─── Node.js hook script template ─────────────────────────────────────────────
28
- function buildRooCheckScript(proxyUrl, workspaceRoot, workspaceId) {
29
- const hookEventsLog = path.join(workspaceRoot, '.intutic', 'events', 'roo-hook-events.jsonl');
30
- const runtimeEnvPath = path.join(os.homedir(), '.intutic', 'env', 'runtime.env');
31
- return `/**
32
- * Intutic Roo Code PreToolUse execution gate.
33
- * Auto-generated by intutic sync-daemon. DO NOT EDIT.
34
- *
35
- * Block format: stdout JSON {"cancel": true, "errorMessage": "..."}
36
- * Allow format: stdout JSON {"cancel": false}
37
- *
38
- * Dual-path logEvent:
39
- * Path B — synchronous file append to roo-hook-events.jsonl
40
- * Path A — fire-and-forget https.request to the control plane
41
- *
42
- * Proxy: ${proxyUrl}
43
- * Generated: ${newIso()}
44
- * Workspace: ${workspaceId}
45
- */
46
- 'use strict';
47
- ${emitJsFailClosedPrelude({ harness: 'roo-code', contract: 'stdout-cancel' })}
48
- const path = require('path');
49
- const os = require('os');
50
- const fs = require('fs');
51
- const https = require('https');
52
- const crypto = require('crypto');
53
- const url = require('url');
54
-
55
- // ── Runtime env loader (Path A credentials) ──────────────────────────────────
56
- const RUNTIME_ENV_PATH = ${JSON.stringify(runtimeEnvPath)};
57
-
58
- function loadRuntimeEnv() {
59
- const env = {
60
- INTUTIC_HOST: 'https://api.intutic.ai',
61
- INTUTIC_API_KEY: '',
62
- INTUTIC_WORKSPACE_ID: ${JSON.stringify(workspaceId)},
63
- };
64
- try {
65
- const raw = fs.readFileSync(RUNTIME_ENV_PATH, 'utf-8');
66
- for (const line of raw.split('\\n')) {
67
- const stripped = line.trim();
68
- if (!stripped || stripped.startsWith('#') || !stripped.includes('=')) continue;
69
- const eq = stripped.indexOf('=');
70
- const k = stripped.slice(0, eq).trim();
71
- const v = stripped.slice(eq + 1).trim();
72
- env[k] = v;
73
- }
74
- } catch { /* file may not exist yet */ }
75
- return env;
76
- }
77
-
78
- // ── Governance-sensitive paths ────────────────────────────────────────────────
79
- ${emitJsGate({ harness: "roo-code", contract: 'stdout-cancel' })}
80
-
81
- // ── Dual-path logEvent ────────────────────────────────────────────────────────
82
- const HOOK_EVENTS_LOG = ${JSON.stringify(hookEventsLog)};
83
-
84
- let _intuticSessionId = '';
85
- function logEvent(env, verdict, toolName, reason) {
86
- const ts = new Date().toISOString();
87
- const incidentId = crypto.createHash('sha1')
88
- .update(ts + toolName + env.INTUTIC_WORKSPACE_ID)
89
- .digest('hex').slice(0, 16);
90
-
91
- const entry = {
92
- // Passed through, not collapsed to two values: the advisory tier emits
93
- // 'tool_flagged', and a ternary here silently recorded it as an allow.
94
- event: verdict,
95
- toolName,
96
- reason: reason || '',
97
- workspaceId: env.INTUTIC_WORKSPACE_ID,
98
- harnessType: 'roo-code',
99
- timestamp: ts,
100
- incidentId,
101
- ...(_intuticSessionId ? { sessionId: _intuticSessionId } : {}),
102
- };
103
-
104
- // Path B — reliable file append
105
- try {
106
- const dir = path.dirname(HOOK_EVENTS_LOG);
107
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
108
- fs.appendFileSync(HOOK_EVENTS_LOG, JSON.stringify(entry) + '\\n', { flag: 'a' });
109
- } catch { /* never crash the hook */ }
110
-
111
- // Path A — fire-and-forget https.request
112
- if (env.INTUTIC_API_KEY) {
113
- try {
114
- const body = Buffer.from(JSON.stringify({ events: [entry] }));
115
- const parsedUrl = url.parse(env.INTUTIC_HOST + '/api/v1/hook-events');
116
- const req = https.request({
117
- hostname: parsedUrl.hostname,
118
- port: parsedUrl.port || 443,
119
- path: parsedUrl.path,
120
- method: 'POST',
121
- headers: {
122
- 'Content-Type': 'application/json',
123
- 'Content-Length': body.length,
124
- 'Authorization': 'Bearer ' + env.INTUTIC_API_KEY,
125
- },
126
- });
127
- req.on('error', () => {}); // fire-and-forget
128
- req.write(body);
129
- req.end();
130
- } catch { /* never crash the hook */ }
131
- }
132
- }
133
-
134
- function block(env, toolName, reason) {
135
- logEvent(env, 'tool_blocked', toolName, reason);
136
- process.stdout.write(JSON.stringify({ cancel: true, errorMessage: reason }));
137
- process.exit(0);
138
- }
139
-
140
- function allow(env, toolName) {
141
- logEvent(env, 'tool_allowed', toolName, '');
142
- process.stdout.write(JSON.stringify({ cancel: false }));
143
- process.exit(0);
144
- }
145
-
146
- // ── Main ──────────────────────────────────────────────────────────────────────
147
- const runtimeEnv = loadRuntimeEnv();
148
- let inputData = '';
149
- process.stdin.on('data', (chunk) => { inputData += chunk; });
150
- process.stdin.on('end', () => {
151
- try {
152
- const ctx = JSON.parse(inputData);
153
- _intuticSessionId = ctx.session_id || ctx.sessionId || ctx.conversation_id || ctx.conversationId || ctx.task_id || ctx.taskId || '';
154
- // An envelope carrying none of the tool fields extracts to empty strings,
155
- // which match no rule — an allow. Refused instead, and the refusal CANCELS
156
- // (this harness ignores exit codes); see intuticGuardEnvelope.
157
- intuticGuardEnvelope(ctx, ['tool_name', 'toolName', 'tool_input', 'toolInput'],
158
- (v, t, r) => logEvent(runtimeEnv, v, t, r));
159
- const toolName = (ctx.tool_name || ctx.toolName || '').toLowerCase()
160
- // Case preserved for the gate. A BLOCK: SOP compiles to a tool-name
161
- // pattern the operator wrote as they see it (Bash, Write) and this
162
- // harness lowercases the tool for its own matching. Handing the gate the
163
- // lowercased form means every SOP tool rule silently matches nothing here
164
- // while appearing active everywhere else.
165
- const rawToolName = ctx.tool_name || ctx.toolName || '';
166
- const toolInput = ctx.tool_input || ctx.toolInput || {};
167
- const toolInputStr = JSON.stringify(toolInput);
168
-
169
- // Roo Code ignores the exit code and reads a cancel object from stdout, so
170
- // the shared gate is emitted with the stdout-cancel contract. Getting that
171
- // wrong is invisible in review — the gate would exit 2 into a harness that
172
- // never looks at it, and every call would proceed.
173
- const targetPath = toolInput.path || toolInput.file_path || toolInput.filePath ||
174
- toolInput.new_path || toolInput.target || toolInput.notebook_path || '';
175
- const command = toolInput.command || toolInput.cmd || toolInput.script || '';
176
- intuticGate(rawToolName, targetPath, command, (v, t, r) => logEvent(runtimeEnv, v, t, r), runtimeEnv.INTUTIC_WORKSPACE_ID, toolInput);
177
-
178
- allow(runtimeEnv, toolName);
179
- } catch (err) {
180
- // Fail closed on parse error
181
- const env = runtimeEnv;
182
- logEvent(env, 'tool_blocked', 'unknown', String(err));
183
- process.stdout.write(JSON.stringify({ cancel: true, errorMessage: '[Intutic] Hook error: ' + String(err) }));
184
- process.exit(0);
185
- }
186
- });
187
- `.trim();
188
- }
189
- // ─── .roorules SOP content ────────────────────────────────────────────────────
190
- function buildRooRulesContent() {
191
- return [
192
- '# Intutic Governance Rules (auto-generated)',
193
- '# DO NOT EDIT — managed by intutic sync daemon',
194
- `# Last sync: ${newIso()}`,
195
- '',
196
- '## Roo Code SOP Governance',
197
- '',
198
- 'This workspace is governed by Intutic SOP policies. All tool executions are',
199
- 'monitored and may be blocked according to the active SOPs configured in the',
200
- 'Intutic control plane.',
201
- '',
202
- '### Protected Paths',
203
- '',
204
- 'The following paths must not be modified by any agent:',
205
- '',
206
- ...UNIVERSAL_PROTECTED_PATHS.map((p) => `- \`${p}\``),
207
- '',
208
- '### Hook Events',
209
- '',
210
- 'All tool executions are logged to `.intutic/events/roo-hook-events.jsonl`',
211
- 'and forwarded to the Intutic control plane on each sync cycle.',
212
- '',
213
- ].join('\n');
214
- }
215
- // ─── Main export ──────────────────────────────────────────────────────────────
216
- /**
217
- * Write the Roo Code governance hook configuration:
218
- * 1. `.roorules` — SOP rules in Roo Code markdown format.
219
- * 2. `.roorules/hooks/hooks.json` — hook config pointing to the Node.js gate.
220
- * 3. `.intutic/hooks/roo-check.js` — Node.js dual-path hook (stdout cancel JSON).
221
- *
222
- * Safe to call repeatedly — uses atomic rename (`.intutic-tmp` → final path).
223
- *
224
- * @param workspaceRoot - Absolute workspace root path.
225
- * @param proxyUrl - Intutic proxy URL written into the hook script header.
226
- * @param workspaceId - Workspace ID embedded in every hook event payload.
227
- */
228
- export async function writeRooCodeHooks(workspaceRoot, proxyUrl, workspaceId = '') {
229
- // ── 1. Ensure directories ──────────────────────────────────────────────────
230
- const hookScriptDir = path.join(workspaceRoot, '.intutic', 'hooks');
231
- const hookEventsDir = path.join(workspaceRoot, '.intutic', 'events');
232
- const rooRulesDir = path.join(workspaceRoot, '.roorules');
233
- const rooHooksDir = path.join(rooRulesDir, 'hooks');
234
- await Promise.all([
235
- fs.mkdir(hookScriptDir, { recursive: true }),
236
- fs.mkdir(hookEventsDir, { recursive: true }),
237
- fs.mkdir(rooHooksDir, { recursive: true }),
238
- ]);
239
- // ── 2. Write hook script (atomic) ─────────────────────────────────────────
240
- const hookScriptPath = path.join(hookScriptDir, 'roo-check.js');
241
- const tmpScript = hookScriptPath + '.intutic-tmp';
242
- await fs.writeFile(tmpScript, buildRooCheckScript(proxyUrl, workspaceRoot, workspaceId), 'utf-8');
243
- await fs.rename(tmpScript, hookScriptPath);
244
- log.info({ action: 'roo_hook_script_written', path: hookScriptPath }, 'Roo Code hook script written');
245
- // ── 3. Write .roorules (atomic) ───────────────────────────────────────────
246
- const rooRulesPath = path.join(workspaceRoot, '.roorules');
247
- // .roorules is a file (not the directory used for hooks), so we check if
248
- // it's already a directory and write a README inside it instead.
249
- let rooRulesIsDir = false;
250
- try {
251
- const stat = await fs.stat(rooRulesPath);
252
- rooRulesIsDir = stat.isDirectory();
253
- }
254
- catch {
255
- // Doesn't exist — write as file
256
- }
257
- if (rooRulesIsDir) {
258
- // Write README.md inside the directory
259
- const readmePath = path.join(rooRulesPath, 'README.md');
260
- const tmpReadme = readmePath + '.intutic-tmp';
261
- await fs.writeFile(tmpReadme, buildRooRulesContent(), 'utf-8');
262
- await fs.rename(tmpReadme, readmePath);
263
- }
264
- else {
265
- const tmpRooRules = rooRulesPath + '.intutic-tmp';
266
- await fs.writeFile(tmpRooRules, buildRooRulesContent(), 'utf-8');
267
- await fs.rename(tmpRooRules, rooRulesPath);
268
- }
269
- log.info({ action: 'roo_rules_written' }, 'Roo Code .roorules written');
270
- // ── 4. Write .roorules/hooks/hooks.json (atomic) ──────────────────────────
271
- const hooksJsonPath = path.join(rooHooksDir, 'hooks.json');
272
- const hooksConfig = {
273
- hooks: [
274
- {
275
- type: 'PreToolUse',
276
- matcher: '.*',
277
- command: `node ${hookScriptPath}`,
278
- },
279
- ],
280
- };
281
- const tmpHooksJson = hooksJsonPath + '.intutic-tmp';
282
- await fs.writeFile(tmpHooksJson, JSON.stringify(hooksConfig, null, 2) + '\n', 'utf-8');
283
- await fs.rename(tmpHooksJson, hooksJsonPath);
284
- log.info({ action: 'roo_hooks_json_written', path: hooksJsonPath }, 'Roo Code hooks.json written');
285
- }
286
- //# sourceMappingURL=rooCodeHooks.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rooCodeHooks.js","sourceRoot":"","sources":["../../src/harness/rooCodeHooks.ts"],"names":[],"mappings":"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"}