@crazx/dsh-api-session-controller 0.1.5-alpha.1.zw.3 → 0.1.5-rc.1.zw.2

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.
@@ -8,7 +8,6 @@ import { flattenLineage } from "./lineage.js";
8
8
  import { Notifier } from "./notifier.js";
9
9
  import { ProjectionValueStore } from "./projection-store.js";
10
10
  import { Session } from "./session.js";
11
- import { SelectionHistory } from "./selection-history.js";
12
11
  function sessionSeqCursor(value) {
13
12
  return value === -1 ? -1 : SessionSeq(value);
14
13
  }
@@ -58,10 +57,6 @@ export class SessionManager {
58
57
  */
59
58
  jobsBySession = new Map();
60
59
  selected;
61
- /** Toolbar back/forward history over selections (session, addressed child, or clear). */
62
- selectionHistory = new SelectionHistory();
63
- /** While replaying a history entry, the selections it makes must not re-record. */
64
- navigatingHistory = false;
65
60
  listSnapshotCache;
66
61
  /** Entry-identity cache (reference stability): list rebuilds reuse the previous entry
67
62
  * object when every field matches — wire refreshes mint all-new summary objects, so identity
@@ -80,11 +75,6 @@ export class SessionManager {
80
75
  this.selected = restoredSelection;
81
76
  if (restoredAddress !== undefined)
82
77
  this.addresses.set(restoredAddress.childSessionId, restoredAddress);
83
- // The restored selection seeds the history so back/forward always has a
84
- // home position; a cold start without one records the cleared state.
85
- this.selectionHistory.record(restoredSelection === undefined
86
- ? {}
87
- : { sessionId: restoredSelection, ...(restoredAddress !== undefined ? { address: restoredAddress } : {}) });
88
78
  this.listSnapshotCache = this.buildListSnapshot();
89
79
  }
90
80
  // ---- Selection ----
@@ -105,8 +95,6 @@ export class SessionManager {
105
95
  this.selected = sessionId;
106
96
  // Looking at the session consumes its completion reminder (dot clears).
107
97
  this.completedNotifications.delete(sessionId);
108
- if (!this.navigatingHistory)
109
- this.selectionHistory.record(address === undefined ? { sessionId } : { sessionId, address });
110
98
  void this.refreshSubagents(sessionId);
111
99
  this.notifier.notifyNow();
112
100
  }
@@ -124,79 +112,14 @@ export class SessionManager {
124
112
  this.sessions.get(address.childSessionId)?.configureSubagent(address, catalog?.parentAvailable);
125
113
  this.selected = address.childSessionId;
126
114
  this.completedNotifications.delete(address.childSessionId);
127
- if (!this.navigatingHistory)
128
- this.selectionHistory.record({ sessionId: address.childSessionId, address });
129
115
  void this.refreshSubagents(address.childSessionId);
130
116
  this.notifier.notifyNow();
131
117
  }
132
118
  /** Clear the selection (the layout falls to the no-session view state). */
133
119
  clearSelection() {
134
120
  this.selected = undefined;
135
- if (!this.navigatingHistory)
136
- this.selectionHistory.record({});
137
121
  this.notifier.notifyNow();
138
122
  }
139
- // ---- Selection history (toolbar back/forward) ----
140
- /** Whether an older selection exists to go back to. */
141
- canBack() {
142
- return this.selectionHistory.canBack();
143
- }
144
- /** Whether a newer selection exists to go forward to. */
145
- canForward() {
146
- return this.selectionHistory.canForward();
147
- }
148
- /**
149
- * Select the previous history entry. Unreachable entries (sessions removed
150
- * before their prune landed) are pruned and the walk continues to older
151
- * entries; the walk stops silently at the oldest bound.
152
- */
153
- back() {
154
- while (this.selectionHistory.canBack()) {
155
- const entry = this.selectionHistory.back();
156
- if (entry === undefined)
157
- return;
158
- if (!this.canReplay(entry)) {
159
- if (entry.sessionId !== undefined)
160
- this.selectionHistory.prune(entry.sessionId);
161
- continue;
162
- }
163
- this.replaySelection(entry);
164
- return;
165
- }
166
- }
167
- /**
168
- * Select the next history entry after a back navigation; silently a
169
- * no-op at the newest bound.
170
- */
171
- forward() {
172
- const entry = this.selectionHistory.forward();
173
- if (entry === undefined)
174
- return;
175
- if (this.canReplay(entry))
176
- this.replaySelection(entry);
177
- else if (entry.sessionId !== undefined)
178
- this.selectionHistory.prune(entry.sessionId);
179
- }
180
- /** Whether a history entry names a session that is still listed or addressed. */
181
- canReplay(entry) {
182
- if (entry.sessionId === undefined)
183
- return true;
184
- return this.summaries.some(summary => summary.sessionId === entry.sessionId)
185
- || this.addresses.has(entry.sessionId);
186
- }
187
- /** Replay one entry without recording it back into the history. */
188
- replaySelection(entry) {
189
- this.navigatingHistory = true;
190
- try {
191
- if (entry.sessionId === undefined)
192
- this.clearSelection();
193
- else
194
- this.select(entry.sessionId);
195
- }
196
- finally {
197
- this.navigatingHistory = false;
198
- }
199
- }
200
123
  /**
201
124
  * Return the durable catalog address retained for one child.
202
125
  * @param sessionId - possible addressed child id.
@@ -456,8 +379,6 @@ export class SessionManager {
456
379
  let summaries = baseline;
457
380
  for (const mutation of mutations) {
458
381
  summaries = applyMutation(summaries, mutation);
459
- if (mutation.kind === 'remove')
460
- this.selectionHistory.prune(mutation.sessionId);
461
382
  this.summaries = summaries;
462
383
  this.syncCompletedNotifications();
463
384
  }
@@ -603,9 +524,6 @@ export class SessionManager {
603
524
  recordMutation(mutation) {
604
525
  this.listMutations?.push(mutation);
605
526
  this.summaries = applyMutation(this.summaries, mutation);
606
- // A removal forgets the session's toolbar back/forward history entries.
607
- if (mutation.kind === 'remove')
608
- this.selectionHistory.prune(mutation.sessionId);
609
527
  // Eager edge reconciliation — a snapshot-build-time pass would miss consecutive status frames.
610
528
  this.syncCompletedNotifications();
611
529
  this.notifier.markDirty();
@@ -185,14 +185,6 @@ export declare class ClientSessions implements ISessions {
185
185
  * per the masked-gap contract until the next open() moves the stage.
186
186
  */
187
187
  clear(): void;
188
- /** Whether the transient selection history has an older entry to go back to. */
189
- canBack(): boolean;
190
- /** Whether the transient selection history has a newer entry to go forward to. */
191
- canForward(): boolean;
192
- /** Select the previous history entry (prunes unreachable entries on the way). */
193
- back(): void;
194
- /** Select the next history entry after a back navigation. */
195
- forward(): void;
196
188
  /**
197
189
  * Refresh the real Session baseline, reusing an in-flight pull.
198
190
  * @returns completion of the current or newly started baseline pull.
@@ -193,22 +193,6 @@ export class ClientSessions {
193
193
  clear() {
194
194
  this.manager.clearSelection();
195
195
  }
196
- /** Whether the transient selection history has an older entry to go back to. */
197
- canBack() {
198
- return this.manager.canBack();
199
- }
200
- /** Whether the transient selection history has a newer entry to go forward to. */
201
- canForward() {
202
- return this.manager.canForward();
203
- }
204
- /** Select the previous history entry (prunes unreachable entries on the way). */
205
- back() {
206
- this.manager.back();
207
- }
208
- /** Select the next history entry after a back navigation. */
209
- forward() {
210
- this.manager.forward();
211
- }
212
196
  /**
213
197
  * Refresh the real Session baseline, reusing an in-flight pull.
214
198
  * @returns completion of the current or newly started baseline pull.
@@ -26,6 +26,8 @@ export interface Config {
26
26
  export interface SessionControllerInternals {
27
27
  /** Native default-application handoff. */
28
28
  readonly openPath?: (path: string, signal: AbortSignal) => Promise<void>;
29
+ /** Native file-manager handoff. */
30
+ readonly revealPath?: (path: string, signal: AbortSignal) => Promise<void>;
29
31
  /** Native handoff availability probe. */
30
32
  readonly canOpenPath?: () => boolean;
31
33
  }
