dsh-foxy-weibo 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/README.md CHANGED
@@ -66,7 +66,7 @@ Cookie 只保存在本机 `~/.dsh/foxy-weibo/settings.json`,不会回传给前
66
66
  1. 扫码登录,填自己的微博 UID,`enabled: true`、`replyMode: off`;
67
67
  2. 设置每日检查时间,或先点「立即运行」,看日志和「调试」里的模型决策;
68
68
  3. 确认判断正常后,再开启 `replyMode: auto`,每日上限先设为 1;
69
- 4. 旧模式需要浏览他人博文时,再关闭「主模式」并配置关注 UID;
69
+ 4. 「立即检查」只判断不发布,用来预览回复;「立即回复」会真实发布一条,适合测试;
70
70
  5. 微博评论有账号风控,不要高频、不要对陌生人全自动回复。
71
71
 
72
72
  ## 记忆事件
package/lib/client.js CHANGED
@@ -227,6 +227,40 @@ window.__ModuleLoader__.load({
227
227
  } catch (e) { setError(e.message) } finally { setBusy('') }
228
228
  }
229
229
 
230
+ const checkNow = async () => {
231
+ setBusy('check'); setError(''); setNotice('')
232
+ try {
233
+ const data = await request('/check-now', { method: 'POST', body: '{}' })
234
+ setStatus(data.status)
235
+ const result = data.result || {}
236
+ setNotice(
237
+ result.skipped === 'no-self'
238
+ ? '未开始:请先扫码登录或填写自己的微博 UID'
239
+ : result.skipped === 'busy'
240
+ ? '正在运行,请稍候'
241
+ : `检查完成:检查 ${result.checked || 0} 条评论,预览 ${result.previewed || 0} 条,跳过 ${result.skipped || 0} 条` +
242
+ (result.errors ? `,失败 ${result.errors} 条` : ''),
243
+ )
244
+ } catch (e) { setError(e.message) } finally { setBusy('') }
245
+ }
246
+
247
+ const replyNow = async () => {
248
+ if (!window.confirm('立即回复会真实发布到微博,确定继续?')) return
249
+ setBusy('reply'); setError(''); setNotice('')
250
+ try {
251
+ const data = await request('/reply-now', { method: 'POST', body: '{}' })
252
+ setStatus(data.status)
253
+ const result = data.result || {}
254
+ setNotice(
255
+ result.replied > 0
256
+ ? `已立即回复 ${result.replied} 条,可在下方日志查看`
257
+ : result.skipped === 'no-self'
258
+ ? '未开始:请先扫码登录或填写自己的微博 UID'
259
+ : '没有可立即回复的评论(可能已处理或模型选择跳过)',
260
+ )
261
+ } catch (e) { setError(e.message) } finally { setBusy('') }
262
+ }
263
+
230
264
  if (!settings) return h('div', { className: 'fw-page' }, h('p', { className: 'fw-muted' }, error || '正在读取微博设置…'))
231
265
 
232
266
  const recent = Array.isArray(status?.recent) ? status.recent : []
