@callimacus/thamyr

中文文档
4.23.5发布于 2026/11/09SEE LICENSE IN LICENSE.mdTypeScriptES Module近 30 天下载 6486

Thamyr 的 Java 脚本包

中文使用文档
文档目录39 节
  1. 概览
  2. 核心概念
  3. 1. 故事
  4. 2. 章节
  5. 3. 输入活动
  6. 4. 回应
  7. 块
  8. 塔米尔如何运作
  9. 技术设置
  10. 先决条件
  11. 仓库的克隆
  12. 安装正确的节点版本
  13. 分支和发展
  14. 全权证书管理
  15. 代码质量检查
  16. 创建拉动请求( PR)
  17. 部署
  18. 解决问题
  19. 如何使用Thamyr SDK
  20. 设置和初始化
  21. 发送用户输入
  22. 无消息回合:降落、互动、刷新
  23. 关于输入框的建议
  24. 读取回合
  25. 块补丁
  26. 渲染块
  27. 动作中块渲染的全部示例
  28. 块组件示例( ImageBlock)
  29. API 命名空间
  30. 可用的命名空间
  31. 与成果合作
  32. 内容 API
  33. 故事 API
  34. 产品 API
  35. 低声API
  36. 分析 API
  37. 墨盒 API
  38. Skesis 和 Sitemap APIs 数据
  39. 从1.x、2.x或3.x升级

Thamyr SDK 文档

概览

Thamyr是Callimacus内部的AI代理,旨在生成并安排动态,直观的用户界面来适应用户意图和上下文. 通过利用专有AI算法,Thamyr在网站设计上超越了传统的打字方法,为用户创造了更沉浸和对上下文敏感的体验.

核心概念

1. 故事

一个"故事"(A Story)是包罗一个用户的旅程,意图,和上下文的总结构. 它由多个分会组成,每个分会代表了互动中独特的部分. 故事通过保持用户的用意和上下文来确保连续性,使Thamyr能够在不同互动之间保持相关性.

2. 章节

一个章节是"故事"中响应特定用户动作或投入的组件. 每个章节都是针对一个输入Event而生成的,可以基于先前的相互作用来演化.

3. 输入活动

一个输入Event是任何触发Thamyr响应的用户交互. 投入活动可以是:

  • 点击网站的一个元素.
  • 用户查询(书面或音频).

4. 回应

Thamyr 处理输入事件生成一个响应,反应由不同类型的块所组成. 这些块是UI的构件并代表了不同的内容形式.

块

A Block是Thamyr针对用户输入生成的内容单位. 每个区块可以是下列类型之一:

  • 文本块:一个简单的文本响应或消息.
  • 图像:可视化表现,如一相相.
  • 图片库: 一组图像一起显示.
  • 视频:一个包含视频的媒体块.
  • 富媒体:可以包含复杂内容的块,如嵌入式元素或交互式特性.
  • 专题:介绍与上下文相关的新主题或主题的块.
  • 自定义元素:一个用户定义的块类型,可以定制以满足特定需要或功能.

塔米尔如何运作

接收输入:当输入Event发生(例如用户点击按钮或问出问题)时,Thamyr接收并处理. 生成故事:根据输入事件,Thamyr在"故事"中确定适当的章节,并产生相关的响应. 创建块:Thamyr的反应由一个或多个块组成,然后这些块被安排为给定上下文创建尽可能最好的用户界面.


技术设置

先决条件

在开始前,请确保您有以下内容:

  • GitHub 账户: 您必须有一个 GitHub 账户才能访问和贡献项目.
  • Git和节点.js:确保您在本地机器上安装了 Git 和 Node.js .
  • nvm (节点版本管理器): 本项目使用 nvm 用于管理Node.js版本。 确保你有 数字 已安装.

仓库的克隆

  1. 访问仓库:在被允许访问寄存器后,您将获得一个克隆它的链接. 使用下列命令将仓库复制到本地机器:

    git clone https://github.com/your-org/your-repo.git
    
  2. 导航到仓库数字 :

    cd your-repo
    

