@intutic/sync-daemon 1.9.0 → 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/README.md +2 -2
  2. package/dist/agentReporter.d.ts +205 -0
  3. package/dist/agentReporter.d.ts.map +1 -0
  4. package/dist/agentReporter.js +394 -0
  5. package/dist/agentReporter.js.map +1 -0
  6. package/dist/configReader.d.ts +39 -2
  7. package/dist/configReader.d.ts.map +1 -1
  8. package/dist/configReader.js +56 -2
  9. package/dist/configReader.js.map +1 -1
  10. package/dist/configWriter.d.ts +51 -1
  11. package/dist/configWriter.d.ts.map +1 -1
  12. package/dist/configWriter.js +490 -63
  13. package/dist/configWriter.js.map +1 -1
  14. package/dist/harness/antigravityHooks.d.ts.map +1 -1
  15. package/dist/harness/antigravityHooks.js +33 -55
  16. package/dist/harness/antigravityHooks.js.map +1 -1
  17. package/dist/harness/claudeCodeHooks.d.ts +47 -13
  18. package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
  19. package/dist/harness/claudeCodeHooks.js +323 -55
  20. package/dist/harness/claudeCodeHooks.js.map +1 -1
  21. package/dist/harness/claudeDesktopHooks.d.ts.map +1 -1
  22. package/dist/harness/claudeDesktopHooks.js +35 -48
  23. package/dist/harness/claudeDesktopHooks.js.map +1 -1
  24. package/dist/harness/clineHooks.d.ts.map +1 -1
  25. package/dist/harness/clineHooks.js +42 -34
  26. package/dist/harness/clineHooks.js.map +1 -1
  27. package/dist/harness/codexHooks.d.ts +36 -0
  28. package/dist/harness/codexHooks.d.ts.map +1 -0
  29. package/dist/harness/codexHooks.js +227 -0
  30. package/dist/harness/codexHooks.js.map +1 -0
  31. package/dist/harness/continueHooks.d.ts +45 -5
  32. package/dist/harness/continueHooks.d.ts.map +1 -1
  33. package/dist/harness/continueHooks.js +225 -5
  34. package/dist/harness/continueHooks.js.map +1 -1
  35. package/dist/harness/cursorHooks.d.ts +31 -0
  36. package/dist/harness/cursorHooks.d.ts.map +1 -1
  37. package/dist/harness/cursorHooks.js +78 -49
  38. package/dist/harness/cursorHooks.js.map +1 -1
  39. package/dist/harness/dshHooks.d.ts +198 -0
  40. package/dist/harness/dshHooks.d.ts.map +1 -0
  41. package/dist/harness/dshHooks.js +569 -0
  42. package/dist/harness/dshHooks.js.map +1 -0
  43. package/dist/harness/gateBody.d.ts +422 -0
  44. package/dist/harness/gateBody.d.ts.map +1 -0
  45. package/dist/harness/gateBody.js +1816 -0
  46. package/dist/harness/gateBody.js.map +1 -0
  47. package/dist/harness/gateKind.d.ts +164 -0
  48. package/dist/harness/gateKind.d.ts.map +1 -0
  49. package/dist/harness/gateKind.js +143 -0
  50. package/dist/harness/gateKind.js.map +1 -0
  51. package/dist/harness/githubCopilotHooks.d.ts +54 -0
  52. package/dist/harness/githubCopilotHooks.d.ts.map +1 -0
  53. package/dist/harness/githubCopilotHooks.js +218 -0
  54. package/dist/harness/githubCopilotHooks.js.map +1 -0
  55. package/dist/harness/gooseHooks.d.ts.map +1 -1
  56. package/dist/harness/gooseHooks.js +67 -37
  57. package/dist/harness/gooseHooks.js.map +1 -1
  58. package/dist/harness/grokHooks.d.ts +77 -0
  59. package/dist/harness/grokHooks.d.ts.map +1 -0
  60. package/dist/harness/grokHooks.js +350 -0
  61. package/dist/harness/grokHooks.js.map +1 -0
  62. package/dist/harness/hermesHooks.d.ts.map +1 -1
  63. package/dist/harness/hermesHooks.js +26 -55
  64. package/dist/harness/hermesHooks.js.map +1 -1
  65. package/dist/harness/holdRedaction.d.ts +69 -0
  66. package/dist/harness/holdRedaction.d.ts.map +1 -0
  67. package/dist/harness/holdRedaction.js +211 -0
  68. package/dist/harness/holdRedaction.js.map +1 -0
  69. package/dist/harness/jetbrainsXmlConfig.d.ts +51 -0
  70. package/dist/harness/jetbrainsXmlConfig.d.ts.map +1 -0
  71. package/dist/harness/jetbrainsXmlConfig.js +151 -0
  72. package/dist/harness/jetbrainsXmlConfig.js.map +1 -0
  73. package/dist/harness/mcpAutoWrite.d.ts +100 -3
  74. package/dist/harness/mcpAutoWrite.d.ts.map +1 -1
  75. package/dist/harness/mcpAutoWrite.js +712 -90
  76. package/dist/harness/mcpAutoWrite.js.map +1 -1
  77. package/dist/harness/museHooks.d.ts +53 -0
  78. package/dist/harness/museHooks.d.ts.map +1 -0
  79. package/dist/harness/museHooks.js +273 -0
  80. package/dist/harness/museHooks.js.map +1 -0
  81. package/dist/harness/n8nHooks.d.ts +25 -9
  82. package/dist/harness/n8nHooks.d.ts.map +1 -1
  83. package/dist/harness/n8nHooks.js +174 -9
  84. package/dist/harness/n8nHooks.js.map +1 -1
  85. package/dist/harness/openCodeHooks.d.ts +93 -0
  86. package/dist/harness/openCodeHooks.d.ts.map +1 -0
  87. package/dist/harness/openCodeHooks.js +248 -0
  88. package/dist/harness/openCodeHooks.js.map +1 -0
  89. package/dist/harness/openWebuiHooks.d.ts.map +1 -1
  90. package/dist/harness/openWebuiHooks.js +56 -11
  91. package/dist/harness/openWebuiHooks.js.map +1 -1
  92. package/dist/harness/openclawHooks.d.ts.map +1 -1
  93. package/dist/harness/openclawHooks.js +30 -54
  94. package/dist/harness/openclawHooks.js.map +1 -1
  95. package/dist/harness/openhandsHooks.d.ts.map +1 -1
  96. package/dist/harness/openhandsHooks.js +35 -41
  97. package/dist/harness/openhandsHooks.js.map +1 -1
  98. package/dist/harness/piHooks.d.ts.map +1 -1
  99. package/dist/harness/piHooks.js +31 -58
  100. package/dist/harness/piHooks.js.map +1 -1
  101. package/dist/harness/protectedPaths.d.ts +353 -0
  102. package/dist/harness/protectedPaths.d.ts.map +1 -0
  103. package/dist/harness/protectedPaths.js +805 -0
  104. package/dist/harness/protectedPaths.js.map +1 -0
  105. package/dist/harness/rooCodeHooks.d.ts.map +1 -1
  106. package/dist/harness/rooCodeHooks.js +34 -48
  107. package/dist/harness/rooCodeHooks.js.map +1 -1
  108. package/dist/harness/windsurfHooks.d.ts +72 -0
  109. package/dist/harness/windsurfHooks.d.ts.map +1 -1
  110. package/dist/harness/windsurfHooks.js +172 -58
  111. package/dist/harness/windsurfHooks.js.map +1 -1
  112. package/dist/harness/windsurfJetBrainsProxy.d.ts +78 -0
  113. package/dist/harness/windsurfJetBrainsProxy.d.ts.map +1 -0
  114. package/dist/harness/windsurfJetBrainsProxy.js +159 -0
  115. package/dist/harness/windsurfJetBrainsProxy.js.map +1 -0
  116. package/dist/hashReporter.js +1 -1
  117. package/dist/hashReporter.js.map +1 -1
  118. package/dist/index.d.ts +12 -6
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.js +14 -6
  121. package/dist/index.js.map +1 -1
  122. package/dist/integrityStore.d.ts +0 -8
  123. package/dist/integrityStore.d.ts.map +1 -1
  124. package/dist/integrityStore.js +6 -29
  125. package/dist/integrityStore.js.map +1 -1
  126. package/dist/lib/approvedBypasses.d.ts +76 -0
  127. package/dist/lib/approvedBypasses.d.ts.map +1 -0
  128. package/dist/lib/approvedBypasses.js +140 -0
  129. package/dist/lib/approvedBypasses.js.map +1 -0
  130. package/dist/lib/complianceProbes.d.ts.map +1 -1
  131. package/dist/lib/complianceProbes.js +5 -0
  132. package/dist/lib/complianceProbes.js.map +1 -1
  133. package/dist/lib/decisionsDigest.d.ts +99 -0
  134. package/dist/lib/decisionsDigest.d.ts.map +1 -0
  135. package/dist/lib/decisionsDigest.js +199 -0
  136. package/dist/lib/decisionsDigest.js.map +1 -0
  137. package/dist/lib/egressPolicy.d.ts +69 -0
  138. package/dist/lib/egressPolicy.d.ts.map +1 -0
  139. package/dist/lib/egressPolicy.js +126 -0
  140. package/dist/lib/egressPolicy.js.map +1 -0
  141. package/dist/lib/gitWorktrees.d.ts +140 -0
  142. package/dist/lib/gitWorktrees.d.ts.map +1 -0
  143. package/dist/lib/gitWorktrees.js +191 -0
  144. package/dist/lib/gitWorktrees.js.map +1 -0
  145. package/dist/lib/policySnapshot.d.ts +224 -0
  146. package/dist/lib/policySnapshot.d.ts.map +1 -0
  147. package/dist/lib/policySnapshot.js +637 -0
  148. package/dist/lib/policySnapshot.js.map +1 -0
  149. package/dist/lib/processPoller.d.ts +44 -0
  150. package/dist/lib/processPoller.d.ts.map +1 -1
  151. package/dist/lib/processPoller.js +176 -1
  152. package/dist/lib/processPoller.js.map +1 -1
  153. package/dist/lib/runtimeEnv.d.ts +8 -0
  154. package/dist/lib/runtimeEnv.d.ts.map +1 -1
  155. package/dist/lib/runtimeEnv.js +3 -0
  156. package/dist/lib/runtimeEnv.js.map +1 -1
  157. package/dist/localTrajectoryHeuristics.d.ts +51 -0
  158. package/dist/localTrajectoryHeuristics.d.ts.map +1 -0
  159. package/dist/localTrajectoryHeuristics.js +90 -0
  160. package/dist/localTrajectoryHeuristics.js.map +1 -0
  161. package/dist/sessionReporter.d.ts +70 -0
  162. package/dist/sessionReporter.d.ts.map +1 -0
  163. package/dist/sessionReporter.js +140 -0
  164. package/dist/sessionReporter.js.map +1 -0
  165. package/dist/skillWriter.d.ts +1 -1
  166. package/dist/skillWriter.d.ts.map +1 -1
  167. package/dist/skillWriter.js +6 -3
  168. package/dist/skillWriter.js.map +1 -1
  169. package/dist/syncLoop.d.ts +105 -3
  170. package/dist/syncLoop.d.ts.map +1 -1
  171. package/dist/syncLoop.js +397 -65
  172. package/dist/syncLoop.js.map +1 -1
  173. package/dist/trajectoryMonitor.d.ts +2 -0
  174. package/dist/trajectoryMonitor.d.ts.map +1 -1
  175. package/dist/trajectoryMonitor.js +57 -0
  176. package/dist/trajectoryMonitor.js.map +1 -1
  177. package/dist/watcher/driftWatcher.d.ts.map +1 -1
  178. package/dist/watcher/driftWatcher.js +12 -3
  179. package/dist/watcher/driftWatcher.js.map +1 -1
  180. package/dist/watcher/settingsGuard.d.ts +23 -0
  181. package/dist/watcher/settingsGuard.d.ts.map +1 -1
  182. package/dist/watcher/settingsGuard.js +202 -17
  183. package/dist/watcher/settingsGuard.js.map +1 -1
  184. package/package.json +37 -6
  185. package/dist/brainIndexer.d.ts +0 -51
  186. package/dist/brainIndexer.d.ts.map +0 -1
  187. package/dist/brainIndexer.js +0 -148
  188. package/dist/brainIndexer.js.map +0 -1
  189. package/dist/harness/cursorHooksJson.d.ts +0 -29
  190. package/dist/harness/cursorHooksJson.d.ts.map +0 -1
  191. package/dist/harness/cursorHooksJson.js +0 -130
  192. package/dist/harness/cursorHooksJson.js.map +0 -1
  193. package/dist/harness/gooseHooksWriter.d.ts +0 -27
  194. package/dist/harness/gooseHooksWriter.d.ts.map +0 -1
  195. package/dist/harness/gooseHooksWriter.js +0 -147
  196. package/dist/harness/gooseHooksWriter.js.map +0 -1
  197. package/dist/harness/openhandsHooksWriter.d.ts +0 -23
  198. package/dist/harness/openhandsHooksWriter.d.ts.map +0 -1
  199. package/dist/harness/openhandsHooksWriter.js +0 -146
  200. package/dist/harness/openhandsHooksWriter.js.map +0 -1
