decant-core 1.0.0 → 1.0.1
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 +20 -20
- package/ai/base.js +4 -4
- package/ai/chatgpt.js +356 -216
- package/ai/chatgpt_helper.js +46 -28
- package/ai/chatgpt_scroll_collector.js +36 -33
- package/ai/chub.js +90 -0
- package/ai/claude.js +119 -92
- package/ai/claude_react_reader.js +8 -6
- package/ai/copilot.js +158 -124
- package/ai/deepseek.js +36 -27
- package/ai/gemini.js +384 -230
- package/ai/gemini_cloud_assist.js +31 -22
- package/ai/google_ai_studio.js +45 -27
- package/ai/google_search_ai.js +32 -23
- package/ai/index.js +25 -19
- package/ai/joyland.js +85 -0
- package/ai/lumo.js +39 -28
- package/ai/meta.js +30 -24
- package/ai/mistral.js +21 -16
- package/ai/notebooklm.js +50 -34
- package/ai/perplexity.js +22 -19
- package/ai/qwen.js +29 -25
- package/ai/z_ai.js +34 -28
- package/detection/detect-platform.js +27 -19
- package/detection/domains.js +32 -24
- package/lib/turndown.js +352 -183
- package/package.json +13 -4
- package/utils/html-to-markdown.js +130 -109
package/ai/claude.js
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
|
-
import { ChatParser } from
|
|
2
|
-
import { convertToMarkdown } from
|
|
1
|
+
import { ChatParser } from "./base.js";
|
|
2
|
+
import { convertToMarkdown } from "../utils/html-to-markdown.js";
|
|
3
3
|
|
|
4
4
|
async function getOrganizationId() {
|
|
5
5
|
try {
|
|
6
|
-
const response = await fetch(
|
|
7
|
-
credentials:
|
|
6
|
+
const response = await fetch("https://claude.ai/api/organizations", {
|
|
7
|
+
credentials: "include",
|
|
8
8
|
headers: {
|
|
9
|
-
Accept:
|
|
9
|
+
Accept: "application/json",
|
|
10
10
|
},
|
|
11
11
|
});
|
|
12
12
|
if (!response.ok) return null;
|
|
13
13
|
const orgs = await response.json();
|
|
14
14
|
if (Array.isArray(orgs) && orgs.length > 0) {
|
|
15
|
-
const chatOrg = orgs.find(
|
|
15
|
+
const chatOrg = orgs.find(
|
|
16
|
+
(org) => org.capabilities && org.capabilities.includes("chat"),
|
|
17
|
+
);
|
|
16
18
|
return chatOrg ? chatOrg.uuid : orgs[0].uuid;
|
|
17
19
|
}
|
|
18
20
|
} catch (e) {
|
|
19
|
-
console.error(
|
|
21
|
+
console.error("[AI Exporter] Failed to detect org ID:", e);
|
|
20
22
|
}
|
|
21
23
|
return null;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
function getConversationId() {
|
|
25
27
|
try {
|
|
26
|
-
if (typeof window ===
|
|
28
|
+
if (typeof window === "undefined" || !window.location) return null;
|
|
27
29
|
return window.location.pathname.match(/\/chat\/([^/?#]+)/)?.[1] ?? null;
|
|
28
30
|
} catch {
|
|
29
31
|
return null;
|
|
@@ -33,9 +35,9 @@ function getConversationId() {
|
|
|
33
35
|
async function fetchConversation(orgId, conversationId) {
|
|
34
36
|
const url = `https://claude.ai/api/organizations/${orgId}/chat_conversations/${conversationId}?tree=True&rendering_mode=messages&render_all_tools=true`;
|
|
35
37
|
const response = await fetch(url, {
|
|
36
|
-
credentials:
|
|
38
|
+
credentials: "include",
|
|
37
39
|
headers: {
|
|
38
|
-
Accept:
|
|
40
|
+
Accept: "application/json",
|
|
39
41
|
},
|
|
40
42
|
});
|
|
41
43
|
if (!response.ok) {
|
|
@@ -80,8 +82,8 @@ function extractArtifactsFromText(text) {
|
|
|
80
82
|
const languageMatch = fullTag.match(/language="([^"]*)"/);
|
|
81
83
|
|
|
82
84
|
artifacts.push({
|
|
83
|
-
title: titleMatch ? titleMatch[1] :
|
|
84
|
-
language: languageMatch ? languageMatch[1] :
|
|
85
|
+
title: titleMatch ? titleMatch[1] : "Artifact",
|
|
86
|
+
language: languageMatch ? languageMatch[1] : "text",
|
|
85
87
|
content: content.trim(),
|
|
86
88
|
});
|
|
87
89
|
}
|
|
@@ -93,39 +95,45 @@ function extractArtifacts(message) {
|
|
|
93
95
|
if (message.content && Array.isArray(message.content)) {
|
|
94
96
|
for (const content of message.content) {
|
|
95
97
|
if (
|
|
96
|
-
content.type ===
|
|
97
|
-
(content.name ===
|
|
98
|
+
content.type === "tool_use" &&
|
|
99
|
+
(content.name === "artifacts" || content.name === "create_file") &&
|
|
98
100
|
content.display_content
|
|
99
101
|
) {
|
|
100
102
|
const displayContent = content.display_content;
|
|
101
|
-
if (displayContent.type ===
|
|
102
|
-
const filename = displayContent.filename ||
|
|
103
|
+
if (displayContent.type === "code_block" && displayContent.code) {
|
|
104
|
+
const filename = displayContent.filename || "artifact";
|
|
103
105
|
const title = filename
|
|
104
|
-
.split(
|
|
106
|
+
.split("/")
|
|
105
107
|
.pop()
|
|
106
|
-
.replace(/\.[^.]+$/,
|
|
108
|
+
.replace(/\.[^.]+$/, "");
|
|
107
109
|
artifacts.push({
|
|
108
|
-
title: title ||
|
|
109
|
-
language: displayContent.language ||
|
|
110
|
+
title: title || "Artifact",
|
|
111
|
+
language: displayContent.language || "text",
|
|
110
112
|
content: displayContent.code.trim(),
|
|
111
113
|
});
|
|
112
|
-
} else if (
|
|
114
|
+
} else if (
|
|
115
|
+
displayContent.type === "json_block" &&
|
|
116
|
+
displayContent.json_block
|
|
117
|
+
) {
|
|
113
118
|
try {
|
|
114
119
|
const data = JSON.parse(displayContent.json_block);
|
|
115
120
|
if (data.filename) {
|
|
116
121
|
const filename = data.filename;
|
|
117
122
|
const title = filename
|
|
118
|
-
.split(
|
|
123
|
+
.split("/")
|
|
119
124
|
.pop()
|
|
120
|
-
.replace(/\.[^.]+$/,
|
|
125
|
+
.replace(/\.[^.]+$/, "");
|
|
121
126
|
artifacts.push({
|
|
122
|
-
title: title ||
|
|
123
|
-
language: data.language ||
|
|
124
|
-
content: (data.code ||
|
|
127
|
+
title: title || "Artifact",
|
|
128
|
+
language: data.language || "text",
|
|
129
|
+
content: (data.code || "").trim(),
|
|
125
130
|
});
|
|
126
131
|
}
|
|
127
132
|
} catch (e) {
|
|
128
|
-
console.warn(
|
|
133
|
+
console.warn(
|
|
134
|
+
"[AI Exporter] Failed to parse tool use artifact json:",
|
|
135
|
+
e,
|
|
136
|
+
);
|
|
129
137
|
}
|
|
130
138
|
}
|
|
131
139
|
}
|
|
@@ -141,24 +149,24 @@ function extractArtifacts(message) {
|
|
|
141
149
|
}
|
|
142
150
|
|
|
143
151
|
export class ClaudeParser extends ChatParser {
|
|
144
|
-
name =
|
|
152
|
+
name = "Claude";
|
|
145
153
|
constructor() {
|
|
146
154
|
super();
|
|
147
155
|
this.lastFetch = null;
|
|
148
156
|
}
|
|
149
157
|
|
|
150
158
|
isAvailable(url) {
|
|
151
|
-
return url.includes(
|
|
159
|
+
return url.includes("claude.ai");
|
|
152
160
|
}
|
|
153
161
|
|
|
154
162
|
async parse(options = {}) {
|
|
155
|
-
const title = document.title ||
|
|
163
|
+
const title = document.title || "Claude Chat";
|
|
156
164
|
const messages = [];
|
|
157
165
|
|
|
158
166
|
const conversationId = getConversationId();
|
|
159
|
-
const parserMode = options.parserMode ||
|
|
167
|
+
const parserMode = options.parserMode || "auto";
|
|
160
168
|
|
|
161
|
-
if (conversationId && parserMode !==
|
|
169
|
+
if (conversationId && parserMode !== "prefer_dom") {
|
|
162
170
|
const orgId = await getOrganizationId();
|
|
163
171
|
if (orgId) {
|
|
164
172
|
try {
|
|
@@ -185,18 +193,18 @@ export class ClaudeParser extends ChatParser {
|
|
|
185
193
|
const convTitle = data.name || title;
|
|
186
194
|
|
|
187
195
|
for (const message of branch) {
|
|
188
|
-
const role = message.sender ===
|
|
196
|
+
const role = message.sender === "human" ? "User" : "Claude";
|
|
189
197
|
|
|
190
|
-
let contentStr =
|
|
198
|
+
let contentStr = "";
|
|
191
199
|
|
|
192
200
|
// Construct content
|
|
193
201
|
if (message.content && Array.isArray(message.content)) {
|
|
194
202
|
for (const block of message.content) {
|
|
195
|
-
if (block.type ===
|
|
196
|
-
contentStr += `> **Thinking Process:**\n> \n> ${block.thinking.replace(/\n/g,
|
|
197
|
-
} else if (block.type ===
|
|
203
|
+
if (block.type === "thinking" && block.thinking) {
|
|
204
|
+
contentStr += `> **Thinking Process:**\n> \n> ${block.thinking.replace(/\n/g, "\n> ")}\n\n`;
|
|
205
|
+
} else if (block.type === "text" && block.text) {
|
|
198
206
|
const cleanText = block.text
|
|
199
|
-
.replace(/<antArtifact[^>]*>[\s\S]*?<\/antArtifact>/g,
|
|
207
|
+
.replace(/<antArtifact[^>]*>[\s\S]*?<\/antArtifact>/g, "")
|
|
200
208
|
.trim();
|
|
201
209
|
if (cleanText) {
|
|
202
210
|
contentStr += `${cleanText}\n\n`;
|
|
@@ -205,7 +213,7 @@ export class ClaudeParser extends ChatParser {
|
|
|
205
213
|
}
|
|
206
214
|
} else if (message.text) {
|
|
207
215
|
const cleanText = message.text
|
|
208
|
-
.replace(/<antArtifact[^>]*>[\s\S]*?<\/antArtifact>/g,
|
|
216
|
+
.replace(/<antArtifact[^>]*>[\s\S]*?<\/antArtifact>/g, "")
|
|
209
217
|
.trim();
|
|
210
218
|
if (cleanText) {
|
|
211
219
|
contentStr += `${cleanText}\n\n`;
|
|
@@ -225,7 +233,7 @@ export class ClaudeParser extends ChatParser {
|
|
|
225
233
|
meta.push(attachment.file_type);
|
|
226
234
|
}
|
|
227
235
|
if (meta.length > 0) {
|
|
228
|
-
header += ` _(${meta.join(
|
|
236
|
+
header += ` _(${meta.join(", ")})_`;
|
|
229
237
|
}
|
|
230
238
|
contentStr += `\n\n${header}\n`;
|
|
231
239
|
if (attachment.extracted_content) {
|
|
@@ -245,49 +253,54 @@ export class ClaudeParser extends ChatParser {
|
|
|
245
253
|
// Extract and push artifacts
|
|
246
254
|
const artifacts = extractArtifacts(message);
|
|
247
255
|
for (const artifact of artifacts) {
|
|
248
|
-
let artContent =
|
|
249
|
-
const artTitle = artifact.title ||
|
|
250
|
-
const artText = artifact.content ||
|
|
251
|
-
const artLang = artifact.language ||
|
|
256
|
+
let artContent = "";
|
|
257
|
+
const artTitle = artifact.title || "Artifact";
|
|
258
|
+
const artText = artifact.content || "";
|
|
259
|
+
const artLang = artifact.language || "text";
|
|
252
260
|
|
|
253
|
-
if (artLang ===
|
|
261
|
+
if (artLang === "markdown" || artLang === "text") {
|
|
254
262
|
const quotedContent = artText
|
|
255
|
-
.split(
|
|
263
|
+
.split("\n")
|
|
256
264
|
.map((line) => `> ${line}`)
|
|
257
|
-
.join(
|
|
265
|
+
.join("\n");
|
|
258
266
|
artContent = `\n\n> **Artifact: ${artTitle}**\n\n${quotedContent}\n\n`;
|
|
259
267
|
} else {
|
|
260
268
|
artContent = `\n\n> **Artifact: ${artTitle}**\n\`\`\`${artLang}\n${artText}\n\`\`\`\n\n`;
|
|
261
269
|
}
|
|
262
270
|
|
|
263
271
|
messages.push({
|
|
264
|
-
role:
|
|
272
|
+
role: "Claude Artifact",
|
|
265
273
|
content: artContent.trim(),
|
|
266
274
|
});
|
|
267
275
|
}
|
|
268
276
|
}
|
|
269
277
|
|
|
270
278
|
const currentUrl =
|
|
271
|
-
typeof window !==
|
|
279
|
+
typeof window !== "undefined" && window.location
|
|
280
|
+
? window.location.href || ""
|
|
281
|
+
: "";
|
|
272
282
|
const metadata = {
|
|
273
|
-
Source:
|
|
283
|
+
Source: "Claude",
|
|
274
284
|
Date: new Date().toLocaleString(),
|
|
275
285
|
Link: currentUrl,
|
|
276
|
-
Model: data.model ||
|
|
286
|
+
Model: data.model || "Claude",
|
|
277
287
|
};
|
|
278
288
|
|
|
279
289
|
return { title: convTitle, messages, url: currentUrl, metadata };
|
|
280
290
|
} catch (e) {
|
|
281
|
-
console.error(
|
|
291
|
+
console.error(
|
|
292
|
+
"[AI Exporter] Claude API parse failed, falling back to DOM:",
|
|
293
|
+
e,
|
|
294
|
+
);
|
|
282
295
|
}
|
|
283
296
|
}
|
|
284
297
|
}
|
|
285
298
|
|
|
286
299
|
// Inject the React reader script if not already injected (DOM Fallback)
|
|
287
|
-
if (!document.getElementById(
|
|
288
|
-
const script = document.createElement(
|
|
289
|
-
script.src = chrome.runtime.getURL(
|
|
290
|
-
script.id =
|
|
300
|
+
if (!document.getElementById("ai-export-claude-reader")) {
|
|
301
|
+
const script = document.createElement("script");
|
|
302
|
+
script.src = chrome.runtime.getURL("content/claude_react_reader.js");
|
|
303
|
+
script.id = "ai-export-claude-reader";
|
|
291
304
|
script.onload = function () {
|
|
292
305
|
this.remove(); // Clean up script tag
|
|
293
306
|
};
|
|
@@ -300,17 +313,20 @@ export class ClaudeParser extends ChatParser {
|
|
|
300
313
|
const getArtifactInfo = (index) => {
|
|
301
314
|
return new Promise((resolve) => {
|
|
302
315
|
const handler = (event) => {
|
|
303
|
-
if (event.data.type ===
|
|
304
|
-
window.removeEventListener(
|
|
316
|
+
if (event.data.type === "RspAtftInfo" && event.data.idx === index) {
|
|
317
|
+
window.removeEventListener("message", handler);
|
|
305
318
|
resolve(event.data.atftInfo);
|
|
306
319
|
}
|
|
307
320
|
};
|
|
308
|
-
window.addEventListener(
|
|
309
|
-
window.postMessage(
|
|
321
|
+
window.addEventListener("message", handler);
|
|
322
|
+
window.postMessage(
|
|
323
|
+
{ type: "ReqAtftInfo", idx: index },
|
|
324
|
+
window.location.origin,
|
|
325
|
+
);
|
|
310
326
|
|
|
311
327
|
// Timeout fallback
|
|
312
328
|
setTimeout(() => {
|
|
313
|
-
window.removeEventListener(
|
|
329
|
+
window.removeEventListener("message", handler);
|
|
314
330
|
resolve(null);
|
|
315
331
|
}, 1000); // 1s timeout
|
|
316
332
|
});
|
|
@@ -318,15 +334,19 @@ export class ClaudeParser extends ChatParser {
|
|
|
318
334
|
|
|
319
335
|
const strictSelectors = [
|
|
320
336
|
'[data-testid="user-message"]',
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
].join(
|
|
337
|
+
".font-claude-message",
|
|
338
|
+
".font-claude-response",
|
|
339
|
+
".artifact-block-cell",
|
|
340
|
+
].join(", ");
|
|
325
341
|
|
|
326
|
-
const fallbackSelectors = [
|
|
342
|
+
const fallbackSelectors = ["div.font-serif"].join(", ");
|
|
327
343
|
|
|
328
|
-
const strictCandidates = Array.from(
|
|
329
|
-
|
|
344
|
+
const strictCandidates = Array.from(
|
|
345
|
+
document.querySelectorAll(strictSelectors),
|
|
346
|
+
);
|
|
347
|
+
const fallbackCandidates = Array.from(
|
|
348
|
+
document.querySelectorAll(fallbackSelectors),
|
|
349
|
+
);
|
|
330
350
|
|
|
331
351
|
const validFallbacks = fallbackCandidates.filter((fallback) => {
|
|
332
352
|
const overlapsWithError = strictCandidates.some(
|
|
@@ -338,54 +358,59 @@ export class ClaudeParser extends ChatParser {
|
|
|
338
358
|
const combined = [...new Set([...strictCandidates, ...validFallbacks])];
|
|
339
359
|
|
|
340
360
|
const allElements = combined.sort((a, b) => {
|
|
341
|
-
return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING
|
|
361
|
+
return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING
|
|
362
|
+
? -1
|
|
363
|
+
: 1;
|
|
342
364
|
});
|
|
343
365
|
|
|
344
|
-
const artifactElements = document.querySelectorAll(
|
|
366
|
+
const artifactElements = document.querySelectorAll(".artifact-block-cell");
|
|
345
367
|
const artifactMap = new Map();
|
|
346
368
|
artifactElements.forEach((el, index) => artifactMap.set(el, index));
|
|
347
369
|
|
|
348
370
|
for (const el of allElements) {
|
|
349
|
-
let role =
|
|
350
|
-
let content =
|
|
371
|
+
let role = "Unknown";
|
|
372
|
+
let content = "";
|
|
351
373
|
|
|
352
374
|
if (el.matches('[data-testid="user-message"]')) {
|
|
353
|
-
role =
|
|
375
|
+
role = "User";
|
|
354
376
|
const clone = el.cloneNode(true);
|
|
355
|
-
clone.querySelectorAll(
|
|
377
|
+
clone.querySelectorAll("button").forEach((btn) => btn.remove());
|
|
356
378
|
content = convertToMarkdown(clone);
|
|
357
379
|
} else if (
|
|
358
|
-
el.matches(
|
|
359
|
-
el.matches(
|
|
360
|
-
el.matches(
|
|
380
|
+
el.matches(".font-claude-message") ||
|
|
381
|
+
el.matches(".font-claude-response") ||
|
|
382
|
+
el.matches("div.font-serif")
|
|
361
383
|
) {
|
|
362
|
-
role =
|
|
384
|
+
role = "Claude";
|
|
363
385
|
const clone = el.cloneNode(true);
|
|
364
|
-
clone.querySelectorAll(
|
|
386
|
+
clone.querySelectorAll("button").forEach((btn) => btn.remove());
|
|
365
387
|
content = convertToMarkdown(clone);
|
|
366
|
-
} else if (el.matches(
|
|
367
|
-
role =
|
|
388
|
+
} else if (el.matches(".artifact-block-cell")) {
|
|
389
|
+
role = "Claude Artifact";
|
|
368
390
|
|
|
369
391
|
const index = artifactMap.get(el);
|
|
370
392
|
if (index !== undefined) {
|
|
371
393
|
const info = await getArtifactInfo(index);
|
|
372
394
|
if (info) {
|
|
373
|
-
const artTitle = info.title ||
|
|
374
|
-
const artContent = info.content ||
|
|
375
|
-
const artLang = info.language ||
|
|
376
|
-
if (artLang ===
|
|
395
|
+
const artTitle = info.title || "Artifact";
|
|
396
|
+
const artContent = info.content || "";
|
|
397
|
+
const artLang = info.language || "text";
|
|
398
|
+
if (artLang === "markdown" || artLang === "text") {
|
|
377
399
|
const quotedContent = artContent
|
|
378
|
-
.split(
|
|
400
|
+
.split("\n")
|
|
379
401
|
.map((line) => `> ${line}`)
|
|
380
|
-
.join(
|
|
402
|
+
.join("\n");
|
|
381
403
|
content = `\n\n> **Artifact: ${artTitle}**\n\n${quotedContent}\n\n`;
|
|
382
404
|
} else {
|
|
383
405
|
content = `\n\n> **Artifact: ${artTitle}**\n\`\`\`${artLang}\n${artContent}\n\`\`\`\n\n`;
|
|
384
406
|
}
|
|
385
407
|
} else {
|
|
386
408
|
const header =
|
|
387
|
-
el.querySelector(
|
|
388
|
-
|
|
409
|
+
el.querySelector(".flex.items-center.gap-2") ||
|
|
410
|
+
el.querySelector(".font-bold");
|
|
411
|
+
const fallbackTitle = header
|
|
412
|
+
? header.innerText.split("\n")[0]
|
|
413
|
+
: "Unknown Artifact";
|
|
389
414
|
content = `\n> [Artifact: ${fallbackTitle} - content extraction failed]\n`;
|
|
390
415
|
}
|
|
391
416
|
}
|
|
@@ -397,12 +422,14 @@ export class ClaudeParser extends ChatParser {
|
|
|
397
422
|
}
|
|
398
423
|
|
|
399
424
|
const currentUrl =
|
|
400
|
-
typeof window !==
|
|
425
|
+
typeof window !== "undefined" && window.location
|
|
426
|
+
? window.location.href || ""
|
|
427
|
+
: "";
|
|
401
428
|
const metadata = {
|
|
402
|
-
Source:
|
|
429
|
+
Source: "Claude",
|
|
403
430
|
Date: new Date().toLocaleString(),
|
|
404
431
|
Link: currentUrl,
|
|
405
|
-
Model:
|
|
432
|
+
Model: "Claude",
|
|
406
433
|
};
|
|
407
434
|
|
|
408
435
|
return { title, messages, url: currentUrl, metadata };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
// Listen for messages from the content script
|
|
3
|
-
window.addEventListener(
|
|
3
|
+
window.addEventListener("message", (event) => {
|
|
4
4
|
// Security check: ensure message is from same origin
|
|
5
5
|
if (event.origin !== window.location.origin) return;
|
|
6
6
|
|
|
7
|
-
if (event.data.type ===
|
|
7
|
+
if (event.data.type === "ReqAtftInfo") {
|
|
8
8
|
const index = event.data.idx;
|
|
9
|
-
const artifacts = document.querySelectorAll(
|
|
9
|
+
const artifacts = document.querySelectorAll("div.artifact-block-cell");
|
|
10
10
|
const artifactElement = artifacts[index];
|
|
11
11
|
|
|
12
12
|
let artifactInfo = null;
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
if (artifactElement) {
|
|
15
15
|
try {
|
|
16
16
|
// Try to find the React Fiber key
|
|
17
|
-
const key = Object.keys(artifactElement).find((k) =>
|
|
17
|
+
const key = Object.keys(artifactElement).find((k) =>
|
|
18
|
+
k.startsWith("__reactFiber"),
|
|
19
|
+
);
|
|
18
20
|
if (key) {
|
|
19
21
|
const fiber = artifactElement[key];
|
|
20
22
|
// Navigate React props structure to find the artifact data
|
|
@@ -42,13 +44,13 @@
|
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
} catch (e) {
|
|
45
|
-
console.error(
|
|
47
|
+
console.error("[AI Export] Error reading React internals:", e);
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
window.postMessage(
|
|
50
52
|
{
|
|
51
|
-
type:
|
|
53
|
+
type: "RspAtftInfo",
|
|
52
54
|
idx: index,
|
|
53
55
|
atftInfo: artifactInfo,
|
|
54
56
|
},
|