chatgpt-pro-research 0.2.0 → 0.2.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/lib/index.js +78 -15
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/plugin.ts
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
|
-
import { dirname as dirname2, extname, isAbsolute, join as join3, resolve as
|
|
5
|
+
import { dirname as dirname2, extname, isAbsolute, join as join3, resolve as resolve3, sep } from "node:path";
|
|
6
6
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import z from "@deepseek-ai/schemastery";
|
|
@@ -597,7 +597,7 @@ var ResearchEngine = class {
|
|
|
597
597
|
if (this.active !== void 0) {
|
|
598
598
|
await this.active.promise;
|
|
599
599
|
} else {
|
|
600
|
-
await new Promise((
|
|
600
|
+
await new Promise((resolve4) => setTimeout(resolve4, 0));
|
|
601
601
|
}
|
|
602
602
|
}
|
|
603
603
|
}
|
|
@@ -838,14 +838,16 @@ ${result.summary}
|
|
|
838
838
|
if (topic.status === "completed" || topic.status === "cancelled") return;
|
|
839
839
|
if (error instanceof TransportError) {
|
|
840
840
|
if (error.failure === "worker") {
|
|
841
|
-
await this.transition(topic, "failed");
|
|
841
|
+
await this.transition(topic, "failed", { stopReason: error.message });
|
|
842
842
|
return;
|
|
843
843
|
}
|
|
844
844
|
const reason = error.failure === "login" || error.failure === "upload" || error.failure === "ui" ? error.failure : "timeout";
|
|
845
|
-
await this.transition(topic, "stalled", { stallReason: reason });
|
|
845
|
+
await this.transition(topic, "stalled", { stallReason: reason, stopReason: error.message });
|
|
846
846
|
return;
|
|
847
847
|
}
|
|
848
|
-
await this.transition(topic, "failed"
|
|
848
|
+
await this.transition(topic, "failed", {
|
|
849
|
+
stopReason: error instanceof Error ? error.message : String(error)
|
|
850
|
+
});
|
|
849
851
|
}
|
|
850
852
|
async transition(topic, next, extra) {
|
|
851
853
|
assertTransition(topic.status, next);
|
|
@@ -901,7 +903,15 @@ var SELECTORS = {
|
|
|
901
903
|
'[data-markdown-text-style="assistant-message"]',
|
|
902
904
|
'[data-message-author-role="assistant"]'
|
|
903
905
|
].join(", "),
|
|
904
|
-
|
|
906
|
+
// The composer has several file inputs (camera, photos, videos). The general
|
|
907
|
+
// attachment input is the one without an `accept` filter; the camera input
|
|
908
|
+
// rejects multiple files.
|
|
909
|
+
fileInput: [
|
|
910
|
+
'input[type="file"][aria-label="\u9644\u52A0\u6587\u4EF6"]',
|
|
911
|
+
'input[type="file"][aria-label*="Attach" i]:not([capture])',
|
|
912
|
+
'form input[type="file"][multiple]:not([accept]):not([capture])',
|
|
913
|
+
'input[type="file"][multiple]:not([accept]):not([capture])'
|
|
914
|
+
].join(", "),
|
|
905
915
|
modelPicker: [
|
|
906
916
|
'button[aria-label*="\u9009\u62E9 ChatGPT \u6A21\u578B"]',
|
|
907
917
|
'button[aria-label*="\u6A21\u578B"]',
|
|
@@ -947,6 +957,7 @@ async function firstVisible(page, selector, timeoutMs) {
|
|
|
947
957
|
}
|
|
948
958
|
var ChatGptWebTransport = class {
|
|
949
959
|
context;
|
|
960
|
+
launching;
|
|
950
961
|
submissions = /* @__PURE__ */ new Map();
|
|
951
962
|
options;
|
|
952
963
|
constructor(options) {
|
|
@@ -957,6 +968,15 @@ var ChatGptWebTransport = class {
|
|
|
957
968
|
}
|
|
958
969
|
async ensureContext() {
|
|
959
970
|
if (this.context !== void 0) return this.context;
|
|
971
|
+
if (this.launching !== void 0) return this.launching;
|
|
972
|
+
this.launching = this.launchContext();
|
|
973
|
+
try {
|
|
974
|
+
return await this.launching;
|
|
975
|
+
} finally {
|
|
976
|
+
this.launching = void 0;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
async launchContext() {
|
|
960
980
|
await mkdir2(this.options.profileDir, { recursive: true });
|
|
961
981
|
const base = {
|
|
962
982
|
headless: this.options.headless ?? false,
|
|
@@ -964,7 +984,12 @@ var ChatGptWebTransport = class {
|
|
|
964
984
|
args: ["--disable-blink-features=AutomationControlled"]
|
|
965
985
|
};
|
|
966
986
|
try {
|
|
967
|
-
|
|
987
|
+
const context = await chromium.launchPersistentContext(this.options.profileDir, { ...base, channel: "chrome" });
|
|
988
|
+
context.on("close", () => {
|
|
989
|
+
if (this.context === context) this.context = void 0;
|
|
990
|
+
});
|
|
991
|
+
this.context = context;
|
|
992
|
+
return context;
|
|
968
993
|
} catch (error) {
|
|
969
994
|
throw new TransportError(
|
|
970
995
|
`cannot launch Chrome with profile ${this.options.profileDir}; install Google Chrome or pass browser.headless=false plus a Playwright browser. ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -972,7 +997,6 @@ var ChatGptWebTransport = class {
|
|
|
972
997
|
{ cause: error }
|
|
973
998
|
);
|
|
974
999
|
}
|
|
975
|
-
return this.context;
|
|
976
1000
|
}
|
|
977
1001
|
async probe() {
|
|
978
1002
|
const context = await this.ensureContext();
|
|
@@ -1120,9 +1144,9 @@ ${attachments.join("\n")}`);
|
|
|
1120
1144
|
const dataUrl = await page.evaluate(async (src) => {
|
|
1121
1145
|
const response = await fetch(src);
|
|
1122
1146
|
const blob = await response.blob();
|
|
1123
|
-
return await new Promise((
|
|
1147
|
+
return await new Promise((resolve4, reject) => {
|
|
1124
1148
|
const reader = new FileReader();
|
|
1125
|
-
reader.onload = () =>
|
|
1149
|
+
reader.onload = () => resolve4(String(reader.result));
|
|
1126
1150
|
reader.onerror = () => reject(reader.error);
|
|
1127
1151
|
reader.readAsDataURL(blob);
|
|
1128
1152
|
});
|
|
@@ -1224,6 +1248,41 @@ ${attachments.join("\n")}`);
|
|
|
1224
1248
|
}
|
|
1225
1249
|
};
|
|
1226
1250
|
|
|
1251
|
+
// ../transport/src/shared.ts
|
|
1252
|
+
import { resolve as resolve2 } from "node:path";
|
|
1253
|
+
var REGISTRY = /* @__PURE__ */ Symbol.for("dsh-pro.transport.shared.v1");
|
|
1254
|
+
function registry() {
|
|
1255
|
+
const holder = globalThis;
|
|
1256
|
+
const existing = holder[REGISTRY];
|
|
1257
|
+
if (existing instanceof Map) return existing;
|
|
1258
|
+
const created = /* @__PURE__ */ new Map();
|
|
1259
|
+
holder[REGISTRY] = created;
|
|
1260
|
+
return created;
|
|
1261
|
+
}
|
|
1262
|
+
function acquireSharedTransport(options, create = () => new ChatGptWebTransport(options)) {
|
|
1263
|
+
const key = resolve2(options.profileDir);
|
|
1264
|
+
const slots = registry();
|
|
1265
|
+
let slot = slots.get(key);
|
|
1266
|
+
if (slot === void 0) {
|
|
1267
|
+
slot = { transport: create(), refs: 0 };
|
|
1268
|
+
slots.set(key, slot);
|
|
1269
|
+
}
|
|
1270
|
+
slot.refs += 1;
|
|
1271
|
+
const target = slot;
|
|
1272
|
+
let released = false;
|
|
1273
|
+
return {
|
|
1274
|
+
transport: target.transport,
|
|
1275
|
+
release: () => {
|
|
1276
|
+
if (released) return;
|
|
1277
|
+
released = true;
|
|
1278
|
+
target.refs -= 1;
|
|
1279
|
+
if (target.refs > 0) return;
|
|
1280
|
+
if (slots.get(key) === target) slots.delete(key);
|
|
1281
|
+
void target.transport.close();
|
|
1282
|
+
}
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1227
1286
|
// src/plugin.ts
|
|
1228
1287
|
var Config = z.object({
|
|
1229
1288
|
rounds: z.number().step(1).min(1).max(10).default(3).description("\u6BCF\u4E3B\u9898\u9ED8\u8BA4\u8F6E\u6B21\u4E0A\u9650\uFF081\u201310\uFF09\u3002"),
|
|
@@ -1331,6 +1390,7 @@ var ProResearchService = class {
|
|
|
1331
1390
|
stores = /* @__PURE__ */ new Map();
|
|
1332
1391
|
topicSessions = /* @__PURE__ */ new Map();
|
|
1333
1392
|
transport;
|
|
1393
|
+
shared;
|
|
1334
1394
|
rootFor(cwd) {
|
|
1335
1395
|
return cwd.trim() === "" ? process.cwd() : cwd;
|
|
1336
1396
|
}
|
|
@@ -1354,10 +1414,11 @@ var ProResearchService = class {
|
|
|
1354
1414
|
}
|
|
1355
1415
|
transportFor() {
|
|
1356
1416
|
if (this.transport !== void 0) return this.transport;
|
|
1357
|
-
this.
|
|
1417
|
+
this.shared = acquireSharedTransport({
|
|
1358
1418
|
profileDir: this.config.browser.profileDir,
|
|
1359
1419
|
headless: this.config.browser.headless
|
|
1360
1420
|
});
|
|
1421
|
+
this.transport = this.shared.transport;
|
|
1361
1422
|
return this.transport;
|
|
1362
1423
|
}
|
|
1363
1424
|
judge() {
|
|
@@ -1532,8 +1593,8 @@ ${input.answer.slice(0, 3e4)}`
|
|
|
1532
1593
|
if (entry === void 0) throw new Error(`unknown topic: ${id}`);
|
|
1533
1594
|
const store = this.storeAt(entry.root, entry.mode);
|
|
1534
1595
|
const dir = await store.dirOf(id);
|
|
1535
|
-
const artifactsRoot =
|
|
1536
|
-
const target =
|
|
1596
|
+
const artifactsRoot = resolve3(dir, "artifacts");
|
|
1597
|
+
const target = resolve3(dir, relativePath);
|
|
1537
1598
|
if (target !== artifactsRoot && !target.startsWith(`${artifactsRoot}${sep}`)) {
|
|
1538
1599
|
throw new Error("artifact path escapes the topic");
|
|
1539
1600
|
}
|
|
@@ -1611,7 +1672,7 @@ ${input.answer.slice(0, 3e4)}`
|
|
|
1611
1672
|
withSources(cwd, refs) {
|
|
1612
1673
|
return refs.map((ref) => ({
|
|
1613
1674
|
...ref,
|
|
1614
|
-
source: isAbsolute(ref.path) ? ref.path :
|
|
1675
|
+
source: isAbsolute(ref.path) ? ref.path : resolve3(cwd, ref.path)
|
|
1615
1676
|
}));
|
|
1616
1677
|
}
|
|
1617
1678
|
withDesignCount(brief, designs) {
|
|
@@ -1686,7 +1747,9 @@ ${input.answer.slice(0, 3e4)}`
|
|
|
1686
1747
|
};
|
|
1687
1748
|
}
|
|
1688
1749
|
dispose() {
|
|
1689
|
-
|
|
1750
|
+
this.shared?.release();
|
|
1751
|
+
this.shared = void 0;
|
|
1752
|
+
this.transport = void 0;
|
|
1690
1753
|
}
|
|
1691
1754
|
};
|
|
1692
1755
|
function registerSkill(ctx, spec2) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chatgpt-pro-research",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "ChatGPT Pro Research: unattended multi-round research through a real ChatGPT Pro web session, with local records and a DSH sidebar.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|