feishu-user-plugin 1.3.8 → 1.3.9

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 (40) hide show
  1. package/.claude-plugin/plugin.json +12 -2
  2. package/CHANGELOG.md +50 -12
  3. package/README.md +4 -4
  4. package/package.json +9 -5
  5. package/proto/lark.proto +10 -0
  6. package/scripts/explore-card-protobuf.js +144 -0
  7. package/scripts/explore-image-minimize.js +163 -0
  8. package/scripts/generate-release-artifacts.js +318 -0
  9. package/scripts/probe-feishu-docx.js +203 -0
  10. package/scripts/sync-team-skills.sh +109 -7
  11. package/skills/feishu-user-plugin/SKILL.md +76 -4
  12. package/skills/feishu-user-plugin/references/CLAUDE.md +74 -54
  13. package/src/auth/credentials.js +36 -0
  14. package/src/cli.js +86 -45
  15. package/src/clients/user.js +15 -13
  16. package/src/events/cursor.js +103 -0
  17. package/src/events/event-buffer.js +8 -5
  18. package/src/events/event-log.js +151 -0
  19. package/src/events/index.js +8 -1
  20. package/src/events/lockfile.js +126 -0
  21. package/src/events/owner.js +73 -0
  22. package/src/events/ws-server.js +95 -25
  23. package/src/oauth.js +48 -7
  24. package/src/resolver.js +10 -0
  25. package/src/server.js +248 -29
  26. package/src/setup.js +99 -25
  27. package/src/test-all.js +12 -9
  28. package/src/test-events-cursor.js +56 -0
  29. package/src/test-events-lockfile.js +36 -0
  30. package/src/test-events-log.js +67 -0
  31. package/src/test-events-owner.js +64 -0
  32. package/src/test-fixtures/doc-blocks/sample-1.json +1256 -0
  33. package/src/test-read-doc-markdown.js +61 -0
  34. package/src/test-switch-profile.js +171 -0
  35. package/src/tools/diagnostics.js +10 -3
  36. package/src/tools/docs.js +93 -3
  37. package/src/tools/events.js +143 -33
  38. package/src/tools/messaging-bot.js +2 -3
  39. package/src/tools/messaging-user.js +23 -14
  40. package/src/tools/profile.js +12 -7
@@ -1,10 +1,12 @@
1
1
  // src/tools/messaging-user.js — User-identity (cookie-based) messaging plus
2
- // batch_send fan-out and the v1.3.6 bot-default send_card_as_user.
2
+ // batch_send fan-out. send_card_as_user lives here (historical naming) but
3
+ // always routes through bot — user-identity card sending is server-side
4
+ // disabled in Feishu at the cookie auth tier.
3
5
  //
4
- // All send_*_as_user handlers route through ctx.getUserClient() (cookie identity).
5
- // batch_send mixes user + bot identities per target. send_card_as_user currently
6
- // delegates to bot via ctx.getOfficialClient() — the "as_user" suffix is reserved
7
- // for v1.3.7's reverse-engineered cookie path; default flips when that lands.
6
+ // All send_*_as_user handlers route through ctx.getUserClient() (cookie identity)
7
+ // EXCEPT send_card_as_user which delegates to bot via ctx.getOfficialClient().
8
+ // The "as_user" suffix on the card tool is historical — v1.3.9 confirmed the
9
+ // cookie protobuf path for CARD is server-side disabled, brute-force exhausted.
8
10
 
9
11
  const { text, sendResult, json } = require('./_registry');
10
12
 
@@ -115,12 +117,17 @@ const schemas = [
115
117
  },
