typebulb 0.28.1 → 0.28.3

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.
@@ -5,7 +5,7 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs";
5
5
  import { resolve } from "node:path";
6
6
  import { Type } from "typebox";
7
7
 
8
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/utils/textUtils.js
8
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/utils/textUtils.js
9
9
  var TextUtils = class _TextUtils {
10
10
  static NormalizeToLf(text) {
11
11
  return (text ?? "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
@@ -103,7 +103,7 @@ var TextUtils = class _TextUtils {
103
103
  }
104
104
  };
105
105
 
106
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/utils/arrayUtils.js
106
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/utils/arrayUtils.js
107
107
  var ArrayUtils = class {
108
108
  /// <summary>
109
109
  /// Groups items by key, preserving first-seen key order (like LINQ's GroupBy).
@@ -141,7 +141,7 @@ var ArrayUtils = class {
141
141
  }
142
142
  };
143
143
 
144
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/models.js
144
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/models.js
145
145
  var PatchInputFile = class {
146
146
  Key;
147
147
  InputFullText;
@@ -201,12 +201,6 @@ var PatchOutput = class {
201
201
  constructor(Files) {
202
202
  this.Files = Files;
203
203
  }
204
- // Patch-scoped errors that belong to no input file: hunks naming files outside
205
- // the input set (FileMismatch). Kept off the per-file channel so one foreign
206
- // hunk cannot mark otherwise-clean files as failed — per-file Errors are about
207
- // that file only. Loudness is preserved: throw-mode still throws these, and
208
- // callers composing success replies must consult BOTH channels.
209
- Errors = [];
210
204
  };
211
205
  var LineType;
212
206
  (function(LineType2) {
@@ -252,6 +246,11 @@ var Hunk = class {
252
246
  // Set by the parser under ControlCharPolicy 'warn' when this hunk's insert
253
247
  // lines carried raw control characters.
254
248
  ControlCharsSuspected = false;
249
+ // Error-reporting stand-in Chunk for a hunk that was never anchored: its lines
250
+ // and diff location, no match.
251
+ ToUnanchoredChunk() {
252
+ return new Chunk([], this.Lines.filter((l) => l.Type == LineType.Delete).map((l) => l.Text), this.Lines.filter((l) => l.Type == LineType.Insert).map((l) => l.Text), [], UniqueMatch.NotFound, new DiffLocation(this));
253
+ }
255
254
  };
256
255
  var Edit = class _Edit {
257
256
  LineIndex;
@@ -370,7 +369,7 @@ var UniqueMatch = class _UniqueMatch {
370
369
  }
371
370
  };
372
371
 
373
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/utils/yaml.js
372
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/utils/yaml.js
374
373
  var Yaml = class _Yaml {
375
374
  _sb = [];
376
375
  // -------- Public API --------
@@ -427,7 +426,7 @@ var Yaml = class _Yaml {
427
426
  }
428
427
  };
429
428
 
430
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/exceptions.js
429
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/exceptions.js
431
430
  var PatchException = class extends Error {
432
431
  Error;
433
432
  constructor(error) {
@@ -443,13 +442,17 @@ var PatchParserException = class extends Error {
443
442
  var PatchError = class {
444
443
  Type;
445
444
  FailedMatch;
446
- // For FileMismatch: the foreign file key the hunk group named, so callers can
447
- // say WHICH file's hunks were ignored (and match it against their own target).
445
+ // The file key(s) the error concerns: the foreign key a FileMismatch named, or
446
+ // the comma-joined candidate keys of an ambiguous headerless routing; null otherwise.
448
447
  FileKey;
449
- constructor(errorType, chunk, fileKey = null) {
448
+ // Diagnosis computed against the file at error time (e.g. the quoted line
449
+ // occurs inside one longer file line); null when no confident diagnosis.
450
+ Hint;
451
+ constructor(errorType, chunk, fileKey = null, hint = null) {
450
452
  this.Type = errorType;
451
453
  this.FailedMatch = chunk;
452
454
  this.FileKey = fileKey;
455
+ this.Hint = hint;
453
456
  }
454
457
  toString() {
455
458
  return `Failed to patch text with the diff provided.
@@ -470,6 +473,8 @@ ${this.SuggestedFixYaml}`;
470
473
  if (this.FileKey != null)
471
474
  y.Scalar(" File", this.FileKey);
472
475
  y.Folded(" Summary", SummaryFor(this.Type));
476
+ if (this.Hint != null)
477
+ y.Folded(" Hint", this.Hint);
473
478
  y.Section(" Details");
474
479
  y.Section(" FailedMatch");
475
480
  y.Block(" ContextBefore", this.FailedMatch.ContextBefore);
@@ -483,7 +488,7 @@ ${this.SuggestedFixYaml}`;
483
488
  }
484
489
  };
485
490
 
486
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/applier/guards.js
491
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/applier/guards.js
487
492
  var DuplicateGuard = class _DuplicateGuard {
488
493
  // Two chunks that resolve to the same anchor with the same deletes and inserts are
489
494
  // provably the same edit (an LLM re-emitting a hunk). Applying it once is
@@ -533,7 +538,7 @@ var OverlapGuard = class {
533
538
  }
534
539
  };
535
540
 
536
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/applier/editMinimizer.js
541
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/applier/editMinimizer.js
537
542
  var EditMinimizer = class _EditMinimizer {
538
543
  static Same(a, b) {
539
544
  return a === b;
@@ -567,7 +572,7 @@ var EditMinimizer = class _EditMinimizer {
567
572
  }
568
573
  };
569
574
 
570
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/applier/indenter.js
575
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/applier/indenter.js
571
576
  var Anchor = class {
572
577
  BaseIndent;
573
578
  Shift;
@@ -658,7 +663,40 @@ var Indenter = class _Indenter {
658
663
  }
659
664
  };
660
665
 
661
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/applier/chunkApplier.js
666
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/applier/matchHint.js
667
+ var MatchHint = class _MatchHint {
668
+ // A quoted line inside exactly one longer file line is the prose line-model
669
+ // mistake: the author's "line" (a sentence of an unwrapped paragraph, or a
670
+ // re-flowed hard wrap) is a slice of the file's physical line. Matching stays
671
+ // refused — a head fragment is byte-identical to an elided whole-line delete,
672
+ // so either auto-reading risks silent corruption — but naming the line is
673
+ // correct under both readings: the retry re-quotes it whole.
674
+ static SubLine(chunk, lines) {
675
+ for (const q of chunk.DeleteLinesWithContext()) {
676
+ if (q.trim().length < _MatchHint.MinHintLineContent)
677
+ continue;
678
+ if (lines.includes(q))
679
+ continue;
680
+ const containing = [];
681
+ for (let i = 0; i < lines.length && containing.length < 2; i++)
682
+ if (lines[i].length > q.length && lines[i].includes(q))
683
+ containing.push(i);
684
+ if (containing.length != 1)
685
+ continue;
686
+ return `The diff line "${_MatchHint.Preview(q)}" matches only PART of line ${containing[0] + 1}, which is ${lines[containing[0]].length} characters long \u2014 in prose, a whole paragraph is often one physical line. Re-send the diff quoting entire lines exactly.`;
687
+ }
688
+ return null;
689
+ }
690
+ static Preview(s) {
691
+ const t = s.trim();
692
+ return t.length <= 60 ? t : t.slice(0, 57) + "...";
693
+ }
694
+ // Trimmed length a quoted line must reach before containment counts as
695
+ // evidence: short strings occur inside longer lines by coincidence.
696
+ static MinHintLineContent = 12;
697
+ };
698
+
699
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/applier/chunkApplier.js
662
700
  var InputChunks = class {
663
701
  InputFullText;
664
702
  Chunks;
@@ -722,12 +760,12 @@ var ChunkApplier = class _ChunkApplier {
722
760
  if (match.IsAmbiguous)
723
761
  throw new PatchException(new PatchError("MatchAmbiguous", chunk));
724
762
  if (match.IsNotFound)
725
- throw new PatchException(new PatchError("MatchNotFound", chunk));
763
+ throw new PatchException(new PatchError("MatchNotFound", chunk, null, MatchHint.SubLine(chunk, lines)));
726
764
  return new Edit(match.LineIndex, Array.from(chunk.DeleteLines), Indenter.AlignInsert(lines, chunk), match.Fuzz);
727
765
  }
728
766
  };
729
767
 
730
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/parser/heuristics.js
768
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/parser/heuristics.js
731
769
  var DiffContentHeuristics = class _DiffContentHeuristics {
732
770
  /**
733
771
  * Checks if a line starts with a doubled marker (++ or --)
@@ -952,7 +990,7 @@ var DiffContentHeuristics = class _DiffContentHeuristics {
952
990
  }
953
991
  };
954
992
 
955
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/parser/hunkBuilder.js
993
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/parser/hunkBuilder.js
956
994
  var Header = class _Header {
957
995
  Path;
958
996
  OldStart;
@@ -1160,7 +1198,7 @@ ${h.NewText}`;
1160
1198
  }
1161
1199
  };
1162
1200
 
1163
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/parser/unifiedDiffParser.js
1201
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/parser/unifiedDiffParser.js
1164
1202
  var UnifiedDiffParser = class _UnifiedDiffParser {
1165
1203
  /**
1166
1204
  * Parse a unified diff into structured hunks.
@@ -1399,7 +1437,7 @@ var UnifiedDiffParser = class _UnifiedDiffParser {
1399
1437
  }
1400
1438
  };
1401
1439
 
1402
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/anchorer/hunkSlicer.js
1440
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/anchorer/hunkSlicer.js
1403
1441
  var Block = class {
1404
1442
  StartIndex;
1405
1443
  EndIndex;
@@ -1452,7 +1490,7 @@ var HunkSlicer = class _HunkSlicer {
1452
1490
  }
1453
1491
  };
1454
1492
 
1455
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/anchorer/search.js
1493
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/anchorer/search.js
1456
1494
  var Match = class {
1457
1495
  LineIndex;
1458
1496
  Fuzz;
@@ -1590,7 +1628,7 @@ var Search = class _Search {
1590
1628
  }
1591
1629
  };
1592
1630
 
1593
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/anchorer/blockAnchorer.js
1631
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/anchorer/blockAnchorer.js
1594
1632
  var BlockAnchorer = class _BlockAnchorer {
1595
1633
  static AnchorBlocks(hunk, blocks, lines, options) {
1596
1634
  return blocks.map((focus, index) => {
@@ -1708,7 +1746,7 @@ var BlockAnchorer = class _BlockAnchorer {
1708
1746
  }
1709
1747
  };
1710
1748
 
1711
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/anchorer/hunkAnchorer.js
1749
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/anchorer/hunkAnchorer.js
1712
1750
  var AnchorOutcome = class {
1713
1751
  Chunks;
1714
1752
  AlreadyAppliedCount;
@@ -1876,7 +1914,7 @@ var HunkAnchorer = class _HunkAnchorer {
1876
1914
  }
1877
1915
  };
1878
1916
 
1879
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/selectionTarget.js
1917
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/selectionTarget.js
1880
1918
  var SelectionTarget = class {
1881
1919
  FullText;
1882
1920
  SelectedText;
@@ -1908,7 +1946,7 @@ var SelectionTarget = class {
1908
1946
  }
1909
1947
  };
1910
1948
 
1911
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/parser/sanitizers/shared.js
1949
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/parser/sanitizers/shared.js
1912
1950
  function isDiffMarker(line) {
1913
1951
  return line.startsWith("--- ") || line.startsWith("+++ ") || line.startsWith("@@") || line.startsWith("diff --git");
1914
1952
  }
@@ -1965,7 +2003,7 @@ function isLikelyFileHeader(trimmed) {
1965
2003
  return trimmed.startsWith("diff --git") || (trimmed.startsWith("--- ") || trimmed.startsWith("+++ ")) && (trimmed.includes(".") || trimmed.includes("/") || trimmed.includes("\\"));
1966
2004
  }
1967
2005
 
1968
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/parser/sanitizers/customFormatSanitizer.js
2006
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/parser/sanitizers/customFormatSanitizer.js
1969
2007
  var CustomFormatSanitizer = class _CustomFormatSanitizer {
1970
2008
  static OPERATIONS = [
1971
2009
  { header: /^\s*\*\*\* Update File: (.+)$/i, fromPath: (p) => `a/${p}`, toPath: (p) => `b/${p}` },
@@ -1990,7 +2028,7 @@ var CustomFormatSanitizer = class _CustomFormatSanitizer {
1990
2028
  }
1991
2029
  };
1992
2030
 
1993
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/parser/sanitizers/decoratedHeaderSanitizer.js
2031
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/parser/sanitizers/decoratedHeaderSanitizer.js
1994
2032
  var DecoratedHeaderSanitizer = class _DecoratedHeaderSanitizer {
1995
2033
  static DECORATED_HEADER_REGEX = /^(---|\+\+\+)\s+(.+?)\s+(---|\+\+\+)+\s*$/;
1996
2034
  static process(text) {
@@ -2003,7 +2041,7 @@ var DecoratedHeaderSanitizer = class _DecoratedHeaderSanitizer {
2003
2041
  }
2004
2042
  };
2005
2043
 
2006
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/parser/sanitizers/decorativeMarkerSanitizer.js
2044
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/parser/sanitizers/decorativeMarkerSanitizer.js
2007
2045
  var DecorativeMarkerSanitizer = class _DecorativeMarkerSanitizer {
2008
2046
  static process(text) {
2009
2047
  return transformOutsideHunkBodies(text, (line) => _DecorativeMarkerSanitizer.isDecorativeMarker(line.trim()) ? null : line);
@@ -2024,14 +2062,14 @@ var DecorativeMarkerSanitizer = class _DecorativeMarkerSanitizer {
2024
2062
  }
2025
2063
  };
2026
2064
 
2027
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/parser/sanitizers/backtickSanitizer.js
2065
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/parser/sanitizers/backtickSanitizer.js
2028
2066
  var BacktickSanitizer = class {
2029
2067
  static process(text) {
2030
2068
  return text.replace(/^```+\s*diff\b/gmi, "```diff").replace(/^```+$/gm, "```");
2031
2069
  }
2032
2070
  };
2033
2071
 
2034
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/parser/sanitizers/diffBlockReunifier.js
2072
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/parser/sanitizers/diffBlockReunifier.js
2035
2073
  var DiffBlockReunifier = class {
2036
2074
  static process(text) {
2037
2075
  const lines = text.split("\n");
@@ -2067,7 +2105,7 @@ var DiffBlockReunifier = class {
2067
2105
  }
2068
2106
  };
2069
2107
 
2070
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/parser/sanitizers/devNullSanitizer.js
2108
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/parser/sanitizers/devNullSanitizer.js
2071
2109
  var DevNullSanitizer = class {
2072
2110
  static process(text, fileKeys) {
2073
2111
  if (!fileKeys?.length)
@@ -2110,7 +2148,7 @@ var DevNullSanitizer = class {
2110
2148
  }
2111
2149
  };
2112
2150
 
2113
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/parser/sanitizers/prefixInjector.js
2151
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/parser/sanitizers/prefixInjector.js
2114
2152
  var PrefixInjector = class {
2115
2153
  static process(text) {
2116
2154
  const lines = text.split("\n");
@@ -2169,7 +2207,7 @@ var PrefixInjector = class {
2169
2207
  }
2170
2208
  };
2171
2209
 
2172
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/parser/diffSanitizer.js
2210
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/parser/diffSanitizer.js
2173
2211
  var DiffSanitizer = class {
2174
2212
  static Process(diff, fileKeys) {
2175
2213
  if (!diff?.trim())
@@ -2185,17 +2223,49 @@ var DiffSanitizer = class {
2185
2223
  }
2186
2224
  };
2187
2225
 
2188
- // ../node_modules/.pnpm/matchu-patchu@0.2.0/node_modules/matchu-patchu/dist/patcher.js
2189
- var Patcher = class _Patcher {
2226
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/headerlessRouter.js
2227
+ var HeaderlessRouter = class {
2228
+ static Route(fileHunks, files, options) {
2229
+ const group = fileHunks.find((g) => g.Key == "");
2230
+ if (group == null || files.some((f) => f.Key == ""))
2231
+ return [];
2232
+ const probeOptions = Object.assign(new PatchOptions(), options, { ContinueOnError: true });
2233
+ const candidates = files.filter((f) => {
2234
+ const target = new SelectionTarget(f.InputFullText, f.InputSelectedText).TargetText;
2235
+ const anchored = HunkAnchorer.Anchor(target, group.Hunks, probeOptions);
2236
+ return ChunkApplier.Apply(target, anchored.Chunks, probeOptions).Errors.length == 0;
2237
+ });
2238
+ if (candidates.length == 1) {
2239
+ fileHunks.splice(fileHunks.indexOf(group), 1);
2240
+ const existing = fileHunks.find((g) => g.Key == candidates[0].Key);
2241
+ if (existing)
2242
+ existing.Hunks.push(...group.Hunks);
2243
+ else
2244
+ fileHunks.push(new FileHunkGroup(candidates[0].Key, group.Hunks));
2245
+ return [];
2246
+ }
2247
+ return [candidates.length == 0 ? new PatchError("MatchNotFound", group.Hunks[0].ToUnanchoredChunk(), null, "The diff has no file headers and its content did not match any file being patched. Make sure context and deleted lines match the target file, and add '--- <file>' / '+++ <file>' headers naming it.") : new PatchError("MatchAmbiguous", group.Hunks[0].ToUnanchoredChunk(), candidates.map((f) => f.Key).join(", "), "The diff has no file headers and its content matched more than one file being patched. Add '--- <file>' / '+++ <file>' headers naming the intended file.")];
2248
+ }
2249
+ };
2250
+
2251
+ // ../node_modules/.pnpm/matchu-patchu@0.3.1/node_modules/matchu-patchu/dist/patcher.js
2252
+ var Patcher = class {
2190
2253
  static Apply(diff, files, options) {
2191
2254
  options = options ?? new PatchOptions();
2192
2255
  const fileKeys = files.map((f) => f.Key);
2193
2256
  const fileContents = new Map(files.map((f) => [f.Key, f.InputFullText]));
2194
2257
  diff = options.SanitizeDiff ? DiffSanitizer.Process(diff, fileKeys) : diff;
2195
2258
  const fileHunks = UnifiedDiffParser.Parse(diff, fileContents, options.Truncation, options.ControlChars);
2196
- const foreignErrors = fileHunks.filter((g) => g.Key != "" && !fileContents.has(g.Key)).map((g) => new PatchError("FileMismatch", _Patcher.ForeignChunk(g.Hunks[0]), g.Key));
2197
- if (foreignErrors.length > 0 && !options.ContinueOnError)
2198
- throw new PatchException(foreignErrors[0]);
2259
+ const routingErrors = HeaderlessRouter.Route(fileHunks, files, options);
2260
+ const namedKeys = fileKeys.filter((k) => k != "");
2261
+ const rosterHint = namedKeys.length > 0 ? `Files being patched: ${namedKeys.join(", ")}.` : null;
2262
+ const reportEntry = (key, errors) => new PatchOutputFile(key, 0, [], "", "", "", errors);
2263
+ const reportFiles = fileHunks.filter((g) => g.Key != "" && !fileContents.has(g.Key)).map((g) => reportEntry(g.Key, [new PatchError("FileMismatch", g.Hunks[0].ToUnanchoredChunk(), g.Key, rosterHint)]));
2264
+ if (routingErrors.length > 0)
2265
+ reportFiles.unshift(reportEntry("", routingErrors));
2266
+ const reportErrors = reportFiles.flatMap((f) => f.Errors);
2267
+ if (reportErrors.length > 0 && !options.ContinueOnError)
2268
+ throw new PatchException(reportErrors[0]);
2199
2269
  const patchOutputFiles = files.map((f) => {
2200
2270
  const targetSelection = new SelectionTarget(f.InputFullText, f.InputSelectedText);
2201
2271
  const targetText = targetSelection.TargetText;
@@ -2204,20 +2274,13 @@ var Patcher = class _Patcher {
2204
2274
  const outputEdits = ChunkApplier.Apply(targetText, anchored.Chunks, options);
2205
2275
  return new PatchOutputFile(f.Key, outputEdits.Edits.map((h) => h.Fuzz).reduce((a, b) => a + b, 0), outputEdits.Edits.map((e) => e.Shift(targetSelection.LineOffset)), f.InputSelectedText, f.InputFullText, targetSelection.Replace(outputEdits.OutputText), [...outputEdits.Errors], anchored.AlreadyAppliedCount, hunks.flatMap((h) => h.Lines).filter((l) => l.CollapsedFrom != null).map((l) => l.CollapsedFrom), hunks.some((h) => h.TruncationSuspected), hunks.some((h) => h.ControlCharsSuspected));
2206
2276
  });
2207
- const output = new PatchOutput(patchOutputFiles);
2208
- output.Errors = foreignErrors;
2209
- return output;
2210
- }
2211
- // Error-reporting stand-in for a hunk that was never anchored (it names a file
2212
- // that isn't being patched): its lines and diff location, no match.
2213
- static ForeignChunk(h) {
2214
- return new Chunk([], h.Lines.filter((l) => l.Type == LineType.Delete).map((l) => l.Text), h.Lines.filter((l) => l.Type == LineType.Insert).map((l) => l.Text), [], UniqueMatch.NotFound, new DiffLocation(h));
2277
+ return new PatchOutput([...patchOutputFiles, ...reportFiles]);
2215
2278
  }
2216
2279
  };
2217
2280
 
2218
2281
  // cli/agents/pi/server/piPatcherExtension.ts
2219
2282
  var DESCRIPTION = true ? "Apply unified diffs to files \u2014 tolerant of form, strict about intent. Repairs sloppy AI-generated diffs (mangled headers, whitespace drift, missing prefixes; line numbers can be wrong or absent \u2014 hunks anchor by fuzzy-matched context lines) and applies all hunks atomically when the intent is unambiguous; fails with a precise, typed error when it isn't. Use for multi-hunk edits in one step, or when exact string-replacement editing fails on whitespace or invisible characters." : "Apply unified diffs to files.";
2220
- var BUILD_TAG = true ? "matchu-patchu-pi 0.2.0, built 2026-07-16 09:21:29" : "matchu-patchu-pi dev";
2283
+ var BUILD_TAG = true ? "matchu-patchu-pi 0.3.1, built 2026-07-16 18:09:29" : "matchu-patchu-pi dev";
2221
2284
  var errorBlocks = (errors) => {
2222
2285
  const parts = [`Patch failed with ${errors.length} error(s):`];
2223
2286
  for (const e of errors) parts.push("", e.toString());
@@ -2227,8 +2290,8 @@ var noOpMessage = (target, alreadyApplied) => alreadyApplied > 0 ? `Applied 0 ed
2227
2290
  var fuzzNote = (fuzz) => fuzz > 0 ? ` (applied with fuzz factor ${fuzz})` : "";
2228
2291
  function discoverDiffKeys(diff) {
2229
2292
  const keys = [];
2230
- for (const e of Patcher.Apply(diff, []).Errors) {
2231
- if (e.FileKey && !keys.includes(e.FileKey)) keys.push(e.FileKey);
2293
+ for (const f of Patcher.Apply(diff, []).Files) {
2294
+ if (f.Key && !keys.includes(f.Key)) keys.push(f.Key);
2232
2295
  }
2233
2296
  return keys;
2234
2297
  }
@@ -2256,7 +2319,7 @@ function applyMulti(cwd, diff, dryRun) {
2256
2319
  return { ok: false, message: missing.map((k) => `Error: file not found: ${k}`).join("\n") };
2257
2320
  const inputs = keys.map((k) => new PatchInputFile(k, readFileSync(resolve(cwd, k), "utf-8")));
2258
2321
  const result = Patcher.Apply(diff, inputs);
2259
- const errors = [...result.Errors, ...result.Files.flatMap((f) => f.Errors)];
2322
+ const errors = result.Files.flatMap((f) => f.Errors);
2260
2323
  if (errors.length > 0) return { ok: false, message: errorBlocks(errors) };
2261
2324
  const lines = [];
2262
2325
  const dryOutputs = [];
@@ -817,16 +817,27 @@ a.server-port:hover { text-decoration: underline; }
817
817
  the logs-link register — marks the category and opens the bulb's published page. A remote
818
818
  (not-yet-downloaded) row's name is additionally muted and inert (no file to open), and its
819
819
  time column stays empty (no mtime to show). */
820
- .server-name.remote { color: var(--muted); cursor: default; }
820
+ .server-name.remote { cursor: default; }
821
821
  .server-name.remote:hover { text-decoration: none; }
822
822
  .sample-link { color: var(--muted); font-size: .76rem; text-decoration: none; cursor: pointer; flex: none; }
823
823
  .sample-link:hover { color: var(--accent); text-decoration: underline; }
824
- /* The samples-catalog fold header (bulbsPill.ts groupRow): caret in the button column, muted label
825
- spanning the remaining tracks. Pitch, hover, and the keyboard highlight inherit from .server-row. */
824
+ /* The remote fold (bulbsPill.ts groupRow / fold-row): the header and the remote rows within share
825
+ one veil step over the menu's panel bg (the picker-peek shade) as ONE contiguous band — each
826
+ row's ::before bridges the grid row-gap up to the row above, junction corners square off, and
827
+ only the band's outer corners round (the header's top; the last row's bottom, via :has). The
828
+ accent label marks the header. Single-class selectors on purpose: .server-row:hover/.active
829
+ outrank them, so the highlight tints still win. */
826
830
  .sample-group { cursor: pointer; color: var(--muted); }
827
- .sample-group:hover, .sample-group.active { color: var(--fg); }
831
+ .sample-group, .fold-row { background: linear-gradient(var(--veil), var(--veil)), var(--panel); }
832
+ .sample-group.open { border-radius: 6px 6px 0 0; }
833
+ .fold-row { position: relative; border-radius: 0; }
834
+ .fold-row::before {
835
+ content: ''; position: absolute; left: 0; right: 0; top: -.15rem; height: .15rem;
836
+ background: linear-gradient(var(--veil), var(--veil)), var(--panel);
837
+ }
838
+ .fold-row:not(:has(+ .fold-row)) { border-radius: 0 0 6px 6px; }
828
839
  .sample-group .caret-tri { justify-self: center; }
829
- .sample-group-label { grid-column: 2 / -1; }
840
+ .sample-group-label { grid-column: 2 / -1; color: var(--accent); }
830
841
  /* The 1fr name column: name + (in full-text mode) its hit count read together, the badge
831
842
  right-aligned at the column's end by the name's flex:1 — the session row's preview/hits layout. */
832
843
  .bulb-name-cell { display: flex; align-items: baseline; gap: .6rem; min-width: 0; }
package/dist/index.js CHANGED
@@ -1915,5 +1915,5 @@ ${oP}
1915
1915
  `);let a=0,c=Promise.resolve();Vt({target:r,onChange:()=>{let l=++a;c=c.then(async()=>{if(l===a)try{console.log("Re-running..."),await o()}catch(d){console.error("Error:",d)}})}})}}mt();import{Console as fP}from"node:console";Ne();async function fy(r,e,t,n){gP();try{let f=Sr(await Y(),r)[0];f&&(_i(f.pid,Re(f.pid).offset),console.error(`note: 'call' boots a fresh server.ts instance; the running server (${f.url}) is not contacted \u2014 state shared with it must live on disk.`))}catch{}let s=ge(t),{bulb:i,config:o}=await xe(r);i.server||Yn("This bulb has no **server.ts** block; nothing to call."),pt(s,r,i.server);let a;try{a=await On(i.server,r,n,o.dependencies)}catch(f){Yn(f instanceof Error?f.message:String(f))}let c=ko(a,e.fn);if(!c){let f=[...Object.keys(a).filter(p=>typeof a[p]=="function"),...Object.keys(So)];Yn(`Function '${e.fn}' not found. Available: ${f.length?f.join(", "):"(none)"}.`)}let l=await dP(e);if(xo(c)){try{for await(let f of c(...l))await uy(JSON.stringify(f,dy)+`
1916
1916
  `)}catch(f){Yn(f instanceof Error?f.stack??f.message:String(f))}return ly(0)}let d;try{d=await c(...l)}catch(f){Yn(f instanceof Error?f.stack??f.message:String(f))}let u=hP(d);u!==void 0&&await uy(u+`
1917
1917
  `),ly(0)}function ly(r){process.exitCode=r,setTimeout(()=>process.exit(r),2e3).unref?.()}async function dP(r){if(r.hasArgsFlag){let e=r.argsJson??"";return e==="-"&&(e=await yP()),mP(e)}return pP(r.positional)}function pP(r){return r.map(e=>{try{return JSON.parse(e)}catch{return e}})}function mP(r){let e;try{e=JSON.parse(r)}catch(t){throw new Error(`--args must be a JSON array: ${t instanceof Error?t.message:String(t)}`)}if(!Array.isArray(e))throw new Error(`--args must be a JSON array, got ${e===null?"null":typeof e}`);return e}function hP(r){if(r!==void 0)return JSON.stringify(r,dy,2)}function dy(r,e){return typeof e=="bigint"?e.toString():e}function Yn(r){process.stderr.write(r+`
1918
- `),process.exit(1)}function gP(){let r=new fP(process.stderr,process.stderr);console.log=r.log.bind(r),console.info=r.info.bind(r),console.debug=r.debug.bind(r),console.dir=r.dir.bind(r)}function uy(r){return new Promise((e,t)=>{process.stdout.write(r,n=>n?t(n):e())})}async function yP(){let r=[];for await(let e of process.stdin)r.push(e);return Buffer.concat(r).toString("utf-8")}var Xl="0.28.1";function py(r,e){r||(console.error(`This bulb runs server-side Node code (server.ts), which --trust must authorize:
1918
+ `),process.exit(1)}function gP(){let r=new fP(process.stderr,process.stderr);console.log=r.log.bind(r),console.info=r.info.bind(r),console.debug=r.debug.bind(r),console.dir=r.dir.bind(r)}function uy(r){return new Promise((e,t)=>{process.stdout.write(r,n=>n?t(n):e())})}async function yP(){let r=[];for await(let e of process.stdin)r.push(e);return Buffer.concat(r).toString("utf-8")}var Xl="0.28.3";function py(r,e){r||(console.error(`This bulb runs server-side Node code (server.ts), which --trust must authorize:
1919
1919
  ${e}`),process.exit(1))}async function bP(){let r=pu(process.argv.slice(2));if(r.version&&(console.log(`typebulb ${Xl}`),process.exit(0)),r.help&&(mu(),process.exit(0)),Ig(),r.subcommand==="logs"){await Jg(r.file||void 0,{follow:r.follow,clear:r.clear,run:r.run,lines:r.lines});return}if(r.subcommand==="wait"){await Kg(r.file||void 0,{match:r.match,timeoutSec:r.timeoutSec});return}if(r.subcommand==="stop"){r.stopScope?await Wg(r.stopScope):await Hg(r.file||void 0);return}if(r.subcommand==="send"){await Vg(r.file,r.sendMessage,r.sendWaitMs??0);return}if(r.subcommand==="skill"){await Fg(Xl);return}if(r.subcommand==="models"){await Bg(r.mode);return}if(r.subcommand==="pull"){await Bm(r.file||void 0,{force:r.force,mode:r.mode});return}if(r.subcommand==="push"){await qm(r.file||void 0,{force:r.force,mode:r.mode});return}if(r.subcommand==="agent"){await(r.agentTarget?oy(r):Dg(Xl));return}if(r.subcommand==="trust"||r.subcommand==="untrust"){await Ng(r.file||void 0,r.subcommand==="trust");return}let e;if(!r.file||r.file==="."){let c=await om(process.cwd());c||(console.error("No .bulb.md file found in current directory"),process.exit(1)),e=c}else e=Gt.resolve(r.file);await my.access(e).then(()=>!0,()=>!1)||(Rr().includes(r.file)&&(console.error(`To open the ${r.file} agent mirror, run: npx typebulb agent:${r.file}`),process.exit(1)),console.error(`File not found: ${e}`),process.exit(1)),e.endsWith(".bulb.md")||(console.error("File must have .bulb.md extension"),process.exit(1));let n=r.file&&r.file!=="."?r.file:Gt.relative(process.cwd(),e)||Gt.basename(e),s=`npx typebulb --trust ${n.includes(" ")?`"${n}"`:n}`;if(r.subcommand==="predict"){await Rg(e,s);return}let i=!r.noTrust&&Bt(e);i&&!r.trust&&console.error("trust: granted from memory (run `typebulb untrust` to revoke)"),r.trust=r.noTrust?!1:r.trust||i;let o;try{o=await xe(e)}catch{}let a;if(r.local){o&&!(r.local.name in(o.config.dependencies??{}))&&(console.error(`--replace: '${r.local.name}' is not a dependency in this bulb's config.json; nothing to replace.`),process.exit(1)),o&&r.subcommand!=="call"&&(!o.bulb.code||r.server)&&console.warn("warning: --replace has no effect in server mode (the override is client-only).");try{a=await fu(r.local)}catch(c){console.error(c instanceof Error?c.message:String(c)),process.exit(1)}console.error(`replace: ${a.name} \u2192 ${Gt.relative(process.cwd(),a.dir)||"."}`)}if(r.subcommand==="check"){await _g(e,a);return}if(r.subcommand==="call"){py(r.trust,s),await fy(e,{fn:r.fn,positional:r.callArgs,argsJson:r.argsJson,hasArgsFlag:r.hasArgsFlag},r.mode,a);return}if(o&&o.bulb.server&&(zs(o.bulb)||r.server)){py(r.trust,s),await cy(e,r.watch,r.mode,a);return}await ry(e,r,s,a)}bP().catch(r=>{console.error("Error:",r.message),process.exit(1)});