larkcc 0.12.2 → 0.12.4

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
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.12.4] - 2026-05-09
11
+
12
+ ### Changed
13
+
14
+ - Footer stats layout: single-line grey text → column_set with equal-width columns (input/output tokens, tool count)
15
+ - Tool panel header: plain text → markdown formatting (bold label + inline code detail)
16
+ - Task panel footer: single-line grey text → column_set
17
+ - Extract `buildStatsTags()` to eliminate duplicated tag construction in cardkit.ts and message.ts
18
+
19
+ ## [0.12.3] - 2026-05-09
20
+
21
+ ### Fixed
22
+
23
+ - Suppress SDK warning for unhandled `im.message.reaction.created_v1` / `deleted_v1` events
24
+
25
+ ## [0.12.2] - 2026-05-09
26
+
27
+ ### Added
28
+
29
+ - Format tool result content by type: Read results use language-tagged code blocks (auto-detected from file extension), Bash results use bash code blocks
30
+ - Increase tool result truncation threshold from 500 to 2000 characters
31
+
10
32
  ## [0.12.1] - 2026-05-09
11
33
 
12
34
  ### Added
package/dist/index.js CHANGED
@@ -135860,6 +135860,158 @@ var init_sanitize = __esm({
135860
135860
  }
135861
135861
  });
135862
135862
 
