Skip to content

feat(skills): content-hash publish/update, hide user-facing version - #87

Merged
liuxy0551 merged 29 commits into
DTStack:masterfrom
TreeTreeDi:feat_skills_hash_publish_update
Jul 29, 2026
Merged

feat(skills): content-hash publish/update, hide user-facing version#87
liuxy0551 merged 29 commits into
DTStack:masterfrom
TreeTreeDi:feat_skills_hash_publish_update

Conversation

@TreeTreeDi

@TreeTreeDi TreeTreeDi commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

摘要

  • 以 hash 为准的 Skills 合同publish / uploadupdate 用内容指纹(fingerprint)判断变更,不再要求用户填写 semver;version 仅作内部兼容占位(默认 0.0.0)。
  • CLI:裸 dt-skill update 同步全部已跟踪 skill;pin 会跳过;结束汇总 N updated / M up to date / P pinned skipped / F failed。首次发布必须选 category;同 hash 再发布为 no-op;hash 不同则覆盖(可确认 / --yes)。
  • Registry:详情只暴露单槽 skill.fingerprint;内容相同 no-op;内容变化则替换;首次发布 category 为封闭枚举。优化: update 命令拆分、slug 工具收敛、publish 创建路径测试修复。

范围说明

  • 规则包本 PR 不做,后续再议。
  • upload 仍是 publish 的别名,且仍要求目录含 SKILL.md

测试计划

  • cd dt-skill && npm run build && npm run test:src(Node ≥20)
  • 主服务:node --test test/skills-registry-contract.test.js(Node 18)
  • 手工:首次 publish(必选 category)→ 同内容 no-op → install + 裸 update → 改内容再 publish → update 跟新 → 非法 category 拒收 → pin 跳过 update
  • Web/API 可见 fingerprint;CLI 汇总计数符合预期

@TreeTreeDi TreeTreeDi changed the title feat(skills): hash-based publish/update without user-facing version feat(skills): 基于 hash 的发布/更新,隐藏用户侧 version Jul 28, 2026
TreeTreeDi pushed a commit to TreeTreeDi/doraemon that referenced this pull request Jul 28, 2026
Align the seven files that failed CI Prettier --check so PR DTStack#87 can pass the pipeline.
@liuxy0551

Copy link
Copy Markdown
Collaborator

Issues

Critical — 无

Important(建议修复)

  1. update.ts 中 up_to_date 分支锁文件重复写入
  • dt-skill/src/cli/commands/update.ts ~155-170 行和 ~227-228 行
  • up_to_date 分支内直接写了一次 writeLockfile,循环体末尾又无条件写一次,函数结尾还有第三次
  • 影响:虽然幂等,但造成不必要的 I/O,且让后续维护者困惑
  • 修复:移除 up_to_date 分支内的 writeLockfile,统一由 lockDirty = true + 循环后写入处理
  1. 测试 mock 中 latestVersion.fingerprint 是死数据
  • dt-skill/src/cli/commands/skills.test.ts 多处(~381, ~396, ~441 行)
  • Mock 返回 { latestVersion: { fingerprint: 'remote-new' } },但服务端 getSkillDetail 实际将 fingerprint 放在 skill.fingerprint,不在 latestVersion 上
  • remoteCurrentFromDetail 读的是 skill.fingerprint,所以 mock 中的 fingerprint 字段从未被使用
  • 影响:测试恰好通过,但没有真正验证 fingerprint 比较路径;阅读测试的人会误以为代码从 latestVersion.fingerprint 读取
  • 修复:mock 改为 { skill: { fingerprint: 'remote-fp' }, latestVersion: { version: '2.0.0' } } 匹配实际服务端响应结构,并补充 up_to_date 路径的测试用例
  1. Category 枚举在服务端和 CLI 重复定义
  • app/service/skillsRegistry.js:8-17 和 dt-skill/src/cli/commands/publish.ts:34-43 各自定义了 SKILL_CATEGORY_OPTIONS
  • 影响:服务端增删 category 时 CLI 会不同步。项目已有 contracts/skill-fingerprint/ 作为跨边界共享模块的先例
  • 修复:提取到共享 JSON 模块(类似 contracts/skill-categories/),两端导入

Minor

  1. ResolveVersionRef / ResolveResult 类型未使用 — dt-skill/src/cli/types.ts:22-30,疑似残留或为未来预留,建议加注释或删除
  2. decideSkillSync 缺少 "有 fingerprint 无 version" 的边界测试 — skillSync.ts:70-72,当前行为合理但未被测试覆盖
  3. Publish no-op 测试未验证 FormData payload 形状 — 可考虑补充

📋 Recommendations

  1. 参照 contracts/skill-fingerprint/ 模式,提取 contracts/skill-categories/ 共享模块
  2. 补充 skills.test.ts 中 hash 匹配 up_to_date 路径的测试(当前 mock 中 skill.fingerprint 未设置,fingerprint 比较始终为 null vs null)
  3. lockfile.ts 的 withPinnedMetadata 函数中,fingerprint: undefined 时静默丢弃是正确行为,建议加注释说明

