🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

用量声明与上报 yzsnstotz/hanamesh-usage

DeepSeek Harness
yzsnstotz35 天前有提交已提供中文文档扫描:含敏感能力

记录本机用量摘要并签名上报服务器

29.8/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add yzsnstotz/hanamesh-usage
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么[目录]—
dsh 原生插件 · other
暂无时间戳·判据 →
装得上吗[实装验证]—
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
数据截至 2026/10/04·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/05·判据 →
还在维护吗[仓库]—
更新放缓:最近一次提交在 35 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 50 处,展示前 50 条)
  • 写入本地文件
    docs/acceptance/session-g-inner-hook-probe.mjs:21
    else if(x.method==='tools/call'){await appendFile(process.env.PROBE_FIXTURE_LOG,JSON.stringify({name:x.params.name})+'\n');result={content:[{type:'tex
  • 写入本地文件
    docs/acceptance/session-g-inner-hook-probe.mjs:29
    await appendFile(process.env.PROBE_HOOK_LOG,JSON.stringify(row)+'\n');
  • 写入本地文件
    docs/acceptance/session-g-inner-hook-probe.mjs:35
    for(const n of ['codex','claude','shared','agent'])await mkdir(join(root,n));
  • 执行外部命令来自配置/变量
    docs/acceptance/session-g-inner-hook-probe.mjs:37
    const version=spawnSync(receipt.hostBinary,['--version'],{cwd:root,env,encoding:'utf8',timeout:10000});if(version.status!==0)throw new Error('BUNDLED_
  • 写入本地文件
    docs/acceptance/session-g-inner-hook-probe.mjs:56
    await writeFile(join(root,'codex','config.toml'),config);
  • 写入本地文件
    docs/acceptance/session-g-inner-hook-probe.mjs:58
    await writeFile(join(root,'codex','hooks.json'),JSON.stringify({hooks:Object.fromEntries(['PreToolUse','PostToolUse','PostToolUseFailure'].map(event=>
  • 执行外部命令来自配置/变量
    docs/acceptance/session-g-inner-hook-probe.mjs:59
    child=spawn(receipt.hostBinary,['exec','--skip-git-repo-check','--ephemeral','--ignore-rules','--dangerously-bypass-hook-trust','--json','Run the disp
  • 读取本地文件
    docs/acceptance/session-g-inner-hook-probe.mjs:63
    const lines=async p=>{try{return(await readFile(p,'utf8')).trim().split('\n').filter(Boolean).map(JSON.parse);}catch{return[];}};
  • 删除本地文件递归
    docs/acceptance/session-g-inner-hook-probe.mjs:72
    await rm(root,{recursive:true,force:true});let groupExists=false;if(child?.pid){await new Promise(resolve=>setTimeout(resolve,25));try{process.kill(-c
  • 写入本地文件
    docs/acceptance/session-g-inner-hook-probe.mjs:74
    const out=process.argv[2]??join(dirname(self),'session-g-inner-hook-probe.json');await writeFile(out,JSON.stringify(receipt,null,2)+'\n');process.stdo
  • 写入本地文件
    src/agent/cli.mjs:33
    await mkdir(r.agentHome,{recursive:true,mode:0o700});
  • 读取本地文件
    src/agent/codex-remote.mjs:20
    try{versions=token(name)?(await readdir(base,{withFileTypes:true})).filter(v=>v.isDirectory()):[];}catch(error){if(error.code!=='ENOENT')throw error;}
  • 读取本地文件
    src/agent/codex-remote.mjs:24
    try{skills=(await readdir(join(root,'skills'),{withFileTypes:true})).filter(s=>s.isDirectory()&&token(s.name)).map(s=>s.name);}catch(error){if(error.c
  • 写入本地文件
    src/agent/hook.mjs:30
    if(row){await mkdir(r.agentHome,{recursive:true,mode:0o700});const release=await agentLock(r.agentHome,'collection',r.config.requestTimeoutMs);if(!rel
  • 读取本地文件
    src/agent/inventory.mjs:11
    let skills=[];try{skills=(await readdir(join(root,'skills'),{withFileTypes:true})).filter(item=>item.isDirectory()&&safeName(item.name)).map(item=>ite
  • 读取本地文件
    src/agent/inventory.mjs:25
    let config;try{config=await readFile(join(hostHome,'config.toml'),'utf8');}catch(error){if(error.code==='ENOENT')config='';else throw error;}
  • 读取本地文件
    src/agent/inventory.mjs:34
    let versions;try{versions=await readdir(root,{withFileTypes:true});}catch(error){if(error.code==='ENOENT')throw new Error('AGENT_INSTALLATION_UNREADAB
  • 写入本地文件
    src/agent/notice.mjs:22
    const dir=join(r.agentHome,'notices');await mkdir(dir,{recursive:true,mode:0o700});
  • 写入本地文件
    src/agent/onboarding.mjs:18
    await r.call({operation:'syncOnboarding'});await mkdir(r.agentHome,{recursive:true,mode:0o700});await atomicJSON(join(r.agentHome,'onboarding.json'),{
  • 写入本地文件
    src/agent/onboarding.mjs:23
    if(synced.consent.state==='granted'&&synced.consent.authorization==='website'){await mkdir(r.agentHome,{recursive:true,mode:0o700});await atomicJSON(j
  • 写入本地文件
    src/agent/onboarding.mjs:25
    if(synced.onboarding?.binding){await mkdir(r.agentHome,{recursive:true,mode:0o700});await atomicJSON(join(r.agentHome,'onboarding.json'),{state:'bound
  • 写入本地文件
    src/agent/onboarding.mjs:32
    const next={...result,state:'pending'};await mkdir(r.agentHome,{recursive:true,mode:0o700});await atomicJSON(join(r.agentHome,'onboarding.json'),next)
  • 读取本地文件
    src/agent/preparation.mjs:18
    const dir=join(r.agentHome,'preparation');let names;try{names=await readdir(dir);}catch(error){if(error.code==='ENOENT')return;throw error;}
  • 删除本地文件
    src/agent/preparation.mjs:28
    if(catalog&&Date.parse(item.occurredAt)<now-catalog.settings.backfillWindowDays*86400000){await rm(join(dir,name));continue;}
  • 删除本地文件
    src/agent/preparation.mjs:31
    await r.store.record(row,true);await rm(join(dir,name));
  • 写入本地文件
    src/agent/remote-catalog.mjs:10
    await mkdir(r.agentHome,{recursive:true,mode:0o700});await atomicJSON(join(r.agentHome,'catalog.json'),catalog);r.cachedCatalog={value:catalog,fetched
  • 执行外部命令来自配置/变量
    src/agent/runtime.mjs:37
    const child=spawn(process.execPath,[paths.coreCLI],{stdio:['pipe','pipe','pipe'],env:{PATH:env.PATH,HOME:env.HOME ?? homedir(),TMPDIR:env.TMPDIR}});
  • 写入本地文件
    src/agent/runtime.mjs:45
    async configure(value){await mkdir(paths.agentHome,{recursive:true,mode:0o700});await atomicJSON(join(paths.agentHome,'config.json'),value);},
  • 发起网络请求
    src/agent/runtime.mjs:49
    const response=await fetch(new URL(path,origin),{...init,redirect:'error',credentials:'omit',signal:AbortSignal.timeout(timeoutMs)});
  • 读取本地文件
    src/agent/store.mjs:7
    try{return JSON.parse(await readFile(path,'utf8'));}catch(error){if(error.code === 'ENOENT')return fallback;throw error;}
  • 删除本地文件
    src/agent/store.mjs:11
    try{const fd=await open(temp,'wx',0o600);try{await fd.writeFile(JSON.stringify(value));await fd.sync();}finally{await fd.close();}await rename(temp,pa
  • 写入本地文件
    src/agent/store.mjs:11
    try{const fd=await open(temp,'wx',0o600);try{await fd.writeFile(JSON.stringify(value));await fd.sync();}finally{await fd.close();}await rename(temp,pa
  • 写入本地文件
    src/agent/store.mjs:20
    await mkdir(this.root,{recursive:true,mode:0o700});
  • 写入本地文件
    src/agent/store.mjs:42
    await mkdir(this.dir,{recursive:true,mode:0o700});
  • 读取本地文件
    src/agent/store.mjs:55
    let names;try{names=await readdir(this.dir);}catch(error){if(error.code==='ENOENT')return [];throw error;}
  • 删除本地文件
    src/agent/store.mjs:61
    for(const row of await this.rows())if(Date.parse(row.occurredAt)<now-settings.backfillWindowDays*86400000){await rm(join(this.dir,`${row.factId}.json`
  • 读取本地文件
    src/agent/store.mjs:62
    let names;try{names=await readdir(this.installDir);}catch(error){if(error.code!=='ENOENT')throw error;names=[];}
  • 写入本地文件
    src/agent/store.mjs:81
    await mkdir(this.installDir,{recursive:true,mode:0o700});await atomicJSON(join(this.installDir,`${wire.eventId}.json`),{eventId:wire.eventId,wire});re
  • 删除本地文件递归
    src/agent/store.mjs:95
    async withdraw(){return this.mutate(async()=>{await rm(this.dir,{recursive:true,force:true});await rm(this.installDir,{recursive:true,force:true});awa
  • 读取本地文件
    src/agent/trust.mjs:8
    let text;try{text=await readFile(join(env.CODEX_HOME,'config.toml'),'utf8');}catch(error){if(error.code==='ENOENT')return {state:'not-installed',effec
  • 写入本地文件
    src/agent/upload.mjs:15
    await mkdir(r.agentHome,{recursive:true,mode:0o700});
  • 写入本地文件
    src/agent/upload.mjs:29
    const inflight=join(r.agentHome,'inflight');await mkdir(inflight,{recursive:true,mode:0o700});const marker=join(inflight,`${key}.json`);
  • 删除本地文件
    src/agent/upload.mjs:35
    await mark({state:rejection?'rejected':result.duplicates?'duplicate':'sent',code});await rm(marker,{force:true});
  • 读取本地文件
    src/agent/withdraw.mjs:22
    let unknown=[];try{unknown=(await readdir(join(r.agentHome,'inflight'))).filter(name=>/^(?:[a-f0-9]{64}|[a-f0-9-]{36})\.json$/.test(name));}catch(erro
  • 删除本地文件递归
    src/agent/withdraw.mjs:28
    await rm(join(r.agentHome,'inflight'),{recursive:true,force:true});
  • 写入本地文件
    src/agent/withdraw.mjs:35
    await mkdir(r.agentHome,{recursive:true,mode:0o700});
  • 删除本地文件递归
    src/agent/withdraw.mjs:38
    try{const stopped=await r.call({operation:'consent',state:'withheld'});await atomicJSON(join(r.agentHome,'withdrawal.json'),{state:'pending',consentId
  • 发起网络请求
    src/client/index.ts:31
    return carrier?.fetch?carrier.fetch(path,init):globalThis.fetch(path,init);
  • 发起网络请求
    src/client/index.ts:194
    ? await carrier.fetch('api/hanamesh/usage/panel/view',init)
  • 发起网络请求
    src/client/index.ts:195
    : await globalThis.fetch('api/hanamesh/usage/panel/view',init);
扫描于 2026/11/5(0 天前) · 范围 全包扫描(包内未声明入口) · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-agent@deepseek-ai/dsh-attachment@deepseek-ai/dsh-client-connection@deepseek-ai/dsh-llm@deepseek-ai/dsh-scope@deepseek-ai/dsh-session@deepseek-ai/dsh-session-persistence@deepseek-ai/dsh-storage@deepseek-ai/dsh-storage-domain@deepseek-ai/dsh-system-prompt@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 记录本机用量摘要
  • 签名上报服务器

README

由 DeepSeek 最新模型翻译生成
hanamesh-usage · 0.2.0-rc.7 版本 0.2.0-rc.7;交付上限为 🧪 DELIVERED,只有用户可签 ACCEPTED。已实测内核:0.1.5-alpha.1、0.1.5-rc.2;rc.7(T6)启用事件的两个归因可选字段 sourceHanaRef / targetRef,并给 use 事件加可选 receipt {providerId, model|null, count}(使用回执,不记内容):本地账本、上报、去重身份、/events、/view 都带上;缺省为 null,rc.6 及更早的本地事件原样可读;record 席位接受这三个键(供 app-host 等投递),六键签名不变。rc.6 把 peerDependencies 里的 @deepseek-ai/dsh- 从精确钉 0.1.5-alpha.1 改为已实测范围 >=0.1.5-alpha.1 <0.2.0(@deepseek-ai/cordis >=4.0.2 <5),代码不变;rc.5 对齐 O1 冻结的上报契约。构建/离线闭包仍钉 DSH 0.1.5-alpha.1(devDependencies/overrides)。
展开完整文档(README 剩余 1 节)
hanamesh-usage · 0.2.0-rc.7

版本 0.2.0-rc.7;交付上限为 🧪 DELIVERED,只有用户可签 ACCEPTED。已实测内核:0.1.5-alpha.1、0.1.5-rc.2;rc.7(T6)启用事件的两个归因可选字段 sourceHanaRef / targetRef,并给 use 事件加可选 receipt {providerId, model|null, count}(使用回执,不记内容):本地账本、上报、去重身份、/events、/view 都带上;缺省为 null,rc.6 及更早的本地事件原样可读;record 席位接受这三个键(供 app-host 等投递),六键签名不变。rc.6 把 peerDependencies 里的 @deepseek-ai/dsh- 从精确钉 0.1.5-alpha.1 改为已实测范围 >=0.1.5-alpha.1 <0.2.0(@deepseek-ai/cordis >=4.0.2 <5),代码不变;rc.5 对齐 O1 冻结的上报契约。构建/离线闭包仍钉 DSH 0.1.5-alpha.1(devDependencies/overrides)。本版提供改名后的用量声明、7 字段设备签名事件、上报/撤回和 Loader 库存发现;本包是 DSH bundle,dsh plugin add 即激活。P1/O1 未登记时真实门分别使用 STANDIN/STUB;inventory 结论为 loader。收录不代表审核或推荐。

hanamesh-usage 保留本机 Declaration 三态使用摘要,并提供同意门、设备签名、事件缓冲与服务器上报。生产路径只保存结构化最小信息,不保存 prompt、对话、文件、完整结果、私有路径或凭据。

安装

hanamesh-usage 是一个 DSH bundle(package.json 声明 dsh.bundle.patch):

dsh plugin --profile add hanamesh-usage

装完即激活,不需要手写 cordis.patch.yml。它是 HanaMesh 套件的一员:装 hanamesh-core 会一次带上本包与 @hanamesh/dsh-app-host,由 core 的 patch 统一激活。

套件与单包互斥(双向):
- 已单独装过本包,再装 hanamesh-core → DSH 启动失败:duplicate loader entry id: hanamesh-usage。先 dsh plugin --profile remove hanamesh-usage,再装 core;本机记录(storage-domain hanamesh_usage)不会丢,同一 profile 里重新激活后仍在。
- 已装套件(core),再显式 add hanamesh-usage → 同样 duplicate loader entry id: hanamesh-usage。撤销这次 add(remove hanamesh-usage)即恢复;套件里的 usage 不受影响。
- 这是 DSH 的既定行为(重复 loader id 让整个 profile 起不来),本插件不做静默去重;失败是响亮的,不会出现两份采集。

依赖: 设备身份与同意开关来自 hanamesh-core(可选)。core 缺席时本插件只在本机记录、不上报,/api/hanamesh/usage/health 显示 core: 'absent'。

从 rc.3(@hanamesh/dsh-activity)升级: storage-domain 由 hanamesh_activity 改为 hanamesh_usage,旧记录不迁入、不删除;需要保留请先在 rc.3 上 POST /api/hanamesh/activity/export 导出。

首次 Loader 扫描会把当前已装插件记为 install,occurredAt 使用扫描时刻;这是 Adoption 弱证据。宿主没有更强的实时 install/uninstall 事件,本版只做跨启动快照比较。

本地接口

- GET /api/hanamesh/usage
- GET /api/hanamesh/usage/view
- POST /api/hanamesh/usage/export
- GET /api/hanamesh/usage/health
- GET /api/hanamesh/usage/events

ctx.hanameshUsage 提供 query、export、health、drain、reconcile 与 record。record 只接受其它 HanaMesh 插件投递的 open / use,安装与卸载由 Loader 观测产生。rc.7 起 record 还接受可选 sourceHanaRef(来源 Hana,npm 包名)、targetRef(目标应用 / 会话,≤160 的 [A-Za-z0-9][A-Za-z0-9_.:-])与只配 use 的 receipt {providerId, model|null, count≥1};同一 idempotencyKey 再投递不同归因或回执得到 rejected: EVENT_IDENTITY_CONFLICT,不覆盖。

隐私与上报边界

- 未同意时不创建 UsageEvent,也不向 Server 上报;本机 Declaration 摘要仍可保留。
- 上线事件必含 deviceId、hanaRef、action、occurredAt、eventId、nonce、signature 七个键;rc.7 起 sourceHanaRef、targetRef、receipt 只在非 null 时随事件上线(服务端把它们纳入内容 digest,不纳入签名)。回执只有供应商 id、模型名和次数,没有 prompt、响应或凭据。
- 撤回先清本地事件缓冲,再调用 Server 删除接口;离线时只完成本地删除并保留可重试状态。
- Declaration 只留本机;它不会作为 summary 上传。

开发与验证

目标工具链:Node 24.13.1、pnpm 10.33.0、TypeScript 5.9.3。仓内使用 npm lockfile;依赖安装前用独立 npm_config_cache。

npm run build:offline
npm test
npm run test:mutations
npm run check
npm run test:detached

真实门必须使用全新隔离的 DSH_HOME 与随机端口;不得触碰 ~/.dsh 或 3080。STUB/STANDIN 证据不能替代 REAL_SERVER/REAL_CORE。
预览分享卡片长什么样 ↓yzsnstotz/hanamesh-usage
分享 · DeepSeek Harness Hub
yzsnstotz/hanamesh-usage

记录本机用量摘要并签名上报服务器

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部