@clinebot/core 0.0.22 → 0.0.24

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 (260) hide show
  1. package/dist/ClineCore.d.ts +110 -0
  2. package/dist/ClineCore.d.ts.map +1 -0
  3. package/dist/account/cline-account-service.d.ts +2 -1
  4. package/dist/account/cline-account-service.d.ts.map +1 -1
  5. package/dist/account/index.d.ts +1 -1
  6. package/dist/account/index.d.ts.map +1 -1
  7. package/dist/account/rpc.d.ts +3 -1
  8. package/dist/account/rpc.d.ts.map +1 -1
  9. package/dist/account/types.d.ts +3 -0
  10. package/dist/account/types.d.ts.map +1 -1
  11. package/dist/agents/plugin-loader.d.ts.map +1 -1
  12. package/dist/agents/plugin-sandbox-bootstrap.js +17 -17
  13. package/dist/auth/client.d.ts +1 -1
  14. package/dist/auth/client.d.ts.map +1 -1
  15. package/dist/auth/cline.d.ts +1 -1
  16. package/dist/auth/cline.d.ts.map +1 -1
  17. package/dist/auth/codex.d.ts +1 -1
  18. package/dist/auth/codex.d.ts.map +1 -1
  19. package/dist/auth/oca.d.ts +1 -1
  20. package/dist/auth/oca.d.ts.map +1 -1
  21. package/dist/auth/utils.d.ts +2 -2
  22. package/dist/auth/utils.d.ts.map +1 -1
  23. package/dist/index.d.ts +50 -5
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +949 -0
  26. package/dist/providers/local-provider-service.d.ts +4 -4
  27. package/dist/providers/local-provider-service.d.ts.map +1 -1
  28. package/dist/runtime/runtime-builder.d.ts +1 -0
  29. package/dist/runtime/runtime-builder.d.ts.map +1 -1
  30. package/dist/runtime/session-runtime.d.ts +2 -1
  31. package/dist/runtime/session-runtime.d.ts.map +1 -1
  32. package/dist/runtime/team-runtime-registry.d.ts +13 -0
  33. package/dist/runtime/team-runtime-registry.d.ts.map +1 -0
  34. package/dist/session/default-session-manager.d.ts +2 -2
  35. package/dist/session/default-session-manager.d.ts.map +1 -1
  36. package/dist/session/rpc-runtime-ensure.d.ts +53 -0
  37. package/dist/session/rpc-runtime-ensure.d.ts.map +1 -0
  38. package/dist/session/session-config-builder.d.ts +2 -3
  39. package/dist/session/session-config-builder.d.ts.map +1 -1
  40. package/dist/session/session-host.d.ts +8 -18
  41. package/dist/session/session-host.d.ts.map +1 -1
  42. package/dist/session/session-manager.d.ts +1 -1
  43. package/dist/session/session-manager.d.ts.map +1 -1
  44. package/dist/session/session-manifest.d.ts +1 -2
  45. package/dist/session/session-manifest.d.ts.map +1 -1
  46. package/dist/session/unified-session-persistence-service.d.ts +2 -2
  47. package/dist/session/unified-session-persistence-service.d.ts.map +1 -1
  48. package/dist/session/utils/helpers.d.ts +1 -1
  49. package/dist/session/utils/helpers.d.ts.map +1 -1
  50. package/dist/session/utils/types.d.ts +1 -1
  51. package/dist/session/utils/types.d.ts.map +1 -1
  52. package/dist/storage/provider-settings-legacy-migration.d.ts.map +1 -1
  53. package/dist/telemetry/OpenTelemetryProvider.d.ts.map +1 -1
  54. package/dist/telemetry/distinct-id.d.ts +2 -0
  55. package/dist/telemetry/distinct-id.d.ts.map +1 -0
  56. package/dist/telemetry/{opentelemetry.d.ts → index.d.ts} +1 -1
  57. package/dist/telemetry/index.d.ts.map +1 -0
  58. package/dist/telemetry/index.js +28 -0
  59. package/dist/tools/constants.d.ts +1 -1
  60. package/dist/tools/constants.d.ts.map +1 -1
  61. package/dist/tools/definitions.d.ts +3 -3
  62. package/dist/tools/definitions.d.ts.map +1 -1
  63. package/dist/tools/executors/apply-patch.d.ts +1 -1
  64. package/dist/tools/executors/apply-patch.d.ts.map +1 -1
  65. package/dist/tools/executors/bash.d.ts +1 -1
  66. package/dist/tools/executors/bash.d.ts.map +1 -1
  67. package/dist/tools/executors/editor.d.ts +1 -1
  68. package/dist/tools/executors/editor.d.ts.map +1 -1
  69. package/dist/tools/executors/file-read.d.ts +1 -1
  70. package/dist/tools/executors/file-read.d.ts.map +1 -1
  71. package/dist/tools/executors/index.d.ts +14 -14
  72. package/dist/tools/executors/index.d.ts.map +1 -1
  73. package/dist/tools/executors/search.d.ts +1 -1
  74. package/dist/tools/executors/search.d.ts.map +1 -1
  75. package/dist/tools/executors/web-fetch.d.ts +1 -1
  76. package/dist/tools/executors/web-fetch.d.ts.map +1 -1
  77. package/dist/tools/helpers.d.ts +1 -1
  78. package/dist/tools/helpers.d.ts.map +1 -1
  79. package/dist/tools/index.d.ts +10 -10
  80. package/dist/tools/index.d.ts.map +1 -1
  81. package/dist/tools/model-tool-routing.d.ts +1 -1
  82. package/dist/tools/model-tool-routing.d.ts.map +1 -1
  83. package/dist/tools/presets.d.ts +1 -1
  84. package/dist/tools/presets.d.ts.map +1 -1
  85. package/dist/types/common.d.ts +17 -8
  86. package/dist/types/common.d.ts.map +1 -1
  87. package/dist/types/config.d.ts +4 -3
  88. package/dist/types/config.d.ts.map +1 -1
  89. package/dist/types/provider-settings.d.ts +1 -1
  90. package/dist/types/provider-settings.d.ts.map +1 -1
  91. package/dist/types.d.ts +5 -2
  92. package/dist/types.d.ts.map +1 -1
  93. package/dist/version.d.ts +2 -0
  94. package/dist/version.d.ts.map +1 -0
  95. package/package.json +44 -38
  96. package/src/ClineCore.ts +137 -0
  97. package/src/account/cline-account-service.test.ts +101 -0
  98. package/src/account/cline-account-service.ts +300 -0
  99. package/src/account/featurebase-token.test.ts +175 -0
  100. package/src/account/index.ts +23 -0
  101. package/src/account/rpc.test.ts +63 -0
  102. package/src/account/rpc.ts +185 -0
  103. package/src/account/types.ts +102 -0
  104. package/src/agents/agent-config-loader.test.ts +236 -0
  105. package/src/agents/agent-config-loader.ts +108 -0
  106. package/src/agents/agent-config-parser.ts +198 -0
  107. package/src/agents/hooks-config-loader.test.ts +20 -0
  108. package/src/agents/hooks-config-loader.ts +118 -0
  109. package/src/agents/index.ts +85 -0
  110. package/src/agents/plugin-config-loader.test.ts +140 -0
  111. package/src/agents/plugin-config-loader.ts +97 -0
  112. package/src/agents/plugin-loader.test.ts +210 -0
  113. package/src/agents/plugin-loader.ts +175 -0
  114. package/src/agents/plugin-sandbox-bootstrap.ts +448 -0
  115. package/src/agents/plugin-sandbox.test.ts +296 -0
  116. package/src/agents/plugin-sandbox.ts +341 -0
  117. package/src/agents/unified-config-file-watcher.test.ts +196 -0
  118. package/src/agents/unified-config-file-watcher.ts +483 -0
  119. package/src/agents/user-instruction-config-loader.test.ts +158 -0
  120. package/src/agents/user-instruction-config-loader.ts +438 -0
  121. package/src/auth/client.test.ts +40 -0
  122. package/src/auth/client.ts +25 -0
  123. package/src/auth/cline.test.ts +130 -0
  124. package/src/auth/cline.ts +420 -0
  125. package/src/auth/codex.test.ts +170 -0
  126. package/src/auth/codex.ts +491 -0
  127. package/src/auth/oca.test.ts +215 -0
  128. package/src/auth/oca.ts +573 -0
  129. package/src/auth/server.ts +216 -0
  130. package/src/auth/types.ts +81 -0
  131. package/src/auth/utils.test.ts +128 -0
  132. package/src/auth/utils.ts +247 -0
  133. package/src/chat/chat-schema.ts +82 -0
  134. package/src/index.ts +479 -0
  135. package/src/input/file-indexer.d.ts +11 -0
  136. package/src/input/file-indexer.test.ts +127 -0
  137. package/src/input/file-indexer.ts +327 -0
  138. package/src/input/index.ts +7 -0
  139. package/src/input/mention-enricher.test.ts +85 -0
  140. package/src/input/mention-enricher.ts +122 -0
  141. package/src/mcp/config-loader.test.ts +238 -0
  142. package/src/mcp/config-loader.ts +219 -0
  143. package/src/mcp/index.ts +26 -0
  144. package/src/mcp/manager.test.ts +106 -0
  145. package/src/mcp/manager.ts +262 -0
  146. package/src/mcp/types.ts +88 -0
  147. package/src/providers/local-provider-registry.ts +232 -0
  148. package/src/providers/local-provider-service.test.ts +783 -0
  149. package/src/providers/local-provider-service.ts +471 -0
  150. package/src/runtime/commands.test.ts +98 -0
  151. package/src/runtime/commands.ts +83 -0
  152. package/src/runtime/hook-file-hooks.test.ts +237 -0
  153. package/src/runtime/hook-file-hooks.ts +859 -0
  154. package/src/runtime/index.ts +37 -0
  155. package/src/runtime/rules.ts +34 -0
  156. package/src/runtime/runtime-builder.team-persistence.test.ts +245 -0
  157. package/src/runtime/runtime-builder.test.ts +371 -0
  158. package/src/runtime/runtime-builder.ts +631 -0
  159. package/src/runtime/runtime-parity.test.ts +143 -0
  160. package/src/runtime/sandbox/subprocess-sandbox.ts +231 -0
  161. package/src/runtime/session-runtime.ts +49 -0
  162. package/src/runtime/skills.ts +44 -0
  163. package/src/runtime/team-runtime-registry.ts +46 -0
  164. package/src/runtime/tool-approval.ts +104 -0
  165. package/src/runtime/workflows.test.ts +119 -0
  166. package/src/runtime/workflows.ts +45 -0
  167. package/src/session/default-session-manager.e2e.test.ts +384 -0
  168. package/src/session/default-session-manager.test.ts +1931 -0
  169. package/src/session/default-session-manager.ts +1422 -0
  170. package/src/session/file-session-service.ts +280 -0
  171. package/src/session/index.ts +45 -0
  172. package/src/session/rpc-runtime-ensure.ts +521 -0
  173. package/src/session/rpc-session-service.ts +107 -0
  174. package/src/session/rpc-spawn-lease.test.ts +49 -0
  175. package/src/session/rpc-spawn-lease.ts +122 -0
  176. package/src/session/runtime-oauth-token-manager.test.ts +137 -0
  177. package/src/session/runtime-oauth-token-manager.ts +272 -0
  178. package/src/session/session-agent-events.ts +248 -0
  179. package/src/session/session-artifacts.ts +106 -0
  180. package/src/session/session-config-builder.ts +113 -0
  181. package/src/session/session-graph.ts +92 -0
  182. package/src/session/session-host.test.ts +89 -0
  183. package/src/session/session-host.ts +205 -0
  184. package/src/session/session-manager.ts +69 -0
  185. package/src/session/session-manifest.ts +29 -0
  186. package/src/session/session-service.team-persistence.test.ts +48 -0
  187. package/src/session/session-service.ts +673 -0
  188. package/src/session/session-team-coordination.ts +229 -0
  189. package/src/session/session-telemetry.ts +100 -0
  190. package/src/session/sqlite-rpc-session-backend.ts +303 -0
  191. package/src/session/unified-session-persistence-service.test.ts +85 -0
  192. package/src/session/unified-session-persistence-service.ts +994 -0
  193. package/src/session/utils/helpers.ts +139 -0
  194. package/src/session/utils/types.ts +57 -0
  195. package/src/session/utils/usage.ts +32 -0
  196. package/src/session/workspace-manager.ts +98 -0
  197. package/src/session/workspace-manifest.ts +100 -0
  198. package/src/storage/artifact-store.ts +1 -0
  199. package/src/storage/file-team-store.ts +257 -0
  200. package/src/storage/index.ts +11 -0
  201. package/src/storage/provider-settings-legacy-migration.test.ts +424 -0
  202. package/src/storage/provider-settings-legacy-migration.ts +826 -0
  203. package/src/storage/provider-settings-manager.test.ts +191 -0
  204. package/src/storage/provider-settings-manager.ts +152 -0
  205. package/src/storage/session-store.ts +1 -0
  206. package/src/storage/sqlite-session-store.ts +275 -0
  207. package/src/storage/sqlite-team-store.ts +454 -0
  208. package/src/storage/team-store.ts +40 -0
  209. package/src/team/index.ts +4 -0
  210. package/src/team/projections.ts +285 -0
  211. package/src/telemetry/ITelemetryAdapter.ts +94 -0
  212. package/src/telemetry/LoggerTelemetryAdapter.test.ts +42 -0
  213. package/src/telemetry/LoggerTelemetryAdapter.ts +114 -0
  214. package/src/telemetry/OpenTelemetryAdapter.test.ts +157 -0
  215. package/src/telemetry/OpenTelemetryAdapter.ts +348 -0
  216. package/src/telemetry/OpenTelemetryProvider.test.ts +113 -0
  217. package/src/telemetry/OpenTelemetryProvider.ts +325 -0
  218. package/src/telemetry/TelemetryService.test.ts +134 -0
  219. package/src/telemetry/TelemetryService.ts +141 -0
  220. package/src/telemetry/core-events.ts +400 -0
  221. package/src/telemetry/distinct-id.test.ts +57 -0
  222. package/src/telemetry/distinct-id.ts +58 -0
  223. package/src/telemetry/index.ts +20 -0
  224. package/src/tools/constants.ts +35 -0
  225. package/src/tools/definitions.test.ts +704 -0
  226. package/src/tools/definitions.ts +709 -0
  227. package/src/tools/executors/apply-patch-parser.ts +520 -0
  228. package/src/tools/executors/apply-patch.ts +359 -0
  229. package/src/tools/executors/bash.test.ts +87 -0
  230. package/src/tools/executors/bash.ts +207 -0
  231. package/src/tools/executors/editor.test.ts +35 -0
  232. package/src/tools/executors/editor.ts +219 -0
  233. package/src/tools/executors/file-read.test.ts +49 -0
  234. package/src/tools/executors/file-read.ts +110 -0
  235. package/src/tools/executors/index.ts +87 -0
  236. package/src/tools/executors/search.ts +278 -0
  237. package/src/tools/executors/web-fetch.ts +259 -0
  238. package/src/tools/helpers.ts +130 -0
  239. package/src/tools/index.ts +169 -0
  240. package/src/tools/model-tool-routing.test.ts +86 -0
  241. package/src/tools/model-tool-routing.ts +132 -0
  242. package/src/tools/presets.test.ts +62 -0
  243. package/src/tools/presets.ts +168 -0
  244. package/src/tools/schemas.ts +327 -0
  245. package/src/tools/types.ts +329 -0
  246. package/src/types/common.ts +26 -0
  247. package/src/types/config.ts +86 -0
  248. package/src/types/events.ts +74 -0
  249. package/src/types/index.ts +24 -0
  250. package/src/types/provider-settings.ts +43 -0
  251. package/src/types/sessions.ts +16 -0
  252. package/src/types/storage.ts +64 -0
  253. package/src/types/workspace.ts +7 -0
  254. package/src/types.ts +132 -0
  255. package/src/version.ts +3 -0
  256. package/dist/index.node.d.ts +0 -47
  257. package/dist/index.node.d.ts.map +0 -1
  258. package/dist/index.node.js +0 -948
  259. package/dist/telemetry/opentelemetry.d.ts.map +0 -1
  260. package/dist/telemetry/opentelemetry.js +0 -27
