@researai/deepscientist 1.5.7 → 1.5.8

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 (148) hide show
  1. package/README.md +4 -0
  2. package/bin/ds.js +220 -5
  3. package/docs/en/07_MEMORY_AND_MCP.md +40 -3
  4. package/docs/en/99_ACKNOWLEDGEMENTS.md +1 -0
  5. package/docs/zh/07_MEMORY_AND_MCP.md +40 -3
  6. package/docs/zh/99_ACKNOWLEDGEMENTS.md +1 -0
  7. package/install.sh +34 -0
  8. package/package.json +1 -1
  9. package/pyproject.toml +1 -1
  10. package/src/deepscientist/__init__.py +1 -1
  11. package/src/deepscientist/acp/envelope.py +1 -0
  12. package/src/deepscientist/artifact/metrics.py +813 -80
  13. package/src/deepscientist/artifact/schemas.py +1 -0
  14. package/src/deepscientist/artifact/service.py +1101 -99
  15. package/src/deepscientist/bash_exec/monitor.py +1 -1
  16. package/src/deepscientist/bash_exec/service.py +17 -9
  17. package/src/deepscientist/channels/qq.py +17 -0
  18. package/src/deepscientist/channels/relay.py +16 -0
  19. package/src/deepscientist/config/models.py +6 -0
  20. package/src/deepscientist/config/service.py +70 -2
  21. package/src/deepscientist/daemon/api/handlers.py +284 -14
  22. package/src/deepscientist/daemon/api/router.py +1 -0
  23. package/src/deepscientist/daemon/app.py +291 -20
  24. package/src/deepscientist/gitops/diff.py +6 -10
  25. package/src/deepscientist/mcp/server.py +188 -39
  26. package/src/deepscientist/prompts/builder.py +51 -18
  27. package/src/deepscientist/quest/service.py +83 -34
  28. package/src/deepscientist/quest/stage_views.py +74 -29
  29. package/src/deepscientist/runners/codex.py +1 -1
  30. package/src/prompts/connectors/qq.md +1 -1
  31. package/src/prompts/contracts/shared_interaction.md +14 -0
  32. package/src/prompts/system.md +106 -32
  33. package/src/skills/analysis-campaign/SKILL.md +10 -14
  34. package/src/skills/baseline/SKILL.md +51 -38
  35. package/src/skills/baseline/references/baseline-plan-template.md +2 -0
  36. package/src/skills/decision/SKILL.md +12 -8
  37. package/src/skills/experiment/SKILL.md +28 -16
  38. package/src/skills/experiment/references/main-experiment-plan-template.md +2 -0
  39. package/src/skills/figure-polish/SKILL.md +1 -0
  40. package/src/skills/finalize/SKILL.md +3 -8
  41. package/src/skills/idea/SKILL.md +2 -8
  42. package/src/skills/intake-audit/SKILL.md +2 -8
  43. package/src/skills/rebuttal/SKILL.md +2 -8
  44. package/src/skills/review/SKILL.md +2 -8
  45. package/src/skills/scout/SKILL.md +2 -8
  46. package/src/skills/write/SKILL.md +52 -16
  47. package/src/skills/write/templates/DEEPSCIENTIST_NOTES.md +21 -0
  48. package/src/skills/write/templates/README.md +408 -0
  49. package/src/skills/write/templates/UPSTREAM_LICENSE.txt +21 -0
  50. package/src/skills/write/templates/aaai2026/README.md +534 -0
  51. package/src/skills/write/templates/aaai2026/aaai2026-unified-supp.tex +144 -0
  52. package/src/skills/write/templates/aaai2026/aaai2026-unified-template.tex +952 -0
  53. package/src/skills/write/templates/aaai2026/aaai2026.bib +111 -0
  54. package/src/skills/write/templates/aaai2026/aaai2026.bst +1493 -0
  55. package/src/skills/write/templates/aaai2026/aaai2026.sty +315 -0
  56. package/src/skills/write/templates/acl/README.md +50 -0
  57. package/src/skills/write/templates/acl/acl.sty +312 -0
  58. package/src/skills/write/templates/acl/acl_latex.tex +377 -0
  59. package/src/skills/write/templates/acl/acl_lualatex.tex +101 -0
  60. package/src/skills/write/templates/acl/acl_natbib.bst +1940 -0
  61. package/src/skills/write/templates/acl/anthology.bib.txt +26 -0
  62. package/src/skills/write/templates/acl/custom.bib +70 -0
  63. package/src/skills/write/templates/acl/formatting.md +326 -0
  64. package/src/skills/write/templates/asplos2027/main.tex +459 -0
  65. package/src/skills/write/templates/asplos2027/references.bib +135 -0
  66. package/src/skills/write/templates/colm2025/README.md +3 -0
  67. package/src/skills/write/templates/colm2025/colm2025_conference.bib +11 -0
  68. package/src/skills/write/templates/colm2025/colm2025_conference.bst +1440 -0
  69. package/src/skills/write/templates/colm2025/colm2025_conference.sty +218 -0
  70. package/src/skills/write/templates/colm2025/colm2025_conference.tex +305 -0
  71. package/src/skills/write/templates/colm2025/fancyhdr.sty +485 -0
  72. package/src/skills/write/templates/colm2025/math_commands.tex +508 -0
  73. package/src/skills/write/templates/colm2025/natbib.sty +1246 -0
  74. package/src/skills/write/templates/iclr2026/fancyhdr.sty +485 -0
  75. package/src/skills/write/templates/iclr2026/iclr2026_conference.bib +24 -0
  76. package/src/skills/write/templates/iclr2026/iclr2026_conference.bst +1440 -0
  77. package/src/skills/write/templates/iclr2026/iclr2026_conference.sty +246 -0
  78. package/src/skills/write/templates/iclr2026/iclr2026_conference.tex +414 -0
  79. package/src/skills/write/templates/iclr2026/math_commands.tex +508 -0
  80. package/src/skills/write/templates/iclr2026/natbib.sty +1246 -0
  81. package/src/skills/write/templates/icml2026/algorithm.sty +79 -0
  82. package/src/skills/write/templates/icml2026/algorithmic.sty +201 -0
  83. package/src/skills/write/templates/icml2026/example_paper.bib +75 -0
  84. package/src/skills/write/templates/icml2026/example_paper.tex +662 -0
  85. package/src/skills/write/templates/icml2026/fancyhdr.sty +864 -0
  86. package/src/skills/write/templates/icml2026/icml2026.bst +1443 -0
  87. package/src/skills/write/templates/icml2026/icml2026.sty +767 -0
  88. package/src/skills/write/templates/neurips2025/Makefile +36 -0
  89. package/src/skills/write/templates/neurips2025/extra_pkgs.tex +53 -0
  90. package/src/skills/write/templates/neurips2025/main.tex +38 -0
  91. package/src/skills/write/templates/neurips2025/neurips.sty +382 -0
  92. package/src/skills/write/templates/nsdi2027/main.tex +426 -0
  93. package/src/skills/write/templates/nsdi2027/references.bib +151 -0
  94. package/src/skills/write/templates/nsdi2027/usenix-2020-09.sty +83 -0
  95. package/src/skills/write/templates/osdi2026/main.tex +429 -0
  96. package/src/skills/write/templates/osdi2026/references.bib +150 -0
  97. package/src/skills/write/templates/osdi2026/usenix-2020-09.sty +83 -0
  98. package/src/skills/write/templates/sosp2026/main.tex +532 -0
  99. package/src/skills/write/templates/sosp2026/references.bib +148 -0
  100. package/src/tui/package.json +1 -1
  101. package/src/ui/dist/assets/{AiManusChatView-BS3V4ZOk.js → AiManusChatView-m2FNtwbn.js} +110 -14
  102. package/src/ui/dist/assets/{AnalysisPlugin-DLPXQsmr.js → AnalysisPlugin-BMTF8EGL.js} +1 -1
  103. package/src/ui/dist/assets/{AutoFigurePlugin-C-Fr9knQ.js → AutoFigurePlugin-DxPdMUNb.js} +5 -5
  104. package/src/ui/dist/assets/{CliPlugin-Dd8AHzFg.js → CliPlugin-BEOWgxCI.js} +9 -9
  105. package/src/ui/dist/assets/{CodeEditorPlugin-Dg-RepTl.js → CodeEditorPlugin-BCXvjqmb.js} +8 -8
  106. package/src/ui/dist/assets/{CodeViewerPlugin-D2J_3nyt.js → CodeViewerPlugin-DaJcy3nD.js} +5 -5
  107. package/src/ui/dist/assets/{DocViewerPlugin-ChRLLKNb.js → DocViewerPlugin-ByfeIq4K.js} +3 -3
  108. package/src/ui/dist/assets/{GitDiffViewerPlugin-DgHfcved.js → GitDiffViewerPlugin-Cksf3VZ-.js} +830 -86
  109. package/src/ui/dist/assets/{ImageViewerPlugin-C89GZMBy.js → ImageViewerPlugin-CFz-OsTS.js} +5 -5
  110. package/src/ui/dist/assets/{LabCopilotPanel-BUfIwUcb.js → LabCopilotPanel-CJ1cJzoX.js} +10 -10
  111. package/src/ui/dist/assets/{LabPlugin-zvUmQUMq.js → LabPlugin-BF3dVJwa.js} +1 -1
  112. package/src/ui/dist/assets/{LatexPlugin-C1SSNuWp.js → LatexPlugin-DDkwZ6Sj.js} +7 -7
  113. package/src/ui/dist/assets/{MarkdownViewerPlugin-D2Mf5tU5.js → MarkdownViewerPlugin-HAuvurcT.js} +4 -4
  114. package/src/ui/dist/assets/{MarketplacePlugin-CF4LgiS2.js → MarketplacePlugin-BtoTYy2C.js} +3 -3
  115. package/src/ui/dist/assets/{index-Be0NAmh8.js → NotebookEditor-CSJYx7b-.js} +12 -155
  116. package/src/ui/dist/assets/{NotebookEditor-BM7Bgwlv.js → NotebookEditor-DQgRezm_.js} +1 -1
  117. package/src/ui/dist/assets/{PdfLoader-Bc5qfD-Z.js → PdfLoader-DPa_-fv6.js} +1 -1
  118. package/src/ui/dist/assets/{PdfMarkdownPlugin-sh1-IRcp.js → PdfMarkdownPlugin-BZpXOEjm.js} +3 -3
  119. package/src/ui/dist/assets/{PdfViewerPlugin-C_a7CpWG.js → PdfViewerPlugin-BT8a6wGR.js} +10 -10
  120. package/src/ui/dist/assets/{SearchPlugin-L4z3HcLf.js → SearchPlugin-D_blveZi.js} +1 -1
  121. package/src/ui/dist/assets/{Stepper-Dk4aQ3fN.js → Stepper-DH2k75Vo.js} +1 -1
  122. package/src/ui/dist/assets/{TextViewerPlugin-BsNtlKVo.js → TextViewerPlugin-Btx0M3hX.js} +4 -4
  123. package/src/ui/dist/assets/{VNCViewer-BpeDcZ5_.js → VNCViewer-DImJO4rO.js} +9 -9
  124. package/src/ui/dist/assets/{bibtex-C4QI-bbj.js → bibtex-B-Hqu0Sg.js} +1 -1
  125. package/src/ui/dist/assets/{code-DuMINRsg.js → code-BUfXGJSl.js} +1 -1
  126. package/src/ui/dist/assets/{file-content-C3N-432K.js → file-content-VqamwI3X.js} +1 -1
  127. package/src/ui/dist/assets/{file-diff-panel-CffQ4ZMg.js → file-diff-panel-C_wOoS7a.js} +1 -1
  128. package/src/ui/dist/assets/{file-socket-CRH59PCO.js → file-socket-D2bTuMVP.js} +1 -1
  129. package/src/ui/dist/assets/{file-utils-vYGtW2mI.js → file-utils--zJCPN1i.js} +1 -1
  130. package/src/ui/dist/assets/{image-DBVGaooo.js → image-BZkGJ4mM.js} +1 -1
  131. package/src/ui/dist/assets/{index-DjSFDmgB.js → index-CxkvSeKw.js} +2 -2
  132. package/src/ui/dist/assets/{index-BpjYH9Vg.js → index-D9QIGcmc.js} +1 -1
  133. package/src/ui/dist/assets/{index-Do9N28uB.css → index-DXZ1daiJ.css} +163 -34
  134. package/src/ui/dist/assets/index-DdRW6RMJ.js +159 -0
  135. package/src/ui/dist/assets/{index-B1P6hQRJ.js → index-DjggJovS.js} +3029 -1780
  136. package/src/ui/dist/assets/{message-square-BsPDBhiY.js → message-square-FUIPIhU2.js} +1 -1
  137. package/src/ui/dist/assets/{monaco-BTkdPojV.js → monaco-DHMc7kKM.js} +1 -1
  138. package/src/ui/dist/assets/{popover-cWjCk-vc.js → popover-B85oCgCS.js} +1 -1
  139. package/src/ui/dist/assets/{project-sync-CXn530xb.js → project-sync-DOMCcPac.js} +1 -1
  140. package/src/ui/dist/assets/{sigma-04Jr12jg.js → sigma-BO2rQrl3.js} +1 -1
  141. package/src/ui/dist/assets/{tooltip-BdVDl0G5.js → tooltip-B1OspAkx.js} +1 -1
  142. package/src/ui/dist/assets/{trash-CB_GlQyC.js → trash-BsVEH_dV.js} +1 -1
  143. package/src/ui/dist/assets/{useCliAccess-BL932NwS.js → useCliAccess-b8L6JuZm.js} +1 -1
  144. package/src/ui/dist/assets/{useFileDiffOverlay-B2WK7Tvq.js → useFileDiffOverlay-BY7uA9hV.js} +1 -1
  145. package/src/ui/dist/assets/{wrap-text-YC68g12z.js → wrap-text-BwyVuUIK.js} +1 -1
  146. package/src/ui/dist/assets/{zoom-out-C0RJvFiJ.js → zoom-out-RDpLugQP.js} +1 -1
  147. package/src/ui/dist/index.html +5 -2
  148. /package/src/ui/dist/assets/{index-CccQYZjX.css → NotebookEditor-CccQYZjX.css} +0 -0