@@ -1,11 +1,24 @@
1
1
  /**
2
- * n8nHooks.ts — n8n governance workflow generator.
2
+ * n8nHooks.ts — n8n governance: workflow-level blocking gate + event workflow.
3
3
  *
4
- * n8n has no native SDK hook system. Governance is implemented via a
5
- * pre-built n8n workflow that users import into their n8n instance:
6
- * - Webhook trigger listening on /webhook/intutic-governance
7
- * - IF node filtering tool_blocked events
8
- * - HTTP Request node forwarding events to the Intutic control plane
4
+ * Two artifacts, honest about what each is:
5
+ *
6
+ * 1. **The blocking gate** (`~/.intutic/hooks/n8n-governance-hook.js`) — an
7
+ * n8n *external hook* module. n8n's only pre-execution mechanism is
8
+ * deployment-level: the operator sets
9
+ * `EXTERNAL_HOOK_FILES=/path/to/n8n-governance-hook.js` in the n8n
10
+ * process's environment, and the module's `workflow.preExecute` function
11
+ * then runs before every workflow execution, receiving the full Workflow
12
+ * object (all nodes and their parameters). **Throwing aborts the
13
+ * execution** — this is genuinely blocking, but per WORKFLOW, not per tool
14
+ * call, and installation is manual and deployment-side: this daemon cannot
15
+ * set another process's environment (the same reason open-webui's filter
16
+ * is installed by hand — see openWebuiHooks.ts). `INSTALL.md` next to the
17
+ * workflow JSON explains the env var.
18
+ *
19
+ * 2. **The event-forwarding workflow** (`~/.intutic/n8n/governance-workflow.json`)
20
+ * — an importable n8n workflow (webhook → IF → HTTP Request) that forwards
21
+ * tool_blocked events to the control plane. Telemetry, not enforcement.
9
22
  *
10
23
  * LLD #14 — Phase 3 cross-harness defence (Gap 3, WS-B)
11
24
  * HLD §3.14 — Three-Tier Defense Cascade (Tier 1 Native Gating)
@@ -17,6 +30,7 @@ import * as path from 'node:path';
17
30
  import * as os from 'node:os';
18
31
  import { createLogger } from '@intutic/logger';
19
32
  import { newIso } from '@intutic/id';
33
+ import { emitN8nWorkflowGate } from './gateBody.js';
20
34
  const log = createLogger('sync-n8n-hooks');
21
35
  /** Default n8n governance workflow directory. */
