dsh-line-bot 0.5.5 → 0.5.6

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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.6
4
+
5
+ - 安裝 CLI 會偵測搭配外掛(`dsh-persona-dafeiyu`、`dsh-meme`、`dsh-tieba-dive`),可互動詢問或 `--with-companions` 一起安裝;`status` 也會顯示安裝狀態。
6
+ - README(五語言)新增「搭配外掛」章節。
7
+
3
8
  ## 0.5.5
4
9
 
5
10
  - 收到 LINE 貼圖時抓取貼圖圖片,透過 DSH 附件服務交給模型閱讀(模型不支援圖片時自動退回貼圖關鍵字)。
package/README.en.md CHANGED
@@ -56,6 +56,25 @@ Then add `dsh-line-bot` to the `dsh.profile.bundles` array in `~/.dsh/profiles/d
56
56
  >
57
57
  > Or from source: `git clone https://github.com/Hanson0901/dsh-line-bot.git`, then choose that folder in the DSH panel's "Install bundle", or run `dsh plugin --profile desktop add /path/to/dsh-line-bot`.
58
58
 
59
+ ## Companion plugins (optional)
60
+
61
+ The bot works on its own; these plugins add capabilities:
62
+
63
+ | Plugin | What it adds | Recommended |
64
+ | --- | --- | --- |
65
+ | `dsh-persona-dafeiyu` | Persona catalog and Tieba sync | Yes |
66
+ | `dsh-meme` | Image/sticker replies | Yes |
67
+ | `dsh-tieba-dive` | Source of Tieba learning sync | Optional |
68
+
69
+ The install CLI detects what is missing and offers to install it:
70
+
71
+ ```bash
72
+ npx dsh-line-bot install --with-companions
73
+ npx dsh-line-bot install --no-companions
74
+ ```
75
+
76
+ Without them: no dafeiyu means only plugin-local personas; no dsh-meme means text-only replies; no dsh-tieba-dive means Tieba sync stays off.
77
+
59
78
  ## First run (5 steps)
60
79
 