@@ -1,4 +1,26 @@
1
- import { z as createLucideIcon, r as reactExports, j as jsxRuntimeExports, b as cn, af as useQuery, a3 as Button, g as RefreshCw, ae as ExternalLink, ag as client } from './index-B1P6hQRJ.js';
1
+ import { z as createLucideIcon, aI as inferWorkspaceContentKindFromMetadata, t as BUILTIN_PLUGINS, aJ as getPluginIdFromMimeType, aK as getPluginIdFromExtension, r as reactExports, j as jsxRuntimeExports, u as useI18n, b as cn, a as useWorkspaceSurfaceStore, aL as useQuery, k as FileText, a3 as Button, g as RefreshCw, aM as buildQuestFileNodeFromDocument, N as toFilesResourcePath, aN as client } from './index-DjggJovS.js';
2
+ import ImageViewerPlugin from './ImageViewerPlugin-CFz-OsTS.js';
3
+ import MarkdownViewerPlugin from './MarkdownViewerPlugin-HAuvurcT.js';
4
+ import { N as NotebookEditor } from './NotebookEditor-CSJYx7b-.js';
5
+ import PdfViewerPlugin from './PdfViewerPlugin-BT8a6wGR.js';
6
+ import './image-BZkGJ4mM.js';
7
+ import './zoom-out-RDpLugQP.js';
8
+ import './code-BUfXGJSl.js';
9
+ import './NotebookEditor-DQgRezm_.js';
10
+ import './function-B5QZkkHC.js';
11
+ import './yjs-DncrqiZ8.js';
12
+ import './project-sync-DOMCcPac.js';
13
+ import './index-D9QIGcmc.js';
14
+ import './popover-B85oCgCS.js';
15
+ import './trash-BsVEH_dV.js';
16
+ import './sigma-BO2rQrl3.js';
17
+ import './useFileDiffOverlay-BY7uA9hV.js';
18
+ import './file-diff-panel-C_wOoS7a.js';
19
+ import './file-socket-D2bTuMVP.js';
20
+ import './pdf-effect-queue-DSw_D3RV.js';
21
+ import './bibtex-B-Hqu0Sg.js';
22
+ import './PdfLoader-DPa_-fv6.js';
23
+ import './message-square-FUIPIhU2.js';
2
24
 