22
36
  const N8N_DIR = path.join(os.homedir(), '.intutic', 'n8n');
@@ -159,12 +173,145 @@ function buildN8nWorkflow(proxyUrl, workspaceId) {
159
173
  },
160
174
  };
161
175
  }
176
+ // ─── External-hook gate builder ───────────────────────────────────────────────
177
+ /**
178
+ * The blocking gate — an n8n external-hook module whose `workflow.preExecute`
179
+ * throws to abort an execution. See the module header for the
180
+ * `EXTERNAL_HOOK_FILES` contract and why installation is manual.
181
+ */
182
+ function buildN8nGovernanceHook(proxyUrl, workspaceId) {
183
+ return `/**
184
+ * Intutic n8n governance gate (external hook module).
185
+ * Auto-generated by intutic sync-daemon. DO NOT EDIT.
186
+ *
187
+ * MANUAL INSTALL (deployment-side): set, in the n8n process's environment,
188
+ * EXTERNAL_HOOK_FILES=/path/to/this/file
189
+ * and restart n8n. The daemon cannot set another process's environment — see
190
+ * INSTALL.md next to ~/.intutic/n8n/governance-workflow.json.
191
+ *
192
+ * workflow.preExecute runs before every execution with the full Workflow
193
+ * object; a throw here ABORTS the execution. Per-workflow granularity: one
194
+ * offending node stops the whole run, and the error names the node and rule.
195
+ *
196
+ * Proxy: ${proxyUrl}
197
+ * Generated: ${newIso()}
198
+ */
199
+ 'use strict';
200
+ const path = require('path');
201
+ const os = require('os');
202
+ const fs = require('fs');
203
+ const crypto = require('crypto');
204
+ const https = require('https');
205
+
206
+ // Runtime credentials
207
+ const _runtimeEnvPath = path.join(os.homedir(), '.intutic', 'env', 'runtime.env');
208
+ let _intuticHost = 'https://api.intutic.ai', _intuticKey = '', _intuticWsId = ${JSON.stringify(workspaceId)};
209
+ try {
210
+ fs.readFileSync(_runtimeEnvPath, 'utf-8').split('\\n').forEach(line => {
211
+ const eq = line.indexOf('='); if (eq < 0) return;
212
+ const k = line.slice(0, eq).trim(), v = line.slice(eq + 1).trim();
213
+ if (k === 'INTUTIC_HOST' && v) _intuticHost = v;
214
+ if (k === 'INTUTIC_API_KEY' && v) _intuticKey = v;
215
+ if (k === 'INTUTIC_WORKSPACE_ID' && v) _intuticWsId = v;
216
+ });
217
+ } catch {}
218
+
219
+ ${emitN8nWorkflowGate()}
220
+
221
+ // Events land under HOME, not a workspace: this runs inside the n8n server
222
+ // process, which has no workspace root — the same reason cline logs there.
223
+ const HOOK_EVENTS_LOG = path.join(os.homedir(), '.intutic', 'events', 'n8n-hook-events.jsonl');
224
+
225
+ function logEvent(verdict, toolName, reason) {
226
+ try {
227
+ const ts = new Date().toISOString();
228
+ const incidentId = crypto.createHash('sha1').update(ts + toolName + _intuticWsId).digest('hex').slice(0, 16);
229
+ const entry = JSON.stringify({
230
+ // Passed through, not collapsed to two values: the advisory tier emits
231
+ // 'tool_flagged', and a ternary here silently recorded it as an allow.
232
+ event: verdict,
233
+ toolName, reason: reason || '',
234
+ workspaceId: _intuticWsId,
235
+ harnessType: 'n8n',
236
+ timestamp: ts,
237
+ incidentId,
238
+ }) + '\\n';
239
+ const dir = path.dirname(HOOK_EVENTS_LOG);
240
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
241
+ fs.appendFileSync(HOOK_EVENTS_LOG, entry, { flag: 'a' });
242
+ if (_intuticKey) {
243
+ try {
244
+ const body = JSON.stringify({ events: [JSON.parse(entry)] });
245
+ const urlObj = new URL('/api/v1/hook-events', _intuticHost);
246
+ const mod = urlObj.protocol === 'https:' ? https : require('http');
247
+ 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 } });
248
+ req.on('error', () => { /* fire-and-forget */ });
249
+ req.write(body); req.end();
250
+ } catch { /* never crash the hook */ }
251
+ }
252
+ } catch { /* never crash the hook */ }
253
+ }
254
+
255
+ module.exports = {
256
+ workflow: {
257
+ preExecute: [
258
+ // No try/catch around the gate: a BLOCKED throw is the refusal, and an
259
+ // internal fault throwing also aborts the execution — fail closed. n8n
260
+ // shows the error message on the aborted execution.
261
+ async function intuticPreExecute(workflow) {
262
+ intuticGateWorkflow(workflow, logEvent, _intuticWsId);
263
+ },
264
+ ],
265
+ },
266
+ };
267
+ `;
268
+ }
269
+ /** INSTALL.md explaining the deployment-side env var the daemon cannot set. */
270
+ function buildInstallMd(hookPath, workflowPath) {
271
+ return `# Intutic governance for n8n — installation
272
+
273
+ Auto-generated by the Intutic sync-daemon. Two artifacts, two install steps.
274
+
275
+ ## 1. The blocking gate (manual, deployment-side)
276
+
277
+ n8n's only pre-execution hook mechanism is the \`EXTERNAL_HOOK_FILES\`
278
+ environment variable, read by the **n8n server process at startup**. The
279
+ Intutic daemon cannot set another process's environment, so this step is
280
+ yours:
281
+
282
+ \`\`\`bash
283
+ export EXTERNAL_HOOK_FILES=${hookPath}
284
+ # then (re)start n8n; for Docker:
285
+ # docker run -e EXTERNAL_HOOK_FILES=/hooks/n8n-governance-hook.js \\
286
+ # -v ${hookPath}:/hooks/n8n-governance-hook.js ...
287
+ \`\`\`
288
+
289
+ Once loaded, the module's \`workflow.preExecute\` hook runs before **every
290
+ workflow execution**, evaluates each node's type and parameters against the
291
+ compiled floor and the policy snapshot, and **throws** on a block-severity
292
+ match — which aborts the execution with an error naming the node and rule.
293
+
294
+ Granularity is per workflow, not per tool call: that is all n8n's hook
295
+ surface offers. If the env var is not set, no gate runs — the daemon
296
+ regenerates this file every sync cycle, but only your deployment can load it.
297
+
298
+ ## 2. The event-forwarding workflow (import via the n8n UI)
299
+
300
+ Import \`${workflowPath}\`
301
+ (Settings > Import Workflow), activate it, and set \`INTUTIC_API_KEY\` as an
302
+ n8n credential. It forwards tool_blocked events to the Intutic control plane.
303
+ This workflow is telemetry only; the gate above is what blocks.
304
+ `;
305
+ }
162
306
  // ─── Main export ──────────────────────────────────────────────────────────────