@@ -311,6 +345,8 @@ window.__ModuleLoader__.load({
311
345
  h(Toggle, { checked: settings.debug, onChange: (v) => setField('debug', v), label: '记录调试日志', hint: '保存模型输出与记忆写入结果,便于排查。' }),
312
346
  h('div', { className: 'fw-actions' },
313
347
  h('button', { className: 'fw-btn primary', disabled: !!busy, onClick: runNow }, busy === 'run' ? '正在运行…' : '立即运行'),
348
+ h('button', { className: 'fw-btn', disabled: !!busy, onClick: checkNow }, busy === 'check' ? '检查中…' : '立即检查'),
349
+ h('button', { className: 'fw-btn', disabled: !!busy, onClick: replyNow }, busy === 'reply' ? '回复中…' : '立即回复'),
314
350
  h('button', { className: 'fw-btn', disabled: !!busy, onClick: save }, busy === 'save' ? '保存中…' : '保存设置'),
315
351
  ),
316
352
  h('div', { className: 'fw-stats' },
package/lib/index.js CHANGED
@@ -11,6 +11,8 @@ export const inject = ['connection']
11
11
  export const STATUS_ROUTE = '/api/dsh-foxy-weibo/status'
12
12
  export const SETTINGS_ROUTE = '/api/dsh-foxy-weibo/settings'
13
13
  export const RUN_ROUTE = '/api/dsh-foxy-weibo/run'
14
+ export const CHECK_NOW_ROUTE = '/api/dsh-foxy-weibo/check-now'
15
+ export const REPLY_NOW_ROUTE = '/api/dsh-foxy-weibo/reply-now'
14
16
  export const LOGIN_START_ROUTE = '/api/dsh-foxy-weibo/login/start'
15
17
  export const LOGIN_POLL_ROUTE = '/api/dsh-foxy-weibo/login/poll'
16
18
  export const LOGOUT_ROUTE = '/api/dsh-foxy-weibo/logout'
@@ -156,15 +158,19 @@ async function rememberReply(ctx, config, state, post, comment, replyText) {
156
158
  }
157
159
  }
158
160
 
159
- async function scanOwnComments(ctx, config, state, log, force = false) {
161
+ async function scanOwnComments(ctx, config, state, log, force = false, options = {}) {
160
162
  if (!config.enabled && !force) return { skipped: 'disabled' }
161
- const canReply = config.replyMode === 'auto'
163
+ const previewOnly = options.previewOnly === true
164
+ const forceReply = options.forceReply === true
165
+ const canReply = !previewOnly && (forceReply || config.replyMode === 'auto')
166
+ const targetCid = String(options.cid || '').trim()
162
167
  const selfUid = String(config.selfUid || config.accountUid || '').trim()
163
168
  if (!selfUid) return { skipped: 'no-self' }
164
169
  const maxPosts = Math.max(1, Math.min(20, Number(config.maxPostsPerRun) || 5))
165
- const maxReplies = Math.max(1, Math.min(8, Number(config.maxCommentsPerDay) || 1))
170
+ const maxReplies = Math.max(1, Math.min(8, Number(options.maxReplies ?? config.maxCommentsPerDay) || 1))
171
+ const ignoreQuota = forceReply
166
172
  const result = {
167
- mode: 'own-comments',
173
+ mode: options.mode || 'own-comments',
168
174
  checked: 0,
169
175
  replied: 0,
170
176
  previewed: 0,
@@ -190,6 +196,7 @@ async function scanOwnComments(ctx, config, state, log, force = false) {
190
196
  continue
191
197
  }
192
198
  for (const comment of comments) {
199
+ if (targetCid && String(comment.cid) !== targetCid) continue
193
200
  if (canReply && result.replied >= maxReplies) break
194
201
  if (!comment.cid || state.commentSeen[comment.cid]) continue
195
202
  if (String(comment.author?.uid || '') === selfUid) {
@@ -197,7 +204,7 @@ async function scanOwnComments(ctx, config, state, log, force = false) {
197
204
  continue
198
205
  }
199
206
  const limit = Math.max(0, Number(config.maxCommentsPerDay) || 0)
200
- if (canReply && commentCount(state) >= limit) break
207
+ if (canReply && !ignoreQuota && commentCount(state) >= limit) break
201
208
  result.checked += 1
202
209
  let entry
203
210
  try {
@@ -474,6 +481,50 @@ export function apply(ctx, rawConfig = {}) {
474
481
  }
475
482
  }
476
483
 
484
+ const checkNow = async () => {
485
+ if (running) return { skipped: 'busy' }
486
+ running = true
487
+ try {
488
+ log('[foxy-weibo] 开始立即检查')
489
+ const result = await scanOwnComments(ctx, config, state, log, true, {
490
+ previewOnly: true,
491
+ mode: 'own-comments-check',
492
+ })
493
+ saveState(state)
494
+ log(`[foxy-weibo] 立即检查结束 ${JSON.stringify(result)}`)
495
+ return result
496
+ } catch (error) {
497
+ saveState(state)
498
+ ctx.logger?.warn?.(`[foxy-weibo] check failed: ${error?.message || error}`)
499
+ return { error: String(error?.message || error) }
500
+ } finally {
501
+ running = false
502
+ }
503
+ }
504
+
505
+ const replyNow = async (cid = '') => {
506
+ if (running) return { skipped: 'busy' }
507
+ running = true
508
+ try {
509
+ log(`[foxy-weibo] 开始立即回复${cid ? ` cid=${cid}` : ''}`)
510
+ const result = await scanOwnComments(ctx, config, state, log, true, {
511
+ forceReply: true,
512
+ maxReplies: 1,
513
+ cid,
514
+ mode: 'own-comments-reply-now',
515
+ })
516
+ saveState(state)
517
+ log(`[foxy-weibo] 立即回复结束 ${JSON.stringify(result)}`)
518
+ return result
519
+ } catch (error) {
520
+ saveState(state)
521
+ ctx.logger?.warn?.(`[foxy-weibo] reply-now failed: ${error?.message || error}`)
522
+ return { error: String(error?.message || error) }
523
+ } finally {
524
+ running = false
525
+ }
526
+ }
527
+
477
528
  const status = () => ({
478
529
  enabled: config.enabled === true,
479
530
  running,
@@ -598,6 +649,17 @@ export function apply(ctx, rawConfig = {}) {
598
649
  const result = await run('manual', true)
599
650
  return json({ ok: true, result, status: status() })
600
651
  })
652
+
653
+ route(CHECK_NOW_ROUTE, ['POST'], async () => {
654
+ const result = await checkNow()
655
+ return json({ ok: true, result, status: status() })
656
+ })
657
+
658
+ route(REPLY_NOW_ROUTE, ['POST'], async (request) => {
659
+ const body = await readJsonBody(request)
660
+ const result = await replyNow(body?.cid)
661
+ return json({ ok: true, result, status: status() })
662
+ })
601
663
  })
602
664
 
603
665
  log(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-foxy-weibo",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Foxy's Weibo transport for DeepSeek Harness: follow users, read posts, comment, reply, and remember events.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",