@sparkelf/dsh-patch-workspace-storage-restore 0.1.0-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +9 -0
- package/README.zh.md +9 -0
- package/package.json +39 -0
- package/patches/workspace-storage-restore.patch +112 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write patches/npm/workspace-storage-restore/README.md
|
|
5
|
+
README.md: 403dd3aa3673d0c7f896e395464688e51c3bf690
|
|
6
|
+
README.zh.md: 69e2d7935a48f955943fce129492a16b05f84522
|
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @sparkelf/dsh-patch-workspace-storage-restore
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
Data-only temporary patch for the official DSH source revision `cd5ef8148158c3a752a658978873241fdf8e2bbc`. It adds `WorkspaceRegistry.withStorageRestore`, which closes the Workspace durable domain around an external file replacement and reopens through normal initialization before returning.
|
|
6
|
+
|
|
7
|
+
The target source revision identifies `dsh-v0.1.2-alpha.1`. That tag has no matching published `@deepseek-ai/dsh-workspace` npm artifact, so this variant cannot truthfully target an npm package version. The Plus distribution declares this exact official base revision; the materializer verifies that base is an ancestor of the Plus checkout, verifies the repository-root payload with `git apply --check`, and then builds DSH from that official source base plus the selected Plus artifacts. There is no alternate revision, fuzzy application, or runtime code in this package.
|
|
8
|
+
|
|
9
|
+
Retire this package when an official DSH release exposes an equivalent Workspace storage restore operation and `@sparkelf/dsh-plugin-backup` can consume it without a local payload.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @sparkelf/dsh-patch-workspace-storage-restore
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
针对official DSH source revision `cd5ef8148158c3a752a658978873241fdf8e2bbc`的data-only temporary patch。它增加`WorkspaceRegistry.withStorageRestore`,在external file replacement期间关闭Workspace durable domain,并在return前通过正常initialization重开。
|
|
6
|
+
|
|
7
|
+
target source revision对应`dsh-v0.1.2-alpha.1`。该tag没有匹配的已发布`@deepseek-ai/dsh-workspace` npm artifact,因此该variant不能诚实地指向npm package version。Plus distribution声明这个exact official base revision;materializer验证该base是Plus checkout的ancestor,通过`git apply --check`验证repository-root payload,然后从official source base与selected Plus artifacts build DSH。本package没有alternate revision、fuzzy application或runtime code。
|
|
8
|
+
|
|
9
|
+
当official DSH release提供等价Workspace storage restore operation,且`@sparkelf/dsh-plugin-backup`无需local payload即可消费时,retire本package。
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Data-only patch adding the Workspace storage restore transaction to the exact official DSH source revision",
|
|
3
|
+
"dshPatch": {
|
|
4
|
+
"formatVersion": 1,
|
|
5
|
+
"variants": [
|
|
6
|
+
{
|
|
7
|
+
"dsh": ">=0.1.2-alpha.1",
|
|
8
|
+
"file": "./patches/workspace-storage-restore.patch",
|
|
9
|
+
"id": "workspace-storage-restore",
|
|
10
|
+
"target": {
|
|
11
|
+
"baseRevision": "cd5ef8148158c3a752a658978873241fdf8e2bbc",
|
|
12
|
+
"kind": "dsh-source",
|
|
13
|
+
"paths": [
|
|
14
|
+
"packages/workspace/workspace/"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
"./package.json": "./package.json",
|
|
22
|
+
"./patches/workspace-storage-restore.patch": "./patches/workspace-storage-restore.patch"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"patches/*.patch"
|
|
26
|
+
],
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"name": "@sparkelf/dsh-patch-workspace-storage-restore",
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"directory": "patches/npm/workspace-storage-restore",
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/SparkElf/deepseek-harness-plus.git"
|
|
36
|
+
},
|
|
37
|
+
"type": "module",
|
|
38
|
+
"version": "0.1.0-rc.10"
|
|
39
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
diff --git a/packages/workspace/workspace/README.i18n.yaml b/packages/workspace/workspace/README.i18n.yaml
|
|
2
|
+
index 70a99f420d..1a1479948e 100644
|
|
3
|
+
--- a/packages/workspace/workspace/README.i18n.yaml
|
|
4
|
+
+++ b/packages/workspace/workspace/README.i18n.yaml
|
|
5
|
+
@@ -2,5 +2,5 @@
|
|
6
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
7
|
+
# after editing either side, bring the other along and re-record with:
|
|
8
|
+
# pnpm run verify-translation-pairing --write packages/workspace/workspace/README.md
|
|
9
|
+
-README.md: 49ca861742fe9ea5f36edbaeb8d9700c475b1d50
|
|
10
|
+
-README.zh.md: 707044970b716577d2f1f95e558c341e217985c4
|
|
11
|
+
+README.md: daa779bee34760eacc222341bfcc09fb1052cb00
|
|
12
|
+
+README.zh.md: 989f81fc6bedcc5e2616e8ea90452c40ee63ea85
|
|
13
|
+
diff --git a/packages/workspace/workspace/README.md b/packages/workspace/workspace/README.md
|
|
14
|
+
index 49ca861742..daa779bee3 100644
|
|
15
|
+
--- a/packages/workspace/workspace/README.md
|
|
16
|
+
+++ b/packages/workspace/workspace/README.md
|
|
17
|
+
@@ -89,6 +89,8 @@ This section explains the design decisions behind the feature and points at the
|
|
18
|
+
|
|
19
|
+
The API is one small family with two owners: `WorkspaceRegistry` creates, orders, and deletes projects and manages their session accounting; the `Workspace` entity exposes the display title, directory status, and the session projection. Per-method contracts live in the code, not this README — see [src/index.ts](src/index.ts) and [src/entity.ts](src/entity.ts).
|
|
20
|
+
|
|
21
|
+
+`WorkspaceRegistry.withStorageRestore` waits for current registry mutations, closes the durable domain while its caller replaces external files, and always reopens through the startup initialization path before resolving so records, archive state, and Session indexes share the restored baseline.
|
|
22
|
+
+
|
|
23
|
+
### Source map
|
|
24
|
+
|
|
25
|
+
| File | Role |
|
|
26
|
+
diff --git a/packages/workspace/workspace/README.zh.md b/packages/workspace/workspace/README.zh.md
|
|
27
|
+
index 707044970b..989f81fc6b 100644
|
|
28
|
+
--- a/packages/workspace/workspace/README.zh.md
|
|
29
|
+
+++ b/packages/workspace/workspace/README.zh.md
|
|
30
|
+
@@ -89,6 +89,8 @@ ctx.workspaceRegistry.list() // shows the project, newest first
|
|
31
|
+
|
|
32
|
+
该 API 是一个由两个所有者构成的小家族:`WorkspaceRegistry` 负责创建、排序与删除项目并管理其会话记账;`Workspace` 实体暴露显示标题、目录状态与会话投影。各方法的精确约定在代码中,而非本 README——参见 [src/index.ts](src/index.ts) 与 [src/entity.ts](src/entity.ts)。
|
|
33
|
+
|
|
34
|
+
+`WorkspaceRegistry.withStorageRestore` 会等待当前 registry mutations,在caller替换external files期间关闭durable domain,并始终在resolve前通过startup initialization path重开,使records、archive state与Session indexes共享恢复后的baseline。
|
|
35
|
+
+
|
|
36
|
+
### 源码地图
|
|
37
|
+
|
|
38
|
+
| 文件 | 职责 |
|
|
39
|
+
diff --git a/packages/workspace/workspace/src/index.ts b/packages/workspace/workspace/src/index.ts
|
|
40
|
+
index 87edb28cad..2f6d57b8ab 100644
|
|
41
|
+
--- a/packages/workspace/workspace/src/index.ts
|
|
42
|
+
+++ b/packages/workspace/workspace/src/index.ts
|
|
43
|
+
@@ -11,7 +11,7 @@ import { basename } from 'node:path'
|
|
44
|
+
import { Context, Service } from '@deepseek-ai/cordis'
|
|
45
|
+
import type { SessionHeader, SessionId } from '@deepseek-ai/dsh-session'
|
|
46
|
+
import type {} from '@deepseek-ai/dsh-session-persistence'
|
|
47
|
+
-import type { DomainGlobal, KvTable } from '@deepseek-ai/dsh-storage-domain'
|
|
48
|
+
+import type { Domain, DomainGlobal, KvTable } from '@deepseek-ai/dsh-storage-domain'
|
|
49
|
+
import { WorkspaceEntity } from './entity.ts'
|
|
50
|
+
import type { WorkspaceEntityHost } from './entity.ts'
|
|
51
|
+
|
|
52
|
+
@@ -92,6 +92,7 @@ const compareHeaders = (left: SessionHeader, right: SessionHeader): number =>
|
|
53
|
+
export class WorkspaceRegistry extends Service {
|
|
54
|
+
static inject = ['storageDomain', 'sessionPersistence']
|
|
55
|
+
|
|
56
|
+
+ private domain?: Domain<typeof workspaceDomainSpec>
|
|
57
|
+
private table?: KvTable<WorkspaceId, WorkspaceRecord>
|
|
58
|
+
private global?: DomainGlobal<WorkspaceDomainState>
|
|
59
|
+
private state?: WorkspaceDomainState
|
|
60
|
+
@@ -117,8 +118,51 @@ export class WorkspaceRegistry extends Service {
|
|
61
|
+
|
|
62
|
+
/** Open the domain, finish bootstrap when required, and rebuild the ordered cache. */
|
|
63
|
+
protected async [Service.init](): Promise<void> {
|
|
64
|
+
+ this.ctx.effect(() => () => this.domain?.close(), 'workspace.domainClose')
|
|
65
|
+
+ await this.openDomain()
|
|
66
|
+
+ }
|
|
67
|
+
+
|
|
68
|
+
+ /**
|
|
69
|
+
+ * Replace external durable files while no Workspace storage handle is open.
|
|
70
|
+
+ * Existing mutations settle first; the domain always reopens through startup
|
|
71
|
+
+ * initialization so records, archive state, and Session indexes share one new
|
|
72
|
+
+ * baseline.
|
|
73
|
+
+ * @param restore - File replacement operation run while Workspace storage is closed.
|
|
74
|
+
+ * @returns the operation result after the new durable baseline is available.
|
|
75
|
+
+ */
|
|
76
|
+
+ async withStorageRestore<T>(restore: () => Promise<T>): Promise<T> {
|
|
77
|
+
+ // restore替换durable files前必须先退出domain;finally复用startup路径重建全部index。
|
|
78
|
+
+ return await this.enqueueOperation(async () => {
|
|
79
|
+
+ const domain = this.domain
|
|
80
|
+
+ if (domain === undefined) throw new Error('workspace registry is not started yet')
|
|
81
|
+
+ const previousArchivedSessions = this.requireState().archivedSessionIds.length
|
|
82
|
+
+ await domain.close()
|
|
83
|
+
+ delete this.domain
|
|
84
|
+
+ delete this.table
|
|
85
|
+
+ delete this.global
|
|
86
|
+
+ delete this.state
|
|
87
|
+
+ this.entities.clear()
|
|
88
|
+
+ this.headers.clear()
|
|
89
|
+
+ this.sessionPaths.clear()
|
|
90
|
+
+ this.invalidSessionPaths.clear()
|
|
91
|
+
+ try {
|
|
92
|
+
+ return await restore()
|
|
93
|
+
+ } finally {
|
|
94
|
+
+ await this.openDomain()
|
|
95
|
+
+ console.info('[workspace] storage restore baseline loaded', {
|
|
96
|
+
+ previousArchivedSessions,
|
|
97
|
+
+ restoredArchivedSessions: this.requireState().archivedSessionIds.length,
|
|
98
|
+
+ workspaces: this.entities.size,
|
|
99
|
+
+ indexedSessionHeaders: this.headers.size,
|
|
100
|
+
+ })
|
|
101
|
+
+ }
|
|
102
|
+
+ })
|
|
103
|
+
+ }
|
|
104
|
+
+
|
|
105
|
+
+ /** Open the durable domain and rebuild every registry cache from its contents. */
|
|
106
|
+
+ private async openDomain(): Promise<void> {
|
|
107
|
+
const domain = await this.ctx.storageDomain.open(workspaceDomainSpec)
|
|
108
|
+
- this.ctx.effect(() => () => domain.close(), 'workspace.domainClose')
|
|
109
|
+
+ this.domain = domain
|
|
110
|
+
this.table = domain.table('workspaces')
|
|
111
|
+
this.global = domain.global
|
|
112
|
+
this.state = domain.global.get()
|