@intutic/sync-daemon 1.6.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 (147) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +73 -0
  3. package/dist/brainIndexer.d.ts +51 -0
  4. package/dist/brainIndexer.d.ts.map +1 -0
  5. package/dist/brainIndexer.js +148 -0
  6. package/dist/brainIndexer.js.map +1 -0
  7. package/dist/configReader.d.ts +46 -0
  8. package/dist/configReader.d.ts.map +1 -0
  9. package/dist/configReader.js +133 -0
  10. package/dist/configReader.js.map +1 -0
  11. package/dist/configWriter.d.ts +53 -0
  12. package/dist/configWriter.d.ts.map +1 -0
  13. package/dist/configWriter.js +503 -0
  14. package/dist/configWriter.js.map +1 -0
  15. package/dist/harness/aiderConfigMerger.d.ts +27 -0
  16. package/dist/harness/aiderConfigMerger.d.ts.map +1 -0
  17. package/dist/harness/aiderConfigMerger.js +139 -0
  18. package/dist/harness/aiderConfigMerger.js.map +1 -0
  19. package/dist/harness/antigravityHooks.d.ts +43 -0
  20. package/dist/harness/antigravityHooks.d.ts.map +1 -0
  21. package/dist/harness/antigravityHooks.js +193 -0
  22. package/dist/harness/antigravityHooks.js.map +1 -0
  23. package/dist/harness/claudeCodeHooks.d.ts +59 -0
  24. package/dist/harness/claudeCodeHooks.d.ts.map +1 -0
  25. package/dist/harness/claudeCodeHooks.js +414 -0
  26. package/dist/harness/claudeCodeHooks.js.map +1 -0
  27. package/dist/harness/claudeDesktopHooks.d.ts +30 -0
  28. package/dist/harness/claudeDesktopHooks.d.ts.map +1 -0
  29. package/dist/harness/claudeDesktopHooks.js +267 -0
  30. package/dist/harness/claudeDesktopHooks.js.map +1 -0
  31. package/dist/harness/clineHooks.d.ts +23 -0
  32. package/dist/harness/clineHooks.d.ts.map +1 -0
  33. package/dist/harness/clineHooks.js +169 -0
  34. package/dist/harness/clineHooks.js.map +1 -0
  35. package/dist/harness/continueHooks.d.ts +33 -0
  36. package/dist/harness/continueHooks.d.ts.map +1 -0
  37. package/dist/harness/continueHooks.js +124 -0
  38. package/dist/harness/continueHooks.js.map +1 -0
  39. package/dist/harness/cursorHooks.d.ts +27 -0
  40. package/dist/harness/cursorHooks.d.ts.map +1 -0
  41. package/dist/harness/cursorHooks.js +221 -0
  42. package/dist/harness/cursorHooks.js.map +1 -0
  43. package/dist/harness/cursorHooksJson.d.ts +29 -0
  44. package/dist/harness/cursorHooksJson.d.ts.map +1 -0
  45. package/dist/harness/cursorHooksJson.js +130 -0
  46. package/dist/harness/cursorHooksJson.js.map +1 -0
  47. package/dist/harness/gooseHardener.d.ts +39 -0
  48. package/dist/harness/gooseHardener.d.ts.map +1 -0
  49. package/dist/harness/gooseHardener.js +152 -0
  50. package/dist/harness/gooseHardener.js.map +1 -0
  51. package/dist/harness/gooseHooks.d.ts +24 -0
  52. package/dist/harness/gooseHooks.d.ts.map +1 -0
  53. package/dist/harness/gooseHooks.js +175 -0
  54. package/dist/harness/gooseHooks.js.map +1 -0
  55. package/dist/harness/gooseHooksWriter.d.ts +27 -0
  56. package/dist/harness/gooseHooksWriter.d.ts.map +1 -0
  57. package/dist/harness/gooseHooksWriter.js +147 -0
  58. package/dist/harness/gooseHooksWriter.js.map +1 -0
  59. package/dist/harness/hermesHooks.d.ts +31 -0
  60. package/dist/harness/hermesHooks.d.ts.map +1 -0
  61. package/dist/harness/hermesHooks.js +245 -0
  62. package/dist/harness/hermesHooks.js.map +1 -0
  63. package/dist/harness/mcpAutoWrite.d.ts +35 -0
  64. package/dist/harness/mcpAutoWrite.d.ts.map +1 -0
  65. package/dist/harness/mcpAutoWrite.js +334 -0
  66. package/dist/harness/mcpAutoWrite.js.map +1 -0
  67. package/dist/harness/n8nHooks.d.ts +28 -0
  68. package/dist/harness/n8nHooks.d.ts.map +1 -0
  69. package/dist/harness/n8nHooks.js +205 -0
  70. package/dist/harness/n8nHooks.js.map +1 -0
  71. package/dist/harness/openWebuiHooks.d.ts +31 -0
  72. package/dist/harness/openWebuiHooks.d.ts.map +1 -0
  73. package/dist/harness/openWebuiHooks.js +166 -0
  74. package/dist/harness/openWebuiHooks.js.map +1 -0
  75. package/dist/harness/openclawHooks.d.ts +34 -0
  76. package/dist/harness/openclawHooks.d.ts.map +1 -0
  77. package/dist/harness/openclawHooks.js +296 -0
  78. package/dist/harness/openclawHooks.js.map +1 -0
  79. package/dist/harness/openhandsHooks.d.ts +24 -0
  80. package/dist/harness/openhandsHooks.d.ts.map +1 -0
  81. package/dist/harness/openhandsHooks.js +178 -0
  82. package/dist/harness/openhandsHooks.js.map +1 -0
  83. package/dist/harness/openhandsHooksWriter.d.ts +23 -0
  84. package/dist/harness/openhandsHooksWriter.d.ts.map +1 -0
  85. package/dist/harness/openhandsHooksWriter.js +146 -0
  86. package/dist/harness/openhandsHooksWriter.js.map +1 -0
  87. package/dist/harness/piHooks.d.ts +32 -0
  88. package/dist/harness/piHooks.d.ts.map +1 -0
  89. package/dist/harness/piHooks.js +257 -0
  90. package/dist/harness/piHooks.js.map +1 -0
  91. package/dist/harness/rooCodeHooks.d.ts +31 -0
  92. package/dist/harness/rooCodeHooks.d.ts.map +1 -0
  93. package/dist/harness/rooCodeHooks.js +300 -0
  94. package/dist/harness/rooCodeHooks.js.map +1 -0
  95. package/dist/harness/windsurfHooks.d.ts +27 -0
  96. package/dist/harness/windsurfHooks.d.ts.map +1 -0
  97. package/dist/harness/windsurfHooks.js +202 -0
  98. package/dist/harness/windsurfHooks.js.map +1 -0
  99. package/dist/hashReporter.d.ts +33 -0
  100. package/dist/hashReporter.d.ts.map +1 -0
  101. package/dist/hashReporter.js +69 -0
  102. package/dist/hashReporter.js.map +1 -0
  103. package/dist/index.d.ts +43 -0
  104. package/dist/index.d.ts.map +1 -0
  105. package/dist/index.js +43 -0
  106. package/dist/index.js.map +1 -0
  107. package/dist/integrityStore.d.ts +43 -0
  108. package/dist/integrityStore.d.ts.map +1 -0
  109. package/dist/integrityStore.js +94 -0
  110. package/dist/integrityStore.js.map +1 -0
  111. package/dist/lib/complianceProbes.d.ts +39 -0
  112. package/dist/lib/complianceProbes.d.ts.map +1 -0
  113. package/dist/lib/complianceProbes.js +115 -0
  114. package/dist/lib/complianceProbes.js.map +1 -0
  115. package/dist/lib/processPoller.d.ts +2 -0
  116. package/dist/lib/processPoller.d.ts.map +1 -0
  117. package/dist/lib/processPoller.js +87 -0
  118. package/dist/lib/processPoller.js.map +1 -0
  119. package/dist/lib/runtimeEnv.d.ts +49 -0
  120. package/dist/lib/runtimeEnv.d.ts.map +1 -0
  121. package/dist/lib/runtimeEnv.js +70 -0
  122. package/dist/lib/runtimeEnv.js.map +1 -0
  123. package/dist/skillWriter.d.ts +24 -0
  124. package/dist/skillWriter.d.ts.map +1 -0
  125. package/dist/skillWriter.js +112 -0
  126. package/dist/skillWriter.js.map +1 -0
  127. package/dist/syncLoop.d.ts +70 -0
  128. package/dist/syncLoop.d.ts.map +1 -0
  129. package/dist/syncLoop.js +546 -0
  130. package/dist/syncLoop.js.map +1 -0
  131. package/dist/trajectoryMonitor.d.ts +126 -0
  132. package/dist/trajectoryMonitor.d.ts.map +1 -0
  133. package/dist/trajectoryMonitor.js +291 -0
  134. package/dist/trajectoryMonitor.js.map +1 -0
  135. package/dist/watcher/driftWatcher.d.ts +25 -0
  136. package/dist/watcher/driftWatcher.d.ts.map +1 -0
  137. package/dist/watcher/driftWatcher.js +72 -0
  138. package/dist/watcher/driftWatcher.js.map +1 -0
  139. package/dist/watcher/settingsGuard.d.ts +32 -0
  140. package/dist/watcher/settingsGuard.d.ts.map +1 -0
  141. package/dist/watcher/settingsGuard.js +250 -0
  142. package/dist/watcher/settingsGuard.js.map +1 -0
  143. package/dist/wsClient.d.ts +49 -0
  144. package/dist/wsClient.d.ts.map +1 -0
  145. package/dist/wsClient.js +149 -0
  146. package/dist/wsClient.js.map +1 -0
  147. package/package.json +96 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piHooks.js","sourceRoot":"","sources":["../../src/harness/piHooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rooCodeHooks.d.ts","sourceRoot":"","sources":["../../src/harness/rooCodeHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAmOH;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CAuEf"}
