agent-messenger 2.23.6 → 2.24.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.
Files changed (79) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.github/workflows/ci.yml +4 -0
  3. package/README.md +12 -1
  4. package/bun.lock +10 -72
  5. package/dist/package.json +7 -4
  6. package/dist/src/platforms/kakaotalk/token-extractor.d.ts.map +1 -1
  7. package/dist/src/platforms/kakaotalk/token-extractor.js +11 -38
  8. package/dist/src/platforms/kakaotalk/token-extractor.js.map +1 -1
  9. package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
  10. package/dist/src/platforms/slack/commands/auth.js +88 -5
  11. package/dist/src/platforms/slack/commands/auth.js.map +1 -1
  12. package/dist/src/platforms/slack/ensure-auth.d.ts +2 -1
  13. package/dist/src/platforms/slack/ensure-auth.d.ts.map +1 -1
  14. package/dist/src/platforms/slack/ensure-auth.js +49 -2
  15. package/dist/src/platforms/slack/ensure-auth.js.map +1 -1
  16. package/dist/src/platforms/slack/index.d.ts +4 -0
  17. package/dist/src/platforms/slack/index.d.ts.map +1 -1
  18. package/dist/src/platforms/slack/index.js +2 -0
  19. package/dist/src/platforms/slack/index.js.map +1 -1
  20. package/dist/src/platforms/slack/qr-http-login.d.ts +14 -0
  21. package/dist/src/platforms/slack/qr-http-login.d.ts.map +1 -0
  22. package/dist/src/platforms/slack/qr-http-login.js +90 -0
  23. package/dist/src/platforms/slack/qr-http-login.js.map +1 -0
  24. package/dist/src/platforms/slack/qr-login.d.ts +10 -0
  25. package/dist/src/platforms/slack/qr-login.d.ts.map +1 -0
  26. package/dist/src/platforms/slack/qr-login.js +72 -0
  27. package/dist/src/platforms/slack/qr-login.js.map +1 -0
  28. package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
  29. package/dist/src/platforms/slack/token-extractor.js +5 -11
  30. package/dist/src/platforms/slack/token-extractor.js.map +1 -1
  31. package/dist/src/shared/chromium/cookie-reader.d.ts.map +1 -1
  32. package/dist/src/shared/chromium/cookie-reader.js +4 -19
  33. package/dist/src/shared/chromium/cookie-reader.js.map +1 -1
  34. package/dist/src/shared/sqlite.d.ts +10 -0
  35. package/dist/src/shared/sqlite.d.ts.map +1 -0
  36. package/dist/src/shared/sqlite.js +46 -0
  37. package/dist/src/shared/sqlite.js.map +1 -0
  38. package/dist/src/vendor/linejs/base/request/mod.js +1 -1
  39. package/dist/src/vendor/linejs/base/request/mod.test.ts +54 -0
  40. package/docs/content/docs/cli/slack.mdx +22 -0
  41. package/docs/content/docs/sdk/slack.mdx +15 -0
  42. package/package.json +7 -4
  43. package/skills/agent-channeltalk/SKILL.md +1 -1
  44. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  45. package/skills/agent-discord/SKILL.md +1 -1
  46. package/skills/agent-discordbot/SKILL.md +1 -1
  47. package/skills/agent-instagram/SKILL.md +1 -1
  48. package/skills/agent-kakaotalk/SKILL.md +1 -1
  49. package/skills/agent-line/SKILL.md +1 -1
  50. package/skills/agent-slack/SKILL.md +45 -1
  51. package/skills/agent-slack/references/authentication.md +29 -0
  52. package/skills/agent-slackbot/SKILL.md +1 -1
  53. package/skills/agent-teams/SKILL.md +1 -1
  54. package/skills/agent-telegram/SKILL.md +1 -1
  55. package/skills/agent-telegrambot/SKILL.md +1 -1
  56. package/skills/agent-webex/SKILL.md +1 -1
  57. package/skills/agent-webexbot/SKILL.md +1 -1
  58. package/skills/agent-wechatbot/SKILL.md +1 -1
  59. package/skills/agent-whatsapp/SKILL.md +1 -1
  60. package/skills/agent-whatsappbot/SKILL.md +1 -1
  61. package/src/platforms/channeltalk/token-extractor.test.ts +2 -2
  62. package/src/platforms/kakaotalk/token-extractor.ts +13 -36
  63. package/src/platforms/slack/commands/auth.ts +106 -5
  64. package/src/platforms/slack/ensure-auth.test.ts +130 -19
  65. package/src/platforms/slack/ensure-auth.ts +57 -2
  66. package/src/platforms/slack/index.test.ts +10 -0
  67. package/src/platforms/slack/index.ts +4 -0
  68. package/src/platforms/slack/qr-http-login.test.ts +157 -0
  69. package/src/platforms/slack/qr-http-login.ts +120 -0
  70. package/src/platforms/slack/qr-login.test.ts +103 -0
  71. package/src/platforms/slack/qr-login.ts +90 -0
  72. package/src/platforms/slack/token-extractor-node-test.ts +5 -3
  73. package/src/platforms/slack/token-extractor.ts +4 -11
  74. package/src/shared/chromium/cookie-reader-node-test.ts +70 -0
  75. package/src/shared/chromium/cookie-reader-node.test.ts +10 -0
  76. package/src/shared/chromium/cookie-reader.ts +4 -21
  77. package/src/shared/sqlite.ts +61 -0
  78. package/src/vendor/linejs/base/request/mod.js +1 -1
  79. package/src/vendor/linejs/base/request/mod.test.ts +54 -0