3
25
  /**
4
26
  * @license lucide-react v0.511.0 - ISC
@@ -16,6 +38,42 @@ const __iconNode = [
16
38
  ];
17
39
  const GitCompare = createLucideIcon("git-compare", __iconNode);
18
40
 
41
+ function basename(path) {
42
+ const raw = String(path || "").trim();
43
+ if (!raw) return "";
44
+ const parts = raw.split("/").filter(Boolean);
45
+ return parts[parts.length - 1] || raw;
46
+ }
47
+ function detectSnapshotPluginId(document) {
48
+ const fileName = basename(document?.path);
49
+ const mimeType = String(document?.mime_type || "").trim();
50
+ return (mimeType ? getPluginIdFromMimeType(mimeType) : void 0) || (fileName ? getPluginIdFromExtension(fileName) : void 0) || null;
51
+ }
52
+ function inferSnapshotPreviewKind(document) {
53
+ const pluginId = detectSnapshotPluginId(document);
54
+ const fileName = basename(document?.path).toLowerCase();
55
+ if (fileName.endsWith(".md") || fileName.endsWith(".markdown") || fileName.endsWith(".mdx")) {
56
+ return "markdown";
57
+ }
58
+ if (pluginId === BUILTIN_PLUGINS.PDF_VIEWER) return "pdf";
59
+ if (pluginId === BUILTIN_PLUGINS.IMAGE_VIEWER) return "image";
60
+ if (pluginId === BUILTIN_PLUGINS.NOTEBOOK) return "notebook";
61
+ return "plain";
62
+ }
63
+ function inferSnapshotContentKind(document) {
64
+ return inferWorkspaceContentKindFromMetadata({
65
+ mimeType: document?.mime_type,
66
+ resourceName: document?.path,
67
+ resourcePath: document?.path
68
+ }) || "file";
69
+ }
70
+ function formatGitDiffPathLabel(path, oldPath, fallback = "Diff") {
71
+ if (path && oldPath && path !== oldPath) {
72
+ return `${oldPath} → ${path}`;
73
+ }
74
+ return path || fallback;
75
+ }
76
+
19
77
  function ownKeys(e, r) {
20
78
  var t = Object.keys(e);
21
79
  if (Object.getOwnPropertySymbols) {
@@ -89,6 +147,9 @@ function _slicedToArray(arr, i) {
89
147
  }
90
148
  }(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
91
149
  }
150
+ function _toArray(arr) {
151
+ return _arrayWithHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableRest();
152
+ }
92
153
  function _toConsumableArray(arr) {
93
154
  return function(arr2) {
94
155
  if (Array.isArray(arr2)) return _arrayLikeToArray(arr2);
@@ -387,6 +448,10 @@ function getCorrespondingLineNumberFactory(baseSide) {
387
448
  throw new Error("Unexpected line position ".concat(lineNumber));
388
449
  };
389
450
  }
451
+ var _baseFindIndex = function(array, predicate, fromIndex, fromRight) {
452
+ for (var length = array.length, index2 = fromIndex + (-1); ++index2 < length; ) if (predicate(array[index2], index2, array)) return index2;
453
+ return -1;
454
+ };
390
455
  var _listCacheClear = function() {
391
456
  this.__data__ = [], this.size = 0;
392
457
  };
@@ -956,6 +1021,32 @@ var property_1 = function(path) {
956
1021
  };
957
1022
  var _baseIteratee = function(value) {
958
1023
  return "function" == typeof value ? value : null == value ? identity_1 : "object" == typeof value ? isArray_1(value) ? _baseMatchesProperty(value[0], value[1]) : _baseMatches(value) : property_1(value);
1024
+ }, reWhitespace = /\s/;
1025
+ var _trimmedEndIndex = function(string) {
1026
+ for (var index2 = string.length; index2-- && reWhitespace.test(string.charAt(index2)); ) ;
1027
+ return index2;
1028
+ }, reTrimStart = /^\s+/;
1029
+ var _baseTrim = function(string) {
1030
+ return string ? string.slice(0, _trimmedEndIndex(string) + 1).replace(reTrimStart, "") : string;
1031
+ }, reIsBadHex = /^[-+]0x[0-9a-f]+$/i, reIsBinary = /^0b[01]+$/i, reIsOctal = /^0o[0-7]+$/i, freeParseInt = parseInt;
1032
+ var toNumber_1 = function(value) {
1033
+ if ("number" == typeof value) return value;
1034
+ if (isSymbol_1(value)) return NaN;
1035
+ if (isObject_1(value)) {
1036
+ var other = "function" == typeof value.valueOf ? value.valueOf() : value;
1037
+ value = isObject_1(other) ? other + "" : other;
1038
+ }
1039
+ if ("string" != typeof value) return 0 === value ? value : +value;
1040
+ value = _baseTrim(value);
1041
+ var isBinary = reIsBinary.test(value);
1042
+ return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NaN : +value;
1043
+ };
1044
+ var toFinite_1 = function(value) {
1045
+ return value ? Infinity === (value = toNumber_1(value)) || -Infinity === value ? 17976931348623157e292 * (value < 0 ? -1 : 1) : value == value ? value : 0 : 0 === value ? value : 0;
1046
+ };
1047
+ var toInteger_1 = function(value) {
1048
+ var result = toFinite_1(value), remainder = result % 1;
1049
+ return result == result ? remainder ? result - remainder : result : 0;
959
1050
  };
960
1051
  function getChangeKey(change) {
961
1052
  if (!change) throw new Error("change is not provided");
@@ -1236,8 +1327,257 @@ function Decoration(props) {
1236
1327
  var _props$className = props.className, className = void 0 === _props$className ? "" : _props$className, _props$gutterClassNam = props.gutterClassName, gutterClassName = void 0 === _props$gutterClassNam ? "" : _props$gutterClassNam, _props$contentClassNa = props.contentClassName, contentClassName = void 0 === _props$contentClassNa ? "" : _props$contentClassNa, children = props.children, _useDiffSettings = useDiffSettings(), viewType = _useDiffSettings.viewType, gutterType = _useDiffSettings.gutterType, monotonous = _useDiffSettings.monotonous, RenderingDecoration = "split" === viewType ? SplitDecoration : UnifiedDecoration; reactExports.Children.count(children); var hideGutter = "none" === gutterType;
1237
1328
  return jsxRuntimeExports.jsx(RenderingDecoration, { hideGutter, monotonous, className, gutterClassName, contentClassName, children });
1238
1329
  }
1239
- _Symbol ? _Symbol.isConcatSpreadable : void 0;
1240
- var diffMatchPatch = createCommonjsModule(function(module) {
1330
+ var _arrayAggregator = function(array, setter, iteratee, accumulator) {
1331
+ for (var index2 = -1, length = null == array ? 0 : array.length; ++index2 < length; ) {
1332
+ var value = array[index2];
1333
+ setter(accumulator, value, iteratee(value), array);
1334
+ }
1335
+ return accumulator;
1336
+ };
1337
+ var _createBaseEach = function(eachFunc, fromRight) {
1338
+ return function(collection, iteratee) {
1339
+ if (null == collection) return collection;
1340
+ if (!isArrayLike_1(collection)) return eachFunc(collection, iteratee);
1341
+ for (var length = collection.length, index2 = -1, iterable = Object(collection); (++index2 < length) && false !== iteratee(iterable[index2], index2, iterable); ) ;
1342
+ return collection;
1343
+ };
1344
+ }, _baseEach = _createBaseEach(_baseForOwn);
1345
+ var _baseAggregator = function(collection, setter, iteratee, accumulator) {
1346
+ return _baseEach(collection, function(value, key, collection2) {
1347
+ setter(accumulator, value, iteratee(value), collection2);
1348
+ }), accumulator;
1349
+ };
1350
+ var _createAggregator = function(setter, initializer) {
1351
+ return function(collection, iteratee) {
1352
+ var func = isArray_1(collection) ? _arrayAggregator : _baseAggregator, accumulator = initializer ? initializer() : {};
1353
+ return func(collection, setter, _baseIteratee(iteratee), accumulator);
1354
+ };
1355
+ }, keyBy_1 = _createAggregator(function(result, value, key) {
1356
+ _baseAssignValue(result, key, value);
1357
+ }), spreadableSymbol = _Symbol ? _Symbol.isConcatSpreadable : void 0;
1358
+ var _isFlattenable = function(value) {
1359
+ return isArray_1(value) || isArguments_1(value) || !!(spreadableSymbol && value && value[spreadableSymbol]);
1360
+ };
1361
+ var _baseFlatten = function baseFlatten(array, depth, predicate, isStrict, result) {
1362
+ var index2 = -1, length = array.length;
1363
+ for (predicate || (predicate = _isFlattenable), result || (result = []); ++index2 < length; ) {
1364
+ var value = array[index2];
1365
+ predicate(value) ? _arrayPush(result, value) : (result[result.length] = value);
1366
+ }
1367
+ return result;
1368
+ };
1369
+ var _baseMap = function(collection, iteratee) {
1370
+ var index2 = -1, result = isArrayLike_1(collection) ? Array(collection.length) : [];
1371
+ return _baseEach(collection, function(value, key, collection2) {
1372
+ result[++index2] = iteratee(value, key, collection2);
1373
+ }), result;
1374
+ };
1375
+ var map_1 = function(collection, iteratee) {
1376
+ return (isArray_1(collection) ? _arrayMap : _baseMap)(collection, _baseIteratee(iteratee));
1377
+ };
1378
+ var flatMap_1 = function(collection, iteratee) {
1379
+ return _baseFlatten(map_1(collection, iteratee));
1380
+ };
1381
+ function applyHunk(linesOfCode, _ref) {
1382
+ var newStart = _ref.newStart, _changes$reduce = _ref.changes.reduce(function(_ref2, change) {
1383
+ var _ref3 = _slicedToArray(_ref2, 2), lines = _ref3[0], cursor = _ref3[1];
1384
+ return isDelete(change) ? (lines.splice(cursor, 1), [lines, cursor]) : (isInsert(change) && lines.splice(cursor, 0, change.content), [lines, cursor + 1]);
1385
+ }, [linesOfCode, newStart - 1]);
1386
+ return _slicedToArray(_changes$reduce, 1)[0];
1387
+ }
1388
+ function mapChanges(changes, side, toValue) {
1389
+ if (!changes.length) return [];
1390
+ var computeLineNumber = "old" === side ? computeOldLineNumber : computeNewLineNumber, changesByLineNumber = keyBy_1(changes, computeLineNumber), maxLineNumber = computeLineNumber(changes[changes.length - 1]);
1391
+ return Array.from({ length: maxLineNumber }).map(function(value, i) {
1392
+ return toValue(changesByLineNumber[i + 1]);
1393
+ });
1394
+ }
1395
+ function toTextPair(hunks) {
1396
+ var _groupChanges = function(hunks2) {
1397
+ return flatMap_1(hunks2, function(hunk) {
1398
+ return hunk.changes;
1399
+ }).reduce(function(_ref4, change) {
1400
+ var _ref5 = _slicedToArray(_ref4, 2), oldChanges2 = _ref5[0], newChanges2 = _ref5[1];
1401
+ return isNormal(change) ? (oldChanges2.push(change), newChanges2.push(change)) : isDelete(change) ? oldChanges2.push(change) : newChanges2.push(change), [oldChanges2, newChanges2];
1402
+ }, [[], []]);
1403
+ }(hunks), _groupChanges2 = _slicedToArray(_groupChanges, 2), oldChanges = _groupChanges2[0], newChanges = _groupChanges2[1], toText = function(change) {
1404
+ return change ? change.content : "";
1405
+ };
1406
+ return [mapChanges(oldChanges, "old", toText).join("\n"), mapChanges(newChanges, "new", toText).join("\n")];
1407
+ }
1408
+ function createRoot(children) {
1409
+ return { type: "root", children };
1410
+ }
1411
+ function toTokenTrees(hunks, options) {
1412
+ if (options.oldSource) {
1413
+ var newSource = function(oldSource, hunks2) {
1414
+ return hunks2.reduce(applyHunk, oldSource.split("\n")).join("\n");
1415
+ }(options.oldSource, hunks), highlightText = options.highlight ? function(text) {
1416
+ return options.refractor.highlight(text, options.language);
1417
+ } : function(text) {
1418
+ return [{ type: "text", value: text }];
1419
+ };
1420
+ return [createRoot(highlightText(options.oldSource)), createRoot(highlightText(newSource))];
1421
+ }
1422
+ var _toTextPair2 = _slicedToArray(toTextPair(hunks), 2), oldText = _toTextPair2[0], newText = _toTextPair2[1], toTree = options.highlight ? function(text) {
1423
+ return createRoot(options.refractor.highlight(text, options.language));
1424
+ } : function(text) {
1425
+ return createRoot([{ type: "text", value: text }]);
1426
+ };
1427
+ return [toTree(oldText), toTree(newText)];
1428
+ }
1429
+ function clone(path) {
1430
+ return path.map(function(node) {
1431
+ return _objectSpread2({}, node);
1432
+ });
1433
+ }
1434
+ function replace(path, leaf) {
1435
+ return [].concat(_toConsumableArray(clone(path.slice(0, -1))), [leaf]);
1436
+ }
1437
+ function leafOf(path) {
1438
+ var last = path[path.length - 1];
1439
+ if ("text" === last.type) return last;
1440
+ throw new Error("Invalid token path with leaf of type ".concat(last.type));
1441
+ }
1442
+ function split(path, splitStart, splitEnd, wrapSplitNode) {
1443
+ var parents = path.slice(0, -1), leaf = leafOf(path), output = [];
1444
+ if (splitEnd <= 0 || splitStart >= (null == leaf ? void 0 : leaf.value.length)) return [path];
1445
+ var split2 = function(start, end) {
1446
+ var value = leaf.value.slice(start, end);
1447
+ return [].concat(_toConsumableArray(parents), [_objectSpread2(_objectSpread2({}, leaf), {}, { value })]);
1448
+ };
1449
+ if (splitStart > 0) {
1450
+ var head = split2(0, splitStart);
1451
+ output.push(clone(head));
1452
+ }
1453
+ var body = split2(Math.max(splitStart, 0), splitEnd);
1454
+ if (output.push(wrapSplitNode ? function(path2, parent) {
1455
+ return [parent].concat(_toConsumableArray(clone(path2)));
1456
+ }(body, wrapSplitNode) : clone(body)), splitEnd < leaf.value.length) {
1457
+ var tail = split2(splitEnd);
1458
+ output.push(clone(tail));
1459
+ }
1460
+ return output;
1461
+ }
1462
+ var _excluded$3 = ["children"];
1463
+ function treeToPathList(node) {
1464
+ var output = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [], path = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : [];
1465
+ if (node.children) {
1466
+ var children = node.children, nodeToUse = _objectWithoutProperties(node, _excluded$3);
1467
+ path.push(nodeToUse);
1468
+ var _step, _iterator = _createForOfIteratorHelper(children);
1469
+ try {
1470
+ for (_iterator.s(); !(_step = _iterator.n()).done; ) {
1471
+ treeToPathList(_step.value, output, path);
1472
+ }
1473
+ } catch (err) {
1474
+ _iterator.e(err);
1475
+ } finally {
1476
+ _iterator.f();
1477
+ }
1478
+ path.pop();
1479
+ } else output.push(clone([].concat(_toConsumableArray(path.slice(1)), [node])));
1480
+ return output;
1481
+ }
1482
+ function splitByLineBreak(paths) {
1483
+ return paths.reduce(function(lines, path) {
1484
+ var currentLine = lines[lines.length - 1], _splitPathToLines = function(path2) {
1485
+ var leaf = leafOf(path2);
1486
+ return leaf.value.includes("\n") ? leaf.value.split("\n").map(function(line) {
1487
+ return replace(path2, _objectSpread2(_objectSpread2({}, leaf), {}, { value: line }));
1488
+ }) : [path2];
1489
+ }(path), _splitPathToLines2 = _toArray(_splitPathToLines), currentRemaining = _splitPathToLines2[0], nextLines = _splitPathToLines2.slice(1);
1490
+ return [].concat(_toConsumableArray(lines.slice(0, -1)), [[].concat(_toConsumableArray(currentLine), [currentRemaining])], _toConsumableArray(nextLines.map(function(path2) {
1491
+ return [path2];
1492
+ })));
1493
+ }, [[]]);
1494
+ }
1495
+ function normalizeToLines(tree) {
1496
+ return splitByLineBreak(treeToPathList(tree));
1497
+ }
1498
+ var isEqualWith_1 = function(value, other, customizer) {
1499
+ var result = (customizer = "function" == typeof customizer ? customizer : void 0) ? customizer(value, other) : void 0;
1500
+ return void 0 === result ? _baseIsEqual(value, other, void 0, customizer) : !!result;
1501
+ };
1502
+ var isEqual_1 = function(value, other) {
1503
+ return _baseIsEqual(value, other);
1504
+ };
1505
+ var last_1 = function(array) {
1506
+ var length = null == array ? 0 : array.length;
1507
+ return length ? array[length - 1] : void 0;
1508
+ };
1509
+ function attachNode(parent, node) {
1510
+ if (!parent.children) throw new Error("parent node missing children property");
1511
+ var x, y, previousSibling = last_1(parent.children);
1512
+ return previousSibling && (y = node, (x = previousSibling).type === y.type && ("text" === x.type || x.children && y.children && isEqualWith_1(x, y, function(x2, y2, name) {
1513
+ return "chlidren" === name || isEqual_1(x2, y2);
1514
+ }))) ? parent.children[parent.children.length - 1] = function(x2, y2) {
1515
+ return "value" in x2 && "value" in y2 ? _objectSpread2(_objectSpread2({}, x2), {}, { value: "".concat(x2.value).concat(y2.value) }) : x2;
1516
+ }(previousSibling, node) : parent.children.push(node), parent.children[parent.children.length - 1];
1517
+ }
1518
+ function backToTree(pathList) {
1519
+ var _step, root = { type: "root", children: [] }, _iterator = _createForOfIteratorHelper(pathList);
1520
+ try {
1521
+ var _loop = function() {
1522
+ var path = _step.value;
1523
+ path.reduce(function(parent, node, i) {
1524
+ return attachNode(parent, i === path.length - 1 ? _objectSpread2({}, node) : _objectSpread2(_objectSpread2({}, node), {}, { children: [] }));
1525
+ }, root);
1526
+ };
1527
+ for (_iterator.s(); !(_step = _iterator.n()).done; ) _loop();
1528
+ } catch (err) {
1529
+ _iterator.e(err);
1530
+ } finally {
1531
+ _iterator.f();
1532
+ }
1533
+ return root;
1534
+ }
1535
+ var hasOwnProperty$1 = Object.prototype.hasOwnProperty, groupBy_1 = _createAggregator(function(result, value, key) {
1536
+ hasOwnProperty$1.call(result, key) ? result[key].push(value) : _baseAssignValue(result, key, [value]);
1537
+ }), hasOwnProperty = Object.prototype.hasOwnProperty;
1538
+ var isEmpty_1 = function(value) {
1539
+ if (null == value) return true;
1540
+ if (isArrayLike_1(value) && (isArray_1(value) || "string" == typeof value || "function" == typeof value.splice || isBuffer_1(value) || isTypedArray_1(value) || isArguments_1(value))) return !value.length;
1541
+ var tag = _getTag(value);
1542
+ if ("[object Map]" == tag || "[object Set]" == tag) return !value.size;
1543
+ if (_isPrototype(value)) return !_baseKeys(value).length;
1544
+ for (var key in value) if (hasOwnProperty.call(value, key)) return false;
1545
+ return true;
1546
+ }, splitPathToEncloseRange = function(paths, node) {
1547
+ var start = node.start, length = node.length, rangeEnd = start + length, _paths$reduce = paths.reduce(function(_ref, path) {
1548
+ var _ref2 = _slicedToArray(_ref, 2), output = _ref2[0], nodeStart = _ref2[1], nodeEnd = nodeStart + leafOf(path).value.length;
1549
+ if (nodeStart > rangeEnd || nodeEnd < start) output.push(path);
1550
+ else {
1551
+ var segments = split(path, start - nodeStart, rangeEnd - nodeStart, node);
1552
+ output.push.apply(output, _toConsumableArray(segments));
1553
+ }
1554
+ return [output, nodeEnd];
1555
+ }, [[], 0]);
1556
+ return _slicedToArray(_paths$reduce, 1)[0];
1557
+ };
1558
+ function process$1(linesOfPaths, ranges) {
1559
+ var rangesByLine = groupBy_1(ranges, "lineNumber");
1560
+ return linesOfPaths.map(function(line, i) {
1561
+ return function(paths, ranges2) {
1562
+ return isEmpty_1(ranges2) ? paths : ranges2.reduce(splitPathToEncloseRange, paths);
1563
+ }(line, rangesByLine[i + 1]);
1564
+ });
1565
+ }
1566
+ function pickRanges(oldRanges, newRanges) {
1567
+ return function(_ref3) {
1568
+ var _ref4 = _slicedToArray(_ref3, 2), oldLinesOfPaths = _ref4[0], newLinesOfPaths = _ref4[1];
1569
+ return [process$1(oldLinesOfPaths, oldRanges), process$1(newLinesOfPaths, newRanges)];
1570
+ };
1571
+ }
1572
+ var flatten_1 = function(array) {
1573
+ return (null == array ? 0 : array.length) ? _baseFlatten(array) : [];
1574
+ }, nativeMax = Math.max;
1575
+ var findIndex_1 = function(array, predicate, fromIndex) {
1576
+ var length = null == array ? 0 : array.length;
1577
+ if (!length) return -1;
1578
+ var index2 = null == fromIndex ? 0 : toInteger_1(fromIndex);
1579
+ return index2 < 0 && (index2 = nativeMax(length + index2, 0)), _baseFindIndex(array, _baseIteratee(predicate), index2);
1580
+ }, diffMatchPatch = createCommonjsModule(function(module) {
1241
1581
  var diff_match_patch = function() {
1242
1582
  this.Diff_Timeout = 1, this.Diff_EditCost = 4, this.Match_Threshold = 0.5, this.Match_Distance = 1e3, this.Patch_DeleteThreshold = 0.5, this.Patch_Margin = 4, this.Match_MaxBits = 32;
1243
1583
  };
@@ -1678,7 +2018,103 @@ var diffMatchPatch = createCommonjsModule(function(module) {
1678
2018
  }
1679
2019
  return text.join("").replace(/%20/g, " ");
1680
2020
  }, module.exports = diff_match_patch, module.exports.diff_match_patch = diff_match_patch, module.exports.DIFF_DELETE = -1, module.exports.DIFF_INSERT = 1, module.exports.DIFF_EQUAL = 0;
1681
- }); diffMatchPatch.DIFF_EQUAL; diffMatchPatch.DIFF_DELETE; diffMatchPatch.DIFF_INSERT;
2021
+ }), DIFF_EQUAL = diffMatchPatch.DIFF_EQUAL, DIFF_DELETE = diffMatchPatch.DIFF_DELETE, DIFF_INSERT = diffMatchPatch.DIFF_INSERT;
2022
+ function findChangeBlocks(changes) {
2023
+ var start = findIndex_1(changes, function(change) {
2024
+ return !isNormal(change);
2025
+ });
2026
+ if (-1 === start) return [];
2027
+ var end = findIndex_1(changes, function(change) {
2028
+ return !!isNormal(change);
2029
+ }, start);
2030
+ return -1 === end ? [changes.slice(start)] : [changes.slice(start, end)].concat(_toConsumableArray(findChangeBlocks(changes.slice(end))));
2031
+ }
2032
+ function splitDiffToLines(diffs) {
2033
+ return diffs.reduce(function(lines, _ref3) {
2034
+ var _ref4 = _slicedToArray(_ref3, 2), type = _ref4[0], _currentLines$map2 = _toArray(_ref4[1].split("\n").map(function(line) {
2035
+ return [type, line];
2036
+ })), currentLineRemaining = _currentLines$map2[0], nextLines = _currentLines$map2.slice(1);
2037
+ return [].concat(_toConsumableArray(lines.slice(0, -1)), [[].concat(_toConsumableArray(lines[lines.length - 1]), [currentLineRemaining])], _toConsumableArray(nextLines.map(function(line) {
2038
+ return [line];
2039
+ })));
2040
+ }, [[]]);
2041
+ }
2042
+ function diffsToEdits(diffs, lineNumber) {
2043
+ return diffs.reduce(function(output, diff) {
2044
+ var _output = _slicedToArray(output, 2), edits = _output[0], start = _output[1], _diff2 = _slicedToArray(diff, 2), type = _diff2[0], value = _diff2[1];
2045
+ if (type !== DIFF_EQUAL) {
2046
+ var edit = { type: "edit", lineNumber, start, length: value.length };
2047
+ edits.push(edit);
2048
+ }
2049
+ return [edits, start + value.length];
2050
+ }, [[], 0])[0];
2051
+ }
2052
+ function convertToLinesOfEdits(linesOfDiffs, startLineNumber) {
2053
+ return flatMap_1(linesOfDiffs, function(diffs, i) {
2054
+ return diffsToEdits(diffs, startLineNumber + i);
2055
+ });
2056
+ }
2057
+ function diffText(x, y) {
2058
+ var dmp = new diffMatchPatch(), diffs = dmp.diff_main(x, y);
2059
+ return dmp.diff_cleanupSemantic(diffs), diffs.length <= 1 ? [[], []] : function(diffs2) {
2060
+ return diffs2.reduce(function(_ref, diff) {
2061
+ var _ref2 = _slicedToArray(_ref, 2), oldDiffs = _ref2[0], newDiffs = _ref2[1];
2062
+ switch (_slicedToArray(diff, 1)[0]) {
2063
+ case DIFF_INSERT:
2064
+ newDiffs.push(diff);
2065
+ break;
2066
+ case DIFF_DELETE:
2067
+ oldDiffs.push(diff);
2068
+ break;
2069
+ default:
2070
+ oldDiffs.push(diff), newDiffs.push(diff);
2071
+ }
2072
+ return [oldDiffs, newDiffs];
2073
+ }, [[], []]);
2074
+ }(diffs);
2075
+ }
2076
+ function diffChangeBlock(changes) {
2077
+ var _changes$reduce = changes.reduce(function(_ref5, change) {
2078
+ var _ref6 = _slicedToArray(_ref5, 2), oldSource = _ref6[0], newSource = _ref6[1];
2079
+ return isDelete(change) ? [oldSource + (oldSource ? "\n" : "") + change.content, newSource] : [oldSource, newSource + (newSource ? "\n" : "") + change.content];
2080
+ }, ["", ""]), _changes$reduce2 = _slicedToArray(_changes$reduce, 2), _diffText2 = _slicedToArray(diffText(_changes$reduce2[0], _changes$reduce2[1]), 2), oldDiffs = _diffText2[0], newDiffs = _diffText2[1];
2081
+ if (0 === oldDiffs.length && 0 === newDiffs.length) return [[], []];
2082
+ var getLineNumber = function(change) {
2083
+ if (change && !isNormal(change)) return change.lineNumber;
2084
+ }, oldStartLineNumber = getLineNumber(changes.find(isDelete)), newStartLineNumber = getLineNumber(changes.find(isInsert));
2085
+ if (void 0 === oldStartLineNumber || void 0 === newStartLineNumber) throw new Error("Could not find start line number for edit");
2086
+ return [convertToLinesOfEdits(splitDiffToLines(oldDiffs), oldStartLineNumber), convertToLinesOfEdits(splitDiffToLines(newDiffs), newStartLineNumber)];
2087
+ }
2088
+ function diffByLine(changes) {
2089
+ var _changes$reduce3 = changes.reduce(function(_ref7, currentChange) {
2090
+ var _ref8 = _slicedToArray(_ref7, 3), oldEdits = _ref8[0], newEdits = _ref8[1], previousChange = _ref8[2];
2091
+ if (!previousChange || !isDelete(previousChange) || !isInsert(currentChange)) return [oldEdits, newEdits, currentChange];
2092
+ var _diffText4 = _slicedToArray(diffText(previousChange.content, currentChange.content), 2), oldDiffs = _diffText4[0], newDiffs = _diffText4[1];
2093
+ return [oldEdits.concat(diffsToEdits(oldDiffs, previousChange.lineNumber)), newEdits.concat(diffsToEdits(newDiffs, currentChange.lineNumber)), currentChange];
2094
+ }, [[], [], null]), _changes$reduce4 = _slicedToArray(_changes$reduce3, 2);
2095
+ return [_changes$reduce4[0], _changes$reduce4[1]];
2096
+ }
2097
+ function markEdits(hunks) {
2098
+ var _ref9$type = (arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}).type, findEdits = "block" === (void 0 === _ref9$type ? "block" : _ref9$type) ? diffChangeBlock : diffByLine, _changeBlocks$map$red = flatMap_1(hunks.map(function(hunk) {
2099
+ return hunk.changes;
2100
+ }), findChangeBlocks).map(findEdits).reduce(function(_ref10, _ref11) {
2101
+ var _ref12 = _slicedToArray(_ref10, 2), oldEdits2 = _ref12[0], newEdits2 = _ref12[1], _ref13 = _slicedToArray(_ref11, 2), currentOld = _ref13[0], currentNew = _ref13[1];
2102
+ return [oldEdits2.concat(currentOld), newEdits2.concat(currentNew)];
2103
+ }, [[], []]), _changeBlocks$map$red2 = _slicedToArray(_changeBlocks$map$red, 2), oldEdits = _changeBlocks$map$red2[0], newEdits = _changeBlocks$map$red2[1];
2104
+ return pickRanges(flatten_1(oldEdits), flatten_1(newEdits));
2105
+ }
2106
+ var _excluded$2 = ["enhancers"], tokenize = function(hunks) {
2107
+ var pair, _ref = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, _ref$enhancers = _ref.enhancers, enhancers = void 0 === _ref$enhancers ? [] : _ref$enhancers, _toTokenTrees2 = _slicedToArray(toTokenTrees(hunks, _objectWithoutProperties(_ref, _excluded$2)), 2), oldTokenTree = _toTokenTrees2[0], newTokenTree = _toTokenTrees2[1], _ref2 = [normalizeToLines(oldTokenTree), normalizeToLines(newTokenTree)], _enhance = (pair = [_ref2[0], _ref2[1]], enhancers.reduce(function(input, enhance) {
2108
+ return enhance(input);
2109
+ }, pair)), _enhance2 = _slicedToArray(_enhance, 2), oldEnhanced = _enhance2[0], newEnhanced = _enhance2[1], _ref3 = [oldEnhanced.map(backToTree), newEnhanced.map(backToTree)], newTrees = _ref3[1];
2110
+ return { old: _ref3[0].map(function(root) {
2111
+ var _root$children;
2112
+ return null !== (_root$children = root.children) && void 0 !== _root$children ? _root$children : [];
2113
+ }), new: newTrees.map(function(root) {
2114
+ var _root$children2;
2115
+ return null !== (_root$children2 = root.children) && void 0 !== _root$children2 ? _root$children2 : [];
2116
+ }) };
2117
+ };
1682
2118
 
1683
2119
  function mapDiffType(status) {
1684
2120
  switch (String(status || "").trim().toLowerCase()) {
@@ -1698,29 +2134,38 @@ function mapDiffType(status) {
1698
2134
  return "modify";
1699
2135
  }
1700
2136
  }
2137
+ function normalizeDiffStatus(status) {
2138
+ return String(status || "").trim().toLowerCase();
2139
+ }
1701
2140
  function buildFallbackDiff(payload) {
1702
2141
  const oldPath = payload.old_path || payload.path;
1703
2142
  const newPath = payload.path;
2143
+ const status = normalizeDiffStatus(payload.status);
2144
+ const previousPathHeader = status === "added" || status === "add" ? "/dev/null" : `a/${oldPath}`;
2145
+ const nextPathHeader = status === "deleted" || status === "delete" ? "/dev/null" : `b/${newPath}`;
1704
2146
  const header = [
1705
2147
  `diff --git a/${oldPath} b/${newPath}`,
1706
- `--- a/${oldPath}`,
1707
- `+++ b/${newPath}`
2148
+ `--- ${previousPathHeader}`,
2149
+ `+++ ${nextPathHeader}`
1708
2150
  ];
1709
2151
  return [...header, ...payload.lines].join("\n");
1710
2152
  }
1711
2153
  function buildUnifiedDiff(payload) {
1712
2154
  if (!payload.lines.length) return "";
1713
2155
  const firstLine = String(payload.lines[0] || "");
2156
+ const oldPath = payload.old_path || payload.path;
2157
+ const newPath = payload.path;
1714
2158
  if (firstLine.startsWith("diff --git ")) {
1715
2159
  return payload.lines.join("\n");
1716
2160
  }
2161
+ if (firstLine.startsWith("--- ") || firstLine.startsWith("Binary files ")) {
2162
+ return [`diff --git a/${oldPath} b/${newPath}`, ...payload.lines].join("\n");
2163
+ }
1717
2164
  return buildFallbackDiff(payload);
1718
2165
  }
1719
- function formatPathLabel$1(diff) {
1720
- if (diff.old_path && diff.old_path !== diff.path) {
1721
- return `${diff.old_path} → ${diff.path}`;
1722
- }
1723
- return diff.path;
2166
+ function formatPathLabel(diff, fallback) {
2167
+ const displayPath = "display_path" in diff && typeof diff.display_path === "string" && diff.display_path.trim() ? diff.display_path.trim() : diff.path;
2168
+ return formatGitDiffPathLabel(displayPath, diff.old_path, fallback);
1724
2169
  }
1725
2170
  function parseSingleFile(text) {
1726
2171
  if (!text.trim()) return null;
@@ -1733,24 +2178,37 @@ function parseSingleFile(text) {
1733
2178
  }
1734
2179
  function GitDiffViewer({
1735
2180
  diff,
1736
- className
2181
+ className,
2182
+ pathLabel
1737
2183
  }) {
2184
+ const { t } = useI18n("workspace");
1738
2185
  const diffText = reactExports.useMemo(() => diff ? buildUnifiedDiff(diff) : "", [diff]);
1739
2186
  const parsed = reactExports.useMemo(() => parseSingleFile(diffText), [diffText]);
2187
+ const tokens = reactExports.useMemo(() => {
2188
+ if (!parsed?.hunks.length) return null;
2189
+ try {
2190
+ return tokenize(parsed.hunks, {
2191
+ enhancers: [markEdits(parsed.hunks, { type: "line" })]
2192
+ });
2193
+ } catch {
2194
+ return null;
2195
+ }
2196
+ }, [parsed]);
2197
+ const resolvedPathLabel = diff ? pathLabel || formatPathLabel(diff, t("git_viewer_diff", void 0, "Diff")) : null;
1740
2198
  if (!diff) {
1741
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm leading-7 text-muted-foreground", children: "No patch selected." });
2199
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm leading-7 text-muted-foreground", children: t("git_diff_none_selected", void 0, "No patch selected.") });
1742
2200
  }
1743
2201
  if (diff.binary) {
1744
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("ds-stage-diff-shell", className), children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ds-stage-diff-filehead", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
1745
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate text-[13px] font-medium text-foreground", children: formatPathLabel$1(diff) }),
1746
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1 text-[11px] text-muted-foreground", children: "Binary file changed." })
2202
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { "data-testid": "git-unified-diff-viewer", className: cn("ds-stage-diff-shell", className), children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ds-stage-diff-filehead", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
2203
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate text-[13px] font-medium text-foreground", children: resolvedPathLabel }),
2204
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1 text-[11px] text-muted-foreground", children: t("git_diff_binary_changed", void 0, "Binary file changed.") })
1747
2205
  ] }) }) });
1748
2206
  }
1749
2207
  if (!parsed || !parsed.hunks.length) {
1750
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn("ds-stage-diff-shell", className), children: [
2208
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { "data-testid": "git-unified-diff-viewer", className: cn("ds-stage-diff-shell", className), children: [
1751
2209
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ds-stage-diff-filehead", children: [
1752
2210
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
1753
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate text-[13px] font-medium text-foreground", children: formatPathLabel$1(diff) }),
2211
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate text-[13px] font-medium text-foreground", children: resolvedPathLabel }),
1754
2212
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1 text-[11px] text-muted-foreground", children: String(diff.status || "modified") })
1755
2213
  ] }),
1756
2214
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 text-[11px]", children: [
@@ -1764,13 +2222,13 @@ function GitDiffViewer({
1764
2222
  ] })
1765
2223
  ] })
1766
2224
  ] }),
1767
- /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "max-h-[36rem] overflow-auto whitespace-pre-wrap break-words px-4 py-3 font-mono text-[12px] leading-6 text-foreground", children: diff.lines.join("\n") || "No patch lines available." })
2225
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "feed-scrollbar overflow-x-auto overflow-y-visible", children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "min-w-max px-4 py-3 font-mono text-[12px] leading-6 text-foreground", children: diff.lines.join("\n") || t("git_diff_no_patch_lines", void 0, "No patch lines available.") }) })
1768
2226
  ] });
1769
2227
  }
1770
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn("ds-stage-diff-shell", className), children: [
2228
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { "data-testid": "git-unified-diff-viewer", className: cn("ds-stage-diff-shell", className), children: [
1771
2229
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ds-stage-diff-filehead", children: [
1772
2230
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
1773
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate text-[13px] font-medium text-foreground", children: formatPathLabel$1(diff) }),
2231
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate text-[13px] font-medium text-foreground", children: resolvedPathLabel }),
1774
2232
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 text-[11px] text-muted-foreground", children: [
1775
2233
  String(diff.status || "modified"),
1776
2234
  " · ",
@@ -1790,24 +2248,86 @@ function GitDiffViewer({
1790
2248
  ] })
1791
2249
  ] })
1792
2250
  ] }),
1793
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "max-h-[36rem] overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2251
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "feed-scrollbar overflow-x-auto overflow-y-visible", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "min-w-max", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1794
2252
  index,
1795
2253
  {
1796
2254
  viewType: "unified",
1797
2255
  diffType: parsed.type || mapDiffType(diff.status),
1798
2256
  hunks: parsed.hunks,
1799
2257
  gutterType: "default",
2258
+ tokens,
1800
2259
  className: "ds-github-diff-table",
1801
2260
  children: (hunks) => hunks.flatMap((hunk) => [
1802
2261
  /* @__PURE__ */ jsxRuntimeExports.jsx(Decoration, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ds-github-diff-hunk", children: hunk.content }) }, `decoration-${hunk.content}`),
1803
2262
  /* @__PURE__ */ jsxRuntimeExports.jsx(Hunk, { hunk }, `hunk-${hunk.content}`)
1804
2263
  ])