@@ -0,0 +1,300 @@
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
+ const log = createLogger('sync-roo-code-hooks');
24
+ /** Governance-sensitive paths that the hook gate protects. */
25
+ const PROTECTED_PATHS = [
26
+ path.join(os.homedir(), '.claude', 'settings.json'),
27
+ path.join(os.homedir(), '.claude', 'settings.local.json'),
28
+ '.claude/settings.json',
29
+ '.claude/settings.local.json',
30
+ '.intutic/hooks',
31
+ '.intutic/integrity.json',
32
+ '.intutic/context_integrity.json',
33
+ '.roorules/hooks',
34
+ ];
35
+ // ─── Node.js hook script template ─────────────────────────────────────────────
36
+ function buildRooCheckScript(proxyUrl, workspaceRoot, workspaceId) {
37
+ const hookEventsLog = path.join(workspaceRoot, '.intutic', 'events', 'roo-hook-events.jsonl');
38
+ const runtimeEnvPath = path.join(os.homedir(), '.intutic', 'env', 'runtime.env');
39
+ return `/**
40
+ * Intutic Roo Code PreToolUse execution gate.
41
+ * Auto-generated by intutic sync-daemon. DO NOT EDIT.
42
+ *
43
+ * Block format: stdout JSON {"cancel": true, "errorMessage": "..."}
44
+ * Allow format: stdout JSON {"cancel": false}
45
+ *
46
+ * Dual-path logEvent:
47
+ * Path B — synchronous file append to roo-hook-events.jsonl
48
+ * Path A — fire-and-forget https.request to the control plane
49
+ *
50
+ * Proxy: ${proxyUrl}
51
+ * Generated: ${newIso()}
52
+ * Workspace: ${workspaceId}
53
+ */
54
+ 'use strict';
55
+ const path = require('path');
56
+ const os = require('os');
57
+ const fs = require('fs');
58
+ const https = require('https');
59
+ const crypto = require('crypto');
60
+ const url = require('url');
61
+
62
+ // ── Runtime env loader (Path A credentials) ──────────────────────────────────
63
+ const RUNTIME_ENV_PATH = ${JSON.stringify(runtimeEnvPath)};
64
+
65
+ function loadRuntimeEnv() {
66
+ const env = {
67
+ INTUTIC_HOST: 'https://api.intutic.ai',
68
+ INTUTIC_API_KEY: '',
69
+ INTUTIC_WORKSPACE_ID: ${JSON.stringify(workspaceId)},
70
+ };
71
+ try {
72
+ const raw = fs.readFileSync(RUNTIME_ENV_PATH, 'utf-8');
73
+ for (const line of raw.split('\\n')) {
74
+ const stripped = line.trim();
75
+ if (!stripped || stripped.startsWith('#') || !stripped.includes('=')) continue;
76
+ const eq = stripped.indexOf('=');
77
+ const k = stripped.slice(0, eq).trim();
78
+ const v = stripped.slice(eq + 1).trim();
79
+ env[k] = v;
80
+ }
81
+ } catch { /* file may not exist yet */ }
82
+ return env;
83
+ }
84
+
85
+ // ── Governance-sensitive paths ────────────────────────────────────────────────
86
+ const PROTECTED_PATHS = ${JSON.stringify(PROTECTED_PATHS)};
87
+
88
+ // ── Dual-path logEvent ────────────────────────────────────────────────────────
89
+ const HOOK_EVENTS_LOG = ${JSON.stringify(hookEventsLog)};
90
+
91
+ function logEvent(env, verdict, toolName, reason) {
92
+ const ts = new Date().toISOString();
93
+ const incidentId = crypto.createHash('sha1')
94
+ .update(ts + toolName + env.INTUTIC_WORKSPACE_ID)
95
+ .digest('hex').slice(0, 16);
96
+
97
+ const entry = {
98
+ event: verdict === 'blocked' ? 'tool_blocked' : 'tool_allowed',
99
+ toolName,
100
+ reason: reason || '',
101
+ workspaceId: env.INTUTIC_WORKSPACE_ID,
102
+ harnessType: 'roo-code',
103
+ timestamp: ts,
104
+ incidentId,
105
+ };
106
+
107
+ // Path B — reliable file append
108
+ try {
109
+ const dir = path.dirname(HOOK_EVENTS_LOG);
110
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
111
+ fs.appendFileSync(HOOK_EVENTS_LOG, JSON.stringify(entry) + '\\n', { flag: 'a' });
112
+ } catch { /* never crash the hook */ }
113
+
114
+ // Path A — fire-and-forget https.request
115
+ if (env.INTUTIC_API_KEY) {
116
+ try {
117
+ const body = Buffer.from(JSON.stringify({ events: [entry] }));
118
+ const parsedUrl = url.parse(env.INTUTIC_HOST + '/api/v1/hook-events');
119
+ const req = https.request({
120
+ hostname: parsedUrl.hostname,
121
+ port: parsedUrl.port || 443,
122
+ path: parsedUrl.path,
123
+ method: 'POST',
124
+ headers: {
125
+ 'Content-Type': 'application/json',
126
+ 'Content-Length': body.length,
127
+ 'Authorization': 'Bearer ' + env.INTUTIC_API_KEY,
128
+ },
129
+ });
130
+ req.on('error', () => {}); // fire-and-forget
131
+ req.write(body);
132
+ req.end();
133
+ } catch { /* never crash the hook */ }
134
+ }
135
+ }
136
+
137
+ function block(env, toolName, reason) {
138
+ logEvent(env, 'blocked', toolName, reason);
139
+ process.stdout.write(JSON.stringify({ cancel: true, errorMessage: reason }));
140
+ process.exit(0);
141
+ }
142
+
143
+ function allow(env, toolName) {
144
+ logEvent(env, 'allowed', toolName, '');
145
+ process.stdout.write(JSON.stringify({ cancel: false }));
146
+ process.exit(0);
147
+ }
148
+
149
+ // ── Main ──────────────────────────────────────────────────────────────────────
150
+ const runtimeEnv = loadRuntimeEnv();
151
+ let inputData = '';
152
+ process.stdin.on('data', (chunk) => { inputData += chunk; });
153
+ process.stdin.on('end', () => {
154
+ try {
155
+ const ctx = JSON.parse(inputData);
156
+ const toolName = (ctx.tool_name || ctx.toolName || '').toLowerCase();
157
+ const toolInput = ctx.tool_input || ctx.toolInput || {};
158
+ const toolInputStr = JSON.stringify(toolInput);
159
+
160
+ // 1. Protected-path guard
161
+ if (['edit', 'write', 'multiedit'].includes(toolName)) {
162
+ const targetPath = toolInput.path || toolInput.file_path ||
163
+ toolInput.new_path || toolInput.target || '';
164
+ for (const p of PROTECTED_PATHS) {
165
+ if (targetPath.includes(p) || String(targetPath).startsWith(p)) {
166
+ const reason = 'Attempt to modify governance-protected path: "' + targetPath + '". ' +
167
+ 'To change governance policy, update your SOP via the Intutic control plane.';
168
+ block(runtimeEnv, toolName, reason);
169
+ return;
170
+ }
171
+ }
172
+ }
173
+
174
+ // 2. Bash/shell command bypass guard
175
+ if (toolName === 'bash') {
176
+ const cmd = toolInput.command || toolInput.cmd || '';
177
+ const BYPASS_PATTERNS = [
178
+ 'chflags nouchg',
179
+ 'chattr -i',
180
+ 'rm -rf .intutic',
181
+ 'rm -rf .roorules',
182
+ ];
183
+ for (const pattern of BYPASS_PATTERNS) {
184
+ if (cmd.includes(pattern)) {
185
+ const reason = 'Shell command matches governance bypass pattern: "' + pattern + '"';
186
+ block(runtimeEnv, toolName, reason);
187
+ return;
188
+ }
189
+ }
190
+ }
191
+
192
+ allow(runtimeEnv, toolName);
193
+ } catch (err) {
194
+ // Fail closed on parse error
195
+ const env = runtimeEnv;
196
+ logEvent(env, 'blocked', 'unknown', String(err));
197
+ process.stdout.write(JSON.stringify({ cancel: true, errorMessage: '[Intutic] Hook error: ' + String(err) }));
198
+ process.exit(0);
199
+ }
200
+ });
201
+ `.trim();
202
+ }
203
+ // ─── .roorules SOP content ────────────────────────────────────────────────────
204
+ function buildRooRulesContent() {
205
+ return [
206
+ '# Intutic Governance Rules (auto-generated)',
207
+ '# DO NOT EDIT — managed by intutic sync daemon',
208
+ `# Last sync: ${newIso()}`,
209
+ '',
210
+ '## Roo Code SOP Governance',
211
+ '',
212
+ 'This workspace is governed by Intutic SOP policies. All tool executions are',
213
+ 'monitored and may be blocked according to the active SOPs configured in the',
214
+ 'Intutic control plane.',
215
+ '',
216
+ '### Protected Paths',
217
+ '',
218
+ 'The following paths must not be modified by any agent:',
219
+ '',
220
+ ...PROTECTED_PATHS.map((p) => `- \`${p}\``),
221
+ '',
222
+ '### Hook Events',
223
+ '',
224
+ 'All tool executions are logged to `.intutic/events/roo-hook-events.jsonl`',
225
+ 'and forwarded to the Intutic control plane on each sync cycle.',
226
+ '',
227
+ ].join('\n');
228
+ }
229
+ // ─── Main export ──────────────────────────────────────────────────────────────
230
+ /**
231
+ * Write the Roo Code governance hook configuration:
232
+ * 1. `.roorules` — SOP rules in Roo Code markdown format.
233
+ * 2. `.roorules/hooks/hooks.json` — hook config pointing to the Node.js gate.
234
+ * 3. `.intutic/hooks/roo-check.js` — Node.js dual-path hook (stdout cancel JSON).
235
+ *
236
+ * Safe to call repeatedly — uses atomic rename (`.intutic-tmp` → final path).
237
+ *
238
+ * @param workspaceRoot - Absolute workspace root path.
239
+ * @param proxyUrl - Intutic proxy URL written into the hook script header.
240
+ * @param workspaceId - Workspace ID embedded in every hook event payload.
241
+ */
242
+ export async function writeRooCodeHooks(workspaceRoot, proxyUrl, workspaceId = '') {
243
+ // ── 1. Ensure directories ──────────────────────────────────────────────────
244
+ const hookScriptDir = path.join(workspaceRoot, '.intutic', 'hooks');
245
+ const hookEventsDir = path.join(workspaceRoot, '.intutic', 'events');
246
+ const rooRulesDir = path.join(workspaceRoot, '.roorules');
247
+ const rooHooksDir = path.join(rooRulesDir, 'hooks');
248
+ await Promise.all([
249
+ fs.mkdir(hookScriptDir, { recursive: true }),
250
+ fs.mkdir(hookEventsDir, { recursive: true }),
251
+ fs.mkdir(rooHooksDir, { recursive: true }),
252
+ ]);
253
+ // ── 2. Write hook script (atomic) ─────────────────────────────────────────
254
+ const hookScriptPath = path.join(hookScriptDir, 'roo-check.js');
255
+ const tmpScript = hookScriptPath + '.intutic-tmp';
256
+ await fs.writeFile(tmpScript, buildRooCheckScript(proxyUrl, workspaceRoot, workspaceId), 'utf-8');
257
+ await fs.rename(tmpScript, hookScriptPath);
258
+ log.info({ action: 'roo_hook_script_written', path: hookScriptPath }, 'Roo Code hook script written');
259
+ // ── 3. Write .roorules (atomic) ───────────────────────────────────────────
260
+ const rooRulesPath = path.join(workspaceRoot, '.roorules');
261
+ // .roorules is a file (not the directory used for hooks), so we check if
262
+ // it's already a directory and write a README inside it instead.
263
+ let rooRulesIsDir = false;
264
+ try {
265
+ const stat = await fs.stat(rooRulesPath);
266
+ rooRulesIsDir = stat.isDirectory();
267
+ }
268
+ catch {
269
+ // Doesn't exist — write as file
270
+ }
271
+ if (rooRulesIsDir) {
272
+ // Write README.md inside the directory
273
+ const readmePath = path.join(rooRulesPath, 'README.md');
274
+ const tmpReadme = readmePath + '.intutic-tmp';
275
+ await fs.writeFile(tmpReadme, buildRooRulesContent(), 'utf-8');
276
+ await fs.rename(tmpReadme, readmePath);
277
+ }
278
+ else {
279
+ const tmpRooRules = rooRulesPath + '.intutic-tmp';
280
+ await fs.writeFile(tmpRooRules, buildRooRulesContent(), 'utf-8');
281
+ await fs.rename(tmpRooRules, rooRulesPath);
282
+ }
283
+ log.info({ action: 'roo_rules_written' }, 'Roo Code .roorules written');
284
+ // ── 4. Write .roorules/hooks/hooks.json (atomic) ──────────────────────────
285
+ const hooksJsonPath = path.join(rooHooksDir, 'hooks.json');
286
+ const hooksConfig = {
287
+ hooks: [
288
+ {
289
+ type: 'PreToolUse',
290
+ matcher: '.*',
291
+ command: `node ${hookScriptPath}`,
292
+ },
293
+ ],
294
+ };
295
+ const tmpHooksJson = hooksJsonPath + '.intutic-tmp';
296
+ await fs.writeFile(tmpHooksJson, JSON.stringify(hooksConfig, null, 2) + '\n', 'utf-8');
297
+ await fs.rename(tmpHooksJson, hooksJsonPath);
298
+ log.info({ action: 'roo_hooks_json_written', path: hooksJsonPath }, 'Roo Code hooks.json written');
299
+ }
300
+ //# sourceMappingURL=rooCodeHooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rooCodeHooks.js","sourceRoot":"","sources":["../../src/harness/rooCodeHooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * windsurfHooks.ts — Windsurf Cascade hooks.json injection.
3
+ *
4
+ * Writes user-level (~/.codeium/windsurf/hooks.json) and workspace-level
5
+ * (.windsurf/hooks.json) governance hooks using the Windsurf Cascade
6
+ * hook system (exit code 2 = block).
7
+ *
8
+ * Also writes the proxy settings into ~/.codeium/windsurf/settings.json
9
+ * so that Windsurf routes HTTP traffic through the Intutic TLS MITM proxy,
10
+ * enabling governance of Cascade AI traffic that has no native base URL override.
11
+ *
12
+ * LLD #14 — Phase 3 cross-harness defence
13
+ * HLD §3.14 — Three-Tier Defense Cascade
14
+ *
15
+ * @module
16
+ */
17
+ /**
18
+ * Write Windsurf hooks at user-level and workspace-level.
19
+ * Also configures the HTTP proxy to route through Intutic's TLS MITM layer.
20
+ *
21
+ * @param workspaceRoot - Absolute workspace root.
22
+ * @param proxyUrl - Intutic proxy URL (used in the hook script comment).
23
+ * @param proxyPort - Local port where the Intutic proxy is listening (for TLS MITM).
24
+ * @param workspaceId - Workspace ID embedded in hook event payloads.
25
+ */
26
+ export declare function writeWindsurfHooks(workspaceRoot: string, proxyUrl: string, proxyPort?: number, workspaceId?: string): Promise<void>;
27
+ //# sourceMappingURL=windsurfHooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windsurfHooks.d.ts","sourceRoot":"","sources":["../../src/harness/windsurfHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAiJH;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,SAAS,SAAO,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CA2Cf"}
@@ -0,0 +1,202 @@
1
+ /**
2
+ * windsurfHooks.ts — Windsurf Cascade hooks.json injection.
3
+ *
4
+ * Writes user-level (~/.codeium/windsurf/hooks.json) and workspace-level
5
+ * (.windsurf/hooks.json) governance hooks using the Windsurf Cascade
6
+ * hook system (exit code 2 = block).
7
+ *
8
+ * Also writes the proxy settings into ~/.codeium/windsurf/settings.json
9
+ * so that Windsurf routes HTTP traffic through the Intutic TLS MITM proxy,
10
+ * enabling governance of Cascade AI traffic that has no native base URL override.
11
+ *
12
+ * LLD #14 — Phase 3 cross-harness defence
13
+ * HLD §3.14 — Three-Tier Defense Cascade
14
+ *
15
+ * @module
16
+ */
17
+ import * as fs from 'node:fs/promises';
18
+ import * as path from 'node:path';
19
+ import * as os from 'node:os';
20
+ import { createLogger } from '@intutic/logger';
21
+ import { newIso } from '@intutic/id';
22
+ const log = createLogger('sync-windsurf-hooks');
23
+ const WINDSURF_USER_DIR = path.join(os.homedir(), '.codeium', 'windsurf');
24
+ const PROTECTED_PATHS = [
25
+ '.codeium/windsurf/hooks.json',
26
+ '.windsurf/hooks.json',
27
+ '.intutic/hooks',
28
+ '.intutic/integrity.json',
29
+ '.claude/settings.json',
30
+ '.cursor/hooks.json',
31
+ '.cline/hooks',
32
+ '.agents/plugins/intutic-governance',
33
+ '.openhands/hooks.json',
34
+ ];
35
+ function buildHooksConfig(hookScriptPath) {
36
+ return {
37
+ _comment: 'Intutic governance hooks — auto-generated. DO NOT EDIT.',
38
+ _lastSync: newIso(),
39
+ hooks: {
40
+ beforeShellExecution: {
41
+ command: `node "${hookScriptPath}"`,
42
+ failClosed: true,
43
+ },
44
+ beforeMCPExecution: {
45
+ command: `node "${hookScriptPath}"`,
46
+ failClosed: true,
47
+ },
48
+ beforeFileEdit: {
49
+ command: `node "${hookScriptPath}"`,
50
+ failClosed: true,
51
+ },
52
+ },
53
+ };
54
+ }
55
+ function buildHookScript(proxyUrl, workspaceRoot, workspaceId) {
56
+ const hookEventsLog = path.join(workspaceRoot, '.intutic', 'events', 'hook-events.jsonl');
57
+ return `#!/usr/bin/env node
58
+ /**
59
+ * Intutic Windsurf governance gate.
60
+ * Auto-generated by intutic sync-daemon. DO NOT EDIT.
61
+ * Proxy: ${proxyUrl}
62
+ * Generated: ${newIso()}
63
+ */
64
+ const fs = require('fs');
65
+ const crypto = require('crypto');
66
+ const https = require('https');
67
+
68
+ // Runtime credentials
69
+ const _runtimeEnvPath = require('path').join(require('os').homedir(), '.intutic', 'env', 'runtime.env');
70
+ let _intuticHost = 'https://api.intutic.ai', _intuticKey = '', _intuticWsId = ${JSON.stringify(workspaceId)};
71
+ try {
72
+ fs.readFileSync(_runtimeEnvPath, 'utf-8').split('\\n').forEach(line => {
73
+ const eq = line.indexOf('='); if (eq < 0) return;
74
+ const k = line.slice(0, eq).trim(), v = line.slice(eq + 1).trim();
75
+ if (k === 'INTUTIC_HOST' && v) _intuticHost = v;
76
+ if (k === 'INTUTIC_API_KEY' && v) _intuticKey = v;
77
+ if (k === 'INTUTIC_WORKSPACE_ID' && v) _intuticWsId = v;
78
+ });
79
+ } catch {}
80
+
81
+ const PROTECTED_PATHS = ${JSON.stringify(PROTECTED_PATHS)};
82
+
83
+ function logEvent(verdict, toolName, reason) {
84
+ try {
85
+ const ts = new Date().toISOString();
86
+ const incidentId = crypto.createHash('sha1').update(ts + toolName + _intuticWsId).digest('hex').slice(0, 16);
87
+ const entry = JSON.stringify({
88
+ event: verdict === 'blocked' ? 'tool_blocked' : 'tool_allowed',
89
+ toolName, reason: reason || '',
90
+ workspaceId: _intuticWsId,
91
+ harnessType: 'windsurf',
92
+ timestamp: ts,
93
+ incidentId,
94
+ }) + '\\n';
95
+ fs.appendFileSync(${JSON.stringify(hookEventsLog)}, entry, { flag: 'a' });
96
+ if (_intuticKey) {
97
+ try {
98
+ const body = JSON.stringify({ events: [JSON.parse(entry)] });
99
+ const urlObj = new URL('/api/v1/hook-events', _intuticHost);
100
+ const mod = urlObj.protocol === 'https:' ? https : require('http');
101
+ 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 } });
102
+ req.on('error', () => { /* fire-and-forget */ });
103
+ req.write(body); req.end();
104
+ } catch { /* never crash the hook */ }
105
+ }
106
+ } catch { /* never crash the hook */ }
107
+ }
108
+
109
+ let raw = '';
110
+ process.stdin.on('data', (c) => { raw += c; });
111
+ process.stdin.on('end', () => {
112
+ try {
113
+ const ctx = JSON.parse(raw);
114
+ const event = (ctx.event || '').toLowerCase();
115
+ const input = ctx.input || ctx;
116
+
117
+ const targetPath = input.path || input.file || input.target || '';
118
+ for (const p of PROTECTED_PATHS) {
119
+ if (String(targetPath).includes(p)) {
120
+ const reason = 'Attempt to modify protected path "' + targetPath + '"';
121
+ process.stderr.write('[Intutic Governance] BLOCKED: ' + reason + '\\n');
122
+ logEvent('blocked', 'edit', reason);
123
+ process.exit(2);
124
+ }
125
+ }
126
+
127
+ // Scan shell commands for governance bypass patterns
128
+ const command = input.command || input.cmd || '';
129
+ const dangerPatterns = [
130
+ /chflags\\s+nouchg/,
131
+ /chattr\\s+-i\\s+/,
132
+ /chmod\\s+[0-9]*[2367][0-9]*\\s+.*hooks/,
133
+ ];
134
+ for (const pat of dangerPatterns) {
135
+ if (pat.test(command)) {
136
+ const reason = 'Command matches bypass pattern: "' + command + '"';
137
+ process.stderr.write('[Intutic Governance] BLOCKED: ' + reason + '\\n');
138
+ logEvent('blocked', 'bash', reason);
139
+ process.exit(2);
140
+ }
141
+ }
142
+
143
+ logEvent('allowed', event || 'tool', '');
144
+ process.exit(0);
145
+ } catch (err) {
146
+ const errMsg = String(err);
147
+ process.stderr.write('[Intutic Governance] Hook error (fail-closed): ' + errMsg + '\\n');
148
+ logEvent('blocked', 'unknown', errMsg);
149
+ process.exit(2);
150
+ }
151
+ });
152
+ `;
153
+ }
154
+ /**
155
+ * Write Windsurf hooks at user-level and workspace-level.
156
+ * Also configures the HTTP proxy to route through Intutic's TLS MITM layer.
157
+ *
158
+ * @param workspaceRoot - Absolute workspace root.
159
+ * @param proxyUrl - Intutic proxy URL (used in the hook script comment).
160
+ * @param proxyPort - Local port where the Intutic proxy is listening (for TLS MITM).
161
+ * @param workspaceId - Workspace ID embedded in hook event payloads.
162
+ */
163
+ export async function writeWindsurfHooks(workspaceRoot, proxyUrl, proxyPort = 8877, workspaceId = '') {
164
+ const hookScriptDir = path.join(workspaceRoot, '.intutic', 'hooks');
165
+ await fs.mkdir(hookScriptDir, { recursive: true });
166
+ // Ensure hook events log directory exists
167
+ await fs.mkdir(path.join(workspaceRoot, '.intutic', 'events'), { recursive: true });
168
+ const hookScriptPath = path.join(hookScriptDir, 'windsurf-check.js');
169
+ const tmpScript = hookScriptPath + '.ws-tmp';
170
+ await fs.writeFile(tmpScript, buildHookScript(proxyUrl, workspaceRoot, workspaceId), 'utf-8');
171
+ await fs.rename(tmpScript, hookScriptPath);
172
+ await fs.chmod(hookScriptPath, 0o755);
173
+ const config = buildHooksConfig(hookScriptPath);
174
+ // 1. User-level hooks
175
+ await fs.mkdir(WINDSURF_USER_DIR, { recursive: true });
176
+ await atomicWriteJson(path.join(WINDSURF_USER_DIR, 'hooks.json'), config);
177
+ log.info({ action: 'windsurf_hooks_written', level: 'user' }, 'Windsurf user-level hooks written');
178
+ // 2. Workspace-level hooks (.windsurf/hooks.json)
179
+ const wsWindsurfDir = path.join(workspaceRoot, '.windsurf');
180
+ await fs.mkdir(wsWindsurfDir, { recursive: true });
181
+ await atomicWriteJson(path.join(wsWindsurfDir, 'hooks.json'), {
182
+ ...config,
183
+ _note: 'Workspace-level hooks — agent may be able to modify this file. User-level hooks take precedence.',
184
+ });
185
+ log.info({ action: 'windsurf_hooks_written', level: 'workspace' }, 'Windsurf workspace-level hooks written');
186
+ // 3. HTTP proxy settings → routes Windsurf's Cascade AI traffic through Intutic TLS MITM
187
+ const wsSettings = {
188
+ _comment: 'Intutic proxy settings — auto-generated. DO NOT EDIT.',
189
+ _lastSync: newIso(),
190
+ 'http.proxy': `http://127.0.0.1:${proxyPort}`,
191
+ 'http.proxyStrictSSL': false, // Our CA cert handles validation
192
+ 'codeium.proxy': `http://127.0.0.1:${proxyPort}`,
193
+ };
194
+ await atomicWriteJson(path.join(WINDSURF_USER_DIR, 'settings.json'), wsSettings);
195
+ log.info({ action: 'windsurf_proxy_configured', port: proxyPort }, 'Windsurf HTTP proxy configured for TLS MITM interception');
196
+ }
197
+ async function atomicWriteJson(filePath, data) {
198
+ const tmp = filePath + '.intutic-tmp';
199
+ await fs.writeFile(tmp, JSON.stringify(data, null, 2) + '\n', 'utf-8');
200
+ await fs.rename(tmp, filePath);
201
+ }
202
+ //# sourceMappingURL=windsurfHooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windsurfHooks.js","sourceRoot":"","sources":["../../src/harness/windsurfHooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * hashReporter.ts — SHA-256 hash computation + integrity comparison.
3
+ *
4
+ * Computes SHA-256 hashes of local harness config files and compares
5
+ * them against canonical hashes from the control plane. This enables
6
+ * SOP drift detection: if a developer manually edits a governed file,
7
+ * the daemon flags it as drifted in the next sync report.
8
+ *
9
+ * HLD §3.14 — SOP Integrity Verification
10
+ * LLD #8 — Sync Daemon / CLI
11
+ *
12
+ * @module
13
+ */
14
+ import type { HarnessType, SopFileHash } from '@intutic/shared-types';
15
+ /**
16
+ * Compute SHA-256 hashes for all harness config files and compare
17
+ * against canonical hashes from the control plane.
18
+ *
19
+ * @param workspaceRoot - Absolute path to the workspace root.
20
+ * @param harnesses - Harness types detected in the workspace.
21
+ * @param canonicalHashes - Expected hashes from last sync (filePath → SHA-256).
22
+ * @returns Array of SopFileHash entries with drift detection flags.
23
+ */
24
+ export declare function computeFileHashes(workspaceRoot: string, harnesses: HarnessType[], canonicalHashes: Record<string, string>): Promise<SopFileHash[]>;
25
+ /**
26
+ * Compute the SHA-256 hex digest of a file's contents.
27
+ *
28
+ * @param filePath - Absolute path to the file.
29
+ * @returns 64-character lowercase hex SHA-256 hash.
30
+ * @throws If the file does not exist or is not readable.
31
+ */
32
+ export declare function hashFile(filePath: string): Promise<string>;
33
+ //# sourceMappingURL=hashReporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashReporter.d.ts","sourceRoot":"","sources":["../src/hashReporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAGrE;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,WAAW,EAAE,EACxB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtC,OAAO,CAAC,WAAW,EAAE,CAAC,CAiCxB;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGhE"}