@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.
Files changed (107) hide show
  1. package/dist/agentReporter.d.ts +4 -12
  2. package/dist/agentReporter.d.ts.map +1 -1
  3. package/dist/agentReporter.js +25 -4
  4. package/dist/agentReporter.js.map +1 -1
  5. package/dist/configWriter.d.ts.map +1 -1
  6. package/dist/configWriter.js +20 -6
  7. package/dist/configWriter.js.map +1 -1
  8. package/dist/harness/aiderConfigMerger.d.ts +41 -5
  9. package/dist/harness/aiderConfigMerger.d.ts.map +1 -1
  10. package/dist/harness/aiderConfigMerger.js +110 -86
  11. package/dist/harness/aiderConfigMerger.js.map +1 -1
  12. package/dist/harness/antigravityHooks.d.ts +13 -8
  13. package/dist/harness/antigravityHooks.d.ts.map +1 -1
  14. package/dist/harness/antigravityHooks.js +51 -39
  15. package/dist/harness/antigravityHooks.js.map +1 -1
  16. package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
  17. package/dist/harness/claudeCodeHooks.js +42 -28
  18. package/dist/harness/claudeCodeHooks.js.map +1 -1
  19. package/dist/harness/clineHooks.d.ts +39 -9
  20. package/dist/harness/clineHooks.d.ts.map +1 -1
  21. package/dist/harness/clineHooks.js +139 -60
  22. package/dist/harness/clineHooks.js.map +1 -1
  23. package/dist/harness/codexConfigMerger.d.ts +38 -0
  24. package/dist/harness/codexConfigMerger.d.ts.map +1 -0
  25. package/dist/harness/codexConfigMerger.js +101 -0
  26. package/dist/harness/codexConfigMerger.js.map +1 -0
  27. package/dist/harness/codexHooks.d.ts +4 -2
  28. package/dist/harness/codexHooks.d.ts.map +1 -1
  29. package/dist/harness/codexHooks.js +11 -11
  30. package/dist/harness/codexHooks.js.map +1 -1
  31. package/dist/harness/continueConfigMerger.d.ts +46 -0
  32. package/dist/harness/continueConfigMerger.d.ts.map +1 -0
  33. package/dist/harness/continueConfigMerger.js +90 -0
  34. package/dist/harness/continueConfigMerger.js.map +1 -0
  35. package/dist/harness/continueHooks.d.ts +15 -25
  36. package/dist/harness/continueHooks.d.ts.map +1 -1
  37. package/dist/harness/continueHooks.js +22 -119
  38. package/dist/harness/continueHooks.js.map +1 -1
  39. package/dist/harness/cursorHooks.d.ts +33 -16
  40. package/dist/harness/cursorHooks.d.ts.map +1 -1
  41. package/dist/harness/cursorHooks.js +66 -25
  42. package/dist/harness/cursorHooks.js.map +1 -1
  43. package/dist/harness/dshHooks.d.ts +59 -52
  44. package/dist/harness/dshHooks.d.ts.map +1 -1
  45. package/dist/harness/dshHooks.js +145 -147
  46. package/dist/harness/dshHooks.js.map +1 -1
  47. package/dist/harness/gateKind.d.ts.map +1 -1
  48. package/dist/harness/gateKind.js +1 -0
  49. package/dist/harness/gateKind.js.map +1 -1
  50. package/dist/harness/githubCopilotHooks.js +1 -1
  51. package/dist/harness/grokHooks.d.ts.map +1 -1
  52. package/dist/harness/grokHooks.js +7 -2
  53. package/dist/harness/grokHooks.js.map +1 -1
  54. package/dist/harness/hermesHooks.d.ts +9 -0
  55. package/dist/harness/hermesHooks.d.ts.map +1 -1
  56. package/dist/harness/hermesHooks.js +32 -31
  57. package/dist/harness/hermesHooks.js.map +1 -1
  58. package/dist/harness/jsonMergeTarget.d.ts +23 -0
  59. package/dist/harness/jsonMergeTarget.d.ts.map +1 -0
  60. package/dist/harness/jsonMergeTarget.js +50 -0
  61. package/dist/harness/jsonMergeTarget.js.map +1 -0
  62. package/dist/harness/mcpAutoWrite.d.ts +28 -6
  63. package/dist/harness/mcpAutoWrite.d.ts.map +1 -1
  64. package/dist/harness/mcpAutoWrite.js +258 -32
  65. package/dist/harness/mcpAutoWrite.js.map +1 -1
  66. package/dist/harness/n8nHooks.d.ts.map +1 -1
  67. package/dist/harness/n8nHooks.js +6 -7
  68. package/dist/harness/n8nHooks.js.map +1 -1
  69. package/dist/harness/openCodeHooks.d.ts +37 -6
  70. package/dist/harness/openCodeHooks.d.ts.map +1 -1
  71. package/dist/harness/openCodeHooks.js +101 -8
  72. package/dist/harness/openCodeHooks.js.map +1 -1
  73. package/dist/harness/openWebuiHooks.d.ts.map +1 -1
  74. package/dist/harness/openWebuiHooks.js +5 -4
  75. package/dist/harness/openWebuiHooks.js.map +1 -1
  76. package/dist/harness/openhandsHooks.d.ts +13 -0
  77. package/dist/harness/openhandsHooks.d.ts.map +1 -1
  78. package/dist/harness/openhandsHooks.js +70 -0
  79. package/dist/harness/openhandsHooks.js.map +1 -1
  80. package/dist/harness/piHooks.d.ts +17 -0
  81. package/dist/harness/piHooks.d.ts.map +1 -1
  82. package/dist/harness/piHooks.js +28 -29
  83. package/dist/harness/piHooks.js.map +1 -1
  84. package/dist/harness/protectedPaths.d.ts +64 -6
  85. package/dist/harness/protectedPaths.d.ts.map +1 -1
  86. package/dist/harness/protectedPaths.js +161 -11
  87. package/dist/harness/protectedPaths.js.map +1 -1
  88. package/dist/harness/windsurfHooks.d.ts +3 -1
  89. package/dist/harness/windsurfHooks.d.ts.map +1 -1
  90. package/dist/harness/windsurfHooks.js +64 -42
  91. package/dist/harness/windsurfHooks.js.map +1 -1
  92. package/dist/harness/windsurfJetBrainsProxy.d.ts +9 -6
  93. package/dist/harness/windsurfJetBrainsProxy.d.ts.map +1 -1
  94. package/dist/harness/windsurfJetBrainsProxy.js +17 -6
  95. package/dist/harness/windsurfJetBrainsProxy.js.map +1 -1
  96. package/dist/index.d.ts +3 -0
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +3 -0
  99. package/dist/index.js.map +1 -1
  100. package/dist/lib/policySnapshot.d.ts +19 -0
  101. package/dist/lib/policySnapshot.d.ts.map +1 -1
  102. package/dist/lib/policySnapshot.js +29 -2
  103. package/dist/lib/policySnapshot.js.map +1 -1
  104. package/dist/watcher/settingsGuard.d.ts.map +1 -1
  105. package/dist/watcher/settingsGuard.js +14 -15
  106. package/dist/watcher/settingsGuard.js.map +1 -1
  107. package/package.json +6 -6
