@spotpatch/runtime 1.15.2 → 1.15.4
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/chunk-ELCIEQGT.js +183 -0
- package/dist/chunk-ELCIEQGT.js.map +1 -0
- package/dist/contextual-ask-panel.cjs +100 -92
- package/dist/contextual-ask-panel.cjs.map +1 -1
- package/dist/contextual-ask-panel.js +74 -235
- package/dist/contextual-ask-panel.js.map +1 -1
- package/dist/data-flow-panel.cjs +28 -28
- package/dist/data-flow-panel.cjs.map +1 -1
- package/dist/data-flow-panel.js +28 -28
- package/dist/data-flow-panel.js.map +1 -1
- package/dist/external-handoff-panel.cjs +300 -110
- package/dist/external-handoff-panel.cjs.map +1 -1
- package/dist/external-handoff-panel.js +132 -110
- package/dist/external-handoff-panel.js.map +1 -1
- package/dist/index.cjs +284 -284
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +284 -284
- package/dist/index.js.map +1 -1
- package/dist/motion.cjs +2 -2
- package/dist/motion.cjs.map +1 -1
- package/dist/motion.js +2 -2
- package/dist/motion.js.map +1 -1
- package/package.json +2 -2
|
@@ -488,6 +488,9 @@ function parseStatusResult(value) {
|
|
|
488
488
|
dispatch
|
|
489
489
|
});
|
|
490
490
|
}
|
|
491
|
+
function isExternalHandoffFramework(value) {
|
|
492
|
+
return import_external_handoff_browser2.EXTERNAL_HANDOFF_FRAMEWORKS.some((framework) => framework === value);
|
|
493
|
+
}
|
|
491
494
|
function parseSummary(value) {
|
|
492
495
|
if (!record(value)) throw new ExternalHandoffApiError();
|
|
493
496
|
const expectedKeys = [
|
|
@@ -503,7 +506,7 @@ function parseSummary(value) {
|
|
|
503
506
|
"targetCount",
|
|
504
507
|
...value.pickedUpAt === void 0 ? [] : ["pickedUpAt"]
|
|
505
508
|
];
|
|
506
|
-
if (!exactKeys(value, expectedKeys) || typeof value.sessionId !== "string" || !OPAQUE_ID_PATTERN.test(value.sessionId) || value.framework
|
|
509
|
+
if (!exactKeys(value, expectedKeys) || typeof value.sessionId !== "string" || !OPAQUE_ID_PATTERN.test(value.sessionId) || !isExternalHandoffFramework(value.framework) || !Number.isSafeInteger(value.revision) || value.revision <= 0 || typeof value.cursor !== "string" || !OPAQUE_ID_PATTERN.test(value.cursor) || !Number.isSafeInteger(value.targetCount) || value.targetCount <= 0 || !record(value.page) || !exactKeys(value.page, ["origin", "pathname"]) || typeof value.page.origin !== "string" || typeof value.page.pathname !== "string" || !validTimestamp(value.publishedAt) || !validTimestamp(value.expiresAt) || value.state !== "available" && value.state !== "expired" && value.state !== "superseded" || !Number.isSafeInteger(value.pickupCount) || value.pickupCount < 0 || value.pickupCount > import_external_handoff_browser2.EXTERNAL_HANDOFF_LIMITS.maximumConnectorReceipts || value.pickedUpAt !== void 0 && !validTimestamp(value.pickedUpAt)) {
|
|
507
510
|
throw new ExternalHandoffApiError();
|
|
508
511
|
}
|
|
509
512
|
return Object.freeze({
|
|
@@ -1030,6 +1033,179 @@ function createButton(document, label, className = "") {
|
|
|
1030
1033
|
return button;
|
|
1031
1034
|
}
|
|
1032
1035
|
|
|
1036
|
+
// src/ui/ask-picker.ts
|
|
1037
|
+
var SELECT_PICKER_STYLES = `
|
|
1038
|
+
.spotpatch-select-picker { position: relative; display: grid; gap: 5px; min-width: 0; }
|
|
1039
|
+
.spotpatch-select-trigger { box-sizing: border-box; display: flex; width: 100%; min-height: 38px; align-items: center; justify-content: space-between; gap: 10px; border: 1px solid var(--spotpatch-border); border-radius: 9px; padding: 0 11px; overflow: hidden; color: var(--spotpatch-text); background: var(--spotpatch-bg-input); cursor: pointer; font: inherit; outline: none; text-align: left; }
|
|
1040
|
+
.spotpatch-select-trigger > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1041
|
+
.spotpatch-select-trigger[data-expandable="true"]::after { width: 7px; height: 7px; flex: 0 0 auto; border-right: 1.5px solid #8f96a3; border-bottom: 1.5px solid #8f96a3; content: ""; transform: translateY(-2px) rotate(45deg); }
|
|
1042
|
+
.spotpatch-select-trigger[aria-expanded="true"]::after { transform: translateY(2px) rotate(225deg); }
|
|
1043
|
+
.spotpatch-select-trigger:focus-visible { border-color: rgb(139 123 255 / 68%); box-shadow: 0 0 0 3px rgb(139 123 255 / 12%); }
|
|
1044
|
+
.spotpatch-select-trigger:disabled { color: var(--spotpatch-text); background: rgb(255 255 255 / 3%); cursor: default; opacity: 1; }
|
|
1045
|
+
.spotpatch-select-trigger[data-empty="true"]:disabled { color: var(--spotpatch-text-muted); }
|
|
1046
|
+
.spotpatch-select-menu { position: relative; z-index: 1; display: grid; gap: 3px; max-height: 224px; overflow-y: auto; overscroll-behavior: contain; border: 1px solid var(--spotpatch-border); border-radius: 9px; padding: 4px; background: var(--spotpatch-bg-input); box-shadow: 0 10px 28px rgb(0 0 0 / 28%); scrollbar-width: thin; }
|
|
1047
|
+
.spotpatch-select-menu[hidden] { display: none; }
|
|
1048
|
+
.spotpatch-select-option { box-sizing: border-box; min-height: 34px; border: 0; border-radius: 6px; padding: 7px 9px; overflow-wrap: anywhere; color: var(--spotpatch-text-secondary); background: transparent; cursor: pointer; font: inherit; text-align: left; }
|
|
1049
|
+
.spotpatch-select-option[data-active="true"], .spotpatch-select-option:hover { color: #fff; background: rgb(139 123 255 / 13%); outline: none; }
|
|
1050
|
+
.spotpatch-select-option[aria-selected="true"] { color: #f4f1ff; background: rgb(139 123 255 / 20%); }
|
|
1051
|
+
.spotpatch-select-native { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; border: 0; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
|
|
1052
|
+
`;
|
|
1053
|
+
function createSelectPicker(document, onViewChange) {
|
|
1054
|
+
const root = createMarkedElement(document, "div");
|
|
1055
|
+
root.className = "spotpatch-select-picker";
|
|
1056
|
+
const trigger = createButton(document, "", "spotpatch-select-trigger");
|
|
1057
|
+
trigger.id = `spotpatch-select-picker-${Math.random().toString(36).slice(2)}`;
|
|
1058
|
+
trigger.setAttribute("role", "combobox");
|
|
1059
|
+
trigger.setAttribute("aria-haspopup", "listbox");
|
|
1060
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
1061
|
+
const text = createMarkedElement(document, "span");
|
|
1062
|
+
trigger.append(text);
|
|
1063
|
+
const menu = createMarkedElement(document, "div");
|
|
1064
|
+
menu.id = `${trigger.id}-menu`;
|
|
1065
|
+
menu.className = "spotpatch-select-menu";
|
|
1066
|
+
menu.setAttribute("role", "listbox");
|
|
1067
|
+
menu.hidden = true;
|
|
1068
|
+
trigger.setAttribute("aria-controls", menu.id);
|
|
1069
|
+
const select = createMarkedElement(document, "select");
|
|
1070
|
+
select.className = "spotpatch-select-native";
|
|
1071
|
+
select.tabIndex = -1;
|
|
1072
|
+
select.setAttribute("aria-hidden", "true");
|
|
1073
|
+
root.append(trigger, menu, select);
|
|
1074
|
+
function close(focus = false) {
|
|
1075
|
+
if (menu.hidden) return;
|
|
1076
|
+
menu.hidden = true;
|
|
1077
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
1078
|
+
trigger.removeAttribute("aria-activedescendant");
|
|
1079
|
+
if (focus) trigger.focus({ preventScroll: true });
|
|
1080
|
+
onViewChange();
|
|
1081
|
+
}
|
|
1082
|
+
function activate(index) {
|
|
1083
|
+
const options = [...menu.children];
|
|
1084
|
+
const active = options[index];
|
|
1085
|
+
if (active === void 0) return;
|
|
1086
|
+
for (const option of options) option.dataset.active = String(option === active);
|
|
1087
|
+
trigger.setAttribute("aria-activedescendant", active.id);
|
|
1088
|
+
const itemRect = active.getBoundingClientRect();
|
|
1089
|
+
const menuRect = menu.getBoundingClientRect();
|
|
1090
|
+
if (itemRect.top < menuRect.top) menu.scrollTop -= menuRect.top - itemRect.top;
|
|
1091
|
+
else if (itemRect.bottom > menuRect.bottom)
|
|
1092
|
+
menu.scrollTop += itemRect.bottom - menuRect.bottom;
|
|
1093
|
+
}
|
|
1094
|
+
function open() {
|
|
1095
|
+
if (trigger.disabled || !menu.hidden) return;
|
|
1096
|
+
menu.hidden = false;
|
|
1097
|
+
trigger.setAttribute("aria-expanded", "true");
|
|
1098
|
+
activate(Math.max(0, select.selectedIndex));
|
|
1099
|
+
onViewChange();
|
|
1100
|
+
}
|
|
1101
|
+
function sync() {
|
|
1102
|
+
text.textContent = select.selectedOptions[0]?.textContent ?? "";
|
|
1103
|
+
trigger.title = text.textContent;
|
|
1104
|
+
trigger.dataset.empty = String(select.value.length === 0);
|
|
1105
|
+
for (const option of [...menu.children]) {
|
|
1106
|
+
option.setAttribute(
|
|
1107
|
+
"aria-selected",
|
|
1108
|
+
String(option.dataset.value === select.value)
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
function choose(value) {
|
|
1113
|
+
if (trigger.disabled) return;
|
|
1114
|
+
select.value = value;
|
|
1115
|
+
sync();
|
|
1116
|
+
close(true);
|
|
1117
|
+
select.dispatchEvent(new Event("change", { bubbles: true }));
|
|
1118
|
+
}
|
|
1119
|
+
function rebuild() {
|
|
1120
|
+
const expanded = !menu.hidden;
|
|
1121
|
+
const nativeOptions = [...select.options];
|
|
1122
|
+
menu.replaceChildren();
|
|
1123
|
+
for (const [index, option] of nativeOptions.entries()) {
|
|
1124
|
+
const item = createMarkedElement(document, "div");
|
|
1125
|
+
item.id = `${menu.id}-${String(index)}`;
|
|
1126
|
+
item.className = "spotpatch-select-option";
|
|
1127
|
+
item.setAttribute("role", "option");
|
|
1128
|
+
item.dataset.value = option.value;
|
|
1129
|
+
item.textContent = option.textContent;
|
|
1130
|
+
item.title = option.textContent;
|
|
1131
|
+
item.addEventListener("pointerdown", (event) => {
|
|
1132
|
+
event.preventDefault();
|
|
1133
|
+
});
|
|
1134
|
+
item.addEventListener("click", () => {
|
|
1135
|
+
choose(option.value);
|
|
1136
|
+
});
|
|
1137
|
+
menu.append(item);
|
|
1138
|
+
}
|
|
1139
|
+
sync();
|
|
1140
|
+
if (expanded) {
|
|
1141
|
+
activate(Math.max(0, select.selectedIndex));
|
|
1142
|
+
onViewChange();
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
trigger.addEventListener("click", () => {
|
|
1146
|
+
if (menu.hidden) open();
|
|
1147
|
+
else close();
|
|
1148
|
+
});
|
|
1149
|
+
trigger.addEventListener("keydown", (event) => {
|
|
1150
|
+
if (event.key === "Escape" && !menu.hidden) {
|
|
1151
|
+
event.preventDefault();
|
|
1152
|
+
event.stopPropagation();
|
|
1153
|
+
close();
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
if (event.key === "Tab") {
|
|
1157
|
+
close();
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
if (["Enter", " "].includes(event.key) && !menu.hidden) {
|
|
1161
|
+
event.preventDefault();
|
|
1162
|
+
const active = [...menu.children].find(
|
|
1163
|
+
(item) => item.id === trigger.getAttribute("aria-activedescendant")
|
|
1164
|
+
);
|
|
1165
|
+
if (active?.dataset.value !== void 0) choose(active.dataset.value);
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
1169
|
+
event.preventDefault();
|
|
1170
|
+
if (menu.hidden) {
|
|
1171
|
+
open();
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
const options = [...menu.children];
|
|
1175
|
+
const index = options.findIndex(
|
|
1176
|
+
(item) => item.id === trigger.getAttribute("aria-activedescendant")
|
|
1177
|
+
);
|
|
1178
|
+
activate(
|
|
1179
|
+
event.key === "Home" ? 0 : event.key === "End" ? options.length - 1 : (index + (event.key === "ArrowDown" ? 1 : -1) + options.length) % options.length
|
|
1180
|
+
);
|
|
1181
|
+
});
|
|
1182
|
+
root.addEventListener("focusout", (event) => {
|
|
1183
|
+
if (!(event.relatedTarget instanceof Node) || !root.contains(event.relatedTarget))
|
|
1184
|
+
close();
|
|
1185
|
+
});
|
|
1186
|
+
const outside = (event) => {
|
|
1187
|
+
if (!event.composedPath().includes(root)) close();
|
|
1188
|
+
};
|
|
1189
|
+
document.addEventListener("pointerdown", outside);
|
|
1190
|
+
select.addEventListener("change", sync);
|
|
1191
|
+
return {
|
|
1192
|
+
root,
|
|
1193
|
+
trigger,
|
|
1194
|
+
select,
|
|
1195
|
+
rebuild,
|
|
1196
|
+
close,
|
|
1197
|
+
setDisabled(disabled) {
|
|
1198
|
+
select.disabled = disabled;
|
|
1199
|
+
trigger.disabled = disabled || select.options.length < 2;
|
|
1200
|
+
trigger.dataset.expandable = String(!trigger.disabled);
|
|
1201
|
+
if (trigger.disabled) close();
|
|
1202
|
+
},
|
|
1203
|
+
dispose() {
|
|
1204
|
+
document.removeEventListener("pointerdown", outside);
|
|
1205
|
+
}
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1033
1209
|
// src/ui/external-handoff-panel.ts
|
|
1034
1210
|
var MESSAGES = Object.freeze({
|
|
1035
1211
|
"en-US": Object.freeze({
|
|
@@ -1039,19 +1215,19 @@ var MESSAGES = Object.freeze({
|
|
|
1039
1215
|
modelLoading: "Connect to load available models",
|
|
1040
1216
|
modelHint: "Applies only to this managed connection, not API Key settings. Apply changes before publishing; switching reconnects Codex.",
|
|
1041
1217
|
applyModel: "Apply model",
|
|
1042
|
-
codexManaged: "Codex
|
|
1218
|
+
codexManaged: "Codex · managed (experimental)",
|
|
1043
1219
|
connectManaged: "Connect Codex",
|
|
1044
1220
|
disconnectManaged: "Disconnect",
|
|
1045
1221
|
revokeManaged: "Revoke grant",
|
|
1046
1222
|
cancelManaged: "Cancel managed task",
|
|
1047
1223
|
resultTitle: "Managed result",
|
|
1048
|
-
controlConnection: (state, mode) => `Connection: ${state}
|
|
1049
|
-
controlAuth: (auth, grant) => `Auth: ${auth}
|
|
1224
|
+
controlConnection: (state, mode) => `Connection: ${state} · Mode: ${mode}`,
|
|
1225
|
+
controlAuth: (auth, grant) => `Auth: ${auth} · Grant: ${grant}`,
|
|
1050
1226
|
controlConsentRequired: (command) => `Initialize project access once: run \`${command}\` from this project, then connect again. No dev-terminal confirmation is required. The grant allows isolated snapshot writes and validated application; revoke it here at any time.`,
|
|
1051
1227
|
controlModel: (model) => `Model: ${model}`,
|
|
1052
1228
|
controlRevision: (task) => `Revision ${String(task.revision)}: ${task.deliveryStatus} / ${task.executionStatus} / ${task.managedPhase}`,
|
|
1053
1229
|
controlValidation: (outcome) => `Validation: ${outcome}`,
|
|
1054
|
-
controlFailure: (error, action) => `Error: ${error}
|
|
1230
|
+
controlFailure: (error, action) => `Error: ${error} · Next: ${action}`,
|
|
1055
1231
|
controlUnavailable: "Page connection management is unavailable; external handoffs still fall back honestly to the Agent inbox.",
|
|
1056
1232
|
controlErrorText: Object.freeze({
|
|
1057
1233
|
AGENT_BINARY_NOT_FOUND: "Codex is not installed or is not on PATH.",
|
|
@@ -1085,17 +1261,17 @@ var MESSAGES = Object.freeze({
|
|
|
1085
1261
|
retry: "Retry the managed connection.",
|
|
1086
1262
|
"inspect-cleanup-warning": "Inspect cleanup status before reconnecting."
|
|
1087
1263
|
}),
|
|
1088
|
-
resultHeader: (revision, outcome) => `Revision ${String(revision)}
|
|
1264
|
+
resultHeader: (revision, outcome) => `Revision ${String(revision)} · Validation ${outcome}`,
|
|
1089
1265
|
resultDisposition: (outcome) => outcome === "passed" ? "Applied to the project after validation passed." : `Candidate only; it was not applied because validation is ${outcome}.`,
|
|
1090
1266
|
resultTiming: (stage, durationMs) => `Timing ${stage}: ${String(durationMs)} ms`,
|
|
1091
1267
|
description: "Send through a ready active adapter, or publish to the project Agent inbox when no active adapter is connected.",
|
|
1092
1268
|
ready: "Local Broker ready. No Agent connection is assumed until a connector reads or waits.",
|
|
1093
1269
|
readyWaiting: (count) => `${String(count)} active connector wait request(s); publishing can wake them immediately.`,
|
|
1094
1270
|
activeReady: (agent) => `${agent} is connected and idle. The next send will dispatch immediately.`,
|
|
1095
|
-
publishing: "Authorizing current source and publishing the handoff
|
|
1271
|
+
publishing: "Authorizing current source and publishing the handoff…",
|
|
1096
1272
|
published: (revision, expiresAt) => `Revision ${String(revision)} is available until ${expiresAt}. It has not been claimed as edited.`,
|
|
1097
1273
|
queued: (agent, revision) => `Revision ${String(revision)} is reserved for ${agent}.`,
|
|
1098
|
-
dispatching: (agent, revision) => `Dispatching revision ${String(revision)} to ${agent}
|
|
1274
|
+
dispatching: (agent, revision) => `Dispatching revision ${String(revision)} to ${agent}…`,
|
|
1099
1275
|
dispatched: (agent, revision) => agent === "Claude Code" ? `Revision ${String(revision)} was written to the Claude Channel transport; there is no model ACK yet.` : `Codex App Server accepted revision ${String(revision)}; waiting for the matching turn to start.`,
|
|
1100
1276
|
working: (agent, revision) => `${agent} is working on revision ${String(revision)}.`,
|
|
1101
1277
|
completed: (agent, revision) => `${agent} ended revision ${String(revision)} normally. Review the diff and checks; this does not prove the requested change is correct.`,
|
|
@@ -1109,7 +1285,7 @@ var MESSAGES = Object.freeze({
|
|
|
1109
1285
|
inboxSend: "Publish to Agent inbox",
|
|
1110
1286
|
retry: "Retry same send",
|
|
1111
1287
|
refresh: "Refresh pickup status",
|
|
1112
|
-
resolveUnknown: "Workspace reviewed
|
|
1288
|
+
resolveUnknown: "Workspace reviewed — allow a new task",
|
|
1113
1289
|
settingsTitle: "Project connection setup",
|
|
1114
1290
|
settingsHelp: "Codex managed mode is owned by the current development server. The browser never receives vendor credentials or arbitrary command access. Generic and attached adapters remain honest Inbox fallbacks.",
|
|
1115
1291
|
disclosureTitle: "Confirm external Agent handoff",
|
|
@@ -1124,100 +1300,101 @@ var MESSAGES = Object.freeze({
|
|
|
1124
1300
|
error: (code) => code === "EXTERNAL_AGENT_BUSY" ? "The active Agent is still busy or blocked by an uncertain delivery." : code === "ACTIVE_DISPATCH_INVALID" ? "The active delivery state changed. Refresh before continuing." : code === "HANDOFF_SOURCE_STALE" ? "The selected source changed. Select the current component again." : code === "HANDOFF_RESPONSE_TOO_LARGE" ? "The handoff is too large. Reduce the selected context." : code === "EXTERNAL_HANDOFF_DISABLED" ? "External Agent handoff is disabled in trusted project configuration." : code === "EXTERNAL_HANDOFF_UNAVAILABLE" || code === "SESSION_CLOSED" ? "The local external Agent Broker is unavailable. Restart the development server." : "The external Agent handoff request failed without publishing a partial revision."
|
|
1125
1301
|
}),
|
|
1126
1302
|
"zh-CN": Object.freeze({
|
|
1127
|
-
title: "
|
|
1303
|
+
title: "外部 Agent 连接",
|
|
1128
1304
|
agentLabel: "Agent",
|
|
1129
|
-
modelLabel: "
|
|
1130
|
-
modelLoading: "
|
|
1131
|
-
modelHint: "
|
|
1132
|
-
applyModel: "
|
|
1133
|
-
codexManaged: "Codex
|
|
1134
|
-
connectManaged: "
|
|
1135
|
-
disconnectManaged: "
|
|
1136
|
-
revokeManaged: "
|
|
1137
|
-
cancelManaged: "
|
|
1138
|
-
resultTitle: "
|
|
1139
|
-
controlConnection: (state, mode) =>
|
|
1140
|
-
controlAuth: (auth, grant) =>
|
|
1141
|
-
controlConsentRequired: (command) =>
|
|
1142
|
-
controlModel: (model) =>
|
|
1143
|
-
controlRevision: (task) => `revision ${String(task.revision)}
|
|
1144
|
-
controlValidation: (outcome) =>
|
|
1145
|
-
controlFailure: (error, action) =>
|
|
1146
|
-
controlUnavailable: "
|
|
1305
|
+
modelLabel: "受管 Codex 模型",
|
|
1306
|
+
modelLoading: "连接后加载可用模型",
|
|
1307
|
+
modelHint: "仅作用于此受管连接,不修改 API Key 配置。更换后请先应用模型,再发布任务;应用时会重新连接 Codex。",
|
|
1308
|
+
applyModel: "应用模型",
|
|
1309
|
+
codexManaged: "Codex · 受管模式(实验性)",
|
|
1310
|
+
connectManaged: "连接 Codex",
|
|
1311
|
+
disconnectManaged: "断开连接",
|
|
1312
|
+
revokeManaged: "撤销授权",
|
|
1313
|
+
cancelManaged: "取消受管任务",
|
|
1314
|
+
resultTitle: "受管执行结果",
|
|
1315
|
+
controlConnection: (state, mode) => `连接:${state} · 模式:${mode}`,
|
|
1316
|
+
controlAuth: (auth, grant) => `认证:${auth} · 授权:${grant}`,
|
|
1317
|
+
controlConsentRequired: (command) => `请在当前项目执行一次初始化:\`${command}\`,然后重新连接,无需在开发终端输入 yes。授权允许隔离快照修改及校验后的应用,可随时在此撤销。`,
|
|
1318
|
+
controlModel: (model) => `模型:${model}`,
|
|
1319
|
+
controlRevision: (task) => `revision ${String(task.revision)}:${task.deliveryStatus} / ${task.executionStatus} / ${task.managedPhase}`,
|
|
1320
|
+
controlValidation: (outcome) => `验证:${outcome}`,
|
|
1321
|
+
controlFailure: (error, action) => `错误:${error} · 下一步:${action}`,
|
|
1322
|
+
controlUnavailable: "页面连接管理不可用;外部交接仍会按真实能力降级为 Agent 收件箱。",
|
|
1147
1323
|
controlErrorText: Object.freeze({
|
|
1148
|
-
AGENT_BINARY_NOT_FOUND: "
|
|
1149
|
-
AGENT_BINARY_UNTRUSTED: "
|
|
1150
|
-
AGENT_VERSION_UNSUPPORTED: "
|
|
1151
|
-
APP_SERVER_HANDSHAKE_FAILED: "Codex App Server
|
|
1152
|
-
AGENT_AUTH_REQUIRED: "Codex
|
|
1153
|
-
AGENT_MODEL_UNAVAILABLE: "Codex
|
|
1154
|
-
AGENT_PROTOCOL_INCOMPATIBLE: "Codex
|
|
1155
|
-
CODEX_CONFIG_ISOLATION_UNSUPPORTED: "
|
|
1156
|
-
MANAGED_GRANT_INVALID: "
|
|
1157
|
-
MANAGED_PLATFORM_UNSUPPORTED: "
|
|
1158
|
-
MANAGED_GIT_REQUIRED: "
|
|
1159
|
-
MANAGED_SNAPSHOT_FAILED: "
|
|
1160
|
-
MANAGED_SCOPE_VIOLATION: "
|
|
1161
|
-
MANAGED_CHANGE_LIMIT_EXCEEDED: "
|
|
1162
|
-
MANAGED_VALIDATION_FAILED: "
|
|
1163
|
-
MANAGED_WORKSPACE_CONFLICT: "
|
|
1164
|
-
MANAGED_APPLY_FAILED: "
|
|
1165
|
-
MANAGED_CLEANUP_INCOMPLETE: "
|
|
1324
|
+
AGENT_BINARY_NOT_FOUND: "未安装 Codex,或 Codex 不在 PATH 中。",
|
|
1325
|
+
AGENT_BINARY_UNTRUSTED: "解析到的 Codex 可执行文件不可信。",
|
|
1326
|
+
AGENT_VERSION_UNSUPPORTED: "已安装的 Codex 版本低于 SpotPatch 兼容基线。",
|
|
1327
|
+
APP_SERVER_HANDSHAKE_FAILED: "Codex App Server 未完成启动握手。",
|
|
1328
|
+
AGENT_AUTH_REQUIRED: "Codex 需要已登录的账户。",
|
|
1329
|
+
AGENT_MODEL_UNAVAILABLE: "Codex 配置的模型当前不可用。",
|
|
1330
|
+
AGENT_PROTOCOL_INCOMPATIBLE: "Codex 生成的 App Server Schema 不满足 SpotPatch 所需协议子集。",
|
|
1331
|
+
CODEX_CONFIG_ISOLATION_UNSUPPORTED: "当前 Codex 版本无法证明受管配置隔离。",
|
|
1332
|
+
MANAGED_GRANT_INVALID: "保存的项目授权未通过校验。",
|
|
1333
|
+
MANAGED_PLATFORM_UNSUPPORTED: "当前平台尚未证明可安全运行受管执行。",
|
|
1334
|
+
MANAGED_GIT_REQUIRED: "受管执行要求项目位于 Git 仓库中。",
|
|
1335
|
+
MANAGED_SNAPSHOT_FAILED: "无法创建独立工作区快照。",
|
|
1336
|
+
MANAGED_SCOPE_VIOLATION: "候选修改超出授权路径。",
|
|
1337
|
+
MANAGED_CHANGE_LIMIT_EXCEEDED: "候选修改超过安全上限。",
|
|
1338
|
+
MANAGED_VALIDATION_FAILED: "候选修改未通过审计或验证。",
|
|
1339
|
+
MANAGED_WORKSPACE_CONFLICT: "执行期间授权源码发生了变化。",
|
|
1340
|
+
MANAGED_APPLY_FAILED: "已审计修改无法安全写入。",
|
|
1341
|
+
MANAGED_CLEANUP_INCOMPLETE: "受管 thread 或工作区清理不完整。"
|
|
1166
1342
|
}),
|
|
1167
1343
|
controlActionText: Object.freeze({
|
|
1168
|
-
"install-agent": "
|
|
1169
|
-
"use-supported-version": "
|
|
1170
|
-
"sign-in": "
|
|
1171
|
-
"choose-available-model": "
|
|
1172
|
-
"use-inbox": "
|
|
1173
|
-
"confirm-managed-access": "
|
|
1174
|
-
"review-candidate-diff": "
|
|
1175
|
-
"review-workspace-conflict": "
|
|
1176
|
-
retry: "
|
|
1177
|
-
"inspect-cleanup-warning": "
|
|
1344
|
+
"install-agent": "安装 Codex 后重试。",
|
|
1345
|
+
"use-supported-version": "改用 Schema 兼容的 Codex 版本。",
|
|
1346
|
+
"sign-in": "登录 Codex 后重试。",
|
|
1347
|
+
"choose-available-model": "选择可用模型后重新连接 Codex。",
|
|
1348
|
+
"use-inbox": "继续使用 Agent 收件箱降级路径。",
|
|
1349
|
+
"confirm-managed-access": "撤销无效授权并重新确认。",
|
|
1350
|
+
"review-candidate-diff": "检查候选 diff 和验证输出。",
|
|
1351
|
+
"review-workspace-conflict": "检查工作区变化后再重试。",
|
|
1352
|
+
retry: "重试受管连接。",
|
|
1353
|
+
"inspect-cleanup-warning": "确认清理状态后再连接。"
|
|
1178
1354
|
}),
|
|
1179
|
-
resultHeader: (revision, outcome) => `revision ${String(revision)}
|
|
1180
|
-
resultDisposition: (outcome) => outcome === "passed" ? "
|
|
1181
|
-
resultTiming: (stage, durationMs) =>
|
|
1182
|
-
description: "
|
|
1183
|
-
ready: "
|
|
1184
|
-
readyWaiting: (count) =>
|
|
1185
|
-
activeReady: (agent) => `${agent}
|
|
1186
|
-
publishing: "
|
|
1187
|
-
published: (revision, expiresAt) =>
|
|
1188
|
-
queued: (agent, revision) =>
|
|
1189
|
-
dispatching: (agent, revision) =>
|
|
1190
|
-
dispatched: (agent, revision) => agent === "Claude Code" ? `revision ${String(revision)}
|
|
1191
|
-
working: (agent, revision) => `${agent}
|
|
1192
|
-
completed: (agent, revision) => `${agent}
|
|
1193
|
-
failed: (agent, revision) => `${agent}
|
|
1194
|
-
unknown: (agent, revision) => `revision ${String(revision)}
|
|
1195
|
-
unknownResolved: (agent, revision) => `${agent}
|
|
1196
|
-
pickedUp: (revision, count, time) =>
|
|
1197
|
-
expired: (revision) =>
|
|
1198
|
-
superseded: (revision) =>
|
|
1199
|
-
send: "
|
|
1200
|
-
inboxSend: "
|
|
1201
|
-
retry: "
|
|
1202
|
-
refresh: "
|
|
1203
|
-
resolveUnknown: "
|
|
1204
|
-
settingsTitle: "
|
|
1205
|
-
settingsHelp: "Codex
|
|
1206
|
-
disclosureTitle: "
|
|
1207
|
-
disclosureIntro: (targets, files) =>
|
|
1208
|
-
disclosureData: "
|
|
1209
|
-
disclosureInbox: "15
|
|
1210
|
-
disclosureProvider: "Agent
|
|
1211
|
-
disclosureNoGuarantee: "
|
|
1212
|
-
disclosureManagedGuarantee: "
|
|
1213
|
-
cancel: "
|
|
1214
|
-
confirm: "
|
|
1215
|
-
error: (code) => code === "EXTERNAL_AGENT_BUSY" ? "
|
|
1355
|
+
resultHeader: (revision, outcome) => `revision ${String(revision)} · 验证 ${outcome}`,
|
|
1356
|
+
resultDisposition: (outcome) => outcome === "passed" ? "验证通过,修改已写入项目。" : `这只是候选 diff;验证状态为 ${outcome},因此没有写入项目。`,
|
|
1357
|
+
resultTiming: (stage, durationMs) => `耗时 ${stage}: ${String(durationMs)} ms`,
|
|
1358
|
+
description: "有主动适配器就立即派发;未连接主动适配器时,诚实降级为项目 Agent 收件箱。",
|
|
1359
|
+
ready: "本地 Broker 已就绪。只有连接器读取或等待后,才能证明发生过连接。",
|
|
1360
|
+
readyWaiting: (count) => `当前有 ${String(count)} 个连接器等待请求,发布后可立即唤醒。`,
|
|
1361
|
+
activeReady: (agent) => `${agent} 已连接并处于空闲状态,下次发送会立即派发。`,
|
|
1362
|
+
publishing: "正在重新授权当前源码并发布交接……",
|
|
1363
|
+
published: (revision, expiresAt) => `交接 revision ${String(revision)} 可读取至 ${expiresAt};这不表示代码已被修改。`,
|
|
1364
|
+
queued: (agent, revision) => `交接 revision ${String(revision)} 已为 ${agent} 预留。`,
|
|
1365
|
+
dispatching: (agent, revision) => `正在把 revision ${String(revision)} 派发给 ${agent}……`,
|
|
1366
|
+
dispatched: (agent, revision) => agent === "Claude Code" ? `revision ${String(revision)} 已写入 Claude Channel transport;当前没有模型 ACK。` : `Codex App Server 已接受 revision ${String(revision)},正在等待匹配 turn 启动。`,
|
|
1367
|
+
working: (agent, revision) => `${agent} 正在处理 revision ${String(revision)}。`,
|
|
1368
|
+
completed: (agent, revision) => `${agent} 已正常结束 revision ${String(revision)}。请核对 diff 和检查结果;这不证明修改要求已经正确完成。`,
|
|
1369
|
+
failed: (agent, revision) => `${agent} 已将 revision ${String(revision)} 报告为失败,连接器已恢复空闲。`,
|
|
1370
|
+
unknown: (agent, revision) => `revision ${String(revision)} 向 ${agent} 的投递结果不确定。受管 writer 已停止,请先核对工作区再允许新任务。`,
|
|
1371
|
+
unknownResolved: (agent, revision) => `${agent} 的 revision ${String(revision)} 仍记为投递未知,但工作区核对已经确认;现在可以重新连接或发布新的收件箱任务。`,
|
|
1372
|
+
pickedUp: (revision, count, time) => `交接 revision ${String(revision)} 已被 ${String(count)} 个连接器实例取走${time === void 0 ? "。" : `,最近取件于 ${time}。`}这不能证明代码已经修改。`,
|
|
1373
|
+
expired: (revision) => `交接 revision ${String(revision)} 已过期,请核对当前选择后重新发布。`,
|
|
1374
|
+
superseded: (revision) => `交接 revision ${String(revision)} 已被更新版本取代。`,
|
|
1375
|
+
send: "发送给 Agent",
|
|
1376
|
+
inboxSend: "发布到 Agent 收件箱",
|
|
1377
|
+
retry: "重试同一次发送",
|
|
1378
|
+
refresh: "刷新取件状态",
|
|
1379
|
+
resolveUnknown: "已核对工作区,允许新任务",
|
|
1380
|
+
settingsTitle: "项目连接设置",
|
|
1381
|
+
settingsHelp: "Codex 受管模式由当前开发服务托管,浏览器不会获得厂商凭证或任意命令权限;通用与 attached adapter 仍按真实能力降级为收件箱。",
|
|
1382
|
+
disclosureTitle: "确认发布到外部 Agent",
|
|
1383
|
+
disclosureIntro: (targets, files) => `将发布 ${String(targets)} 个目标,涉及 ${String(files)} 个项目相对文件。`,
|
|
1384
|
+
disclosureData: "交接包含修改说明、组件与页面上下文、已清洗的 DOM/CSS,以及本地 Node 服务重新读取的有界源码。",
|
|
1385
|
+
disclosureInbox: "15 分钟有效期内,本项目中任何已配置的 SpotPatch Connector 都可能读取。",
|
|
1386
|
+
disclosureProvider: "Agent 宿主可能依据其产品数据策略,将内容发送给云端模型服务。",
|
|
1387
|
+
disclosureNoGuarantee: "外部修改不具备 SpotPatch 内建 Agent 的 worktree、Apply 或 Revert 保证。",
|
|
1388
|
+
disclosureManagedGuarantee: "受管 Codex 只写独立临时快照。SpotPatch 会审计 diff,且仅在所有可信 required checks 通过后才写入业务仓库。",
|
|
1389
|
+
cancel: "取消",
|
|
1390
|
+
confirm: "确认并发送",
|
|
1391
|
+
error: (code) => code === "EXTERNAL_AGENT_BUSY" ? "主动 Agent 仍在工作,或存在尚未核对的投递未知状态。" : code === "ACTIVE_DISPATCH_INVALID" ? "主动投递状态已经变化,请刷新后再继续。" : code === "HANDOFF_SOURCE_STALE" ? "选中源码已经变化,请重新选择当前组件。" : code === "HANDOFF_RESPONSE_TOO_LARGE" ? "交接内容超过上限,请减少所选上下文。" : code === "EXTERNAL_HANDOFF_DISABLED" ? "可信项目配置没有启用外部 Agent 交接。" : code === "EXTERNAL_HANDOFF_UNAVAILABLE" || code === "SESSION_CLOSED" ? "本地外部 Agent Broker 不可用,请重启开发服务。" : "外部 Agent 交接请求失败,未发布任何部分 revision。"
|
|
1216
1392
|
})
|
|
1217
1393
|
});
|
|
1218
1394
|
function createStyles(document) {
|
|
1219
1395
|
const styles = document.createElement("style");
|
|
1220
1396
|
styles.textContent = `
|
|
1397
|
+
${SELECT_PICKER_STYLES}
|
|
1221
1398
|
.spotpatch-external-handoff { margin-top: 12px; padding: 12px; border: 1px solid var(--spotpatch-border); border-radius: var(--spotpatch-radius-card); background: rgb(82 168 255 / 5%); }
|
|
1222
1399
|
.spotpatch-external-handoff[hidden] { display: none; }
|
|
1223
1400
|
.spotpatch-external-heading { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
@@ -1227,8 +1404,10 @@ function createStyles(document) {
|
|
|
1227
1404
|
.spotpatch-external-status[data-state="error"] { border-color: var(--spotpatch-danger); color: #fecdd3; }
|
|
1228
1405
|
.spotpatch-external-status[data-state="picked-up"] { border-color: var(--spotpatch-success); color: #a7f3d0; }
|
|
1229
1406
|
.spotpatch-external-control { margin-top: 9px; padding: 9px; border: 1px solid var(--spotpatch-border); border-radius: 8px; background: rgb(3 7 18 / 28%); }
|
|
1230
|
-
.spotpatch-external-control
|
|
1231
|
-
.spotpatch-external-control
|
|
1407
|
+
.spotpatch-external-control-field { display: grid; gap: 5px; min-width: 0; }
|
|
1408
|
+
.spotpatch-external-control-field + .spotpatch-external-control-field { margin-top: 9px; }
|
|
1409
|
+
.spotpatch-external-control-field > label { color: var(--spotpatch-text-secondary); font-size: 10px; }
|
|
1410
|
+
.spotpatch-external-agent-value { box-sizing: border-box; display: flex; width: 100%; min-height: 38px; align-items: center; border: 1px solid var(--spotpatch-border); border-radius: 9px; padding: 0 11px; overflow: hidden; color: var(--spotpatch-text); background: rgb(255 255 255 / 3%); font: inherit; text-overflow: ellipsis; white-space: nowrap; }
|
|
1232
1411
|
.spotpatch-external-control-status { margin: 7px 0 0; color: #cbd5e1; font-size: 10.5px; line-height: 1.5; white-space: pre-wrap; }
|
|
1233
1412
|
.spotpatch-external-control-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
|
|
1234
1413
|
.spotpatch-external-control-actions button { padding: 5px 8px; border: 1px solid var(--spotpatch-border); border-radius: 6px; background: var(--spotpatch-bg-active); color: var(--spotpatch-text); font: inherit; font-size: 10px; cursor: pointer; }
|
|
@@ -1383,18 +1562,24 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
|
|
|
1383
1562
|
status.setAttribute("aria-live", "polite");
|
|
1384
1563
|
const controlRoot = createMarkedElement(document, "div");
|
|
1385
1564
|
controlRoot.className = "spotpatch-external-control";
|
|
1565
|
+
const agentField = createMarkedElement(document, "div");
|
|
1566
|
+
agentField.className = "spotpatch-external-control-field";
|
|
1386
1567
|
const agentLabel = createMarkedElement(document, "label");
|
|
1387
1568
|
const agentLabelText = createMarkedElement(document, "span");
|
|
1388
|
-
const
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1569
|
+
const agentValue = createMarkedElement(document, "div");
|
|
1570
|
+
agentValue.className = "spotpatch-external-agent-value";
|
|
1571
|
+
agentLabel.append(agentLabelText);
|
|
1572
|
+
agentField.append(agentLabel, agentValue);
|
|
1573
|
+
const modelField = createMarkedElement(document, "div");
|
|
1574
|
+
modelField.className = "spotpatch-external-control-field";
|
|
1393
1575
|
const modelLabel = createMarkedElement(document, "label");
|
|
1394
1576
|
const modelLabelText = createMarkedElement(document, "span");
|
|
1395
|
-
const
|
|
1577
|
+
const modelPicker = createSelectPicker(document, options.onViewChange);
|
|
1578
|
+
const modelSelect = modelPicker.select;
|
|
1579
|
+
modelLabel.htmlFor = modelPicker.trigger.id;
|
|
1396
1580
|
const modelHint = createMarkedElement(document, "p");
|
|
1397
|
-
modelLabel.append(modelLabelText
|
|
1581
|
+
modelLabel.append(modelLabelText);
|
|
1582
|
+
modelField.append(modelLabel, modelPicker.root);
|
|
1398
1583
|
const controlStatus = createMarkedElement(document, "p");
|
|
1399
1584
|
controlStatus.className = "spotpatch-external-control-status";
|
|
1400
1585
|
controlStatus.setAttribute("role", "status");
|
|
@@ -1418,8 +1603,8 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
|
|
|
1418
1603
|
const managedResultDiff = createMarkedElement(document, "pre");
|
|
1419
1604
|
managedResult.append(managedResultTitle, managedResultSummary, managedResultDiff);
|
|
1420
1605
|
controlRoot.append(
|
|
1421
|
-
|
|
1422
|
-
|
|
1606
|
+
agentField,
|
|
1607
|
+
modelField,
|
|
1423
1608
|
modelHint,
|
|
1424
1609
|
controlStatus,
|
|
1425
1610
|
controlActions,
|
|
@@ -1482,10 +1667,11 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
|
|
|
1482
1667
|
}
|
|
1483
1668
|
};
|
|
1484
1669
|
const modelPending = () => control?.mode === "managed" && modelSelect.value !== "" && modelSelect.value !== control.requestedModel;
|
|
1670
|
+
const modelChangeBlocksSend = () => activeAdapter?.canDispatch === true && modelPending();
|
|
1485
1671
|
const controlPending = () => controlOperationBusy || control?.connectionState === "diagnosing" || control?.connectionState === "connecting" || control?.connectionState === "disconnecting";
|
|
1486
1672
|
const refreshActions = () => {
|
|
1487
1673
|
sendButton.textContent = retryable ? messages.retry : activeAdapter?.canDispatch === true ? messages.send : messages.inboxSend;
|
|
1488
|
-
sendButton.disabled = !visible || !brokerReady || !contextReady || operationBusy ||
|
|
1674
|
+
sendButton.disabled = !visible || !brokerReady || !contextReady || operationBusy || modelChangeBlocksSend() || !retryable && dispatchBlocksSend;
|
|
1489
1675
|
sendButton.setAttribute("aria-busy", String(operationBusy));
|
|
1490
1676
|
refreshButton.disabled = !visible || operationBusy;
|
|
1491
1677
|
resolveButton.hidden = !unknownDelivery;
|
|
@@ -1493,8 +1679,8 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
|
|
|
1493
1679
|
};
|
|
1494
1680
|
const refreshControlActions = () => {
|
|
1495
1681
|
connectButton.textContent = modelPending() ? messages.applyModel : messages.connectManaged;
|
|
1496
|
-
modelSelect.disabled = true;
|
|
1497
1682
|
if (control === void 0) {
|
|
1683
|
+
modelPicker.setDisabled(true);
|
|
1498
1684
|
connectButton.disabled = true;
|
|
1499
1685
|
disconnectButton.disabled = true;
|
|
1500
1686
|
revokeButton.disabled = true;
|
|
@@ -1503,7 +1689,9 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
|
|
|
1503
1689
|
}
|
|
1504
1690
|
const state = control.connectionState;
|
|
1505
1691
|
const operationPending = controlPending();
|
|
1506
|
-
|
|
1692
|
+
modelPicker.setDisabled(
|
|
1693
|
+
controlOperationBusy || state === "busy" || !control.models?.length
|
|
1694
|
+
);
|
|
1507
1695
|
connectButton.disabled = operationPending || state === "ready" && !modelPending() || state === "busy";
|
|
1508
1696
|
disconnectButton.disabled = operationPending || state === "disconnected";
|
|
1509
1697
|
revokeButton.disabled = operationPending || control.grantState !== "valid";
|
|
@@ -1560,7 +1748,7 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
|
|
|
1560
1748
|
if (modelSelect.options.length === 1 && modelSelect.options[0]?.value === "") {
|
|
1561
1749
|
modelSelect.options[0].textContent = messages.modelLoading;
|
|
1562
1750
|
}
|
|
1563
|
-
|
|
1751
|
+
agentValue.textContent = messages.codexManaged;
|
|
1564
1752
|
connectButton.textContent = messages.connectManaged;
|
|
1565
1753
|
disconnectButton.textContent = messages.disconnectManaged;
|
|
1566
1754
|
revokeButton.textContent = messages.revokeManaged;
|
|
@@ -1608,12 +1796,13 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
|
|
|
1608
1796
|
})
|
|
1609
1797
|
);
|
|
1610
1798
|
modelSelect.value = models.includes(previous) ? previous : control?.requestedModel ?? models[0] ?? "";
|
|
1799
|
+
modelPicker.rebuild();
|
|
1611
1800
|
};
|
|
1612
1801
|
renderModels();
|
|
1613
1802
|
const unsubscribeLocale = options.subscribeLocale(applyMessages);
|
|
1614
1803
|
applyMessages();
|
|
1615
1804
|
status.textContent = messages.ready;
|
|
1616
|
-
controlStatus.textContent = options.locale() === "zh-CN" ? "
|
|
1805
|
+
controlStatus.textContent = options.locale() === "zh-CN" ? "正在读取本地连接状态……" : "Reading local connection status…";
|
|
1617
1806
|
refreshActions();
|
|
1618
1807
|
refreshControlActions();
|
|
1619
1808
|
const summaryMessage = (summary) => summary.state === "expired" ? messages.expired(summary.revision) : summary.state === "superseded" ? messages.superseded(summary.revision) : summary.pickupCount > 0 ? messages.pickedUp(
|
|
@@ -1663,7 +1852,7 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
|
|
|
1663
1852
|
annotation.targets.length,
|
|
1664
1853
|
paths.length
|
|
1665
1854
|
);
|
|
1666
|
-
disclosureFiles.textContent = paths.length === 0 ? "
|
|
1855
|
+
disclosureFiles.textContent = paths.length === 0 ? "—" : paths.join("\n");
|
|
1667
1856
|
disclosure.hidden = false;
|
|
1668
1857
|
const rootNode = root.getRootNode();
|
|
1669
1858
|
const activeElement = "activeElement" in rootNode ? rootNode.activeElement : document.activeElement;
|
|
@@ -1773,6 +1962,7 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
|
|
|
1773
1962
|
settings.removeEventListener("toggle", options.onViewChange);
|
|
1774
1963
|
managedResult.removeEventListener("toggle", options.onViewChange);
|
|
1775
1964
|
modelSelect.removeEventListener("change", handleModelChange);
|
|
1965
|
+
modelPicker.dispose();
|
|
1776
1966
|
unsubscribeLocale();
|
|
1777
1967
|
}
|
|
1778
1968
|
});
|