Skip to content

Latest commit

 

History

History
314 lines (247 loc) · 6.93 KB

File metadata and controls

314 lines (247 loc) · 6.93 KB

Skillman 数据模型详细设计 (v2.2)

目标:打通 skill 的安装 / 发布 / 更新闭环,以及跨项目 skill 快速构建(以 profile 为唯一快速构建入口)


1. 设计原则

  1. Skillman 只管理 skill 目录生命周期,不解析 skill 内部格式。
  2. market 类型只支持 fsgit
  3. 安装记录不存 agent,用安装路径作为稳定事实。
  4. profile 以“路径分组 + skill 列表”表达,不反推 agent。
  5. source_type 必须保留:market / worktree
  6. config.json.agents 主要用于安装时声明相对路径;配置变更只影响新安装与运行时归类。

2. 目录结构

~/.skillman/
├── settings.json
├── skillman.lock
└── data/
    ├── config.json
    ├── market_subscriptions.json
    ├── markets/
    │   └── <market-name>/
    │       └── skills/
    ├── registry/
    │   ├── projects.txt
    │   └── installed_skills.json
    ├── profiles/
    │   └── <profile-name>.json
    ├── pending_prs.json
    └── worktrees/
        └── <market>-<skill>-<timestamp>/

3. settings.json

interface Settings {
  schema: 1;
  paths: {
    data_dir: string;
    log_dir: string;
  };
  defaults: {
    default_market?: string;
    default_install_mode: "copy" | "link"; // 默认 link
    default_agents?: string[]; // 默认 ["codex"]
  };
}

4. config.json(Market 与 Agent 配置)

type MarketType = "fs" | "git";

type SourceType = "market" | "worktree";
type InstallMode = "copy" | "link";

interface GitAuth {
  mode: "inherit" | "env" | "ssh" | "token";
  env?: Record<string, string>;
}

interface GitConfig {
  branch: string; // 默认 main
  auth?: GitAuth;
}

interface Market {
  name: string;
  type: MarketType;
  uri: string;          // 用户输入源
  install_path: string; // 本地 clone / 挂载根目录
  path: string;         // skills 根目录
  git?: GitConfig;
}

interface AgentConfig {
  name: string;       // codex / claude / gemini / 其他
  skill_path: string; // 项目内 skills 根目录;支持相对路径
  uninstall_cmd?: string;
}

interface ConfigFile {
  schema: 1;
  markets: Market[];
  agents: AgentConfig[];
}

4.1 uninstall_cmd 模板变量

支持变量:

  • {{project_root}}
  • {{install_root}}
  • {{market}}
  • {{skill_name}}

最小约定:

  • 这是一个完整命令模板。
  • 若为空:内置 codex/claude/gemini 用默认命令;其他 agent 记 warning 并跳过调用。

5. MarketSubscription

用于记录“某 market 在某项目哪个 skill 根路径生效过”。

interface MarketSubscription {
  market: string;
  project_root: string;
  install_root: string;
  installed_at: string;
  updated_at: string;
}

interface MarketSubscriptionsFile {
  schema: 1;
  subscriptions: MarketSubscription[];
}

主键:(market, project_root, install_root)

说明:

  • 不存 agent,因为 remove 阶段按“最新 agents 配置路径”动态归类。
  • 归类失败的路径进入“未匹配 agent”分组。

6. ProjectInstalledSkill(安装记录)

interface ProjectInstalledSkill {
  market: string;
  skill_name: string;

  project_root: string;
  install_root: string;
  install_path: string;  // 绝对路径 = install_root + "/" + skill_name
  relative_path: string; // 相对 project_root 的路径

  mode: InstallMode;

  source_type: SourceType;
  source_path: string;

  version: string; // git commit hash 或 mtime
  version_type: "git_commit" | "mtime";
  content_hash: string;

  installed_at: string;
  updated_at: string;
}

主键:(market, skill_name, install_path)

说明:

  • 同一 skill 安装到多个路径会产生多条记录。
  • 不依赖 agent 作为主键或必需字段。

7. Profile(跨项目快速构建)

7.1 模型

interface ProfileSkillRef {
  market: string;
  skill_name: string;
  mode: InstallMode;
  source_type: SourceType;
}

interface ProfilePathGroup {
  relative_path: string;        // 例如 .claude/skills
  skills: ProfileSkillRef[];
}

interface Profile {
  schema: 1;
  name: string;
  description?: string;
  items: ProfilePathGroup[];
  created_at: string;
  updated_at: string;
  source_project?: string;
}

7.2 snapshot 规则

  • relative_path 聚合已安装记录。
  • 每个路径下输出 skills[],元素最小字段为 { market, skill_name, mode, source_type }

7.3 apply 规则

  1. 通过 projects.txt 解析当前 project_root(最长前缀匹配)。
  2. 对每个 item.relative_path 计算 install_root = project_root + relative_path
  3. 逐 skill 安装到该 install_root
  4. source_type=worktree
    • 优先 worktree;
    • worktree 不存在则回退到 market;
    • market 也不存在则跳过该项并返回 warning。

8. PendingPR(worktree 生命周期)

interface PRConsumer {
  project_root: string;
  install_root: string;
  install_path: string;
  mode: InstallMode;
}

interface PendingPR {
  market: string;
  skill_name: string;
  branch: string;
  worktree_path: string;
  pr_number?: number;
  pr_url?: string;
  origin_project: string;
  consumers: PRConsumer[];
  created_at: string;
  updated_at: string;
}

interface PendingPRsFile {
  schema: 1;
  records: PendingPR[];
}

主键:(market, skill_name)


9. projects.txt

规则:

  • UTF-8 文本。
  • 一行一个 project_root 绝对路径。
  • 空行忽略。
  • 规范化后去重(Windows 忽略大小写)。
  • 保留首次写入顺序。

10. 运行时 agent 归类(market remove 专用)

interface AgentBucket {
  agent: string; // codex / claude / gemini / 其他配置名 / unmatched
  install_roots: string[];
}

function classifyInstallRoot(
  projectRoot: string,
  installRoot: string,
  agents: AgentConfig[]
): string {
  for (const agent of agents) {
    const expected = path.isAbsolute(agent.skill_path)
      ? path.normalize(agent.skill_path)
      : path.normalize(path.join(projectRoot, agent.skill_path));
    if (expected === path.normalize(installRoot)) return agent.name;
  }
  return "unmatched";
}

说明:

  • 保留 codex/claude/gemini/其他 agents 归类。
  • 任意安装路径匹配不上时进入 unmatched

11. 关系摘要

config.json(markets, agents)
        │
        ├── install(按选定 agent 解析 install_root)
        ▼
ProjectInstalledSkill(key: market+skill+install_path)
        │
        ├── snapshot/apply(按 relative_path 分组)
        ├── archive/worktree(source_type 生命周期)
        └── 聚合
               ▼
        MarketSubscription(key: market+project_root+install_root)

market remove:
1) 按 market 拉取记录
2) 处理 link/copy 清理
3) 按最新 agents 路径归类(含 unmatched)并执行卸载调用
4) 清理 subscription/pending/config