116
118
  {
117
119
  name: 'send_image_as_user',
118
- description: '[User Identity] Send an image as the logged-in user. Requires image_key (upload via Official API first).',
120
+ description: '[User Identity, v1.3.9] Send an image as the logged-in user (NOT bot). Requires image_key from a prior upload_image call. Cookie-protobuf wire format requires both imageKey + thumbnailKey — when no separate thumbnail is provided, plugin defaults thumbnailKey to imageKey (Feishu accepts this for messenger-uploaded images). Width/height/mime/size are optional metadata; Feishu auto-derives display sizing on its side.',
119
121
  inputSchema: {
120
122
  type: 'object',
121
123
  properties: {
122
124
  chat_id: { type: 'string', description: 'Target chat ID. Numeric preferred; oc_xxx is auto-resolved (v1.3.7 C1.4).' },
123
125
  image_key: { type: 'string', description: 'Image key from upload (img_v2_xxx or img_v3_xxx)' },
126
+ thumbnail_key: { type: 'string', description: 'Optional separate thumbnail image key. Defaults to image_key when omitted.' },
127
+ width: { type: 'number', description: 'Optional image width in pixels.' },
128
+ height: { type: 'number', description: 'Optional image height in pixels.' },
129
+ mime: { type: 'string', description: 'Optional MIME type (e.g. "image/png").' },
130
+ size: { type: 'number', description: 'Optional file size in bytes.' },
124
131
  root_id: { type: 'string', description: 'Thread root message ID (optional)' },
125
132
  },
126
133
  required: ['chat_id', 'image_key'],
@@ -160,13 +167,12 @@ const schemas = [
160
167
  },
161
168
  {
162
169
  name: 'send_card_as_user',
163
- description: '[v1.3.6+: bot-routed default] Send an interactive card to a chat. **Identity defaults to BOT** because user-identity card sending requires reverse-engineering the Feishu web protobuf (deferred to v1.3.9; v1.3.8 shipped the capture/decode tooling). The tool name keeps the "as_user" suffix so callers don\'t have to migrate when v1.3.9 lands; once user-identity is implemented the default flips. Pass `card` as a JSON object (Feishu card schema). To force bot explicitly set via="bot".',
170
+ description: '[v1.3.9+: bot-only] Send an interactive Feishu card to a chat via bot identity (Official API). User-identity cookie protobuf path is server-side disabled at the auth tier confirmed by exhaustive brute-force in v1.3.9, see scripts/explore-card-protobuf.js. The "as_user" suffix is historical naming kept for backward compat; the tool always routes through bot. Pass `card` as a JSON object (Feishu card schema, see https://open.feishu.cn/cardkit).',
164
171
  inputSchema: {
165
172
  type: 'object',
166
173
  properties: {
167
174
  chat_id: { type: 'string', description: 'Target chat_id (oc_xxx) or open_id' },
168
175
  card: { description: 'Feishu card JSON. See https://open.feishu.cn/cardkit for the schema; build cards visually then paste the resulting JSON here.' },
169
- via: { type: 'string', enum: ['bot', 'user'], description: 'Identity to send as. Default "bot". "user" returns an explicit not-yet-implemented error in v1.3.6.' },
170
176
  },
171
177
  required: ['chat_id', 'card'],
172
178
  },
@@ -264,7 +270,14 @@ const handlers = {
264
270
  async send_image_as_user(args, ctx) {
265
271
  const c = await ctx.getUserClient();
266
272
  const chatId = await _resolveCookieChatId(args.chat_id, ctx);
267
- const r = await c.sendImage(chatId, args.image_key, { rootId: args.root_id });
273
+ const r = await c.sendImage(chatId, args.image_key, {
274
+ rootId: args.root_id,
275
+ thumbnailKey: args.thumbnail_key,
276
+ width: args.width,
277
+ height: args.height,
278
+ mime: args.mime,
279
+ size: args.size,
280
+ });
268
281
  return sendResult(r, `Image sent to ${args.chat_id}`);
269
282
  },
270
283
  async send_file_as_user(args, ctx) {
@@ -280,12 +293,8 @@ const handlers = {
280
293
  return sendResult(r, `Post sent to ${args.chat_id}`);
281
294
  },
282
295
  async send_card_as_user(args, ctx) {
283
- const via = args.via || 'bot';
284
- if (via === 'user') {
285
- return text('send_card_as_user via="user" is not implemented in v1.3.6 — user-identity card sending requires reverse-engineering the Feishu web protobuf and is scheduled for v1.3.7. Use via="bot" (default) for now.');
286
- }
287
296
  const r = await ctx.getOfficialClient().sendMessageAsBot(args.chat_id, 'interactive', args.card);
288
- return text(`Card sent (${via}): ${r.messageId}`);
297
+ return text(`Card sent (bot): ${r.messageId}`);
289
298
  },
290
299
  };
291
300
 
@@ -1,24 +1,29 @@
1
- // src/tools/profile.js — multi-account profile management (v1.3.6).
1
+ // src/tools/profile.js — multi-account profile management.
2
2
  //
3
- // LARK_PROFILES_JSON env var registers extra credential sets; this module
4
- // exposes them via list_profiles + switch_profile so callers can hot-swap
5
- // between accounts/tenants without restarting the MCP server.
3
+ // v1.3.9 SSOT: profiles live in ~/.feishu-user-plugin/credentials.json under
4
+ // `profiles[]`. Switching writes `active` field; cross-process MCP picks it up
5
+ // via dispatcher mtime hook (~10μs/call) within ms.
6
+ //
7
+ // Legacy LARK_PROFILES_JSON env still works as a back-compat fallback when
8
+ // credentials.json doesn't exist. New profiles should be added via
9
+ // `npx feishu-user-plugin setup --profile <name> --app-id ... --app-secret ... --cookie ...`,
10
+ // then optionally `npx feishu-user-plugin oauth --profile <name>` for UAT.
6
11
 
7
12
  const { text, json } = require('./_registry');
8
13
 
9
14
  const schemas = [
10
15
  {
11
16
  name: 'list_profiles',
12
- description: '[Plugin] List all available identity profiles (sets of LARK_COOKIE/APP_ID/APP_SECRET/UAT). The "default" profile uses the top-level env vars; additional profiles come from LARK_PROFILES_JSON. Marks the currently active profile.',
17
+ description: '[Plugin] List all available identity profiles (each profile has its own LARK_COOKIE / APP_ID / APP_SECRET / UAT). v1.3.9 SSOT: profiles live in ~/.feishu-user-plugin/credentials.json::profiles. Legacy fallback: LARK_PROFILES_JSON env var. Marks the currently active profile.',
13
18
  inputSchema: { type: 'object', properties: {} },
14
19
  },
15
20
  {
16
21
  name: 'switch_profile',
17
- description: '[Plugin] Switch the active identity profile. Subsequent tool calls use the new profile\'s credentials. Cached client instances are reset so the next call rebuilds against the new creds.',
22
+ description: '[Plugin v1.3.9] Switch the active identity profile. Atomically writes credentials.json::active; cached clients in this process are invalidated; cross-process MCPs (Codex / another Claude Code) auto-sync via dispatcher mtime check on next tool call (~10μs). To add a new profile, run `npx feishu-user-plugin setup --profile <name> --app-id ... --app-secret ... --cookie ...` then `npx feishu-user-plugin oauth --profile <name>` for UAT.',
18
23
  inputSchema: {
19
24
  type: 'object',
20
25
  properties: {
21
- name: { type: 'string', description: 'Profile name. "default" for top-level env vars; any key from LARK_PROFILES_JSON otherwise.' },
26
+ name: { type: 'string', description: 'Profile name. Use "default" for the primary profile; other names come from credentials.json or LARK_PROFILES_JSON.' },
22
27
  },
23
28
  required: ['name'],
24
29
  },