From 709e026be11685616f6e2ac7e67434e5f8310ee4 Mon Sep 17 00:00:00 2001 From: luojiyin Date: Sun, 8 Mar 2026 20:34:35 +0800 Subject: [PATCH 1/3] fix: use spawnSync for autocorrect command --- .../baoyu-format-markdown/scripts/autocorrect.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/skills/baoyu-format-markdown/scripts/autocorrect.ts b/skills/baoyu-format-markdown/scripts/autocorrect.ts index 9043dab..bb8a629 100644 --- a/skills/baoyu-format-markdown/scripts/autocorrect.ts +++ b/skills/baoyu-format-markdown/scripts/autocorrect.ts @@ -1,10 +1,10 @@ -import { execSync } from "child_process"; +import { spawnSync } from "node:child_process"; +import process from "node:process"; export function applyAutocorrect(filePath: string): boolean { - try { - execSync(`npx autocorrect-node --fix "${filePath}"`, { stdio: "inherit" }); - return true; - } catch { - return false; - } + const npxCmd = process.platform === "win32" ? "npx.cmd" : "npx"; + const result = spawnSync(npxCmd, ["autocorrect-node", "--fix", filePath], { + stdio: "inherit", + }); + return result.status === 0; } From 366e7b5403f4722e7170eb4fed560bcc12c23308 Mon Sep 17 00:00:00 2001 From: luojiyin Date: Sun, 8 Mar 2026 20:34:39 +0800 Subject: [PATCH 2/3] fix: use execFileSync for google curl requests --- .../scripts/providers/google.ts | 43 ++++++++++++++++--- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/skills/baoyu-image-gen/scripts/providers/google.ts b/skills/baoyu-image-gen/scripts/providers/google.ts index 021e58a..a3649f0 100644 --- a/skills/baoyu-image-gen/scripts/providers/google.ts +++ b/skills/baoyu-image-gen/scripts/providers/google.ts @@ -1,6 +1,6 @@ import path from "node:path"; import { readFile } from "node:fs/promises"; -import { execSync } from "node:child_process"; +import { execFileSync } from "node:child_process"; import type { CliArgs } from "../types"; const GOOGLE_MULTIMODAL_MODELS = [ @@ -76,14 +76,43 @@ async function postGoogleJsonViaCurl( ): Promise { const proxy = getHttpProxy(); const bodyStr = JSON.stringify(body); - const proxyArgs = proxy ? `-x "${proxy}"` : ""; + const args = [ + "-s", + "--connect-timeout", + "30", + "--max-time", + "300", + ...(proxy ? ["-x", proxy] : []), + url, + "-H", + "Content-Type: application/json", + "-H", + `x-goog-api-key: ${apiKey}`, + "-d", + "@-", + ]; - const result = execSync( - `curl -s --connect-timeout 30 --max-time 300 ${proxyArgs} "${url}" -H "Content-Type: application/json" -H "x-goog-api-key: ${apiKey}" -d @-`, - { input: bodyStr, maxBuffer: 100 * 1024 * 1024, timeout: 310000 }, - ); + let result = ""; + try { + result = execFileSync("curl", args, { + input: bodyStr, + encoding: "utf8", + maxBuffer: 100 * 1024 * 1024, + timeout: 310000, + }); + } catch (error) { + const e = error as { message?: string; stderr?: string | Buffer }; + const stderrText = + typeof e.stderr === "string" + ? e.stderr + : e.stderr + ? e.stderr.toString("utf8") + : ""; + const details = stderrText.trim() || e.message || "curl request failed"; + throw new Error(`Google API request failed via curl: ${details}`); + } - const parsed = JSON.parse(result.toString()) as any; + const parsed = JSON.parse(result) as any; if (parsed.error) { throw new Error( `Google API error (${parsed.error.code}): ${parsed.error.message}`, From ca9a0a14047bbbd80ac7ff05fbca8ce54b862e74 Mon Sep 17 00:00:00 2001 From: luojiyin Date: Sun, 8 Mar 2026 20:34:43 +0800 Subject: [PATCH 3/3] fix: harden wechat agent-browser command and eval handling --- .../scripts/wechat-agent-browser.ts | 105 +++++++++++------- 1 file changed, 62 insertions(+), 43 deletions(-) diff --git a/skills/baoyu-post-to-wechat/scripts/wechat-agent-browser.ts b/skills/baoyu-post-to-wechat/scripts/wechat-agent-browser.ts index 08aa746..1795647 100644 --- a/skills/baoyu-post-to-wechat/scripts/wechat-agent-browser.ts +++ b/skills/baoyu-post-to-wechat/scripts/wechat-agent-browser.ts @@ -1,4 +1,4 @@ -import { execSync, spawnSync } from 'node:child_process'; +import { spawnSync } from 'node:child_process'; import fs from 'node:fs'; import path from 'node:path'; import process from 'node:process'; @@ -10,30 +10,42 @@ function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } -function ab(cmd: string, json = false): string { - const fullCmd = `agent-browser --session ${SESSION} ${cmd}${json ? ' --json' : ''}`; - console.log(`[ab] ${fullCmd}`); - try { - const result = execSync(fullCmd, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }); - return result.trim(); - } catch (e: unknown) { - const err = e as { stdout?: string; stderr?: string; message?: string }; - console.error(`[ab] Error: ${err.stderr || err.message}`); - return err.stdout || ''; - } +function quoteForLog(arg: string): string { + return /[\s"'\\]/.test(arg) ? JSON.stringify(arg) : arg; } -function abRaw(args: string[]): { success: boolean; output: string } { +function toSafeJsStringLiteral(value: string): string { + return JSON.stringify(value) + .replace(/\u2028/g, '\\u2028') + .replace(/\u2029/g, '\\u2029'); +} + +function runAgentBrowser(args: string[]): { success: boolean; output: string } { const result = spawnSync('agent-browser', ['--session', SESSION, ...args], { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }); + const output = result.stdout || result.stderr || ''; return { success: result.status === 0, - output: result.stdout || result.stderr || '' + output }; } +function ab(args: string[], json = false): string { + const fullArgs = json ? [...args, '--json'] : args; + console.log(`[ab] agent-browser --session ${SESSION} ${fullArgs.map(quoteForLog).join(' ')}`); + const result = runAgentBrowser(fullArgs); + if (!result.success) { + console.error(`[ab] Error: ${result.output.trim()}`); + } + return result.output.trim(); +} + +function abRaw(args: string[]): { success: boolean; output: string } { + return runAgentBrowser(args); +} + interface SnapshotElement { ref: string; role: string; @@ -99,17 +111,17 @@ async function postToWeChat(options: WeChatOptions): Promise { } console.log('[wechat] Opening WeChat Official Account...'); - ab(`open ${WECHAT_URL} --headed`); + ab(['open', WECHAT_URL, '--headed']); await sleep(5000); console.log('[wechat] Checking login status...'); - let url = ab('get url'); + let url = ab(['get', 'url']); console.log(`[wechat] Current URL: ${url}`); const waitForLogin = async (timeoutMs = 120_000): Promise => { const start = Date.now(); while (Date.now() - start < timeoutMs) { - url = ab('get url'); + url = ab(['get', 'url']); if (url.includes('/cgi-bin/home')) return true; console.log('[wechat] Waiting for login...'); await sleep(3000); @@ -126,7 +138,7 @@ async function postToWeChat(options: WeChatOptions): Promise { await sleep(2000); console.log('[wechat] Getting page snapshot...'); - let snapshot = ab('snapshot'); + let snapshot = ab(['snapshot']); console.log(snapshot); console.log('[wechat] Looking for "图文" menu...'); @@ -134,16 +146,16 @@ async function postToWeChat(options: WeChatOptions): Promise { if (!tuWenRef) { console.log('[wechat] Using eval to find and click menu...'); - ab(`eval "document.querySelectorAll('.new-creation__menu .new-creation__menu-item')[2].click()"`); + ab(['eval', "document.querySelectorAll('.new-creation__menu .new-creation__menu-item')[2].click()"]); } else { console.log(`[wechat] Clicking menu ref: ${tuWenRef}`); - ab(`click ${tuWenRef}`); + ab(['click', tuWenRef]); } await sleep(4000); console.log('[wechat] Checking for new tab...'); - const tabsOutput = ab('tab'); + const tabsOutput = ab(['tab']); console.log(`[wechat] Tabs: ${tabsOutput}`); const tabLines = tabsOutput.split('\n'); @@ -153,14 +165,14 @@ async function postToWeChat(options: WeChatOptions): Promise { const tabMatch = tabsOutput.match(/\[(\d+)\].*(?:appmsg|edit)/i); if (tabMatch) { console.log(`[wechat] Switching to editor tab ${tabMatch[1]}...`); - ab(`tab ${tabMatch[1]}`); + ab(['tab', tabMatch[1]]); } else { const lastTabMatch = tabsOutput.match(/\[(\d+)\]/g); if (lastTabMatch && lastTabMatch.length > 1) { const lastTab = lastTabMatch[lastTabMatch.length - 1].match(/\d+/)?.[0]; if (lastTab) { console.log(`[wechat] Switching to last tab ${lastTab}...`); - ab(`tab ${lastTab}`); + ab(['tab', lastTab]); } } } @@ -168,38 +180,44 @@ async function postToWeChat(options: WeChatOptions): Promise { await sleep(3000); - url = ab('get url'); + url = ab(['get', 'url']); console.log(`[wechat] Editor URL: ${url}`); console.log('[wechat] Getting editor snapshot...'); - snapshot = ab('snapshot'); + snapshot = ab(['snapshot']); console.log(snapshot.substring(0, 2000)); console.log('[wechat] Uploading images...'); const fileInputSelector = '.js_upload_btn_container input[type=file]'; + const fileInputSelectorJs = toSafeJsStringLiteral(fileInputSelector); - ab(`eval "document.querySelector('${fileInputSelector}').style.display = 'block'"`); + ab(['eval', `{ + const input = document.querySelector(${fileInputSelectorJs}); + if (input) input.style.display = 'block'; + }`]); await sleep(500); - const uploadResult = abRaw(['upload', `"${fileInputSelector}"`, ...absoluteImages]); + const uploadResult = abRaw(['upload', fileInputSelector, ...absoluteImages]); console.log(`[wechat] Upload result: ${uploadResult.output}`); if (!uploadResult.success) { console.log('[wechat] Using alternative upload method...'); for (const img of absoluteImages) { console.log(`[wechat] Uploading: ${img}`); - ab(`eval " - const input = document.querySelector('${fileInputSelector}'); + const imgUrlJs = toSafeJsStringLiteral(`file://${img}`); + const imgFileNameJs = toSafeJsStringLiteral(path.basename(img)); + ab(['eval', ` + const input = document.querySelector(${fileInputSelectorJs}); if (input) { const dt = new DataTransfer(); - fetch('file://${img}').then(r => r.blob()).then(b => { - const file = new File([b], '${path.basename(img)}', { type: 'image/png' }); + fetch(${imgUrlJs}).then(r => r.blob()).then(b => { + const file = new File([b], ${imgFileNameJs}, { type: 'image/png' }); dt.items.add(file); input.files = dt.files; input.dispatchEvent(new Event('change', { bubbles: true })); }); } - "`); + `]); await sleep(2000); } } @@ -208,13 +226,14 @@ async function postToWeChat(options: WeChatOptions): Promise { await sleep(10000); console.log('[wechat] Filling title...'); - snapshot = ab('snapshot -i'); + snapshot = ab(['snapshot', '-i']); const titleRef = findElementByText(snapshot, 'title') || findElementByText(snapshot, '标题'); if (titleRef) { - ab(`fill ${titleRef} "${title.replace(/"/g, '\\"')}"`); + ab(['fill', titleRef, title]); } else { - ab(`eval "const t = document.querySelector('#title'); if(t) { t.value = '${title.replace(/'/g, "\\'")}'; t.dispatchEvent(new Event('input', {bubbles: true})); }"`); + const titleJs = toSafeJsStringLiteral(title); + ab(['eval', `const t = document.querySelector('#title'); if(t) { t.value = ${titleJs}; t.dispatchEvent(new Event('input', {bubbles: true})); }`]); } await sleep(500); @@ -222,9 +241,9 @@ async function postToWeChat(options: WeChatOptions): Promise { const editorRef = findElementByText(snapshot, 'js_pmEditorArea') || findElementByText(snapshot, 'textbox'); if (editorRef) { - ab(`click ${editorRef}`); + ab(['click', editorRef]); } else { - ab(`eval "document.querySelector('.js_pmEditorArea')?.click()"`); + ab(['eval', "document.querySelector('.js_pmEditorArea')?.click()"]); } await sleep(500); @@ -233,11 +252,11 @@ async function postToWeChat(options: WeChatOptions): Promise { for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (line.length > 0) { - const escapedLine = line.replace(/"/g, '\\"').replace(/'/g, "\\'"); - ab(`eval "document.execCommand('insertText', false, '${escapedLine}')"`); + const lineJs = toSafeJsStringLiteral(line); + ab(['eval', `document.execCommand('insertText', false, ${lineJs})`]); } if (i < lines.length - 1) { - ab('press Enter'); + ab(['press', 'Enter']); } await sleep(100); } @@ -249,9 +268,9 @@ async function postToWeChat(options: WeChatOptions): Promise { console.log('[wechat] Saving as draft...'); const submitRef = findElementByText(snapshot, 'js_submit') || findElementByText(snapshot, '保存'); if (submitRef) { - ab(`click ${submitRef}`); + ab(['click', submitRef]); } else { - ab(`eval "document.querySelector('#js_submit')?.click()"`); + ab(['eval', "document.querySelector('#js_submit')?.click()"]); } await sleep(3000); console.log('[wechat] Draft saved!'); @@ -261,7 +280,7 @@ async function postToWeChat(options: WeChatOptions): Promise { if (!keepOpen) { console.log('[wechat] Closing browser...'); - ab('close'); + ab(['close']); } else { console.log('[wechat] Done. Browser window left open.'); }