@intutic/sync-daemon 2.0.0 → 2.2.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 +5 -12
- package/dist/agentReporter.d.ts.map +1 -1
- package/dist/agentReporter.js +25 -4
- package/dist/agentReporter.js.map +1 -1
- package/dist/configReader.d.ts +44 -22
- package/dist/configReader.d.ts.map +1 -1
- package/dist/configReader.js +70 -44
- package/dist/configReader.js.map +1 -1
- package/dist/configWriter.d.ts +29 -41
- package/dist/configWriter.d.ts.map +1 -1
- package/dist/configWriter.js +28 -625
- package/dist/configWriter.js.map +1 -1
- package/dist/disconnect/harnesses.d.ts +31 -0
- package/dist/disconnect/harnesses.d.ts.map +1 -0
- package/dist/disconnect/harnesses.js +728 -0
- package/dist/disconnect/harnesses.js.map +1 -0
- package/dist/disconnect/index.d.ts +25 -0
- package/dist/disconnect/index.d.ts.map +1 -0
- package/dist/disconnect/index.js +82 -0
- package/dist/disconnect/index.js.map +1 -0
- package/dist/disconnect/mcp.d.ts +60 -0
- package/dist/disconnect/mcp.d.ts.map +1 -0
- package/dist/disconnect/mcp.js +283 -0
- package/dist/disconnect/mcp.js.map +1 -0
- package/dist/disconnect/originals.d.ts +88 -0
- package/dist/disconnect/originals.d.ts.map +1 -0
- package/dist/disconnect/originals.js +257 -0
- package/dist/disconnect/originals.js.map +1 -0
- package/dist/disconnect/plan.d.ts +175 -0
- package/dist/disconnect/plan.d.ts.map +1 -0
- package/dist/disconnect/plan.js +580 -0
- package/dist/disconnect/plan.js.map +1 -0
- package/dist/disconnect/recognise.d.ts +43 -0
- package/dist/disconnect/recognise.d.ts.map +1 -0
- package/dist/disconnect/recognise.js +98 -0
- package/dist/disconnect/recognise.js.map +1 -0
- package/dist/disconnect/tomlLines.d.ts +39 -0
- package/dist/disconnect/tomlLines.d.ts.map +1 -0
- package/dist/disconnect/tomlLines.js +105 -0
- package/dist/disconnect/tomlLines.js.map +1 -0
- package/dist/harness/aiderConfigMerger.d.ts +42 -5
- package/dist/harness/aiderConfigMerger.d.ts.map +1 -1
- package/dist/harness/aiderConfigMerger.js +113 -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 +53 -39
- package/dist/harness/antigravityHooks.js.map +1 -1
- package/dist/harness/claudeCodeHooks.d.ts +1 -2
- package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
- package/dist/harness/claudeCodeHooks.js +61 -34
- package/dist/harness/claudeCodeHooks.js.map +1 -1
- package/dist/harness/claudeDesktopHooks.d.ts +3 -0
- package/dist/harness/claudeDesktopHooks.d.ts.map +1 -1
- package/dist/harness/claudeDesktopHooks.js +3 -1
- package/dist/harness/claudeDesktopHooks.js.map +1 -1
- package/dist/harness/claudeProjectApproval.d.ts +53 -0
- package/dist/harness/claudeProjectApproval.d.ts.map +1 -0
- package/dist/harness/claudeProjectApproval.js +159 -0
- package/dist/harness/claudeProjectApproval.js.map +1 -0
- package/dist/harness/clineHooks.d.ts +39 -9
- package/dist/harness/clineHooks.d.ts.map +1 -1
- package/dist/harness/clineHooks.js +142 -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 +105 -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 +14 -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 +94 -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 +25 -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 +69 -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 +152 -147
- package/dist/harness/dshHooks.js.map +1 -1
- package/dist/harness/gateBody.d.ts +11 -2
- package/dist/harness/gateBody.d.ts.map +1 -1
- package/dist/harness/gateBody.js +33 -6
- package/dist/harness/gateBody.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.d.ts.map +1 -1
- package/dist/harness/githubCopilotHooks.js +5 -10
- package/dist/harness/githubCopilotHooks.js.map +1 -1
- package/dist/harness/gooseHooks.d.ts +15 -0
- package/dist/harness/gooseHooks.d.ts.map +1 -1
- package/dist/harness/gooseHooks.js +55 -43
- package/dist/harness/gooseHooks.js.map +1 -1
- package/dist/harness/grokHooks.d.ts.map +1 -1
- package/dist/harness/grokHooks.js +14 -12
- 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 +39 -33
- package/dist/harness/hermesHooks.js.map +1 -1
- package/dist/harness/holdRedaction.d.ts +4 -1
- package/dist/harness/holdRedaction.d.ts.map +1 -1
- package/dist/harness/holdRedaction.js +32 -8
- package/dist/harness/holdRedaction.js.map +1 -1
- package/dist/harness/jetbrainsXmlConfig.d.ts +20 -0
- package/dist/harness/jetbrainsXmlConfig.d.ts.map +1 -1
- package/dist/harness/jetbrainsXmlConfig.js +39 -18
- package/dist/harness/jetbrainsXmlConfig.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 +64 -20
- package/dist/harness/mcpAutoWrite.d.ts.map +1 -1
- package/dist/harness/mcpAutoWrite.js +429 -85
- package/dist/harness/mcpAutoWrite.js.map +1 -1
- package/dist/harness/museHooks.d.ts.map +1 -1
- package/dist/harness/museHooks.js +6 -2
- package/dist/harness/museHooks.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 +103 -13
- package/dist/harness/openCodeHooks.js.map +1 -1
- package/dist/harness/openWebuiHooks.d.ts.map +1 -1
- package/dist/harness/openWebuiHooks.js +10 -5
- package/dist/harness/openWebuiHooks.js.map +1 -1
- package/dist/harness/openclawHooks.d.ts +5 -0
- package/dist/harness/openclawHooks.d.ts.map +1 -1
- package/dist/harness/openclawHooks.js +3 -1
- package/dist/harness/openclawHooks.js.map +1 -1
- package/dist/harness/openhandsHooks.d.ts +26 -1
- package/dist/harness/openhandsHooks.d.ts.map +1 -1
- package/dist/harness/openhandsHooks.js +160 -40
- 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 +31 -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/rooCodeHooks.d.ts.map +1 -1
- package/dist/harness/rooCodeHooks.js +5 -10
- package/dist/harness/rooCodeHooks.js.map +1 -1
- package/dist/harness/windsurfHooks.d.ts +21 -3
- package/dist/harness/windsurfHooks.d.ts.map +1 -1
- package/dist/harness/windsurfHooks.js +96 -44
- package/dist/harness/windsurfHooks.js.map +1 -1
- package/dist/harness/windsurfJetBrainsProxy.d.ts +10 -7
- package/dist/harness/windsurfJetBrainsProxy.d.ts.map +1 -1
- package/dist/harness/windsurfJetBrainsProxy.js +22 -7
- package/dist/harness/windsurfJetBrainsProxy.js.map +1 -1
- package/dist/index.d.ts +12 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -10
- package/dist/index.js.map +1 -1
- package/dist/lib/decisionsDigest.d.ts +1 -1
- package/dist/lib/decisionsDigest.js +1 -1
- package/dist/lib/policySnapshot.d.ts +37 -0
- package/dist/lib/policySnapshot.d.ts.map +1 -1
- package/dist/lib/policySnapshot.js +170 -8
- package/dist/lib/policySnapshot.js.map +1 -1
- package/dist/sessionReporter.d.ts +2 -2
- package/dist/sessionReporter.js +2 -2
- package/dist/syncCycle.d.ts +142 -0
- package/dist/syncCycle.d.ts.map +1 -0
- package/dist/syncCycle.js +315 -0
- package/dist/syncCycle.js.map +1 -0
- package/dist/trajectoryMonitor.d.ts +1 -1
- package/dist/trajectoryMonitor.d.ts.map +1 -1
- package/dist/trajectoryMonitor.js +1 -1
- package/dist/trajectoryMonitor.js.map +1 -1
- package/dist/watcher/settingsGuard.d.ts +4 -1
- package/dist/watcher/settingsGuard.d.ts.map +1 -1
- package/dist/watcher/settingsGuard.js +42 -18
- package/dist/watcher/settingsGuard.js.map +1 -1
- package/package.json +6 -6
- package/dist/hashReporter.d.ts +0 -33
- package/dist/hashReporter.d.ts.map +0 -1
- package/dist/hashReporter.js +0 -69
- package/dist/hashReporter.js.map +0 -1
- package/dist/integrityStore.d.ts +0 -35
- package/dist/integrityStore.d.ts.map +0 -1
- package/dist/integrityStore.js +0 -71
- package/dist/integrityStore.js.map +0 -1
- package/dist/lib/gitWorktrees.d.ts +0 -140
- package/dist/lib/gitWorktrees.d.ts.map +0 -1
- package/dist/lib/gitWorktrees.js +0 -191
- package/dist/lib/gitWorktrees.js.map +0 -1
- package/dist/syncLoop.d.ts +0 -172
- package/dist/syncLoop.d.ts.map +0 -1
- package/dist/syncLoop.js +0 -878
- package/dist/syncLoop.js.map +0 -1
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* recognise.ts — how disconnect tells Intutic's entries from the user's.
|
|
3
|
+
*
|
|
4
|
+
* Every test here is on content Intutic writes and nothing else: a hook
|
|
5
|
+
* command that runs a gate script from an `.intutic/hooks/` directory, a
|
|
6
|
+
* rules file that starts with the generated header, a URL on the origin of
|
|
7
|
+
* the proxy connect pointed the harness at.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import * as node_fs from 'node:fs/promises';
|
|
12
|
+
import * as node_path from 'node:path';
|
|
13
|
+
import { proxyHost } from '@intutic/shared-types';
|
|
14
|
+
import { isObject } from './plan.js';
|
|
15
|
+
/** First line of every rules file Intutic generates. */
|
|
16
|
+
export const RULES_HEADER = '# Intutic Governance Rules (auto-generated)';
|
|
17
|
+
export function startsWithRulesHeader(text) {
|
|
18
|
+
return text.startsWith(RULES_HEADER);
|
|
19
|
+
}
|
|
20
|
+
/** Whether `text` mentions `marker`, for owned files recognised by a line Intutic writes in them. */
|
|
21
|
+
export function contains(marker) {
|
|
22
|
+
return (text) => text.includes(marker);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Whether `command` runs the gate script `script` from an `.intutic/hooks/`
|
|
26
|
+
* directory (any workspace's, or the home one) — however it is quoted or
|
|
27
|
+
* whichever interpreter runs it.
|
|
28
|
+
*/
|
|
29
|
+
export function runsGate(command, script) {
|
|
30
|
+
if (typeof command !== 'string')
|
|
31
|
+
return false;
|
|
32
|
+
const escaped = script.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
33
|
+
return new RegExp(`[\\\\/]\\.intutic[\\\\/]hooks[\\\\/]${escaped}(?=["'\\s]|$)`).test(command);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Whether a `{ matcher, hooks: [{ command }] }` entry is Intutic's: every
|
|
37
|
+
* hook in it runs `script`. The shape Claude Code, Codex, Continue, Muse,
|
|
38
|
+
* Gemini CLI, Pi and Claude Desktop share.
|
|
39
|
+
*/
|
|
40
|
+
export function isGateEntry(script) {
|
|
41
|
+
return (entry) => {
|
|
42
|
+
if (!isObject(entry) || !Array.isArray(entry.hooks) || entry.hooks.length === 0)
|
|
43
|
+
return false;
|
|
44
|
+
return entry.hooks.every((h) => isObject(h) && runsGate(h.command, script));
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Whether a `{ command }` entry (Cursor, Windsurf, Roo) runs `script`. */
|
|
48
|
+
export function isGateCommandEntry(script) {
|
|
49
|
+
return (entry) => isObject(entry) && runsGate(entry.command, script);
|
|
50
|
+
}
|
|
51
|
+
/** Loopback hosts compare equal: connect writes `localhost` in one place and `127.0.0.1` in another. */
|
|
52
|
+
function originOf(value) {
|
|
53
|
+
try {
|
|
54
|
+
const url = new URL(value);
|
|
55
|
+
const host = url.hostname === 'localhost' || url.hostname === '[::1]' ? '127.0.0.1' : url.hostname;
|
|
56
|
+
const port = url.port || (url.protocol === 'https:' ? '443' : '80');
|
|
57
|
+
return `${url.protocol}//${host}:${port}`;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A test for "this value is a URL on the Intutic proxy", given the proxy
|
|
65
|
+
* URLs connect is known to have written. Any path on the proxy's origin
|
|
66
|
+
* counts: connect writes the bare host for Anthropic SDKs, `/v1` for OpenAI
|
|
67
|
+
* ones, and a trailing slash for Continue.
|
|
68
|
+
*/
|
|
69
|
+
export function proxyUrlMatcher(proxyUrls) {
|
|
70
|
+
const origins = new Set(proxyUrls.map((u) => originOf(proxyHost(u))).filter((o) => o !== null));
|
|
71
|
+
return (value) => typeof value === 'string' && origins.size > 0 && origins.has(originOf(value) ?? '');
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Proxy URLs an earlier connect left in a workspace's own generated files:
|
|
75
|
+
* the "Proxy URL" line of a rules file and `INTUTIC_PROXY_URL` in
|
|
76
|
+
* `.env.intutic`. Used when connect predates the recorded list.
|
|
77
|
+
*/
|
|
78
|
+
export async function proxyUrlsInWorkspace(workspaceRoot) {
|
|
79
|
+
const found = new Set();
|
|
80
|
+
const files = ['CLAUDE.md', '.cursorrules', '.windsurfrules', 'AGENTS.md', '.github/copilot-instructions.md', '.env.intutic'];
|
|
81
|
+
for (const rel of files) {
|
|
82
|
+
let text;
|
|
83
|
+
try {
|
|
84
|
+
text = await node_fs.readFile(node_path.join(workspaceRoot, rel), 'utf-8');
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (!startsWithRulesHeader(text))
|
|
90
|
+
continue;
|
|
91
|
+
for (const m of text.matchAll(/^> \*\*Proxy URL:\*\* `([^`]+)`$/gm))
|
|
92
|
+
found.add(m[1]);
|
|
93
|
+
for (const m of text.matchAll(/^export INTUTIC_PROXY_URL="([^"]+)"$/gm))
|
|
94
|
+
found.add(m[1]);
|
|
95
|
+
}
|
|
96
|
+
return [...found];
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=recognise.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recognise.js","sourceRoot":"","sources":["../../src/disconnect/recognise.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tomlLines.ts — line-level TOML edits that keep the user's comments.
|
|
3
|
+
*
|
|
4
|
+
* Codex's and OpenHands' writers set a key or append a table by editing
|
|
5
|
+
* lines, so the user's comments survive; undoing them the same way keeps
|
|
6
|
+
* that promise. Only the shapes those writers produce are handled: a
|
|
7
|
+
* `key = value` line in the top level or in a `[table]`, and a whole table.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
interface Section {
|
|
12
|
+
/** Table name as written between the brackets, or null for the top level. */
|
|
13
|
+
name: string | null;
|
|
14
|
+
/** Index of the header line (-1 for the top level). */
|
|
15
|
+
header: number;
|
|
16
|
+
/** One past the last line of the section. */
|
|
17
|
+
end: number;
|
|
18
|
+
}
|
|
19
|
+
/** Splits lines into sections, ignoring `[` lines inside multi-line strings. */
|
|
20
|
+
export declare function tomlSections(lines: readonly string[]): Section[];
|
|
21
|
+
/** The value a one-line `key = value` assignment holds, or undefined when the line is not one. */
|
|
22
|
+
export declare function lineValue(line: string, key: string): unknown;
|
|
23
|
+
/** Index of `key`'s line in the first section named `table` (null: top level), or -1. */
|
|
24
|
+
export declare function findKeyLine(lines: readonly string[], table: string | null, key: string): number;
|
|
25
|
+
/**
|
|
26
|
+
* Removes the table named `table`, header to end, with the blank line a
|
|
27
|
+
* writer put before it when it appended the table.
|
|
28
|
+
*/
|
|
29
|
+
export declare function removeTable(lines: string[], table: string): boolean;
|
|
30
|
+
/** Removes a `[table]` header with nothing left under it but blank lines. */
|
|
31
|
+
export declare function removeEmptyTable(lines: string[], table: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Puts back one key a writer set. When the original text had the key in
|
|
34
|
+
* the same section its line is restored; otherwise the line is removed.
|
|
35
|
+
* Only a line whose value `isIntutic` recognises is touched.
|
|
36
|
+
*/
|
|
37
|
+
export declare function restoreKeyLine(lines: string[], table: string | null, key: string, originalLines: readonly string[] | null, isIntutic: (value: unknown) => boolean): boolean;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=tomlLines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tomlLines.d.ts","sourceRoot":"","sources":["../../src/disconnect/tomlLines.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,UAAU,OAAO;IACf,6EAA6E;IAC7E,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAA;IACd,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,EAAE,CAuBhE;AAED,kGAAkG;AAClG,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAO5D;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAO/F;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAOnE;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAKxE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,EACvC,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,GACrC,OAAO,CAWT"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tomlLines.ts — line-level TOML edits that keep the user's comments.
|
|
3
|
+
*
|
|
4
|
+
* Codex's and OpenHands' writers set a key or append a table by editing
|
|
5
|
+
* lines, so the user's comments survive; undoing them the same way keeps
|
|
6
|
+
* that promise. Only the shapes those writers produce are handled: a
|
|
7
|
+
* `key = value` line in the top level or in a `[table]`, and a whole table.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import { parse as parseToml } from 'smol-toml';
|
|
12
|
+
/** Splits lines into sections, ignoring `[` lines inside multi-line strings. */
|
|
13
|
+
export function tomlSections(lines) {
|
|
14
|
+
const sections = [{ name: null, header: -1, end: lines.length }];
|
|
15
|
+
let inString = null;
|
|
16
|
+
lines.forEach((line, i) => {
|
|
17
|
+
if (inString === null) {
|
|
18
|
+
// `[table]` or `[[array.of.tables]]`; the name is what is between the brackets.
|
|
19
|
+
const header = /^\s*\[\[?\s*([^\][]+?)\s*\]\]?\s*(#.*)?$/.exec(line);
|
|
20
|
+
if (header) {
|
|
21
|
+
sections[sections.length - 1].end = i;
|
|
22
|
+
sections.push({ name: header[1], header: i, end: lines.length });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
for (const quote of ['"""', "'''"]) {
|
|
27
|
+
let at = line.indexOf(quote);
|
|
28
|
+
while (at !== -1) {
|
|
29
|
+
if (inString === null)
|
|
30
|
+
inString = quote;
|
|
31
|
+
else if (inString === quote)
|
|
32
|
+
inString = null;
|
|
33
|
+
at = line.indexOf(quote, at + 3);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return sections;
|
|
38
|
+
}
|
|
39
|
+
/** The value a one-line `key = value` assignment holds, or undefined when the line is not one. */
|
|
40
|
+
export function lineValue(line, key) {
|
|
41
|
+
if (!new RegExp(`^\\s*${key}\\s*=`).test(line))
|
|
42
|
+
return undefined;
|
|
43
|
+
try {
|
|
44
|
+
return parseToml(line)[key];
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Index of `key`'s line in the first section named `table` (null: top level), or -1. */
|
|
51
|
+
export function findKeyLine(lines, table, key) {
|
|
52
|
+
const section = tomlSections(lines).find((s) => s.name === table);
|
|
53
|
+
if (!section)
|
|
54
|
+
return -1;
|
|
55
|
+
for (let i = section.header + 1; i < section.end; i++) {
|
|
56
|
+
if (lineValue(lines[i], key) !== undefined)
|
|
57
|
+
return i;
|
|
58
|
+
}
|
|
59
|
+
return -1;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Removes the table named `table`, header to end, with the blank line a
|
|
63
|
+
* writer put before it when it appended the table.
|
|
64
|
+
*/
|
|
65
|
+
export function removeTable(lines, table) {
|
|
66
|
+
const section = tomlSections(lines).find((s) => s.name === table);
|
|
67
|
+
if (!section)
|
|
68
|
+
return false;
|
|
69
|
+
let start = section.header;
|
|
70
|
+
if (start > 0 && lines[start - 1].trim() === '')
|
|
71
|
+
start--;
|
|
72
|
+
lines.splice(start, section.end - start);
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
/** Removes a `[table]` header with nothing left under it but blank lines. */
|
|
76
|
+
export function removeEmptyTable(lines, table) {
|
|
77
|
+
const section = tomlSections(lines).find((s) => s.name === table);
|
|
78
|
+
if (!section)
|
|
79
|
+
return false;
|
|
80
|
+
for (let i = section.header + 1; i < section.end; i++)
|
|
81
|
+
if (lines[i].trim() !== '')
|
|
82
|
+
return false;
|
|
83
|
+
return removeTable(lines, table);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Puts back one key a writer set. When the original text had the key in
|
|
87
|
+
* the same section its line is restored; otherwise the line is removed.
|
|
88
|
+
* Only a line whose value `isIntutic` recognises is touched.
|
|
89
|
+
*/
|
|
90
|
+
export function restoreKeyLine(lines, table, key, originalLines, isIntutic) {
|
|
91
|
+
const at = findKeyLine(lines, table, key);
|
|
92
|
+
if (at === -1 || !isIntutic(lineValue(lines[at], key)))
|
|
93
|
+
return false;
|
|
94
|
+
const was = originalLines ? findKeyLine(originalLines, table, key) : -1;
|
|
95
|
+
if (was !== -1) {
|
|
96
|
+
if (lines[at] === originalLines[was])
|
|
97
|
+
return false;
|
|
98
|
+
lines[at] = originalLines[was];
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
lines.splice(at, 1);
|
|
102
|
+
}
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=tomlLines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tomlLines.js","sourceRoot":"","sources":["../../src/disconnect/tomlLines.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,8 +2,26 @@
|
|
|
2
2
|
* aiderConfigMerger.ts — Safe YAML merge for .aider.conf.yml.
|
|
3
3
|
*
|
|
4
4
|
* Reads any existing .aider.conf.yml, STRIPS dangerous auto-exec keys
|
|
5
|
-
* (test-cmd, lint-cmd, auto-test, auto-lint), merges in Intutic
|
|
6
|
-
*
|
|
5
|
+
* (test-cmd, lint-cmd, auto-test, auto-lint), merges in the Intutic proxy
|
|
6
|
+
* routing, and writes back atomically. Everything else in the file — lists,
|
|
7
|
+
* nested values, comments — is kept: the file is edited through the `yaml`
|
|
8
|
+
* library's document model, never re-serialised from a flattened copy.
|
|
9
|
+
*
|
|
10
|
+
* Aider rejects any config key that is not one of its command-line options
|
|
11
|
+
* ("unrecognized arguments"), so only real options are written:
|
|
12
|
+
*
|
|
13
|
+
* - `openai-api-base` — the proxy's OpenAI-style base URL (host + `/v1`).
|
|
14
|
+
* - `set-env: ANTHROPIC_BASE_URL=<host>` — Aider has no Anthropic base-URL
|
|
15
|
+
* option; its model layer (LiteLLM) reads this variable, and wants the bare
|
|
16
|
+
* host because it appends `/v1/messages` itself. Entries the user set for
|
|
17
|
+
* other variables are kept.
|
|
18
|
+
* - `read: .intutic/aider-sops.md` — the SOP text, as a read-only context
|
|
19
|
+
* file (Aider's own mechanism for conventions), written next to the config.
|
|
20
|
+
*
|
|
21
|
+
* Earlier versions wrote `anthropic-api-base` and `extra-instructions`, which
|
|
22
|
+
* are not Aider options and stopped Aider from starting; both are removed.
|
|
23
|
+
*
|
|
24
|
+
* A file that does not parse as YAML, or is not a mapping, is left untouched.
|
|
7
25
|
*
|
|
8
26
|
* Each strip emits a governance_config_sanitized log entry visible in
|
|
9
27
|
* the control plane audit feed.
|
|
@@ -13,15 +31,34 @@
|
|
|
13
31
|
*
|
|
14
32
|
* @module
|
|
15
33
|
*/
|
|
34
|
+
/** SOP file, relative to the workspace root (where Aider runs). */
|
|
35
|
+
export declare const AIDER_SOPS_FILE = ".intutic/aider-sops.md";
|
|
36
|
+
export declare function stripOwnHeader(raw: string): string;
|
|
37
|
+
/** Result of merging the Intutic keys into an Aider config's text. */
|
|
38
|
+
export interface AiderMergeResult {
|
|
39
|
+
/** New file content, or `null` when the file must be left untouched. */
|
|
40
|
+
content: string | null;
|
|
41
|
+
/** Suppressed keys that were removed. */
|
|
42
|
+
stripped: string[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Merge the Intutic keys into the text of an `.aider.conf.yml`.
|
|
46
|
+
*
|
|
47
|
+
* @param raw - Current file content ('' when the file does not exist).
|
|
48
|
+
* @param proxyUrl - The proxy host (a trailing `/v1` is tolerated).
|
|
49
|
+
* @param hasSops - Whether the SOP file is to be listed under `read`.
|
|
50
|
+
*/
|
|
51
|
+
export declare function mergeAiderYaml(raw: string, proxyUrl: string, hasSops: boolean): AiderMergeResult;
|
|
16
52
|
/**
|
|
17
53
|
* Merge Intutic governance settings into .aider.conf.yml.
|
|
18
54
|
*
|
|
19
55
|
* Preserves all user keys EXCEPT the suppressed auto-exec keys.
|
|
20
|
-
* Adds/updates openai-api-base and anthropic-api-base.
|
|
21
56
|
*
|
|
22
57
|
* @param configPath - Absolute path to .aider.conf.yml
|
|
23
58
|
* @param proxyUrl - Intutic proxy URL
|
|
24
|
-
* @param sopsText - Optional SOP instructions
|
|
59
|
+
* @param sopsText - Optional SOP instructions, written to the `read` file
|
|
60
|
+
* @returns `true` when the config was written, `false` when it was left
|
|
61
|
+
* untouched because it is not a YAML mapping (a warning is logged).
|
|
25
62
|
*/
|
|
26
|
-
export declare function mergeAiderConfig(configPath: string, proxyUrl: string, sopsText?: string): Promise<
|
|
63
|
+
export declare function mergeAiderConfig(configPath: string, proxyUrl: string, sopsText?: string): Promise<boolean>;
|
|
27
64
|
//# sourceMappingURL=aiderConfigMerger.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiderConfigMerger.d.ts","sourceRoot":"","sources":["../../src/harness/aiderConfigMerger.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"aiderConfigMerger.d.ts","sourceRoot":"","sources":["../../src/harness/aiderConfigMerger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAoBH,mEAAmE;AACnE,eAAO,MAAM,eAAe,2BAA2B,CAAA;AAcvD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAC/B,wEAAwE;IACxE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAYD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,gBAAgB,CA2BhG;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CA8ClB"}
|
|
@@ -2,8 +2,26 @@
|
|
|
2
2
|
* aiderConfigMerger.ts — Safe YAML merge for .aider.conf.yml.
|
|
3
3
|
*
|
|
4
4
|
* Reads any existing .aider.conf.yml, STRIPS dangerous auto-exec keys
|
|
5
|
-
* (test-cmd, lint-cmd, auto-test, auto-lint), merges in Intutic
|
|
6
|
-
*
|
|
5
|
+
* (test-cmd, lint-cmd, auto-test, auto-lint), merges in the Intutic proxy
|
|
6
|
+
* routing, and writes back atomically. Everything else in the file — lists,
|
|
7
|
+
* nested values, comments — is kept: the file is edited through the `yaml`
|
|
8
|
+
* library's document model, never re-serialised from a flattened copy.
|
|
9
|
+
*
|
|
10
|
+
* Aider rejects any config key that is not one of its command-line options
|
|
11
|
+
* ("unrecognized arguments"), so only real options are written:
|
|
12
|
+
*
|
|
13
|
+
* - `openai-api-base` — the proxy's OpenAI-style base URL (host + `/v1`).
|
|
14
|
+
* - `set-env: ANTHROPIC_BASE_URL=<host>` — Aider has no Anthropic base-URL
|
|
15
|
+
* option; its model layer (LiteLLM) reads this variable, and wants the bare
|
|
16
|
+
* host because it appends `/v1/messages` itself. Entries the user set for
|
|
17
|
+
* other variables are kept.
|
|
18
|
+
* - `read: .intutic/aider-sops.md` — the SOP text, as a read-only context
|
|
19
|
+
* file (Aider's own mechanism for conventions), written next to the config.
|
|
20
|
+
*
|
|
21
|
+
* Earlier versions wrote `anthropic-api-base` and `extra-instructions`, which
|
|
22
|
+
* are not Aider options and stopped Aider from starting; both are removed.
|
|
23
|
+
*
|
|
24
|
+
* A file that does not parse as YAML, or is not a mapping, is left untouched.
|
|
7
25
|
*
|
|
8
26
|
* Each strip emits a governance_config_sanitized log entry visible in
|
|
9
27
|
* the control plane audit feed.
|
|
@@ -15,125 +33,134 @@
|
|
|
15
33
|
*/
|
|
16
34
|
import * as fs from 'node:fs/promises';
|
|
17
35
|
import * as path from 'node:path';
|
|
36
|
+
import { parseDocument, isMap, isSeq, isScalar, YAMLSeq } from 'yaml';
|
|
18
37
|
import { createLogger } from '@intutic/logger';
|
|
19
|
-
import {
|
|
38
|
+
import { keepOriginal } from '../disconnect/originals.js';
|
|
39
|
+
import { anthropicBaseUrl, openaiBaseUrl } from '@intutic/shared-types';
|
|
20
40
|
const log = createLogger('sync-aider-merger');
|
|
21
41
|
/**
|
|
22
42
|
* Keys that Aider auto-executes on startup without user confirmation.
|
|
23
43
|
* Stripping these prevents supply-chain persistence attacks.
|
|
24
44
|
*/
|
|
25
45
|
const SUPPRESSED_KEYS = ['test-cmd', 'lint-cmd', 'auto-test', 'auto-lint', 'test_cmd', 'lint_cmd'];
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
46
|
+
/** Keys earlier versions wrote that Aider rejects as unrecognized arguments. */
|
|
47
|
+
const INVALID_LEGACY_KEYS = ['anthropic-api-base', 'extra-instructions'];
|
|
48
|
+
/** SOP file, relative to the workspace root (where Aider runs). */
|
|
49
|
+
export const AIDER_SOPS_FILE = '.intutic/aider-sops.md';
|
|
50
|
+
/** Header written at the top of the file. Kept short: it sits above the
|
|
51
|
+
* user's own content, and is replaced, not stacked, on every sync. */
|
|
52
|
+
const HEADER = [
|
|
53
|
+
'# Intutic: openai-api-base, the ANTHROPIC_BASE_URL set-env entry and the',
|
|
54
|
+
`# ${AIDER_SOPS_FILE} read entry are managed by intutic connect. test-cmd,`,
|
|
55
|
+
'# lint-cmd, auto-test and auto-lint are removed on every sync.',
|
|
56
|
+
];
|
|
57
|
+
/** Leading lines this product wrote (the header above, or the one earlier
|
|
58
|
+
* versions wrote), removed before the file is parsed. */
|
|
59
|
+
const OWN_HEADER_LINE = /^# (Intutic: |Intutic Governance Rules \(auto-generated|Last sync: |WARNING: test-cmd and lint-cmd keys are suppressed|\.intutic\/aider-sops\.md read entry|lint-cmd, auto-test and auto-lint are removed)/;
|
|
60
|
+
export function stripOwnHeader(raw) {
|
|
33
61
|
const lines = raw.split('\n');
|
|
34
62
|
let i = 0;
|
|
35
|
-
while (i < lines.length)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
while (i < lines.length && (lines[i].startsWith(' ') || lines[i] === '')) {
|
|
54
|
-
blockLines.push(lines[i].startsWith(' ') ? lines[i].slice(2) : '');
|
|
55
|
-
i++;
|
|
56
|
-
}
|
|
57
|
-
result[key] = blockLines.join('\n').trimEnd();
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
// Strip inline quotes
|
|
61
|
-
result[key] = rest.replace(/^["']|["']$/g, '');
|
|
62
|
-
i++;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return result;
|
|
63
|
+
while (i < lines.length && OWN_HEADER_LINE.test(lines[i]))
|
|
64
|
+
i++;
|
|
65
|
+
if (i === 0)
|
|
66
|
+
return raw;
|
|
67
|
+
while (i < lines.length && lines[i].trim() === '')
|
|
68
|
+
i++;
|
|
69
|
+
return lines.slice(i).join('\n');
|
|
70
|
+
}
|
|
71
|
+
/** Turn `key`'s value into a sequence (a scalar becomes a one-item list). */
|
|
72
|
+
function ensureSeq(doc, key) {
|
|
73
|
+
const current = doc.get(key, true);
|
|
74
|
+
if (isSeq(current))
|
|
75
|
+
return current;
|
|
76
|
+
const seq = new YAMLSeq();
|
|
77
|
+
if (isScalar(current) && current.value !== null && current.value !== '')
|
|
78
|
+
seq.add(current.value);
|
|
79
|
+
doc.set(key, seq);
|
|
80
|
+
return seq;
|
|
66
81
|
}
|
|
67
82
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
83
|
+
* Merge the Intutic keys into the text of an `.aider.conf.yml`.
|
|
84
|
+
*
|
|
85
|
+
* @param raw - Current file content ('' when the file does not exist).
|
|
86
|
+
* @param proxyUrl - The proxy host (a trailing `/v1` is tolerated).
|
|
87
|
+
* @param hasSops - Whether the SOP file is to be listed under `read`.
|
|
70
88
|
*/
|
|
71
|
-
function
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
export function mergeAiderYaml(raw, proxyUrl, hasSops) {
|
|
90
|
+
const doc = parseDocument(stripOwnHeader(raw));
|
|
91
|
+
if (doc.errors.length > 0)
|
|
92
|
+
return { content: null, stripped: [] };
|
|
93
|
+
// A missing, empty or comment-only file starts as an empty mapping (its
|
|
94
|
+
// comments stay on the document); anything else that is not a mapping (a
|
|
95
|
+
// list, a bare scalar) is not an Aider config to merge into.
|
|
96
|
+
if (doc.contents === null)
|
|
97
|
+
doc.contents = doc.createNode({});
|
|
98
|
+
if (!isMap(doc.contents))
|
|
99
|
+
return { content: null, stripped: [] };
|
|
100
|
+
const stripped = SUPPRESSED_KEYS.filter((key) => doc.has(key));
|
|
101
|
+
for (const key of [...stripped, ...INVALID_LEGACY_KEYS])
|
|
102
|
+
doc.delete(key);
|
|
103
|
+
doc.set('openai-api-base', openaiBaseUrl(proxyUrl));
|
|
104
|
+
const setEnv = ensureSeq(doc, 'set-env');
|
|
105
|
+
setEnv.items = setEnv.items.filter((item) => {
|
|
106
|
+
const value = isScalar(item) ? item.value : item;
|
|
107
|
+
return !(typeof value === 'string' && value.startsWith('ANTHROPIC_BASE_URL='));
|
|
108
|
+
});
|
|
109
|
+
setEnv.add(`ANTHROPIC_BASE_URL=${anthropicBaseUrl(proxyUrl)}`);
|
|
110
|
+
const read = ensureSeq(doc, 'read');
|
|
111
|
+
read.items = read.items.filter((item) => (isScalar(item) ? item.value : item) !== AIDER_SOPS_FILE);
|
|
112
|
+
if (hasSops)
|
|
113
|
+
read.add(AIDER_SOPS_FILE);
|
|
114
|
+
if (read.items.length === 0)
|
|
115
|
+
doc.delete('read');
|
|
116
|
+
return { content: `${HEADER.join('\n')}\n\n${doc.toString()}`, stripped };
|
|
88
117
|
}
|
|
89
118
|
/**
|
|
90
119
|
* Merge Intutic governance settings into .aider.conf.yml.
|
|
91
120
|
*
|
|
92
121
|
* Preserves all user keys EXCEPT the suppressed auto-exec keys.
|
|
93
|
-
* Adds/updates openai-api-base and anthropic-api-base.
|
|
94
122
|
*
|
|
95
123
|
* @param configPath - Absolute path to .aider.conf.yml
|
|
96
124
|
* @param proxyUrl - Intutic proxy URL
|
|
97
|
-
* @param sopsText - Optional SOP instructions
|
|
125
|
+
* @param sopsText - Optional SOP instructions, written to the `read` file
|
|
126
|
+
* @returns `true` when the config was written, `false` when it was left
|
|
127
|
+
* untouched because it is not a YAML mapping (a warning is logged).
|
|
98
128
|
*/
|
|
99
129
|
export async function mergeAiderConfig(configPath, proxyUrl, sopsText) {
|
|
100
|
-
|
|
101
|
-
let existing = {};
|
|
130
|
+
let raw = '';
|
|
102
131
|
try {
|
|
103
|
-
|
|
104
|
-
existing = parseAiderYaml(raw);
|
|
132
|
+
raw = await fs.readFile(configPath, 'utf-8');
|
|
105
133
|
}
|
|
106
|
-
catch {
|
|
107
|
-
|
|
134
|
+
catch (err) {
|
|
135
|
+
if (err.code !== 'ENOENT')
|
|
136
|
+
throw err;
|
|
108
137
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
stripped.push(key);
|
|
114
|
-
delete existing[key];
|
|
115
|
-
}
|
|
138
|
+
const { content, stripped } = mergeAiderYaml(raw, proxyUrl, Boolean(sopsText));
|
|
139
|
+
if (content === null) {
|
|
140
|
+
log.warn({ action: 'aider_config_merge_skipped', path: configPath }, `${configPath} is not a YAML mapping — left untouched; fix it and the next sync will add the Intutic keys`);
|
|
141
|
+
return false;
|
|
116
142
|
}
|
|
117
143
|
if (stripped.length > 0) {
|
|
118
144
|
log.warn({ action: 'aider_keys_stripped', keys: stripped, path: configPath }, `Stripped dangerous auto-exec keys from .aider.conf.yml: ${stripped.join(', ')}`);
|
|
119
145
|
}
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
existing['anthropic-api-base'] = proxyUrl;
|
|
146
|
+
// The SOP file lives next to the config, under the workspace's .intutic/.
|
|
147
|
+
const sopsPath = path.join(path.dirname(configPath), AIDER_SOPS_FILE);
|
|
123
148
|
if (sopsText) {
|
|
124
|
-
|
|
149
|
+
await fs.mkdir(path.dirname(sopsPath), { recursive: true });
|
|
150
|
+
const tmpSops = sopsPath + '.intutic-tmp';
|
|
151
|
+
await fs.writeFile(tmpSops, sopsText + '\n', 'utf-8');
|
|
152
|
+
await fs.rename(tmpSops, sopsPath);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
await fs.rm(sopsPath, { force: true });
|
|
125
156
|
}
|
|
126
|
-
const header = [
|
|
127
|
-
'# Intutic Governance Rules (auto-generated — do not edit proxy keys)',
|
|
128
|
-
`# Last sync: ${newIso()}`,
|
|
129
|
-
`# WARNING: test-cmd and lint-cmd keys are suppressed by Intutic governance`,
|
|
130
|
-
'',
|
|
131
|
-
].join('\n');
|
|
132
|
-
const content = header + serializeAiderYaml(existing) + '\n';
|
|
133
157
|
const tmpPath = configPath + '.intutic-tmp';
|
|
158
|
+
// The config sits at the workspace root, so its directory is the workspace.
|
|
159
|
+
await keepOriginal(configPath, path.dirname(configPath));
|
|
134
160
|
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
135
161
|
await fs.writeFile(tmpPath, content, 'utf-8');
|
|
136
162
|
await fs.rename(tmpPath, configPath);
|
|
137
163
|
log.info({ action: 'aider_config_written', path: configPath, stripped }, 'Aider config merged with proxy URL and dangerous keys stripped');
|
|
164
|
+
return true;
|
|
138
165
|
}
|
|
139
166
|
//# sourceMappingURL=aiderConfigMerger.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiderConfigMerger.js","sourceRoot":"","sources":["../../src/harness/aiderConfigMerger.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"aiderConfigMerger.js","sourceRoot":"","sources":["../../src/harness/aiderConfigMerger.ts"],"names":[],"mappings":"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"}
|