dsh-cloudq 0.1.9 → 0.2.0
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 +206 -154
- package/package.json +1 -1
- package/skills/cloudq/scripts/create_role.py +29 -4
package/lib/client.js
CHANGED
|
@@ -1014,7 +1014,9 @@ body.dsh-cloudq-mode-active [class*=composerHero] [class*=root][class*=hero] {
|
|
|
1014
1014
|
}
|
|
1015
1015
|
.dsh-cloudq-convo-chip {
|
|
1016
1016
|
position: fixed;
|
|
1017
|
-
|
|
1017
|
+
/* Below the conversation header divider (header bottom ≈76px) so the chip
|
|
1018
|
+
never overlaps the Session log affordance in the title row. */
|
|
1019
|
+
top: 88px;
|
|
1018
1020
|
right: 16px;
|
|
1019
1021
|
display: inline-flex;
|
|
1020
1022
|
align-items: center;
|
|
@@ -1605,12 +1607,24 @@ body.dsh-cloudq-mode-active [class*=composerHero] [class*=root][class*=hero] {
|
|
|
1605
1607
|
}
|
|
1606
1608
|
.dsh-cloudq-artifact__download {
|
|
1607
1609
|
justify-self: end;
|
|
1610
|
+
padding: 0;
|
|
1611
|
+
border: 0;
|
|
1612
|
+
background: none;
|
|
1608
1613
|
color: var(--dsw-alias-state-business-primary, #006eff);
|
|
1614
|
+
font: inherit;
|
|
1609
1615
|
text-decoration: none;
|
|
1616
|
+
cursor: pointer;
|
|
1610
1617
|
}
|
|
1611
1618
|
.dsh-cloudq-artifact__download:hover {
|
|
1612
1619
|
text-decoration: underline;
|
|
1613
1620
|
}
|
|
1621
|
+
.dsh-cloudq-artifact__download:disabled {
|
|
1622
|
+
cursor: default;
|
|
1623
|
+
opacity: .6;
|
|
1624
|
+
}
|
|
1625
|
+
span.dsh-cloudq-artifact__download {
|
|
1626
|
+
cursor: default;
|
|
1627
|
+
}
|
|
1614
1628
|
/* architecture library */
|
|
1615
1629
|
.dsh-cloudq-arch__toolbar {
|
|
1616
1630
|
position: relative;
|
|
@@ -2036,12 +2050,10 @@ display: none;
|
|
|
2036
2050
|
let panelBody = null;
|
|
2037
2051
|
let panelView = "usage";
|
|
2038
2052
|
let panelExpanded = false;
|
|
2039
|
-
let inspirationCache = null;
|
|
2040
2053
|
let inspirationCategory = 0;
|
|
2041
|
-
|
|
2042
|
-
let
|
|
2043
|
-
let
|
|
2044
|
-
let architectureFirstFolderId = null;
|
|
2054
|
+
const artifactCollapsedSessions = /* @__PURE__ */ new Set();
|
|
2055
|
+
let artifactRefreshTimer = 0;
|
|
2056
|
+
let artifactRetryTimer = 0;
|
|
2045
2057
|
let architectureRequestSeq = 0;
|
|
2046
2058
|
let architecturePickerCleanup = null;
|
|
2047
2059
|
function renderUsageView() {
|
|
@@ -2345,17 +2357,12 @@ display: none;
|
|
|
2345
2357
|
list.appendChild(card);
|
|
2346
2358
|
}
|
|
2347
2359
|
};
|
|
2348
|
-
if (inspirationCache) {
|
|
2349
|
-
paint(inspirationCache);
|
|
2350
|
-
return;
|
|
2351
|
-
}
|
|
2352
2360
|
const hint = document.createElement("div");
|
|
2353
2361
|
hint.className = "dsh-cloudq-panel__hint";
|
|
2354
2362
|
hint.textContent = "正在加载灵感…";
|
|
2355
2363
|
list.appendChild(hint);
|
|
2356
2364
|
requireCloudqCredential().then(() => cloudqRequest(API_INSPIRATIONS)).then((data) => {
|
|
2357
|
-
|
|
2358
|
-
paint(inspirationCache);
|
|
2365
|
+
paint(Array.isArray(data.inspirations) ? data.inspirations : []);
|
|
2359
2366
|
}).catch((error) => {
|
|
2360
2367
|
if (!panelExpanded) return;
|
|
2361
2368
|
list.textContent = "";
|
|
@@ -2365,140 +2372,181 @@ display: none;
|
|
|
2365
2372
|
list.appendChild(err);
|
|
2366
2373
|
});
|
|
2367
2374
|
}
|
|
2368
|
-
|
|
2375
|
+
/**
|
|
2376
|
+
* Refresh the artifact list in the background after a CloudQ conversation
|
|
2377
|
+
* turn completes. Never shows the loading hint: the visible list stays
|
|
2378
|
+
* untouched and is repainted synchronously once fresh data arrives. The
|
|
2379
|
+
* delayed retry covers artifacts archived with a lag.
|
|
2380
|
+
*/
|
|
2381
|
+
function scheduleArtifactSilentRefresh() {
|
|
2382
|
+
window.clearTimeout(artifactRefreshTimer);
|
|
2383
|
+
window.clearTimeout(artifactRetryTimer);
|
|
2384
|
+
const run = () => {
|
|
2385
|
+
cloudqRequest(API_ARTIFACTS).then((data) => {
|
|
2386
|
+
if (panelView !== "artifact" || !panelExpanded) return;
|
|
2387
|
+
paintArtifactList(Array.isArray(data?.sessions) ? data.sessions : [], Number(data?.total) || 0);
|
|
2388
|
+
}).catch(() => {});
|
|
2389
|
+
};
|
|
2390
|
+
artifactRefreshTimer = window.setTimeout(run, 3e3);
|
|
2391
|
+
artifactRetryTimer = window.setTimeout(run, 15e3);
|
|
2392
|
+
}
|
|
2393
|
+
function paintArtifactList(sessions, total) {
|
|
2394
|
+
if (panelView !== "artifact" || !panelExpanded) return;
|
|
2369
2395
|
panelBody.textContent = "";
|
|
2370
|
-
const
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
action.
|
|
2467
|
-
action.
|
|
2468
|
-
|
|
2469
|
-
action.
|
|
2470
|
-
action.
|
|
2471
|
-
action.
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2396
|
+
const safeSessions = Array.isArray(sessions) ? sessions : [];
|
|
2397
|
+
const artifactCount = safeSessions.reduce((sum, session) => {
|
|
2398
|
+
return sum + (Array.isArray(session?.Artifacts) ? session.Artifacts : []).length;
|
|
2399
|
+
}, 0);
|
|
2400
|
+
const toolbar = document.createElement("div");
|
|
2401
|
+
toolbar.className = "dsh-cloudq-artifact__toolbar";
|
|
2402
|
+
const summary = document.createElement("span");
|
|
2403
|
+
summary.textContent = `共 ${Number(total) || safeSessions.length} 组会话,${artifactCount} 个制品`;
|
|
2404
|
+
const refresh = document.createElement("button");
|
|
2405
|
+
refresh.type = "button";
|
|
2406
|
+
refresh.className = "dsh-cloudq-artifact__refresh";
|
|
2407
|
+
refresh.dataset.testid = "cloudq-artifact-refresh-btn";
|
|
2408
|
+
refresh.textContent = "刷新";
|
|
2409
|
+
refresh.addEventListener("click", () => renderArtifactView());
|
|
2410
|
+
toolbar.appendChild(summary);
|
|
2411
|
+
toolbar.appendChild(refresh);
|
|
2412
|
+
panelBody.appendChild(toolbar);
|
|
2413
|
+
if (safeSessions.length === 0) {
|
|
2414
|
+
const empty = document.createElement("div");
|
|
2415
|
+
empty.className = "dsh-cloudq-usage__table__empty";
|
|
2416
|
+
empty.textContent = "暂无制品";
|
|
2417
|
+
panelBody.appendChild(empty);
|
|
2418
|
+
return;
|
|
2419
|
+
}
|
|
2420
|
+
const list = document.createElement("div");
|
|
2421
|
+
list.className = "dsh-cloudq-artifact__list";
|
|
2422
|
+
const columns = document.createElement("div");
|
|
2423
|
+
columns.className = "dsh-cloudq-artifact__columns";
|
|
2424
|
+
for (const label of [
|
|
2425
|
+
"报告名称",
|
|
2426
|
+
"用户名称",
|
|
2427
|
+
"生成时间",
|
|
2428
|
+
"操作"
|
|
2429
|
+
]) {
|
|
2430
|
+
const cell = document.createElement("span");
|
|
2431
|
+
cell.textContent = label;
|
|
2432
|
+
columns.appendChild(cell);
|
|
2433
|
+
}
|
|
2434
|
+
list.appendChild(columns);
|
|
2435
|
+
for (const session of safeSessions) {
|
|
2436
|
+
const artifacts = Array.isArray(session?.Artifacts) ? session.Artifacts : [];
|
|
2437
|
+
const sessionKey = String(session?.SessionID ?? "");
|
|
2438
|
+
const group = document.createElement("section");
|
|
2439
|
+
group.className = "dsh-cloudq-artifact__session";
|
|
2440
|
+
const startCollapsed = sessionKey !== "" && artifactCollapsedSessions.has(sessionKey);
|
|
2441
|
+
if (startCollapsed) group.classList.add("is-collapsed");
|
|
2442
|
+
const sessionHead = document.createElement("button");
|
|
2443
|
+
sessionHead.type = "button";
|
|
2444
|
+
sessionHead.className = "dsh-cloudq-artifact__session-head";
|
|
2445
|
+
sessionHead.dataset.testid = `cloudq-artifact-session-${session?.SessionID ?? "unknown"}`;
|
|
2446
|
+
sessionHead.setAttribute("aria-expanded", String(!startCollapsed));
|
|
2447
|
+
const chevron = document.createElement("span");
|
|
2448
|
+
chevron.className = "dsh-cloudq-artifact__chevron";
|
|
2449
|
+
chevron.textContent = "▼";
|
|
2450
|
+
const title = document.createElement("span");
|
|
2451
|
+
title.className = "dsh-cloudq-artifact__session-title";
|
|
2452
|
+
title.textContent = session?.SessionTitle || "未命名会话";
|
|
2453
|
+
title.title = title.textContent;
|
|
2454
|
+
const latestTime = artifacts.reduce((latest, artifact) => {
|
|
2455
|
+
const time = String(artifact?.ArchiveTime ?? "");
|
|
2456
|
+
return time > latest ? time : latest;
|
|
2457
|
+
}, "");
|
|
2458
|
+
const meta = document.createElement("span");
|
|
2459
|
+
meta.className = "dsh-cloudq-artifact__session-meta";
|
|
2460
|
+
meta.textContent = `${artifacts.length} 个制品${latestTime ? ` · 最近 ${latestTime.slice(0, 10)}` : ""}`;
|
|
2461
|
+
sessionHead.appendChild(chevron);
|
|
2462
|
+
sessionHead.appendChild(title);
|
|
2463
|
+
sessionHead.appendChild(meta);
|
|
2464
|
+
const files = document.createElement("div");
|
|
2465
|
+
files.className = "dsh-cloudq-artifact__files";
|
|
2466
|
+
for (const artifact of artifacts) {
|
|
2467
|
+
const row = document.createElement("div");
|
|
2468
|
+
row.className = "dsh-cloudq-artifact__file";
|
|
2469
|
+
const main = document.createElement("div");
|
|
2470
|
+
main.className = "dsh-cloudq-artifact__file-main";
|
|
2471
|
+
const type = document.createElement("span");
|
|
2472
|
+
type.className = "dsh-cloudq-artifact__file-type";
|
|
2473
|
+
type.textContent = artifact?.FileType || "file";
|
|
2474
|
+
const name = document.createElement("span");
|
|
2475
|
+
name.className = "dsh-cloudq-artifact__file-name";
|
|
2476
|
+
name.textContent = artifact?.FileName || "未命名文件";
|
|
2477
|
+
name.title = `${name.textContent} · ${formatFileSize(artifact?.SizeBytes)}`;
|
|
2478
|
+
main.appendChild(type);
|
|
2479
|
+
main.appendChild(name);
|
|
2480
|
+
const owner = document.createElement("span");
|
|
2481
|
+
owner.className = "dsh-cloudq-artifact__owner";
|
|
2482
|
+
owner.textContent = artifact?.UserName || "—";
|
|
2483
|
+
const time = document.createElement("span");
|
|
2484
|
+
time.className = "dsh-cloudq-artifact__time";
|
|
2485
|
+
time.textContent = formatDateTime(artifact?.ArchiveTime);
|
|
2486
|
+
const downloadUrl = safeDownloadUrl(artifact?.DownloadURL);
|
|
2487
|
+
const fileName = artifact?.FileName || "未命名文件";
|
|
2488
|
+
const action = document.createElement(downloadUrl ? "button" : "span");
|
|
2489
|
+
action.className = "dsh-cloudq-artifact__download";
|
|
2490
|
+
action.textContent = downloadUrl ? "下载" : "不可用";
|
|
2491
|
+
if (downloadUrl) {
|
|
2492
|
+
action.type = "button";
|
|
2493
|
+
action.dataset.testid = `cloudq-artifact-download-${artifact?.ArtifactID ?? "unknown"}`;
|
|
2494
|
+
action.addEventListener("click", () => {
|
|
2495
|
+
if (action.disabled) return;
|
|
2496
|
+
action.disabled = true;
|
|
2497
|
+
action.textContent = "下载中…";
|
|
2498
|
+
const restore = () => {
|
|
2499
|
+
action.disabled = false;
|
|
2500
|
+
action.textContent = "下载";
|
|
2501
|
+
};
|
|
2502
|
+
fetch(downloadUrl).then((res) => {
|
|
2503
|
+
if (!res.ok) throw new Error(`download failed: ${res.status}`);
|
|
2504
|
+
return res.blob();
|
|
2505
|
+
}).then((blob) => {
|
|
2506
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
2507
|
+
const link = document.createElement("a");
|
|
2508
|
+
link.href = objectUrl;
|
|
2509
|
+
link.download = fileName;
|
|
2510
|
+
link.rel = "noopener noreferrer";
|
|
2511
|
+
link.click();
|
|
2512
|
+
window.setTimeout(() => URL.revokeObjectURL(objectUrl), 1e4);
|
|
2513
|
+
}).catch(() => {
|
|
2514
|
+
const link = document.createElement("a");
|
|
2515
|
+
link.href = downloadUrl;
|
|
2516
|
+
link.download = fileName;
|
|
2517
|
+
link.rel = "noopener noreferrer";
|
|
2518
|
+
link.click();
|
|
2519
|
+
}).finally(restore);
|
|
2520
|
+
});
|
|
2479
2521
|
}
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
group.appendChild(files);
|
|
2486
|
-
list.appendChild(group);
|
|
2522
|
+
row.appendChild(main);
|
|
2523
|
+
row.appendChild(owner);
|
|
2524
|
+
row.appendChild(time);
|
|
2525
|
+
row.appendChild(action);
|
|
2526
|
+
files.appendChild(row);
|
|
2487
2527
|
}
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2528
|
+
sessionHead.addEventListener("click", () => {
|
|
2529
|
+
const collapsed = group.classList.toggle("is-collapsed");
|
|
2530
|
+
sessionHead.setAttribute("aria-expanded", String(!collapsed));
|
|
2531
|
+
if (sessionKey) {
|
|
2532
|
+
if (collapsed) artifactCollapsedSessions.add(sessionKey);
|
|
2533
|
+
else artifactCollapsedSessions.delete(sessionKey);
|
|
2534
|
+
}
|
|
2535
|
+
});
|
|
2536
|
+
group.appendChild(sessionHead);
|
|
2537
|
+
group.appendChild(files);
|
|
2538
|
+
list.appendChild(group);
|
|
2493
2539
|
}
|
|
2540
|
+
panelBody.appendChild(list);
|
|
2541
|
+
}
|
|
2542
|
+
function renderArtifactView() {
|
|
2543
|
+
panelBody.textContent = "";
|
|
2494
2544
|
const hint = document.createElement("div");
|
|
2495
2545
|
hint.className = "dsh-cloudq-panel__hint";
|
|
2496
2546
|
hint.textContent = "正在加载制品…";
|
|
2497
2547
|
panelBody.appendChild(hint);
|
|
2498
2548
|
requireCloudqCredential().then(() => cloudqRequest(API_ARTIFACTS)).then((data) => {
|
|
2499
|
-
|
|
2500
|
-
artifactTotal = Number(data?.total) || artifactCache.length;
|
|
2501
|
-
paint(artifactCache, artifactTotal);
|
|
2549
|
+
paintArtifactList(Array.isArray(data?.sessions) ? data.sessions : [], Number(data?.total) || 0);
|
|
2502
2550
|
}).catch((error) => {
|
|
2503
2551
|
if (panelView !== "artifact" || !panelExpanded) return;
|
|
2504
2552
|
panelBody.textContent = "";
|
|
@@ -2733,14 +2781,16 @@ display: none;
|
|
|
2733
2781
|
}
|
|
2734
2782
|
for (const architecture of architectures) {
|
|
2735
2783
|
const imageUrl = safeDownloadUrl(architecture?.SvgURL);
|
|
2736
|
-
const
|
|
2784
|
+
const archId = typeof architecture?.ArchId === "string" ? architecture.ArchId.trim() : "";
|
|
2785
|
+
const consoleUrl = archId ? `https://console.cloud.tencent.com/advisor?archId=${encodeURIComponent(archId)}` : "";
|
|
2786
|
+
const card = document.createElement(consoleUrl ? "a" : "article");
|
|
2737
2787
|
card.className = "dsh-cloudq-arch__card";
|
|
2738
2788
|
card.dataset.testid = `cloudq-architecture-card-${architecture?.ArchId ?? "unknown"}`;
|
|
2739
|
-
if (
|
|
2740
|
-
card.href =
|
|
2789
|
+
if (consoleUrl) {
|
|
2790
|
+
card.href = consoleUrl;
|
|
2741
2791
|
card.target = "_blank";
|
|
2742
2792
|
card.rel = "noopener noreferrer";
|
|
2743
|
-
card.setAttribute("aria-label",
|
|
2793
|
+
card.setAttribute("aria-label", `打开架构图:${architecture?.ArchName || "未命名系统"}`);
|
|
2744
2794
|
}
|
|
2745
2795
|
const preview = document.createElement("div");
|
|
2746
2796
|
preview.className = "dsh-cloudq-arch__preview";
|
|
@@ -2759,7 +2809,7 @@ display: none;
|
|
|
2759
2809
|
image.addEventListener("load", () => placeholder.remove());
|
|
2760
2810
|
image.addEventListener("error", () => {
|
|
2761
2811
|
image.remove();
|
|
2762
|
-
placeholder.textContent = "
|
|
2812
|
+
placeholder.textContent = consoleUrl ? "预览加载失败,点击打开架构图" : "预览加载失败";
|
|
2763
2813
|
});
|
|
2764
2814
|
preview.appendChild(image);
|
|
2765
2815
|
}
|
|
@@ -2791,14 +2841,8 @@ display: none;
|
|
|
2791
2841
|
};
|
|
2792
2842
|
loadArchitectures(selectedFolderId);
|
|
2793
2843
|
};
|
|
2794
|
-
if (architectureDirectoriesCache !== null) {
|
|
2795
|
-
paintDirectories(architectureDirectoriesCache, architectureFirstFolderId);
|
|
2796
|
-
return;
|
|
2797
|
-
}
|
|
2798
2844
|
requireCloudqCredential().then(() => cloudqRequest(API_ARCH_DIRECTORIES)).then((data) => {
|
|
2799
|
-
|
|
2800
|
-
architectureFirstFolderId = Number(data?.firstFolderId) || null;
|
|
2801
|
-
paintDirectories(architectureDirectoriesCache, architectureFirstFolderId);
|
|
2845
|
+
paintDirectories(Array.isArray(data?.folders) ? data.folders : [], Number(data?.firstFolderId) || null);
|
|
2802
2846
|
}).catch((error) => {
|
|
2803
2847
|
if (panelView !== "architecture" || !panelExpanded || viewRequest !== architectureRequestSeq) return;
|
|
2804
2848
|
panelBody.textContent = "";
|
|
@@ -3073,12 +3117,7 @@ display: none;
|
|
|
3073
3117
|
panelEl = null;
|
|
3074
3118
|
panelBody = null;
|
|
3075
3119
|
}
|
|
3076
|
-
inspirationCache = null;
|
|
3077
3120
|
inspirationCategory = 0;
|
|
3078
|
-
artifactCache = null;
|
|
3079
|
-
artifactTotal = 0;
|
|
3080
|
-
architectureDirectoriesCache = null;
|
|
3081
|
-
architectureFirstFolderId = null;
|
|
3082
3121
|
architectureRequestSeq += 1;
|
|
3083
3122
|
panelView = "usage";
|
|
3084
3123
|
};
|
|
@@ -3644,6 +3683,19 @@ display: none;
|
|
|
3644
3683
|
window.removeEventListener("storage", onStorage);
|
|
3645
3684
|
};
|
|
3646
3685
|
}, "dsh-cloudq: reconcile durable session identities");
|
|
3686
|
+
ctx.effect(() => {
|
|
3687
|
+
const list = ctx?.sessions?.list;
|
|
3688
|
+
if (!list?.subscribe || !list?.getSnapshot) return void 0;
|
|
3689
|
+
const prevRunning = /* @__PURE__ */ new Map();
|
|
3690
|
+
return list.subscribe(() => {
|
|
3691
|
+
const byId = list.getSnapshot()?.byId ?? {};
|
|
3692
|
+
for (const [id, summary] of Object.entries(byId)) {
|
|
3693
|
+
const running = summary?.running === true;
|
|
3694
|
+
if (prevRunning.get(id) === true && !running && cloudqSessions.has(id)) scheduleArtifactSilentRefresh();
|
|
3695
|
+
prevRunning.set(id, running);
|
|
3696
|
+
}
|
|
3697
|
+
});
|
|
3698
|
+
}, "dsh-cloudq: refresh artifacts on turn completion");
|
|
3647
3699
|
ctx.effect(() => {
|
|
3648
3700
|
const markIfCloudqClaim = () => {
|
|
3649
3701
|
const textarea = document.querySelector("textarea[class*=input]");
|
package/package.json
CHANGED
|
@@ -104,7 +104,7 @@ def find_available_role_name() -> tuple:
|
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
def save_config(account_uin: str, role_arn: str, role_id: str = "",
|
|
107
|
-
auto_created: bool = True):
|
|
107
|
+
auto_created: bool = True, role_name: str = ""):
|
|
108
108
|
"""保存配置到文件"""
|
|
109
109
|
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
110
110
|
|
|
@@ -114,15 +114,25 @@ def save_config(account_uin: str, role_arn: str, role_id: str = "",
|
|
|
114
114
|
except OSError:
|
|
115
115
|
pass
|
|
116
116
|
|
|
117
|
+
# 保留 DSH 插件写入的免密开关偏好,避免重建角色时被重置。
|
|
118
|
+
existing = {}
|
|
119
|
+
if CONFIG_FILE.exists():
|
|
120
|
+
try:
|
|
121
|
+
existing = json.loads(CONFIG_FILE.read_text(encoding="utf-8"))
|
|
122
|
+
except (json.JSONDecodeError, IOError):
|
|
123
|
+
existing = {}
|
|
124
|
+
|
|
117
125
|
config = {
|
|
118
126
|
"accountUin": account_uin,
|
|
119
|
-
"roleName": ROLE_NAME,
|
|
127
|
+
"roleName": role_name or ROLE_NAME,
|
|
120
128
|
"roleArn": role_arn,
|
|
121
129
|
"roleId": role_id,
|
|
122
130
|
"configuredAt": datetime.now(timezone.utc).isoformat(),
|
|
123
131
|
"autoCreated": auto_created,
|
|
124
132
|
"version": "1.0",
|
|
125
133
|
}
|
|
134
|
+
if isinstance(existing.get("enabled"), bool):
|
|
135
|
+
config["enabled"] = existing["enabled"]
|
|
126
136
|
|
|
127
137
|
CONFIG_FILE.write_text(
|
|
128
138
|
json.dumps(config, indent=2, ensure_ascii=False),
|
|
@@ -153,6 +163,21 @@ def main():
|
|
|
153
163
|
secret_id = os.environ.get("TENCENTCLOUD_SECRET_ID", "")
|
|
154
164
|
secret_key = os.environ.get("TENCENTCLOUD_SECRET_KEY", "")
|
|
155
165
|
|
|
166
|
+
# 环境变量缺失时回退到凭证文件(与 login_url.py 一致),
|
|
167
|
+
# 使 DSH 插件等宿主可直接调用而无需注入环境变量。
|
|
168
|
+
if not secret_id or not secret_key:
|
|
169
|
+
try:
|
|
170
|
+
from credential_manager import get_credential
|
|
171
|
+
cred = get_credential()
|
|
172
|
+
secret_id = cred["secretId"]
|
|
173
|
+
secret_key = cred["secretKey"]
|
|
174
|
+
if cred.get("token"):
|
|
175
|
+
os.environ["TENCENTCLOUD_TOKEN"] = cred["token"]
|
|
176
|
+
except ImportError:
|
|
177
|
+
pass
|
|
178
|
+
except Exception:
|
|
179
|
+
pass
|
|
180
|
+
|
|
156
181
|
if not secret_id or not secret_key:
|
|
157
182
|
print(output_json(output_error(
|
|
158
183
|
"MissingCredentials",
|
|
@@ -210,7 +235,7 @@ def main():
|
|
|
210
235
|
attach_warnings.append(f"策略 {policy_name} 关联失败: {err_msg}")
|
|
211
236
|
print(f"WARNING: {attach_warnings[-1]}", file=sys.stderr)
|
|
212
237
|
|
|
213
|
-
save_config(account_uin, role_arn, role_id, auto_created=False)
|
|
238
|
+
save_config(account_uin, role_arn, role_id, auto_created=False, role_name=target_role)
|
|
214
239
|
result = output_success(role_arn, account_uin, role_id)
|
|
215
240
|
result["data"]["roleName"] = target_role
|
|
216
241
|
if attach_warnings:
|
|
@@ -266,7 +291,7 @@ def main():
|
|
|
266
291
|
|
|
267
292
|
# ============== 6. 保存配置 ==============
|
|
268
293
|
role_arn = f"qcs::cam::uin/{account_uin}:roleName/{target_role}"
|
|
269
|
-
save_config(account_uin, role_arn, role_id, auto_created=True)
|
|
294
|
+
save_config(account_uin, role_arn, role_id, auto_created=True, role_name=target_role)
|
|
270
295
|
|
|
271
296
|
# ============== 7. 输出结果 ==============
|
|
272
297
|
result = output_success(role_arn, account_uin, role_id)
|