135863
+ // src/format/duration.ts
135864
+ function formatDuration(seconds) {
135865
+ if (seconds < 60) return `${seconds.toFixed(1)}s`;
135866
+ const minutes = Math.floor(seconds / 60);
135867
+ const remainSec = Math.round(seconds % 60);
135868
+ return `${minutes}m ${remainSec}s`;
135869
+ }
135870
+ function formatReasoningDuration(ms) {
135871
+ return formatDuration(ms / 1e3);
135872
+ }
135873
+ function buildThinkingPanel(options) {
135874
+ const truncatedThinking = options.thinking.length > THINKING_OVERFLOW_TRUNCATE ? truncateSafely(options.thinking, THINKING_OVERFLOW_TRUNCATE, "\n...") : options.thinking;
135875
+ const durLabel = options.reasoningElapsedMs ? ` ${formatReasoningDuration(options.reasoningElapsedMs)}` : "";
135876
+ return [
135877
+ {
135878
+ tag: "collapsible_panel",
135879
+ expanded: false,
135880
+ background_color: "wathet",
135881
+ header: {
135882
+ title: {
135883
+ tag: "markdown",
135884
+ content: `\u{1F4AD} Thought${durLabel}`,
135885
+ i18n_content: {
135886
+ zh_cn: `\u{1F4AD} \u601D\u8003${durLabel}`,
135887
+ en_us: `\u{1F4AD} Thought${durLabel}`
135888
+ }
135889
+ },
135890
+ vertical_align: "center",
135891
+ icon: {
135892
+ tag: "standard_icon",
135893
+ token: "down-small-ccm_outlined",
135894
+ size: "16px 16px"
135895
+ },
135896
+ icon_position: "follow_text",
135897
+ icon_expanded_angle: -180
135898
+ },
135899
+ border: { color: "grey", corner_radius: "5px" },
135900
+ vertical_spacing: "8px",
135901
+ padding: "8px 8px 8px 8px",
135902
+ elements: [
135903
+ {
135904
+ tag: "markdown",
135905
+ content: truncatedThinking,
135906
+ text_size: "notation"
135907
+ }
135908
+ ]
135909
+ },
135910
+ { tag: "hr" }
135911
+ ];
135912
+ }
135913
+ function detectLangFromPath(filePath) {
135914
+ const ext = filePath.split(".").pop()?.toLowerCase() ?? "";
135915
+ return EXT_LANG_MAP[ext] ?? "";
135916
+ }
135917
+ function formatToolContent(toolName, detail, result) {
135918
+ if (toolName === "Read") {
135919
+ const lang = detectLangFromPath(detail);
135920
+ return "```" + lang + "\n" + result + "\n```";
135921
+ }
135922
+ if (toolName === "Bash") {
135923
+ return "```bash\n" + result + "\n```";
135924
+ }
135925
+ return result;
135926
+ }
135927
+ function buildToolResultPanel(entry) {
135928
+ const raw = entry.resultPreview.length > TOOL_RESULT_TRUNCATE ? truncateSafely(entry.resultPreview, TOOL_RESULT_TRUNCATE, "\n...") : entry.resultPreview;
135929
+ const content = formatToolContent(entry.toolName, entry.detail, raw);
135930
+ const headerTitle = entry.detail ? `**${entry.label}** \`${entry.detail}\`` : entry.label;
135931
+ return {
135932
+ tag: "collapsible_panel",
135933
+ expanded: false,
135934
+ background_color: "grey",
135935
+ header: {
135936
+ title: {
135937
+ tag: "markdown",
135938
+ content: headerTitle
135939
+ },
135940
+ vertical_align: "center",
135941
+ icon: {
135942
+ tag: "standard_icon",
135943
+ token: "down-small-ccm_outlined",
135944
+ size: "16px 16px"
135945
+ },
135946
+ icon_position: "right",
135947
+ icon_expanded_angle: -180
135948
+ },
135949
+ border: { color: "grey", corner_radius: "5px" },
135950
+ vertical_spacing: "8px",
135951
+ padding: "8px 8px 8px 8px",
135952
+ elements: [
135953
+ {
135954
+ tag: "markdown",
135955
+ content,
135956
+ text_size: "notation"
135957
+ }
135958
+ ]
135959
+ };
135960
+ }
135961
+ function buildToolPanels(results) {
135962
+ if (results.length === 0) return [];
135963
+ return results.map((r2) => buildToolResultPanel(r2));
135964
+ }
135965
+ var THINKING_OVERFLOW_TRUNCATE, TOOL_RESULT_TRUNCATE, EXT_LANG_MAP;
135966
+ var init_duration = __esm({
135967
+ "src/format/duration.ts"() {
135968
+ "use strict";
135969
+ init_card_optimize();
135970
+ THINKING_OVERFLOW_TRUNCATE = 3e3;
135971
+ TOOL_RESULT_TRUNCATE = 2e3;
135972
+ EXT_LANG_MAP = {
135973
+ ts: "typescript",
135974
+ tsx: "typescript",
135975
+ js: "javascript",
135976
+ jsx: "javascript",
135977
+ mjs: "javascript",
135978
+ py: "python",
135979
+ go: "go",
135980
+ rs: "rust",
135981
+ java: "java",
135982
+ json: "json",
135983
+ yaml: "yaml",
135984
+ yml: "yaml",
135985
+ md: "markdown",
135986
+ html: "html",
135987
+ htm: "html",
135988
+ css: "css",
135989
+ sql: "sql",
135990
+ sh: "bash",
135991
+ bash: "bash",
135992
+ zsh: "bash",
135993
+ xml: "xml",
135994
+ toml: "toml",
135995
+ ini: "ini",
135996
+ c: "c",
135997
+ h: "c",
135998
+ cpp: "cpp",
135999
+ cc: "cpp",
136000
+ cxx: "cpp",
136001
+ hpp: "cpp",
136002
+ rb: "ruby",
136003
+ php: "php",
136004
+ swift: "swift",
136005
+ kt: "kotlin",
136006
+ kts: "kotlin",
136007
+ dart: "dart",
136008
+ dockerfile: "dockerfile",
136009
+ makefile: "makefile",
136010
+ diff: "diff"
136011
+ };
136012
+ }
136013
+ });
136014
+
135863
136015
  // src/format/card.ts
