tuyoo-devflow 0.1.12 → 0.1.16
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/CHANGELOG.md +26 -0
- package/README.md +3 -1
- package/dist/commands/agent/doctor.js +44 -13
- package/dist/commands/agent/doctor.js.map +1 -1
- package/dist/commands/agent/shared.js +2 -2
- package/dist/commands/agent/shared.js.map +1 -1
- package/dist/core/precheck/network.d.ts +1 -0
- package/dist/core/precheck/network.js +72 -0
- package/dist/core/precheck/network.js.map +1 -1
- package/dist/core/store/doctorJenkinsUrlCache.d.ts +8 -0
- package/dist/core/store/doctorJenkinsUrlCache.js +60 -0
- package/dist/core/store/doctorJenkinsUrlCache.js.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,32 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.1.16] - 2026-04-22
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- `agent doctor` / `agent install` 现在会先做工具检查,再做网络检查。
|
|
14
|
+
- GitLab 白名单检查新增 `git ls-remote` 仓库访问探测,用真实 Git 请求补足仅测 `443` 端口的盲区。
|
|
15
|
+
|
|
16
|
+
## [0.1.15] - 2026-04-22
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- GitLab shell runner 在宿主机未预装 Node/npm 时,CI 现在会自动下载并缓存 Node 20,避免在 `npm ci` 前直接失败。
|
|
21
|
+
|
|
22
|
+
## [0.1.14] - 2026-04-22
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- GitLab CI 现在默认绑定 runner tag `pytuyoo_pipeline`,确保 tag 发布任务能被对应 runner 正常接单执行。
|
|
27
|
+
|
|
28
|
+
## [0.1.13] - 2026-04-22
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- `agent doctor` 现在会缓存上次输入的 Jenkins URL;再次执行时会提示是否复用,交互方式与 `agent install` 的命令缓存保持一致。
|
|
33
|
+
- GitHub npm 发布流程更新为在 `self-hosted` + `pytuyoo_pipeline` runner 上执行,并在发布前显式校验 `NPM_TOKEN` 是否已配置。
|
|
34
|
+
|
|
9
35
|
## [0.1.12] - 2026-04-22
|
|
10
36
|
|
|
11
37
|
### Changed
|
package/README.md
CHANGED
|
@@ -175,11 +175,13 @@ npm run pack:dry
|
|
|
175
175
|
|
|
176
176
|
- GitHub Actions
|
|
177
177
|
- CI:`.github/workflows/ci.yml`
|
|
178
|
-
- 发布:`.github/workflows/publish.yml`(tag `v*` 或手动触发)
|
|
178
|
+
- 发布:`.github/workflows/publish.yml`(push tag `v*` 或手动触发)
|
|
179
|
+
- 发布 Runner:`self-hosted` + `pytuyoo_pipeline`
|
|
179
180
|
- Secret:`NPM_TOKEN`
|
|
180
181
|
- GitLab CI
|
|
181
182
|
- CI + 发布:`.gitlab-ci.yml`
|
|
182
183
|
- 规则:tag 命中 `vX.Y.Z` 时执行 `npm publish`
|
|
184
|
+
- Runner tag:`pytuyoo_pipeline`
|
|
183
185
|
- Variable:`NPM_TOKEN`
|
|
184
186
|
|
|
185
187
|
详细发布步骤见 `RELEASING.md`。
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { input } from "@inquirer/prompts";
|
|
2
|
+
import { confirm, input } from "@inquirer/prompts";
|
|
3
3
|
import { getCurrentUsername, getSupportedPlatform } from "../../core/platform.js";
|
|
4
4
|
import { safeErrorMessage } from "../../core/log/redact.js";
|
|
5
5
|
import { summarizeDoctorCheckProfile, } from "../../core/precheck/checkProfile.js";
|
|
@@ -7,10 +7,21 @@ import { guideAndInstallMissingTools } from "../../core/precheck/autoInstall.js"
|
|
|
7
7
|
import { checkRequiredTools } from "../../core/precheck/tools.js";
|
|
8
8
|
import { collectSystemInfoResults } from "../../core/precheck/systemInfo.js";
|
|
9
9
|
import { readDoctorCheckProfile, writeDoctorCheckProfile, } from "../../core/store/doctorCheckProfileStore.js";
|
|
10
|
+
import { loadDoctorJenkinsUrlCache, saveDoctorJenkinsUrlCache, shouldPersistDoctorJenkinsUrlCache, } from "../../core/store/doctorJenkinsUrlCache.js";
|
|
10
11
|
import { CheckReport } from "../../ui/CheckReport.js";
|
|
11
12
|
import { renderOnce } from "../../ui/renderOnce.js";
|
|
12
13
|
import { getFailedToolChecks, hasLinuxOrNetworkFailure, printCheckSummary, printFailedWhitelistReport, runDoctorChecks, } from "./shared.js";
|
|
13
14
|
import { promptDoctorCheckProfile } from "./checkProfilePrompt.js";
|
|
15
|
+
function formatCacheTime(isoTime) {
|
|
16
|
+
if (!isoTime) {
|
|
17
|
+
return "未知时间";
|
|
18
|
+
}
|
|
19
|
+
const date = new Date(isoTime);
|
|
20
|
+
if (Number.isNaN(date.getTime())) {
|
|
21
|
+
return isoTime;
|
|
22
|
+
}
|
|
23
|
+
return date.toLocaleString();
|
|
24
|
+
}
|
|
14
25
|
export function registerDoctorCommand(agentCommand) {
|
|
15
26
|
agentCommand
|
|
16
27
|
.command("doctor")
|
|
@@ -21,18 +32,38 @@ export function registerDoctorCommand(agentCommand) {
|
|
|
21
32
|
const username = getCurrentUsername();
|
|
22
33
|
const systemInfo = collectSystemInfoResults(platform, username);
|
|
23
34
|
await renderOnce(_jsx(CheckReport, { title: "\u5F53\u524D\u7CFB\u7EDF\u4FE1\u606F", results: systemInfo }));
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
const cachedJenkinsUrl = await loadDoctorJenkinsUrlCache();
|
|
36
|
+
let jenkinsUrl;
|
|
37
|
+
if (cachedJenkinsUrl) {
|
|
38
|
+
console.log(`检测到本地缓存的 Jenkins URL(更新时间: ${formatCacheTime(cachedJenkinsUrl.updatedAt)})。`);
|
|
39
|
+
console.log(`缓存内容: ${cachedJenkinsUrl.jenkinsUrl}`);
|
|
40
|
+
const shouldModifyCachedUrl = await confirm({
|
|
41
|
+
message: "是否需要修改 Jenkins URL?(默认不修改,直接继续下一步)",
|
|
42
|
+
default: false,
|
|
43
|
+
});
|
|
44
|
+
if (!shouldModifyCachedUrl) {
|
|
45
|
+
jenkinsUrl = cachedJenkinsUrl.jenkinsUrl;
|
|
46
|
+
console.log("已使用本地缓存的 Jenkins URL,继续执行。");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
jenkinsUrl =
|
|
50
|
+
jenkinsUrl ??
|
|
51
|
+
(await input({
|
|
52
|
+
message: "请输入 Jenkins URL(例如 http://jenkins.example.com/)",
|
|
53
|
+
default: cachedJenkinsUrl?.jenkinsUrl,
|
|
54
|
+
validate(value) {
|
|
55
|
+
try {
|
|
56
|
+
new URL(value);
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return "URL 格式不正确";
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
}));
|
|
64
|
+
if (shouldPersistDoctorJenkinsUrlCache(jenkinsUrl)) {
|
|
65
|
+
await saveDoctorJenkinsUrlCache(jenkinsUrl);
|
|
66
|
+
}
|
|
36
67
|
const previousProfile = await readDoctorCheckProfile();
|
|
37
68
|
const checkProfile = await promptDoctorCheckProfile(jenkinsUrl, previousProfile);
|
|
38
69
|
await writeDoctorCheckProfile(checkProfile);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/commands/agent/doctor.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/commands/agent/doctor.tsx"],"names":[],"mappings":"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"}
|
|
@@ -7,8 +7,8 @@ import { CheckReport } from "../../ui/CheckReport.js";
|
|
|
7
7
|
import { renderOnce } from "../../ui/renderOnce.js";
|
|
8
8
|
export async function runDoctorChecks(platform, jenkinsBaseUrl, selectedNetworkTargets) {
|
|
9
9
|
const linuxResults = platform === "linux" ? await checkLinuxGuards() : [];
|
|
10
|
-
const networkResults = await checkWhitelistConnectivity(jenkinsBaseUrl, selectedNetworkTargets);
|
|
11
10
|
const toolResults = await checkRequiredTools(platform);
|
|
11
|
+
const networkResults = await checkWhitelistConnectivity(jenkinsBaseUrl, selectedNetworkTargets);
|
|
12
12
|
return {
|
|
13
13
|
linuxResults,
|
|
14
14
|
networkResults,
|
|
@@ -31,6 +31,7 @@ export async function printCheckSummary(checks) {
|
|
|
31
31
|
if (checks.linuxResults.length > 0) {
|
|
32
32
|
await renderOnce(_jsx(CheckReport, { title: "Linux \u524D\u7F6E\u68C0\u67E5", results: checks.linuxResults }));
|
|
33
33
|
}
|
|
34
|
+
await renderOnce(_jsx(CheckReport, { title: "\u5DE5\u5177\u4E0E\u7248\u672C\u68C0\u67E5", results: checks.toolResults }));
|
|
34
35
|
await renderOnce(_jsx(CheckReport, { title: "\u7F51\u7EDC\u767D\u540D\u5355\u68C0\u67E5", results: checks.networkResults.length > 0
|
|
35
36
|
? checks.networkResults
|
|
36
37
|
: [
|
|
@@ -40,7 +41,6 @@ export async function printCheckSummary(checks) {
|
|
|
40
41
|
detail: "未选择任何网络白名单检查项,本次已跳过。",
|
|
41
42
|
},
|
|
42
43
|
] }));
|
|
43
|
-
await renderOnce(_jsx(CheckReport, { title: "\u5DE5\u5177\u4E0E\u7248\u672C\u68C0\u67E5", results: checks.toolResults }));
|
|
44
44
|
}
|
|
45
45
|
export async function printFailedWhitelistReport(checks) {
|
|
46
46
|
const failedNetworkChecks = getFailedNetworkChecks(checks);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/commands/agent/shared.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EACL,4BAA4B,EAC5B,0BAA0B,GAC3B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAQpD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAA2B,EAC3B,cAAsB,EACtB,sBAA2C;IAE3C,MAAM,YAAY,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,MAAM,
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/commands/agent/shared.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import { NetworkCheckResult, NetworkTargetKey } from "../../types.js";
|
|
2
|
+
export declare function isGitLabRepositoryReachableFromProbe(output: string): boolean;
|
|
2
3
|
export declare function checkWhitelistConnectivity(jenkinsBaseUrl: string, selectedTargetKeys?: NetworkTargetKey[]): Promise<NetworkCheckResult[]>;
|
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import dns from "node:dns/promises";
|
|
2
2
|
import net from "node:net";
|
|
3
3
|
import { getWhitelistTargets } from "../../constants/whitelist.js";
|
|
4
|
+
import { runCommand } from "../shell/commandRunner.js";
|
|
5
|
+
const GITLAB_REPOSITORY_PROBE_PATH = "liutongqing/pytuyoo-pipeline.git";
|
|
6
|
+
const GITLAB_REACHABLE_PATTERNS = [
|
|
7
|
+
"could not read username for",
|
|
8
|
+
"authentication failed",
|
|
9
|
+
"http basic: access denied",
|
|
10
|
+
"repository not found",
|
|
11
|
+
"the requested url returned error: 401",
|
|
12
|
+
"the requested url returned error: 403",
|
|
13
|
+
"the requested url returned error: 404",
|
|
14
|
+
"access denied",
|
|
15
|
+
];
|
|
16
|
+
function buildGitLabRepositoryProbeUrl(host) {
|
|
17
|
+
return `https://${host}/${GITLAB_REPOSITORY_PROBE_PATH}`;
|
|
18
|
+
}
|
|
19
|
+
export function isGitLabRepositoryReachableFromProbe(output) {
|
|
20
|
+
const normalized = output.trim().toLowerCase();
|
|
21
|
+
if (!normalized) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return GITLAB_REACHABLE_PATTERNS.some((pattern) => normalized.includes(pattern));
|
|
25
|
+
}
|
|
4
26
|
async function resolveTargetAddresses(host) {
|
|
5
27
|
if (net.isIP(host)) {
|
|
6
28
|
return [host];
|
|
@@ -48,11 +70,61 @@ async function checkTcpTarget(target) {
|
|
|
48
70
|
socket.connect(target.port, target.host);
|
|
49
71
|
});
|
|
50
72
|
}
|
|
73
|
+
async function checkGitLabRepositoryAccess(target) {
|
|
74
|
+
const resolvedAddresses = await resolveTargetAddresses(target.host);
|
|
75
|
+
const gitCheck = await runCommand("command -v git", { allowFailure: true });
|
|
76
|
+
if (gitCheck.code !== 0) {
|
|
77
|
+
return {
|
|
78
|
+
name: "网络连通: GitLab 仓库访问",
|
|
79
|
+
status: "warn",
|
|
80
|
+
detail: "未检测到 git,已跳过 GitLab 仓库访问探测。",
|
|
81
|
+
hint: "请先修复 Git 工具检查,再重新执行 doctor/install。",
|
|
82
|
+
target,
|
|
83
|
+
resolvedAddresses,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const probeUrl = buildGitLabRepositoryProbeUrl(target.host);
|
|
87
|
+
const result = await runCommand(`GIT_TERMINAL_PROMPT=0 git ls-remote --heads "${probeUrl}"`, {
|
|
88
|
+
allowFailure: true,
|
|
89
|
+
});
|
|
90
|
+
const output = `${result.stderr}\n${result.stdout}`.trim();
|
|
91
|
+
if (result.code === 0) {
|
|
92
|
+
return {
|
|
93
|
+
name: "网络连通: GitLab 仓库访问",
|
|
94
|
+
status: "pass",
|
|
95
|
+
detail: `${probeUrl} 可通过 git 访问`,
|
|
96
|
+
target,
|
|
97
|
+
resolvedAddresses,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (isGitLabRepositoryReachableFromProbe(output)) {
|
|
101
|
+
return {
|
|
102
|
+
name: "网络连通: GitLab 仓库访问",
|
|
103
|
+
status: "pass",
|
|
104
|
+
detail: "GitLab 仓库访问探测已到达服务端(当前仓库可能需要认证或额外权限)。",
|
|
105
|
+
hint: "已验证到达 GitLab 服务端;如后续 clone 失败,请检查用户名、Token 与仓库权限。",
|
|
106
|
+
target,
|
|
107
|
+
resolvedAddresses,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const detail = output.split("\n").map((line) => line.trim()).find(Boolean) ?? `${probeUrl} git 访问失败`;
|
|
111
|
+
return {
|
|
112
|
+
name: "网络连通: GitLab 仓库访问",
|
|
113
|
+
status: "fail",
|
|
114
|
+
detail,
|
|
115
|
+
hint: "仅 443 端口可达不足以保证 git clone 正常;请确认 GitLab 白名单、代理与出口策略。",
|
|
116
|
+
target,
|
|
117
|
+
resolvedAddresses,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
51
120
|
export async function checkWhitelistConnectivity(jenkinsBaseUrl, selectedTargetKeys) {
|
|
52
121
|
const targets = getWhitelistTargets(jenkinsBaseUrl, selectedTargetKeys);
|
|
53
122
|
const results = [];
|
|
54
123
|
for (const target of targets) {
|
|
55
124
|
results.push(await checkTcpTarget(target));
|
|
125
|
+
if (target.key === "gitlab") {
|
|
126
|
+
results.push(await checkGitLabRepositoryAccess(target));
|
|
127
|
+
}
|
|
56
128
|
}
|
|
57
129
|
return results;
|
|
58
130
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../../src/core/precheck/network.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,mBAAmB,CAAC;AACpC,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../../src/core/precheck/network.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface DoctorJenkinsUrlCache {
|
|
2
|
+
jenkinsUrl: string;
|
|
3
|
+
updatedAt: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function shouldPersistDoctorJenkinsUrlCache(jenkinsUrl: string): boolean;
|
|
6
|
+
export declare function clearDoctorJenkinsUrlCache(): Promise<void>;
|
|
7
|
+
export declare function loadDoctorJenkinsUrlCache(): Promise<DoctorJenkinsUrlCache | null>;
|
|
8
|
+
export declare function saveDoctorJenkinsUrlCache(jenkinsUrl: string): Promise<void>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getConfigDir } from "../platform.js";
|
|
4
|
+
function getCacheFilePath() {
|
|
5
|
+
return path.join(getConfigDir(), "tmp", "agent-doctor-jenkins-url-cache.json");
|
|
6
|
+
}
|
|
7
|
+
function isPlaceholderValue(jenkinsUrl) {
|
|
8
|
+
const normalized = jenkinsUrl.trim().toLowerCase();
|
|
9
|
+
const placeholderKeywords = ["jenkins.example.com", "example.com", "<jenkins-host>", "http://<"];
|
|
10
|
+
return placeholderKeywords.some((keyword) => normalized.includes(keyword));
|
|
11
|
+
}
|
|
12
|
+
export function shouldPersistDoctorJenkinsUrlCache(jenkinsUrl) {
|
|
13
|
+
if (!jenkinsUrl.trim()) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
new URL(jenkinsUrl);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (isPlaceholderValue(jenkinsUrl)) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
export async function clearDoctorJenkinsUrlCache() {
|
|
28
|
+
const filePath = getCacheFilePath();
|
|
29
|
+
if (await fs.pathExists(filePath)) {
|
|
30
|
+
await fs.remove(filePath);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export async function loadDoctorJenkinsUrlCache() {
|
|
34
|
+
const filePath = getCacheFilePath();
|
|
35
|
+
const exists = await fs.pathExists(filePath);
|
|
36
|
+
if (!exists) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const data = (await fs.readJson(filePath));
|
|
40
|
+
if (!data.jenkinsUrl || !shouldPersistDoctorJenkinsUrlCache(data.jenkinsUrl)) {
|
|
41
|
+
await clearDoctorJenkinsUrlCache();
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
jenkinsUrl: data.jenkinsUrl,
|
|
46
|
+
updatedAt: data.updatedAt ?? "",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export async function saveDoctorJenkinsUrlCache(jenkinsUrl) {
|
|
50
|
+
const filePath = getCacheFilePath();
|
|
51
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
52
|
+
await fs.writeJson(filePath, {
|
|
53
|
+
jenkinsUrl,
|
|
54
|
+
updatedAt: new Date().toISOString(),
|
|
55
|
+
}, { spaces: 2 });
|
|
56
|
+
if (process.platform !== "win32") {
|
|
57
|
+
await fs.chmod(filePath, 0o600);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=doctorJenkinsUrlCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctorJenkinsUrlCache.js","sourceRoot":"","sources":["../../../src/core/store/doctorJenkinsUrlCache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAO9C,SAAS,gBAAgB;IACvB,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,qCAAqC,CAAC,CAAC;AACjF,CAAC;AAED,SAAS,kBAAkB,CAAC,UAAkB;IAC5C,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACnD,MAAM,mBAAmB,GAAG,CAAC,qBAAqB,EAAE,aAAa,EAAE,gBAAgB,EAAE,UAAU,CAAC,CAAC;IACjG,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,kCAAkC,CAAC,UAAkB;IACnE,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,kBAAkB,CAAC,UAAU,CAAC,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC;IACpC,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB;IAC7C,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAmC,CAAC;IAC7E,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,kCAAkC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7E,MAAM,0BAA0B,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,EAAE;KAChC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,UAAkB;IAChE,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC;IACpC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC3C,MAAM,EAAE,CAAC,SAAS,CAChB,QAAQ,EACR;QACE,UAAU;QACV,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,EACD,EAAE,MAAM,EAAE,CAAC,EAAE,CACd,CAAC;IACF,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;AACH,CAAC"}
|