@@ -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 (unlike the module-scope N8N_DIR) so tests
326
- // that move HOME before invoking are honoured — the gooseHooks lesson.
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(N8N_DIR, { recursive: true }),
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(N8N_DIR, 'governance-workflow.json');
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(N8N_DIR, 'INSTALL.md');
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":"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"}
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` 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).
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
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` 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).
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
- const tool = String(toolName || 'tool');
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(_input) {
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;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,UAAU,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA;AAEpE,MAAM,GAAG,GAAG,YAAY,CAAC,qBAAqB,CAAC,CAAA;AAE/C,kGAAkG;AAClG,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;AACpE,qCAAqC;AACrC,MAAM,CAAC,MAAM,oBAAoB,GAAG,uBAAuB,CAAA;AAC3D,sEAAsE;AACtE,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAC,CAAA;AAElF;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,aAAqB,EAAE,WAAmB;IAC5F,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAA;IACzF,OAAO;;;YAGG,QAAQ;gBACJ,MAAM,EAAE;;;;;;;;;;;;;;;;;gFAiBwD,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;;;;;;;;;;;EAWzG,UAAU,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,wBAAwB,CAAC,EAAE,CAAC;;;;;;;;;;;;;;;;sBAgB/H,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFlD,CAAA;AACD,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,aAAqB,EACrB,QAAgB,EAChB,WAAW,GAAG,EAAE;IAEhB,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACnF,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAAA;IAC/D,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE9C,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,CAAC,CAAA;IACtE,KAAK,MAAM,GAAG,IAAI,CAAC,oBAAoB,EAAE,uBAAuB,CAAC,EAAE,CAAC;QAClE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;QAC5C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC7D,MAAM,GAAG,GAAG,UAAU,GAAG,cAAc,CAAA;QACvC,MAAM,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;QACxC,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;QAChC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,yBAAyB,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,oCAAoC,CAAC,CAAA;IACzG,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"openCodeHooks.js","sourceRoot":"","sources":["../../src/harness/openCodeHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2EG;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,UAAU,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA;AAEpE,MAAM,GAAG,GAAG,YAAY,CAAC,qBAAqB,CAAC,CAAA;AAE/C,kGAAkG;AAClG,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;AACpE,qCAAqC;AACrC,MAAM,CAAC,MAAM,oBAAoB,GAAG,uBAAuB,CAAA;AAC3D,sEAAsE;AACtE,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAC,CAAA;AAElF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDjC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,aAAqB,EAAE,WAAmB;IAC5F,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAA;IACzF,OAAO;;;YAGG,QAAQ;gBACJ,MAAM,EAAE;;;;;;;;;;;;;;;;;gFAiBwD,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;;;;;;;;;;;EAWzG,UAAU,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,wBAAwB,CAAC,EAAE,CAAC;EACnJ,kBAAkB;;;8BAGU,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC;;;;;;;;;;;;;;;;sBAgBrC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2FlD,CAAA;AACD,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,aAAqB,EACrB,QAAgB,EAChB,WAAW,GAAG,EAAE;IAEhB,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACnF,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAAA;IAC/D,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE9C,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,CAAC,CAAA;IACtE,KAAK,MAAM,GAAG,IAAI,CAAC,oBAAoB,EAAE,uBAAuB,CAAC,EAAE,CAAC;QAClE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;QAC5C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC7D,MAAM,GAAG,GAAG,UAAU,GAAG,cAAc,CAAA;QACvC,MAAM,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;QACxC,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;QAChC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,yBAAyB,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,oCAAoC,CAAC,CAAA;IACzG,CAAC;AACH,CAAC"}
@@ -1 +1 @@
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"}
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(OPEN_WEBUI_DIR, { recursive: true }),
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(OPEN_WEBUI_DIR, 'intutic-governance-filter.py');
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":"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"}
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;AAUH;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CA+Gf"}
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":"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"}
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;AAgMH;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,GACf,OAAO,CAAC,IAAI,CAAC,CAuFf"}
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"}
@@ -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 — update existing providers' baseUrl and add
138
- * missing providers. The three canonical providers are anthropic, openai,
139
- * and google.
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 targetProviders = ['anthropic', 'openai', 'google'];
147
+ const targets = {
148
+ anthropic: anthropicBaseUrl(proxyUrl),
149
+ openai: openaiBaseUrl(proxyUrl),
150
+ };
144
151
  const mergedProviders = { ...providers };
145
- for (const provider of targetProviders) {
152
+ for (const [provider, baseUrl] of Object.entries(targets)) {
146
153
  mergedProviders[provider] = {
147
154
  ...(providers[provider] ?? {}),
148
- baseUrl: proxyUrl,
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
- let existingHooks = {};
189
- try {
190
- const raw = await fs.readFile(PI_HOOKS_CONFIG, 'utf-8');
191
- existingHooks = JSON.parse(raw);
192
- }
193
- catch {
194
- // File doesn't exist or is unparseable — start fresh
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
- let existingModels = {};
203
- try {
204
- const raw = await fs.readFile(PI_MODELS_CONFIG, 'utf-8');
205
- existingModels = JSON.parse(raw);
206
- }
207
- catch {
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 = [