1805
2264
  }
1806
- ) }),
1807
- diff.truncated ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t border-black/[0.06] px-4 py-2 text-[11px] text-muted-foreground dark:border-white/[0.08]", children: "Patch output is truncated." }) : null
2265
+ ) }) }),
2266
+ diff.truncated ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t border-black/[0.06] px-4 py-2 text-[11px] text-muted-foreground dark:border-white/[0.08]", children: t("git_diff_patch_truncated", void 0, "Patch output is truncated.") }) : null
1808
2267
  ] });
1809
2268
  }
1810
2269
 
2270
+ function resolveSnapshotRevision(document) {
2271
+ const gitRevision = document?.meta?.git_revision;
2272
+ if (typeof gitRevision === "string" && gitRevision.trim()) {
2273
+ return gitRevision.trim();
2274
+ }
2275
+ const revision = String(document?.revision || "").trim();
2276
+ return revision || null;
2277
+ }
2278
+ function GitSnapshotViewer({
2279
+ document,
2280
+ className
2281
+ }) {
2282
+ const { t } = useI18n("workspace");
2283
+ const lines = reactExports.useMemo(() => String(document?.content || "").split("\n"), [document?.content]);
2284
+ const revision = resolveSnapshotRevision(document);
2285
+ const isBinaryLike = !document?.content && !document?.encoding && Number(document?.size_bytes || 0) > 0;
2286
+ if (!document) {
2287
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm leading-7 text-muted-foreground", children: t("git_snapshot_none_selected", void 0, "No snapshot selected.") });
2288
+ }
2289
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { "data-testid": "git-snapshot-viewer", className: cn("ds-stage-diff-shell", className), children: [
2290
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ds-stage-diff-filehead", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
2291
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate text-[13px] font-medium text-foreground", children: document.path || document.title || t("git_viewer_snapshot", void 0, "Snapshot") }),
2292
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-2 text-[11px] text-muted-foreground", children: [
2293
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t("git_snapshot_meta_label", void 0, "Snapshot") }),
2294
+ revision ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
2295
+ "· ",
2296
+ revision
2297
+ ] }) : null,
2298
+ document.mime_type ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
2299
+ "· ",
2300
+ document.mime_type
2301
+ ] }) : null,
2302
+ typeof document.size_bytes === "number" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
2303
+ "· ",
2304
+ document.size_bytes,
2305
+ " bytes"
2306
+ ] }) : null
2307
+ ] })
2308
+ ] }) }),
2309
+ isBinaryLike ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-8 text-sm text-muted-foreground", children: t(
2310
+ "git_snapshot_binary_unavailable",
2311
+ void 0,
2312
+ "Snapshot preview is unavailable for binary files."
2313
+ ) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "feed-scrollbar overflow-x-auto overflow-y-visible", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "min-w-max", children: lines.length === 1 && lines[0] === "" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-6 font-mono text-[12px] leading-6 text-muted-foreground", children: t("git_snapshot_empty_file", void 0, "File is empty.") }) : lines.map((line, index) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
2314
+ "div",
2315
+ {
2316
+ className: "grid grid-cols-[64px_minmax(0,1fr)] border-b border-black/[0.05] font-mono text-[12px] leading-6 text-foreground last:border-b-0 dark:border-white/[0.06]",
2317
+ children: [
2318
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "select-none border-r border-black/[0.06] bg-black/[0.02] px-3 py-0.5 text-right text-[11px] text-muted-foreground dark:border-white/[0.06] dark:bg-white/[0.03]", children: index + 1 }),
2319
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "whitespace-pre px-4 py-0.5", children: line || " " })
2320
+ ]
2321
+ },
2322
+ `snapshot-line-${index + 1}`
2323
+ )) }) })
2324
+ ] });
2325
+ }
2326
+
2327
+ const normalizeBoolean = (value) => {
2328
+ if (typeof value === "boolean") return value;
2329
+ return null;
2330
+ };
1811
2331
  const normalizeNumber = (value) => {
1812
2332
  if (typeof value === "number" && Number.isFinite(value)) return value;
1813
2333
  return null;
@@ -1817,37 +2337,154 @@ const normalizeString = (value) => {
1817
2337
  const trimmed = value.trim();
1818
2338
  return trimmed || null;
1819
2339
  };
1820
- const formatPathLabel = (path, oldPath) => {
1821
- if (path && oldPath && path !== oldPath) {
1822
- return `${oldPath} → ${path}`;
2340
+ const isFileChangeDiffPayload = (value) => Boolean(value && "available" in value);
2341
+ function GitSnapshotContent({
2342
+ document,
2343
+ projectId,
2344
+ parentTabId
2345
+ }) {
2346
+ const clearWorkspaceTabState = useWorkspaceSurfaceStore((state) => state.clearTabState);
2347
+ const clearWorkspaceTabReferences = useWorkspaceSurfaceStore((state) => state.clearTabReferences);
2348
+ const previewKind = reactExports.useMemo(() => inferSnapshotPreviewKind(document), [document]);
2349
+ const snapshotFileNode = reactExports.useMemo(
2350
+ () => document ? buildQuestFileNodeFromDocument(projectId, document) : null,
2351
+ [document, projectId]
2352
+ );
2353
+ const previewTabId = reactExports.useMemo(
2354
+ () => `${parentTabId}::snapshot-preview::${previewKind}`,
2355
+ [parentTabId, previewKind]
2356
+ );
2357
+ const pluginProps = reactExports.useMemo(() => {
2358
+ if (!snapshotFileNode) return null;
2359
+ const resourcePath = snapshotFileNode.path ? toFilesResourcePath(snapshotFileNode.path) : void 0;
2360
+ const fileMeta = {
2361
+ updatedAt: snapshotFileNode.updatedAt,
2362
+ sizeBytes: snapshotFileNode.size,
2363
+ mimeType: snapshotFileNode.mimeType
2364
+ };
2365
+ return {
2366
+ context: {
2367
+ type: previewKind === "notebook" ? "notebook" : "file",
2368
+ resourceId: snapshotFileNode.id,
2369
+ resourceName: snapshotFileNode.name,
2370
+ resourcePath,
2371
+ mimeType: snapshotFileNode.mimeType,
2372
+ customData: {
2373
+ projectId,
2374
+ readonly: true,
2375
+ readOnlyMode: true,
2376
+ size: snapshotFileNode.size,
2377
+ fileMeta
2378
+ }
2379
+ },
2380
+ tabId: previewTabId,
2381
+ setDirty: () => void 0,
2382
+ setTitle: () => void 0
2383
+ };
2384
+ }, [previewKind, previewTabId, projectId, snapshotFileNode]);
2385
+ reactExports.useEffect(() => {
2386
+ return () => {
2387
+ clearWorkspaceTabReferences(previewTabId);
2388
+ clearWorkspaceTabState(previewTabId);
2389
+ };
2390
+ }, [clearWorkspaceTabReferences, clearWorkspaceTabState, previewTabId]);
2391
+ if (!document || previewKind === "plain" || !pluginProps) {
2392
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2393
+ GitSnapshotViewer,
2394
+ {
2395
+ document,
2396
+ className: "border border-black/[0.06] bg-white/[0.92] shadow-none dark:border-white/[0.08] dark:bg-[rgba(24,26,31,0.92)]"
2397
+ }
2398
+ );
1823
2399
  }
1824
- return path || "Diff";
1825
- };
2400
+ if (previewKind === "markdown") {
2401
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(MarkdownViewerPlugin, { ...pluginProps }) });
2402
+ }
2403
+ if (previewKind === "notebook") {
2404
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(NotebookEditor, { ...pluginProps, className: "h-full" }) });
2405
+ }
2406
+ if (previewKind === "pdf") {
2407
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(PdfViewerPlugin, { ...pluginProps }) });
2408
+ }
2409
+ if (previewKind === "image") {
2410
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ImageViewerPlugin, { ...pluginProps }) });
2411
+ }
2412
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2413
+ GitSnapshotViewer,
2414
+ {
2415
+ document,
2416
+ className: "border border-black/[0.06] bg-white/[0.92] shadow-none dark:border-white/[0.08] dark:bg-[rgba(24,26,31,0.92)]"
2417
+ }
2418
+ );
2419
+ }
1826
2420
  function GitDiffViewerPlugin({
1827
2421
  context,
2422
+ tabId,
1828
2423
  setTitle
1829
2424
  }) {
2425
+ const { t } = useI18n("workspace");
1830
2426
  const custom = context.customData ?? {};
2427
+ const updateWorkspaceTabState = useWorkspaceSurfaceStore((state) => state.updateTabState);
1831
2428
  const projectId = normalizeString(custom.projectId);
2429
+ const resolver = custom.resolver === "file_change" ? "file_change" : "git";
2430
+ const initialMode = custom.initialMode === "snapshot" ? "snapshot" : "diff";
1832
2431
  const base = normalizeString(custom.base);
1833
2432
  const head = normalizeString(custom.head);
1834
2433
  const path = normalizeString(custom.path);
2434
+ const queryPath = normalizeString(custom.queryPath);
2435
+ const displayPath = normalizeString(custom.displayPath);
2436
+ const runId = normalizeString(custom.runId);
2437
+ const eventId = normalizeString(custom.eventId);
1835
2438
  const status = normalizeString(custom.status);
1836
2439
  const oldPath = normalizeString(custom.oldPath);
1837
2440
  const added = normalizeNumber(custom.added);
1838
2441
  const removed = normalizeNumber(custom.removed);
2442
+ const snapshotRevision = normalizeString(custom.snapshotRevision);
2443
+ const snapshotDocumentId = normalizeString(custom.snapshotDocumentId);
2444
+ const hasValidDiffContext = resolver === "file_change" ? Boolean(projectId && runId && queryPath) : Boolean(projectId && base && head && path);
2445
+ const resolvedSnapshotDocumentId = snapshotDocumentId || (snapshotRevision && path ? `git::${snapshotRevision}::${path}` : null);
2446
+ const hasValidSnapshotContext = Boolean(projectId && resolvedSnapshotDocumentId);
2447
+ const explicitAllowSnapshot = normalizeBoolean(custom.allowSnapshot);
2448
+ const explicitAllowDiff = normalizeBoolean(custom.allowDiff);
2449
+ const allowSnapshot = explicitAllowSnapshot ?? hasValidSnapshotContext;
2450
+ const allowDiff = explicitAllowDiff ?? hasValidDiffContext;
2451
+ const [viewMode, setViewMode] = reactExports.useState(() => {
2452
+ if (initialMode === "snapshot" && allowSnapshot) return "snapshot";
2453
+ return "diff";
2454
+ });
1839
2455
  reactExports.useEffect(() => {
1840
- setTitle(formatPathLabel(path, oldPath));
1841
- }, [oldPath, path, setTitle]);
2456
+ if (viewMode === "snapshot" && !allowSnapshot && allowDiff) {
2457
+ setViewMode("diff");
2458
+ return;
2459
+ }
2460
+ if (viewMode === "diff" && !allowDiff && allowSnapshot) {
2461
+ setViewMode("snapshot");
2462
+ }
2463
+ }, [allowDiff, allowSnapshot, viewMode]);
2464
+ const snapshotQuery = useQuery({
2465
+ queryKey: ["git-diff-viewer", "snapshot", projectId, resolvedSnapshotDocumentId],
2466
+ queryFn: () => client.openDocument(projectId, resolvedSnapshotDocumentId),
2467
+ enabled: Boolean(projectId && resolvedSnapshotDocumentId && allowSnapshot && viewMode === "snapshot"),
2468
+ staleTime: 3e4
2469
+ });
1842
2470
  const diffQuery = useQuery({
1843
- queryKey: ["git-diff-viewer", projectId, base, head, path],
1844
- queryFn: () => client.gitDiffFile(projectId, base, head, path),
1845
- enabled: Boolean(projectId && base && head && path),
2471
+ queryKey: ["git-diff-viewer", "diff", resolver, projectId, base, head, path, queryPath, runId, eventId],
2472
+ queryFn: () => resolver === "file_change" ? client.fileChangeDiff(projectId, runId, queryPath, eventId || void 0) : client.gitDiffFile(projectId, base, head, path),
2473
+ enabled: Boolean(hasValidDiffContext && allowDiff && viewMode === "diff"),
1846
2474
  staleTime: 3e4
1847
2475
  });
