{"_id":"@buddhilive/dsh-attachment-local","name":"@buddhilive/dsh-attachment-local","dist-tags":{"alpha":"0.1.2-alpha.3","latest":"0.1.2-alpha.3"},"versions":{"0.1.2-alpha.3":{"name":"@buddhilive/dsh-attachment-local","description":"Private content-addressed DSH_HOME attachment storage","version":"0.1.2-alpha.3","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/attachment/attachment-local"},"type":"module","main":"lib/index.js","types":"lib/types/index.d.ts","exports":{".":{"types":"./lib/types/index.d.ts","default":"./lib/index.js"},"./invariant":{"types":"./lib/types/invariant.d.ts","default":"./lib/invariant.js"},"./src/*":"./src/*","./package.json":"./package.json"},"license":"MIT","peerDependencies":{"@buddhilive/dsh-attachment":"^0.1.2-alpha.3","@buddhilive/dsh-home-paths":"^0.1.2-alpha.3","@buddhilive/dsh-invariants":"^0.1.2-alpha.3","@deepseek-ai/cordis":"^4.0.2"},"dependencies":{"sharp":"^0.35.3","@deepseek-ai/schemastery":"^3.18.2"},"devDependencies":{"@buddhilive/dsh-invariants":"^0.1.2-alpha.3","@buddhilive/dsh-attachment":"^0.1.2-alpha.3","@buddhilive/dsh-home-paths":"^0.1.2-alpha.3","@deepseek-ai/cordis":"^4.0.2"},"_id":"@buddhilive/dsh-attachment-local@0.1.2-alpha.3","bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","_integrity":"sha512-G3UFK8MMvg8jHyPjuXzdYTt3S46PKBMMD6HKW1hI5l0J7QzdOA5svn9s+xkomaa/vtbQM/1iPEdxayAXsHn+zQ==","_resolved":"C:\\DevDojo\\Buddhi\\buddhi-ai-harness\\dist\\npm\\buddhilive-dsh-attachment-local-0.1.2-alpha.3.tgz","_from":"file:C:/DevDojo/Buddhi/buddhi-ai-harness/dist/npm/buddhilive-dsh-attachment-local-0.1.2-alpha.3.tgz","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-G3UFK8MMvg8jHyPjuXzdYTt3S46PKBMMD6HKW1hI5l0J7QzdOA5svn9s+xkomaa/vtbQM/1iPEdxayAXsHn+zQ==","shasum":"df7d3893c8d45bc4ee6035d58e28e3f62f65298b","tarball":"https://registry.npmjs.org/@buddhilive/dsh-attachment-local/-/dsh-attachment-local-0.1.2-alpha.3.tgz","fileCount":15,"unpackedSize":79367,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIA3RahOUpsbPKqZCAafEnR8uTCVsT7/3631p/wyqmIK9AiEAi5MYj0aqXoRdACtLWoN/lxdzI1sj++WyI6Q5fcxc7Wg="}]},"_npmUser":{"name":"buddhilive","email":"visitbudkavin@gmail.com"},"directories":{},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-attachment-local_0.1.2-alpha.3_1788165520185_0.4273682859789889"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-31T08:38:39.772Z","0.1.2-alpha.3":"2026-08-31T08:38:40.364Z","modified":"2026-08-31T08:38:40.804Z"},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"description":"Private content-addressed DSH_HOME attachment storage","homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/attachment/attachment-local"},"bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"license":"MIT","readme":"---\ndescription: \"DSH_HOME 下附加图片的本地存储，供用户与维护者选择或排查图片附件的存放位置。\"\nkind: \"package-reference\"\n---\n\n# @buddhilive/dsh-attachment-local\n\n[English](README.md) | 中文\n\n## 概述\n\n本包提供附件的本地存储与图片处理后端：源图经过校验、方向修正、元数据与色彩配置移除，并规范化为 8-bit sRGB/sRGBA 后保存在 `DSH_HOME` 下；路由专用请求版本另行派生并缓存。随附的 `dsh` 组合使用的就是它，因此持久图片附件无需配置即可工作。相同规范化图片只存一份，同一请求变体的并发读取共享工作，即使后来收紧准入限制，已存图片仍然可读。存储仅限本机——其他主机无法读取这些图片——对象也永远不会自动删除。\n\n## 目录\n\n- [使用本包](#use-this-package)\n- [理解实现](#understand-the-implementation)\n- [进一步探索](#further-exploration)\n- [模型体验](#model-experience)\n- [已知限制与延期工作](#known-limitations-and-deferred-work)\n- [开发备注](#dev-note)\n\n-----\n\n<a id=\"use-this-package\"></a>\n## 使用本包\n\n在默认组合中，把图片附加到提示词或命令，它们会自动保存到本机。自行组合时，挂载这一个插件即可获得持久图片附件。\n\n### 最小配置\n\n挂载插件，无需任何必填配置。下表默认值定义你可以附加什么；生成的配置目录是每个字段的穷尽式真源。\n\n```yaml\n- name: '@buddhilive/dsh-attachment-local'\n```\n\n| 字段 | 默认值 | 含义 |\n|---|---|---|\n| `dshHome` | 自动解析 | 显式 harness home；省略时依次跟随 `$DSH_HOME` 与 `~/.dsh` |\n| `maxImageBytes` | `20 MiB` | 单张图片接受的最大编码源字节数 |\n| `maxImagesPerMessage` | `20` | 单条提交消息接受的最大图片数量 |\n| `maxMessageImageBytes` | `200 MiB` | 单条提交消息接受的最大编码源图字节总数 |\n| `maxImagePixels` | `64,000,000` | 源图接受的最大宽度乘以高度 |\n| `maxImageDimension` | `8192` | 源图接受的最大宽度或高度 |\n| `normalizedImageMaxPixels` | `2048 × 2048` | 已存规范化图片的总像素预算 |\n| `normalizedImageMaxDimension` | `8192` | 应用总像素预算后的最大长边 |\n| `normalizedImageMaxBytes` | `4 MiB` | 编码字节目标；没有候选满足时保留质量阶梯中的最小输出 |\n| `imageCompressionConcurrency` | `2` | 并发规范化与请求变换的 FIFO 上限 |\n\n生成的[配置目录](../../../docs/config-catalog.zh.md#buddhilivedsh-attachment-local)是每个受支持字段及其 JSDoc 的穷尽式真源。\n\n### 图片存储在哪里、会保留多久\n\n附加的图片保存在本机的 `<DSH_HOME>/attachments/v1` 下。已存储的图片永远不会被自动删除，相同图片只会存储一份，之后收紧限制也绝不会让已保存的图片不可读。如果你的图片需要能从另一台机器读取，本包并不合适。\n\n### 附加图片时会发生什么\n\n附加图片后，会先检查源图限制、媒体类型、尺寸与像素，再完成规范化并保存。系统应用 EXIF 方向、移除元数据与色彩配置、保留透明度，并按总像素预算与长边上限缩小光栅。带 alpha 的图片使用 WebP，不透明图片使用 JPEG，共享 85/75/60 质量阶梯；全部候选都超过字节目标时保留最小输出。被接受的图片会重新出现在历史和后续轮次中，重启后也不例外；所选模型路由会收到缓存的请求版本，并在其文件系统可映射宿主对象时收到只读执行世界路径。\n\n### 可能出什么问题\n\n附加图片时可能被拒绝：格式不受支持、超出字节、像素或单边尺寸限制，或者字节与声明类型不符。之后读取时，磁盘上被删除或损坏的图片会以明确错误失败。每个失败都带有稳定错误码，客户端与协议适配器可以用自己的措辞解释。\n\n-----\n\n<a id=\"understand-the-implementation\"></a>\n## 理解实现\n\n<details>\n<summary>实现细节——点击展开</summary>\n\n本节解释存储背后的持久性与校验设计，以及实现它的写入与读取路径；可观察行为已在[使用本包](#use-this-package)中完整说明。\n\n### 设计决策\n\n- **持久性靠 fsync 链，而非存在性。** 当目录项从未到达存储时，仅同步文件无法在崩溃后存活，因此写入路径会在引用可能到达会话检查点前，把每个祖先条目同步到进程已验证的边界。\n- **一次规范化，按路由投影。** 准入持久保存一份提供方无关的规范化附件；请求投影派生确定性变体而不改写持久历史。\n- **惰性 alpha 路由编码。** 带 alpha 的图片使用 WebP，不透明图片使用 JPEG；质量候选按 85/75/60 顺序运行，没有候选满足编码字节目标时保留最小输出。\n- **限制是写入时策略。** 字节、总像素与单边尺寸限制只约束准入，因此之后收紧它们绝不会让已接纳的历史不可读。\n\n### 写入与读取路径\n\n对象存放在 `<DSH_HOME>/attachments/v1/objects/<sha256-prefix>/<sha256>`；相同字节会去重为同一个对象和同一个 `sha256:` 标识符。首次写入前，进程会把 home 的每个祖先目录逐级同步到文件系统根目录，因此绝不会把另一个进程已创建但尚未同步的目录误认为安全边界。随后，写入过程把字节暂存到 `v1/tmp`、同步临时文件、以原子且排他的硬链接发布，并同步发布目录——在 Windows 上，文件系统元数据日志负责目录项持久性。保存成功后，已报告的引用即持久。\n\n准入允许每条消息最多 20 张图片与 200 MiB 源字节；单个源图最多 20 MiB、6400 万像素与单边 8192 像素。系统应用方向、移除元数据与色彩配置，并把规范化结果限制在 2048×2048 总像素预算、8192 像素长边和 4 MiB 编码字节目标内，因此极端宽高比会保留短边分辨率。已经满足限制的干净、单帧、8-bit sRGB/sRGBA PNG、JPEG 或 WebP 会逐字节直通；GIF、动画、元数据、方向、16-bit PNG 与不兼容色彩空间会触发转换。\n\n请求版本位于 `<DSH_HOME>/attachments/v1/request-images/`。`readImageRequest` 在不放大的前提下缩放到路由像素预算，再通过相同的 alpha 路由与质量阶梯应用独立编码字节目标。缓存身份包含附件 id、变换版本、预算与固定编码参数；缓存字节会先探测格式、8-bit sRGB/sRGBA、尺寸与 alpha 信息，不匹配时重新生成。并发调用方共享一次变换与缓存写入，且只在没有等待方时由取消停止共享工作。`imageHostPath` 派生规范化对象的宿主路径，挂载的文件系统可以把该路径映射进执行世界，而不会写入持久历史。\n\n### 源码地图\n\n| 文件 | 职责 |\n|---|---|\n| [`src/index.ts`](src/index.ts) | 插件入口：`LocalAttachmentStore`、`Config` schema、默认值 |\n| [`src/store.ts`](src/store.ts) | 内容寻址写入与校验读取：暂存、硬链接发布、fsync 链、摘要校验 |\n| [`src/normalization.ts`](src/normalization.ts) + [`src/encoding.ts`](src/encoding.ts) | 提供方无关的规范化与有界格式／质量候选 |\n| [`src/request-image.ts`](src/request-image.ts) | 路由专用请求变换、缓存身份与 singleflight |\n| [`src/image.ts`](src/image.ts) | 完整光栅解码与元数据校验 |\n| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件（无运行时不变式；不可变写入与校验读取在后端边界直接强制） |\n\n</details>\n\n-----\n\n<a id=\"further-exploration\"></a>\n## 进一步探索\n\n完整的服务约定与载荷类型请看子系统参考；这份存储所支撑的能力请看 seam 包。\n\n- [附件子系统参考](../../../docs/subsystems/attachment.zh.md)——服务约定、载荷类型与 `ctx.attachments` 的 cordis 接口面。\n- [附件 seam 包](../attachment/README.zh.md)——本存储支撑的图片附件能力。\n- [生成配置目录](../../../docs/config-catalog.zh.md#buddhilivedsh-attachment-local)——每个受支持配置字段及其源声明。\n- [Home 路径解析](../../util/home-paths/README.zh.md)——`DSH_HOME` 如何从显式配置、环境变量与用户主目录解析。\n\n-----\n\n<a id=\"model-experience\"></a>\n## 模型体验\n\n本包通过请求描述符间接影响模型。执行文件系统可以映射宿主对象时，模型会随请求字节看到每张图片的身份、尺寸、媒体类型、只读进程路径、可写副本扩展名与规范化警告。\n\n#### KV Cache 影响\n\n规范化和请求投影都是确定性的。附件和路由策略不变时，之后各轮会复用相同的缓存请求字节；执行世界路径映射可以改变描述符文本，而不会改变这些字节或其 `variantId`。\n\n## 已知限制与延期工作\n\n<a id=\"known-limitations-and-deferred-work\"></a>\n\n\n这些限制描述了这份存储能做什么、不能做什么；它们是当前包约束。\n\n- **图片会永久保留**——已存储的图片永远不会被自动删除，也没有任何机制回收未被引用的对象。\n- **仅限本机**——图片存放在运行 harness 的机器上；其他主机无法读取。\n- **动态 GIF 变为静态**——规范化只保留第一帧；动画不属于版本一图片约定。\n- **编码器输出带版本**——已安装的 Sharp/libvips 构建钉定规范化与请求字节；编码器或变换版本升级会让未来变体产生新地址，已有对象继续有效。\n\n<a id=\"dev-note\"></a>\n### 开发备注\n\n<details>\n<summary>维护者的工作上下文——点击展开</summary>\n\n本开发备注是维护者的工作上下文：尚未决定的探索方向与开放问题。它明确不具权威性——已交付的行为与限制以上文和包代码为准。\n\n#### 未来：保留与远程存储\n\n保留与垃圾回收被推迟，因为恢复和 fork 后的会话可能共享不可变对象；服务于远程运行时或共享存储的后端则需要自己的持久性证明。两个方向都尚未决定；本地存储当前在 `DSH_HOME` 下保留所有对象。\n\n</details>\n","readmeFilename":"README.zh.md","_rev":"1-ce4e85ba4a9a96e5136495b5eaffa7d8"}