clanka 0.0.21 → 0.0.22

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/src/AgentTools.ts CHANGED
@@ -86,7 +86,7 @@ export const AgentTools = Toolkit.make(
86
86
  }),
87
87
  Tool.make("applyPatch", {
88
88
  description:
89
- "Apply a git diff / unified diff patch across one or more files.",
89
+ "Apply a git diff / unified diff patch, or a wrapped apply_patch patch, across one or more files.",
90
90
  parameters: Schema.String.annotate({
91
91
  identifier: "patch",
92
92
  }),
@@ -131,6 +131,9 @@ export const AgentTools = Toolkit.make(
131
131
  glob: Schema.optional(Schema.String).annotate({
132
132
  documentation: "--glob",
133
133
  }),
134
+ noIgnore: Schema.optional(Schema.Boolean).annotate({
135
+ documentation: "--no-ignore",
136
+ }),
134
137
  maxLines: Schema.optional(Schema.Finite).annotate({
135
138
  documentation:
136
139
  "The total maximum number of lines to return across all files (default: 500)",
@@ -301,6 +304,9 @@ export const AgentToolHandlers = AgentTools.toLayer(
301
304
  if (options.glob) {
302
305
  args.push("--glob", options.glob)
303
306
  }
307
+ if (options.noIgnore) {
308
+ args.push("--no-ignore")
309
+ }
304
310
  args.push(options.pattern)
305
311
  let stream = pipe(
306
312
  spawner.streamLines(
@@ -192,6 +192,344 @@ describe("patchContent", () => {
192
192
  ])
193
193
  })
194
194
 
195
+ it("parses larger realistic multi-file unified diffs", () => {
196
+ expect(
197
+ parsePatch(
198
+ [
199
+ "diff --git a/dist/index.js b/dist/index.js",
200
+ "index f33510a..e887a60 100644",
201
+ "--- a/dist/index.js",
202
+ "+++ b/dist/index.js",
203
+ "@@ -1,7 +1,12 @@",
204
+ " if (reasoningStarted && !textStarted) {",
205
+ " controller.enqueue({",
206
+ ' type: "reasoning-end",',
207
+ "- id: reasoningId || generateId()",
208
+ "+ id: reasoningId || generateId(),",
209
+ "+ providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
210
+ "+ openrouter: {",
211
+ "+ reasoning_details: accumulatedReasoningDetails",
212
+ "+ }",
213
+ "+ } : undefined",
214
+ " });",
215
+ " }",
216
+ "@@ -20,7 +25,12 @@",
217
+ " if (reasoningStarted) {",
218
+ " controller.enqueue({",
219
+ ' type: "reasoning-end",',
220
+ "- id: reasoningId || generateId()",
221
+ "+ id: reasoningId || generateId(),",
222
+ "+ providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
223
+ "+ openrouter: {",
224
+ "+ reasoning_details: accumulatedReasoningDetails",
225
+ "+ }",
226
+ "+ } : undefined",
227
+ " });",
228
+ " }",
229
+ "diff --git a/dist/index.mjs b/dist/index.mjs",
230
+ "index 8a68833..6310cb8 100644",
231
+ "--- a/dist/index.mjs",
232
+ "+++ b/dist/index.mjs",
233
+ "@@ -1,7 +1,12 @@",
234
+ " if (reasoningStarted && !textStarted) {",
235
+ " controller.enqueue({",
236
+ ' type: "reasoning-end",',
237
+ "- id: reasoningId || generateId()",
238
+ "+ id: reasoningId || generateId(),",
239
+ "+ providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
240
+ "+ openrouter: {",
241
+ "+ reasoning_details: accumulatedReasoningDetails",
242
+ "+ }",
243
+ "+ } : undefined",
244
+ " });",
245
+ " }",
246
+ "@@ -20,7 +25,12 @@",
247
+ " if (reasoningStarted) {",
248
+ " controller.enqueue({",
249
+ ' type: "reasoning-end",',
250
+ "- id: reasoningId || generateId()",
251
+ "+ id: reasoningId || generateId(),",
252
+ "+ providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
253
+ "+ openrouter: {",
254
+ "+ reasoning_details: accumulatedReasoningDetails",
255
+ "+ }",
256
+ "+ } : undefined",
257
+ " });",
258
+ " }",
259
+ "diff --git a/dist/internal/index.js b/dist/internal/index.js",
260
+ "index d40fa66..8dd86d1 100644",
261
+ "--- a/dist/internal/index.js",
262
+ "+++ b/dist/internal/index.js",
263
+ "@@ -1,7 +1,12 @@",
264
+ " if (reasoningStarted && !textStarted) {",
265
+ " controller.enqueue({",
266
+ ' type: "reasoning-end",',
267
+ "- id: reasoningId || generateId()",
268
+ "+ id: reasoningId || generateId(),",
269
+ "+ providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
270
+ "+ openrouter: {",
271
+ "+ reasoning_details: accumulatedReasoningDetails",
272
+ "+ }",
273
+ "+ } : undefined",
274
+ " });",
275
+ " }",
276
+ "@@ -20,7 +25,12 @@",
277
+ " if (reasoningStarted) {",
278
+ " controller.enqueue({",
279
+ ' type: "reasoning-end",',
280
+ "- id: reasoningId || generateId()",
281
+ "+ id: reasoningId || generateId(),",
282
+ "+ providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
283
+ "+ openrouter: {",
284
+ "+ reasoning_details: accumulatedReasoningDetails",
285
+ "+ }",
286
+ "+ } : undefined",
287
+ " });",
288
+ " }",
289
+ "diff --git a/dist/internal/index.mjs b/dist/internal/index.mjs",
290
+ "index b0ed9d1..5695930 100644",
291
+ "--- a/dist/internal/index.mjs",
292
+ "+++ b/dist/internal/index.mjs",
293
+ "@@ -1,7 +1,12 @@",
294
+ " if (reasoningStarted && !textStarted) {",
295
+ " controller.enqueue({",
296
+ ' type: "reasoning-end",',
297
+ "- id: reasoningId || generateId()",
298
+ "+ id: reasoningId || generateId(),",
299
+ "+ providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
300
+ "+ openrouter: {",
301
+ "+ reasoning_details: accumulatedReasoningDetails",
302
+ "+ }",
303
+ "+ } : undefined",
304
+ " });",
305
+ " }",
306
+ "@@ -20,7 +25,12 @@",
307
+ " if (reasoningStarted) {",
308
+ " controller.enqueue({",
309
+ ' type: "reasoning-end",',
310
+ "- id: reasoningId || generateId()",
311
+ "+ id: reasoningId || generateId(),",
312
+ "+ providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
313
+ "+ openrouter: {",
314
+ "+ reasoning_details: accumulatedReasoningDetails",
315
+ "+ }",
316
+ "+ } : undefined",
317
+ " });",
318
+ " }",
319
+ ].join("\n"),
320
+ ),
321
+ ).toEqual([
322
+ {
323
+ type: "update",
324
+ path: "dist/index.js",
325
+ chunks: [
326
+ {
327
+ old: [
328
+ "if (reasoningStarted && !textStarted) {",
329
+ " controller.enqueue({",
330
+ ' type: "reasoning-end",',
331
+ " id: reasoningId || generateId()",
332
+ " });",
333
+ "}",
334
+ ],
335
+ next: [
336
+ "if (reasoningStarted && !textStarted) {",
337
+ " controller.enqueue({",
338
+ ' type: "reasoning-end",',
339
+ " id: reasoningId || generateId(),",
340
+ " providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
341
+ " openrouter: {",
342
+ " reasoning_details: accumulatedReasoningDetails",
343
+ " }",
344
+ " } : undefined",
345
+ " });",
346
+ "}",
347
+ ],
348
+ },
349
+ {
350
+ old: [
351
+ "if (reasoningStarted) {",
352
+ " controller.enqueue({",
353
+ ' type: "reasoning-end",',
354
+ " id: reasoningId || generateId()",
355
+ " });",
356
+ "}",
357
+ ],
358
+ next: [
359
+ "if (reasoningStarted) {",
360
+ " controller.enqueue({",
361
+ ' type: "reasoning-end",',
362
+ " id: reasoningId || generateId(),",
363
+ " providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
364
+ " openrouter: {",
365
+ " reasoning_details: accumulatedReasoningDetails",
366
+ " }",
367
+ " } : undefined",
368
+ " });",
369
+ "}",
370
+ ],
371
+ },
372
+ ],
373
+ },
374
+ {
375
+ type: "update",
376
+ path: "dist/index.mjs",
377
+ chunks: [
378
+ {
379
+ old: [
380
+ "if (reasoningStarted && !textStarted) {",
381
+ " controller.enqueue({",
382
+ ' type: "reasoning-end",',
383
+ " id: reasoningId || generateId()",
384
+ " });",
385
+ "}",
386
+ ],
387
+ next: [
388
+ "if (reasoningStarted && !textStarted) {",
389
+ " controller.enqueue({",
390
+ ' type: "reasoning-end",',
391
+ " id: reasoningId || generateId(),",
392
+ " providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
393
+ " openrouter: {",
394
+ " reasoning_details: accumulatedReasoningDetails",
395
+ " }",
396
+ " } : undefined",
397
+ " });",
398
+ "}",
399
+ ],
400
+ },
401
+ {
402
+ old: [
403
+ "if (reasoningStarted) {",
404
+ " controller.enqueue({",
405
+ ' type: "reasoning-end",',
406
+ " id: reasoningId || generateId()",
407
+ " });",
408
+ "}",
409
+ ],
410
+ next: [
411
+ "if (reasoningStarted) {",
412
+ " controller.enqueue({",
413
+ ' type: "reasoning-end",',
414
+ " id: reasoningId || generateId(),",
415
+ " providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
416
+ " openrouter: {",
417
+ " reasoning_details: accumulatedReasoningDetails",
418
+ " }",
419
+ " } : undefined",
420
+ " });",
421
+ "}",
422
+ ],
423
+ },
424
+ ],
425
+ },
426
+ {
427
+ type: "update",
428
+ path: "dist/internal/index.js",
429
+ chunks: [
430
+ {
431
+ old: [
432
+ "if (reasoningStarted && !textStarted) {",
433
+ " controller.enqueue({",
434
+ ' type: "reasoning-end",',
435
+ " id: reasoningId || generateId()",
436
+ " });",
437
+ "}",
438
+ ],
439
+ next: [
440
+ "if (reasoningStarted && !textStarted) {",
441
+ " controller.enqueue({",
442
+ ' type: "reasoning-end",',
443
+ " id: reasoningId || generateId(),",
444
+ " providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
445
+ " openrouter: {",
446
+ " reasoning_details: accumulatedReasoningDetails",
447
+ " }",
448
+ " } : undefined",
449
+ " });",
450
+ "}",
451
+ ],
452
+ },
453
+ {
454
+ old: [
455
+ "if (reasoningStarted) {",
456
+ " controller.enqueue({",
457
+ ' type: "reasoning-end",',
458
+ " id: reasoningId || generateId()",
459
+ " });",
460
+ "}",
461
+ ],
462
+ next: [
463
+ "if (reasoningStarted) {",
464
+ " controller.enqueue({",
465
+ ' type: "reasoning-end",',
466
+ " id: reasoningId || generateId(),",
467
+ " providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
468
+ " openrouter: {",
469
+ " reasoning_details: accumulatedReasoningDetails",
470
+ " }",
471
+ " } : undefined",
472
+ " });",
473
+ "}",
474
+ ],
475
+ },
476
+ ],
477
+ },
478
+ {
479
+ type: "update",
480
+ path: "dist/internal/index.mjs",
481
+ chunks: [
482
+ {
483
+ old: [
484
+ "if (reasoningStarted && !textStarted) {",
485
+ " controller.enqueue({",
486
+ ' type: "reasoning-end",',
487
+ " id: reasoningId || generateId()",
488
+ " });",
489
+ "}",
490
+ ],
491
+ next: [
492
+ "if (reasoningStarted && !textStarted) {",
493
+ " controller.enqueue({",
494
+ ' type: "reasoning-end",',
495
+ " id: reasoningId || generateId(),",
496
+ " providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
497
+ " openrouter: {",
498
+ " reasoning_details: accumulatedReasoningDetails",
499
+ " }",
500
+ " } : undefined",
501
+ " });",
502
+ "}",
503
+ ],
504
+ },
505
+ {
506
+ old: [
507
+ "if (reasoningStarted) {",
508
+ " controller.enqueue({",
509
+ ' type: "reasoning-end",',
510
+ " id: reasoningId || generateId()",
511
+ " });",
512
+ "}",
513
+ ],
514
+ next: [
515
+ "if (reasoningStarted) {",
516
+ " controller.enqueue({",
517
+ ' type: "reasoning-end",',
518
+ " id: reasoningId || generateId(),",
519
+ " providerMetadata: accumulatedReasoningDetails.length > 0 ? {",
520
+ " openrouter: {",
521
+ " reasoning_details: accumulatedReasoningDetails",
522
+ " }",
523
+ " } : undefined",
524
+ " });",
525
+ "}",
526
+ ],
527
+ },
528
+ ],
529
+ },
530
+ ])
531
+ })
532
+
195
533
  it("parses heredoc-wrapped hunks", () => {
196
534
  expect(
197
535
  patchContent("sample.txt", "old\n", "<<'EOF'\n@@\n-old\n+new\nEOF"),
@@ -216,6 +554,25 @@ describe("patchContent", () => {
216
554
  ).toBe("Done\n")
217
555
  })
218
556
 
557
+ it("uses context to disambiguate repeated nearby matches", () => {
558
+ expect(
559
+ patchContent(
560
+ "sample.txt",
561
+ [
562
+ "before",
563
+ "target",
564
+ "old",
565
+ "between",
566
+ "target",
567
+ "old",
568
+ "after",
569
+ "",
570
+ ].join("\n"),
571
+ ["@@ target", " target", "-old", "+new"].join("\n"),
572
+ ),
573
+ ).toBe("before\ntarget\nold\nbetween\ntarget\nnew\nafter\n")
574
+ })
575
+
219
576
  it("matches EOF hunks from the end of the file", () => {
220
577
  expect(
221
578
  patchContent(
@@ -232,6 +589,18 @@ describe("patchContent", () => {
232
589
  )
233
590
  })
234
591
 
592
+ it("rejects malformed multi-file git diffs without hunks", () => {
593
+ expect(() =>
594
+ parsePatch(
595
+ [
596
+ "diff --git a/src/app.ts b/src/app.ts",
597
+ "--- a/src/app.ts",
598
+ "+++ b/src/app.ts",
599
+ ].join("\n"),
600
+ ),
601
+ ).toThrow("no hunks found for src/app.ts")
602
+ })
603
+
235
604
  it("rejects multi-file wrapped patches", () => {
236
605
  expect(() =>
237
606
  patchContent(