@@ -0,0 +1,520 @@
1
+ /**
2
+ * Apply Patch parser and patch model types.
3
+ *
4
+ * This parser supports the Cline apply_patch format used by the legacy runtime.
5
+ */
6
+
7
+ export const PATCH_MARKERS = {
8
+ BEGIN: "*** Begin Patch",
9
+ END: "*** End Patch",
10
+ ADD: "*** Add File: ",
11
+ UPDATE: "*** Update File: ",
12
+ DELETE: "*** Delete File: ",
13
+ MOVE: "*** Move to: ",
14
+ SECTION: "@@",
15
+ END_FILE: "*** End of File",
16
+ } as const;
17
+
18
+ export const BASH_WRAPPERS = ["%%bash", "apply_patch", "EOF", "```"] as const;
19
+
20
+ export enum PatchActionType {
21
+ ADD = "add",
22
+ DELETE = "delete",
23
+ UPDATE = "update",
24
+ }
25
+
26
+ export interface PatchChunk {
27
+ origIndex: number;
28
+ delLines: string[];
29
+ insLines: string[];
30
+ }
31
+
32
+ export interface PatchAction {
33
+ type: PatchActionType;
34
+ newFile?: string;
35
+ chunks: PatchChunk[];
36
+ movePath?: string;
37
+ }
38
+
39
+ export interface PatchWarning {
40
+ path: string;
41
+ chunkIndex?: number;
42
+ message: string;
43
+ context?: string;
44
+ }
45
+
46
+ export interface Patch {
47
+ actions: Record<string, PatchAction>;
48
+ warnings?: PatchWarning[];
49
+ }
50
+
51
+ export class DiffError extends Error {
52
+ constructor(message: string) {
53
+ super(message);
54
+ this.name = "DiffError";
55
+ }
56
+ }
57
+
58
+ function canonicalize(input: string): string {
59
+ const punctuationMap: Record<string, string> = {
60
+ "\u2010": "-",
61
+ "\u2011": "-",
62
+ "\u2012": "-",
63
+ "\u2013": "-",
64
+ "\u2014": "-",
65
+ "\u2212": "-",
66
+ "\u201C": '"',
67
+ "\u201D": '"',
68
+ "\u201E": '"',
69
+ "\u00AB": '"',
70
+ "\u00BB": '"',
71
+ "\u2018": "'",
72
+ "\u2019": "'",
73
+ "\u201B": "'",
74
+ "\u00A0": " ",
75
+ "\u202F": " ",
76
+ };
77
+ return input
78
+ .normalize("NFC")
79
+ .replace(/./gu, (char) => punctuationMap[char] ?? char)
80
+ .replace(/\\`/g, "`")
81
+ .replace(/\\'/g, "'")
82
+ .replace(/\\"/g, '"');
83
+ }
84
+
85
+ export class PatchParser {
86
+ private patch: Patch = { actions: {}, warnings: [] };
87
+ private index = 0;
88
+ private fuzz = 0;
89
+ private currentPath?: string;
90
+
91
+ constructor(
92
+ private readonly lines: string[],
93
+ private readonly currentFiles: Record<string, string>,
94
+ ) {}
95
+
96
+ parse(): { patch: Patch; fuzz: number } {
97
+ this.skipBeginSentinel();
98
+
99
+ while (this.hasMoreLines() && !this.isEndMarker()) {
100
+ this.parseNextAction();
101
+ }
102
+
103
+ if (this.patch.warnings?.length === 0) {
104
+ delete this.patch.warnings;
105
+ }
106
+
107
+ return { patch: this.patch, fuzz: this.fuzz };
108
+ }
109
+
110
+ private addWarning(warning: PatchWarning): void {
111
+ if (!this.patch.warnings) {
112
+ this.patch.warnings = [];
113
+ }
114
+ this.patch.warnings.push(warning);
115
+ }
116
+
117
+ private skipBeginSentinel(): void {
118
+ if (this.lines[this.index]?.startsWith(PATCH_MARKERS.BEGIN)) {
119
+ this.index++;
120
+ }
121
+ }
122
+
123
+ private hasMoreLines(): boolean {
124
+ return this.index < this.lines.length;
125
+ }
126
+
127
+ private isEndMarker(): boolean {
128
+ return this.lines[this.index]?.startsWith(PATCH_MARKERS.END) ?? false;
129
+ }
130
+
131
+ private parseNextAction(): void {
132
+ const line = this.lines[this.index];
133
+ if (line?.startsWith(PATCH_MARKERS.UPDATE)) {
134
+ this.parseUpdate(line.substring(PATCH_MARKERS.UPDATE.length).trim());
135
+ return;
136
+ }
137
+ if (line?.startsWith(PATCH_MARKERS.DELETE)) {
138
+ this.parseDelete(line.substring(PATCH_MARKERS.DELETE.length).trim());
139
+ return;
140
+ }
141
+ if (line?.startsWith(PATCH_MARKERS.ADD)) {
142
+ this.parseAdd(line.substring(PATCH_MARKERS.ADD.length).trim());
143
+ return;
144
+ }
145
+ throw new DiffError(`Unknown line while parsing: ${line}`);
146
+ }
147
+
148
+ private checkDuplicate(path: string, operation: string): void {
149
+ if (path in this.patch.actions) {
150
+ throw new DiffError(`Duplicate ${operation} for file: ${path}`);
151
+ }
152
+ }
153
+
154
+ private parseUpdate(path: string): void {
155
+ this.checkDuplicate(path, "update");
156
+ this.currentPath = path;
157
+
158
+ this.index++;
159
+ const movePath = this.lines[this.index]?.startsWith(PATCH_MARKERS.MOVE)
160
+ ? (this.lines[this.index++] ?? "")
161
+ .substring(PATCH_MARKERS.MOVE.length)
162
+ .trim()
163
+ : undefined;
164
+
165
+ if (!(path in this.currentFiles)) {
166
+ throw new DiffError(`Update File Error: Missing File: ${path}`);
167
+ }
168
+
169
+ const text = this.currentFiles[path] ?? "";
170
+ const action = this.parseUpdateFile(text, path);
171
+ action.movePath = movePath;
172
+ this.patch.actions[path] = action;
173
+ this.currentPath = undefined;
174
+ }
175
+
176
+ private parseUpdateFile(text: string, path: string): PatchAction {
177
+ const action: PatchAction = { type: PatchActionType.UPDATE, chunks: [] };
178
+ const fileLines = text.split("\n");
179
+ let index = 0;
180
+
181
+ const stopMarkers = [
182
+ PATCH_MARKERS.END,
183
+ PATCH_MARKERS.UPDATE,
184
+ PATCH_MARKERS.DELETE,
185
+ PATCH_MARKERS.ADD,
186
+ PATCH_MARKERS.END_FILE,
187
+ ];
188
+
189
+ while (
190
+ !stopMarkers.some((marker) =>
191
+ this.lines[this.index]?.startsWith(marker.trim()),
192
+ )
193
+ ) {
194
+ const currentLine = this.lines[this.index];
195
+ const defStr = currentLine?.startsWith("@@ ")
196
+ ? currentLine.substring(3)
197
+ : undefined;
198
+ const sectionStr = currentLine === "@@" ? currentLine : undefined;
199
+
200
+ if (defStr !== undefined || sectionStr !== undefined) {
201
+ this.index++;
202
+ } else if (index !== 0) {
203
+ throw new DiffError(`Invalid Line:\n${this.lines[this.index]}`);
204
+ }
205
+
206
+ if (defStr?.trim()) {
207
+ const canonDefStr = canonicalize(defStr.trim());
208
+ for (let i = index; i < fileLines.length; i++) {
209
+ const fileLine = fileLines[i];
210
+ if (
211
+ fileLine &&
212
+ (canonicalize(fileLine) === canonDefStr ||
213
+ canonicalize(fileLine.trim()) === canonDefStr)
214
+ ) {
215
+ index = i + 1;
216
+ if (
217
+ canonicalize(fileLine.trim()) === canonDefStr &&
218
+ canonicalize(fileLine) !== canonDefStr
219
+ ) {
220
+ this.fuzz++;
221
+ }
222
+ break;
223
+ }
224
+ }
225
+ }
226
+
227
+ const [nextChunkContext, chunks, endPatchIndex, eof] = peek(
228
+ this.lines,
229
+ this.index,
230
+ );
231
+ const [newIndex, fuzz, similarity] = findContext(
232
+ fileLines,
233
+ nextChunkContext,
234
+ index,
235
+ eof,
236
+ );
237
+
238
+ if (newIndex === -1) {
239
+ const contextText = nextChunkContext.join("\n");
240
+ this.addWarning({
241
+ path: this.currentPath || path,
242
+ chunkIndex: action.chunks.length,
243
+ message: `Could not find matching context (similarity: ${similarity.toFixed(2)}). Chunk skipped.`,
244
+ context:
245
+ contextText.length > 200
246
+ ? `${contextText.substring(0, 200)}...`
247
+ : contextText,
248
+ });
249
+ this.index = endPatchIndex;
250
+ } else {
251
+ this.fuzz += fuzz;
252
+ for (const chunk of chunks) {
253
+ chunk.origIndex += newIndex;
254
+ action.chunks.push(chunk);
255
+ }
256
+ index = newIndex + nextChunkContext.length;
257
+ this.index = endPatchIndex;
258
+ }
259
+ }
260
+
261
+ return action;
262
+ }
263
+
264
+ private parseDelete(path: string): void {
265
+ this.checkDuplicate(path, "delete");
266
+ if (!(path in this.currentFiles)) {
267
+ throw new DiffError(`Delete File Error: Missing File: ${path}`);
268
+ }
269
+ this.patch.actions[path] = { type: PatchActionType.DELETE, chunks: [] };
270
+ this.index++;
271
+ }
272
+
273
+ private parseAdd(path: string): void {
274
+ this.checkDuplicate(path, "add");
275
+ if (path in this.currentFiles) {
276
+ throw new DiffError(`Add File Error: File already exists: ${path}`);
277
+ }
278
+
279
+ this.index++;
280
+ const lines: string[] = [];
281
+ const stopMarkers = [
282
+ PATCH_MARKERS.END,
283
+ PATCH_MARKERS.UPDATE,
284
+ PATCH_MARKERS.DELETE,
285
+ PATCH_MARKERS.ADD,
286
+ ];
287
+
288
+ while (
289
+ this.hasMoreLines() &&
290
+ !stopMarkers.some((marker) =>
291
+ this.lines[this.index]?.startsWith(marker.trim()),
292
+ )
293
+ ) {
294
+ const line = this.lines[this.index++];
295
+ if (line === undefined) {
296
+ break;
297
+ }
298
+ if (!line.startsWith("+")) {
299
+ throw new DiffError(`Invalid Add File line (missing '+'): ${line}`);
300
+ }
301
+ lines.push(line.substring(1));
302
+ }
303
+
304
+ this.patch.actions[path] = {
305
+ type: PatchActionType.ADD,
306
+ newFile: lines.join("\n"),
307
+ chunks: [],
308
+ };
309
+ }
310
+ }
311
+
312
+ function calculateSimilarity(str1: string, str2: string): number {
313
+ const longer = str1.length > str2.length ? str1 : str2;
314
+ const shorter = str1.length > str2.length ? str2 : str1;
315
+ if (longer.length === 0) {
316
+ return 1;
317
+ }
318
+ const editDistance = levenshteinDistance(shorter, longer);
319
+ return (longer.length - editDistance) / longer.length;
320
+ }
321
+
322
+ function levenshteinDistance(str1: string, str2: string): number {
323
+ const rows = str2.length + 1;
324
+ const cols = str1.length + 1;
325
+ const matrix = new Array<number>(rows * cols).fill(0);
326
+ const at = (r: number, c: number): number => matrix[r * cols + c] ?? 0;
327
+ const set = (r: number, c: number, value: number): void => {
328
+ matrix[r * cols + c] = value;
329
+ };
330
+
331
+ for (let i = 0; i <= str2.length; i++) set(i, 0, i);
332
+ for (let j = 0; j <= str1.length; j++) set(0, j, j);
333
+
334
+ for (let i = 1; i <= str2.length; i++) {
335
+ for (let j = 1; j <= str1.length; j++) {
336
+ if (str2[i - 1] === str1[j - 1]) {
337
+ set(i, j, at(i - 1, j - 1));
338
+ } else {
339
+ set(i, j, 1 + Math.min(at(i - 1, j - 1), at(i, j - 1), at(i - 1, j)));
340
+ }
341
+ }
342
+ }
343
+
344
+ return at(str2.length, str1.length);
345
+ }
346
+
347
+ function findContext(
348
+ lines: string[],
349
+ context: string[],
350
+ start: number,
351
+ eof: boolean,
352
+ ): [number, number, number] {
353
+ if (context.length === 0) {
354
+ return [start, 0, 1];
355
+ }
356
+
357
+ let bestSimilarity = 0;
358
+ const findCore = (startIdx: number): [number, number, number] => {
359
+ const canonicalContext = canonicalize(context.join("\n"));
360
+
361
+ for (let i = startIdx; i < lines.length; i++) {
362
+ const segment = canonicalize(
363
+ lines.slice(i, i + context.length).join("\n"),
364
+ );
365
+ if (segment === canonicalContext) {
366
+ return [i, 0, 1];
367
+ }
368
+ const similarity = calculateSimilarity(segment, canonicalContext);
369
+ if (similarity > bestSimilarity) {
370
+ bestSimilarity = similarity;
371
+ }
372
+ }
373
+
374
+ for (let i = startIdx; i < lines.length; i++) {
375
+ const segment = canonicalize(
376
+ lines
377
+ .slice(i, i + context.length)
378
+ .map((line) => line.trimEnd())
379
+ .join("\n"),
380
+ );
381
+ const canonicalTrimmed = canonicalize(
382
+ context.map((line) => line.trimEnd()).join("\n"),
383
+ );
384
+ if (segment === canonicalTrimmed) {
385
+ return [i, 1, 1];
386
+ }
387
+ }
388
+
389
+ for (let i = startIdx; i < lines.length; i++) {
390
+ const segment = canonicalize(
391
+ lines
392
+ .slice(i, i + context.length)
393
+ .map((line) => line.trim())
394
+ .join("\n"),
395
+ );
396
+ const canonicalTrimmed = canonicalize(
397
+ context.map((line) => line.trim()).join("\n"),
398
+ );
399
+ if (segment === canonicalTrimmed) {
400
+ return [i, 100, 1];
401
+ }
402
+ }
403
+
404
+ const similarityThreshold = 0.66;
405
+ for (let i = startIdx; i < lines.length; i++) {
406
+ const segment = canonicalize(
407
+ lines.slice(i, i + context.length).join("\n"),
408
+ );
409
+ const similarity = calculateSimilarity(segment, canonicalContext);
410
+ if (similarity >= similarityThreshold) {
411
+ return [i, 1000, similarity];
412
+ }
413
+ if (similarity > bestSimilarity) {
414
+ bestSimilarity = similarity;
415
+ }
416
+ }
417
+
418
+ return [-1, 0, bestSimilarity];
419
+ };
420
+
421
+ if (eof) {
422
+ let [newIndex, fuzz, similarity] = findCore(lines.length - context.length);
423
+ if (newIndex !== -1) {
424
+ return [newIndex, fuzz, similarity];
425
+ }
426
+ [newIndex, fuzz, similarity] = findCore(start);
427
+ return [newIndex, fuzz + 10000, similarity];
428
+ }
429
+
430
+ return findCore(start);
431
+ }
432
+
433
+ type PeekResult = [string[], PatchChunk[], number, boolean];
434
+
435
+ function peek(lines: string[], initialIndex: number): PeekResult {
436
+ let index = initialIndex;
437
+ const old: string[] = [];
438
+ let delLines: string[] = [];
439
+ let insLines: string[] = [];
440
+ const chunks: PatchChunk[] = [];
441
+ let mode: "keep" | "add" | "delete" = "keep";
442
+
443
+ const stopMarkers = [
444
+ "@@",
445
+ PATCH_MARKERS.END,
446
+ PATCH_MARKERS.UPDATE,
447
+ PATCH_MARKERS.DELETE,
448
+ PATCH_MARKERS.ADD,
449
+ PATCH_MARKERS.END_FILE,
450
+ ];
451
+
452
+ while (index < lines.length) {
453
+ const sourceLine = lines[index];
454
+ if (
455
+ !sourceLine ||
456
+ stopMarkers.some((marker) => sourceLine.startsWith(marker.trim()))
457
+ ) {
458
+ break;
459
+ }
460
+ if (sourceLine === "***") {
461
+ break;
462
+ }
463
+ if (sourceLine.startsWith("***")) {
464
+ throw new DiffError(`Invalid line: ${sourceLine}`);
465
+ }
466
+
467
+ index++;
468
+ const previousMode: "keep" | "add" | "delete" = mode;
469
+ let line = sourceLine;
470
+
471
+ if (line[0] === "+") {
472
+ mode = "add";
473
+ } else if (line[0] === "-") {
474
+ mode = "delete";
475
+ } else if (line[0] === " ") {
476
+ mode = "keep";
477
+ } else {
478
+ mode = "keep";
479
+ line = ` ${line}`;
480
+ }
481
+
482
+ line = line.slice(1);
483
+
484
+ if (mode === "keep" && previousMode !== mode) {
485
+ if (insLines.length || delLines.length) {
486
+ chunks.push({
487
+ origIndex: old.length - delLines.length,
488
+ delLines,
489
+ insLines,
490
+ });
491
+ }
492
+ delLines = [];
493
+ insLines = [];
494
+ }
495
+
496
+ if (mode === "delete") {
497
+ delLines.push(line);
498
+ old.push(line);
499
+ } else if (mode === "add") {
500
+ insLines.push(line);
501
+ } else {
502
+ old.push(line);
503
+ }
504
+ }
505
+
506
+ if (insLines.length || delLines.length) {
507
+ chunks.push({
508
+ origIndex: old.length - delLines.length,
509
+ delLines,
510
+ insLines,
511
+ });
512
+ }
513
+
514
+ if (index < lines.length && lines[index] === PATCH_MARKERS.END_FILE) {
515
+ index++;
516
+ return [old, chunks, index, true];
517
+ }
518
+
519
+ return [old, chunks, index, false];
520
+ }