安装正确的节点版本

  1. 安装节点版本: 存储器包含一个 .nvmrc 指定要使用的节点.js版本的文件。 要安装正确的版本, 请运行以下命令 :

    nvm install
    

    这将自动安装在 .nvmrc 文档.

  2. 使用正确的版本:安装完成后,可以通过运行使用指定的节点版本:

    nvm use
    

分支和发展

  1. 创建发展处:主分支用于生产,因此为任何特性或bug修复创建一个新的分支. 分支机构必须遵守命名公约:

    branch.repo.gymnasium.callimacus.ai
    

    示例

    git checkout -b new-feature.repo.gymnasium.callimacus.ai
    

    这保证了每个分支在部署时都有独特的URL.

  2. 更改: 本地开发并测试您的更改。 要遵循项目的编码惯例.

  3. 提交信件: 提交信息必须遵循 常规提交规格。这有助于确保一贯的承诺历史和自动版本.

    示例承诺消息 :

    feat(button): add primary button style
    
  4. 按下更改:在完成您的工作后, 将您的更改执行到 GitHub :

    git add .
    git commit -m "feat(new-feature): implement new feature"
    git push origin new-feature.repo.gymnasium.callimacus.ai
    

全权证书管理

  1. 基本 HTTP 认证:所有已部署的URL都由基本的HTTP认证保护. 您可以通过 Callimacus 后台。 。 。 .

  2. 客户身份: Callimacus 需要客户端ID (cal-pk-…)用于认证以正常运行. 要使用它, 请用您的客户端 ID 初始化 Callimacus 实例如下 :

    const instance = new Thamyr({
        clientId: import.meta.env.VITE_CALLIMACUS_CLIENT_ID,
    });
    

您可以通过 Callimacus 后台. 确保安全存储客户端ID,并在适当的环境变量中使用(VITE_CALLIMACUS_CLIENT_ID) (中文(简体) ).

代码质量检查

在将代码合并到 main 分支,确保您的代码通过质量检查。 这些检查包括:

  • 线性:检查代码样式,确保最佳做法.
  • 代码覆盖:确保为您的变化进行充分的测试和测试.

当生成牵引请求(PR)时,质量检查会自动通过CI管道运行. 然而,您可以在推动您的修改前在当地运行 :

npm run build && npm run lint && npm run test
  • 线性: 此命令将检查代码样式问题 .
  • 测试: 此命令将运行测试以验证您的代码是否如预期的那样行为 .

创建拉动请求( PR)

  1. 打开 PR: 一旦您的代码准备好, 请从您的分支创建拉出请求 (PR) (例如, ) , new-feature.repo.gymnasium.callimacus.ai改为: main 树枝.

  2. 通过质量检查:确保CI管道在合并前通过所有检查(投放、测试和覆盖)。 您可对任何错误或失败的检查进行公关状态监控 .

  3. 合并到主:在公关通过所有检查和审查后,你可以将其合并到 main 树枝。 这将引发对生产的部署.

部署

  • 前端主机:前端由Callimacus自动托管. 一旦合并到 main 切换到生产环境.
  • 预览环境: 您创建的每个分支将自动在格式下有一个独特的预览 URL branch.repo.gymnasium.callimacus.ai。 。 。 .

解决问题

  • 质量检查失败: 如果您的PR没有进行质量检查, 请查看 CI 管道中的错误信息 。 通常,这些出错与脱落或失败测试有关. 运行 npm run lint 财务报告和审定财务报表 npm run test 在再次推进之前先在当地查明和解决问题.

  • 部门命名问题: 确保您的分支名称遵循正确的格式。 如果分支名称不符合要求的模式,则可能不会被部署到预览环境.

  • 合并冲突:如果遇到合并冲突,请从中抽取最新的更改来解决 main 分支和更新您的特性分支 :

    git pull origin main
    

如何使用Thamyr SDK

设置和初始化

