dsh-codex-subscription 2.2.2 → 2.2.4

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
@@ -3298,7 +3298,7 @@ window.__ModuleLoader__.load({
3298
3298
  const expire = () => {
3299
3299
  clear();
3300
3300
  generation++;
3301
- if (state !== "stopped") update("failed");
3301
+ if (state === "drawing") update("failed");
3302
3302
  };
3303
3303
  return {
3304
3304
  get state() {
@@ -4627,6 +4627,68 @@ window.__ModuleLoader__.load({
4627
4627
  //#endregion
4628
4628
  //#region src/client-locales.js
4629
4629
  const zh = {
4630
+ "diagnosticsSnapshotTime": "报告快照时间:",
4631
+ "diagnosticsUnresolved": "仍有其他未恢复的失败记录,见上方摘要。",
4632
+ "diagnosticSeverity_warning": "需关注",
4633
+ "diagnosticSeverity_info": "信息",
4634
+ "diagnosticNext_restart": "重启后重新生成报告;若版本仍不一致,检查插件更新是否生效。",
4635
+ "diagnosticNext_regenerate": "复现问题后立即重新生成报告;若仍不完整,连同操作步骤反馈。",
4636
+ "diagnosticNext_supported-options": "继续使用当前可选档位即可;新增能力需要适配验证,不建议手动填入未知参数。",
4637
+ "diagnosticNext_reproduce": "核对下列操作与时间是否对应你的问题;若持续失败,反馈操作步骤和本报告。",
4638
+ "diagnosticFinding_evidence-truncated": "部分旧记录或宿主作用域未包含在快照中,报告不能覆盖全部历史。",
4639
+ "diagnosticsNoRecordedFailure": "当前记录未发现失败;未执行的功能仍未验证。",
4640
+ "diagnosticFinding_version-mismatch": "前后端版本不一致,请重启 DSH 后重新生成报告。",
4641
+ "diagnosticFinding_collection-incomplete": "部分检查未能完成,请查看详情中的失败或超时项。",
4642
+ "diagnosticFinding_catalog-gap": "在线模型目录包含当前适配层尚未支持的档位或能力;不代表模型不可用。",
4643
+ "diagnosticFinding_recent-failure": "最近 15 分钟有操作或请求失败,且同一操作尚无后续成功记录。请结合发生时间查看详情。",
4644
+ "diagnosticReason_no-readiness-check": "无独立前置检查",
4645
+ "diagnosticReason_inspection-failed": "检查未完成",
4646
+ "diagnosticReason_inspection-timeout": "检查超时",
4647
+ "diagnosticSource_network": "网络请求(非完整回复)",
4648
+ "diagnosticReason_catalog-online": "在线目录已载入",
4649
+ "diagnosticReason_catalog-fallback": "使用备用目录",
4650
+ "diagnosticReason_storage-readable": "预测缓存可读",
4651
+ "diagnosticReason_tool-registered": "全局工具已注册",
4652
+ "diagnosticReason_tool-missing": "未找到全局工具",
4653
+ "diagnosticsCoverageHint": "分别展示前置条件与最近 15 分钟的进程级证据;不限定当前账号或会话。接口响应、网络请求和工具结果不能替代完整功能验收。",
4654
+ "diagnosticsVersionMismatch": "前后端插件版本不同,请重载后重试。",
4655
+ "diagnosticsPartial": "部分信息未能采集,其余检查结果已保留。请在详情中查看失败或超时项。",
4656
+ "diagnosticsCapability": "功能",
4657
+ "diagnosticsReadiness": "前置条件",
4658
+ "diagnosticsEvidence": "近期操作证据",
4659
+ "diagnosticsUnverified": "尚未验证",
4660
+ "diagnosticsHostCollected": "已采集宿主注册与选中结果。registrant 是宿主标签,可能被压缩,不能据此识别插件或判断干扰。",
4661
+ "diagnosticsHostUnknown": "宿主界面检查不可用或未挂载,不能据此判断插件干扰。",
4662
+ "diagnosticsDetails": "展开脱敏详情",
4663
+ "diagnosticsCopyFailed": "复制失败,可展开详情手动复制。",
4664
+ "diagnosticSource_rpc": "接口响应",
4665
+ "diagnosticSource_tool": "工具",
4666
+ "diagnosticOutcome_completed": "完成",
4667
+ "diagnosticOutcome_failed": "失败",
4668
+ "diagnosticOutcome_cancelled": "取消",
4669
+ "diagnosticCapability_account": "登录",
4670
+ "diagnosticCapability_accounts": "多账号",
4671
+ "diagnosticCapability_settings": "设置",
4672
+ "diagnosticCapability_models": "模型",
4673
+ "diagnosticCapability_quota": "额度",
4674
+ "diagnosticCapability_search": "搜索",
4675
+ "diagnosticCapability_images": "生图与编辑",
4676
+ "diagnosticCapability_sketch": "草图",
4677
+ "diagnosticCapability_subagents": "子任务",
4678
+ "diagnosticCapability_compaction": "压缩",
4679
+ "diagnosticCapability_transport": "连接",
4680
+ "diagnosticCapability_storage": "存储",
4681
+ "diagnosticCapability_host-ui": "宿主界面",
4682
+ "diagnosticReason_not-instrumented": "证据不足",
4683
+ "diagnosticReason_disabled-or-host-owned": "未启用或由宿主管理",
4684
+ "diagnosticReason_sign-in-required": "依赖登录",
4685
+ "diagnosticReason_local-sign-in-present": "本地登录存在",
4686
+ "diagnosticReason_sign-in-unverified": "登录未确认",
4687
+ "diagnosticReason_settings-writable": "可写",
4688
+ "diagnosticReason_settings-readonly": "不可写",
4689
+ "diagnosticReason_restart-required": "需要重启",
4690
+ "diagnosticReason_runtime-present": "组件已安装",
4691
+ "diagnosticReason_runtime-missing": "组件未安装",
4630
4692
  storageLoading: "正在读取缓存占用…",
4631
4693
  storageTitle: "存储与缓存",
4632
4694
  storageForecast: "额度预测缓存",
@@ -4954,6 +5016,7 @@ window.__ModuleLoader__.load({
4954
5016
  unlimited: "不限额",
4955
5017
  monthlyCreditLimit: "Credits 月度消费上限",
4956
5018
  resetCredits: "额度重置",
5019
+ resetCreditsAvailable: "额度重置(可用 {count} 次)",
4957
5020
  resetCreditDefaultName: "额度重置",
4958
5021
  resetUse: "使用",
4959
5022
  resetPreparing: "准备中…",
@@ -5099,6 +5162,68 @@ window.__ModuleLoader__.load({
5099
5162
  imageRemoveAnnotation: "删除标注"
5100
5163
  };
5101
5164
  const en = {
5165
+ "diagnosticsSnapshotTime": "Report captured at:",
5166
+ "diagnosticsUnresolved": "Other failures remain without a later success; see the summary.",
5167
+ "diagnosticSeverity_warning": "Attention",
5168
+ "diagnosticSeverity_info": "Information",
5169
+ "diagnosticNext_restart": "Restart and regenerate. If versions still differ, check that the plugin update took effect.",
5170
+ "diagnosticNext_regenerate": "Regenerate immediately after reproducing. If collection remains incomplete, include the steps with your report.",
5171
+ "diagnosticNext_supported-options": "Keep using supported choices. New capabilities need adapter validation; do not insert unknown parameters manually.",
5172
+ "diagnosticNext_reproduce": "Match the operations and timestamps below to your problem. If failures persist, provide reproduction steps and this report.",
5173
+ "diagnosticFinding_evidence-truncated": "Older records or additional host scopes are omitted. This snapshot does not cover the entire history.",
5174
+ "diagnosticsNoRecordedFailure": "No failure in the current records; unused features remain unverified.",
5175
+ "diagnosticFinding_version-mismatch": "Client and server versions differ. Restart DSH and regenerate the report.",
5176
+ "diagnosticFinding_collection-incomplete": "Some checks could not finish. Inspect failed or timed-out collectors in the details.",
5177
+ "diagnosticFinding_catalog-gap": "The online catalog contains capabilities not supported by this adapter. This does not mean the model is unavailable.",
5178
+ "diagnosticFinding_recent-failure": "An operation or request failed within 15 minutes without a later success for the same operation. Inspect its timestamp and details.",
5179
+ "diagnosticReason_no-readiness-check": "No independent prerequisite check",
5180
+ "diagnosticReason_inspection-failed": "Check incomplete",
5181
+ "diagnosticReason_inspection-timeout": "Check timed out",
5182
+ "diagnosticSource_network": "Network request (not full reply)",
5183
+ "diagnosticReason_catalog-online": "Online catalog loaded",
5184
+ "diagnosticReason_catalog-fallback": "Fallback catalog",
5185
+ "diagnosticReason_storage-readable": "Forecast cache readable",
5186
+ "diagnosticReason_tool-registered": "Global tool registered",
5187
+ "diagnosticReason_tool-missing": "Global tool not found",
5188
+ "diagnosticsCoverageHint": "Shows prerequisites and process-wide evidence from the last 15 minutes, not limited to this account or session. RPC, network and tool outcomes are not end-to-end validation.",
5189
+ "diagnosticsVersionMismatch": "Client and server versions differ. Reload and retry.",
5190
+ "diagnosticsPartial": "Some inspections failed or timed out. Other results are preserved; see details.",
5191
+ "diagnosticsCapability": "Capability",
5192
+ "diagnosticsReadiness": "Prerequisites",
5193
+ "diagnosticsEvidence": "Recent evidence",
5194
+ "diagnosticsUnverified": "Unverified",
5195
+ "diagnosticsHostCollected": "Host registrations and selection are included. Registrant labels may be minified; they do not identify packages or prove interference.",
5196
+ "diagnosticsHostUnknown": "Host inspection unavailable or unmounted; interference cannot be determined.",
5197
+ "diagnosticsDetails": "Redacted details",
5198
+ "diagnosticsCopyFailed": "Copy failed. Expand the details to copy manually.",
5199
+ "diagnosticSource_rpc": "RPC response",
5200
+ "diagnosticSource_tool": "Tool",
5201
+ "diagnosticOutcome_completed": "Completed",
5202
+ "diagnosticOutcome_failed": "Failed",
5203
+ "diagnosticOutcome_cancelled": "Cancelled",
5204
+ "diagnosticCapability_account": "Sign-in",
5205
+ "diagnosticCapability_accounts": "Accounts",
5206
+ "diagnosticCapability_settings": "Settings",
5207
+ "diagnosticCapability_models": "Models",
5208
+ "diagnosticCapability_quota": "Quota",
5209
+ "diagnosticCapability_search": "Search",
5210
+ "diagnosticCapability_images": "Images",
5211
+ "diagnosticCapability_sketch": "Sketch",
5212
+ "diagnosticCapability_subagents": "Subtasks",
5213
+ "diagnosticCapability_compaction": "Compaction",
5214
+ "diagnosticCapability_transport": "Connection",
5215
+ "diagnosticCapability_storage": "Storage",
5216
+ "diagnosticCapability_host-ui": "Host UI",
5217
+ "diagnosticReason_not-instrumented": "Insufficient evidence",
5218
+ "diagnosticReason_disabled-or-host-owned": "Disabled or host-managed",
5219
+ "diagnosticReason_sign-in-required": "Sign-in required",
5220
+ "diagnosticReason_local-sign-in-present": "Local sign-in present",
5221
+ "diagnosticReason_sign-in-unverified": "Sign-in unverified",
5222
+ "diagnosticReason_settings-writable": "Writable",
5223
+ "diagnosticReason_settings-readonly": "Read-only",
5224
+ "diagnosticReason_restart-required": "Restart required",
5225
+ "diagnosticReason_runtime-present": "Runtime installed",
5226
+ "diagnosticReason_runtime-missing": "Runtime missing",
5102
5227
  storageLoading: "Reading cache size…",
5103
5228
  storageTitle: "Storage and cache",
5104
5229
  storageForecast: "Quota forecast cache",
@@ -5426,6 +5551,7 @@ window.__ModuleLoader__.load({
5426
5551
  unlimited: "Unlimited",
5427
5552
  monthlyCreditLimit: "Monthly Credits spending cap",
5428
5553
  resetCredits: "Quota resets",
5554
+ resetCreditsAvailable: "Quota resets ({count} available)",
5429
5555
  resetCreditDefaultName: "Quota reset",
5430
5556
  resetUse: "Use",
5431
5557
  resetPreparing: "Preparing…",
@@ -5699,11 +5825,15 @@ window.__ModuleLoader__.load({
5699
5825
  .codexSubscriptionCreditBalance strong{font:600 18px/24px ui-monospace,SFMono-Regular,Consolas,monospace;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
5700
5826
  .codexSubscriptionCreditRows{display:flex;flex-direction:column;gap:6px}
5701
5827
  .codexSubscriptionResetMeta{display:flex;min-width:0;flex-direction:column;gap:1px}
5828
+ .codexSubscriptionResetDisclosure>summary{cursor:pointer;width:fit-content;color:var(--dsw-alias-label-primary);border-radius:6px}
5829
+ .codexSubscriptionResetDisclosure>summary:focus-visible{outline:2px solid currentColor;outline-offset:4px}
5830
+ .codexSubscriptionResetDisclosure[open]>summary{margin-bottom:10px}
5702
5831
  .codexSubscriptionResetBalance{display:flex;flex-direction:column;gap:8px}
5703
5832
  .codexSubscriptionResetCard{display:flex;align-items:center;justify-content:space-between;gap:10px;min-width:0;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-bg-module-platform)}
5704
- .codexSubscriptionResetCard .codexSubscriptionResetMeta{flex:1}
5833
+ .codexSubscriptionResetCard{flex-wrap:wrap}
5834
+ .codexSubscriptionResetCard .codexSubscriptionResetMeta{flex:1 1 180px}
5835
+ .codexSubscriptionResetCard .codexSubscriptionActions{width:auto;flex:0 0 auto}
5705
5836
  .codexSubscriptionResetCard strong{overflow:hidden;font-size:12px;line-height:18px;font-weight:500;text-overflow:ellipsis;white-space:nowrap}
5706
- .codexSubscriptionResetCard .codexSubscriptionActions{flex:0 0 auto}
5707
5837
  .codexSubscriptionResetCard .codexSubscriptionResetUse{min-height:28px;padding:0 10px}
5708
5838
  .codexSubscriptionResetBalance .codexSubscriptionActions{justify-content:flex-start}
5709
5839
  .codexSubscriptionResetFlow{display:flex;flex-direction:column;gap:10px;border-top:1px solid var(--dsw-alias-border-l2);padding-top:10px}
@@ -5752,7 +5882,7 @@ window.__ModuleLoader__.load({
5752
5882
  .codexModelSelectEffort{flex:none;color:var(--dsw-alias-label-caption)}
5753
5883
  .codexModelSelectChevron{flex:none;color:var(--dsw-alias-label-caption);transition:transform 120ms}
5754
5884
  .codexModelSelectTrigger[aria-expanded=true] .codexModelSelectChevron{transform:rotate(180deg)}
5755
- .codexModelSelectMenu,.codexModelSelectSubmenu{position:absolute;z-index:30;box-sizing:border-box;width:max-content;min-width:min(240px,calc(100vw - 32px));max-width:min(420px,calc(100vw - 32px));max-height:min(360px,calc(100vh - 96px));padding:4px;border:1px solid var(--dsw-alias-border-inverted);border-radius:12px;background:var(--dsw-specific-menu);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);overflow:hidden}
5885
+ .codexModelSelectMenu,.codexModelSelectSubmenu{position:absolute;z-index:30;box-sizing:border-box;width:max-content;min-width:min(240px,calc(100vw - 32px));max-width:min(420px,calc(100vw - 32px));max-height:min(360px,calc(100vh - 96px));padding:4px;border:1px solid var(--dsw-alias-border-inverted);border-radius:12px;background:var(--dsw-alias-bg-layer-2,#2c2c2e);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);overflow:hidden}
5756
5886
  .codexModelSelectMenu{right:0;bottom:calc(100% + 8px)}
5757
5887
  .codexModelSelectSubmenu{right:calc(100% + 8px);bottom:0;min-width:min(230px,calc(100vw - 32px))}
5758
5888
  .codexModelSelectCell{display:flex;align-items:center;gap:8px;width:100%;min-width:100%;height:40px;box-sizing:border-box;padding:0 10px;border:0;border-radius:10px;background:transparent;color:inherit;font-size:14px;line-height:22px;text-align:left;cursor:pointer}
@@ -5763,7 +5893,7 @@ window.__ModuleLoader__.load({
5763
5893
  .codexModelSelectCellChevron{flex:none;color:var(--dsw-alias-label-tertiary)}
5764
5894
  .codexModelSelectGroups{min-height:0;max-height:352px;overflow-y:auto}
5765
5895
  .codexModelSelectGroup+.codexModelSelectGroup{margin-top:4px}
5766
- .codexModelSelectGroupTitle{position:sticky;top:0;z-index:1;padding:5px 8px 3px;background:var(--dsw-specific-menu);color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:500;line-height:18px}
5896
+ .codexModelSelectGroupTitle{position:sticky;top:0;z-index:1;padding:5px 8px 3px;background:var(--dsw-alias-bg-layer-2,#2c2c2e);color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:500;line-height:18px}
5767
5897
  .codexModelSelectOption{display:flex;align-items:center;gap:8px;width:100%;min-width:100%;min-height:38px;box-sizing:border-box;padding:6px 8px;border:0;border-radius:10px;outline:0;background:transparent;color:inherit;text-align:left;cursor:pointer}
5768
5898
  .codexModelSelectOption:hover:not(:disabled),.codexModelSelectOption:focus-visible{background:var(--dsw-alias-interactive-bg-hover)}
5769
5899
  .codexModelSelectOption:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}
@@ -7445,7 +7575,7 @@ window.__ModuleLoader__.load({
7445
7575
  }
7446
7576
  //#endregion
7447
7577
  //#region src/version.js
7448
- const PACKAGE_VERSION = "2.2.2";
7578
+ const PACKAGE_VERSION = "2.2.4";
7449
7579
  //#endregion
7450
7580
  //#region src/client-recovery.js
7451
7581
  async function recoveryCall(rpc, endpoint, payload = {}, timeoutMs = 1e4) {
@@ -9424,25 +9554,118 @@ window.__ModuleLoader__.load({
9424
9554
  ]
9425
9555
  });
9426
9556
  }
9557
+ const areas = {
9558
+ catalog: "models",
9559
+ quota: "quota",
9560
+ search: "search",
9561
+ image: "images",
9562
+ model: "transport",
9563
+ login: "account",
9564
+ "quota-reset": "quota"
9565
+ };
9566
+ function diagnosticEvidence({ operations, history }, now) {
9567
+ return [...(operations?.events ?? []).map((e) => ({
9568
+ capability: e.capability,
9569
+ action: e.action,
9570
+ source: e.source,
9571
+ status: e.status,
9572
+ observedAt: e.observedAt
9573
+ })), ...(history?.events ?? []).map((e) => ({
9574
+ capability: areas[e.area],
9575
+ action: e.area,
9576
+ source: "network",
9577
+ status: e.status === "ok" ? "completed" : "failed",
9578
+ observedAt: e.observedAt
9579
+ }))].filter((e) => Number.isSafeInteger(e.observedAt) && now >= e.observedAt && now - e.observedAt <= 9e5).sort((a, b) => a.observedAt - b.observedAt);
9580
+ }
9581
+ function unresolvedFailures(events) {
9582
+ const failed = /* @__PURE__ */ new Map();
9583
+ for (const event of events) {
9584
+ const key = `${event.source}:${event.action}`;
9585
+ if (event.status === "failed") failed.set(key, event);
9586
+ else if (event.status === "completed") failed.delete(key);
9587
+ }
9588
+ return [...failed.values()];
9589
+ }
9590
+ //#endregion
9591
+ //#region src/diagnostic-summary.js
9592
+ function diagnosticSummary(report, now = Date.now()) {
9593
+ const findings = [];
9594
+ const checks = [...report.inspection?.checks ?? [], ...report.client?.checks ?? []];
9595
+ if (report.version && report.client?.version && report.version !== report.client.version) findings.push({
9596
+ code: "version-mismatch",
9597
+ severity: "warning",
9598
+ next: "restart",
9599
+ evidence: ["version", "client.version"]
9600
+ });
9601
+ if (!report.inspection || report.client?.status === "unknown" || checks.some((check) => ["inspection-failed", "inspection-timeout"].includes(check.reason))) findings.push({
9602
+ code: "collection-incomplete",
9603
+ severity: "warning",
9604
+ next: "regenerate",
9605
+ evidence: checks.filter((c) => c.status === "unknown").map((c) => c.id)
9606
+ });
9607
+ if (report.catalog?.unsupported?.length) findings.push({
9608
+ code: "catalog-gap",
9609
+ severity: "info",
9610
+ next: "supported-options",
9611
+ evidence: ["catalog.unsupported"]
9612
+ });
9613
+ const capturedAt = Date.parse(report.generatedAt);
9614
+ const failures = unresolvedFailures(diagnosticEvidence({
9615
+ operations: report.operations,
9616
+ history: report.requestHistory
9617
+ }, Number.isFinite(capturedAt) ? capturedAt : now));
9618
+ if (failures.length) findings.push({
9619
+ code: "recent-failure",
9620
+ severity: "warning",
9621
+ next: "reproduce",
9622
+ evidence: failures
9623
+ });
9624
+ if ((report.requestHistory?.dropped ?? 0) + (report.operations?.dropped ?? 0) > 0 || report.client?.truncated) findings.push({
9625
+ code: "evidence-truncated",
9626
+ severity: "info",
9627
+ next: "regenerate",
9628
+ evidence: [
9629
+ "requestHistory.dropped",
9630
+ "operations.dropped",
9631
+ "client.truncated"
9632
+ ]
9633
+ });
9634
+ return {
9635
+ scope: "recorded-evidence-only",
9636
+ findings,
9637
+ unverified: (report.inspection?.capabilities ?? []).filter((c) => c.execution === "not-verified" && c.readiness !== "not-applicable").length
9638
+ };
9639
+ }
9427
9640
  //#endregion
9428
9641
  //#region src/client-diagnostics.jsx
9429
- function DiagnosticsCard({ rpc, t }) {
9642
+ function DiagnosticsCard({ rpc, t, diagnostics }) {
9430
9643
  const [report, setReport] = (0, react.useState)();
9431
9644
  const [busy, setBusy] = (0, react.useState)(false);
9432
9645
  const [copied, setCopied] = (0, react.useState)(false);
9433
9646
  const [error, setError] = (0, react.useState)(false);
9647
+ const [copyError, setCopyError] = (0, react.useState)(false);
9434
9648
  const load = () => {
9435
9649
  setBusy(true);
9436
9650
  setError(false);
9437
9651
  setCopied(false);
9438
- recoveryCall(rpc, "diagnostics").then(setReport).catch((error) => {
9439
- setReport(clientDiagnostic(error));
9440
- setError(true);
9652
+ setCopyError(false);
9653
+ Promise.allSettled([recoveryCall(rpc, "diagnostics"), Promise.resolve().then(() => diagnostics?.collect())]).then(([server, client]) => {
9654
+ setError(server.status === "rejected");
9655
+ const combined = {
9656
+ ...server.status === "fulfilled" ? server.value : clientDiagnostic(server.reason),
9657
+ client: client.status === "fulfilled" && client.value ? client.value : { status: "unknown" }
9658
+ };
9659
+ setReport({
9660
+ ...combined,
9661
+ summary: diagnosticSummary(combined)
9662
+ });
9441
9663
  }).finally(() => setBusy(false));
9442
9664
  };
9443
9665
  const copy = () => {
9444
9666
  if (report === void 0) return;
9445
- navigator.clipboard.writeText(JSON.stringify(report, null, 2)).then(() => setCopied(true)).catch(() => setError(true));
9667
+ setCopyError(false);
9668
+ Promise.resolve().then(() => navigator.clipboard.writeText(JSON.stringify(report, null, 2))).then(() => setCopied(true)).catch(() => setCopyError(true));
9446
9669
  };
9447
9670
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9448
9671
  className: "codexSubscriptionCard codexSubscriptionDiagnostics",
@@ -9481,11 +9704,70 @@ window.__ModuleLoader__.load({
9481
9704
  ]
9482
9705
  })]
9483
9706
  }),
9484
- report === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: JSON.stringify(report, null, 2) }),
9707
+ report === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
9708
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9709
+ className: "codexSubscriptionHelp",
9710
+ children: t("diagnosticsCoverageHint")
9711
+ }),
9712
+ report.generatedAt ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
9713
+ className: "codexSubscriptionHelp",
9714
+ children: [
9715
+ t("diagnosticsSnapshotTime"),
9716
+ " ",
9717
+ new Date(report.generatedAt).toLocaleString()
9718
+ ]
9719
+ }) : null,
9720
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9721
+ role: "status",
9722
+ children: report.summary?.findings.length ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", { children: report.summary.findings.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
9723
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t(`diagnosticSeverity_${item.severity}`) }),
9724
+ " · ",
9725
+ t(`diagnosticFinding_${item.code}`),
9726
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9727
+ className: "codexSubscriptionHelp",
9728
+ children: t(`diagnosticNext_${item.next}`)
9729
+ }),
9730
+ item.code === "recent-failure" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", { children: item.evidence.map((event) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
9731
+ event.action,
9732
+ " · ",
9733
+ t(`diagnosticSource_${event.source}`),
9734
+ " · ",
9735
+ new Date(event.observedAt).toLocaleTimeString()
9736
+ ] }, `${event.source}:${event.action}`)) }) : null
9737
+ ] }, item.code)) }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("diagnosticsNoRecordedFailure") })
9738
+ }),
9739
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
9740
+ style: {
9741
+ width: "100%",
9742
+ fontSize: 12,
9743
+ textAlign: "left",
9744
+ borderSpacing: "0 8px"
9745
+ },
9746
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
9747
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t("diagnosticsCapability") }),
9748
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t("diagnosticsReadiness") }),
9749
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t("diagnosticsEvidence") })
9750
+ ] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: (report.inspection?.capabilities ?? []).map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
9751
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: t(`diagnosticCapability_${item.id}`) }),
9752
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("td", { children: [t(`diagnosticReason_${item.reason}`), item.blockedBy ? ` · ${t(`diagnosticCapability_${item.blockedBy}`)}` : ""] }),
9753
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("td", { children: [item.latest ? `${item.latest.action} · ${t(`diagnosticSource_${item.latest.source}`)} · ${t(`diagnosticOutcome_${item.latest.status}`)} · ${new Date(item.latest.observedAt).toLocaleTimeString()}` : t("diagnosticsUnverified"), item.unresolved?.length ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("diagnosticsUnresolved") }) : null] })
9754
+ ] }, item.id)) })]
9755
+ }),
9756
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9757
+ className: "codexSubscriptionHelp",
9758
+ children: report.client?.topology?.length ? t("diagnosticsHostCollected") : t("diagnosticsHostUnknown")
9759
+ }),
9760
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t("diagnosticsDetails") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: JSON.stringify(report, null, 2) })] })
9761
+ ] }),
9485
9762
  error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9486
9763
  className: "codexSubscriptionError",
9487
9764
  role: "alert",
9488
9765
  children: t("diagnosticsFailed")
9766
+ }) : null,
9767
+ copyError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9768
+ className: "codexSubscriptionError",
9769
+ role: "alert",
9770
+ children: t("diagnosticsCopyFailed")
9489
9771
  }) : null
9490
9772
  ]
9491
9773
  });
@@ -9948,9 +10230,9 @@ window.__ModuleLoader__.load({
9948
10230
  className: "codexSubscriptionCreditBalance",
9949
10231
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("creditsBalance") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: visibleUsage.credits.unlimited ? t("unlimited") : `${visibleUsage.credits.balance ?? t("unavailable")} ${t("creditsUnit")}` })]
9950
10232
  }) : null,
9951
- visibleUsage?.resetCredits?.availableCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9952
- className: "codexSubscriptionCreditBalance",
9953
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetCredits") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditList, {
10233
+ visibleUsage?.resetCredits?.availableCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
10234
+ className: "codexSubscriptionCreditBalance codexSubscriptionResetDisclosure",
10235
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: fill(t("resetCreditsAvailable"), { count: visibleUsage.resetCredits.availableCount }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditList, {
9954
10236
  rpc,
9955
10237
  t,
9956
10238
  count: visibleUsage.resetCredits.availableCount,
@@ -9996,7 +10278,7 @@ window.__ModuleLoader__.load({
9996
10278
  }
9997
10279
  //#endregion
9998
10280
  //#region src/client-section.jsx
9999
- function CodexSection({ preference, rpc, accountStatus, t }) {
10281
+ function CodexSection({ preference, rpc, accountStatus, t, diagnostics }) {
10000
10282
  const [tab, setTab] = (0, react.useState)("account");
10001
10283
  const id = (0, react.useId)();
10002
10284
  const tabs = [
@@ -10115,13 +10397,168 @@ window.__ModuleLoader__.load({
10115
10397
  t
10116
10398
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DiagnosticsCard, {
10117
10399
  rpc,
10118
- t
10400
+ t,
10401
+ diagnostics
10119
10402
  })]
10120
10403
  })
10121
10404
  ]
10122
10405
  });
10123
10406
  }