61
80
  1. **Create / obtain credentials**: go to [LINE Official Account Manager](https://manager.line.biz/) and create an Official Account → [LINE Developers Console](https://developers.line.biz/console/) and create (or pick) a Messaging API channel → open the **Use webhook** toggle on the "Messaging API" tab → copy the **Channel ID** and **Channel secret**.
package/README.ja.md CHANGED
@@ -56,6 +56,25 @@ dsh plugin --profile desktop add dsh-line-bot
56
56
  >
57
57
  > ソースからなら:`git clone https://github.com/Hanson0901/dsh-line-bot.git` して、DSH パネルの「bundle をインストール」でそのフォルダを選ぶか、`dsh plugin --profile desktop add /path/to/dsh-line-bot` を実行します。
58
58
 
59
+ ## 連携プラグイン(任意)
60
+
61
+ LINE Bot は単体でも動きます。以下を入れると機能が増えます:
62
+
63
+ | プラグイン | 追加される機能 | 推奨 |
64
+ | --- | --- | --- |
65
+ | `dsh-persona-dafeiyu` | ペルソナ一覧と貼吧同期 | 推奨 |
66
+ | `dsh-meme` | 画像/スタンプ返信 | 推奨 |
67
+ | `dsh-tieba-dive` | 貼吧学習同期の取得元 | 任意 |
68
+
69
+ インストール CLI は不足を検出して、一緒に入れるか確認します:
70
+
71
+ ```bash
72
+ npx dsh-line-bot install --with-companions
73
+ npx dsh-line-bot install --no-companions
74
+ ```
75
+
76
+ ない場合の影響:大肥魚なし → プラグイン内のペルソナのみ、dsh-meme なし → テキストのみ、貼吧プラグインなし → 貼吧同期は停止。
77
+
59
78
  ## 初回セットアップ(5 ステップ)
60
79
 
61
80
  1. **認証情報を用意**:[LINE Official Account Manager](https://manager.line.biz/) で公式アカウントを作成 → [LINE Developers Console](https://developers.line.biz/console/) で Messaging API チャネルを作成(または選択)→ 「Messaging API」タブで **Use webhook** をオン → **Channel ID** と **Channel secret** をコピーします。
package/README.ko.md CHANGED
@@ -56,6 +56,25 @@ dsh plugin --profile desktop add dsh-line-bot
56
56
  >
57
57
  > 소스에서 설치하려면 `git clone https://github.com/Hanson0901/dsh-line-bot.git` 후 DSH 패널의 "bundle 설치"에서 그 폴더를 선택하거나 `dsh plugin --profile desktop add /path/to/dsh-line-bot`을 실행합니다.
58
58
 
59
+ ## 함께 쓰는 플러그인 (선택)
60
+
61
+ LINE Bot은 단독으로도 동작하며, 아래 플러그인을 설치하면 기능이 늘어납니다:
62
+
63
+ | 플러그인 | 추가 기능 | 권장 |
64
+ | --- | --- | --- |
65
+ | `dsh-persona-dafeiyu` | 페르소나 목록, 톄바 동기화 | 권장 |
66
+ | `dsh-meme` | 이미지/스티커 답장 | 권장 |
67
+ | `dsh-tieba-dive` | 톄바 학습 동기화 소스 | 선택 |
68
+
69
+ 설치 CLI는 없는 것을 감지해 함께 설치할지 물어봅니다:
70
+
71
+ ```bash
72
+ npx dsh-line-bot install --with-companions
73
+ npx dsh-line-bot install --no-companions
74
+ ```
75
+
76
+ 없을 때: 대비어 없음 → 플러그인 자체 페르소나만, dsh-meme 없음 → 텍스트만, 톄바 플러그인 없음 → 톄바 동기화 꺼짐.
77
+
59
78
  ## 첫 구동(5단계)
60
79
 
61
80
  1. **자격 증명 준비**: [LINE Official Account Manager](https://manager.line.biz/)에서 공식 계정 생성 → [LINE Developers Console](https://developers.line.biz/console/)에서 Messaging API 채널 생성(또는 선택) → "Messaging API" 탭에서 **Use webhook** 켜기 → **Channel ID**와 **Channel secret** 복사.
package/README.md CHANGED
@@ -56,6 +56,25 @@ dsh plugin --profile desktop add dsh-line-bot
56
56
  >
57
57
  > 或從原始碼:`git clone https://github.com/Hanson0901/dsh-line-bot.git`,在 DSH 面板「安裝 bundle」選那個資料夾,或 `dsh plugin --profile desktop add /path/to/dsh-line-bot`。
58
58
 
59
+ ## 搭配外掛(可選)
60
+
61
+ LINE Bot 可以獨立運作;裝了下面這些外掛會多出對應功能:
62
+
63
+ | 外掛 | 用途 | 建議 |
64
+ | --- | --- | --- |
65
+ | `dsh-persona-dafeiyu` | 人設清單、貼吧同步 | 建議 |
66
+ | `dsh-meme` | 讓角色回圖片/貼圖 | 建議 |
67
+ | `dsh-tieba-dive` | 貼吧學習同步的來源 | 可選 |
68
+
69
+ 安裝時 CLI 會偵測缺哪些,並詢問要不要一起安裝:
70
+
71
+ ```bash
72
+ npx dsh-line-bot install --with-companions
73
+ npx dsh-line-bot install --no-companions
74
+ ```
75
+
76
+ 少了它們的影響:沒有大肥魚 → 人設只剩插件自訂的;沒有 dsh-meme → 只能回文字;沒有刷貼吧 → 貼吧同步自動停用。
77
+
59
78
  ## 第一次上線(5 步)
60
79
 
61
80
  1. **建立/取得憑證**:到 [LINE Official Account Manager](https://manager.line.biz/) 建立官方帳號 → [LINE Developers Console](https://developers.line.biz/console/) 建立(或選用)Messaging API channel → 在「Messaging API」分頁把 **Use webhook** 打開 → 複製 **Channel ID** 與 **Channel secret**。
package/README.zh-CN.md CHANGED
@@ -56,6 +56,25 @@ dsh plugin --profile desktop add dsh-line-bot
56
56
  >
57
57
  > 或从源码:`git clone https://github.com/Hanson0901/dsh-line-bot.git`,在 DSH 面板「安装 bundle」选那个文件夹,或 `dsh plugin --profile desktop add /path/to/dsh-line-bot`。
58
58
 
59
+ ## 搭配插件(可选)
60
+
61
+ LINE Bot 可以独立运行;装上下面这些插件会多出对应功能:
62
+
63
+ | 插件 | 用途 | 建议 |
64
+ | --- | --- | --- |
65
+ | `dsh-persona-dafeiyu` | 人设清单、贴吧同步 | 建议 |
66
+ | `dsh-meme` | 让角色回图片/贴图 | 建议 |
67
+ | `dsh-tieba-dive` | 贴吧学习同步的来源 | 可选 |
68
+
69
+ 安装时 CLI 会检测缺哪些,并询问要不要一起安装:
70
+
71
+ ```bash
72
+ npx dsh-line-bot install --with-companions
73
+ npx dsh-line-bot install --no-companions
74
+ ```
75
+
76
+ 少了它们的影响:没有大肥鱼 → 人设只剩插件自定义的;没有 dsh-meme → 只能回文字;没有刷贴吧 → 贴吧同步自动停用。
77
+
59
78
  ## 第一次上线(5 步)
60
79
 
61
80
  1. **创建/取得凭证**:到 [LINE Official Account Manager](https://manager.line.biz/) 创建官方账号 → [LINE Developers Console](https://developers.line.biz/console/) 创建(或选用)Messaging API channel → 在「Messaging API」分页把 **Use webhook** 打开 → 复制 **Channel ID** 与 **Channel secret**。
package/bin/cli.mjs CHANGED
@@ -16,6 +16,7 @@ import fs from 'node:fs'
16
16
  import os from 'node:os'
17
17
  import path from 'node:path'
18
18
  import { spawnSync } from 'node:child_process'
19
+ import readline from 'node:readline/promises'
19
20
 
20
21
  const IS_WIN = process.platform === 'win32'
21
22
  import { fileURLToPath } from 'node:url'
@@ -23,6 +24,13 @@ import { fileURLToPath } from 'node:url'
23
24
  const PKG = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
24
25
  const NAME = PKG.name || 'dsh-line-bot'
25
26
 
27
+ // 搭配的外掛:不裝也能用,但少掉某些功能。安裝時會偵測並詢問是否一起裝。
28
+ const COMPANIONS = [
29
+ { name: 'dsh-persona-dafeiyu', label: '大肥魚人設', hint: '人設清單、貼吧同步(建議)' },
30
+ { name: 'dsh-meme', label: '表情包圖庫', hint: '讓角色回圖片/貼圖(建議)' },
31
+ { name: 'dsh-tieba-dive', label: '刷貼吧', hint: '貼吧學習同步的來源(可選)' },
32
+ ]
33
+
26
34
  function out(line = '') {
27
35
  process.stdout.write(`${line}\n`)
28
36
  }
@@ -32,7 +40,7 @@ function fail(message) {
32
40
  }
33
41
 
34
42
  function parseArgs(argv) {
35
- const options = { command: '', profile: '', version: '', spec: '', dryRun: false, enable: true }
43
+ const options = { command: '', profile: '', version: '', spec: '', dryRun: false, enable: true, companions: 'ask' }
36
44
  const rest = [...argv]
37
45
  options.command = (rest.shift() || 'help').toLowerCase()
38
46
  for (let index = 0; index < rest.length; index += 1) {
@@ -56,6 +64,10 @@ function parseArgs(argv) {
56
64
  options.spec = arg.slice('--spec='.length)
57
65
  } else if (arg === '--no-enable') {
58
66
  options.enable = false
67
+ } else if (arg === '--with-companions') {
68
+ options.companions = 'yes'
69
+ } else if (arg === '--no-companions') {
70
+ options.companions = 'no'
59
71
  } else if (arg === '--help' || arg === '-h') {
60
72
  options.command = 'help'
61
73
  } else {
@@ -125,12 +137,12 @@ function bundlesOf(manifest) {
125
137
  return Array.isArray(bundles) ? [...bundles] : []
126
138
  }
127
139
 
128
- function withBundle(manifest, enabled) {
140
+ function withBundle(manifest, enabled, name = NAME) {
129
141
  const bundles = bundlesOf(manifest)
130
142
  if (enabled) {
131
- if (!bundles.includes(NAME)) bundles.push(NAME)
143
+ if (!bundles.includes(name)) bundles.push(name)
132
144
  } else {
133
- const index = bundles.indexOf(NAME)
145
+ const index = bundles.indexOf(name)
134
146
  if (index >= 0) bundles.splice(index, 1)
135
147
  }
136
148
  return {
@@ -218,7 +230,66 @@ function runInstall(profile, versionSpec, { dryRun }) {
218
230
  }
219
231
  }
220
232
 
221
- function commandInstall(options) {
233
+ function companionMissing(profile, dir, manifest, name) {
234
+ const deps = { ...(manifest.dependencies || {}), ...(manifest.devDependencies || {}) }
235
+ if (deps[name]) return false
236
+ if (bundlesOf(manifest).includes(name)) return false
237
+ return !fs.existsSync(path.join(dir, 'node_modules', name, 'package.json'))
238
+ }
239
+
240
+ async function askYesNo(question) {
241
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
242
+ try {
243
+ const answer = (await rl.question(question)).trim().toLowerCase()
244
+ return answer === '' || answer === 'y' || answer === 'yes' || answer === '是'
245
+ } finally {
246
+ rl.close()
247
+ }
248
+ }
249
+
250
+ function installCompanion(profile, name, options) {
251
+ runInstall(profile, `${name}@latest`, options)
252
+ if (options.dryRun) return
253
+ const { file } = readManifest(profile)
254
+ const current = readManifest(profile).manifest
255
+ const next = withBundle(current, true, name)
256
+ if (JSON.stringify(next) !== JSON.stringify(current)) {
257
+ writeManifestAtomic(file, next)
258
+ out(`✔ 已啟用 ${name}`)
259
+ }
260
+ }
261
+
262
+ async function setupCompanions(profile, options) {
263
+ const { dir, manifest } = readManifest(profile)
264
+ const missing = COMPANIONS.filter((item) => companionMissing(profile, dir, manifest, item.name))
265
+ if (missing.length === 0) {
266
+ out('• 搭配外掛都已安裝。')
267
+ return
268
+ }
269
+ out('')
270
+ out('搭配外掛(可選,不裝也能用):')
271
+ for (const item of missing) out(` • ${item.name} — ${item.label}:${item.hint}`)
272
+ if (options.dryRun) {
273
+ out(`→ 會詢問是否一起安裝 ${missing.map((item) => item.name).join('、')}`)
274
+ return
275
+ }
276
+ let install = false
277
+ if (options.companions === 'yes') install = true
278
+ else if (options.companions === 'no') install = false
279
+ else if (process.stdin.isTTY) install = await askYesNo('要一起安裝嗎?(Y/n) ')
280
+ else {
281
+ out('• 目前不是互動終端,略過搭配外掛;可加 --with-companions 一起安裝。')
282
+ return
283
+ }
284
+ if (!install) {
285
+ out('• 略過搭配外掛。之後可再跑 npx dsh-line-bot install --with-companions。')
286
+ return
287
+ }
288
+ for (const item of missing) installCompanion(profile, item.name, options)
289
+ out('✔ 搭配外掛安裝完成。')
290
+ }
291
+
292
+ async function commandInstall(options) {
222
293
  const profile = pickProfile(options.profile)
223
294
  const { dir, file, manifest } = readManifest(profile)
224
295
  const versionSpec = options.spec || (options.version ? `${NAME}@${options.version}` : `${NAME}@${PKG.version}`)
@@ -245,6 +316,8 @@ function commandInstall(options) {
245
316
  }
246
317
  }
247
318
 
319
+ await setupCompanions(profile, options)
320
+
248
321
  out('')
249
322
  out('完成。下一步:')
250
323
  out(' 1. 完全結束並重開 DeepSeek Harness(桌面版請確認選單列沒有殘留)。')
@@ -295,6 +368,11 @@ function commandStatus(options) {
295
368
  out(`profile:${profile}(${dir})`)
296
369
  out(`依賴:${dependency || '(未安裝)'}`)
297
370
  out(`bundle 啟用:${enabled ? '是' : '否'}`)
371
+ const companions = COMPANIONS.map((item) => {
372
+ const ok = !companionMissing(profile, dir, manifest, item.name)
373
+ return `${item.name}${ok ? '(已安裝)' : '(未安裝)'}`
374
+ })
375
+ out(`搭配外掛:${companions.join('、')}`)
298
376
  if (fs.existsSync(path.join(dshHome(), 'line-bot', 'config.json'))) {
299
377
  out('設定檔:<DSH_HOME>/line-bot/config.json(已存在)')
300
378
  }
@@ -314,6 +392,8 @@ function commandHelp() {
314
392
  out(' --version, -v <版本> 指定要安裝的版本(預設跟這個 CLI 相同)')
315
393
  out(' --spec <pnpm 規格> 直接指定套件規格,例如 github:Hanson0901/dsh-line-bot')
316
394
  out(' --no-enable 只安裝套件,不寫入 bundle 清單')
395
+ out(' --with-companions 一起安裝搭配外掛(dsh-persona-dafeiyu、dsh-meme、dsh-tieba-dive)')
396
+ out(' --no-companions 不詢問搭配外掛')
317
397
  out(' --dry-run, -n 只顯示會做什麼,不寫入')
318
398
  out(' --help, -h 顯示這段說明')
319
399
  out('')
@@ -324,7 +404,7 @@ const options = parseArgs(process.argv.slice(2))
324
404
  switch (options.command) {
325
405
  case 'install':
326
406
  case 'add':
327
- commandInstall(options)
407
+ await commandInstall(options)
328
408
  break
329
409
  case 'uninstall':
330
410
  case 'remove':
package/lib/host.mjs CHANGED
@@ -41,7 +41,7 @@ const { createMemeSource } = memeSourceMod
41
41
  const { createStickerImages } = stickerImageMod
42
42
  const { chunkText, clip, inQuietWindow, jsonFail, jsonOk, maskSecret, readJsonBody, safeArray, sleep } = utilMod
43
43
 
44
- export const VERSION = '0.5.5'
44
+ export const VERSION = '0.5.6'
45
45
 
46
46
  // 環境變數提供的 Cloudflare API Token(方便用 shell 注入、不用把 token 寫進設定檔)。
47
47
  // 設定檔裡的 token 優先;兩者都沒有時才用環境變數。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-line-bot",
3
- "version": "0.5.5",
3
+ "version": "0.5.6",
4
4
  "description": "把 LINE 官方帳號(Messaging API)接進 DeepSeek Harness 的插件:內建 Cloudflare Tunnel、人設選擇(大肥魚或插件自訂)、主動傳訊與完整設定面板。",
5
5
  "type": "module",
6
6
  "main": "index.js",