为了在您的项目中使用Thamyr SDK, 请遵循这些步骤:

  1. 安装 SDK: 首先,需要安装Thamyr SDK包. 在工程目录中运行以下命令 :

    npm install @callimacus/thamyr
    
  2. 启动 Thamyr: 在您的反应组件中,初始化 Thamyr 使用客户端标识, API 互动需要该标识。 为了安全目的,客户身份通常存储在环境变量中.

    示例

    import { useEffect, useRef, useState } from 'react';
    import { Thamyr, ThamyrResponseType } from '@callimacus/thamyr';
    
    function App() {
        const [chapters, setChapters] = useState([]);
        const thamyrRef = useRef(null);
    
        useEffect(() => {
            const instance = new Thamyr({
                 clientId: import.meta.env.VITE_CALLIMACUS_CLIENT_ID,
            });
    
            thamyrRef.current = instance;
    
            instance.onResponse(response => {
                if (response.type === ThamyrResponseType.CHAPTER_EVENT) {
                    setChapters(prev => {
                        const existingIndex = prev.findIndex(c => c.id === response.chapter.id);
                        if (existingIndex !== -1) {
                            const updated = [...prev];
                            updated[existingIndex] = response.chapter;
                            return updated;
                        } else {
                            return [...prev, response.chapter];
                        }
                    });
                }
            });
        }, []);
    }
    

提示:用反应建造? @callimacus/thamyr-react 用钩子包裹此 SDK( S)useInitThamyr({clientId}), (中文(简体) ), useThamyr, (中文(简体) ), useConnection, (中文(简体) ), useOnResponse, (中文(简体) ), useOnConnectionChange, (中文(简体) ), useOnError, (中文(简体) ), useOnWarning, (中文(简体) ), useApi, (中文(简体) ), useCart, (中文(简体) ), useSkesis, (中文(简体) ), useSitemap, (中文(简体) ), useMapPage, (中文(简体) ), useCallimacusStore附加时 useVoiceRecorder 财务报告和审定财务报表 useTtsAudio 用于语音输入和文字对语音回放),所以你从不自己管理实例.

发送用户输入

要触发互动并发送用户输入,需要处理用户事件,如文本输入或点击. 在下面的例子中,我们发送一个问题作为一个投入活动.

  1. 处理用户输入: 收集用户输入(例如从文本框中),并作为输入事件发送给Thamyr.

    import { UserInteractionType, SLInputEventType } from '@callimacus/thamyr';
    
    const handleAsk = () => {
        const inputSL = {
            type: SLInputEventType.question, // Type of input event
            data: { value: inputText } // User's input text
        };
        setInputText("Type your next question");
    
        thamyrRef.current?.sendUserInteraction(UserInteractionType.CREATE_ROUND, {
            inputEvent: inputSL,
        });
    };
    
  2. 触发用户交互:当用户按下 Enter 键时,您会将问题发送给Thamyr.

    const handleKeyDown = (e) => {
        if (e.key === "Enter") {
            e.preventDefault();
            handleAsk();
        }
    };
    

无消息回合:降落、互动、刷新

不是每个回合都从一个问题开始 租户的配置文件宣布了登陆页和登记名称 互动 存储前端可能发送; SDK 打开这些回合时有3个助手,所以你从不手工组装输入事件.

// The landing page, composed from the tenant's landing configuration.
// `value` is the landing value its blocks read ({{input.value}}) — a page slug, a campaign; at most 200 characters.
thamyr.openLanding('spring-edit', { language: 'it' });

// A declared interaction, with the block it comes from and what it carries.
thamyr.sendInteraction('pick-size', { block: 'hero', payload: { size: 'M' }, storyId });

// A refresh: the interaction sent with the block's key. The round composes like any other; a block
// whose `patchOn` names the interaction is updated in place instead (see Block patches).
thamyr.refresh('hero', 'reshuffle', { storyId });

每个帮手都拿 storyId 财务报告和审定财务报表 language 喜欢 CREATE_ROUND 有; 被宣布为 system 被记录和关闭,没有任何内容.

类型 sendInteraction 通过增加租户的登记 ThamyrInteractionMap 一次在您的项目中: id 成为已申报的 id 的联盟, 并且检查每个有效载荷 .

declare module '@callimacus/thamyr-core' {
  interface ThamyrInteractionMap {
    'pick-size': { size: string };
    reshuffle: undefined;
  }
}

在反应中,来自相同的三个助手 useThamyr() 并经过其连接门:

const { openLanding, sendInteraction, refresh } = useThamyr();

关于输入框的建议

suggest(prefix) 通过套接字的承认回答,从不作为故事的回答:租户的起步题,而前缀比三个字符短,从那里自动完成. 它从未拒绝——残疾的房客、失去的连接或超时(默认为4s)都决意不提出建议.

const { suggestions } = await thamyr.suggest(inputText, { storyId, timeoutMs: 2000 });

在反应中, useSuggestions(prefix, { storyId }) 以访问者类型来跟踪输入——已解出(默认为200 ms,空前缀一次询问),而后接的答案永远不会覆盖更新的前缀 :

const [text, setText] = useState('');
const { suggestions, loading } = useSuggestions(text, { storyId });

读取回合

三个东西一圆 值得阅读的名字,而不是挖 data数字 :

  • 受体 ——标签为分类者指定了此消息(不是会话意图). receptorsOf(chapter) 读取 chapter.receptors,掉到后面的 intent 名称为所用的旧服务器.
  • 块键 - 一个区块的身份由下列因素构成、固定和连接:; block.type 是两个块可能共享的参数提示. blockKeyOf(block) 从一个自定义块读取( 遗留块没有).
  • 点对点结果 ——当流量加到手推车上时,每个圆块都背负着它是如何发展起来的 data.addToCart· ; addToCartResultOf(block) 缩小到 {status: 'resolved' | 'size_selection_needed' | 'error', ...}。一个需要大小的圆 也发出一个 custom:addToCartResult 块ADD_TO_CART_RESULT_BLOCK) (中文(简体) ).
thamyr.onResponse((response) => {
  if (response.type !== ThamyrResponseType.CHAPTER_EVENT) return;
  const labels = receptorsOf(response.chapter);
  for (const block of response.chapter.blocks ?? []) {
    const result = addToCartResultOf(block);
    if (result?.status === 'size_selection_needed') showSizePicker(result.availableSizes);
  }
});

块补丁

块的活性内容声明在 patchOn,随块的密钥一起发送,不组成新回合:服务器用一个 block-patch 重置已放入屏幕的动画的响应. values, (中文(简体) ), inputs 财务报告和审定财务报表 textRuns 仅保留改变的事物; fire 列出一次播放的触发器, 按顺序排列( e) :input:<name> 或者说 vm:<name>) (中文(简体) ).

applyBlockPatch(chapter, patch) 返回与补丁合并到它命名的动画中的圆(patch.contentId,一个被点入的路径 block.data),或没有这种块的同一章. React and React Industrial stores 将它应用到历史中为您服务;补丁本身仍然到达 onResponse,这是玩的地方 fire,所以触发器永远不会从状态重放.

thamyr.onResponse((response) => {
  if (response.type !== ThamyrResponseType.BLOCK_PATCH) return;
  round = applyBlockPatch(round, response.data);
  player.fire(response.data.fire);
});

渲染块

Thamyr根据输入事件以不同类型的内容块响应. 您可以使用切换大小写结构或动态渲染来渲染您的用户界面中的这些块 .

在所提供的代码中,块会根据其类型来制取. 例如:

  • 文本块: 以纯文本显示.
  • 图像块: 显示为图像.
  • 视频块: 显示为视频.

以下是如何使不同的块类型:

const BlockRenderer = ({ block }) => {
    switch (block.type) {
        case "demosthenesResponse":
            return <TextBlock data={block.data} />;
        case "image":
            return <ImageBlock data={block.data} />;
        case "video":
            return <VideoBlock data={block.data} />;
        case "gallery":
            return <GalleryNew data={block.data} />;
        default:
            return <div>Unsupported block type: {block.type}</div>;
    }
};

动作中块渲染的全部示例

return (
    <div className="App">
        <div>
            {chapters.length > 0 ? (
                chapters.map((item, idx) => (
                    item.status === ChapterStatus.understandingQuery ? (
                        <p key={idx + 1}>Loading...</p>
                    ) : (
                        <div key={idx + 1}>
                            {item.blocks?.map(block => (
                                <BlockRenderer key={block.id} block={block} />
                            ))}
                        </div>
                    )
                ))
            ) : <p key={0}></p>}
        </div>
        <input
            type="text"
            value={inputText}
            onChange={e => setInputText(e.target.value)}
            placeholder="Type your question"
            onKeyDown={handleKeyDown}
        />
    </div>
);