163
307
  /**
164
- * Write the n8n governance workflow and installation env snippet.
308
+ * Write the n8n governance gate, workflow, and installation notes.
165
309
  *
166
- * 1. Writes `~/.intutic/n8n/governance-workflow.json` — importable n8n 1.x workflow.
167
- * 2. Writes `.intutic/env/n8n.env` with webhook URL and import instructions.
310
+ * 1. Writes `~/.intutic/hooks/n8n-governance-hook.js` — the blocking
311
+ * EXTERNAL_HOOK_FILES module (manual, deployment-side install).
312
+ * 2. Writes `~/.intutic/n8n/governance-workflow.json` — importable n8n 1.x workflow.
313
+ * 3. Writes `~/.intutic/n8n/INSTALL.md` — the EXTERNAL_HOOK_FILES instructions.
314
+ * 4. Writes `.intutic/env/n8n.env` with webhook URL and import instructions.
168
315
  *
169
316
  * Safe to call repeatedly — uses atomic rename (`.intutic-tmp` → final path).
170
317
  *
@@ -175,10 +322,20 @@ function buildN8nWorkflow(proxyUrl, workspaceId) {
175
322
  export async function writeN8nHooks(workspaceRoot, proxyUrl, workspaceId = '') {
176
323
  // ── 1. Ensure directories ──────────────────────────────────────────────────
177
324
  const envDir = path.join(workspaceRoot, '.intutic', 'env');
325
+ // homedir() read at call time (unlike the module-scope N8N_DIR) so tests
326
+ // that move HOME before invoking are honoured — the gooseHooks lesson.
327
+ const hooksDir = path.join(os.homedir(), '.intutic', 'hooks');
178
328
  await Promise.all([
179
329
  fs.mkdir(N8N_DIR, { recursive: true }),
180
330
  fs.mkdir(envDir, { recursive: true }),
331
+ fs.mkdir(hooksDir, { recursive: true }),
181
332
  ]);
333
+ // ── 1b. Write the blocking external-hook gate (atomic) ────────────────────
334
+ const hookPath = path.join(hooksDir, 'n8n-governance-hook.js');
335
+ const tmpHook = hookPath + '.intutic-tmp';
336
+ await fs.writeFile(tmpHook, buildN8nGovernanceHook(proxyUrl, workspaceId), 'utf-8');
337
+ await fs.rename(tmpHook, hookPath);
338
+ log.info({ action: 'n8n_governance_hook_written', path: hookPath }, 'n8n workflow-level gate written (requires EXTERNAL_HOOK_FILES — see INSTALL.md)');
182
339
  // ── 2. Write governance-workflow.json (atomic) ────────────────────────────
183
340
  const workflowPath = path.join(N8N_DIR, 'governance-workflow.json');
184
341
  const workflow = buildN8nWorkflow(proxyUrl, workspaceId);
@@ -186,11 +343,19 @@ export async function writeN8nHooks(workspaceRoot, proxyUrl, workspaceId = '') {
186
343
  await fs.writeFile(tmpWorkflow, JSON.stringify(workflow, null, 2) + '\n', 'utf-8');
187
344
  await fs.rename(tmpWorkflow, workflowPath);
188
345
  log.info({ action: 'n8n_workflow_written', path: workflowPath }, 'n8n governance workflow written');
346
+ // ── 2b. Write INSTALL.md (atomic) ─────────────────────────────────────────
347
+ const installPath = path.join(N8N_DIR, 'INSTALL.md');
348
+ const tmpInstall = installPath + '.intutic-tmp';
349
+ await fs.writeFile(tmpInstall, buildInstallMd(hookPath, workflowPath), 'utf-8');
350
+ await fs.rename(tmpInstall, installPath);
189
351
  // ── 3. Write .intutic/env/n8n.env (atomic) ────────────────────────────────
190
352
  const envContent = [
191
353
  `# Intutic n8n governance env — auto-generated ${newIso()}`,
192
354
  `# This file is managed by the Intutic sync-daemon. DO NOT EDIT.`,
193
355
  `INTUTIC_N8N_WEBHOOK=http://localhost:5678/webhook/intutic-governance`,
356
+ `# BLOCKING GATE (manual, deployment-side): set in the n8n process's env`,
357
+ `# EXTERNAL_HOOK_FILES=${hookPath}`,
358
+ `# and restart n8n. See ~/.intutic/n8n/INSTALL.md.`,
194
359
  `# Import ~/.intutic/n8n/governance-workflow.json into your n8n instance.`,
195
360
  `# In n8n: Settings > Import Workflow > select the file above.`,
196
361
  `# Then activate the workflow and set INTUTIC_API_KEY as an n8n credential.`,
@@ -1 +1 @@
1
- {"version":3,"file":"n8nHooks.js","sourceRoot":"","sources":["../../src/harness/n8nHooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"n8nHooks.js","sourceRoot":"","sources":["../../src/harness/n8nHooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * openCodeHooks.ts — OpenCode plugin gate (TD-397).
3
+ *
4
+ * OpenCode (the open-source terminal coding agent: npm `opencode-ai` 1.x,
5
+ * `@opencode/cli` 2.x) has no hook file, no hook JSON and no stdin/stdout
6
+ * gate contract. What it has is a **plugin**: a JavaScript module OpenCode
7
+ * loads INTO ITS OWN PROCESS from `.opencode/plugins/*.{js,ts}` (project) or
8
+ * `~/.config/opencode/plugins/`, or from an npm package named in
9
+ * `opencode.json`. The plugin returns hooks; one of them runs before every
10
+ * tool call and vetoes it by throwing:
11
+ *
12
+ * - 1.x: `export default async (input) => ({ "tool.execute.before": async (i, o) => { … } })`,
13
+ * `i = { tool, sessionID, callID }`, `o = { args }`. Fired from
14
+ * `packages/opencode/src/session/tools.ts` before `item.execute(args, ctx)`,
15
+ * for built-in tools, the `task` tool and MCP tools alike. A thrown Error
16
+ * becomes a `tool-error` part whose message the model reads; the tool
17
+ * never runs. (OpenCode's own docs demonstrate exactly this shape to keep
18
+ * `read` away from `.env`.)
19
+ * - 2.x: `ctx.tool.hook("execute.before", (event) => { … })` with
20
+ * `event = { tool, input, sessionID, … }`; "only tool execute.before may
21
+ * fail: a Tool.Error rejects the call before it runs". 2.x does NOT run
22
+ * 1.x-shaped plugins, and it discovers local plugins as DIRECTORIES —
23
+ * `.opencode/plugins/<name>/index.{js,ts}` — while 1.x globs FILES —
24
+ * `.opencode/{plugin,plugins}/*.{js,ts}` — so each line sees only its
25
+ * own layout. The same module is therefore written twice: the flat file
26
+ * for 1.x and `<name>/index.js` for 2.x. Its default export is the 1.x
27
+ * plugin function, which also carries `id`, `server` and `setup` so a
28
+ * 2.x loader reading `default.setup()` finds the same gate. The 1.x
29
+ * loader accepts a function (or an object with a `.server` function) and
30
+ * rejects anything else, which is why the file exports exactly one value.
31
+ *
32
+ * The typed 1.x `permission.ask` hook is NOT used: it has had no trigger site
33
+ * since v1.0.182 and would be a gate that never fires.
34
+ *
35
+ * ## Same gate as every other hook harness
36
+ *
37
+ * The file embeds the shared `emitJsGate` body with the `'throw'` contract:
38
+ * the compiled-in floor, `~/.intutic/hooks/policy-snapshot.rules`, the WHERE
39
+ * clauses and the audit line are exactly what `codex-check.js` or
40
+ * `muse-check.js` enforce. This is why the plugin is a generated file and not
41
+ * an `@intutic/gate` npm dependency: gate-js does not carry the floor, and a
42
+ * dependency the user's project has to `bun install` is one more thing to
43
+ * drift. Nothing to register — OpenCode globs the directory.
44
+ *
45
+ * ## In-process, so no process-level handlers
46
+ *
47
+ * The plugin runs inside OpenCode. `emitJsFailClosedPrelude` (an
48
+ * `uncaughtException` handler that exits 2) would exit the user's editor on
49
+ * any unrelated fault, so it is deliberately absent — the same reasoning
50
+ * `emitN8nWorkflowGate` records. Fail-closed is local instead: the hook
51
+ * wraps the evaluation and rethrows ANY fault as a BLOCKED error, so a gate
52
+ * that cannot decide refuses rather than allows.
53
+ *
54
+ * ## What is not written
55
+ *
56
+ * `opencode.json` is left alone: the model base URL is a `provider.<id>.
57
+ * options.baseURL` field there (or `OPENCODE_CONFIG_CONTENT`), and the static
58
+ * `permission` deny map cannot express argument rules — both are documented
59
+ * for the user, not generated. OpenCode's MCP servers are not proxy-wrapped
60
+ * this phase (its MCP tool ids are `<server>_<tool>`, not `mcp__<server>__
61
+ * <tool>`, so the allowlist backstop does not compose yet — see TD-487).
62
+ *
63
+ * @module
64
+ */
65
+ /** Where OpenCode looks for project plugins (1.x globs files here, 2.x reads sub-directories). */
66
+ export declare const OPENCODE_PLUGIN_DIR: string;
67
+ /** The 1.x layout: one flat file. */
68
+ export declare const OPENCODE_PLUGIN_FILE = "intutic-governance.js";
69
+ /** The 2.x layout: `<name>/index.js`. Same bytes as the flat file. */
70
+ export declare const OPENCODE_PLUGIN_V2_FILE: string;
71
+ /**
72
+ * The plugin source. ESM, because a 1.x loader does `Object.values(module)`
73
+ * and a CommonJS file would surface every `module.exports` property as a
74
+ * named export (Bun and Node both synthesise them) — a string `id` among
75
+ * them is a `TypeError` at load. `createRequire` keeps the gate body's own
76
+ * `require()` calls (fs, os, path, crypto, http) working under ESM.
77
+ */
78
+ export declare function buildPluginScript(proxyUrl: string, workspaceRoot: string, workspaceId: string): string;
79
+ /**
80
+ * Write the OpenCode plugin under `<workspaceRoot>/.opencode/plugins/`, in
81
+ * both layouts (see the module doc): `intutic-governance.js` for 1.x and
82
+ * `intutic-governance/index.js` for 2.x — identical bytes.
83
+ *
84
+ * Safe to call repeatedly — atomic rename (`.intutic-tmp` → final path) and
85
+ * fixed file names, so repeated syncs replace rather than stack. Nothing
86
+ * else is touched: OpenCode discovers the files by scanning the directory.
87
+ *
88
+ * @param workspaceRoot - Absolute workspace root path.
89
+ * @param proxyUrl - Intutic proxy URL written into the plugin header.
90
+ * @param workspaceId - Workspace ID embedded in every hook event payload.
91
+ */
92
+ export declare function writeOpenCodeHooks(workspaceRoot: string, proxyUrl: string, workspaceId?: string): Promise<void>;
93
+ //# sourceMappingURL=openCodeHooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openCodeHooks.d.ts","sourceRoot":"","sources":["../../src/harness/openCodeHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AAUH,kGAAkG;AAClG,eAAO,MAAM,mBAAmB,QAAoC,CAAA;AACpE,qCAAqC;AACrC,eAAO,MAAM,oBAAoB,0BAA0B,CAAA;AAC3D,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,QAA8C,CAAA;AAElF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAwItG;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CACtC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CAcf"}
@@ -0,0 +1,248 @@
1
+ /**
2
+ * openCodeHooks.ts — OpenCode plugin gate (TD-397).
3
+ *
4
+ * OpenCode (the open-source terminal coding agent: npm `opencode-ai` 1.x,
5
+ * `@opencode/cli` 2.x) has no hook file, no hook JSON and no stdin/stdout
6
+ * gate contract. What it has is a **plugin**: a JavaScript module OpenCode
7
+ * loads INTO ITS OWN PROCESS from `.opencode/plugins/*.{js,ts}` (project) or
8
+ * `~/.config/opencode/plugins/`, or from an npm package named in
9
+ * `opencode.json`. The plugin returns hooks; one of them runs before every
10
+ * tool call and vetoes it by throwing:
11
+ *
12
+ * - 1.x: `export default async (input) => ({ "tool.execute.before": async (i, o) => { … } })`,
13
+ * `i = { tool, sessionID, callID }`, `o = { args }`. Fired from
14
+ * `packages/opencode/src/session/tools.ts` before `item.execute(args, ctx)`,
15
+ * for built-in tools, the `task` tool and MCP tools alike. A thrown Error
16
+ * becomes a `tool-error` part whose message the model reads; the tool
17
+ * never runs. (OpenCode's own docs demonstrate exactly this shape to keep
18
+ * `read` away from `.env`.)
19
+ * - 2.x: `ctx.tool.hook("execute.before", (event) => { … })` with
20
+ * `event = { tool, input, sessionID, … }`; "only tool execute.before may
21
+ * fail: a Tool.Error rejects the call before it runs". 2.x does NOT run
22
+ * 1.x-shaped plugins, and it discovers local plugins as DIRECTORIES —
23
+ * `.opencode/plugins/<name>/index.{js,ts}` — while 1.x globs FILES —
24
+ * `.opencode/{plugin,plugins}/*.{js,ts}` — so each line sees only its
25
+ * own layout. The same module is therefore written twice: the flat file
26
+ * for 1.x and `<name>/index.js` for 2.x. Its default export is the 1.x
27
+ * plugin function, which also carries `id`, `server` and `setup` so a
28
+ * 2.x loader reading `default.setup()` finds the same gate. The 1.x
29
+ * loader accepts a function (or an object with a `.server` function) and
30
+ * rejects anything else, which is why the file exports exactly one value.
31
+ *
32
+ * The typed 1.x `permission.ask` hook is NOT used: it has had no trigger site
33
+ * since v1.0.182 and would be a gate that never fires.
34
+ *
35
+ * ## Same gate as every other hook harness
36
+ *
37
+ * The file embeds the shared `emitJsGate` body with the `'throw'` contract:
38
+ * the compiled-in floor, `~/.intutic/hooks/policy-snapshot.rules`, the WHERE
39
+ * clauses and the audit line are exactly what `codex-check.js` or
40
+ * `muse-check.js` enforce. This is why the plugin is a generated file and not
41
+ * an `@intutic/gate` npm dependency: gate-js does not carry the floor, and a
42
+ * dependency the user's project has to `bun install` is one more thing to
43
+ * drift. Nothing to register — OpenCode globs the directory.
44
+ *
45
+ * ## In-process, so no process-level handlers
46
+ *
47
+ * The plugin runs inside OpenCode. `emitJsFailClosedPrelude` (an
48
+ * `uncaughtException` handler that exits 2) would exit the user's editor on
49
+ * any unrelated fault, so it is deliberately absent — the same reasoning
50
+ * `emitN8nWorkflowGate` records. Fail-closed is local instead: the hook
51
+ * wraps the evaluation and rethrows ANY fault as a BLOCKED error, so a gate
52
+ * that cannot decide refuses rather than allows.
53
+ *
54
+ * ## What is not written
55
+ *
56
+ * `opencode.json` is left alone: the model base URL is a `provider.<id>.
57
+ * options.baseURL` field there (or `OPENCODE_CONFIG_CONTENT`), and the static
58
+ * `permission` deny map cannot express argument rules — both are documented
59
+ * for the user, not generated. OpenCode's MCP servers are not proxy-wrapped
60
+ * this phase (its MCP tool ids are `<server>_<tool>`, not `mcp__<server>__
61
+ * <tool>`, so the allowlist backstop does not compose yet — see TD-487).
62
+ *
63
+ * @module
64
+ */
65
+ import * as fs from 'node:fs/promises';
66
+ import * as path from 'node:path';
67
+ import { createLogger } from '@intutic/logger';
68
+ import { newIso } from '@intutic/id';
69
+ import { emitJsGate, REVIEW_REQUESTS_BASENAME } from './gateBody.js';
70
+ const log = createLogger('sync-opencode-hooks');
71
+ /** Where OpenCode looks for project plugins (1.x globs files here, 2.x reads sub-directories). */
72
+ export const OPENCODE_PLUGIN_DIR = path.join('.opencode', 'plugins');
73
+ /** The 1.x layout: one flat file. */
74
+ export const OPENCODE_PLUGIN_FILE = 'intutic-governance.js';
75
+ /** The 2.x layout: `<name>/index.js`. Same bytes as the flat file. */
76
+ export const OPENCODE_PLUGIN_V2_FILE = path.join('intutic-governance', 'index.js');
77
+ /**
78
+ * The plugin source. ESM, because a 1.x loader does `Object.values(module)`
79
+ * and a CommonJS file would surface every `module.exports` property as a
80
+ * named export (Bun and Node both synthesise them) — a string `id` among
81
+ * them is a `TypeError` at load. `createRequire` keeps the gate body's own
82
+ * `require()` calls (fs, os, path, crypto, http) working under ESM.
83
+ */
84
+ export function buildPluginScript(proxyUrl, workspaceRoot, workspaceId) {
85
+ const hookEventsLog = path.join(workspaceRoot, '.intutic', 'events', 'hook-events.jsonl');
86
+ return `/**
87
+ * Intutic OpenCode governance plugin.
88
+ * Auto-generated by intutic sync-daemon. DO NOT EDIT.
89
+ * Proxy: ${proxyUrl}
90
+ * Generated: ${newIso()}
91
+ *
92
+ * Runs INSIDE OpenCode as a plugin (1.x: tool.execute.before; 2.x: tool
93
+ * execute.before). Refuses a tool call by throwing — OpenCode turns the
94
+ * thrown message into the tool-error the model reads, and the tool never
95
+ * runs. See services/sync-daemon/src/harness/openCodeHooks.ts.
96
+ */
97
+ import { createRequire } from 'node:module';
98
+ const require = createRequire(import.meta.url);
99
+ const path = require('path');
100
+ const os = require('os');
101
+ const fs = require('fs');
102
+ const crypto = require('crypto');
103
+ const https = require('https');
104
+
105
+ // Runtime credentials
106
+ const _runtimeEnvPath = path.join(os.homedir(), '.intutic', 'env', 'runtime.env');
107
+ let _intuticHost = 'https://api.intutic.ai', _intuticKey = '', _intuticWsId = ${JSON.stringify(workspaceId)};
108
+ try {
109
+ fs.readFileSync(_runtimeEnvPath, 'utf-8').split('\\n').forEach(line => {
110
+ const eq = line.indexOf('='); if (eq < 0) return;
111
+ const k = line.slice(0, eq).trim(), v = line.slice(eq + 1).trim();
112
+ if (k === 'INTUTIC_HOST' && v) _intuticHost = v;
113
+ if (k === 'INTUTIC_API_KEY' && v) _intuticKey = v;
114
+ if (k === 'INTUTIC_WORKSPACE_ID' && v) _intuticWsId = v;
115
+ });
116
+ } catch {}
117
+
118
+ ${emitJsGate({ harness: 'opencode', contract: 'throw', reviewRequestFile: path.join(workspaceRoot, '.intutic', 'events', REVIEW_REQUESTS_BASENAME) })}
119
+
120
+ let _intuticSessionId = '';
121
+ function logEvent(verdict, toolName, reason) {
122
+ try {
123
+ const ts = new Date().toISOString();
124
+ const incidentId = crypto.createHash('sha1').update(ts + toolName + _intuticWsId).digest('hex').slice(0, 16);
125
+ const entry = JSON.stringify({
126
+ event: verdict,
127
+ toolName, reason: reason || '',
128
+ workspaceId: _intuticWsId,
129
+ harnessType: 'opencode',
130
+ timestamp: ts,
131
+ incidentId,
132
+ ...(_intuticSessionId ? { sessionId: _intuticSessionId } : {}),
133
+ }) + '\\n';
134
+ const logPath = ${JSON.stringify(hookEventsLog)};
135
+ try { fs.mkdirSync(path.dirname(logPath), { recursive: true }); } catch {}
136
+ fs.appendFileSync(logPath, entry, { flag: 'a' });
137
+ if (_intuticKey) {
138
+ try {
139
+ const body = JSON.stringify({ events: [JSON.parse(entry)] });
140
+ const urlObj = new URL('/api/v1/hook-events', _intuticHost);
141
+ const mod = urlObj.protocol === 'https:' ? https : require('http');
142
+ 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 } });
143
+ req.on('error', () => { /* fire-and-forget */ });
144
+ req.write(body); req.end();
145
+ } catch { /* never crash the hook */ }
146
+ }
147
+ } catch { /* never crash the hook */ }
148
+ }
149
+
150
+ /**
151
+ * One tool call. Returns to allow; throws '[Intutic Governance] BLOCKED: …'
152
+ * to refuse. \`args\` is the tool's argument object (1.x: output.args; 2.x:
153
+ * event.input). Anything that is not an object is refused outright — the
154
+ * gate reads paths and commands out of it, and an argument shape it cannot
155
+ * read is the same anomaly the stdin gates' envelope guard refuses.
156
+ */
157
+ function intuticEvaluate(toolName, args, sessionID) {
158
+ _intuticSessionId = sessionID || '';
159
+ const tool = String(toolName || 'tool');
160
+ if (!args || typeof args !== 'object' || Array.isArray(args)) {
161
+ const reason = '[Intutic Governance] BLOCKED: tool "' + tool + '" was called with arguments the gate cannot read (' +
162
+ (args === null ? 'null' : typeof args) + '); refusing rather than allowing a call it cannot evaluate.';
163
+ try { logEvent('tool_blocked', tool, reason); } catch (e) {}
164
+ throw new Error(reason);
165
+ }
166
+ const targetPath = args.filePath || args.path || args.file_path || args.file || args.target || args.notebook_path || '';
167
+ const command = args.command || args.cmd || args.script || '';
168
+ intuticGate(tool, targetPath, command, logEvent, _intuticWsId, args);
169
+ logEvent('tool_allowed', tool, '');
170
+ }
171
+
172
+ /** Fail CLOSED: a fault inside the gate is a refusal, never an allow. */
173
+ function intuticGuarded(toolName, args, sessionID) {
174
+ try {
175
+ intuticEvaluate(toolName, args, sessionID);
176
+ } catch (err) {
177
+ const msg = String((err && err.message) || err);
178
+ if (msg.indexOf('[Intutic Governance]') === 0) throw err;
179
+ const reason = '[Intutic Governance] BLOCKED: gate fault (failing closed): ' + msg;
180
+ try { logEvent('tool_blocked', String(toolName || 'unknown'), reason); } catch (e) {}
181
+ throw new Error(reason);
182
+ }
183
+ }
184
+
185
+ // One load-time line, so a missing or stale snapshot is visible in OpenCode's
186
+ // stderr rather than silently enforcing only the floor.
187
+ function intuticAnnounce() {
188
+ try {
189
+ const snap = intuticLoadSnapshot(_intuticWsId);
190
+ const line = '[Intutic Governance] OpenCode plugin loaded (snapshot: ' + snap.state + ', rules: ' + snap.rules.length + ')';
191
+ try { process.stderr.write(line + '\\n'); } catch (e) {}
192
+ try { logEvent('plugin_loaded', 'opencode', 'snapshot ' + snap.state); } catch (e) {}
193
+ } catch (e) { /* never fail the load */ }
194
+ }
195
+
196
+ // ── 1.x: Plugin = (input) => Promise<Hooks> ───────────────────────────────
197
+ async function intuticServer(_input) {
198
+ if (!globalThis.__intuticOpencode) { globalThis.__intuticOpencode = true; intuticAnnounce(); }
199
+ return {
200
+ 'tool.execute.before': async (input, output) => {
201
+ intuticGuarded(input && input.tool, output && output.args, input && input.sessionID);
202
+ },
203
+ };
204
+ }
205
+
206
+ // ── 2.x: plugin.setup(ctx) registering a tool execute.before hook ─────────
207
+ async function intuticSetup(ctx) {
208
+ if (!globalThis.__intuticOpencode) { globalThis.__intuticOpencode = true; intuticAnnounce(); }
209
+ await ctx.tool.hook('execute.before', (event) => {
210
+ intuticGuarded(event && event.tool, event && event.input, event && event.sessionID);
211
+ });
212
+ }
213
+
214
+ const plugin = intuticServer;
215
+ plugin.id = 'intutic-governance';
216
+ plugin.server = intuticServer;
217
+ plugin.setup = intuticSetup;
218
+ export default plugin;
219
+ `;
220
+ }
221
+ /**
222
+ * Write the OpenCode plugin under `<workspaceRoot>/.opencode/plugins/`, in
223
+ * both layouts (see the module doc): `intutic-governance.js` for 1.x and
224
+ * `intutic-governance/index.js` for 2.x — identical bytes.
225
+ *
226
+ * Safe to call repeatedly — atomic rename (`.intutic-tmp` → final path) and
227
+ * fixed file names, so repeated syncs replace rather than stack. Nothing
228
+ * else is touched: OpenCode discovers the files by scanning the directory.
229
+ *
230
+ * @param workspaceRoot - Absolute workspace root path.
231
+ * @param proxyUrl - Intutic proxy URL written into the plugin header.
232
+ * @param workspaceId - Workspace ID embedded in every hook event payload.
233
+ */
234
+ export async function writeOpenCodeHooks(workspaceRoot, proxyUrl, workspaceId = '') {
235
+ await fs.mkdir(path.join(workspaceRoot, '.intutic', 'events'), { recursive: true });
236
+ const pluginDir = path.join(workspaceRoot, OPENCODE_PLUGIN_DIR);
237
+ await fs.mkdir(pluginDir, { recursive: true });
238
+ const script = buildPluginScript(proxyUrl, workspaceRoot, workspaceId);
239
+ for (const rel of [OPENCODE_PLUGIN_FILE, OPENCODE_PLUGIN_V2_FILE]) {
240
+ const pluginPath = path.join(pluginDir, rel);
241
+ await fs.mkdir(path.dirname(pluginPath), { recursive: true });
242
+ const tmp = pluginPath + '.intutic-tmp';
243
+ await fs.writeFile(tmp, script, 'utf-8');
244
+ await fs.rename(tmp, pluginPath);
245
+ log.info({ action: 'opencode_plugin_written', path: pluginPath }, 'OpenCode governance plugin written');
246
+ }
247
+ }
248
+ //# sourceMappingURL=openCodeHooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openCodeHooks.js","sourceRoot":"","sources":["../../src/harness/openCodeHooks.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"openWebuiHooks.d.ts","sourceRoot":"","sources":["../../src/harness/openWebuiHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAmHH;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CA2Cf"}
1
+ {"version":3,"file":"openWebuiHooks.d.ts","sourceRoot":"","sources":["../../src/harness/openWebuiHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAgKH;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CA2Cf"}