dsh-remote-local-plugin 0.8.6 → 0.8.7

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/README.md CHANGED
@@ -7,7 +7,7 @@ Remote development that appears as ordinary local sessions.
7
7
  This plugin targets the official **DSH Desktop** application. Tested/supported versions:
8
8
 
9
9
  - [DSH Desktop](https://github.com/deepseek-ai/deepseek-harness) [`0.2.1-rc.2`](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.2.1-rc.2)
10
- - Plugin [`0.8.6`](https://www.npmjs.com/package/dsh-remote-local-plugin)
10
+ - Plugin [`0.8.7`](https://www.npmjs.com/package/dsh-remote-local-plugin)
11
11
  - Remote DSH [`0.2.1-rc.2`](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.2.1-rc.2)
12
12
  - Remote [Node.js `22.19+`](https://nodejs.org/en/download) on Linux/macOS
13
13
 
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /* dsh-remote-local-plugin@0.8.6 — bundled host entry */
1
+ /* dsh-remote-local-plugin@0.8.7 — bundled host entry */
2
2
 
3
3
  // src/index.ts
4
4
  import { credentialRef } from "@deepseek-ai/dsh-credentials";
@@ -664,14 +664,14 @@ var RemoteMirrorService = class {
664
664
  const workspaces = await this.#hosts.workspaces(hostId);
665
665
  for (const workspace of workspaces) {
666
666
  if (isTestHidden(workspace.path, workspace.workspaceId, this.#testVisibility)) continue;
667
- const sessions = await this.#hosts.sessions(hostId, workspace.workspaceId);
667
+ const sessions = await this.#hosts.sessions(hostId, workspace.workspaceId, true);
668
668
  const summary2 = sessions.sessions.find((item) => item.sessionId === remoteSessionId);
669
669
  if (summary2 === void 0) continue;
670
670
  const localWorkspace2 = await this.#ensureWorkspace(host, workspace);
671
671
  const record = await this.#ensureMirror(host, summary2, localWorkspace2, workspace.path);
672
672
  return record?.localSessionId;
673
673
  }
674
- const all = await this.#hosts.sessions(hostId);
674
+ const all = await this.#hosts.sessions(hostId, void 0, true);
675
675
  const summary = all.sessions.find((item) => item.sessionId === remoteSessionId);
676
676
  if (summary === void 0) return void 0;
677
677
  if (summary.cwd !== null && isTestHidden(summary.cwd, "", this.#testVisibility)) return void 0;
@@ -742,24 +742,31 @@ var RemoteMirrorService = class {
742
742
  await this.#reconcileTestHidden(host);
743
743
  const workspaces = await this.#hosts.workspaces(host.id);
744
744
  const covered = /* @__PURE__ */ new Set();
745
+ const subagents = /* @__PURE__ */ new Set();
745
746
  const byPath = /* @__PURE__ */ new Map();
746
747
  for (const workspace of workspaces) {
747
748
  if (isTestHidden(workspace.path, workspace.workspaceId, this.#testVisibility)) {
748
- const sessions2 = await this.#hosts.sessions(host.id, workspace.workspaceId);
749
+ const sessions2 = await this.#hosts.sessions(host.id, workspace.workspaceId, true);
749
750
  for (const summary of sessions2.sessions) covered.add(summary.sessionId);
750
751
  continue;
751
752
  }
752
753
  const local = await this.#ensureWorkspace(host, workspace);
753
754
  byPath.set(workspace.path, { workspace: local, anchor: this.#anchorFor(local) });
754
- const sessions = await this.#hosts.sessions(host.id, workspace.workspaceId);
755
+ const sessions = await this.#hosts.sessions(host.id, workspace.workspaceId, true);
755
756
  for (const summary of sessions.sessions) {
756
757
  covered.add(summary.sessionId);
758
+ if (summary.origin === "subagent") {
759
+ subagents.add(summary.sessionId);
760
+ continue;
761
+ }
757
762
  await this.#ensureMirror(host, summary, local, workspace.path);
758
763
  }
759
764
  }
760
- const all = await this.#hosts.sessions(host.id);
765
+ const all = await this.#hosts.sessions(host.id, void 0, true);
761
766
  for (const summary of all.sessions) {
767
+ if (summary.origin === "subagent") subagents.add(summary.sessionId);
762
768
  if (covered.has(summary.sessionId)) continue;
769
+ if (summary.origin === "subagent") continue;
763
770
  if (summary.cwd !== null && isTestHidden(summary.cwd, "", this.#testVisibility)) continue;
764
771
  const workspace = summary.cwd === null ? void 0 : byPath.get(summary.cwd);
765
772
  if (workspace !== void 0) {
@@ -769,8 +776,47 @@ var RemoteMirrorService = class {
769
776
  const ungrouped = await this.#ensureUngroupedWorkspace(host, summary.cwd ?? "ungrouped");
770
777
  await this.#ensureMirror(host, summary, ungrouped.workspace, ungrouped.anchor);
771
778
  }
779
+ await this.#pruneMirroredSubagents(host.id, subagents);
780
+ }
781
+ /** Remove local mirrors for remote subagent Sessions, including stale rows. */
782
+ async #pruneMirroredSubagents(hostId, subagents) {
783
+ let changed = false;
784
+ for (const [ref, record] of Object.entries(this.#state.sessions)) {
785
+ if (record.hostId !== hostId || !subagents.has(record.remoteSessionId)) continue;
786
+ const runtime = this.#runtimes.get(record.localSessionId);
787
+ if (runtime !== void 0) {
788
+ runtime.stopped = true;
789
+ if (runtime.timer !== void 0) clearTimeout(runtime.timer);
790
+ runtime.stream?.abort();
791
+ runtime.assistant?.abort();
792
+ this.#runtimes.delete(record.localSessionId);
793
+ }
794
+ const registration = this.#registrations.get(record.localSessionId);
795
+ if (registration !== void 0) {
796
+ registration();
797
+ this.#registrations.delete(record.localSessionId);
798
+ }
799
+ await this.#archive(record.localSessionId);
800
+ delete this.#state.sessions[ref];
801
+ changed = true;
802
+ }
803
+ if (!changed) return;
804
+ for (const [ref, workspace] of Object.entries(this.#state.workspaces)) {
805
+ if (workspace.hostId !== hostId || workspace.remoteWorkspaceId !== null) continue;
806
+ const used = Object.values(this.#state.sessions).some(
807
+ (session) => session.hostId === hostId && session.anchor === workspace.anchor
808
+ );
809
+ if (used) continue;
810
+ try {
811
+ await this.#workspaceRegistry.delete(workspace.localWorkspaceId);
812
+ } catch {
813
+ }
814
+ delete this.#state.workspaces[ref];
815
+ }
816
+ await this.#save();
772
817
  }
773
818
  /**
819
+ * Apply the test-only manifest to already-mirrored workspaces. Hidden entries /**
774
820
  * Apply the test-only manifest to already-mirrored workspaces. Hidden entries
775
821
  * archive local Sessions and remove the local workspace row; removing an
776
822
  * entry unarchives the Sessions and lets the normal sync rebuild the row.
@@ -2363,7 +2409,7 @@ function isRemoteWorkspace(value) {
2363
2409
  function isRemoteSession(value) {
2364
2410
  if (!isRecord(value))
2365
2411
  return false;
2366
- return isString(value.sessionId) && (value.workspaceId === null || isString(value.workspaceId)) && (value.cwd === null || isString(value.cwd)) && isIsoString(value.createdAt) && typeof value.live === "boolean" && (value.eventCount === null || typeof value.eventCount === "number");
2412
+ return isString(value.sessionId) && (value.workspaceId === null || isString(value.workspaceId)) && (value.cwd === null || isString(value.cwd)) && isIsoString(value.createdAt) && typeof value.live === "boolean" && (value.eventCount === null || typeof value.eventCount === "number") && (value.origin === void 0 || value.origin === "subagent") && (value.parentSession === void 0 || isString(value.parentSession));
2367
2413
  }
2368
2414
  function isRemoteEvent(value) {
2369
2415
  return isRecord(value) && typeof value.seq === "number" && isString(value.type) && typeof value.time === "number" && "data" in value;
@@ -4436,11 +4482,13 @@ var RemoteHostsService = class {
4436
4482
  }
4437
4483
  }
4438
4484
  /** List remote sessions, optionally within one workspace. */
4439
- async sessions(id, workspaceId) {
4485
+ async sessions(id, workspaceId, includeSubagents = false) {
4440
4486
  const client = this.#requireClient(id);
4441
4487
  try {
4442
4488
  const sessions = await client.listSessions(workspaceId);
4443
- return { sessions };
4489
+ return {
4490
+ sessions: includeSubagents ? sessions : sessions.filter((session) => session.origin !== "subagent")
4491
+ };
4444
4492
  } catch (error) {
4445
4493
  throw this.#remoteFailure(id, error);
4446
4494
  }
@@ -60,7 +60,7 @@ export declare class RemoteHostsService {
60
60
  /** List remote workspaces. */
61
61
  workspaces(id: string): Promise<readonly RemoteWorkspace[]>;
62
62
  /** List remote sessions, optionally within one workspace. */
63
- sessions(id: string, workspaceId?: string): Promise<ListSessionsResult>;
63
+ sessions(id: string, workspaceId?: string, includeSubagents?: boolean): Promise<ListSessionsResult>;
64
64
  /** Follow a live remote session from a cursor as an SSE-backed stream. */
65
65
  followSessionEvents(id: string, sessionId: string, cursor: number, signal: AbortSignal): AsyncGenerator<SessionStreamFrame>;
66
66
  /** Read one session snapshot. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-remote-local-plugin",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "description": "DSH remote-development local plugin: host registry, SSH tunnels, remote workspace/session discovery, an authenticated Connection RPC surface, agent tools, and a Settings page.",
5
5
  "keywords": [
6
6
  "dsh",