@TreeTreeDi

Copy link
Copy Markdown
Contributor Author
  1. 写 lock 写两遍:确实多余。改成循环里只改内存,最后统一写一次。
  2. 测试 mock 不对:mock 已改,并加了「hash 一样就 up to date」的用例。
  3. category 两边各写一份:后面考虑这个功能优化下, 后面再抽公共配置,这轮先不动。

TreeTreeDi pushed a commit to TreeTreeDi/doraemon that referenced this pull request Jul 28, 2026
Remove ResolveVersionRef/ResolveResult left from the pre-hash update path
(ticket 01, PR DTStack#87 I1).
TreeTreeDi pushed a commit to TreeTreeDi/doraemon that referenced this pull request Jul 28, 2026
Remove unused resolve mock and rename case (ticket 03, PR DTStack#87 I3).
TreeTreeDi pushed a commit to TreeTreeDi/doraemon that referenced this pull request Jul 28, 2026
Add contracts/skill-categories and wire registry, skills service, and
CLI publish to one authoritative list (ticket 04, PR DTStack#87 I4).
@TreeTreeDi
TreeTreeDi force-pushed the feat_skills_hash_publish_update branch 2 times, most recently from b145759 to f252da7 Compare July 29, 2026 01:57
@TreeTreeDi
TreeTreeDi marked this pull request as ready for review July 29, 2026 09:48
huaiju added 20 commits July 29, 2026 18:03
Align Doraemon skills with vercel-style content hashing: publish/upload
pushes remote without requiring semver; re-publish is no-op when hash
matches; bare update refreshes all lock-tracked skills by fingerprint.
First publish requires category; CLI E2E verified against local registry.
Continue batch update after per-skill failures with a summary exit code,
confirm overwrite only when content hash differs, keep content no-ops free
of metadata churn, type resolve fingerprints, and validate category enums
server-side. Expand CLI and registry contract tests accordingly.
Extract SkillSync decide module and cmdUpdate command so the happy path
compares content fingerprints only (no resolve dual-signal). Registry
detail exposes fingerprint on skill alone; publishSkill splits normalize
/ noop / replace internals. skills.ts re-exports update; helpers share
slug and directory replace utilities.
Drop the duplicated normalizeSkillSlugOrFail copy left after C4 split.
Align the seven files that failed CI Prettier --check so PR DTStack#87 can pass the pipeline.
Write lockfile once when lockDirty after the update loop instead of mid-loop.
Align update mocks with skill.fingerprint and cover hash match up_to_date.
Remove unused imports from skills.ts, use const for publish version, and fix update.ts import order so CI ESLint passes.
Remove ResolveVersionRef/ResolveResult left from the pre-hash update path
(ticket 01, PR DTStack#87 I1).
Remove unused resolve mock and rename case (ticket 03, PR DTStack#87 I3).
When payload omits category, write the existing skill.category into the
update payload so retention is a deliberate contract (ticket 02, I2).
Add contracts/skill-categories and wire registry, skills service, and
CLI publish to one authoritative list (ticket 04, PR DTStack#87 I4).
Use http://172.16.100.225:7001 when no flag, env, cache, or site
discovery is set so CLI works out of the box (ticket 01).
Always normalize and return DEFAULT_REGISTRY; throw only if empty.
Assert --registry and DT_SKILL_REGISTRY beat default and cache (ticket 02).
Extract pickRegistryFromCliAndEnv used by cli.ts so override priority
is unit-tested on the shipped selection helper (ticket 02 review).
CLI help, README, and AGENTS.md cover built-in deploy URL and
DT_SKILL_REGISTRY / --registry for local dev (ticket 03).
Remove stale CLAWHUB_ / no-default wording; interpolate DEFAULT_REGISTRY in help.
huaiju added 4 commits July 29, 2026 18:03
Point repository/homepage/bugs at DTStack/doraemon, bump version to
0.18.4 for public npm, and include package LICENSE.
Local dt-skill publish (single and batch) fills contributor from
cwd git config user.name when set, logs the value, and fails if the
name exceeds 50 characters. Registry v1 publishSkill now persists
contributor so the single-skill path matches import-file.
@TreeTreeDi
TreeTreeDi force-pushed the feat_skills_hash_publish_update branch from f252da7 to 7c29957 Compare July 29, 2026 10:14
huaiju added 5 commits July 29, 2026 18:16
When v1 publish is a content hash no-op, still persist contributor if
the client sent it so git user.name attribution can change without a
file edit.
Release CLI that fills contributor from git user.name on local publish.
Drop the duplicate local helper in skills.ts; update.ts already uses
the shared skillHelpers implementation.
Pass the publish transaction into computeSkillFingerprint so the
unchanged no-op decision and file listing share one consistent view.
@TreeTreeDi TreeTreeDi changed the title feat(skills): 基于 hash 的发布/更新,隐藏用户侧 version feat(skills): content-hash publish/update, hide user-facing version Jul 29, 2026
@liuxy0551
liuxy0551 merged commit 5132137 into DTStack:master Jul 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants