@blue-soda/dsh-remote 0.5.5 → 0.5.6

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
@@ -23,7 +23,7 @@ Continue DeepSeek Harness sessions and experimental Codex workspaces from anothe
23
23
  Add the current package version to the `web` profile, then restart Harness:
24
24
 
25
25
  ```sh
26
- dsh plugin --profile web add -w @blue-soda/dsh-remote@0.5.4
26
+ dsh plugin --profile web add -w @blue-soda/dsh-remote@0.5.6
27
27
  ```
28
28
 
29
29
  ### dsh-TUI Host
@@ -31,7 +31,7 @@ dsh plugin --profile web add -w @blue-soda/dsh-remote@0.5.4
31
31
  Remote can also run as a Host in a terminal-only [dsh-TUI](https://github.com/ccch1mneyyy/dsh-TUI) profile:
32
32
 
33
33
  ```sh
34
- dsh plugin --profile dsh-tui add -w @blue-soda/dsh-remote@0.5.4
34
+ dsh plugin --profile dsh-tui add -w @blue-soda/dsh-remote@0.5.6
35
35
  ```
36
36
 
37
37
  After starting dsh-TUI, manage Remote with `/remote`, `/remote login`, `/remote status`, and `/remote logout`.
package/dist/index.js CHANGED
@@ -13521,7 +13521,7 @@ function normalizeServerUrl(value) {
13521
13521
  }
13522
13522
 
13523
13523
  // src/version.ts
13524
- var PLUGIN_VERSION = "0.5.5";
13524
+ var PLUGIN_VERSION = "0.5.6";
13525
13525
 
13526
13526
  // src/server-api.ts
13527
13527
  var ENABLED_QR_PROVIDERS = ["github"];
@@ -15512,7 +15512,7 @@ var CodexRemoteClient = class {
15512
15512
  if (!isRecord(result) || !Array.isArray(result.data))
15513
15513
  throw invalidResponse("thread list");
15514
15514
  return {
15515
- sessions: result.data.map(projectCodexThread).filter((value) => value !== void 0),
15515
+ sessions: uniqueCodexThreadRows(result.data).map(projectCodexThread).filter((value) => value !== void 0),
15516
15516
  ...typeof result.nextCursor === "string" ? { nextCursor: result.nextCursor } : {}
15517
15517
  };
15518
15518
  }
@@ -15666,6 +15666,33 @@ function projectCodexThread(value) {
15666
15666
  ...typeof value.isPinned === "boolean" ? { pinned: value.isPinned } : {}
15667
15667
  };
15668
15668
  }
15669
+ var THREAD_ID_KEY = /^[A-Za-z0-9][A-Za-z0-9._-]{0,255}$/u;
15670
+ var LEGACY_ROW_KEY = /^([A-Za-z0-9][A-Za-z0-9._-]{0,255})~[^~]{0,64}~[0-9]{1,9}$/u;
15671
+ function codexThreadIdFromKey(key) {
15672
+ if (THREAD_ID_KEY.test(key))
15673
+ return key;
15674
+ return LEGACY_ROW_KEY.exec(key)?.[1];
15675
+ }
15676
+ function rowFreshness(row) {
15677
+ for (const field of ["updatedAt", "createdAt"]) {
15678
+ const value = row[field];
15679
+ if (typeof value === "number" && Number.isFinite(value))
15680
+ return value;
15681
+ }
15682
+ return 0;
15683
+ }
15684
+ function uniqueCodexThreadRows(values) {
15685
+ const byThread = /* @__PURE__ */ new Map();
15686
+ for (const value of values) {
15687
+ if (!isRecord(value) || typeof value.id !== "string" || value.id.length === 0)
15688
+ continue;
15689
+ const threadId = codexThreadIdFromKey(value.id) ?? value.id;
15690
+ const current = byThread.get(threadId);
15691
+ if (current === void 0 || rowFreshness(value) > rowFreshness(current))
15692
+ byThread.set(threadId, value);
15693
+ }
15694
+ return [...byThread.values()];
15695
+ }
15669
15696
  function deriveCodexCwdWorkspaces(values) {
15670
15697
  const byPath = /* @__PURE__ */ new Map();
15671
15698
  const usedIds = /* @__PURE__ */ new Set();
@@ -17540,6 +17567,17 @@ function record(value) {
17540
17567
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
17541
17568
  }
17542
17569
 
17570
+ // src/codex/session-id.ts
17571
+ var SESSION_PREFIX = "codex:";
17572
+ function parseCodexSessionId(value) {
17573
+ if (typeof value !== "string" || !value.startsWith(SESSION_PREFIX)) return void 0;
17574
+ const threadId = codexThreadIdFromKey(value.slice(SESSION_PREFIX.length));
17575
+ return threadId === void 0 ? void 0 : { sessionId: value, threadId };
17576
+ }
17577
+ function resolveCodexThreadKey(key) {
17578
+ return codexThreadIdFromKey(key) ?? key;
17579
+ }
17580
+
17543
17581
  // src/codex/method-policy.ts
17544
17582
  var id2 = external_exports.string().min(1).max(256);
17545
17583
  var cursor = external_exports.string().min(1).max(4096).nullable().optional();
@@ -19411,7 +19449,7 @@ async function loadCatalog(client, signal, pendingThreads) {
19411
19449
  updatedAt: workspace.updatedAt
19412
19450
  }));