10124
10407
  //#endregion
10408
+ //#region src/diagnostic-checks.js
10409
+ const states = /* @__PURE__ */ new Set([
10410
+ "pass",
10411
+ "fail",
10412
+ "warn",
10413
+ "unknown",
10414
+ "not-applicable"
10415
+ ]);
10416
+ /** Adapters return bounded reason codes, never exceptions or raw service data. */
10417
+ async function collectChecks(definitions, { timeoutMs = 1500, now = Date.now, source = "server", scope = "plugin-process" } = {}) {
10418
+ return Promise.all(definitions.map(async ({ id, capability, run }) => {
10419
+ const startedAt = now();
10420
+ let timer;
10421
+ const controller = new AbortController();
10422
+ const base = {
10423
+ id,
10424
+ capability,
10425
+ source,
10426
+ scope
10427
+ };
10428
+ try {
10429
+ if (!run) return {
10430
+ ...base,
10431
+ status: "unknown",
10432
+ reason: "not-instrumented",
10433
+ observedAt: now()
10434
+ };
10435
+ const result = await Promise.race([Promise.resolve().then(() => run(controller.signal)), new Promise((resolve) => {
10436
+ timer = setTimeout(() => {
10437
+ controller.abort();
10438
+ resolve({
10439
+ status: "unknown",
10440
+ reason: "inspection-timeout"
10441
+ });
10442
+ }, timeoutMs);
10443
+ })]);
10444
+ const valid = states.has(result?.status) && /^[a-z][a-z0-9-]{0,63}$/u.test(result?.reason ?? "");
10445
+ return {
10446
+ ...base,
10447
+ status: valid ? result.status : "unknown",
10448
+ reason: valid ? result.reason : "invalid-inspection-result",
10449
+ observedAt: now(),
10450
+ elapsedMs: Math.max(0, now() - startedAt)
10451
+ };
10452
+ } catch {
10453
+ return {
10454
+ ...base,
10455
+ status: "unknown",
10456
+ reason: "inspection-failed",
10457
+ observedAt: now(),
10458
+ elapsedMs: Math.max(0, now() - startedAt)
10459
+ };
10460
+ } finally {
10461
+ clearTimeout(timer);
10462
+ }
10463
+ }));
10464
+ }
10465
+ Object.freeze([
10466
+ "account",
10467
+ "accounts",
10468
+ "settings",
10469
+ "models",
10470
+ "quota",
10471
+ "search",
10472
+ "images",
10473
+ "sketch",
10474
+ "subagents",
10475
+ "compaction",
10476
+ "transport",
10477
+ "storage",
10478
+ "host-ui"
10479
+ ]);
10480
+ //#endregion
10481
+ //#region src/diagnostic-host.js
10482
+ const roots = [
10483
+ "settings.section",
10484
+ "conversation.input.right",
10485
+ "conversation.input.model",
10486
+ "conversation.input.attachments",
10487
+ "conversation.message.images",
10488
+ "conversation.trajectory.images",
10489
+ "shell.overlay"
10490
+ ];
10491
+ const packageName = /^(?:@[a-z0-9_.-]+\/)?[a-z0-9][a-z0-9_.-]{0,99}$/u;
10492
+ function projectHostSlots(slots) {
10493
+ if (typeof slots?.snapshot !== "function") return void 0;
10494
+ return roots.map((name) => {
10495
+ const nodes = slots.snapshot(name);
10496
+ const node = Array.isArray(nodes) ? nodes.find((item) => item.type === "slot" && item.name === name) : void 0;
10497
+ const occupants = Array.isArray(node?.occupants) ? node.occupants : [];
10498
+ return {
10499
+ name,
10500
+ declared: !!node,
10501
+ truncated: occupants.length > 16,
10502
+ occupants: occupants.slice(0, 16).map((value) => ({
10503
+ registrant: typeof value.registrant === "string" && packageName.test(value.registrant) ? value.registrant : "unknown",
10504
+ identity: "unverified-host-label",
10505
+ active: value.active === true
10506
+ }))
10507
+ };
10508
+ });
10509
+ }
10510
+ function createHostDiagnostics() {
10511
+ const scopes = /* @__PURE__ */ new Map();
10512
+ let sequence = 0;
10513
+ return {
10514
+ register(slots) {
10515
+ const item = scopes.get(slots) ?? {
10516
+ alias: `scope-${++sequence}`,
10517
+ count: 0
10518
+ };
10519
+ item.count++;
10520
+ scopes.set(slots, item);
10521
+ return () => {
10522
+ if (--item.count === 0) scopes.delete(slots);
10523
+ };
10524
+ },
10525
+ async collect() {
10526
+ const topology = [];
10527
+ const active = [...scopes.entries()].slice(0, 8);
10528
+ const checks = await collectChecks(active.map(([slots, item]) => ({
10529
+ id: `host-slots-${item.alias}`,
10530
+ capability: "host-ui",
10531
+ run: () => {
10532
+ const value = projectHostSlots(slots);
10533
+ if (!value) return {
10534
+ status: "unknown",
10535
+ reason: "host-inspection-unavailable"
10536
+ };
10537
+ topology.push({
10538
+ scope: item.alias,
10539
+ slots: value
10540
+ });
10541
+ return {
10542
+ status: "pass",
10543
+ reason: "inspection-completed"
10544
+ };
10545
+ }
10546
+ })), {
10547
+ source: "client",
10548
+ scope: "mounted-host-scopes"
10549
+ });
10550
+ return {
10551
+ version: PACKAGE_VERSION,
10552
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
10553
+ checks,
10554
+ topology,
10555
+ truncated: scopes.size > active.length,
10556
+ interpretation: "host-selection-not-visual-or-execution-proof"
10557
+ };
10558
+ }
10559
+ };
10560
+ }
10561
+ //#endregion
10125
10562
  //#region src/client.jsx
