@intutic/sync-daemon 2.1.0 → 2.3.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/README.md +1 -1
- package/dist/agentReporter.d.ts +24 -11
- package/dist/agentReporter.d.ts.map +1 -1
- package/dist/agentReporter.js +20 -13
- package/dist/agentReporter.js.map +1 -1
- package/dist/configReader.d.ts +45 -25
- package/dist/configReader.d.ts.map +1 -1
- package/dist/configReader.js +70 -46
- package/dist/configReader.js.map +1 -1
- package/dist/configWriter.d.ts +32 -45
- package/dist/configWriter.d.ts.map +1 -1
- package/dist/configWriter.js +52 -686
- package/dist/configWriter.js.map +1 -1
- package/dist/disconnect/harnesses.d.ts +29 -0
- package/dist/disconnect/harnesses.d.ts.map +1 -0
- package/dist/disconnect/harnesses.js +805 -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 +92 -0
- package/dist/disconnect/index.js.map +1 -0
- package/dist/disconnect/mcp.d.ts +81 -0
- package/dist/disconnect/mcp.d.ts.map +1 -0
- package/dist/disconnect/mcp.js +354 -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 +108 -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 +29 -8
- package/dist/harness/aiderConfigMerger.d.ts.map +1 -1
- package/dist/harness/aiderConfigMerger.js +63 -12
- package/dist/harness/aiderConfigMerger.js.map +1 -1
- package/dist/harness/antigravityCliHooks.d.ts +61 -0
- package/dist/harness/antigravityCliHooks.d.ts.map +1 -0
- package/dist/harness/antigravityCliHooks.js +207 -0
- package/dist/harness/antigravityCliHooks.js.map +1 -0
- package/dist/harness/antigravityHooks.d.ts +12 -2
- package/dist/harness/antigravityHooks.d.ts.map +1 -1
- package/dist/harness/antigravityHooks.js +38 -16
- package/dist/harness/antigravityHooks.js.map +1 -1
- package/dist/harness/antigravityProducts.d.ts +40 -0
- package/dist/harness/antigravityProducts.d.ts.map +1 -0
- package/dist/harness/antigravityProducts.js +109 -0
- package/dist/harness/antigravityProducts.js.map +1 -0
- package/dist/harness/claudeAgentsMd.d.ts +29 -0
- package/dist/harness/claudeAgentsMd.d.ts.map +1 -0
- package/dist/harness/claudeAgentsMd.js +80 -0
- package/dist/harness/claudeAgentsMd.js.map +1 -0
- package/dist/harness/claudeCodeHooks.d.ts +6 -6
- package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
- package/dist/harness/claudeCodeHooks.js +115 -28
- package/dist/harness/claudeCodeHooks.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 +0 -1
- package/dist/harness/clineHooks.d.ts.map +1 -1
- package/dist/harness/clineHooks.js +13 -4
- package/dist/harness/clineHooks.js.map +1 -1
- package/dist/harness/codexConfigMerger.d.ts.map +1 -1
- package/dist/harness/codexConfigMerger.js +4 -0
- package/dist/harness/codexConfigMerger.js.map +1 -1
- package/dist/harness/codexHooks.d.ts +2 -0
- package/dist/harness/codexHooks.d.ts.map +1 -1
- package/dist/harness/codexHooks.js +15 -4
- package/dist/harness/codexHooks.js.map +1 -1
- package/dist/harness/continueConfigMerger.d.ts.map +1 -1
- package/dist/harness/continueConfigMerger.js +4 -0
- package/dist/harness/continueConfigMerger.js.map +1 -1
- package/dist/harness/cursorHooks.d.ts +5 -2
- package/dist/harness/cursorHooks.d.ts.map +1 -1
- package/dist/harness/cursorHooks.js +12 -3
- package/dist/harness/cursorHooks.js.map +1 -1
- package/dist/harness/dshHooks.d.ts +5 -5
- package/dist/harness/dshHooks.d.ts.map +1 -1
- package/dist/harness/dshHooks.js +12 -5
- package/dist/harness/dshHooks.js.map +1 -1
- package/dist/harness/gateArtifacts.d.ts +35 -0
- package/dist/harness/gateArtifacts.d.ts.map +1 -0
- package/dist/harness/gateArtifacts.js +88 -0
- package/dist/harness/gateArtifacts.js.map +1 -0
- package/dist/harness/gateBody.d.ts +195 -69
- package/dist/harness/gateBody.d.ts.map +1 -1
- package/dist/harness/gateBody.js +847 -182
- package/dist/harness/gateBody.js.map +1 -1
- package/dist/harness/gateSightings.d.ts +47 -0
- package/dist/harness/gateSightings.d.ts.map +1 -0
- package/dist/harness/gateSightings.js +159 -0
- package/dist/harness/gateSightings.js.map +1 -0
- package/dist/harness/githubCopilotHooks.d.ts.map +1 -1
- package/dist/harness/githubCopilotHooks.js +11 -10
- package/dist/harness/githubCopilotHooks.js.map +1 -1
- package/dist/harness/gooseHardener.d.ts +0 -1
- package/dist/harness/gooseHardener.d.ts.map +1 -1
- package/dist/harness/gooseHardener.js +1 -1
- package/dist/harness/gooseHardener.js.map +1 -1
- package/dist/harness/gooseHooks.d.ts +29 -1
- package/dist/harness/gooseHooks.d.ts.map +1 -1
- package/dist/harness/gooseHooks.js +107 -69
- package/dist/harness/gooseHooks.js.map +1 -1
- package/dist/harness/grokHooks.d.ts +2 -2
- package/dist/harness/grokHooks.d.ts.map +1 -1
- package/dist/harness/grokHooks.js +20 -18
- package/dist/harness/grokHooks.js.map +1 -1
- package/dist/harness/hermesHooks.d.ts +18 -8
- package/dist/harness/hermesHooks.d.ts.map +1 -1
- package/dist/harness/hermesHooks.js +55 -19
- 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/mcpAutoWrite.d.ts +62 -25
- package/dist/harness/mcpAutoWrite.d.ts.map +1 -1
- package/dist/harness/mcpAutoWrite.js +406 -95
- package/dist/harness/mcpAutoWrite.js.map +1 -1
- package/dist/harness/museHooks.d.ts +3 -3
- package/dist/harness/museHooks.d.ts.map +1 -1
- package/dist/harness/museHooks.js +15 -7
- package/dist/harness/museHooks.js.map +1 -1
- package/dist/harness/n8nHooks.d.ts +0 -1
- package/dist/harness/n8nHooks.d.ts.map +1 -1
- package/dist/harness/n8nHooks.js +4 -1
- package/dist/harness/n8nHooks.js.map +1 -1
- package/dist/harness/openCodeHooks.d.ts +2 -2
- package/dist/harness/openCodeHooks.d.ts.map +1 -1
- package/dist/harness/openCodeHooks.js +9 -8
- package/dist/harness/openCodeHooks.js.map +1 -1
- package/dist/harness/openWebuiHooks.d.ts +0 -1
- package/dist/harness/openWebuiHooks.d.ts.map +1 -1
- package/dist/harness/openWebuiHooks.js +11 -3
- package/dist/harness/openWebuiHooks.js.map +1 -1
- package/dist/harness/openclawHooks.d.ts +75 -18
- package/dist/harness/openclawHooks.d.ts.map +1 -1
- package/dist/harness/openclawHooks.js +214 -160
- package/dist/harness/openclawHooks.js.map +1 -1
- package/dist/harness/openhandsHooks.d.ts +37 -11
- package/dist/harness/openhandsHooks.d.ts.map +1 -1
- package/dist/harness/openhandsHooks.js +148 -97
- package/dist/harness/openhandsHooks.js.map +1 -1
- package/dist/harness/piHooks.d.ts +52 -17
- package/dist/harness/piHooks.d.ts.map +1 -1
- package/dist/harness/piHooks.js +177 -163
- package/dist/harness/piHooks.js.map +1 -1
- package/dist/harness/protectedPaths.d.ts +107 -25
- package/dist/harness/protectedPaths.d.ts.map +1 -1
- package/dist/harness/protectedPaths.js +342 -48
- package/dist/harness/protectedPaths.js.map +1 -1
- package/dist/harness/rulesSection.d.ts +62 -0
- package/dist/harness/rulesSection.d.ts.map +1 -0
- package/dist/harness/rulesSection.js +145 -0
- package/dist/harness/rulesSection.js.map +1 -0
- package/dist/harness/windsurfHooks.d.ts +18 -3
- package/dist/harness/windsurfHooks.d.ts.map +1 -1
- package/dist/harness/windsurfHooks.js +41 -8
- package/dist/harness/windsurfHooks.js.map +1 -1
- package/dist/harness/windsurfJetBrainsProxy.d.ts +1 -1
- package/dist/harness/windsurfJetBrainsProxy.d.ts.map +1 -1
- package/dist/harness/windsurfJetBrainsProxy.js +5 -1
- package/dist/harness/windsurfJetBrainsProxy.js.map +1 -1
- package/dist/index.d.ts +21 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -19
- package/dist/index.js.map +1 -1
- package/dist/inventory.d.ts +53 -0
- package/dist/inventory.d.ts.map +1 -0
- package/dist/inventory.js +133 -0
- package/dist/inventory.js.map +1 -0
- package/dist/lib/complianceProbes.d.ts +2 -1
- package/dist/lib/complianceProbes.d.ts.map +1 -1
- package/dist/lib/complianceProbes.js +1 -1
- package/dist/lib/complianceProbes.js.map +1 -1
- package/dist/lib/decisionsDigest.d.ts +35 -17
- package/dist/lib/decisionsDigest.d.ts.map +1 -1
- package/dist/lib/decisionsDigest.js +106 -47
- package/dist/lib/decisionsDigest.js.map +1 -1
- package/dist/lib/egressPolicy.d.ts +2 -2
- package/dist/lib/egressPolicy.js +2 -2
- package/dist/lib/mcpRegistryPy.d.ts +11 -0
- package/dist/lib/mcpRegistryPy.d.ts.map +1 -0
- package/dist/lib/mcpRegistryPy.js +173 -0
- package/dist/lib/mcpRegistryPy.js.map +1 -0
- package/dist/lib/phrasesPy.d.ts +11 -0
- package/dist/lib/phrasesPy.d.ts.map +1 -0
- package/dist/lib/phrasesPy.js +351 -0
- package/dist/lib/phrasesPy.js.map +1 -0
- package/dist/lib/policySnapshot.d.ts +63 -9
- package/dist/lib/policySnapshot.d.ts.map +1 -1
- package/dist/lib/policySnapshot.js +269 -45
- package/dist/lib/policySnapshot.js.map +1 -1
- package/dist/lib/processPoller.d.ts.map +1 -1
- package/dist/lib/processPoller.js +9 -2
- package/dist/lib/processPoller.js.map +1 -1
- package/dist/lib/regexLinearity.d.ts +43 -0
- package/dist/lib/regexLinearity.d.ts.map +1 -0
- package/dist/lib/regexLinearity.js +275 -0
- package/dist/lib/regexLinearity.js.map +1 -0
- package/dist/lib/runtimeEnv.d.ts +1 -3
- package/dist/lib/runtimeEnv.d.ts.map +1 -1
- package/dist/lib/runtimeEnv.js +0 -2
- package/dist/lib/runtimeEnv.js.map +1 -1
- package/dist/lib/sequencePy.d.ts +10 -0
- package/dist/lib/sequencePy.d.ts.map +1 -0
- package/dist/lib/sequencePy.js +102 -0
- package/dist/lib/sequencePy.js.map +1 -0
- package/dist/sessionReporter.d.ts +18 -12
- package/dist/sessionReporter.d.ts.map +1 -1
- package/dist/sessionReporter.js +37 -24
- package/dist/sessionReporter.js.map +1 -1
- package/dist/skillWriter.d.ts +23 -5
- package/dist/skillWriter.d.ts.map +1 -1
- package/dist/skillWriter.js +159 -16
- package/dist/skillWriter.js.map +1 -1
- package/dist/syncCycle.d.ts +142 -0
- package/dist/syncCycle.d.ts.map +1 -0
- package/dist/syncCycle.js +327 -0
- package/dist/syncCycle.js.map +1 -0
- package/dist/trajectoryMonitor.d.ts +2 -4
- package/dist/trajectoryMonitor.d.ts.map +1 -1
- package/dist/trajectoryMonitor.js +2 -5
- package/dist/trajectoryMonitor.js.map +1 -1
- package/dist/watcher/driftWatcher.d.ts +0 -1
- package/dist/watcher/driftWatcher.d.ts.map +1 -1
- package/dist/watcher/driftWatcher.js +1 -2
- package/dist/watcher/driftWatcher.js.map +1 -1
- package/dist/watcher/settingsGuard.d.ts +36 -7
- package/dist/watcher/settingsGuard.d.ts.map +1 -1
- package/dist/watcher/settingsGuard.js +397 -60
- package/dist/watcher/settingsGuard.js.map +1 -1
- package/dist/watcher/vscodeHookSettings.d.ts +30 -0
- package/dist/watcher/vscodeHookSettings.d.ts.map +1 -0
- package/dist/watcher/vscodeHookSettings.js +170 -0
- package/dist/watcher/vscodeHookSettings.js.map +1 -0
- package/dist/wsClient.d.ts +0 -1
- package/dist/wsClient.d.ts.map +1 -1
- package/dist/wsClient.js +0 -1
- package/dist/wsClient.js.map +1 -1
- package/package.json +5 -5
- package/dist/harness/claudeDesktopHooks.d.ts +0 -30
- package/dist/harness/claudeDesktopHooks.d.ts.map +0 -1
- package/dist/harness/claudeDesktopHooks.js +0 -254
- package/dist/harness/claudeDesktopHooks.js.map +0 -1
- package/dist/harness/continueHooks.d.ts +0 -63
- package/dist/harness/continueHooks.d.ts.map +0 -1
- package/dist/harness/continueHooks.js +0 -247
- package/dist/harness/continueHooks.js.map +0 -1
- package/dist/harness/gateKind.d.ts +0 -164
- package/dist/harness/gateKind.d.ts.map +0 -1
- package/dist/harness/gateKind.js +0 -144
- package/dist/harness/gateKind.js.map +0 -1
- package/dist/harness/rooCodeHooks.d.ts +0 -31
- package/dist/harness/rooCodeHooks.d.ts.map +0 -1
- package/dist/harness/rooCodeHooks.js +0 -286
- package/dist/harness/rooCodeHooks.js.map +0 -1
- 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,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* originals.ts — what a file looked like before Intutic first wrote to it.
|
|
3
|
+
*
|
|
4
|
+
* `intutic disconnect` puts every file `intutic connect` touched back the way
|
|
5
|
+
* it was. For an entry Intutic adds to a file the user owns (a hook
|
|
6
|
+
* registration, a wrapped MCP server) the entry itself says it is Intutic's.
|
|
7
|
+
* But some writes replace what was there: a rules file (`CLAUDE.md`,
|
|
8
|
+
* `AGENTS.md`, ...) is written whole, a proxy base URL overwrites the user's
|
|
9
|
+
* own, a deny list is replaced. Those can only be undone if the original was
|
|
10
|
+
* kept, so every such writer calls {@link keepOriginal} before it writes, and
|
|
11
|
+
* {@link noteWritten} after a write of a file it owns whole.
|
|
12
|
+
*
|
|
13
|
+
* One record per file, under `<root>/.intutic/originals/`, where `<root>` is
|
|
14
|
+
* the workspace for files inside it and the home directory for the rest:
|
|
15
|
+
*
|
|
16
|
+
* - `existed: false` — Intutic created the file (and `createdDirs`, the
|
|
17
|
+
* directories it had to make for it); disconnect deletes them.
|
|
18
|
+
* - `existed: true` — the bytes as they were, in a copy next to the record.
|
|
19
|
+
* - `writtenSha256` — what Intutic last wrote to a file it owns whole. A file
|
|
20
|
+
* that no longer matches was edited since, and disconnect leaves it alone
|
|
21
|
+
* rather than throw the edit away.
|
|
22
|
+
*
|
|
23
|
+
* Only the first record for a path is kept (created with O_EXCL, so two
|
|
24
|
+
* writers racing on one file cannot both claim it): the original is the file
|
|
25
|
+
* before Intutic's FIRST write, not before its latest one. A record per file,
|
|
26
|
+
* rather than one index, is what lets the MCP writers, which run in parallel,
|
|
27
|
+
* record without a lock.
|
|
28
|
+
*
|
|
29
|
+
* Best-effort by design: a failure to record must never stop the write it
|
|
30
|
+
* precedes. The cost is that disconnect then treats the file as one written
|
|
31
|
+
* by an earlier version, which kept no record.
|
|
32
|
+
*
|
|
33
|
+
* @module
|
|
34
|
+
*/
|
|
35
|
+
import * as node_fs from 'node:fs/promises';
|
|
36
|
+
import * as node_path from 'node:path';
|
|
37
|
+
import * as node_os from 'node:os';
|
|
38
|
+
import * as node_crypto from 'node:crypto';
|
|
39
|
+
export function sha256(content) {
|
|
40
|
+
return node_crypto.createHash('sha256').update(content).digest('hex');
|
|
41
|
+
}
|
|
42
|
+
/** The directory whose `.intutic/originals` holds `filePath`'s record. */
|
|
43
|
+
export function ledgerRootFor(filePath, workspaceRoot) {
|
|
44
|
+
const rel = node_path.relative(node_path.resolve(workspaceRoot), node_path.resolve(filePath));
|
|
45
|
+
return rel && !rel.startsWith('..') && !node_path.isAbsolute(rel) ? node_path.resolve(workspaceRoot) : node_os.homedir();
|
|
46
|
+
}
|
|
47
|
+
export function ledgerDir(root) {
|
|
48
|
+
return node_path.join(root, '.intutic', 'originals');
|
|
49
|
+
}
|
|
50
|
+
function recordBase(filePath, workspaceRoot) {
|
|
51
|
+
const abs = node_path.resolve(filePath);
|
|
52
|
+
return node_path.join(ledgerDir(ledgerRootFor(abs, workspaceRoot)), sha256(abs).slice(0, 32));
|
|
53
|
+
}
|
|
54
|
+
async function ensureLedgerDir(dir) {
|
|
55
|
+
await node_fs.mkdir(dir, { recursive: true, mode: 0o700 });
|
|
56
|
+
// A workspace's `.intutic/` may be committed; the copies here can hold
|
|
57
|
+
// whatever the user's config held, credentials included.
|
|
58
|
+
const ignore = node_path.join(dir, '.gitignore');
|
|
59
|
+
await node_fs.writeFile(ignore, '*\n', { flag: 'wx', mode: 0o600 }).catch(() => undefined);
|
|
60
|
+
}
|
|
61
|
+
async function readRecord(base) {
|
|
62
|
+
try {
|
|
63
|
+
return JSON.parse(await node_fs.readFile(`${base}.json`, 'utf-8'));
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** The directories between `root` and `filePath` that do not exist yet, outermost first. */
|
|
70
|
+
async function missingDirs(filePath, root) {
|
|
71
|
+
const out = [];
|
|
72
|
+
let dir = node_path.dirname(filePath);
|
|
73
|
+
while (dir !== root && dir.startsWith(root + node_path.sep)) {
|
|
74
|
+
try {
|
|
75
|
+
await node_fs.access(dir);
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
out.unshift(dir);
|
|
80
|
+
dir = node_path.dirname(dir);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Keeps `filePath` as it is now, unless an earlier call already did. Call it
|
|
87
|
+
* immediately before Intutic's write.
|
|
88
|
+
*/
|
|
89
|
+
export async function keepOriginal(filePath, workspaceRoot) {
|
|
90
|
+
try {
|
|
91
|
+
const abs = node_path.resolve(filePath);
|
|
92
|
+
const root = ledgerRootFor(abs, workspaceRoot);
|
|
93
|
+
const base = recordBase(abs, workspaceRoot);
|
|
94
|
+
try {
|
|
95
|
+
await node_fs.access(`${base}.json`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// No record yet.
|
|
100
|
+
}
|
|
101
|
+
let content = null;
|
|
102
|
+
let mode;
|
|
103
|
+
try {
|
|
104
|
+
content = await node_fs.readFile(abs);
|
|
105
|
+
mode = (await node_fs.stat(abs)).mode & 0o7777;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
content = null;
|
|
109
|
+
}
|
|
110
|
+
const record = { path: abs, existed: content !== null, recordedAt: new Date().toISOString() };
|
|
111
|
+
if (content === null) {
|
|
112
|
+
const dirs = await missingDirs(abs, root);
|
|
113
|
+
if (dirs.length > 0)
|
|
114
|
+
record.createdDirs = dirs;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
record.mode = mode;
|
|
118
|
+
}
|
|
119
|
+
await ensureLedgerDir(ledgerDir(root));
|
|
120
|
+
if (content !== null)
|
|
121
|
+
await node_fs.writeFile(`${base}.orig`, content, { mode: 0o600 });
|
|
122
|
+
await node_fs.writeFile(`${base}.json`, JSON.stringify(record, null, 2) + '\n', { flag: 'wx', mode: 0o600 });
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Best-effort; see the module doc.
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Notes what Intutic just wrote to a file it owns whole, so disconnect can
|
|
130
|
+
* tell a later edit apart; `meta` is merged into the record's.
|
|
131
|
+
*/
|
|
132
|
+
export async function noteWritten(filePath, workspaceRoot, content, meta) {
|
|
133
|
+
try {
|
|
134
|
+
const base = recordBase(filePath, workspaceRoot);
|
|
135
|
+
const record = await readRecord(base);
|
|
136
|
+
if (!record)
|
|
137
|
+
return;
|
|
138
|
+
const next = { ...record };
|
|
139
|
+
if (content !== null)
|
|
140
|
+
next.writtenSha256 = sha256(content);
|
|
141
|
+
if (meta)
|
|
142
|
+
next.meta = { ...(record.meta ?? {}), ...meta };
|
|
143
|
+
if (JSON.stringify(next) === JSON.stringify(record))
|
|
144
|
+
return;
|
|
145
|
+
const tmp = `${base}.${process.pid}.tmp`;
|
|
146
|
+
await node_fs.writeFile(tmp, JSON.stringify(next, null, 2) + '\n', { mode: 0o600 });
|
|
147
|
+
await node_fs.rename(tmp, `${base}.json`);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Best-effort; see the module doc.
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Writes a file Intutic owns whole, keeping the original first and noting
|
|
155
|
+
* what was written: the write every rules file, generated hook file and
|
|
156
|
+
* plugin goes through.
|
|
157
|
+
*/
|
|
158
|
+
export async function writeOwnedFile(filePath, workspaceRoot, content, mode) {
|
|
159
|
+
await keepOriginal(filePath, workspaceRoot);
|
|
160
|
+
await node_fs.mkdir(node_path.dirname(filePath), { recursive: true });
|
|
161
|
+
const tmp = `${filePath}.intutic-tmp`;
|
|
162
|
+
await node_fs.writeFile(tmp, content, 'utf-8');
|
|
163
|
+
if (mode !== undefined)
|
|
164
|
+
await node_fs.chmod(tmp, mode);
|
|
165
|
+
await node_fs.rename(tmp, filePath);
|
|
166
|
+
await noteWritten(filePath, workspaceRoot, content);
|
|
167
|
+
}
|
|
168
|
+
/** The record for `filePath`, with the saved bytes when the file existed. */
|
|
169
|
+
export async function readOriginal(filePath, workspaceRoot) {
|
|
170
|
+
const base = recordBase(filePath, workspaceRoot);
|
|
171
|
+
const record = await readRecord(base);
|
|
172
|
+
if (!record)
|
|
173
|
+
return null;
|
|
174
|
+
if (!record.existed)
|
|
175
|
+
return record;
|
|
176
|
+
try {
|
|
177
|
+
return { ...record, content: await node_fs.readFile(`${base}.orig`) };
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
// The copy is gone: the record can no longer restore anything.
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/** Forgets `filePath` once disconnect has dealt with it. */
|
|
185
|
+
export async function forgetOriginal(filePath, workspaceRoot) {
|
|
186
|
+
const base = recordBase(filePath, workspaceRoot);
|
|
187
|
+
await node_fs.rm(`${base}.json`, { force: true });
|
|
188
|
+
await node_fs.rm(`${base}.orig`, { force: true });
|
|
189
|
+
}
|
|
190
|
+
/** Every file recorded under `root`. */
|
|
191
|
+
export async function recordedFiles(root) {
|
|
192
|
+
let names;
|
|
193
|
+
try {
|
|
194
|
+
names = await node_fs.readdir(ledgerDir(root));
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
const out = [];
|
|
200
|
+
for (const name of names.filter((n) => n.endsWith('.json')).sort()) {
|
|
201
|
+
const record = await readRecord(node_path.join(ledgerDir(root), name.slice(0, -'.json'.length)));
|
|
202
|
+
if (record && typeof record.path === 'string')
|
|
203
|
+
out.push(record);
|
|
204
|
+
}
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
/** Removes `root`'s ledger directory once it holds no record, and `.intutic/` if that leaves it empty. */
|
|
208
|
+
export async function pruneLedger(root) {
|
|
209
|
+
const dir = ledgerDir(root);
|
|
210
|
+
try {
|
|
211
|
+
const left = (await node_fs.readdir(dir)).filter((n) => n !== '.gitignore');
|
|
212
|
+
if (left.length > 0)
|
|
213
|
+
return;
|
|
214
|
+
await node_fs.rm(node_path.join(dir, '.gitignore'), { force: true });
|
|
215
|
+
await node_fs.rmdir(dir);
|
|
216
|
+
await node_fs.rmdir(node_path.dirname(dir));
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
// Not empty, or already gone.
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// ─── Proxy URLs ──────────────────────────────────────────────────────────────
|
|
223
|
+
function proxyUrlsPath() {
|
|
224
|
+
return node_path.join(ledgerDir(node_os.homedir()), 'proxy-urls.json');
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Remembers a proxy URL connect wrote into harness configs. Disconnect uses
|
|
228
|
+
* the list to recognise a base-URL setting as Intutic's when no original was
|
|
229
|
+
* kept for it.
|
|
230
|
+
*/
|
|
231
|
+
export async function noteProxyUrl(url) {
|
|
232
|
+
try {
|
|
233
|
+
const known = await knownProxyUrls();
|
|
234
|
+
if (!url || known.includes(url))
|
|
235
|
+
return;
|
|
236
|
+
await ensureLedgerDir(ledgerDir(node_os.homedir()));
|
|
237
|
+
const tmp = `${proxyUrlsPath()}.${process.pid}.tmp`;
|
|
238
|
+
await node_fs.writeFile(tmp, JSON.stringify([...known, url], null, 2) + '\n', { mode: 0o600 });
|
|
239
|
+
await node_fs.rename(tmp, proxyUrlsPath());
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// Best-effort; see the module doc.
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
export async function knownProxyUrls() {
|
|
246
|
+
try {
|
|
247
|
+
const parsed = JSON.parse(await node_fs.readFile(proxyUrlsPath(), 'utf-8'));
|
|
248
|
+
return Array.isArray(parsed) ? parsed.filter((u) => typeof u === 'string') : [];
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
return [];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
export async function forgetProxyUrls() {
|
|
255
|
+
await node_fs.rm(proxyUrlsPath(), { force: true });
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=originals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"originals.js","sourceRoot":"","sources":["../../src/disconnect/originals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* plan.ts — the changes `intutic disconnect` will make, computed before any is
|
|
3
|
+
* made, so `--dry-run` prints exactly what a real run does.
|
|
4
|
+
*
|
|
5
|
+
* Every reverser adds to one {@link DisconnectPlan}. A change is either a
|
|
6
|
+
* file restored, rewritten or deleted, or a command run; a note is something
|
|
7
|
+
* left alone on purpose, with the reason. The helpers here cover the two
|
|
8
|
+
* shapes nearly every Intutic write takes:
|
|
9
|
+
*
|
|
10
|
+
* - {@link reverseOwnedFile}: a file Intutic writes whole (a rules file, a
|
|
11
|
+
* gate script, a hook definition it owns).
|
|
12
|
+
* - {@link reverseStructuredFile}: a JSON, YAML or TOML file the user owns
|
|
13
|
+
* that Intutic merges entries into.
|
|
14
|
+
*
|
|
15
|
+
* Both consult the record `originals.ts` kept, and both end the same way: a
|
|
16
|
+
* file that comes out semantically equal to its original gets the original
|
|
17
|
+
* bytes back, so an untouched file is restored exactly even where Intutic's
|
|
18
|
+
* write had reformatted it.
|
|
19
|
+
*
|
|
20
|
+
* @module
|
|
21
|
+
*/
|
|
22
|
+
import { type Document } from 'yaml';
|
|
23
|
+
import { type OriginalRecord } from './originals.js';
|
|
24
|
+
export interface PlannedChange {
|
|
25
|
+
path: string;
|
|
26
|
+
/** What happens, in the words `--dry-run` prints. */
|
|
27
|
+
describe: string;
|
|
28
|
+
/** Housekeeping (forgetting a record) that is not worth printing. */
|
|
29
|
+
quiet?: boolean;
|
|
30
|
+
apply: () => Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export interface PlanNote {
|
|
33
|
+
path: string;
|
|
34
|
+
message: string;
|
|
35
|
+
}
|
|
36
|
+
export declare class DisconnectPlan {
|
|
37
|
+
readonly changes: PlannedChange[];
|
|
38
|
+
readonly notes: PlanNote[];
|
|
39
|
+
change(path: string, describe: string, apply: () => Promise<void>): void;
|
|
40
|
+
quiet(path: string, apply: () => Promise<void>): void;
|
|
41
|
+
note(path: string, message: string): void;
|
|
42
|
+
private readonly claimed;
|
|
43
|
+
/**
|
|
44
|
+
* Claims `path` for one reverser. A file several writers touch is reversed
|
|
45
|
+
* in one pass; a second claim (another harness listing the same file)
|
|
46
|
+
* gets false and must leave it to the first.
|
|
47
|
+
*/
|
|
48
|
+
claim(path: string): boolean;
|
|
49
|
+
/** The changes a user should see, without the housekeeping. */
|
|
50
|
+
visible(): PlannedChange[];
|
|
51
|
+
private readonly emptyDirs;
|
|
52
|
+
/**
|
|
53
|
+
* Removes `dir` after every change has run, if nothing is left in it. Only
|
|
54
|
+
* for directories named for Intutic (`.intutic/hooks`, a plugin directory
|
|
55
|
+
* called `intutic-governance`) and ones a record says Intutic created: a
|
|
56
|
+
* directory created for one file may hold another Intutic file deleted
|
|
57
|
+
* later in the run, so it is retried at the end.
|
|
58
|
+
*/
|
|
59
|
+
removeIfEmpty(dir: string): void;
|
|
60
|
+
/** Runs every change in order, then the directory clean-up, deepest directory first. */
|
|
61
|
+
apply(): Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
export declare function readText(file: string): Promise<string | null>;
|
|
64
|
+
/** Deletes `file`, then each directory in `dirs` (deepest first) that is left empty. */
|
|
65
|
+
export declare function deleteFile(file: string, dirs?: string[]): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* The version of `file` committed at HEAD, when it is tracked in a git
|
|
68
|
+
* repository; null otherwise.
|
|
69
|
+
*/
|
|
70
|
+
export declare function committedVersion(file: string): Buffer | null;
|
|
71
|
+
/**
|
|
72
|
+
* Plans the reversal of a file Intutic writes whole.
|
|
73
|
+
*
|
|
74
|
+
* With a record: an unedited file gets its original back, or is deleted
|
|
75
|
+
* along with the directories Intutic made for it; an edited one stays, with
|
|
76
|
+
* a note. Without one (an earlier version wrote it): a file `isOurs` does not
|
|
77
|
+
* recognise is not Intutic's and is left alone; one it does is deleted when
|
|
78
|
+
* untracked, or put back to the committed version when git has one that is
|
|
79
|
+
* not Intutic's.
|
|
80
|
+
*/
|
|
81
|
+
export declare function reverseOwnedFile(plan: DisconnectPlan, file: string, workspaceRoot: string, isOurs: (text: string) => boolean, options?: {
|
|
82
|
+
beforeApply?: () => Promise<void>;
|
|
83
|
+
}): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* How to read and write one config format. Edits work on the plain-object
|
|
86
|
+
* form (`toJS`); `write` turns the edited object back into text, keeping
|
|
87
|
+
* whatever the format can of the file around the edits.
|
|
88
|
+
*/
|
|
89
|
+
export interface StructuredFormat<H> {
|
|
90
|
+
parse(raw: string): H;
|
|
91
|
+
toJS(handle: H): JsonObject;
|
|
92
|
+
/** `original` is the parsed original, when a record was kept: a format can copy its layout back. */
|
|
93
|
+
write(handle: H, next: JsonObject, raw: string, original: H | null): string;
|
|
94
|
+
}
|
|
95
|
+
export type JsonObject = Record<string, unknown>;
|
|
96
|
+
export declare const jsonFormat: StructuredFormat<JsonObject>;
|
|
97
|
+
/**
|
|
98
|
+
* YAML through `yaml`'s Document: the edit is applied to the document node
|
|
99
|
+
* by node, so comments and layout away from the edited keys survive.
|
|
100
|
+
*/
|
|
101
|
+
export declare const yamlFormat: StructuredFormat<Document>;
|
|
102
|
+
/** Rebuilds `doc`'s top-level keys in `original`'s order, the rest after them as they were. */
|
|
103
|
+
export declare function orderLike(doc: JsonObject, original: JsonObject): void;
|
|
104
|
+
/** TOML through smol-toml. Comments are lost on a rewrite, as they were on Intutic's own write. */
|
|
105
|
+
export declare const tomlFormat: StructuredFormat<JsonObject>;
|
|
106
|
+
export declare function isObject(v: unknown): v is JsonObject;
|
|
107
|
+
/** Whether `js` holds nothing: no keys, or only empty objects and arrays. */
|
|
108
|
+
export declare function isEmptyValue(js: unknown): boolean;
|
|
109
|
+
export interface ReverseContext {
|
|
110
|
+
/** The file as it was before Intutic first wrote it, when a record was kept. */
|
|
111
|
+
original: JsonObject | null;
|
|
112
|
+
record: OriginalRecord | null;
|
|
113
|
+
/** The format's parsed form, for an edit that works on it directly (a YAML list). */
|
|
114
|
+
handle: unknown;
|
|
115
|
+
note(message: string): void;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Plans the reversal of Intutic's entries in a JSON, YAML or TOML file the
|
|
119
|
+
* user owns. `edit` removes them from `doc` in place and reports whether it
|
|
120
|
+
* changed anything.
|
|
121
|
+
*
|
|
122
|
+
* The result is written only if `edit` changed something. A result equal to
|
|
123
|
+
* the original gets the original bytes; a file Intutic created that ends up
|
|
124
|
+
* empty is deleted; a file with no record that ends up empty is deleted only
|
|
125
|
+
* when `deleteIfEmptyWithoutRecord` says an earlier version created it.
|
|
126
|
+
*/
|
|
127
|
+
export declare function reverseStructuredFile<H>(plan: DisconnectPlan, file: string, workspaceRoot: string, format: StructuredFormat<H>, edit: (doc: JsonObject, ctx: ReverseContext) => boolean, options?: {
|
|
128
|
+
deleteIfEmptyWithoutRecord?: boolean;
|
|
129
|
+
}): Promise<void>;
|
|
130
|
+
/**
|
|
131
|
+
* Plans the reversal of Intutic's lines in a text config edited line by line
|
|
132
|
+
* (Codex's and OpenHands' TOML, where a rewrite through a parser would drop
|
|
133
|
+
* the user's comments). `edit` returns the new text, or null for no change;
|
|
134
|
+
* `parse` is only used to compare: a result that means the same as the
|
|
135
|
+
* original gets the original bytes back.
|
|
136
|
+
*/
|
|
137
|
+
export declare function reverseTextFile(plan: DisconnectPlan, file: string, workspaceRoot: string, parse: (text: string) => unknown, edit: (text: string, ctx: {
|
|
138
|
+
originalText: string | null;
|
|
139
|
+
note(message: string): void;
|
|
140
|
+
}) => string | null): Promise<void>;
|
|
141
|
+
/** Reads the value at `path`; array elements are addressed by their index. */
|
|
142
|
+
export declare function getPath(obj: unknown, path: readonly string[]): unknown;
|
|
143
|
+
/** Sets `path` to `value`, creating objects on the way. */
|
|
144
|
+
export declare function setPath(doc: JsonObject, path: readonly string[], value: unknown): void;
|
|
145
|
+
/** Removes the key at `path`. Array elements are never removed this way: it would renumber their siblings. */
|
|
146
|
+
export declare function deletePath(doc: JsonObject, path: readonly string[]): boolean;
|
|
147
|
+
/**
|
|
148
|
+
* Walks up from `path`, removing each empty object or array that the
|
|
149
|
+
* original did not have (with no original, every empty one: Intutic made it).
|
|
150
|
+
*/
|
|
151
|
+
export declare function pruneEmpty(doc: JsonObject, path: readonly string[], original: JsonObject | null): void;
|
|
152
|
+
/**
|
|
153
|
+
* Removes the elements of the array at `path` that `isOurs` claims. An array
|
|
154
|
+
* (and each parent object) left empty is removed too, unless the original
|
|
155
|
+
* had it there.
|
|
156
|
+
*/
|
|
157
|
+
export declare function removeFromArray(doc: JsonObject, path: readonly string[], isOurs: (entry: unknown) => boolean, original: JsonObject | null): boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Puts a key Intutic overwrote back. With an original, the key gets the
|
|
160
|
+
* original's value, or is removed when the original had none. Without one,
|
|
161
|
+
* the key is removed (the earlier value is unknown, and the harness's
|
|
162
|
+
* default is closer to it than Intutic's), with a note saying so. Only a key
|
|
163
|
+
* whose current value `isIntutic` recognises is touched: anything else was
|
|
164
|
+
* set since by someone else.
|
|
165
|
+
*/
|
|
166
|
+
export declare function restoreKey(doc: JsonObject, path: readonly string[], ctx: Pick<ReverseContext, 'original' | 'note'>, isIntutic: (value: unknown) => boolean): boolean;
|
|
167
|
+
/**
|
|
168
|
+
* Applies {@link restoreKey} to every string value in `doc` that `isIntutic`
|
|
169
|
+
* recognises, wherever it sits — for writers that set a proxy URL on every
|
|
170
|
+
* model, or on whichever key a pattern happened to match.
|
|
171
|
+
*/
|
|
172
|
+
export declare function restoreMatchingValues(doc: JsonObject, ctx: Pick<ReverseContext, 'original' | 'note'>, isIntutic: (value: unknown) => boolean): boolean;
|
|
173
|
+
/** Runs every edit (none short-circuits the others) and reports whether any changed something. */
|
|
174
|
+
export declare function allEdits(...results: boolean[]): boolean;
|
|
175
|
+
//# sourceMappingURL=plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/disconnect/plan.ts"],"names":[],"mappings":"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"}
|