{"_id":"@buddhilive/dsh-storage-json","name":"@buddhilive/dsh-storage-json","dist-tags":{"alpha":"0.1.2-alpha.3","latest":"0.1.2-alpha.3"},"versions":{"0.1.2-alpha.3":{"name":"@buddhilive/dsh-storage-json","description":"JSON file KV storage backend for the DeepSeek Harness storage hub","version":"0.1.2-alpha.3","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/storage/storage-json"},"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-invariants":"^0.1.2-alpha.3","@buddhilive/dsh-storage":"^0.1.2-alpha.3","@deepseek-ai/cordis":"^4.0.2"},"dependencies":{"@deepseek-ai/schemastery":"^3.18.2"},"devDependencies":{"@buddhilive/dsh-storage":"^0.1.2-alpha.3","@deepseek-ai/cordis":"^4.0.2","@buddhilive/dsh-invariants":"^0.1.2-alpha.3"},"_id":"@buddhilive/dsh-storage-json@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-TxIDjDbhrIY2OMSpCO+rrKP3dlC+CbHeSsrrQ4gfyIdH/pRZgLWqppKv43/vJzmtxBTs8r3qmIbY8pRiBiohGw==","_resolved":"C:\\DevDojo\\Buddhi\\buddhi-ai-harness\\dist\\npm\\buddhilive-dsh-storage-json-0.1.2-alpha.3.tgz","_from":"file:C:/DevDojo/Buddhi/buddhi-ai-harness/dist/npm/buddhilive-dsh-storage-json-0.1.2-alpha.3.tgz","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-TxIDjDbhrIY2OMSpCO+rrKP3dlC+CbHeSsrrQ4gfyIdH/pRZgLWqppKv43/vJzmtxBTs8r3qmIbY8pRiBiohGw==","shasum":"74b0b77a3558e4c5b7f5508e1b4d63fa4db4659b","tarball":"https://registry.npmjs.org/@buddhilive/dsh-storage-json/-/dsh-storage-json-0.1.2-alpha.3.tgz","fileCount":13,"unpackedSize":52161,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDNvldHsNki0iH2kW4GUmvzn+gO+pedBuLfRHeLEwkEhgIgbNnpzkNK2rZdSodDyxJnyz1wPYhlbtYaBS2DSPkVDtk="}]},"_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-storage-json_0.1.2-alpha.3_1788165818793_0.8585162750057405"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-31T08:43:38.561Z","0.1.2-alpha.3":"2026-08-31T08:43:38.937Z","modified":"2026-08-31T08:43:39.206Z"},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"description":"JSON file KV storage backend for the DeepSeek Harness storage hub","homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/storage/storage-json"},"bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"license":"MIT","readme":"---\ndescription: \"JSON 存储后端：面向在配置根目录下选择、配置或排查整单元文件与逐记录文件的宿主与维护者。\"\nkind: \"package-reference\"\n---\n\n# @buddhilive/dsh-storage-json\n\n[English](README.md) | 中文\n\n## 概述\n\n`dsh-storage-json` 在配置的根目录下把领域数据存为可读 JSON，并注册为后端 `json`。默认的 `single` 布局为每个单元保存一份完整的 `<unit>.json` 文件；`per-record` 布局为每条记录保存一份带版本戳的文档。两种布局都以原子方式发布每个变更文件，领域层负责安排调用顺序。当运维方需要可检查文件且所选布局适合写入量时选择它；对于更大或高并发的数据则选择 SQLite。本后端只面向宿主侧，不贡献提示词、工具或 schema。\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当组合需要可读、可编辑的 JSON 存储时使用本包。把相关领域路由到 `json` 后端；每个领域规范选择 `single` 或 `per-record` 布局。\n\n### 何时选择\n\n小型单元需要一份完整、美化打印的文件时，选择默认的 `single` 布局。定点写入只应替换一份记录文档时，选择 `per-record`。当数据量大、写入频繁或多条记录需要事务更新时，选择 SQLite 后端。\n\n### 配置\n\n唯一的插件字段是 `root`，用于保存单元文件与目录。它是必填项，因为本后端不回退到 `process.cwd()`。后端按需以 `0o700` 模式创建根目录。领域规范选择其布局；本插件不提供布局覆盖项。\n\n```yaml\n- name: '@buddhilive/dsh-storage'\n- name: '@buddhilive/dsh-storage-json'\n  config:\n    root: /var/lib/dsh/data\n- name: '@buddhilive/dsh-storage-domain'\n  config:\n    backend: json\n```\n\n| 字段 | 默认值 | 含义 |\n|---|---|---|\n| `root` | 必填 | 保存 `<unit>.json` 文件与 `<unit>/` 目录树的目录；按需以 `0o700` 创建 |\n\n生成的[配置目录](../../../docs/config-catalog.zh.md#buddhilivedsh-storage-json)是每个受支持字段及其 JSDoc 的穷尽式真源。\n\n### 可观察行为\n\n缺失的 `single` 文件或 `per-record` 目录会作为空单元打开，并在第一次写入时物化。在 `single` 中，畸形内容以 `malformed-medium` 拒绝，不同的已存版本以 `version-mismatch` 拒绝。在 `per-record` 中，每份畸形、不可读或版本不同的文档都读作记录不存在，因此单个坏文档不会使单元被拒绝。记录键必须匹配 `[a-zA-Z0-9_-]+`；不安全的键在任何文件操作前被拒绝。每次已完成的写入都已持久化，关闭后的操作以 `closed` 拒绝。\n\n空的 `per-record` 目录树可以从有效的 `<root>/<unit>.json` 整单元文档初始化其已声明表。后端保持该源文件不变。已声明表中只要存在任意文档路径，或存在已声明的 `global.json`，就会对整个单元禁止该初始化，即使该文档不可读或版本陈旧。\n\n-----\n\n<a id=\"understand-the-implementation\"></a>\n## 理解实现\n\n<details>\n<summary>实现细节——点击展开</summary>\n\n两种布局共享原子发布机制，但以不同方式确定状态所有权。`single` 拥有一份内存单元投影；`per-record` 把目录树视为权威状态。\n\n### 设计理念\n\n- **`single` 以内存为权威状态。** 每次写入都会更改内存单元、序列化其完整状态，并以原子方式替换 `<unit>.json`。发布失败会恢复先前的内存值。\n- **`per-record` 以目录为权威状态。** 每次 put 或 delete 都会更改一个 `<unit>/<table>/<key>.json` 文档，`loadAll()` 则重新读取目录树。每份文档都带有单元版本戳与一条记录值。\n- **每次调用都持久发布。** 写入过程使用临时文件、fsync、原子 `rename()` 替换，并在 POSIX 上 fsync 父目录。领域层写入链负责安排跨调用的顺序。\n\n### 文件格式\n\n`single` 文档携带单元标识、全局单例与所有表：\n\n```json\n{\n  \"unit\": { \"name\": \"workspace\", \"version\": 1 },\n  \"global\": null,\n  \"tables\": { \"workspaces\": { \"<key>\": { \"path\": \"/work/demo\" } } }\n}\n```\n\n`per-record` 表文档位于 `<root>/<unit>/<table>/<key>.json`，形式为 `{ \"version\": 1, \"record\": <value> }`；可选的全局值使用 `<root>/<unit>/global.json`。格式版本来自领域规范。\n\n### 源码地图\n\n| 文件 | 职责 |\n|---|---|\n| [`src/index.ts`](src/index.ts) | 插件入口：后端注册、`root` 配置、单元打开／关闭表 |\n| [`src/single-unit.ts`](src/single-unit.ts) | 一个 `single` 单元：权威内存、写入原语与发布回滚 |\n| [`src/per-record-unit.ts`](src/per-record-unit.ts) | 一个 `per-record` 单元：目录树读取、路径安全记录与单文档写入 |\n| [`src/format.ts`](src/format.ts) | 带版本校验的整单元与记录序列化 |\n| [`src/atomic.ts`](src/atomic.ts) | 原子文件替换：临时文件写入、fsync、rename、目录 fsync |\n| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件（无运行时不变式：正确性靠往返持久性） |\n\n</details>\n\n-----\n\n<a id=\"further-exploration\"></a>\n## 进一步探索\n\n当本后端视角不够用时阅读以下页面：子系统参考是权威约定，兄弟后端展示了另一种介质。\n\n- [存储子系统](../../../docs/subsystems/storage.zh.md)——后端约定、领域语义与生成的 API。\n- [存储包映射](../README.zh.md)——家族的各包及其在仓库中的位置。\n- [SQLite 存储后端](../storage-sqlite/README.zh.md)——面向高频数据的定点更新介质。\n- [领域 KV 存储 Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)——后端家族背后的设计及其延期工作。\n\n-----\n\n<a id=\"model-experience\"></a>\n## 模型体验\n\n### 已存领域记录\n\n#### 模型看到什么\n\n无。本后端不贡献提示词、工具或 schema；它在 `ctx.storage` 后面持久化非会话领域数据，只供宿主侧消费方使用。\n\n#### Token 影响\n\n实时请求 token 为零。\n\n#### KV Cache 影响\n\n无：本后端从不触碰实时请求前缀。\n\n## 已知限制与延期工作\n\n<a id=\"known-limitations-and-deferred-work\"></a>\n\n\n这些限制说明本后端何时不合适，或何时需要特别的运维注意。它们是当前包约束，不是任务积压。\n\n- **`single` 会重写整个单元**——每次写入都重新发布完整单元文件；当此成本过高时，使用 `per-record` 或把领域路由到 SQLite。\n- **没有跨进程写锁**——两个进程写入同一单元时可能交错执行替换；对同一文件的写入以最后完成者为准。\n- **Windows rename 没有显式 write-through**——持久性依赖 libuv 的 `rename()`（`MoveFileExW` 并启用替换）；`log` 分面落地时，计划把会话日志后端更严格的 Win32 write-through 发布辅助函数下移到此处。\n\n<a id=\"dev-note\"></a>\n### 开发备注\n\n<details>\n<summary>维护者的工作上下文——点击展开</summary>\n\nAgent Note 把整单元重写的规模前提标记为风险：如果在被路由到 SQLite 之前，第二个消费方以千条记录规模落到本后端，重写成本会比预期更早显现。缓解办法是配置——把 `routes` 指向 SQLite 后端——而不是修改本包。\n\n</details>\n","readmeFilename":"README.zh.md","_rev":"1-e6d4f37196a596706746742344a24c6b"}