10126
10563
  const inject = [
10127
10564
  "slots",
@@ -10134,6 +10571,8 @@ window.__ModuleLoader__.load({
10134
10571
  "sessions"
10135
10572
  ];
10136
10573
  function apply(ctx) {
10574
+ const diagnostics = createHostDiagnostics();
10575
+ ctx.effect(() => diagnostics.register(ctx.slots), "codex-subscription: host inspection");
10137
10576
  const imageViewer = new SubscriptionImageViewerService();
10138
10577
  ctx.effect(() => ctx.locale.register(NS, {
10139
10578
  zh,
@@ -10194,11 +10633,13 @@ window.__ModuleLoader__.load({
10194
10633
  preference,
10195
10634
  rpc,
10196
10635
  accountStatus,
10197
- t
10636
+ t,
10637
+ diagnostics
10198
10638
  })
10199
10639
  }, CodexSection));
10200
10640
  const sessions = ctx.get("sessions");
10201
10641
  const installDirectorySlots = (scope) => {
10642
+ scope.effect(() => diagnostics.register(scope.slots), "codex-subscription: scoped host inspection");
10202
10643
  const modelDirectories = scope.get("modelDirectories");
10203
10644
  scope.slots.inject("conversation.input.right", () => scope.slots.register({
10204
10645
  name: "conversation.input.right",