135864
136016
  function buildHeader(options) {
135865
136017
  const header = {
@@ -135886,19 +136038,50 @@ function buildHeader(options) {
135886
136038
  }
135887
136039
  return header;
135888
136040
  }
135889
- function buildFooterMarkdown(stats) {
135890
- const parts = [];
136041
+ function buildStatsTags(stats) {
136042
+ const tags = [];
136043
+ if (stats.model) tags.push({ text: stats.model, color: "blue" });
136044
+ const totalTokens = (stats.inputTokens ?? 0) + (stats.outputTokens ?? 0);
136045
+ if (totalTokens > 0) tags.push({ text: `${totalTokens.toLocaleString()} tokens`, color: "turquoise" });
136046
+ if (stats.duration != null) tags.push({ text: formatDuration(stats.duration), color: "orange" });
136047
+ return tags;
136048
+ }
136049
+ function buildFooterElement(stats) {
136050
+ const columns = [];
135891
136051
  if (stats.inputTokens != null) {
135892
- parts.push(`\u{1F4E5} ${stats.inputTokens.toLocaleString()}`);
136052
+ columns.push({
136053
+ tag: "column",
136054
+ width: "weighted",
136055
+ weight: 1,
136056
+ vertical_align: "center",
136057
+ elements: [{ tag: "markdown", content: `<font color='grey'>\u{1F4E5} ${stats.inputTokens.toLocaleString()}</font>`, text_size: "notation" }]
136058
+ });
135893
136059
  }
135894
136060
  if (stats.outputTokens != null) {
135895
- parts.push(`\u{1F4E4} ${stats.outputTokens.toLocaleString()}`);
136061
+ columns.push({
136062
+ tag: "column",
136063
+ width: "weighted",
136064
+ weight: 1,
136065
+ vertical_align: "center",
136066
+ elements: [{ tag: "markdown", content: `<font color='grey'>\u{1F4E4} ${stats.outputTokens.toLocaleString()}</font>`, text_size: "notation" }]
136067
+ });
135896
136068
  }
135897
136069
  if (stats.toolCount != null && stats.toolCount > 0) {
135898
- parts.push(`\u{1F527} ${stats.toolCount}`);
136070
+ columns.push({
136071
+ tag: "column",
136072
+ width: "weighted",
136073
+ weight: 1,
136074
+ vertical_align: "center",
136075
+ elements: [{ tag: "markdown", content: `<font color='grey'>\u{1F527} ${stats.toolCount}</font>`, text_size: "notation" }]
136076
+ });
135899
136077
  }
135900
- if (parts.length === 0) return null;
135901
- return `<font color='grey'>${parts.join(" \xB7 ")}</font>`;
136078
+ if (columns.length === 0) return null;
136079
+ return {
136080
+ tag: "column_set",
136081
+ flex_mode: "none",
136082
+ background_style: "default",
136083
+ columns
136084
+ };
135902
136085
  }
135903
136086
  function buildStatusCard(options) {
135904
136087
  const header = buildHeader({
@@ -135929,6 +136112,7 @@ var init_card = __esm({
135929
136112
  "src/format/card.ts"() {
135930
136113
  "use strict";
135931
136114
  init_sanitize();
136115
+ init_duration();
135932
136116
  DEFAULT_ICON_TOKEN = "larkcommunity_colorful";
135933
136117
  }
135934
136118
  });
@@ -136859,158 +137043,6 @@ var init_format = __esm({
136859
137043
  }
136860
137044
  });
136861
137045
 
136862
- // src/format/duration.ts
136863
- function formatDuration(seconds) {
136864
- if (seconds < 60) return `${seconds.toFixed(1)}s`;
136865
- const minutes = Math.floor(seconds / 60);
136866
- const remainSec = Math.round(seconds % 60);
136867
- return `${minutes}m ${remainSec}s`;
136868
- }
136869
- function formatReasoningDuration(ms) {
136870
- return formatDuration(ms / 1e3);
136871
- }
136872
- function buildThinkingPanel(options) {
136873
- const truncatedThinking = options.thinking.length > THINKING_OVERFLOW_TRUNCATE ? truncateSafely(options.thinking, THINKING_OVERFLOW_TRUNCATE, "\n...") : options.thinking;
136874
- const durLabel = options.reasoningElapsedMs ? ` ${formatReasoningDuration(options.reasoningElapsedMs)}` : "";
136875
- return [
136876
- {
136877
- tag: "collapsible_panel",
136878
- expanded: false,
136879
- background_color: "wathet",
136880
- header: {
136881
- title: {
136882
- tag: "markdown",
136883
- content: `\u{1F4AD} Thought${durLabel}`,
136884
- i18n_content: {
136885
- zh_cn: `\u{1F4AD} \u601D\u8003${durLabel}`,
136886
- en_us: `\u{1F4AD} Thought${durLabel}`
136887
- }
136888
- },
136889
- vertical_align: "center",
136890
- icon: {
136891
- tag: "standard_icon",
136892
- token: "down-small-ccm_outlined",
136893
- size: "16px 16px"
136894
- },
136895
- icon_position: "follow_text",
136896
- icon_expanded_angle: -180
136897
- },
136898
- border: { color: "grey", corner_radius: "5px" },
136899
- vertical_spacing: "8px",
136900
- padding: "8px 8px 8px 8px",
136901
- elements: [
136902
- {
136903
- tag: "markdown",
136904
- content: truncatedThinking,
136905
- text_size: "notation"
136906
- }
136907
- ]
136908
- },
136909
- { tag: "hr" }
136910
- ];
136911
- }
136912
- function detectLangFromPath(filePath) {
136913
- const ext = filePath.split(".").pop()?.toLowerCase() ?? "";
136914
- return EXT_LANG_MAP[ext] ?? "";
136915
- }
136916
- function formatToolContent(toolName, detail, result) {
136917
- if (toolName === "Read") {
136918
- const lang = detectLangFromPath(detail);
136919
- return "```" + lang + "\n" + result + "\n```";
136920
- }
136921
- if (toolName === "Bash") {
136922
- return "```bash\n" + result + "\n```";
136923
- }
136924
- return result;
136925
- }
136926
- function buildToolResultPanel(entry) {
136927
- const raw = entry.resultPreview.length > TOOL_RESULT_TRUNCATE ? truncateSafely(entry.resultPreview, TOOL_RESULT_TRUNCATE, "\n...") : entry.resultPreview;
136928
- const content = formatToolContent(entry.toolName, entry.detail, raw);
136929
- const headerTitle = entry.detail ? `${entry.label} \u2014 ${entry.detail}` : entry.label;
136930
- return {
136931
- tag: "collapsible_panel",
136932
- expanded: false,
136933
- background_color: "grey",
136934
- header: {
136935
- title: {
136936
- tag: "plain_text",
136937
- content: headerTitle
136938
- },
136939
- vertical_align: "center",
136940
- icon: {
136941
- tag: "standard_icon",
136942
- token: "down-small-ccm_outlined",
136943
- size: "16px 16px"
136944
- },
136945
- icon_position: "right",
136946
- icon_expanded_angle: -180
136947
- },
136948
- border: { color: "grey", corner_radius: "5px" },
136949
- vertical_spacing: "8px",
136950
- padding: "8px 8px 8px 8px",
136951
- elements: [
136952
- {
136953
- tag: "markdown",
136954
- content,
136955
- text_size: "notation"
136956
- }
136957
- ]
136958
- };
136959
- }
136960
- function buildToolPanels(results) {
136961
- if (results.length === 0) return [];
136962
- return results.map((r2) => buildToolResultPanel(r2));
136963
- }
136964
- var THINKING_OVERFLOW_TRUNCATE, TOOL_RESULT_TRUNCATE, EXT_LANG_MAP;
136965
- var init_duration = __esm({
136966
- "src/format/duration.ts"() {
136967
- "use strict";
136968
- init_card_optimize();
136969
- THINKING_OVERFLOW_TRUNCATE = 3e3;
136970
- TOOL_RESULT_TRUNCATE = 2e3;
136971
- EXT_LANG_MAP = {
136972
- ts: "typescript",
136973
- tsx: "typescript",
136974
- js: "javascript",
136975
- jsx: "javascript",
136976
- mjs: "javascript",
136977
- py: "python",
136978
- go: "go",
136979
- rs: "rust",
136980
- java: "java",
136981
- json: "json",
136982
- yaml: "yaml",
136983
- yml: "yaml",
136984
- md: "markdown",
136985
- html: "html",
136986
- htm: "html",
136987
- css: "css",
136988
- sql: "sql",
136989
- sh: "bash",
136990
- bash: "bash",
136991
- zsh: "bash",
136992
- xml: "xml",
136993
- toml: "toml",
136994
- ini: "ini",
136995
- c: "c",
136996
- h: "c",
136997
- cpp: "cpp",
136998
- cc: "cpp",
136999
- cxx: "cpp",
137000
- hpp: "cpp",
137001
- rb: "ruby",
137002
- php: "php",
137003
- swift: "swift",
137004
- kt: "kotlin",
137005
- kts: "kotlin",
137006
- dart: "dart",
137007
- dockerfile: "dockerfile",
137008
- makefile: "makefile",
137009
- diff: "diff"
137010
- };
137011
- }
137012
- });
137013
-
137014
137046
  // src/feishu/document.ts
137015
137047
  import * as fs3 from "fs";
137016
137048
  import * as path2 from "path";
@@ -137510,19 +137542,14 @@ async function replyWithDocument(client, chatId, rootMsgId, markdown, context, o
137510
137542
  \u26A0\uFE0F ${docWarnings.join("\uFF1B")}`;
137511
137543
  }
137512
137544
  const elements = [{ tag: "markdown", content: replyMsg }];
137513
- const footer = buildFooterMarkdown({
137545
+ const footer = buildFooterElement({
137514
137546
  inputTokens: stats?.inputTokens,
137515
137547
  outputTokens: stats?.outputTokens,
137516
137548
  toolCount: stats?.toolCount
137517
137549
  });
137518
137550
  if (footer) {
137519
- elements.push({ tag: "hr" }, { tag: "markdown", content: footer, text_size: "notation" });
137551
+ elements.push({ tag: "hr" }, footer);
137520
137552
  }
137521
- const tags = [];
137522
- if (stats?.model) tags.push({ text: stats.model, color: "blue" });
137523
- const totalTokens = (stats?.inputTokens ?? 0) + (stats?.outputTokens ?? 0);
137524
- if (totalTokens > 0) tags.push({ text: `${totalTokens.toLocaleString()} tokens`, color: "turquoise" });
137525
- if (stats?.duration != null) tags.push({ text: formatDuration(stats.duration), color: "orange" });
137526
137553
  const docCard = {
137527
137554
  schema: "2.0",
137528
137555
  config: { wide_screen_mode: true },
@@ -137531,7 +137558,7 @@ async function replyWithDocument(client, chatId, rootMsgId, markdown, context, o
137531
137558
  subtitle: "\u5185\u5BB9\u5DF2\u5199\u5165\u4E91\u6587\u6863",
137532
137559
  template: "green",
137533
137560
  iconImgKey: options?.headerIconImgKey,
137534
- tags
137561
+ tags: buildStatsTags(stats ?? {})
137535
137562
  }),
137536
137563
  body: { elements }
137537
137564
  };
@@ -137666,7 +137693,6 @@ var init_message = __esm({
137666
137693
  init_format();
137667
137694
  init_duration();
137668
137695
  init_card();
137669
- init_duration();
137670
137696
  init_client();
137671
137697
  init_document2();
137672
137698
  CHUNK_SIZE = 2800;
@@ -137810,11 +137836,32 @@ function buildTaskPanelCard(options) {
137810
137836
  } else if (status === "running") {
137811
137837
  elements.push({ tag: "markdown", content: "Processing..." });
137812
137838
  }
137813
- const footerParts = [];
137814
- if (elapsedSeconds != null) footerParts.push(`\u23F1 ${fmtDur(elapsedSeconds)}`);
137815
- if (status !== "running" && tokens != null) footerParts.push(`\u{1FA99} ${tokens.toLocaleString()} tokens`);
137816
- if (footerParts.length > 0) {
137817
- elements.push({ tag: "markdown", content: `<font color='grey'>${footerParts.join(" \xB7 ")}</font>` });
137839
+ const footerColumns = [];
137840
+ if (elapsedSeconds != null) {
137841
+ footerColumns.push({
137842
+ tag: "column",
137843
+ width: "weighted",
137844
+ weight: 1,
137845
+ vertical_align: "center",
137846
+ elements: [{ tag: "markdown", content: `<font color='grey'>\u23F1 ${fmtDur(elapsedSeconds)}</font>`, text_size: "notation" }]
137847
+ });
137848
+ }
137849
+ if (status !== "running" && tokens != null) {
137850
+ footerColumns.push({
137851
+ tag: "column",
137852
+ width: "weighted",
137853
+ weight: 1,
137854
+ vertical_align: "center",
137855
+ elements: [{ tag: "markdown", content: `<font color='grey'>\u{1FA99} ${tokens.toLocaleString()} tokens</font>`, text_size: "notation" }]
137856
+ });
137857
+ }
137858
+ if (footerColumns.length > 0) {
137859
+ elements.push({
137860
+ tag: "column_set",
137861
+ flex_mode: "none",
137862
+ background_style: "default",
137863
+ columns: footerColumns
137864
+ });
137818
137865
  }
137819
137866
  const icon = headerIconImgKey ? { tag: "custom_icon", img_key: headerIconImgKey } : { tag: "standard_icon", token: "larkcommunity_colorful" };
137820
137867
  return {
@@ -137933,7 +137980,7 @@ var VERSION3;
137933
137980
  var init_version = __esm({
137934
137981
  "src/version.ts"() {
137935
137982
  "use strict";
137936
- VERSION3 = "0.12.2";
137983
+ VERSION3 = "0.12.4";
137937
137984
  }
137938
137985
  });
137939
137986
 
@@ -155410,14 +155457,13 @@ ${displayContent}`;
155410
155457
  element_id: this.streamElementId
155411
155458
  }
155412
155459
  ];
155413
- const footer = buildFooterMarkdown({
155460
+ const footer = buildFooterElement({
155414
155461
  inputTokens: stats?.inputTokens,
155415
155462
  outputTokens: stats?.outputTokens,
155416
- toolCount: stats?.toolCount,
155417
- duration: stats?.duration
155463
+ toolCount: stats?.toolCount
155418
155464
  });
155419
155465
  if (footer) {
155420
- elements.push({ tag: "hr" }, { tag: "markdown", content: footer, text_size: "notation" });
155466
+ elements.push({ tag: "hr" }, footer);
155421
155467
  }
155422
155468
  const cardJson = {
155423
155469
  schema: "2.0",
@@ -155428,23 +155474,12 @@ ${displayContent}`;
155428
155474
  body: { elements }
155429
155475
  };
155430
155476
  if (this.cardTitle) {
155431
- const tags = [];
155432
- if (stats?.model) {
155433
- tags.push({ text: stats.model, color: "blue" });
155434
- }
155435
- const totalTokens = (stats?.inputTokens ?? 0) + (stats?.outputTokens ?? 0);
155436
- if (totalTokens > 0) {
155437
- tags.push({ text: `${totalTokens.toLocaleString()} tokens`, color: "turquoise" });
155438
- }
155439
- if (stats?.duration != null) {
155440
- tags.push({ text: formatDuration(stats.duration), color: "orange" });
155441
- }
155442
155477
  cardJson.header = buildHeader({
155443
155478
  title: this.cardTitle,
155444
155479
  subtitle: "\u5BF9\u8BDD\u5B8C\u6210",
155445
155480
  template: "green",
155446
155481
  iconImgKey: this.headerIconImgKey,
155447
- tags
155482
+ tags: buildStatsTags(stats ?? {})
155448
155483
  });
155449
155484
  }
155450
155485
  return cardJson;
@@ -156981,7 +157016,11 @@ async function startApp(cwd2, config2, profile2, continueSession = false, force
156981
157016
  });
156982
157017
  wsClient.start({
156983
157018
  eventDispatcher: new EventDispatcher({}).register({
156984
- "im.message.receive_v1": handler
157019
+ "im.message.receive_v1": handler,
157020
+ "im.message.reaction.created_v1": () => {
157021
+ },
157022
+ "im.message.reaction.deleted_v1": () => {
157023
+ }
156985
157024
  })
156986
157025
  });
156987
157026
  logger.success("Feishu connected! Waiting for messages...");