tuyoo-devflow 0.1.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.
Files changed (97) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/LICENSE +21 -0
  3. package/README.md +150 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +21 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/agent/doctor.d.ts +2 -0
  8. package/dist/commands/agent/doctor.js +70 -0
  9. package/dist/commands/agent/doctor.js.map +1 -0
  10. package/dist/commands/agent/index.d.ts +2 -0
  11. package/dist/commands/agent/index.js +8 -0
  12. package/dist/commands/agent/index.js.map +1 -0
  13. package/dist/commands/agent/install.d.ts +2 -0
  14. package/dist/commands/agent/install.js +300 -0
  15. package/dist/commands/agent/install.js.map +1 -0
  16. package/dist/commands/agent/shared.d.ts +11 -0
  17. package/dist/commands/agent/shared.js +33 -0
  18. package/dist/commands/agent/shared.js.map +1 -0
  19. package/dist/commands/agent/start.d.ts +3 -0
  20. package/dist/commands/agent/start.js +85 -0
  21. package/dist/commands/agent/start.js.map +1 -0
  22. package/dist/constants/versionPolicy.d.ts +12 -0
  23. package/dist/constants/versionPolicy.js +13 -0
  24. package/dist/constants/versionPolicy.js.map +1 -0
  25. package/dist/constants/whitelist.d.ts +3 -0
  26. package/dist/constants/whitelist.js +43 -0
  27. package/dist/constants/whitelist.js.map +1 -0
  28. package/dist/core/generator/linuxSystemd.d.ts +15 -0
  29. package/dist/core/generator/linuxSystemd.js +64 -0
  30. package/dist/core/generator/linuxSystemd.js.map +1 -0
  31. package/dist/core/generator/macLaunchd.d.ts +15 -0
  32. package/dist/core/generator/macLaunchd.js +104 -0
  33. package/dist/core/generator/macLaunchd.js.map +1 -0
  34. package/dist/core/generator/macScript.d.ts +2 -0
  35. package/dist/core/generator/macScript.js +20 -0
  36. package/dist/core/generator/macScript.js.map +1 -0
  37. package/dist/core/generator/winBat.d.ts +2 -0
  38. package/dist/core/generator/winBat.js +20 -0
  39. package/dist/core/generator/winBat.js.map +1 -0
  40. package/dist/core/jenkins/directLaunch.d.ts +2 -0
  41. package/dist/core/jenkins/directLaunch.js +22 -0
  42. package/dist/core/jenkins/directLaunch.js.map +1 -0
  43. package/dist/core/jenkins/downloadAgentJar.d.ts +1 -0
  44. package/dist/core/jenkins/downloadAgentJar.js +13 -0
  45. package/dist/core/jenkins/downloadAgentJar.js.map +1 -0
  46. package/dist/core/jenkins/launchArgs.d.ts +2 -0
  47. package/dist/core/jenkins/launchArgs.js +22 -0
  48. package/dist/core/jenkins/launchArgs.js.map +1 -0
  49. package/dist/core/jenkins/parseAgentCommand.d.ts +7 -0
  50. package/dist/core/jenkins/parseAgentCommand.js +108 -0
  51. package/dist/core/jenkins/parseAgentCommand.js.map +1 -0
  52. package/dist/core/log/redact.d.ts +2 -0
  53. package/dist/core/log/redact.js +26 -0
  54. package/dist/core/log/redact.js.map +1 -0
  55. package/dist/core/pipeline/setupPytuyooPipeline.d.ts +30 -0
  56. package/dist/core/pipeline/setupPytuyooPipeline.js +254 -0
  57. package/dist/core/pipeline/setupPytuyooPipeline.js.map +1 -0
  58. package/dist/core/platform.d.ts +5 -0
  59. package/dist/core/platform.js +27 -0
  60. package/dist/core/platform.js.map +1 -0
  61. package/dist/core/precheck/autoInstall.d.ts +9 -0
  62. package/dist/core/precheck/autoInstall.js +249 -0
  63. package/dist/core/precheck/autoInstall.js.map +1 -0
  64. package/dist/core/precheck/linuxGuard.d.ts +2 -0
  65. package/dist/core/precheck/linuxGuard.js +48 -0
  66. package/dist/core/precheck/linuxGuard.js.map +1 -0
  67. package/dist/core/precheck/network.d.ts +2 -0
  68. package/dist/core/precheck/network.js +42 -0
  69. package/dist/core/precheck/network.js.map +1 -0
  70. package/dist/core/precheck/systemInfo.d.ts +2 -0
  71. package/dist/core/precheck/systemInfo.js +37 -0
  72. package/dist/core/precheck/systemInfo.js.map +1 -0
  73. package/dist/core/precheck/tools.d.ts +12 -0
  74. package/dist/core/precheck/tools.js +135 -0
  75. package/dist/core/precheck/tools.js.map +1 -0
  76. package/dist/core/security/secretStore.d.ts +5 -0
  77. package/dist/core/security/secretStore.js +310 -0
  78. package/dist/core/security/secretStore.js.map +1 -0
  79. package/dist/core/shell/commandRunner.d.ts +17 -0
  80. package/dist/core/shell/commandRunner.js +94 -0
  81. package/dist/core/shell/commandRunner.js.map +1 -0
  82. package/dist/core/store/installCommandCache.d.ts +9 -0
  83. package/dist/core/store/installCommandCache.js +66 -0
  84. package/dist/core/store/installCommandCache.js.map +1 -0
  85. package/dist/core/store/profileStore.d.ts +4 -0
  86. package/dist/core/store/profileStore.js +43 -0
  87. package/dist/core/store/profileStore.js.map +1 -0
  88. package/dist/types.d.ts +41 -0
  89. package/dist/types.js +2 -0
  90. package/dist/types.js.map +1 -0
  91. package/dist/ui/CheckReport.d.ts +5 -0
  92. package/dist/ui/CheckReport.js +24 -0
  93. package/dist/ui/CheckReport.js.map +1 -0
  94. package/dist/ui/renderOnce.d.ts +2 -0
  95. package/dist/ui/renderOnce.js +9 -0
  96. package/dist/ui/renderOnce.js.map +1 -0
  97. package/package.json +63 -0