1848
2476
  const mergedDiff = reactExports.useMemo(() => {
1849
2477
  const payload = diffQuery.data ?? null;
1850
- if (!payload || !path || !base || !head) return payload;
2478
+ if (!payload) return payload;
2479
+ if (resolver === "file_change") {
2480
+ return {
2481
+ ...payload,
2482
+ display_path: (isFileChangeDiffPayload(payload) ? payload.display_path : null) || displayPath || void 0,
2483
+ run_id: isFileChangeDiffPayload(payload) ? payload.run_id || runId || void 0 : runId || void 0,
2484
+ event_id: isFileChangeDiffPayload(payload) ? payload.event_id || eventId || void 0 : eventId || void 0
2485
+ };
2486
+ }
2487
+ if (!path || !base || !head) return payload;
1851
2488
  return {
1852
2489
  ...payload,
1853
2490
  path,
@@ -1858,61 +2495,168 @@ function GitDiffViewerPlugin({
1858
2495
  added: payload.added ?? added ?? void 0,
1859
2496
  removed: payload.removed ?? removed ?? void 0
1860
2497
  };
1861
- }, [added, base, diffQuery.data, head, oldPath, path, removed, status]);
1862
- if (!projectId || !base || !head || !path) {
1863
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-full items-center justify-center px-6 text-sm text-muted-foreground", children: "Missing diff context." });
2498
+ }, [added, base, diffQuery.data, displayPath, eventId, head, oldPath, path, removed, resolver, runId, status]);
2499
+ const resolvedBase = mergedDiff?.base || base || "";
2500
+ const resolvedHead = mergedDiff?.head || head || "";
2501
+ const resolvedStatus = mergedDiff?.status || status || "modified";
2502
+ const resolvedOldPath = mergedDiff?.old_path || oldPath || null;
2503
+ const resolvedAdded = mergedDiff?.added ?? added;
2504
+ const resolvedRemoved = mergedDiff?.removed ?? removed;
2505
+ const snapshotContentKind = reactExports.useMemo(
2506
+ () => inferSnapshotContentKind(snapshotQuery.data),
2507
+ [snapshotQuery.data]
2508
+ );
2509
+ const snapshotPreviewKind = reactExports.useMemo(
2510
+ () => inferSnapshotPreviewKind(snapshotQuery.data),
2511
+ [snapshotQuery.data]
2512
+ );
2513
+ const resolvedPathLabel = resolver === "file_change" ? (isFileChangeDiffPayload(mergedDiff) ? mergedDiff.display_path : null) || displayPath || mergedDiff?.path || queryPath || t("git_viewer_diff", void 0, "Diff") : formatGitDiffPathLabel(
2514
+ path || mergedDiff?.path || displayPath,
2515
+ resolvedOldPath,
2516
+ t("git_viewer_diff", void 0, "Diff")
2517
+ );
2518
+ reactExports.useEffect(() => {
2519
+ setTitle(resolvedPathLabel);
2520
+ }, [resolvedPathLabel, setTitle]);
2521
+ reactExports.useEffect(() => {
2522
+ updateWorkspaceTabState(tabId, {
2523
+ contentKind: viewMode === "snapshot" ? snapshotContentKind : "code",
2524
+ documentMode: viewMode,
2525
+ isReadOnly: true,
2526
+ resourceName: resolvedPathLabel,
2527
+ resourcePath: viewMode === "snapshot" ? snapshotQuery.data?.path || path || void 0 : mergedDiff?.path || path || queryPath || void 0
2528
+ });
2529
+ }, [
2530
+ mergedDiff?.path,
2531
+ path,
2532
+ queryPath,
2533
+ resolvedPathLabel,
2534
+ snapshotContentKind,
2535
+ snapshotQuery.data?.path,
2536
+ tabId,
2537
+ updateWorkspaceTabState,
2538
+ viewMode
2539
+ ]);
2540
+ const unavailableMessage = resolver === "file_change" && isFileChangeDiffPayload(mergedDiff) && !mergedDiff.available ? mergedDiff.message || t("git_viewer_historical_patch_unavailable", void 0, "Historical patch unavailable.") : null;
2541
+ const currentQuery = viewMode === "snapshot" ? snapshotQuery : diffQuery;
2542
+ const useEmbeddedSnapshotShell = viewMode === "snapshot" && Boolean(snapshotQuery.data) && snapshotPreviewKind !== "plain";
2543
+ if (!projectId || !hasValidSnapshotContext && !hasValidDiffContext) {
2544
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-full items-center justify-center px-6 text-sm text-muted-foreground", children: t("git_viewer_missing_context", void 0, "Missing diff context.") });
1864
2545
  }
1865
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex h-full min-h-0 flex-col bg-[rgba(250,248,244,0.86)] dark:bg-[rgba(18,20,24,0.92)]", children: [
1866
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-b border-black/[0.06] px-6 py-5 dark:border-white/[0.08]", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [
1867
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
1868
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2 text-[11px] font-medium uppercase tracking-[0.14em] text-muted-foreground", children: [
1869
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1", children: [
1870
- /* @__PURE__ */ jsxRuntimeExports.jsx(GitCompare, { className: "h-3.5 w-3.5" }),
1871
- "Diff"
2546
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
2547
+ "div",
2548
+ {
2549
+ "data-testid": "git-diff-viewer-plugin",
2550
+ className: "flex h-full min-h-0 flex-col bg-[rgba(250,248,244,0.86)] dark:bg-[rgba(18,20,24,0.92)]",
2551
+ children: [
2552
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-b border-black/[0.06] px-6 py-5 dark:border-white/[0.08]", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [
2553
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
2554
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2 text-[11px] font-medium uppercase tracking-[0.14em] text-muted-foreground", children: [
2555
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1", children: [
2556
+ viewMode === "snapshot" ? /* @__PURE__ */ jsxRuntimeExports.jsx(FileText, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(GitCompare, { className: "h-3.5 w-3.5" }),
2557
+ viewMode === "snapshot" ? t("git_viewer_snapshot", void 0, "Snapshot") : resolver === "file_change" ? t("git_viewer_historical_diff", void 0, "Historical Diff") : t("git_viewer_diff", void 0, "Diff")
2558
+ ] }),
2559
+ viewMode === "diff" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2560
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "·" }),
2561
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: resolvedStatus })
2562
+ ] }) : null
2563
+ ] }),
2564
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 break-words text-[24px] font-semibold tracking-[-0.03em] text-foreground", children: resolvedPathLabel }),
2565
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-3 text-sm text-muted-foreground", children: [
2566
+ viewMode === "snapshot" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2567
+ snapshotRevision ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: snapshotRevision }) : null,
2568
+ allowDiff && resolvedBase ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: resolvedBase }) : null,
2569
+ allowDiff && resolvedBase && resolvedHead ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "→" }) : null,
2570
+ allowDiff && resolvedHead ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: resolvedHead }) : null
2571
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2572
+ resolvedBase ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: resolvedBase }) : null,
2573
+ resolvedBase && resolvedHead ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "→" }) : null,
2574
+ resolvedHead ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: resolvedHead }) : null
2575
+ ] }),
2576
+ resolvedAdded != null ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-emerald-700 dark:text-emerald-300", children: [
2577
+ "+",
2578
+ resolvedAdded
2579
+ ] }) : null,
2580
+ resolvedRemoved != null ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-rose-700 dark:text-rose-300", children: [
2581
+ "-",
2582
+ resolvedRemoved
2583
+ ] }) : null
2584
+ ] })
1872
2585
  ] }),
