dsh-rewind-plugin 0.15.3 → 0.16.0-alpha.1

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/SECURITY.md CHANGED
@@ -120,8 +120,8 @@ hides the `[target, marker]` span from the rendered transcript.
120
120
  - **Restores name only recorded paths**: the store contains resolved display
121
121
  paths of the session's own write-class tool calls (plus boundary re-checks
122
122
  over that same tracked set) — a restore can never write an arbitrary path.
123
- - **Path resolution rule**: relative paths resolve against the session
124
- workspace cwd, mirroring the fs tools' own rule (`src/session-cwd.ts`).
123
+ - **Path resolution rule**: relative paths resolve against the session's current
124
+ working directory, read from the same service the fs tools resolve through.
125
125
  - **Bounded backups**: `prune` keeps the newest 100 anchor groups per session
126
126
  (`MAX_ANCHOR_GROUPS`), except groups a non-terminal restore journal still
127
127
  references (pinned so the op can be finished), so backup accumulation stays
package/lib/client.js CHANGED
@@ -1359,7 +1359,7 @@ function createRewindBridge(deps) {
1359
1359
  }
1360
1360
 
1361
1361
  // src/client/build-info.ts
1362
- var PLUGIN_VERSION = true ? "0.15.3" : "dev";
1362
+ var PLUGIN_VERSION = true ? "0.16.0-alpha.1" : "dev";
1363
1363
  var PLUGIN_PACKAGE = "dsh-rewind-plugin";
1364
1364
  var BUILD_HASH = true ? "f36f8be8" : "dev";
1365
1365
 
package/lib/index.js CHANGED
@@ -224,14 +224,6 @@ function planRewind(events, surface, target) {
224
224
  };
225
225
  }
226
226
 
227
- // src/session-cwd.ts
228
- function sessionCwd(cwd) {
229
- return cwd;
230
- }
231
- function execSessionCwd(exec) {
232
- return sessionCwd(exec.agent?.session.header.cwd);
233
- }
234
-
235
227
  // src/snapshot.ts
236
228
  import { createHash } from "node:crypto";
