@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.
Files changed (206) hide show
  1. package/dist/agentReporter.d.ts +5 -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/configReader.d.ts +44 -22
  6. package/dist/configReader.d.ts.map +1 -1
  7. package/dist/configReader.js +70 -44
  8. package/dist/configReader.js.map +1 -1
  9. package/dist/configWriter.d.ts +29 -41
  10. package/dist/configWriter.d.ts.map +1 -1
  11. package/dist/configWriter.js +28 -625
  12. package/dist/configWriter.js.map +1 -1
  13. package/dist/disconnect/harnesses.d.ts +31 -0
  14. package/dist/disconnect/harnesses.d.ts.map +1 -0
  15. package/dist/disconnect/harnesses.js +728 -0
  16. package/dist/disconnect/harnesses.js.map +1 -0
  17. package/dist/disconnect/index.d.ts +25 -0
  18. package/dist/disconnect/index.d.ts.map +1 -0
  19. package/dist/disconnect/index.js +82 -0
  20. package/dist/disconnect/index.js.map +1 -0
  21. package/dist/disconnect/mcp.d.ts +60 -0
  22. package/dist/disconnect/mcp.d.ts.map +1 -0
  23. package/dist/disconnect/mcp.js +283 -0
  24. package/dist/disconnect/mcp.js.map +1 -0
  25. package/dist/disconnect/originals.d.ts +88 -0
  26. package/dist/disconnect/originals.d.ts.map +1 -0
  27. package/dist/disconnect/originals.js +257 -0
  28. package/dist/disconnect/originals.js.map +1 -0
  29. package/dist/disconnect/plan.d.ts +175 -0
  30. package/dist/disconnect/plan.d.ts.map +1 -0
  31. package/dist/disconnect/plan.js +580 -0
  32. package/dist/disconnect/plan.js.map +1 -0
  33. package/dist/disconnect/recognise.d.ts +43 -0
  34. package/dist/disconnect/recognise.d.ts.map +1 -0
  35. package/dist/disconnect/recognise.js +98 -0
  36. package/dist/disconnect/recognise.js.map +1 -0
  37. package/dist/disconnect/tomlLines.d.ts +39 -0
  38. package/dist/disconnect/tomlLines.d.ts.map +1 -0
  39. package/dist/disconnect/tomlLines.js +105 -0
  40. package/dist/disconnect/tomlLines.js.map +1 -0
  41. package/dist/harness/aiderConfigMerger.d.ts +42 -5
  42. package/dist/harness/aiderConfigMerger.d.ts.map +1 -1
  43. package/dist/harness/aiderConfigMerger.js +113 -86
  44. package/dist/harness/aiderConfigMerger.js.map +1 -1
  45. package/dist/harness/antigravityHooks.d.ts +13 -8
  46. package/dist/harness/antigravityHooks.d.ts.map +1 -1
  47. package/dist/harness/antigravityHooks.js +53 -39
  48. package/dist/harness/antigravityHooks.js.map +1 -1
  49. package/dist/harness/claudeCodeHooks.d.ts +1 -2
  50. package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
  51. package/dist/harness/claudeCodeHooks.js +61 -34
  52. package/dist/harness/claudeCodeHooks.js.map +1 -1
  53. package/dist/harness/claudeDesktopHooks.d.ts +3 -0
  54. package/dist/harness/claudeDesktopHooks.d.ts.map +1 -1
  55. package/dist/harness/claudeDesktopHooks.js +3 -1
  56. package/dist/harness/claudeDesktopHooks.js.map +1 -1
  57. package/dist/harness/claudeProjectApproval.d.ts +53 -0
  58. package/dist/harness/claudeProjectApproval.d.ts.map +1 -0
  59. package/dist/harness/claudeProjectApproval.js +159 -0
  60. package/dist/harness/claudeProjectApproval.js.map +1 -0
  61. package/dist/harness/clineHooks.d.ts +39 -9
  62. package/dist/harness/clineHooks.d.ts.map +1 -1
  63. package/dist/harness/clineHooks.js +142 -60
  64. package/dist/harness/clineHooks.js.map +1 -1
  65. package/dist/harness/codexConfigMerger.d.ts +38 -0
  66. package/dist/harness/codexConfigMerger.d.ts.map +1 -0
  67. package/dist/harness/codexConfigMerger.js +105 -0
  68. package/dist/harness/codexConfigMerger.js.map +1 -0
  69. package/dist/harness/codexHooks.d.ts +4 -2
  70. package/dist/harness/codexHooks.d.ts.map +1 -1
  71. package/dist/harness/codexHooks.js +14 -11
  72. package/dist/harness/codexHooks.js.map +1 -1
  73. package/dist/harness/continueConfigMerger.d.ts +46 -0
  74. package/dist/harness/continueConfigMerger.d.ts.map +1 -0
  75. package/dist/harness/continueConfigMerger.js +94 -0
  76. package/dist/harness/continueConfigMerger.js.map +1 -0
  77. package/dist/harness/continueHooks.d.ts +15 -25
  78. package/dist/harness/continueHooks.d.ts.map +1 -1
  79. package/dist/harness/continueHooks.js +25 -119
  80. package/dist/harness/continueHooks.js.map +1 -1
  81. package/dist/harness/cursorHooks.d.ts +33 -16
  82. package/dist/harness/cursorHooks.d.ts.map +1 -1
  83. package/dist/harness/cursorHooks.js +69 -25
  84. package/dist/harness/cursorHooks.js.map +1 -1
  85. package/dist/harness/dshHooks.d.ts +59 -52
  86. package/dist/harness/dshHooks.d.ts.map +1 -1
  87. package/dist/harness/dshHooks.js +152 -147
  88. package/dist/harness/dshHooks.js.map +1 -1
  89. package/dist/harness/gateBody.d.ts +11 -2
  90. package/dist/harness/gateBody.d.ts.map +1 -1
  91. package/dist/harness/gateBody.js +33 -6
  92. package/dist/harness/gateBody.js.map +1 -1
  93. package/dist/harness/gateKind.d.ts.map +1 -1
  94. package/dist/harness/gateKind.js +1 -0
  95. package/dist/harness/gateKind.js.map +1 -1
  96. package/dist/harness/githubCopilotHooks.d.ts.map +1 -1
  97. package/dist/harness/githubCopilotHooks.js +5 -10
  98. package/dist/harness/githubCopilotHooks.js.map +1 -1
  99. package/dist/harness/gooseHooks.d.ts +15 -0
  100. package/dist/harness/gooseHooks.d.ts.map +1 -1
  101. package/dist/harness/gooseHooks.js +55 -43
  102. package/dist/harness/gooseHooks.js.map +1 -1
  103. package/dist/harness/grokHooks.d.ts.map +1 -1
  104. package/dist/harness/grokHooks.js +14 -12
  105. package/dist/harness/grokHooks.js.map +1 -1
  106. package/dist/harness/hermesHooks.d.ts +9 -0
  107. package/dist/harness/hermesHooks.d.ts.map +1 -1
  108. package/dist/harness/hermesHooks.js +39 -33
  109. package/dist/harness/hermesHooks.js.map +1 -1
  110. package/dist/harness/holdRedaction.d.ts +4 -1
  111. package/dist/harness/holdRedaction.d.ts.map +1 -1
  112. package/dist/harness/holdRedaction.js +32 -8
  113. package/dist/harness/holdRedaction.js.map +1 -1
  114. package/dist/harness/jetbrainsXmlConfig.d.ts +20 -0
  115. package/dist/harness/jetbrainsXmlConfig.d.ts.map +1 -1
  116. package/dist/harness/jetbrainsXmlConfig.js +39 -18
  117. package/dist/harness/jetbrainsXmlConfig.js.map +1 -1
  118. package/dist/harness/jsonMergeTarget.d.ts +23 -0
  119. package/dist/harness/jsonMergeTarget.d.ts.map +1 -0
  120. package/dist/harness/jsonMergeTarget.js +50 -0
  121. package/dist/harness/jsonMergeTarget.js.map +1 -0
  122. package/dist/harness/mcpAutoWrite.d.ts +64 -20
  123. package/dist/harness/mcpAutoWrite.d.ts.map +1 -1
  124. package/dist/harness/mcpAutoWrite.js +429 -85
  125. package/dist/harness/mcpAutoWrite.js.map +1 -1
  126. package/dist/harness/museHooks.d.ts.map +1 -1
  127. package/dist/harness/museHooks.js +6 -2
  128. package/dist/harness/museHooks.js.map +1 -1
  129. package/dist/harness/n8nHooks.d.ts.map +1 -1
  130. package/dist/harness/n8nHooks.js +6 -7
  131. package/dist/harness/n8nHooks.js.map +1 -1
  132. package/dist/harness/openCodeHooks.d.ts +37 -6
  133. package/dist/harness/openCodeHooks.d.ts.map +1 -1
  134. package/dist/harness/openCodeHooks.js +103 -13
  135. package/dist/harness/openCodeHooks.js.map +1 -1
  136. package/dist/harness/openWebuiHooks.d.ts.map +1 -1
  137. package/dist/harness/openWebuiHooks.js +10 -5
  138. package/dist/harness/openWebuiHooks.js.map +1 -1
  139. package/dist/harness/openclawHooks.d.ts +5 -0
  140. package/dist/harness/openclawHooks.d.ts.map +1 -1
  141. package/dist/harness/openclawHooks.js +3 -1
  142. package/dist/harness/openclawHooks.js.map +1 -1
  143. package/dist/harness/openhandsHooks.d.ts +26 -1
  144. package/dist/harness/openhandsHooks.d.ts.map +1 -1
  145. package/dist/harness/openhandsHooks.js +160 -40
  146. package/dist/harness/openhandsHooks.js.map +1 -1
  147. package/dist/harness/piHooks.d.ts +17 -0
  148. package/dist/harness/piHooks.d.ts.map +1 -1
  149. package/dist/harness/piHooks.js +31 -29
  150. package/dist/harness/piHooks.js.map +1 -1
  151. package/dist/harness/protectedPaths.d.ts +64 -6
  152. package/dist/harness/protectedPaths.d.ts.map +1 -1
  153. package/dist/harness/protectedPaths.js +161 -11
  154. package/dist/harness/protectedPaths.js.map +1 -1
  155. package/dist/harness/rooCodeHooks.d.ts.map +1 -1
  156. package/dist/harness/rooCodeHooks.js +5 -10
  157. package/dist/harness/rooCodeHooks.js.map +1 -1
  158. package/dist/harness/windsurfHooks.d.ts +21 -3
  159. package/dist/harness/windsurfHooks.d.ts.map +1 -1
  160. package/dist/harness/windsurfHooks.js +96 -44
  161. package/dist/harness/windsurfHooks.js.map +1 -1
  162. package/dist/harness/windsurfJetBrainsProxy.d.ts +10 -7
  163. package/dist/harness/windsurfJetBrainsProxy.d.ts.map +1 -1
  164. package/dist/harness/windsurfJetBrainsProxy.js +22 -7
  165. package/dist/harness/windsurfJetBrainsProxy.js.map +1 -1
  166. package/dist/index.d.ts +12 -12
  167. package/dist/index.d.ts.map +1 -1
  168. package/dist/index.js +11 -10
  169. package/dist/index.js.map +1 -1
  170. package/dist/lib/decisionsDigest.d.ts +1 -1
  171. package/dist/lib/decisionsDigest.js +1 -1
  172. package/dist/lib/policySnapshot.d.ts +37 -0
  173. package/dist/lib/policySnapshot.d.ts.map +1 -1
  174. package/dist/lib/policySnapshot.js +170 -8
  175. package/dist/lib/policySnapshot.js.map +1 -1
  176. package/dist/sessionReporter.d.ts +2 -2
  177. package/dist/sessionReporter.js +2 -2
  178. package/dist/syncCycle.d.ts +142 -0
  179. package/dist/syncCycle.d.ts.map +1 -0
  180. package/dist/syncCycle.js +315 -0
  181. package/dist/syncCycle.js.map +1 -0
  182. package/dist/trajectoryMonitor.d.ts +1 -1
  183. package/dist/trajectoryMonitor.d.ts.map +1 -1
  184. package/dist/trajectoryMonitor.js +1 -1
  185. package/dist/trajectoryMonitor.js.map +1 -1
  186. package/dist/watcher/settingsGuard.d.ts +4 -1
  187. package/dist/watcher/settingsGuard.d.ts.map +1 -1
  188. package/dist/watcher/settingsGuard.js +42 -18
  189. package/dist/watcher/settingsGuard.js.map +1 -1
  190. package/package.json +6 -6
  191. package/dist/hashReporter.d.ts +0 -33
  192. package/dist/hashReporter.d.ts.map +0 -1
  193. package/dist/hashReporter.js +0 -69
  194. package/dist/hashReporter.js.map +0 -1
  195. package/dist/integrityStore.d.ts +0 -35
  196. package/dist/integrityStore.d.ts.map +0 -1
  197. package/dist/integrityStore.js +0 -71
  198. package/dist/integrityStore.js.map +0 -1
  199. package/dist/lib/gitWorktrees.d.ts +0 -140
  200. package/dist/lib/gitWorktrees.d.ts.map +0 -1
  201. package/dist/lib/gitWorktrees.js +0 -191
  202. package/dist/lib/gitWorktrees.js.map +0 -1
  203. package/dist/syncLoop.d.ts +0 -172
  204. package/dist/syncLoop.d.ts.map +0 -1
  205. package/dist/syncLoop.js +0 -878
  206. package/dist/syncLoop.js.map +0 -1
