@jay-framework/aiditor 0.17.3 → 0.18.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/README.md +1 -5
- package/dist/actions/check-add-page-route.jay-action +12 -0
- package/dist/actions/check-add-page-route.jay-action.d.ts +10 -0
- package/dist/actions/check-page-add-page-brief.jay-action +9 -0
- package/dist/actions/check-page-add-page-brief.jay-action.d.ts +8 -0
- package/dist/actions/check-plugin-update.jay-action +14 -0
- package/dist/actions/check-plugin-update.jay-action.d.ts +13 -0
- package/dist/actions/ensure-project-plugin.jay-action +9 -0
- package/dist/actions/ensure-project-plugin.jay-action.d.ts +8 -0
- package/dist/actions/generate-add-page-brief-from-image.jay-action +20 -0
- package/dist/actions/generate-add-page-brief-from-image.jay-action.d.ts +20 -0
- package/dist/actions/get-plugin-setup-status.jay-action +9 -0
- package/dist/actions/get-plugin-setup-status.jay-action.d.ts +6 -0
- package/dist/actions/list-jay-plugins.jay-action +8 -0
- package/dist/actions/list-jay-plugins.jay-action.d.ts +5 -0
- package/dist/actions/list-plugin-contracts.jay-action +11 -0
- package/dist/actions/list-plugin-contracts.jay-action.d.ts +9 -0
- package/dist/actions/open-add-page-from-brief.jay-action +20 -0
- package/dist/actions/open-add-page-from-brief.jay-action.d.ts +18 -0
- package/dist/actions/reclassify-add-page-asset.jay-action +12 -0
- package/dist/actions/reclassify-add-page-asset.jay-action.d.ts +10 -0
- package/dist/actions/rerun-plugin-setup.jay-action +12 -0
- package/dist/actions/rerun-plugin-setup.jay-action.d.ts +10 -0
- package/dist/actions/save-add-page-draft.jay-action +10 -0
- package/dist/actions/save-add-page-draft.jay-action.d.ts +9 -0
- package/dist/actions/start-add-page-request.jay-action +12 -0
- package/dist/actions/start-add-page-request.jay-action.d.ts +10 -0
- package/dist/actions/submit-add-page.jay-action +21 -0
- package/dist/actions/submit-add-page.jay-action.d.ts +17 -0
- package/dist/actions/submit-task.jay-action +1 -0
- package/dist/actions/submit-task.jay-action.d.ts +1 -0
- package/dist/actions/sync-add-page-plugin-manifest.jay-action +11 -0
- package/dist/actions/sync-add-page-plugin-manifest.jay-action.d.ts +9 -0
- package/dist/actions/upload-add-page-asset.jay-action +13 -0
- package/dist/actions/upload-add-page-asset.jay-action.d.ts +13 -0
- package/dist/actions/write-plugin-source.jay-action +13 -0
- package/dist/actions/write-plugin-source.jay-action.d.ts +12 -0
- package/dist/add-page-agent/SKILL.md +79 -0
- package/dist/add-page-agent/system.md +47 -0
- package/dist/index.client.js +2696 -278
- package/dist/index.d.ts +797 -6
- package/dist/index.js +2682 -14
- package/dist/pages/aiditor/page.jay-html +603 -2
- package/dist/prompts/add-page-figma-brief-prompt.md +163 -0
- package/dist/prompts/add-page-figma-design-definitions-prompt.md +256 -0
- package/dist/prompts/add-page-figma-design-from-image-prompt.md +144 -0
- package/package.json +24 -7
- package/plugin.yaml +34 -0
package/dist/index.client.js
CHANGED
|
@@ -10,6 +10,9 @@ const visualModeToForm = {
|
|
|
10
10
|
video: "5"
|
|
11
11
|
};
|
|
12
12
|
const CHANNEL_MAX_FILE_PARTS = 300;
|
|
13
|
+
function isChatSubmitOptions(options) {
|
|
14
|
+
return options != null && "kind" in options && options.kind === "chat";
|
|
15
|
+
}
|
|
13
16
|
function countAttachmentFiles(m) {
|
|
14
17
|
if (!m) return 0;
|
|
15
18
|
let n = 0;
|
|
@@ -26,14 +29,18 @@ function validateMultipartPartBudget(options) {
|
|
|
26
29
|
}
|
|
27
30
|
return null;
|
|
28
31
|
}
|
|
29
|
-
function submitAndStreamTask(notes,
|
|
32
|
+
function submitAndStreamTask(notes, options, callbacks) {
|
|
30
33
|
let aborted = false;
|
|
31
34
|
const abort = () => {
|
|
32
35
|
aborted = true;
|
|
33
36
|
};
|
|
34
37
|
const input = { notes };
|
|
35
|
-
if (
|
|
36
|
-
|
|
38
|
+
if (isChatSubmitOptions(options)) {
|
|
39
|
+
input.messageKind = "chat";
|
|
40
|
+
input.pageRoute = options.pageRoute;
|
|
41
|
+
input.renderedUrl = options.renderedUrl;
|
|
42
|
+
} else if (options?.mode === "video") {
|
|
43
|
+
const v = options;
|
|
37
44
|
const attCount = countAttachmentFiles(v.attachmentsByPin);
|
|
38
45
|
const includeVideo = Boolean(v.video);
|
|
39
46
|
const err = validateMultipartPartBudget({
|
|
@@ -76,8 +83,8 @@ function submitAndStreamTask(notes, visual, callbacks) {
|
|
|
76
83
|
}
|
|
77
84
|
}
|
|
78
85
|
input.extraFiles = extraFiles;
|
|
79
|
-
} else if (
|
|
80
|
-
const v =
|
|
86
|
+
} else if (options?.dual) {
|
|
87
|
+
const v = options;
|
|
81
88
|
input.visualTask = visualModeToForm[v.mode];
|
|
82
89
|
input.pageRoute = v.pageRoute;
|
|
83
90
|
input.renderedUrl = v.renderedUrl;
|
|
@@ -7975,7 +7982,7 @@ function freezeTransientStyles(iframeEl) {
|
|
|
7975
7982
|
const seen = /* @__PURE__ */ new Set();
|
|
7976
7983
|
for (const pseudo of TRANSIENT_PSEUDOCLASSES) {
|
|
7977
7984
|
try {
|
|
7978
|
-
for (const el of doc.querySelectorAll(pseudo)) seen.add(el);
|
|
7985
|
+
for (const el of Array.from(doc.querySelectorAll(pseudo))) seen.add(el);
|
|
7979
7986
|
} catch {
|
|
7980
7987
|
}
|
|
7981
7988
|
}
|
|
@@ -8553,7 +8560,17 @@ function stopMediaStreamTracks(stream) {
|
|
|
8553
8560
|
}
|
|
8554
8561
|
}
|
|
8555
8562
|
const AIDITOR_NOTES_VERSION = 1;
|
|
8563
|
+
const AIDITOR_NOTES_BINDING_VERSION = 1.1;
|
|
8564
|
+
function serializedAnnotationHasBindings(annotation) {
|
|
8565
|
+
return (annotation.pluginBindings?.length ?? 0) > 0 || !!annotation.pluginBinding;
|
|
8566
|
+
}
|
|
8556
8567
|
function serializeAiditorNotes(payload) {
|
|
8568
|
+
if ("annotations" in payload && payload.annotations.some((a2) => serializedAnnotationHasBindings(a2))) {
|
|
8569
|
+
return JSON.stringify({
|
|
8570
|
+
...payload,
|
|
8571
|
+
version: AIDITOR_NOTES_BINDING_VERSION
|
|
8572
|
+
});
|
|
8573
|
+
}
|
|
8557
8574
|
return JSON.stringify(payload);
|
|
8558
8575
|
}
|
|
8559
8576
|
function resolvePreviewContextAtTime(timeSec, navLog, fallback) {
|
|
@@ -8680,178 +8697,183 @@ function joinHttpBaseUrlAndPath(httpBaseUrl, pathname) {
|
|
|
8680
8697
|
const path = !pathname || pathname === "/" ? "/" : pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
8681
8698
|
return new URL(path, baseUrl).href;
|
|
8682
8699
|
}
|
|
8683
|
-
|
|
8684
|
-
const
|
|
8685
|
-
|
|
8686
|
-
|
|
8687
|
-
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
}
|
|
8692
|
-
function
|
|
8693
|
-
return
|
|
8700
|
+
const checkAddPageRouteAction = createActionCaller("aiditor.checkAddPageRoute", "GET");
|
|
8701
|
+
const startAddPageRequestAction = createActionCaller("aiditor.startAddPageRequest", "GET");
|
|
8702
|
+
createActionCaller("aiditor.saveAddPageDraft", "GET");
|
|
8703
|
+
const uploadAddPageAssetAction = createActionCaller("aiditor.uploadAddPageAsset", "POST", { acceptsFiles: true });
|
|
8704
|
+
const reclassifyAddPageAssetAction = createActionCaller("aiditor.reclassifyAddPageAsset", "GET");
|
|
8705
|
+
const checkPageAddPageBriefAction = createActionCaller("aiditor.checkPageAddPageBrief", "GET");
|
|
8706
|
+
const openAddPageFromBriefAction = createActionCaller("aiditor.openAddPageFromBrief", "GET");
|
|
8707
|
+
const submitAddPageAction = createStreamCaller("aiditor.submitAddPage");
|
|
8708
|
+
const generateAddPageBriefFromImageAction = createActionCaller("aiditor.generateAddPageBriefFromImage", "POST", { acceptsFiles: true });
|
|
8709
|
+
async function checkAddPageRoute(pageRoute) {
|
|
8710
|
+
return checkAddPageRouteAction({ pageRoute });
|
|
8694
8711
|
}
|
|
8695
|
-
function
|
|
8696
|
-
return
|
|
8712
|
+
async function startAddPageRequest(pageRoute) {
|
|
8713
|
+
return startAddPageRequestAction({ pageRoute });
|
|
8697
8714
|
}
|
|
8698
|
-
function
|
|
8699
|
-
|
|
8700
|
-
return { kind: "point", x: a2.x, y: a2.y };
|
|
8701
|
-
if (a2.kind === "area")
|
|
8702
|
-
return { kind: "area", x: a2.x, y: a2.y, w: a2.w, h: a2.h };
|
|
8703
|
-
return { kind: "arrow", x1: a2.x1, y1: a2.y1, x2: a2.x2, y2: a2.y2 };
|
|
8715
|
+
async function uploadAddPageAsset(input) {
|
|
8716
|
+
return uploadAddPageAssetAction(input);
|
|
8704
8717
|
}
|
|
8705
|
-
function
|
|
8706
|
-
return
|
|
8707
|
-
version: AIDITOR_NOTES_VERSION,
|
|
8708
|
-
breakpoint,
|
|
8709
|
-
annotations: annotations.map((a2) => ({
|
|
8710
|
-
id: a2.id,
|
|
8711
|
-
mode: a2.kind,
|
|
8712
|
-
instruction: a2.instruction.trim(),
|
|
8713
|
-
geometry: serializeGeometry(a2)
|
|
8714
|
-
}))
|
|
8715
|
-
};
|
|
8718
|
+
async function reclassifyAddPageAsset(input) {
|
|
8719
|
+
return reclassifyAddPageAssetAction(input);
|
|
8716
8720
|
}
|
|
8717
|
-
function
|
|
8718
|
-
const
|
|
8719
|
-
|
|
8720
|
-
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
|
|
8729
|
-
return {
|
|
8730
|
-
id: a2.id,
|
|
8731
|
-
mode: a2.kind,
|
|
8732
|
-
instruction: a2.instruction.trim(),
|
|
8733
|
-
geometry: serializeGeometry(a2),
|
|
8734
|
-
timeSec: a2.timeSec,
|
|
8735
|
-
previewUrlAtTime: ctx.href,
|
|
8736
|
-
pagePathAtTime: ctx.locationPath
|
|
8737
|
-
};
|
|
8738
|
-
})
|
|
8739
|
-
};
|
|
8740
|
-
return JSON.stringify(payload);
|
|
8721
|
+
async function generateAddPageBriefFromImage(input) {
|
|
8722
|
+
const extraFiles = {};
|
|
8723
|
+
input.images.forEach((file, i) => {
|
|
8724
|
+
extraFiles[`image_${i}`] = file;
|
|
8725
|
+
});
|
|
8726
|
+
return generateAddPageBriefFromImageAction({
|
|
8727
|
+
target: input.target,
|
|
8728
|
+
requestId: input.requestId,
|
|
8729
|
+
pageRoute: input.pageRoute,
|
|
8730
|
+
contextNotes: input.contextNotes,
|
|
8731
|
+
extraFiles
|
|
8732
|
+
});
|
|
8741
8733
|
}
|
|
8742
|
-
function
|
|
8743
|
-
|
|
8744
|
-
|
|
8745
|
-
|
|
8746
|
-
instruction: a2.instruction,
|
|
8747
|
-
geometry: serializeGeometry(a2),
|
|
8748
|
-
timeSec: a2.timeSec
|
|
8734
|
+
function submitAddPageStream(input, callbacks) {
|
|
8735
|
+
let aborted = false;
|
|
8736
|
+
const abort = () => {
|
|
8737
|
+
aborted = true;
|
|
8749
8738
|
};
|
|
8739
|
+
void (async () => {
|
|
8740
|
+
try {
|
|
8741
|
+
for await (const chunk of submitAddPageAction(input)) {
|
|
8742
|
+
if (aborted) break;
|
|
8743
|
+
callbacks.onChunk(chunk);
|
|
8744
|
+
if (chunk.type === "done" || chunk.type === "error") {
|
|
8745
|
+
callbacks.onEnd();
|
|
8746
|
+
return;
|
|
8747
|
+
}
|
|
8748
|
+
}
|
|
8749
|
+
if (!aborted) callbacks.onEnd();
|
|
8750
|
+
} catch (err) {
|
|
8751
|
+
if (!aborted) {
|
|
8752
|
+
callbacks.onError(err instanceof Error ? err : new Error(String(err)));
|
|
8753
|
+
}
|
|
8754
|
+
}
|
|
8755
|
+
})();
|
|
8756
|
+
return abort;
|
|
8750
8757
|
}
|
|
8751
|
-
function
|
|
8752
|
-
|
|
8753
|
-
return "Point";
|
|
8754
|
-
if (kind === "area")
|
|
8755
|
-
return "Area";
|
|
8756
|
-
return "Arrow";
|
|
8758
|
+
async function checkPageAddPageBrief(input) {
|
|
8759
|
+
return checkPageAddPageBriefAction(input);
|
|
8757
8760
|
}
|
|
8758
|
-
|
|
8759
|
-
|
|
8760
|
-
return Math.abs(playheadSec - annotationTimeSec) <= VIDEO_ANNOTATION_TIME_TOLERANCE_SEC;
|
|
8761
|
+
async function openAddPageFromBrief(input) {
|
|
8762
|
+
return openAddPageFromBriefAction(input);
|
|
8761
8763
|
}
|
|
8762
|
-
function
|
|
8763
|
-
if (
|
|
8764
|
-
return {
|
|
8765
|
-
if (a2.kind === "area") {
|
|
8766
|
-
return { nx: Math.min(1, a2.x + a2.w), ny: Math.min(1, a2.y + a2.h) };
|
|
8764
|
+
async function ensureAddPageRequestId(pageRoute, currentRequestId) {
|
|
8765
|
+
if (currentRequestId) {
|
|
8766
|
+
return { requestId: currentRequestId };
|
|
8767
8767
|
}
|
|
8768
|
-
|
|
8768
|
+
const trimmed = pageRoute.trim();
|
|
8769
|
+
if (!trimmed) {
|
|
8770
|
+
return {
|
|
8771
|
+
requestId: "",
|
|
8772
|
+
error: "Enter a page route before attaching files or pasting images."
|
|
8773
|
+
};
|
|
8774
|
+
}
|
|
8775
|
+
const result = await startAddPageRequest(trimmed);
|
|
8776
|
+
if (result.routeExists) {
|
|
8777
|
+
return {
|
|
8778
|
+
requestId: "",
|
|
8779
|
+
error: result.routeExistsMessage ?? "This route already exists."
|
|
8780
|
+
};
|
|
8781
|
+
}
|
|
8782
|
+
if (!result.requestId) {
|
|
8783
|
+
return {
|
|
8784
|
+
requestId: "",
|
|
8785
|
+
error: result.routeExistsMessage ?? "Could not create page request. Check the route and try again."
|
|
8786
|
+
};
|
|
8787
|
+
}
|
|
8788
|
+
return { requestId: result.requestId };
|
|
8769
8789
|
}
|
|
8770
|
-
|
|
8771
|
-
const
|
|
8772
|
-
|
|
8773
|
-
|
|
8774
|
-
|
|
8775
|
-
|
|
8776
|
-
}
|
|
8790
|
+
function insertTextAtCursor(textarea, text, currentValue) {
|
|
8791
|
+
const start = textarea.selectionStart ?? currentValue.length;
|
|
8792
|
+
const end = textarea.selectionEnd ?? start;
|
|
8793
|
+
const before = currentValue.slice(0, start);
|
|
8794
|
+
const after = currentValue.slice(end);
|
|
8795
|
+
const prefix = before.length > 0 && !before.endsWith("\n") ? "\n" : "";
|
|
8796
|
+
const insertion = `${prefix}${text}
|
|
8797
|
+
`;
|
|
8798
|
+
const next = before + insertion + after;
|
|
8799
|
+
const newPos = before.length + insertion.length;
|
|
8800
|
+
queueMicrotask(() => {
|
|
8801
|
+
textarea.selectionStart = newPos;
|
|
8802
|
+
textarea.selectionEnd = newPos;
|
|
8803
|
+
textarea.focus();
|
|
8804
|
+
});
|
|
8805
|
+
return next;
|
|
8777
8806
|
}
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
|
|
8807
|
+
function inferRouteKindFromRoute(route) {
|
|
8808
|
+
return /\[[^\]/]+\]/.test(route) ? "dynamic" : "static";
|
|
8809
|
+
}
|
|
8810
|
+
const BRIEF_FILL_MAX_IMAGES = 5;
|
|
8811
|
+
function dedupePastedFiles$1(files) {
|
|
8781
8812
|
const seen = /* @__PURE__ */ new Set();
|
|
8782
8813
|
const out = [];
|
|
8783
8814
|
for (const f2 of files) {
|
|
8784
|
-
const k = `${f2.name}
|
|
8785
|
-
if (seen.has(k))
|
|
8786
|
-
continue;
|
|
8815
|
+
const k = `${f2.name}:${f2.size}:${f2.type}`;
|
|
8816
|
+
if (seen.has(k)) continue;
|
|
8787
8817
|
seen.add(k);
|
|
8788
8818
|
out.push(f2);
|
|
8789
8819
|
}
|
|
8790
8820
|
return out;
|
|
8791
8821
|
}
|
|
8792
|
-
function filesFromClipboardData(cd) {
|
|
8793
|
-
if (!cd)
|
|
8794
|
-
return [];
|
|
8822
|
+
function filesFromClipboardData$1(cd) {
|
|
8823
|
+
if (!cd) return [];
|
|
8795
8824
|
const accum = [];
|
|
8796
8825
|
for (let i = 0; i < cd.files.length; i++) {
|
|
8797
8826
|
const f2 = cd.files.item(i);
|
|
8798
|
-
if (f2)
|
|
8799
|
-
accum.push(f2);
|
|
8827
|
+
if (f2) accum.push(f2);
|
|
8800
8828
|
}
|
|
8801
8829
|
if (cd.items) {
|
|
8802
8830
|
for (let i = 0; i < cd.items.length; i++) {
|
|
8803
8831
|
const it = cd.items[i];
|
|
8804
8832
|
if (it?.kind === "file") {
|
|
8805
8833
|
const f2 = it.getAsFile();
|
|
8806
|
-
if (f2)
|
|
8807
|
-
accum.push(f2);
|
|
8834
|
+
if (f2) accum.push(f2);
|
|
8808
8835
|
}
|
|
8809
8836
|
}
|
|
8810
8837
|
}
|
|
8811
|
-
return dedupePastedFiles(accum);
|
|
8812
|
-
}
|
|
8813
|
-
function clipboardItemsArray(cd) {
|
|
8814
|
-
const items = cd?.items;
|
|
8815
|
-
if (!items || items.length === 0)
|
|
8816
|
-
return [];
|
|
8817
|
-
return Array.from({ length: items.length }, (_, i) => items[i]).filter(Boolean);
|
|
8838
|
+
return dedupePastedFiles$1(accum).filter((f2) => f2.type.startsWith("image/"));
|
|
8818
8839
|
}
|
|
8819
|
-
function
|
|
8840
|
+
function dataUrlToImageFile(dataUrl, index) {
|
|
8820
8841
|
const comma = dataUrl.indexOf(",");
|
|
8821
|
-
if (comma < 0)
|
|
8822
|
-
return null;
|
|
8842
|
+
if (comma < 0) return null;
|
|
8823
8843
|
const header = dataUrl.slice(0, comma);
|
|
8824
8844
|
const dataPart = dataUrl.slice(comma + 1);
|
|
8825
8845
|
const mimeMatch = header.match(/^data:([^;,]+)/i);
|
|
8826
8846
|
const mime = mimeMatch?.[1]?.trim() ?? "";
|
|
8827
|
-
if (!mime.startsWith("image/"))
|
|
8828
|
-
return null;
|
|
8847
|
+
if (!mime.startsWith("image/")) return null;
|
|
8829
8848
|
const isBase64 = /;base64/i.test(header);
|
|
8830
8849
|
let bytes;
|
|
8831
8850
|
if (isBase64) {
|
|
8832
8851
|
try {
|
|
8833
8852
|
const bin = atob(dataPart.replace(/\s/g, ""));
|
|
8834
8853
|
bytes = new Uint8Array(bin.length);
|
|
8835
|
-
for (let i = 0; i < bin.length; i++)
|
|
8836
|
-
bytes[i] = bin.charCodeAt(i);
|
|
8854
|
+
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
|
|
8837
8855
|
} catch {
|
|
8838
8856
|
return null;
|
|
8839
8857
|
}
|
|
8840
8858
|
} else {
|
|
8841
8859
|
try {
|
|
8842
|
-
bytes = new TextEncoder().encode(
|
|
8860
|
+
bytes = new TextEncoder().encode(
|
|
8861
|
+
decodeURIComponent(dataPart.replace(/\+/g, "%20"))
|
|
8862
|
+
);
|
|
8843
8863
|
} catch {
|
|
8844
8864
|
return null;
|
|
8845
8865
|
}
|
|
8846
8866
|
}
|
|
8847
8867
|
const extPart = mime.split("/")[1] || "png";
|
|
8848
8868
|
const ext = extPart.replace(/\+xml$/, "").split("+")[0] || "png";
|
|
8849
|
-
const buf = bytes.buffer.slice(
|
|
8869
|
+
const buf = bytes.buffer.slice(
|
|
8870
|
+
bytes.byteOffset,
|
|
8871
|
+
bytes.byteOffset + bytes.byteLength
|
|
8872
|
+
);
|
|
8850
8873
|
return new File([buf], `paste-${index}.${ext}`, { type: mime });
|
|
8851
8874
|
}
|
|
8852
|
-
function filesFromPastedHtmlDataUrls(html) {
|
|
8853
|
-
if (!html)
|
|
8854
|
-
return [];
|
|
8875
|
+
function filesFromPastedHtmlDataUrls$1(html) {
|
|
8876
|
+
if (!html) return [];
|
|
8855
8877
|
let doc;
|
|
8856
8878
|
try {
|
|
8857
8879
|
doc = new DOMParser().parseFromString(html, "text/html");
|
|
@@ -8861,69 +8883,2108 @@ function filesFromPastedHtmlDataUrls(html) {
|
|
|
8861
8883
|
const out = [];
|
|
8862
8884
|
for (const img of Array.from(doc.querySelectorAll("img[src]"))) {
|
|
8863
8885
|
const src = img.getAttribute("src");
|
|
8864
|
-
if (!src?.startsWith("data:image"))
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
if (f2)
|
|
8868
|
-
out.push(f2);
|
|
8886
|
+
if (!src?.startsWith("data:image")) continue;
|
|
8887
|
+
const f2 = dataUrlToImageFile(src, out.length);
|
|
8888
|
+
if (f2) out.push(f2);
|
|
8869
8889
|
}
|
|
8870
|
-
return dedupePastedFiles(out);
|
|
8890
|
+
return dedupePastedFiles$1(out);
|
|
8871
8891
|
}
|
|
8872
|
-
function filesFromPlainDataImageUrl(text) {
|
|
8892
|
+
function filesFromPlainDataImageUrl$1(text) {
|
|
8873
8893
|
const t = text.trim();
|
|
8874
|
-
if (!t.startsWith("data:image/"))
|
|
8875
|
-
|
|
8876
|
-
const f2 = dataUrlToImageFileSync(t, 0);
|
|
8894
|
+
if (!t.startsWith("data:image/")) return [];
|
|
8895
|
+
const f2 = dataUrlToImageFile(t, 0);
|
|
8877
8896
|
return f2 ? [f2] : [];
|
|
8878
8897
|
}
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
8882
|
-
|
|
8883
|
-
|
|
8884
|
-
|
|
8885
|
-
|
|
8886
|
-
|
|
8887
|
-
|
|
8888
|
-
|
|
8889
|
-
|
|
8890
|
-
|
|
8891
|
-
for (const
|
|
8892
|
-
if (
|
|
8893
|
-
|
|
8894
|
-
|
|
8895
|
-
|
|
8896
|
-
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
8900
|
-
|
|
8898
|
+
function imageFilesFromPasteEvent(event) {
|
|
8899
|
+
const cd = event.clipboardData;
|
|
8900
|
+
const direct = filesFromClipboardData$1(cd);
|
|
8901
|
+
if (direct.length > 0) return direct;
|
|
8902
|
+
const html = cd?.getData("text/html") ?? "";
|
|
8903
|
+
const plain = (cd?.getData("text/plain") ?? "").trim();
|
|
8904
|
+
const fromRich = dedupePastedFiles$1([
|
|
8905
|
+
...filesFromPastedHtmlDataUrls$1(html),
|
|
8906
|
+
...filesFromPlainDataImageUrl$1(plain)
|
|
8907
|
+
]);
|
|
8908
|
+
if (fromRich.length > 0) return fromRich;
|
|
8909
|
+
if (cd?.items) {
|
|
8910
|
+
for (const item of Array.from(cd.items)) {
|
|
8911
|
+
if (item.type.startsWith("image/")) {
|
|
8912
|
+
const file = item.getAsFile();
|
|
8913
|
+
if (file) return [file];
|
|
8914
|
+
}
|
|
8915
|
+
}
|
|
8916
|
+
}
|
|
8917
|
+
return [];
|
|
8918
|
+
}
|
|
8919
|
+
function initAddPageBriefFillPanel(deps) {
|
|
8920
|
+
const [showPopover, setShowPopover] = createSignal(false);
|
|
8921
|
+
const [target, setTarget] = createSignal("content");
|
|
8922
|
+
const [contextNotes, setContextNotes] = createSignal("");
|
|
8923
|
+
const [images, setImages] = createSignal([]);
|
|
8924
|
+
const [thumbUrls, setThumbUrls] = createSignal([]);
|
|
8925
|
+
const [generating, setGenerating] = createSignal(false);
|
|
8926
|
+
const [popoverError, setPopoverError] = createSignal("");
|
|
8927
|
+
const [pendingReferenceFiles, setPendingReferenceFiles] = createSignal([]);
|
|
8928
|
+
const [suggestedRoute, setSuggestedRoute] = createSignal(null);
|
|
8929
|
+
const [suggestedRouteKind, setSuggestedRouteKind] = createSignal(null);
|
|
8930
|
+
const showSuggestedRouteBanner = createMemo(
|
|
8931
|
+
() => suggestedRoute() !== null && suggestedRoute().length > 0
|
|
8932
|
+
);
|
|
8933
|
+
const suggestedRouteLabel = createMemo(() => {
|
|
8934
|
+
const r = suggestedRoute();
|
|
8935
|
+
const k = suggestedRouteKind();
|
|
8936
|
+
if (!r) return "";
|
|
8937
|
+
return k ? `${r} (${k})` : r;
|
|
8938
|
+
});
|
|
8939
|
+
const briefFillDisabled = createMemo(() => deps.isBusy() || generating());
|
|
8940
|
+
const showBriefFillPopover = createMemo(() => showPopover());
|
|
8941
|
+
const canGenerate = createMemo(
|
|
8942
|
+
() => images().length > 0 && !generating() && !deps.isBusy()
|
|
8943
|
+
);
|
|
8944
|
+
const briefFillInputDisabled = createMemo(() => generating());
|
|
8945
|
+
const briefFillDropzoneClass = createMemo(
|
|
8946
|
+
() => briefFillInputDisabled() ? "add-page-brief-fill-dropzone add-page-brief-fill-dropzone-disabled" : "add-page-brief-fill-dropzone"
|
|
8947
|
+
);
|
|
8948
|
+
const generateDisabled = createMemo(() => !canGenerate());
|
|
8949
|
+
const briefFillStatusHint = createMemo(() => {
|
|
8950
|
+
if (generating()) {
|
|
8951
|
+
return target() === "content" ? "Generating content brief…" : "Generating design brief…";
|
|
8952
|
+
}
|
|
8953
|
+
return "";
|
|
8954
|
+
});
|
|
8955
|
+
const showBriefFillStatusHint = createMemo(
|
|
8956
|
+
() => briefFillStatusHint().length > 0
|
|
8957
|
+
);
|
|
8958
|
+
const imageThumbRows = createMemo(
|
|
8959
|
+
() => images().map((f2, i) => ({
|
|
8960
|
+
rowKey: `${f2.name}-${f2.size}-${i}`,
|
|
8961
|
+
name: f2.name,
|
|
8962
|
+
thumbUrl: thumbUrls()[i] ?? "",
|
|
8963
|
+
index: i,
|
|
8964
|
+
removeDisabled: generating()
|
|
8965
|
+
}))
|
|
8966
|
+
);
|
|
8967
|
+
const showBriefFillThumbnails = createMemo(() => imageThumbRows().length > 0);
|
|
8968
|
+
function revokeThumbUrls() {
|
|
8969
|
+
for (const url of thumbUrls()) {
|
|
8970
|
+
if (url) URL.revokeObjectURL(url);
|
|
8971
|
+
}
|
|
8972
|
+
}
|
|
8973
|
+
function resetPopoverState() {
|
|
8974
|
+
revokeThumbUrls();
|
|
8975
|
+
setImages([]);
|
|
8976
|
+
setThumbUrls([]);
|
|
8977
|
+
setContextNotes("");
|
|
8978
|
+
setPopoverError("");
|
|
8979
|
+
}
|
|
8980
|
+
function closePopover() {
|
|
8981
|
+
setShowPopover(false);
|
|
8982
|
+
resetPopoverState();
|
|
8983
|
+
}
|
|
8984
|
+
function openPopover(t) {
|
|
8985
|
+
resetPopoverState();
|
|
8986
|
+
setTarget(t);
|
|
8987
|
+
setShowPopover(true);
|
|
8988
|
+
}
|
|
8989
|
+
function addImageFiles(files) {
|
|
8990
|
+
if (generating()) return;
|
|
8991
|
+
const imageOnly = files.filter((f2) => f2.type.startsWith("image/"));
|
|
8992
|
+
if (imageOnly.length === 0) return;
|
|
8993
|
+
setPopoverError("");
|
|
8994
|
+
setImages((prev) => {
|
|
8995
|
+
const merged = [...prev];
|
|
8996
|
+
for (const f2 of imageOnly) {
|
|
8997
|
+
if (merged.length >= BRIEF_FILL_MAX_IMAGES) break;
|
|
8998
|
+
merged.push(f2);
|
|
8999
|
+
}
|
|
9000
|
+
if (prev.length + imageOnly.length > BRIEF_FILL_MAX_IMAGES) {
|
|
9001
|
+
setPopoverError(`Maximum ${BRIEF_FILL_MAX_IMAGES} images.`);
|
|
9002
|
+
}
|
|
9003
|
+
return merged;
|
|
9004
|
+
});
|
|
9005
|
+
setThumbUrls((prev) => {
|
|
9006
|
+
const next = [...prev];
|
|
9007
|
+
for (const f2 of imageOnly) {
|
|
9008
|
+
if (next.length >= BRIEF_FILL_MAX_IMAGES) break;
|
|
9009
|
+
next.push(URL.createObjectURL(f2));
|
|
8901
9010
|
}
|
|
9011
|
+
return next;
|
|
9012
|
+
});
|
|
9013
|
+
}
|
|
9014
|
+
function removeImageAt(index) {
|
|
9015
|
+
if (generating()) return;
|
|
9016
|
+
setImages((prev) => prev.filter((_, i) => i !== index));
|
|
9017
|
+
setThumbUrls((prev) => {
|
|
9018
|
+
const url = prev[index];
|
|
9019
|
+
if (url) URL.revokeObjectURL(url);
|
|
9020
|
+
return prev.filter((_, i) => i !== index);
|
|
9021
|
+
});
|
|
9022
|
+
}
|
|
9023
|
+
function applyMarkdownToTarget(md, t) {
|
|
9024
|
+
const current = t === "content" ? deps.getContentMd() : deps.getDesignMd();
|
|
9025
|
+
const setter = t === "content" ? deps.setContentMd : deps.setDesignMd;
|
|
9026
|
+
if (!current.trim()) {
|
|
9027
|
+
setter(md);
|
|
9028
|
+
return;
|
|
9029
|
+
}
|
|
9030
|
+
const replace = window.confirm(
|
|
9031
|
+
t === "content" ? "Replace existing Content brief? Click Cancel to append below." : "Replace existing Design brief? Click Cancel to append below."
|
|
9032
|
+
);
|
|
9033
|
+
if (replace) {
|
|
9034
|
+
setter(md);
|
|
9035
|
+
} else {
|
|
9036
|
+
setter((prev) => `${prev.trim()}
|
|
9037
|
+
|
|
9038
|
+
---
|
|
9039
|
+
|
|
9040
|
+
${md}`);
|
|
9041
|
+
}
|
|
9042
|
+
}
|
|
9043
|
+
async function flushPendingReferenceFiles(requestId) {
|
|
9044
|
+
const pending = pendingReferenceFiles();
|
|
9045
|
+
if (pending.length === 0) return;
|
|
9046
|
+
setPendingReferenceFiles([]);
|
|
9047
|
+
const chips = [];
|
|
9048
|
+
for (const file of pending) {
|
|
9049
|
+
const result = await uploadAddPageAsset({
|
|
9050
|
+
requestId,
|
|
9051
|
+
role: "reference",
|
|
9052
|
+
file
|
|
9053
|
+
});
|
|
9054
|
+
chips.push({
|
|
9055
|
+
rowKey: result.id,
|
|
9056
|
+
id: result.id,
|
|
9057
|
+
filename: file.name,
|
|
9058
|
+
path: result.path,
|
|
9059
|
+
role: "reference",
|
|
9060
|
+
roleLabel: "Reference"
|
|
9061
|
+
});
|
|
8902
9062
|
}
|
|
9063
|
+
if (chips.length > 0) deps.appendAttachments(chips);
|
|
8903
9064
|
}
|
|
8904
|
-
|
|
8905
|
-
|
|
8906
|
-
|
|
8907
|
-
|
|
8908
|
-
|
|
8909
|
-
|
|
8910
|
-
|
|
8911
|
-
|
|
9065
|
+
async function runGenerate() {
|
|
9066
|
+
if (!canGenerate()) return;
|
|
9067
|
+
setPopoverError("");
|
|
9068
|
+
setGenerating(true);
|
|
9069
|
+
deps.setComposerError("");
|
|
9070
|
+
const files = images();
|
|
9071
|
+
const t = target();
|
|
9072
|
+
let requestId = deps.getRequestId() ?? void 0;
|
|
9073
|
+
if (!requestId && deps.getRoute().trim()) {
|
|
9074
|
+
const minted = await deps.mintRequestIdIfNeeded();
|
|
9075
|
+
if (minted) requestId = minted;
|
|
9076
|
+
}
|
|
9077
|
+
try {
|
|
9078
|
+
const result = await generateAddPageBriefFromImage({
|
|
9079
|
+
target: t,
|
|
9080
|
+
requestId,
|
|
9081
|
+
pageRoute: deps.getRoute().trim() || void 0,
|
|
9082
|
+
contextNotes: contextNotes().trim() || void 0,
|
|
9083
|
+
images: files
|
|
9084
|
+
});
|
|
9085
|
+
if (!result.ok || !result.markdown) {
|
|
9086
|
+
setPopoverError(result.error ?? "Brief generation failed.");
|
|
9087
|
+
return;
|
|
9088
|
+
}
|
|
9089
|
+
applyMarkdownToTarget(result.markdown, t);
|
|
9090
|
+
if (t === "content" && result.suggestedRoute) {
|
|
9091
|
+
setSuggestedRoute(result.suggestedRoute);
|
|
9092
|
+
setSuggestedRouteKind(result.suggestedRouteKind ?? null);
|
|
9093
|
+
}
|
|
9094
|
+
if (result.referenceAttachments?.length) {
|
|
9095
|
+
deps.appendAttachments(
|
|
9096
|
+
result.referenceAttachments.map((a2) => ({
|
|
9097
|
+
rowKey: a2.id,
|
|
9098
|
+
id: a2.id,
|
|
9099
|
+
filename: a2.filename,
|
|
9100
|
+
path: a2.path,
|
|
9101
|
+
role: "reference",
|
|
9102
|
+
roleLabel: "Reference"
|
|
9103
|
+
}))
|
|
9104
|
+
);
|
|
9105
|
+
} else if (!requestId) {
|
|
9106
|
+
setPendingReferenceFiles((prev) => [...prev, ...files]);
|
|
9107
|
+
}
|
|
9108
|
+
closePopover();
|
|
9109
|
+
} catch (err) {
|
|
9110
|
+
setPopoverError(err instanceof Error ? err.message : String(err));
|
|
9111
|
+
} finally {
|
|
9112
|
+
setGenerating(false);
|
|
9113
|
+
}
|
|
9114
|
+
}
|
|
9115
|
+
function applySuggestedRoute() {
|
|
9116
|
+
const route = suggestedRoute();
|
|
9117
|
+
if (!route) return;
|
|
9118
|
+
deps.setRoute(route);
|
|
9119
|
+
deps.setRequestId(null);
|
|
9120
|
+
deps.scheduleRouteCheck(route);
|
|
9121
|
+
setSuggestedRoute(null);
|
|
9122
|
+
setSuggestedRouteKind(null);
|
|
9123
|
+
}
|
|
9124
|
+
function dismissSuggestedRoute() {
|
|
9125
|
+
setSuggestedRoute(null);
|
|
9126
|
+
setSuggestedRouteKind(null);
|
|
9127
|
+
}
|
|
9128
|
+
function onRequestIdMinted(requestId) {
|
|
9129
|
+
void flushPendingReferenceFiles(requestId);
|
|
9130
|
+
}
|
|
9131
|
+
function resetBriefFill() {
|
|
9132
|
+
closePopover();
|
|
9133
|
+
setSuggestedRoute(null);
|
|
9134
|
+
setSuggestedRouteKind(null);
|
|
9135
|
+
setPendingReferenceFiles([]);
|
|
9136
|
+
}
|
|
9137
|
+
function bindBriefFillRefs(refs) {
|
|
9138
|
+
refs.addPageFillContentFromImageBtn.onclick(() => openPopover("content"));
|
|
9139
|
+
refs.addPageFillDesignFromImageBtn.onclick(() => openPopover("design"));
|
|
9140
|
+
refs.addPageBriefFillCancelBtn.onclick(() => closePopover());
|
|
9141
|
+
refs.addPageBriefFillCloseBtn.onclick(() => closePopover());
|
|
9142
|
+
refs.addPageBriefFillGenerateBtn.onclick(() => {
|
|
9143
|
+
void runGenerate();
|
|
9144
|
+
});
|
|
9145
|
+
refs.addPageBriefFillContextNotes.oninput(
|
|
9146
|
+
({ event }) => {
|
|
9147
|
+
if (generating()) return;
|
|
9148
|
+
setContextNotes(event.target.value);
|
|
9149
|
+
}
|
|
9150
|
+
);
|
|
9151
|
+
refs.addPageBriefFillFileInput.onchange(
|
|
9152
|
+
({ event }) => {
|
|
9153
|
+
if (generating()) return;
|
|
9154
|
+
const input = event.target;
|
|
9155
|
+
const files = input.files ? Array.from(input.files) : [];
|
|
9156
|
+
addImageFiles(files);
|
|
9157
|
+
input.value = "";
|
|
9158
|
+
}
|
|
9159
|
+
);
|
|
9160
|
+
refs.addPageBriefFillDropzone.onclick(() => {
|
|
9161
|
+
if (generating()) return;
|
|
9162
|
+
refs.addPageBriefFillFileInput.exec$?.((el) => {
|
|
9163
|
+
el.click();
|
|
9164
|
+
});
|
|
9165
|
+
});
|
|
9166
|
+
refs.addPageBriefFillDropzone.ondragover(
|
|
9167
|
+
({ event }) => {
|
|
9168
|
+
event.preventDefault();
|
|
9169
|
+
}
|
|
9170
|
+
);
|
|
9171
|
+
refs.addPageBriefFillDropzone.ondrop(
|
|
9172
|
+
({ event }) => {
|
|
9173
|
+
event.preventDefault();
|
|
9174
|
+
if (generating()) return;
|
|
9175
|
+
const dt = event.dataTransfer;
|
|
9176
|
+
if (!dt?.files?.length) return;
|
|
9177
|
+
addImageFiles(Array.from(dt.files));
|
|
9178
|
+
}
|
|
9179
|
+
);
|
|
9180
|
+
refs.addPageBriefFillDropzone.addEventListener(
|
|
9181
|
+
"paste",
|
|
9182
|
+
(ev) => {
|
|
9183
|
+
if (generating()) return;
|
|
9184
|
+
const pasted = imageFilesFromPasteEvent(ev.event);
|
|
9185
|
+
if (pasted.length === 0) return;
|
|
9186
|
+
ev.event.preventDefault();
|
|
9187
|
+
addImageFiles(pasted);
|
|
9188
|
+
}
|
|
9189
|
+
);
|
|
9190
|
+
refs.addPageBriefFillThumbnails.onclick(
|
|
9191
|
+
({ event }) => {
|
|
9192
|
+
if (generating()) return;
|
|
9193
|
+
const btn = event.target.closest(
|
|
9194
|
+
"[data-brief-fill-remove]"
|
|
9195
|
+
);
|
|
9196
|
+
if (!btn) return;
|
|
9197
|
+
const idx = Number.parseInt(btn.dataset.briefFillRemove ?? "", 10);
|
|
9198
|
+
if (Number.isNaN(idx)) return;
|
|
9199
|
+
removeImageAt(idx);
|
|
9200
|
+
}
|
|
9201
|
+
);
|
|
9202
|
+
refs.addPageSuggestedRouteApplyBtn.onclick(() => applySuggestedRoute());
|
|
9203
|
+
refs.addPageSuggestedRouteDismissBtn.onclick(() => dismissSuggestedRoute());
|
|
8912
9204
|
}
|
|
8913
|
-
|
|
8914
|
-
|
|
9205
|
+
return {
|
|
9206
|
+
showBriefFillPopover,
|
|
9207
|
+
briefFillContextNotes: contextNotes,
|
|
9208
|
+
briefFillPopoverError: popoverError,
|
|
9209
|
+
showBriefFillPopoverError: createMemo(() => popoverError().length > 0),
|
|
9210
|
+
briefFillDisabled,
|
|
9211
|
+
briefFillInputDisabled,
|
|
9212
|
+
briefFillDropzoneClass,
|
|
9213
|
+
generateDisabled,
|
|
9214
|
+
briefFillStatusHint,
|
|
9215
|
+
showBriefFillStatusHint,
|
|
9216
|
+
imageThumbRows,
|
|
9217
|
+
showBriefFillThumbnails,
|
|
9218
|
+
showSuggestedRouteBanner,
|
|
9219
|
+
suggestedRouteLabel,
|
|
9220
|
+
bindBriefFillRefs,
|
|
9221
|
+
resetBriefFill,
|
|
9222
|
+
onRequestIdMinted,
|
|
9223
|
+
briefFillGenerating: generating
|
|
9224
|
+
};
|
|
8915
9225
|
}
|
|
8916
|
-
|
|
8917
|
-
|
|
8918
|
-
|
|
8919
|
-
|
|
8920
|
-
|
|
8921
|
-
|
|
8922
|
-
|
|
8923
|
-
|
|
8924
|
-
|
|
8925
|
-
|
|
8926
|
-
|
|
9226
|
+
const CATALOG = [
|
|
9227
|
+
{
|
|
9228
|
+
pluginName: "wix-server-client",
|
|
9229
|
+
packageName: "@jay-framework/wix-server-client",
|
|
9230
|
+
description: "Wix API client and authentication",
|
|
9231
|
+
kind: "service-only",
|
|
9232
|
+
requires: [],
|
|
9233
|
+
showInAddPagePicker: false,
|
|
9234
|
+
configFiles: ["config/.wix.yaml"]
|
|
9235
|
+
},
|
|
9236
|
+
{
|
|
9237
|
+
pluginName: "wix-cart",
|
|
9238
|
+
packageName: "@jay-framework/wix-cart",
|
|
9239
|
+
description: "Shopping cart headless components",
|
|
9240
|
+
kind: "headless",
|
|
9241
|
+
requires: ["wix-server-client"],
|
|
9242
|
+
showInAddPagePicker: true
|
|
9243
|
+
},
|
|
9244
|
+
{
|
|
9245
|
+
pluginName: "wix-stores",
|
|
9246
|
+
packageName: "@jay-framework/wix-stores",
|
|
9247
|
+
description: "Wix Stores product search, product page, categories",
|
|
9248
|
+
kind: "headless",
|
|
9249
|
+
requires: ["wix-server-client", "wix-cart"],
|
|
9250
|
+
showInAddPagePicker: true,
|
|
9251
|
+
configFiles: ["config/.wix-stores.yaml"]
|
|
9252
|
+
},
|
|
9253
|
+
{
|
|
9254
|
+
pluginName: "wix-stores-v1",
|
|
9255
|
+
packageName: "@jay-framework/wix-stores-v1",
|
|
9256
|
+
description: "Wix Stores v1 catalog API",
|
|
9257
|
+
kind: "headless",
|
|
9258
|
+
requires: ["wix-server-client", "wix-cart"],
|
|
9259
|
+
showInAddPagePicker: true
|
|
9260
|
+
},
|
|
9261
|
+
{
|
|
9262
|
+
pluginName: "wix-data",
|
|
9263
|
+
packageName: "@jay-framework/wix-data",
|
|
9264
|
+
description: "Wix Data collections CMS",
|
|
9265
|
+
kind: "headless",
|
|
9266
|
+
requires: ["wix-server-client"],
|
|
9267
|
+
showInAddPagePicker: true,
|
|
9268
|
+
configFiles: ["config/.wix-data.yaml"]
|
|
9269
|
+
},
|
|
9270
|
+
{
|
|
9271
|
+
pluginName: "wix-media",
|
|
9272
|
+
packageName: "@jay-framework/wix-media",
|
|
9273
|
+
description: "Wix media service (no page components)",
|
|
9274
|
+
kind: "service-only",
|
|
9275
|
+
requires: ["wix-server-client"],
|
|
9276
|
+
showInAddPagePicker: true
|
|
9277
|
+
},
|
|
9278
|
+
{
|
|
9279
|
+
pluginName: "ui-kit",
|
|
9280
|
+
packageName: "@jay-framework/ui-kit",
|
|
9281
|
+
description: "Jay UI kit headless components",
|
|
9282
|
+
kind: "headless",
|
|
9283
|
+
requires: [],
|
|
9284
|
+
showInAddPagePicker: true
|
|
9285
|
+
},
|
|
9286
|
+
{
|
|
9287
|
+
pluginName: "gemini-agent",
|
|
9288
|
+
packageName: "@jay-framework/gemini-agent",
|
|
9289
|
+
description: "Gemini AI agent plugin",
|
|
9290
|
+
kind: "headless",
|
|
9291
|
+
requires: [],
|
|
9292
|
+
showInAddPagePicker: true,
|
|
9293
|
+
configFiles: ["config/.gemini-agent.yaml"]
|
|
9294
|
+
},
|
|
9295
|
+
{
|
|
9296
|
+
pluginName: "webmcp",
|
|
9297
|
+
packageName: "@jay-framework/webmcp",
|
|
9298
|
+
description: "Web MCP tooling",
|
|
9299
|
+
kind: "tooling",
|
|
9300
|
+
requires: [],
|
|
9301
|
+
showInAddPagePicker: false
|
|
9302
|
+
},
|
|
9303
|
+
{
|
|
9304
|
+
pluginName: "aiditor",
|
|
9305
|
+
packageName: "@jay-framework/aiditor",
|
|
9306
|
+
description: "AIditor self plugin",
|
|
9307
|
+
kind: "tooling",
|
|
9308
|
+
requires: [],
|
|
9309
|
+
showInAddPagePicker: false
|
|
9310
|
+
}
|
|
9311
|
+
];
|
|
9312
|
+
function getCatalogEntry(pluginName) {
|
|
9313
|
+
return CATALOG.find((e2) => e2.pluginName === pluginName);
|
|
9314
|
+
}
|
|
9315
|
+
const DEFAULT_COMPONENT_KEYS = {
|
|
9316
|
+
"product-page": "p",
|
|
9317
|
+
"product-search": "search",
|
|
9318
|
+
"cart-indicator": "cart",
|
|
9319
|
+
"cart-page": "cartPage",
|
|
9320
|
+
"category-list": "categories"
|
|
9321
|
+
};
|
|
9322
|
+
function getDefaultComponentKey(contractName) {
|
|
9323
|
+
if (contractName in DEFAULT_COMPONENT_KEYS) {
|
|
9324
|
+
return DEFAULT_COMPONENT_KEYS[contractName];
|
|
9325
|
+
}
|
|
9326
|
+
return contractName.charAt(0) || "c";
|
|
9327
|
+
}
|
|
9328
|
+
const listJayPluginsAction = createActionCaller("aiditor.listJayPlugins", "GET");
|
|
9329
|
+
createActionCaller("aiditor.listPluginContracts", "GET");
|
|
9330
|
+
const checkPluginUpdateAction = createActionCaller("aiditor.checkPluginUpdate", "GET");
|
|
9331
|
+
const ensureProjectPluginAction = createStreamCaller("aiditor.ensureProjectPlugin");
|
|
9332
|
+
createActionCaller("aiditor.getPluginSetupStatus", "GET");
|
|
9333
|
+
const rerunPluginSetupAction = createActionCaller("aiditor.rerunPluginSetup", "GET");
|
|
9334
|
+
const syncAddPagePluginManifestAction = createActionCaller("aiditor.syncAddPagePluginManifest", "GET");
|
|
9335
|
+
const writePluginSourceAction = createActionCaller("aiditor.writePluginSource", "GET");
|
|
9336
|
+
async function listJayPlugins(refreshSetupStatus = false) {
|
|
9337
|
+
return listJayPluginsAction({ refreshSetupStatus });
|
|
9338
|
+
}
|
|
9339
|
+
async function checkPluginUpdate(pluginName) {
|
|
9340
|
+
return checkPluginUpdateAction({ pluginName });
|
|
9341
|
+
}
|
|
9342
|
+
function ensureProjectPluginStream(input, callbacks) {
|
|
9343
|
+
let aborted = false;
|
|
9344
|
+
const abort = () => {
|
|
9345
|
+
aborted = true;
|
|
9346
|
+
};
|
|
9347
|
+
void (async () => {
|
|
9348
|
+
try {
|
|
9349
|
+
for await (const chunk of ensureProjectPluginAction(input)) {
|
|
9350
|
+
if (aborted) break;
|
|
9351
|
+
callbacks.onChunk(chunk);
|
|
9352
|
+
if (chunk.type === "done" || chunk.type === "error") {
|
|
9353
|
+
callbacks.onEnd();
|
|
9354
|
+
return;
|
|
9355
|
+
}
|
|
9356
|
+
}
|
|
9357
|
+
if (!aborted) callbacks.onEnd();
|
|
9358
|
+
} catch (err) {
|
|
9359
|
+
if (!aborted) {
|
|
9360
|
+
callbacks.onError(err instanceof Error ? err : new Error(String(err)));
|
|
9361
|
+
}
|
|
9362
|
+
}
|
|
9363
|
+
})();
|
|
9364
|
+
return abort;
|
|
9365
|
+
}
|
|
9366
|
+
async function syncAddPagePluginManifest(input) {
|
|
9367
|
+
return syncAddPagePluginManifestAction(input);
|
|
9368
|
+
}
|
|
9369
|
+
async function rerunPluginSetup(pluginName, force) {
|
|
9370
|
+
return rerunPluginSetupAction({ pluginName, force });
|
|
9371
|
+
}
|
|
9372
|
+
async function writePluginSource(input) {
|
|
9373
|
+
return writePluginSourceAction(input);
|
|
9374
|
+
}
|
|
9375
|
+
const ADD_PAGE_MANAGE_PLUGINS_VALUE = "__manage_plugins__";
|
|
9376
|
+
function upsertPagePluginContract(prev, pluginName, packageName, contractName, componentKey) {
|
|
9377
|
+
const next = [...prev];
|
|
9378
|
+
let plugin = next.find((p) => p.pluginName === pluginName);
|
|
9379
|
+
if (!plugin) {
|
|
9380
|
+
plugin = {
|
|
9381
|
+
pluginName,
|
|
9382
|
+
packageName,
|
|
9383
|
+
contracts: [],
|
|
9384
|
+
installStatus: "not_needed"
|
|
9385
|
+
};
|
|
9386
|
+
next.push(plugin);
|
|
9387
|
+
}
|
|
9388
|
+
const exists = plugin.contracts.some((c) => c.contractName === contractName);
|
|
9389
|
+
const contracts = exists ? plugin.contracts.map(
|
|
9390
|
+
(c) => c.contractName === contractName ? { ...c, componentKey } : c
|
|
9391
|
+
) : [...plugin.contracts, { contractName, componentKey }];
|
|
9392
|
+
return next.map(
|
|
9393
|
+
(p) => p.pluginName === pluginName ? { ...p, packageName, contracts } : p
|
|
9394
|
+
);
|
|
9395
|
+
}
|
|
9396
|
+
function removePagePluginContract(prev, pluginName, contractName) {
|
|
9397
|
+
return prev.map(
|
|
9398
|
+
(p) => p.pluginName === pluginName ? {
|
|
9399
|
+
...p,
|
|
9400
|
+
contracts: p.contracts.filter(
|
|
9401
|
+
(c) => c.contractName !== contractName
|
|
9402
|
+
)
|
|
9403
|
+
} : p
|
|
9404
|
+
).filter((p) => p.contracts.length > 0);
|
|
9405
|
+
}
|
|
9406
|
+
function initAddPagePluginsPanel(deps) {
|
|
9407
|
+
const { projectPlugins, openProjectSettings } = deps;
|
|
9408
|
+
const [selectedPlugins, setSelectedPlugins] = createSignal([]);
|
|
9409
|
+
const [pickerPlugin, setPickerPlugin] = createSignal("");
|
|
9410
|
+
const [pickerValue, setPickerValue] = createSignal("");
|
|
9411
|
+
let syncTimer;
|
|
9412
|
+
const installedHeadlessPlugins = createMemo(
|
|
9413
|
+
() => projectPlugins.pluginsList().filter(
|
|
9414
|
+
(p) => p.installed && p.kind === "headless" && p.contracts.length > 0
|
|
9415
|
+
)
|
|
9416
|
+
);
|
|
9417
|
+
const addPagePluginPickerOptions = createMemo(
|
|
9418
|
+
() => {
|
|
9419
|
+
const options = installedHeadlessPlugins().map((p) => ({
|
|
9420
|
+
rowKey: p.pluginName,
|
|
9421
|
+
value: p.pluginName,
|
|
9422
|
+
label: p.pluginName
|
|
9423
|
+
}));
|
|
9424
|
+
options.push({
|
|
9425
|
+
rowKey: ADD_PAGE_MANAGE_PLUGINS_VALUE,
|
|
9426
|
+
value: ADD_PAGE_MANAGE_PLUGINS_VALUE,
|
|
9427
|
+
label: "Manage plugins…"
|
|
9428
|
+
});
|
|
9429
|
+
return options;
|
|
9430
|
+
}
|
|
9431
|
+
);
|
|
9432
|
+
const addPageContractPickerRows = createMemo(
|
|
9433
|
+
() => {
|
|
9434
|
+
const pluginName = pickerPlugin();
|
|
9435
|
+
if (!pluginName) return [];
|
|
9436
|
+
const entry = projectPlugins.pluginsList().find((p) => p.pluginName === pluginName);
|
|
9437
|
+
if (!entry?.installed || entry.kind !== "headless") return [];
|
|
9438
|
+
const sel = selectedPlugins().find((s) => s.pluginName === pluginName);
|
|
9439
|
+
return entry.contracts.map((c) => ({
|
|
9440
|
+
rowKey: `${pluginName}:${c.contractName}`,
|
|
9441
|
+
pluginName,
|
|
9442
|
+
packageName: entry.packageName,
|
|
9443
|
+
contractName: c.contractName,
|
|
9444
|
+
description: c.description ?? "",
|
|
9445
|
+
onPage: !!sel?.contracts.some((x) => x.contractName === c.contractName),
|
|
9446
|
+
componentKey: sel?.contracts.find((x) => x.contractName === c.contractName)?.componentKey ?? getDefaultComponentKey(c.contractName)
|
|
9447
|
+
}));
|
|
9448
|
+
}
|
|
9449
|
+
);
|
|
9450
|
+
const pagePluginChipRows = createMemo(() => {
|
|
9451
|
+
const chips = [];
|
|
9452
|
+
for (const plugin of selectedPlugins()) {
|
|
9453
|
+
for (const contract of plugin.contracts) {
|
|
9454
|
+
chips.push({
|
|
9455
|
+
rowKey: `${plugin.pluginName}:${contract.contractName}`,
|
|
9456
|
+
label: `${plugin.pluginName} · ${contract.contractName}`,
|
|
9457
|
+
pluginName: plugin.pluginName,
|
|
9458
|
+
packageName: plugin.packageName,
|
|
9459
|
+
contractName: contract.contractName,
|
|
9460
|
+
componentKey: contract.componentKey ?? getDefaultComponentKey(contract.contractName)
|
|
9461
|
+
});
|
|
9462
|
+
}
|
|
9463
|
+
}
|
|
9464
|
+
return chips;
|
|
9465
|
+
});
|
|
9466
|
+
const showContractPicker = createMemo(() => pickerPlugin().length > 0);
|
|
9467
|
+
const showPagePluginsZone = createMemo(() => true);
|
|
9468
|
+
const showPluginsPanel = createMemo(
|
|
9469
|
+
() => projectPlugins.pluginsLoaded() && projectPlugins.pluginsList().length > 0
|
|
9470
|
+
);
|
|
9471
|
+
const showPagePluginsEmptyHint = createMemo(
|
|
9472
|
+
() => showPluginsPanel() && pagePluginChipRows().length === 0
|
|
9473
|
+
);
|
|
9474
|
+
const pluginsBlockCreatePage = createMemo(() => {
|
|
9475
|
+
if (projectPlugins.installInProgress()) return true;
|
|
9476
|
+
return selectedPlugins().some(
|
|
9477
|
+
(p) => p.installStatus === "installing" || p.installStatus === "pending" || p.installStatus === "failed"
|
|
9478
|
+
);
|
|
9479
|
+
});
|
|
9480
|
+
function scheduleManifestSync() {
|
|
9481
|
+
const requestId = deps.getRequestId();
|
|
9482
|
+
if (!requestId) return;
|
|
9483
|
+
if (syncTimer) clearTimeout(syncTimer);
|
|
9484
|
+
syncTimer = setTimeout(() => {
|
|
9485
|
+
void syncAddPagePluginManifest({
|
|
9486
|
+
requestId,
|
|
9487
|
+
selectedPlugins: selectedPlugins()
|
|
9488
|
+
}).then((res) => {
|
|
9489
|
+
if (res.ok && res.contentMd) {
|
|
9490
|
+
deps.setContentMd(res.contentMd);
|
|
9491
|
+
}
|
|
9492
|
+
});
|
|
9493
|
+
}, 300);
|
|
9494
|
+
}
|
|
9495
|
+
function addContractToPage(pluginName, packageName, contractName, componentKey) {
|
|
9496
|
+
setSelectedPlugins(
|
|
9497
|
+
(prev) => upsertPagePluginContract(
|
|
9498
|
+
prev,
|
|
9499
|
+
pluginName,
|
|
9500
|
+
packageName,
|
|
9501
|
+
contractName,
|
|
9502
|
+
componentKey
|
|
9503
|
+
)
|
|
9504
|
+
);
|
|
9505
|
+
scheduleManifestSync();
|
|
9506
|
+
}
|
|
9507
|
+
function removeFromPage(pluginName, packageName, contractName) {
|
|
9508
|
+
setSelectedPlugins(
|
|
9509
|
+
(prev) => removePagePluginContract(prev, pluginName, contractName)
|
|
9510
|
+
);
|
|
9511
|
+
scheduleManifestSync();
|
|
9512
|
+
}
|
|
9513
|
+
function handlePickerChange(value) {
|
|
9514
|
+
setPickerValue("");
|
|
9515
|
+
if (value === ADD_PAGE_MANAGE_PLUGINS_VALUE) {
|
|
9516
|
+
openProjectSettings();
|
|
9517
|
+
setPickerPlugin("");
|
|
9518
|
+
return;
|
|
9519
|
+
}
|
|
9520
|
+
if (!value) {
|
|
9521
|
+
setPickerPlugin("");
|
|
9522
|
+
return;
|
|
9523
|
+
}
|
|
9524
|
+
setPickerPlugin(value);
|
|
9525
|
+
}
|
|
9526
|
+
function resetPluginsPanel() {
|
|
9527
|
+
setSelectedPlugins([]);
|
|
9528
|
+
setPickerPlugin("");
|
|
9529
|
+
setPickerValue("");
|
|
9530
|
+
if (syncTimer) clearTimeout(syncTimer);
|
|
9531
|
+
}
|
|
9532
|
+
function bindPluginsPanelRefs(refs) {
|
|
9533
|
+
refs.addPagePluginPicker?.onchange(
|
|
9534
|
+
({ event }) => {
|
|
9535
|
+
const value = event.target.value;
|
|
9536
|
+
handlePickerChange(value);
|
|
9537
|
+
}
|
|
9538
|
+
);
|
|
9539
|
+
refs.addPagePluginsPanel.onclick(
|
|
9540
|
+
({ event }) => {
|
|
9541
|
+
const target = event.target;
|
|
9542
|
+
const manageLink = target.closest("[data-add-page-manage-plugins]");
|
|
9543
|
+
if (manageLink) {
|
|
9544
|
+
openProjectSettings();
|
|
9545
|
+
return;
|
|
9546
|
+
}
|
|
9547
|
+
const addBtn = target.closest(
|
|
9548
|
+
"[data-add-page-add-contract]"
|
|
9549
|
+
);
|
|
9550
|
+
if (addBtn?.dataset.plugin && addBtn.dataset.contract && addBtn.dataset.package) {
|
|
9551
|
+
addContractToPage(
|
|
9552
|
+
addBtn.dataset.plugin,
|
|
9553
|
+
addBtn.dataset.package,
|
|
9554
|
+
addBtn.dataset.contract,
|
|
9555
|
+
addBtn.dataset.key ?? getDefaultComponentKey(addBtn.dataset.contract)
|
|
9556
|
+
);
|
|
9557
|
+
return;
|
|
9558
|
+
}
|
|
9559
|
+
const removeChip = target.closest(
|
|
9560
|
+
"[data-add-page-remove-chip]"
|
|
9561
|
+
);
|
|
9562
|
+
if (removeChip?.dataset.plugin && removeChip.dataset.contract && removeChip.dataset.package) {
|
|
9563
|
+
removeFromPage(
|
|
9564
|
+
removeChip.dataset.plugin,
|
|
9565
|
+
removeChip.dataset.package,
|
|
9566
|
+
removeChip.dataset.contract
|
|
9567
|
+
);
|
|
9568
|
+
}
|
|
9569
|
+
}
|
|
9570
|
+
);
|
|
9571
|
+
}
|
|
9572
|
+
return {
|
|
9573
|
+
selectedPlugins,
|
|
9574
|
+
setSelectedPlugins,
|
|
9575
|
+
scheduleManifestSync,
|
|
9576
|
+
syncManifestNow: async () => {
|
|
9577
|
+
const requestId = deps.getRequestId();
|
|
9578
|
+
if (!requestId) return;
|
|
9579
|
+
const res = await syncAddPagePluginManifest({
|
|
9580
|
+
requestId,
|
|
9581
|
+
selectedPlugins: selectedPlugins()
|
|
9582
|
+
});
|
|
9583
|
+
if (res.ok && res.contentMd) deps.setContentMd(res.contentMd);
|
|
9584
|
+
},
|
|
9585
|
+
bindPluginsPanelRefs,
|
|
9586
|
+
addPagePluginPickerOptions,
|
|
9587
|
+
addPagePluginPickerValue: pickerValue,
|
|
9588
|
+
addPagePickerPluginLabel: createMemo(() => {
|
|
9589
|
+
const name = pickerPlugin();
|
|
9590
|
+
return name ? `Components from ${name}` : "";
|
|
9591
|
+
}),
|
|
9592
|
+
addPageContractPickerRows,
|
|
9593
|
+
pagePluginChipRows,
|
|
9594
|
+
showContractPicker,
|
|
9595
|
+
showPagePluginsZone,
|
|
9596
|
+
showPluginsPanel,
|
|
9597
|
+
showPagePluginsEmptyHint,
|
|
9598
|
+
pluginsBlockCreatePage,
|
|
9599
|
+
pickerPlugin,
|
|
9600
|
+
setPickerPlugin,
|
|
9601
|
+
handlePickerChange,
|
|
9602
|
+
resetPluginsPanel
|
|
9603
|
+
};
|
|
9604
|
+
}
|
|
9605
|
+
function tryJayRefExec(refObj, fn) {
|
|
9606
|
+
if (typeof refObj?.exec$ !== "function") return false;
|
|
9607
|
+
try {
|
|
9608
|
+
refObj.exec$(fn);
|
|
9609
|
+
return true;
|
|
9610
|
+
} catch {
|
|
9611
|
+
return false;
|
|
9612
|
+
}
|
|
9613
|
+
}
|
|
9614
|
+
function initAddPageComposer(deps) {
|
|
9615
|
+
const [showAddPageComposer, setShowAddPageComposer] = createSignal(false);
|
|
9616
|
+
const [addPageRoute, setAddPageRoute] = createSignal("");
|
|
9617
|
+
const [addPageContentMd, setAddPageContentMd] = createSignal("");
|
|
9618
|
+
const [addPageDesignMd, setAddPageDesignMd] = createSignal("");
|
|
9619
|
+
const [addPageRequestId, setAddPageRequestId] = createSignal(
|
|
9620
|
+
null
|
|
9621
|
+
);
|
|
9622
|
+
const [addPageRequestRoute, setAddPageRequestRoute] = createSignal(null);
|
|
9623
|
+
const [addPageRouteError, setAddPageRouteError] = createSignal("");
|
|
9624
|
+
const [addPageComposerError, setAddPageComposerError] = createSignal("");
|
|
9625
|
+
const [addPageUploadHint, setAddPageUploadHint] = createSignal("");
|
|
9626
|
+
const [addPageAttachments, setAddPageAttachments] = createSignal([]);
|
|
9627
|
+
const [addPageShowDesignHint, setAddPageShowDesignHint] = createSignal(false);
|
|
9628
|
+
const [addPageIsDynamicRoute, setAddPageIsDynamicRoute] = createSignal(false);
|
|
9629
|
+
const [addPageSubmitting, setAddPageSubmitting] = createSignal(false);
|
|
9630
|
+
const pluginsPanel = initAddPagePluginsPanel({
|
|
9631
|
+
projectPlugins: deps.projectPlugins,
|
|
9632
|
+
getRequestId: () => addPageRequestId(),
|
|
9633
|
+
getContentMd: () => addPageContentMd(),
|
|
9634
|
+
setContentMd: setAddPageContentMd,
|
|
9635
|
+
openProjectSettings: deps.openProjectSettings
|
|
9636
|
+
});
|
|
9637
|
+
const briefFillPanel = initAddPageBriefFillPanel({
|
|
9638
|
+
isBusy: () => deps.isRunning() || addPageSubmitting(),
|
|
9639
|
+
getRoute: () => addPageRoute(),
|
|
9640
|
+
setRoute: setAddPageRoute,
|
|
9641
|
+
getRequestId: () => addPageRequestId(),
|
|
9642
|
+
setRequestId: setAddPageRequestId,
|
|
9643
|
+
getContentMd: () => addPageContentMd(),
|
|
9644
|
+
setContentMd: setAddPageContentMd,
|
|
9645
|
+
getDesignMd: () => addPageDesignMd(),
|
|
9646
|
+
setDesignMd: setAddPageDesignMd,
|
|
9647
|
+
appendAttachments: (chips) => {
|
|
9648
|
+
setAddPageAttachments((prev) => [...prev, ...chips]);
|
|
9649
|
+
updateDesignHint();
|
|
9650
|
+
},
|
|
9651
|
+
mintRequestIdIfNeeded,
|
|
9652
|
+
scheduleRouteCheck,
|
|
9653
|
+
setComposerError: setAddPageComposerError
|
|
9654
|
+
});
|
|
9655
|
+
let routeCheckTimer;
|
|
9656
|
+
let contentTextareaEl = null;
|
|
9657
|
+
let designTextareaEl = null;
|
|
9658
|
+
const showAddPageRouteError = createMemo(
|
|
9659
|
+
() => addPageRouteError().length > 0
|
|
9660
|
+
);
|
|
9661
|
+
const showAddPageComposerError = createMemo(
|
|
9662
|
+
() => addPageComposerError().length > 0
|
|
9663
|
+
);
|
|
9664
|
+
const showAddPageUploadHint = createMemo(
|
|
9665
|
+
() => addPageUploadHint().length > 0
|
|
9666
|
+
);
|
|
9667
|
+
const showAddPageAttachments = createMemo(
|
|
9668
|
+
() => addPageAttachments().length > 0
|
|
9669
|
+
);
|
|
9670
|
+
const addPageRunningHint = createMemo(
|
|
9671
|
+
() => deps.isRunning() ? "Agent is running…" : ""
|
|
9672
|
+
);
|
|
9673
|
+
const showAddPageRunningHint = createMemo(
|
|
9674
|
+
() => addPageRunningHint().length > 0
|
|
9675
|
+
);
|
|
9676
|
+
const addPageAttachmentDisplayRows = createMemo(
|
|
9677
|
+
() => addPageAttachments().map((a2) => ({
|
|
9678
|
+
...a2,
|
|
9679
|
+
rowKey: a2.id
|
|
9680
|
+
}))
|
|
9681
|
+
);
|
|
9682
|
+
const addPageCanSubmit = createMemo(() => {
|
|
9683
|
+
if (deps.isRunning() || addPageSubmitting() || briefFillPanel.briefFillGenerating()) {
|
|
9684
|
+
return false;
|
|
9685
|
+
}
|
|
9686
|
+
if (pluginsPanel.pluginsBlockCreatePage()) return false;
|
|
9687
|
+
const route = addPageRoute().trim();
|
|
9688
|
+
if (!route || addPageRouteError()) return false;
|
|
9689
|
+
const hasMd = addPageContentMd().trim().length > 0 || addPageDesignMd().trim().length > 0;
|
|
9690
|
+
return hasMd;
|
|
9691
|
+
});
|
|
9692
|
+
const addPageCreateDisabled = createMemo(
|
|
9693
|
+
() => !addPageCanSubmit() || deps.isRunning() || briefFillPanel.briefFillGenerating()
|
|
9694
|
+
);
|
|
9695
|
+
function resetAddPageComposer() {
|
|
9696
|
+
setAddPageRoute("");
|
|
9697
|
+
setAddPageContentMd("");
|
|
9698
|
+
setAddPageDesignMd("");
|
|
9699
|
+
setAddPageRequestId(null);
|
|
9700
|
+
setAddPageRequestRoute(null);
|
|
9701
|
+
setAddPageRouteError("");
|
|
9702
|
+
setAddPageComposerError("");
|
|
9703
|
+
setAddPageUploadHint("");
|
|
9704
|
+
setAddPageAttachments([]);
|
|
9705
|
+
setAddPageShowDesignHint(false);
|
|
9706
|
+
setAddPageIsDynamicRoute(false);
|
|
9707
|
+
pluginsPanel.resetPluginsPanel();
|
|
9708
|
+
briefFillPanel.resetBriefFill();
|
|
9709
|
+
}
|
|
9710
|
+
function openAddPageComposer() {
|
|
9711
|
+
resetAddPageComposer();
|
|
9712
|
+
setShowAddPageComposer(true);
|
|
9713
|
+
void deps.projectPlugins.refreshPluginsList();
|
|
9714
|
+
}
|
|
9715
|
+
async function refreshCurrentPageBriefAvailability() {
|
|
9716
|
+
const filePath = deps.selectedPageFilePath().trim();
|
|
9717
|
+
if (!filePath) {
|
|
9718
|
+
deps.setCurrentPageHasBrief(false);
|
|
9719
|
+
return;
|
|
9720
|
+
}
|
|
9721
|
+
try {
|
|
9722
|
+
const result = await checkPageAddPageBrief({
|
|
9723
|
+
jayHtmlPath: filePath,
|
|
9724
|
+
pageRoute: deps.selectedPageUrl() ?? void 0
|
|
9725
|
+
});
|
|
9726
|
+
deps.setCurrentPageHasBrief(result.hasBrief);
|
|
9727
|
+
} catch {
|
|
9728
|
+
deps.setCurrentPageHasBrief(false);
|
|
9729
|
+
}
|
|
9730
|
+
}
|
|
9731
|
+
async function openAddPageComposerFromBrief() {
|
|
9732
|
+
const filePath = deps.selectedPageFilePath().trim();
|
|
9733
|
+
const sourceRoute = deps.selectedPageUrl();
|
|
9734
|
+
if (!filePath || !sourceRoute) {
|
|
9735
|
+
setAddPageComposerError(
|
|
9736
|
+
"Select a project page with saved Add Page briefs."
|
|
9737
|
+
);
|
|
9738
|
+
setShowAddPageComposer(true);
|
|
9739
|
+
return;
|
|
9740
|
+
}
|
|
9741
|
+
resetAddPageComposer();
|
|
9742
|
+
setShowAddPageComposer(true);
|
|
9743
|
+
setAddPageComposerError("");
|
|
9744
|
+
void deps.projectPlugins.refreshPluginsList();
|
|
9745
|
+
try {
|
|
9746
|
+
const result = await openAddPageFromBrief({
|
|
9747
|
+
jayHtmlPath: filePath,
|
|
9748
|
+
sourcePageRoute: sourceRoute
|
|
9749
|
+
});
|
|
9750
|
+
if (!result.ok || !result.requestId || !result.pageRoute) {
|
|
9751
|
+
setAddPageComposerError(result.error ?? "Could not load page brief.");
|
|
9752
|
+
return;
|
|
9753
|
+
}
|
|
9754
|
+
setAddPageRoute(result.pageRoute);
|
|
9755
|
+
setAddPageContentMd(result.contentMd ?? "");
|
|
9756
|
+
setAddPageDesignMd(result.designMd ?? "");
|
|
9757
|
+
setAddPageRequestId(result.requestId);
|
|
9758
|
+
setAddPageRequestRoute(result.pageRoute);
|
|
9759
|
+
setAddPageIsDynamicRoute(result.routeKind === "dynamic");
|
|
9760
|
+
setAddPageRouteError("");
|
|
9761
|
+
setAddPageAttachments(
|
|
9762
|
+
(result.attachments ?? []).map((a2) => ({
|
|
9763
|
+
rowKey: a2.id,
|
|
9764
|
+
id: a2.id,
|
|
9765
|
+
filename: a2.filename,
|
|
9766
|
+
path: a2.path,
|
|
9767
|
+
role: a2.role,
|
|
9768
|
+
roleLabel: a2.role === "reference" ? "Reference" : "Asset"
|
|
9769
|
+
}))
|
|
9770
|
+
);
|
|
9771
|
+
updateDesignHint();
|
|
9772
|
+
} catch (err) {
|
|
9773
|
+
setAddPageComposerError(err instanceof Error ? err.message : String(err));
|
|
9774
|
+
}
|
|
9775
|
+
}
|
|
9776
|
+
function closeAddPageComposer(force = false) {
|
|
9777
|
+
const hasText = addPageRoute().trim() || addPageContentMd().trim() || addPageDesignMd().trim() || addPageAttachments().length > 0;
|
|
9778
|
+
if (!force && hasText && !window.confirm("Discard Add Page draft?")) {
|
|
9779
|
+
return;
|
|
9780
|
+
}
|
|
9781
|
+
setShowAddPageComposer(false);
|
|
9782
|
+
resetAddPageComposer();
|
|
9783
|
+
}
|
|
9784
|
+
function scheduleRouteCheck(route) {
|
|
9785
|
+
if (routeCheckTimer) clearTimeout(routeCheckTimer);
|
|
9786
|
+
setAddPageIsDynamicRoute(inferRouteKindFromRoute(route) === "dynamic");
|
|
9787
|
+
if (!route.trim()) {
|
|
9788
|
+
setAddPageRouteError("");
|
|
9789
|
+
return;
|
|
9790
|
+
}
|
|
9791
|
+
routeCheckTimer = setTimeout(() => {
|
|
9792
|
+
void checkAddPageRoute(route).then((res) => {
|
|
9793
|
+
if (!res.valid) {
|
|
9794
|
+
setAddPageRouteError(res.error ?? "Invalid route.");
|
|
9795
|
+
setAddPageRequestId(null);
|
|
9796
|
+
setAddPageRequestRoute(null);
|
|
9797
|
+
return;
|
|
9798
|
+
}
|
|
9799
|
+
if (res.routeExists) {
|
|
9800
|
+
setAddPageRouteError("This route already exists.");
|
|
9801
|
+
setAddPageRequestId(null);
|
|
9802
|
+
setAddPageRequestRoute(null);
|
|
9803
|
+
return;
|
|
9804
|
+
}
|
|
9805
|
+
setAddPageRouteError("");
|
|
9806
|
+
setAddPageIsDynamicRoute(res.routeKind === "dynamic");
|
|
9807
|
+
if (addPageRequestId() && addPageRequestRoute() && addPageRequestRoute() !== res.normalizedRoute) {
|
|
9808
|
+
setAddPageRequestId(null);
|
|
9809
|
+
}
|
|
9810
|
+
if (!addPageRequestId()) {
|
|
9811
|
+
void ensureAddPageRequestId(res.normalizedRoute, null).then(
|
|
9812
|
+
(ensured) => {
|
|
9813
|
+
if (ensured.requestId) {
|
|
9814
|
+
setAddPageRequestId(ensured.requestId);
|
|
9815
|
+
setAddPageRequestRoute(res.normalizedRoute);
|
|
9816
|
+
briefFillPanel.onRequestIdMinted(ensured.requestId);
|
|
9817
|
+
}
|
|
9818
|
+
}
|
|
9819
|
+
);
|
|
9820
|
+
}
|
|
9821
|
+
}).catch((err) => {
|
|
9822
|
+
setAddPageRouteError(
|
|
9823
|
+
err instanceof Error ? err.message : String(err)
|
|
9824
|
+
);
|
|
9825
|
+
setAddPageRequestId(null);
|
|
9826
|
+
setAddPageRequestRoute(null);
|
|
9827
|
+
});
|
|
9828
|
+
}, 300);
|
|
9829
|
+
}
|
|
9830
|
+
function updateDesignHint() {
|
|
9831
|
+
const thinDesign = addPageDesignMd().trim().length < 40;
|
|
9832
|
+
const noRefs = addPageAttachments().length === 0;
|
|
9833
|
+
setAddPageShowDesignHint(thinDesign && noRefs);
|
|
9834
|
+
}
|
|
9835
|
+
async function mintRequestIdIfNeeded() {
|
|
9836
|
+
const route = addPageRoute().trim();
|
|
9837
|
+
if (!route) {
|
|
9838
|
+
setAddPageComposerError(
|
|
9839
|
+
"Enter a page route before attaching files or pasting images."
|
|
9840
|
+
);
|
|
9841
|
+
return null;
|
|
9842
|
+
}
|
|
9843
|
+
if (addPageRouteError()) {
|
|
9844
|
+
setAddPageComposerError(addPageRouteError());
|
|
9845
|
+
return null;
|
|
9846
|
+
}
|
|
9847
|
+
const ensured = await ensureAddPageRequestId(route, addPageRequestId());
|
|
9848
|
+
if (ensured.error) {
|
|
9849
|
+
setAddPageComposerError(ensured.error);
|
|
9850
|
+
return null;
|
|
9851
|
+
}
|
|
9852
|
+
setAddPageRequestId(ensured.requestId);
|
|
9853
|
+
setAddPageRequestRoute(route);
|
|
9854
|
+
briefFillPanel.onRequestIdMinted(ensured.requestId);
|
|
9855
|
+
return ensured.requestId;
|
|
9856
|
+
}
|
|
9857
|
+
async function handleAddPageUpload(file, role, markdownTarget = "content") {
|
|
9858
|
+
setAddPageComposerError("");
|
|
9859
|
+
setAddPageUploadHint(`Uploading ${file.name}…`);
|
|
9860
|
+
const requestId = await mintRequestIdIfNeeded();
|
|
9861
|
+
if (!requestId) {
|
|
9862
|
+
setAddPageUploadHint("");
|
|
9863
|
+
return;
|
|
9864
|
+
}
|
|
9865
|
+
try {
|
|
9866
|
+
const result = await uploadAddPageAsset({
|
|
9867
|
+
requestId,
|
|
9868
|
+
role,
|
|
9869
|
+
file
|
|
9870
|
+
});
|
|
9871
|
+
const chip = {
|
|
9872
|
+
rowKey: result.id,
|
|
9873
|
+
id: result.id,
|
|
9874
|
+
filename: file.name,
|
|
9875
|
+
path: result.path,
|
|
9876
|
+
role,
|
|
9877
|
+
roleLabel: role === "reference" ? "Reference" : "Asset"
|
|
9878
|
+
};
|
|
9879
|
+
setAddPageAttachments((prev) => [...prev, chip]);
|
|
9880
|
+
if (role === "asset" && result.markdownSnippet) {
|
|
9881
|
+
const ta = markdownTarget === "design" ? designTextareaEl : contentTextareaEl;
|
|
9882
|
+
const setMd = markdownTarget === "design" ? setAddPageDesignMd : setAddPageContentMd;
|
|
9883
|
+
if (ta) {
|
|
9884
|
+
setMd((md) => insertTextAtCursor(ta, result.markdownSnippet, md));
|
|
9885
|
+
}
|
|
9886
|
+
}
|
|
9887
|
+
updateDesignHint();
|
|
9888
|
+
} catch (err) {
|
|
9889
|
+
setAddPageComposerError(err instanceof Error ? err.message : String(err));
|
|
9890
|
+
} finally {
|
|
9891
|
+
setAddPageUploadHint("");
|
|
9892
|
+
}
|
|
9893
|
+
}
|
|
9894
|
+
function handleAddPageChunk(chunk) {
|
|
9895
|
+
if (chunk.type === "thinking" && chunk.text) {
|
|
9896
|
+
deps.appendAgentOutputChunk(chunk.text, "chunk chunk-thinking");
|
|
9897
|
+
} else if (chunk.type === "chunk" && chunk.text) {
|
|
9898
|
+
deps.appendAgentOutputChunk(chunk.text);
|
|
9899
|
+
} else if (chunk.type === "status" && chunk.message) {
|
|
9900
|
+
deps.appendAgentOutputChunk(chunk.message, "chunk chunk-status");
|
|
9901
|
+
} else if (chunk.type === "tool" && chunk.name) {
|
|
9902
|
+
const detail = chunk.text ? ` ${chunk.text}` : "";
|
|
9903
|
+
const fp = chunk.name === "Read" || chunk.name === "Write" ? chunk.text?.split("\n")[0]?.trim() ?? "" : "";
|
|
9904
|
+
deps.appendAgentOutputChunk(
|
|
9905
|
+
`> ${chunk.name}${detail}`,
|
|
9906
|
+
"chunk chunk-tool",
|
|
9907
|
+
fp,
|
|
9908
|
+
fp ? chunk.name : ""
|
|
9909
|
+
);
|
|
9910
|
+
} else if (chunk.type === "error" && chunk.message) {
|
|
9911
|
+
deps.appendAgentOutputChunk(chunk.message, "chunk chunk-error");
|
|
9912
|
+
if (chunk.text) {
|
|
9913
|
+
deps.appendAgentOutputChunk(chunk.text, "chunk chunk-error");
|
|
9914
|
+
}
|
|
9915
|
+
} else if (chunk.type === "result") {
|
|
9916
|
+
deps.appendAgentOutputChunk(
|
|
9917
|
+
chunk.message ?? "Page created.",
|
|
9918
|
+
"chunk chunk-result"
|
|
9919
|
+
);
|
|
9920
|
+
}
|
|
9921
|
+
}
|
|
9922
|
+
function findProjectPageForRoute(pageRoute) {
|
|
9923
|
+
const normalized = pageRoute.replace(/\/+$/, "") || "/";
|
|
9924
|
+
return deps.projectPages().find((p) => p.url === normalized) ?? deps.projectPages().find((p) => p.url === pageRoute);
|
|
9925
|
+
}
|
|
9926
|
+
async function openPreviewForRoute(pageRoute) {
|
|
9927
|
+
const normalized = pageRoute.replace(/\/+$/, "") || "/";
|
|
9928
|
+
await deps.loadProjectInfo();
|
|
9929
|
+
let page2 = findProjectPageForRoute(pageRoute);
|
|
9930
|
+
if (!page2) {
|
|
9931
|
+
await new Promise((r) => setTimeout(r, 400));
|
|
9932
|
+
await deps.loadProjectInfo();
|
|
9933
|
+
page2 = findProjectPageForRoute(pageRoute);
|
|
9934
|
+
}
|
|
9935
|
+
if (!page2) {
|
|
9936
|
+
page2 = {
|
|
9937
|
+
name: normalized,
|
|
9938
|
+
url: normalized,
|
|
9939
|
+
filePath: "",
|
|
9940
|
+
usedComponents: []
|
|
9941
|
+
};
|
|
9942
|
+
}
|
|
9943
|
+
deps.selectProjectPage(page2);
|
|
9944
|
+
if (inferRouteKindFromRoute(pageRoute) === "dynamic") {
|
|
9945
|
+
try {
|
|
9946
|
+
const allRows = [];
|
|
9947
|
+
for await (const batch of getPageParamsAction({ route: pageRoute })) {
|
|
9948
|
+
allRows.push(...batch);
|
|
9949
|
+
}
|
|
9950
|
+
const paths = pathnamesFromParamRows(page2.url, allRows);
|
|
9951
|
+
if (paths.length === 0) {
|
|
9952
|
+
deps.appendAgentOutputChunk(
|
|
9953
|
+
"Add a param value in the route picker to preview this dynamic page.",
|
|
9954
|
+
"chunk chunk-status"
|
|
9955
|
+
);
|
|
9956
|
+
}
|
|
9957
|
+
} catch {
|
|
9958
|
+
deps.appendAgentOutputChunk(
|
|
9959
|
+
"Add a param value in the route picker to preview this dynamic page.",
|
|
9960
|
+
"chunk chunk-status"
|
|
9961
|
+
);
|
|
9962
|
+
}
|
|
9963
|
+
}
|
|
9964
|
+
}
|
|
9965
|
+
let lastSubmitSnapshot = null;
|
|
9966
|
+
function submitAddPage(isRetry = false) {
|
|
9967
|
+
if (!addPageCanSubmit()) return;
|
|
9968
|
+
const route = addPageRoute().trim();
|
|
9969
|
+
void (async () => {
|
|
9970
|
+
setAddPageComposerError("");
|
|
9971
|
+
setAddPageSubmitting(true);
|
|
9972
|
+
const requestId = await mintRequestIdIfNeeded();
|
|
9973
|
+
if (!requestId) {
|
|
9974
|
+
setAddPageSubmitting(false);
|
|
9975
|
+
return;
|
|
9976
|
+
}
|
|
9977
|
+
lastSubmitSnapshot = {
|
|
9978
|
+
requestId,
|
|
9979
|
+
pageRoute: route,
|
|
9980
|
+
contentMd: addPageContentMd(),
|
|
9981
|
+
designMd: addPageDesignMd()
|
|
9982
|
+
};
|
|
9983
|
+
setShowAddPageComposer(false);
|
|
9984
|
+
deps.setChunks([]);
|
|
9985
|
+
deps.setIsRunning(true);
|
|
9986
|
+
deps.setBottomPanelCollapsed(false);
|
|
9987
|
+
deps.setAddPageResultBanner(null);
|
|
9988
|
+
await pluginsPanel.syncManifestNow();
|
|
9989
|
+
deps.getStopStream()?.();
|
|
9990
|
+
const abort = submitAddPageStream(
|
|
9991
|
+
{
|
|
9992
|
+
requestId,
|
|
9993
|
+
contentMd: addPageContentMd(),
|
|
9994
|
+
designMd: addPageDesignMd(),
|
|
9995
|
+
pageRoute: route,
|
|
9996
|
+
isRetry
|
|
9997
|
+
},
|
|
9998
|
+
{
|
|
9999
|
+
onChunk: (chunk) => {
|
|
10000
|
+
handleAddPageChunk(chunk);
|
|
10001
|
+
if (chunk.type === "result" && chunk.text) {
|
|
10002
|
+
deps.setAddPageResultBanner({
|
|
10003
|
+
kind: "success",
|
|
10004
|
+
message: "Page created — use annotate tools to refine details.",
|
|
10005
|
+
pageRoute: chunk.text,
|
|
10006
|
+
showRetry: false,
|
|
10007
|
+
showFixWithAiditor: false
|
|
10008
|
+
});
|
|
10009
|
+
void openPreviewForRoute(chunk.text);
|
|
10010
|
+
}
|
|
10011
|
+
if (chunk.type === "error" && "validateErrors" in chunk && Array.isArray(
|
|
10012
|
+
chunk.validateErrors
|
|
10013
|
+
) && (chunk.validateErrors?.length ?? 0) > 0) {
|
|
10014
|
+
deps.setAddPageResultBanner({
|
|
10015
|
+
kind: "failed",
|
|
10016
|
+
message: "Validation failed.",
|
|
10017
|
+
pageRoute: route,
|
|
10018
|
+
showRetry: true,
|
|
10019
|
+
showFixWithAiditor: true
|
|
10020
|
+
});
|
|
10021
|
+
} else if (chunk.type === "error") {
|
|
10022
|
+
deps.setAddPageResultBanner({
|
|
10023
|
+
kind: "failed",
|
|
10024
|
+
message: chunk.message ?? "Add Page failed.",
|
|
10025
|
+
pageRoute: route,
|
|
10026
|
+
showRetry: true,
|
|
10027
|
+
showFixWithAiditor: true
|
|
10028
|
+
});
|
|
10029
|
+
}
|
|
10030
|
+
},
|
|
10031
|
+
onEnd: () => {
|
|
10032
|
+
deps.setIsRunning(false);
|
|
10033
|
+
setAddPageSubmitting(false);
|
|
10034
|
+
},
|
|
10035
|
+
onError: (err) => {
|
|
10036
|
+
deps.appendAgentOutputChunk(err.message, "chunk chunk-error");
|
|
10037
|
+
deps.setIsRunning(false);
|
|
10038
|
+
setAddPageSubmitting(false);
|
|
10039
|
+
deps.setAddPageResultBanner({
|
|
10040
|
+
kind: "failed",
|
|
10041
|
+
message: err.message,
|
|
10042
|
+
pageRoute: route,
|
|
10043
|
+
showRetry: true,
|
|
10044
|
+
showFixWithAiditor: false
|
|
10045
|
+
});
|
|
10046
|
+
}
|
|
10047
|
+
}
|
|
10048
|
+
);
|
|
10049
|
+
deps.setStopStream(abort);
|
|
10050
|
+
})();
|
|
10051
|
+
}
|
|
10052
|
+
function retryAddPage() {
|
|
10053
|
+
const snap = lastSubmitSnapshot;
|
|
10054
|
+
if (!snap) {
|
|
10055
|
+
openAddPageComposer();
|
|
10056
|
+
return;
|
|
10057
|
+
}
|
|
10058
|
+
setAddPageRoute(snap.pageRoute);
|
|
10059
|
+
setAddPageContentMd(snap.contentMd);
|
|
10060
|
+
setAddPageDesignMd(snap.designMd);
|
|
10061
|
+
setAddPageRequestId(snap.requestId);
|
|
10062
|
+
submitAddPage(true);
|
|
10063
|
+
}
|
|
10064
|
+
function bindAddPageRefs(refs) {
|
|
10065
|
+
refs.addPageOpenBtn.onclick(() => openAddPageComposer());
|
|
10066
|
+
refs.addPageFromBriefBtn.onclick(() => {
|
|
10067
|
+
void openAddPageComposerFromBrief();
|
|
10068
|
+
});
|
|
10069
|
+
refs.addPageCloseBtn.onclick(() => closeAddPageComposer());
|
|
10070
|
+
refs.addPageCancelBtn.onclick(() => closeAddPageComposer());
|
|
10071
|
+
refs.addPageOverlay.onclick(({ event }) => {
|
|
10072
|
+
if (event.target === event.currentTarget) {
|
|
10073
|
+
closeAddPageComposer();
|
|
10074
|
+
}
|
|
10075
|
+
});
|
|
10076
|
+
refs.addPageCreateBtn.onclick(() => submitAddPage(false));
|
|
10077
|
+
refs.addPageRouteInput.oninput(({ event }) => {
|
|
10078
|
+
const v = event.target.value;
|
|
10079
|
+
setAddPageRoute(v);
|
|
10080
|
+
scheduleRouteCheck(v);
|
|
10081
|
+
});
|
|
10082
|
+
refs.addPageContentMd.oninput(({ event }) => {
|
|
10083
|
+
contentTextareaEl = event.target;
|
|
10084
|
+
setAddPageContentMd(contentTextareaEl.value);
|
|
10085
|
+
updateDesignHint();
|
|
10086
|
+
});
|
|
10087
|
+
refs.addPageDesignMd.oninput(({ event }) => {
|
|
10088
|
+
designTextareaEl = event.target;
|
|
10089
|
+
setAddPageDesignMd(designTextareaEl.value);
|
|
10090
|
+
updateDesignHint();
|
|
10091
|
+
});
|
|
10092
|
+
function imageFilesFromDataTransfer(dt) {
|
|
10093
|
+
if (!dt?.files?.length) return [];
|
|
10094
|
+
return Array.from(dt.files).filter((f2) => f2.type.startsWith("image/"));
|
|
10095
|
+
}
|
|
10096
|
+
function bindAddPageMarkdownFileDrop(ref, markdownTarget) {
|
|
10097
|
+
ref.ondragover(({ event }) => {
|
|
10098
|
+
if (imageFilesFromDataTransfer(event.dataTransfer).length > 0) {
|
|
10099
|
+
event.preventDefault();
|
|
10100
|
+
}
|
|
10101
|
+
});
|
|
10102
|
+
ref.ondrop(({ event }) => {
|
|
10103
|
+
const files = imageFilesFromDataTransfer(event.dataTransfer);
|
|
10104
|
+
if (files.length === 0) return;
|
|
10105
|
+
event.preventDefault();
|
|
10106
|
+
for (const file of files) {
|
|
10107
|
+
void handleAddPageUpload(file, "asset", markdownTarget);
|
|
10108
|
+
}
|
|
10109
|
+
});
|
|
10110
|
+
ref.addEventListener("paste", (ev) => {
|
|
10111
|
+
const files = imageFilesFromPasteEvent(ev.event);
|
|
10112
|
+
if (files.length === 0) return;
|
|
10113
|
+
ev.event.preventDefault();
|
|
10114
|
+
for (const file of files) {
|
|
10115
|
+
void handleAddPageUpload(file, "asset", markdownTarget);
|
|
10116
|
+
}
|
|
10117
|
+
});
|
|
10118
|
+
}
|
|
10119
|
+
bindAddPageMarkdownFileDrop(refs.addPageContentMd, "content");
|
|
10120
|
+
bindAddPageMarkdownFileDrop(refs.addPageDesignMd, "design");
|
|
10121
|
+
refs.addPageReferenceFileInput.onchange(
|
|
10122
|
+
({ event }) => {
|
|
10123
|
+
const input = event.target;
|
|
10124
|
+
const files = input.files ? Array.from(input.files) : [];
|
|
10125
|
+
for (const file of files) void handleAddPageUpload(file, "reference");
|
|
10126
|
+
input.value = "";
|
|
10127
|
+
}
|
|
10128
|
+
);
|
|
10129
|
+
refs.addPageReferenceDrop.ondragover(
|
|
10130
|
+
({ event }) => {
|
|
10131
|
+
event.preventDefault();
|
|
10132
|
+
}
|
|
10133
|
+
);
|
|
10134
|
+
refs.addPageReferenceDrop.ondrop(
|
|
10135
|
+
({ event }) => {
|
|
10136
|
+
event.preventDefault();
|
|
10137
|
+
const files = event.dataTransfer?.files;
|
|
10138
|
+
if (!files?.length) return;
|
|
10139
|
+
for (const file of Array.from(files)) {
|
|
10140
|
+
void handleAddPageUpload(file, "reference");
|
|
10141
|
+
}
|
|
10142
|
+
}
|
|
10143
|
+
);
|
|
10144
|
+
refs.addPageAttachReferenceBtn.onclick(() => {
|
|
10145
|
+
tryJayRefExec(refs.addPageReferenceFileInput, (el) => {
|
|
10146
|
+
el.click();
|
|
10147
|
+
});
|
|
10148
|
+
});
|
|
10149
|
+
pluginsPanel.bindPluginsPanelRefs(refs);
|
|
10150
|
+
briefFillPanel.bindBriefFillRefs(refs);
|
|
10151
|
+
refs.addPageAttachmentsList.onchange(
|
|
10152
|
+
({ event }) => {
|
|
10153
|
+
const sel = event.target;
|
|
10154
|
+
const id = sel.dataset.attachmentId;
|
|
10155
|
+
const newRole = sel.value;
|
|
10156
|
+
if (!id) return;
|
|
10157
|
+
const chip = addPageAttachments().find((c) => c.id === id);
|
|
10158
|
+
if (!chip || chip.role === newRole) return;
|
|
10159
|
+
const requestId = addPageRequestId();
|
|
10160
|
+
if (!requestId) return;
|
|
10161
|
+
void reclassifyAddPageAsset({
|
|
10162
|
+
requestId,
|
|
10163
|
+
attachmentId: id,
|
|
10164
|
+
newRole
|
|
10165
|
+
}).then((res) => {
|
|
10166
|
+
setAddPageAttachments(
|
|
10167
|
+
(prev) => prev.map(
|
|
10168
|
+
(c) => c.id === id ? {
|
|
10169
|
+
...c,
|
|
10170
|
+
role: newRole,
|
|
10171
|
+
roleLabel: newRole === "reference" ? "Reference" : "Asset",
|
|
10172
|
+
path: res.path
|
|
10173
|
+
} : c
|
|
10174
|
+
)
|
|
10175
|
+
);
|
|
10176
|
+
});
|
|
10177
|
+
}
|
|
10178
|
+
);
|
|
10179
|
+
refs.addPageAttachmentsList.onclick(
|
|
10180
|
+
({ event }) => {
|
|
10181
|
+
const btn = event.target.closest(
|
|
10182
|
+
"[data-add-page-remove]"
|
|
10183
|
+
);
|
|
10184
|
+
if (!btn) return;
|
|
10185
|
+
const id = btn.dataset.addPageRemove;
|
|
10186
|
+
if (!id) return;
|
|
10187
|
+
setAddPageAttachments((prev) => prev.filter((c) => c.id !== id));
|
|
10188
|
+
updateDesignHint();
|
|
10189
|
+
}
|
|
10190
|
+
);
|
|
10191
|
+
}
|
|
10192
|
+
return {
|
|
10193
|
+
showAddPageComposer,
|
|
10194
|
+
addPageRoute,
|
|
10195
|
+
addPageContentMd,
|
|
10196
|
+
addPageDesignMd,
|
|
10197
|
+
addPageRouteError,
|
|
10198
|
+
addPageComposerError,
|
|
10199
|
+
addPageUploadHint,
|
|
10200
|
+
addPageAttachmentRows: addPageAttachmentDisplayRows,
|
|
10201
|
+
addPageShowDesignHint,
|
|
10202
|
+
showAddPagePluginsPanel: pluginsPanel.showPluginsPanel,
|
|
10203
|
+
showAddPagePagePluginsZone: pluginsPanel.showPagePluginsZone,
|
|
10204
|
+
addPagePluginPickerOptions: pluginsPanel.addPagePluginPickerOptions,
|
|
10205
|
+
addPagePluginPickerValue: pluginsPanel.addPagePluginPickerValue,
|
|
10206
|
+
showAddPageContractPicker: pluginsPanel.showContractPicker,
|
|
10207
|
+
addPagePickerPluginLabel: pluginsPanel.addPagePickerPluginLabel,
|
|
10208
|
+
addPageContractPickerRows: pluginsPanel.addPageContractPickerRows,
|
|
10209
|
+
addPagePagePluginChips: pluginsPanel.pagePluginChipRows,
|
|
10210
|
+
showAddPageHasPagePluginChips: createMemo(
|
|
10211
|
+
() => pluginsPanel.pagePluginChipRows().length > 0
|
|
10212
|
+
),
|
|
10213
|
+
showAddPagePagePluginsEmptyHint: pluginsPanel.showPagePluginsEmptyHint,
|
|
10214
|
+
addPageIsDynamicRoute,
|
|
10215
|
+
addPageCreateDisabled,
|
|
10216
|
+
showAddPageRouteError,
|
|
10217
|
+
showAddPageComposerError,
|
|
10218
|
+
showAddPageUploadHint,
|
|
10219
|
+
showAddPageAttachments,
|
|
10220
|
+
addPageRunningHint,
|
|
10221
|
+
showAddPageRunningHint,
|
|
10222
|
+
showBriefFillPopover: briefFillPanel.showBriefFillPopover,
|
|
10223
|
+
briefFillContextNotes: briefFillPanel.briefFillContextNotes,
|
|
10224
|
+
briefFillPopoverError: briefFillPanel.briefFillPopoverError,
|
|
10225
|
+
showBriefFillPopoverError: briefFillPanel.showBriefFillPopoverError,
|
|
10226
|
+
briefFillDisabled: briefFillPanel.briefFillDisabled,
|
|
10227
|
+
briefFillInputDisabled: briefFillPanel.briefFillInputDisabled,
|
|
10228
|
+
briefFillDropzoneClass: briefFillPanel.briefFillDropzoneClass,
|
|
10229
|
+
addPageBriefFillGenerateDisabled: briefFillPanel.generateDisabled,
|
|
10230
|
+
briefFillStatusHint: briefFillPanel.briefFillStatusHint,
|
|
10231
|
+
showBriefFillStatusHint: briefFillPanel.showBriefFillStatusHint,
|
|
10232
|
+
addPageBriefFillThumbRows: briefFillPanel.imageThumbRows,
|
|
10233
|
+
showBriefFillThumbnails: briefFillPanel.showBriefFillThumbnails,
|
|
10234
|
+
showSuggestedRouteBanner: briefFillPanel.showSuggestedRouteBanner,
|
|
10235
|
+
suggestedRouteLabel: briefFillPanel.suggestedRouteLabel,
|
|
10236
|
+
openAddPageComposer,
|
|
10237
|
+
openAddPageComposerFromBrief,
|
|
10238
|
+
refreshCurrentPageBriefAvailability,
|
|
10239
|
+
closeAddPageComposer,
|
|
10240
|
+
submitAddPage,
|
|
10241
|
+
retryAddPage,
|
|
10242
|
+
openPreviewForRoute,
|
|
10243
|
+
bindAddPageRefs
|
|
10244
|
+
};
|
|
10245
|
+
}
|
|
10246
|
+
function annotationPluginBindings(annotation) {
|
|
10247
|
+
if (annotation.pluginBindings?.length) return [...annotation.pluginBindings];
|
|
10248
|
+
if (annotation.pluginBinding) return [annotation.pluginBinding];
|
|
10249
|
+
return [];
|
|
10250
|
+
}
|
|
10251
|
+
function buildBindingChipLabel(binding, annotationId) {
|
|
10252
|
+
const where = binding.scope === "page" ? "anywhere on page" : `marker #${annotationId}`;
|
|
10253
|
+
return `${binding.pluginName} · ${binding.contractName} · ${where}`;
|
|
10254
|
+
}
|
|
10255
|
+
function markerHeadlessPluginOptions(plugins) {
|
|
10256
|
+
const installed = plugins.filter(
|
|
10257
|
+
(p) => p.kind === "headless" && p.installed && p.showInAddPagePicker !== false && p.contracts.length > 0
|
|
10258
|
+
);
|
|
10259
|
+
const options = installed.map((p) => ({
|
|
10260
|
+
rowKey: p.pluginName,
|
|
10261
|
+
value: p.pluginName,
|
|
10262
|
+
label: p.pluginName
|
|
10263
|
+
}));
|
|
10264
|
+
options.push({
|
|
10265
|
+
rowKey: ADD_PAGE_MANAGE_PLUGINS_VALUE,
|
|
10266
|
+
value: ADD_PAGE_MANAGE_PLUGINS_VALUE,
|
|
10267
|
+
label: "Manage plugins…"
|
|
10268
|
+
});
|
|
10269
|
+
return options;
|
|
10270
|
+
}
|
|
10271
|
+
function markerContractPickerRows(plugins, pluginName, bindings) {
|
|
10272
|
+
const entry = plugins.find((p) => p.pluginName === pluginName);
|
|
10273
|
+
if (!entry?.installed) return [];
|
|
10274
|
+
return entry.contracts.map((c) => ({
|
|
10275
|
+
rowKey: `${pluginName}:${c.contractName}`,
|
|
10276
|
+
pluginName,
|
|
10277
|
+
packageName: entry.packageName,
|
|
10278
|
+
contractName: c.contractName,
|
|
10279
|
+
description: c.description ?? "",
|
|
10280
|
+
onPage: bindings.some(
|
|
10281
|
+
(b) => b.pluginName === pluginName && b.contractName === c.contractName
|
|
10282
|
+
),
|
|
10283
|
+
componentKey: bindings.find(
|
|
10284
|
+
(b) => b.pluginName === pluginName && b.contractName === c.contractName
|
|
10285
|
+
)?.componentKey ?? getDefaultComponentKey(c.contractName)
|
|
10286
|
+
}));
|
|
10287
|
+
}
|
|
10288
|
+
function upsertAnnotationBinding(prev, binding) {
|
|
10289
|
+
const idx = prev.findIndex(
|
|
10290
|
+
(b) => b.pluginName === binding.pluginName && b.contractName === binding.contractName
|
|
10291
|
+
);
|
|
10292
|
+
if (idx === -1) return [...prev, binding];
|
|
10293
|
+
const next = [...prev];
|
|
10294
|
+
next[idx] = binding;
|
|
10295
|
+
return next;
|
|
10296
|
+
}
|
|
10297
|
+
function removeAnnotationBinding(prev, pluginName, contractName) {
|
|
10298
|
+
return prev.filter(
|
|
10299
|
+
(b) => !(b.pluginName === pluginName && b.contractName === contractName)
|
|
10300
|
+
);
|
|
10301
|
+
}
|
|
10302
|
+
function enrichAnnotationBindingUi(annotation, plugins) {
|
|
10303
|
+
const bindings = annotationPluginBindings(annotation);
|
|
10304
|
+
const pickerPlugin = annotation.bindingPickerPlugin ?? "";
|
|
10305
|
+
const open = !!annotation.bindingSectionOpen;
|
|
10306
|
+
return {
|
|
10307
|
+
bindingSectionOpen: open,
|
|
10308
|
+
showBindingControls: open,
|
|
10309
|
+
showMarkerHasBindingChips: bindings.length > 0,
|
|
10310
|
+
showMarkerBindingEmptyHint: bindings.length === 0,
|
|
10311
|
+
markerBindingChips: bindings.map((b) => ({
|
|
10312
|
+
rowKey: `${b.pluginName}:${b.contractName}`,
|
|
10313
|
+
label: buildBindingChipLabel(b, annotation.id),
|
|
10314
|
+
pluginName: b.pluginName,
|
|
10315
|
+
packageName: b.packageName,
|
|
10316
|
+
contractName: b.contractName,
|
|
10317
|
+
scope: b.scope
|
|
10318
|
+
})),
|
|
10319
|
+
markerPluginOptions: markerHeadlessPluginOptions(plugins),
|
|
10320
|
+
markerContractPickerRows: markerContractPickerRows(
|
|
10321
|
+
plugins,
|
|
10322
|
+
pickerPlugin,
|
|
10323
|
+
bindings
|
|
10324
|
+
),
|
|
10325
|
+
showMarkerContractPicker: pickerPlugin.length > 0,
|
|
10326
|
+
markerPickerPluginLabel: pickerPlugin ? `Components from ${pickerPlugin}` : ""
|
|
10327
|
+
};
|
|
10328
|
+
}
|
|
10329
|
+
function bindingFromSelection(plugins, pluginName, contractName, scope) {
|
|
10330
|
+
const entry = plugins.find((p) => p.pluginName === pluginName);
|
|
10331
|
+
if (!entry?.installed || !contractName) return void 0;
|
|
10332
|
+
return {
|
|
10333
|
+
pluginName,
|
|
10334
|
+
packageName: entry.packageName,
|
|
10335
|
+
contractName,
|
|
10336
|
+
componentKey: getDefaultComponentKey(contractName),
|
|
10337
|
+
scope
|
|
10338
|
+
};
|
|
10339
|
+
}
|
|
10340
|
+
function buildPluginInstallAgentNotes(entry, installError, projectDirHint) {
|
|
10341
|
+
const requires = entry.requires.length > 0 ? entry.requires.join(", ") : "(none — install this plugin only)";
|
|
10342
|
+
const wixPortal = entry.packageName.startsWith("@jay-framework/wix-") ? `
|
|
10343
|
+
- If npm is unreachable, use portal from project root: \`portal:../../../wix/packages/${entry.pluginName}\` (adjust if your wix repo path differs).` : "";
|
|
10344
|
+
return [
|
|
10345
|
+
"Install a Jay Framework plugin for this project. Work in the project directory shown below.",
|
|
10346
|
+
"",
|
|
10347
|
+
`Project directory (Jay stack app root): ${projectDirHint}`,
|
|
10348
|
+
"",
|
|
10349
|
+
"## Plugin to install",
|
|
10350
|
+
`- pluginName: ${entry.pluginName}`,
|
|
10351
|
+
`- packageName: ${entry.packageName}`,
|
|
10352
|
+
`- requires (install these first if missing): ${requires}`,
|
|
10353
|
+
"",
|
|
10354
|
+
"## AIditor automatic install failed",
|
|
10355
|
+
installError,
|
|
10356
|
+
"",
|
|
10357
|
+
"## Required steps (in order)",
|
|
10358
|
+
"1. Determine monorepo layout: if the project is `examples/starter` inside `jay-aiditor`, run Yarn from the **workspace root** (parent with `packageManager: yarn@4.x` in package.json), NOT global Yarn 1.x.",
|
|
10359
|
+
"2. Install dependencies first, then the plugin:",
|
|
10360
|
+
" - From workspace root: `corepack yarn workspace aiditor-starter add <packageName>` (use latest published version, or an explicit `@0.16.x` if needed).",
|
|
10361
|
+
" - Or from project root with Yarn 4: `corepack yarn add <packageName>`.",
|
|
10362
|
+
" - Do NOT use bare `yarn add` if it reports Yarn 1.22 — use `corepack yarn` instead.",
|
|
10363
|
+
"3. Run `npx jay-stack-cli setup <pluginName>` in the project directory.",
|
|
10364
|
+
"4. Run `npx jay-stack-cli agent-kit --plugin <pluginName>` in the project directory.",
|
|
10365
|
+
"5. Confirm `package.json` lists the package and `agent-kit/plugins-index.yaml` includes the plugin contracts.",
|
|
10366
|
+
"",
|
|
10367
|
+
"## Local / monorepo alternative",
|
|
10368
|
+
wixPortal,
|
|
10369
|
+
"- Read `agent-kit/plugin/INSTRUCTIONS.md` for plugin setup conventions.",
|
|
10370
|
+
"",
|
|
10371
|
+
"When finished, summarize what you installed and any config files the user must edit (e.g. config/.wix.yaml)."
|
|
10372
|
+
].filter((line) => line !== "").join("\n");
|
|
10373
|
+
}
|
|
10374
|
+
const LOCAL_SPEC_PREFIXES = ["portal:", "file:", "workspace:"];
|
|
10375
|
+
function isRegistryInstallSpec(installSpec) {
|
|
10376
|
+
if (!installSpec) return true;
|
|
10377
|
+
return !LOCAL_SPEC_PREFIXES.some((p) => installSpec.startsWith(p));
|
|
10378
|
+
}
|
|
10379
|
+
const VALID_INSTALL_PREFIXES = ["portal:", "file:", "workspace:"];
|
|
10380
|
+
function isValidInstallSpec(spec) {
|
|
10381
|
+
return VALID_INSTALL_PREFIXES.some((p) => spec.startsWith(p));
|
|
10382
|
+
}
|
|
10383
|
+
function initProjectPluginsManager(deps) {
|
|
10384
|
+
const [pluginsList, setPluginsList] = createSignal([]);
|
|
10385
|
+
const [pluginsLoaded, setPluginsLoaded] = createSignal(false);
|
|
10386
|
+
const [installingPlugin, setInstallingPlugin] = createSignal(
|
|
10387
|
+
null
|
|
10388
|
+
);
|
|
10389
|
+
const [installStepLabel, setInstallStepLabel] = createSignal("");
|
|
10390
|
+
const [pluginsPanelError, setPluginsPanelError] = createSignal("");
|
|
10391
|
+
const [failedInstallPlugin, setFailedInstallPlugin] = createSignal(null);
|
|
10392
|
+
const [wixConfigWarning, setWixConfigWarning] = createSignal(false);
|
|
10393
|
+
const [showReloadPreviewBanner, setShowReloadPreviewBanner] = createSignal(false);
|
|
10394
|
+
const [showAddLocalPluginForm, setShowAddLocalPluginForm] = createSignal(false);
|
|
10395
|
+
const [addLocalPluginName, setAddLocalPluginName] = createSignal("");
|
|
10396
|
+
const [addLocalPackageName, setAddLocalPackageName] = createSignal("");
|
|
10397
|
+
const [addLocalPath, setAddLocalPath] = createSignal("");
|
|
10398
|
+
const [pluginUpdateUi, setPluginUpdateUi] = createSignal({});
|
|
10399
|
+
let installAbort;
|
|
10400
|
+
function updateUiForPlugin(pluginName, patch) {
|
|
10401
|
+
setPluginUpdateUi((prev) => ({
|
|
10402
|
+
...prev,
|
|
10403
|
+
[pluginName]: {
|
|
10404
|
+
checked: false,
|
|
10405
|
+
checking: false,
|
|
10406
|
+
updateAvailable: false,
|
|
10407
|
+
isLocalSource: false,
|
|
10408
|
+
...prev[pluginName],
|
|
10409
|
+
...patch
|
|
10410
|
+
}
|
|
10411
|
+
}));
|
|
10412
|
+
}
|
|
10413
|
+
const availableInstallRows = createMemo(() => {
|
|
10414
|
+
const installing = installingPlugin();
|
|
10415
|
+
return pluginsList().filter(
|
|
10416
|
+
(p) => p.showInAddPagePicker && !p.installed && p.kind !== "tooling"
|
|
10417
|
+
).map((p) => ({
|
|
10418
|
+
rowKey: p.pluginName,
|
|
10419
|
+
pluginName: p.pluginName,
|
|
10420
|
+
packageName: p.packageName,
|
|
10421
|
+
description: p.description,
|
|
10422
|
+
buttonLabel: installing === p.pluginName ? "Installing…" : "Install",
|
|
10423
|
+
buttonDisabled: installing !== null
|
|
10424
|
+
}));
|
|
10425
|
+
});
|
|
10426
|
+
const installedPluginRows = createMemo(() => {
|
|
10427
|
+
const ui = pluginUpdateUi();
|
|
10428
|
+
return pluginsList().filter((p) => p.installed).map((p) => {
|
|
10429
|
+
const updateState = ui[p.pluginName];
|
|
10430
|
+
const isLocal = updateState?.isLocalSource || !isRegistryInstallSpec(p.installSpec);
|
|
10431
|
+
const showUpdateControl = !isLocal;
|
|
10432
|
+
let updateButtonLabel = "Check for update";
|
|
10433
|
+
let showCheckForUpdateBtn = showUpdateControl;
|
|
10434
|
+
let showRunUpdateBtn = false;
|
|
10435
|
+
let updateButtonDisabled = installingPlugin() !== null;
|
|
10436
|
+
if (updateState?.checking) {
|
|
10437
|
+
updateButtonLabel = "Checking…";
|
|
10438
|
+
updateButtonDisabled = true;
|
|
10439
|
+
showCheckForUpdateBtn = true;
|
|
10440
|
+
showRunUpdateBtn = false;
|
|
10441
|
+
} else if (updateState?.checked && updateState.updateAvailable) {
|
|
10442
|
+
updateButtonLabel = `Update to ${updateState.latestVersion ?? "latest"}`;
|
|
10443
|
+
showCheckForUpdateBtn = false;
|
|
10444
|
+
showRunUpdateBtn = true;
|
|
10445
|
+
} else if (updateState?.checked && !updateState.updateAvailable) {
|
|
10446
|
+
updateButtonLabel = "Up to date";
|
|
10447
|
+
updateButtonDisabled = true;
|
|
10448
|
+
showCheckForUpdateBtn = true;
|
|
10449
|
+
showRunUpdateBtn = false;
|
|
10450
|
+
}
|
|
10451
|
+
const versionLabel = updateState?.installedVersion ? `v${updateState.installedVersion}` : p.installedVersion ? `v${p.installedVersion}` : isLocal ? "local" : "";
|
|
10452
|
+
const setupBadge = p.setupStatus === "configured" ? "Configured" : p.setupStatus === "needs-config" ? "Needs configuration" : p.setupStatus === "error" ? "Setup failed" : "";
|
|
10453
|
+
const setupBadgeClass = p.setupStatus === "configured" ? "add-page-setup-ok" : p.setupStatus === "needs-config" ? "add-page-setup-warn" : "add-page-setup-error";
|
|
10454
|
+
const contractSummary = p.kind === "headless" && p.contracts.length > 0 ? p.contracts.map((c) => c.contractName).join(", ") : p.kind === "service-only" ? "No page components (service)" : "";
|
|
10455
|
+
return {
|
|
10456
|
+
rowKey: p.pluginName,
|
|
10457
|
+
pluginName: p.pluginName,
|
|
10458
|
+
packageName: p.packageName,
|
|
10459
|
+
description: p.description,
|
|
10460
|
+
versionLabel,
|
|
10461
|
+
setupBadge,
|
|
10462
|
+
setupBadgeClass,
|
|
10463
|
+
configFile: p.configFiles[0] ?? "",
|
|
10464
|
+
showConfig: p.configFiles.length > 0,
|
|
10465
|
+
contractSummary,
|
|
10466
|
+
showUpdateControl,
|
|
10467
|
+
showCheckForUpdateBtn,
|
|
10468
|
+
showRunUpdateBtn,
|
|
10469
|
+
updateButtonLabel,
|
|
10470
|
+
updateButtonDisabled
|
|
10471
|
+
};
|
|
10472
|
+
});
|
|
10473
|
+
});
|
|
10474
|
+
const showInstallZone = createMemo(() => availableInstallRows().length > 0);
|
|
10475
|
+
const showInstalledZone = createMemo(() => installedPluginRows().length > 0);
|
|
10476
|
+
const showPluginsPanel = createMemo(
|
|
10477
|
+
() => pluginsLoaded() && pluginsList().length > 0
|
|
10478
|
+
);
|
|
10479
|
+
const showPluginsPanelError = createMemo(
|
|
10480
|
+
() => pluginsPanelError().length > 0
|
|
10481
|
+
);
|
|
10482
|
+
const showFixInstallWithAgent = createMemo(
|
|
10483
|
+
() => showPluginsPanelError() && failedInstallPlugin() !== null && deps.fixInstallWithAgent !== void 0
|
|
10484
|
+
);
|
|
10485
|
+
const fixInstallPluginName = createMemo(() => failedInstallPlugin() ?? "");
|
|
10486
|
+
const showInstallProgress = createMemo(
|
|
10487
|
+
() => installingPlugin() !== null && installStepLabel().length > 0
|
|
10488
|
+
);
|
|
10489
|
+
const installInProgress = createMemo(() => installingPlugin() !== null);
|
|
10490
|
+
const showWixConfigWarning = createMemo(() => wixConfigWarning());
|
|
10491
|
+
const showReloadPreview = createMemo(() => showReloadPreviewBanner());
|
|
10492
|
+
async function refreshPluginsList(refreshSetup = false) {
|
|
10493
|
+
try {
|
|
10494
|
+
const result = await listJayPlugins(refreshSetup);
|
|
10495
|
+
setPluginsList(result.plugins);
|
|
10496
|
+
setPluginsLoaded(true);
|
|
10497
|
+
const wixClient = result.plugins.find(
|
|
10498
|
+
(p) => p.pluginName === "wix-server-client"
|
|
10499
|
+
);
|
|
10500
|
+
setWixConfigWarning(
|
|
10501
|
+
!!wixClient?.installed && wixClient.setupStatus === "needs-config"
|
|
10502
|
+
);
|
|
10503
|
+
} catch (err) {
|
|
10504
|
+
setPluginsPanelError(err instanceof Error ? err.message : String(err));
|
|
10505
|
+
}
|
|
10506
|
+
}
|
|
10507
|
+
async function runCheckUpdate(pluginName) {
|
|
10508
|
+
updateUiForPlugin(pluginName, { checking: true });
|
|
10509
|
+
setPluginsPanelError("");
|
|
10510
|
+
try {
|
|
10511
|
+
const result = await checkPluginUpdate(pluginName);
|
|
10512
|
+
updateUiForPlugin(pluginName, {
|
|
10513
|
+
checking: false,
|
|
10514
|
+
checked: true,
|
|
10515
|
+
updateAvailable: result.updateAvailable,
|
|
10516
|
+
installedVersion: result.installedVersion ?? void 0,
|
|
10517
|
+
latestVersion: result.latestVersion ?? void 0,
|
|
10518
|
+
isLocalSource: result.isLocalSource,
|
|
10519
|
+
message: result.message
|
|
10520
|
+
});
|
|
10521
|
+
if (result.message && !result.updateAvailable) {
|
|
10522
|
+
setPluginsPanelError("");
|
|
10523
|
+
}
|
|
10524
|
+
} catch (err) {
|
|
10525
|
+
updateUiForPlugin(pluginName, { checking: false, checked: false });
|
|
10526
|
+
setPluginsPanelError(err instanceof Error ? err.message : String(err));
|
|
10527
|
+
}
|
|
10528
|
+
}
|
|
10529
|
+
async function runInstall(pluginName, installSpec, options) {
|
|
10530
|
+
setInstallingPlugin(pluginName);
|
|
10531
|
+
setInstallStepLabel(
|
|
10532
|
+
options?.upgrade ? "Starting update…" : "Starting install…"
|
|
10533
|
+
);
|
|
10534
|
+
setPluginsPanelError("");
|
|
10535
|
+
setFailedInstallPlugin(null);
|
|
10536
|
+
installAbort?.();
|
|
10537
|
+
installAbort = ensureProjectPluginStream(
|
|
10538
|
+
{ pluginName, installSpec, upgrade: options?.upgrade },
|
|
10539
|
+
{
|
|
10540
|
+
onChunk: (chunk) => {
|
|
10541
|
+
if (chunk.type === "progress" && chunk.message) {
|
|
10542
|
+
const step = chunk.step === "package" ? "Package" : chunk.step === "requires" ? "Dependencies" : chunk.step === "setup" ? "Setup" : chunk.step === "agent-kit" ? "Contracts" : "Installing";
|
|
10543
|
+
setInstallStepLabel(`${step}: ${chunk.message}`);
|
|
10544
|
+
}
|
|
10545
|
+
if (chunk.type === "error") {
|
|
10546
|
+
setFailedInstallPlugin(pluginName);
|
|
10547
|
+
setPluginsPanelError(
|
|
10548
|
+
chunk.installError ?? chunk.message ?? "Install failed."
|
|
10549
|
+
);
|
|
10550
|
+
setInstallingPlugin(null);
|
|
10551
|
+
setInstallStepLabel("");
|
|
10552
|
+
}
|
|
10553
|
+
if (chunk.type === "complete") {
|
|
10554
|
+
setInstallingPlugin(null);
|
|
10555
|
+
setInstallStepLabel("");
|
|
10556
|
+
updateUiForPlugin(pluginName, {
|
|
10557
|
+
checked: false,
|
|
10558
|
+
checking: false,
|
|
10559
|
+
updateAvailable: false
|
|
10560
|
+
});
|
|
10561
|
+
void refreshPluginsList(true).then(() => deps.loadProjectInfo());
|
|
10562
|
+
setShowReloadPreviewBanner(true);
|
|
10563
|
+
}
|
|
10564
|
+
},
|
|
10565
|
+
onEnd: () => {
|
|
10566
|
+
setInstallingPlugin(null);
|
|
10567
|
+
},
|
|
10568
|
+
onError: (err) => {
|
|
10569
|
+
setFailedInstallPlugin(pluginName);
|
|
10570
|
+
setPluginsPanelError(err.message);
|
|
10571
|
+
setInstallingPlugin(null);
|
|
10572
|
+
setInstallStepLabel("");
|
|
10573
|
+
}
|
|
10574
|
+
}
|
|
10575
|
+
);
|
|
10576
|
+
}
|
|
10577
|
+
function resetManager() {
|
|
10578
|
+
setPluginsList([]);
|
|
10579
|
+
setPluginsLoaded(false);
|
|
10580
|
+
setInstallingPlugin(null);
|
|
10581
|
+
setInstallStepLabel("");
|
|
10582
|
+
setPluginsPanelError("");
|
|
10583
|
+
setFailedInstallPlugin(null);
|
|
10584
|
+
setWixConfigWarning(false);
|
|
10585
|
+
setShowReloadPreviewBanner(false);
|
|
10586
|
+
setShowAddLocalPluginForm(false);
|
|
10587
|
+
setAddLocalPluginName("");
|
|
10588
|
+
setAddLocalPackageName("");
|
|
10589
|
+
setAddLocalPath("");
|
|
10590
|
+
setPluginUpdateUi({});
|
|
10591
|
+
installAbort?.();
|
|
10592
|
+
installAbort = void 0;
|
|
10593
|
+
}
|
|
10594
|
+
function bindProjectPluginsRefs(refs) {
|
|
10595
|
+
refs.projectPluginsPanel.onclick(
|
|
10596
|
+
({ event }) => {
|
|
10597
|
+
const target = event.target;
|
|
10598
|
+
const installBtn = target.closest(
|
|
10599
|
+
"[data-project-install-plugin]"
|
|
10600
|
+
);
|
|
10601
|
+
if (installBtn) {
|
|
10602
|
+
const name = installBtn.dataset.plugin;
|
|
10603
|
+
if (name) void runInstall(name, installBtn.dataset.installSpec);
|
|
10604
|
+
return;
|
|
10605
|
+
}
|
|
10606
|
+
const checkUpdateBtn = target.closest(
|
|
10607
|
+
"[data-project-check-update]"
|
|
10608
|
+
);
|
|
10609
|
+
if (checkUpdateBtn?.dataset.plugin) {
|
|
10610
|
+
void runCheckUpdate(checkUpdateBtn.dataset.plugin);
|
|
10611
|
+
return;
|
|
10612
|
+
}
|
|
10613
|
+
const runUpdateBtn = target.closest(
|
|
10614
|
+
"[data-project-run-update]"
|
|
10615
|
+
);
|
|
10616
|
+
if (runUpdateBtn?.dataset.plugin) {
|
|
10617
|
+
void runInstall(runUpdateBtn.dataset.plugin, void 0, {
|
|
10618
|
+
upgrade: true
|
|
10619
|
+
});
|
|
10620
|
+
return;
|
|
10621
|
+
}
|
|
10622
|
+
const rerunBtn = target.closest(
|
|
10623
|
+
"[data-project-rerun-setup]"
|
|
10624
|
+
);
|
|
10625
|
+
if (rerunBtn?.dataset.plugin) {
|
|
10626
|
+
void rerunPluginSetup(rerunBtn.dataset.plugin).then(
|
|
10627
|
+
() => refreshPluginsList(true)
|
|
10628
|
+
);
|
|
10629
|
+
return;
|
|
10630
|
+
}
|
|
10631
|
+
const openConfigBtn = target.closest(
|
|
10632
|
+
"[data-project-open-config]"
|
|
10633
|
+
);
|
|
10634
|
+
if (openConfigBtn?.dataset.config) {
|
|
10635
|
+
void readFileAction({ filePath: openConfigBtn.dataset.config }).then(
|
|
10636
|
+
(res) => {
|
|
10637
|
+
if (res.type === "text") {
|
|
10638
|
+
window.alert(
|
|
10639
|
+
`${openConfigBtn.dataset.config}
|
|
10640
|
+
|
|
10641
|
+
(Edit in your IDE — secrets are not edited in AIditor.)
|
|
10642
|
+
|
|
10643
|
+
${res.data.slice(0, 2e3)}`
|
|
10644
|
+
);
|
|
10645
|
+
}
|
|
10646
|
+
}
|
|
10647
|
+
);
|
|
10648
|
+
return;
|
|
10649
|
+
}
|
|
10650
|
+
const fixAgentBtn = target.closest(
|
|
10651
|
+
"[data-project-fix-install-agent]"
|
|
10652
|
+
);
|
|
10653
|
+
if (fixAgentBtn?.dataset.plugin) {
|
|
10654
|
+
const name = fixAgentBtn.dataset.plugin;
|
|
10655
|
+
const err = pluginsPanelError();
|
|
10656
|
+
if (name && err && deps.fixInstallWithAgent) {
|
|
10657
|
+
deps.fixInstallWithAgent(name, err);
|
|
10658
|
+
}
|
|
10659
|
+
return;
|
|
10660
|
+
}
|
|
10661
|
+
if (target.closest("[data-project-show-local-plugin]")) {
|
|
10662
|
+
setShowAddLocalPluginForm(true);
|
|
10663
|
+
return;
|
|
10664
|
+
}
|
|
10665
|
+
if (target.closest("[data-project-cancel-local-plugin]")) {
|
|
10666
|
+
setShowAddLocalPluginForm(false);
|
|
10667
|
+
return;
|
|
10668
|
+
}
|
|
10669
|
+
if (target.closest("[data-project-save-local-plugin]")) {
|
|
10670
|
+
void (async () => {
|
|
10671
|
+
const pluginName = addLocalPluginName().trim();
|
|
10672
|
+
const packageName = addLocalPackageName().trim();
|
|
10673
|
+
let installSpec = addLocalPath().trim();
|
|
10674
|
+
if (!pluginName || !packageName || !installSpec) {
|
|
10675
|
+
setPluginsPanelError("Fill plugin name, package, and path.");
|
|
10676
|
+
return;
|
|
10677
|
+
}
|
|
10678
|
+
if (!isValidInstallSpec(installSpec)) {
|
|
10679
|
+
installSpec = `portal:${installSpec.replace(/^\.\//, "")}`;
|
|
10680
|
+
}
|
|
10681
|
+
if (!isValidInstallSpec(installSpec)) {
|
|
10682
|
+
setPluginsPanelError(
|
|
10683
|
+
"Path must be portal:, file:, or workspace: (or a relative path for portal:)."
|
|
10684
|
+
);
|
|
10685
|
+
return;
|
|
10686
|
+
}
|
|
10687
|
+
try {
|
|
10688
|
+
await writePluginSource({
|
|
10689
|
+
pluginName,
|
|
10690
|
+
packageName,
|
|
10691
|
+
installSpec,
|
|
10692
|
+
label: "Local"
|
|
10693
|
+
});
|
|
10694
|
+
setShowAddLocalPluginForm(false);
|
|
10695
|
+
setAddLocalPluginName("");
|
|
10696
|
+
setAddLocalPackageName("");
|
|
10697
|
+
setAddLocalPath("");
|
|
10698
|
+
setPluginsPanelError("");
|
|
10699
|
+
await refreshPluginsList();
|
|
10700
|
+
} catch (err) {
|
|
10701
|
+
setPluginsPanelError(
|
|
10702
|
+
err instanceof Error ? err.message : String(err)
|
|
10703
|
+
);
|
|
10704
|
+
}
|
|
10705
|
+
})();
|
|
10706
|
+
}
|
|
10707
|
+
}
|
|
10708
|
+
);
|
|
10709
|
+
}
|
|
10710
|
+
return {
|
|
10711
|
+
pluginsList,
|
|
10712
|
+
pluginsLoaded,
|
|
10713
|
+
refreshPluginsList,
|
|
10714
|
+
resetManager,
|
|
10715
|
+
bindProjectPluginsRefs,
|
|
10716
|
+
availableInstallRows,
|
|
10717
|
+
installedPluginRows,
|
|
10718
|
+
showInstallZone,
|
|
10719
|
+
showInstalledZone,
|
|
10720
|
+
showPluginsPanel,
|
|
10721
|
+
showPluginsPanelError,
|
|
10722
|
+
showFixInstallWithAgent,
|
|
10723
|
+
fixInstallPluginName,
|
|
10724
|
+
pluginsPanelError,
|
|
10725
|
+
showInstallProgress,
|
|
10726
|
+
installStepLabel,
|
|
10727
|
+
showWixConfigWarning,
|
|
10728
|
+
showReloadPreview,
|
|
10729
|
+
installInProgress,
|
|
10730
|
+
showAddLocalPluginForm,
|
|
10731
|
+
addLocalPluginName,
|
|
10732
|
+
addLocalPackageName,
|
|
10733
|
+
addLocalPath,
|
|
10734
|
+
setAddLocalPluginName,
|
|
10735
|
+
setAddLocalPackageName,
|
|
10736
|
+
setAddLocalPath,
|
|
10737
|
+
runInstall
|
|
10738
|
+
};
|
|
10739
|
+
}
|
|
10740
|
+
setActionCallerOptions({ timeout: 12e4 });
|
|
10741
|
+
const MAX_ATTACHMENTS_PER_PIN = 10;
|
|
10742
|
+
const MAX_ATTACHMENT_BYTES_PER_PIN = 5 * 1024 * 1024;
|
|
10743
|
+
function mbLabel(bytes) {
|
|
10744
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
10745
|
+
}
|
|
10746
|
+
function newLocalAttachmentId() {
|
|
10747
|
+
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `f_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;
|
|
10748
|
+
}
|
|
10749
|
+
function newAnnotationId() {
|
|
10750
|
+
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `ann_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;
|
|
10751
|
+
}
|
|
10752
|
+
function renumberAnnotations(list) {
|
|
10753
|
+
return list.map((a2, i) => ({ ...a2, id: String(i + 1) }));
|
|
10754
|
+
}
|
|
10755
|
+
function serializeGeometry(a2) {
|
|
10756
|
+
if (a2.kind === "point")
|
|
10757
|
+
return { kind: "point", x: a2.x, y: a2.y };
|
|
10758
|
+
if (a2.kind === "area")
|
|
10759
|
+
return { kind: "area", x: a2.x, y: a2.y, w: a2.w, h: a2.h };
|
|
10760
|
+
return { kind: "arrow", x1: a2.x1, y1: a2.y1, x2: a2.x2, y2: a2.y2 };
|
|
10761
|
+
}
|
|
10762
|
+
function toNotesPayload(annotations, breakpoint) {
|
|
10763
|
+
return {
|
|
10764
|
+
version: AIDITOR_NOTES_VERSION,
|
|
10765
|
+
breakpoint,
|
|
10766
|
+
annotations: annotations.map((a2) => ({
|
|
10767
|
+
id: a2.id,
|
|
10768
|
+
mode: a2.kind,
|
|
10769
|
+
instruction: a2.instruction.trim(),
|
|
10770
|
+
geometry: serializeGeometry(a2),
|
|
10771
|
+
...a2.pluginBindings?.length ? { pluginBindings: a2.pluginBindings } : {}
|
|
10772
|
+
}))
|
|
10773
|
+
};
|
|
10774
|
+
}
|
|
10775
|
+
function toVideoNotesPayload(annotations, videoMeta, notesContext) {
|
|
10776
|
+
const baseOrigin = typeof window !== "undefined" ? window.location.origin : JAY_DEV_URL_DEFAULT;
|
|
10777
|
+
const fallback = fallbackPreviewContextFromBar(notesContext.fallbackRenderedUrl, notesContext.fallbackRoute, baseOrigin);
|
|
10778
|
+
const navLog = notesContext.previewNavLog.length > 0 ? notesContext.previewNavLog : void 0;
|
|
10779
|
+
const payload = {
|
|
10780
|
+
version: 2,
|
|
10781
|
+
taskKind: "video",
|
|
10782
|
+
videoMeta,
|
|
10783
|
+
previewNavLog: navLog,
|
|
10784
|
+
breakpoint: notesContext.breakpoint,
|
|
10785
|
+
annotations: annotations.map((a2) => {
|
|
10786
|
+
const ctx = resolvePreviewContextAtTime(a2.timeSec, navLog, fallback);
|
|
10787
|
+
return {
|
|
10788
|
+
id: a2.id,
|
|
10789
|
+
mode: a2.kind,
|
|
10790
|
+
instruction: a2.instruction.trim(),
|
|
10791
|
+
geometry: serializeGeometry(a2),
|
|
10792
|
+
timeSec: a2.timeSec,
|
|
10793
|
+
previewUrlAtTime: ctx.href,
|
|
10794
|
+
pagePathAtTime: ctx.locationPath,
|
|
10795
|
+
...a2.pluginBindings?.length ? { pluginBindings: a2.pluginBindings } : {}
|
|
10796
|
+
};
|
|
10797
|
+
})
|
|
10798
|
+
};
|
|
10799
|
+
return JSON.stringify(payload);
|
|
10800
|
+
}
|
|
10801
|
+
function toSerializedVideoForPins(a2) {
|
|
10802
|
+
return {
|
|
10803
|
+
id: a2.id,
|
|
10804
|
+
mode: a2.kind,
|
|
10805
|
+
instruction: a2.instruction,
|
|
10806
|
+
geometry: serializeGeometry(a2),
|
|
10807
|
+
timeSec: a2.timeSec
|
|
10808
|
+
};
|
|
10809
|
+
}
|
|
10810
|
+
function kindLabel(kind) {
|
|
10811
|
+
if (kind === "point")
|
|
10812
|
+
return "Point";
|
|
10813
|
+
if (kind === "area")
|
|
10814
|
+
return "Area";
|
|
10815
|
+
return "Arrow";
|
|
10816
|
+
}
|
|
10817
|
+
const VIDEO_ANNOTATION_TIME_TOLERANCE_SEC = 0.15;
|
|
10818
|
+
function isVideoAnnotationAtPlayhead(playheadSec, annotationTimeSec) {
|
|
10819
|
+
return Math.abs(playheadSec - annotationTimeSec) <= VIDEO_ANNOTATION_TIME_TOLERANCE_SEC;
|
|
10820
|
+
}
|
|
10821
|
+
function bubbleAnchorNorm(a2) {
|
|
10822
|
+
if (a2.kind === "point")
|
|
10823
|
+
return { nx: a2.x, ny: a2.y };
|
|
10824
|
+
if (a2.kind === "area") {
|
|
10825
|
+
return { nx: Math.min(1, a2.x + a2.w), ny: Math.min(1, a2.y + a2.h) };
|
|
10826
|
+
}
|
|
10827
|
+
return { nx: a2.x2, ny: a2.y2 };
|
|
10828
|
+
}
|
|
10829
|
+
const POPOVER_FLIP_X_PCT = 56;
|
|
10830
|
+
const POPOVER_FLIP_Y_PCT = 52;
|
|
10831
|
+
function popoverFlipFromPct(leftPct, topPct) {
|
|
10832
|
+
return {
|
|
10833
|
+
flipX: leftPct > POPOVER_FLIP_X_PCT,
|
|
10834
|
+
flipY: topPct > POPOVER_FLIP_Y_PCT
|
|
10835
|
+
};
|
|
10836
|
+
}
|
|
10837
|
+
const JAY_DEV_URL_DEFAULT = typeof window !== "undefined" ? window.location.origin : "http://localhost:3000";
|
|
10838
|
+
const paramsCache = /* @__PURE__ */ new Map();
|
|
10839
|
+
function dedupePastedFiles(files) {
|
|
10840
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10841
|
+
const out = [];
|
|
10842
|
+
for (const f2 of files) {
|
|
10843
|
+
const k = `${f2.name}\0${f2.size}\0${f2.lastModified}\0${f2.type}`;
|
|
10844
|
+
if (seen.has(k))
|
|
10845
|
+
continue;
|
|
10846
|
+
seen.add(k);
|
|
10847
|
+
out.push(f2);
|
|
10848
|
+
}
|
|
10849
|
+
return out;
|
|
10850
|
+
}
|
|
10851
|
+
function filesFromClipboardData(cd) {
|
|
10852
|
+
if (!cd)
|
|
10853
|
+
return [];
|
|
10854
|
+
const accum = [];
|
|
10855
|
+
for (let i = 0; i < cd.files.length; i++) {
|
|
10856
|
+
const f2 = cd.files.item(i);
|
|
10857
|
+
if (f2)
|
|
10858
|
+
accum.push(f2);
|
|
10859
|
+
}
|
|
10860
|
+
if (cd.items) {
|
|
10861
|
+
for (let i = 0; i < cd.items.length; i++) {
|
|
10862
|
+
const it = cd.items[i];
|
|
10863
|
+
if (it?.kind === "file") {
|
|
10864
|
+
const f2 = it.getAsFile();
|
|
10865
|
+
if (f2)
|
|
10866
|
+
accum.push(f2);
|
|
10867
|
+
}
|
|
10868
|
+
}
|
|
10869
|
+
}
|
|
10870
|
+
return dedupePastedFiles(accum);
|
|
10871
|
+
}
|
|
10872
|
+
function clipboardItemsArray(cd) {
|
|
10873
|
+
const items = cd?.items;
|
|
10874
|
+
if (!items || items.length === 0)
|
|
10875
|
+
return [];
|
|
10876
|
+
return Array.from({ length: items.length }, (_, i) => items[i]).filter(Boolean);
|
|
10877
|
+
}
|
|
10878
|
+
function dataUrlToImageFileSync(dataUrl, index) {
|
|
10879
|
+
const comma = dataUrl.indexOf(",");
|
|
10880
|
+
if (comma < 0)
|
|
10881
|
+
return null;
|
|
10882
|
+
const header = dataUrl.slice(0, comma);
|
|
10883
|
+
const dataPart = dataUrl.slice(comma + 1);
|
|
10884
|
+
const mimeMatch = header.match(/^data:([^;,]+)/i);
|
|
10885
|
+
const mime = mimeMatch?.[1]?.trim() ?? "";
|
|
10886
|
+
if (!mime.startsWith("image/"))
|
|
10887
|
+
return null;
|
|
10888
|
+
const isBase64 = /;base64/i.test(header);
|
|
10889
|
+
let bytes;
|
|
10890
|
+
if (isBase64) {
|
|
10891
|
+
try {
|
|
10892
|
+
const bin = atob(dataPart.replace(/\s/g, ""));
|
|
10893
|
+
bytes = new Uint8Array(bin.length);
|
|
10894
|
+
for (let i = 0; i < bin.length; i++)
|
|
10895
|
+
bytes[i] = bin.charCodeAt(i);
|
|
10896
|
+
} catch {
|
|
10897
|
+
return null;
|
|
10898
|
+
}
|
|
10899
|
+
} else {
|
|
10900
|
+
try {
|
|
10901
|
+
bytes = new TextEncoder().encode(decodeURIComponent(dataPart.replace(/\+/g, "%20")));
|
|
10902
|
+
} catch {
|
|
10903
|
+
return null;
|
|
10904
|
+
}
|
|
10905
|
+
}
|
|
10906
|
+
const extPart = mime.split("/")[1] || "png";
|
|
10907
|
+
const ext = extPart.replace(/\+xml$/, "").split("+")[0] || "png";
|
|
10908
|
+
const buf = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
10909
|
+
return new File([buf], `paste-${index}.${ext}`, { type: mime });
|
|
10910
|
+
}
|
|
10911
|
+
function filesFromPastedHtmlDataUrls(html) {
|
|
10912
|
+
if (!html)
|
|
10913
|
+
return [];
|
|
10914
|
+
let doc;
|
|
10915
|
+
try {
|
|
10916
|
+
doc = new DOMParser().parseFromString(html, "text/html");
|
|
10917
|
+
} catch {
|
|
10918
|
+
return [];
|
|
10919
|
+
}
|
|
10920
|
+
const out = [];
|
|
10921
|
+
for (const img of Array.from(doc.querySelectorAll("img[src]"))) {
|
|
10922
|
+
const src = img.getAttribute("src");
|
|
10923
|
+
if (!src?.startsWith("data:image"))
|
|
10924
|
+
continue;
|
|
10925
|
+
const f2 = dataUrlToImageFileSync(src, out.length);
|
|
10926
|
+
if (f2)
|
|
10927
|
+
out.push(f2);
|
|
10928
|
+
}
|
|
10929
|
+
return dedupePastedFiles(out);
|
|
10930
|
+
}
|
|
10931
|
+
function filesFromPlainDataImageUrl(text) {
|
|
10932
|
+
const t = text.trim();
|
|
10933
|
+
if (!t.startsWith("data:image/"))
|
|
10934
|
+
return [];
|
|
10935
|
+
const f2 = dataUrlToImageFileSync(t, 0);
|
|
10936
|
+
return f2 ? [f2] : [];
|
|
10937
|
+
}
|
|
10938
|
+
async function imageFilesFromNavigatorClipboard() {
|
|
10939
|
+
if (!navigator.clipboard?.read)
|
|
10940
|
+
return [];
|
|
10941
|
+
let clipItems;
|
|
10942
|
+
try {
|
|
10943
|
+
clipItems = await navigator.clipboard.read();
|
|
10944
|
+
} catch {
|
|
10945
|
+
return [];
|
|
10946
|
+
}
|
|
10947
|
+
const out = [];
|
|
10948
|
+
let idx = 0;
|
|
10949
|
+
for (const ci of clipItems) {
|
|
10950
|
+
for (const type of ci.types) {
|
|
10951
|
+
if (!type.startsWith("image/"))
|
|
10952
|
+
continue;
|
|
10953
|
+
try {
|
|
10954
|
+
const blob = await ci.getType(type);
|
|
10955
|
+
if (!(blob instanceof Blob) || blob.size === 0)
|
|
10956
|
+
continue;
|
|
10957
|
+
const ext = type.split("/")[1]?.split("+")[0] || "png";
|
|
10958
|
+
out.push(new File([blob], `paste-${idx++}.${ext}`, { type }));
|
|
10959
|
+
} catch {
|
|
10960
|
+
}
|
|
10961
|
+
}
|
|
10962
|
+
}
|
|
10963
|
+
return dedupePastedFiles(out);
|
|
10964
|
+
}
|
|
10965
|
+
let aiditorBoundDocumentPaste = null;
|
|
10966
|
+
function bindAiditorDocumentPasteCapture(handler) {
|
|
10967
|
+
if (typeof document === "undefined")
|
|
10968
|
+
return;
|
|
10969
|
+
if (aiditorBoundDocumentPaste) {
|
|
10970
|
+
document.removeEventListener("paste", aiditorBoundDocumentPaste, true);
|
|
10971
|
+
}
|
|
10972
|
+
aiditorBoundDocumentPaste = handler;
|
|
10973
|
+
document.addEventListener("paste", handler, true);
|
|
10974
|
+
}
|
|
10975
|
+
function aiditorConstructor(_props, refs) {
|
|
10976
|
+
const [projectDir, setProjectDir] = createSignal("");
|
|
10977
|
+
const [jayDevUrl, setJayDevUrl] = createSignal(JAY_DEV_URL_DEFAULT);
|
|
10978
|
+
const [isBootstrapping, setIsBootstrapping] = createSignal(true);
|
|
10979
|
+
const [showBootstrapError, setShowBootstrapError] = createSignal(false);
|
|
10980
|
+
const [bootstrapErrorText, setBootstrapErrorText] = createSignal("");
|
|
10981
|
+
const [activeTaskId, setActiveTaskId] = createSignal(null);
|
|
10982
|
+
const [chunks, setChunks] = createSignal([]);
|
|
10983
|
+
const [bottomPanelCollapsed, setBottomPanelCollapsed] = createSignal(true);
|
|
10984
|
+
const [agentChatMessage, setAgentChatMessage] = createSignal("");
|
|
10985
|
+
const [addPageResultBanner, setAddPageResultBanner] = createSignal(null);
|
|
10986
|
+
const [isRunning, setIsRunning] = createSignal(false);
|
|
10987
|
+
const [showFilePreview, setShowFilePreview] = createSignal(false);
|
|
8927
10988
|
const [filePreviewPath, setFilePreviewPath] = createSignal("");
|
|
8928
10989
|
const [filePreviewContent, setFilePreviewContent] = createSignal("");
|
|
8929
10990
|
const [filePreviewIsImage, setFilePreviewIsImage] = createSignal(false);
|
|
@@ -8935,6 +10996,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
8935
10996
|
const [httpBaseUrl, setHttpBaseUrl] = createSignal("");
|
|
8936
10997
|
const [isPreviewMode, setIsPreviewMode] = createSignal(false);
|
|
8937
10998
|
const [selectedPageUrl, setSelectedPageUrl] = createSignal(null);
|
|
10999
|
+
const [currentPageHasBrief, setCurrentPageHasBrief] = createSignal(false);
|
|
8938
11000
|
const [previewSrc, setPreviewSrc] = createSignal("");
|
|
8939
11001
|
const [previewUrlBar, setPreviewUrlBar] = createSignal("");
|
|
8940
11002
|
const [previewLoading, setPreviewLoading] = createSignal(false);
|
|
@@ -8956,6 +11018,21 @@ function aiditorConstructor(_props, refs) {
|
|
|
8956
11018
|
const [areaDraft, setAreaDraft] = createSignal(null);
|
|
8957
11019
|
const [arrowPending, setArrowPending] = createSignal(null);
|
|
8958
11020
|
const [visualSubmitError, setVisualSubmitError] = createSignal("");
|
|
11021
|
+
const [showProjectSettingsModal, setShowProjectSettingsModal] = createSignal(false);
|
|
11022
|
+
let runPluginInstallAgent;
|
|
11023
|
+
const projectPlugins = initProjectPluginsManager({
|
|
11024
|
+
loadProjectInfo: () => loadProjectInfo(),
|
|
11025
|
+
fixInstallWithAgent: (pluginName, installError) => {
|
|
11026
|
+
runPluginInstallAgent?.(pluginName, installError);
|
|
11027
|
+
}
|
|
11028
|
+
});
|
|
11029
|
+
function openProjectSettings() {
|
|
11030
|
+
setShowProjectSettingsModal(true);
|
|
11031
|
+
void projectPlugins.refreshPluginsList();
|
|
11032
|
+
}
|
|
11033
|
+
function closeProjectSettings() {
|
|
11034
|
+
setShowProjectSettingsModal(false);
|
|
11035
|
+
}
|
|
8959
11036
|
const [showVideoReviewModal, setShowVideoReviewModal] = createSignal(false);
|
|
8960
11037
|
const [videoReviewObjectUrl, setVideoReviewObjectUrl] = createSignal("");
|
|
8961
11038
|
const [videoReviewPreparing, setVideoReviewPreparing] = createSignal(false);
|
|
@@ -9072,6 +11149,14 @@ function aiditorConstructor(_props, refs) {
|
|
|
9072
11149
|
});
|
|
9073
11150
|
const selectedRouteSelectValue = createMemo(() => selectedPageUrl() ?? "");
|
|
9074
11151
|
const hasPages = createMemo(() => projectPages().length > 0);
|
|
11152
|
+
const selectedPageFilePath = createMemo(() => {
|
|
11153
|
+
const url = selectedPageUrl();
|
|
11154
|
+
if (!url)
|
|
11155
|
+
return "";
|
|
11156
|
+
const page2 = projectPages().find((p) => p.url === url) ?? projectPages().find((p) => p.url === url.replace(/\/+$/, "") || "/");
|
|
11157
|
+
return page2?.filePath ?? "";
|
|
11158
|
+
});
|
|
11159
|
+
const showAddPageFromBriefBtn = createMemo(() => currentPageHasBrief() && selectedPageFilePath().length > 0);
|
|
9075
11160
|
const showPathSelect = createMemo(() => isPreviewMode() && !previewLoading() && !previewError() && previewPathOptions().length > 0);
|
|
9076
11161
|
const showPreviewIframe = createMemo(() => isPreviewMode() && !previewLoading() && !!previewSrc() && !previewError());
|
|
9077
11162
|
const showVisualToolbar = createMemo(() => isPreviewMode() && !previewLoading() && !previewError() && !!previewSrc());
|
|
@@ -9224,6 +11309,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
9224
11309
|
});
|
|
9225
11310
|
const visualAnnotationRows = createMemo(() => {
|
|
9226
11311
|
const runDisabled = visualRunDisabled();
|
|
11312
|
+
const plugins = projectPlugins.pluginsList();
|
|
9227
11313
|
return visualAnnotations().map((a2) => {
|
|
9228
11314
|
const { nx, ny } = bubbleAnchorNorm(a2);
|
|
9229
11315
|
const leftPct = nx * 100;
|
|
@@ -9244,7 +11330,8 @@ function aiditorConstructor(_props, refs) {
|
|
|
9244
11330
|
topPct,
|
|
9245
11331
|
popoverFlipX: flipX,
|
|
9246
11332
|
popoverFlipY: flipY,
|
|
9247
|
-
attachmentChips
|
|
11333
|
+
attachmentChips,
|
|
11334
|
+
...enrichAnnotationBindingUi(a2, plugins)
|
|
9248
11335
|
};
|
|
9249
11336
|
});
|
|
9250
11337
|
});
|
|
@@ -9375,6 +11462,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
9375
11462
|
const t = videoReviewCurrentTimeSec();
|
|
9376
11463
|
const list = fullList.filter((a2) => isVideoAnnotationAtPlayhead(t, a2.timeSec));
|
|
9377
11464
|
const runDisabled = fullList.length > 0 && (isRunning() || fullList.some((a2) => a2.instruction.trim().length === 0));
|
|
11465
|
+
const plugins = projectPlugins.pluginsList();
|
|
9378
11466
|
return list.map((a2) => {
|
|
9379
11467
|
const { nx, ny } = bubbleAnchorNorm(a2);
|
|
9380
11468
|
const leftPct = nx * 100;
|
|
@@ -9396,7 +11484,8 @@ function aiditorConstructor(_props, refs) {
|
|
|
9396
11484
|
topPct,
|
|
9397
11485
|
popoverFlipX: flipX,
|
|
9398
11486
|
popoverFlipY: flipY,
|
|
9399
|
-
attachmentChips
|
|
11487
|
+
attachmentChips,
|
|
11488
|
+
...enrichAnnotationBindingUi(a2, plugins)
|
|
9400
11489
|
};
|
|
9401
11490
|
});
|
|
9402
11491
|
});
|
|
@@ -9521,30 +11610,34 @@ function aiditorConstructor(_props, refs) {
|
|
|
9521
11610
|
const snapshotAreaDraftTopPct = createMemo(() => (snapshotAreaDraftNorm()?.y ?? 0) * 100);
|
|
9522
11611
|
const snapshotAreaDraftWidthPct = createMemo(() => (snapshotAreaDraftNorm()?.w ?? 0) * 100);
|
|
9523
11612
|
const snapshotAreaDraftHeightPct = createMemo(() => (snapshotAreaDraftNorm()?.h ?? 0) * 100);
|
|
9524
|
-
const snapshotAnnotationItems = createMemo(() =>
|
|
9525
|
-
const
|
|
9526
|
-
|
|
9527
|
-
|
|
9528
|
-
|
|
9529
|
-
|
|
9530
|
-
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
11613
|
+
const snapshotAnnotationItems = createMemo(() => {
|
|
11614
|
+
const plugins = projectPlugins.pluginsList();
|
|
11615
|
+
return snapshotAnnotations().map((a2) => {
|
|
11616
|
+
const { nx, ny } = bubbleAnchorNorm(a2);
|
|
11617
|
+
const leftPct = nx * 100;
|
|
11618
|
+
const topPct = ny * 100;
|
|
11619
|
+
const { flipX, flipY } = popoverFlipFromPct(leftPct, topPct);
|
|
11620
|
+
const attachmentChips = a2.attachments.map((at) => ({
|
|
11621
|
+
key: at.id,
|
|
11622
|
+
name: at.file.name,
|
|
11623
|
+
thumbUrl: at.previewUrl && at.file.type.startsWith("image/") ? at.previewUrl : "",
|
|
11624
|
+
annotationId: a2.id
|
|
11625
|
+
}));
|
|
11626
|
+
return {
|
|
11627
|
+
id: a2.id,
|
|
11628
|
+
indexLabel: a2.id,
|
|
11629
|
+
kindLabel: `${a2.id} — ${kindLabel(a2.kind)}`,
|
|
11630
|
+
instruction: a2.instruction,
|
|
11631
|
+
kind: a2.kind,
|
|
11632
|
+
leftPct,
|
|
11633
|
+
topPct,
|
|
11634
|
+
popoverFlipX: flipX,
|
|
11635
|
+
popoverFlipY: flipY,
|
|
11636
|
+
attachmentChips,
|
|
11637
|
+
...enrichAnnotationBindingUi(a2, plugins)
|
|
11638
|
+
};
|
|
11639
|
+
});
|
|
11640
|
+
});
|
|
9548
11641
|
const showSnapshotAnnotationsPanel = createMemo(() => snapshotAnnotations().length > 0);
|
|
9549
11642
|
const showSnapshotSubmitError = createMemo(() => snapshotSubmitError().trim().length > 0);
|
|
9550
11643
|
const showSnapshotPointMarkers = createMemo(() => snapshotPointDisplayItems().length > 0);
|
|
@@ -9558,6 +11651,10 @@ function aiditorConstructor(_props, refs) {
|
|
|
9558
11651
|
const bottomPanelClass = createMemo(() => bottomPanelCollapsed() ? "bottom-panel bottom-panel-collapsed" : "bottom-panel");
|
|
9559
11652
|
const bottomPanelToggleGlyph = createMemo(() => bottomPanelCollapsed() ? "▲" : "▼");
|
|
9560
11653
|
const showBottomPanelRunning = createMemo(() => isRunning());
|
|
11654
|
+
const showAgentChatInput = createMemo(() => !bottomPanelCollapsed());
|
|
11655
|
+
const agentChatInputDisabled = createMemo(() => isRunning());
|
|
11656
|
+
const agentChatSendDisabled = createMemo(() => isRunning() || agentChatMessage().trim().length === 0);
|
|
11657
|
+
const agentChatPlaceholder = createMemo(() => isRunning() ? "Agent is working…" : "Type a message…");
|
|
9561
11658
|
let stopStream = null;
|
|
9562
11659
|
let previewParamsGeneration = 0;
|
|
9563
11660
|
let attachTargetPinId = null;
|
|
@@ -9766,7 +11863,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
9766
11863
|
}
|
|
9767
11864
|
function focusLastSnapshotAnnotationTextarea() {
|
|
9768
11865
|
requestAnimationFrame(() => {
|
|
9769
|
-
|
|
11866
|
+
tryJayRefExec2(refs.snapshotBackdrop, (backdrop) => {
|
|
9770
11867
|
const textareas = backdrop.querySelectorAll("textarea.visual-annotation-instruction");
|
|
9771
11868
|
const last = textareas[textareas.length - 1];
|
|
9772
11869
|
if (last)
|
|
@@ -9787,6 +11884,85 @@ function aiditorConstructor(_props, refs) {
|
|
|
9787
11884
|
setVisualAnnotations((prev) => prev.map((a2) => a2.id === id ? { ...a2, instruction } : a2));
|
|
9788
11885
|
setVisualSubmitError("");
|
|
9789
11886
|
}
|
|
11887
|
+
createEffect(() => {
|
|
11888
|
+
if (visualAnnotations().length > 0 || snapshotAnnotations().length > 0 || videoSessionAnnotations().length > 0 || showProjectSettingsModal()) {
|
|
11889
|
+
void projectPlugins.refreshPluginsList();
|
|
11890
|
+
}
|
|
11891
|
+
});
|
|
11892
|
+
function updateVisualAnnotation(id, updater) {
|
|
11893
|
+
setVisualAnnotations((prev) => prev.map((a2) => a2.id === id ? updater(a2) : a2));
|
|
11894
|
+
}
|
|
11895
|
+
function updateSnapshotAnnotation(id, updater) {
|
|
11896
|
+
setSnapshotAnnotations((prev) => prev.map((a2) => a2.id === id ? updater(a2) : a2));
|
|
11897
|
+
}
|
|
11898
|
+
function updateVideoAnnotation(id, updater) {
|
|
11899
|
+
setVideoSessionAnnotations((prev) => prev.map((a2) => a2.id === id ? updater(a2) : a2));
|
|
11900
|
+
}
|
|
11901
|
+
function updateVideoAsVisual(id, updater) {
|
|
11902
|
+
updateVideoAnnotation(id, (a2) => updater(a2));
|
|
11903
|
+
}
|
|
11904
|
+
function toggleBindingSection(update, id) {
|
|
11905
|
+
update(id, (a2) => ({
|
|
11906
|
+
...a2,
|
|
11907
|
+
bindingSectionOpen: !a2.bindingSectionOpen
|
|
11908
|
+
}));
|
|
11909
|
+
}
|
|
11910
|
+
function setBindingPickerPlugin(update, id, pluginName) {
|
|
11911
|
+
if (pluginName === ADD_PAGE_MANAGE_PLUGINS_VALUE || pluginName === "__install__") {
|
|
11912
|
+
openProjectSettings();
|
|
11913
|
+
return;
|
|
11914
|
+
}
|
|
11915
|
+
update(id, (a2) => ({
|
|
11916
|
+
...a2,
|
|
11917
|
+
bindingSectionOpen: true,
|
|
11918
|
+
bindingPickerPlugin: pluginName
|
|
11919
|
+
}));
|
|
11920
|
+
}
|
|
11921
|
+
function addBindingToAnnotation(update, id, pluginName, _packageName, contractName, componentKey) {
|
|
11922
|
+
const plugins = projectPlugins.pluginsList();
|
|
11923
|
+
update(id, (a2) => {
|
|
11924
|
+
const binding = bindingFromSelection(plugins, pluginName, contractName, "marker");
|
|
11925
|
+
if (!binding)
|
|
11926
|
+
return a2;
|
|
11927
|
+
if (componentKey)
|
|
11928
|
+
binding.componentKey = componentKey;
|
|
11929
|
+
return {
|
|
11930
|
+
...a2,
|
|
11931
|
+
bindingSectionOpen: true,
|
|
11932
|
+
pluginBindings: upsertAnnotationBinding(a2.pluginBindings ?? [], binding)
|
|
11933
|
+
};
|
|
11934
|
+
});
|
|
11935
|
+
}
|
|
11936
|
+
function removeBindingFromAnnotation(update, id, pluginName, contractName) {
|
|
11937
|
+
update(id, (a2) => ({
|
|
11938
|
+
...a2,
|
|
11939
|
+
pluginBindings: removeAnnotationBinding(a2.pluginBindings ?? [], pluginName, contractName)
|
|
11940
|
+
}));
|
|
11941
|
+
}
|
|
11942
|
+
function handleBindingUiEvent(target, id, update) {
|
|
11943
|
+
if (target.classList.contains("annotation-binding-toggle")) {
|
|
11944
|
+
toggleBindingSection(update, id);
|
|
11945
|
+
return;
|
|
11946
|
+
}
|
|
11947
|
+
if (target.closest("[data-marker-manage-plugins]")) {
|
|
11948
|
+
openProjectSettings();
|
|
11949
|
+
return;
|
|
11950
|
+
}
|
|
11951
|
+
if (target.classList.contains("annotation-binding-plugin")) {
|
|
11952
|
+
setBindingPickerPlugin(update, id, target.value);
|
|
11953
|
+
return;
|
|
11954
|
+
}
|
|
11955
|
+
const addBtn = target.closest("[data-marker-add-contract]");
|
|
11956
|
+
if (addBtn?.dataset.plugin && addBtn.dataset.contract && addBtn.dataset.package) {
|
|
11957
|
+
addBindingToAnnotation(update, id, addBtn.dataset.plugin, addBtn.dataset.package, addBtn.dataset.contract, addBtn.dataset.key ?? "");
|
|
11958
|
+
return;
|
|
11959
|
+
}
|
|
11960
|
+
const removeChip = target.closest("[data-marker-remove-binding]");
|
|
11961
|
+
if (removeChip?.dataset.plugin && removeChip.dataset.contract) {
|
|
11962
|
+
removeBindingFromAnnotation(update, id, removeChip.dataset.plugin, removeChip.dataset.contract);
|
|
11963
|
+
return;
|
|
11964
|
+
}
|
|
11965
|
+
}
|
|
9790
11966
|
function setRecordingDraftInstruction(instruction) {
|
|
9791
11967
|
setRecordingDraftAnnotation((prev) => {
|
|
9792
11968
|
if (!prev)
|
|
@@ -9835,7 +12011,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
9835
12011
|
}
|
|
9836
12012
|
function focusLastAnnotationTextarea() {
|
|
9837
12013
|
requestAnimationFrame(() => {
|
|
9838
|
-
|
|
12014
|
+
tryJayRefExec2(refs.visualOverlay, (overlay) => {
|
|
9839
12015
|
const root = overlay.closest(".main-panel") ?? overlay.parentElement;
|
|
9840
12016
|
if (!root)
|
|
9841
12017
|
return;
|
|
@@ -9904,7 +12080,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
9904
12080
|
});
|
|
9905
12081
|
}
|
|
9906
12082
|
function touchAnnotationDropWire() {
|
|
9907
|
-
|
|
12083
|
+
tryJayRefExec2(refs.previewCaptureRoot, (root) => {
|
|
9908
12084
|
const el = root;
|
|
9909
12085
|
if (el._aiditorAnnotEvents)
|
|
9910
12086
|
return;
|
|
@@ -9950,8 +12126,8 @@ function aiditorConstructor(_props, refs) {
|
|
|
9950
12126
|
}
|
|
9951
12127
|
function loadProjectInfo() {
|
|
9952
12128
|
if (!projectDir())
|
|
9953
|
-
return;
|
|
9954
|
-
getProjectInfoAction({ jayDevUrl: jayDevUrl() }).then((raw) => {
|
|
12129
|
+
return Promise.resolve();
|
|
12130
|
+
return getProjectInfoAction({ jayDevUrl: jayDevUrl() }).then((raw) => {
|
|
9955
12131
|
const routes = raw.routes ?? [];
|
|
9956
12132
|
const pages = routes.map((r) => ({
|
|
9957
12133
|
name: r.path,
|
|
@@ -9967,7 +12143,9 @@ function aiditorConstructor(_props, refs) {
|
|
|
9967
12143
|
const home = pages.find((p) => p.url === "/" || p.url === "");
|
|
9968
12144
|
if (home)
|
|
9969
12145
|
selectProjectPage(home);
|
|
9970
|
-
}).catch((err) =>
|
|
12146
|
+
}).catch((err) => {
|
|
12147
|
+
console.error("[aiditor] getProjectInfo error:", err);
|
|
12148
|
+
});
|
|
9971
12149
|
}
|
|
9972
12150
|
function loadFreezes(route) {
|
|
9973
12151
|
listFreezesAction({ route }).then(({ freezes }) => {
|
|
@@ -10049,6 +12227,20 @@ function aiditorConstructor(_props, refs) {
|
|
|
10049
12227
|
}
|
|
10050
12228
|
})();
|
|
10051
12229
|
}
|
|
12230
|
+
function appendAgentOutputChunk(text, cssClass = "chunk", filePath = "", toolName = "", showUserPrefix = false) {
|
|
12231
|
+
setChunks((prev) => [
|
|
12232
|
+
...prev,
|
|
12233
|
+
{ text, cssClass, filePath, toolName, showUserPrefix }
|
|
12234
|
+
]);
|
|
12235
|
+
requestAnimationFrame(() => {
|
|
12236
|
+
tryJayRefExec2(refs.outputScroll, (el) => {
|
|
12237
|
+
el.scrollTop = el.scrollHeight;
|
|
12238
|
+
});
|
|
12239
|
+
});
|
|
12240
|
+
}
|
|
12241
|
+
const refreshPageBriefRef = {
|
|
12242
|
+
current: null
|
|
12243
|
+
};
|
|
10052
12244
|
function selectProjectPage(page2) {
|
|
10053
12245
|
++previewParamsGeneration;
|
|
10054
12246
|
clearVisualSession();
|
|
@@ -10064,6 +12256,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
10064
12256
|
setPreviewSrc("");
|
|
10065
12257
|
setPreviewUrlBar("");
|
|
10066
12258
|
setPreviewError("Connect to Jay dev (setup) to load previews.");
|
|
12259
|
+
void refreshPageBriefRef.current?.();
|
|
10067
12260
|
return;
|
|
10068
12261
|
}
|
|
10069
12262
|
if (!page2.url.includes(":")) {
|
|
@@ -10073,11 +12266,44 @@ function aiditorConstructor(_props, refs) {
|
|
|
10073
12266
|
setLogicalPreviewFull(full);
|
|
10074
12267
|
queueMicrotask(() => touchAnnotationDropWire());
|
|
10075
12268
|
loadFreezes(page2.url);
|
|
12269
|
+
void refreshPageBriefRef.current?.();
|
|
10076
12270
|
return;
|
|
10077
12271
|
}
|
|
10078
12272
|
setPreviewSrc("");
|
|
10079
12273
|
loadParamsForRoute(page2);
|
|
10080
|
-
|
|
12274
|
+
void refreshPageBriefRef.current?.();
|
|
12275
|
+
}
|
|
12276
|
+
const addPage = initAddPageComposer({
|
|
12277
|
+
projectDir,
|
|
12278
|
+
isRunning,
|
|
12279
|
+
setIsRunning,
|
|
12280
|
+
setBottomPanelCollapsed,
|
|
12281
|
+
appendAgentOutputChunk,
|
|
12282
|
+
setChunks,
|
|
12283
|
+
loadProjectInfo,
|
|
12284
|
+
projectPlugins,
|
|
12285
|
+
openProjectSettings,
|
|
12286
|
+
projectPages,
|
|
12287
|
+
httpBaseUrl,
|
|
12288
|
+
setSelectedPageUrl,
|
|
12289
|
+
selectProjectPage,
|
|
12290
|
+
setAddPageResultBanner,
|
|
12291
|
+
getStopStream: () => stopStream ?? void 0,
|
|
12292
|
+
setStopStream: (fn) => {
|
|
12293
|
+
stopStream = fn ?? null;
|
|
12294
|
+
},
|
|
12295
|
+
selectedPageFilePath,
|
|
12296
|
+
selectedPageUrl,
|
|
12297
|
+
setCurrentPageHasBrief
|
|
12298
|
+
});
|
|
12299
|
+
refreshPageBriefRef.current = () => {
|
|
12300
|
+
void addPage.refreshCurrentPageBriefAvailability();
|
|
12301
|
+
};
|
|
12302
|
+
const showAddPageResultBanner = createMemo(() => addPageResultBanner() !== null);
|
|
12303
|
+
const addPageResultBannerClass = createMemo(() => addPageResultBanner()?.kind === "success" ? "add-page-result-success" : "add-page-result-failed");
|
|
12304
|
+
const addPageResultBannerMessage = createMemo(() => addPageResultBanner()?.message ?? "");
|
|
12305
|
+
const showAddPageRetry = createMemo(() => addPageResultBanner()?.showRetry === true);
|
|
12306
|
+
const showAddPageFixWithAiditor = createMemo(() => addPageResultBanner()?.showFixWithAiditor === true);
|
|
10081
12307
|
runBootstrap();
|
|
10082
12308
|
ensurePreviewProbePoll();
|
|
10083
12309
|
function handleSnapshotShortcut() {
|
|
@@ -10114,6 +12340,41 @@ function aiditorConstructor(_props, refs) {
|
|
|
10114
12340
|
});
|
|
10115
12341
|
}
|
|
10116
12342
|
refs.retryBootstrapBtn.onclick(() => runBootstrap());
|
|
12343
|
+
addPage.bindAddPageRefs(refs);
|
|
12344
|
+
refs.projectSettingsBtn.onclick(() => openProjectSettings());
|
|
12345
|
+
refs.projectSettingsCloseBtn.onclick(() => closeProjectSettings());
|
|
12346
|
+
refs.projectSettingsOverlay.onclick(({ event }) => {
|
|
12347
|
+
if (event.target === event.currentTarget)
|
|
12348
|
+
closeProjectSettings();
|
|
12349
|
+
});
|
|
12350
|
+
projectPlugins.bindProjectPluginsRefs(refs);
|
|
12351
|
+
refs.projectPluginsPanel.oninput(({ event }) => {
|
|
12352
|
+
const t = event.target;
|
|
12353
|
+
if (t.classList.contains("project-local-name")) {
|
|
12354
|
+
projectPlugins.setAddLocalPluginName(t.value);
|
|
12355
|
+
} else if (t.classList.contains("project-local-package")) {
|
|
12356
|
+
projectPlugins.setAddLocalPackageName(t.value);
|
|
12357
|
+
} else if (t.classList.contains("project-local-path")) {
|
|
12358
|
+
projectPlugins.setAddLocalPath(t.value);
|
|
12359
|
+
}
|
|
12360
|
+
});
|
|
12361
|
+
refs.addPageResultBannerSlot.onclick(({ event }) => {
|
|
12362
|
+
const target = event.target.closest("[data-add-page-retry], [data-add-page-fix]");
|
|
12363
|
+
if (!target)
|
|
12364
|
+
return;
|
|
12365
|
+
const banner = addPageResultBanner();
|
|
12366
|
+
if (!banner)
|
|
12367
|
+
return;
|
|
12368
|
+
if (target.hasAttribute("data-add-page-retry")) {
|
|
12369
|
+
setAddPageResultBanner(null);
|
|
12370
|
+
addPage.retryAddPage();
|
|
12371
|
+
return;
|
|
12372
|
+
}
|
|
12373
|
+
if (target.hasAttribute("data-add-page-fix")) {
|
|
12374
|
+
setAddPageResultBanner(null);
|
|
12375
|
+
void addPage.openPreviewForRoute(banner.pageRoute);
|
|
12376
|
+
}
|
|
12377
|
+
});
|
|
10117
12378
|
refs.pageRouteSelect.onchange(({ event }) => {
|
|
10118
12379
|
const v = event.target.value;
|
|
10119
12380
|
if (!v)
|
|
@@ -10353,11 +12614,25 @@ function aiditorConstructor(_props, refs) {
|
|
|
10353
12614
|
if (btn.classList.contains("visual-annotation-attach")) {
|
|
10354
12615
|
event.preventDefault();
|
|
10355
12616
|
attachTargetPinId = draft.id;
|
|
10356
|
-
|
|
12617
|
+
tryJayRefExec2(refs.visualAttachFileInput, (el) => el.click());
|
|
10357
12618
|
}
|
|
10358
12619
|
});
|
|
12620
|
+
refs.visualAnnotationRows.annotationRow.onchange(({ event }) => {
|
|
12621
|
+
const t = event.target;
|
|
12622
|
+
const card = t.closest("[data-annotation-id]");
|
|
12623
|
+
const id = card?.getAttribute("data-annotation-id");
|
|
12624
|
+
if (!id)
|
|
12625
|
+
return;
|
|
12626
|
+
handleBindingUiEvent(t, id, updateVisualAnnotation);
|
|
12627
|
+
});
|
|
10359
12628
|
refs.visualAnnotationRows.annotationRow.onclick(({ event, viewState }) => {
|
|
10360
|
-
const
|
|
12629
|
+
const raw = event.target;
|
|
12630
|
+
if (raw.closest(".annotation-binding")) {
|
|
12631
|
+
event.preventDefault();
|
|
12632
|
+
handleBindingUiEvent(raw, viewState.id, updateVisualAnnotation);
|
|
12633
|
+
return;
|
|
12634
|
+
}
|
|
12635
|
+
const t = raw.closest("button");
|
|
10361
12636
|
if (!t)
|
|
10362
12637
|
return;
|
|
10363
12638
|
if (t.classList.contains("visual-attachment-remove-file")) {
|
|
@@ -10371,7 +12646,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
10371
12646
|
if (t.classList.contains("visual-annotation-attach")) {
|
|
10372
12647
|
event.preventDefault();
|
|
10373
12648
|
attachTargetPinId = viewState.id;
|
|
10374
|
-
|
|
12649
|
+
tryJayRefExec2(refs.visualAttachFileInput, (el) => el.click());
|
|
10375
12650
|
return;
|
|
10376
12651
|
}
|
|
10377
12652
|
if (t.classList.contains("visual-annotation-remove")) {
|
|
@@ -10408,7 +12683,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
10408
12683
|
setIsRunning(true);
|
|
10409
12684
|
setVisualSubmitError("");
|
|
10410
12685
|
let rootEl = null;
|
|
10411
|
-
const gotRoot =
|
|
12686
|
+
const gotRoot = tryJayRefExec2(refs.previewCaptureRoot, (el) => {
|
|
10412
12687
|
rootEl = el;
|
|
10413
12688
|
});
|
|
10414
12689
|
if (!gotRoot || !rootEl) {
|
|
@@ -10491,13 +12766,13 @@ function aiditorConstructor(_props, refs) {
|
|
|
10491
12766
|
if (!previewIsSameOriginForCapture(previewSrc()))
|
|
10492
12767
|
return;
|
|
10493
12768
|
let rootEl = null;
|
|
10494
|
-
|
|
12769
|
+
tryJayRefExec2(refs.previewCaptureRoot, (el) => {
|
|
10495
12770
|
rootEl = el;
|
|
10496
12771
|
});
|
|
10497
12772
|
if (!rootEl)
|
|
10498
12773
|
return;
|
|
10499
12774
|
let iframeEl = null;
|
|
10500
|
-
|
|
12775
|
+
tryJayRefExec2(refs.previewIframe, (el) => {
|
|
10501
12776
|
iframeEl = el;
|
|
10502
12777
|
});
|
|
10503
12778
|
try {
|
|
@@ -10585,7 +12860,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
10585
12860
|
}
|
|
10586
12861
|
}
|
|
10587
12862
|
function ensureIframeShortcutForwarder() {
|
|
10588
|
-
|
|
12863
|
+
tryJayRefExec2(refs.previewIframe, (fr) => {
|
|
10589
12864
|
const iframe = fr;
|
|
10590
12865
|
try {
|
|
10591
12866
|
const doc = iframe.contentDocument;
|
|
@@ -10613,7 +12888,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
10613
12888
|
if (!src || !previewIsSameOriginForCapture(src))
|
|
10614
12889
|
return;
|
|
10615
12890
|
ensureIframeShortcutForwarder();
|
|
10616
|
-
|
|
12891
|
+
tryJayRefExec2(refs.previewIframe, (fr) => {
|
|
10617
12892
|
const iframe = fr;
|
|
10618
12893
|
try {
|
|
10619
12894
|
const win = iframe.contentWindow;
|
|
@@ -10644,7 +12919,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
10644
12919
|
recordingPreviewNavLog = [];
|
|
10645
12920
|
queueMicrotask(tickPreviewIframeProbe);
|
|
10646
12921
|
}
|
|
10647
|
-
function
|
|
12922
|
+
function tryJayRefExec2(refObj, fn) {
|
|
10648
12923
|
const r = refObj;
|
|
10649
12924
|
if (typeof r?.exec$ !== "function")
|
|
10650
12925
|
return false;
|
|
@@ -10673,13 +12948,13 @@ function aiditorConstructor(_props, refs) {
|
|
|
10673
12948
|
normalizeRecordingPinsToVideoDurationIfNeeded(dur);
|
|
10674
12949
|
setVideoDurationSec(dur);
|
|
10675
12950
|
setVideoTimeLabel(`${formatClock(cur)} / ${formatClock(dur)}`);
|
|
10676
|
-
|
|
12951
|
+
tryJayRefExec2(refs.videoTimeline, (inp) => {
|
|
10677
12952
|
inp.value = String(Math.round(cur / dur * 1e3));
|
|
10678
12953
|
});
|
|
10679
12954
|
}
|
|
10680
12955
|
}
|
|
10681
12956
|
function pauseVideoForAnnotationCapture() {
|
|
10682
|
-
|
|
12957
|
+
tryJayRefExec2(refs.videoReviewPlayer, (el) => {
|
|
10683
12958
|
const v = el;
|
|
10684
12959
|
if (!v.paused)
|
|
10685
12960
|
v.pause();
|
|
@@ -10688,13 +12963,13 @@ function aiditorConstructor(_props, refs) {
|
|
|
10688
12963
|
}
|
|
10689
12964
|
function syncReviewTransportAfterAnnotation() {
|
|
10690
12965
|
queueMicrotask(() => {
|
|
10691
|
-
|
|
12966
|
+
tryJayRefExec2(refs.videoReviewPlayer, (el) => {
|
|
10692
12967
|
refreshVideoReviewTransport(el);
|
|
10693
12968
|
});
|
|
10694
12969
|
});
|
|
10695
12970
|
}
|
|
10696
12971
|
function seekVideoReviewToTimeAndPause(timeSec) {
|
|
10697
|
-
|
|
12972
|
+
tryJayRefExec2(refs.videoReviewPlayer, (el) => {
|
|
10698
12973
|
const v = el;
|
|
10699
12974
|
v.pause();
|
|
10700
12975
|
let dur = effectiveVideoDuration(v);
|
|
@@ -10768,7 +13043,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
10768
13043
|
});
|
|
10769
13044
|
}
|
|
10770
13045
|
};
|
|
10771
|
-
const wired =
|
|
13046
|
+
const wired = tryJayRefExec2(refs.videoReviewPlayer, (el) => bindVideo(el)) || (() => {
|
|
10772
13047
|
const q = document.querySelector("[data-aiditor-video-review]");
|
|
10773
13048
|
if (q?.isConnected) {
|
|
10774
13049
|
bindVideo(q);
|
|
@@ -10777,7 +13052,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
10777
13052
|
return false;
|
|
10778
13053
|
})();
|
|
10779
13054
|
if (wired) {
|
|
10780
|
-
|
|
13055
|
+
tryJayRefExec2(refs.videoReviewBackdrop, (el) => {
|
|
10781
13056
|
el.focus();
|
|
10782
13057
|
});
|
|
10783
13058
|
startWatchdog();
|
|
@@ -10921,7 +13196,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
10921
13196
|
}
|
|
10922
13197
|
function currentVideoTimeForNewPin() {
|
|
10923
13198
|
let t = 0;
|
|
10924
|
-
|
|
13199
|
+
tryJayRefExec2(refs.videoReviewPlayer, (v) => {
|
|
10925
13200
|
t = v.currentTime;
|
|
10926
13201
|
});
|
|
10927
13202
|
return t;
|
|
@@ -10955,10 +13230,10 @@ function aiditorConstructor(_props, refs) {
|
|
|
10955
13230
|
}
|
|
10956
13231
|
let captureRoot = null;
|
|
10957
13232
|
let videoEl = null;
|
|
10958
|
-
|
|
13233
|
+
tryJayRefExec2(refs.videoReviewCaptureRoot, (r) => {
|
|
10959
13234
|
captureRoot = r;
|
|
10960
13235
|
});
|
|
10961
|
-
|
|
13236
|
+
tryJayRefExec2(refs.videoReviewPlayer, (v) => {
|
|
10962
13237
|
videoEl = v;
|
|
10963
13238
|
});
|
|
10964
13239
|
if (!captureRoot || !videoEl) {
|
|
@@ -11038,6 +13313,79 @@ function aiditorConstructor(_props, refs) {
|
|
|
11038
13313
|
event.stopPropagation();
|
|
11039
13314
|
setChunks([]);
|
|
11040
13315
|
});
|
|
13316
|
+
refs.agentChatInput.oninput(({ event }) => {
|
|
13317
|
+
setAgentChatMessage(event.target.value);
|
|
13318
|
+
});
|
|
13319
|
+
refs.agentChatInput.onkeydown(({ event }) => {
|
|
13320
|
+
if (event.key !== "Enter" || event.shiftKey)
|
|
13321
|
+
return;
|
|
13322
|
+
event.preventDefault();
|
|
13323
|
+
sendChatMessage();
|
|
13324
|
+
});
|
|
13325
|
+
refs.agentChatSendBtn.onclick(() => {
|
|
13326
|
+
sendChatMessage();
|
|
13327
|
+
});
|
|
13328
|
+
function focusAgentChatInput() {
|
|
13329
|
+
requestAnimationFrame(() => {
|
|
13330
|
+
tryJayRefExec2(refs.agentChatInput, (el) => {
|
|
13331
|
+
el.focus();
|
|
13332
|
+
});
|
|
13333
|
+
});
|
|
13334
|
+
}
|
|
13335
|
+
function handleAgentStreamChunk(chunk) {
|
|
13336
|
+
if (chunk.type === "thinking" && chunk.text) {
|
|
13337
|
+
appendAgentOutputChunk(chunk.text, "chunk chunk-thinking");
|
|
13338
|
+
} else if (chunk.type === "chunk" && chunk.text) {
|
|
13339
|
+
appendAgentOutputChunk(chunk.text);
|
|
13340
|
+
} else if (chunk.type === "status" && chunk.message) {
|
|
13341
|
+
appendAgentOutputChunk(chunk.message, "chunk chunk-status");
|
|
13342
|
+
} else if (chunk.type === "tool" && chunk.name) {
|
|
13343
|
+
const detail = chunk.text ? ` ${chunk.text}` : "";
|
|
13344
|
+
const isFileOp = chunk.name === "Read" || chunk.name === "Write";
|
|
13345
|
+
const fp = isFileOp && chunk.text ? chunk.text.split("\n")[0].trim() : "";
|
|
13346
|
+
appendAgentOutputChunk(`> ${chunk.name}${detail}`, "chunk chunk-tool", fp, fp ? chunk.name : "");
|
|
13347
|
+
} else if (chunk.type === "error" && chunk.message) {
|
|
13348
|
+
appendAgentOutputChunk(chunk.message, "chunk chunk-error");
|
|
13349
|
+
} else if (chunk.type === "result") {
|
|
13350
|
+
const cost = chunk.cost ? ` ($${chunk.cost.toFixed(4)})` : "";
|
|
13351
|
+
appendAgentOutputChunk(`Done${cost}`, "chunk chunk-result");
|
|
13352
|
+
}
|
|
13353
|
+
}
|
|
13354
|
+
function finishAgentStreamRun() {
|
|
13355
|
+
setIsRunning(false);
|
|
13356
|
+
focusAgentChatInput();
|
|
13357
|
+
}
|
|
13358
|
+
function runAgentStream(notes2, options, streamOptions) {
|
|
13359
|
+
stopStream?.();
|
|
13360
|
+
if (streamOptions.clearOutput)
|
|
13361
|
+
setChunks([]);
|
|
13362
|
+
setIsRunning(true);
|
|
13363
|
+
setBottomPanelCollapsed(false);
|
|
13364
|
+
stopStream = submitAndStreamTask(notes2, options, {
|
|
13365
|
+
onChunk: handleAgentStreamChunk,
|
|
13366
|
+
onEnd: finishAgentStreamRun,
|
|
13367
|
+
onError: (err) => {
|
|
13368
|
+
appendAgentOutputChunk(err.message, "chunk chunk-error");
|
|
13369
|
+
finishAgentStreamRun();
|
|
13370
|
+
}
|
|
13371
|
+
});
|
|
13372
|
+
}
|
|
13373
|
+
function sendChatMessage() {
|
|
13374
|
+
if (isRunning())
|
|
13375
|
+
return;
|
|
13376
|
+
const text = agentChatMessage().trim();
|
|
13377
|
+
if (!text)
|
|
13378
|
+
return;
|
|
13379
|
+
const route = selectedPageUrl() ?? "/";
|
|
13380
|
+
const rendered = previewUrlBar().trim();
|
|
13381
|
+
appendAgentOutputChunk(text, "chunk chunk-user", "", "", true);
|
|
13382
|
+
setAgentChatMessage("");
|
|
13383
|
+
runAgentStream(text, {
|
|
13384
|
+
kind: "chat",
|
|
13385
|
+
pageRoute: route,
|
|
13386
|
+
renderedUrl: rendered
|
|
13387
|
+
}, { clearOutput: false });
|
|
13388
|
+
}
|
|
11041
13389
|
refs.outputScroll.onclick(({ event }) => {
|
|
11042
13390
|
const target = event.target;
|
|
11043
13391
|
if (!target.classList.contains("file-link"))
|
|
@@ -11098,7 +13446,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
11098
13446
|
document.addEventListener("mouseup", onUp);
|
|
11099
13447
|
});
|
|
11100
13448
|
refs.freezeBtn.onclick(() => {
|
|
11101
|
-
|
|
13449
|
+
tryJayRefExec2(refs.previewIframe, (fr) => {
|
|
11102
13450
|
const iframe = fr;
|
|
11103
13451
|
iframe.contentWindow?.postMessage({ type: "jay:requestFreeze" }, "*");
|
|
11104
13452
|
});
|
|
@@ -11118,7 +13466,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
11118
13466
|
setVisualSubmitError("");
|
|
11119
13467
|
setVideoRecordingNavLog([]);
|
|
11120
13468
|
let rootEl = null;
|
|
11121
|
-
const gotRoot =
|
|
13469
|
+
const gotRoot = tryJayRefExec2(refs.previewCaptureRoot, (r) => {
|
|
11122
13470
|
rootEl = r;
|
|
11123
13471
|
});
|
|
11124
13472
|
if (!gotRoot || !rootEl) {
|
|
@@ -11317,6 +13665,14 @@ function aiditorConstructor(_props, refs) {
|
|
|
11317
13665
|
}
|
|
11318
13666
|
}
|
|
11319
13667
|
});
|
|
13668
|
+
refs.videoAnnotationRows.videoAnnotationRow.onchange(({ event }) => {
|
|
13669
|
+
const t = event.target;
|
|
13670
|
+
const card = t.closest("[data-annotation-id]");
|
|
13671
|
+
const id = card?.getAttribute("data-annotation-id");
|
|
13672
|
+
if (!id)
|
|
13673
|
+
return;
|
|
13674
|
+
handleBindingUiEvent(t, id, updateVideoAsVisual);
|
|
13675
|
+
});
|
|
11320
13676
|
refs.videoAnnotationRows.videoAnnotationRow.oninput(({ event }) => {
|
|
11321
13677
|
const t = event.target;
|
|
11322
13678
|
if (t.tagName !== "TEXTAREA" || !t.classList.contains("visual-annotation-instruction"))
|
|
@@ -11327,7 +13683,13 @@ function aiditorConstructor(_props, refs) {
|
|
|
11327
13683
|
setVideoAnnotationInstruction(id, t.value);
|
|
11328
13684
|
});
|
|
11329
13685
|
refs.videoAnnotationRows.videoAnnotationRow.onclick(({ event, viewState }) => {
|
|
11330
|
-
const
|
|
13686
|
+
const raw = event.target;
|
|
13687
|
+
if (raw.closest(".annotation-binding")) {
|
|
13688
|
+
event.preventDefault();
|
|
13689
|
+
handleBindingUiEvent(raw, viewState.id, updateVideoAsVisual);
|
|
13690
|
+
return;
|
|
13691
|
+
}
|
|
13692
|
+
const t = raw.closest("button");
|
|
11331
13693
|
if (!t)
|
|
11332
13694
|
return;
|
|
11333
13695
|
if (t.classList.contains("visual-attachment-remove-file")) {
|
|
@@ -11341,7 +13703,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
11341
13703
|
if (t.classList.contains("visual-video-annotation-attach")) {
|
|
11342
13704
|
event.preventDefault();
|
|
11343
13705
|
attachVideoTargetPinId = viewState.id;
|
|
11344
|
-
|
|
13706
|
+
tryJayRefExec2(refs.videoReviewAttachFileInput, (el) => el.click());
|
|
11345
13707
|
return;
|
|
11346
13708
|
}
|
|
11347
13709
|
if (t.classList.contains("visual-annotation-remove")) {
|
|
@@ -11362,7 +13724,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
11362
13724
|
});
|
|
11363
13725
|
refs.videoTimeline.oninput(({ event }) => {
|
|
11364
13726
|
const val = Number(event.target.value);
|
|
11365
|
-
|
|
13727
|
+
tryJayRefExec2(refs.videoReviewPlayer, (el) => {
|
|
11366
13728
|
const v = el;
|
|
11367
13729
|
let dur = effectiveVideoDuration(v);
|
|
11368
13730
|
if (dur <= 0)
|
|
@@ -11388,7 +13750,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
11388
13750
|
seekVideoReviewToTimeAndPause(t);
|
|
11389
13751
|
});
|
|
11390
13752
|
refs.videoPlayPauseBtn.onclick(() => {
|
|
11391
|
-
|
|
13753
|
+
tryJayRefExec2(refs.videoReviewPlayer, (el) => {
|
|
11392
13754
|
const v = el;
|
|
11393
13755
|
if (v.paused)
|
|
11394
13756
|
void v.play().catch(() => {
|
|
@@ -11413,7 +13775,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
11413
13775
|
refs.videoReviewBackdrop.onkeydown(({ event }) => {
|
|
11414
13776
|
if (event.key === "Escape") {
|
|
11415
13777
|
event.preventDefault();
|
|
11416
|
-
|
|
13778
|
+
tryJayRefExec2(refs.videoReviewCloseBtn, (b) => b.click());
|
|
11417
13779
|
}
|
|
11418
13780
|
});
|
|
11419
13781
|
refs.snapshotToolPointBtn.onclick(() => onSelectSnapshotTool("point"));
|
|
@@ -11454,7 +13816,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
11454
13816
|
return;
|
|
11455
13817
|
const el = event.currentTarget;
|
|
11456
13818
|
let imgEl = null;
|
|
11457
|
-
|
|
13819
|
+
tryJayRefExec2(refs.snapshotImg, (img) => {
|
|
11458
13820
|
imgEl = img;
|
|
11459
13821
|
});
|
|
11460
13822
|
if (!imgEl)
|
|
@@ -11524,7 +13886,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
11524
13886
|
return;
|
|
11525
13887
|
const el = event.currentTarget;
|
|
11526
13888
|
let imgEl = null;
|
|
11527
|
-
|
|
13889
|
+
tryJayRefExec2(refs.snapshotImg, (img) => {
|
|
11528
13890
|
imgEl = img;
|
|
11529
13891
|
});
|
|
11530
13892
|
if (!imgEl)
|
|
@@ -11568,6 +13930,14 @@ function aiditorConstructor(_props, refs) {
|
|
|
11568
13930
|
}
|
|
11569
13931
|
}
|
|
11570
13932
|
});
|
|
13933
|
+
refs.snapshotAnnotationItems.snapshotAnnotationRow.onchange(({ event }) => {
|
|
13934
|
+
const t = event.target;
|
|
13935
|
+
const card = t.closest("[data-annotation-id]");
|
|
13936
|
+
const id = card?.getAttribute("data-annotation-id");
|
|
13937
|
+
if (!id)
|
|
13938
|
+
return;
|
|
13939
|
+
handleBindingUiEvent(t, id, updateSnapshotAnnotation);
|
|
13940
|
+
});
|
|
11571
13941
|
refs.snapshotAnnotationItems.snapshotAnnotationRow.oninput(({ event }) => {
|
|
11572
13942
|
const t = event.target;
|
|
11573
13943
|
if (t.tagName !== "TEXTAREA" || !t.classList.contains("visual-annotation-instruction"))
|
|
@@ -11593,7 +13963,16 @@ function aiditorConstructor(_props, refs) {
|
|
|
11593
13963
|
}
|
|
11594
13964
|
});
|
|
11595
13965
|
refs.snapshotAnnotationItems.snapshotAnnotationRow.onclick(({ event }) => {
|
|
11596
|
-
const
|
|
13966
|
+
const raw = event.target;
|
|
13967
|
+
if (raw.closest(".annotation-binding")) {
|
|
13968
|
+
event.preventDefault();
|
|
13969
|
+
const card = raw.closest("[data-annotation-id]");
|
|
13970
|
+
const id = card?.getAttribute("data-annotation-id");
|
|
13971
|
+
if (id)
|
|
13972
|
+
handleBindingUiEvent(raw, id, updateSnapshotAnnotation);
|
|
13973
|
+
return;
|
|
13974
|
+
}
|
|
13975
|
+
const btn = raw.closest("button");
|
|
11597
13976
|
if (!btn)
|
|
11598
13977
|
return;
|
|
11599
13978
|
if (btn.classList.contains("snapshot-annotation-remove")) {
|
|
@@ -11610,7 +13989,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
11610
13989
|
if (!id)
|
|
11611
13990
|
return;
|
|
11612
13991
|
snapshotAttachTargetPinId = id;
|
|
11613
|
-
|
|
13992
|
+
tryJayRefExec2(refs.snapshotAttachFileInput, (inp) => inp.click());
|
|
11614
13993
|
return;
|
|
11615
13994
|
}
|
|
11616
13995
|
if (btn.classList.contains("visual-attachment-remove-file")) {
|
|
@@ -11635,7 +14014,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
11635
14014
|
createEffect(() => {
|
|
11636
14015
|
if (showSnapshotModal()) {
|
|
11637
14016
|
requestAnimationFrame(() => {
|
|
11638
|
-
|
|
14017
|
+
tryJayRefExec2(refs.snapshotBackdrop, (el) => el.focus());
|
|
11639
14018
|
});
|
|
11640
14019
|
}
|
|
11641
14020
|
});
|
|
@@ -11731,47 +14110,16 @@ function aiditorConstructor(_props, refs) {
|
|
|
11731
14110
|
});
|
|
11732
14111
|
}
|
|
11733
14112
|
bindAiditorDocumentPasteCapture(onAiditorDocumentPasteCapture);
|
|
14113
|
+
runPluginInstallAgent = (pluginName, installError) => {
|
|
14114
|
+
const entry = getCatalogEntry(pluginName);
|
|
14115
|
+
if (!entry)
|
|
14116
|
+
return;
|
|
14117
|
+
setShowProjectSettingsModal(false);
|
|
14118
|
+
const notes2 = buildPluginInstallAgentNotes(entry, installError, projectDir() || "Jay project root (where jay-stack dev runs)");
|
|
14119
|
+
startAgentStream(notes2, void 0);
|
|
14120
|
+
};
|
|
11734
14121
|
function startAgentStream(notes2, visual) {
|
|
11735
|
-
|
|
11736
|
-
setChunks([]);
|
|
11737
|
-
setIsRunning(true);
|
|
11738
|
-
setBottomPanelCollapsed(false);
|
|
11739
|
-
const addChunk = (text, cssClass = "chunk", filePath = "", toolName = "") => {
|
|
11740
|
-
setChunks((prev) => [...prev, { text, cssClass, filePath, toolName }]);
|
|
11741
|
-
requestAnimationFrame(() => {
|
|
11742
|
-
tryJayRefExec(refs.outputScroll, (el) => {
|
|
11743
|
-
el.scrollTop = el.scrollHeight;
|
|
11744
|
-
});
|
|
11745
|
-
});
|
|
11746
|
-
};
|
|
11747
|
-
stopStream = submitAndStreamTask(notes2, visual, {
|
|
11748
|
-
onChunk: (chunk) => {
|
|
11749
|
-
if (chunk.type === "thinking" && chunk.text) {
|
|
11750
|
-
addChunk(chunk.text, "chunk chunk-thinking");
|
|
11751
|
-
} else if (chunk.type === "chunk" && chunk.text) {
|
|
11752
|
-
addChunk(chunk.text);
|
|
11753
|
-
} else if (chunk.type === "status" && chunk.message) {
|
|
11754
|
-
addChunk(chunk.message, "chunk chunk-status");
|
|
11755
|
-
} else if (chunk.type === "tool" && chunk.name) {
|
|
11756
|
-
const detail = chunk.text ? ` ${chunk.text}` : "";
|
|
11757
|
-
const isFileOp = chunk.name === "Read" || chunk.name === "Write";
|
|
11758
|
-
const fp = isFileOp && chunk.text ? chunk.text.split("\n")[0].trim() : "";
|
|
11759
|
-
addChunk(`> ${chunk.name}${detail}`, "chunk chunk-tool", fp, fp ? chunk.name : "");
|
|
11760
|
-
} else if (chunk.type === "error" && chunk.message) {
|
|
11761
|
-
addChunk(chunk.message, "chunk chunk-error");
|
|
11762
|
-
} else if (chunk.type === "result") {
|
|
11763
|
-
const cost = chunk.cost ? ` ($${chunk.cost.toFixed(4)})` : "";
|
|
11764
|
-
addChunk(`Done${cost}`, "chunk chunk-result");
|
|
11765
|
-
}
|
|
11766
|
-
},
|
|
11767
|
-
onEnd: () => {
|
|
11768
|
-
setIsRunning(false);
|
|
11769
|
-
},
|
|
11770
|
-
onError: (err) => {
|
|
11771
|
-
addChunk(err.message, "chunk chunk-error");
|
|
11772
|
-
setIsRunning(false);
|
|
11773
|
-
}
|
|
11774
|
-
});
|
|
14122
|
+
runAgentStream(notes2, visual, { clearOutput: true });
|
|
11775
14123
|
}
|
|
11776
14124
|
return {
|
|
11777
14125
|
render: () => ({
|
|
@@ -11806,6 +14154,11 @@ function aiditorConstructor(_props, refs) {
|
|
|
11806
14154
|
bottomPanelClass,
|
|
11807
14155
|
bottomPanelToggleGlyph,
|
|
11808
14156
|
showBottomPanelRunning,
|
|
14157
|
+
agentChatMessage,
|
|
14158
|
+
showAgentChatInput,
|
|
14159
|
+
agentChatInputDisabled,
|
|
14160
|
+
agentChatSendDisabled,
|
|
14161
|
+
agentChatPlaceholder,
|
|
11809
14162
|
showFilePreview,
|
|
11810
14163
|
filePreviewPath,
|
|
11811
14164
|
filePreviewContent,
|
|
@@ -11912,7 +14265,72 @@ function aiditorConstructor(_props, refs) {
|
|
|
11912
14265
|
snapshotAnnotationItems,
|
|
11913
14266
|
showSnapshotAnnotationsPanel,
|
|
11914
14267
|
showSnapshotSubmitError,
|
|
11915
|
-
snapshotSubmitError
|
|
14268
|
+
snapshotSubmitError,
|
|
14269
|
+
showAddPageComposer: addPage.showAddPageComposer,
|
|
14270
|
+
addPageRoute: addPage.addPageRoute,
|
|
14271
|
+
addPageContentMd: addPage.addPageContentMd,
|
|
14272
|
+
addPageDesignMd: addPage.addPageDesignMd,
|
|
14273
|
+
addPageRouteError: addPage.addPageRouteError,
|
|
14274
|
+
showAddPageRouteError: addPage.showAddPageRouteError,
|
|
14275
|
+
addPageComposerError: addPage.addPageComposerError,
|
|
14276
|
+
showAddPageComposerError: addPage.showAddPageComposerError,
|
|
14277
|
+
addPageUploadHint: addPage.addPageUploadHint,
|
|
14278
|
+
showAddPageUploadHint: addPage.showAddPageUploadHint,
|
|
14279
|
+
addPageIsDynamicRoute: addPage.addPageIsDynamicRoute,
|
|
14280
|
+
addPageShowDesignHint: addPage.addPageShowDesignHint,
|
|
14281
|
+
addPageCreateDisabled: addPage.addPageCreateDisabled,
|
|
14282
|
+
addPageRunningHint: addPage.addPageRunningHint,
|
|
14283
|
+
showAddPageRunningHint: addPage.showAddPageRunningHint,
|
|
14284
|
+
addPageAttachmentRows: addPage.addPageAttachmentRows,
|
|
14285
|
+
showAddPageAttachments: addPage.showAddPageAttachments,
|
|
14286
|
+
showProjectSettingsModal,
|
|
14287
|
+
showProjectSettingsPluginsPanel: projectPlugins.showPluginsPanel,
|
|
14288
|
+
showProjectSettingsInstallZone: projectPlugins.showInstallZone,
|
|
14289
|
+
showProjectSettingsInstalledZone: projectPlugins.showInstalledZone,
|
|
14290
|
+
projectSettingsInstallRows: projectPlugins.availableInstallRows,
|
|
14291
|
+
projectSettingsInstalledRows: projectPlugins.installedPluginRows,
|
|
14292
|
+
showProjectSettingsPluginsError: projectPlugins.showPluginsPanelError,
|
|
14293
|
+
showFixInstallWithAgent: projectPlugins.showFixInstallWithAgent,
|
|
14294
|
+
fixInstallPluginName: projectPlugins.fixInstallPluginName,
|
|
14295
|
+
projectSettingsPluginsError: projectPlugins.pluginsPanelError,
|
|
14296
|
+
showProjectSettingsInstallProgress: projectPlugins.showInstallProgress,
|
|
14297
|
+
projectSettingsInstallProgress: projectPlugins.installStepLabel,
|
|
14298
|
+
showProjectSettingsWixConfigWarning: projectPlugins.showWixConfigWarning,
|
|
14299
|
+
showProjectSettingsReloadPreview: projectPlugins.showReloadPreview,
|
|
14300
|
+
showProjectLocalPluginForm: projectPlugins.showAddLocalPluginForm,
|
|
14301
|
+
projectLocalPluginName: projectPlugins.addLocalPluginName,
|
|
14302
|
+
projectLocalPackageName: projectPlugins.addLocalPackageName,
|
|
14303
|
+
projectLocalPath: projectPlugins.addLocalPath,
|
|
14304
|
+
showAddPagePluginsPanel: addPage.showAddPagePluginsPanel,
|
|
14305
|
+
showAddPagePagePluginsZone: addPage.showAddPagePagePluginsZone,
|
|
14306
|
+
addPagePluginPickerOptions: addPage.addPagePluginPickerOptions,
|
|
14307
|
+
addPagePluginPickerValue: addPage.addPagePluginPickerValue,
|
|
14308
|
+
showAddPageContractPicker: addPage.showAddPageContractPicker,
|
|
14309
|
+
addPagePickerPluginLabel: addPage.addPagePickerPluginLabel,
|
|
14310
|
+
addPageContractPickerRows: addPage.addPageContractPickerRows,
|
|
14311
|
+
addPagePagePluginChips: addPage.addPagePagePluginChips,
|
|
14312
|
+
showAddPageHasPagePluginChips: addPage.showAddPageHasPagePluginChips,
|
|
14313
|
+
showAddPagePagePluginsEmptyHint: addPage.showAddPagePagePluginsEmptyHint,
|
|
14314
|
+
showAddPageResultBanner,
|
|
14315
|
+
addPageResultBannerClass,
|
|
14316
|
+
addPageResultBannerMessage,
|
|
14317
|
+
showAddPageRetry,
|
|
14318
|
+
showAddPageFixWithAiditor,
|
|
14319
|
+
showAddPageFromBriefBtn,
|
|
14320
|
+
showBriefFillPopover: addPage.showBriefFillPopover,
|
|
14321
|
+
briefFillContextNotes: addPage.briefFillContextNotes,
|
|
14322
|
+
briefFillPopoverError: addPage.briefFillPopoverError,
|
|
14323
|
+
showBriefFillPopoverError: addPage.showBriefFillPopoverError,
|
|
14324
|
+
briefFillDisabled: addPage.briefFillDisabled,
|
|
14325
|
+
briefFillInputDisabled: addPage.briefFillInputDisabled,
|
|
14326
|
+
briefFillDropzoneClass: addPage.briefFillDropzoneClass,
|
|
14327
|
+
addPageBriefFillGenerateDisabled: addPage.addPageBriefFillGenerateDisabled,
|
|
14328
|
+
briefFillStatusHint: addPage.briefFillStatusHint,
|
|
14329
|
+
showBriefFillStatusHint: addPage.showBriefFillStatusHint,
|
|
14330
|
+
showBriefFillThumbnails: addPage.showBriefFillThumbnails,
|
|
14331
|
+
addPageBriefFillThumbRows: addPage.addPageBriefFillThumbRows,
|
|
14332
|
+
showSuggestedRouteBanner: addPage.showSuggestedRouteBanner,
|
|
14333
|
+
suggestedRouteLabel: addPage.suggestedRouteLabel
|
|
11916
14334
|
})
|
|
11917
14335
|
};
|
|
11918
14336
|
}
|