@spotpatch/runtime 1.15.5 → 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 +386 -226
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +262 -91
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -56,6 +56,7 @@ function freezeReact(react2) {
|
|
|
56
56
|
function freezeElement(element2) {
|
|
57
57
|
return Object.freeze({
|
|
58
58
|
...element2,
|
|
59
|
+
...element2.instance === void 0 ? {} : { instance: Object.freeze({ ...element2.instance }) },
|
|
59
60
|
rect: Object.freeze({ ...element2.rect })
|
|
60
61
|
});
|
|
61
62
|
}
|
|
@@ -856,6 +857,66 @@ function collectStyleContext(options) {
|
|
|
856
857
|
});
|
|
857
858
|
}
|
|
858
859
|
|
|
860
|
+
// src/state/selected-instance.ts
|
|
861
|
+
import {
|
|
862
|
+
ELEMENT_INSTANCE_HINT_ATTRIBUTE as ELEMENT_INSTANCE_HINT_ATTRIBUTE2,
|
|
863
|
+
ELEMENT_INSTANCE_LIMITS as ELEMENT_INSTANCE_LIMITS2,
|
|
864
|
+
SOURCE_MARKER_ATTRIBUTE
|
|
865
|
+
} from "@spotpatch/shared";
|
|
866
|
+
|
|
867
|
+
// src/collectors/dom-collector.ts
|
|
868
|
+
import {
|
|
869
|
+
ELEMENT_INSTANCE_HINT_ATTRIBUTE
|
|
870
|
+
} from "@spotpatch/shared";
|
|
871
|
+
|
|
872
|
+
// src/collectors/element-locator.ts
|
|
873
|
+
import { ELEMENT_INSTANCE_LIMITS, redactSensitiveText as redactSensitiveText2 } from "@spotpatch/shared";
|
|
874
|
+
function escapeIdentifier(value) {
|
|
875
|
+
return Array.from(value).map(
|
|
876
|
+
(character) => /[a-z\d_-]/iu.test(character) ? character : `\\${(character.codePointAt(0) ?? 0).toString(16)} `
|
|
877
|
+
).join("");
|
|
878
|
+
}
|
|
879
|
+
function uniqueMatch(element2, selector) {
|
|
880
|
+
if (selector.length > ELEMENT_INSTANCE_LIMITS.selectorCharacters) return false;
|
|
881
|
+
try {
|
|
882
|
+
const matches = element2.ownerDocument.querySelectorAll(selector);
|
|
883
|
+
return matches.length === 1 && matches[0] === element2;
|
|
884
|
+
} catch {
|
|
885
|
+
return false;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
function createElementLocator(element2) {
|
|
889
|
+
if (!element2.isConnected || element2.getRootNode() !== element2.ownerDocument)
|
|
890
|
+
return "";
|
|
891
|
+
const segments = [];
|
|
892
|
+
let current = element2;
|
|
893
|
+
while (current !== null && segments.length < ELEMENT_INSTANCE_LIMITS.locatorDepth) {
|
|
894
|
+
const tag = current.localName;
|
|
895
|
+
const testId = current.getAttribute("data-testid");
|
|
896
|
+
const anchors = [
|
|
897
|
+
...current.id.length > 0 && redactSensitiveText2(current.id) === current.id ? [`${tag}#${escapeIdentifier(current.id)}`] : [],
|
|
898
|
+
...testId && redactSensitiveText2(testId) === testId ? [
|
|
899
|
+
`${tag}[data-testid="${testId.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"]`
|
|
900
|
+
] : []
|
|
901
|
+
];
|
|
902
|
+
for (const anchor of anchors) {
|
|
903
|
+
const candidate2 = [anchor, ...segments].join(" > ");
|
|
904
|
+
if (redactSensitiveText2(candidate2) === candidate2 && uniqueMatch(element2, candidate2))
|
|
905
|
+
return candidate2;
|
|
906
|
+
}
|
|
907
|
+
const siblings = current.parentElement === null ? [current] : Array.from(current.parentElement.children).filter(
|
|
908
|
+
(sibling) => sibling.localName === tag
|
|
909
|
+
);
|
|
910
|
+
const segment = siblings.length > 1 ? `${tag}:nth-of-type(${String(siblings.indexOf(current) + 1)})` : tag;
|
|
911
|
+
segments.unshift(segment);
|
|
912
|
+
const candidate = segments.join(" > ");
|
|
913
|
+
if (uniqueMatch(element2, candidate)) return candidate;
|
|
914
|
+
if (candidate.length > ELEMENT_INSTANCE_LIMITS.selectorCharacters) return "";
|
|
915
|
+
current = current.parentElement;
|
|
916
|
+
}
|
|
917
|
+
return "";
|
|
918
|
+
}
|
|
919
|
+
|
|
859
920
|
// src/collectors/dom-collector.ts
|
|
860
921
|
var DOM_COLLECTION_LIMITS = Object.freeze({
|
|
861
922
|
maxDepth: 3,
|
|
@@ -923,7 +984,7 @@ function escapeHtml(value) {
|
|
|
923
984
|
return value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">");
|
|
924
985
|
}
|
|
925
986
|
function isPreservedAttribute(name) {
|
|
926
|
-
return SAFE_ATTRIBUTE_NAMES.has(name) || name.startsWith("aria-") || name === "data-testid";
|
|
987
|
+
return SAFE_ATTRIBUTE_NAMES.has(name) || name.startsWith("aria-") || name === "data-testid" || name === ELEMENT_INSTANCE_HINT_ATTRIBUTE;
|
|
927
988
|
}
|
|
928
989
|
function openingTag(element2) {
|
|
929
990
|
const tagName = element2.tagName.toLowerCase();
|
|
@@ -999,44 +1060,6 @@ function truncateContext(value, maxCharacters) {
|
|
|
999
1060
|
}
|
|
1000
1061
|
return `${value.slice(0, Math.max(0, maxCharacters - 1)).trimEnd()}…`;
|
|
1001
1062
|
}
|
|
1002
|
-
function escapeCssIdentifier(value) {
|
|
1003
|
-
return Array.from(value).map(
|
|
1004
|
-
(character) => /[a-z\d_-]/iu.test(character) ? character : `\\${character.charCodeAt(0).toString(16)} `
|
|
1005
|
-
).join("");
|
|
1006
|
-
}
|
|
1007
|
-
function escapeCssAttribute(value) {
|
|
1008
|
-
return value.replaceAll("\\", "\\\\").replaceAll('"', '\\"');
|
|
1009
|
-
}
|
|
1010
|
-
function selectorSegment(element2) {
|
|
1011
|
-
const tagName = element2.tagName.toLowerCase();
|
|
1012
|
-
if (element2.id.length > 0) {
|
|
1013
|
-
return `${tagName}#${escapeCssIdentifier(element2.id)}`;
|
|
1014
|
-
}
|
|
1015
|
-
const testId = element2.getAttribute("data-testid");
|
|
1016
|
-
if (testId !== null && testId.length > 0) {
|
|
1017
|
-
return `${tagName}[data-testid="${escapeCssAttribute(testId)}"]`;
|
|
1018
|
-
}
|
|
1019
|
-
const classes = Array.from(element2.classList).slice(0, 2).map((name) => `.${escapeCssIdentifier(name)}`).join("");
|
|
1020
|
-
const sameTagSiblings = element2.parentElement === null ? [] : Array.from(element2.parentElement.children).filter(
|
|
1021
|
-
(sibling) => sibling.tagName === element2.tagName
|
|
1022
|
-
);
|
|
1023
|
-
const position = sameTagSiblings.indexOf(element2);
|
|
1024
|
-
const nth = sameTagSiblings.length > 1 && position >= 0 ? `:nth-of-type(${String(position + 1)})` : "";
|
|
1025
|
-
return `${tagName}${classes}${nth}`;
|
|
1026
|
-
}
|
|
1027
|
-
function createSelector(element2) {
|
|
1028
|
-
const segments = [];
|
|
1029
|
-
let current = element2;
|
|
1030
|
-
while (current !== null && segments.length < 5) {
|
|
1031
|
-
const segment = selectorSegment(current);
|
|
1032
|
-
segments.unshift(segment);
|
|
1033
|
-
if (current.id.length > 0 || current.hasAttribute("data-testid")) {
|
|
1034
|
-
break;
|
|
1035
|
-
}
|
|
1036
|
-
current = current.parentElement;
|
|
1037
|
-
}
|
|
1038
|
-
return segments.join(" > ");
|
|
1039
|
-
}
|
|
1040
1063
|
function collectElementContext(options) {
|
|
1041
1064
|
const lines = ["<!-- Selected element -->"];
|
|
1042
1065
|
const state = { nodeCount: 0, truncated: false };
|
|
@@ -1050,7 +1073,7 @@ function collectElementContext(options) {
|
|
|
1050
1073
|
const role = options.element.getAttribute("role");
|
|
1051
1074
|
return Object.freeze({
|
|
1052
1075
|
tagName: options.element.tagName.toLowerCase(),
|
|
1053
|
-
selector:
|
|
1076
|
+
selector: createElementLocator(options.element),
|
|
1054
1077
|
sanitizedHtml: truncateContext(lines.join("\n"), options.maxCharacters),
|
|
1055
1078
|
...text2.length === 0 ? {} : {
|
|
1056
1079
|
textPreview: text2.length <= DOM_COLLECTION_LIMITS.maxTextCharacters ? text2 : `${text2.slice(0, DOM_COLLECTION_LIMITS.maxTextCharacters)}…`
|
|
@@ -1065,6 +1088,65 @@ function collectElementContext(options) {
|
|
|
1065
1088
|
});
|
|
1066
1089
|
}
|
|
1067
1090
|
|
|
1091
|
+
// src/state/selected-instance.ts
|
|
1092
|
+
function instanceScope(element2) {
|
|
1093
|
+
let candidate = element2;
|
|
1094
|
+
for (let depth = 0; candidate !== null && depth < ELEMENT_INSTANCE_LIMITS2.ancestorDepth; depth += 1) {
|
|
1095
|
+
if (candidate === element2.ownerDocument.body || candidate === element2.ownerDocument.documentElement)
|
|
1096
|
+
break;
|
|
1097
|
+
if (candidate.hasAttribute(ELEMENT_INSTANCE_HINT_ATTRIBUTE2) || candidate.matches("article, li, tr, [role=row], [role=listitem]"))
|
|
1098
|
+
return candidate;
|
|
1099
|
+
const marker = candidate.getAttribute(SOURCE_MARKER_ATTRIBUTE);
|
|
1100
|
+
if (marker !== null && candidate.parentElement !== null && Array.from(candidate.parentElement.children).some(
|
|
1101
|
+
(sibling) => sibling !== candidate && sibling.getAttribute(SOURCE_MARKER_ATTRIBUTE) === marker
|
|
1102
|
+
))
|
|
1103
|
+
return candidate;
|
|
1104
|
+
candidate = candidate.parentElement;
|
|
1105
|
+
}
|
|
1106
|
+
const parent = element2.parentElement;
|
|
1107
|
+
return parent === null || parent === element2.ownerDocument.body || parent === element2.ownerDocument.documentElement ? element2 : parent;
|
|
1108
|
+
}
|
|
1109
|
+
function captureSelectedInstance(element2, id, maxCharacters) {
|
|
1110
|
+
const context = collectElementContext({ element: element2, maxCharacters });
|
|
1111
|
+
const scope = instanceScope(element2);
|
|
1112
|
+
const nearby = collectElementContext({
|
|
1113
|
+
element: scope,
|
|
1114
|
+
maxCharacters: ELEMENT_INSTANCE_LIMITS2.contextCharacters
|
|
1115
|
+
});
|
|
1116
|
+
return Object.freeze({
|
|
1117
|
+
scope,
|
|
1118
|
+
context: Object.freeze({
|
|
1119
|
+
...context,
|
|
1120
|
+
instance: Object.freeze({
|
|
1121
|
+
id,
|
|
1122
|
+
state: "captured",
|
|
1123
|
+
selectorStatus: context.selector.length > 0 ? "unique-at-capture" : "unavailable",
|
|
1124
|
+
label: (nearby.textPreview ?? context.textPreview ?? context.tagName).slice(
|
|
1125
|
+
0,
|
|
1126
|
+
ELEMENT_INSTANCE_LIMITS2.labelCharacters
|
|
1127
|
+
),
|
|
1128
|
+
context: nearby.sanitizedHtml
|
|
1129
|
+
})
|
|
1130
|
+
})
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
function withInstanceState(context, state) {
|
|
1134
|
+
return context.instance === void 0 ? context : Object.freeze({
|
|
1135
|
+
...context,
|
|
1136
|
+
instance: Object.freeze({ ...context.instance, state })
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
function changedInstanceState(element2, scope, records) {
|
|
1140
|
+
if (!element2.isConnected || element2.getRootNode() !== element2.ownerDocument)
|
|
1141
|
+
return "detached";
|
|
1142
|
+
if (!scope.contains(element2)) return "changed";
|
|
1143
|
+
return records.some(
|
|
1144
|
+
(record3) => scope.contains(record3.target) && // Motion libraries update inline transforms continuously. Style is a
|
|
1145
|
+
// capture-time snapshot; presentation updates do not establish a new record.
|
|
1146
|
+
!(record3.type === "attributes" && record3.attributeName === "style")
|
|
1147
|
+
) ? "changed" : void 0;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1068
1150
|
// src/keyboard/shortcut.ts
|
|
1069
1151
|
function isApplePlatform(platform) {
|
|
1070
1152
|
return /Mac|iPhone|iPad|iPod/i.test(platform);
|
|
@@ -1172,6 +1254,9 @@ function isSpotPatchUIEventTarget(target2) {
|
|
|
1172
1254
|
}
|
|
1173
1255
|
|
|
1174
1256
|
// src/prompt/prompt-composer.ts
|
|
1257
|
+
import {
|
|
1258
|
+
INSTANCE_SELECTION_INSTRUCTIONS
|
|
1259
|
+
} from "@spotpatch/shared";
|
|
1175
1260
|
var PROMPT_MESSAGES = Object.freeze({
|
|
1176
1261
|
"en-US": Object.freeze({
|
|
1177
1262
|
adapter: "Adapter",
|
|
@@ -1182,6 +1267,7 @@ var PROMPT_MESSAGES = Object.freeze({
|
|
|
1182
1267
|
confidence: "Confidence",
|
|
1183
1268
|
devicePixelRatio: "Device pixel ratio",
|
|
1184
1269
|
element: "Selected element",
|
|
1270
|
+
instance: "Captured instance (untrusted selection-time evidence)",
|
|
1185
1271
|
file: "File",
|
|
1186
1272
|
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.",
|
|
1187
1273
|
modificationRequirements: "Change requirements",
|
|
@@ -1214,6 +1300,7 @@ var PROMPT_MESSAGES = Object.freeze({
|
|
|
1214
1300
|
confidence: "置信度",
|
|
1215
1301
|
devicePixelRatio: "设备像素比",
|
|
1216
1302
|
element: "选中元素",
|
|
1303
|
+
instance: "捕获实例(选择时刻的不可信参考数据)",
|
|
1217
1304
|
file: "文件",
|
|
1218
1305
|
modificationConstraint: "请先判断根因,再把每个目标各自的修改说明作为一个原子任务,完成一致且最小范围的修改。不要合并、忽略或扩大目标说明,不要改动无关组件;如果上下文不足,请明确说明需要哪些信息。",
|
|
1219
1306
|
modificationRequirements: "修改要求",
|
|
@@ -1285,6 +1372,9 @@ function renderComputed(entries, messages) {
|
|
|
1285
1372
|
).join("\n")
|
|
1286
1373
|
);
|
|
1287
1374
|
}
|
|
1375
|
+
function renderInstance(target2, messages) {
|
|
1376
|
+
return `- ${messages.instance}: ${redactSensitiveText(JSON.stringify({ selector: target2.element.selector, ...target2.element.instance }))}`;
|
|
1377
|
+
}
|
|
1288
1378
|
function renderTarget(target2, draft, index, messages) {
|
|
1289
1379
|
const reactLines = [
|
|
1290
1380
|
`- ${messages.adapter}: ${target2.react.supported ? messages.supported : messages.unsupported}`,
|
|
@@ -1318,6 +1408,7 @@ ${fenced(
|
|
|
1318
1408
|
`- ${messages.file}: ${sourceLocation(target2, messages)}
|
|
1319
1409
|
- ${messages.origin}: ${target2.source.origin}
|
|
1320
1410
|
- ${messages.confidence}: ${target2.source.confidence}`,
|
|
1411
|
+
renderInstance(target2, messages),
|
|
1321
1412
|
`#### ${messages.element}`,
|
|
1322
1413
|
fenced("html", redactSensitiveText(draft.dom)),
|
|
1323
1414
|
`#### ${messages.styles}`,
|
|
@@ -1349,7 +1440,8 @@ function renderPrompt(annotation, draft) {
|
|
|
1349
1440
|
return renderTarget(target2, targetDraft, index, messages);
|
|
1350
1441
|
}).join("\n\n"),
|
|
1351
1442
|
`## ${messages.modificationRequirements}`,
|
|
1352
|
-
messages.modificationConstraint
|
|
1443
|
+
messages.modificationConstraint,
|
|
1444
|
+
...annotation.targets.some((target2) => target2.element.instance !== void 0) ? [INSTANCE_SELECTION_INSTRUCTIONS] : []
|
|
1353
1445
|
].join("\n\n");
|
|
1354
1446
|
}
|
|
1355
1447
|
function shrinkCode(target2, draft) {
|
|
@@ -1432,6 +1524,7 @@ function renderCompactPrompt(annotation, draft) {
|
|
|
1432
1524
|
`- ${messages.requestedChange}: ${targetDraft?.instruction ?? redactSensitiveText(target2.instruction)}`,
|
|
1433
1525
|
`- ${messages.file}: ${sourceLocation(target2, messages)}`,
|
|
1434
1526
|
...component === void 0 ? [] : [`- ${messages.component}: ${redactSensitiveText(component)}`],
|
|
1527
|
+
renderInstance(target2, messages),
|
|
1435
1528
|
`- ${messages.element}: ${redactSensitiveText(openingTag2(targetDraft?.dom ?? target2.element.sanitizedHtml, messages.unavailable))}`
|
|
1436
1529
|
].join("\n");
|
|
1437
1530
|
});
|
|
@@ -1439,7 +1532,8 @@ function renderCompactPrompt(annotation, draft) {
|
|
|
1439
1532
|
`## ${messages.selectedTargets(annotation.targets.length)}`,
|
|
1440
1533
|
targets.join("\n\n"),
|
|
1441
1534
|
`## ${messages.modificationRequirements}`,
|
|
1442
|
-
messages.modificationConstraint
|
|
1535
|
+
messages.modificationConstraint,
|
|
1536
|
+
...annotation.targets.some((target2) => target2.element.instance !== void 0) ? [INSTANCE_SELECTION_INSTRUCTIONS] : []
|
|
1443
1537
|
].join("\n\n");
|
|
1444
1538
|
}
|
|
1445
1539
|
function composeBounded(annotation, maxCharacters) {
|
|
@@ -1546,6 +1640,10 @@ function reduceRuntimeState(state, event) {
|
|
|
1546
1640
|
}
|
|
1547
1641
|
|
|
1548
1642
|
// src/state/selection-session.ts
|
|
1643
|
+
import {
|
|
1644
|
+
ELEMENT_INSTANCE_LIMITS as ELEMENT_INSTANCE_LIMITS3,
|
|
1645
|
+
ELEMENT_INSTANCE_STATES
|
|
1646
|
+
} from "@spotpatch/shared";
|
|
1549
1647
|
var STORAGE_PREFIX = "spotpatch:selection:";
|
|
1550
1648
|
var SNAPSHOT_VERSION = 1;
|
|
1551
1649
|
var MAX_SNAPSHOT_CHARACTERS = 1e6;
|
|
@@ -1582,7 +1680,11 @@ function page(value) {
|
|
|
1582
1680
|
function element(value) {
|
|
1583
1681
|
const item = record(value);
|
|
1584
1682
|
const rect = record(item?.rect);
|
|
1585
|
-
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);
|
|
1683
|
+
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);
|
|
1684
|
+
}
|
|
1685
|
+
function instance(value) {
|
|
1686
|
+
const item = record(value);
|
|
1687
|
+
return item !== void 0 && Object.keys(item).length === 5 && text(item.id) && item.id.length <= ELEMENT_INSTANCE_LIMITS3.idCharacters && /^[A-Za-z0-9_-]+$/u.test(item.id) && ELEMENT_INSTANCE_STATES.some((state) => state === item.state) && (item.selectorStatus === "unique-at-capture" || item.selectorStatus === "unavailable") && text(item.label) && item.label.length <= ELEMENT_INSTANCE_LIMITS3.labelCharacters && text(item.context) && item.context.length <= ELEMENT_INSTANCE_LIMITS3.contextCharacters;
|
|
1586
1688
|
}
|
|
1587
1689
|
function styles(value) {
|
|
1588
1690
|
const item = record(value);
|
|
@@ -1663,14 +1765,14 @@ function createSelectionSession(window, sessionId, maximumTargets) {
|
|
|
1663
1765
|
// src/source/source-resolver.ts
|
|
1664
1766
|
import {
|
|
1665
1767
|
parseSourceMarker,
|
|
1666
|
-
SOURCE_MARKER_ATTRIBUTE
|
|
1768
|
+
SOURCE_MARKER_ATTRIBUTE as SOURCE_MARKER_ATTRIBUTE2
|
|
1667
1769
|
} from "@spotpatch/shared";
|
|
1668
1770
|
var EMPTY_REACT_CONTEXT = Object.freeze({
|
|
1669
1771
|
supported: false,
|
|
1670
1772
|
componentStack: Object.freeze([])
|
|
1671
1773
|
});
|
|
1672
1774
|
function directMarker(element2) {
|
|
1673
|
-
return parseSourceMarker(element2.getAttribute(
|
|
1775
|
+
return parseSourceMarker(element2.getAttribute(SOURCE_MARKER_ATTRIBUTE2));
|
|
1674
1776
|
}
|
|
1675
1777
|
function ancestorMarker(element2) {
|
|
1676
1778
|
let ancestor = element2.parentElement;
|
|
@@ -2624,6 +2726,13 @@ var ERROR_MESSAGES_ZH = Object.freeze({
|
|
|
2624
2726
|
[ERROR_CODES2.INTERNAL_ERROR]: "Agent 失败,未暴露私有细节。"
|
|
2625
2727
|
});
|
|
2626
2728
|
var SUMMARY_MESSAGES_EN = Object.freeze({
|
|
2729
|
+
instance: "Selected instance",
|
|
2730
|
+
instanceStates: {
|
|
2731
|
+
captured: "Captured element; locator describes selection time",
|
|
2732
|
+
changed: "Page content changed; snapshot preserved. Select again to confirm the current instance",
|
|
2733
|
+
detached: "Element unloaded; historical snapshot preserved",
|
|
2734
|
+
restored: "Restored snapshot; not bound to the current page"
|
|
2735
|
+
},
|
|
2627
2736
|
adapter: "React adapter",
|
|
2628
2737
|
api: "API",
|
|
2629
2738
|
apiStatuses: Object.freeze({
|
|
@@ -2664,6 +2773,13 @@ var SUMMARY_MESSAGES_EN = Object.freeze({
|
|
|
2664
2773
|
warning: "Warning"
|
|
2665
2774
|
});
|
|
2666
2775
|
var SUMMARY_MESSAGES_ZH = Object.freeze({
|
|
2776
|
+
instance: "选中实例",
|
|
2777
|
+
instanceStates: {
|
|
2778
|
+
captured: "已捕获元素;定位信息对应选择时刻",
|
|
2779
|
+
changed: "页面内容已变化,已保留快照;请重新选择以确认当前实例",
|
|
2780
|
+
detached: "元素已卸载,已保留历史快照",
|
|
2781
|
+
restored: "已恢复历史快照,未绑定当前页面"
|
|
2782
|
+
},
|
|
2667
2783
|
adapter: "React 适配器",
|
|
2668
2784
|
api: "API",
|
|
2669
2785
|
apiStatuses: Object.freeze({
|
|
@@ -2848,13 +2964,13 @@ var UI_MESSAGES = Object.freeze({
|
|
|
2848
2964
|
addCancelled: "Additional selection cancelled.",
|
|
2849
2965
|
selectionLimit: (maximum) => `The selection limit of ${String(maximum)} elements has been reached.`,
|
|
2850
2966
|
chooseAdditional: (selected, maximum) => `Choose another element. ${String(selected)} of ${String(maximum)} selected.`,
|
|
2851
|
-
duplicate: "That
|
|
2967
|
+
duplicate: "That page element is already selected.",
|
|
2968
|
+
instanceBudgetExceeded: "The prompt cannot preserve every selected instance within its budget. Remove some targets or increase the context budget.",
|
|
2852
2969
|
sourceProbable: "A probable React component was found without an authorized file token.",
|
|
2853
2970
|
sourceMissing: "No authorized source marker was found for the selected element.",
|
|
2854
2971
|
noSelectable: "No selectable element was found.",
|
|
2855
2972
|
allTargetsRemoved: "All targets were removed. Choose an element to continue.",
|
|
2856
2973
|
targetRemoved: "Selected target removed.",
|
|
2857
|
-
detachedTargetPreserved: "The page element was unloaded; its collected context remains selected.",
|
|
2858
2974
|
contextWarning: "Browser context collection completed with a warning.",
|
|
2859
2975
|
contextCollected: "Browser context collected.",
|
|
2860
2976
|
editorOpening: "Opening source…",
|
|
@@ -3012,13 +3128,13 @@ var UI_MESSAGES = Object.freeze({
|
|
|
3012
3128
|
addCancelled: "已取消追加选择。",
|
|
3013
3129
|
selectionLimit: (maximum) => `已达到 ${String(maximum)} 个元素的选择上限。`,
|
|
3014
3130
|
chooseAdditional: (selected, maximum) => `请选择另一个元素,当前已选 ${String(selected)} / ${String(maximum)}。`,
|
|
3015
|
-
duplicate: "
|
|
3131
|
+
duplicate: "该页面元素已经在当前选择中。",
|
|
3132
|
+
instanceBudgetExceeded: "上下文预算无法完整保留所有选中实例,请减少目标数量或提高上下文预算。",
|
|
3016
3133
|
sourceProbable: "找到可能的 React 组件,但没有获授权的源码标记。",
|
|
3017
3134
|
sourceMissing: "选中元素没有获授权的源码标记。",
|
|
3018
3135
|
noSelectable: "当前位置没有可选择的元素。",
|
|
3019
3136
|
allTargetsRemoved: "已移除全部目标,请重新选择元素。",
|
|
3020
3137
|
targetRemoved: "已移除选中目标。",
|
|
3021
|
-
detachedTargetPreserved: "页面元素已卸载,已采集的上下文仍保留在选择中。",
|
|
3022
3138
|
contextWarning: "浏览器上下文采集完成,但存在警告。",
|
|
3023
3139
|
contextCollected: "浏览器上下文采集完成。",
|
|
3024
3140
|
editorOpening: "正在打开源码……",
|
|
@@ -4850,6 +4966,9 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
4850
4966
|
requestFloatingSurfaceLayout();
|
|
4851
4967
|
}
|
|
4852
4968
|
function statusText(target2) {
|
|
4969
|
+
if (target2.instanceState !== void 0 && target2.instanceState !== "captured") {
|
|
4970
|
+
return messages.summary.instanceStates[target2.instanceState];
|
|
4971
|
+
}
|
|
4853
4972
|
if (target2.status === "ready") {
|
|
4854
4973
|
return messages.targets.statusReady;
|
|
4855
4974
|
}
|
|
@@ -5490,6 +5609,11 @@ function createSelectionSummary(input, messages) {
|
|
|
5490
5609
|
`${messages.confidence}: ${input.resolution.source.confidence} (${messages.confidenceLabels[input.resolution.source.confidence]})`,
|
|
5491
5610
|
`${messages.origin}: ${input.resolution.source.origin}`
|
|
5492
5611
|
];
|
|
5612
|
+
if (input.instance !== void 0) {
|
|
5613
|
+
lines.push(
|
|
5614
|
+
`${messages.instance}: ${messages.instanceStates[input.instance.state]}`
|
|
5615
|
+
);
|
|
5616
|
+
}
|
|
5493
5617
|
if (input.resolution.react.componentName !== void 0) {
|
|
5494
5618
|
lines.push(`${messages.component}: ${input.resolution.react.componentName}`);
|
|
5495
5619
|
}
|
|
@@ -5948,7 +6072,7 @@ function sourceLabel(target2, unavailable) {
|
|
|
5948
6072
|
return `${path}${line === void 0 ? "" : `:${String(line)}`}${column === void 0 ? "" : `:${String(column)}`}`;
|
|
5949
6073
|
}
|
|
5950
6074
|
function targetStatus(target2) {
|
|
5951
|
-
if (target2.apiStatus === "failed" || target2.collectionStatus === "failed") {
|
|
6075
|
+
if (target2.apiStatus === "failed" || target2.collectionStatus === "failed" || target2.elementContext?.instance !== void 0 && target2.elementContext.instance.state !== "captured") {
|
|
5952
6076
|
return "warning";
|
|
5953
6077
|
}
|
|
5954
6078
|
if (target2.apiStatus === "loading" || target2.collectionStatus === "loading") {
|
|
@@ -5991,6 +6115,7 @@ function createController(config, dependencies = {}) {
|
|
|
5991
6115
|
const now = dependencies.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
5992
6116
|
const selectionSession = dependencies.selectionSession ?? createSelectionSession(browser.window, config.sessionId, config.maxTargets);
|
|
5993
6117
|
const restoredSelection = selectionSession.load();
|
|
6118
|
+
const instanceNamespace = createBrowserAnnotationId(browser.window);
|
|
5994
6119
|
const sourceResolver = createSourceResolver({
|
|
5995
6120
|
adapter: dependencies.reactAdapter ?? createReact18Adapter({
|
|
5996
6121
|
...config.dataFlow.enabled ? {
|
|
@@ -6022,7 +6147,8 @@ function createController(config, dependencies = {}) {
|
|
|
6022
6147
|
dataFlowReport: void 0,
|
|
6023
6148
|
dataFlowStatus: "idle",
|
|
6024
6149
|
element: void 0,
|
|
6025
|
-
|
|
6150
|
+
instanceScope: void 0,
|
|
6151
|
+
elementContext: withInstanceState(target2.element, "restored"),
|
|
6026
6152
|
instruction: target2.instruction,
|
|
6027
6153
|
marker,
|
|
6028
6154
|
page: target2.page,
|
|
@@ -6181,6 +6307,7 @@ function createController(config, dependencies = {}) {
|
|
|
6181
6307
|
);
|
|
6182
6308
|
}
|
|
6183
6309
|
function selectedAskSelection() {
|
|
6310
|
+
refreshInstanceStates(mutationObserver?.takeRecords() ?? []);
|
|
6184
6311
|
const snapshots = targets.flatMap((target2) => {
|
|
6185
6312
|
const snapshot = snapshotTarget(target2);
|
|
6186
6313
|
return snapshot === void 0 ? [] : [snapshot];
|
|
@@ -6199,6 +6326,7 @@ function createController(config, dependencies = {}) {
|
|
|
6199
6326
|
const summary = createSelectionSummary(
|
|
6200
6327
|
{
|
|
6201
6328
|
resolution: target2.resolution,
|
|
6329
|
+
...target2.elementContext?.instance === void 0 ? {} : { instance: target2.elementContext.instance },
|
|
6202
6330
|
...target2.code === void 0 ? {} : { code: target2.code },
|
|
6203
6331
|
...target2.styles === void 0 ? {} : { styles: target2.styles },
|
|
6204
6332
|
apiStatus: target2.apiStatus,
|
|
@@ -6244,7 +6372,11 @@ ${summary}`;
|
|
|
6244
6372
|
view.renderTargets(
|
|
6245
6373
|
targets.map((target2) => ({
|
|
6246
6374
|
id: target2.id,
|
|
6247
|
-
|
|
6375
|
+
...target2.elementContext?.instance === void 0 ? {} : { instanceState: target2.elementContext.instance.state },
|
|
6376
|
+
label: [
|
|
6377
|
+
target2.resolution.react.componentName ?? target2.elementContext?.tagName ?? "Element",
|
|
6378
|
+
(target2.elementContext?.instance?.label ?? target2.elementContext?.textPreview)?.slice(0, 80)
|
|
6379
|
+
].filter(Boolean).join(" · "),
|
|
6248
6380
|
source: sourceLabel(target2, view.messages().context.sourceUnavailable),
|
|
6249
6381
|
canOpenEditor: target2.marker !== void 0,
|
|
6250
6382
|
status: targetStatus(target2),
|
|
@@ -6264,6 +6396,7 @@ ${summary}`;
|
|
|
6264
6396
|
}
|
|
6265
6397
|
}
|
|
6266
6398
|
function selectedAnnotation() {
|
|
6399
|
+
refreshInstanceStates(mutationObserver?.takeRecords() ?? []);
|
|
6267
6400
|
if (!canPreview()) {
|
|
6268
6401
|
return void 0;
|
|
6269
6402
|
}
|
|
@@ -6416,6 +6549,9 @@ ${summary}`;
|
|
|
6416
6549
|
resizeObserver?.disconnect();
|
|
6417
6550
|
for (const target2 of targets) {
|
|
6418
6551
|
target2.element = void 0;
|
|
6552
|
+
target2.instanceScope = void 0;
|
|
6553
|
+
if (target2.elementContext !== void 0)
|
|
6554
|
+
target2.elementContext = withInstanceState(target2.elementContext, "detached");
|
|
6419
6555
|
}
|
|
6420
6556
|
view.hideHighlight();
|
|
6421
6557
|
view.hideSelectionHighlights();
|
|
@@ -6503,17 +6639,11 @@ ${summary}`;
|
|
|
6503
6639
|
if (!targetIsCurrent(target2, revision)) {
|
|
6504
6640
|
return;
|
|
6505
6641
|
}
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
target2.elementContext = collectElementContext({
|
|
6509
|
-
element: element2,
|
|
6510
|
-
maxCharacters: config.budget.domCharacters
|
|
6511
|
-
});
|
|
6512
|
-
} catch {
|
|
6513
|
-
target2.elementContext = void 0;
|
|
6514
|
-
failed = true;
|
|
6515
|
-
}
|
|
6642
|
+
refreshInstanceStates(mutationObserver?.takeRecords() ?? []);
|
|
6643
|
+
let failed = target2.elementContext === void 0;
|
|
6516
6644
|
try {
|
|
6645
|
+
if (target2.element !== element2)
|
|
6646
|
+
throw new Error("Selected instance changed before style collection.");
|
|
6517
6647
|
target2.styles = collectStyleContext({
|
|
6518
6648
|
document: browser.document,
|
|
6519
6649
|
element: element2,
|
|
@@ -6537,18 +6667,11 @@ ${summary}`;
|
|
|
6537
6667
|
}, 0);
|
|
6538
6668
|
collectionTimers.set(target2.id, timer);
|
|
6539
6669
|
}
|
|
6540
|
-
function duplicateTarget(element2, marker) {
|
|
6541
|
-
if (marker !== void 0) {
|
|
6542
|
-
return targets.find(
|
|
6543
|
-
(target2) => target2.marker?.fileId === marker.fileId && target2.marker.line === marker.line && target2.marker.column === marker.column
|
|
6544
|
-
);
|
|
6545
|
-
}
|
|
6546
|
-
return targets.find((target2) => target2.element === element2);
|
|
6547
|
-
}
|
|
6548
6670
|
function selectElement(element2) {
|
|
6671
|
+
refreshInstanceStates(mutationObserver?.takeRecords() ?? []);
|
|
6549
6672
|
const resolution = sourceResolver.resolve(element2);
|
|
6550
6673
|
const marker = sourceRefToMarker(resolution.source);
|
|
6551
|
-
const duplicate =
|
|
6674
|
+
const duplicate = targets.find((target3) => target3.element === element2);
|
|
6552
6675
|
if (duplicate !== void 0) {
|
|
6553
6676
|
activeTargetId = duplicate.id;
|
|
6554
6677
|
addingTarget = false;
|
|
@@ -6580,6 +6703,7 @@ ${summary}`;
|
|
|
6580
6703
|
const target2 = {
|
|
6581
6704
|
id: `target-${String(targetSequence)}`,
|
|
6582
6705
|
element: element2,
|
|
6706
|
+
instanceScope: void 0,
|
|
6583
6707
|
resolution,
|
|
6584
6708
|
marker,
|
|
6585
6709
|
page: collectPageContext(browser.document, browser.window),
|
|
@@ -6592,6 +6716,17 @@ ${summary}`;
|
|
|
6592
6716
|
dataFlowReport: void 0,
|
|
6593
6717
|
dataFlowStatus: "idle"
|
|
6594
6718
|
};
|
|
6719
|
+
try {
|
|
6720
|
+
const capture = captureSelectedInstance(
|
|
6721
|
+
element2,
|
|
6722
|
+
`${instanceNamespace}_${target2.id}`,
|
|
6723
|
+
config.budget.domCharacters
|
|
6724
|
+
);
|
|
6725
|
+
target2.elementContext = capture.context;
|
|
6726
|
+
target2.instanceScope = capture.scope;
|
|
6727
|
+
} catch {
|
|
6728
|
+
target2.collectionStatus = "failed";
|
|
6729
|
+
}
|
|
6595
6730
|
targets.push(target2);
|
|
6596
6731
|
if (!initialSelection) {
|
|
6597
6732
|
contextualAskWorkflow?.selectionChanged();
|
|
@@ -6722,25 +6857,32 @@ ${summary}`;
|
|
|
6722
6857
|
persistSelection();
|
|
6723
6858
|
view.announce(view.messages().announcements.targetRemoved);
|
|
6724
6859
|
}
|
|
6725
|
-
function
|
|
6726
|
-
|
|
6727
|
-
|
|
6860
|
+
function refreshInstanceStates(records) {
|
|
6861
|
+
let changed = false;
|
|
6862
|
+
for (const target2 of targets) {
|
|
6863
|
+
if (target2.element === void 0) continue;
|
|
6864
|
+
const next = target2.page.url !== browser.window.location.href ? "changed" : changedInstanceState(
|
|
6865
|
+
target2.element,
|
|
6866
|
+
target2.instanceScope ?? target2.element,
|
|
6867
|
+
records
|
|
6868
|
+
);
|
|
6869
|
+
if (next === void 0) continue;
|
|
6870
|
+
resizeObserver?.unobserve(target2.element);
|
|
6871
|
+
target2.element = void 0;
|
|
6872
|
+
target2.instanceScope = void 0;
|
|
6873
|
+
if (target2.elementContext !== void 0)
|
|
6874
|
+
target2.elementContext = withInstanceState(target2.elementContext, next);
|
|
6875
|
+
changed = true;
|
|
6728
6876
|
}
|
|
6729
|
-
|
|
6730
|
-
(target2) => target2.element !== void 0 && !target2.element.isConnected
|
|
6731
|
-
);
|
|
6732
|
-
if (disconnected.length > 0) {
|
|
6733
|
-
for (const target2 of disconnected) {
|
|
6734
|
-
if (target2.element !== void 0) {
|
|
6735
|
-
resizeObserver?.unobserve(target2.element);
|
|
6736
|
-
target2.element = void 0;
|
|
6737
|
-
}
|
|
6738
|
-
}
|
|
6877
|
+
if (changed) {
|
|
6739
6878
|
refreshSelectionView();
|
|
6740
6879
|
persistSelection();
|
|
6741
|
-
|
|
6742
|
-
return;
|
|
6880
|
+
contextualAskWorkflow?.selectionChanged();
|
|
6743
6881
|
}
|
|
6882
|
+
}
|
|
6883
|
+
function refreshSelectedGeometry() {
|
|
6884
|
+
if (state.status === "idle" || targets.length === 0) return;
|
|
6885
|
+
refreshInstanceStates(mutationObserver?.takeRecords() ?? []);
|
|
6744
6886
|
refreshHighlights();
|
|
6745
6887
|
}
|
|
6746
6888
|
function handleOpenEditor(targetId) {
|
|
@@ -6794,6 +6936,15 @@ ${summary}`;
|
|
|
6794
6936
|
agentWorkflow.run();
|
|
6795
6937
|
}
|
|
6796
6938
|
}
|
|
6939
|
+
function composeSelectionPrompt(annotation) {
|
|
6940
|
+
try {
|
|
6941
|
+
return promptComposer.compose(annotation);
|
|
6942
|
+
} catch (error) {
|
|
6943
|
+
if (!(error instanceof RangeError)) throw error;
|
|
6944
|
+
view.announce(view.messages().announcements.instanceBudgetExceeded);
|
|
6945
|
+
return void 0;
|
|
6946
|
+
}
|
|
6947
|
+
}
|
|
6797
6948
|
function handlePreview() {
|
|
6798
6949
|
if (state.status !== "selected") {
|
|
6799
6950
|
return;
|
|
@@ -6803,7 +6954,9 @@ ${summary}`;
|
|
|
6803
6954
|
view.announce(view.messages().announcements.completeInstructions);
|
|
6804
6955
|
return;
|
|
6805
6956
|
}
|
|
6806
|
-
|
|
6957
|
+
const composed = composeSelectionPrompt(annotation);
|
|
6958
|
+
if (composed === void 0) return;
|
|
6959
|
+
previewPrompt = composed;
|
|
6807
6960
|
transition({ type: "PREVIEW" });
|
|
6808
6961
|
view.showPreview(previewPrompt);
|
|
6809
6962
|
view.focusPrompt();
|
|
@@ -6812,6 +6965,12 @@ ${summary}`;
|
|
|
6812
6965
|
if (state.status !== "previewing" || previewPrompt.length === 0) {
|
|
6813
6966
|
return;
|
|
6814
6967
|
}
|
|
6968
|
+
const annotation = selectedAnnotation();
|
|
6969
|
+
if (annotation === void 0) return;
|
|
6970
|
+
const composed = composeSelectionPrompt(annotation);
|
|
6971
|
+
if (composed === void 0) return;
|
|
6972
|
+
previewPrompt = composed;
|
|
6973
|
+
view.showPreview(previewPrompt);
|
|
6815
6974
|
if (clipboard === void 0) {
|
|
6816
6975
|
transition({ type: "COPY_FAILURE" });
|
|
6817
6976
|
view.focusPrompt();
|
|
@@ -6848,8 +7007,11 @@ ${summary}`;
|
|
|
6848
7007
|
if (state.status === "previewing") {
|
|
6849
7008
|
const annotation = selectedAnnotation();
|
|
6850
7009
|
if (annotation !== void 0) {
|
|
6851
|
-
|
|
6852
|
-
|
|
7010
|
+
const composed = composeSelectionPrompt(annotation);
|
|
7011
|
+
if (composed !== void 0) {
|
|
7012
|
+
previewPrompt = composed;
|
|
7013
|
+
view.showPreview(previewPrompt);
|
|
7014
|
+
}
|
|
6853
7015
|
}
|
|
6854
7016
|
}
|
|
6855
7017
|
}
|
|
@@ -6903,6 +7065,8 @@ ${summary}`;
|
|
|
6903
7065
|
browser.document.addEventListener("keydown", handleKeydown, true);
|
|
6904
7066
|
browser.window.addEventListener("scroll", refreshSelectedGeometry, true);
|
|
6905
7067
|
browser.window.addEventListener("resize", refreshSelectedGeometry);
|
|
7068
|
+
browser.window.addEventListener("popstate", refreshSelectedGeometry);
|
|
7069
|
+
browser.window.addEventListener("hashchange", refreshSelectedGeometry);
|
|
6906
7070
|
view.triggerButton.addEventListener("click", activate);
|
|
6907
7071
|
view.addTargetButton.addEventListener("click", beginAddTarget);
|
|
6908
7072
|
view.reselectButton.addEventListener("click", handleReselect);
|
|
@@ -6939,10 +7103,15 @@ ${summary}`;
|
|
|
6939
7103
|
resizeObserver = new browser.resizeObserver(refreshSelectedGeometry);
|
|
6940
7104
|
}
|
|
6941
7105
|
if (browser.mutationObserver !== void 0) {
|
|
6942
|
-
mutationObserver = new browser.mutationObserver(
|
|
7106
|
+
mutationObserver = new browser.mutationObserver((records) => {
|
|
7107
|
+
refreshInstanceStates(records);
|
|
7108
|
+
refreshHighlights();
|
|
7109
|
+
});
|
|
6943
7110
|
mutationObserver.observe(browser.document.documentElement, {
|
|
6944
7111
|
childList: true,
|
|
6945
|
-
subtree: true
|
|
7112
|
+
subtree: true,
|
|
7113
|
+
attributes: true,
|
|
7114
|
+
characterData: true
|
|
6946
7115
|
});
|
|
6947
7116
|
}
|
|
6948
7117
|
if (selectionOpen && targets.length > 0) {
|
|
@@ -6977,6 +7146,8 @@ ${summary}`;
|
|
|
6977
7146
|
browser.document.removeEventListener("keydown", handleKeydown, true);
|
|
6978
7147
|
browser.window.removeEventListener("scroll", refreshSelectedGeometry, true);
|
|
6979
7148
|
browser.window.removeEventListener("resize", refreshSelectedGeometry);
|
|
7149
|
+
browser.window.removeEventListener("popstate", refreshSelectedGeometry);
|
|
7150
|
+
browser.window.removeEventListener("hashchange", refreshSelectedGeometry);
|
|
6980
7151
|
view.triggerButton.removeEventListener("click", activate);
|
|
6981
7152
|
view.addTargetButton.removeEventListener("click", beginAddTarget);
|
|
6982
7153
|
view.reselectButton.removeEventListener("click", handleReselect);
|