dsh-code-server-app 0.3.39 → 0.3.41

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/lib/index.js CHANGED
@@ -756,8 +756,8 @@ export async function apply(ctx, config) {
756
756
  /** 上次记录过的"有没有人在看"(0.3.30:状态翻转才写诊断日志)。 */
757
757
  let bridgeWatchLogged = false;
758
758
  /** 首帧是否已写过诊断(0.3.31:"一直没人看"也要留下证据)。 */
759
- let bridgeWatchWroteFirst = false;
760
- /** 上次写过的 hasPanel 判据原文(变了才写,避免每 600ms 刷屏)。 */
759
+ let bridgeWatchWroteFirst = false;
760
+ /** 上次写过的 hasPanel 判据原文(变了才写,避免每 600ms 刷屏)。 */
761
761
  let bridgeHasPanelLine = '';
762
762
  /** 客户端(self-declared)是否能把授权卡片画出来(0.3.30)。 */
763
763
  let bridgeApprovalsUi = false;
@@ -810,16 +810,16 @@ export async function apply(ctx, config) {
810
810
  // 客户端能画卡片 = 编辑器面板自报可以的 **或** 对话框开着且有会话(0.3.33)。
811
811
  // "活着"由 /ask/state 轮询证明)。0.3.31 的日志给出了反例:用户从**对话框**提问 ⇒
812
812
  // 编辑器面板是 null ⇒ 旧判据误判成"画不出卡片",授权被让给了 DSH 界面。
813
- hasPanel: () => {
814
- const watcher = hasWatcher();
815
- const dialogCapable = askDialogLive();
816
- const verdict = watcher && (bridgeApprovalsUi || dialogCapable);
817
- // 判据的**原始值**一起落日志(0.3.35):只记结论的话,出问题还是只能猜。
818
- const line = 'hasPanel -> ' + verdict + ' (hasWatcher=' + watcher + ' approvalsUi=' + bridgeApprovalsUi
819
- + ' dialogLive=' + dialogCapable + ' polls=' + askDialog.polls + ' open=' + askDialog.open
820
- + ' session=' + String(askDialog.sessionId) + ')';
821
- if (line !== bridgeHasPanelLine) { bridgeHasPanelLine = line; bridgeDiag(line); }
822
- return verdict;
813
+ hasPanel: () => {
814
+ const watcher = hasWatcher();
815
+ const dialogCapable = askDialogLive();
816
+ const verdict = watcher && (bridgeApprovalsUi || dialogCapable);
817
+ // 判据的**原始值**一起落日志(0.3.35):只记结论的话,出问题还是只能猜。
818
+ const line = 'hasPanel -> ' + verdict + ' (hasWatcher=' + watcher + ' approvalsUi=' + bridgeApprovalsUi
819
+ + ' dialogLive=' + dialogCapable + ' polls=' + askDialog.polls + ' open=' + askDialog.open
820
+ + ' session=' + String(askDialog.sessionId) + ')';
821
+ if (line !== bridgeHasPanelLine) { bridgeHasPanelLine = line; bridgeDiag(line); }
822
+ return verdict;
823
823
  },
824
824
  log: (message) => {
825
825
  console.warn(`[code-server] 编辑器桥授权:${message}`);
@@ -836,7 +836,7 @@ export async function apply(ctx, config) {
836
836
  * - 状态与动作的 HTTP 面(`/api/code-server/ask/*`,与 DSH 同源、吃它的 cookie/Origin 校验);
837
837
  * - 把面板产物(thread.js / thread.css)交给对话框注入(Lib 版本与 DSH 界面同版本,见 build-webview.mjs)。
838
838
  */
839
- const askDialog = { open: false, mode: 'selection', at: 0, sessionId: null, polls: 0, lastPollAt: 0 };
839
+ const askDialog = { open: false, armed: false, mode: 'selection', at: 0, sessionId: null, polls: 0, lastPollAt: 0 };
840
840
 
841
841
  /**
842
842
  * 对话框"活着吗" —— **能力位必须以此为准**(0.3.25)。
@@ -852,7 +852,12 @@ export async function apply(ctx, config) {
852
852
  // TTL 取 10 分钟:浏览器后台节流会把 900ms 拖到分钟级,短 TTL 会让"人就在编辑器旁边"
853
853
  // 被误判成"没人看"(实测连续踩了两轮)。
854
854
  const TTL_MS = 10 * 60 * 1000;
855
- if (askDialog.polls > 0 && Date.now() - askDialog.lastPollAt < TTL_MS) return true;
855
+ // **必须在"武装"状态下**才算有能力显示卡片(0.3.40):
856
+ // 只认"最近轮询过"会让**已经关掉的对话框**在 10 分钟内继续被当成能显示卡片的 UI ——
857
+ // 那时我们仍会接住请求,而卡片无处显示(就是用户说的"没弹出授权")。
858
+ // armed 在 /ask/state 轮询时置位,在 /ask/close 时立刻清除 ⇒ 关掉之后下一次判据复查(≤500ms)
859
+ // 就会把正在等待的请求交回官方卡片。
860
+ if (askDialog.armed === true && askDialog.polls > 0 && Date.now() - askDialog.lastPollAt < TTL_MS) return true;
856
861
  // 心跳还没建立(刚重启)时:对话框开着且有会话也算。
857
862
  return askDialog.open && askDialog.sessionId !== null;
858
863
  }
@@ -2084,10 +2089,12 @@ export async function apply(ctx, config) {
2084
2089
  async function handleAskState(request) {
2085
2090
  // 这一条就是"客户端半部活着"的证据(能力位 askDialog 以它为准,见 askDialogLive)。
2086
2091
  askDialog.polls += 1;
2087
- askDialog.lastPollAt = Date.now();
2088
- // 心跳证据(0.3.35):首次 + 每 40 次写一行,证明"对话框在持续发活跃通知"。
2089
- if (askDialog.polls % 40 === 1) {
2090
- bridgeDiag('dialog heartbeat #' + askDialog.polls + ' (open=' + askDialog.open + ' session=' + String(askDialog.sessionId) + ')');
2092
+ // 有轮询 = 对话框活着 ⇒ 武装(关掉时 /ask/close 会立刻解除)。
2093
+ askDialog.armed = true;
2094
+ askDialog.lastPollAt = Date.now();
2095
+ // 心跳证据(0.3.35):首次 + 每 40 次写一行,证明"对话框在持续发活跃通知"。
2096
+ if (askDialog.polls % 40 === 1) {
2097
+ bridgeDiag('dialog heartbeat #' + askDialog.polls + ' (open=' + askDialog.open + ' session=' + String(askDialog.sessionId) + ')');
2091
2098
  }
2092
2099
  if (askDialog.polls === 1) {
2093
2100
  console.log('[code-server] 「问 DSH」对话框已连上客户端半部:/ask/state 开始轮询');
@@ -2156,6 +2163,9 @@ export async function apply(ctx, config) {
2156
2163
  /** 对话框关掉:不再看会话 ⇒ 待决授权按"没人看"交回官方链路(拦截器的轮询会立刻放行)。 */
2157
2164
  async function handleAskClose() {
2158
2165
  askDialog.open = false;
2166
+ // **关闭即解除武装**(0.3.40):否则 10 分钟 TTL 内我们还会继续拦截,而卡片已经没地方显示。
2167
+ askDialog.armed = false;
2168
+ askDialog.lastPollAt = 0;
2159
2169
  askDialog.sessionId = null;
2160
2170
  refreshDialogWatch();
2161
2171
  return jsonResponse({ ok: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-code-server-app",
3
- "version": "0.3.39",
3
+ "version": "0.3.41",
4
4
  "description": "VS Code (from a code-server release) inside DSH: a right-sidebar tab driven by the plugin's own launcher over the in-process VS Code server (lib/launcher.mjs). Since 0.3.0 the bundle also ships an editor bridge (assets/extensions/dshcs-editor-bridge): a read-only channel between the in-tree VS Code extension host and DSH, giving the agent what only the editor knows (unsaved buffers, language-server diagnostics, the active selection) and letting editor gestures drive the session. Since 0.3.22 the ask panel renders that session's new content with DSH's own Markdown renderer (pinned to the deployed DSH UI version); since 0.3.23 it is a full-width dialog with collapsible thinking rows and can answer approval requests in place — the bridge's only non-read-only route (POST /approve, constrained to pending in-process requests and the outcomes allowed-once/rejected; panel-first for 5 minutes, handed back to the official card the moment the panel closes). The tab claims DSH file addresses (dsh-resource://file/**) by file type (setting claimExtensions), so the product's own produced-file chips, delivered-file previews and inline prose mentions open in the workbench. The IDE is a resident surface moved with Element.moveBefore instead of being remounted, so switching sidebar tabs no longer reloads it. Opening the tab switches the right sidebar to fullscreen by default (setting fullscreenOnOpen). Following a workspace switch is lightweight: the workbench re-navigates with the new ?folder= and the IDE process is not restarted (since 0.2.12). Requires a DSH with the right-sidebar services (sidebarRightTabs/sidebarRight, >= 0.1.5-alpha.1); older DSH versions get a single upgrade notice on the settings page and no other UI. Two serving modes: loopback port (default) or same-origin mount on DSH's own webServer (/code-server, protected by ctx.connection.requestRejection). No code-server Node layer, no argon2, no C++ toolchain.",
5
5
  "homepage": "https://github.com/jinsiyu/dsh-code-server-app",
6
6
  "repository": {
@@ -3,7 +3,7 @@
3
3
  "vscodeVersion": "1.137.0",
4
4
  "productPath": "stable-b11dabdaca0d3369986975be285db92c8795cea5",
5
5
  "layout": "vscode-only",
6
- "preparedAt": "2026-09-13T12:47:27.183Z",
6
+ "preparedAt": "2026-09-13T13:12:03.503Z",
7
7
  "source": "registry",
8
8
  "node": "v24.21.0",
9
9
  "platform": "win32",