237
229
  import { chmod, copyFile, lstat, mkdir, open, readFile, readdir, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
@@ -2388,10 +2380,7 @@ function anchorSeqOf(session, cache) {
2388
2380
  }
2389
2381
  async function resolveTarget(fs, path, cwd, signal) {
2390
2382
  try {
2391
- return await fs.resolve(path, {
2392
- ...cwd !== void 0 ? { cwd } : {},
2393
- signal
2394
- });
2383
+ return await fs.resolve(path, { cwd, signal });
2395
2384
  } catch {
2396
2385
  return void 0;
2397
2386
  }
@@ -2400,20 +2389,20 @@ function isNotFoundError(error) {
2400
2389
  const code = error?.code;
2401
2390
  return code === "ENOENT" || code === "FS_NOT_FOUND";
2402
2391
  }
2403
- async function captureBefore(fs, store, exec, pending) {
2392
+ async function captureBefore(fs, workingDirectory, store, exec, pending) {
2404
2393
  if (!TRACKED_TOOLS.has(exec.name)) return;
2405
- const session = exec.agent?.session;
2406
- if (session !== void 0 && isSubagentSession(session)) return;
2394
+ const agent = exec.agent;
2395
+ if (agent === void 0) return;
2396
+ if (isSubagentSession(agent.session)) return;
2407
2397
  const path = mutationPathOf(exec);
2408
2398
  if (path === void 0) return;
2409
- const cwd = execSessionCwd(exec);
2399
+ const cwd = await workingDirectory.ensure(agent, exec.signal);
2410
2400
  const target = await resolveTarget(fs, path, cwd, exec.signal);
2411
2401
  if (target === void 0) return;
2412
2402
  const info = await fs.stat(target, exec.signal).catch((error) => {
2413
2403
  if (isNotFoundError(error)) return void 0;
2414
2404
  throw error;
2415
2405
  });
2416
- if (session === void 0) return;
2417
2406
  if (info !== void 0 && info.type !== "file") return;
2418
2407
  if (info !== void 0 && store.isOverFileCap(info.size)) return;
2419
2408
  const key = `${exec.agent?.id ?? "anon"}:${exec.callId}`;
@@ -2421,7 +2410,7 @@ async function captureBefore(fs, store, exec, pending) {
2421
2410
  pending.set(key, { path: target.displayPath, backup: null });
2422
2411
  return;
2423
2412
  }
2424
- const staged = await store.stageCapture(session.id, key);
2413
+ const staged = await store.stageCapture(agent.session.id, key);
2425
2414
  let backup;
2426
2415
  try {
2427
2416
  await copyFile2(target.displayPath, staged);
@@ -2959,12 +2948,13 @@ function apply(ctx, config) {
2959
2948
  }
2960
2949
  })();
2961
2950
  }, { global: true });
2962
- ctx.inject(["fs"], (scope) => {
2951
+ ctx.inject(["fs", "workingDirectory"], (scope) => {
2963
2952
  const fs = scope.fs;
2953
+ const workingDirectory = scope.workingDirectory;
2964
2954
  fsService = fs;
2965
2955
  scope.on("tools/execute", async (exec, next) => {
2966
2956
  try {
2967
- await captureBefore(fs, store, exec, pending);
2957
+ await captureBefore(fs, workingDirectory, store, exec, pending);
2968
2958
  } catch (error) {
2969
2959
  ctx.logger.warn(`[dsh-rewind] before-capture failed for ${exec.name}: ${error instanceof Error ? error.message : String(error)}`);
2970
2960
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-rewind-plugin",
3
- "version": "0.15.3",
3
+ "version": "0.16.0-alpha.1",
4
4
  "description": "In-window conversation rewind with workspace file restore · 同窗口内对话回退并可还原工作区文件",
5
5
  "icon": "./assets/icon.svg",
6
6
  "keywords": [
@@ -20,7 +20,7 @@
20
20
  "license": "MIT",
21
21
  "engines": {
22
22
  "node": "^22.19.0 || >=24.0.0",
23
- "dsh": ">=0.2.0-rc.1"
23
+ "dsh": ">=0.2.1-alpha.2"
24
24
  },
25
25
  "type": "module",
26
26
  "main": "lib/index.js",
@@ -74,20 +74,21 @@
74
74
  },
75
75
  "peerDependencies": {
76
76
  "@deepseek-ai/cordis": "^4.0.1",
77
- "@deepseek-ai/dsh-client-locale": "^0.2.0-rc.1",
78
- "@deepseek-ai/dsh-client-ui-commands": "^0.2.0-rc.1",
79
- "@deepseek-ai/dsh-client-ui-plugin-manager": "^0.2.0-rc.1",
80
- "@deepseek-ai/dsh-client-ui-primitives": "^0.2.0-rc.1",
81
- "@deepseek-ai/dsh-client-ui-settings": "^0.2.0-rc.1",
82
- "@deepseek-ai/dsh-client-ui-slots": "^0.2.0-rc.1",
83
- "@deepseek-ai/dsh-commands": "^0.2.0-rc.1",
84
- "@deepseek-ai/dsh-fs": "^0.2.0-rc.1",
85
- "@deepseek-ai/dsh-home-paths": "^0.2.0-rc.1",
86
- "@deepseek-ai/dsh-llm": "^0.2.0-rc.1",
87
- "@deepseek-ai/dsh-sandbox": "^0.2.0-rc.1",
88
- "@deepseek-ai/dsh-session": "^0.2.0-rc.1",
89
- "@deepseek-ai/dsh-settings": "^0.2.0-rc.1",
90
- "@deepseek-ai/dsh-tools": "^0.2.0-rc.1",
77
+ "@deepseek-ai/dsh-client-locale": "^0.2.1-alpha.2",
78
+ "@deepseek-ai/dsh-client-ui-commands": "^0.2.1-alpha.2",
79
+ "@deepseek-ai/dsh-client-ui-plugin-manager": "^0.2.1-alpha.2",
80
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.2.1-alpha.2",
81
+ "@deepseek-ai/dsh-client-ui-settings": "^0.2.1-alpha.2",
82
+ "@deepseek-ai/dsh-client-ui-slots": "^0.2.1-alpha.2",
83
+ "@deepseek-ai/dsh-commands": "^0.2.1-alpha.2",
84
+ "@deepseek-ai/dsh-fs": "^0.2.1-alpha.2",
85
+ "@deepseek-ai/dsh-home-paths": "^0.2.1-alpha.2",
86
+ "@deepseek-ai/dsh-llm": "^0.2.1-alpha.2",
87
+ "@deepseek-ai/dsh-sandbox": "^0.2.1-alpha.2",
88
+ "@deepseek-ai/dsh-session": "^0.2.1-alpha.2",
89
+ "@deepseek-ai/dsh-settings": "^0.2.1-alpha.2",
90
+ "@deepseek-ai/dsh-tools": "^0.2.1-alpha.2",
91
+ "@deepseek-ai/dsh-working-directory": "^0.2.1-alpha.2",
91
92
  "@deepseek-ai/schemastery": "^3.18.4"
92
93
  },
93
94
  "peerDependenciesMeta": {
@@ -136,6 +137,9 @@
136
137
  "@deepseek-ai/dsh-tools": {
137
138
  "optional": true
138
139
  },
140
+ "@deepseek-ai/dsh-working-directory": {
141
+ "optional": true
142
+ },
139
143
  "@deepseek-ai/schemastery": {
140
144
  "optional": true
141
145
  }
@@ -143,41 +147,42 @@
143
147
  "devDependencies": {
144
148
  "@deepseek-ai/cordis": "4.0.3",
145
149
  "@deepseek-ai/cosmokit": "1.8.4",
146
- "@deepseek-ai/dsh-agent": "0.2.1-alpha.1",
147
- "@deepseek-ai/dsh-api-session-controller": "0.2.1-alpha.1",
148
- "@deepseek-ai/dsh-attachment": "0.2.1-alpha.1",
149
- "@deepseek-ai/dsh-client-connection": "0.2.1-alpha.1",
150
- "@deepseek-ai/dsh-client-locale": "0.2.1-alpha.1",
151
- "@deepseek-ai/dsh-client-store": "0.2.1-alpha.1",
152
- "@deepseek-ai/dsh-client-ui-commands": "0.2.1-alpha.1",
153
- "@deepseek-ai/dsh-client-ui-conversation": "0.2.1-alpha.1",
154
- "@deepseek-ai/dsh-client-ui-input-trigger": "0.2.1-alpha.1",
155
- "@deepseek-ai/dsh-client-ui-plugin-manager": "0.2.1-alpha.1",
156
- "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-alpha.1",
157
- "@deepseek-ai/dsh-client-ui-session": "0.2.1-alpha.1",
158
- "@deepseek-ai/dsh-client-ui-settings": "0.2.1-alpha.1",
159
- "@deepseek-ai/dsh-client-ui-slots": "0.2.1-alpha.1",
160
- "@deepseek-ai/dsh-command-compact": "0.2.1-alpha.1",
161
- "@deepseek-ai/dsh-commands": "0.2.1-alpha.1",
162
- "@deepseek-ai/dsh-compaction": "0.2.1-alpha.1",
163
- "@deepseek-ai/dsh-compaction-basic": "0.2.1-alpha.1",
164
- "@deepseek-ai/dsh-compaction-image-offload": "0.2.1-alpha.1",
165
- "@deepseek-ai/dsh-fs": "0.2.1-alpha.1",
166
- "@deepseek-ai/dsh-goal": "0.2.1-alpha.1",
167
- "@deepseek-ai/dsh-home-paths": "0.2.1-alpha.1",
168
- "@deepseek-ai/dsh-llm": "0.2.1-alpha.1",
169
- "@deepseek-ai/dsh-plan-mode": "0.2.1-alpha.1",
170
- "@deepseek-ai/dsh-sandbox": "0.2.1-alpha.1",
171
- "@deepseek-ai/dsh-scope": "0.2.1-alpha.1",
172
- "@deepseek-ai/dsh-session": "0.2.1-alpha.1",
173
- "@deepseek-ai/dsh-session-projection": "0.2.1-alpha.1",
174
- "@deepseek-ai/dsh-session-stats": "0.2.1-alpha.1",
175
- "@deepseek-ai/dsh-session-title": "0.2.1-alpha.1",
176
- "@deepseek-ai/dsh-settings": "0.2.1-alpha.1",
177
- "@deepseek-ai/dsh-token-meter": "0.2.1-alpha.1",
178
- "@deepseek-ai/dsh-tools": "0.2.1-alpha.1",
179
- "@deepseek-ai/dsh-typert-protocol": "0.2.1-alpha.1",
180
- "@deepseek-ai/dsh-user-questions": "0.2.1-alpha.1",
150
+ "@deepseek-ai/dsh-agent": "0.2.1-alpha.2",
151
+ "@deepseek-ai/dsh-api-session-controller": "0.2.1-alpha.2",
152
+ "@deepseek-ai/dsh-attachment": "0.2.1-alpha.2",
153
+ "@deepseek-ai/dsh-client-connection": "0.2.1-alpha.2",
154
+ "@deepseek-ai/dsh-client-locale": "0.2.1-alpha.2",
155
+ "@deepseek-ai/dsh-client-store": "0.2.1-alpha.2",
156
+ "@deepseek-ai/dsh-client-ui-commands": "0.2.1-alpha.2",
157
+ "@deepseek-ai/dsh-client-ui-conversation": "0.2.1-alpha.2",
158
+ "@deepseek-ai/dsh-client-ui-input-trigger": "0.2.1-alpha.2",
159
+ "@deepseek-ai/dsh-client-ui-plugin-manager": "0.2.1-alpha.2",
160
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-alpha.2",
161
+ "@deepseek-ai/dsh-client-ui-session": "0.2.1-alpha.2",
162
+ "@deepseek-ai/dsh-client-ui-settings": "0.2.1-alpha.2",
163
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.1-alpha.2",
164
+ "@deepseek-ai/dsh-command-compact": "0.2.1-alpha.2",
165
+ "@deepseek-ai/dsh-commands": "0.2.1-alpha.2",
166
+ "@deepseek-ai/dsh-compaction": "0.2.1-alpha.2",
167
+ "@deepseek-ai/dsh-compaction-basic": "0.2.1-alpha.2",
168
+ "@deepseek-ai/dsh-compaction-image-offload": "0.2.1-alpha.2",
169
+ "@deepseek-ai/dsh-fs": "0.2.1-alpha.2",
170
+ "@deepseek-ai/dsh-goal": "0.2.1-alpha.2",
171
+ "@deepseek-ai/dsh-home-paths": "0.2.1-alpha.2",
172
+ "@deepseek-ai/dsh-llm": "0.2.1-alpha.2",
173
+ "@deepseek-ai/dsh-plan-mode": "0.2.1-alpha.2",
174
+ "@deepseek-ai/dsh-sandbox": "0.2.1-alpha.2",
175
+ "@deepseek-ai/dsh-scope": "0.2.1-alpha.2",
176
+ "@deepseek-ai/dsh-session": "0.2.1-alpha.2",
177
+ "@deepseek-ai/dsh-session-projection": "0.2.1-alpha.2",
178
+ "@deepseek-ai/dsh-session-stats": "0.2.1-alpha.2",
179
+ "@deepseek-ai/dsh-session-title": "0.2.1-alpha.2",
180
+ "@deepseek-ai/dsh-settings": "0.2.1-alpha.2",
181
+ "@deepseek-ai/dsh-token-meter": "0.2.1-alpha.2",
182
+ "@deepseek-ai/dsh-tools": "0.2.1-alpha.2",
183
+ "@deepseek-ai/dsh-typert-protocol": "0.2.1-alpha.2",
184
+ "@deepseek-ai/dsh-user-questions": "0.2.1-alpha.2",
185
+ "@deepseek-ai/dsh-working-directory": "0.2.1-alpha.2",
181
186
  "@deepseek-ai/schemastery": "3.18.4",
182
187
  "@types/node": "^24.0.0",
183
188
  "@types/react": "^18.3.31",
@@ -1,21 +0,0 @@
1
- /**
2
- * Session-cwd resolution for snapshot tracking reads: relative paths resolve
3
- * against the calling agent's session workspace (`exec.agent.session.header.cwd`),
4
- * returned verbatim — no canonicalization — or `undefined` when the session has
5
- * none (the filesystem backend then applies its own default base).
6
- *
7
- * @module dsh-rewind/session-cwd
8
- */
9
- import type { ToolExecution } from '@deepseek-ai/dsh-tools';
10
- /**
11
- * The session workspace cwd to resolve a requested path against.
12
- * @param cwd - the session's `header.cwd`, if any.
13
- * @returns the cwd unchanged, or undefined when there is none.
14
- */
15
- export declare function sessionCwd(cwd: string | undefined): string | undefined;
16
- /**
17
- * Session cwd for one tool execution.
18
- * @param exec - the tool-execution context; only its optional `agent` is read.
19
- * @returns the calling agent's session cwd, or undefined for a non-agent caller.
20
- */
21
- export declare function execSessionCwd(exec: ToolExecution): string | undefined;