# skill-storage · 对象存储与公开分享技能 > AI Agent 的"仓库管理员"——二进制大文件(图片/音频/视频/报告 HTML)上云,本地零占用,一键生成公开分享链接。 [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) ## 零配置用法(0 步,推荐) **当前版本(0.4.0)默认通道免密钥**:只要容器/环境里有登录态 `sessionToken`(数字生命容器默认就有),直接上传即可拿到公开链接——不用申请 AK/SK、不用 init。 ```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)" } ``` 自检: ```bash node skills/fmode-storage/scripts/uploader.mjs test # → { "ok": true, "via": "level0:cloudfunc(...)", "message": "云函数免密钥通道自检成功(本机无需任何 AK/SK)" } ``` 原理:平台云函数 `fmodeagent-upload-url` 持有真实 AK/SK,按调用者身份签发 5 分钟有效的 OBS 预签名 PUT 地址;**密钥永不下发到容器**。对象键强制挂在 `user/<你自己的id>/` 前缀下(服务端校验,写不了别人的);上传即 `public-read`,公网地址 `https://s3.fmode.cn/`。 ## (兜底)申请 OBS 子账号 + init 向导 需要写**平台桶**(如 `obs://www-fmode.cn/`)而不是个人空间时,才走这条 4 级兜底链。 ### 执行 init 向导(约 1 分钟) ```bash node skills/fmode-storage/scripts/uploader.mjs init \ --ak <你的AK> --sk <你的SK> \ --endpoint obs.cn-north-4.myhuaweicloud.com \ --bucket # 省略参数则进入交互模式逐项询问 ``` 写入 `~/.obsutilconfig`(600 权限)+ `~/.fmode/config.json` 技能 config 段(不含密钥本体),随后自动执行 test。 ### 步骤 3:验证(约 30 秒) ```bash node skills/fmode-storage/scripts/uploader.mjs test # → 上传 1KB 探针文件 → 删除 → { "ok": true, ... } ``` ## 能力 - 📤 大文件上传对象存储(华为云 OBS / S3 协议),本地磁盘零长期占用 - 🔗 生成公开分享链接(`https://<域名>/` 形态,可配 CDN) - 📄 报告/课件 HTML 发布即分享(传完即得可转发 URL) - 🧪 自检:`test` 命令上传→删除探针文件全链验证 - 🧹 生命周期管理(前缀用量统计/批量清理/ACL 设置) ## 各工具安装 ### Claude Code ```bash git clone https://git.fmode.cn/fmode/skill-storage.git cp -r skill-storage/skills/fmode-storage ~/.claude/skills/fmode-storage ``` 之后在会话里直接说:「把这个报告上传并给我公开链接」。 ### 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 ``` ## 凭据(诚实 5 级,零密钥入库) 凭据解析链(命中即用,检测不到就换下一级;**全失败打印初始化向导并退出码 2,绝不伪装成功**): ``` 第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//(项目隔离前缀,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) ``` - **旧版 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)。 > 自建 OBS 配置方法(一次性,第2级):`obsutil config -i= -k= -e=obs.cn-north-4.myhuaweicloud.com` > **不要把 AK/SK、sessionToken、STS 写进本仓库或任何对话。** ## 用法示例 ```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 # 诊断(不含任何密钥本体) node skills/fmode-storage/scripts/uploader.mjs config # 兜底:需要平台桶时才走 obsutil 4 级链 node skills/fmode-storage/scripts/uploader.mjs init --ak .. --sk .. --bucket .. ``` ## Changelog ### 0.4.0(新增免密钥首选通道) - **新增第 0 级:云函数预签名直传**(`fmodeagent-upload-url`)。只需登录态 `sessionToken`, 平台云函数持有 AK/SK 并签发 5 分钟预签名 PUT 地址 → 对象键 `user////...`, 公网 `https://s3.fmode.cn/`。**容器无需任何 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//` 前缀(防越权路径) ### 0.2.1 - 修复 mjs 双 shebang 语法错误 ### 0.1.0 - 首版:对象存储上传/公开链接/ACL,4 级凭据解析,多工具指南 ## License MIT