@@ -1,9 +1,8 @@
1
1
  import { copyFileSync, existsSync, rmSync } from 'node:fs'
2
- import { createRequire } from 'node:module'
3
2
  import { tmpdir } from 'node:os'
4
3
  import { join } from 'node:path'
5
4
 
6
- const require = createRequire(import.meta.url)
5
+ import { openReadonlyDatabase } from '@/shared/sqlite'
7
6
 
8
7
  /**
9
8
  * Reads Chromium SQLite cookie databases with Bun/Node dual-runtime support.
@@ -70,24 +69,7 @@ export class ChromiumCookieReader {
70
69
  params: unknown[] | undefined,
71
70
  mode: 'all' | 'first',
72
71
  ): T[] | T | null {
73
- if (typeof globalThis.Bun !== 'undefined') {
74
- const { Database } = require('bun:sqlite')
75
- const db = new Database(tempPath, { readonly: true })
76
-
77
- try {
78
- const stmt = db.query(sql)
79
- if (mode === 'all') {
80
- return (params ? stmt.all(...params) : stmt.all()) as T[]
81
- }
82
-
83
- return (params ? stmt.get(...params) : stmt.get()) as T | null
84
- } finally {
85
- db.close()
86
- }
87
- }
88
-
89
- const Database = require('better-sqlite3')
90
- const db = new Database(tempPath, { readonly: true })
72
+ const db = openReadonlyDatabase(tempPath)
91
73
 
92
74
  try {
93
75
  const stmt = db.prepare(sql)
@@ -95,7 +77,8 @@ export class ChromiumCookieReader {
95
77
  return (params ? stmt.all(...params) : stmt.all()) as T[]
96
78
  }
97
79
 
98
- return (params ? stmt.get(...params) : stmt.get()) as T | null
80
+ const row = params ? stmt.get(...params) : stmt.get()
81
+ return (row ?? null) as T | null
99
82
  } finally {
100
83
  db.close()
101
84
  }
@@ -0,0 +1,61 @@
1
+ import { createRequire } from 'node:module'
2
+
3
+ const require = createRequire(import.meta.url)
4
+
5
+ export interface ReadonlyStatement {
6
+ get(...params: unknown[]): unknown
7
+ all(...params: unknown[]): unknown[]
8
+ }
9
+
10
+ export interface ReadonlyDatabase {
11
+ prepare(sql: string): ReadonlyStatement
12
+ close(): void
13
+ }
14
+
15
+ type ReadonlyDatabaseConstructor = new (path: string, options: { readOnly: boolean }) => ReadonlyDatabase
16
+
17
+ // Uses the runtime's built-in driver (bun:sqlite on Bun, node:sqlite on Node >= 22.13)
18
+ // to avoid a native addon dependency.
19
+ //
20
+ // Runtime quirks callers must respect (both drivers behave this way):
21
+ // - BLOB columns are returned as Uint8Array, not Buffer. Wrap with Buffer.from()
22
+ // before any Buffer-specific call (e.g. .toString('utf8'), node:crypto helpers).
23
+ // - node:sqlite throws ERR_OUT_OF_RANGE when reading an INTEGER above
24
+ // Number.MAX_SAFE_INTEGER, so never SELECT raw microsecond timestamps such as
25
+ // Chromium's *_utc columns; use them only in WHERE / ORDER BY clauses.
26
+ export function openReadonlyDatabase(path: string): ReadonlyDatabase {
27
+ if (typeof globalThis.Bun !== 'undefined') {
28
+ const { Database } = require('bun:sqlite')
29
+ return new Database(path, { readonly: true }) as ReadonlyDatabase
30
+ }
31
+
32
+ let DatabaseSync: ReadonlyDatabaseConstructor
33
+ // node:sqlite emits a one-time ExperimentalWarning to stderr on load
34
+ // (Node < 24.15) that clutters the CLI's output. Suppress just that warning
35
+ // while loading the module, then restore the original handler.
36
+ const originalEmitWarning = process.emitWarning
37
+ const filteredEmitWarning = (...args: unknown[]): void => {
38
+ const [warning, second] = args
39
+ const name =
40
+ warning instanceof Error
41
+ ? warning.name
42
+ : typeof second === 'string'
43
+ ? second
44
+ : (second as { type?: string } | undefined)?.type
45
+ const message = warning instanceof Error ? warning.message : String(warning)
46
+ if (name === 'ExperimentalWarning' && message.includes('SQLite')) return
47
+ ;(originalEmitWarning as (...forwarded: unknown[]) => void).apply(process, args)
48
+ }
49
+ process.emitWarning = filteredEmitWarning as typeof process.emitWarning
50
+ try {
51
+ DatabaseSync = require('node:sqlite').DatabaseSync
52
+ } catch {
53
+ throw new Error(
54
+ 'SQLite support requires Node.js >= 22.13.0 (the built-in node:sqlite module) or Bun. Please upgrade Node.js.',
55
+ )
56
+ } finally {
57
+ process.emitWarning = originalEmitWarning
58
+ }
59
+
60
+ return new DatabaseSync(path, { readOnly: true })
61
+ }
@@ -158,7 +158,7 @@ const square = [
158
158
  throw new InternalError("RequestError", `Request internal failed, ${methodName}(${path}) -> ` + JSON.stringify(res.data.e), res.data.e);
159
159
  }
160
160
  if (hasError && !isRefresh) {
161
- if (res.data.e.code === "NOT_AUTHORIZED_DEVICE") {
161
+ if (res.data.e && res.data.e.code === "NOT_AUTHORIZED_DEVICE") {
162
162
  delete this.client.authToken;
163
163
  this.client.emit("end", this.client.profile);
164
164
  }
@@ -0,0 +1,54 @@
1
+ import { describe, expect, it } from 'bun:test'
2
+
3
+ import { InternalError } from '../core/mod.js'
4
+ import { RequestClient } from './mod.js'
5
+
6
+ // Regression: a thrift error response can set hasError (empty res.data[0]) while
7
+ // omitting the exception struct (res.data[1] absent), leaving res.data.e undefined.
8
+ function createClient(readThriftResult: { data: Record<string, unknown> }) {
9
+ const deviceDetails = {
10
+ device: 'TEST',
11
+ appVersion: '0.0.0',
12
+ systemName: 'TEST',
13
+ systemVersion: '0.0.0',
14
+ }
15
+ const stubClient = {
16
+ deviceDetails,
17
+ endpoint: 'legy.line-apps.test',
18
+ authToken: 'expired-token',
19
+ config: { timeout: 1000 },
20
+ storage: { get: async () => undefined },
21
+ log: () => {},
22
+ emit: () => {},
23
+ fetch: async () => ({
24
+ headers: { get: () => null },
25
+ arrayBuffer: async () => new ArrayBuffer(0),
26
+ }),
27
+ thrift: {
28
+ writeThrift: () => new Uint8Array(),
29
+ readThrift: () => readThriftResult,
30
+ rename_data: () => {},
31
+ },
32
+ }
33
+
34
+ return new RequestClient(stubClient as never)
35
+ }
36
+
37
+ describe('RequestClient.requestCore error handling', () => {
38
+ it('throws a clean RequestError when hasError is set but no exception struct is present', async () => {
39
+ // given: an error response with an empty success slot and no exception struct
40
+ const client = createClient({ data: { 0: undefined, someField: 1 } })
41
+
42
+ // when / then: the error branch must throw InternalError, not a TypeError
43
+ let thrown: unknown
44
+ try {
45
+ await client.requestCore('/S3', [], 'testMethod', 3)
46
+ } catch (error) {
47
+ thrown = error
48
+ }
49
+
50
+ expect(thrown).toBeInstanceOf(InternalError)
51
+ expect((thrown as InternalError).type).toBe('RequestError')
52
+ expect(thrown).not.toBeInstanceOf(TypeError)
53
+ })
54
+ })