lark-relay 0.6.2 → 0.6.3

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
@@ -23,8 +23,10 @@ lark-relay take --app <app> --chats oc_xxx --render text
23
23
  lark-relay status
24
24
  ```
25
25
 
26
- 采集在启动时读取 `lark-cli profile list`,跳过排除项以及未授权/授权过期的 profile
27
- 新增 profile 或重新授权后需重启采集,每个 app 的 consumer 独立退避重连
26
+ 采集在启动时读取 `lark-cli profile list`,每个未被 `--exclude` 排除的 profile 启动一个 bot consumer
27
+ user 未登录或授权过期不影响 bot 采集,bot 凭据和权限由 `lark-cli event consume --as bot` 检查
28
+ 认证或连接失败会记录 CLI 错误并独立退避重试,无需采集的 profile 用 `--exclude` 排除
29
+ 新增或移除 profile 后需重启采集
28
30
  同一 app 的事件总线只允许一个实例,本地互斥锁按 `LARK_RELAY_HOME` 隔离
29
31
 
30
32
  ## 取批规则
@@ -79,6 +81,7 @@ lark-relay status
79
81
  日志直写 stderr,每行带 ISO 时间戳,不做轮转
80
82
  需要缩减日志时截断文件,不要删除或替换 launchd 持有的文件
81
83
  `status` 中 collect running 只说明主进程在跑,各 app 是否连接成功需查看采集日志
84
+ `collect.profiles` 列出已配置 profile,不表示正在采集,也不反映 collect 的 `--exclude`
82
85
 
83
86
  ## 许可
84
87
 
package/lib/collect.js CHANGED
@@ -139,37 +139,24 @@ async function runCollect(opts) {
139
139
  return 1
140
140
  }
141
141
 
142
- const chosen = []
143
- const skipped = []
144
- for (const p of profiles) {
145
- if (exclude.has(p.name)) {
146
- skipped.push(`${p.name} [excluded]`)
147
- continue
148
- }
149
- // expired = 授权过期,not-authed = 从未 login。两者都永久失败,重试是死循环。
150
- // 用户重新 login 后下次启动自动纳入。
151
- if (!p.usable) {
152
- skipped.push(`${p.name} [${p.reason}]`)
153
- continue
154
- }
155
- chosen.push(p)
156
- }
142
+ const chosen = profiles.filter((name) => !exclude.has(name))
143
+ const skipped = profiles.filter((name) => exclude.has(name))
157
144
 
158
145
  if (skipped.length) {
159
- logLine(`warn: 跳过 ${skipped.join(' ')}`)
146
+ logLine(`跳过 --exclude: ${skipped.join(' ')}`)
160
147
  }
161
148
  if (!chosen.length) {
162
- logLine('error: 没有可用 profile。先 `lark-cli auth login`')
149
+ logLine('error: 没有待采集的 profile,检查 `lark-cli profile list` 和 --exclude')
163
150
  return 1
164
151
  }
165
152
 
166
153
  logLine(
167
154
  `lark-relay-collect: ${chosen.length}/${profiles.length} profiles → ${paths.store}\n` +
168
- ` ${chosen.map((p) => p.name).join(' ')}\n` +
155
+ ` ${chosen.join(' ')}\n` +
169
156
  ` event_key=${EVENT_KEY} store 保留 ${opts.retain}天`,
170
157
  )
171
158
 
172
- const collectors = chosen.map((p) => new AppCollector(p.name))
159
+ const collectors = chosen.map((name) => new AppCollector(name))
173
160
  for (const c of collectors) c.start()
174
161
 
175
162
  // 只回收超期事件,保留消费者的断点
package/lib/help.js CHANGED
@@ -37,8 +37,9 @@ const COLLECT_HELP = `lark-relay-collect -- 常驻收集 im.message.receive_v1
37
37
  lark-relay-collect
38
38
  lark-relay status
39
39
 
40
- 启动时读取 lark-cli profile list,每个可用 profile 启动一个 consumer
41
- 新增 profile 或重新授权后需重启采集
40
+ 启动时读取 lark-cli profile list,每个未被 --exclude 排除的 profile 启动一个 bot consumer
41
+ 不依赖 user 登录态,bot 凭据和权限由 lark-cli 检查;失败会记录并退避重试
42
+ 新增或移除 profile 后需重启采集
42
43
  每 app 独立退避重连,断线期间的消息无法回放
43
44
  同一 app 只允许一个事件总线实例,接管前先停止现有采集
