@intutic/sync-daemon 2.0.0 → 2.1.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/dist/agentReporter.d.ts +4 -12
- package/dist/agentReporter.d.ts.map +1 -1
- package/dist/agentReporter.js +25 -4
- package/dist/agentReporter.js.map +1 -1
- package/dist/configWriter.d.ts.map +1 -1
- package/dist/configWriter.js +20 -6
- package/dist/configWriter.js.map +1 -1
- package/dist/harness/aiderConfigMerger.d.ts +41 -5
- package/dist/harness/aiderConfigMerger.d.ts.map +1 -1
- package/dist/harness/aiderConfigMerger.js +110 -86
- package/dist/harness/aiderConfigMerger.js.map +1 -1
- package/dist/harness/antigravityHooks.d.ts +13 -8
- package/dist/harness/antigravityHooks.d.ts.map +1 -1
- package/dist/harness/antigravityHooks.js +51 -39
- package/dist/harness/antigravityHooks.js.map +1 -1
- package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
- package/dist/harness/claudeCodeHooks.js +42 -28
- package/dist/harness/claudeCodeHooks.js.map +1 -1
- package/dist/harness/clineHooks.d.ts +39 -9
- package/dist/harness/clineHooks.d.ts.map +1 -1
- package/dist/harness/clineHooks.js +139 -60
- package/dist/harness/clineHooks.js.map +1 -1
- package/dist/harness/codexConfigMerger.d.ts +38 -0
- package/dist/harness/codexConfigMerger.d.ts.map +1 -0
- package/dist/harness/codexConfigMerger.js +101 -0
- package/dist/harness/codexConfigMerger.js.map +1 -0
- package/dist/harness/codexHooks.d.ts +4 -2
- package/dist/harness/codexHooks.d.ts.map +1 -1
- package/dist/harness/codexHooks.js +11 -11
- package/dist/harness/codexHooks.js.map +1 -1
- package/dist/harness/continueConfigMerger.d.ts +46 -0
- package/dist/harness/continueConfigMerger.d.ts.map +1 -0
- package/dist/harness/continueConfigMerger.js +90 -0
- package/dist/harness/continueConfigMerger.js.map +1 -0
- package/dist/harness/continueHooks.d.ts +15 -25
- package/dist/harness/continueHooks.d.ts.map +1 -1
- package/dist/harness/continueHooks.js +22 -119
- package/dist/harness/continueHooks.js.map +1 -1
- package/dist/harness/cursorHooks.d.ts +33 -16
- package/dist/harness/cursorHooks.d.ts.map +1 -1
- package/dist/harness/cursorHooks.js +66 -25
- package/dist/harness/cursorHooks.js.map +1 -1
- package/dist/harness/dshHooks.d.ts +59 -52
- package/dist/harness/dshHooks.d.ts.map +1 -1
- package/dist/harness/dshHooks.js +145 -147
- package/dist/harness/dshHooks.js.map +1 -1
- package/dist/harness/gateKind.d.ts.map +1 -1
- package/dist/harness/gateKind.js +1 -0
- package/dist/harness/gateKind.js.map +1 -1
- package/dist/harness/githubCopilotHooks.js +1 -1
- package/dist/harness/grokHooks.d.ts.map +1 -1
- package/dist/harness/grokHooks.js +7 -2
- package/dist/harness/grokHooks.js.map +1 -1
- package/dist/harness/hermesHooks.d.ts +9 -0
- package/dist/harness/hermesHooks.d.ts.map +1 -1
- package/dist/harness/hermesHooks.js +32 -31
- package/dist/harness/hermesHooks.js.map +1 -1
- package/dist/harness/jsonMergeTarget.d.ts +23 -0
- package/dist/harness/jsonMergeTarget.d.ts.map +1 -0
- package/dist/harness/jsonMergeTarget.js +50 -0
- package/dist/harness/jsonMergeTarget.js.map +1 -0
- package/dist/harness/mcpAutoWrite.d.ts +28 -6
- package/dist/harness/mcpAutoWrite.d.ts.map +1 -1
- package/dist/harness/mcpAutoWrite.js +258 -32
- package/dist/harness/mcpAutoWrite.js.map +1 -1
- package/dist/harness/n8nHooks.d.ts.map +1 -1
- package/dist/harness/n8nHooks.js +6 -7
- package/dist/harness/n8nHooks.js.map +1 -1
- package/dist/harness/openCodeHooks.d.ts +37 -6
- package/dist/harness/openCodeHooks.d.ts.map +1 -1
- package/dist/harness/openCodeHooks.js +101 -8
- package/dist/harness/openCodeHooks.js.map +1 -1
- package/dist/harness/openWebuiHooks.d.ts.map +1 -1
- package/dist/harness/openWebuiHooks.js +5 -4
- package/dist/harness/openWebuiHooks.js.map +1 -1
- package/dist/harness/openhandsHooks.d.ts +13 -0
- package/dist/harness/openhandsHooks.d.ts.map +1 -1
- package/dist/harness/openhandsHooks.js +70 -0
- package/dist/harness/openhandsHooks.js.map +1 -1
- package/dist/harness/piHooks.d.ts +17 -0
- package/dist/harness/piHooks.d.ts.map +1 -1
- package/dist/harness/piHooks.js +28 -29
- package/dist/harness/piHooks.js.map +1 -1
- package/dist/harness/protectedPaths.d.ts +64 -6
- package/dist/harness/protectedPaths.d.ts.map +1 -1
- package/dist/harness/protectedPaths.js +161 -11
- package/dist/harness/protectedPaths.js.map +1 -1
- package/dist/harness/windsurfHooks.d.ts +3 -1
- package/dist/harness/windsurfHooks.d.ts.map +1 -1
- package/dist/harness/windsurfHooks.js +64 -42
- package/dist/harness/windsurfHooks.js.map +1 -1
- package/dist/harness/windsurfJetBrainsProxy.d.ts +9 -6
- package/dist/harness/windsurfJetBrainsProxy.d.ts.map +1 -1
- package/dist/harness/windsurfJetBrainsProxy.js +17 -6
- package/dist/harness/windsurfJetBrainsProxy.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/policySnapshot.d.ts +19 -0
- package/dist/lib/policySnapshot.d.ts.map +1 -1
- package/dist/lib/policySnapshot.js +29 -2
- package/dist/lib/policySnapshot.js.map +1 -1
- package/dist/watcher/settingsGuard.d.ts.map +1 -1
- package/dist/watcher/settingsGuard.js +14 -15
- package/dist/watcher/settingsGuard.js.map +1 -1
- package/package.json +6 -6
package/dist/harness/n8nHooks.js
CHANGED
|
@@ -32,8 +32,6 @@ import { createLogger } from '@intutic/logger';
|
|
|
32
32
|
import { newIso } from '@intutic/id';
|
|
33
33
|
import { emitN8nWorkflowGate } from './gateBody.js';
|
|
34
34
|
const log = createLogger('sync-n8n-hooks');
|
|
35
|
-
/** Default n8n governance workflow directory. */
|
|
36
|
-
const N8N_DIR = path.join(os.homedir(), '.intutic', 'n8n');
|
|
37
35
|
// ─── Static node UUIDs (hardcoded for workflow stability) ─────────────────────
|
|
38
36
|
const NODE_ID_WEBHOOK = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';
|
|
39
37
|
const NODE_ID_IF = 'b2c3d4e5-f6a7-8901-bcde-f12345678901';
|
|
@@ -322,11 +320,12 @@ This workflow is telemetry only; the gate above is what blocks.
|
|
|
322
320
|
export async function writeN8nHooks(workspaceRoot, proxyUrl, workspaceId = '') {
|
|
323
321
|
// ── 1. Ensure directories ──────────────────────────────────────────────────
|
|
324
322
|
const envDir = path.join(workspaceRoot, '.intutic', 'env');
|
|
325
|
-
// homedir() read at call time
|
|
326
|
-
//
|
|
323
|
+
// homedir() read at call time so tests that move HOME before invoking are
|
|
324
|
+
// honoured — the gooseHooks lesson.
|
|
327
325
|
const hooksDir = path.join(os.homedir(), '.intutic', 'hooks');
|
|
326
|
+
const n8nDir = path.join(os.homedir(), '.intutic', 'n8n');
|
|
328
327
|
await Promise.all([
|
|
329
|
-
fs.mkdir(
|
|
328
|
+
fs.mkdir(n8nDir, { recursive: true }),
|
|
330
329
|
fs.mkdir(envDir, { recursive: true }),
|
|
331
330
|
fs.mkdir(hooksDir, { recursive: true }),
|
|
332
331
|
]);
|
|
@@ -337,14 +336,14 @@ export async function writeN8nHooks(workspaceRoot, proxyUrl, workspaceId = '') {
|
|
|
337
336
|
await fs.rename(tmpHook, hookPath);
|
|
338
337
|
log.info({ action: 'n8n_governance_hook_written', path: hookPath }, 'n8n workflow-level gate written (requires EXTERNAL_HOOK_FILES — see INSTALL.md)');
|
|
339
338
|
// ── 2. Write governance-workflow.json (atomic) ────────────────────────────
|
|
340
|
-
const workflowPath = path.join(
|
|
339
|
+
const workflowPath = path.join(n8nDir, 'governance-workflow.json');
|
|
341
340
|
const workflow = buildN8nWorkflow(proxyUrl, workspaceId);
|
|
342
341
|
const tmpWorkflow = workflowPath + '.intutic-tmp';
|
|
343
342
|
await fs.writeFile(tmpWorkflow, JSON.stringify(workflow, null, 2) + '\n', 'utf-8');
|
|
344
343
|
await fs.rename(tmpWorkflow, workflowPath);
|
|
345
344
|
log.info({ action: 'n8n_workflow_written', path: workflowPath }, 'n8n governance workflow written');
|
|
346
345
|
// ── 2b. Write INSTALL.md (atomic) ─────────────────────────────────────────
|
|
347
|
-
const installPath = path.join(
|
|
346
|
+
const installPath = path.join(n8nDir, 'INSTALL.md');
|
|
348
347
|
const tmpInstall = installPath + '.intutic-tmp';
|
|
349
348
|
await fs.writeFile(tmpInstall, buildInstallMd(hookPath, workflowPath), 'utf-8');
|
|
350
349
|
await fs.rename(tmpInstall, installPath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"n8nHooks.js","sourceRoot":"","sources":["../../src/harness/n8nHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAEnD,MAAM,GAAG,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"n8nHooks.js","sourceRoot":"","sources":["../../src/harness/n8nHooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -53,12 +53,24 @@
|
|
|
53
53
|
*
|
|
54
54
|
* ## What is not written
|
|
55
55
|
*
|
|
56
|
-
* `opencode.json`
|
|
57
|
-
* options.baseURL` field there (or `OPENCODE_CONFIG_CONTENT`),
|
|
58
|
-
* `permission` deny map cannot express argument rules — both
|
|
59
|
-
* for the user, not generated.
|
|
60
|
-
*
|
|
61
|
-
*
|
|
56
|
+
* This writer leaves `opencode.json` alone: the model base URL is a
|
|
57
|
+
* `provider.<id>.options.baseURL` field there (or `OPENCODE_CONFIG_CONTENT`),
|
|
58
|
+
* and the static `permission` deny map cannot express argument rules — both
|
|
59
|
+
* are documented for the user, not generated. The file's `mcp` block is
|
|
60
|
+
* proxy-wrapped by `mcpAutoWrite.ts` (`injectOpenCode`, TD-487), which edits
|
|
61
|
+
* that block and nothing else.
|
|
62
|
+
*
|
|
63
|
+
* ## MCP tool ids
|
|
64
|
+
*
|
|
65
|
+
* OpenCode names an MCP tool `<server>_<tool>` (`mcp/catalog.ts`: both halves
|
|
66
|
+
* passed through `sanitize`, which turns anything outside `[A-Za-z0-9_-]`
|
|
67
|
+
* into `_`), where the gate's per-server allowlist expects
|
|
68
|
+
* `mcp__<server>__<tool>`. The underscore is ambiguous — `my_db_query` could
|
|
69
|
+
* be server `my`, tool `db_query` or server `my_db`, tool `query` — so the
|
|
70
|
+
* plugin reads the server names from the OpenCode config files on each call
|
|
71
|
+
* and composes the id against the LONGEST sanitized name that prefixes it
|
|
72
|
+
* (`OPENCODE_MCP_ID_JS`). A tool that matches no configured server — every
|
|
73
|
+
* built-in — passes through unchanged.
|
|
62
74
|
*
|
|
63
75
|
* @module
|
|
64
76
|
*/
|
|
@@ -68,6 +80,25 @@ export declare const OPENCODE_PLUGIN_DIR: string;
|
|
|
68
80
|
export declare const OPENCODE_PLUGIN_FILE = "intutic-governance.js";
|
|
69
81
|
/** The 2.x layout: `<name>/index.js`. Same bytes as the flat file. */
|
|
70
82
|
export declare const OPENCODE_PLUGIN_V2_FILE: string;
|
|
83
|
+
/**
|
|
84
|
+
* The JavaScript embedded in the plugin that composes OpenCode's MCP tool id
|
|
85
|
+
* into `mcp__<server>__<tool>` (see the module doc). A string rather than a
|
|
86
|
+
* TypeScript function so the plugin and the unit test run the same text —
|
|
87
|
+
* tests evaluate it directly.
|
|
88
|
+
*
|
|
89
|
+
* `intuticOpenCodeMcpId(tool, names)` is pure: `names` are the configured
|
|
90
|
+
* server names (the keys of OpenCode's `mcp` blocks). The composed id carries
|
|
91
|
+
* the configured name, which is what the workspace allowlist lists.
|
|
92
|
+
*
|
|
93
|
+
* `intuticOpenCodeMcpServerNames(dirs)` reads those names from the files
|
|
94
|
+
* OpenCode itself loads them from: the global config dir
|
|
95
|
+
* (`$XDG_CONFIG_HOME|~/.config` + `/opencode`), `$OPENCODE_CONFIG_DIR`,
|
|
96
|
+
* `$OPENCODE_CONFIG`, `opencode.json{,c}` and `.opencode/opencode.json{,c}`
|
|
97
|
+
* in each of `dirs`, and `$OPENCODE_CONFIG_CONTENT`. JSONC is accepted
|
|
98
|
+
* (comments and trailing commas stripped outside strings); an unreadable file
|
|
99
|
+
* contributes nothing. Read per call, so a server added mid-session is seen.
|
|
100
|
+
*/
|
|
101
|
+
export declare const OPENCODE_MCP_ID_JS = "\nfunction intuticOpenCodeSanitize(v) { return String(v).replace(/[^a-zA-Z0-9_-]/g, '_'); }\nfunction intuticOpenCodeMcpId(tool, names) {\n tool = String(tool);\n if (tool.indexOf('mcp__') === 0) return tool;\n var best = null, bestLen = -1;\n for (var i = 0; i < names.length; i++) {\n var s = intuticOpenCodeSanitize(names[i]);\n if (s.length > bestLen && tool.length > s.length + 1 && tool.slice(0, s.length + 1) === s + '_') {\n best = names[i]; bestLen = s.length;\n }\n }\n return best === null ? tool : 'mcp__' + best + '__' + tool.slice(bestLen + 1);\n}\nfunction intuticParseJsonc(text) {\n var out = '', i = 0, n = text.length;\n while (i < n) {\n var c = text[i];\n if (c === '\"') {\n var j = i + 1;\n while (j < n && text[j] !== '\"') j += text[j] === '\\\\' ? 2 : 1;\n out += text.slice(i, j + 1); i = j + 1;\n } else if (c === '/' && text[i + 1] === '/') {\n while (i < n && text[i] !== '\\n') i++;\n } else if (c === '/' && text[i + 1] === '*') {\n var end = text.indexOf('*/', i + 2); i = end < 0 ? n : end + 2;\n } else { out += c; i++; }\n }\n return JSON.parse(out.replace(/,(\\s*[}\\]])/g, '$1'));\n}\nfunction intuticOpenCodeMcpServerNames(dirs) {\n var names = [];\n function add(text) {\n try {\n var cfg = intuticParseJsonc(text);\n if (cfg && cfg.mcp && typeof cfg.mcp === 'object') {\n for (var k in cfg.mcp) if (names.indexOf(k) < 0) names.push(k);\n }\n } catch (e) {}\n }\n function addFile(p) { try { add(fs.readFileSync(p, 'utf-8')); } catch (e) {} }\n var configDirs = [path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'opencode')];\n if (process.env.OPENCODE_CONFIG_DIR) configDirs.push(process.env.OPENCODE_CONFIG_DIR);\n for (var d = 0; d < dirs.length; d++) { configDirs.push(dirs[d]); configDirs.push(path.join(dirs[d], '.opencode')); }\n for (var c = 0; c < configDirs.length; c++) {\n addFile(path.join(configDirs[c], 'opencode.json'));\n addFile(path.join(configDirs[c], 'opencode.jsonc'));\n }\n if (process.env.OPENCODE_CONFIG) addFile(process.env.OPENCODE_CONFIG);\n if (process.env.OPENCODE_CONFIG_CONTENT) add(process.env.OPENCODE_CONFIG_CONTENT);\n return names;\n}\n";
|
|
71
102
|
/**
|
|
72
103
|
* The plugin source. ESM, because a 1.x loader does `Object.values(module)`
|
|
73
104
|
* and a CommonJS file would surface every `module.exports` property as a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openCodeHooks.d.ts","sourceRoot":"","sources":["../../src/harness/openCodeHooks.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"openCodeHooks.d.ts","sourceRoot":"","sources":["../../src/harness/openCodeHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2EG;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;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,kBAAkB,itEAoD9B,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAkJtG;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CACtC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CAcf"}
|
|
@@ -53,12 +53,24 @@
|
|
|
53
53
|
*
|
|
54
54
|
* ## What is not written
|
|
55
55
|
*
|
|
56
|
-
* `opencode.json`
|
|
57
|
-
* options.baseURL` field there (or `OPENCODE_CONFIG_CONTENT`),
|
|
58
|
-
* `permission` deny map cannot express argument rules — both
|
|
59
|
-
* for the user, not generated.
|
|
60
|
-
*
|
|
61
|
-
*
|
|
56
|
+
* This writer leaves `opencode.json` alone: the model base URL is a
|
|
57
|
+
* `provider.<id>.options.baseURL` field there (or `OPENCODE_CONFIG_CONTENT`),
|
|
58
|
+
* and the static `permission` deny map cannot express argument rules — both
|
|
59
|
+
* are documented for the user, not generated. The file's `mcp` block is
|
|
60
|
+
* proxy-wrapped by `mcpAutoWrite.ts` (`injectOpenCode`, TD-487), which edits
|
|
61
|
+
* that block and nothing else.
|
|
62
|
+
*
|
|
63
|
+
* ## MCP tool ids
|
|
64
|
+
*
|
|
65
|
+
* OpenCode names an MCP tool `<server>_<tool>` (`mcp/catalog.ts`: both halves
|
|
66
|
+
* passed through `sanitize`, which turns anything outside `[A-Za-z0-9_-]`
|
|
67
|
+
* into `_`), where the gate's per-server allowlist expects
|
|
68
|
+
* `mcp__<server>__<tool>`. The underscore is ambiguous — `my_db_query` could
|
|
69
|
+
* be server `my`, tool `db_query` or server `my_db`, tool `query` — so the
|
|
70
|
+
* plugin reads the server names from the OpenCode config files on each call
|
|
71
|
+
* and composes the id against the LONGEST sanitized name that prefixes it
|
|
72
|
+
* (`OPENCODE_MCP_ID_JS`). A tool that matches no configured server — every
|
|
73
|
+
* built-in — passes through unchanged.
|
|
62
74
|
*
|
|
63
75
|
* @module
|
|
64
76
|
*/
|
|
@@ -74,6 +86,77 @@ export const OPENCODE_PLUGIN_DIR = path.join('.opencode', 'plugins');
|
|
|
74
86
|
export const OPENCODE_PLUGIN_FILE = 'intutic-governance.js';
|
|
75
87
|
/** The 2.x layout: `<name>/index.js`. Same bytes as the flat file. */
|
|
76
88
|
export const OPENCODE_PLUGIN_V2_FILE = path.join('intutic-governance', 'index.js');
|
|
89
|
+
/**
|
|
90
|
+
* The JavaScript embedded in the plugin that composes OpenCode's MCP tool id
|
|
91
|
+
* into `mcp__<server>__<tool>` (see the module doc). A string rather than a
|
|
92
|
+
* TypeScript function so the plugin and the unit test run the same text —
|
|
93
|
+
* tests evaluate it directly.
|
|
94
|
+
*
|
|
95
|
+
* `intuticOpenCodeMcpId(tool, names)` is pure: `names` are the configured
|
|
96
|
+
* server names (the keys of OpenCode's `mcp` blocks). The composed id carries
|
|
97
|
+
* the configured name, which is what the workspace allowlist lists.
|
|
98
|
+
*
|
|
99
|
+
* `intuticOpenCodeMcpServerNames(dirs)` reads those names from the files
|
|
100
|
+
* OpenCode itself loads them from: the global config dir
|
|
101
|
+
* (`$XDG_CONFIG_HOME|~/.config` + `/opencode`), `$OPENCODE_CONFIG_DIR`,
|
|
102
|
+
* `$OPENCODE_CONFIG`, `opencode.json{,c}` and `.opencode/opencode.json{,c}`
|
|
103
|
+
* in each of `dirs`, and `$OPENCODE_CONFIG_CONTENT`. JSONC is accepted
|
|
104
|
+
* (comments and trailing commas stripped outside strings); an unreadable file
|
|
105
|
+
* contributes nothing. Read per call, so a server added mid-session is seen.
|
|
106
|
+
*/
|
|
107
|
+
export const OPENCODE_MCP_ID_JS = `
|
|
108
|
+
function intuticOpenCodeSanitize(v) { return String(v).replace(/[^a-zA-Z0-9_-]/g, '_'); }
|
|
109
|
+
function intuticOpenCodeMcpId(tool, names) {
|
|
110
|
+
tool = String(tool);
|
|
111
|
+
if (tool.indexOf('mcp__') === 0) return tool;
|
|
112
|
+
var best = null, bestLen = -1;
|
|
113
|
+
for (var i = 0; i < names.length; i++) {
|
|
114
|
+
var s = intuticOpenCodeSanitize(names[i]);
|
|
115
|
+
if (s.length > bestLen && tool.length > s.length + 1 && tool.slice(0, s.length + 1) === s + '_') {
|
|
116
|
+
best = names[i]; bestLen = s.length;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return best === null ? tool : 'mcp__' + best + '__' + tool.slice(bestLen + 1);
|
|
120
|
+
}
|
|
121
|
+
function intuticParseJsonc(text) {
|
|
122
|
+
var out = '', i = 0, n = text.length;
|
|
123
|
+
while (i < n) {
|
|
124
|
+
var c = text[i];
|
|
125
|
+
if (c === '"') {
|
|
126
|
+
var j = i + 1;
|
|
127
|
+
while (j < n && text[j] !== '"') j += text[j] === '\\\\' ? 2 : 1;
|
|
128
|
+
out += text.slice(i, j + 1); i = j + 1;
|
|
129
|
+
} else if (c === '/' && text[i + 1] === '/') {
|
|
130
|
+
while (i < n && text[i] !== '\\n') i++;
|
|
131
|
+
} else if (c === '/' && text[i + 1] === '*') {
|
|
132
|
+
var end = text.indexOf('*/', i + 2); i = end < 0 ? n : end + 2;
|
|
133
|
+
} else { out += c; i++; }
|
|
134
|
+
}
|
|
135
|
+
return JSON.parse(out.replace(/,(\\s*[}\\]])/g, '$1'));
|
|
136
|
+
}
|
|
137
|
+
function intuticOpenCodeMcpServerNames(dirs) {
|
|
138
|
+
var names = [];
|
|
139
|
+
function add(text) {
|
|
140
|
+
try {
|
|
141
|
+
var cfg = intuticParseJsonc(text);
|
|
142
|
+
if (cfg && cfg.mcp && typeof cfg.mcp === 'object') {
|
|
143
|
+
for (var k in cfg.mcp) if (names.indexOf(k) < 0) names.push(k);
|
|
144
|
+
}
|
|
145
|
+
} catch (e) {}
|
|
146
|
+
}
|
|
147
|
+
function addFile(p) { try { add(fs.readFileSync(p, 'utf-8')); } catch (e) {} }
|
|
148
|
+
var configDirs = [path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'opencode')];
|
|
149
|
+
if (process.env.OPENCODE_CONFIG_DIR) configDirs.push(process.env.OPENCODE_CONFIG_DIR);
|
|
150
|
+
for (var d = 0; d < dirs.length; d++) { configDirs.push(dirs[d]); configDirs.push(path.join(dirs[d], '.opencode')); }
|
|
151
|
+
for (var c = 0; c < configDirs.length; c++) {
|
|
152
|
+
addFile(path.join(configDirs[c], 'opencode.json'));
|
|
153
|
+
addFile(path.join(configDirs[c], 'opencode.jsonc'));
|
|
154
|
+
}
|
|
155
|
+
if (process.env.OPENCODE_CONFIG) addFile(process.env.OPENCODE_CONFIG);
|
|
156
|
+
if (process.env.OPENCODE_CONFIG_CONTENT) add(process.env.OPENCODE_CONFIG_CONTENT);
|
|
157
|
+
return names;
|
|
158
|
+
}
|
|
159
|
+
`;
|
|
77
160
|
/**
|
|
78
161
|
* The plugin source. ESM, because a 1.x loader does `Object.values(module)`
|
|
79
162
|
* and a CommonJS file would surface every `module.exports` property as a
|
|
@@ -116,6 +199,10 @@ try {
|
|
|
116
199
|
} catch {}
|
|
117
200
|
|
|
118
201
|
${emitJsGate({ harness: 'opencode', contract: 'throw', reviewRequestFile: path.join(workspaceRoot, '.intutic', 'events', REVIEW_REQUESTS_BASENAME) })}
|
|
202
|
+
${OPENCODE_MCP_ID_JS}
|
|
203
|
+
// Directories whose opencode.json may declare MCP servers: the workspace this
|
|
204
|
+
// plugin was written for, and the directory OpenCode reports (1.x input).
|
|
205
|
+
const _intuticConfigDirs = [${JSON.stringify(workspaceRoot)}];
|
|
119
206
|
|
|
120
207
|
let _intuticSessionId = '';
|
|
121
208
|
function logEvent(verdict, toolName, reason) {
|
|
@@ -156,7 +243,10 @@ function logEvent(verdict, toolName, reason) {
|
|
|
156
243
|
*/
|
|
157
244
|
function intuticEvaluate(toolName, args, sessionID) {
|
|
158
245
|
_intuticSessionId = sessionID || '';
|
|
159
|
-
|
|
246
|
+
let tool = String(toolName || 'tool');
|
|
247
|
+
// OpenCode's MCP ids are <server>_<tool>; compose them into the
|
|
248
|
+
// mcp__<server>__<tool> shape the allowlist reads (TD-487).
|
|
249
|
+
if (tool.indexOf('_') > 0) tool = intuticOpenCodeMcpId(tool, intuticOpenCodeMcpServerNames(_intuticConfigDirs));
|
|
160
250
|
if (!args || typeof args !== 'object' || Array.isArray(args)) {
|
|
161
251
|
const reason = '[Intutic Governance] BLOCKED: tool "' + tool + '" was called with arguments the gate cannot read (' +
|
|
162
252
|
(args === null ? 'null' : typeof args) + '); refusing rather than allowing a call it cannot evaluate.';
|
|
@@ -194,7 +284,10 @@ function intuticAnnounce() {
|
|
|
194
284
|
}
|
|
195
285
|
|
|
196
286
|
// ── 1.x: Plugin = (input) => Promise<Hooks> ───────────────────────────────
|
|
197
|
-
async function intuticServer(
|
|
287
|
+
async function intuticServer(input) {
|
|
288
|
+
if (input && typeof input.directory === 'string' && _intuticConfigDirs.indexOf(input.directory) < 0) {
|
|
289
|
+
_intuticConfigDirs.push(input.directory);
|
|
290
|
+
}
|
|
198
291
|
if (!globalThis.__intuticOpencode) { globalThis.__intuticOpencode = true; intuticAnnounce(); }
|
|
199
292
|
return {
|
|
200
293
|
'tool.execute.before': async (input, output) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openCodeHooks.js","sourceRoot":"","sources":["../../src/harness/openCodeHooks.ts"],"names":[],"mappings":"AAAA
|
|
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;
|
|
1
|
+
{"version":3,"file":"openWebuiHooks.d.ts","sourceRoot":"","sources":["../../src/harness/openWebuiHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AA8JH;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CA8Cf"}
|
|
@@ -22,8 +22,6 @@ import { createLogger } from '@intutic/logger';
|
|
|
22
22
|
import { newIso } from '@intutic/id';
|
|
23
23
|
import { emitPythonGate } from './gateBody.js';
|
|
24
24
|
const log = createLogger('sync-open-webui-hooks');
|
|
25
|
-
/** Default target directory for the Open WebUI governance filter. */
|
|
26
|
-
const OPEN_WEBUI_DIR = path.join(os.homedir(), '.open-webui');
|
|
27
25
|
// ─── Python filter template ───────────────────────────────────────────────────
|
|
28
26
|
function buildOpenWebuiFilter(workspaceId, proxyUrl) {
|
|
29
27
|
return `"""
|
|
@@ -182,12 +180,15 @@ class Filter:
|
|
|
182
180
|
export async function writeOpenWebuiHooks(workspaceRoot, proxyUrl, workspaceId = '') {
|
|
183
181
|
// ── 1. Ensure directories ──────────────────────────────────────────────────
|
|
184
182
|
const envDir = path.join(workspaceRoot, '.intutic', 'env');
|
|
183
|
+
// The filter's target directory; homedir() read at call time so tests that
|
|
184
|
+
// move HOME before invoking are honoured.
|
|
185
|
+
const openWebuiDir = path.join(os.homedir(), '.open-webui');
|
|
185
186
|
await Promise.all([
|
|
186
|
-
fs.mkdir(
|
|
187
|
+
fs.mkdir(openWebuiDir, { recursive: true }),
|
|
187
188
|
fs.mkdir(envDir, { recursive: true }),
|
|
188
189
|
]);
|
|
189
190
|
// ── 2. Write Python filter (atomic) ───────────────────────────────────────
|
|
190
|
-
const filterPath = path.join(
|
|
191
|
+
const filterPath = path.join(openWebuiDir, 'intutic-governance-filter.py');
|
|
191
192
|
const tmpFilter = filterPath + '.intutic-tmp';
|
|
192
193
|
await fs.writeFile(tmpFilter, buildOpenWebuiFilter(workspaceId, proxyUrl), 'utf-8');
|
|
193
194
|
await fs.rename(tmpFilter, filterPath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openWebuiHooks.js","sourceRoot":"","sources":["../../src/harness/openWebuiHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C,MAAM,GAAG,GAAG,YAAY,CAAC,uBAAuB,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"openWebuiHooks.js","sourceRoot":"","sources":["../../src/harness/openWebuiHooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,4 +21,17 @@
|
|
|
21
21
|
* @param workspaceId - Workspace ID embedded in hook event payloads.
|
|
22
22
|
*/
|
|
23
23
|
export declare function writeOpenHandsHooks(workspaceRoot: string, proxyUrl: string, workspaceId?: string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Merge Intutic's keys into an OpenHands `config.toml`:
|
|
26
|
+
* - `[llm] base_url` — the proxy, in the form the configured model's SDK
|
|
27
|
+
* expects (LiteLLM appends `/v1/messages` to an Anthropic base and
|
|
28
|
+
* `/chat/completions` to an OpenAI-style one);
|
|
29
|
+
* - an `[intutic]` table carrying the SOP text, replaced whole each sync.
|
|
30
|
+
*
|
|
31
|
+
* Edited line by line so the user's own settings and comments survive; the
|
|
32
|
+
* result is parsed before it is returned. Earlier versions replaced the whole
|
|
33
|
+
* file, so a file starting with their header holds nothing of the user's and
|
|
34
|
+
* is regenerated. Returns `null` when the existing file is not valid TOML.
|
|
35
|
+
*/
|
|
36
|
+
export declare function mergeOpenHandsToml(raw: string, proxyUrl: string, instructions: string): string | null;
|
|
24
37
|
//# sourceMappingURL=openhandsHooks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openhandsHooks.d.ts","sourceRoot":"","sources":["../../src/harness/openhandsHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"openhandsHooks.d.ts","sourceRoot":"","sources":["../../src/harness/openhandsHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CA+Gf;AAwED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkCrG"}
|
|
@@ -17,6 +17,8 @@ import * as path from 'node:path';
|
|
|
17
17
|
import { createLogger } from '@intutic/logger';
|
|
18
18
|
import { newIso } from '@intutic/id';
|
|
19
19
|
import { emitShellGate, SHELL_EXTRACT, SHELL_FAIL_CLOSED } from './gateBody.js';
|
|
20
|
+
import { parse as parseToml } from 'smol-toml';
|
|
21
|
+
import { anthropicBaseUrl, openaiBaseUrl } from '@intutic/shared-types';
|
|
20
22
|
const log = createLogger('sync-openhands-hooks');
|
|
21
23
|
/**
|
|
22
24
|
* Write .openhands/hooks.json and the pre-tool-check shell script.
|
|
@@ -169,4 +171,72 @@ async function mergeOpenHandsConfig(workspaceRoot, proxyUrl) {
|
|
|
169
171
|
log.info({ action: 'openhands_config_written', path: configPath }, 'OpenHands config.toml updated with proxy base_url');
|
|
170
172
|
}
|
|
171
173
|
}
|
|
174
|
+
// ─── config.toml merge ───────────────────────────────────────────────────────
|
|
175
|
+
/** First line of the file earlier adapter versions wrote over config.toml. */
|
|
176
|
+
const LEGACY_HEADER = '# Intutic Governance Rules (auto-generated)';
|
|
177
|
+
function parsesAsToml(text) {
|
|
178
|
+
try {
|
|
179
|
+
return parseToml(text);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** Index of the line that starts table `name`, or -1. */
|
|
186
|
+
function tableStart(lines, name) {
|
|
187
|
+
return lines.findIndex((l) => l.trim() === `[${name}]`);
|
|
188
|
+
}
|
|
189
|
+
/** Index just past the last line of the table starting at `start`. */
|
|
190
|
+
function tableEnd(lines, start) {
|
|
191
|
+
const next = lines.findIndex((l, i) => i > start && /^\s*\[/.test(l));
|
|
192
|
+
return next === -1 ? lines.length : next;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Merge Intutic's keys into an OpenHands `config.toml`:
|
|
196
|
+
* - `[llm] base_url` — the proxy, in the form the configured model's SDK
|
|
197
|
+
* expects (LiteLLM appends `/v1/messages` to an Anthropic base and
|
|
198
|
+
* `/chat/completions` to an OpenAI-style one);
|
|
199
|
+
* - an `[intutic]` table carrying the SOP text, replaced whole each sync.
|
|
200
|
+
*
|
|
201
|
+
* Edited line by line so the user's own settings and comments survive; the
|
|
202
|
+
* result is parsed before it is returned. Earlier versions replaced the whole
|
|
203
|
+
* file, so a file starting with their header holds nothing of the user's and
|
|
204
|
+
* is regenerated. Returns `null` when the existing file is not valid TOML.
|
|
205
|
+
*/
|
|
206
|
+
export function mergeOpenHandsToml(raw, proxyUrl, instructions) {
|
|
207
|
+
const source = raw.startsWith(LEGACY_HEADER) ? '' : raw;
|
|
208
|
+
const parsed = parsesAsToml(source);
|
|
209
|
+
if (parsed === null)
|
|
210
|
+
return null;
|
|
211
|
+
const llm = (parsed['llm'] ?? {});
|
|
212
|
+
const model = typeof llm['model'] === 'string' ? llm['model'] : '';
|
|
213
|
+
const baseUrl = /^(anthropic\/|claude)/.test(model) ? anthropicBaseUrl(proxyUrl) : openaiBaseUrl(proxyUrl);
|
|
214
|
+
let lines = source.split('\n');
|
|
215
|
+
// Drop the previous [intutic] table; it is rewritten whole below.
|
|
216
|
+
const oldIntutic = tableStart(lines, 'intutic');
|
|
217
|
+
if (oldIntutic !== -1)
|
|
218
|
+
lines.splice(oldIntutic, tableEnd(lines, oldIntutic) - oldIntutic);
|
|
219
|
+
const baseLine = `base_url = ${JSON.stringify(baseUrl)}`;
|
|
220
|
+
const llmStart = tableStart(lines, 'llm');
|
|
221
|
+
if (llmStart === -1) {
|
|
222
|
+
lines.push('', '[llm]', baseLine);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
const end = tableEnd(lines, llmStart);
|
|
226
|
+
const existing = lines.findIndex((l, i) => i > llmStart && i < end && /^\s*base_url\s*=/.test(l));
|
|
227
|
+
if (existing !== -1)
|
|
228
|
+
lines[existing] = baseLine;
|
|
229
|
+
else
|
|
230
|
+
lines.splice(llmStart + 1, 0, baseLine);
|
|
231
|
+
}
|
|
232
|
+
while (lines.length > 0 && lines[lines.length - 1].trim() === '')
|
|
233
|
+
lines.pop();
|
|
234
|
+
const escaped = instructions.replace(/\\/g, '\\\\').replace(/"""/g, '\\"\\"\\"');
|
|
235
|
+
lines = [...lines, '', '[intutic]', `proxy_url = ${JSON.stringify(proxyUrl)}`, `instructions = """\n${escaped}\n"""`, ''];
|
|
236
|
+
const next = (lines[0] === '' ? lines.slice(1) : lines).join('\n');
|
|
237
|
+
const check = parsesAsToml(next);
|
|
238
|
+
if (check === null || check['llm']?.['base_url'] !== baseUrl)
|
|
239
|
+
return null;
|
|
240
|
+
return next;
|
|
241
|
+
}
|
|
172
242
|
//# sourceMappingURL=openhandsHooks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openhandsHooks.js","sourceRoot":"","sources":["../../src/harness/openhandsHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"openhandsHooks.js","sourceRoot":"","sources":["../../src/harness/openhandsHooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,22 @@
|
|
|
17
17
|
*
|
|
18
18
|
* @module
|
|
19
19
|
*/
|
|
20
|
+
interface PiProvider {
|
|
21
|
+
baseUrl?: string;
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
}
|
|
24
|
+
interface PiModelsConfig {
|
|
25
|
+
providers?: Record<string, PiProvider>;
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Merge Pi models.json — point the anthropic and openai providers at the
|
|
30
|
+
* proxy, each with the base URL its SDK expects (the Anthropic SDK appends
|
|
31
|
+
* `/v1/messages`, the OpenAI one `/chat/completions`). Google is left alone:
|
|
32
|
+
* the proxy does not serve the Gemini API, so routing it there would break it.
|
|
33
|
+
* Every other provider and key is kept.
|
|
34
|
+
*/
|
|
35
|
+
export declare function mergePiModels(existing: PiModelsConfig, proxyUrl: string): PiModelsConfig;
|
|
20
36
|
/**
|
|
21
37
|
* Write the Pi governance hook script, merge hooks.json and models.json,
|
|
22
38
|
* and write the env snippet.
|
|
@@ -29,4 +45,5 @@
|
|
|
29
45
|
* @param workspaceId - Workspace ID embedded in every hook event payload.
|
|
30
46
|
*/
|
|
31
47
|
export declare function writePiHooks(workspaceRoot: string, proxyUrl: string, workspaceId?: string): Promise<void>;
|
|
48
|
+
export {};
|
|
32
49
|
//# sourceMappingURL=piHooks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"piHooks.d.ts","sourceRoot":"","sources":["../../src/harness/piHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"piHooks.d.ts","sourceRoot":"","sources":["../../src/harness/piHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAwCH,UAAU,UAAU;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,UAAU,cAAc;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACtC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAyHD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAmBxF;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CA6Ef"}
|
package/dist/harness/piHooks.js
CHANGED
|
@@ -23,6 +23,8 @@ import * as os from 'node:os';
|
|
|
23
23
|
import { createLogger } from '@intutic/logger';
|
|
24
24
|
import { newIso } from '@intutic/id';
|
|
25
25
|
import { emitShellGate, SHELL_EXTRACT, SHELL_FAIL_CLOSED } from './gateBody.js';
|
|
26
|
+
import { readJsonObjectForMerge } from './jsonMergeTarget.js';
|
|
27
|
+
import { anthropicBaseUrl, openaiBaseUrl } from '@intutic/shared-types';
|
|
26
28
|
const log = createLogger('sync-pi-hooks');
|
|
27
29
|
/** Path to the Pi hooks config. */
|
|
28
30
|
const PI_HOOKS_CONFIG = path.join(os.homedir(), '.pi', 'hooks.json');
|
|
@@ -134,18 +136,23 @@ function mergePiHooks(existing, hookScriptPath) {
|
|
|
134
136
|
}
|
|
135
137
|
// ─── Pi models.json merge ─────────────────────────────────────────────────────
|
|
136
138
|
/**
|
|
137
|
-
* Merge Pi models.json —
|
|
138
|
-
*
|
|
139
|
-
*
|
|
139
|
+
* Merge Pi models.json — point the anthropic and openai providers at the
|
|
140
|
+
* proxy, each with the base URL its SDK expects (the Anthropic SDK appends
|
|
141
|
+
* `/v1/messages`, the OpenAI one `/chat/completions`). Google is left alone:
|
|
142
|
+
* the proxy does not serve the Gemini API, so routing it there would break it.
|
|
143
|
+
* Every other provider and key is kept.
|
|
140
144
|
*/
|
|
141
|
-
function mergePiModels(existing, proxyUrl) {
|
|
145
|
+
export function mergePiModels(existing, proxyUrl) {
|
|
142
146
|
const providers = existing.providers ?? {};
|
|
143
|
-
const
|
|
147
|
+
const targets = {
|
|
148
|
+
anthropic: anthropicBaseUrl(proxyUrl),
|
|
149
|
+
openai: openaiBaseUrl(proxyUrl),
|
|
150
|
+
};
|
|
144
151
|
const mergedProviders = { ...providers };
|
|
145
|
-
for (const provider of
|
|
152
|
+
for (const [provider, baseUrl] of Object.entries(targets)) {
|
|
146
153
|
mergedProviders[provider] = {
|
|
147
154
|
...(providers[provider] ?? {}),
|
|
148
|
-
baseUrl
|
|
155
|
+
baseUrl,
|
|
149
156
|
};
|
|
150
157
|
}
|
|
151
158
|
return {
|
|
@@ -185,32 +192,24 @@ export async function writePiHooks(workspaceRoot, proxyUrl, workspaceId = '') {
|
|
|
185
192
|
await fs.chmod(hookScriptPath, 0o755);
|
|
186
193
|
log.info({ action: 'pi_hook_script_written', path: hookScriptPath }, 'Pi hook script written');
|
|
187
194
|
// ── 3. Write/merge ~/.pi/hooks.json ───────────────────────────────────────
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
+
// A file that is not a plain JSON object is left untouched (and reported)
|
|
196
|
+
// rather than replaced with only the Intutic entries.
|
|
197
|
+
const existingHooks = await readJsonObjectForMerge(PI_HOOKS_CONFIG);
|
|
198
|
+
if (existingHooks !== null) {
|
|
199
|
+
const mergedHooks = mergePiHooks(existingHooks, hookScriptPath);
|
|
200
|
+
const tmpHooks = PI_HOOKS_CONFIG + '.intutic-tmp';
|
|
201
|
+
await fs.writeFile(tmpHooks, JSON.stringify(mergedHooks, null, 2) + '\n', 'utf-8');
|
|
202
|
+
await fs.rename(tmpHooks, PI_HOOKS_CONFIG);
|
|
195
203
|
}
|
|
196
|
-
const mergedHooks = mergePiHooks(existingHooks, hookScriptPath);
|
|
197
|
-
const tmpHooks = PI_HOOKS_CONFIG + '.intutic-tmp';
|
|
198
|
-
await fs.writeFile(tmpHooks, JSON.stringify(mergedHooks, null, 2) + '\n', 'utf-8');
|
|
199
|
-
await fs.rename(tmpHooks, PI_HOOKS_CONFIG);
|
|
200
204
|
log.info({ action: 'pi_hooks_written', path: PI_HOOKS_CONFIG }, 'Pi hooks.json written');
|
|
201
205
|
// ── 4. Write/merge ~/.pi/models.json ──────────────────────────────────────
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
// File doesn't exist or is unparseable — start fresh
|
|
206
|
+
const existingModels = await readJsonObjectForMerge(PI_MODELS_CONFIG);
|
|
207
|
+
if (existingModels !== null) {
|
|
208
|
+
const mergedModels = mergePiModels(existingModels, proxyUrl);
|
|
209
|
+
const tmpModels = PI_MODELS_CONFIG + '.intutic-tmp';
|
|
210
|
+
await fs.writeFile(tmpModels, JSON.stringify(mergedModels, null, 2) + '\n', 'utf-8');
|
|
211
|
+
await fs.rename(tmpModels, PI_MODELS_CONFIG);
|
|
209
212
|
}
|
|
210
|
-
const mergedModels = mergePiModels(existingModels, proxyUrl);
|
|
211
|
-
const tmpModels = PI_MODELS_CONFIG + '.intutic-tmp';
|
|
212
|
-
await fs.writeFile(tmpModels, JSON.stringify(mergedModels, null, 2) + '\n', 'utf-8');
|
|
213
|
-
await fs.rename(tmpModels, PI_MODELS_CONFIG);
|
|
214
213
|
log.info({ action: 'pi_models_written', path: PI_MODELS_CONFIG }, 'Pi models.json written');
|
|
215
214
|
// ── 5. Write env snippet ───────────────────────────────────────────────────
|
|
216
215
|
const envSnippet = [
|