1873
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "·" }),
1874
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: status || "modified" })
1875
- ] }),
1876
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 break-words text-[24px] font-semibold tracking-[-0.03em] text-foreground", children: formatPathLabel(path, oldPath) }),
1877
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-3 text-sm text-muted-foreground", children: [
1878
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: base }),
1879
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "→" }),
1880
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: head }),
1881
- added != null ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-emerald-700 dark:text-emerald-300", children: [
1882
- "+",
1883
- added
1884
- ] }) : null,
1885
- removed != null ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-rose-700 dark:text-rose-300", children: [
1886
- "-",
1887
- removed
1888
- ] }) : null
1889
- ] })
1890
- ] }),
1891
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
1892
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
1893
- Button,
2586
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
2587
+ allowSnapshot || allowDiff ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center rounded-full border border-black/[0.08] bg-white/[0.86] p-1 dark:border-white/[0.1] dark:bg-white/[0.03]", children: [
2588
+ allowSnapshot ? /* @__PURE__ */ jsxRuntimeExports.jsx(
2589
+ "button",
2590
+ {
2591
+ type: "button",
2592
+ onClick: () => setViewMode("snapshot"),
2593
+ "data-testid": "git-diff-viewer-snapshot-toggle",
2594
+ className: cn(
2595
+ "rounded-full px-3 py-1.5 text-[12px] font-medium transition-colors",
2596
+ viewMode === "snapshot" ? "bg-black/[0.06] text-foreground dark:bg-white/[0.12]" : "text-muted-foreground hover:text-foreground"
2597
+ ),
2598
+ children: t("git_viewer_snapshot", void 0, "Snapshot")
2599
+ }
2600
+ ) : null,
2601
+ allowDiff ? /* @__PURE__ */ jsxRuntimeExports.jsx(
2602
+ "button",
2603
+ {
2604
+ type: "button",
2605
+ onClick: () => setViewMode("diff"),
2606
+ "data-testid": "git-diff-viewer-diff-toggle",
2607
+ className: cn(
2608
+ "rounded-full px-3 py-1.5 text-[12px] font-medium transition-colors",
2609
+ viewMode === "diff" ? "bg-black/[0.06] text-foreground dark:bg-white/[0.12]" : "text-muted-foreground hover:text-foreground"
2610
+ ),
2611
+ children: t("git_viewer_diff", void 0, "Diff")
2612
+ }
2613
+ ) : null
2614
+ ] }) : null,
2615
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
2616
+ Button,
2617
+ {
2618
+ type: "button",
2619
+ size: "sm",
2620
+ variant: "outline",
2621
+ onClick: () => {
2622
+ void currentQuery.refetch();
2623
+ },
2624
+ className: "h-9 rounded-full border-black/[0.08] bg-white/[0.86] px-3 text-[12px] shadow-none hover:bg-black/[0.03] dark:border-white/[0.1] dark:bg-white/[0.03] dark:hover:bg-white/[0.06]",
2625
+ children: [
2626
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: cn("mr-1.5 h-3.5 w-3.5", currentQuery.isFetching && "animate-spin") }),
2627
+ t("explorer_refresh")
2628
+ ]
2629
+ }
2630
+ )
2631
+ ] })
2632
+ ] }) }),
2633
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
2634
+ "div",
1894
2635
  {
1895
- type: "button",
1896
- size: "sm",
1897
- variant: "outline",
1898
- onClick: () => {
1899
- void diffQuery.refetch();
1900
- },
1901
- className: "h-9 rounded-full border-black/[0.08] bg-white/[0.86] px-3 text-[12px] shadow-none hover:bg-black/[0.03] dark:border-white/[0.1] dark:bg-white/[0.03] dark:hover:bg-white/[0.06]",
1902
- children: [
1903
- /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: cn("mr-1.5 h-3.5 w-3.5", diffQuery.isFetching && "animate-spin") }),
1904
- "Refresh"
1905
- ]
2636
+ className: cn(
2637
+ "min-h-0 flex-1 px-6 py-6",
2638
+ useEmbeddedSnapshotShell ? "overflow-hidden" : "overflow-y-auto"
2639
+ ),
2640
+ children: viewMode === "snapshot" ? !allowSnapshot || !hasValidSnapshotContext ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-[20px] border border-black/[0.08] bg-white/[0.82] px-4 py-4 text-sm leading-7 text-muted-foreground dark:border-white/[0.08] dark:bg-white/[0.04]", children: t("git_viewer_snapshot_unavailable", void 0, "Snapshot preview is unavailable for this file.") }) : snapshotQuery.isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm leading-7 text-muted-foreground", children: t("git_viewer_loading_snapshot", void 0, "Loading snapshot…") }) : snapshotQuery.isError ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-[20px] border border-rose-200/80 bg-rose-50/70 px-4 py-4 text-sm text-rose-700 dark:border-rose-400/20 dark:bg-rose-500/10 dark:text-rose-200", children: t("git_viewer_failed_snapshot", void 0, "Failed to load snapshot.") }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
2641
+ GitSnapshotContent,
2642
+ {
2643
+ document: snapshotQuery.data,
2644
+ projectId,
2645
+ parentTabId: tabId
2646
+ }
2647
+ ) : !allowDiff || !hasValidDiffContext ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-[20px] border border-black/[0.08] bg-white/[0.82] px-4 py-4 text-sm leading-7 text-muted-foreground dark:border-white/[0.08] dark:bg-white/[0.04]", children: t("git_viewer_diff_unavailable", void 0, "Diff preview is unavailable for this file.") }) : diffQuery.isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm leading-7 text-muted-foreground", children: t("git_viewer_loading_diff", void 0, "Loading patch…") }) : diffQuery.isError ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-[20px] border border-rose-200/80 bg-rose-50/70 px-4 py-4 text-sm text-rose-700 dark:border-rose-400/20 dark:bg-rose-500/10 dark:text-rose-200", children: t("git_viewer_failed_diff", void 0, "Failed to load diff.") }) : unavailableMessage ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-[20px] border border-black/[0.08] bg-white/[0.82] px-4 py-4 text-sm leading-7 text-muted-foreground dark:border-white/[0.08] dark:bg-white/[0.04]", children: unavailableMessage }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
2648
+ GitDiffViewer,
2649
+ {
2650
+ diff: mergedDiff,
2651
+ pathLabel: resolvedPathLabel,
2652
+ className: "border border-black/[0.06] bg-white/[0.92] shadow-none dark:border-white/[0.08] dark:bg-[rgba(24,26,31,0.92)]"
2653
+ }
2654
+ )
1906
2655
  }
1907
- ),
1908
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "inline-flex items-center gap-1 rounded-full border border-black/[0.08] bg-white/[0.7] px-3 py-2 text-[11px] text-muted-foreground dark:border-white/[0.1] dark:bg-white/[0.03]", children: [
1909
- /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "h-3.5 w-3.5" }),
1910
- "Central diff view"
1911
- ] })
1912
- ] })
1913
- ] }) }),
1914
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-6 py-6", children: diffQuery.isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm leading-7 text-muted-foreground", children: "Loading patch…" }) : diffQuery.isError ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-[20px] border border-rose-200/80 bg-rose-50/70 px-4 py-4 text-sm text-rose-700 dark:border-rose-400/20 dark:bg-rose-500/10 dark:text-rose-200", children: "Failed to load diff." }) : /* @__PURE__ */ jsxRuntimeExports.jsx(GitDiffViewer, { diff: mergedDiff, className: "border border-black/[0.06] bg-white/[0.92] shadow-none dark:border-white/[0.08] dark:bg-[rgba(24,26,31,0.92)]" }) })
1915
- ] });
2656
+ )
2657
+ ]
2658
+ }
2659
+ );
1916
2660
  }
1917
2661
 
1918
2662
  export { GitDiffViewerPlugin as default };