dsh-cloudq 0.1.7 → 0.1.9

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/client.js CHANGED
@@ -599,14 +599,17 @@ linear-gradient(-30deg, transparent 49.5%, #2c2c31 49.5%, #2c2c31 50.5%, transpa
599
599
  return !!sessionId && cloudqSessions.has(sessionId);
600
600
  }
601
601
  let cloudqHistorySync = null;
602
+ let reconcileQueued = false;
602
603
  function reconcileCloudqSessionsFromHost() {
603
- if (cloudqHistorySync) return cloudqHistorySync;
604
+ if (cloudqHistorySync) {
605
+ reconcileQueued = true;
606
+ return cloudqHistorySync;
607
+ }
604
608
  cloudqHistorySync = cloudqRequest(API_CLOUDQ_SESSIONS, void 0, 6e4).then((response) => {
605
609
  const detected = new Set(Array.isArray(response?.sessionIds) ? response.sessionIds : []);
606
- const snapshot = cloudqCtx?.sessions?.list?.getSnapshot?.();
607
- for (const sessionId of Array.from(cloudqSessions)) {
608
- const summary = snapshot?.byId?.[sessionId];
609
- if (summary && !summary.blank && !detected.has(sessionId)) cloudqSessions.delete(sessionId);
610
+ const known = new Set(Array.isArray(response?.knownIds) ? response.knownIds : []);
611
+ if (known.size > 0) {
612
+ for (const sessionId of Array.from(cloudqSessions)) if (!known.has(sessionId)) cloudqSessions.delete(sessionId);
610
613
  }
611
614
  for (const sessionId of detected) cloudqSessions.add(sessionId);
612
615
  saveCloudqSessions(cloudqSessions);
@@ -614,6 +617,10 @@ linear-gradient(-30deg, transparent 49.5%, #2c2c31 49.5%, #2c2c31 50.5%, transpa
614
617
  return detected;
615
618
  }).catch(() => /* @__PURE__ */ new Set()).finally(() => {
616
619
  cloudqHistorySync = null;
620
+ if (reconcileQueued) {
621
+ reconcileQueued = false;
622
+ reconcileCloudqSessionsFromHost();
623
+ }
617
624
  });
618
625
  return cloudqHistorySync;
619
626
  }
@@ -792,6 +799,17 @@ linear-gradient(-30deg, transparent 49.5%, #2c2c31 49.5%, #2c2c31 50.5%, transpa
792
799
  * order (manual and recent-order variants). Only if a collapsed/search
793
800
  * view prevents an exact sequence match do we fall back to title matching.
794
801
  */
802
+ function rowSessionId(row) {
803
+ const fiberKey = Object.keys(row).find((key) => key.startsWith("__reactFiber$"));
804
+ if (!fiberKey) return void 0;
805
+ let fiber = row[fiberKey];
806
+ for (let depth = 0; fiber && depth < 12; depth += 1) {
807
+ const props = fiber.memoizedProps;
808
+ const id = props?.node?.id ?? props?.sessionId;
809
+ if (typeof id === "string" && id.startsWith("session-")) return id;
810
+ fiber = fiber.return;
811
+ }
812
+ }
795
813
  function installSessionBadges() {
796
814
  let disposed = false;
797
815
  let frame = 0;
@@ -821,7 +839,8 @@ linear-gradient(-30deg, transparent 49.5%, #2c2c31 49.5%, #2c2c31 50.5%, transpa
821
839
  const exact = exactOrder?.[index] ?? (selected ? snapshot.byId?.[snapshot.current] : void 0);
822
840
  const candidates = exact ? [exact] : byTitle.get(title) ?? [];
823
841
  const states = new Set(candidates.map((summary) => isCloudqSession(summary.id)));
824
- const cloudq = candidates.length > 0 && states.size === 1 && states.has(true);
842
+ const fiberId = rowSessionId(row);
843
+ const cloudq = fiberId !== void 0 ? isCloudqSession(fiberId) : candidates.length > 0 && states.size === 1 && states.has(true);
825
844
  const existing = row.querySelector("[data-cloudq-session-badge=\"true\"]");
826
845
  if (!cloudq) {
827
846
  existing?.remove();
@@ -3615,12 +3634,38 @@ display: none;
3615
3634
  window.dispatchEvent(new CustomEvent("dsh-cloudq:sessions-changed"));
3616
3635
  };
3617
3636
  window.addEventListener("storage", onStorage);
3637
+ const backstop = window.setInterval(() => {
3638
+ if (!disposed) reconcileCloudqSessionsFromHost();
3639
+ }, 3e4);
3618
3640
  syncHistory();
3619
3641
  return () => {
3620
3642
  disposed = true;
3643
+ window.clearInterval(backstop);
3621
3644
  window.removeEventListener("storage", onStorage);
3622
3645
  };
3623
3646
  }, "dsh-cloudq: reconcile durable session identities");
3647
+ ctx.effect(() => {
3648
+ const markIfCloudqClaim = () => {
3649
+ const textarea = document.querySelector("textarea[class*=input]");
3650
+ const draft = typeof textarea?.value === "string" ? textarea.value : "";
3651
+ if (!/^\s*\/cloudq(?:\s|$)/i.test(draft)) return;
3652
+ const sessionId = cloudqCtx?.sessions?.selection?.getSnapshot?.()?.sessionId ?? cloudqCtx?.sessions?.list?.getSnapshot?.()?.current;
3653
+ if (sessionId) markCloudqSession(sessionId);
3654
+ };
3655
+ const onKeyDown = (event) => {
3656
+ if (event.key !== "Enter" || event.shiftKey || event.isComposing) return;
3657
+ if (event.target instanceof HTMLTextAreaElement) markIfCloudqClaim();
3658
+ };
3659
+ const onClick = (event) => {
3660
+ if (event.target?.closest?.("button[class*=primary]")) markIfCloudqClaim();
3661
+ };
3662
+ document.addEventListener("keydown", onKeyDown, true);
3663
+ document.addEventListener("click", onClick, true);
3664
+ return () => {
3665
+ document.removeEventListener("keydown", onKeyDown, true);
3666
+ document.removeEventListener("click", onClick, true);
3667
+ };
3668
+ }, "dsh-cloudq: mark session on claim submit");
3624
3669
  ctx.effect(installStyles, "dsh-cloudq: styles");
3625
3670
  ctx.effect(() => {
3626
3671
  const slots = ctx.slots;
package/lib/index.js CHANGED
@@ -589,18 +589,23 @@ async function detectCloudqSessionIds(ctx) {
589
589
  if (query === void 0) throw new HttpError(503, "session-query-unavailable", "当前 DSH 未启用会话查询服务。");
590
590
  const records = await query.listSessions();
591
591
  const ids = [];
592
+ const knownIds = [];
592
593
  const queue = [...records];
593
594
  const worker = async () => {
594
595
  while (queue.length > 0) {
595
596
  const sessionId = queue.shift()?.header?.id;
596
597
  if (!sessionId) continue;
598
+ knownIds.push(sessionId);
597
599
  try {
598
600
  if (hasCloudqEvidence((await query.readSession(sessionId))?.events)) ids.push(sessionId);
599
601
  } catch {}
600
602
  }
601
603
  };
602
604
  await Promise.all(Array.from({ length: Math.min(6, queue.length) }, () => worker()));
603
- return ids;
605
+ return {
606
+ ids,
607
+ knownIds
608
+ };
604
609
  }
605
610
  /** Settings namespace for the browser card (must equal client card `key`). */
606
611
  const SETTINGS_NAMESPACE = "dsh-cloudq";
@@ -627,7 +632,7 @@ function apply(ctx) {
627
632
  name: "cloudq",
628
633
  description: "用户咨询腾讯云产品资源、AWS、阿里云等多云资源时,查看智能顾问架构图、架构目录、架构详情、架构评估结果、绘制架构图、开通智能顾问时、AI智能巡检、AI容量监测、AI混沌演练、AI云诊断、主动预警、架构健康度、云运维问答、云资源查询、云成本优化、安全合规、云资源盘点、闲置资源检查、云产品最佳实践等AIOps、ChatOps、CloudOps操作时使用。",
629
634
  whenToUse: "用户要求进入 CloudQ 模式、使用 CloudQ、咨询云上架构/资源/成本/巡检/诊断等多云或腾讯云运维问题,或点击输入栏 CloudQ 按钮时使用;也适用于架构图查看/评估、AI 巡检、容量监测、混沌演练、云诊断等场景。",
630
- source: "dsh",
635
+ source: "bundled",
631
636
  resourceBase: {
632
637
  kind: "directory",
633
638
  path: skillDirectory()
@@ -825,9 +830,11 @@ function apply(ctx) {
825
830
  handler: async (request, response) => {
826
831
  try {
827
832
  assertSafeRequest(request, "GET");
833
+ const { ids, knownIds } = await detectCloudqSessionIds(ctx);
828
834
  sendJson(response, 200, {
829
835
  ok: true,
830
- sessionIds: await detectCloudqSessionIds(ctx)
836
+ sessionIds: ids,
837
+ knownIds
831
838
  });
832
839
  } catch (error) {
833
840
  sendError(response, error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-cloudq",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "CloudQ integration for DeepSeek Harness with secure credential, workspace, and plugin-management surfaces",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -280,9 +280,8 @@ def call_sse_api(question: str, session_id: str,
280
280
  # OAuth / Connector 模式下需要标记使用 CloudQ 控制台凭证
281
281
  if cred_source in ("oauth", "connector"):
282
282
  payload["UseCloudQCredential"] = True
283
- # Source 字段统一发送(CloudQChatCompletions 三种鉴权方式均支持)
284
- if source:
285
- payload["Source"] = source
283
+ # Source 字段统一发送且固定为 dsh(CloudQChatCompletions 三种鉴权方式均支持)
284
+ payload["Source"] = "dsh"
286
285
  payload_str = json.dumps(payload, separators=(",", ":"))
287
286
 
288
287
  # ---- TC3-HMAC-SHA256 签名 ----