@@ -0,0 +1,310 @@
1
+ import { spawn } from "node:child_process";
2
+ import fs from "fs-extra";
3
+ import path from "node:path";
4
+ import { getConfigDir } from "../platform.js";
5
+ const SERVICE_NAME = "tuyoo-devflow";
6
+ const ACCOUNT_GITLAB_TOKEN = "gitlab.token";
7
+ const FALLBACK_NOTICE = "检测到 keytar 在当前环境异常,已自动切换到 macOS security CLI 访问 Keychain。";
8
+ const FILE_FALLBACK_NOTICE = "系统密钥环不可用,已回退到本地受限文件存储(0600)。";
9
+ let activeBackend = null;
10
+ let fallbackNotified = false;
11
+ let fileFallbackNotified = false;
12
+ function rawErrorMessage(error) {
13
+ if (error instanceof Error && error.message) {
14
+ return error.message;
15
+ }
16
+ return String(error);
17
+ }
18
+ function secureStoreHint() {
19
+ if (process.platform === "darwin") {
20
+ return "请确认登录钥匙串已解锁,并允许当前终端访问 Keychain(可尝试重启终端后重试)。";
21
+ }
22
+ if (process.platform === "win32") {
23
+ return "请确认 Windows Credential Manager 服务可用,并在桌面会话中运行命令。";
24
+ }
25
+ return "请确认系统 Secret Service/Keyring 可用(如 gnome-keyring 或 libsecret)。";
26
+ }
27
+ function wrapSecureStoreError(action, error) {
28
+ const message = rawErrorMessage(error);
29
+ const reason = !message || message === "An unknown error occurred."
30
+ ? "系统密钥环返回未知错误"
31
+ : message;
32
+ return new Error(`密钥环操作失败(${action}): ${reason}。${secureStoreHint()}`);
33
+ }
34
+ function isUnknownKeychainError(error) {
35
+ const msg = rawErrorMessage(error).toLowerCase();
36
+ return msg.includes("an unknown error occurred") || msg.includes("unknown error");
37
+ }
38
+ function isSecurityItemNotFound(text) {
39
+ const normalized = text.toLowerCase();
40
+ return (normalized.includes("could not be found") ||
41
+ normalized.includes("item not found") ||
42
+ normalized.includes("specified item could not be found"));
43
+ }
44
+ function getLocalSecretFilePath() {
45
+ return path.join(getConfigDir(), "secrets.local.json");
46
+ }
47
+ async function ensureLocalSecretFile() {
48
+ const filePath = getLocalSecretFilePath();
49
+ await fs.ensureDir(path.dirname(filePath));
50
+ if (!(await fs.pathExists(filePath))) {
51
+ const initial = { secrets: {} };
52
+ await fs.writeJson(filePath, initial, { spaces: 2 });
53
+ if (process.platform !== "win32") {
54
+ await fs.chmod(filePath, 0o600);
55
+ }
56
+ }
57
+ }
58
+ async function readLocalSecretFile() {
59
+ await ensureLocalSecretFile();
60
+ const data = (await fs.readJson(getLocalSecretFilePath()));
61
+ return {
62
+ secrets: data.secrets ?? {},
63
+ };
64
+ }
65
+ async function writeLocalSecretFile(data) {
66
+ await ensureLocalSecretFile();
67
+ await fs.writeJson(getLocalSecretFilePath(), data, { spaces: 2 });
68
+ if (process.platform !== "win32") {
69
+ await fs.chmod(getLocalSecretFilePath(), 0o600);
70
+ }
71
+ }
72
+ async function runSecurity(args) {
73
+ return await new Promise((resolve, reject) => {
74
+ const child = spawn("/usr/bin/security", args, {
75
+ stdio: ["ignore", "pipe", "pipe"],
76
+ env: process.env,
77
+ });
78
+ let stdout = "";
79
+ let stderr = "";
80
+ child.stdout.on("data", (chunk) => {
81
+ stdout += String(chunk);
82
+ });
83
+ child.stderr.on("data", (chunk) => {
84
+ stderr += String(chunk);
85
+ });
86
+ child.on("error", (error) => {
87
+ reject(error);
88
+ });
89
+ child.on("close", (code) => {
90
+ resolve({
91
+ code: code ?? 1,
92
+ stdout,
93
+ stderr,
94
+ });
95
+ });
96
+ });
97
+ }
98
+ function createSecurityCliBackend() {
99
+ if (process.platform !== "darwin") {
100
+ throw new Error("security CLI 仅可在 macOS 使用。");
101
+ }
102
+ return {
103
+ kind: "security-cli",
104
+ async setPassword(account, password) {
105
+ const result = await runSecurity([
106
+ "add-generic-password",
107
+ "-U",
108
+ "-a",
109
+ account,
110
+ "-s",
111
+ SERVICE_NAME,
112
+ "-w",
113
+ password,
114
+ ]);
115
+ if (result.code !== 0) {
116
+ throw new Error(result.stderr || result.stdout || "security add-generic-password 失败");
117
+ }
118
+ },
119
+ async getPassword(account) {
120
+ const result = await runSecurity([
121
+ "find-generic-password",
122
+ "-a",
123
+ account,
124
+ "-s",
125
+ SERVICE_NAME,
126
+ "-w",
127
+ ]);
128
+ if (result.code !== 0) {
129
+ if (isSecurityItemNotFound(result.stderr || result.stdout)) {
130
+ return null;
131
+ }
132
+ throw new Error(result.stderr || result.stdout || "security find-generic-password 失败");
133
+ }
134
+ return result.stdout.trimEnd();
135
+ },
136
+ async deletePassword(account) {
137
+ const result = await runSecurity([
138
+ "delete-generic-password",
139
+ "-a",
140
+ account,
141
+ "-s",
142
+ SERVICE_NAME,
143
+ ]);
144
+ if (result.code !== 0) {
145
+ if (isSecurityItemNotFound(result.stderr || result.stdout)) {
146
+ return false;
147
+ }
148
+ throw new Error(result.stderr || result.stdout || "security delete-generic-password 失败");
149
+ }
150
+ return true;
151
+ },
152
+ };
153
+ }
154
+ function createLocalFileBackend() {
155
+ return {
156
+ kind: "local-file",
157
+ async setPassword(account, password) {
158
+ const data = await readLocalSecretFile();
159
+ data.secrets[account] = password;
160
+ await writeLocalSecretFile(data);
161
+ },
162
+ async getPassword(account) {
163
+ const data = await readLocalSecretFile();
164
+ return data.secrets[account] ?? null;
165
+ },
166
+ async deletePassword(account) {
167
+ const data = await readLocalSecretFile();
168
+ if (!(account in data.secrets)) {
169
+ return false;
170
+ }
171
+ delete data.secrets[account];
172
+ await writeLocalSecretFile(data);
173
+ return true;
174
+ },
175
+ };
176
+ }
177
+ async function loadKeytarModule() {
178
+ try {
179
+ const keytar = await import("keytar");
180
+ return keytar.default;
181
+ }
182
+ catch (error) {
183
+ throw new Error(`无法加载 keytar,请确认依赖安装和系统密钥环可用: ${error instanceof Error ? error.message : String(error)}`);
184
+ }
185
+ }
186
+ async function createKeytarBackend() {
187
+ const keytar = await loadKeytarModule();
188
+ return {
189
+ kind: "keytar",
190
+ async setPassword(account, password) {
191
+ await keytar.setPassword(SERVICE_NAME, account, password);
192
+ },
193
+ async getPassword(account) {
194
+ return await keytar.getPassword(SERVICE_NAME, account);
195
+ },
196
+ async deletePassword(account) {
197
+ return await keytar.deletePassword(SERVICE_NAME, account);
198
+ },
199
+ };
200
+ }
201
+ async function resolveBackend() {
202
+ if (activeBackend) {
203
+ return activeBackend;
204
+ }
205
+ try {
206
+ activeBackend = await createKeytarBackend();
207
+ return activeBackend;
208
+ }
209
+ catch (error) {
210
+ if (process.platform === "darwin") {
211
+ activeBackend = createSecurityCliBackend();
212
+ if (!fallbackNotified) {
213
+ console.warn(FALLBACK_NOTICE);
214
+ fallbackNotified = true;
215
+ }
216
+ return activeBackend;
217
+ }
218
+ activeBackend = createLocalFileBackend();
219
+ if (!fileFallbackNotified) {
220
+ console.warn(FILE_FALLBACK_NOTICE);
221
+ fileFallbackNotified = true;
222
+ }
223
+ return activeBackend;
224
+ }
225
+ }
226
+ async function runWithBackend(action, fn) {
227
+ const backend = await resolveBackend();
228
+ try {
229
+ return await fn(backend);
230
+ }
231
+ catch (error) {
232
+ if (process.platform === "darwin" && backend.kind === "keytar" && isUnknownKeychainError(error)) {
233
+ activeBackend = createSecurityCliBackend();
234
+ if (!fallbackNotified) {
235
+ console.warn(FALLBACK_NOTICE);
236
+ fallbackNotified = true;
237
+ }
238
+ try {
239
+ return await fn(activeBackend);
240
+ }
241
+ catch (fallbackError) {
242
+ activeBackend = createLocalFileBackend();
243
+ if (!fileFallbackNotified) {
244
+ console.warn(FILE_FALLBACK_NOTICE);
245
+ fileFallbackNotified = true;
246
+ }
247
+ try {
248
+ return await fn(activeBackend);
249
+ }
250
+ catch (fileError) {
251
+ throw wrapSecureStoreError(action, fileError);
252
+ }
253
+ }
254
+ }
255
+ if (backend.kind === "keytar" && process.platform !== "darwin") {
256
+ activeBackend = createLocalFileBackend();
257
+ if (!fileFallbackNotified) {
258
+ console.warn(FILE_FALLBACK_NOTICE);
259
+ fileFallbackNotified = true;
260
+ }
261
+ try {
262
+ return await fn(activeBackend);
263
+ }
264
+ catch (fileError) {
265
+ throw wrapSecureStoreError(action, fileError);
266
+ }
267
+ }
268
+ throw wrapSecureStoreError(action, error);
269
+ }
270
+ }
271
+ function profileSecretAccount(profileId) {
272
+ return `profile.${profileId}.jenkinsSecret`;
273
+ }
274
+ export async function ensureSecureStoreAvailable() {
275
+ await runWithBackend("健康检查", async (backend) => {
276
+ const probeAccount = "healthcheck";
277
+ const probeValue = "ok";
278
+ await backend.setPassword(probeAccount, probeValue);
279
+ const value = await backend.getPassword(probeAccount);
280
+ await backend.deletePassword(probeAccount);
281
+ if (value !== probeValue) {
282
+ throw new Error("读写探测失败");
283
+ }
284
+ });
285
+ }
286
+ export async function saveJenkinsSecret(profileId, secret) {
287
+ await runWithBackend("保存 Jenkins Secret", async (backend) => {
288
+ await backend.setPassword(profileSecretAccount(profileId), secret);
289
+ });
290
+ }
291
+ export async function getJenkinsSecret(profileId) {
292
+ const value = await runWithBackend("读取 Jenkins Secret", async (backend) => {
293
+ return await backend.getPassword(profileSecretAccount(profileId));
294
+ });
295
+ if (!value) {
296
+ throw new Error(`未找到 profile(${profileId}) 的 Jenkins secret。`);
297
+ }
298
+ return value;
299
+ }
300
+ export async function saveGitlabToken(token) {
301
+ await runWithBackend("保存 GitLab Token", async (backend) => {
302
+ await backend.setPassword(ACCOUNT_GITLAB_TOKEN, token);
303
+ });
304
+ }
305
+ export async function getGitlabToken() {
306
+ return await runWithBackend("读取 GitLab Token", async (backend) => {
307
+ return await backend.getPassword(ACCOUNT_GITLAB_TOKEN);
308
+ });
309
+ }
310
+ //# sourceMappingURL=secretStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secretStore.js","sourceRoot":"","sources":["../../../src/core/security/secretStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface RunCommandOptions {
2
+ cwd?: string;
3
+ asUser?: string;
4
+ allowFailure?: boolean;
5
+ streamOutput?: boolean;
6
+ streamPrefix?: string;
7
+ heartbeatIntervalMs?: number;
8
+ heartbeatText?: string;
9
+ redactValues?: string[];
10
+ inheritStdin?: boolean;
11
+ }
12
+ export interface RunCommandResult {
13
+ code: number;
14
+ stdout: string;
15
+ stderr: string;
16
+ }
17
+ export declare function runCommand(command: string, options?: RunCommandOptions): Promise<RunCommandResult>;
@@ -0,0 +1,94 @@
1
+ import { spawn } from "node:child_process";
2
+ import os from "node:os";
3
+ import { redactText } from "../log/redact.js";
4
+ function buildSpawnArgs(command, asUser) {
5
+ if (process.platform === "win32") {
6
+ return {
7
+ cmd: "powershell.exe",
8
+ args: ["-NoProfile", "-Command", command],
9
+ };
10
+ }
11
+ if (asUser && process.platform === "linux") {
12
+ const currentUser = process.env.USER ?? process.env.LOGNAME ?? os.userInfo().username;
13
+ if (asUser === currentUser) {
14
+ return {
15
+ cmd: "bash",
16
+ args: ["-lc", command],
17
+ };
18
+ }
19
+ return {
20
+ cmd: "sudo",
21
+ args: ["-u", asUser, "-H", "bash", "-lc", command],
22
+ };
23
+ }
24
+ return {
25
+ cmd: "bash",
26
+ args: ["-lc", command],
27
+ };
28
+ }
29
+ export async function runCommand(command, options = {}) {
30
+ const spawnArgs = buildSpawnArgs(command, options.asUser);
31
+ const streamPrefix = options.streamPrefix ? `[${options.streamPrefix}] ` : "";
32
+ const startAt = Date.now();
33
+ return await new Promise((resolve, reject) => {
34
+ const child = spawn(spawnArgs.cmd, spawnArgs.args, {
35
+ cwd: options.cwd,
36
+ stdio: [options.inheritStdin ? "inherit" : "ignore", "pipe", "pipe"],
37
+ env: process.env,
38
+ });
39
+ let stdout = "";
40
+ let stderr = "";
41
+ let lastOutputAt = Date.now();
42
+ let heartbeatTimer;
43
+ if (options.heartbeatIntervalMs && options.heartbeatIntervalMs > 0) {
44
+ heartbeatTimer = setInterval(() => {
45
+ const elapsedSec = Math.floor((Date.now() - startAt) / 1000);
46
+ const idleSec = Math.floor((Date.now() - lastOutputAt) / 1000);
47
+ const text = options.heartbeatText ??
48
+ `命令仍在执行中,已耗时 ${elapsedSec}s(最近输出 ${idleSec}s 前)`;
49
+ process.stdout.write(`${streamPrefix}${text}\n`);
50
+ }, options.heartbeatIntervalMs);
51
+ heartbeatTimer.unref?.();
52
+ }
53
+ child.stdout.on("data", (chunk) => {
54
+ const text = String(chunk);
55
+ stdout += text;
56
+ lastOutputAt = Date.now();
57
+ if (options.streamOutput) {
58
+ const safe = redactText(text, options.redactValues ?? []);
59
+ process.stdout.write(`${streamPrefix}${safe}`);
60
+ }
61
+ });
62
+ child.stderr.on("data", (chunk) => {
63
+ const text = String(chunk);
64
+ stderr += text;
65
+ lastOutputAt = Date.now();
66
+ if (options.streamOutput) {
67
+ const safe = redactText(text, options.redactValues ?? []);
68
+ process.stderr.write(`${streamPrefix}${safe}`);
69
+ }
70
+ });
71
+ child.on("error", (error) => {
72
+ if (heartbeatTimer) {
73
+ clearInterval(heartbeatTimer);
74
+ }
75
+ reject(error);
76
+ });
77
+ child.on("close", (code) => {
78
+ if (heartbeatTimer) {
79
+ clearInterval(heartbeatTimer);
80
+ }
81
+ const exitCode = code ?? 1;
82
+ if (!options.allowFailure && exitCode !== 0) {
83
+ reject(new Error(stderr || stdout || `Command failed: ${command}`));
84
+ return;
85
+ }
86
+ resolve({
87
+ code: exitCode,
88
+ stdout,
89
+ stderr,
90
+ });
91
+ });
92
+ });
93
+ }
94
+ //# sourceMappingURL=commandRunner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commandRunner.js","sourceRoot":"","sources":["../../../src/core/shell/commandRunner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export interface InstallCommandCache {
2
+ curlLine: string;
3
+ javaLine: string;
4
+ updatedAt: string;
5
+ }
6
+ export declare function shouldPersistInstallCommandCache(curlLine: string, javaLine: string): boolean;
7
+ export declare function clearInstallCommandCache(): Promise<void>;
8
+ export declare function loadInstallCommandCache(): Promise<InstallCommandCache | null>;
9
+ export declare function saveInstallCommandCache(curlLine: string, javaLine: string): Promise<void>;
@@ -0,0 +1,66 @@
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-install-command-cache.json");
6
+ }
7
+ function isPlaceholderValue(curlLine, javaLine) {
8
+ const combined = `${curlLine}\n${javaLine}`.toLowerCase();
9
+ const placeholderKeywords = [
10
+ "jenkins.example.com",
11
+ "example.com",
12
+ "<jenkins-host>",
13
+ "<secret>",
14
+ "http://<",
15
+ ];
16
+ return placeholderKeywords.some((keyword) => combined.includes(keyword));
17
+ }
18
+ export function shouldPersistInstallCommandCache(curlLine, javaLine) {
19
+ if (!curlLine.trim() || !javaLine.trim()) {
20
+ return false;
21
+ }
22
+ if (isPlaceholderValue(curlLine, javaLine)) {
23
+ return false;
24
+ }
25
+ return true;
26
+ }
27
+ export async function clearInstallCommandCache() {
28
+ const filePath = getCacheFilePath();
29
+ if (await fs.pathExists(filePath)) {
30
+ await fs.remove(filePath);
31
+ }
32
+ }
33
+ export async function loadInstallCommandCache() {
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.curlLine || !data.javaLine) {
41
+ await clearInstallCommandCache();
42
+ return null;
43
+ }
44
+ if (!shouldPersistInstallCommandCache(data.curlLine, data.javaLine)) {
45
+ await clearInstallCommandCache();
46
+ return null;
47
+ }
48
+ return {
49
+ curlLine: data.curlLine,
50
+ javaLine: data.javaLine,
51
+ updatedAt: data.updatedAt ?? "",
52
+ };
53
+ }
54
+ export async function saveInstallCommandCache(curlLine, javaLine) {
55
+ const filePath = getCacheFilePath();
56
+ await fs.ensureDir(path.dirname(filePath));
57
+ await fs.writeJson(filePath, {
58
+ curlLine,
59
+ javaLine,
60
+ updatedAt: new Date().toISOString(),
61
+ }, { spaces: 2 });
62
+ if (process.platform !== "win32") {
63
+ await fs.chmod(filePath, 0o600);
64
+ }
65
+ }
66
+ //# sourceMappingURL=installCommandCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installCommandCache.js","sourceRoot":"","sources":["../../../src/core/store/installCommandCache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { AgentProfile } from "../../types.js";
2
+ export declare function listProfiles(): Promise<AgentProfile[]>;
3
+ export declare function getProfile(profileId: string): Promise<AgentProfile | undefined>;
4
+ export declare function saveProfile(profile: Omit<AgentProfile, "id" | "createdAt">): Promise<AgentProfile>;
@@ -0,0 +1,43 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import fs from "fs-extra";
3
+ import path from "node:path";
4
+ import { getConfigDir } from "../platform.js";
5
+ function getProfilesFilePath() {
6
+ return path.join(getConfigDir(), "profiles.json");
7
+ }
8
+ async function ensureProfileFile() {
9
+ const filePath = getProfilesFilePath();
10
+ await fs.ensureDir(path.dirname(filePath));
11
+ if (!(await fs.pathExists(filePath))) {
12
+ const initial = { profiles: [] };
13
+ await fs.writeJson(filePath, initial, { spaces: 2 });
14
+ }
15
+ }
16
+ async function readProfileFile() {
17
+ await ensureProfileFile();
18
+ return await fs.readJson(getProfilesFilePath());
19
+ }
20
+ async function writeProfileFile(data) {
21
+ await ensureProfileFile();
22
+ await fs.writeJson(getProfilesFilePath(), data, { spaces: 2 });
23
+ }
24
+ export async function listProfiles() {
25
+ const data = await readProfileFile();
26
+ return data.profiles;
27
+ }
28
+ export async function getProfile(profileId) {
29
+ const data = await readProfileFile();
30
+ return data.profiles.find((item) => item.id === profileId);
31
+ }
32
+ export async function saveProfile(profile) {
33
+ const data = await readProfileFile();
34
+ const finalProfile = {
35
+ ...profile,
36
+ id: randomUUID(),
37
+ createdAt: new Date().toISOString(),
38
+ };
39
+ data.profiles.push(finalProfile);
40
+ await writeProfileFile(data);
41
+ return finalProfile;
42
+ }
43
+ //# sourceMappingURL=profileStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profileStore.js","sourceRoot":"","sources":["../../../src/core/store/profileStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAM9C,SAAS,mBAAmB;IAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,eAAe,CAAC,CAAC;AACpD,CAAC;AAED,KAAK,UAAU,iBAAiB;IAC9B,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;IACvC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC3C,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QACrC,MAAM,OAAO,GAAsB,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACpD,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IACvD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,eAAe;IAC5B,MAAM,iBAAiB,EAAE,CAAC;IAC1B,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,IAAuB;IACrD,MAAM,iBAAiB,EAAE,CAAC;IAC1B,MAAM,EAAE,CAAC,SAAS,CAAC,mBAAmB,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,IAAI,GAAG,MAAM,eAAe,EAAE,CAAC;IACrC,OAAO,IAAI,CAAC,QAAQ,CAAC;AACvB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,SAAiB;IAChD,MAAM,IAAI,GAAG,MAAM,eAAe,EAAE,CAAC;IACrC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA+C;IAC/E,MAAM,IAAI,GAAG,MAAM,eAAe,EAAE,CAAC;IACrC,MAAM,YAAY,GAAiB;QACjC,GAAG,OAAO;QACV,EAAE,EAAE,UAAU,EAAE;QAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACjC,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,YAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,41 @@
1
+ export type SupportedPlatform = "macos" | "windows" | "linux";
2
+ export type CheckStatus = "pass" | "fail" | "warn";
3
+ export interface CheckResult {
4
+ name: string;
5
+ status: CheckStatus;
6
+ detail: string;
7
+ hint?: string;
8
+ }
9
+ export interface NetworkTarget {
10
+ name: string;
11
+ host: string;
12
+ port: number;
13
+ timeoutMs?: number;
14
+ }
15
+ export interface ParsedAgentCommand {
16
+ mode: "url" | "jnlpUrl";
17
+ curlLine: string;
18
+ javaLine: string;
19
+ jarDownloadUrl: string;
20
+ jenkinsBaseUrl: string;
21
+ jnlpUrl?: string;
22
+ secret: string;
23
+ nodeName?: string;
24
+ workDir: string;
25
+ additionalArgs: string[];
26
+ }
27
+ export interface AgentProfile {
28
+ id: string;
29
+ createdAt: string;
30
+ platform: SupportedPlatform;
31
+ mode: "url" | "jnlpUrl";
32
+ jenkinsBaseUrl: string;
33
+ jenkinsSecret: string;
34
+ jnlpUrl?: string;
35
+ nodeName?: string;
36
+ workDir: string;
37
+ jarDownloadUrl: string;
38
+ additionalArgs: string[];
39
+ startupScriptPath: string;
40
+ serviceName?: string;
41
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import { CheckResult } from "../types.js";
2
+ export declare function CheckReport({ title, results }: {
3
+ title: string;
4
+ results: CheckResult[];
5
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ function icon(status) {
4
+ if (status === "pass") {
5
+ return "✓";
6
+ }
7
+ if (status === "warn") {
8
+ return "!";
9
+ }
10
+ return "✗";
11
+ }
12
+ function color(status) {
13
+ if (status === "pass") {
14
+ return "green";
15
+ }
16
+ if (status === "warn") {
17
+ return "yellow";
18
+ }
19
+ return "red";
20
+ }
21
+ export function CheckReport({ title, results }) {
22
+ return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, children: title }), results.map((item) => (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: color(item.status), children: [icon(item.status), " ", item.name] }), _jsxs(Text, { children: [" ", item.detail] }), item.hint ? _jsxs(Text, { color: "gray", children: [" \u5EFA\u8BAE: ", item.hint] }) : null] }, item.name)))] }));
23
+ }
24
+ //# sourceMappingURL=CheckReport.js.map