|
|
@@ -1,151 +1,233 @@
|
|
|
-# skill-storage · 对象存储与公开分享技能
|
|
|
+# skill-storage · 对象存储与公开分享
|
|
|
|
|
|
-> AI Agent 的"仓库管理员"——二进制大文件(图片/音频/视频/报告 HTML)上云,本地零占用,一键生成公开分享链接。
|
|
|
+> **未来飞马 — 让AI进化提前发生,让AI落地快人一步**
|
|
|
|
|
|
[](LICENSE)
|
|
|
+[](#快速开始)
|
|
|
+[](https://www.npmjs.com/package/fmode-storage)
|
|
|
|
|
|
-## 零配置用法(0 步,推荐)
|
|
|
+---
|
|
|
|
|
|
-**当前版本(0.4.0)默认通道免密钥**:只要容器/环境里有登录态 `sessionToken`(数字生命容器默认就有),直接上传即可拿到公开链接——不用申请 AK/SK、不用 init。
|
|
|
+## 简介
|
|
|
+
|
|
|
+`skill-storage` 是智能体的「仓库管理员」:把二进制大文件(图片 / 音频 / 视频 / 报告 HTML)上传到对象存储,本地磁盘零长期占用,一键生成可转发的公开分享链接。
|
|
|
+
|
|
|
+**默认通道免密钥**:只要环境里有登录态 `sessionToken`,平台云函数即按调用者身份签发上传地址——不用申请 AK/SK、不用初始化。密钥由云函数保管,**永不下发到调用方**。
|
|
|
+
|
|
|
+本技能以 ESM 原生模块交付,Node.js ≥ 18 直接 `import`,零依赖、零构建。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 核心定位
|
|
|
+
|
|
|
+| 维度 | 说明 |
|
|
|
+|------|------|
|
|
|
+| **解决什么** | 大文件上云 + 公开链接生成:报告发布即分享、素材托管、批量上传 |
|
|
|
+| **不解决什么** | 不做文件转码、不做内容审核、不托管长期私有数据 |
|
|
|
+| **与网盘的区别** | 产出的是**可直接嵌入/转发的公网 URL**,而非需要登录的分享页 |
|
|
|
+| **层级** | 服务级(Platform Services) |
|
|
|
+| **适用平台** | FmodeAgent · FmodeCode |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 核心能力 & 交付物
|
|
|
+
|
|
|
+- 📤 **大文件上传** —— 对象存储直传,本地磁盘零长期占用
|
|
|
+- 🔗 **公开分享链接** —— 上传即得公网 URL,可直接转发或嵌入
|
|
|
+- 📄 **报告发布即分享** —— HTML 报告/课件传完即得可转发链接
|
|
|
+- 🧪 **自检命令** —— `test` 上传→删除探针文件,全链路验证
|
|
|
+- 🧹 **生命周期管理** —— 前缀用量统计、批量清理、ACL 设置
|
|
|
+- 🔐 **凭据零入库** —— 密钥永不落盘、永不进日志、永不进对话
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 快速开始
|
|
|
+
|
|
|
+### 零配置用法(0 步,推荐)
|
|
|
|
|
|
```bash
|
|
|
node skills/fmode-storage/scripts/uploader.mjs put ./report.html --key report/202609/report.html
|
|
|
# → { "ok": true,
|
|
|
# "key": "user/<你的id>/report/202609/report.html",
|
|
|
-# "url": "https://s3.fmode.cn/user/<你的id>/report/202609/report.html",
|
|
|
-# "via": "level0:cloudfunc(AlP56LCKFm)" }
|
|
|
+# "url": "https://s3.fmode.cn/user/<你的id>/report/202609/report.html" }
|
|
|
+
|
|
|
+node skills/fmode-storage/scripts/uploader.mjs test # 自检
|
|
|
```
|
|
|
|
|
|
-自检:
|
|
|
+`--key` 给相对路径即可,服务端会强制挂到 `user/<你的id>/` 前缀下;省略则自动命名。上传即 `public-read`,**不需要**再调 `setacl`。
|
|
|
|
|
|
-```bash
|
|
|
-node skills/fmode-storage/scripts/uploader.mjs test
|
|
|
-# → { "ok": true, "via": "level0:cloudfunc(...)", "message": "云函数免密钥通道自检成功(本机无需任何 AK/SK)" }
|
|
|
+### Node.js(ESM)
|
|
|
+
|
|
|
+```javascript
|
|
|
+import { putViaCloudFunction } from './skills/fmode-storage/scripts/uploader.mjs';
|
|
|
+
|
|
|
+const r = await putViaCloudFunction(
|
|
|
+ '/path/report.html',
|
|
|
+ 'report/202609/report.html',
|
|
|
+ 'report',
|
|
|
+);
|
|
|
+// r = { ok, key, url, bytes, via }
|
|
|
+console.log(r.url);
|
|
|
```
|
|
|
|
|
|
-原理:平台云函数 `fmodeagent-upload-url` 持有真实 AK/SK,按调用者身份签发 5 分钟有效的 OBS 预签名 PUT 地址;**密钥永不下发到容器**。对象键强制挂在 `user/<你自己的id>/` 前缀下(服务端校验,写不了别人的);上传即 `public-read`,公网地址 `https://s3.fmode.cn/<key>`。
|
|
|
+### 浏览器(原生 ES Module)
|
|
|
|
|
|
-## (兜底)申请 OBS 子账号 + init 向导
|
|
|
+```html
|
|
|
+<script type="module">
|
|
|
+ // 浏览器端只消费上传后得到的公开链接,不持有任何密钥
|
|
|
+ const url = 'https://s3.fmode.cn/user/<id>/report/202609/report.html';
|
|
|
+ const res = await fetch(url, { method: 'HEAD' });
|
|
|
+ console.log('published:', res.ok, res.status);
|
|
|
+</script>
|
|
|
+```
|
|
|
|
|
|
-需要写**平台桶**(如 `obs://www-fmode.cn/`)而不是个人空间时,才走这条 4 级兜底链。
|
|
|
+### 兜底:需要写平台桶时
|
|
|
|
|
|
-### 执行 init 向导(约 1 分钟)
|
|
|
+需要写**平台桶**(而非个人空间)时,才走 `init` 向导配置 OBS 子账号:
|
|
|
|
|
|
```bash
|
|
|
node skills/fmode-storage/scripts/uploader.mjs init \
|
|
|
--ak <你的AK> --sk <你的SK> \
|
|
|
- --endpoint obs.cn-north-4.myhuaweicloud.com \
|
|
|
- --bucket <bucket>
|
|
|
-# 省略参数则进入交互模式逐项询问
|
|
|
+ --endpoint obs.cn-north-4.myhuaweicloud.com --bucket <bucket>
|
|
|
```
|
|
|
|
|
|
-写入 `~/.obsutilconfig`(600 权限)+ `~/.fmode/config.json` 技能 config 段(不含密钥本体),随后自动执行 test。
|
|
|
+---
|
|
|
|
|
|
-### 步骤 3:验证(约 30 秒)
|
|
|
+## 凭据链(命中即用,零密钥入库)
|
|
|
|
|
|
-```bash
|
|
|
-node skills/fmode-storage/scripts/uploader.mjs test
|
|
|
-# → 上传 1KB 探针文件 → 删除 → { "ok": true, ... }
|
|
|
+```
|
|
|
+┌─ 第0级【首选·免密钥】sessionToken → 云函数签发预签名 PUT
|
|
|
+│ AK/SK 由云函数保管,调用方只拿 5 分钟有效的上传地址。无需任何本地配置。
|
|
|
+│ 第1级 环境变量 OBS_AK/OBS_SK(可选 OBS_ENDPOINT/OBS_BUCKET)
|
|
|
+│ 第2级 obsutil config(OBSUTIL_CONFIG 或 ~/.obsutilconfig)
|
|
|
+│ 第3级 sessionToken + storageProjectId → 项目级 STS(作用域限定项目前缀)
|
|
|
+│ 第4级 项目级 ./.fmode/config.json(obsBucket/obsEndpoint/cdnDomain)
|
|
|
+│ 全失败 → 打印初始化向导并退出码 2,绝不伪装成功
|
|
|
+└──────────────────────────────────────────────────────────────────────────┘
|
|
|
```
|
|
|
|
|
|
-## 能力
|
|
|
+- **对象只能写自己的前缀** —— `user/<自己的id>/`,由服务端强制校验,写不了别人的
|
|
|
+- **STS 仅内存持有** —— 临时凭证带过期时间与权限范围,用完即删
|
|
|
+- **诊断输出脱敏** —— `config` 命令的输出绝不含任何密钥本体
|
|
|
|
|
|
-- 📤 大文件上传对象存储(华为云 OBS / S3 协议),本地磁盘零长期占用
|
|
|
-- 🔗 生成公开分享链接(`https://<域名>/<key>` 形态,可配 CDN)
|
|
|
-- 📄 报告/课件 HTML 发布即分享(传完即得可转发 URL)
|
|
|
-- 🧪 自检:`test` 命令上传→删除探针文件全链验证
|
|
|
-- 🧹 生命周期管理(前缀用量统计/批量清理/ACL 设置)
|
|
|
+> ⚠️ **不要把 AK/SK、sessionToken、STS 写进本仓库或任何对话。**
|
|
|
|
|
|
-## 各工具安装
|
|
|
+---
|
|
|
|
|
|
-### Claude Code
|
|
|
-```bash
|
|
|
-git clone https://git.fmode.cn/fmode/skill-storage.git
|
|
|
-cp -r skill-storage/skills/fmode-storage ~/.claude/skills/fmode-storage
|
|
|
-```
|
|
|
-之后在会话里直接说:「把这个报告上传并给我公开链接」。
|
|
|
+## FAQ
|
|
|
|
|
|
-### Codex / Gemini CLI
|
|
|
-把 `skills/fmode-storage/SKILL.md` 的内容并入 `AGENTS.md`(Codex)或 `~/.gemini/commands/storage.toml`(Gemini CLI,prompt 段引用 scripts/uploader.mjs)。
|
|
|
+### 技术概念
|
|
|
|
|
|
-### WorkBuddy / Hermes
|
|
|
-```bash
|
|
|
-git clone https://git.fmode.cn/fmode/skill-storage.git
|
|
|
-cp -r skill-storage/skills/fmode-storage <你的工具技能目录>/fmode-storage
|
|
|
-```
|
|
|
+**Q1:为什么要用对象存储,不直接把文件放在本地?**
|
|
|
+本地文件无法被外部访问,也无法嵌入到别人的文档或聊天里。对象存储提供稳定的公网 URL,磁盘占用为零,且天然适合大文件与高并发下载。
|
|
|
+
|
|
|
+**Q2:STS 临时凭证和 AK/SK 长期密钥有什么区别?**
|
|
|
+AK/SK 是长期身份密钥,泄露即长期风险;STS 是平台签发的**临时**凭证,带过期时间与权限范围,仅内存持有、用完即删。云函数预签名地址同理,有效期仅 5 分钟。优先走这两条临时通道。
|
|
|
+
|
|
|
+**Q3:云函数签发地址,密钥会不会下发到我的容器?**
|
|
|
+不会。真实 AK/SK 只存在于平台云函数侧,调用方拿到的是一个 5 分钟有效的预签名 PUT 地址。密钥永不下发、永不落盘。
|
|
|
|
|
|
-## 凭据(诚实 5 级,零密钥入库)
|
|
|
+**Q4:诊断命令会不会泄露我的密钥?**
|
|
|
+不会。`config` 命令的输出经过脱敏,绝不包含任何密钥本体。
|
|
|
|
|
|
-凭据解析链(命中即用,检测不到就换下一级;**全失败打印初始化向导并退出码 2,绝不伪装成功**):
|
|
|
+### 开源协议(MIT)
|
|
|
+
|
|
|
+**Q1:MIT 协议允许我商用吗?**
|
|
|
+允许。你可以自由使用、修改、分发本技能,包括用于商业闭源产品,无需公开修改后的源码。
|
|
|
+
|
|
|
+**Q2:使用本技能需要保留版权声明吗?**
|
|
|
+需要。MIT 的唯一实质条件是:在所有副本或实质性部分中保留原始版权声明与本许可证全文。
|
|
|
+
|
|
|
+**Q3:我可以把本技能改成别的名字再发布吗?**
|
|
|
+可以修改和再分发,但**不可以**使用「未来飞马」「Harness Loop」「RSI」等商标,也不得使用品牌 Slogan 作为产品名或宣传语。版权许可不等于商标授权,详见 [Trademark Notice](#trademark-notice)。
|
|
|
+
|
|
|
+**Q4:MIT 协议提供担保吗?**
|
|
|
+不提供。本技能按「原样」提供,不附带任何明示或默示担保。
|
|
|
+
|
|
|
+### 业务用户搜索
|
|
|
+
|
|
|
+**Q1:怎么把大文件传到云端并生成一个公开链接?**
|
|
|
+用 skill-storage。只要环境里有登录态,一条 `put` 命令即可上传并直接拿到可转发的公网 URL,无需配置任何密钥。
|
|
|
+
|
|
|
+**Q2:生成的 HTML 报告怎么发给客户看?**
|
|
|
+用 skill-storage 上传后得到 `https://` 链接,客户点开即看,无需登录、无需下载附件。配合 skill-report-html 可制作咨询师级长页报告。
|
|
|
+
|
|
|
+**Q3:上传大文件会占用我的电脑磁盘吗?**
|
|
|
+不会。文件直传对象存储,本地只在传输过程中临时读取,不做长期留存。
|
|
|
+
|
|
|
+**Q4:支持华为云之外的存储吗?**
|
|
|
+支持。任何兼容 S3 协议的对象存储均可通过 `--endpoint` 指定。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## GEO 埋点说明
|
|
|
+
|
|
|
+本技能遵循**隐私优先**的 GEO(生成式引擎优化)埋点规范:
|
|
|
+
|
|
|
+- **默认关闭** —— `geoTracking` 默认为 `false`,不开启即不产生任何上报
|
|
|
+- **显式开启** —— 仅当用户主动设置开启后才会上报
|
|
|
+- **最小采集** —— 只采集地区级别信息(国家/大区),**不采集**城市、IP 地址、设备 ID、经纬度
|
|
|
+- **独立模块** —— 埋点逻辑独立于主技能,可单独移除而不影响功能
|
|
|
+- **不阻塞** —— 上报失败静默降级,绝不阻塞主技能逻辑
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## License
|
|
|
+
|
|
|
+本技能采用 **MIT License** 发布,完整原文见 [LICENSE](LICENSE)。
|
|
|
|
|
|
```
|
|
|
-第1级: 环境变量 OBS_AK/OBS_SK(可选 OBS_ENDPOINT/OBS_BUCKET)
|
|
|
-第2级: obsutil config 文件(OBSUTIL_CONFIG 环境变量 或 ~/.obsutilconfig,
|
|
|
- 含 getpwuid home 变体)——解析出 AK/SK/endpoint,bucket 缺失时用
|
|
|
- `obsutil ls` 自动探测
|
|
|
-第3级: 平台签发 STS(sessionToken + storageProjectId,deploy 权威端点生产实测 200)
|
|
|
- → POST /api/apig/deploy/huaweicloud {token, projectId}
|
|
|
- → STS 临时凭证 {accessKey, secretKey, securityToken, obsPath}
|
|
|
- obsPath = obs://nova-cloud/dev/<projectId>/(项目隔离前缀,key 强制限定)
|
|
|
- → 一次性 obsutil 临时配置直传 OBS(STS 仅内存持有,用完即删)
|
|
|
- projectId 来源:FMODE_STORAGE_PROJECT_ID → ~/.fmode/config.json 的
|
|
|
- storageProjectId → user.json → ./.fmode/deploy.json 的 projectId
|
|
|
- (设计文档中的 /api/storage/credentials 从未上线:HEAD 探测 404,缓存
|
|
|
- .sts-probe.json 1 小时;上线后 --experimental-sts 启用该备用路径)
|
|
|
-第4级: 项目级 ./.fmode/config.json(obsBucket/obsEndpoint/cdnDomain)
|
|
|
+MIT License
|
|
|
+
|
|
|
+Copyright (c) 2026 未来飞马 Fmode
|
|
|
```
|
|
|
|
|
|
-- **旧版 0.2.x 的"sessionToken→/api/storage/credentials 自举"是伪自举**:该端点从未上线(探测 404,设计文档 `fmode-studio/docs/obs-cdn/04-API设计.md` 状态"规划中"),"登录即可上传"从未真正通过。0.3.0 诚实化:该路径降级为 `--experimental-sts`(探测 200 才启用);第3级改用真实上线的 deploy STS 端点。
|
|
|
-- **AK/SK 长期密钥只存在于 obsutil config / 环境变量**(用户自己配的);`config` 命令诊断输出绝不含任何密钥本体。
|
|
|
-- **当前版本需一次性配置 AK/SK**(见顶部"三分钟初始化");deploy STS 自举需登录 FMODE Studio 获得 sessionToken + 配置 storageProjectId(免 OBS 密钥,但需 projectId)。
|
|
|
+## Trademark Notice
|
|
|
|
|
|
-> 自建 OBS 配置方法(一次性,第2级):`obsutil config -i=<AK> -k=<SK> -e=obs.cn-north-4.myhuaweicloud.com`
|
|
|
-> **不要把 AK/SK、sessionToken、STS 写进本仓库或任何对话。**
|
|
|
+> MPL-2.0 governs copyright for source code only.
|
|
|
+> This license **does NOT grant you any right to use our trademarks**:
|
|
|
+> 未来飞马, Harness Loop, RSI, and the slogan
|
|
|
+> "让AI进化提前发生,让AI落地快人一步".
|
|
|
+>
|
|
|
+> You may not use these trademarks in your product name, marketing,
|
|
|
+> documentation, or public promotion unless you obtain separate written
|
|
|
+> permission from 未来飞马.
|
|
|
|
|
|
-## 用法示例
|
|
|
+---
|
|
|
|
|
|
-```bash
|
|
|
-# 首选:免配置(有 sessionToken 即可)
|
|
|
-node skills/fmode-storage/scripts/uploader.mjs put ./report.html --key report/202609/report.html
|
|
|
-# → https://s3.fmode.cn/user/<你的id>/report/202609/report.html
|
|
|
+## 贡献指南
|
|
|
|
|
|
-# 自检
|
|
|
-node skills/fmode-storage/scripts/uploader.mjs test
|
|
|
+1. **Fork** 本仓库并创建特性分支:`git checkout -b feature/your-idea`
|
|
|
+2. **零依赖优先** —— 优先使用平台内置能力,不引入第三方包
|
|
|
+3. **凭据纪律** —— 任何情况下不得在仓库、Issue、PR 中写入真实密钥
|
|
|
+4. **提交前自检** —— 运行 `npm run smoke` 或 `node skills/fmode-storage/scripts/uploader.mjs test`
|
|
|
+5. **提交 PR** —— 说明动机、变更范围与验证方式
|
|
|
|
|
|
-# 诊断(不含任何密钥本体)
|
|
|
-node skills/fmode-storage/scripts/uploader.mjs config
|
|
|
+---
|
|
|
|
|
|
-# 兜底:需要平台桶时才走 obsutil 4 级链
|
|
|
-node skills/fmode-storage/scripts/uploader.mjs init --ak .. --sk .. --bucket ..
|
|
|
-```
|
|
|
+## 相关项目
|
|
|
|
|
|
-## Changelog
|
|
|
+- **Harness Loop** —— 未来飞马技能生态的持续迭代回路
|
|
|
+- **RSI** —— 递归自我改进(Recursive Self-Improvement)机制
|
|
|
+- **FmodeAgent / FmodeCode** —— 本技能的目标运行平台
|
|
|
|
|
|
-### 0.4.0(新增免密钥首选通道)
|
|
|
-- **新增第 0 级:云函数预签名直传**(`fmodeagent-upload-url`)。只需登录态 `sessionToken`,
|
|
|
- 平台云函数持有 AK/SK 并签发 5 分钟预签名 PUT 地址 → 对象键 `user/<id>/<ns>/<YYYYMM>/...`,
|
|
|
- 公网 `https://s3.fmode.cn/<key>`。**容器无需任何 OBS 凭据 / storageProjectId**。
|
|
|
-- `put` / `test` 优先走第 0 级;第 1–4 级保留为兜底(平台桶等场景)。
|
|
|
-- `setacl` 在第 0 级下为 no-op(上传即 `x-obs-acl:public-read`)。
|
|
|
-- 真因:第 1–4 级要求"每台容器各自配密钥 / 有 storageProjectId",实际 34 台容器无一具备,
|
|
|
- 导致技能只能打印向导并 exit 2 —— 报告生成成功却发不出去。
|
|
|
-
|
|
|
-### 0.3.0(凭据链语义变更)
|
|
|
-- **真因修复**:旧版第0级调用 `POST /api/storage/credentials` 换 STS —— 该端点**从未上线(404)**(设计文档 `fmode-studio/docs/obs-cdn/04-API设计.md`,status:规划中),"登录即可上传"是伪自举
|
|
|
-- 字段名纠错:真实身份字段是 `~/.fmode/config/user.json` 的 **fmodeApiToken**(sk- 开头),不是 sessionToken(deploy STS 自举仍用 sessionToken,见下)
|
|
|
-- "能跑通"假象纠偏:部分环境"能跑"只是因为历史遗留的手工 obsutilconfig 存在(第1/2级回落生效),其他机器无此文件即全链死——现在全链失败时明确打印初始化向导并退出码 2,不再伪装成功
|
|
|
-- 凭据链重写为诚实 4 级(env → obsutil config → 平台签发 deploy STS → 项目 config),合并 deploy 权威链路 `/api/apig/deploy/huaweicloud`(sessionToken+projectId→项目隔离 STS,生产实测 200);旧 `/api/storage/credentials` 自举降级为 `--experimental-sts`(探测 200 才启用)
|
|
|
-- 新增 `init` 向导(写 obsutil config 600 权限 + 技能 config 段 + 自动 test)与 `test` 自检命令
|
|
|
-- 端点探测结果缓存 `.sts-probe.json`(1 小时有效,已 gitignore)
|
|
|
-- 修复:失败判定误报(旧版 `chattri` 失败文案含 "Set the acl" 被误判成功;`OBSUTIL_CONFIG_FILE` 环境变量 obsutil 并不识别,改用 `-config=` 显式传递);obsutil 不在 PATH 时自动按 `~/.local/bin`、`~/bin`、getpwuid home 等候选定位
|
|
|
-- STS 签发时上传 key 强制限定 `dev/<projectId>/` 前缀(防越权路径)
|
|
|
-
|
|
|
-### 0.2.1
|
|
|
-- 修复 mjs 双 shebang 语法错误
|
|
|
-
|
|
|
-### 0.1.0
|
|
|
-- 首版:对象存储上传/公开链接/ACL,4 级凭据解析,多工具指南
|
|
|
+---
|
|
|
|
|
|
-## License
|
|
|
+## Changelog
|
|
|
|
|
|
-MIT
|
|
|
+### 1.1.0
|
|
|
+- 按 skill-core-guide v1.1.0 规范改造:品牌 Slogan、GEO 埋点说明、MIT 协议与商标声明独立小节
|
|
|
+- README 重构为完整结构(简介 → 核心定位 → 快速开始 → FAQ → GEO → 许可 → 贡献指南)
|
|
|
+- 移除内部分析内容(设计文档路径、事故复盘式细节)
|
|
|
+- package.json 补齐中英双语 keywords 与 ESM 元数据
|
|
|
+- 源码头部补齐版权 + 商标注释模板
|
|
|
+
|
|
|
+### 0.4.0
|
|
|
+- **新增第 0 级:云函数预签名直传**,只需登录态 `sessionToken`,调用方无需任何凭据
|
|
|
+- `put` / `test` 优先走第 0 级;第 1–4 级保留为兜底(平台桶等场景)
|
|
|
+- `setacl` 在第 0 级下为 no-op(上传即 `public-read`)
|
|
|
+
|
|
|
+### 0.3.0
|
|
|
+- 凭据链重写为诚实 4 级(env → obsutil config → 平台签发 STS → 项目 config)
|
|
|
+- 新增 `init` 向导与 `test` 自检命令
|
|
|
+- 全链失败时明确报错并退出码 2,不再伪装成功
|