(单位:千美元)ChapterStatus 从 @callimacus/thamyr. ) (中文(简体) )

块组件示例( ImageBlock)

const ImageBlock = ({ data }) => {
    return <img src={data.url} alt={data.content} className="rounded-lg shadow-lg" />;
};

export default ImageBlock;

API 命名空间

Thamyr SDK将其API组织成逻辑命名空间,以更好的代码组织和可发现性.

可用的命名空间

  • content - 页数、专题和文件
  • stories - 故事分享
  • products - 产品建议和类似性
  • whisper - 低声留言
  • analytics - 事件跟踪和分析
  • cart - 购物车业务
  • skesis - 类似及相关的骨架物品
  • sitemap - 现场地图检索

这个 content, (中文(简体) ), stories, (中文(简体) ), products, (中文(简体) ), whisper, (中文(简体) ), analytics, (中文(简体) ), cart 财务报告和审定财务报表 skesis 方法镜像平台 API 的一对一: 每一个都取出单个参数对象( 无参数读取像 cart.getCart 解决 {data, error, response},而新的终点会自动作为SDK释放的方法出现. 这个 sitemap namespace 保留其经典签名(直接解决值的许诺).

与成果合作

平台 API 调用解析 {data, error, response} 并且从不丢入 HTTP 错误 — 检查 error (或 response.status)而不是在尝试/捕捉中接通电话:

const thamyr = new Thamyr({
    clientId: import.meta.env.VITE_CALLIMACUS_CLIENT_ID,
});

const { data: page, error } = await thamyr.content.getPage({ language: 'en', id: 'home' });

if (error) {
    console.error('Could not load page:', error);
} else {
    renderPage(page);
}

"没有找到"也是个值: 在404上, data 实值 undefined, (中文(简体) ), error 携带尸体 response.status === 404; 在网络失败时 response 实值 undefined。如果您喜欢例外,请使用第二个选项参数(第一个关于无参数方法,例如 cart.getCart:结果缩小为 { data, request, response } 拒绝是 ThamyrHttpError (自4.1.0起)a Error 与 status, (中文(简体) ), body, (中文(简体) ), response 财务报告和审定财务报表 request数字 :

import { ThamyrHttpError } from '@callimacus/thamyr';

const { data: page } = await thamyr.content.getPage({ language: 'en', id: 'home' }, { throwOnError: true });

try {
    await thamyr.cart.addItemToCart({ productId }, { throwOnError: true });
} catch (error) {
    if (error instanceof ThamyrHttpError && error.status === 500) retryOnce();
}

内容 API

查阅网页、专题和文件. language 需要 —— 明确通过您的语言:

// Get a page by ID
const { data: page } = await thamyr.content.getPage({ language: 'en', id: 'home' });

// List topics
const { data: topics } = await thamyr.content.listTopics({ language: 'en' });

// Get the contents of a topic
const { data: contents } = await thamyr.content.getTopicContents({ language: 'en', idOrSlug: 'running' });

// Get a document by slug, group, or sitemap path
const { data: bySlug } = await thamyr.content.getDocumentBySlug({ language: 'en', slug: 'about-us' });
const { data: byGroup } = await thamyr.content.getDocumentByGroup({ language: 'en', groupId: 'group-42' });
const { data: byPath } = await thamyr.content.getDocumentByPath({ path: '/en/about-us' });

故事 API

分享一个故事

// Create a shareable link for a story
const { data: share } = await thamyr.stories.share({ id: 'story-123' });

// Get a shared story
const { data: shared } = await thamyr.stories.getShared({ id: 'share-id-123' });

产品 API

获得产品建议和类似项目:

// Get similar products — deprecated in favour of thamyr.skesis.similar; stays for all of 4.x, removed only after a product-shaped skesis read exists
const { data: similar } = await thamyr.products.getSimilar({ productId: 'product-123', topK: 10 });

// Get product recommendations — deprecated: use thamyr.skesis.related
const { data: recommendations } = await thamyr.products.getRecommendations({ productId: 'product-123' });

低声API

为一个故事获取最新的悄悄消息( 404 简单意味着还没有消息):

const { data, response } = await thamyr.whisper.getLast({ storyId: 'story-123' });

if (response.status !== 404) {
    showWhisper(data?.whisper);
}

分析 API

跟踪单个内容项目的事件 :

void thamyr.analytics.trackEvent({
   storyId: 'story-123',
   eventName: 'content_click',
   content: 'doc-42',
});

跟踪“ generic” 事件( 无内容 id) — 省略 content 如果您没有与事件相关的内容 :

void thamyr.analytics.trackEvent({
   storyId: 'story-123',
   eventName: 'button_click',
   payload: { buttonId: 'cta-primary', timestamp: Date.now() },
});

跟踪内容和自定义有效载荷:

void thamyr.analytics.trackEvent({
   storyId: 'story-123',
   eventName: 'content_click',
   content: 'doc-42',
   payload: {
      source: 'carousel',
      position: 2,
      highlighted: true,
   },
});

墨盒 API

管理购物车业务. 和每个合同的命名空间一样,推车方法采用平坦的参数对象并解决 {data, error, response} 信封——篮子是 data,而 HTTP 失败以 error绝不是拒绝 篮子外形是 Salesforce 自己出版的 SFCC schema (Basket) (中文(简体) ).

// Get current cart
const {data: cart, error} = await thamyr.cart.getCart();

// Add item to cart
const {data: updated} = await thamyr.cart.addItemToCart({productId: 'product-123'});

// Remove item from cart
await thamyr.cart.removeItemFromCart({productId: 'product-123'});

// Update product quantity
await thamyr.cart.updateProductQuantity({productId: 'product-123', quantity: 5});

Skesis 和 Sitemap APIs 数据

// Similar and related skesis items
const { data: similar } = await thamyr.skesis.similar({ anchorId: 'item-123', topK: 4 });
const { data: related } = await thamyr.skesis.related({ anchorId: 'item-123' });

// Full site map
const sitemap = await thamyr.sitemap.getSitemap();

从1.x、2.x或3.x升级

自 v1 以来, 电线协议没有改变 : 任何对同一服务器的重大交谈, 每段中断都是编译时间, 除了 向导要求的三件事: 错误处理、 重试、 构造器拒绝空或相对 endpoint 启动时( 4. 0.2).

从什么样的断裂何处
1.x 运算@callimacus/common 进口, accessToken,平面包装、位置性 REST 参数、轴式错误来自v1
2.x 数据thamyr.cart.* 位置参数和赤色 Basket 结果, CartAPI移动到 v3
3.x 运算SkesisAPI位置 skesis.*, (中文(简体) ), products.* 贬值(通过4.x), endpoint 审定(4.02), basketId 所需员额(4.0.3)移动到 v4

本包裹内的同一艘向导舰 MIGRATION.md旁边 CHANGELOG.md 财务报告和审定财务报表 CHANGELOG.core.md (docs网站需要一个Callimacus账户).


版本与发布记录

@callimacus/thamyr 共发布 39 个版本,首次发布于 2026/09/29;过去 12 个月发布了 39 个版本。

版本发布日期距今
4.23.5latest2026/11/09今天
4.23.42026/11/072 天前
4.23.32026/11/062 天前
4.23.22026/11/062 天前
4.23.12026/11/063 天前
4.23.02026/11/053 天前

关于 @callimacus/thamyr 的常见问题

@callimacus/thamyr 是什么?

Thamyr 的 Java 脚本包

如何安装 @callimacus/thamyr?

在项目目录运行 npm install @callimacus/thamyr,或使用 pnpm add / yarn add / bun add。

@callimacus/thamyr 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@callimacus/thamyr 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@callimacus/thamyr 可以商用吗?

@callimacus/thamyr 使用 SEE LICENSE IN LICENSE.md 许可。许可条款写在包内的独立文件中,请阅读该文件确认可否商用。以上为概括,不构成法律意见,请以许可原文为准。

@callimacus/thamyr 的下载量有多少?

根据 npm 官方下载统计,@callimacus/thamyr 在 2026/10/09 – 2026/11/07 这 30 天内被下载 6,486 次,日均约 216 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@callimacus/thamyr 还在维护吗?

最新版本 4.23.5 发布于 2026/11/09(今天);至今共发布 39 个版本,其中过去 12 个月发布了 39 个;首次发布于 2026/09/29。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。