44
45
 
@@ -64,6 +65,7 @@ const STATUS_HELP = `lark-relay status -- 采集状态、事件数量和消费
64
65
  lark-relay status --json
65
66
 
66
67
  消费者以持锁进程是否存活区分在跑/未运行,未运行的断点仍保留
68
+ profiles 列出已配置项,不表示正在采集,也不反映 collect 的 --exclude
67
69
  collect running 只表示主进程在跑,各 app 的连接状态需查看采集日志`
68
70
 
69
71
  module.exports = { TAKE_HELP, COLLECT_HELP, STATUS_HELP }
package/lib/larkcli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- // 唯一外部依赖:spawn lark-cli。不读 ~/.lark-cli 内部结构 —— profile list 才是公开契约。
3
+ // 唯一外部依赖:spawn lark-cli,通过公开命令读取配置
4
4
  const { spawn, execFile } = require('child_process')
5
5
 
6
6
  const CLI = process.env.LARK_CLI_BIN || 'lark-cli'
@@ -23,20 +23,10 @@ function run(args, opts = {}) {
23
23
  })
24
24
  }
25
25
 
26
- // profile list 输出 JSON;授权过期或缺少 user 的 profile 不参与采集
26
+ // 只枚举配置;bot 认证和权限由 event consume --as bot 检查
27
27
  async function listProfiles() {
28
28
  const { stdout } = await run(['profile', 'list'])
29
- const arr = JSON.parse(stdout)
30
- return arr.map((p) => {
31
- let reason = null
32
- if (p.tokenStatus === 'expired') reason = 'expired'
33
- else if (!p.user) reason = 'not-authed'
34
- return {
35
- name: p.name,
36
- usable: reason === null,
37
- reason,
38
- }
39
- })
29
+ return JSON.parse(stdout).map((p) => p.name)
40
30
  }
41
31
 
42
32
  // 保持 stdin 管道打开,stdout NDJSON 由 collect 原子写入
package/lib/status.js CHANGED
@@ -73,16 +73,13 @@ async function buildStatus() {
73
73
  try {
74
74
  profiles = await larkcli.listProfiles()
75
75
  } catch {}
76
- const expired = profiles.filter((p) => !p.usable).map((p) => `${p.name}[${p.reason}]`)
77
- const usable = profiles.filter((p) => p.usable).map((p) => p.name)
78
-
79
76
  const byApp = new Map()
80
77
  for (const c of listCursors()) {
81
78
  if (!byApp.has(c.app)) byApp.set(c.app, [])
82
79
  byApp.get(c.app).push(c)
83
80
  }
84
81
 
85
- const apps = [...new Set([...store.listApps(), ...usable])].sort()
82
+ const apps = [...new Set([...store.listApps(), ...profiles])].sort()
86
83
  const rows = apps.map((app) => {
87
84
  const latest = store.latestEntry(app)
88
85
  const ev = latest ? store.readEvent(latest) : null
@@ -98,8 +95,7 @@ async function buildStatus() {
98
95
  collect: {
99
96
  state,
100
97
  pid,
101
- usable,
102
- expired,
98
+ profiles,
103
99
  hint: `sudo launchctl bootstrap system /Library/LaunchDaemons/${COLLECT_LABEL}.plist`,
104
100
  },
105
101
  apps: rows,
@@ -124,11 +120,8 @@ function formatStatus(s) {
124
120
  let head = `collect ${dot} ${s.collect.state === 'active' ? 'running' : s.collect.state}`
125
121
  const bits = []
126
122
  if (s.collect.pid) bits.push(`pid ${s.collect.pid}`)
127
- const total = s.collect.usable.length + s.collect.expired.length
128
- if (total) bits.push(`${s.collect.usable.length}/${total} profiles`)
129
- if (bits.length) head += ` (${bits.join(', ')}`
130
- if (s.collect.expired.length) head += `; skipped: ${s.collect.expired.join(' ')}`
131
- if (bits.length) head += ')'
123
+ if (s.collect.profiles.length) bits.push(`${s.collect.profiles.length} configured profiles`)
124
+ if (bits.length) head += ` (${bits.join(', ')})`
132
125
  out.push(head)
133
126
  if (s.collect.state !== 'active') {
134
127
  out.push(' ⚠ collect 没在跑 —— 此刻的消息会永久丢失,不是延迟送达')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lark-relay",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "Lark event relay: collect events to disk, take a batch when you need it.",
5
5
  "keywords": [
6
6
  "lark",