{"_id":"@buddhilive/dsh-workspace","name":"@buddhilive/dsh-workspace","dist-tags":{"alpha":"0.1.2-alpha.3","latest":"0.1.2-alpha.3"},"versions":{"0.1.2-alpha.3":{"name":"@buddhilive/dsh-workspace","description":"Workspace entity registry (ctx.workspaceRegistry): durable workspace records with validated session attachment over the domain data form for the DeepSeek Harness","version":"0.1.2-alpha.3","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/workspace/workspace"},"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"},"./types":{"types":"./lib/types/types.d.ts","default":"./lib/types/types.js"},"./src/*":"./src/*","./package.json":"./package.json"},"license":"MIT","peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@buddhilive/dsh-invariants":"^0.1.2-alpha.3","@buddhilive/dsh-session":"^0.1.2-alpha.3","@buddhilive/dsh-session-persistence":"^0.1.2-alpha.3","@buddhilive/dsh-storage":"^0.1.2-alpha.3","@buddhilive/dsh-storage-domain":"^0.1.2-alpha.3","@buddhilive/dsh-typert-protocol":"^0.1.2-alpha.3"},"dependencies":{"zod":"^4.4.3","@buddhilive/dsh-brand":"^0.1.2-alpha.3"},"devDependencies":{"@buddhilive/dsh-invariants":"^0.1.2-alpha.3","@buddhilive/dsh-session":"^0.1.2-alpha.3","@deepseek-ai/cordis":"^4.0.2","@buddhilive/dsh-session-persistence":"^0.1.2-alpha.3","@buddhilive/dsh-storage":"^0.1.2-alpha.3","@buddhilive/dsh-typert-protocol":"^0.1.2-alpha.3","@buddhilive/dsh-storage-domain":"^0.1.2-alpha.3"},"_id":"@buddhilive/dsh-workspace@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-RZtZDUwSlDzJVWUKD1WT6kVSk3Sm3sSC+ZCitrevFtHFxYHr4ksf3CEDTq8QtLq8UsdYpaJxzc4BvJpI8p1Bgw==","_resolved":"C:\\DevDojo\\Buddhi\\buddhi-ai-harness\\dist\\npm\\buddhilive-dsh-workspace-0.1.2-alpha.3.tgz","_from":"file:C:/DevDojo/Buddhi/buddhi-ai-harness/dist/npm/buddhilive-dsh-workspace-0.1.2-alpha.3.tgz","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-RZtZDUwSlDzJVWUKD1WT6kVSk3Sm3sSC+ZCitrevFtHFxYHr4ksf3CEDTq8QtLq8UsdYpaJxzc4BvJpI8p1Bgw==","shasum":"b21a93d3defe50775c9eb734657701906a267213","tarball":"https://registry.npmjs.org/@buddhilive/dsh-workspace/-/dsh-workspace-0.1.2-alpha.3.tgz","fileCount":19,"unpackedSize":120831,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDF6hM12jcM6xtvQNJiDiiG97wNCrBUKZkWCaNNBSY16wIhAN+sCm8jztJieeLL8IP7qzKHOY4mQWK+BN1mgBKDag2y"}]},"_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-workspace_0.1.2-alpha.3_1788165467803_0.25763214133421153"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-31T08:37:47.633Z","0.1.2-alpha.3":"2026-08-31T08:37:47.922Z","modified":"2026-08-31T08:37:48.103Z"},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"description":"Workspace entity registry (ctx.workspaceRegistry): durable workspace records with validated session attachment over the domain data form for the DeepSeek Harness","homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/workspace/workspace"},"bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"license":"MIT","readme":"---\ndescription: \"面向选择、挂载或排查持久 workspace 记录与会话头校验成员资格的宿主的 Workspace 实体注册表（ctx.workspaceRegistry）说明。\"\nkind: \"package-reference\"\n---\n\n# @buddhilive/dsh-workspace\n\n[English](README.md) | 中文\n\n## 概述\n\n`dsh-workspace` 为宿主提供一组持久 workspace：命名用户目录，每个目录带有在其中运行的会话，并在重启之间保持稳定顺序。借助它，UI 可以显示项目侧边栏、把会话附加到正确的项目、把会话从分组中隐藏而不丢失它，以及移除项目——移除绝不会删除文件夹或会话历史，它们变成 Ungrouped。在需要持久项目分组的 GUI 或宿主组合中使用它；headless 与最小运行可以完全省略它。此包只面向宿主侧：模型、工具与 agent loop 永远不会看到它，因此不会增加任何 token、提示词或请求上下文。它需要会话存储与持久化后端一并挂载；设置只需几行组合配置。\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使用此包为产品提供项目列表：用户工作的命名目录、每个目录中运行的会话、稳定顺序，以及在不丢失会话的前提下将其隐藏的能力。每项操作背后的 API 约定放在实现章节中。\n\n### 何时使用\n\n当产品展示持久 workspace 界面——侧边栏、会话分组或需要命名并排序目录的自动化——时使用它。它对模型不可见，因此不增加任何 token 或请求成本。没有分组界面时跳过它；harness 中没有其他包需要它。\n\n### 设置\n\n此包本身不声明任何配置；它需要会话存储、会话持久化后端，以及保存其记录的存储行。最小组合如下：\n\n```yaml\n- name: '@buddhilive/dsh-session'\n- name: '@buddhilive/dsh-session-persistence-jsonl'\n- name: '@buddhilive/dsh-storage'\n- name: '@buddhilive/dsh-storage-json'\n- name: '@buddhilive/dsh-storage-domain'\n  config:\n    backend: json\n- name: '@buddhilive/dsh-workspace'\n```\n\n挂载这些行之后，创建项目会立即出现在列表中并在重启后保留；首次启动还会按会话运行的目录对既有会话分组。如果缺少某个必需依赖，workspace 功能会一直不可用，直到它被挂载。\n\n### 创建与排序项目\n\n从任何存在的目录创建项目：给出路径和可选标题，项目即出现在列表中，新到旧排列。不存在的路径或文件而非目录会被拒绝，且不会有任何变化；为已有项目的目录再次创建会原样返回现有项目。你可以随时重命名项目，并把它移动到列表中的任意位置：\n\n```text\n// Host consumer code, after the composition above is loaded:\nconst project = await ctx.workspaceRegistry.create('/path/to/dir', 'My Project')\nawait project.setTitle('Renamed')\nctx.workspaceRegistry.list() // shows the project, newest first\n```\n\n### 将会话归入项目\n\n会话加入它运行目录所在的项目：在项目目录中创建会话，它就会出现在该项目下，新到旧排列。一个会话只能属于一个项目。目录无法校验的会话——没有记录目录，或目录被移动、删除——无法加入，保持 Ungrouped。\n\n### 隐藏会话与移除项目\n\n当会话不应再出现在分组中时隐藏它：它会从可见列表中消失，但其会话、历史与在项目中的位置都保持不变。项目不再需要时移除它：它离开列表，而其文件夹、文件与会话历史绝不受影响——这些会话变成 Ungrouped。之后再次添加同一目录会从空项目开始，不会带回旧会话。\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- **每个规范路径一条记录。** `fs.realpath` 是唯一的一套唯一性规范：路径以规范化形式存储，因此指向已被拥有目录的符号链接会与之冲突，唯一性即规范路径的字符串相等。\n- **成员资格是所有权加实时 cwd 事实。** 记录的 `sessionIds` 顺序是所有权真源；启动时的头部索引校验它，`sessionIds` 在读取时过滤，下一次变更持久剪除。\n- **仅读取头部。** 引导与 attach 校验只读取 `SessionHeader` 字段；事件正文绝不加载。\n- **两次写入的变更带显式标记。** 创建与删除在记录/顺序对可能分叉之前先持久化 `pendingMutation` 标记，因此启动只补全被中断的操作，未标记的分叉作为损坏明确报错。\n- **串行化写入。** 注册表操作跑在同一条操作链上；实体变更通过领域写链上的 `table.update` 执行，盖上 `updatedAt` 并在其链槽决定成员资格。\n\n### API 行为\n\n该 API 是一个由两个所有者构成的小家族：`WorkspaceRegistry` 负责创建、排序与删除项目并管理其会话记账；`Workspace` 实体暴露显示标题、目录状态与会话投影。各方法的精确约定在代码中，而非本 README——参见 [src/index.ts](src/index.ts) 与 [src/entity.ts](src/entity.ts)。\n\n### 源码地图\n\n| 文件 | 职责 |\n|---|---|\n| [`src/index.ts`](src/index.ts) | 插件入口：`WorkspaceRegistry` 服务、头部索引、引导、操作串行化 |\n| [`src/entity.ts`](src/entity.ts) | 包私有 `Workspace` 实现及其唯一的 `mutate` 写入路径 |\n| [`src/spec.ts`](src/spec.ts) | 领域声明：记录 schema、注册表状态、`defineDomain` 规范 |\n| [`src/types.ts`](src/types.ts) | 公开 `Workspace` 接口与 `WorkspaceId` 品牌 |\n| [`src/paths.ts`](src/paths.ts) | `realpath` 唯一性规范 |\n| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件：实体缓存镜像持久表 |\n\n### 持久形态\n\n注册表打开 `workspace` 领域（版本 2）：一张以 `WorkspaceId` 为键的 `workspaces` 表，加上一个持有 `workspaceIds`（权威显示顺序）、`archivedSessionIds` 与可选 `pendingMutation` 标记的全局状态。在 `archivedSessionIds` 存在之前写入的记录会通过 schema 默认值解析为空集合。\n\n### 生命周期\n\n启动时，注册表打开领域、若存在标记则补全被标记的变更、校验已存状态——重复路径、重复会话账本与顺序漂移都会明确报错——并在尚未初始化时先凭持久化头部引导历史、最后写入已初始化标记，因此被中断的引导可以安全恢复。全新空注册表一旦初始化即为真，绝不会再次引导。\n\n### 失败与恢复\n\n创建或删除的第二次写入失败时，缓存与先前顺序会回滚；当操作与回滚都失败时，持久标记仍指明被中断的操作，下一次启动会补全或回滚它。已提交的删除即使标记清理失败仍报告成功，下一次启动会幂等地清除该标记。\n\n### 不变式\n\n`workspace-invariant` 伴生插件注册归属关系：`workspaces` 表的每个持久 `domain/changed` 都必须指向实体缓存已持有的记录——只有在注册表从缓存移除实体之后删除才有效，因此绕过注册表的写入路径会触发不变式失败。\n\n</details>\n\n-----\n\n<a id=\"further-exploration\"></a>\n## 进一步探索\n\n当本包的视角不够用时阅读以下页面：子系统参考是权威的功能约定，Agent Note 记录了项目为何从会话历史起步、以及移除为何是非破坏性的。\n\n- [Workspace 子系统](../../../docs/subsystems/workspace.zh.md)——项目及其会话的功能约定，以及 workspace 服务的生成 API。\n- [Workspace 包映射](../README.zh.md)——本组唯一的包及其仓库位置。\n- [领域 KV 存储 Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)——为什么项目记录使用领域数据形式。\n- [Workspace UI 产品流 Agent Note](../../../.agents/notes/implemented/feature/2026-07-25-workspace-ui-product-flow.zh.md)——首次启动如何从会话历史构建项目，以及 GUI 如何排序。\n- [删除 Workspace 注册记录决策](../../../.agents/notes/implemented/feature/2026-07-27-workspace-registration-deletion.zh.md)——为什么移除项目绝不会删除其文件夹或会话。\n\n-----\n\n<a id=\"model-experience\"></a>\n## 模型体验\n\n### Workspace 记录与会话账本\n\n#### 模型看到什么\n\n没有。`ctx.workspaceRegistry` 只向宿主侧消费方提供 workspace 记录：此包不注册工具、不注入提示词、不写入会话事件，因此没有请求字段会携带此包数据。\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- **移除绝不删除数据**——移除项目会保留其文件夹、文件与会话历史；这些会话变成 Ungrouped，而会话删除与文件夹移除是彼此独立且尚未提供的功能（参见[决策记录](../../../.agents/notes/implemented/feature/2026-07-27-workspace-registration-deletion.zh.md)）。\n- **只有带记录目录的会话才能加入**——只有记录中带有可解析为项目路径的目录的会话才属于项目；没有目录的会话保持 Ungrouped，来自其他目录的会话无法移入。\n- **外部变更延迟可见**——如果另一进程删除或损坏目录，项目只能在下次刷新或重启后反映出来。\n- **归档是单向的**——被隐藏的会话保留其历史与位置，但目前没有取消归档操作；归档集合是持久的显示过滤器。\n- **重新添加目录从空开始**——移除后再次添加同一目录会创建空会话列表的新项目；旧会话不会自动回来。\n\n<a id=\"dev-note\"></a>\n### 开发备注\n\n<details>\n<summary>维护者的工作上下文——点击展开</summary>\n\n本开发备注是维护者的工作上下文：开放问题与尚未决定的探索方向。它明确不具权威性——已交付的行为、限制与既定理由以上文、包代码和相关 Agent Note 为准。\n\n#### 开放：`create(path, title?)` 的 title 参数\n\n网关的按名称创建分支移除后，`title` 参数已无生产调用方；代码中的 TODO 提议把该参数与其 `@param` 子句一并移除（参见[笔记](../../../.agents/notes/implemented/simplification/2026-07-31-one-route-to-add-a-workspace.zh.md)）。\n\n</details>\n","readmeFilename":"README.zh.md","_rev":"1-dd269e2789f66b9030800e6226d62d43"}