@palmyr/cli 1.9.1 → 1.10.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.
@@ -0,0 +1,518 @@
1
+ /**
2
+ * Local real-browser TikTok login — the agent-smooth alternative to fighting
3
+ * TikTok's anti-bot from a headless VPS session (the old `tiktok login` form
4
+ * driver perma-spun ~70% of the time).
5
+ *
6
+ * The idea (borrowed from Hermes Agent's `/browser connect`): don't emulate a
7
+ * human, *be* one. We launch the operator's real Chrome/Edge/Brave — real
8
+ * fingerprint, real home IP — point it at TikTok's login page, and let the
9
+ * human solve login + captcha + 2FA themselves (free, and unbeatable by any
10
+ * solver). The moment a `sessionid` cookie appears we harvest the full jar and
11
+ * hand it back; the caller drops it into the same encrypted session cache that
12
+ * `post`/`follow`/`like` already read, so every downstream op is unchanged.
13
+ *
14
+ * Why CDP and not Playwright: TikTok's `sessionid` is HttpOnly, so a
15
+ * `document.cookie` scrape can never see it. CDP's `Network.getAllCookies`
16
+ * reads HttpOnly cookies directly — and it rides the `ws` dependency the CLI
17
+ * already ships, so this adds zero install weight.
18
+ *
19
+ * Agent contract: this never blocks forever (bounded by `timeoutMs`) and never
20
+ * needs a keystroke (it auto-detects the session). The caller gets a single
21
+ * structured result it can branch on.
22
+ */
23
+ import { spawn } from "child_process";
24
+ import { existsSync, mkdtempSync, rmSync, writeFileSync } from "fs";
25
+ import { tmpdir } from "os";
26
+ import { join } from "path";
27
+ import { createServer } from "net";
28
+ import http from "http";
29
+ import WebSocket from "ws";
30
+ /**
31
+ * Find a Chromium-family browser. Only returns paths that exist on disk, so a
32
+ * null result is a reliable "no browser here" signal (→ graceful handoff to the
33
+ * manual import path rather than a doomed launch).
34
+ */
35
+ function findBrowser(explicit) {
36
+ const tryList = [];
37
+ const override = explicit || process.env.PALMYR_BROWSER_PATH;
38
+ if (override)
39
+ tryList.push({ path: override, name: "custom" });
40
+ const plat = process.platform;
41
+ if (plat === "win32") {
42
+ const pf = process.env["PROGRAMFILES"] || "C:\\Program Files";
43
+ const pf86 = process.env["PROGRAMFILES(X86)"] || "C:\\Program Files (x86)";
44
+ const local = process.env["LOCALAPPDATA"];
45
+ tryList.push({ path: join(pf, "Google\\Chrome\\Application\\chrome.exe"), name: "chrome" }, { path: join(pf86, "Google\\Chrome\\Application\\chrome.exe"), name: "chrome" }, ...(local ? [{ path: join(local, "Google\\Chrome\\Application\\chrome.exe"), name: "chrome" }] : []), { path: join(pf86, "Microsoft\\Edge\\Application\\msedge.exe"), name: "edge" }, { path: join(pf, "Microsoft\\Edge\\Application\\msedge.exe"), name: "edge" }, ...(local ? [{ path: join(local, "BraveSoftware\\Brave-Browser\\Application\\brave.exe"), name: "brave" }] : []));
46
+ }
47
+ else if (plat === "darwin") {
48
+ tryList.push({ path: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", name: "chrome" }, { path: "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge", name: "edge" }, { path: "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser", name: "brave" }, { path: "/Applications/Chromium.app/Contents/MacOS/Chromium", name: "chromium" });
49
+ }
50
+ else {
51
+ // Linux — enumerate common absolute locations across distros/snap.
52
+ for (const dir of ["/usr/bin", "/usr/local/bin", "/snap/bin", "/opt/google/chrome"]) {
53
+ tryList.push({ path: join(dir, "google-chrome"), name: "chrome" }, { path: join(dir, "google-chrome-stable"), name: "chrome" }, { path: join(dir, "chromium"), name: "chromium" }, { path: join(dir, "chromium-browser"), name: "chromium" }, { path: join(dir, "microsoft-edge"), name: "edge" }, { path: join(dir, "brave-browser"), name: "brave" }, { path: join(dir, "chrome"), name: "chrome" });
54
+ }
55
+ }
56
+ for (const c of tryList) {
57
+ try {
58
+ if (existsSync(c.path))
59
+ return c;
60
+ }
61
+ catch {
62
+ /* keep looking */
63
+ }
64
+ }
65
+ return null;
66
+ }
67
+ /* ─── Small helpers ──────────────────────────────────────────────────────── */
68
+ function getFreePort() {
69
+ return new Promise((resolve, reject) => {
70
+ const srv = createServer();
71
+ srv.on("error", reject);
72
+ srv.listen(0, "127.0.0.1", () => {
73
+ const addr = srv.address();
74
+ const port = typeof addr === "object" && addr ? addr.port : 0;
75
+ srv.close(() => (port ? resolve(port) : reject(new Error("could not allocate a port"))));
76
+ });
77
+ });
78
+ }
79
+ function httpGetJson(url, timeoutMs = 2000) {
80
+ return new Promise((resolve, reject) => {
81
+ const req = http.get(url, (res) => {
82
+ let body = "";
83
+ res.on("data", (d) => (body += d));
84
+ res.on("end", () => {
85
+ try {
86
+ resolve(JSON.parse(body));
87
+ }
88
+ catch (e) {
89
+ reject(e);
90
+ }
91
+ });
92
+ });
93
+ req.on("error", reject);
94
+ req.setTimeout(timeoutMs, () => req.destroy(new Error("timeout")));
95
+ });
96
+ }
97
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
98
+ /** CDP `sameSite` → Playwright's accepted set; omit anything unexpected. */
99
+ function normalizeSameSite(v) {
100
+ if (v === "Strict" || v === "Lax" || v === "None")
101
+ return v;
102
+ return undefined;
103
+ }
104
+ /** CDP cookie → the clean Playwright-injectable shape (drops size/priority/etc.). */
105
+ function normalizeCookie(c) {
106
+ const out = {
107
+ name: c.name,
108
+ value: c.value,
109
+ domain: c.domain,
110
+ path: c.path || "/",
111
+ httpOnly: !!c.httpOnly,
112
+ secure: !!c.secure,
113
+ };
114
+ // CDP gives expires in Unix seconds, or -1 for a session cookie — omit those.
115
+ if (typeof c.expires === "number" && c.expires > 0)
116
+ out.expires = Math.floor(c.expires);
117
+ const ss = normalizeSameSite(c.sameSite);
118
+ if (ss)
119
+ out.sameSite = ss;
120
+ return out;
121
+ }
122
+ function isTikTokCookie(domain) {
123
+ return domain.replace(/^\./, "").toLowerCase().endsWith("tiktok.com");
124
+ }
125
+ /**
126
+ * Timezone → ISO country, mirroring the server's COUNTRY_PROFILES set (plus the
127
+ * extra US/CA/AU zones a single capital-city entry misses). Only consulted when
128
+ * the browser locale has no region subtag, so it doesn't need to be exhaustive.
129
+ */
130
+ const TZ_COUNTRY = {
131
+ "America/New_York": "us", "America/Chicago": "us", "America/Denver": "us",
132
+ "America/Los_Angeles": "us", "America/Phoenix": "us", "America/Anchorage": "us",
133
+ "America/Toronto": "ca", "America/Vancouver": "ca", "America/Edmonton": "ca",
134
+ "Europe/London": "gb", "Europe/Dublin": "ie",
135
+ "Australia/Sydney": "au", "Australia/Melbourne": "au", "Australia/Perth": "au", "Australia/Brisbane": "au",
136
+ "Pacific/Auckland": "nz",
137
+ "Europe/Berlin": "de", "Europe/Vienna": "at", "Europe/Zurich": "ch",
138
+ "Europe/Paris": "fr", "Europe/Brussels": "be", "Europe/Amsterdam": "nl",
139
+ "Europe/Madrid": "es", "Europe/Rome": "it", "Europe/Lisbon": "pt",
140
+ "Europe/Warsaw": "pl", "Europe/Prague": "cz", "Europe/Stockholm": "se",
141
+ "Europe/Oslo": "no", "Europe/Copenhagen": "dk", "Europe/Helsinki": "fi",
142
+ "Europe/Athens": "gr", "Europe/Bucharest": "ro", "Europe/Budapest": "hu",
143
+ "Europe/Istanbul": "tr", "Europe/Moscow": "ru", "Europe/Kyiv": "ua",
144
+ "America/Sao_Paulo": "br", "America/Mexico_City": "mx", "America/Argentina/Buenos_Aires": "ar",
145
+ "Asia/Tokyo": "jp", "Asia/Seoul": "kr", "Asia/Kolkata": "in", "Asia/Jakarta": "id",
146
+ "Asia/Manila": "ph", "Asia/Bangkok": "th", "Asia/Ho_Chi_Minh": "vn", "Asia/Singapore": "sg",
147
+ "Asia/Kuala_Lumpur": "my", "Asia/Dubai": "ae", "Asia/Riyadh": "sa", "Asia/Jerusalem": "il",
148
+ "Africa/Johannesburg": "za",
149
+ };
150
+ /**
151
+ * Infer the account's country from the live browser. Locale region subtag is
152
+ * the primary signal (e.g. `en-US` → us, `pt-BR` → br) since modern browsers
153
+ * almost always include it; timezone is the fallback when they don't.
154
+ */
155
+ function countryFromBrowser(locale, timezone) {
156
+ if (locale) {
157
+ const m = locale.match(/[-_]([A-Za-z]{2})(?:$|[-_])/);
158
+ if (m)
159
+ return m[1].toLowerCase();
160
+ }
161
+ if (timezone && TZ_COUNTRY[timezone])
162
+ return TZ_COUNTRY[timezone];
163
+ return undefined;
164
+ }
165
+ /* ─── Minimal CDP client over a single page target ───────────────────────── */
166
+ class CdpSession {
167
+ ws;
168
+ nextId = 1;
169
+ pending = new Map();
170
+ closed = false;
171
+ constructor(ws) {
172
+ this.ws = ws;
173
+ ws.on("message", (data) => {
174
+ let msg;
175
+ try {
176
+ msg = JSON.parse(data.toString());
177
+ }
178
+ catch {
179
+ return;
180
+ }
181
+ if (typeof msg.id === "number" && this.pending.has(msg.id)) {
182
+ const p = this.pending.get(msg.id);
183
+ this.pending.delete(msg.id);
184
+ if (msg.error)
185
+ p.reject(new Error(msg.error.message || "CDP error"));
186
+ else
187
+ p.resolve(msg.result);
188
+ }
189
+ });
190
+ ws.on("close", () => {
191
+ this.closed = true;
192
+ for (const p of this.pending.values())
193
+ p.reject(new Error("CDP socket closed"));
194
+ this.pending.clear();
195
+ });
196
+ ws.on("error", () => {
197
+ /* surfaced via close */
198
+ });
199
+ }
200
+ static connect(wsUrl) {
201
+ return new Promise((resolve, reject) => {
202
+ const ws = new WebSocket(wsUrl);
203
+ const onErr = (e) => reject(e);
204
+ ws.once("error", onErr);
205
+ ws.once("open", () => {
206
+ ws.removeListener("error", onErr);
207
+ resolve(new CdpSession(ws));
208
+ });
209
+ });
210
+ }
211
+ send(method, params = {}) {
212
+ if (this.closed)
213
+ return Promise.reject(new Error("CDP socket closed"));
214
+ const id = this.nextId++;
215
+ return new Promise((resolve, reject) => {
216
+ this.pending.set(id, { resolve, reject });
217
+ this.ws.send(JSON.stringify({ id, method, params }), (e) => {
218
+ if (e) {
219
+ this.pending.delete(id);
220
+ reject(e);
221
+ }
222
+ });
223
+ });
224
+ }
225
+ close() {
226
+ try {
227
+ this.ws.close();
228
+ }
229
+ catch {
230
+ /* noop */
231
+ }
232
+ }
233
+ }
234
+ /** Pick the first inspectable page target from CDP's target list. */
235
+ async function findPageTarget(port) {
236
+ try {
237
+ const targets = await httpGetJson(`http://127.0.0.1:${port}/json`);
238
+ if (!Array.isArray(targets))
239
+ return null;
240
+ const page = targets.find((t) => t.type === "page" && typeof t.webSocketDebuggerUrl === "string");
241
+ return page?.webSocketDebuggerUrl || null;
242
+ }
243
+ catch {
244
+ return null;
245
+ }
246
+ }
247
+ /**
248
+ * Extract TikTok's login QR from `/login/qrcode`. The QR is a same-origin
249
+ * <canvas> inside [data-e2e="qr-code"] (verified against the live page), so
250
+ * `canvas.toDataURL()` works; fall back to a CDP element screenshot if the
251
+ * canvas is ever tainted or swapped for an <img>. Polls until it renders.
252
+ */
253
+ async function extractTikTokQr(cdp) {
254
+ for (let i = 0; i < 12; i++) {
255
+ try {
256
+ const ev = await cdp.send("Runtime.evaluate", {
257
+ expression: `(()=>{const c=document.querySelector('[data-e2e="qr-code"] canvas')||document.querySelector('canvas');` +
258
+ `if(!c||!c.width)return '';try{return c.toDataURL('image/png');}catch(e){return 'TAINTED';}})()`,
259
+ returnByValue: true,
260
+ });
261
+ const v = ev?.result?.value;
262
+ if (typeof v === "string" && v.startsWith("data:image"))
263
+ return { dataUrl: v };
264
+ }
265
+ catch {
266
+ /* retry */
267
+ }
268
+ await sleep(1000);
269
+ }
270
+ // Fallback: screenshot the QR element region.
271
+ try {
272
+ const boxEv = await cdp.send("Runtime.evaluate", {
273
+ expression: `(()=>{const e=document.querySelector('[data-e2e="qr-code"]')||document.querySelector('canvas');` +
274
+ `if(!e)return '';const r=e.getBoundingClientRect();return JSON.stringify({x:r.x,y:r.y,w:r.width,h:r.height});})()`,
275
+ returnByValue: true,
276
+ });
277
+ const v = boxEv?.result?.value;
278
+ if (typeof v === "string" && v) {
279
+ const b = JSON.parse(v);
280
+ if (b.w > 0) {
281
+ const shot = await cdp.send("Page.captureScreenshot", {
282
+ format: "png",
283
+ clip: { x: b.x, y: b.y, width: b.w, height: b.h, scale: 1 },
284
+ });
285
+ if (shot?.data)
286
+ return { dataUrl: "data:image/png;base64," + shot.data };
287
+ }
288
+ }
289
+ }
290
+ catch {
291
+ /* give up — caller reports no QR */
292
+ }
293
+ return {};
294
+ }
295
+ function saveQrPng(dataUrl) {
296
+ const b64 = dataUrl.split(",")[1] || "";
297
+ const path = join(tmpdir(), `palmyr-tiktok-qr-${Date.now()}.png`);
298
+ writeFileSync(path, Buffer.from(b64, "base64"));
299
+ return path;
300
+ }
301
+ /* ─── Main entry ─────────────────────────────────────────────────────────── */
302
+ export async function connectTikTok(opts = {}) {
303
+ const timeoutMs = opts.timeoutMs ?? 300_000;
304
+ const progress = opts.onProgress ?? (() => { });
305
+ const browser = findBrowser(opts.browserPath);
306
+ if (!browser) {
307
+ return {
308
+ success: false,
309
+ reason: "no_local_browser",
310
+ error: "No Chrome/Edge/Brave found. Install one, pass --browser-path, or import cookies manually from DevTools.",
311
+ };
312
+ }
313
+ if (opts.browserPath && !existsSync(opts.browserPath)) {
314
+ return { success: false, reason: "no_local_browser", error: `--browser-path not found: ${opts.browserPath}` };
315
+ }
316
+ let port;
317
+ try {
318
+ port = await getFreePort();
319
+ }
320
+ catch (e) {
321
+ return { success: false, reason: "launch_failed", error: e.message };
322
+ }
323
+ // Fresh, throwaway profile dir — this is what forces a brand-new browser
324
+ // process that actually owns the debug port. Launching against the user's
325
+ // normal profile while their browser is already open would just open a tab
326
+ // in the existing process and ignore --remote-debugging-port entirely.
327
+ let userDataDir;
328
+ try {
329
+ userDataDir = mkdtempSync(join(tmpdir(), "palmyr-tiktok-"));
330
+ }
331
+ catch (e) {
332
+ return { success: false, reason: "launch_failed", error: `could not create temp profile: ${e.message}` };
333
+ }
334
+ // Chromium won't start its sandbox as root and exits immediately — and many
335
+ // container / CI / agent shells run as root. Detect that (or an explicit
336
+ // opt-in) and drop the sandbox so the browser actually launches. On a normal
337
+ // non-root desktop the sandbox stays on.
338
+ const isRootPosix = process.platform !== "win32" && typeof process.getuid === "function" && process.getuid() === 0;
339
+ const noSandbox = opts.noSandbox === true || isRootPosix;
340
+ // QR mode lands on TikTok's QR-login page; typed login on the form page.
341
+ const landingUrl = opts.qr
342
+ ? "https://www.tiktok.com/login/qrcode"
343
+ : "https://www.tiktok.com/login/phone-or-email/email";
344
+ // Always run HEADED. TikTok refuses to authorize a login into a headless
345
+ // session — headless Chrome's UA literally contains "HeadlessChrome", which it
346
+ // detects and rejects ("Couldn't log in. Try another login method"). A headed
347
+ // window presents a normal Chrome UA with no automation tells. On a server,
348
+ // run under a virtual display (xvfb). --disable-blink-features keeps
349
+ // navigator.webdriver clean across Chrome versions.
350
+ const args = [
351
+ `--remote-debugging-port=${port}`,
352
+ `--user-data-dir=${userDataDir}`,
353
+ "--no-first-run",
354
+ "--no-default-browser-check",
355
+ "--new-window",
356
+ "--disable-blink-features=AutomationControlled",
357
+ "--window-size=1280,800", // realistic, non-zero geometry (a headless tell)
358
+ ...(noSandbox ? ["--no-sandbox", "--disable-dev-shm-usage"] : []),
359
+ landingUrl,
360
+ ];
361
+ let child;
362
+ try {
363
+ child = spawn(browser.path, args, { stdio: "ignore", detached: false });
364
+ }
365
+ catch (e) {
366
+ cleanupDir(userDataDir);
367
+ return { success: false, reason: "launch_failed", error: `${browser.name} launch failed: ${e.message}` };
368
+ }
369
+ let childExited = false;
370
+ child.on("exit", () => (childExited = true));
371
+ if (noSandbox)
372
+ progress("launched with --no-sandbox (root / headless environment detected).");
373
+ if (opts.qr) {
374
+ progress(`opened ${browser.name} — fetching TikTok's login QR (a window opens; scan from it or the saved image)…`);
375
+ }
376
+ else {
377
+ progress(`opened ${browser.name} — log in to TikTok (solve any captcha / 2FA yourself).`);
378
+ progress("capturing automatically the moment you're signed in… (window will close on success)");
379
+ }
380
+ const deadline = Date.now() + timeoutMs;
381
+ let cdp = null;
382
+ let qrPngPath;
383
+ let qrDataUrl;
384
+ let result = { success: false, reason: "login_timeout", error: "timed out waiting for login", browser: browser.name };
385
+ try {
386
+ while (Date.now() < deadline) {
387
+ // The human closed the window before finishing → don't hang out the clock.
388
+ if (childExited) {
389
+ result = {
390
+ success: false,
391
+ reason: "aborted",
392
+ error: "browser closed before a session was captured. On a headless / root box the browser can exit instantly — ensure a display is available (e.g. xvfb) and the sandbox is off (auto on root Linux, or pass --no-sandbox).",
393
+ browser: browser.name,
394
+ };
395
+ break;
396
+ }
397
+ // (Re)attach if we have no live CDP session — covers the brief startup
398
+ // window and the case where the user navigated in a way that recycled
399
+ // the page target.
400
+ if (!cdp || cdp.closed) {
401
+ const wsUrl = await findPageTarget(port);
402
+ if (wsUrl) {
403
+ try {
404
+ cdp = await CdpSession.connect(wsUrl);
405
+ await cdp.send("Network.enable");
406
+ if (opts.qr) {
407
+ try {
408
+ await cdp.send("Page.enable");
409
+ }
410
+ catch { /* screenshot fallback only */ }
411
+ }
412
+ }
413
+ catch {
414
+ cdp = null;
415
+ }
416
+ }
417
+ }
418
+ if (cdp && !cdp.closed) {
419
+ // QR mode: surface the QR once, as soon as it renders, so the agent can
420
+ // forward it to a human while we keep polling for the scan.
421
+ if (opts.qr && !qrDataUrl) {
422
+ const { dataUrl } = await extractTikTokQr(cdp);
423
+ if (dataUrl) {
424
+ qrDataUrl = dataUrl;
425
+ try {
426
+ qrPngPath = saveQrPng(dataUrl);
427
+ }
428
+ catch { /* path optional */ }
429
+ progress("QR ready — forward it to a human to scan with the TikTok app; I capture the session automatically once they confirm.");
430
+ if (qrPngPath)
431
+ progress(`QR image saved: ${qrPngPath}`);
432
+ try {
433
+ await opts.onQr?.(dataUrl);
434
+ }
435
+ catch { /* hosting is optional; PNG/data-URL still work */ }
436
+ }
437
+ }
438
+ try {
439
+ const { cookies } = await cdp.send("Network.getAllCookies");
440
+ const ttCookies = (cookies || []).filter((c) => isTikTokCookie(c.domain));
441
+ const sessionid = ttCookies.find((c) => c.name === "sessionid" && typeof c.value === "string" && c.value.length > 10);
442
+ if (sessionid) {
443
+ const harvested = ttCookies.map(normalizeCookie);
444
+ // Infer the account's country from the real browser env so the
445
+ // operator/agent never has to supply --country. Best-effort: if the
446
+ // eval fails, the caller falls back to its own default.
447
+ let detectedLocale;
448
+ let detectedTimezone;
449
+ try {
450
+ const ev = await cdp.send("Runtime.evaluate", {
451
+ expression: "JSON.stringify({l:navigator.language,t:Intl.DateTimeFormat().resolvedOptions().timeZone})",
452
+ returnByValue: true,
453
+ });
454
+ const v = ev?.result?.value;
455
+ if (typeof v === "string") {
456
+ const parsed = JSON.parse(v);
457
+ detectedLocale = typeof parsed.l === "string" ? parsed.l : undefined;
458
+ detectedTimezone = typeof parsed.t === "string" ? parsed.t : undefined;
459
+ }
460
+ }
461
+ catch {
462
+ /* detection is best-effort */
463
+ }
464
+ result = {
465
+ success: true,
466
+ cookies: harvested,
467
+ cookiesCaptured: harvested.length,
468
+ sessionidPresent: true,
469
+ browser: browser.name,
470
+ detectedLocale,
471
+ detectedTimezone,
472
+ detectedCountry: countryFromBrowser(detectedLocale, detectedTimezone),
473
+ };
474
+ progress(`captured ${harvested.length} cookies (sessionid present)` +
475
+ (result.detectedCountry ? `; detected country: ${result.detectedCountry}.` : "."));
476
+ break;
477
+ }
478
+ }
479
+ catch {
480
+ // Transient — socket may have closed mid-poll; loop re-attaches.
481
+ cdp = null;
482
+ }
483
+ }
484
+ await sleep(2000);
485
+ }
486
+ // Carry the QR artifacts onto whatever we return (incl. timeout) so the
487
+ // caller always has the QR that was generated.
488
+ if (qrPngPath && !result.qrPngPath)
489
+ result.qrPngPath = qrPngPath;
490
+ if (qrDataUrl && !result.qrDataUrl)
491
+ result.qrDataUrl = qrDataUrl;
492
+ }
493
+ finally {
494
+ if (cdp)
495
+ cdp.close();
496
+ if (!childExited) {
497
+ try {
498
+ child.kill();
499
+ }
500
+ catch {
501
+ /* noop */
502
+ }
503
+ }
504
+ cleanupDir(userDataDir);
505
+ }
506
+ return result;
507
+ }
508
+ function cleanupDir(dir) {
509
+ // Chrome may briefly hold a lock on the profile dir after kill; a failed
510
+ // cleanup is harmless (OS temp reclaims it), so swallow errors.
511
+ try {
512
+ rmSync(dir, { recursive: true, force: true });
513
+ }
514
+ catch {
515
+ /* noop */
516
+ }
517
+ }
518
+ //# sourceMappingURL=tiktok-connect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiktok-connect.js","sourceRoot":"","sources":["../tiktok-connect.ts"],"names":[],"mappings":"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"}
@@ -125,19 +125,24 @@ export function evaluateTriggers(p) {
125
125
  proposedAction: 'sell-100',
126
126
  autoExecuted: false,
127
127
  };
128
+ // Without auto-execute the position stays 'open', so a threshold that's met
129
+ // keeps re-firing every tick — spamming pending.jsonl + the trade log. Gate
130
+ // each trigger on a fire-once watermark (mirrors lastThesisFiredAt below).
131
+ const fired = p.monitorState?.firedTriggers ?? {};
128
132
  const cutThreshold = parsePctString(p.exitPlan.cut);
129
- if (cutThreshold !== null && currentPct <= cutThreshold) {
133
+ if (cutThreshold !== null && currentPct <= cutThreshold && !fired.cut) {
130
134
  out.push({ ...base, trigger: 'cut', thresholdPct: cutThreshold });
131
135
  }
132
136
  const tpThreshold = parsePctString(p.exitPlan.takeProfit);
133
- if (tpThreshold !== null && currentPct >= tpThreshold) {
137
+ if (tpThreshold !== null && currentPct >= tpThreshold && !fired.takeProfit) {
134
138
  out.push({ ...base, trigger: 'takeProfit', thresholdPct: tpThreshold });
135
139
  }
136
140
  const trailPct = parsePctString(p.exitPlan.trailingStop);
137
141
  if (trailPct !== null &&
138
142
  p.monitorState &&
139
143
  p.monitorState.peakUnrealizedPct > 0 &&
140
- p.monitorState.peakUnrealizedPct - currentPct >= trailPct) {
144
+ p.monitorState.peakUnrealizedPct - currentPct >= trailPct &&
145
+ !fired.trailingStop) {
141
146
  const peak = p.monitorState.peakUnrealizedPct;
142
147
  out.push({
143
148
  ...base,
@@ -150,7 +155,7 @@ export function evaluateTriggers(p) {
150
155
  const limitMs = parseDurationToMs(p.exitPlan.timeLimit);
151
156
  if (limitMs !== null) {
152
157
  const elapsedMs = Date.now() - new Date(p.entry.time).getTime();
153
- if (elapsedMs >= limitMs) {
158
+ if (elapsedMs >= limitMs && !fired.timeLimit) {
154
159
  out.push({
155
160
  ...base,
156
161
  trigger: 'timeLimit',
@@ -372,6 +377,17 @@ async function processPositionFires(p, opts) {
372
377
  p.monitorState.lastThesisFiredAt = fire.ts;
373
378
  writePosition(p);
374
379
  }
380
+ else if (fire.trigger === 'cut' || fire.trigger === 'takeProfit' ||
381
+ fire.trigger === 'trailingStop' || fire.trigger === 'timeLimit') {
382
+ // Stamp the watermark so this trigger doesn't re-append every tick when
383
+ // auto-execute is off (auto-exec closes the position, making this a no-op).
384
+ if (!p.monitorState)
385
+ p.monitorState = { peakUnrealizedPct: p.pnl.unrealizedPct, peakAt: fire.ts };
386
+ if (!p.monitorState.firedTriggers)
387
+ p.monitorState.firedTriggers = {};
388
+ p.monitorState.firedTriggers[fire.trigger] = fire.ts;
389
+ writePosition(p);
390
+ }
375
391
  out.push(fire);
376
392
  }
377
393
  return out;