@@ -0,0 +1,88 @@
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
+ export interface OriginalRecord {
36
+ /** Absolute path of the file this record is for. */
37
+ path: string;
38
+ /** Whether the file existed before Intutic first wrote it. */
39
+ existed: boolean;
40
+ /** Its permission bits then, so a restore keeps them. */
41
+ mode?: number;
42
+ /** Directories Intutic created to hold the file, outermost first. */
43
+ createdDirs?: string[];
44
+ /** SHA-256 of what Intutic last wrote, for files it owns whole. */
45
+ writtenSha256?: string;
46
+ /** Writer-specific detail disconnect needs, e.g. the deny rules Intutic added. */
47
+ meta?: Record<string, unknown>;
48
+ recordedAt: string;
49
+ }
50
+ export declare function sha256(content: string | Buffer): string;
51
+ /** The directory whose `.intutic/originals` holds `filePath`'s record. */
52
+ export declare function ledgerRootFor(filePath: string, workspaceRoot: string): string;
53
+ export declare function ledgerDir(root: string): string;
54
+ /**
55
+ * Keeps `filePath` as it is now, unless an earlier call already did. Call it
56
+ * immediately before Intutic's write.
57
+ */
58
+ export declare function keepOriginal(filePath: string, workspaceRoot: string): Promise<void>;
59
+ /**
60
+ * Notes what Intutic just wrote to a file it owns whole, so disconnect can
61
+ * tell a later edit apart; `meta` is merged into the record's.
62
+ */
63
+ export declare function noteWritten(filePath: string, workspaceRoot: string, content: string | Buffer | null, meta?: Record<string, unknown>): Promise<void>;
64
+ /**
65
+ * Writes a file Intutic owns whole, keeping the original first and noting
66
+ * what was written: the write every rules file, generated hook file and
67
+ * plugin goes through.
68
+ */
69
+ export declare function writeOwnedFile(filePath: string, workspaceRoot: string, content: string, mode?: number): Promise<void>;
70
+ /** The record for `filePath`, with the saved bytes when the file existed. */
71
+ export declare function readOriginal(filePath: string, workspaceRoot: string): Promise<(OriginalRecord & {
72
+ content?: Buffer;
73
+ }) | null>;
74
+ /** Forgets `filePath` once disconnect has dealt with it. */
75
+ export declare function forgetOriginal(filePath: string, workspaceRoot: string): Promise<void>;
76
+ /** Every file recorded under `root`. */
77
+ export declare function recordedFiles(root: string): Promise<OriginalRecord[]>;
78
+ /** Removes `root`'s ledger directory once it holds no record, and `.intutic/` if that leaves it empty. */
79
+ export declare function pruneLedger(root: string): Promise<void>;
80
+ /**
81
+ * Remembers a proxy URL connect wrote into harness configs. Disconnect uses
82
+ * the list to recognise a base-URL setting as Intutic's when no original was
83
+ * kept for it.
84
+ */
85
+ export declare function noteProxyUrl(url: string): Promise<void>;
86
+ export declare function knownProxyUrls(): Promise<string[]>;
87
+ export declare function forgetProxyUrls(): Promise<void>;
88
+ //# sourceMappingURL=originals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"originals.d.ts","sourceRoot":"","sources":["../../src/disconnect/originals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAOH,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ,8DAA8D;IAC9D,OAAO,EAAE,OAAO,CAAA;IAChB,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAEvD;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAG7E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAuCD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCzF;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAC/B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ3H;AAED,6EAA6E;AAC7E,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,CAAC,cAAc,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,IAAI,CAAC,CAWzD;AAED,4DAA4D;AAC5D,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI3F;AAED,wCAAwC;AACxC,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAa3E;AAED,0GAA0G;AAC1G,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW7D;AAQD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW7D;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAOxD;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAErD"}
@@ -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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"}