@spotpatch/runtime 1.0.0 → 1.1.0
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 +187 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +190 -28
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { SPOTPATCH_API_BASE, RuntimeAiConfig, ContextBudget, SpotPatchLocalePreference } from '@spotpatch/shared';
|
|
1
|
+
import { SPOTPATCH_API_BASE, RuntimeAiConfig, ContextBudget, SpotPatchEditorPreference, SpotPatchLocalePreference } from '@spotpatch/shared';
|
|
2
2
|
|
|
3
3
|
interface RuntimeConfig {
|
|
4
4
|
readonly apiBase: typeof SPOTPATCH_API_BASE;
|
|
5
5
|
readonly ai: RuntimeAiConfig;
|
|
6
6
|
readonly budget: Readonly<ContextBudget>;
|
|
7
7
|
readonly debug: boolean;
|
|
8
|
+
readonly editor: SpotPatchEditorPreference;
|
|
8
9
|
readonly locale: SpotPatchLocalePreference;
|
|
9
10
|
readonly maxTargets: number;
|
|
10
11
|
readonly redact: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { SPOTPATCH_API_BASE, RuntimeAiConfig, ContextBudget, SpotPatchLocalePreference } from '@spotpatch/shared';
|
|
1
|
+
import { SPOTPATCH_API_BASE, RuntimeAiConfig, ContextBudget, SpotPatchEditorPreference, SpotPatchLocalePreference } from '@spotpatch/shared';
|
|
2
2
|
|
|
3
3
|
interface RuntimeConfig {
|
|
4
4
|
readonly apiBase: typeof SPOTPATCH_API_BASE;
|
|
5
5
|
readonly ai: RuntimeAiConfig;
|
|
6
6
|
readonly budget: Readonly<ContextBudget>;
|
|
7
7
|
readonly debug: boolean;
|
|
8
|
+
readonly editor: SpotPatchEditorPreference;
|
|
8
9
|
readonly locale: SpotPatchLocalePreference;
|
|
9
10
|
readonly maxTargets: number;
|
|
10
11
|
readonly redact: boolean;
|
package/dist/index.js
CHANGED
|
@@ -76,6 +76,7 @@ function createAnnotation(input) {
|
|
|
76
76
|
// src/api/runtime-api.ts
|
|
77
77
|
import {
|
|
78
78
|
SPOTPATCH_ENDPOINTS,
|
|
79
|
+
SPOTPATCH_EDITOR_PREFERENCES,
|
|
79
80
|
SPOTPATCH_TOKEN_HEADER,
|
|
80
81
|
getAgentJobEndpoint
|
|
81
82
|
} from "@spotpatch/shared";
|
|
@@ -248,6 +249,9 @@ function readSuccessData(value) {
|
|
|
248
249
|
function isCodeContext(value) {
|
|
249
250
|
return isRecord2(value) && typeof value.relativePath === "string" && (value.language === "tsx" || value.language === "jsx") && typeof value.startLine === "number" && typeof value.endLine === "number" && typeof value.excerpt === "string" && (value.boundary === "component" || value.boundary === "nearby-lines");
|
|
250
251
|
}
|
|
252
|
+
function isEditorOpenResult(value) {
|
|
253
|
+
return isRecord2(value) && typeof value.editor === "string" && SPOTPATCH_EDITOR_PREFERENCES.includes(value.editor);
|
|
254
|
+
}
|
|
251
255
|
function deepFreezeUnknown(value) {
|
|
252
256
|
if (!isRecord2(value) && !Array.isArray(value)) {
|
|
253
257
|
return;
|
|
@@ -474,7 +478,11 @@ function createRuntimeApi(options) {
|
|
|
474
478
|
return Object.freeze({ ...data });
|
|
475
479
|
},
|
|
476
480
|
async openEditor(request) {
|
|
477
|
-
await requestJson(SPOTPATCH_ENDPOINTS.openEditor, "POST", request);
|
|
481
|
+
const data = await requestJson(SPOTPATCH_ENDPOINTS.openEditor, "POST", request);
|
|
482
|
+
if (!isEditorOpenResult(data)) {
|
|
483
|
+
throw new RuntimeApiError();
|
|
484
|
+
}
|
|
485
|
+
return Object.freeze({ editor: data.editor });
|
|
478
486
|
},
|
|
479
487
|
async agentCapability(request) {
|
|
480
488
|
return parseCapability(
|
|
@@ -1504,7 +1512,8 @@ function createSourceResolver(options) {
|
|
|
1504
1512
|
// src/ui/runtime-view.ts
|
|
1505
1513
|
import {
|
|
1506
1514
|
MAX_ANNOTATION_INSTRUCTION_CHARACTERS as MAX_ANNOTATION_INSTRUCTION_CHARACTERS2,
|
|
1507
|
-
MAX_TARGET_INSTRUCTION_CHARACTERS as MAX_TARGET_INSTRUCTION_CHARACTERS2
|
|
1515
|
+
MAX_TARGET_INSTRUCTION_CHARACTERS as MAX_TARGET_INSTRUCTION_CHARACTERS2,
|
|
1516
|
+
SPOTPATCH_REPOSITORY_URL
|
|
1508
1517
|
} from "@spotpatch/shared";
|
|
1509
1518
|
|
|
1510
1519
|
// src/ui/dom.ts
|
|
@@ -2132,6 +2141,15 @@ var STATUS_ZH = Object.freeze({
|
|
|
2132
2141
|
reverted: "\u5DF2\u64A4\u9500",
|
|
2133
2142
|
failed: "\u5931\u8D25"
|
|
2134
2143
|
});
|
|
2144
|
+
function editorName(editor, automatic) {
|
|
2145
|
+
if (editor === "vscode") {
|
|
2146
|
+
return "VS Code";
|
|
2147
|
+
}
|
|
2148
|
+
if (editor === "cursor") {
|
|
2149
|
+
return "Cursor";
|
|
2150
|
+
}
|
|
2151
|
+
return automatic;
|
|
2152
|
+
}
|
|
2135
2153
|
var ERROR_MESSAGES_EN = Object.freeze({
|
|
2136
2154
|
[ERROR_CODES2.INVALID_REQUEST]: "The Agent request was rejected as invalid.",
|
|
2137
2155
|
[ERROR_CODES2.INVALID_TOKEN]: "The local SpotPatch session expired.",
|
|
@@ -2267,7 +2285,12 @@ var UI_MESSAGES = Object.freeze({
|
|
|
2267
2285
|
localeName: "EN",
|
|
2268
2286
|
alternateLocaleName: "\u4E2D",
|
|
2269
2287
|
switchLocale: "Switch interface language to Chinese",
|
|
2270
|
-
brand: Object.freeze({
|
|
2288
|
+
brand: Object.freeze({
|
|
2289
|
+
name: "SpotPatch",
|
|
2290
|
+
context: "Live context",
|
|
2291
|
+
repository: "GitHub",
|
|
2292
|
+
repositoryTitle: "Star SpotPatch on GitHub"
|
|
2293
|
+
}),
|
|
2271
2294
|
trigger: Object.freeze({
|
|
2272
2295
|
select: "Select element",
|
|
2273
2296
|
stop: "Stop selecting",
|
|
@@ -2319,7 +2342,8 @@ var UI_MESSAGES = Object.freeze({
|
|
|
2319
2342
|
actions: Object.freeze({
|
|
2320
2343
|
addElement: "Add element",
|
|
2321
2344
|
reselect: "Start over",
|
|
2322
|
-
openEditor: "Open in
|
|
2345
|
+
openEditor: (editor) => editor === "auto" ? "Open source" : `Open in ${editorName(editor, "editor")}`,
|
|
2346
|
+
openTarget: (index, editor) => `Open target ${String(index)} in ${editorName(editor, "the detected editor")}`,
|
|
2323
2347
|
preview: "Preview prompt",
|
|
2324
2348
|
copy: "Copy prompt",
|
|
2325
2349
|
back: "Back to edit"
|
|
@@ -2375,8 +2399,9 @@ var UI_MESSAGES = Object.freeze({
|
|
|
2375
2399
|
detachedTargetRemoved: "A removed page element was dropped from the selection.",
|
|
2376
2400
|
contextWarning: "Browser context collection completed with a warning.",
|
|
2377
2401
|
contextCollected: "Browser context collected.",
|
|
2378
|
-
|
|
2379
|
-
|
|
2402
|
+
editorOpening: (editor) => `Opening ${editorName(editor, "the detected editor")}\u2026`,
|
|
2403
|
+
editorOpened: (editor) => `Opened the source in ${editorName(editor, "the detected editor")}.`,
|
|
2404
|
+
editorFailed: (editor) => `Could not open ${editorName(editor, "an editor")}. Start the editor or configure editor: "cursor" / "vscode".`,
|
|
2380
2405
|
completeInstructions: "Add an instruction for every target and wait for context collection to finish.",
|
|
2381
2406
|
promptCopied: "Prompt copied to the clipboard.",
|
|
2382
2407
|
clipboardUnavailable: "Clipboard access is unavailable. Select the prompt manually.",
|
|
@@ -2389,7 +2414,12 @@ var UI_MESSAGES = Object.freeze({
|
|
|
2389
2414
|
localeName: "\u4E2D",
|
|
2390
2415
|
alternateLocaleName: "EN",
|
|
2391
2416
|
switchLocale: "\u5C06\u754C\u9762\u8BED\u8A00\u5207\u6362\u4E3A\u82F1\u6587",
|
|
2392
|
-
brand: Object.freeze({
|
|
2417
|
+
brand: Object.freeze({
|
|
2418
|
+
name: "SpotPatch",
|
|
2419
|
+
context: "\u5B9E\u65F6\u4E0A\u4E0B\u6587",
|
|
2420
|
+
repository: "GitHub",
|
|
2421
|
+
repositoryTitle: "\u5728 GitHub \u4E0A Star SpotPatch"
|
|
2422
|
+
}),
|
|
2393
2423
|
trigger: Object.freeze({
|
|
2394
2424
|
select: "\u9009\u62E9\u5143\u7D20",
|
|
2395
2425
|
stop: "\u505C\u6B62\u9009\u62E9",
|
|
@@ -2441,7 +2471,8 @@ var UI_MESSAGES = Object.freeze({
|
|
|
2441
2471
|
actions: Object.freeze({
|
|
2442
2472
|
addElement: "\u6DFB\u52A0\u5143\u7D20",
|
|
2443
2473
|
reselect: "\u91CD\u65B0\u5F00\u59CB",
|
|
2444
|
-
openEditor: "\u5728
|
|
2474
|
+
openEditor: (editor) => editor === "auto" ? "\u6253\u5F00\u6E90\u7801" : `\u5728 ${editorName(editor, "\u7F16\u8F91\u5668")} \u4E2D\u6253\u5F00`,
|
|
2475
|
+
openTarget: (index, editor) => `\u5728${editorName(editor, "\u81EA\u52A8\u68C0\u6D4B\u7684\u7F16\u8F91\u5668")}\u4E2D\u6253\u5F00\u76EE\u6807 ${String(index)} \u7684\u6E90\u7801`,
|
|
2445
2476
|
preview: "\u9884\u89C8 Prompt",
|
|
2446
2477
|
copy: "\u590D\u5236 Prompt",
|
|
2447
2478
|
back: "\u8FD4\u56DE\u7F16\u8F91"
|
|
@@ -2497,8 +2528,9 @@ var UI_MESSAGES = Object.freeze({
|
|
|
2497
2528
|
detachedTargetRemoved: "\u9875\u9762\u4E2D\u7684\u76EE\u6807\u5DF2\u5378\u8F7D\uFF0C\u5DF2\u4ECE\u5F53\u524D\u9009\u62E9\u4E2D\u79FB\u9664\u3002",
|
|
2498
2529
|
contextWarning: "\u6D4F\u89C8\u5668\u4E0A\u4E0B\u6587\u91C7\u96C6\u5B8C\u6210\uFF0C\u4F46\u5B58\u5728\u8B66\u544A\u3002",
|
|
2499
2530
|
contextCollected: "\u6D4F\u89C8\u5668\u4E0A\u4E0B\u6587\u91C7\u96C6\u5B8C\u6210\u3002",
|
|
2500
|
-
|
|
2501
|
-
|
|
2531
|
+
editorOpening: (editor) => `\u6B63\u5728\u6253\u5F00${editorName(editor, "\u81EA\u52A8\u68C0\u6D4B\u7684\u7F16\u8F91\u5668")}\u2026\u2026`,
|
|
2532
|
+
editorOpened: (editor) => `\u5DF2\u5728${editorName(editor, "\u81EA\u52A8\u68C0\u6D4B\u7684\u7F16\u8F91\u5668")}\u4E2D\u6253\u5F00\u6E90\u7801\u3002`,
|
|
2533
|
+
editorFailed: (editor) => `\u65E0\u6CD5\u6253\u5F00${editorName(editor, "\u7F16\u8F91\u5668")}\u3002\u8BF7\u5148\u542F\u52A8\u7F16\u8F91\u5668\uFF0C\u6216\u914D\u7F6E editor: "cursor" / "vscode"\u3002`,
|
|
2502
2534
|
completeInstructions: "\u8BF7\u4E3A\u6BCF\u4E2A\u76EE\u6807\u586B\u5199\u4FEE\u6539\u8BF4\u660E\uFF0C\u5E76\u7B49\u5F85\u4E0A\u4E0B\u6587\u91C7\u96C6\u5B8C\u6210\u3002",
|
|
2503
2535
|
promptCopied: "Prompt \u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F\u3002",
|
|
2504
2536
|
clipboardUnavailable: "\u65E0\u6CD5\u8BBF\u95EE\u526A\u8D34\u677F\uFF0C\u8BF7\u624B\u52A8\u9009\u62E9\u5E76\u590D\u5236 Prompt\u3002",
|
|
@@ -2793,6 +2825,28 @@ function createStyles(document) {
|
|
|
2793
2825
|
gap: 8px;
|
|
2794
2826
|
flex: none;
|
|
2795
2827
|
}
|
|
2828
|
+
.spotpatch-repository {
|
|
2829
|
+
display: inline-flex;
|
|
2830
|
+
height: 30px;
|
|
2831
|
+
align-items: center;
|
|
2832
|
+
gap: 5px;
|
|
2833
|
+
border: 1px solid rgb(68 202 224 / 20%);
|
|
2834
|
+
border-radius: 9px;
|
|
2835
|
+
padding: 0 10px;
|
|
2836
|
+
color: #bcecf2;
|
|
2837
|
+
background: rgb(8 145 178 / 7%);
|
|
2838
|
+
font-size: 11px;
|
|
2839
|
+
font-weight: 680;
|
|
2840
|
+
text-decoration: none;
|
|
2841
|
+
transition: border-color 150ms ease, color 150ms ease, background 150ms ease, transform 150ms ease;
|
|
2842
|
+
}
|
|
2843
|
+
.spotpatch-repository::after { content: "\u2197"; font-size: 10px; }
|
|
2844
|
+
.spotpatch-repository:hover {
|
|
2845
|
+
border-color: rgb(68 202 224 / 42%);
|
|
2846
|
+
color: #e6fbff;
|
|
2847
|
+
background: rgb(8 145 178 / 12%);
|
|
2848
|
+
transform: translateY(-1px);
|
|
2849
|
+
}
|
|
2796
2850
|
.spotpatch-locale {
|
|
2797
2851
|
min-width: 38px;
|
|
2798
2852
|
height: 30px;
|
|
@@ -2936,7 +2990,7 @@ function createStyles(document) {
|
|
|
2936
2990
|
}
|
|
2937
2991
|
.spotpatch-target-summary {
|
|
2938
2992
|
display: grid;
|
|
2939
|
-
grid-template-columns: minmax(0, 1fr) 34px;
|
|
2993
|
+
grid-template-columns: minmax(0, 1fr) 34px 34px;
|
|
2940
2994
|
align-items: stretch;
|
|
2941
2995
|
gap: 4px;
|
|
2942
2996
|
padding: 5px;
|
|
@@ -2987,6 +3041,7 @@ function createStyles(document) {
|
|
|
2987
3041
|
white-space: nowrap;
|
|
2988
3042
|
}
|
|
2989
3043
|
.spotpatch-target-state[data-complete="false"] { color: #f5c97a; background: rgb(245 158 11 / 9%); }
|
|
3044
|
+
.spotpatch-target-open,
|
|
2990
3045
|
.spotpatch-target-remove {
|
|
2991
3046
|
display: inline-grid;
|
|
2992
3047
|
width: 34px;
|
|
@@ -3000,6 +3055,8 @@ function createStyles(document) {
|
|
|
3000
3055
|
background: transparent;
|
|
3001
3056
|
cursor: pointer;
|
|
3002
3057
|
}
|
|
3058
|
+
.spotpatch-target-open { color: #79d9e7; }
|
|
3059
|
+
.spotpatch-target-open:hover:not(:disabled) { border-color: rgb(68 202 224 / 30%); color: #c8f7ff; background: rgb(8 145 178 / 11%); }
|
|
3003
3060
|
.spotpatch-target-remove:hover:not(:disabled) { border-color: rgb(251 113 133 / 24%); color: #fda4af; background: rgb(127 29 29 / 12%); }
|
|
3004
3061
|
.spotpatch-target-editor {
|
|
3005
3062
|
border-top: 1px solid rgb(255 255 255 / 7%);
|
|
@@ -3109,6 +3166,30 @@ function createStyles(document) {
|
|
|
3109
3166
|
border-top: 1px solid rgb(255 255 255 / 8%);
|
|
3110
3167
|
background: rgb(8 12 22 / 82%);
|
|
3111
3168
|
}
|
|
3169
|
+
.spotpatch-editor-feedback {
|
|
3170
|
+
display: flex;
|
|
3171
|
+
width: 100%;
|
|
3172
|
+
align-items: center;
|
|
3173
|
+
gap: 7px;
|
|
3174
|
+
margin-bottom: 1px;
|
|
3175
|
+
color: #9ca5b5;
|
|
3176
|
+
font-size: 11px;
|
|
3177
|
+
line-height: 1.45;
|
|
3178
|
+
}
|
|
3179
|
+
.spotpatch-editor-feedback[hidden] { display: none; }
|
|
3180
|
+
.spotpatch-editor-feedback::before {
|
|
3181
|
+
width: 6px;
|
|
3182
|
+
height: 6px;
|
|
3183
|
+
flex: none;
|
|
3184
|
+
border-radius: 999px;
|
|
3185
|
+
background: #94a3b8;
|
|
3186
|
+
content: "";
|
|
3187
|
+
}
|
|
3188
|
+
.spotpatch-editor-feedback[data-state="opening"]::before { background: #38bdf8; }
|
|
3189
|
+
.spotpatch-editor-feedback[data-state="success"] { color: #9fe3c4; }
|
|
3190
|
+
.spotpatch-editor-feedback[data-state="success"]::before { background: #34d399; }
|
|
3191
|
+
.spotpatch-editor-feedback[data-state="error"] { color: #fecaca; }
|
|
3192
|
+
.spotpatch-editor-feedback[data-state="error"]::before { background: #fb7185; }
|
|
3112
3193
|
.spotpatch-actions button {
|
|
3113
3194
|
display: inline-flex;
|
|
3114
3195
|
min-height: 40px;
|
|
@@ -3140,6 +3221,8 @@ function createStyles(document) {
|
|
|
3140
3221
|
.spotpatch-actions .spotpatch-primary::after { margin-left: 8px; content: "\u2197"; font-size: 12px; }
|
|
3141
3222
|
.spotpatch-actions button:disabled { cursor: not-allowed; opacity: .4; transform: none; }
|
|
3142
3223
|
.spotpatch-actions button:focus-visible,
|
|
3224
|
+
.spotpatch-repository:focus-visible,
|
|
3225
|
+
.spotpatch-target-open:focus-visible,
|
|
3143
3226
|
.spotpatch-target-remove:focus-visible,
|
|
3144
3227
|
.spotpatch-close:focus-visible,
|
|
3145
3228
|
.spotpatch-trigger:focus-visible,
|
|
@@ -3172,6 +3255,8 @@ function createStyles(document) {
|
|
|
3172
3255
|
.spotpatch-actions { padding-left: 16px; padding-right: 16px; }
|
|
3173
3256
|
.spotpatch-target-select { grid-template-columns: 32px minmax(0, 1fr); }
|
|
3174
3257
|
.spotpatch-target-state { display: none; }
|
|
3258
|
+
.spotpatch-repository { width: 30px; overflow: hidden; padding: 0; justify-content: center; color: transparent; }
|
|
3259
|
+
.spotpatch-repository::after { color: #bcecf2; content: "\u2197"; }
|
|
3175
3260
|
}
|
|
3176
3261
|
${AGENT_PANEL_STYLES}
|
|
3177
3262
|
`;
|
|
@@ -3181,7 +3266,7 @@ function summaryLine(summary, prefix) {
|
|
|
3181
3266
|
const line = summary.split("\n").find((candidate) => candidate.startsWith(`${prefix}: `));
|
|
3182
3267
|
return line?.slice(prefix.length + 2).trim();
|
|
3183
3268
|
}
|
|
3184
|
-
function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: false }), localePreference = "auto") {
|
|
3269
|
+
function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: false }), localePreference = "auto", editorPreference = "auto") {
|
|
3185
3270
|
const localizer = createUiLocalizer(document, localePreference);
|
|
3186
3271
|
let messages = localizer.messages();
|
|
3187
3272
|
const host = document.createElement("spotpatch-root");
|
|
@@ -3231,9 +3316,14 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3231
3316
|
brand.append(createBrandMark(document), brandCopy);
|
|
3232
3317
|
const headerControls = createMarkedElement(document, "span");
|
|
3233
3318
|
headerControls.className = "spotpatch-header-controls";
|
|
3319
|
+
const repositoryLink = createMarkedElement(document, "a");
|
|
3320
|
+
repositoryLink.className = "spotpatch-repository";
|
|
3321
|
+
repositoryLink.href = SPOTPATCH_REPOSITORY_URL;
|
|
3322
|
+
repositoryLink.target = "_blank";
|
|
3323
|
+
repositoryLink.rel = "noopener noreferrer";
|
|
3234
3324
|
const localeButton = createButton(document, "", "spotpatch-locale");
|
|
3235
3325
|
const closeButton = createButton(document, "\xD7", "spotpatch-close");
|
|
3236
|
-
headerControls.append(localeButton, closeButton);
|
|
3326
|
+
headerControls.append(repositoryLink, localeButton, closeButton);
|
|
3237
3327
|
brandRow.append(brand, headerControls);
|
|
3238
3328
|
const title = createMarkedElement(document, "h2");
|
|
3239
3329
|
title.id = "spotpatch-selection-title";
|
|
@@ -3297,9 +3387,18 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3297
3387
|
body.append(selectionPanel, previewPanel);
|
|
3298
3388
|
const actions = createMarkedElement(document, "footer");
|
|
3299
3389
|
actions.className = "spotpatch-actions";
|
|
3390
|
+
const editorFeedback = createMarkedElement(document, "div");
|
|
3391
|
+
editorFeedback.className = "spotpatch-editor-feedback";
|
|
3392
|
+
editorFeedback.dataset.state = "idle";
|
|
3393
|
+
editorFeedback.setAttribute("role", "status");
|
|
3394
|
+
editorFeedback.setAttribute("aria-live", "polite");
|
|
3395
|
+
editorFeedback.hidden = true;
|
|
3300
3396
|
const addTargetButton = createButton(document, messages.actions.addElement);
|
|
3301
3397
|
const reselectButton = createButton(document, messages.actions.reselect);
|
|
3302
|
-
const openEditorButton = createButton(
|
|
3398
|
+
const openEditorButton = createButton(
|
|
3399
|
+
document,
|
|
3400
|
+
messages.actions.openEditor(editorPreference)
|
|
3401
|
+
);
|
|
3303
3402
|
const previewButton = createButton(
|
|
3304
3403
|
document,
|
|
3305
3404
|
messages.actions.preview,
|
|
@@ -3308,6 +3407,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3308
3407
|
const copyButton = createButton(document, messages.actions.copy, "spotpatch-primary");
|
|
3309
3408
|
const backButton = createButton(document, messages.actions.back);
|
|
3310
3409
|
actions.append(
|
|
3410
|
+
editorFeedback,
|
|
3311
3411
|
agentPanel.runButton,
|
|
3312
3412
|
previewButton,
|
|
3313
3413
|
agentPanel.testButton,
|
|
@@ -3345,6 +3445,23 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3345
3445
|
let editingEnabled = true;
|
|
3346
3446
|
let currentTargets = [];
|
|
3347
3447
|
let currentMaximum = 0;
|
|
3448
|
+
let currentEditorFeedbackState = "idle";
|
|
3449
|
+
function defaultEditorFeedback(state) {
|
|
3450
|
+
if (state === "opening") {
|
|
3451
|
+
return messages.announcements.editorOpening(editorPreference);
|
|
3452
|
+
}
|
|
3453
|
+
if (state === "success") {
|
|
3454
|
+
return messages.announcements.editorOpened(editorPreference);
|
|
3455
|
+
}
|
|
3456
|
+
return state === "error" ? messages.announcements.editorFailed(editorPreference) : "";
|
|
3457
|
+
}
|
|
3458
|
+
function renderEditorStatus(state, message = defaultEditorFeedback(state)) {
|
|
3459
|
+
currentEditorFeedbackState = state;
|
|
3460
|
+
editorFeedback.dataset.state = state;
|
|
3461
|
+
editorFeedback.hidden = state === "idle";
|
|
3462
|
+
editorFeedback.textContent = message;
|
|
3463
|
+
placeDialog();
|
|
3464
|
+
}
|
|
3348
3465
|
function statusText(target) {
|
|
3349
3466
|
if (target.status === "ready") {
|
|
3350
3467
|
return messages.targets.statusReady;
|
|
@@ -3423,12 +3540,20 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3423
3540
|
state.dataset.complete = String(instructionComplete);
|
|
3424
3541
|
state.textContent = instructionComplete ? messages.targets.instructionReady : messages.targets.instructionMissing;
|
|
3425
3542
|
select.append(number, copy, state);
|
|
3543
|
+
const open = createButton(document, "\u2197", "spotpatch-target-open");
|
|
3544
|
+
open.dataset.openTargetId = target.id;
|
|
3545
|
+
open.disabled = !target.canOpenEditor;
|
|
3546
|
+
open.setAttribute(
|
|
3547
|
+
"aria-label",
|
|
3548
|
+
messages.actions.openTarget(index + 1, editorPreference)
|
|
3549
|
+
);
|
|
3550
|
+
open.title = messages.actions.openTarget(index + 1, editorPreference);
|
|
3426
3551
|
const remove = createButton(document, "\xD7", "spotpatch-target-remove");
|
|
3427
3552
|
remove.dataset.removeTargetId = target.id;
|
|
3428
3553
|
remove.disabled = !editingEnabled;
|
|
3429
3554
|
remove.setAttribute("aria-label", messages.targets.remove(index + 1));
|
|
3430
3555
|
remove.title = messages.targets.removeTitle;
|
|
3431
|
-
targetSummary.append(select, remove);
|
|
3556
|
+
targetSummary.append(select, open, remove);
|
|
3432
3557
|
item.append(targetSummary);
|
|
3433
3558
|
if (target.active) {
|
|
3434
3559
|
const editor = createMarkedElement(document, "label");
|
|
@@ -3606,6 +3731,9 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3606
3731
|
messages = localizer.messages();
|
|
3607
3732
|
brandName.textContent = messages.brand.name;
|
|
3608
3733
|
brandContext.textContent = messages.brand.context;
|
|
3734
|
+
repositoryLink.textContent = messages.brand.repository;
|
|
3735
|
+
repositoryLink.title = messages.brand.repositoryTitle;
|
|
3736
|
+
repositoryLink.setAttribute("aria-label", messages.brand.repositoryTitle);
|
|
3609
3737
|
localeButton.textContent = messages.alternateLocaleName;
|
|
3610
3738
|
localeButton.title = messages.switchLocale;
|
|
3611
3739
|
localeButton.setAttribute("aria-label", messages.switchLocale);
|
|
@@ -3617,13 +3745,14 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3617
3745
|
promptOutput.setAttribute("aria-label", messages.diagnostics.promptAriaLabel);
|
|
3618
3746
|
addTargetButton.textContent = messages.actions.addElement;
|
|
3619
3747
|
reselectButton.textContent = messages.actions.reselect;
|
|
3620
|
-
openEditorButton.textContent = messages.actions.openEditor;
|
|
3748
|
+
openEditorButton.textContent = messages.actions.openEditor(editorPreference);
|
|
3621
3749
|
previewButton.textContent = messages.actions.preview;
|
|
3622
3750
|
copyButton.textContent = messages.actions.copy;
|
|
3623
3751
|
backButton.textContent = messages.actions.back;
|
|
3624
3752
|
triggerButton.title = messages.trigger.title(shortcut);
|
|
3625
3753
|
triggerButton.textContent = currentStatus === "inspecting" ? messages.trigger.stop : messages.trigger.select;
|
|
3626
3754
|
renderPanelStatus(currentStatus);
|
|
3755
|
+
renderEditorStatus(currentEditorFeedbackState);
|
|
3627
3756
|
if (currentTargets.length > 0) {
|
|
3628
3757
|
renderTargets(currentTargets, currentMaximum);
|
|
3629
3758
|
} else {
|
|
@@ -3654,6 +3783,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3654
3783
|
targetList,
|
|
3655
3784
|
reselectButton,
|
|
3656
3785
|
openEditorButton,
|
|
3786
|
+
repositoryLink,
|
|
3657
3787
|
previewButton,
|
|
3658
3788
|
copyButton,
|
|
3659
3789
|
backButton,
|
|
@@ -3673,6 +3803,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3673
3803
|
triggerButton.textContent = inspecting ? messages.trigger.stop : messages.trigger.select;
|
|
3674
3804
|
renderPanelStatus(status);
|
|
3675
3805
|
},
|
|
3806
|
+
renderEditorStatus,
|
|
3676
3807
|
showHighlight(rect, label) {
|
|
3677
3808
|
currentRect = rect;
|
|
3678
3809
|
highlight.hidden = false;
|
|
@@ -3716,6 +3847,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3716
3847
|
currentTargets = [];
|
|
3717
3848
|
currentMaximum = 0;
|
|
3718
3849
|
currentSummaryText = "";
|
|
3850
|
+
renderEditorStatus("idle");
|
|
3719
3851
|
targetCount.textContent = messages.targets.count(0, 0);
|
|
3720
3852
|
targetComplete.textContent = messages.targets.complete(0, 0);
|
|
3721
3853
|
targetLabel.textContent = messages.context.selectedElement;
|
|
@@ -3759,7 +3891,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3759
3891
|
).forEach((control) => {
|
|
3760
3892
|
control.disabled = !enabled;
|
|
3761
3893
|
});
|
|
3762
|
-
openEditorButton.disabled = !
|
|
3894
|
+
openEditorButton.disabled = !currentCanOpenEditor;
|
|
3763
3895
|
previewButton.disabled = !enabled || !currentCanPreview;
|
|
3764
3896
|
agentPanel.setEditingEnabled(enabled);
|
|
3765
3897
|
placeDialog();
|
|
@@ -4249,7 +4381,13 @@ function resolveBrowserDependencies(dependencies) {
|
|
|
4249
4381
|
}
|
|
4250
4382
|
function createController(config, dependencies = {}) {
|
|
4251
4383
|
const browser = resolveBrowserDependencies(dependencies);
|
|
4252
|
-
const view = dependencies.view ?? createRuntimeView(
|
|
4384
|
+
const view = dependencies.view ?? createRuntimeView(
|
|
4385
|
+
browser.document,
|
|
4386
|
+
config.shortcut,
|
|
4387
|
+
config.ai,
|
|
4388
|
+
config.locale,
|
|
4389
|
+
config.editor
|
|
4390
|
+
);
|
|
4253
4391
|
const api = dependencies.api ?? createRuntimeApi({
|
|
4254
4392
|
apiBase: config.apiBase,
|
|
4255
4393
|
fetch: browser.window.fetch.bind(browser.window),
|
|
@@ -4280,6 +4418,7 @@ function createController(config, dependencies = {}) {
|
|
|
4280
4418
|
let activeTargetId;
|
|
4281
4419
|
let targetSequence = 0;
|
|
4282
4420
|
let sessionRevision = 0;
|
|
4421
|
+
let editorRequestRevision = 0;
|
|
4283
4422
|
let addingTarget = false;
|
|
4284
4423
|
let previewPrompt = "";
|
|
4285
4424
|
let previousFocus;
|
|
@@ -4354,6 +4493,7 @@ ${summary}`;
|
|
|
4354
4493
|
id: target.id,
|
|
4355
4494
|
label: target.resolution.react.componentName ?? (target.element === void 0 ? target.elementContext?.tagName ?? "Element" : elementLabel(target.element)),
|
|
4356
4495
|
source: sourceLabel(target, view.messages().context.sourceUnavailable),
|
|
4496
|
+
canOpenEditor: target.marker !== void 0,
|
|
4357
4497
|
status: targetStatus(target),
|
|
4358
4498
|
active: target.id === activeTargetId,
|
|
4359
4499
|
instruction: target.instruction
|
|
@@ -4497,7 +4637,6 @@ ${summary}`;
|
|
|
4497
4637
|
resizeObserver?.disconnect();
|
|
4498
4638
|
for (const target of targets) {
|
|
4499
4639
|
target.element = void 0;
|
|
4500
|
-
target.marker = void 0;
|
|
4501
4640
|
}
|
|
4502
4641
|
view.hideHighlight();
|
|
4503
4642
|
view.hideSelectionHighlights();
|
|
@@ -4774,24 +4913,37 @@ ${summary}`;
|
|
|
4774
4913
|
}
|
|
4775
4914
|
refreshHighlights();
|
|
4776
4915
|
}
|
|
4777
|
-
function handleOpenEditor() {
|
|
4778
|
-
const current = activeTarget();
|
|
4916
|
+
function handleOpenEditor(targetId) {
|
|
4917
|
+
const current = targetId === void 0 ? activeTarget() : targets.find((target) => target.id === targetId);
|
|
4779
4918
|
if (state.status !== "selected" || current?.marker === void 0) {
|
|
4780
4919
|
return;
|
|
4781
4920
|
}
|
|
4921
|
+
if (activeTargetId !== current.id) {
|
|
4922
|
+
activeTargetId = current.id;
|
|
4923
|
+
refreshSelectionView();
|
|
4924
|
+
}
|
|
4782
4925
|
const marker = current.marker;
|
|
4926
|
+
const selectionRevision = sessionRevision;
|
|
4927
|
+
const requestRevision = ++editorRequestRevision;
|
|
4783
4928
|
transition({ type: "OPEN_EDITOR" });
|
|
4929
|
+
const openingMessage = view.messages().announcements.editorOpening(config.editor);
|
|
4930
|
+
view.renderEditorStatus("opening", openingMessage);
|
|
4931
|
+
view.announce(openingMessage);
|
|
4784
4932
|
void api.openEditor({
|
|
4785
4933
|
fileId: marker.fileId,
|
|
4786
4934
|
line: marker.line,
|
|
4787
4935
|
column: marker.column
|
|
4788
|
-
}).then(() => {
|
|
4789
|
-
if (mounted && state.status === "selected") {
|
|
4790
|
-
view.
|
|
4936
|
+
}).then((result) => {
|
|
4937
|
+
if (mounted && state.status === "selected" && selectionRevision === sessionRevision && requestRevision === editorRequestRevision && activeTargetId === current.id && targets.includes(current)) {
|
|
4938
|
+
const message = view.messages().announcements.editorOpened(result.editor);
|
|
4939
|
+
view.renderEditorStatus("success", message);
|
|
4940
|
+
view.announce(message);
|
|
4791
4941
|
}
|
|
4792
4942
|
}).catch(() => {
|
|
4793
|
-
if (mounted && state.status === "selected") {
|
|
4794
|
-
view.
|
|
4943
|
+
if (mounted && state.status === "selected" && selectionRevision === sessionRevision && requestRevision === editorRequestRevision && activeTargetId === current.id && targets.includes(current)) {
|
|
4944
|
+
const message = view.messages().announcements.editorFailed(config.editor);
|
|
4945
|
+
view.renderEditorStatus("error", message);
|
|
4946
|
+
view.announce(message);
|
|
4795
4947
|
}
|
|
4796
4948
|
});
|
|
4797
4949
|
}
|
|
@@ -4808,6 +4960,9 @@ ${summary}`;
|
|
|
4808
4960
|
view.updateTargetInstruction(target.id, target.instruction);
|
|
4809
4961
|
view.setPreviewEnabled(canPreview());
|
|
4810
4962
|
}
|
|
4963
|
+
function handleOpenEditorButtonClick() {
|
|
4964
|
+
handleOpenEditor();
|
|
4965
|
+
}
|
|
4811
4966
|
function handleTargetListKeydown(event) {
|
|
4812
4967
|
if (config.ai.enabled && state.status === "selected" && event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
|
|
4813
4968
|
event.preventDefault();
|
|
@@ -4885,6 +5040,13 @@ ${summary}`;
|
|
|
4885
5040
|
removeTarget(removeButton.dataset.removeTargetId);
|
|
4886
5041
|
return;
|
|
4887
5042
|
}
|
|
5043
|
+
const openButton = eventTarget.closest(
|
|
5044
|
+
"button[data-open-target-id]"
|
|
5045
|
+
);
|
|
5046
|
+
if (openButton?.dataset.openTargetId !== void 0) {
|
|
5047
|
+
handleOpenEditor(openButton.dataset.openTargetId);
|
|
5048
|
+
return;
|
|
5049
|
+
}
|
|
4888
5050
|
const activateButton = eventTarget.closest(
|
|
4889
5051
|
"button[data-activate-target-id]"
|
|
4890
5052
|
);
|
|
@@ -4916,7 +5078,7 @@ ${summary}`;
|
|
|
4916
5078
|
view.targetList.addEventListener("click", handleTargetListClick);
|
|
4917
5079
|
view.targetList.addEventListener("input", handleTargetListInput);
|
|
4918
5080
|
view.targetList.addEventListener("keydown", handleTargetListKeydown);
|
|
4919
|
-
view.openEditorButton.addEventListener("click",
|
|
5081
|
+
view.openEditorButton.addEventListener("click", handleOpenEditorButtonClick);
|
|
4920
5082
|
view.previewButton.addEventListener("click", handlePreview);
|
|
4921
5083
|
view.copyButton.addEventListener("click", handleCopy);
|
|
4922
5084
|
view.backButton.addEventListener("click", handleBack);
|
|
@@ -4976,7 +5138,7 @@ ${summary}`;
|
|
|
4976
5138
|
view.targetList.removeEventListener("click", handleTargetListClick);
|
|
4977
5139
|
view.targetList.removeEventListener("input", handleTargetListInput);
|
|
4978
5140
|
view.targetList.removeEventListener("keydown", handleTargetListKeydown);
|
|
4979
|
-
view.openEditorButton.removeEventListener("click",
|
|
5141
|
+
view.openEditorButton.removeEventListener("click", handleOpenEditorButtonClick);
|
|
4980
5142
|
view.previewButton.removeEventListener("click", handlePreview);
|
|
4981
5143
|
view.copyButton.removeEventListener("click", handleCopy);
|
|
4982
5144
|
view.backButton.removeEventListener("click", handleBack);
|