@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.
- package/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/brainIndexer.d.ts +51 -0
- package/dist/brainIndexer.d.ts.map +1 -0
- package/dist/brainIndexer.js +148 -0
- package/dist/brainIndexer.js.map +1 -0
- package/dist/configReader.d.ts +46 -0
- package/dist/configReader.d.ts.map +1 -0
- package/dist/configReader.js +133 -0
- package/dist/configReader.js.map +1 -0
- package/dist/configWriter.d.ts +53 -0
- package/dist/configWriter.d.ts.map +1 -0
- package/dist/configWriter.js +503 -0
- package/dist/configWriter.js.map +1 -0
- package/dist/harness/aiderConfigMerger.d.ts +27 -0
- package/dist/harness/aiderConfigMerger.d.ts.map +1 -0
- package/dist/harness/aiderConfigMerger.js +139 -0
- package/dist/harness/aiderConfigMerger.js.map +1 -0
- package/dist/harness/antigravityHooks.d.ts +43 -0
- package/dist/harness/antigravityHooks.d.ts.map +1 -0
- package/dist/harness/antigravityHooks.js +193 -0
- package/dist/harness/antigravityHooks.js.map +1 -0
- package/dist/harness/claudeCodeHooks.d.ts +59 -0
- package/dist/harness/claudeCodeHooks.d.ts.map +1 -0
- package/dist/harness/claudeCodeHooks.js +414 -0
- package/dist/harness/claudeCodeHooks.js.map +1 -0
- package/dist/harness/claudeDesktopHooks.d.ts +30 -0
- package/dist/harness/claudeDesktopHooks.d.ts.map +1 -0
- package/dist/harness/claudeDesktopHooks.js +267 -0
- package/dist/harness/claudeDesktopHooks.js.map +1 -0
- package/dist/harness/clineHooks.d.ts +23 -0
- package/dist/harness/clineHooks.d.ts.map +1 -0
- package/dist/harness/clineHooks.js +169 -0
- package/dist/harness/clineHooks.js.map +1 -0
- package/dist/harness/continueHooks.d.ts +33 -0
- package/dist/harness/continueHooks.d.ts.map +1 -0
- package/dist/harness/continueHooks.js +124 -0
- package/dist/harness/continueHooks.js.map +1 -0
- package/dist/harness/cursorHooks.d.ts +27 -0
- package/dist/harness/cursorHooks.d.ts.map +1 -0
- package/dist/harness/cursorHooks.js +221 -0
- package/dist/harness/cursorHooks.js.map +1 -0
- package/dist/harness/cursorHooksJson.d.ts +29 -0
- package/dist/harness/cursorHooksJson.d.ts.map +1 -0
- package/dist/harness/cursorHooksJson.js +130 -0
- package/dist/harness/cursorHooksJson.js.map +1 -0
- package/dist/harness/gooseHardener.d.ts +39 -0
- package/dist/harness/gooseHardener.d.ts.map +1 -0
- package/dist/harness/gooseHardener.js +152 -0
- package/dist/harness/gooseHardener.js.map +1 -0
- package/dist/harness/gooseHooks.d.ts +24 -0
- package/dist/harness/gooseHooks.d.ts.map +1 -0
- package/dist/harness/gooseHooks.js +175 -0
- package/dist/harness/gooseHooks.js.map +1 -0
- package/dist/harness/gooseHooksWriter.d.ts +27 -0
- package/dist/harness/gooseHooksWriter.d.ts.map +1 -0
- package/dist/harness/gooseHooksWriter.js +147 -0
- package/dist/harness/gooseHooksWriter.js.map +1 -0
- package/dist/harness/hermesHooks.d.ts +31 -0
- package/dist/harness/hermesHooks.d.ts.map +1 -0
- package/dist/harness/hermesHooks.js +245 -0
- package/dist/harness/hermesHooks.js.map +1 -0
- package/dist/harness/mcpAutoWrite.d.ts +35 -0
- package/dist/harness/mcpAutoWrite.d.ts.map +1 -0
- package/dist/harness/mcpAutoWrite.js +334 -0
- package/dist/harness/mcpAutoWrite.js.map +1 -0
- package/dist/harness/n8nHooks.d.ts +28 -0
- package/dist/harness/n8nHooks.d.ts.map +1 -0
- package/dist/harness/n8nHooks.js +205 -0
- package/dist/harness/n8nHooks.js.map +1 -0
- package/dist/harness/openWebuiHooks.d.ts +31 -0
- package/dist/harness/openWebuiHooks.d.ts.map +1 -0
- package/dist/harness/openWebuiHooks.js +166 -0
- package/dist/harness/openWebuiHooks.js.map +1 -0
- package/dist/harness/openclawHooks.d.ts +34 -0
- package/dist/harness/openclawHooks.d.ts.map +1 -0
- package/dist/harness/openclawHooks.js +296 -0
- package/dist/harness/openclawHooks.js.map +1 -0
- package/dist/harness/openhandsHooks.d.ts +24 -0
- package/dist/harness/openhandsHooks.d.ts.map +1 -0
- package/dist/harness/openhandsHooks.js +178 -0
- package/dist/harness/openhandsHooks.js.map +1 -0
- package/dist/harness/openhandsHooksWriter.d.ts +23 -0
- package/dist/harness/openhandsHooksWriter.d.ts.map +1 -0
- package/dist/harness/openhandsHooksWriter.js +146 -0
- package/dist/harness/openhandsHooksWriter.js.map +1 -0
- package/dist/harness/piHooks.d.ts +32 -0
- package/dist/harness/piHooks.d.ts.map +1 -0
- package/dist/harness/piHooks.js +257 -0
- package/dist/harness/piHooks.js.map +1 -0
- package/dist/harness/rooCodeHooks.d.ts +31 -0
- package/dist/harness/rooCodeHooks.d.ts.map +1 -0
- package/dist/harness/rooCodeHooks.js +300 -0
- package/dist/harness/rooCodeHooks.js.map +1 -0
- package/dist/harness/windsurfHooks.d.ts +27 -0
- package/dist/harness/windsurfHooks.d.ts.map +1 -0
- package/dist/harness/windsurfHooks.js +202 -0
- package/dist/harness/windsurfHooks.js.map +1 -0
- package/dist/hashReporter.d.ts +33 -0
- package/dist/hashReporter.d.ts.map +1 -0
- package/dist/hashReporter.js +69 -0
- package/dist/hashReporter.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/integrityStore.d.ts +43 -0
- package/dist/integrityStore.d.ts.map +1 -0
- package/dist/integrityStore.js +94 -0
- package/dist/integrityStore.js.map +1 -0
- package/dist/lib/complianceProbes.d.ts +39 -0
- package/dist/lib/complianceProbes.d.ts.map +1 -0
- package/dist/lib/complianceProbes.js +115 -0
- package/dist/lib/complianceProbes.js.map +1 -0
- package/dist/lib/processPoller.d.ts +2 -0
- package/dist/lib/processPoller.d.ts.map +1 -0
- package/dist/lib/processPoller.js +87 -0
- package/dist/lib/processPoller.js.map +1 -0
- package/dist/lib/runtimeEnv.d.ts +49 -0
- package/dist/lib/runtimeEnv.d.ts.map +1 -0
- package/dist/lib/runtimeEnv.js +70 -0
- package/dist/lib/runtimeEnv.js.map +1 -0
- package/dist/skillWriter.d.ts +24 -0
- package/dist/skillWriter.d.ts.map +1 -0
- package/dist/skillWriter.js +112 -0
- package/dist/skillWriter.js.map +1 -0
- package/dist/syncLoop.d.ts +70 -0
- package/dist/syncLoop.d.ts.map +1 -0
- package/dist/syncLoop.js +546 -0
- package/dist/syncLoop.js.map +1 -0
- package/dist/trajectoryMonitor.d.ts +126 -0
- package/dist/trajectoryMonitor.d.ts.map +1 -0
- package/dist/trajectoryMonitor.js +291 -0
- package/dist/trajectoryMonitor.js.map +1 -0
- package/dist/watcher/driftWatcher.d.ts +25 -0
- package/dist/watcher/driftWatcher.d.ts.map +1 -0
- package/dist/watcher/driftWatcher.js +72 -0
- package/dist/watcher/driftWatcher.js.map +1 -0
- package/dist/watcher/settingsGuard.d.ts +32 -0
- package/dist/watcher/settingsGuard.d.ts.map +1 -0
- package/dist/watcher/settingsGuard.js +250 -0
- package/dist/watcher/settingsGuard.js.map +1 -0
- package/dist/wsClient.d.ts +49 -0
- package/dist/wsClient.d.ts.map +1 -0
- package/dist/wsClient.js +149 -0
- package/dist/wsClient.js.map +1 -0
- package/package.json +96 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermesHooks.js","sourceRoot":"","sources":["../../src/harness/hermesHooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcpAutoWrite.ts — Injects Intutic MCP server configurations and wraps existing
|
|
3
|
+
* MCP servers with the @intutic/mcp-governance-proxy.
|
|
4
|
+
*
|
|
5
|
+
* Injects and proxy-wraps MCP server entries in:
|
|
6
|
+
* - Claude Code: ~/.claude/mcp.json
|
|
7
|
+
* - Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json
|
|
8
|
+
* - Cursor (global): ~/Library/Application Support/Cursor/User/globalSettings.json
|
|
9
|
+
* - Cursor (project): <workspaceRoot>/.cursor/mcp.json
|
|
10
|
+
* - Cline: <workspaceRoot>/.cline/mcp.json
|
|
11
|
+
* - Windsurf: ~/.codeium/windsurf/mcp_config.json
|
|
12
|
+
* - Continue: ~/.continue/config.json (mcpServers section)
|
|
13
|
+
* - Goose: ~/.config/goose/config.yaml (mcp section)
|
|
14
|
+
* - OpenHands: <workspaceRoot>/.openhands/mcp.json
|
|
15
|
+
*
|
|
16
|
+
* Proxy-wrapping convention:
|
|
17
|
+
* Each existing MCP server entry is rewritten so that the governance proxy
|
|
18
|
+
* binary is the command, and the original server command is passed after `--`.
|
|
19
|
+
* A `__intutic_wrapped: true` flag is added to prevent double-wrapping.
|
|
20
|
+
*
|
|
21
|
+
* LLD #14 — mcpAutoWrite.ts
|
|
22
|
+
* HLD §3.14 — GUI Harness Interception (MCP registration + Universal MCP Governance)
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Injects and proxy-wraps the Intutic MCP server configuration into all supported harnesses.
|
|
28
|
+
*
|
|
29
|
+
* Non-fatal: a failure in one harness does not prevent other harnesses from being updated.
|
|
30
|
+
*
|
|
31
|
+
* @param workspaceId - The workspace ID for policy lookups and event attribution.
|
|
32
|
+
* @param workspaceRoot - Absolute path to the project workspace root.
|
|
33
|
+
*/
|
|
34
|
+
export declare function injectMcpServer(workspaceRoot: string, workspaceId?: string): Promise<void>;
|
|
35
|
+
//# sourceMappingURL=mcpAutoWrite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpAutoWrite.d.ts","sourceRoot":"","sources":["../../src/harness/mcpAutoWrite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAiYH;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,WAAW,SAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBnG"}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcpAutoWrite.ts — Injects Intutic MCP server configurations and wraps existing
|
|
3
|
+
* MCP servers with the @intutic/mcp-governance-proxy.
|
|
4
|
+
*
|
|
5
|
+
* Injects and proxy-wraps MCP server entries in:
|
|
6
|
+
* - Claude Code: ~/.claude/mcp.json
|
|
7
|
+
* - Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json
|
|
8
|
+
* - Cursor (global): ~/Library/Application Support/Cursor/User/globalSettings.json
|
|
9
|
+
* - Cursor (project): <workspaceRoot>/.cursor/mcp.json
|
|
10
|
+
* - Cline: <workspaceRoot>/.cline/mcp.json
|
|
11
|
+
* - Windsurf: ~/.codeium/windsurf/mcp_config.json
|
|
12
|
+
* - Continue: ~/.continue/config.json (mcpServers section)
|
|
13
|
+
* - Goose: ~/.config/goose/config.yaml (mcp section)
|
|
14
|
+
* - OpenHands: <workspaceRoot>/.openhands/mcp.json
|
|
15
|
+
*
|
|
16
|
+
* Proxy-wrapping convention:
|
|
17
|
+
* Each existing MCP server entry is rewritten so that the governance proxy
|
|
18
|
+
* binary is the command, and the original server command is passed after `--`.
|
|
19
|
+
* A `__intutic_wrapped: true` flag is added to prevent double-wrapping.
|
|
20
|
+
*
|
|
21
|
+
* LLD #14 — mcpAutoWrite.ts
|
|
22
|
+
* HLD §3.14 — GUI Harness Interception (MCP registration + Universal MCP Governance)
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
25
|
+
*/
|
|
26
|
+
import * as node_fs from 'node:fs/promises';
|
|
27
|
+
import * as node_path from 'node:path';
|
|
28
|
+
import * as node_os from 'node:os';
|
|
29
|
+
import { existsSync } from 'node:fs';
|
|
30
|
+
import { createLogger } from '@intutic/logger';
|
|
31
|
+
const log = createLogger('sync-mcp-autowrite');
|
|
32
|
+
// ─── Proxy Binary Resolution ─────────────────────────────────────────────────
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the path to the @intutic/mcp-governance-proxy binary.
|
|
35
|
+
*
|
|
36
|
+
* Resolution order:
|
|
37
|
+
* 1. `<workspaceRoot>/node_modules/@intutic/mcp-governance-proxy/dist/index.js`
|
|
38
|
+
* — created by pnpm after `pnpm install` (post-install production path)
|
|
39
|
+
* 2. `<workspaceRoot>/packages/mcp-proxy/dist/index.js`
|
|
40
|
+
* — direct monorepo source path (dev without pnpm install, or if symlink is missing)
|
|
41
|
+
*
|
|
42
|
+
* Using synchronous existsSync is intentional — this runs at daemon init time
|
|
43
|
+
* (not in a hot path), and avoids async complexity in callers.
|
|
44
|
+
*/
|
|
45
|
+
function resolveProxyBin(workspaceRoot) {
|
|
46
|
+
const nmPath = node_path.join(workspaceRoot, 'node_modules', '@intutic', 'mcp-governance-proxy', 'dist', 'index.js');
|
|
47
|
+
if (existsSync(nmPath))
|
|
48
|
+
return nmPath;
|
|
49
|
+
// Fallback: direct monorepo package path for dev environments
|
|
50
|
+
const pkgPath = node_path.join(workspaceRoot, 'packages', 'mcp-proxy', 'dist', 'index.js');
|
|
51
|
+
return pkgPath;
|
|
52
|
+
}
|
|
53
|
+
// ─── Proxy Wrapping ───────────────────────────────────────────────────────────
|
|
54
|
+
/**
|
|
55
|
+
* Wrap a single MCP server entry with the governance proxy.
|
|
56
|
+
* Returns the entry unmodified if it's already wrapped.
|
|
57
|
+
*/
|
|
58
|
+
function wrapWithProxy(entry, workspaceId, workspaceRoot) {
|
|
59
|
+
if (entry.__intutic_wrapped)
|
|
60
|
+
return entry;
|
|
61
|
+
const proxyBin = resolveProxyBin(workspaceRoot);
|
|
62
|
+
const originalArgs = entry.args ?? [];
|
|
63
|
+
return {
|
|
64
|
+
command: 'node',
|
|
65
|
+
args: [
|
|
66
|
+
proxyBin,
|
|
67
|
+
'--workspace-id', workspaceId,
|
|
68
|
+
'--',
|
|
69
|
+
entry.command,
|
|
70
|
+
...originalArgs,
|
|
71
|
+
],
|
|
72
|
+
env: {
|
|
73
|
+
...(entry.env ?? {}),
|
|
74
|
+
INTUTIC_WORKSPACE_ID: workspaceId,
|
|
75
|
+
},
|
|
76
|
+
__intutic_wrapped: true,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Wrap all servers in an mcpServers map, preserving the `intutic` entry as-is.
|
|
81
|
+
* The `intutic` entry is the control plane MCP server — it must NOT be proxied
|
|
82
|
+
* through itself (circular dependency).
|
|
83
|
+
*/
|
|
84
|
+
function wrapAllServers(servers, workspaceId, workspaceRoot) {
|
|
85
|
+
const result = {};
|
|
86
|
+
for (const [name, entry] of Object.entries(servers)) {
|
|
87
|
+
if (name === 'intutic') {
|
|
88
|
+
// Never wrap the Intutic server through itself
|
|
89
|
+
result[name] = entry;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
result[name] = wrapWithProxy(entry, workspaceId, workspaceRoot);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
// ─── Intutic MCP Server Entry ─────────────────────────────────────────────────
|
|
98
|
+
function buildIntuticMcpEntry(workspaceRoot) {
|
|
99
|
+
return {
|
|
100
|
+
command: 'node',
|
|
101
|
+
args: [
|
|
102
|
+
resolveProxyBin(workspaceRoot),
|
|
103
|
+
],
|
|
104
|
+
env: {
|
|
105
|
+
NODE_ENV: 'production',
|
|
106
|
+
// CRITICAL: pino must write to stderr so stdout stays pure JSON-RPC.
|
|
107
|
+
// ESM hoists imports above process.env mutations in code, so we set
|
|
108
|
+
// this in the environment before node starts rather than in index.ts.
|
|
109
|
+
PINO_DEST: 'stderr',
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// ─── JSON helpers ─────────────────────────────────────────────────────────────
|
|
114
|
+
async function readJsonFile(filePath, fallback) {
|
|
115
|
+
try {
|
|
116
|
+
const raw = await node_fs.readFile(filePath, 'utf-8');
|
|
117
|
+
return JSON.parse(raw);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return fallback;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async function writeJsonFile(filePath, data) {
|
|
124
|
+
await node_fs.mkdir(node_path.dirname(filePath), { recursive: true });
|
|
125
|
+
await node_fs.writeFile(filePath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
126
|
+
}
|
|
127
|
+
// ─── Target: Claude Code ─────────────────────────────────────────────────────
|
|
128
|
+
async function injectClaudeCode(workspaceId, workspaceRoot) {
|
|
129
|
+
const home = node_os.homedir();
|
|
130
|
+
const configPath = node_path.join(home, '.claude', 'mcp.json');
|
|
131
|
+
const current = await readJsonFile(configPath, {});
|
|
132
|
+
current.mcpServers = wrapAllServers({ intutic: buildIntuticMcpEntry(workspaceRoot), ...(current.mcpServers ?? {}) }, workspaceId, workspaceRoot);
|
|
133
|
+
await writeJsonFile(configPath, current);
|
|
134
|
+
log.info({ action: 'claude_code_mcp_injected' }, 'Claude Code ~/.claude/mcp.json updated');
|
|
135
|
+
}
|
|
136
|
+
// ─── Target: Claude Desktop ───────────────────────────────────────────────────
|
|
137
|
+
async function injectClaudeDesktop(workspaceId, workspaceRoot) {
|
|
138
|
+
const home = node_os.homedir();
|
|
139
|
+
let configPath;
|
|
140
|
+
if (process.platform === 'darwin') {
|
|
141
|
+
configPath = node_path.join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
142
|
+
}
|
|
143
|
+
else if (process.platform === 'win32') {
|
|
144
|
+
configPath = node_path.join(process.env['APPDATA'] ?? '', 'Claude', 'claude_desktop_config.json');
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
configPath = node_path.join(home, '.config', 'Claude', 'claude_desktop_config.json');
|
|
148
|
+
}
|
|
149
|
+
// Skip if Claude Desktop directory doesn't exist (not installed)
|
|
150
|
+
try {
|
|
151
|
+
await node_fs.access(node_path.dirname(configPath));
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
log.debug({ action: 'claude_desktop_skip' }, 'Claude Desktop not installed — skipping');
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const current = await readJsonFile(configPath, {});
|
|
158
|
+
current.mcpServers = wrapAllServers({ intutic: buildIntuticMcpEntry(workspaceRoot), ...(current.mcpServers ?? {}) }, workspaceId, workspaceRoot);
|
|
159
|
+
await writeJsonFile(configPath, current);
|
|
160
|
+
log.info({ action: 'claude_desktop_mcp_injected' }, 'Claude Desktop config updated');
|
|
161
|
+
}
|
|
162
|
+
// ─── Target: Cursor (global + project) ───────────────────────────────────────
|
|
163
|
+
async function injectCursor(workspaceId, workspaceRoot) {
|
|
164
|
+
const home = node_os.homedir();
|
|
165
|
+
// Global settings
|
|
166
|
+
let globalPath;
|
|
167
|
+
if (process.platform === 'darwin') {
|
|
168
|
+
globalPath = node_path.join(home, 'Library', 'Application Support', 'Cursor', 'User', 'globalSettings.json');
|
|
169
|
+
}
|
|
170
|
+
else if (process.platform === 'win32') {
|
|
171
|
+
globalPath = node_path.join(process.env['APPDATA'] ?? '', 'Cursor', 'User', 'globalSettings.json');
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
globalPath = node_path.join(home, '.config', 'Cursor', 'User', 'globalSettings.json');
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
await node_fs.access(node_path.dirname(globalPath));
|
|
178
|
+
const current = await readJsonFile(globalPath, {});
|
|
179
|
+
current.mcpServers = wrapAllServers({ intutic: buildIntuticMcpEntry(workspaceRoot), ...(current.mcpServers ?? {}) }, workspaceId, workspaceRoot);
|
|
180
|
+
await writeJsonFile(globalPath, current);
|
|
181
|
+
log.info({ action: 'cursor_global_mcp_injected' }, 'Cursor globalSettings.json updated');
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
log.debug({ action: 'cursor_global_skip' }, 'Cursor not installed — skipping global settings');
|
|
185
|
+
}
|
|
186
|
+
// Project-level .cursor/mcp.json
|
|
187
|
+
const projectPath = node_path.join(workspaceRoot, '.cursor', 'mcp.json');
|
|
188
|
+
try {
|
|
189
|
+
const current = await readJsonFile(projectPath, {});
|
|
190
|
+
current.mcpServers = wrapAllServers({ intutic: buildIntuticMcpEntry(workspaceRoot), ...(current.mcpServers ?? {}) }, workspaceId, workspaceRoot);
|
|
191
|
+
await writeJsonFile(projectPath, current);
|
|
192
|
+
log.info({ action: 'cursor_project_mcp_injected' }, 'Cursor .cursor/mcp.json updated');
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
log.warn({ action: 'cursor_project_mcp_failed', err: err.message }, 'Could not update .cursor/mcp.json');
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// ─── Target: Cline ────────────────────────────────────────────────────────────
|
|
199
|
+
async function injectCline(workspaceId, workspaceRoot) {
|
|
200
|
+
const configPath = node_path.join(workspaceRoot, '.cline', 'mcp.json');
|
|
201
|
+
try {
|
|
202
|
+
const current = await readJsonFile(configPath, {});
|
|
203
|
+
current.mcpServers = wrapAllServers({ intutic: buildIntuticMcpEntry(workspaceRoot), ...(current.mcpServers ?? {}) }, workspaceId, workspaceRoot);
|
|
204
|
+
await writeJsonFile(configPath, current);
|
|
205
|
+
log.info({ action: 'cline_mcp_injected' }, 'Cline .cline/mcp.json updated');
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
log.debug({ action: 'cline_mcp_skip', err: err.message }, 'Cline config not found — skipping');
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// ─── Target: Windsurf ─────────────────────────────────────────────────────────
|
|
212
|
+
async function injectWindsurf(workspaceId, workspaceRoot) {
|
|
213
|
+
const home = node_os.homedir();
|
|
214
|
+
const configPath = node_path.join(home, '.codeium', 'windsurf', 'mcp_config.json');
|
|
215
|
+
try {
|
|
216
|
+
await node_fs.access(node_path.dirname(configPath));
|
|
217
|
+
const current = await readJsonFile(configPath, {});
|
|
218
|
+
current.mcpServers = wrapAllServers({ intutic: buildIntuticMcpEntry(workspaceRoot), ...(current.mcpServers ?? {}) }, workspaceId, workspaceRoot);
|
|
219
|
+
await writeJsonFile(configPath, current);
|
|
220
|
+
log.info({ action: 'windsurf_mcp_injected' }, 'Windsurf mcp_config.json updated');
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
log.debug({ action: 'windsurf_skip' }, 'Windsurf not installed — skipping');
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async function injectContinue(workspaceId, workspaceRoot) {
|
|
227
|
+
const home = node_os.homedir();
|
|
228
|
+
const configPath = node_path.join(home, '.continue', 'config.json');
|
|
229
|
+
try {
|
|
230
|
+
await node_fs.access(node_path.dirname(configPath));
|
|
231
|
+
const current = await readJsonFile(configPath, {});
|
|
232
|
+
// Continue uses an array format for mcpServers
|
|
233
|
+
if (!Array.isArray(current.mcpServers)) {
|
|
234
|
+
current.mcpServers = [];
|
|
235
|
+
}
|
|
236
|
+
// Remove any existing intutic entry and add the wrapped one
|
|
237
|
+
current.mcpServers = current.mcpServers.filter((s) => s.name !== 'intutic');
|
|
238
|
+
// Wrap existing non-intutic servers
|
|
239
|
+
current.mcpServers = current.mcpServers.map((s) => {
|
|
240
|
+
if (s.__intutic_wrapped)
|
|
241
|
+
return s;
|
|
242
|
+
return {
|
|
243
|
+
name: s.name,
|
|
244
|
+
command: 'node',
|
|
245
|
+
args: [
|
|
246
|
+
resolveProxyBin(workspaceRoot),
|
|
247
|
+
'--workspace-id', workspaceId,
|
|
248
|
+
'--',
|
|
249
|
+
s.command,
|
|
250
|
+
...(s.args ?? []),
|
|
251
|
+
],
|
|
252
|
+
env: { ...(s.env ?? {}), INTUTIC_WORKSPACE_ID: workspaceId },
|
|
253
|
+
__intutic_wrapped: true,
|
|
254
|
+
};
|
|
255
|
+
});
|
|
256
|
+
// Add Intutic MCP server
|
|
257
|
+
const entry = buildIntuticMcpEntry(workspaceRoot);
|
|
258
|
+
current.mcpServers.unshift({ name: 'intutic', ...entry });
|
|
259
|
+
await writeJsonFile(configPath, current);
|
|
260
|
+
log.info({ action: 'continue_mcp_injected' }, 'Continue ~/.continue/config.json updated');
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
log.debug({ action: 'continue_skip' }, 'Continue not installed — skipping');
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// ─── Target: Goose ────────────────────────────────────────────────────────────
|
|
267
|
+
async function injectGoose(workspaceId, workspaceRoot) {
|
|
268
|
+
const home = node_os.homedir();
|
|
269
|
+
const configPath = node_path.join(home, '.config', 'goose', 'config.yaml');
|
|
270
|
+
try {
|
|
271
|
+
await node_fs.access(node_path.dirname(configPath));
|
|
272
|
+
let yaml = '';
|
|
273
|
+
try {
|
|
274
|
+
yaml = await node_fs.readFile(configPath, 'utf-8');
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
yaml = '';
|
|
278
|
+
}
|
|
279
|
+
// Inject MCP server block if not present (simple string injection — avoids yaml dep)
|
|
280
|
+
const proxyBin = resolveProxyBin(workspaceRoot);
|
|
281
|
+
const intuticBlock = [
|
|
282
|
+
'mcp:',
|
|
283
|
+
' intutic:',
|
|
284
|
+
` command: node`,
|
|
285
|
+
` args: [${JSON.stringify(proxyBin)}, "--workspace-id", ${JSON.stringify(workspaceId)}]`,
|
|
286
|
+
].join('\n');
|
|
287
|
+
if (!yaml.includes('intutic:')) {
|
|
288
|
+
yaml = yaml.trimEnd() + '\n\n' + intuticBlock + '\n';
|
|
289
|
+
}
|
|
290
|
+
await node_fs.mkdir(node_path.dirname(configPath), { recursive: true });
|
|
291
|
+
await node_fs.writeFile(configPath, yaml, 'utf-8');
|
|
292
|
+
log.info({ action: 'goose_mcp_injected' }, 'Goose config.yaml updated');
|
|
293
|
+
}
|
|
294
|
+
catch {
|
|
295
|
+
log.debug({ action: 'goose_skip' }, 'Goose not installed — skipping');
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// ─── Target: OpenHands ────────────────────────────────────────────────────────
|
|
299
|
+
async function injectOpenHands(workspaceId, workspaceRoot) {
|
|
300
|
+
const configPath = node_path.join(workspaceRoot, '.openhands', 'mcp.json');
|
|
301
|
+
try {
|
|
302
|
+
const current = await readJsonFile(configPath, {});
|
|
303
|
+
current.mcpServers = wrapAllServers({ intutic: buildIntuticMcpEntry(workspaceRoot), ...(current.mcpServers ?? {}) }, workspaceId, workspaceRoot);
|
|
304
|
+
await writeJsonFile(configPath, current);
|
|
305
|
+
log.info({ action: 'openhands_mcp_injected' }, 'OpenHands .openhands/mcp.json updated');
|
|
306
|
+
}
|
|
307
|
+
catch (err) {
|
|
308
|
+
log.debug({ action: 'openhands_mcp_skip', err: err.message }, 'OpenHands config not found — skipping');
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
312
|
+
/**
|
|
313
|
+
* Injects and proxy-wraps the Intutic MCP server configuration into all supported harnesses.
|
|
314
|
+
*
|
|
315
|
+
* Non-fatal: a failure in one harness does not prevent other harnesses from being updated.
|
|
316
|
+
*
|
|
317
|
+
* @param workspaceId - The workspace ID for policy lookups and event attribution.
|
|
318
|
+
* @param workspaceRoot - Absolute path to the project workspace root.
|
|
319
|
+
*/
|
|
320
|
+
export async function injectMcpServer(workspaceRoot, workspaceId = 'unknown') {
|
|
321
|
+
log.info({ action: 'mcp_inject_start', workspaceRoot, workspaceId }, 'Starting MCP server injection');
|
|
322
|
+
await Promise.allSettled([
|
|
323
|
+
injectClaudeCode(workspaceId, workspaceRoot).catch((err) => log.error({ err: err.message, target: 'claude-code' }, 'MCP injection failed')),
|
|
324
|
+
injectClaudeDesktop(workspaceId, workspaceRoot).catch((err) => log.error({ err: err.message, target: 'claude-desktop' }, 'MCP injection failed')),
|
|
325
|
+
injectCursor(workspaceId, workspaceRoot).catch((err) => log.error({ err: err.message, target: 'cursor' }, 'MCP injection failed')),
|
|
326
|
+
injectCline(workspaceId, workspaceRoot).catch((err) => log.error({ err: err.message, target: 'cline' }, 'MCP injection failed')),
|
|
327
|
+
injectWindsurf(workspaceId, workspaceRoot).catch((err) => log.error({ err: err.message, target: 'windsurf' }, 'MCP injection failed')),
|
|
328
|
+
injectContinue(workspaceId, workspaceRoot).catch((err) => log.error({ err: err.message, target: 'continue' }, 'MCP injection failed')),
|
|
329
|
+
injectGoose(workspaceId, workspaceRoot).catch((err) => log.error({ err: err.message, target: 'goose' }, 'MCP injection failed')),
|
|
330
|
+
injectOpenHands(workspaceId, workspaceRoot).catch((err) => log.error({ err: err.message, target: 'openhands' }, 'MCP injection failed')),
|
|
331
|
+
]);
|
|
332
|
+
log.info({ action: 'mcp_inject_complete', workspaceRoot }, 'MCP server injection complete');
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=mcpAutoWrite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpAutoWrite.js","sourceRoot":"","sources":["../../src/harness/mcpAutoWrite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* n8nHooks.ts — n8n governance workflow generator.
|
|
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
|
|
9
|
+
*
|
|
10
|
+
* LLD #14 — Phase 3 cross-harness defence (Gap 3, WS-B)
|
|
11
|
+
* HLD §3.14 — Three-Tier Defense Cascade (Tier 1 Native Gating)
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Write the n8n governance workflow and installation env snippet.
|
|
17
|
+
*
|
|
18
|
+
* 1. Writes `~/.intutic/n8n/governance-workflow.json` — importable n8n 1.x workflow.
|
|
19
|
+
* 2. Writes `.intutic/env/n8n.env` with webhook URL and import instructions.
|
|
20
|
+
*
|
|
21
|
+
* Safe to call repeatedly — uses atomic rename (`.intutic-tmp` → final path).
|
|
22
|
+
*
|
|
23
|
+
* @param workspaceRoot - Absolute workspace root path.
|
|
24
|
+
* @param proxyUrl - Intutic control plane URL for the HTTP Request node.
|
|
25
|
+
* @param workspaceId - Workspace ID embedded in workflow metadata and HTTP headers.
|
|
26
|
+
*/
|
|
27
|
+
export declare function writeN8nHooks(workspaceRoot: string, proxyUrl: string, workspaceId?: string): Promise<void>;
|
|
28
|
+
//# sourceMappingURL=n8nHooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"n8nHooks.d.ts","sourceRoot":"","sources":["../../src/harness/n8nHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA8JH;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CACjC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CA4Cf"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* n8nHooks.ts — n8n governance workflow generator.
|
|
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
|
|
9
|
+
*
|
|
10
|
+
* LLD #14 — Phase 3 cross-harness defence (Gap 3, WS-B)
|
|
11
|
+
* HLD §3.14 — Three-Tier Defense Cascade (Tier 1 Native Gating)
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from 'node:fs/promises';
|
|
16
|
+
import * as path from 'node:path';
|
|
17
|
+
import * as os from 'node:os';
|
|
18
|
+
import { createLogger } from '@intutic/logger';
|
|
19
|
+
import { newIso } from '@intutic/id';
|
|
20
|
+
const log = createLogger('sync-n8n-hooks');
|
|
21
|
+
/** Default n8n governance workflow directory. */
|
|
22
|
+
const N8N_DIR = path.join(os.homedir(), '.intutic', 'n8n');
|
|
23
|
+
// ─── Static node UUIDs (hardcoded for workflow stability) ─────────────────────
|
|
24
|
+
const NODE_ID_WEBHOOK = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';
|
|
25
|
+
const NODE_ID_IF = 'b2c3d4e5-f6a7-8901-bcde-f12345678901';
|
|
26
|
+
const NODE_ID_HTTP = 'c3d4e5f6-a7b8-9012-cdef-123456789012';
|
|
27
|
+
const NODE_ID_NO_OP = 'd4e5f6a7-b8c9-0123-defa-234567890123';
|
|
28
|
+
const WORKFLOW_ID = 'e5f6a7b8-c9d0-1234-efab-345678901234';
|
|
29
|
+
// ─── n8n workflow JSON builder ────────────────────────────────────────────────
|
|
30
|
+
function buildN8nWorkflow(proxyUrl, workspaceId) {
|
|
31
|
+
return {
|
|
32
|
+
id: WORKFLOW_ID,
|
|
33
|
+
name: 'Intutic Governance — Hook Events',
|
|
34
|
+
active: true,
|
|
35
|
+
meta: {
|
|
36
|
+
instanceId: 'intutic-sync-daemon',
|
|
37
|
+
templateCredsSetupCompleted: true,
|
|
38
|
+
},
|
|
39
|
+
tags: [{ name: 'intutic' }, { name: 'governance' }],
|
|
40
|
+
// n8n 1.x settings block
|
|
41
|
+
settings: {
|
|
42
|
+
executionOrder: 'v1',
|
|
43
|
+
saveManualExecutions: false,
|
|
44
|
+
callerPolicy: 'workflowsFromSameOwner',
|
|
45
|
+
errorWorkflow: '',
|
|
46
|
+
},
|
|
47
|
+
// Static credential placeholders (user fills in API key via n8n UI)
|
|
48
|
+
staticData: null,
|
|
49
|
+
nodes: [
|
|
50
|
+
// ── Webhook trigger ──────────────────────────────────────────────────
|
|
51
|
+
{
|
|
52
|
+
id: NODE_ID_WEBHOOK,
|
|
53
|
+
name: 'Intutic Webhook',
|
|
54
|
+
type: 'n8n-nodes-base.webhook',
|
|
55
|
+
typeVersion: 1,
|
|
56
|
+
position: [240, 300],
|
|
57
|
+
parameters: {
|
|
58
|
+
httpMethod: 'POST',
|
|
59
|
+
path: 'intutic-governance',
|
|
60
|
+
responseMode: 'onReceived',
|
|
61
|
+
responseData: 'allEntries',
|
|
62
|
+
options: {},
|
|
63
|
+
},
|
|
64
|
+
webhookId: 'intutic-governance',
|
|
65
|
+
},
|
|
66
|
+
// ── IF — filter tool_blocked events ──────────────────────────────────
|
|
67
|
+
{
|
|
68
|
+
id: NODE_ID_IF,
|
|
69
|
+
name: 'Is Blocked?',
|
|
70
|
+
type: 'n8n-nodes-base.if',
|
|
71
|
+
typeVersion: 1,
|
|
72
|
+
position: [480, 300],
|
|
73
|
+
parameters: {
|
|
74
|
+
conditions: {
|
|
75
|
+
string: [
|
|
76
|
+
{
|
|
77
|
+
value1: '={{ $json.body.event }}',
|
|
78
|
+
operation: 'equal',
|
|
79
|
+
value2: 'tool_blocked',
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
// ── HTTP Request — forward to Intutic control plane ───────────────────
|
|
86
|
+
{
|
|
87
|
+
id: NODE_ID_HTTP,
|
|
88
|
+
name: 'Forward to Intutic',
|
|
89
|
+
type: 'n8n-nodes-base.httpRequest',
|
|
90
|
+
typeVersion: 3,
|
|
91
|
+
position: [720, 200],
|
|
92
|
+
parameters: {
|
|
93
|
+
method: 'POST',
|
|
94
|
+
url: `${proxyUrl}/api/v1/hook-events`,
|
|
95
|
+
sendHeaders: true,
|
|
96
|
+
headerParameters: {
|
|
97
|
+
parameters: [
|
|
98
|
+
{
|
|
99
|
+
name: 'Content-Type',
|
|
100
|
+
value: 'application/json',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'Authorization',
|
|
104
|
+
// Users should replace this with their API key via n8n Credentials
|
|
105
|
+
value: 'Bearer {{ $env.INTUTIC_API_KEY }}',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'X-Intutic-Workspace-Id',
|
|
109
|
+
value: workspaceId,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
sendBody: true,
|
|
114
|
+
bodyParameters: {
|
|
115
|
+
parameters: [],
|
|
116
|
+
},
|
|
117
|
+
specifyBody: 'json',
|
|
118
|
+
jsonBody: '={{ JSON.stringify({ events: [$json.body] }) }}',
|
|
119
|
+
options: {
|
|
120
|
+
timeout: 10000,
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
// ── No-op for non-blocked events ──────────────────────────────────────
|
|
125
|
+
{
|
|
126
|
+
id: NODE_ID_NO_OP,
|
|
127
|
+
name: 'Allowed (no-op)',
|
|
128
|
+
type: 'n8n-nodes-base.noOp',
|
|
129
|
+
typeVersion: 1,
|
|
130
|
+
position: [720, 400],
|
|
131
|
+
parameters: {},
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
// n8n 1.x connections format
|
|
135
|
+
connections: {
|
|
136
|
+
'Intutic Webhook': {
|
|
137
|
+
main: [
|
|
138
|
+
[
|
|
139
|
+
{ node: 'Is Blocked?', type: 'main', index: 0 },
|
|
140
|
+
],
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
'Is Blocked?': {
|
|
144
|
+
main: [
|
|
145
|
+
// true branch → forward to control plane
|
|
146
|
+
[{ node: 'Forward to Intutic', type: 'main', index: 0 }],
|
|
147
|
+
// false branch → no-op
|
|
148
|
+
[{ node: 'Allowed (no-op)', type: 'main', index: 0 }],
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
// Workflow metadata
|
|
153
|
+
_intuticMeta: {
|
|
154
|
+
generatedBy: 'intutic-sync-daemon',
|
|
155
|
+
generatedAt: newIso(),
|
|
156
|
+
workspaceId,
|
|
157
|
+
proxyUrl,
|
|
158
|
+
webhookPath: '/webhook/intutic-governance',
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
// ─── Main export ──────────────────────────────────────────────────────────────
|
|
163
|
+
/**
|
|
164
|
+
* Write the n8n governance workflow and installation env snippet.
|
|
165
|
+
*
|
|
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.
|
|
168
|
+
*
|
|
169
|
+
* Safe to call repeatedly — uses atomic rename (`.intutic-tmp` → final path).
|
|
170
|
+
*
|
|
171
|
+
* @param workspaceRoot - Absolute workspace root path.
|
|
172
|
+
* @param proxyUrl - Intutic control plane URL for the HTTP Request node.
|
|
173
|
+
* @param workspaceId - Workspace ID embedded in workflow metadata and HTTP headers.
|
|
174
|
+
*/
|
|
175
|
+
export async function writeN8nHooks(workspaceRoot, proxyUrl, workspaceId = '') {
|
|
176
|
+
// ── 1. Ensure directories ──────────────────────────────────────────────────
|
|
177
|
+
const envDir = path.join(workspaceRoot, '.intutic', 'env');
|
|
178
|
+
await Promise.all([
|
|
179
|
+
fs.mkdir(N8N_DIR, { recursive: true }),
|
|
180
|
+
fs.mkdir(envDir, { recursive: true }),
|
|
181
|
+
]);
|
|
182
|
+
// ── 2. Write governance-workflow.json (atomic) ────────────────────────────
|
|
183
|
+
const workflowPath = path.join(N8N_DIR, 'governance-workflow.json');
|
|
184
|
+
const workflow = buildN8nWorkflow(proxyUrl, workspaceId);
|
|
185
|
+
const tmpWorkflow = workflowPath + '.intutic-tmp';
|
|
186
|
+
await fs.writeFile(tmpWorkflow, JSON.stringify(workflow, null, 2) + '\n', 'utf-8');
|
|
187
|
+
await fs.rename(tmpWorkflow, workflowPath);
|
|
188
|
+
log.info({ action: 'n8n_workflow_written', path: workflowPath }, 'n8n governance workflow written');
|
|
189
|
+
// ── 3. Write .intutic/env/n8n.env (atomic) ────────────────────────────────
|
|
190
|
+
const envContent = [
|
|
191
|
+
`# Intutic n8n governance env — auto-generated ${newIso()}`,
|
|
192
|
+
`# This file is managed by the Intutic sync-daemon. DO NOT EDIT.`,
|
|
193
|
+
`INTUTIC_N8N_WEBHOOK=http://localhost:5678/webhook/intutic-governance`,
|
|
194
|
+
`# Import ~/.intutic/n8n/governance-workflow.json into your n8n instance.`,
|
|
195
|
+
`# In n8n: Settings > Import Workflow > select the file above.`,
|
|
196
|
+
`# Then activate the workflow and set INTUTIC_API_KEY as an n8n credential.`,
|
|
197
|
+
workspaceId ? `INTUTIC_WORKSPACE_ID=${workspaceId}` : '',
|
|
198
|
+
].filter((l) => l !== '').join('\n') + '\n';
|
|
199
|
+
const envFilePath = path.join(envDir, 'n8n.env');
|
|
200
|
+
const tmpEnv = envFilePath + '.intutic-tmp';
|
|
201
|
+
await fs.writeFile(tmpEnv, envContent, 'utf-8');
|
|
202
|
+
await fs.rename(tmpEnv, envFilePath);
|
|
203
|
+
log.info({ action: 'n8n_env_written', path: envFilePath }, 'n8n env snippet written');
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=n8nHooks.js.map
|