@@ -39,6 +41,7 @@ export declare class SessionController extends TypertRemoteService {
39
41
  private readonly history;
40
42
  private readonly listState;
41
43
  private readonly openPath;
44
+ private readonly revealPath;
42
45
  private readonly canOpenPath;
43
46
  private readonly promotions;
44
47
  /**
@@ -97,6 +100,15 @@ export declare class SessionController extends TypertRemoteService {
97
100
  * @returns true when the matching open operation is available.
98
101
  */
99
102
  canOpenWorkspacePath(): boolean;
103
+ /**
104
+ * Describe the serving desktop for authenticated file-action routes.
105
+ * @returns Host name, configured availability, and platform-specific file-manager behavior.
106
+ */
107
+ workspaceDesktop(): {
108
+ name: string;
109
+ available: boolean;
110
+ fileManager: 'finder' | 'explorer' | 'directory' | null;
111
+ };
100
112
  /**
101
113
  * Open one path prepared by a Session-aware caller on the Host desktop.
102
114
  * @param request - path after best-effort Session workspace resolution.
@@ -85,9 +85,10 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
85
85
  var e = new Error(message);
86
86
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
87
87
  });
88
+ import { hostname } from 'node:os';
88
89
  import z from '@deepseek-ai/schemastery';
89
90
  import { errorChain } from '@deepseek-ai/dsh-llm';
90
- import { canOpenNativePath, openNativePath } from '@deepseek-ai/dsh-native-command';
91
+ import { canOpenNativePath, nativeFileManager, openNativePath, revealNativePath } from '@deepseek-ai/dsh-native-command';
91
92
  import { Remote, RemoteError, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
92
93
  import { ApiSessionAgentController, inspectApiSession, } from "./agent.js";
93
94
  import { SessionCommandController } from "./commands.js";
@@ -180,6 +181,7 @@ let SessionController = (() => {
180
181
  history;
181
182
  listState;
182
183
  openPath;
184
+ revealPath;
183
185
  canOpenPath;
184
186
  promotions = new Set();
185
187
  /**
@@ -207,6 +209,7 @@ let SessionController = (() => {
207
209
  this.history = new SessionHistoryController(ctx, (observation) => { this.promote(observation); });
208
210
  this.listState = new ApiSessionList(ctx);
209
211
  this.openPath = internals.openPath ?? openNativePath;
212
+ this.revealPath = internals.revealPath ?? revealNativePath;
210
213
  this.canOpenPath = internals.canOpenPath
211
214
  ?? (() => config.nativeOpen ?? (internals.openPath !== undefined || canOpenNativePath()));
212
215
  ctx.plugin(SessionFileReferences);
@@ -331,6 +334,14 @@ let SessionController = (() => {
331
334
  canOpenWorkspacePath() {
332
335
  return this.canOpenPath();
333
336
  }
337
+ /**
338
+ * Describe the serving desktop for authenticated file-action routes.
339
+ * @returns Host name, configured availability, and platform-specific file-manager behavior.
340
+ */
341
+ workspaceDesktop() {
342
+ const fileManager = nativeFileManager();
343
+ return { name: hostname(), available: fileManager !== null && this.canOpenPath(), fileManager };
344
+ }
334
345
  /**
335
346
  * Open one path prepared by a Session-aware caller on the Host desktop.
336
347
  * @param request - path after best-effort Session workspace resolution.
@@ -344,7 +355,10 @@ let SessionController = (() => {
344
355
  }
345
356
  signal.throwIfAborted();
346
357
  try {
347
- await this.openPath(request.path, signal);
358
+ if (request.action === 'reveal')
359
+ await this.revealPath(request.path, signal);
360
+ else
361
+ await this.openPath(request.path, signal);
348
362
  return { opened: true };
349
363
  }
350
364
  catch (error) {
@@ -332,6 +332,8 @@ export interface SessionCancelValue {
332
332
  }
333
333
  /** Request to open one path prepared by a Session-aware caller on the Host desktop. */
334
334
  export interface SessionOpenWorkspacePathRequest {
335
+ /** File-manager navigation when requested; omission uses the default application. */
336
+ readonly action?: 'reveal';
335
337
  /** Path after best-effort Session workspace resolution, in Host filesystem syntax. */
336
338
  readonly path: string;
337
339
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@crazx/dsh-api-session-controller",
3
3
  "description": "Session Remote commands, cold reads, and live control transport",
4
- "version": "0.1.5-alpha.1.zw.3",
4
+ "version": "0.1.5-rc.1.zw.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -64,42 +64,42 @@
64
64
  ],
65
65
  "license": "MIT",
66
66
  "dependencies": {
67
- "@deepseek-ai/dsh-brand": "^0.1.5-alpha.1",
68
- "@deepseek-ai/dsh-deque": "^0.1.5-alpha.1",
67
+ "@deepseek-ai/dsh-brand": "^0.1.5-rc.1",
68
+ "@deepseek-ai/dsh-deque": "^0.1.5-rc.1",
69
69
  "@deepseek-ai/schemastery": "^3.18.2",
70
70
  "mime-types": "^3.0.2",
71
71
  "zod": "^4.4.3"
72
72
  },
73
73
  "peerDependencies": {
74
74
  "@deepseek-ai/cordis": "^4.0.2",
75
- "@deepseek-ai/dsh-agent": "^0.1.5-alpha.1",
76
- "@deepseek-ai/dsh-agent-default-model": "npm:@crazx/dsh-agent-default-model@0.1.5-alpha.1.zw.3",
77
- "@deepseek-ai/dsh-agent-presets": "^0.1.5-alpha.1",
78
- "@deepseek-ai/dsh-api-gateway": "^0.1.5-alpha.1",
79
- "@deepseek-ai/dsh-attachment": "^0.1.5-alpha.1",
80
- "@deepseek-ai/dsh-client-connection": "^0.1.5-alpha.1",
81
- "@deepseek-ai/dsh-client-file-upload": "^0.1.5-alpha.1",
82
- "@deepseek-ai/dsh-commands": "^0.1.5-alpha.1",
83
- "@deepseek-ai/dsh-file-reference": "^0.1.5-alpha.1",
84
- "@deepseek-ai/dsh-fs": "^0.1.5-alpha.1",
85
- "@deepseek-ai/dsh-jobs": "^0.1.5-alpha.1",
86
- "@deepseek-ai/dsh-llm": "^0.1.5-alpha.1",
87
- "@deepseek-ai/dsh-native-command": "^0.1.5-alpha.1",
88
- "@deepseek-ai/dsh-scope": "^0.1.5-alpha.1",
89
- "@deepseek-ai/dsh-session": "^0.1.5-alpha.1",
90
- "@deepseek-ai/dsh-session-persistence": "^0.1.5-alpha.1",
91
- "@deepseek-ai/dsh-session-projection": "^0.1.5-alpha.1",
92
- "@deepseek-ai/dsh-session-projection-cache": "^0.1.5-alpha.1",
93
- "@deepseek-ai/dsh-session-query": "^0.1.5-alpha.1",
94
- "@deepseek-ai/dsh-session-title": "^0.1.5-alpha.1",
95
- "@deepseek-ai/dsh-skill": "^0.1.5-alpha.1",
96
- "@deepseek-ai/dsh-subagent": "^0.1.5-alpha.1",
97
- "@deepseek-ai/dsh-typert-protocol": "^0.1.5-alpha.1",
98
- "@deepseek-ai/dsh-typert-registry": "^0.1.5-alpha.1",
99
- "@deepseek-ai/dsh-util-time": "^0.1.5-alpha.1",
100
- "@deepseek-ai/dsh-util-values": "^0.1.5-alpha.1",
101
- "@deepseek-ai/dsh-util-workspace-path": "^0.1.5-alpha.1",
102
- "@deepseek-ai/dsh-workspace": "^0.1.5-alpha.1"
75
+ "@deepseek-ai/dsh-agent": "^0.1.5-rc.1",
76
+ "@deepseek-ai/dsh-agent-default-model": "0.1.5-rc.1.zw.2",
77
+ "@deepseek-ai/dsh-agent-presets": "^0.1.5-rc.1",
78
+ "@deepseek-ai/dsh-api-gateway": "^0.1.5-rc.1",
79
+ "@deepseek-ai/dsh-attachment": "^0.1.5-rc.1",
80
+ "@deepseek-ai/dsh-client-connection": "^0.1.5-rc.1",
81
+ "@deepseek-ai/dsh-client-file-upload": "^0.1.5-rc.1",
82
+ "@deepseek-ai/dsh-commands": "^0.1.5-rc.1",
83
+ "@deepseek-ai/dsh-file-reference": "^0.1.5-rc.1",
84
+ "@deepseek-ai/dsh-fs": "^0.1.5-rc.1",
85
+ "@deepseek-ai/dsh-jobs": "^0.1.5-rc.1",
86
+ "@deepseek-ai/dsh-llm": "^0.1.5-rc.1",
87
+ "@deepseek-ai/dsh-native-command": "^0.1.5-rc.1",
88
+ "@deepseek-ai/dsh-scope": "^0.1.5-rc.1",
89
+ "@deepseek-ai/dsh-session": "^0.1.5-rc.1",
90
+ "@deepseek-ai/dsh-session-persistence": "^0.1.5-rc.1",
91
+ "@deepseek-ai/dsh-session-projection": "^0.1.5-rc.1",
92
+ "@deepseek-ai/dsh-session-projection-cache": "^0.1.5-rc.1",
93
+ "@deepseek-ai/dsh-session-query": "^0.1.5-rc.1",
94
+ "@deepseek-ai/dsh-session-title": "^0.1.5-rc.1",
95
+ "@deepseek-ai/dsh-skill": "^0.1.5-rc.1",
96
+ "@deepseek-ai/dsh-subagent": "^0.1.5-rc.1",
97
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.5-rc.1",
98
+ "@deepseek-ai/dsh-typert-registry": "^0.1.5-rc.1",
99
+ "@deepseek-ai/dsh-util-time": "^0.1.5-rc.1",
100
+ "@deepseek-ai/dsh-util-values": "^0.1.5-rc.1",
101
+ "@deepseek-ai/dsh-util-workspace-path": "^0.1.5-rc.1",
102
+ "@deepseek-ai/dsh-workspace": "^0.1.5-rc.1"
103
103
  },
104
104
  "peerDependenciesMeta": {
105
105
  "@deepseek-ai/dsh-jobs": {
@@ -114,43 +114,43 @@
114
114
  },
115
115
  "devDependencies": {
116
116
  "@deepseek-ai/cordis": "^4.0.2",
117
- "@deepseek-ai/dsh-agent": "^0.1.5-alpha.1",
118
- "@deepseek-ai/dsh-agent-default-model": "npm:@crazx/dsh-agent-default-model@0.1.5-alpha.1.zw.3",
119
- "@deepseek-ai/dsh-agent-loop": "^0.1.5-alpha.1",
120
- "@deepseek-ai/dsh-agent-loop-testkit": "^0.1.5-alpha.1",
121
- "@deepseek-ai/dsh-agent-presets": "^0.1.5-alpha.1",
122
- "@deepseek-ai/dsh-api-gateway": "^0.1.5-alpha.1",
123
- "@deepseek-ai/dsh-attachment": "^0.1.5-alpha.1",
124
- "@deepseek-ai/dsh-client-connection": "^0.1.5-alpha.1",
125
- "@deepseek-ai/dsh-client-file-upload": "^0.1.5-alpha.1",
126
- "@deepseek-ai/dsh-client-store": "^0.1.5-alpha.1",
127
- "@deepseek-ai/dsh-commands": "^0.1.5-alpha.1",
128
- "@deepseek-ai/dsh-file-reference": "^0.1.5-alpha.1",
129
- "@deepseek-ai/dsh-fs": "^0.1.5-alpha.1",
130
- "@deepseek-ai/dsh-fs-local": "^0.1.5-alpha.1",
131
- "@deepseek-ai/dsh-jobs": "^0.1.5-alpha.1",
132
- "@deepseek-ai/dsh-llm": "^0.1.5-alpha.1",
133
- "@deepseek-ai/dsh-native-command": "^0.1.5-alpha.1",
134
- "@deepseek-ai/dsh-permission-presets": "^0.1.5-alpha.1",
135
- "@deepseek-ai/dsh-scope": "^0.1.5-alpha.1",
136
- "@deepseek-ai/dsh-session": "^0.1.5-alpha.1",
137
- "@deepseek-ai/dsh-session-persistence": "^0.1.5-alpha.1",
138
- "@deepseek-ai/dsh-session-projection": "^0.1.5-alpha.1",
139
- "@deepseek-ai/dsh-session-projection-cache": "^0.1.5-alpha.1",
140
- "@deepseek-ai/dsh-session-query": "^0.1.5-alpha.1",
141
- "@deepseek-ai/dsh-session-title": "^0.1.5-alpha.1",
142
- "@deepseek-ai/dsh-skill": "^0.1.5-alpha.1",
143
- "@deepseek-ai/dsh-storage": "^0.1.5-alpha.1",
144
- "@deepseek-ai/dsh-storage-domain": "^0.1.5-alpha.1",
145
- "@deepseek-ai/dsh-storage-json": "^0.1.5-alpha.1",
146
- "@deepseek-ai/dsh-subagent": "^0.1.5-alpha.1",
147
- "@deepseek-ai/dsh-typert-protocol": "^0.1.5-alpha.1",
148
- "@deepseek-ai/dsh-typert-registry": "^0.1.5-alpha.1",
149
- "@deepseek-ai/dsh-util-crypto": "^0.1.5-alpha.1",
150
- "@deepseek-ai/dsh-util-time": "^0.1.5-alpha.1",
151
- "@deepseek-ai/dsh-util-values": "^0.1.5-alpha.1",
152
- "@deepseek-ai/dsh-util-workspace-path": "^0.1.5-alpha.1",
153
- "@deepseek-ai/dsh-workspace": "^0.1.5-alpha.1",
117
+ "@deepseek-ai/dsh-agent": "^0.1.5-rc.1",
118
+ "@deepseek-ai/dsh-agent-default-model": "npm:@crazx/dsh-agent-default-model@0.1.5-rc.1.zw.2",
119
+ "@deepseek-ai/dsh-agent-loop": "^0.1.5-rc.1",
120
+ "@deepseek-ai/dsh-agent-loop-testkit": "^0.1.5-rc.1",
121
+ "@deepseek-ai/dsh-agent-presets": "^0.1.5-rc.1",
122
+ "@deepseek-ai/dsh-api-gateway": "^0.1.5-rc.1",
123
+ "@deepseek-ai/dsh-attachment": "^0.1.5-rc.1",
124
+ "@deepseek-ai/dsh-client-connection": "^0.1.5-rc.1",
125
+ "@deepseek-ai/dsh-client-file-upload": "^0.1.5-rc.1",
126
+ "@deepseek-ai/dsh-client-store": "^0.1.5-rc.1",
127
+ "@deepseek-ai/dsh-commands": "^0.1.5-rc.1",
128
+ "@deepseek-ai/dsh-file-reference": "^0.1.5-rc.1",
129
+ "@deepseek-ai/dsh-fs": "^0.1.5-rc.1",
130
+ "@deepseek-ai/dsh-fs-local": "^0.1.5-rc.1",
131
+ "@deepseek-ai/dsh-jobs": "^0.1.5-rc.1",
132
+ "@deepseek-ai/dsh-llm": "^0.1.5-rc.1",
133
+ "@deepseek-ai/dsh-native-command": "^0.1.5-rc.1",
134
+ "@deepseek-ai/dsh-permission-presets": "^0.1.5-rc.1",
135
+ "@deepseek-ai/dsh-scope": "^0.1.5-rc.1",
136
+ "@deepseek-ai/dsh-session": "^0.1.5-rc.1",
137
+ "@deepseek-ai/dsh-session-persistence": "^0.1.5-rc.1",
138
+ "@deepseek-ai/dsh-session-projection": "^0.1.5-rc.1",
139
+ "@deepseek-ai/dsh-session-projection-cache": "^0.1.5-rc.1",
140
+ "@deepseek-ai/dsh-session-query": "^0.1.5-rc.1",
141
+ "@deepseek-ai/dsh-session-title": "^0.1.5-rc.1",
142
+ "@deepseek-ai/dsh-skill": "^0.1.5-rc.1",
143
+ "@deepseek-ai/dsh-storage": "^0.1.5-rc.1",
144
+ "@deepseek-ai/dsh-storage-domain": "^0.1.5-rc.1",
145
+ "@deepseek-ai/dsh-storage-json": "^0.1.5-rc.1",
146
+ "@deepseek-ai/dsh-subagent": "^0.1.5-rc.1",
147
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.5-rc.1",
148
+ "@deepseek-ai/dsh-typert-registry": "^0.1.5-rc.1",
149
+ "@deepseek-ai/dsh-util-crypto": "^0.1.5-rc.1",
150
+ "@deepseek-ai/dsh-util-time": "^0.1.5-rc.1",
151
+ "@deepseek-ai/dsh-util-values": "^0.1.5-rc.1",
152
+ "@deepseek-ai/dsh-util-workspace-path": "^0.1.5-rc.1",
153
+ "@deepseek-ai/dsh-workspace": "^0.1.5-rc.1",
154
154
  "@types/mime-types": "^3.0.1"
155
155
  },
156
156
  "scripts": {
@@ -1,55 +0,0 @@
1
- /**
2
- * Bounded transient selection history behind the desktop toolbar's
3
- * back/forward navigation. Entries record WHICH selection was made — a
4
- * listed session, an addressed subagent, or the cleared no-session state —
5
- * never when, and never any session content. Browser-local and transient by
6
- * design: nothing here is persisted, so a reload starts empty.
7
- */
8
- import type { SessionId } from '@deepseek-ai/dsh-session/types';
9
- import type { SubagentAddress } from '@deepseek-ai/dsh-subagent/client';
10
- /** One selection-history entry; `sessionId: undefined` is the cleared state. */
11
- export interface SelectionEntry {
12
- readonly sessionId?: SessionId;
13
- /** Retained direct-parent address for an addressed subagent selection. */
14
- readonly address?: SubagentAddress;
15
- }
16
- /**
17
- * Bounded LIFO-with-cursor history. Recording a selection made outside
18
- * navigation collapses consecutive repeats, truncates the forward tail after
19
- * a backtrack, and drops the oldest entry past the bound. Pruning removes
20
- * deleted sessions wherever they sit and re-points the cursor onto the same
21
- * logical position.
22
- */
23
- export declare class SelectionHistory {
24
- #private;
25
- private readonly limit;
26
- constructor(limit?: number);
27
- get entries(): readonly SelectionEntry[];
28
- get cursor(): number;
29
- /** Whether an older entry exists to go back to. */
30
- canBack(): boolean;
31
- /** Whether a newer entry exists to go forward to. */
32
- canForward(): boolean;
33
- /**
34
- * Record one selection made outside history navigation.
35
- * @param entry - the selection (session, addressed subagent, or clear).
36
- */
37
- record(entry: SelectionEntry): void;
38
- /**
39
- * Step one entry back.
40
- * @returns the entry to replay, or undefined at the oldest bound.
41
- */
42
- back(): SelectionEntry | undefined;
43
- /**
44
- * Step one entry forward.
45
- * @returns the entry to replay, or undefined at the newest bound.
46
- */
47
- forward(): SelectionEntry | undefined;
48
- /**
49
- * Drop every entry referencing the removed session wherever it sits,
50
- * keeping the cursor on the same logical position.
51
- * @param sessionId - the removed session.
52
- */
53
- prune(sessionId: SessionId): void;
54
- }
55
- //# sourceMappingURL=selection-history.d.ts.map
@@ -1,91 +0,0 @@
1
- function sameSelection(left, right) {
2
- return left.sessionId === right.sessionId
3
- && left.address?.parentSessionId === right.address?.parentSessionId
4
- && left.address?.childSessionId === right.address?.childSessionId;
5
- }
6
- /**
7
- * Bounded LIFO-with-cursor history. Recording a selection made outside
8
- * navigation collapses consecutive repeats, truncates the forward tail after
9
- * a backtrack, and drops the oldest entry past the bound. Pruning removes
10
- * deleted sessions wherever they sit and re-points the cursor onto the same
11
- * logical position.
12
- */
13
- export class SelectionHistory {
14
- limit;
15
- /** Oldest-first; the cursor sits ON the current entry (-1 while empty). */
16
- #entries = [];
17
- #cursor = -1;
18
- constructor(limit = 50) {
19
- this.limit = limit;
20
- }
21
- get entries() {
22
- return this.#entries;
23
- }
24
- get cursor() {
25
- return this.#cursor;
26
- }
27
- /** Whether an older entry exists to go back to. */
28
- canBack() {
29
- return this.#cursor > 0;
30
- }
31
- /** Whether a newer entry exists to go forward to. */
32
- canForward() {
33
- return this.#cursor < this.#entries.length - 1;
34
- }
35
- /**
36
- * Record one selection made outside history navigation.
37
- * @param entry - the selection (session, addressed subagent, or clear).
38
- */
39
- record(entry) {
40
- const current = this.#entries[this.#cursor];
41
- if (current !== undefined && sameSelection(current, entry))
42
- return;
43
- this.#entries.length = this.#cursor + 1;
44
- this.#entries.push(entry);
45
- if (this.#entries.length > this.limit)
46
- this.#entries.shift();
47
- this.#cursor = this.#entries.length - 1;
48
- }
49
- /**
50
- * Step one entry back.
51
- * @returns the entry to replay, or undefined at the oldest bound.
52
- */
53
- back() {
54
- if (!this.canBack())
55
- return undefined;
56
- this.#cursor -= 1;
57
- const entry = this.#entries[this.#cursor];
58
- return entry;
59
- }
60
- /**
61
- * Step one entry forward.
62
- * @returns the entry to replay, or undefined at the newest bound.
63
- */
64
- forward() {
65
- if (!this.canForward())
66
- return undefined;
67
- this.#cursor += 1;
68
- const entry = this.#entries[this.#cursor];
69
- return entry;
70
- }
71
- /**
72
- * Drop every entry referencing the removed session wherever it sits,
73
- * keeping the cursor on the same logical position.
74
- * @param sessionId - the removed session.
75
- */
76
- prune(sessionId) {
77
- let removedBeforeCursor = 0;
78
- for (let index = this.#entries.length - 1; index >= 0; index -= 1) {
79
- const entry = this.#entries[index];
80
- if (entry === undefined || entry.sessionId !== sessionId)
81
- continue;
82
- this.#entries.splice(index, 1);
83
- if (index <= this.#cursor)
84
- removedBeforeCursor += 1;
85
- }
86
- this.#cursor -= removedBeforeCursor;
87
- if (this.#cursor > this.#entries.length - 1)
88
- this.#cursor = this.#entries.length - 1;
89
- }
90
- }
91
- //# sourceMappingURL=selection-history.js.map