19413
19451
  }
19414
- const projected = threads.map((thread) => {
19452
+ const projected = uniqueCodexThreadRows(threads).map((thread) => {
19415
19453
  const session = projectCodexThread(thread);
19416
19454
  return session === void 0 ? void 0 : { thread, session };
19417
19455
  }).filter((value) => value !== void 0);
@@ -20121,10 +20159,9 @@ function sessionIdFromAddress(address) {
20121
20159
  return requiredString(address.childSessionId, "childSessionId");
20122
20160
  }
20123
20161
  function nativeThreadId(sessionId) {
20124
- if (!sessionId.startsWith(CODEX_SESSION_PREFIX) || sessionId.length === CODEX_SESSION_PREFIX.length) {
20125
- throw new Error("The selected Session does not belong to CodeX.");
20126
- }
20127
- return sessionId.slice(CODEX_SESSION_PREFIX.length);
20162
+ const parsed = parseCodexSessionId(sessionId);
20163
+ if (parsed === void 0) throw new Error("The selected Session does not belong to CodeX.");
20164
+ return parsed.threadId;
20128
20165
  }
20129
20166
  function activeTurnId(value) {
20130
20167
  if (!Array.isArray(value)) return void 0;
@@ -24679,8 +24716,9 @@ var CodexPeerBridge = class {
24679
24716
  method: "thread/read",
24680
24717
  params: { threadId: params.threadId, includeTurns: false }
24681
24718
  });
24682
- this.streams.set(params.streamId, params.threadId);
24683
- return { opened: true, streamId: params.streamId, threadId: params.threadId };
24719
+ const threadId = resolveCodexThreadKey(params.threadId);
24720
+ this.streams.set(params.streamId, threadId);
24721
+ return { opened: true, streamId: params.streamId, threadId };
24684
24722
  }
24685
24723
  closeStream(input2) {
24686
24724
  const params = streamCloseSchema.parse(input2);
@@ -25026,9 +25064,7 @@ var CodexRemoteDomain = class {
25026
25064
  }));
25027
25065
  }
25028
25066
  if (isRecord12(call.params) && typeof call.params.threadId === "string") {
25029
- const rowKey = call.params.threadId;
25030
- const separator = rowKey.indexOf("~");
25031
- if (separator > 0) call.params.threadId = rowKey.slice(0, separator);
25067
+ call.params.threadId = resolveCodexThreadKey(call.params.threadId);
25032
25068
  }
25033
25069
  if (call.method === "thread/list") {
25034
25070
  const result = sanitizeThreadList(await this.callUpstream(call.method, call.params));
@@ -25038,10 +25074,7 @@ var CodexRemoteDomain = class {
25038
25074
  );
25039
25075
  return {
25040
25076
  ...authorized,
25041
- data: authorized.data.map((row, index) => ({
25042
- ...row,
25043
- id: `${String(row.id)}~${String(row.createdAt ?? "")}~${index}`
25044
- }))
25077
+ data: uniqueCodexThreadRows(authorized.data)
25045
25078
  };
25046
25079
  }
25047
25080
  if (call.method === "thread/start") {
@@ -26724,13 +26757,6 @@ function redact(value, key = "") {
26724
26757
  return Object.fromEntries(Object.entries(value).map(([childKey, child]) => [childKey, redact(child, childKey)]));
26725
26758
  }
26726
26759
 
26727
- // src/codex/session-id.ts
26728
- function parseCodexSessionId(value) {
26729
- if (typeof value !== "string") return void 0;
26730
- const match = /^codex:([A-Za-z0-9][A-Za-z0-9._-]{0,255})$/.exec(value);
26731
- return match === null ? void 0 : { sessionId: value, threadId: match[1] };
26732
- }
26733
-
26734
26760
  // src/terminal-policy.ts
26735
26761
  var TERMINAL_CALLS = /* @__PURE__ */ new Set([
26736
26762
  "terminal/environment",
@@ -26744,6 +26770,7 @@ var TERMINAL_CALLS = /* @__PURE__ */ new Set([
26744
26770
  ]);
26745
26771
  var TERMINAL_STREAMS = /* @__PURE__ */ new Set(["terminal/follow", "terminal/retain"]);
26746
26772
  var id3 = external_exports.string().regex(/^[A-Za-z0-9_:-]{1,256}$/);
26773
+ var sessionKey = external_exports.string().regex(/^[A-Za-z0-9_:~-]{1,512}$/);
26747
26774
  var TerminalPolicy = class {
26748
26775
  constructor(enabled, deviceId, owners) {
26749
26776
  this.enabled = enabled;
@@ -26758,7 +26785,7 @@ var TerminalPolicy = class {
26758
26785
  );
26759
26786
  const args = external_exports.object({ args: external_exports.record(external_exports.unknown()) }).strict().parse(payload).args;
26760
26787
  const rawSessionId = args.agentId ?? args.sessionId;
26761
- const sessionId = id3.parse(rawSessionId);
26788
+ const sessionId = sessionKey.parse(rawSessionId);
26762
26789
  const codexSession = parseCodexSessionId(sessionId);
26763
26790
  void codexSession;
26764
26791
  if (endpoint === "terminal/environment" || endpoint === "terminal/shells" || endpoint === "terminal/list") return {};