# 铁铺 (TiePM) 设计笔记
> **版本**:v0.1.0 | **状态**:早期开发阶段
> 本文档由ClaudeFable5生成。
---
## 设计目标
铁铺是玄铁语言的包管理器,核心目标:
1. **安装**:从远程索引获取包,下载、验证哈希、解压到本地
2. **搜索**:按关键词搜索可用铁器
3. **发布**:将本地项目打包并登记到远程索引
4. **轻量**:不依赖第三方包管理器运行时(Node.js/Python 等),核心逻辑用玄铁自举实现
---
## 架构总览
```
┌─────────────────┐ HTTP ┌──────────────────┐
│ 铁铺 CLI │ ◄──────────► │ TiePM 官网 │
│ (铁铺.xt) │ JSON API │ (tiepm-site/) │
│ │ │ Go + 静态 HTML │
├─────────────────┤ ├──────────────────┤
│ • 安装/搜索/发布 │ │ GET /api/index │
│ • SHA256 验证 │ │ POST /api/publish │
│ • TOML 清单解析 │ │ GET /api/search │
│ • 本地缓存管理 │ │ GET /download/* │
└─────────────────┘ └────────┬─────────┘
│ 读写
┌──────▼──────────┐
│ data/index.json│
│ (包索引文件) │
└─────────────────┘
```
**关键设计决策**:
- **索引与源码分离**:官网只托管包索引 JSON,包源码由 GitHub Releases 承载。TiePM 不存储任何包文件。
- **无状态服务**:Go 服务器以本地 JSON 文件作为持久化存储,无需数据库。
- **embed 静态文件**:HTML/CSS 通过 Go 1.16+ `embed.FS` 编译进二进制,单文件部署。
- **裸包名导入**:编译器自动识别裸包名(无路径前缀的 `引 "包名"`),解析到 `~/.tiepm/已安装/<包名>/` 下查找入口文件。安装后使用体验与 npm/pip 一致——无需手写路径。
---
## 包索引格式
索引文件为单个 JSON 对象,结构如下:
```json
{
"数组工具": {
"1.0.0": {
"版本": "1.0.0",
"哈希": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6...",
"仓库": "https://github.com/username/array-utils",
"作者": "张三",
"描述": "提供数组去重、过滤、映射等工具函数"
}
}
}
```
字段说明:
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| 版本 | 字 | 是 | 语义版本号(如 `1.0.0`) |
| 哈希 | 字 | 是 | 打包文件 SHA256 十六进制字符串 |
| 仓库 | 字 | 是 | GitHub 仓库地址,用于构造下载 URL |
| 作者 | 字 | 否 | 包作者/维护者名称 |
| 描述 | 字 | 否 | 包功能简述 |
索引顶层 key 为包名,包名下可包含多个版本。`/api/search` 返回每个包的最新版本。
---
## API 设计
### GET /api/index
返回完整索引用 JSON。
### GET /api/search?q=<关键词>
按关键词搜索包名和描述,返回数组:
```json
[
{
"名称": "数组工具",
"最新版本": "1.0.0",
"作者": "张三",
"描述": "提供数组去重、过滤、映射等工具函数"
}
]
```
### POST /api/publish
登记新包或新版本。请求体:
```json
{
"名称": "数组工具",
"版本": "1.0.0",
"哈希": "a1b2c3...",
"仓库": "https://github.com/username/array-utils",
"作者": "张三",
"描述": "数组操作工具"
}
```
成功返回 `{"状态":"成功","消息":"..."}`。缺少必填字段返回 400。
### GET /download/:name/:version
302 重定向到 `{仓库}/archive/v{版本}.zip`(GitHub 自动打包)。
---
## 编译期裸包名解析
铁铺最核心的设计创新在于**编译器直接参与包解析**。当编译器遇到不带路径前缀的 `引` 语句(如 `引 "数组工具"`),自动在铁铺安装目录下查找:
### 解析逻辑
```
引 "数组工具" (裸包名)
│
├─ isBarePackageName() → 真(无 \、/、: 且不以 . 开头)
│
├─ getTiePMInstallDir() → ~/.tiepm/已安装
│ ├─ 优先使用 $TIEPM_HOME 环境变量
│ └─ 否则使用 %USERPROFILE%\.tiepm\已安装
│
├─ resolveTiePMPackagePath()
│ ├─ 方案1: <安装目录>\数组工具\数组工具.xt
│ ├─ 方案2: <安装目录>\数组工具\<内层目录>\数组工具.xt
│ │ (GitHub archive 格式: <名>-<版本>/)
│ └─ 均失败 → 空字符串
│
└─ 成功 → 使用解析后的绝对路径编译
失败 → 报错"请先执行 '铁铺 安装 数组工具'"
```
### 实现位置
| 编译器 | 文件 | 关键函数 |
|--------|------|----------|
| 自举编译器 | `编译.xt` | `是裸包名()`, `获取铁铺安装目录()`, `解析铁铺包路径()`, `预扫描引入()` |
| Go 种子 | `compiler/compiler.go` | `isBarePackageName()`, `getTiePMInstallDir()`, `resolveTiePMPackagePath()`, `importExpressionCode()` |
| Go 解释器 | `evaluator/evaluator.go` | 同名函数(Eval 后缀), `evalImportExpression()` |
---
## 安装流程
```
铁铺 安装 <包名>
│
├─ 1. GET /api/index 获取远程索引
├─ 2. 查找包名,获取最新版本的哈希、仓库
├─ 3. 构造 URL: {仓库}/archive/v{版本}.zip
├─ 4. 下载 ZIP 到 ~/.tiepm/缓存/
├─ 5. SHA256 验证(certutil -hashfile)
├─ 6. tar -xf 解压到 ~/.tiepm/已安装/<包名>/
└─ 7. 清理下载缓存
```
### 本地目录结构
```
~/.tiepm/
├── 缓存/ # 下载的 ZIP 缓存
└── 已安装/ # 已安装的包
├── 数组工具/ # 每个包独立目录
└── ...
```
---
## 发布流程
```
项目根目录/
├── tiepm.toml # 包清单
├── src/ # 源代码
└── ...
```
### tiepm.toml 清单
```toml
[包]
名称 = "数组工具"
版本 = "1.0.0"
仓库 = "https://github.com/username/array-utils"
[作者]
姓名 = "开发者名"
邮箱 = "dev@example.com"
[描述]
简介 = "提供数组去重、过滤、映射等工具函数"
许可 = "MIT"
```
### 发布步骤
1. 编写 `tiepm.toml`
2. 执行 `铁铺 发布` — 打包为 `.zip` 并计算 SHA256
3. `git tag v1.0.0 && git push --tags`
4. 创建 GitHub Release,上传 `.zip`
5. 执行 `curl -X POST /api/publish` 向索引登记
---
## 安全设计
### 哈希验证
安装时必须验证下载文件的 SHA256 哈希与索引中记录的一致。当前通过 Windows `certutil -hashfile` 实现,后续计划用纯玄铁实现 SHA256。
### 线程安全
Go 服务端使用 `sync.RWMutex` 保护索引读写,支持并发查询但写入独占。
### 输入验证
- 发布 API 校验必填字段(名称、版本、哈希),缺少则返回 400
- 搜索 API 对关键词做大小写不敏感处理
- 哈希日志预览安全截断(<=16 字符直接显示,超过则截取并加 `...`)
---
## 已知局限与后续规划
| 局限 | 说明 | 计划 |
|------|------|------|
| 依赖解析递归深度限制 | 最大 10 层嵌套依赖 | 可配置 |
| 版本冲突无自动解决 | 冲突需手动统一版本 | v0.3+ 自动选择策略 |
| 无权限控制 | 发布无认证机制 | v0.3+ |
| Windows 限定 | 哈希/解压依赖 cmd 命令 | 跨平台支持 |
| 单索引源 | 仅支持一个远端索引 | 多注册表支持 |
---
## 项目文件结构
```
tiepm/ # 铁铺核心库(玄铁源码)
├── 核心.xt # 包管理核心逻辑
├── 核心_test.xt # 测试
└── 示例tiepm.toml # 清单模板
tiepm-site/ # 铁铺官网(独立 Go 项目)
├── .gitignore # 排除于玄铁主仓库
├── main.go # Go HTTP 服务端
├── static/
│ ├── index.html # 前端页面
│ └── style.css # 样式(深色主题)
└── data/
└── index.json # 包索引数据(运行时生成)
铁铺.xt # 独立 CLI 入口(可直接编译执行)
```
---
## 技术栈
| 组件 | 技术 | 原因 |
|------|------|------|
| CLI | 玄铁自举 | 展示语言能力,零外部依赖 |
| 官网后端 | Go + net/http | 单文件部署,无框架依赖 |
| 官网前端 | 原生 HTML/CSS/JS | 零构建步骤,embed 到二进制 |
| 源码托管 | GitHub Releases | 利用现有 CDN,无存储成本 |
| 索引存储 | 本地 JSON 文件 | 无数据库运维,Git 可追踪 |