@spotpatch/runtime 1.15.4 → 1.15.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -32,7 +32,7 @@ module.exports = __toCommonJS(src_exports);
32
32
 
33
33
  // src/controller/runtime-controller.ts
34
34
  var import_react_adapter = require("@spotpatch/react-adapter");
35
- var import_shared9 = require("@spotpatch/shared");
35
+ var import_shared14 = require("@spotpatch/shared");
36
36
 
37
37
  // src/annotation/create-annotation.ts
38
38
  var import_shared = require("@spotpatch/shared");
@@ -52,6 +52,7 @@ function freezeReact(react2) {
52
52
  function freezeElement(element2) {
53
53
  return Object.freeze({
54
54
  ...element2,
55
+ ...element2.instance === void 0 ? {} : { instance: Object.freeze({ ...element2.instance }) },
55
56
  rect: Object.freeze({ ...element2.rect })
56
57
  });
57
58
  }
@@ -841,6 +842,60 @@ function collectStyleContext(options) {
841
842
  });
842
843
  }
843
844
 
845
+ // src/state/selected-instance.ts
846
+ var import_shared7 = require("@spotpatch/shared");
847
+
848
+ // src/collectors/dom-collector.ts
849
+ var import_shared6 = require("@spotpatch/shared");
850
+
851
+ // src/collectors/element-locator.ts
852
+ var import_shared5 = require("@spotpatch/shared");
853
+ function escapeIdentifier(value) {
854
+ return Array.from(value).map(
855
+ (character) => /[a-z\d_-]/iu.test(character) ? character : `\\${(character.codePointAt(0) ?? 0).toString(16)} `
856
+ ).join("");
857
+ }
858
+ function uniqueMatch(element2, selector) {
859
+ if (selector.length > import_shared5.ELEMENT_INSTANCE_LIMITS.selectorCharacters) return false;
860
+ try {
861
+ const matches = element2.ownerDocument.querySelectorAll(selector);
862
+ return matches.length === 1 && matches[0] === element2;
863
+ } catch {
864
+ return false;
865
+ }
866
+ }
867
+ function createElementLocator(element2) {
868
+ if (!element2.isConnected || element2.getRootNode() !== element2.ownerDocument)
869
+ return "";
870
+ const segments = [];
871
+ let current = element2;
872
+ while (current !== null && segments.length < import_shared5.ELEMENT_INSTANCE_LIMITS.locatorDepth) {
873
+ const tag = current.localName;
874
+ const testId = current.getAttribute("data-testid");
875
+ const anchors = [
876
+ ...current.id.length > 0 && (0, import_shared5.redactSensitiveText)(current.id) === current.id ? [`${tag}#${escapeIdentifier(current.id)}`] : [],
877
+ ...testId && (0, import_shared5.redactSensitiveText)(testId) === testId ? [
878
+ `${tag}[data-testid="${testId.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"]`
879
+ ] : []
880
+ ];
881
+ for (const anchor of anchors) {
882
+ const candidate2 = [anchor, ...segments].join(" > ");
883
+ if ((0, import_shared5.redactSensitiveText)(candidate2) === candidate2 && uniqueMatch(element2, candidate2))
884
+ return candidate2;
885
+ }
886
+ const siblings = current.parentElement === null ? [current] : Array.from(current.parentElement.children).filter(
887
+ (sibling) => sibling.localName === tag
888
+ );
889
+ const segment = siblings.length > 1 ? `${tag}:nth-of-type(${String(siblings.indexOf(current) + 1)})` : tag;
890
+ segments.unshift(segment);
891
+ const candidate = segments.join(" > ");
892
+ if (uniqueMatch(element2, candidate)) return candidate;
893
+ if (candidate.length > import_shared5.ELEMENT_INSTANCE_LIMITS.selectorCharacters) return "";
894
+ current = current.parentElement;
895
+ }
896
+ return "";
897
+ }
898
+
844
899
  // src/collectors/dom-collector.ts
845
900
  var DOM_COLLECTION_LIMITS = Object.freeze({
846
901
  maxDepth: 3,
@@ -908,7 +963,7 @@ function escapeHtml(value) {
908
963
  return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
909
964
  }
910
965
  function isPreservedAttribute(name) {
911
- return SAFE_ATTRIBUTE_NAMES.has(name) || name.startsWith("aria-") || name === "data-testid";
966
+ return SAFE_ATTRIBUTE_NAMES.has(name) || name.startsWith("aria-") || name === "data-testid" || name === import_shared6.ELEMENT_INSTANCE_HINT_ATTRIBUTE;
912
967
  }
913
968
  function openingTag(element2) {
914
969
  const tagName = element2.tagName.toLowerCase();
@@ -984,44 +1039,6 @@ function truncateContext(value, maxCharacters) {
984
1039
  }
985
1040
  return `${value.slice(0, Math.max(0, maxCharacters - 1)).trimEnd()}…`;
986
1041
  }
987
- function escapeCssIdentifier(value) {
988
- return Array.from(value).map(
989
- (character) => /[a-z\d_-]/iu.test(character) ? character : `\\${character.charCodeAt(0).toString(16)} `
990
- ).join("");
991
- }
992
- function escapeCssAttribute(value) {
993
- return value.replaceAll("\\", "\\\\").replaceAll('"', '\\"');
994
- }
995
- function selectorSegment(element2) {
996
- const tagName = element2.tagName.toLowerCase();
997
- if (element2.id.length > 0) {
998
- return `${tagName}#${escapeCssIdentifier(element2.id)}`;
999
- }
1000
- const testId = element2.getAttribute("data-testid");
1001
- if (testId !== null && testId.length > 0) {
1002
- return `${tagName}[data-testid="${escapeCssAttribute(testId)}"]`;
1003
- }
1004
- const classes = Array.from(element2.classList).slice(0, 2).map((name) => `.${escapeCssIdentifier(name)}`).join("");
1005
- const sameTagSiblings = element2.parentElement === null ? [] : Array.from(element2.parentElement.children).filter(
1006
- (sibling) => sibling.tagName === element2.tagName
1007
- );
1008
- const position = sameTagSiblings.indexOf(element2);
1009
- const nth = sameTagSiblings.length > 1 && position >= 0 ? `:nth-of-type(${String(position + 1)})` : "";
1010
- return `${tagName}${classes}${nth}`;
1011
- }
1012
- function createSelector(element2) {
1013
- const segments = [];
1014
- let current = element2;
1015
- while (current !== null && segments.length < 5) {
1016
- const segment = selectorSegment(current);
1017
- segments.unshift(segment);
1018
- if (current.id.length > 0 || current.hasAttribute("data-testid")) {
1019
- break;
1020
- }
1021
- current = current.parentElement;
1022
- }
1023
- return segments.join(" > ");
1024
- }
1025
1042
  function collectElementContext(options) {
1026
1043
  const lines = ["<!-- Selected element -->"];
1027
1044
  const state = { nodeCount: 0, truncated: false };
@@ -1035,7 +1052,7 @@ function collectElementContext(options) {
1035
1052
  const role = options.element.getAttribute("role");
1036
1053
  return Object.freeze({
1037
1054
  tagName: options.element.tagName.toLowerCase(),
1038
- selector: createSelector(options.element),
1055
+ selector: createElementLocator(options.element),
1039
1056
  sanitizedHtml: truncateContext(lines.join("\n"), options.maxCharacters),
1040
1057
  ...text2.length === 0 ? {} : {
1041
1058
  textPreview: text2.length <= DOM_COLLECTION_LIMITS.maxTextCharacters ? text2 : `${text2.slice(0, DOM_COLLECTION_LIMITS.maxTextCharacters)}…`
@@ -1050,6 +1067,65 @@ function collectElementContext(options) {
1050
1067
  });
1051
1068
  }
1052
1069
 
1070
+ // src/state/selected-instance.ts
1071
+ function instanceScope(element2) {
1072
+ let candidate = element2;
1073
+ for (let depth = 0; candidate !== null && depth < import_shared7.ELEMENT_INSTANCE_LIMITS.ancestorDepth; depth += 1) {
1074
+ if (candidate === element2.ownerDocument.body || candidate === element2.ownerDocument.documentElement)
1075
+ break;
1076
+ if (candidate.hasAttribute(import_shared7.ELEMENT_INSTANCE_HINT_ATTRIBUTE) || candidate.matches("article, li, tr, [role=row], [role=listitem]"))
1077
+ return candidate;
1078
+ const marker = candidate.getAttribute(import_shared7.SOURCE_MARKER_ATTRIBUTE);
1079
+ if (marker !== null && candidate.parentElement !== null && Array.from(candidate.parentElement.children).some(
1080
+ (sibling) => sibling !== candidate && sibling.getAttribute(import_shared7.SOURCE_MARKER_ATTRIBUTE) === marker
1081
+ ))
1082
+ return candidate;
1083
+ candidate = candidate.parentElement;
1084
+ }
1085
+ const parent = element2.parentElement;
1086
+ return parent === null || parent === element2.ownerDocument.body || parent === element2.ownerDocument.documentElement ? element2 : parent;
1087
+ }
1088
+ function captureSelectedInstance(element2, id, maxCharacters) {
1089
+ const context = collectElementContext({ element: element2, maxCharacters });
1090
+ const scope = instanceScope(element2);
1091
+ const nearby = collectElementContext({
1092
+ element: scope,
1093
+ maxCharacters: import_shared7.ELEMENT_INSTANCE_LIMITS.contextCharacters
1094
+ });
1095
+ return Object.freeze({
1096
+ scope,
1097
+ context: Object.freeze({
1098
+ ...context,
1099
+ instance: Object.freeze({
1100
+ id,
1101
+ state: "captured",
1102
+ selectorStatus: context.selector.length > 0 ? "unique-at-capture" : "unavailable",
1103
+ label: (nearby.textPreview ?? context.textPreview ?? context.tagName).slice(
1104
+ 0,
1105
+ import_shared7.ELEMENT_INSTANCE_LIMITS.labelCharacters
1106
+ ),
1107
+ context: nearby.sanitizedHtml
1108
+ })
1109
+ })
1110
+ });
1111
+ }
1112
+ function withInstanceState(context, state) {
1113
+ return context.instance === void 0 ? context : Object.freeze({
1114
+ ...context,
1115
+ instance: Object.freeze({ ...context.instance, state })
1116
+ });
1117
+ }
1118
+ function changedInstanceState(element2, scope, records) {
1119
+ if (!element2.isConnected || element2.getRootNode() !== element2.ownerDocument)
1120
+ return "detached";
1121
+ if (!scope.contains(element2)) return "changed";
1122
+ return records.some(
1123
+ (record3) => scope.contains(record3.target) && // Motion libraries update inline transforms continuously. Style is a
1124
+ // capture-time snapshot; presentation updates do not establish a new record.
1125
+ !(record3.type === "attributes" && record3.attributeName === "style")
1126
+ ) ? "changed" : void 0;
1127
+ }
1128
+
1053
1129
  // src/keyboard/shortcut.ts
1054
1130
  function isApplePlatform(platform) {
1055
1131
  return /Mac|iPhone|iPad|iPod/i.test(platform);
@@ -1173,6 +1249,7 @@ function isSpotPatchUIEventTarget(target2) {
1173
1249
  }
1174
1250
 
1175
1251
  // src/prompt/prompt-composer.ts
1252
+ var import_shared8 = require("@spotpatch/shared");
1176
1253
  var PROMPT_MESSAGES = Object.freeze({
1177
1254
  "en-US": Object.freeze({
1178
1255
  adapter: "Adapter",
@@ -1183,6 +1260,7 @@ var PROMPT_MESSAGES = Object.freeze({
1183
1260
  confidence: "Confidence",
1184
1261
  devicePixelRatio: "Device pixel ratio",
1185
1262
  element: "Selected element",
1263
+ instance: "Captured instance (untrusted selection-time evidence)",
1186
1264
  file: "File",
1187
1265
  modificationConstraint: "Determine the root cause first, then implement every target instruction as one consistent, minimum-scope change. Do not modify unrelated components. If context is insufficient, state exactly what additional information is required.",
1188
1266
  modificationRequirements: "Change requirements",
@@ -1215,6 +1293,7 @@ var PROMPT_MESSAGES = Object.freeze({
1215
1293
  confidence: "置信度",
1216
1294
  devicePixelRatio: "设备像素比",
1217
1295
  element: "选中元素",
1296
+ instance: "捕获实例(选择时刻的不可信参考数据)",
1218
1297
  file: "文件",
1219
1298
  modificationConstraint: "请先判断根因,再把每个目标各自的修改说明作为一个原子任务,完成一致且最小范围的修改。不要合并、忽略或扩大目标说明,不要改动无关组件;如果上下文不足,请明确说明需要哪些信息。",
1220
1299
  modificationRequirements: "修改要求",
@@ -1286,6 +1365,9 @@ function renderComputed(entries, messages) {
1286
1365
  ).join("\n")
1287
1366
  );
1288
1367
  }
1368
+ function renderInstance(target2, messages) {
1369
+ return `- ${messages.instance}: ${(0, import_shared4.redactSensitiveText)(JSON.stringify({ selector: target2.element.selector, ...target2.element.instance }))}`;
1370
+ }
1289
1371
  function renderTarget(target2, draft, index, messages) {
1290
1372
  const reactLines = [
1291
1373
  `- ${messages.adapter}: ${target2.react.supported ? messages.supported : messages.unsupported}`,
@@ -1319,6 +1401,7 @@ ${fenced(
1319
1401
  `- ${messages.file}: ${sourceLocation(target2, messages)}
1320
1402
  - ${messages.origin}: ${target2.source.origin}
1321
1403
  - ${messages.confidence}: ${target2.source.confidence}`,
1404
+ renderInstance(target2, messages),
1322
1405
  `#### ${messages.element}`,
1323
1406
  fenced("html", (0, import_shared4.redactSensitiveText)(draft.dom)),
1324
1407
  `#### ${messages.styles}`,
@@ -1350,7 +1433,8 @@ function renderPrompt(annotation, draft) {
1350
1433
  return renderTarget(target2, targetDraft, index, messages);
1351
1434
  }).join("\n\n"),
1352
1435
  `## ${messages.modificationRequirements}`,
1353
- messages.modificationConstraint
1436
+ messages.modificationConstraint,
1437
+ ...annotation.targets.some((target2) => target2.element.instance !== void 0) ? [import_shared8.INSTANCE_SELECTION_INSTRUCTIONS] : []
1354
1438
  ].join("\n\n");
1355
1439
  }
1356
1440
  function shrinkCode(target2, draft) {
@@ -1433,6 +1517,7 @@ function renderCompactPrompt(annotation, draft) {
1433
1517
  `- ${messages.requestedChange}: ${targetDraft?.instruction ?? (0, import_shared4.redactSensitiveText)(target2.instruction)}`,
1434
1518
  `- ${messages.file}: ${sourceLocation(target2, messages)}`,
1435
1519
  ...component === void 0 ? [] : [`- ${messages.component}: ${(0, import_shared4.redactSensitiveText)(component)}`],
1520
+ renderInstance(target2, messages),
1436
1521
  `- ${messages.element}: ${(0, import_shared4.redactSensitiveText)(openingTag2(targetDraft?.dom ?? target2.element.sanitizedHtml, messages.unavailable))}`
1437
1522
  ].join("\n");
1438
1523
  });
@@ -1440,7 +1525,8 @@ function renderCompactPrompt(annotation, draft) {
1440
1525
  `## ${messages.selectedTargets(annotation.targets.length)}`,
1441
1526
  targets.join("\n\n"),
1442
1527
  `## ${messages.modificationRequirements}`,
1443
- messages.modificationConstraint
1528
+ messages.modificationConstraint,
1529
+ ...annotation.targets.some((target2) => target2.element.instance !== void 0) ? [import_shared8.INSTANCE_SELECTION_INSTRUCTIONS] : []
1444
1530
  ].join("\n\n");
1445
1531
  }
1446
1532
  function composeBounded(annotation, maxCharacters) {
@@ -1547,6 +1633,7 @@ function reduceRuntimeState(state, event) {
1547
1633
  }
1548
1634
 
1549
1635
  // src/state/selection-session.ts
1636
+ var import_shared9 = require("@spotpatch/shared");
1550
1637
  var STORAGE_PREFIX = "spotpatch:selection:";
1551
1638
  var SNAPSHOT_VERSION = 1;
1552
1639
  var MAX_SNAPSHOT_CHARACTERS = 1e6;
@@ -1583,7 +1670,11 @@ function page(value) {
1583
1670
  function element(value) {
1584
1671
  const item = record(value);
1585
1672
  const rect = record(item?.rect);
1586
- return item !== void 0 && text(item.tagName) && text(item.selector) && text(item.sanitizedHtml) && optionalText(item.textPreview) && optionalText(item.role) && rect !== void 0 && finiteNumber(rect.x) && finiteNumber(rect.y) && finiteNumber(rect.width) && finiteNumber(rect.height);
1673
+ return item !== void 0 && (item.instance === void 0 || instance(item.instance)) && text(item.tagName) && text(item.selector) && text(item.sanitizedHtml) && optionalText(item.textPreview) && optionalText(item.role) && rect !== void 0 && finiteNumber(rect.x) && finiteNumber(rect.y) && finiteNumber(rect.width) && finiteNumber(rect.height);
1674
+ }
1675
+ function instance(value) {
1676
+ const item = record(value);
1677
+ return item !== void 0 && Object.keys(item).length === 5 && text(item.id) && item.id.length <= import_shared9.ELEMENT_INSTANCE_LIMITS.idCharacters && /^[A-Za-z0-9_-]+$/u.test(item.id) && import_shared9.ELEMENT_INSTANCE_STATES.some((state) => state === item.state) && (item.selectorStatus === "unique-at-capture" || item.selectorStatus === "unavailable") && text(item.label) && item.label.length <= import_shared9.ELEMENT_INSTANCE_LIMITS.labelCharacters && text(item.context) && item.context.length <= import_shared9.ELEMENT_INSTANCE_LIMITS.contextCharacters;
1587
1678
  }
1588
1679
  function styles(value) {
1589
1680
  const item = record(value);
@@ -1662,13 +1753,13 @@ function createSelectionSession(window, sessionId, maximumTargets) {
1662
1753
  }
1663
1754
 
1664
1755
  // src/source/source-resolver.ts
1665
- var import_shared5 = require("@spotpatch/shared");
1756
+ var import_shared10 = require("@spotpatch/shared");
1666
1757
  var EMPTY_REACT_CONTEXT = Object.freeze({
1667
1758
  supported: false,
1668
1759
  componentStack: Object.freeze([])
1669
1760
  });
1670
1761
  function directMarker(element2) {
1671
- return (0, import_shared5.parseSourceMarker)(element2.getAttribute(import_shared5.SOURCE_MARKER_ATTRIBUTE));
1762
+ return (0, import_shared10.parseSourceMarker)(element2.getAttribute(import_shared10.SOURCE_MARKER_ATTRIBUTE));
1672
1763
  }
1673
1764
  function ancestorMarker(element2) {
1674
1765
  let ancestor = element2.parentElement;
@@ -1748,7 +1839,7 @@ function createSourceResolver(options) {
1748
1839
  }
1749
1840
 
1750
1841
  // src/ui/runtime-view.ts
1751
- var import_shared7 = require("@spotpatch/shared");
1842
+ var import_shared12 = require("@spotpatch/shared");
1752
1843
 
1753
1844
  // src/ui/dom.ts
1754
1845
  function createMarkedElement(document, tagName) {
@@ -1771,7 +1862,7 @@ var AGENT_PANEL_STYLES = `
1771
1862
  overflow: hidden;
1772
1863
  border: 1px solid var(--spotpatch-border-subtle);
1773
1864
  border-radius: var(--spotpatch-radius-card);
1774
- background: rgb(255 255 255 / 2.5%);
1865
+ background: var(--spotpatch-bg-raised);
1775
1866
  }
1776
1867
  .spotpatch-agent-head {
1777
1868
  display: flex;
@@ -1779,17 +1870,17 @@ var AGENT_PANEL_STYLES = `
1779
1870
  justify-content: space-between;
1780
1871
  gap: 10px;
1781
1872
  padding: 10px 12px;
1782
- border-bottom: 1px solid rgb(255 255 255 / 7%);
1873
+ border-bottom: 1px solid var(--spotpatch-border-subtle);
1783
1874
  }
1784
- .spotpatch-agent-title { color: #eef0f5; font-size: 13px; font-weight: 650; }
1875
+ .spotpatch-agent-title { font-size: 13px; font-weight: 620; }
1785
1876
  .spotpatch-agent-badge {
1786
- border: 1px solid rgb(129 112 247 / 24%);
1787
- border-radius: 999px;
1788
- padding: 3px 7px;
1789
- color: #c5cafa;
1790
- background: rgb(109 93 246 / 9%);
1791
- font-size: 10px;
1792
- font-weight: 650;
1877
+ border: 1px solid var(--spotpatch-accent-line);
1878
+ border-radius: var(--spotpatch-radius-pill);
1879
+ padding: 2px 8px;
1880
+ color: var(--spotpatch-accent-soft);
1881
+ background: var(--spotpatch-accent-tint);
1882
+ font-size: 11px;
1883
+ font-weight: 600;
1793
1884
  }
1794
1885
  .spotpatch-agent-setup { padding: 12px; }
1795
1886
  .spotpatch-agent-selectors { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
@@ -1799,71 +1890,71 @@ var AGENT_PANEL_STYLES = `
1799
1890
  box-sizing: border-box;
1800
1891
  width: 100%;
1801
1892
  min-width: 0;
1802
- min-height: 34px;
1893
+ min-height: 36px;
1803
1894
  margin-top: 4px;
1804
1895
  border: 1px solid var(--spotpatch-border);
1805
- border-radius: 8px;
1806
- padding: 7px 32px 7px 9px;
1807
- color: #e8ebf2;
1808
- color-scheme: dark;
1809
- background: linear-gradient(180deg, rgb(255 255 255 / 4%), rgb(255 255 255 / 2%));
1810
- font-size: 12px;
1896
+ border-radius: var(--spotpatch-radius-sm);
1897
+ padding: 7px 32px 7px 10px;
1898
+ color: var(--spotpatch-text);
1899
+ background: var(--spotpatch-bg-input);
1900
+ font-size: 12.5px;
1811
1901
  font-weight: 560;
1812
1902
  line-height: 1.35;
1813
1903
  outline: none;
1814
- transition: 160ms ease;
1904
+ transition:
1905
+ border-color var(--spotpatch-duration-fast) ease,
1906
+ box-shadow var(--spotpatch-duration-fast) ease;
1815
1907
  }
1816
- .spotpatch-agent select:hover { border-color: rgb(148 163 184 / 38%); background-color: rgb(255 255 255 / 5%); }
1817
- .spotpatch-agent select:focus-visible { border-color: rgb(139 124 247 / 76%); box-shadow: 0 0 0 3px rgb(109 93 246 / 18%); }
1818
- .spotpatch-agent select option { min-height: 42px; color: #e8ebf2; background: #10151e; }
1908
+ .spotpatch-agent select:hover { border-color: var(--spotpatch-border-strong); }
1909
+ .spotpatch-agent select:focus-visible { border-color: var(--spotpatch-accent-line); box-shadow: 0 0 0 3px var(--spotpatch-accent-tint); }
1910
+ .spotpatch-agent select option { min-height: 42px; color: var(--spotpatch-text); background: var(--spotpatch-bg-raised); }
1819
1911
  @supports (appearance: base-select) {
1820
1912
  .spotpatch-agent select,
1821
1913
  ::picker(select) { appearance: base-select; }
1822
- .spotpatch-agent select { padding: 7px 9px; }
1914
+ .spotpatch-agent select { padding: 7px 10px; }
1823
1915
  .spotpatch-agent select::picker-icon {
1824
- color: #9da6b5;
1825
- transition: rotate 180ms cubic-bezier(.2, .8, .2, 1);
1916
+ color: var(--spotpatch-text-muted);
1917
+ transition: rotate var(--spotpatch-duration-base) var(--spotpatch-ease-out);
1826
1918
  }
1827
- .spotpatch-agent select:open::picker-icon { rotate: 180deg; color: #c4b5fd; }
1919
+ .spotpatch-agent select:open::picker-icon { rotate: 180deg; color: var(--spotpatch-accent-soft); }
1828
1920
  .spotpatch-agent select::picker(select) {
1829
- top: calc(anchor(bottom) + 7px);
1921
+ top: calc(anchor(bottom) + 6px);
1830
1922
  left: anchor(left);
1831
1923
  width: anchor-size(width);
1832
1924
  max-height: min(280px, 40vh);
1833
1925
  margin: 0;
1834
1926
  overflow: auto;
1835
- border: 1px solid rgb(139 124 247 / 28%);
1836
- border-radius: 12px;
1837
- padding: 6px;
1838
- background: #10151e;
1839
- box-shadow: 0 18px 50px rgb(0 0 0 / 38%);
1927
+ border: 1px solid var(--spotpatch-border);
1928
+ border-radius: var(--spotpatch-radius-card);
1929
+ padding: 5px;
1930
+ background: var(--spotpatch-bg-raised);
1931
+ box-shadow: var(--spotpatch-shadow-panel);
1840
1932
  opacity: 1;
1841
1933
  transform: translateY(0) scale(1);
1842
- transition: opacity 150ms ease, transform 180ms cubic-bezier(.2, .8, .2, 1), overlay 180ms allow-discrete, display 180ms allow-discrete;
1934
+ transition:
1935
+ opacity var(--spotpatch-duration-fast) ease,
1936
+ transform var(--spotpatch-duration-base) var(--spotpatch-ease-out),
1937
+ overlay var(--spotpatch-duration-base) allow-discrete,
1938
+ display var(--spotpatch-duration-base) allow-discrete;
1843
1939
  }
1844
1940
  @starting-style {
1845
1941
  .spotpatch-agent select::picker(select):popover-open {
1846
1942
  opacity: 0;
1847
- transform: translateY(-5px) scale(.985);
1943
+ transform: translateY(-5px) scale(.98);
1848
1944
  }
1849
1945
  }
1850
1946
  .spotpatch-agent select option {
1851
- min-height: 42px;
1852
- border-radius: 8px;
1853
- padding: 10px 12px;
1854
- color: #dfe4ee;
1947
+ min-height: 40px;
1948
+ border-radius: var(--spotpatch-radius-sm);
1949
+ padding: 9px 11px;
1950
+ color: var(--spotpatch-text-secondary);
1855
1951
  background: transparent;
1856
1952
  cursor: pointer;
1857
1953
  }
1858
1954
  .spotpatch-agent select option:hover,
1859
- .spotpatch-agent select option:focus { color: #fff; background: rgb(109 93 246 / 16%); }
1860
- .spotpatch-agent select option:checked { color: #fff; background: rgb(109 93 246 / 24%); }
1861
- .spotpatch-agent select option::checkmark { color: #8b7cf7; }
1862
- }
1863
- .spotpatch-agent select:focus-visible,
1864
- .spotpatch-consent input:focus-visible {
1865
- outline: 2px solid #8b7cf7;
1866
- outline-offset: 2px;
1955
+ .spotpatch-agent select option:focus { color: var(--spotpatch-text); background: var(--spotpatch-hover); }
1956
+ .spotpatch-agent select option:checked { color: var(--spotpatch-text); background: var(--spotpatch-accent-tint); }
1957
+ .spotpatch-agent select option::checkmark { color: var(--spotpatch-accent-soft); }
1867
1958
  }
1868
1959
  .spotpatch-consent {
1869
1960
  display: flex;
@@ -1872,26 +1963,21 @@ var AGENT_PANEL_STYLES = `
1872
1963
  margin-top: 10px;
1873
1964
  color: var(--spotpatch-text-secondary);
1874
1965
  cursor: pointer;
1875
- font-size: 11.5px;
1966
+ font-size: 12px;
1876
1967
  line-height: 1.5;
1877
1968
  }
1878
1969
  .spotpatch-consent input { width: 14px; height: 14px; flex: none; margin: 2px 0 0; accent-color: var(--spotpatch-accent); }
1879
- .spotpatch-trusted-consent {
1880
- border: 1px solid rgb(251 191 36 / 20%);
1881
- border-radius: 10px;
1882
- padding: 9px 10px;
1883
- color: #e5e7eb;
1884
- background: rgb(120 53 15 / 10%);
1885
- }
1970
+ .spotpatch-trusted-consent,
1886
1971
  .spotpatch-workspace-consent {
1887
- margin-top: 9px;
1888
- border: 1px solid rgb(251 191 36 / 18%);
1889
- border-radius: 10px;
1972
+ border: 1px solid var(--spotpatch-warning-line);
1973
+ border-radius: var(--spotpatch-radius-md);
1890
1974
  padding: 9px 10px;
1891
- background: rgb(120 53 15 / 9%);
1975
+ background: var(--spotpatch-warning-tint);
1892
1976
  }
1893
- .spotpatch-workspace-consent strong { display: block; color: #fde68a; font-size: 11.5px; font-weight: 620; }
1894
- .spotpatch-workspace-consent small { display: block; margin-top: 2px; color: #aeb6c4; font-size: 10.5px; line-height: 1.45; }
1977
+ .spotpatch-trusted-consent { color: var(--spotpatch-text); }
1978
+ .spotpatch-workspace-consent { margin-top: 9px; }
1979
+ .spotpatch-workspace-consent strong { display: block; color: var(--spotpatch-warning-text); font-size: 12px; font-weight: 600; }
1980
+ .spotpatch-workspace-consent small { display: block; margin-top: 2px; color: var(--spotpatch-text-secondary); font-size: 11px; line-height: 1.45; }
1895
1981
  .spotpatch-agent-health-list { display: grid; gap: 6px; margin-top: 10px; }
1896
1982
  .spotpatch-agent-workspace,
1897
1983
  .spotpatch-agent-capability {
@@ -1899,83 +1985,85 @@ var AGENT_PANEL_STYLES = `
1899
1985
  align-items: center;
1900
1986
  gap: 8px;
1901
1987
  margin: 0;
1902
- color: #929bab;
1903
- font-size: 11px;
1988
+ color: var(--spotpatch-text-secondary);
1989
+ font-size: 11.5px;
1904
1990
  }
1991
+ .spotpatch-agent-workspace::before,
1905
1992
  .spotpatch-agent-capability::before {
1906
1993
  width: 6px;
1907
1994
  height: 6px;
1908
1995
  flex: none;
1909
- border-radius: 999px;
1910
- background: #64748b;
1911
- content: "";
1912
- }
1913
- .spotpatch-agent-capability[data-state="probing"]::before { background: var(--spotpatch-warning); }
1914
- .spotpatch-agent-capability[data-state="ready"] { color: #a7f3d0; }
1915
- .spotpatch-agent-capability[data-state="ready"]::before { background: var(--spotpatch-success); }
1916
- .spotpatch-agent-capability[data-state="error"] { color: #fecaca; }
1917
- .spotpatch-agent-capability[data-state="error"]::before { background: var(--spotpatch-danger); }
1918
- .spotpatch-agent-workspace::before {
1919
- width: 6px;
1920
- height: 6px;
1921
- flex: none;
1922
- border-radius: 999px;
1923
- background: #64748b;
1996
+ border-radius: 50%;
1997
+ background: var(--spotpatch-text-muted);
1924
1998
  content: "";
1925
1999
  }
2000
+ .spotpatch-agent-capability[data-state="probing"]::before,
1926
2001
  .spotpatch-agent-workspace[data-state="checking"]::before { background: var(--spotpatch-warning); }
1927
- .spotpatch-agent-workspace[data-state="ready"] { color: #a7f3d0; }
2002
+ .spotpatch-agent-capability[data-state="ready"],
2003
+ .spotpatch-agent-workspace[data-state="ready"] { color: var(--spotpatch-success-text); }
2004
+ .spotpatch-agent-capability[data-state="ready"]::before,
1928
2005
  .spotpatch-agent-workspace[data-state="ready"]::before { background: var(--spotpatch-success); }
1929
- .spotpatch-agent-workspace[data-state="consent-required"] { color: #fde68a; }
1930
- .spotpatch-agent-workspace[data-state="consent-required"]::before { background: #fbbf24; }
1931
- .spotpatch-agent-workspace[data-state="blocked"] { color: #fecaca; }
2006
+ .spotpatch-agent-workspace[data-state="consent-required"] { color: var(--spotpatch-warning-text); }
2007
+ .spotpatch-agent-workspace[data-state="consent-required"]::before { background: var(--spotpatch-warning); }
2008
+ .spotpatch-agent-capability[data-state="error"],
2009
+ .spotpatch-agent-workspace[data-state="blocked"] { color: var(--spotpatch-danger-text); }
2010
+ .spotpatch-agent-capability[data-state="error"]::before,
1932
2011
  .spotpatch-agent-workspace[data-state="blocked"]::before { background: var(--spotpatch-danger); }
1933
2012
  .spotpatch-agent-job { padding: 12px; }
1934
2013
  .spotpatch-agent-job-meta { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
1935
- .spotpatch-agent-model { min-width: 0; overflow: hidden; color: #d6dafe; font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }
2014
+ .spotpatch-agent-model { min-width: 0; overflow: hidden; font-size: 13px; font-weight: 580; text-overflow: ellipsis; white-space: nowrap; }
1936
2015
  .spotpatch-agent-status {
1937
2016
  flex: none;
1938
- border-radius: 999px;
1939
- padding: 3px 7px;
1940
- color: #bae6fd;
1941
- background: rgb(14 116 144 / 20%);
2017
+ border-radius: var(--spotpatch-radius-pill);
2018
+ padding: 3px 8px;
2019
+ color: var(--spotpatch-cyan-text);
2020
+ background: var(--spotpatch-cyan-tint);
1942
2021
  font-size: 11px;
1943
- font-weight: 650;
2022
+ font-weight: 600;
1944
2023
  }
1945
- .spotpatch-agent-phase { margin: 12px 0 0; color: #e2e5ec; font-size: 13px; line-height: 1.55; }
2024
+ .spotpatch-agent-phase { margin: 12px 0 0; font-size: 13px; line-height: 1.55; }
1946
2025
  .spotpatch-agent-error {
1947
2026
  margin: 9px 0 0;
1948
- border: 1px solid rgb(251 113 133 / 22%);
1949
- border-radius: 9px;
2027
+ border: 1px solid var(--spotpatch-danger-line);
2028
+ border-radius: var(--spotpatch-radius-md);
1950
2029
  padding: 9px 10px;
1951
- color: #fecaca;
1952
- background: rgb(127 29 29 / 14%);
2030
+ color: var(--spotpatch-danger-text);
2031
+ background: var(--spotpatch-danger-tint);
1953
2032
  font-size: 12px;
1954
2033
  }
1955
2034
  .spotpatch-agent-activity { display: grid; gap: 5px; margin: 9px 0 0; padding: 0; list-style: none; }
1956
- .spotpatch-agent-activity li { display: flex; gap: 8px; color: #929bab; font: 11.5px/1.55 ui-monospace, SFMono-Regular, Menlo, monospace; }
1957
- .spotpatch-agent-activity li::before { color: #64748b; content: "•"; }
1958
- .spotpatch-agent-activity li[data-state="active"]::before { color: #fbbf24; }
1959
- .spotpatch-agent-activity li[data-state="success"]::before { color: #34d399; }
1960
- .spotpatch-agent-activity li[data-state="failure"]::before { color: #fb7185; }
1961
- .spotpatch-agent-result { margin-top: 11px; border-top: 1px solid rgb(148 163 184 / 10%); padding-top: 10px; }
1962
- .spotpatch-agent-summary { margin: 0; color: #dce1eb; font-size: 13px; line-height: 1.6; white-space: pre-wrap; }
2035
+ .spotpatch-agent-activity li { display: flex; gap: 8px; color: var(--spotpatch-text-secondary); font: 11.5px/1.55 var(--spotpatch-font-mono); }
2036
+ .spotpatch-agent-activity li::before { color: var(--spotpatch-text-muted); content: "•"; }
2037
+ .spotpatch-agent-activity li[data-state="active"]::before { color: var(--spotpatch-warning); }
2038
+ .spotpatch-agent-activity li[data-state="success"]::before { color: var(--spotpatch-success); }
2039
+ .spotpatch-agent-activity li[data-state="failure"]::before { color: var(--spotpatch-danger); }
2040
+ .spotpatch-agent-result { margin-top: 12px; border-top: 1px solid var(--spotpatch-border-subtle); padding-top: 10px; }
2041
+ .spotpatch-agent-summary { margin: 0; font-size: 13px; line-height: 1.6; white-space: pre-wrap; }
1963
2042
  .spotpatch-agent-files { display: grid; gap: 4px; margin: 9px 0 0; padding: 0; list-style: none; }
1964
- .spotpatch-agent-files li { color: #bbc2f7; font: 11.5px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; overflow-wrap: anywhere; }
2043
+ .spotpatch-agent-files li { color: var(--spotpatch-accent-soft); font: 11.5px/1.5 var(--spotpatch-font-mono); overflow-wrap: anywhere; }
1965
2044
  .spotpatch-agent-checks { display: grid; gap: 5px; margin-top: 9px; }
1966
- .spotpatch-agent-checks details { border: 1px solid rgb(148 163 184 / 12%); border-radius: 8px; background: rgb(2 6 23 / 30%); }
1967
- .spotpatch-agent-checks summary { padding: 9px 10px; color: #cbd0db; cursor: pointer; font-size: 11.5px; }
1968
- .spotpatch-agent-checks pre { max-height: 140px; margin: 0; overflow: auto; border-top: 1px solid rgb(255 255 255 / 7%); padding: 10px; color: #929bab; font: 11px/1.55 ui-monospace, SFMono-Regular, Menlo, monospace; white-space: pre-wrap; }
2045
+ .spotpatch-agent-checks details { border: 1px solid var(--spotpatch-border-subtle); border-radius: var(--spotpatch-radius-sm); background: var(--spotpatch-bg-input); }
2046
+ .spotpatch-agent-checks summary { padding: 9px 10px; color: var(--spotpatch-text-secondary); cursor: pointer; font-size: 12px; }
2047
+ .spotpatch-agent-checks pre {
2048
+ max-height: 140px;
2049
+ margin: 0;
2050
+ overflow: auto;
2051
+ border-top: 1px solid var(--spotpatch-border-subtle);
2052
+ padding: 10px;
2053
+ color: var(--spotpatch-text-secondary);
2054
+ font: 11px/1.55 var(--spotpatch-font-mono);
2055
+ white-space: pre-wrap;
2056
+ }
1969
2057
  .spotpatch-agent-diff {
1970
2058
  max-height: 300px;
1971
2059
  margin: 9px 0 0;
1972
2060
  overflow: auto;
1973
- border: 1px solid rgb(129 140 248 / 18%);
1974
- border-radius: 9px;
1975
- padding: 8px;
1976
- color: #cbd5e1;
1977
- background: rgb(2 6 23 / 66%);
1978
- font: 11.5px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace;
2061
+ border: 1px solid var(--spotpatch-border-subtle);
2062
+ border-radius: var(--spotpatch-radius-md);
2063
+ padding: 8px 10px;
2064
+ color: var(--spotpatch-text);
2065
+ background: var(--spotpatch-bg-input);
2066
+ font: 11.5px/1.6 var(--spotpatch-font-mono);
1979
2067
  overflow-wrap: normal;
1980
2068
  white-space: pre;
1981
2069
  user-select: text;
@@ -2546,6 +2634,113 @@ function getDataFlowExtension(target2 = globalThis) {
2546
2634
  return target2[DATA_FLOW_EXTENSION_KEY];
2547
2635
  }
2548
2636
 
2637
+ // src/ui/theme.ts
2638
+ var THEME_STYLES = `
2639
+ :host {
2640
+ all: initial;
2641
+ color-scheme: dark;
2642
+
2643
+ --spotpatch-bg: #0c0d12;
2644
+ --spotpatch-bg-raised: #14161d;
2645
+ --spotpatch-bg-active: #1b1e28;
2646
+ --spotpatch-bg-input: #08090d;
2647
+ --spotpatch-border-subtle: rgb(255 255 255 / 7%);
2648
+ --spotpatch-border: rgb(255 255 255 / 11%);
2649
+ --spotpatch-border-strong: rgb(255 255 255 / 20%);
2650
+ --spotpatch-hover: rgb(255 255 255 / 5%);
2651
+
2652
+ --spotpatch-text: #f4f5f7;
2653
+ --spotpatch-text-secondary: #a7acb8;
2654
+ --spotpatch-text-muted: #737987;
2655
+ --spotpatch-text-on-accent: #ffffff;
2656
+
2657
+ --spotpatch-accent: #7c4dff;
2658
+ --spotpatch-accent-strong: #6d35ff;
2659
+ --spotpatch-accent-soft: #c4b3ff;
2660
+ --spotpatch-accent-cyan: #00d9e9;
2661
+ --spotpatch-accent-blue: #168eff;
2662
+ --spotpatch-success: #45d483;
2663
+ --spotpatch-warning: #f4b860;
2664
+ --spotpatch-danger: #ff6b7a;
2665
+
2666
+ --spotpatch-accent-tint: color-mix(in srgb, var(--spotpatch-accent) 16%, transparent);
2667
+ --spotpatch-accent-line: color-mix(in srgb, var(--spotpatch-accent) 48%, transparent);
2668
+ --spotpatch-cyan-text: color-mix(in srgb, var(--spotpatch-accent-cyan) 70%, var(--spotpatch-text));
2669
+ --spotpatch-cyan-tint: color-mix(in srgb, var(--spotpatch-accent-cyan) 10%, transparent);
2670
+ --spotpatch-cyan-line: color-mix(in srgb, var(--spotpatch-accent-cyan) 30%, transparent);
2671
+ --spotpatch-success-text: color-mix(in srgb, var(--spotpatch-success) 72%, var(--spotpatch-text));
2672
+ --spotpatch-success-tint: color-mix(in srgb, var(--spotpatch-success) 12%, transparent);
2673
+ --spotpatch-warning-text: color-mix(in srgb, var(--spotpatch-warning) 78%, var(--spotpatch-text));
2674
+ --spotpatch-warning-tint: color-mix(in srgb, var(--spotpatch-warning) 11%, transparent);
2675
+ --spotpatch-warning-line: color-mix(in srgb, var(--spotpatch-warning) 30%, transparent);
2676
+ --spotpatch-danger-text: color-mix(in srgb, var(--spotpatch-danger) 72%, var(--spotpatch-text));
2677
+ --spotpatch-danger-tint: color-mix(in srgb, var(--spotpatch-danger) 11%, transparent);
2678
+ --spotpatch-danger-line: color-mix(in srgb, var(--spotpatch-danger) 30%, transparent);
2679
+
2680
+ --spotpatch-primary-fill: linear-gradient(135deg, var(--spotpatch-accent), var(--spotpatch-accent-strong));
2681
+ --spotpatch-brand-line: linear-gradient(90deg, var(--spotpatch-accent), var(--spotpatch-accent-blue), var(--spotpatch-accent-cyan));
2682
+ --spotpatch-surface-fill:
2683
+ linear-gradient(180deg, rgb(255 255 255 / 3.5%), transparent 30%),
2684
+ var(--spotpatch-bg);
2685
+ --spotpatch-scrim: rgb(3 3 8 / 72%);
2686
+
2687
+ --spotpatch-shadow-float: 0 18px 44px rgb(6 8 18 / 30%), 0 2px 8px rgb(6 8 18 / 18%);
2688
+ --spotpatch-shadow-panel: 0 28px 70px rgb(6 8 18 / 42%), 0 4px 14px rgb(6 8 18 / 22%);
2689
+ --spotpatch-shadow-inset: inset 0 1px 0 rgb(255 255 255 / 7%);
2690
+ --spotpatch-shadow-accent: 0 10px 26px -10px color-mix(in srgb, var(--spotpatch-accent-strong) 80%, transparent);
2691
+
2692
+ --spotpatch-radius-xs: 6px;
2693
+ --spotpatch-radius-sm: 8px;
2694
+ --spotpatch-radius-md: 10px;
2695
+ --spotpatch-radius-card: 12px;
2696
+ --spotpatch-radius-panel: 20px;
2697
+ --spotpatch-radius-pill: 999px;
2698
+
2699
+ --spotpatch-ease-out: cubic-bezier(.16, 1, .3, 1);
2700
+ --spotpatch-ease-spring: cubic-bezier(.34, 1.36, .64, 1);
2701
+ --spotpatch-ease-standard: cubic-bezier(.2, 0, 0, 1);
2702
+ --spotpatch-duration-fast: 140ms;
2703
+ --spotpatch-duration-base: 220ms;
2704
+ --spotpatch-duration-slow: 420ms;
2705
+
2706
+ --spotpatch-font-sans: Inter, "SF Pro Text", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
2707
+ --spotpatch-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
2708
+
2709
+ color: var(--spotpatch-text);
2710
+ font-family: var(--spotpatch-font-sans);
2711
+ font-size: 14px;
2712
+ line-height: 1.5;
2713
+ -webkit-font-smoothing: antialiased;
2714
+ }
2715
+ [hidden] { display: none !important; }
2716
+ button, textarea, select, input { font: inherit; }
2717
+ :focus-visible {
2718
+ outline: 2px solid var(--spotpatch-accent-soft);
2719
+ outline-offset: 2px;
2720
+ }
2721
+ * {
2722
+ scrollbar-color: var(--spotpatch-border-strong) transparent;
2723
+ scrollbar-width: thin;
2724
+ }
2725
+ @keyframes spotpatch-enter {
2726
+ from { opacity: 0; filter: blur(3px); transform: translate3d(0, 6px, 0); }
2727
+ }
2728
+ @keyframes spotpatch-pop {
2729
+ from { opacity: 0; transform: scale(.94); }
2730
+ }
2731
+ @media (prefers-reduced-motion: reduce) {
2732
+ *, *::before, *::after {
2733
+ animation-duration: .01ms !important;
2734
+ animation-iteration-count: 1 !important;
2735
+ transition-duration: .01ms !important;
2736
+ }
2737
+ }
2738
+ `;
2739
+ var THEME_MOTION_COLORS = Object.freeze({
2740
+ dispatchGlowRest: "0 0 0 0 rgb(124 77 255 / 0%)",
2741
+ dispatchGlow: "0 0 0 4px rgb(124 77 255 / 22%)"
2742
+ });
2743
+
2549
2744
  // src/ui/external-handoff-contract.ts
2550
2745
  var EXTERNAL_HANDOFF_EXTENSION_KEY = /* @__PURE__ */ Symbol.for("spotpatch.external-handoff.v1");
2551
2746
  function getExternalHandoffExtension() {
@@ -2565,7 +2760,7 @@ function getFloatingSurfaceMotionExtension() {
2565
2760
  }
2566
2761
 
2567
2762
  // src/ui/localization.ts
2568
- var import_shared6 = require("@spotpatch/shared");
2763
+ var import_shared11 = require("@spotpatch/shared");
2569
2764
  var STATUS_EN = Object.freeze({
2570
2765
  queued: "Queued",
2571
2766
  preparing: "Preparing",
@@ -2644,118 +2839,125 @@ function executionActivityLane(kind, detail) {
2644
2839
  var EXTERNAL_HANDOFF_ERROR_EN = "The external Agent handoff request failed.";
2645
2840
  var EXTERNAL_HANDOFF_ERROR_ZH = "外部 Agent 交接请求失败。";
2646
2841
  var ERROR_MESSAGES_EN = Object.freeze({
2647
- [import_shared6.ERROR_CODES.INVALID_REQUEST]: "The Agent request was rejected as invalid.",
2648
- [import_shared6.ERROR_CODES.INVALID_TOKEN]: "The local SpotPatch session expired.",
2649
- [import_shared6.ERROR_CODES.ORIGIN_NOT_ALLOWED]: "The current page origin is not authorized.",
2650
- [import_shared6.ERROR_CODES.SOURCE_NOT_FOUND]: "The selected source is no longer available.",
2651
- [import_shared6.ERROR_CODES.SOURCE_OUTSIDE_ROOT]: "The selected source is outside the project.",
2652
- [import_shared6.ERROR_CODES.SOURCE_TOO_LARGE]: "The selected source exceeds the safety limit.",
2653
- [import_shared6.ERROR_CODES.EDITOR_OPEN_FAILED]: "The editor request failed.",
2654
- [import_shared6.ERROR_CODES.DATA_FLOW_DISABLED]: "Component data-flow analysis is disabled.",
2655
- [import_shared6.ERROR_CODES.DATA_FLOW_SOURCE_STALE]: "The selected source changed. Select the component again.",
2656
- [import_shared6.ERROR_CODES.DATA_FLOW_ANALYSIS_CANCELLED]: "Component data-flow analysis was cancelled.",
2657
- [import_shared6.ERROR_CODES.AI_DISABLED]: "AI execution is disabled in Vite configuration.",
2658
- [import_shared6.ERROR_CODES.PROVIDER_NOT_CONFIGURED]: "The provider Key environment variable is missing on the Vite process.",
2659
- [import_shared6.ERROR_CODES.PROVIDER_AUTH_FAILED]: "The provider rejected authentication. Check the server-side Key.",
2660
- [import_shared6.ERROR_CODES.PROVIDER_PROTOCOL_UNSUPPORTED]: "The relay does not match the configured OpenAI-compatible protocol.",
2661
- [import_shared6.ERROR_CODES.MODEL_NOT_ALLOWED]: "The selected model profile is not allowed.",
2662
- [import_shared6.ERROR_CODES.MODEL_TOOL_CALL_UNSUPPORTED]: "The selected model did not start or continue the required tool call.",
2663
- [import_shared6.ERROR_CODES.PROVIDER_RATE_LIMITED]: "The provider is rate limited. Wait and try again.",
2664
- [import_shared6.ERROR_CODES.AGENT_BUSY]: "Another write Agent job is still active.",
2665
- [import_shared6.ERROR_CODES.AGENT_LIMIT_EXCEEDED]: "The Agent stopped at a configured time, turn, output, or size limit.",
2666
- [import_shared6.ERROR_CODES.AGENT_CANCELLED]: "The Agent job was cancelled.",
2667
- [import_shared6.ERROR_CODES.EXTERNAL_HANDOFF_DISABLED]: EXTERNAL_HANDOFF_ERROR_EN,
2668
- [import_shared6.ERROR_CODES.EXTERNAL_HANDOFF_UNAVAILABLE]: EXTERNAL_HANDOFF_ERROR_EN,
2669
- [import_shared6.ERROR_CODES.HANDOFF_VALIDATION_FAILED]: EXTERNAL_HANDOFF_ERROR_EN,
2670
- [import_shared6.ERROR_CODES.HANDOFF_SOURCE_STALE]: EXTERNAL_HANDOFF_ERROR_EN,
2671
- [import_shared6.ERROR_CODES.HANDOFF_NOT_FOUND]: EXTERNAL_HANDOFF_ERROR_EN,
2672
- [import_shared6.ERROR_CODES.HANDOFF_EXPIRED]: EXTERNAL_HANDOFF_ERROR_EN,
2673
- [import_shared6.ERROR_CODES.HANDOFF_CURSOR_INVALID]: EXTERNAL_HANDOFF_ERROR_EN,
2674
- [import_shared6.ERROR_CODES.HANDOFF_RESPONSE_TOO_LARGE]: EXTERNAL_HANDOFF_ERROR_EN,
2675
- [import_shared6.ERROR_CODES.BRIDGE_UNAUTHORIZED]: EXTERNAL_HANDOFF_ERROR_EN,
2676
- [import_shared6.ERROR_CODES.BRIDGE_PROTOCOL_MISMATCH]: EXTERNAL_HANDOFF_ERROR_EN,
2677
- [import_shared6.ERROR_CODES.BRIDGE_BUSY]: EXTERNAL_HANDOFF_ERROR_EN,
2678
- [import_shared6.ERROR_CODES.EXTERNAL_AGENT_BUSY]: EXTERNAL_HANDOFF_ERROR_EN,
2679
- [import_shared6.ERROR_CODES.ACTIVE_ADAPTER_CONFLICT]: EXTERNAL_HANDOFF_ERROR_EN,
2680
- [import_shared6.ERROR_CODES.ACTIVE_ADAPTER_LEASE_INVALID]: EXTERNAL_HANDOFF_ERROR_EN,
2681
- [import_shared6.ERROR_CODES.ACTIVE_DISPATCH_INVALID]: EXTERNAL_HANDOFF_ERROR_EN,
2682
- [import_shared6.ERROR_CODES.SESSION_NOT_FOUND]: EXTERNAL_HANDOFF_ERROR_EN,
2683
- [import_shared6.ERROR_CODES.SESSION_AMBIGUOUS]: EXTERNAL_HANDOFF_ERROR_EN,
2684
- [import_shared6.ERROR_CODES.SESSION_CLOSED]: EXTERNAL_HANDOFF_ERROR_EN,
2685
- [import_shared6.ERROR_CODES.WORKTREE_DIRTY]: "Confirm inclusion of local changes before running AI.",
2686
- [import_shared6.ERROR_CODES.WORKTREE_NOT_REPOSITORY]: "Vite root must be an initialized Git repository root.",
2687
- [import_shared6.ERROR_CODES.WORKTREE_OPERATION_IN_PROGRESS]: "Finish the active merge, rebase, cherry-pick, or revert.",
2688
- [import_shared6.ERROR_CODES.WORKTREE_CONFLICTED]: "Resolve all Git conflicts before running AI.",
2689
- [import_shared6.ERROR_CODES.WORKTREE_LOCAL_CHANGES_TOO_LARGE]: "Reduce untracked files below the safe count and size limits.",
2690
- [import_shared6.ERROR_CODES.WORKTREE_UNTRACKED_UNSUPPORTED]: "An untracked path is missing, linked, or not a regular file.",
2691
- [import_shared6.ERROR_CODES.WORKTREE_LOCAL_CHANGES_UNSUPPORTED]: "Local changes cannot be isolated safely.",
2692
- [import_shared6.ERROR_CODES.TOOL_DENIED]: "A tool request violated local safety policy.",
2693
- [import_shared6.ERROR_CODES.TOOL_INPUT_INVALID]: "Invalid tool request.",
2694
- [import_shared6.ERROR_CODES.TOOL_ARGUMENTS_INVALID]: "Tool arguments are invalid.",
2695
- [import_shared6.ERROR_CODES.TOOL_CALL_ID_CONFLICT]: "Tool ID conflicts in this turn.",
2696
- [import_shared6.ERROR_CODES.TOOL_PATH_DENIED]: "The model requested a protected or external path.",
2697
- [import_shared6.ERROR_CODES.PATCH_REJECTED]: "The patch violated local policy.",
2698
- [import_shared6.ERROR_CODES.VALIDATION_FAILED]: "Required checks failed; changes cannot be applied.",
2699
- [import_shared6.ERROR_CODES.APPLY_CONFLICT]: "Agent-touched files changed; nothing was overwritten.",
2700
- [import_shared6.ERROR_CODES.INTERNAL_ERROR]: "The Agent failed without exposing private details."
2842
+ [import_shared11.ERROR_CODES.INVALID_REQUEST]: "The Agent request was rejected as invalid.",
2843
+ [import_shared11.ERROR_CODES.INVALID_TOKEN]: "The local SpotPatch session expired.",
2844
+ [import_shared11.ERROR_CODES.ORIGIN_NOT_ALLOWED]: "The current page origin is not authorized.",
2845
+ [import_shared11.ERROR_CODES.SOURCE_NOT_FOUND]: "The selected source is no longer available.",
2846
+ [import_shared11.ERROR_CODES.SOURCE_OUTSIDE_ROOT]: "The selected source is outside the project.",
2847
+ [import_shared11.ERROR_CODES.SOURCE_TOO_LARGE]: "The selected source exceeds the safety limit.",
2848
+ [import_shared11.ERROR_CODES.EDITOR_OPEN_FAILED]: "The editor request failed.",
2849
+ [import_shared11.ERROR_CODES.DATA_FLOW_DISABLED]: "Component data-flow analysis is disabled.",
2850
+ [import_shared11.ERROR_CODES.DATA_FLOW_SOURCE_STALE]: "The selected source changed. Select the component again.",
2851
+ [import_shared11.ERROR_CODES.DATA_FLOW_ANALYSIS_CANCELLED]: "Component data-flow analysis was cancelled.",
2852
+ [import_shared11.ERROR_CODES.AI_DISABLED]: "AI execution is disabled in Vite configuration.",
2853
+ [import_shared11.ERROR_CODES.PROVIDER_NOT_CONFIGURED]: "The provider Key environment variable is missing on the Vite process.",
2854
+ [import_shared11.ERROR_CODES.PROVIDER_AUTH_FAILED]: "The provider rejected authentication. Check the server-side Key.",
2855
+ [import_shared11.ERROR_CODES.PROVIDER_PROTOCOL_UNSUPPORTED]: "The relay does not match the configured OpenAI-compatible protocol.",
2856
+ [import_shared11.ERROR_CODES.MODEL_NOT_ALLOWED]: "The selected model profile is not allowed.",
2857
+ [import_shared11.ERROR_CODES.MODEL_TOOL_CALL_UNSUPPORTED]: "The selected model did not start or continue the required tool call.",
2858
+ [import_shared11.ERROR_CODES.PROVIDER_RATE_LIMITED]: "The provider is rate limited. Wait and try again.",
2859
+ [import_shared11.ERROR_CODES.AGENT_BUSY]: "Another write Agent job is still active.",
2860
+ [import_shared11.ERROR_CODES.AGENT_LIMIT_EXCEEDED]: "The Agent stopped at a configured time, turn, output, or size limit.",
2861
+ [import_shared11.ERROR_CODES.AGENT_CANCELLED]: "The Agent job was cancelled.",
2862
+ [import_shared11.ERROR_CODES.EXTERNAL_HANDOFF_DISABLED]: EXTERNAL_HANDOFF_ERROR_EN,
2863
+ [import_shared11.ERROR_CODES.EXTERNAL_HANDOFF_UNAVAILABLE]: EXTERNAL_HANDOFF_ERROR_EN,
2864
+ [import_shared11.ERROR_CODES.HANDOFF_VALIDATION_FAILED]: EXTERNAL_HANDOFF_ERROR_EN,
2865
+ [import_shared11.ERROR_CODES.HANDOFF_SOURCE_STALE]: EXTERNAL_HANDOFF_ERROR_EN,
2866
+ [import_shared11.ERROR_CODES.HANDOFF_NOT_FOUND]: EXTERNAL_HANDOFF_ERROR_EN,
2867
+ [import_shared11.ERROR_CODES.HANDOFF_EXPIRED]: EXTERNAL_HANDOFF_ERROR_EN,
2868
+ [import_shared11.ERROR_CODES.HANDOFF_CURSOR_INVALID]: EXTERNAL_HANDOFF_ERROR_EN,
2869
+ [import_shared11.ERROR_CODES.HANDOFF_RESPONSE_TOO_LARGE]: EXTERNAL_HANDOFF_ERROR_EN,
2870
+ [import_shared11.ERROR_CODES.BRIDGE_UNAUTHORIZED]: EXTERNAL_HANDOFF_ERROR_EN,
2871
+ [import_shared11.ERROR_CODES.BRIDGE_PROTOCOL_MISMATCH]: EXTERNAL_HANDOFF_ERROR_EN,
2872
+ [import_shared11.ERROR_CODES.BRIDGE_BUSY]: EXTERNAL_HANDOFF_ERROR_EN,
2873
+ [import_shared11.ERROR_CODES.EXTERNAL_AGENT_BUSY]: EXTERNAL_HANDOFF_ERROR_EN,
2874
+ [import_shared11.ERROR_CODES.ACTIVE_ADAPTER_CONFLICT]: EXTERNAL_HANDOFF_ERROR_EN,
2875
+ [import_shared11.ERROR_CODES.ACTIVE_ADAPTER_LEASE_INVALID]: EXTERNAL_HANDOFF_ERROR_EN,
2876
+ [import_shared11.ERROR_CODES.ACTIVE_DISPATCH_INVALID]: EXTERNAL_HANDOFF_ERROR_EN,
2877
+ [import_shared11.ERROR_CODES.SESSION_NOT_FOUND]: EXTERNAL_HANDOFF_ERROR_EN,
2878
+ [import_shared11.ERROR_CODES.SESSION_AMBIGUOUS]: EXTERNAL_HANDOFF_ERROR_EN,
2879
+ [import_shared11.ERROR_CODES.SESSION_CLOSED]: EXTERNAL_HANDOFF_ERROR_EN,
2880
+ [import_shared11.ERROR_CODES.WORKTREE_DIRTY]: "Confirm inclusion of local changes before running AI.",
2881
+ [import_shared11.ERROR_CODES.WORKTREE_NOT_REPOSITORY]: "Vite root must be an initialized Git repository root.",
2882
+ [import_shared11.ERROR_CODES.WORKTREE_OPERATION_IN_PROGRESS]: "Finish the active merge, rebase, cherry-pick, or revert.",
2883
+ [import_shared11.ERROR_CODES.WORKTREE_CONFLICTED]: "Resolve all Git conflicts before running AI.",
2884
+ [import_shared11.ERROR_CODES.WORKTREE_LOCAL_CHANGES_TOO_LARGE]: "Reduce untracked files below the safe count and size limits.",
2885
+ [import_shared11.ERROR_CODES.WORKTREE_UNTRACKED_UNSUPPORTED]: "An untracked path is missing, linked, or not a regular file.",
2886
+ [import_shared11.ERROR_CODES.WORKTREE_LOCAL_CHANGES_UNSUPPORTED]: "Local changes cannot be isolated safely.",
2887
+ [import_shared11.ERROR_CODES.TOOL_DENIED]: "A tool request violated local safety policy.",
2888
+ [import_shared11.ERROR_CODES.TOOL_INPUT_INVALID]: "Invalid tool request.",
2889
+ [import_shared11.ERROR_CODES.TOOL_ARGUMENTS_INVALID]: "Tool arguments are invalid.",
2890
+ [import_shared11.ERROR_CODES.TOOL_CALL_ID_CONFLICT]: "Tool ID conflicts in this turn.",
2891
+ [import_shared11.ERROR_CODES.TOOL_PATH_DENIED]: "The model requested a protected or external path.",
2892
+ [import_shared11.ERROR_CODES.PATCH_REJECTED]: "The patch violated local policy.",
2893
+ [import_shared11.ERROR_CODES.VALIDATION_FAILED]: "Required checks failed; changes cannot be applied.",
2894
+ [import_shared11.ERROR_CODES.APPLY_CONFLICT]: "Agent-touched files changed; nothing was overwritten.",
2895
+ [import_shared11.ERROR_CODES.INTERNAL_ERROR]: "The Agent failed without exposing private details."
2701
2896
  });
2702
2897
  var ERROR_MESSAGES_ZH = Object.freeze({
2703
- [import_shared6.ERROR_CODES.INVALID_REQUEST]: "Agent 请求无效,已被拒绝。",
2704
- [import_shared6.ERROR_CODES.INVALID_TOKEN]: "本地 SpotPatch 会话已失效。",
2705
- [import_shared6.ERROR_CODES.ORIGIN_NOT_ALLOWED]: "当前页面来源未获授权。",
2706
- [import_shared6.ERROR_CODES.SOURCE_NOT_FOUND]: "选中目标对应的源码已不可用。",
2707
- [import_shared6.ERROR_CODES.SOURCE_OUTSIDE_ROOT]: "选中源码位于项目根目录之外。",
2708
- [import_shared6.ERROR_CODES.SOURCE_TOO_LARGE]: "选中源码超过安全大小限制。",
2709
- [import_shared6.ERROR_CODES.EDITOR_OPEN_FAILED]: "编辑器打开请求失败。",
2710
- [import_shared6.ERROR_CODES.DATA_FLOW_DISABLED]: "组件数据链路分析未启用。",
2711
- [import_shared6.ERROR_CODES.DATA_FLOW_SOURCE_STALE]: "选中源码已经变化,请重新选择组件。",
2712
- [import_shared6.ERROR_CODES.DATA_FLOW_ANALYSIS_CANCELLED]: "组件数据链路分析已取消。",
2713
- [import_shared6.ERROR_CODES.AI_DISABLED]: "Vite 配置未启用 AI 执行。",
2714
- [import_shared6.ERROR_CODES.PROVIDER_NOT_CONFIGURED]: "启动 Vite 的进程中缺少模型服务 Key 环境变量。",
2715
- [import_shared6.ERROR_CODES.PROVIDER_AUTH_FAILED]: "模型服务鉴权失败,请检查服务端 Key。",
2716
- [import_shared6.ERROR_CODES.PROVIDER_PROTOCOL_UNSUPPORTED]: "中转服务与配置的 OpenAI 兼容协议不一致。",
2717
- [import_shared6.ERROR_CODES.MODEL_NOT_ALLOWED]: "当前模型配置未获授权。",
2718
- [import_shared6.ERROR_CODES.MODEL_TOOL_CALL_UNSUPPORTED]: "当前模型未完成必要的工具调用或结果续接。",
2719
- [import_shared6.ERROR_CODES.PROVIDER_RATE_LIMITED]: "模型服务正在限流,请稍后重试。",
2720
- [import_shared6.ERROR_CODES.AGENT_BUSY]: "当前项目已有一个写入任务正在运行。",
2721
- [import_shared6.ERROR_CODES.AGENT_LIMIT_EXCEEDED]: "Agent 达到时间、轮次、输出或变更规模限制。",
2722
- [import_shared6.ERROR_CODES.AGENT_CANCELLED]: "Agent 任务已取消。",
2723
- [import_shared6.ERROR_CODES.EXTERNAL_HANDOFF_DISABLED]: EXTERNAL_HANDOFF_ERROR_ZH,
2724
- [import_shared6.ERROR_CODES.EXTERNAL_HANDOFF_UNAVAILABLE]: EXTERNAL_HANDOFF_ERROR_ZH,
2725
- [import_shared6.ERROR_CODES.HANDOFF_VALIDATION_FAILED]: EXTERNAL_HANDOFF_ERROR_ZH,
2726
- [import_shared6.ERROR_CODES.HANDOFF_SOURCE_STALE]: EXTERNAL_HANDOFF_ERROR_ZH,
2727
- [import_shared6.ERROR_CODES.HANDOFF_NOT_FOUND]: EXTERNAL_HANDOFF_ERROR_ZH,
2728
- [import_shared6.ERROR_CODES.HANDOFF_EXPIRED]: EXTERNAL_HANDOFF_ERROR_ZH,
2729
- [import_shared6.ERROR_CODES.HANDOFF_CURSOR_INVALID]: EXTERNAL_HANDOFF_ERROR_ZH,
2730
- [import_shared6.ERROR_CODES.HANDOFF_RESPONSE_TOO_LARGE]: EXTERNAL_HANDOFF_ERROR_ZH,
2731
- [import_shared6.ERROR_CODES.BRIDGE_UNAUTHORIZED]: EXTERNAL_HANDOFF_ERROR_ZH,
2732
- [import_shared6.ERROR_CODES.BRIDGE_PROTOCOL_MISMATCH]: EXTERNAL_HANDOFF_ERROR_ZH,
2733
- [import_shared6.ERROR_CODES.BRIDGE_BUSY]: EXTERNAL_HANDOFF_ERROR_ZH,
2734
- [import_shared6.ERROR_CODES.EXTERNAL_AGENT_BUSY]: EXTERNAL_HANDOFF_ERROR_ZH,
2735
- [import_shared6.ERROR_CODES.ACTIVE_ADAPTER_CONFLICT]: EXTERNAL_HANDOFF_ERROR_ZH,
2736
- [import_shared6.ERROR_CODES.ACTIVE_ADAPTER_LEASE_INVALID]: EXTERNAL_HANDOFF_ERROR_ZH,
2737
- [import_shared6.ERROR_CODES.ACTIVE_DISPATCH_INVALID]: EXTERNAL_HANDOFF_ERROR_ZH,
2738
- [import_shared6.ERROR_CODES.SESSION_NOT_FOUND]: EXTERNAL_HANDOFF_ERROR_ZH,
2739
- [import_shared6.ERROR_CODES.SESSION_AMBIGUOUS]: EXTERNAL_HANDOFF_ERROR_ZH,
2740
- [import_shared6.ERROR_CODES.SESSION_CLOSED]: EXTERNAL_HANDOFF_ERROR_ZH,
2741
- [import_shared6.ERROR_CODES.WORKTREE_DIRTY]: "运行 AI 前,请明确同意将当前本地修改纳入隔离基线。",
2742
- [import_shared6.ERROR_CODES.WORKTREE_NOT_REPOSITORY]: "Vite 根目录不是已初始化 Git 仓库的顶层目录。",
2743
- [import_shared6.ERROR_CODES.WORKTREE_OPERATION_IN_PROGRESS]: "请先完成当前 merge、rebase、cherry-pick 或 revert,再运行 AI。",
2744
- [import_shared6.ERROR_CODES.WORKTREE_CONFLICTED]: "请先解决全部 Git 冲突,再运行 AI。",
2745
- [import_shared6.ERROR_CODES.WORKTREE_LOCAL_CHANGES_TOO_LARGE]: "未跟踪文件超过安全数量或体积上限,请先精简。",
2746
- [import_shared6.ERROR_CODES.WORKTREE_UNTRACKED_UNSUPPORTED]: "未跟踪项已丢失、是符号链接或不是普通文件。",
2747
- [import_shared6.ERROR_CODES.WORKTREE_LOCAL_CHANGES_UNSUPPORTED]: "当前本地修改无法安全隔离。",
2748
- [import_shared6.ERROR_CODES.TOOL_DENIED]: "工具请求违反本地安全策略。",
2749
- [import_shared6.ERROR_CODES.TOOL_INPUT_INVALID]: "工具请求无效。",
2750
- [import_shared6.ERROR_CODES.TOOL_ARGUMENTS_INVALID]: "工具参数无效。",
2751
- [import_shared6.ERROR_CODES.TOOL_CALL_ID_CONFLICT]: "本轮工具 ID 冲突。",
2752
- [import_shared6.ERROR_CODES.TOOL_PATH_DENIED]: "模型请求了受保护或项目外路径。",
2753
- [import_shared6.ERROR_CODES.PATCH_REJECTED]: "补丁违反本地策略。",
2754
- [import_shared6.ERROR_CODES.VALIDATION_FAILED]: "必需检查失败,无法应用变更。",
2755
- [import_shared6.ERROR_CODES.APPLY_CONFLICT]: "Agent 触及文件已变化,未覆盖。",
2756
- [import_shared6.ERROR_CODES.INTERNAL_ERROR]: "Agent 失败,未暴露私有细节。"
2898
+ [import_shared11.ERROR_CODES.INVALID_REQUEST]: "Agent 请求无效,已被拒绝。",
2899
+ [import_shared11.ERROR_CODES.INVALID_TOKEN]: "本地 SpotPatch 会话已失效。",
2900
+ [import_shared11.ERROR_CODES.ORIGIN_NOT_ALLOWED]: "当前页面来源未获授权。",
2901
+ [import_shared11.ERROR_CODES.SOURCE_NOT_FOUND]: "选中目标对应的源码已不可用。",
2902
+ [import_shared11.ERROR_CODES.SOURCE_OUTSIDE_ROOT]: "选中源码位于项目根目录之外。",
2903
+ [import_shared11.ERROR_CODES.SOURCE_TOO_LARGE]: "选中源码超过安全大小限制。",
2904
+ [import_shared11.ERROR_CODES.EDITOR_OPEN_FAILED]: "编辑器打开请求失败。",
2905
+ [import_shared11.ERROR_CODES.DATA_FLOW_DISABLED]: "组件数据链路分析未启用。",
2906
+ [import_shared11.ERROR_CODES.DATA_FLOW_SOURCE_STALE]: "选中源码已经变化,请重新选择组件。",
2907
+ [import_shared11.ERROR_CODES.DATA_FLOW_ANALYSIS_CANCELLED]: "组件数据链路分析已取消。",
2908
+ [import_shared11.ERROR_CODES.AI_DISABLED]: "Vite 配置未启用 AI 执行。",
2909
+ [import_shared11.ERROR_CODES.PROVIDER_NOT_CONFIGURED]: "启动 Vite 的进程中缺少模型服务 Key 环境变量。",
2910
+ [import_shared11.ERROR_CODES.PROVIDER_AUTH_FAILED]: "模型服务鉴权失败,请检查服务端 Key。",
2911
+ [import_shared11.ERROR_CODES.PROVIDER_PROTOCOL_UNSUPPORTED]: "中转服务与配置的 OpenAI 兼容协议不一致。",
2912
+ [import_shared11.ERROR_CODES.MODEL_NOT_ALLOWED]: "当前模型配置未获授权。",
2913
+ [import_shared11.ERROR_CODES.MODEL_TOOL_CALL_UNSUPPORTED]: "当前模型未完成必要的工具调用或结果续接。",
2914
+ [import_shared11.ERROR_CODES.PROVIDER_RATE_LIMITED]: "模型服务正在限流,请稍后重试。",
2915
+ [import_shared11.ERROR_CODES.AGENT_BUSY]: "当前项目已有一个写入任务正在运行。",
2916
+ [import_shared11.ERROR_CODES.AGENT_LIMIT_EXCEEDED]: "Agent 达到时间、轮次、输出或变更规模限制。",
2917
+ [import_shared11.ERROR_CODES.AGENT_CANCELLED]: "Agent 任务已取消。",
2918
+ [import_shared11.ERROR_CODES.EXTERNAL_HANDOFF_DISABLED]: EXTERNAL_HANDOFF_ERROR_ZH,
2919
+ [import_shared11.ERROR_CODES.EXTERNAL_HANDOFF_UNAVAILABLE]: EXTERNAL_HANDOFF_ERROR_ZH,
2920
+ [import_shared11.ERROR_CODES.HANDOFF_VALIDATION_FAILED]: EXTERNAL_HANDOFF_ERROR_ZH,
2921
+ [import_shared11.ERROR_CODES.HANDOFF_SOURCE_STALE]: EXTERNAL_HANDOFF_ERROR_ZH,
2922
+ [import_shared11.ERROR_CODES.HANDOFF_NOT_FOUND]: EXTERNAL_HANDOFF_ERROR_ZH,
2923
+ [import_shared11.ERROR_CODES.HANDOFF_EXPIRED]: EXTERNAL_HANDOFF_ERROR_ZH,
2924
+ [import_shared11.ERROR_CODES.HANDOFF_CURSOR_INVALID]: EXTERNAL_HANDOFF_ERROR_ZH,
2925
+ [import_shared11.ERROR_CODES.HANDOFF_RESPONSE_TOO_LARGE]: EXTERNAL_HANDOFF_ERROR_ZH,
2926
+ [import_shared11.ERROR_CODES.BRIDGE_UNAUTHORIZED]: EXTERNAL_HANDOFF_ERROR_ZH,
2927
+ [import_shared11.ERROR_CODES.BRIDGE_PROTOCOL_MISMATCH]: EXTERNAL_HANDOFF_ERROR_ZH,
2928
+ [import_shared11.ERROR_CODES.BRIDGE_BUSY]: EXTERNAL_HANDOFF_ERROR_ZH,
2929
+ [import_shared11.ERROR_CODES.EXTERNAL_AGENT_BUSY]: EXTERNAL_HANDOFF_ERROR_ZH,
2930
+ [import_shared11.ERROR_CODES.ACTIVE_ADAPTER_CONFLICT]: EXTERNAL_HANDOFF_ERROR_ZH,
2931
+ [import_shared11.ERROR_CODES.ACTIVE_ADAPTER_LEASE_INVALID]: EXTERNAL_HANDOFF_ERROR_ZH,
2932
+ [import_shared11.ERROR_CODES.ACTIVE_DISPATCH_INVALID]: EXTERNAL_HANDOFF_ERROR_ZH,
2933
+ [import_shared11.ERROR_CODES.SESSION_NOT_FOUND]: EXTERNAL_HANDOFF_ERROR_ZH,
2934
+ [import_shared11.ERROR_CODES.SESSION_AMBIGUOUS]: EXTERNAL_HANDOFF_ERROR_ZH,
2935
+ [import_shared11.ERROR_CODES.SESSION_CLOSED]: EXTERNAL_HANDOFF_ERROR_ZH,
2936
+ [import_shared11.ERROR_CODES.WORKTREE_DIRTY]: "运行 AI 前,请明确同意将当前本地修改纳入隔离基线。",
2937
+ [import_shared11.ERROR_CODES.WORKTREE_NOT_REPOSITORY]: "Vite 根目录不是已初始化 Git 仓库的顶层目录。",
2938
+ [import_shared11.ERROR_CODES.WORKTREE_OPERATION_IN_PROGRESS]: "请先完成当前 merge、rebase、cherry-pick 或 revert,再运行 AI。",
2939
+ [import_shared11.ERROR_CODES.WORKTREE_CONFLICTED]: "请先解决全部 Git 冲突,再运行 AI。",
2940
+ [import_shared11.ERROR_CODES.WORKTREE_LOCAL_CHANGES_TOO_LARGE]: "未跟踪文件超过安全数量或体积上限,请先精简。",
2941
+ [import_shared11.ERROR_CODES.WORKTREE_UNTRACKED_UNSUPPORTED]: "未跟踪项已丢失、是符号链接或不是普通文件。",
2942
+ [import_shared11.ERROR_CODES.WORKTREE_LOCAL_CHANGES_UNSUPPORTED]: "当前本地修改无法安全隔离。",
2943
+ [import_shared11.ERROR_CODES.TOOL_DENIED]: "工具请求违反本地安全策略。",
2944
+ [import_shared11.ERROR_CODES.TOOL_INPUT_INVALID]: "工具请求无效。",
2945
+ [import_shared11.ERROR_CODES.TOOL_ARGUMENTS_INVALID]: "工具参数无效。",
2946
+ [import_shared11.ERROR_CODES.TOOL_CALL_ID_CONFLICT]: "本轮工具 ID 冲突。",
2947
+ [import_shared11.ERROR_CODES.TOOL_PATH_DENIED]: "模型请求了受保护或项目外路径。",
2948
+ [import_shared11.ERROR_CODES.PATCH_REJECTED]: "补丁违反本地策略。",
2949
+ [import_shared11.ERROR_CODES.VALIDATION_FAILED]: "必需检查失败,无法应用变更。",
2950
+ [import_shared11.ERROR_CODES.APPLY_CONFLICT]: "Agent 触及文件已变化,未覆盖。",
2951
+ [import_shared11.ERROR_CODES.INTERNAL_ERROR]: "Agent 失败,未暴露私有细节。"
2757
2952
  });
2758
2953
  var SUMMARY_MESSAGES_EN = Object.freeze({
2954
+ instance: "Selected instance",
2955
+ instanceStates: {
2956
+ captured: "Captured element; locator describes selection time",
2957
+ changed: "Page content changed; snapshot preserved. Select again to confirm the current instance",
2958
+ detached: "Element unloaded; historical snapshot preserved",
2959
+ restored: "Restored snapshot; not bound to the current page"
2960
+ },
2759
2961
  adapter: "React adapter",
2760
2962
  api: "API",
2761
2963
  apiStatuses: Object.freeze({
@@ -2796,6 +2998,13 @@ var SUMMARY_MESSAGES_EN = Object.freeze({
2796
2998
  warning: "Warning"
2797
2999
  });
2798
3000
  var SUMMARY_MESSAGES_ZH = Object.freeze({
3001
+ instance: "选中实例",
3002
+ instanceStates: {
3003
+ captured: "已捕获元素;定位信息对应选择时刻",
3004
+ changed: "页面内容已变化,已保留快照;请重新选择以确认当前实例",
3005
+ detached: "元素已卸载,已保留历史快照",
3006
+ restored: "已恢复历史快照,未绑定当前页面"
3007
+ },
2799
3008
  adapter: "React 适配器",
2800
3009
  api: "API",
2801
3010
  apiStatuses: Object.freeze({
@@ -2980,13 +3189,13 @@ var UI_MESSAGES = Object.freeze({
2980
3189
  addCancelled: "Additional selection cancelled.",
2981
3190
  selectionLimit: (maximum) => `The selection limit of ${String(maximum)} elements has been reached.`,
2982
3191
  chooseAdditional: (selected, maximum) => `Choose another element. ${String(selected)} of ${String(maximum)} selected.`,
2983
- duplicate: "That source target is already selected.",
3192
+ duplicate: "That page element is already selected.",
3193
+ instanceBudgetExceeded: "The prompt cannot preserve every selected instance within its budget. Remove some targets or increase the context budget.",
2984
3194
  sourceProbable: "A probable React component was found without an authorized file token.",
2985
3195
  sourceMissing: "No authorized source marker was found for the selected element.",
2986
3196
  noSelectable: "No selectable element was found.",
2987
3197
  allTargetsRemoved: "All targets were removed. Choose an element to continue.",
2988
3198
  targetRemoved: "Selected target removed.",
2989
- detachedTargetPreserved: "The page element was unloaded; its collected context remains selected.",
2990
3199
  contextWarning: "Browser context collection completed with a warning.",
2991
3200
  contextCollected: "Browser context collected.",
2992
3201
  editorOpening: "Opening source…",
@@ -3144,13 +3353,13 @@ var UI_MESSAGES = Object.freeze({
3144
3353
  addCancelled: "已取消追加选择。",
3145
3354
  selectionLimit: (maximum) => `已达到 ${String(maximum)} 个元素的选择上限。`,
3146
3355
  chooseAdditional: (selected, maximum) => `请选择另一个元素,当前已选 ${String(selected)} / ${String(maximum)}。`,
3147
- duplicate: "该源码目标已经在当前选择中。",
3356
+ duplicate: "该页面元素已经在当前选择中。",
3357
+ instanceBudgetExceeded: "上下文预算无法完整保留所有选中实例,请减少目标数量或提高上下文预算。",
3148
3358
  sourceProbable: "找到可能的 React 组件,但没有获授权的源码标记。",
3149
3359
  sourceMissing: "选中元素没有获授权的源码标记。",
3150
3360
  noSelectable: "当前位置没有可选择的元素。",
3151
3361
  allTargetsRemoved: "已移除全部目标,请重新选择元素。",
3152
3362
  targetRemoved: "已移除选中目标。",
3153
- detachedTargetPreserved: "页面元素已卸载,已采集的上下文仍保留在选择中。",
3154
3363
  contextWarning: "浏览器上下文采集完成,但存在警告。",
3155
3364
  contextCollected: "浏览器上下文采集完成。",
3156
3365
  editorOpening: "正在打开源码……",
@@ -3713,67 +3922,102 @@ function resolveStyleNonce(document) {
3713
3922
  function createStyles(document) {
3714
3923
  const style = document.createElement("style");
3715
3924
  style.textContent = `
3716
- :host {
3717
- all: initial;
3718
- --spotpatch-bg: #0e0e12;
3719
- --spotpatch-bg-raised: #17171c;
3720
- --spotpatch-bg-active: #1c1c22;
3721
- --spotpatch-bg-input: #0b0b0f;
3722
- --spotpatch-border: #2a2a32;
3723
- --spotpatch-border-subtle: #232329;
3724
- --spotpatch-text: #f2f2f5;
3725
- --spotpatch-text-secondary: #96969f;
3726
- --spotpatch-text-muted: #686872;
3727
- --spotpatch-accent: #8b7bff;
3728
- --spotpatch-accent-strong: #6a5ce8;
3729
- --spotpatch-accent-cyan: #52a8ff;
3730
- --spotpatch-danger: #fb7185;
3731
- --spotpatch-success: #34d399;
3732
- --spotpatch-warning: #f59e0b;
3733
- --spotpatch-text-on-accent: #0b0b12;
3734
- --spotpatch-radius-card: 10px;
3735
- color: var(--spotpatch-text);
3736
- font-family: Inter, "SF Pro Display", "SF Pro Text", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
3737
- font-size: 14px;
3738
- line-height: 1.5;
3739
- }
3740
- [hidden] { display: none !important; }
3741
- button, textarea, select { font: inherit; }
3925
+ ${THEME_STYLES}
3742
3926
  .spotpatch-floating-surface {
3743
3927
  position: fixed;
3744
3928
  right: ${String(FLOATING_SURFACE_LAYOUT.desktopInset)}px;
3745
3929
  bottom: ${String(FLOATING_SURFACE_LAYOUT.desktopInset)}px;
3746
3930
  z-index: ${String(UI_Z_INDEX.controls)};
3931
+ box-sizing: border-box;
3932
+ overflow: hidden;
3747
3933
  isolation: isolate;
3934
+ border: 1px solid var(--spotpatch-border);
3935
+ background: var(--spotpatch-surface-fill);
3936
+ box-shadow: var(--spotpatch-shadow-float), var(--spotpatch-shadow-inset);
3937
+ transform-origin: 100% 100%;
3748
3938
  }
3749
- .spotpatch-highlight {
3939
+ .spotpatch-floating-surface[data-scene="pill"],
3940
+ .spotpatch-floating-surface[data-scene="capturing"] {
3941
+ width: max-content;
3942
+ border-radius: var(--spotpatch-radius-pill);
3943
+ }
3944
+ .spotpatch-floating-surface[data-scene="planner"] {
3945
+ border-radius: var(--spotpatch-radius-panel);
3946
+ box-shadow: var(--spotpatch-shadow-panel), var(--spotpatch-shadow-inset);
3947
+ }
3948
+
3949
+ .spotpatch-trigger {
3950
+ display: inline-flex;
3951
+ min-height: 44px;
3952
+ align-items: center;
3953
+ gap: 10px;
3954
+ border: 0;
3955
+ border-radius: var(--spotpatch-radius-pill);
3956
+ padding: 0 18px 0 16px;
3957
+ color: var(--spotpatch-text);
3958
+ background: transparent;
3959
+ cursor: pointer;
3960
+ font-size: 13.5px;
3961
+ font-weight: 620;
3962
+ letter-spacing: -.005em;
3963
+ touch-action: none;
3964
+ user-select: none;
3965
+ transition: background var(--spotpatch-duration-fast) ease;
3966
+ }
3967
+ .spotpatch-trigger::before {
3968
+ width: 8px;
3969
+ height: 8px;
3970
+ border-radius: 50%;
3971
+ background: var(--spotpatch-accent);
3972
+ box-shadow: 0 0 0 4px var(--spotpatch-accent-tint);
3973
+ content: "";
3974
+ transition: background var(--spotpatch-duration-base) ease;
3975
+ }
3976
+ .spotpatch-trigger:hover { background: var(--spotpatch-hover); }
3977
+ .spotpatch-trigger[aria-pressed="true"]::before {
3978
+ background: var(--spotpatch-accent-cyan);
3979
+ animation: spotpatch-trigger-pulse 1.6s var(--spotpatch-ease-standard) infinite;
3980
+ }
3981
+ .spotpatch-trigger[data-dragging="true"] { cursor: grabbing; }
3982
+ @keyframes spotpatch-trigger-pulse {
3983
+ 0% { box-shadow: 0 0 0 0 var(--spotpatch-cyan-line); }
3984
+ 100% { box-shadow: 0 0 0 9px transparent; }
3985
+ }
3986
+
3987
+ .spotpatch-highlight,
3988
+ .spotpatch-selection-highlight {
3750
3989
  position: fixed;
3751
3990
  top: 0;
3752
3991
  left: 0;
3753
- z-index: ${String(UI_Z_INDEX.highlight)};
3754
3992
  box-sizing: border-box;
3755
- border: 2px solid var(--spotpatch-accent);
3756
- border-radius: 6px;
3757
- background: rgb(109 93 246 / 8%);
3758
- box-shadow: inset 0 0 0 1px rgb(255 255 255 / 22%), 0 0 0 1px rgb(109 93 246 / 10%);
3993
+ border-radius: var(--spotpatch-radius-xs);
3759
3994
  pointer-events: none;
3760
3995
  }
3761
- .spotpatch-highlight-label {
3996
+ .spotpatch-highlight {
3997
+ z-index: ${String(UI_Z_INDEX.highlight)};
3998
+ border: 1.5px solid var(--spotpatch-accent);
3999
+ background: var(--spotpatch-accent-tint);
4000
+ box-shadow: 0 0 0 4px color-mix(in srgb, var(--spotpatch-accent) 12%, transparent);
4001
+ transition:
4002
+ transform var(--spotpatch-duration-fast) var(--spotpatch-ease-out),
4003
+ width var(--spotpatch-duration-fast) var(--spotpatch-ease-out),
4004
+ height var(--spotpatch-duration-fast) var(--spotpatch-ease-out);
4005
+ }
4006
+ .spotpatch-highlight-label,
4007
+ .spotpatch-selection-highlight > span {
3762
4008
  position: absolute;
3763
- top: -30px;
3764
- left: -2px;
3765
- max-width: min(380px, 80vw);
4009
+ bottom: calc(100% + 6px);
4010
+ left: -1.5px;
3766
4011
  overflow: hidden;
3767
- border: 1px solid rgb(255 255 255 / 14%);
3768
- border-radius: 8px 8px 8px 3px;
3769
- padding: 6px 10px;
3770
- color: #fff;
3771
- background: #5546dc;
3772
- box-shadow: 0 8px 20px rgb(49 46 129 / 22%);
3773
- font: 650 12px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace;
4012
+ border-radius: var(--spotpatch-radius-xs);
4013
+ padding: 4px 8px;
4014
+ color: var(--spotpatch-text-on-accent);
4015
+ background: var(--spotpatch-accent-strong);
4016
+ font: 600 11px/1.3 var(--spotpatch-font-mono);
3774
4017
  text-overflow: ellipsis;
3775
4018
  white-space: nowrap;
3776
4019
  }
4020
+ .spotpatch-highlight-label { max-width: min(380px, 80vw); }
3777
4021
  .spotpatch-selection-highlights {
3778
4022
  position: fixed;
3779
4023
  inset: 0;
@@ -3781,37 +4025,27 @@ function createStyles(document) {
3781
4025
  pointer-events: none;
3782
4026
  }
3783
4027
  .spotpatch-selection-highlight {
3784
- position: fixed;
3785
- top: 0;
3786
- left: 0;
3787
- box-sizing: border-box;
3788
- border: 2px solid var(--spotpatch-accent-cyan);
3789
- border-radius: 6px;
3790
- background: rgb(8 182 214 / 5%);
3791
- box-shadow: inset 0 0 0 1px rgb(255 255 255 / 16%);
4028
+ border: 1.5px solid var(--spotpatch-accent-cyan);
4029
+ background: var(--spotpatch-cyan-tint);
3792
4030
  }
3793
4031
  .spotpatch-selection-highlight[data-active="true"] {
3794
- border-color: #7768f7;
3795
- background: rgb(109 93 246 / 8%);
3796
- box-shadow: inset 0 0 0 1px rgb(255 255 255 / 20%);
4032
+ border-color: var(--spotpatch-accent);
4033
+ background: var(--spotpatch-accent-tint);
4034
+ box-shadow: 0 0 0 4px color-mix(in srgb, var(--spotpatch-accent) 12%, transparent);
4035
+ }
4036
+ .spotpatch-selection-highlight[data-entering="true"] {
4037
+ animation: spotpatch-pop var(--spotpatch-duration-base) var(--spotpatch-ease-spring) both;
3797
4038
  }
3798
4039
  .spotpatch-selection-highlight > span {
3799
- position: absolute;
3800
- top: -24px;
3801
- left: -2px;
3802
4040
  max-width: min(300px, 70vw);
3803
- overflow: hidden;
3804
- border-radius: 7px 7px 7px 2px;
3805
- padding: 4px 8px;
3806
- color: #ecfeff;
3807
- background: rgb(14 67 82 / 96%);
3808
- font: 650 11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace;
3809
- text-overflow: ellipsis;
3810
- white-space: nowrap;
4041
+ color: var(--spotpatch-bg);
4042
+ background: var(--spotpatch-accent-cyan);
3811
4043
  }
3812
4044
  .spotpatch-selection-highlight[data-active="true"] > span {
3813
- background: #5546dc;
4045
+ color: var(--spotpatch-text-on-accent);
4046
+ background: var(--spotpatch-accent-strong);
3814
4047
  }
4048
+
3815
4049
  .spotpatch-dialog {
3816
4050
  position: relative;
3817
4051
  box-sizing: border-box;
@@ -3819,18 +4053,14 @@ function createStyles(document) {
3819
4053
  outline: none;
3820
4054
  }
3821
4055
  .spotpatch-shell {
3822
- position: relative;
3823
- z-index: 1;
3824
4056
  display: flex;
3825
4057
  box-sizing: border-box;
3826
4058
  max-height: min(${String(FLOATING_SURFACE_LAYOUT.workbenchMaxHeight)}px, calc(100vh - ${String(FLOATING_SURFACE_LAYOUT.desktopInset * 2)}px));
3827
4059
  overflow: hidden;
3828
4060
  flex-direction: column;
3829
4061
  }
3830
- .spotpatch-header {
3831
- position: relative;
3832
- padding: 0 18px 14px;
3833
- }
4062
+
4063
+ .spotpatch-header { padding: 0 18px 16px; }
3834
4064
  .spotpatch-header[data-spotpatch-drag-handle] { cursor: grab; touch-action: none; user-select: none; }
3835
4065
  .spotpatch-header[data-dragging="true"] { cursor: grabbing; }
3836
4066
  .spotpatch-header button,
@@ -3840,133 +4070,115 @@ function createStyles(document) {
3840
4070
  align-items: center;
3841
4071
  justify-content: space-between;
3842
4072
  gap: 12px;
3843
- margin: 0 -18px 18px;
3844
- padding: 14px 18px 13px;
4073
+ margin: 0 -18px 16px;
4074
+ padding: 12px 14px 12px 18px;
3845
4075
  border-bottom: 1px solid var(--spotpatch-border-subtle);
3846
4076
  }
3847
- .spotpatch-brand {
3848
- display: inline-flex;
3849
- align-items: center;
3850
- gap: 10px;
3851
- min-width: 0;
3852
- color: #f8fafc;
3853
- }
3854
- .spotpatch-brand-mark {
3855
- width: 30px;
3856
- height: 30px;
3857
- flex: none;
3858
- filter: drop-shadow(0 6px 12px rgb(76 29 149 / 22%));
3859
- }
4077
+ .spotpatch-brand { display: inline-flex; min-width: 0; align-items: center; gap: 10px; }
4078
+ .spotpatch-brand-mark { width: 28px; height: 28px; flex: none; }
3860
4079
  .spotpatch-brand-copy { display: grid; min-width: 0; gap: 1px; }
3861
- .spotpatch-header-controls {
3862
- display: inline-flex;
3863
- align-items: center;
3864
- gap: 6px;
3865
- flex: none;
3866
- }
4080
+ .spotpatch-brand-name { font-size: 13.5px; font-weight: 650; letter-spacing: -.01em; }
4081
+ .spotpatch-brand-context { color: var(--spotpatch-text-muted); font-size: 11px; font-weight: 520; }
4082
+ .spotpatch-header-controls { display: inline-flex; flex: none; align-items: center; gap: 2px; }
3867
4083
  .spotpatch-repository,
3868
4084
  .spotpatch-locale,
3869
4085
  .spotpatch-reset-position,
3870
- .spotpatch-close {
3871
- height: 27px;
3872
- border: 1px solid rgb(255 255 255 / 11%);
3873
- border-radius: 7px;
3874
- background: transparent;
3875
- }
3876
- .spotpatch-repository {
3877
- display: inline-flex;
3878
- align-items: center;
3879
- padding: 0 9px;
3880
- color: var(--spotpatch-text-secondary);
3881
- font-size: 11px;
3882
- font-weight: 680;
3883
- text-decoration: none;
3884
- }
3885
- .spotpatch-locale {
3886
- min-width: 34px;
3887
- padding: 0 8px;
3888
- color: #c5cad5;
3889
- cursor: pointer;
3890
- font-size: 12px;
3891
- font-weight: 650;
3892
- }
3893
- .spotpatch-reset-position {
3894
- display: inline-grid;
3895
- width: 27px;
3896
- padding: 0;
3897
- place-items: center;
3898
- color: #c5cad5;
3899
- cursor: pointer;
3900
- font-size: 15px;
3901
- line-height: 1;
3902
- }
3903
4086
  .spotpatch-close {
3904
4087
  display: inline-grid;
3905
- width: 27px;
3906
- padding: 0;
4088
+ box-sizing: border-box;
4089
+ min-width: 28px;
4090
+ height: 28px;
3907
4091
  place-items: center;
3908
- color: #9da5b4;
3909
- cursor: pointer;
3910
- font-size: 15px;
4092
+ border: 0;
4093
+ border-radius: var(--spotpatch-radius-sm);
4094
+ padding: 0 7px;
4095
+ color: var(--spotpatch-text-muted);
4096
+ background: transparent;
4097
+ font-size: 12px;
4098
+ font-weight: 600;
3911
4099
  line-height: 1;
3912
- transition: border-color 150ms ease, color 150ms ease, background 150ms ease;
4100
+ text-decoration: none;
4101
+ transition:
4102
+ color var(--spotpatch-duration-fast) ease,
4103
+ background var(--spotpatch-duration-fast) ease;
3913
4104
  }
3914
- .spotpatch-close:hover,
4105
+ .spotpatch-reset-position,
4106
+ .spotpatch-close { padding: 0; font-size: 15px; }
4107
+ .spotpatch-reset-position svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-linecap: round; stroke-width: 1.5; }
4108
+ .spotpatch-repository:hover,
3915
4109
  .spotpatch-locale:hover,
3916
4110
  .spotpatch-reset-position:hover,
3917
- .spotpatch-repository:hover { border-color: rgb(129 112 247 / 45%); color: #fff; background: rgb(109 93 246 / 10%); }
4111
+ .spotpatch-close:hover { color: var(--spotpatch-text); background: var(--spotpatch-hover); }
4112
+
4113
+ .spotpatch-title {
4114
+ margin: 0;
4115
+ font-size: 17px;
4116
+ font-weight: 650;
4117
+ letter-spacing: -.02em;
4118
+ line-height: 1.3;
4119
+ }
4120
+ .spotpatch-subtitle {
4121
+ max-width: 400px;
4122
+ margin: 4px 0 0;
4123
+ color: var(--spotpatch-text-secondary);
4124
+ font-size: 12.5px;
4125
+ line-height: 1.55;
4126
+ }
3918
4127
  .spotpatch-target-row {
3919
4128
  display: flex;
3920
- align-items: center;
3921
- gap: 8px;
3922
4129
  min-width: 0;
4130
+ align-items: center;
4131
+ gap: 10px;
3923
4132
  margin-top: 14px;
3924
4133
  }
3925
4134
  .spotpatch-target-label {
3926
4135
  min-width: 0;
3927
4136
  overflow: hidden;
3928
- border: 1px solid rgb(129 112 247 / 24%);
3929
- border-radius: 999px;
3930
- padding: 4px 10px;
3931
- color: #cdd2ff;
3932
- background: rgb(109 93 246 / 10%);
3933
- font: 600 11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace;
4137
+ border: 1px solid var(--spotpatch-accent-line);
4138
+ border-radius: var(--spotpatch-radius-pill);
4139
+ padding: 3px 10px;
4140
+ color: var(--spotpatch-accent-soft);
4141
+ background: var(--spotpatch-accent-tint);
4142
+ font: 600 11px/1.4 var(--spotpatch-font-mono);
3934
4143
  text-overflow: ellipsis;
3935
4144
  white-space: nowrap;
3936
4145
  }
3937
4146
  .spotpatch-context-state {
3938
4147
  display: inline-flex;
4148
+ flex: none;
3939
4149
  align-items: center;
3940
4150
  gap: 6px;
3941
- flex: none;
3942
- color: #a5adba;
3943
- font-size: 11px;
4151
+ color: var(--spotpatch-warning-text);
4152
+ font-size: 11.5px;
3944
4153
  white-space: nowrap;
3945
4154
  }
3946
4155
  .spotpatch-context-state::before {
3947
4156
  width: 6px;
3948
4157
  height: 6px;
3949
- border-radius: 999px;
3950
- background: #f59e0b;
4158
+ border-radius: 50%;
4159
+ background: var(--spotpatch-warning);
3951
4160
  content: "";
3952
4161
  }
4162
+ .spotpatch-context-state[data-state="loading"]::before {
4163
+ animation: spotpatch-dot-breathe 1.4s ease-in-out infinite;
4164
+ }
3953
4165
  .spotpatch-context-state[data-state="ready"],
3954
- .spotpatch-editor-feedback[data-state="success"] { color: #9fe3c4; }
4166
+ .spotpatch-editor-feedback[data-state="success"] { color: var(--spotpatch-success-text); }
3955
4167
  .spotpatch-context-state[data-state="ready"]::before,
3956
- .spotpatch-editor-feedback[data-state="success"]::before { background: #34d399; }
4168
+ .spotpatch-editor-feedback[data-state="success"]::before { background: var(--spotpatch-success); }
3957
4169
  .spotpatch-context-state[data-state="warning"],
3958
- .spotpatch-editor-feedback[data-state="error"] { color: #fecaca; }
4170
+ .spotpatch-editor-feedback[data-state="error"] { color: var(--spotpatch-danger-text); }
3959
4171
  .spotpatch-context-state[data-state="warning"]::before,
3960
- .spotpatch-editor-feedback[data-state="error"]::before { background: #fb7185; }
4172
+ .spotpatch-editor-feedback[data-state="error"]::before { background: var(--spotpatch-danger); }
4173
+ @keyframes spotpatch-dot-breathe {
4174
+ 50% { opacity: .35; }
4175
+ }
4176
+
3961
4177
  .spotpatch-body {
3962
4178
  min-height: 0;
3963
4179
  overflow: auto;
3964
- padding: 0 18px 14px;
3965
- scrollbar-color: rgb(100 116 139 / 50%) transparent;
3966
- scrollbar-width: thin;
3967
- }
3968
- .spotpatch-targets {
3969
- margin: 0;
4180
+ overscroll-behavior: contain;
4181
+ padding: 0 18px 16px;
3970
4182
  }
3971
4183
  .spotpatch-targets-heading {
3972
4184
  display: flex;
@@ -3974,71 +4186,73 @@ function createStyles(document) {
3974
4186
  justify-content: space-between;
3975
4187
  gap: 10px;
3976
4188
  margin-bottom: 8px;
3977
- color: var(--spotpatch-text-secondary);
4189
+ color: var(--spotpatch-text-muted);
3978
4190
  font-size: 11px;
3979
- font-weight: 650;
3980
- letter-spacing: .04em;
4191
+ font-weight: 600;
4192
+ letter-spacing: .06em;
3981
4193
  text-transform: uppercase;
3982
4194
  }
3983
4195
  .spotpatch-targets-meta {
3984
4196
  display: flex;
4197
+ min-width: 0;
3985
4198
  align-items: center;
3986
4199
  gap: 8px;
3987
- min-width: 0;
3988
4200
  letter-spacing: 0;
3989
4201
  text-transform: none;
3990
4202
  }
3991
- .spotpatch-target-complete { color: var(--spotpatch-text-muted); font-size: 11px; font-weight: 560; }
3992
- .spotpatch-target-budget {
3993
- color: var(--spotpatch-text-muted);
3994
- font: 550 10.5px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace;
3995
- }
4203
+ .spotpatch-target-budget { font: 500 11px/1.4 var(--spotpatch-font-mono); }
3996
4204
  .spotpatch-target-budget[data-state="ready"] { display: none; }
3997
- .spotpatch-target-budget[data-state="over"] { color: #fda4af; }
4205
+ .spotpatch-target-budget[data-state="over"] { color: var(--spotpatch-danger-text); }
3998
4206
  .spotpatch-target-count {
3999
4207
  margin-left: auto;
4000
- border-radius: 999px;
4001
- padding: 3px 8px;
4002
4208
  color: var(--spotpatch-text-muted);
4003
- font: 600 10.5px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace;
4209
+ font: 500 11px/1.4 var(--spotpatch-font-mono);
4004
4210
  }
4005
4211
  .spotpatch-target-progress {
4006
- height: 3px;
4007
- margin-bottom: 13px;
4212
+ height: 2px;
4213
+ margin-bottom: 12px;
4008
4214
  overflow: hidden;
4009
- border-radius: 999px;
4215
+ border-radius: var(--spotpatch-radius-pill);
4010
4216
  background: var(--spotpatch-border-subtle);
4011
4217
  }
4012
4218
  .spotpatch-target-progress-fill {
4013
4219
  width: 0;
4014
4220
  height: 100%;
4015
4221
  border-radius: inherit;
4016
- background: linear-gradient(90deg, var(--spotpatch-accent), var(--spotpatch-accent-cyan));
4017
- transition: width 180ms ease;
4222
+ background: var(--spotpatch-brand-line);
4223
+ transition: width var(--spotpatch-duration-slow) var(--spotpatch-ease-out);
4018
4224
  }
4019
4225
  .spotpatch-target-list {
4020
4226
  display: grid;
4021
4227
  gap: 8px;
4022
4228
  max-height: min(340px, 48vh);
4023
4229
  overflow: auto;
4024
- padding-right: 2px;
4230
+ padding: 2px;
4231
+ margin: -2px;
4025
4232
  }
4233
+
4026
4234
  .spotpatch-target-item {
4027
4235
  overflow: hidden;
4028
4236
  border: 1px solid var(--spotpatch-border-subtle);
4029
4237
  border-radius: var(--spotpatch-radius-card);
4030
4238
  background: var(--spotpatch-bg-raised);
4031
- transition: border-color 150ms ease, background 150ms ease;
4239
+ transition:
4240
+ border-color var(--spotpatch-duration-base) ease,
4241
+ background var(--spotpatch-duration-base) ease,
4242
+ box-shadow var(--spotpatch-duration-base) ease;
4032
4243
  }
4033
4244
  .spotpatch-target-item[data-active="true"] {
4034
- border-color: rgb(139 123 255 / 34%);
4245
+ border-color: var(--spotpatch-accent-line);
4035
4246
  background: var(--spotpatch-bg-active);
4036
- box-shadow: 0 0 0 3px rgb(139 123 255 / 10%);
4247
+ box-shadow: 0 0 0 3px var(--spotpatch-accent-tint);
4248
+ }
4249
+ .spotpatch-target-item[data-entering="true"] {
4250
+ animation: spotpatch-enter var(--spotpatch-duration-slow) var(--spotpatch-ease-out) both;
4037
4251
  }
4038
4252
  .spotpatch-target-summary {
4039
4253
  display: grid;
4040
- grid-template-columns: minmax(0, 1fr) 28px 28px;
4041
- align-items: stretch;
4254
+ grid-template-columns: minmax(0, 1fr) 30px 30px;
4255
+ align-items: center;
4042
4256
  gap: 2px;
4043
4257
  padding: 4px;
4044
4258
  }
@@ -4046,27 +4260,31 @@ function createStyles(document) {
4046
4260
  display: grid;
4047
4261
  grid-template-columns: 24px minmax(0, 1fr) auto;
4048
4262
  align-items: center;
4049
- gap: 9px;
4263
+ gap: 10px;
4050
4264
  min-width: 0;
4051
4265
  border: 0;
4052
- border-radius: 8px;
4053
- padding: 8px;
4266
+ border-radius: var(--spotpatch-radius-sm);
4267
+ padding: 7px 8px;
4054
4268
  color: inherit;
4055
4269
  background: transparent;
4056
4270
  cursor: pointer;
4057
4271
  text-align: left;
4272
+ transition: background var(--spotpatch-duration-fast) ease;
4058
4273
  }
4059
- .spotpatch-target-select:hover { background: rgb(255 255 255 / 3.5%); }
4274
+ .spotpatch-target-select:hover { background: var(--spotpatch-hover); }
4060
4275
  .spotpatch-target-index {
4061
4276
  display: inline-grid;
4062
- width: 22px;
4063
- height: 22px;
4277
+ width: 24px;
4278
+ height: 24px;
4064
4279
  place-items: center;
4065
- border: 1px solid rgb(68 202 224 / 25%);
4066
- border-radius: 6px;
4280
+ border-radius: var(--spotpatch-radius-xs);
4067
4281
  color: var(--spotpatch-text-secondary);
4068
- background: var(--spotpatch-bg);
4069
- font: 650 11px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
4282
+ background: var(--spotpatch-hover);
4283
+ font: 600 11px/1 var(--spotpatch-font-mono);
4284
+ }
4285
+ [data-active="true"] .spotpatch-target-index {
4286
+ color: var(--spotpatch-text-on-accent);
4287
+ background: var(--spotpatch-accent-strong);
4070
4288
  }
4071
4289
  .spotpatch-target-copy { min-width: 0; }
4072
4290
  .spotpatch-target-name,
@@ -4076,37 +4294,49 @@ function createStyles(document) {
4076
4294
  text-overflow: ellipsis;
4077
4295
  white-space: nowrap;
4078
4296
  }
4079
- .spotpatch-target-name { color: #f2f2f5; font-size: 13px; font-weight: 650; }
4080
- .spotpatch-target-source { margin-top: 1px; color: var(--spotpatch-text-muted); font: 500 10.5px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; }
4297
+ .spotpatch-target-name { font-size: 13px; font-weight: 620; }
4298
+ .spotpatch-target-source {
4299
+ margin-top: 1px;
4300
+ color: var(--spotpatch-text-muted);
4301
+ font: 500 11px/1.4 var(--spotpatch-font-mono);
4302
+ }
4081
4303
  .spotpatch-target-state {
4082
- border-radius: 999px;
4304
+ border-radius: var(--spotpatch-radius-pill);
4083
4305
  padding: 3px 8px;
4084
- color: #a7f3d0;
4085
- background: rgb(16 185 129 / 9%);
4086
- font-size: 10.5px;
4087
- font-weight: 650;
4306
+ color: var(--spotpatch-success-text);
4307
+ background: var(--spotpatch-success-tint);
4308
+ font-size: 11px;
4309
+ font-weight: 600;
4088
4310
  white-space: nowrap;
4089
4311
  }
4090
- .spotpatch-target-state[data-complete="false"] { color: #f5c97a; background: rgb(245 158 11 / 9%); }
4312
+ .spotpatch-target-state[data-complete="false"] {
4313
+ color: var(--spotpatch-warning-text);
4314
+ background: var(--spotpatch-warning-tint);
4315
+ }
4091
4316
  .spotpatch-target-open,
4092
4317
  .spotpatch-target-remove {
4093
4318
  display: inline-grid;
4094
- width: 28px;
4095
- height: 100%;
4096
- min-height: 34px;
4097
- padding: 0;
4319
+ width: 30px;
4320
+ height: 30px;
4098
4321
  place-items: center;
4099
- border: 1px solid transparent;
4100
- border-radius: 7px;
4101
- color: #7f899a;
4322
+ border: 0;
4323
+ border-radius: var(--spotpatch-radius-sm);
4324
+ padding: 0;
4325
+ color: var(--spotpatch-text-muted);
4102
4326
  background: transparent;
4103
4327
  cursor: pointer;
4104
- }
4105
- .spotpatch-target-open { color: #79d9e7; }
4106
- .spotpatch-target-open:hover:not(:disabled) { border-color: rgb(68 202 224 / 30%); color: #c8f7ff; background: rgb(8 145 178 / 11%); }
4107
- .spotpatch-target-remove:hover:not(:disabled) { border-color: rgb(251 113 133 / 24%); color: #fda4af; background: rgb(127 29 29 / 12%); }
4328
+ transition:
4329
+ color var(--spotpatch-duration-fast) ease,
4330
+ background var(--spotpatch-duration-fast) ease;
4331
+ }
4332
+ .spotpatch-target-open:hover:not(:disabled) { color: var(--spotpatch-cyan-text); background: var(--spotpatch-cyan-tint); }
4333
+ .spotpatch-target-remove:hover:not(:disabled) { color: var(--spotpatch-danger-text); background: var(--spotpatch-danger-tint); }
4334
+ .spotpatch-target-open:disabled,
4335
+ .spotpatch-target-remove:disabled { cursor: not-allowed; opacity: .35; }
4336
+
4108
4337
  .spotpatch-target-editor {
4109
- padding: 0 12px 12px;
4338
+ display: block;
4339
+ padding: 2px 12px 12px;
4110
4340
  }
4111
4341
  .spotpatch-target-editor-head {
4112
4342
  display: flex;
@@ -4115,179 +4345,178 @@ function createStyles(document) {
4115
4345
  gap: 12px;
4116
4346
  margin-bottom: 6px;
4117
4347
  }
4118
- .spotpatch-target-editor-label { color: var(--spotpatch-text-secondary); font-size: 11px; font-weight: 650; }
4119
- .spotpatch-target-editor-count { color: var(--spotpatch-text-muted); font: 500 10.5px/1.3 ui-monospace, SFMono-Regular, Menlo, monospace; }
4348
+ .spotpatch-target-editor-label { color: var(--spotpatch-text-secondary); font-size: 11.5px; font-weight: 600; }
4349
+ .spotpatch-target-editor-count { color: var(--spotpatch-text-muted); font: 500 11px/1.3 var(--spotpatch-font-mono); }
4120
4350
  .spotpatch-target-editor textarea {
4351
+ display: block;
4121
4352
  box-sizing: border-box;
4122
4353
  width: 100%;
4123
- min-height: 74px;
4354
+ min-height: 76px;
4124
4355
  resize: vertical;
4125
4356
  border: 1px solid var(--spotpatch-border);
4126
- border-radius: 7px;
4127
- padding: 9px 10px;
4128
- color: #f8fafc;
4129
- caret-color: #8b7cf7;
4357
+ border-radius: var(--spotpatch-radius-md);
4358
+ padding: 10px 12px;
4359
+ color: var(--spotpatch-text);
4360
+ caret-color: var(--spotpatch-accent-soft);
4130
4361
  background: var(--spotpatch-bg-input);
4131
- font-size: 12.5px;
4362
+ font-size: 13px;
4132
4363
  line-height: 1.55;
4133
4364
  outline: none;
4134
- transition: border-color 150ms ease, box-shadow 150ms ease, background 150ms ease;
4365
+ transition:
4366
+ border-color var(--spotpatch-duration-fast) ease,
4367
+ box-shadow var(--spotpatch-duration-fast) ease;
4135
4368
  }
4136
- .spotpatch-target-editor textarea::placeholder { color: #687284; }
4137
- .spotpatch-target-editor textarea:hover { border-color: rgb(139 124 247 / 34%); }
4369
+ .spotpatch-target-editor textarea::placeholder { color: var(--spotpatch-text-muted); }
4370
+ .spotpatch-target-editor textarea:hover { border-color: var(--spotpatch-border-strong); }
4138
4371
  .spotpatch-target-editor textarea:focus {
4139
- border-color: rgb(139 124 247 / 68%);
4140
- background: rgb(3 7 18 / 65%);
4141
- box-shadow: 0 0 0 2px rgb(109 93 246 / 10%);
4372
+ border-color: var(--spotpatch-accent-line);
4373
+ box-shadow: 0 0 0 3px var(--spotpatch-accent-tint);
4142
4374
  }
4375
+
4143
4376
  .spotpatch-diagnostics {
4144
4377
  margin-top: 10px;
4145
4378
  overflow: hidden;
4146
- border: 1px solid rgb(255 255 255 / 8%);
4147
- border-radius: 9px;
4148
- background: rgb(255 255 255 / 2.5%);
4379
+ border: 1px solid var(--spotpatch-border-subtle);
4380
+ border-radius: var(--spotpatch-radius-md);
4149
4381
  }
4150
4382
  .spotpatch-diagnostics > summary {
4151
4383
  display: flex;
4152
4384
  align-items: center;
4153
4385
  gap: 8px;
4154
- padding: 9px 11px;
4155
- color: #bfc5d0;
4386
+ padding: 9px 12px;
4387
+ color: var(--spotpatch-text-secondary);
4156
4388
  cursor: pointer;
4157
- font-size: 11px;
4158
- font-weight: 650;
4389
+ font-size: 11.5px;
4390
+ font-weight: 600;
4159
4391
  list-style: none;
4160
4392
  user-select: none;
4161
4393
  }
4162
4394
  .spotpatch-diagnostics > summary::-webkit-details-marker { display: none; }
4163
4395
  .spotpatch-diagnostics > summary::before {
4164
- color: #778193;
4396
+ color: var(--spotpatch-text-muted);
4165
4397
  content: "›";
4166
4398
  font-size: 16px;
4167
4399
  line-height: 1;
4168
- transform: rotate(0deg);
4169
- transition: transform 150ms ease;
4400
+ transition: transform var(--spotpatch-duration-base) var(--spotpatch-ease-out);
4170
4401
  }
4171
4402
  .spotpatch-diagnostics[open] > summary::before { transform: rotate(90deg); }
4172
4403
  .spotpatch-source-peek {
4173
4404
  min-width: 0;
4174
- overflow: hidden;
4175
4405
  margin-left: auto;
4176
- color: #64748b;
4177
- font: 500 10.5px/1.3 ui-monospace, SFMono-Regular, Menlo, monospace;
4406
+ overflow: hidden;
4407
+ color: var(--spotpatch-text-muted);
4408
+ font: 500 11px/1.3 var(--spotpatch-font-mono);
4178
4409
  text-overflow: ellipsis;
4179
4410
  white-space: nowrap;
4180
4411
  }
4181
- .spotpatch-summary {
4182
- max-height: 170px;
4412
+ .spotpatch-summary,
4413
+ .spotpatch-prompt {
4183
4414
  margin: 0;
4184
4415
  overflow: auto;
4185
- border-top: 1px solid rgb(255 255 255 / 7%);
4186
- padding: 10px 11px 11px;
4187
- color: #9ca5b5;
4188
- font: 10.5px/1.55 ui-monospace, SFMono-Regular, Menlo, monospace;
4189
4416
  overflow-wrap: anywhere;
4190
4417
  white-space: pre-wrap;
4191
4418
  user-select: text;
4419
+ font: 11px/1.6 var(--spotpatch-font-mono);
4420
+ }
4421
+ .spotpatch-summary {
4422
+ max-height: 170px;
4423
+ border-top: 1px solid var(--spotpatch-border-subtle);
4424
+ padding: 10px 12px 12px;
4425
+ color: var(--spotpatch-text-secondary);
4192
4426
  }
4193
4427
  .spotpatch-prompt {
4194
4428
  max-height: min(500px, 60vh);
4195
- margin: 0;
4196
- overflow: auto;
4197
- border: 1px solid rgb(255 255 255 / 9%);
4198
- border-radius: 9px;
4199
- padding: 11px;
4200
- color: #d8ddeb;
4201
- background: rgb(3 7 18 / 55%);
4202
- font: 11px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace;
4203
- overflow-wrap: anywhere;
4204
- white-space: pre-wrap;
4205
- user-select: text;
4429
+ border: 1px solid var(--spotpatch-border-subtle);
4430
+ border-radius: var(--spotpatch-radius-md);
4431
+ padding: 12px;
4432
+ color: var(--spotpatch-text);
4433
+ background: var(--spotpatch-bg-input);
4206
4434
  }
4435
+
4207
4436
  .spotpatch-actions {
4208
4437
  display: grid;
4209
4438
  gap: 8px;
4210
- padding: 10px 18px 14px;
4211
- border-top: 1px solid rgb(255 255 255 / 8%);
4212
- background: rgb(8 8 12 / 86%);
4213
- }
4214
- .spotpatch-editor-feedback {
4215
- white-space: normal;
4439
+ border-top: 1px solid var(--spotpatch-border-subtle);
4440
+ padding: 12px 18px 16px;
4216
4441
  }
4442
+ .spotpatch-editor-feedback { white-space: normal; }
4217
4443
  .spotpatch-secondary-actions,
4218
- .spotpatch-primary-actions {
4219
- display: flex;
4220
- align-items: center;
4221
- gap: 7px;
4222
- }
4223
- .spotpatch-secondary-actions { min-height: 30px; }
4444
+ .spotpatch-primary-actions { display: flex; align-items: center; gap: 8px; }
4445
+ .spotpatch-secondary-actions { gap: 2px; margin: 0 -8px; }
4224
4446
  .spotpatch-actions button {
4225
4447
  display: inline-flex;
4226
- min-height: 34px;
4448
+ min-height: 36px;
4227
4449
  align-items: center;
4228
4450
  justify-content: center;
4229
- border: 1px solid rgb(255 255 255 / 10%);
4230
- border-radius: 9px;
4231
- padding: 7px 11px;
4232
- color: var(--spotpatch-text-secondary);
4233
- background: rgb(255 255 255 / 4%);
4451
+ gap: 6px;
4452
+ border: 1px solid var(--spotpatch-border);
4453
+ border-radius: var(--spotpatch-radius-md);
4454
+ padding: 0 12px;
4455
+ color: var(--spotpatch-text);
4456
+ background: var(--spotpatch-bg-raised);
4234
4457
  cursor: pointer;
4235
- font-size: 12px;
4236
- font-weight: 650;
4237
- transition: border-color 150ms ease, box-shadow 150ms ease, color 150ms ease, transform 150ms ease;
4458
+ font-size: 12.5px;
4459
+ font-weight: 600;
4460
+ white-space: nowrap;
4461
+ transition:
4462
+ border-color var(--spotpatch-duration-fast) ease,
4463
+ background var(--spotpatch-duration-fast) ease,
4464
+ box-shadow var(--spotpatch-duration-base) ease,
4465
+ transform var(--spotpatch-duration-fast) ease;
4238
4466
  }
4239
4467
  .spotpatch-actions button:hover:not(:disabled) {
4240
- border-color: rgb(139 124 247 / 45%);
4241
- color: #fff;
4242
- transform: translateY(-1px);
4468
+ border-color: var(--spotpatch-border-strong);
4469
+ background: var(--spotpatch-bg-active);
4243
4470
  }
4471
+ .spotpatch-actions button:active:not(:disabled) { transform: scale(.98); }
4244
4472
  .spotpatch-actions .spotpatch-primary {
4245
- min-width: 138px;
4473
+ min-width: 140px;
4246
4474
  flex: 1;
4247
4475
  border-color: transparent;
4248
4476
  color: var(--spotpatch-text-on-accent);
4249
- background: linear-gradient(135deg, var(--spotpatch-accent), var(--spotpatch-accent-strong));
4250
- box-shadow: 0 8px 20px -8px rgb(139 123 255 / 55%);
4477
+ background: var(--spotpatch-primary-fill);
4478
+ box-shadow: var(--spotpatch-shadow-accent), var(--spotpatch-shadow-inset);
4479
+ }
4480
+ .spotpatch-actions .spotpatch-primary:hover:not(:disabled) {
4481
+ border-color: transparent;
4482
+ background: var(--spotpatch-primary-fill);
4483
+ filter: brightness(1.1);
4251
4484
  }
4252
- .spotpatch-actions .spotpatch-primary:hover:not(:disabled) { color: var(--spotpatch-text-on-accent); filter: brightness(1.08); }
4253
- .spotpatch-actions .spotpatch-primary::after { margin-left: 8px; content: "↗"; font-size: 12px; }
4485
+ .spotpatch-actions .spotpatch-primary::after { content: "↗"; font-size: 12px; opacity: .8; }
4254
4486
  .spotpatch-actions .spotpatch-secondary-action {
4255
4487
  min-height: 30px;
4256
- border-style: dashed;
4257
- padding: 5px 10px;
4258
- color: var(--spotpatch-text-muted);
4488
+ border-color: transparent;
4489
+ padding: 0 8px;
4490
+ color: var(--spotpatch-text-secondary);
4259
4491
  background: transparent;
4260
- font-size: 11px;
4492
+ font-size: 12px;
4493
+ font-weight: 550;
4494
+ }
4495
+ .spotpatch-actions .spotpatch-secondary-action:hover:not(:disabled) {
4496
+ border-color: transparent;
4497
+ color: var(--spotpatch-text);
4498
+ background: var(--spotpatch-hover);
4261
4499
  }
4262
4500
  .spotpatch-actions .spotpatch-icon-action {
4263
- width: 34px;
4264
- min-width: 34px;
4501
+ width: 36px;
4502
+ min-width: 36px;
4265
4503
  padding: 0;
4266
4504
  font-size: 0;
4267
4505
  }
4268
4506
  .spotpatch-actions .spotpatch-icon-action::before {
4269
4507
  color: var(--spotpatch-text-secondary);
4270
4508
  content: attr(data-compact-icon);
4271
- font-size: 18px;
4509
+ font-size: 17px;
4272
4510
  font-weight: 400;
4273
4511
  line-height: 1;
4274
4512
  }
4275
- .spotpatch-actions button:disabled { cursor: not-allowed; opacity: .4; transform: none; }
4276
- .spotpatch-actions button:focus-visible,
4277
- .spotpatch-repository:focus-visible,
4278
- .spotpatch-target-open:focus-visible,
4279
- .spotpatch-target-remove:focus-visible,
4280
- .spotpatch-close:focus-visible,
4281
- .spotpatch-reset-position:focus-visible,
4282
- .spotpatch-trigger:focus-visible,
4283
- .spotpatch-target-select:focus-visible,
4284
- .spotpatch-target-editor textarea:focus-visible,
4285
- .spotpatch-locale:focus-visible,
4286
- .spotpatch-prompt:focus-visible,
4287
- .spotpatch-diagnostics > summary:focus-visible {
4288
- outline: 2px solid #8b7cf7;
4289
- outline-offset: 2px;
4513
+ .spotpatch-actions button:disabled {
4514
+ box-shadow: none;
4515
+ cursor: not-allowed;
4516
+ filter: none;
4517
+ opacity: .4;
4290
4518
  }
4519
+
4291
4520
  .spotpatch-live {
4292
4521
  position: absolute;
4293
4522
  width: 1px;
@@ -4297,16 +4526,11 @@ function createStyles(document) {
4297
4526
  clip-path: inset(50%);
4298
4527
  white-space: nowrap;
4299
4528
  }
4300
- @media (prefers-reduced-motion: reduce) {
4301
- .spotpatch-trigger,
4302
- .spotpatch-actions button,
4303
- .spotpatch-diagnostics > summary::before { transition: none; }
4304
- }
4305
4529
  @media (max-width: 520px) {
4306
4530
  .spotpatch-dialog { width: calc(100vw - 16px); }
4307
4531
  .spotpatch-shell { max-height: calc(100dvh - 16px); }
4308
- .spotpatch-header, .spotpatch-body { padding-left: 14px; padding-right: 14px; }
4309
- .spotpatch-brand-row { margin-right: -14px; margin-left: -14px; padding-right: 14px; padding-left: 14px; }
4532
+ .spotpatch-header, .spotpatch-body { padding-right: 14px; padding-left: 14px; }
4533
+ .spotpatch-brand-row { margin-right: -14px; margin-left: -14px; padding-right: 10px; padding-left: 14px; }
4310
4534
  .spotpatch-actions { padding-right: 14px; padding-left: 14px; }
4311
4535
  .spotpatch-target-select { grid-template-columns: 24px minmax(0, 1fr); }
4312
4536
  .spotpatch-target-state { display: none; }
@@ -4316,6 +4540,19 @@ function createStyles(document) {
4316
4540
  `;
4317
4541
  return style;
4318
4542
  }
4543
+ function createResetPositionIcon(document) {
4544
+ const namespace = "http://www.w3.org/2000/svg";
4545
+ const icon = document.createElementNS(namespace, "svg");
4546
+ icon.setAttribute("viewBox", "0 0 16 16");
4547
+ icon.setAttribute("aria-hidden", "true");
4548
+ const path = document.createElementNS(namespace, "path");
4549
+ path.setAttribute(
4550
+ "d",
4551
+ "M8 1.5v3M8 11.5v3M1.5 8h3M11.5 8h3M11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
4552
+ );
4553
+ icon.append(path);
4554
+ return icon;
4555
+ }
4319
4556
  function summaryLine(summary, prefix) {
4320
4557
  const line = summary.split("\n").find((candidate) => candidate.startsWith(`${prefix}: `));
4321
4558
  return line?.slice(prefix.length + 2).trim();
@@ -4442,11 +4679,12 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4442
4679
  headerControls.className = "spotpatch-header-controls";
4443
4680
  const repositoryLink = createMarkedElement(document, "a");
4444
4681
  repositoryLink.className = "spotpatch-repository";
4445
- repositoryLink.href = import_shared7.SPOTPATCH_REPOSITORY_URL;
4682
+ repositoryLink.href = import_shared12.SPOTPATCH_REPOSITORY_URL;
4446
4683
  repositoryLink.target = "_blank";
4447
4684
  repositoryLink.rel = "noopener noreferrer";
4448
4685
  const localeButton = createButton(document, "", "spotpatch-locale");
4449
- const resetPositionButton = createButton(document, "⌖", "spotpatch-reset-position");
4686
+ const resetPositionButton = createButton(document, "", "spotpatch-reset-position");
4687
+ resetPositionButton.append(createResetPositionIcon(document));
4450
4688
  const closeButton = createButton(document, "×", "spotpatch-close");
4451
4689
  headerControls.append(repositoryLink, localeButton, resetPositionButton, closeButton);
4452
4690
  brandRow.append(brand, headerControls);
@@ -4673,6 +4911,8 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4673
4911
  let editingEnabled = true;
4674
4912
  let currentTargets = [];
4675
4913
  let currentMaximum = 0;
4914
+ let renderedTargetIds = /* @__PURE__ */ new Set();
4915
+ let renderedHighlightIds = /* @__PURE__ */ new Set();
4676
4916
  let currentEditorFeedbackState = "idle";
4677
4917
  let currentDataFlowState = Object.freeze({
4678
4918
  component: Object.freeze({
@@ -4951,6 +5191,9 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4951
5191
  requestFloatingSurfaceLayout();
4952
5192
  }
4953
5193
  function statusText(target2) {
5194
+ if (target2.instanceState !== void 0 && target2.instanceState !== "captured") {
5195
+ return messages.summary.instanceStates[target2.instanceState];
5196
+ }
4954
5197
  if (target2.status === "ready") {
4955
5198
  return messages.targets.statusReady;
4956
5199
  }
@@ -4977,6 +5220,8 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4977
5220
  const selectionEnd = focusedInstruction?.selectionEnd;
4978
5221
  currentTargets = targets.map((target2) => Object.freeze({ ...target2 }));
4979
5222
  currentMaximum = maximum;
5223
+ const previousTargetIds = renderedTargetIds;
5224
+ renderedTargetIds = new Set(targets.map((target2) => target2.id));
4980
5225
  targetList.replaceChildren();
4981
5226
  const completeCount = targets.filter(
4982
5227
  (target2) => target2.instruction.trim().length > 0
@@ -4991,14 +5236,14 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4991
5236
  completeCount,
4992
5237
  targets.length
4993
5238
  );
4994
- const instructionLimitExceeded = instructionCharacters > import_shared7.MAX_ANNOTATION_INSTRUCTION_CHARACTERS;
5239
+ const instructionLimitExceeded = instructionCharacters > import_shared12.MAX_ANNOTATION_INSTRUCTION_CHARACTERS;
4995
5240
  targetBudget.dataset.state = instructionLimitExceeded ? "over" : "ready";
4996
5241
  targetBudget.textContent = instructionLimitExceeded ? messages.targets.instructionBudgetExceeded(
4997
5242
  instructionCharacters,
4998
- import_shared7.MAX_ANNOTATION_INSTRUCTION_CHARACTERS
5243
+ import_shared12.MAX_ANNOTATION_INSTRUCTION_CHARACTERS
4999
5244
  ) : messages.targets.instructionBudget(
5000
5245
  instructionCharacters,
5001
- import_shared7.MAX_ANNOTATION_INSTRUCTION_CHARACTERS
5246
+ import_shared12.MAX_ANNOTATION_INSTRUCTION_CHARACTERS
5002
5247
  );
5003
5248
  addTargetButton.disabled = !editingEnabled || targets.length >= maximum;
5004
5249
  addTargetButton.title = targets.length >= maximum ? messages.targets.limitTitle(maximum) : messages.targets.addTitle;
@@ -5009,6 +5254,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
5009
5254
  item.dataset.active = String(target2.active);
5010
5255
  item.dataset.status = target2.status;
5011
5256
  item.dataset.targetId = target2.id;
5257
+ item.dataset.entering = String(!previousTargetIds.has(target2.id));
5012
5258
  const targetSummary = createMarkedElement(document, "div");
5013
5259
  targetSummary.className = "spotpatch-target-summary";
5014
5260
  const select = createButton(document, "", "spotpatch-target-select");
@@ -5057,12 +5303,12 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
5057
5303
  characterCount.className = "spotpatch-target-editor-count";
5058
5304
  characterCount.textContent = messages.targets.instructionCount(
5059
5305
  target2.instruction.length,
5060
- import_shared7.MAX_TARGET_INSTRUCTION_CHARACTERS
5306
+ import_shared12.MAX_TARGET_INSTRUCTION_CHARACTERS
5061
5307
  );
5062
5308
  editorHead.append(editorLabel, characterCount);
5063
5309
  const input = createMarkedElement(document, "textarea");
5064
5310
  input.rows = 4;
5065
- input.maxLength = import_shared7.MAX_TARGET_INSTRUCTION_CHARACTERS;
5311
+ input.maxLength = import_shared12.MAX_TARGET_INSTRUCTION_CHARACTERS;
5066
5312
  input.value = target2.instruction;
5067
5313
  input.placeholder = messages.targets.instructionPlaceholder;
5068
5314
  input.disabled = !editingEnabled;
@@ -5105,7 +5351,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
5105
5351
  if (count !== null) {
5106
5352
  count.textContent = messages.targets.instructionCount(
5107
5353
  instruction.length,
5108
- import_shared7.MAX_TARGET_INSTRUCTION_CHARACTERS
5354
+ import_shared12.MAX_TARGET_INSTRUCTION_CHARACTERS
5109
5355
  );
5110
5356
  }
5111
5357
  const completeCount = currentTargets.filter(
@@ -5120,22 +5366,25 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
5120
5366
  (total, target2) => total + target2.instruction.trim().length,
5121
5367
  0
5122
5368
  );
5123
- const instructionLimitExceeded = instructionCharacters > import_shared7.MAX_ANNOTATION_INSTRUCTION_CHARACTERS;
5369
+ const instructionLimitExceeded = instructionCharacters > import_shared12.MAX_ANNOTATION_INSTRUCTION_CHARACTERS;
5124
5370
  targetBudget.dataset.state = instructionLimitExceeded ? "over" : "ready";
5125
5371
  targetBudget.textContent = instructionLimitExceeded ? messages.targets.instructionBudgetExceeded(
5126
5372
  instructionCharacters,
5127
- import_shared7.MAX_ANNOTATION_INSTRUCTION_CHARACTERS
5373
+ import_shared12.MAX_ANNOTATION_INSTRUCTION_CHARACTERS
5128
5374
  ) : messages.targets.instructionBudget(
5129
5375
  instructionCharacters,
5130
- import_shared7.MAX_ANNOTATION_INSTRUCTION_CHARACTERS
5376
+ import_shared12.MAX_ANNOTATION_INSTRUCTION_CHARACTERS
5131
5377
  );
5132
5378
  }
5133
5379
  function showSelectionHighlights(targets) {
5380
+ const previousHighlightIds = renderedHighlightIds;
5381
+ renderedHighlightIds = new Set(targets.map((target2) => target2.id));
5134
5382
  selectionHighlights.replaceChildren();
5135
5383
  for (const [index, target2] of targets.entries()) {
5136
5384
  const box = createMarkedElement(document, "div");
5137
5385
  box.className = "spotpatch-selection-highlight";
5138
5386
  box.dataset.targetId = target2.id;
5387
+ box.dataset.entering = String(!previousHighlightIds.has(target2.id));
5139
5388
  box.dataset.active = String(target2.active);
5140
5389
  box.style.transform = `translate(${String(target2.rect.x)}px, ${String(target2.rect.y)}px)`;
5141
5390
  box.style.width = `${String(target2.rect.width)}px`;
@@ -5245,7 +5494,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
5245
5494
  targetBudget.dataset.state = "ready";
5246
5495
  targetBudget.textContent = messages.targets.instructionBudget(
5247
5496
  0,
5248
- import_shared7.MAX_ANNOTATION_INSTRUCTION_CHARACTERS
5497
+ import_shared12.MAX_ANNOTATION_INSTRUCTION_CHARACTERS
5249
5498
  );
5250
5499
  targetLabel.textContent = messages.context.selectedElement;
5251
5500
  }
@@ -5585,6 +5834,11 @@ function createSelectionSummary(input, messages) {
5585
5834
  `${messages.confidence}: ${input.resolution.source.confidence} (${messages.confidenceLabels[input.resolution.source.confidence]})`,
5586
5835
  `${messages.origin}: ${input.resolution.source.origin}`
5587
5836
  ];
5837
+ if (input.instance !== void 0) {
5838
+ lines.push(
5839
+ `${messages.instance}: ${messages.instanceStates[input.instance.state]}`
5840
+ );
5841
+ }
5588
5842
  if (input.resolution.react.componentName !== void 0) {
5589
5843
  lines.push(`${messages.component}: ${input.resolution.react.componentName}`);
5590
5844
  }
@@ -5618,7 +5872,7 @@ function createSelectionSummary(input, messages) {
5618
5872
  }
5619
5873
 
5620
5874
  // src/controller/agent-workflow.ts
5621
- var import_shared8 = require("@spotpatch/shared");
5875
+ var import_shared13 = require("@spotpatch/shared");
5622
5876
  function capabilityKey(providerProfileId, modelProfileId) {
5623
5877
  return `${providerProfileId}:${modelProfileId}`;
5624
5878
  }
@@ -5656,7 +5910,7 @@ function activityFromEvent(event) {
5656
5910
  return void 0;
5657
5911
  }
5658
5912
  function createAgentWorkflow(options) {
5659
- const errorCode = (error) => runtimeApiErrorCode(error) ?? import_shared8.ERROR_CODES.INTERNAL_ERROR;
5913
+ const errorCode = (error) => runtimeApiErrorCode(error) ?? import_shared13.ERROR_CODES.INTERNAL_ERROR;
5660
5914
  const errorMessage = (error) => options.view.messages().errors[errorCode(error)];
5661
5915
  const capabilities = /* @__PURE__ */ new Map();
5662
5916
  const providerConsents = /* @__PURE__ */ new Set();
@@ -5742,7 +5996,7 @@ function createAgentWorkflow(options) {
5742
5996
  }
5743
5997
  if (capability.state !== "agent-ready") {
5744
5998
  throw new RuntimeApiError(
5745
- capability.errorCode ?? import_shared8.ERROR_CODES.MODEL_TOOL_CALL_UNSUPPORTED
5999
+ capability.errorCode ?? import_shared13.ERROR_CODES.MODEL_TOOL_CALL_UNSUPPORTED
5746
6000
  );
5747
6001
  }
5748
6002
  capabilities.set(key, capability);
@@ -5936,11 +6190,11 @@ function createAgentWorkflow(options) {
5936
6190
  }
5937
6191
  if (health.state === "blocked") {
5938
6192
  throw new RuntimeApiError(
5939
- health.errorCode ?? import_shared8.ERROR_CODES.WORKTREE_LOCAL_CHANGES_UNSUPPORTED
6193
+ health.errorCode ?? import_shared13.ERROR_CODES.WORKTREE_LOCAL_CHANGES_UNSUPPORTED
5940
6194
  );
5941
6195
  }
5942
6196
  if (health.state === "consent-required" && !options.view.agentWorkspaceConsentGranted()) {
5943
- throw new RuntimeApiError(import_shared8.ERROR_CODES.WORKTREE_DIRTY);
6197
+ throw new RuntimeApiError(import_shared13.ERROR_CODES.WORKTREE_DIRTY);
5944
6198
  }
5945
6199
  const created = await options.api.createAgentJob({
5946
6200
  annotation,
@@ -6041,7 +6295,7 @@ function sourceLabel(target2, unavailable) {
6041
6295
  return `${path}${line === void 0 ? "" : `:${String(line)}`}${column === void 0 ? "" : `:${String(column)}`}`;
6042
6296
  }
6043
6297
  function targetStatus(target2) {
6044
- if (target2.apiStatus === "failed" || target2.collectionStatus === "failed") {
6298
+ if (target2.apiStatus === "failed" || target2.collectionStatus === "failed" || target2.elementContext?.instance !== void 0 && target2.elementContext.instance.state !== "captured") {
6045
6299
  return "warning";
6046
6300
  }
6047
6301
  if (target2.apiStatus === "loading" || target2.collectionStatus === "loading") {
@@ -6084,6 +6338,7 @@ function createController(config, dependencies = {}) {
6084
6338
  const now = dependencies.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
6085
6339
  const selectionSession = dependencies.selectionSession ?? createSelectionSession(browser.window, config.sessionId, config.maxTargets);
6086
6340
  const restoredSelection = selectionSession.load();
6341
+ const instanceNamespace = createBrowserAnnotationId(browser.window);
6087
6342
  const sourceResolver = createSourceResolver({
6088
6343
  adapter: dependencies.reactAdapter ?? (0, import_react_adapter.createReact18Adapter)({
6089
6344
  ...config.dataFlow.enabled ? {
@@ -6115,7 +6370,8 @@ function createController(config, dependencies = {}) {
6115
6370
  dataFlowReport: void 0,
6116
6371
  dataFlowStatus: "idle",
6117
6372
  element: void 0,
6118
- elementContext: target2.element,
6373
+ instanceScope: void 0,
6374
+ elementContext: withInstanceState(target2.element, "restored"),
6119
6375
  instruction: target2.instruction,
6120
6376
  marker,
6121
6377
  page: target2.page,
@@ -6149,14 +6405,14 @@ function createController(config, dependencies = {}) {
6149
6405
  const react2 = target2.resolution.react;
6150
6406
  if (react2.componentSourceId !== void 0 && react2.sourceVersion !== void 0) {
6151
6407
  return Object.freeze({
6152
- schemaVersion: import_shared9.DATA_FLOW_SCHEMA_VERSION,
6408
+ schemaVersion: import_shared14.DATA_FLOW_SCHEMA_VERSION,
6153
6409
  componentSourceId: react2.componentSourceId,
6154
6410
  sourceVersion: react2.sourceVersion
6155
6411
  });
6156
6412
  }
6157
6413
  const marker = target2.marker;
6158
6414
  return marker === void 0 ? void 0 : Object.freeze({
6159
- schemaVersion: import_shared9.DATA_FLOW_SCHEMA_VERSION,
6415
+ schemaVersion: import_shared14.DATA_FLOW_SCHEMA_VERSION,
6160
6416
  fileId: marker.fileId,
6161
6417
  line: marker.line,
6162
6418
  column: marker.column
@@ -6204,7 +6460,7 @@ function createController(config, dependencies = {}) {
6204
6460
  const [componentResult, pageResult] = await Promise.allSettled([
6205
6461
  currentRequest === void 0 ? Promise.resolve(void 0) : api.componentDataFlowReport(currentRequest),
6206
6462
  pageTargets.length === 0 ? Promise.resolve(void 0) : api.pageDataFlowReport({
6207
- schemaVersion: import_shared9.DATA_FLOW_SCHEMA_VERSION,
6463
+ schemaVersion: import_shared14.DATA_FLOW_SCHEMA_VERSION,
6208
6464
  targets: pageTargets
6209
6465
  })
6210
6466
  ]);
@@ -6269,11 +6525,12 @@ function createController(config, dependencies = {}) {
6269
6525
  (total, target2) => total + target2.instruction.trim().length,
6270
6526
  0
6271
6527
  );
6272
- return targets.length > 0 && instructionCharacters <= import_shared9.MAX_ANNOTATION_INSTRUCTION_CHARACTERS && targets.every(
6528
+ return targets.length > 0 && instructionCharacters <= import_shared14.MAX_ANNOTATION_INSTRUCTION_CHARACTERS && targets.every(
6273
6529
  (target2) => target2.instruction.trim().length > 0 && target2.elementContext !== void 0 && target2.styles !== void 0 && target2.apiStatus !== "loading"
6274
6530
  );
6275
6531
  }
6276
6532
  function selectedAskSelection() {
6533
+ refreshInstanceStates(mutationObserver?.takeRecords() ?? []);
6277
6534
  const snapshots = targets.flatMap((target2) => {
6278
6535
  const snapshot = snapshotTarget(target2);
6279
6536
  return snapshot === void 0 ? [] : [snapshot];
@@ -6292,6 +6549,7 @@ function createController(config, dependencies = {}) {
6292
6549
  const summary = createSelectionSummary(
6293
6550
  {
6294
6551
  resolution: target2.resolution,
6552
+ ...target2.elementContext?.instance === void 0 ? {} : { instance: target2.elementContext.instance },
6295
6553
  ...target2.code === void 0 ? {} : { code: target2.code },
6296
6554
  ...target2.styles === void 0 ? {} : { styles: target2.styles },
6297
6555
  apiStatus: target2.apiStatus,
@@ -6337,7 +6595,11 @@ ${summary}`;
6337
6595
  view.renderTargets(
6338
6596
  targets.map((target2) => ({
6339
6597
  id: target2.id,
6340
- label: target2.resolution.react.componentName ?? (target2.element === void 0 ? target2.elementContext?.tagName ?? "Element" : elementLabel(target2.element)),
6598
+ ...target2.elementContext?.instance === void 0 ? {} : { instanceState: target2.elementContext.instance.state },
6599
+ label: [
6600
+ target2.resolution.react.componentName ?? target2.elementContext?.tagName ?? "Element",
6601
+ (target2.elementContext?.instance?.label ?? target2.elementContext?.textPreview)?.slice(0, 80)
6602
+ ].filter(Boolean).join(" · "),
6341
6603
  source: sourceLabel(target2, view.messages().context.sourceUnavailable),
6342
6604
  canOpenEditor: target2.marker !== void 0,
6343
6605
  status: targetStatus(target2),
@@ -6357,6 +6619,7 @@ ${summary}`;
6357
6619
  }
6358
6620
  }
6359
6621
  function selectedAnnotation() {
6622
+ refreshInstanceStates(mutationObserver?.takeRecords() ?? []);
6360
6623
  if (!canPreview()) {
6361
6624
  return void 0;
6362
6625
  }
@@ -6509,6 +6772,9 @@ ${summary}`;
6509
6772
  resizeObserver?.disconnect();
6510
6773
  for (const target2 of targets) {
6511
6774
  target2.element = void 0;
6775
+ target2.instanceScope = void 0;
6776
+ if (target2.elementContext !== void 0)
6777
+ target2.elementContext = withInstanceState(target2.elementContext, "detached");
6512
6778
  }
6513
6779
  view.hideHighlight();
6514
6780
  view.hideSelectionHighlights();
@@ -6596,17 +6862,11 @@ ${summary}`;
6596
6862
  if (!targetIsCurrent(target2, revision)) {
6597
6863
  return;
6598
6864
  }
6599
- let failed = false;
6600
- try {
6601
- target2.elementContext = collectElementContext({
6602
- element: element2,
6603
- maxCharacters: config.budget.domCharacters
6604
- });
6605
- } catch {
6606
- target2.elementContext = void 0;
6607
- failed = true;
6608
- }
6865
+ refreshInstanceStates(mutationObserver?.takeRecords() ?? []);
6866
+ let failed = target2.elementContext === void 0;
6609
6867
  try {
6868
+ if (target2.element !== element2)
6869
+ throw new Error("Selected instance changed before style collection.");
6610
6870
  target2.styles = collectStyleContext({
6611
6871
  document: browser.document,
6612
6872
  element: element2,
@@ -6630,18 +6890,11 @@ ${summary}`;
6630
6890
  }, 0);
6631
6891
  collectionTimers.set(target2.id, timer);
6632
6892
  }
6633
- function duplicateTarget(element2, marker) {
6634
- if (marker !== void 0) {
6635
- return targets.find(
6636
- (target2) => target2.marker?.fileId === marker.fileId && target2.marker.line === marker.line && target2.marker.column === marker.column
6637
- );
6638
- }
6639
- return targets.find((target2) => target2.element === element2);
6640
- }
6641
6893
  function selectElement(element2) {
6894
+ refreshInstanceStates(mutationObserver?.takeRecords() ?? []);
6642
6895
  const resolution = sourceResolver.resolve(element2);
6643
6896
  const marker = sourceRefToMarker(resolution.source);
6644
- const duplicate = duplicateTarget(element2, marker);
6897
+ const duplicate = targets.find((target3) => target3.element === element2);
6645
6898
  if (duplicate !== void 0) {
6646
6899
  activeTargetId = duplicate.id;
6647
6900
  addingTarget = false;
@@ -6673,6 +6926,7 @@ ${summary}`;
6673
6926
  const target2 = {
6674
6927
  id: `target-${String(targetSequence)}`,
6675
6928
  element: element2,
6929
+ instanceScope: void 0,
6676
6930
  resolution,
6677
6931
  marker,
6678
6932
  page: collectPageContext(browser.document, browser.window),
@@ -6685,6 +6939,17 @@ ${summary}`;
6685
6939
  dataFlowReport: void 0,
6686
6940
  dataFlowStatus: "idle"
6687
6941
  };
6942
+ try {
6943
+ const capture = captureSelectedInstance(
6944
+ element2,
6945
+ `${instanceNamespace}_${target2.id}`,
6946
+ config.budget.domCharacters
6947
+ );
6948
+ target2.elementContext = capture.context;
6949
+ target2.instanceScope = capture.scope;
6950
+ } catch {
6951
+ target2.collectionStatus = "failed";
6952
+ }
6688
6953
  targets.push(target2);
6689
6954
  if (!initialSelection) {
6690
6955
  contextualAskWorkflow?.selectionChanged();
@@ -6815,25 +7080,32 @@ ${summary}`;
6815
7080
  persistSelection();
6816
7081
  view.announce(view.messages().announcements.targetRemoved);
6817
7082
  }
6818
- function refreshSelectedGeometry() {
6819
- if (state.status === "idle" || targets.length === 0) {
6820
- return;
7083
+ function refreshInstanceStates(records) {
7084
+ let changed = false;
7085
+ for (const target2 of targets) {
7086
+ if (target2.element === void 0) continue;
7087
+ const next = target2.page.url !== browser.window.location.href ? "changed" : changedInstanceState(
7088
+ target2.element,
7089
+ target2.instanceScope ?? target2.element,
7090
+ records
7091
+ );
7092
+ if (next === void 0) continue;
7093
+ resizeObserver?.unobserve(target2.element);
7094
+ target2.element = void 0;
7095
+ target2.instanceScope = void 0;
7096
+ if (target2.elementContext !== void 0)
7097
+ target2.elementContext = withInstanceState(target2.elementContext, next);
7098
+ changed = true;
6821
7099
  }
6822
- const disconnected = targets.filter(
6823
- (target2) => target2.element !== void 0 && !target2.element.isConnected
6824
- );
6825
- if (disconnected.length > 0) {
6826
- for (const target2 of disconnected) {
6827
- if (target2.element !== void 0) {
6828
- resizeObserver?.unobserve(target2.element);
6829
- target2.element = void 0;
6830
- }
6831
- }
7100
+ if (changed) {
6832
7101
  refreshSelectionView();
6833
7102
  persistSelection();
6834
- view.announce(view.messages().announcements.detachedTargetPreserved);
6835
- return;
7103
+ contextualAskWorkflow?.selectionChanged();
6836
7104
  }
7105
+ }
7106
+ function refreshSelectedGeometry() {
7107
+ if (state.status === "idle" || targets.length === 0) return;
7108
+ refreshInstanceStates(mutationObserver?.takeRecords() ?? []);
6837
7109
  refreshHighlights();
6838
7110
  }
6839
7111
  function handleOpenEditor(targetId) {
@@ -6887,6 +7159,15 @@ ${summary}`;
6887
7159
  agentWorkflow.run();
6888
7160
  }
6889
7161
  }
7162
+ function composeSelectionPrompt(annotation) {
7163
+ try {
7164
+ return promptComposer.compose(annotation);
7165
+ } catch (error) {
7166
+ if (!(error instanceof RangeError)) throw error;
7167
+ view.announce(view.messages().announcements.instanceBudgetExceeded);
7168
+ return void 0;
7169
+ }
7170
+ }
6890
7171
  function handlePreview() {
6891
7172
  if (state.status !== "selected") {
6892
7173
  return;
@@ -6896,7 +7177,9 @@ ${summary}`;
6896
7177
  view.announce(view.messages().announcements.completeInstructions);
6897
7178
  return;
6898
7179
  }
6899
- previewPrompt = promptComposer.compose(annotation);
7180
+ const composed = composeSelectionPrompt(annotation);
7181
+ if (composed === void 0) return;
7182
+ previewPrompt = composed;
6900
7183
  transition({ type: "PREVIEW" });
6901
7184
  view.showPreview(previewPrompt);
6902
7185
  view.focusPrompt();
@@ -6905,6 +7188,12 @@ ${summary}`;
6905
7188
  if (state.status !== "previewing" || previewPrompt.length === 0) {
6906
7189
  return;
6907
7190
  }
7191
+ const annotation = selectedAnnotation();
7192
+ if (annotation === void 0) return;
7193
+ const composed = composeSelectionPrompt(annotation);
7194
+ if (composed === void 0) return;
7195
+ previewPrompt = composed;
7196
+ view.showPreview(previewPrompt);
6908
7197
  if (clipboard === void 0) {
6909
7198
  transition({ type: "COPY_FAILURE" });
6910
7199
  view.focusPrompt();
@@ -6941,8 +7230,11 @@ ${summary}`;
6941
7230
  if (state.status === "previewing") {
6942
7231
  const annotation = selectedAnnotation();
6943
7232
  if (annotation !== void 0) {
6944
- previewPrompt = promptComposer.compose(annotation);
6945
- view.showPreview(previewPrompt);
7233
+ const composed = composeSelectionPrompt(annotation);
7234
+ if (composed !== void 0) {
7235
+ previewPrompt = composed;
7236
+ view.showPreview(previewPrompt);
7237
+ }
6946
7238
  }
6947
7239
  }
6948
7240
  }
@@ -6996,6 +7288,8 @@ ${summary}`;
6996
7288
  browser.document.addEventListener("keydown", handleKeydown, true);
6997
7289
  browser.window.addEventListener("scroll", refreshSelectedGeometry, true);
6998
7290
  browser.window.addEventListener("resize", refreshSelectedGeometry);
7291
+ browser.window.addEventListener("popstate", refreshSelectedGeometry);
7292
+ browser.window.addEventListener("hashchange", refreshSelectedGeometry);
6999
7293
  view.triggerButton.addEventListener("click", activate);
7000
7294
  view.addTargetButton.addEventListener("click", beginAddTarget);
7001
7295
  view.reselectButton.addEventListener("click", handleReselect);
@@ -7032,10 +7326,15 @@ ${summary}`;
7032
7326
  resizeObserver = new browser.resizeObserver(refreshSelectedGeometry);
7033
7327
  }
7034
7328
  if (browser.mutationObserver !== void 0) {
7035
- mutationObserver = new browser.mutationObserver(refreshSelectedGeometry);
7329
+ mutationObserver = new browser.mutationObserver((records) => {
7330
+ refreshInstanceStates(records);
7331
+ refreshHighlights();
7332
+ });
7036
7333
  mutationObserver.observe(browser.document.documentElement, {
7037
7334
  childList: true,
7038
- subtree: true
7335
+ subtree: true,
7336
+ attributes: true,
7337
+ characterData: true
7039
7338
  });
7040
7339
  }
7041
7340
  if (selectionOpen && targets.length > 0) {
@@ -7070,6 +7369,8 @@ ${summary}`;
7070
7369
  browser.document.removeEventListener("keydown", handleKeydown, true);
7071
7370
  browser.window.removeEventListener("scroll", refreshSelectedGeometry, true);
7072
7371
  browser.window.removeEventListener("resize", refreshSelectedGeometry);
7372
+ browser.window.removeEventListener("popstate", refreshSelectedGeometry);
7373
+ browser.window.removeEventListener("hashchange", refreshSelectedGeometry);
7073
7374
  view.triggerButton.removeEventListener("click", activate);
7074
7375
  view.addTargetButton.removeEventListener("click", beginAddTarget);
7075
7376
  view.reselectButton.removeEventListener("click", handleReselect);
@@ -7555,7 +7856,7 @@ function getDataFlowRuntime(target2 = globalThis) {
7555
7856
  }
7556
7857
 
7557
7858
  // src/data-flow/report-merger.ts
7558
- var import_shared10 = require("@spotpatch/shared");
7859
+ var import_shared15 = require("@spotpatch/shared");
7559
7860
  function observationMatchesDependency(observation, dependency) {
7560
7861
  const origin = dependency.origin;
7561
7862
  const transportMatches = dependency.kind === "rpc" ? observation.transport === "trpc" && dependency.operation !== void 0 && observation.operation === dependency.operation : dependency.kind === "http" ? observation.transport === "fetch" || observation.transport === "xhr" : false;
@@ -7625,7 +7926,7 @@ function mergeComponentDataFlowReport(report, observations) {
7625
7926
  (observation) => observation.componentSourceId === void 0 || owners.has(observation.componentSourceId)
7626
7927
  );
7627
7928
  const merged = mergeDependencies(report.dependencies, componentObservations);
7628
- return (0, import_shared10.limitDataFlowReportCollections)(
7929
+ return (0, import_shared15.limitDataFlowReportCollections)(
7629
7930
  Object.freeze({
7630
7931
  ...report,
7631
7932
  dependencies: merged.dependencies,
@@ -7654,7 +7955,7 @@ function unassignedDependency(observation) {
7654
7955
  (path) => Object.freeze({
7655
7956
  path,
7656
7957
  position: "query",
7657
- sensitive: (0, import_shared10.isSensitiveName)(path),
7958
+ sensitive: (0, import_shared15.isSensitiveName)(path),
7658
7959
  valueState: "not-collected",
7659
7960
  evidenceIds: Object.freeze([observation.id])
7660
7961
  })
@@ -7676,7 +7977,7 @@ function mergePageDataFlowReport(report, observations) {
7676
7977
  const merged = mergeDependencies(report.dependencies, currentObservations);
7677
7978
  const unassigned = currentObservations.filter(({ id }) => !merged.matchedObservationIds.has(id)).map(unassignedDependency);
7678
7979
  const allObservationIds = new Set(currentObservations.map(({ id }) => id));
7679
- return (0, import_shared10.limitDataFlowReportCollections)(
7980
+ return (0, import_shared15.limitDataFlowReportCollections)(
7680
7981
  Object.freeze({
7681
7982
  ...report,
7682
7983
  dependencies: Object.freeze([...merged.dependencies, ...unassigned]),