@bifos/nhncloud-cli 0.19.0 → 0.21.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/README.md +12 -5
- package/dist/index.js +1207 -297
- package/package.json +4 -3
- package/skills/nhncloud-cli/SKILL.md +1 -1
- package/skills/nhncloud-cli/references/common.md +128 -11
- package/skills/nhncloud-cli/references/skm.md +32 -0
- package/skills/nhncloud-cli/references/troubleshooting.md +3 -1
package/dist/index.js
CHANGED
|
@@ -333,6 +333,69 @@ async function warnLegacyDeployTargets() {
|
|
|
333
333
|
)
|
|
334
334
|
);
|
|
335
335
|
}
|
|
336
|
+
async function readJsonState(filePath) {
|
|
337
|
+
let raw;
|
|
338
|
+
try {
|
|
339
|
+
raw = await (0, import_promises.readFile)(filePath, "utf-8");
|
|
340
|
+
} catch (err) {
|
|
341
|
+
const code = err.code;
|
|
342
|
+
if (code === "ENOENT") return { state: "missing" };
|
|
343
|
+
return { state: "unreadable", reason: `\uD30C\uC77C\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4 (${code ?? "UNKNOWN"})` };
|
|
344
|
+
}
|
|
345
|
+
try {
|
|
346
|
+
return { state: "ok", parsed: JSON.parse(raw) };
|
|
347
|
+
} catch {
|
|
348
|
+
return { state: "invalid", reason: "JSON \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4" };
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
async function inspectPermissions(filePath) {
|
|
352
|
+
try {
|
|
353
|
+
const { mode } = await (0, import_promises.stat)(filePath);
|
|
354
|
+
if (process.platform === "win32") return "unknown";
|
|
355
|
+
return (mode & 63) === 0 ? "ok" : "too-open";
|
|
356
|
+
} catch {
|
|
357
|
+
return void 0;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function summarizeProfile(name, value) {
|
|
361
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
362
|
+
return { name, environment: "invalid", blocks: [] };
|
|
363
|
+
}
|
|
364
|
+
const profile = value;
|
|
365
|
+
const env = profile["environment"];
|
|
366
|
+
const environment = env === void 0 ? "real" : env === "gov" ? "gov" : "invalid";
|
|
367
|
+
const blocks = Object.keys(profile).filter((key) => key !== "environment").sort();
|
|
368
|
+
return { name, environment, blocks };
|
|
369
|
+
}
|
|
370
|
+
async function inspectCredentialsFile() {
|
|
371
|
+
const result = await readJsonState(CREDENTIALS_PATH);
|
|
372
|
+
const permissions = result.state === "missing" ? void 0 : await inspectPermissions(CREDENTIALS_PATH);
|
|
373
|
+
const base = { path: CREDENTIALS_PATH, ...permissions ? { permissions } : {}, profiles: [] };
|
|
374
|
+
if (result.state !== "ok") {
|
|
375
|
+
return { ...base, state: result.state, ...result.reason ? { reason: result.reason } : {} };
|
|
376
|
+
}
|
|
377
|
+
if (!isCredentials(result.parsed)) {
|
|
378
|
+
return { ...base, state: "invalid", reason: "version: 1 \uACFC profiles \uD544\uB4DC\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4" };
|
|
379
|
+
}
|
|
380
|
+
const profiles = Object.entries(result.parsed.profiles).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([name, value]) => summarizeProfile(name, value));
|
|
381
|
+
return { ...base, state: "ok", profiles };
|
|
382
|
+
}
|
|
383
|
+
async function inspectConfigFile() {
|
|
384
|
+
const result = await readJsonState(CONFIG_PATH);
|
|
385
|
+
const base = { path: CONFIG_PATH, defaultProfile: null };
|
|
386
|
+
if (result.state !== "ok") {
|
|
387
|
+
return { ...base, state: result.state, ...result.reason ? { reason: result.reason } : {} };
|
|
388
|
+
}
|
|
389
|
+
if (!isConfig(result.parsed)) {
|
|
390
|
+
return { ...base, state: "invalid", reason: "version: 1 \uC774 \uD544\uC694\uD569\uB2C8\uB2E4" };
|
|
391
|
+
}
|
|
392
|
+
const defaultProfile = result.parsed.defaultProfile;
|
|
393
|
+
return {
|
|
394
|
+
...base,
|
|
395
|
+
state: "ok",
|
|
396
|
+
defaultProfile: typeof defaultProfile === "string" && defaultProfile !== "" ? defaultProfile : null
|
|
397
|
+
};
|
|
398
|
+
}
|
|
336
399
|
|
|
337
400
|
// src/utils/terminal.ts
|
|
338
401
|
function sanitizeForTerminal(value) {
|
|
@@ -357,6 +420,71 @@ function getRequestTimeoutMs() {
|
|
|
357
420
|
return DEFAULT_TIMEOUT_MS;
|
|
358
421
|
}
|
|
359
422
|
|
|
423
|
+
// src/api/proxy.ts
|
|
424
|
+
function nonEmpty(value) {
|
|
425
|
+
return value === void 0 || value === "" ? void 0 : value;
|
|
426
|
+
}
|
|
427
|
+
function readEnvPair(env, lower, upper) {
|
|
428
|
+
const lowerValue = nonEmpty(env[lower]);
|
|
429
|
+
if (lowerValue !== void 0) {
|
|
430
|
+
return { source: lower, value: lowerValue };
|
|
431
|
+
}
|
|
432
|
+
const upperValue = nonEmpty(env[upper]);
|
|
433
|
+
if (upperValue !== void 0) {
|
|
434
|
+
return { source: upper, value: upperValue };
|
|
435
|
+
}
|
|
436
|
+
return void 0;
|
|
437
|
+
}
|
|
438
|
+
function validateProxyUrl({ source, value }) {
|
|
439
|
+
let protocol;
|
|
440
|
+
try {
|
|
441
|
+
protocol = new URL(value).protocol;
|
|
442
|
+
} catch {
|
|
443
|
+
protocol = void 0;
|
|
444
|
+
}
|
|
445
|
+
if (protocol !== "http:" && protocol !== "https:") {
|
|
446
|
+
throw new NhnCloudCliError(
|
|
447
|
+
`${source} \uAC12\uC774 \uD504\uB85D\uC2DC URL \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4. http:// \uB610\uB294 https:// \uB85C \uC2DC\uC791\uD558\uB294 URL \uC744 \uC9C0\uC815\uD558\uC138\uC694.`,
|
|
448
|
+
EXIT_PARAM_ERROR
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
return value;
|
|
452
|
+
}
|
|
453
|
+
function resolveProxySettings(option, env) {
|
|
454
|
+
const noProxy = readEnvPair(env, "no_proxy", "NO_PROXY")?.value;
|
|
455
|
+
const optionValue = nonEmpty(option);
|
|
456
|
+
let settings;
|
|
457
|
+
if (optionValue !== void 0) {
|
|
458
|
+
const proxy = validateProxyUrl({ source: "--proxy", value: optionValue });
|
|
459
|
+
settings = { httpProxy: proxy, httpsProxy: proxy };
|
|
460
|
+
} else {
|
|
461
|
+
const https = readEnvPair(env, "https_proxy", "HTTPS_PROXY");
|
|
462
|
+
const http = readEnvPair(env, "http_proxy", "HTTP_PROXY");
|
|
463
|
+
if (https === void 0 && http === void 0) {
|
|
464
|
+
return void 0;
|
|
465
|
+
}
|
|
466
|
+
settings = {};
|
|
467
|
+
if (https !== void 0) {
|
|
468
|
+
settings.httpsProxy = validateProxyUrl(https);
|
|
469
|
+
}
|
|
470
|
+
if (http !== void 0) {
|
|
471
|
+
settings.httpProxy = validateProxyUrl(http);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (noProxy !== void 0) {
|
|
475
|
+
settings.noProxy = noProxy;
|
|
476
|
+
}
|
|
477
|
+
return settings;
|
|
478
|
+
}
|
|
479
|
+
async function installProxy(settings) {
|
|
480
|
+
const { EnvHttpProxyAgent, setGlobalDispatcher } = await import("undici");
|
|
481
|
+
const options = {};
|
|
482
|
+
if (settings.httpProxy !== void 0) options.httpProxy = settings.httpProxy;
|
|
483
|
+
if (settings.httpsProxy !== void 0) options.httpsProxy = settings.httpsProxy;
|
|
484
|
+
if (settings.noProxy !== void 0) options.noProxy = settings.noProxy;
|
|
485
|
+
setGlobalDispatcher(new EnvHttpProxyAgent(options));
|
|
486
|
+
}
|
|
487
|
+
|
|
360
488
|
// src/commands/parse-options.ts
|
|
361
489
|
var POSITIVE_INTEGER_PATTERN = /^[1-9]\d*$/;
|
|
362
490
|
var NON_NEGATIVE_INTEGER_PATTERN = /^(0|[1-9]\d*)$/;
|
|
@@ -400,14 +528,97 @@ function parseNonNegativeIntegerOption(value, flag) {
|
|
|
400
528
|
|
|
401
529
|
// src/commands/commander-errors.ts
|
|
402
530
|
var import_commander = require("commander");
|
|
403
|
-
|
|
531
|
+
|
|
532
|
+
// src/commands/unknown-option-hint.ts
|
|
533
|
+
function normalizeName(name) {
|
|
534
|
+
return name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
535
|
+
}
|
|
536
|
+
function parseUnknownOptionName(message) {
|
|
537
|
+
return /unknown option '--([^'=]+)/.exec(message)?.[1];
|
|
538
|
+
}
|
|
539
|
+
function findReferencedArgument(optionName, commandPath2, argumentNames) {
|
|
540
|
+
const option = normalizeName(optionName);
|
|
541
|
+
const normalized = argumentNames.map(normalizeName);
|
|
542
|
+
const exact = normalized.indexOf(option);
|
|
543
|
+
if (exact !== -1) {
|
|
544
|
+
return argumentNames[exact];
|
|
545
|
+
}
|
|
546
|
+
const prefixed = argumentNames.filter((_, i) => normalized[i].startsWith(`${option}-`));
|
|
547
|
+
const candidates = new Set(prefixed.length === 1 ? prefixed : []);
|
|
548
|
+
const segments = commandPath2.slice(1).map(normalizeName);
|
|
549
|
+
argumentNames.forEach((name, i) => {
|
|
550
|
+
const otherArguments = normalized.filter((_, j) => j !== i);
|
|
551
|
+
const matched = segments.some(
|
|
552
|
+
(segment) => !otherArguments.includes(segment) && option === `${segment}-${normalized[i]}`
|
|
553
|
+
);
|
|
554
|
+
if (matched) {
|
|
555
|
+
candidates.add(name);
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
return candidates.size === 1 ? [...candidates][0] : void 0;
|
|
559
|
+
}
|
|
560
|
+
function formatArgument(argument) {
|
|
561
|
+
const name = argument.variadic ? `${argument.name}...` : argument.name;
|
|
562
|
+
return argument.required ? `<${name}>` : `[${name}]`;
|
|
563
|
+
}
|
|
564
|
+
function buildUnknownOptionHint(input) {
|
|
565
|
+
if (input.message.includes("(Did you mean")) {
|
|
566
|
+
return "";
|
|
567
|
+
}
|
|
568
|
+
const optionName = parseUnknownOptionName(input.message);
|
|
569
|
+
if (optionName === void 0) {
|
|
570
|
+
return "";
|
|
571
|
+
}
|
|
572
|
+
const referenced = findReferencedArgument(
|
|
573
|
+
optionName,
|
|
574
|
+
input.commandPath,
|
|
575
|
+
input.arguments.map((argument2) => argument2.name)
|
|
576
|
+
);
|
|
577
|
+
const argument = input.arguments.find((candidate) => candidate.name === referenced);
|
|
578
|
+
if (argument === void 0) {
|
|
579
|
+
return "";
|
|
580
|
+
}
|
|
581
|
+
return `\uC548\uB0B4: --${optionName} \uB294 \uC635\uC158\uC774 \uC544\uB2D9\uB2C8\uB2E4. \uC704\uCE58 \uC778\uC218 ${formatArgument(argument)} \uB85C \uC804\uB2EC\uD558\uC138\uC694.
|
|
582
|
+
\uC0AC\uC6A9\uBC95: ${input.commandPath.join(" ")} ${input.usage}
|
|
583
|
+
`;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// src/commands/commander-errors.ts
|
|
587
|
+
function writeUnknownOptionHint(command, error) {
|
|
588
|
+
const commandPath2 = [];
|
|
589
|
+
for (let current2 = command; current2 !== null; current2 = current2.parent) {
|
|
590
|
+
commandPath2.unshift(current2.name());
|
|
591
|
+
}
|
|
592
|
+
const hint = buildUnknownOptionHint({
|
|
593
|
+
message: error.message,
|
|
594
|
+
commandPath: commandPath2,
|
|
595
|
+
usage: command.usage(),
|
|
596
|
+
arguments: command.registeredArguments.map((argument) => ({
|
|
597
|
+
name: argument.name(),
|
|
598
|
+
required: argument.required,
|
|
599
|
+
variadic: argument.variadic
|
|
600
|
+
}))
|
|
601
|
+
});
|
|
602
|
+
if (hint === "") {
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
const writeErr = command.configureOutput().writeErr;
|
|
606
|
+
if (writeErr) {
|
|
607
|
+
writeErr(hint);
|
|
608
|
+
} else {
|
|
609
|
+
process.stderr.write(hint);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
function handleCommanderError(command, error) {
|
|
404
613
|
if (error.code === "commander.missingMandatoryOptionValue") {
|
|
405
614
|
error.exitCode = EXIT_PARAM_ERROR;
|
|
615
|
+
} else if (error.code === "commander.unknownOption") {
|
|
616
|
+
writeUnknownOptionHint(command, error);
|
|
406
617
|
}
|
|
407
618
|
throw error;
|
|
408
619
|
}
|
|
409
620
|
function configureCommanderExitCodes(root) {
|
|
410
|
-
root.exitOverride(
|
|
621
|
+
root.exitOverride((error) => handleCommanderError(root, error));
|
|
411
622
|
for (const command of root.commands) {
|
|
412
623
|
configureCommanderExitCodes(command);
|
|
413
624
|
}
|
|
@@ -422,7 +633,7 @@ function configureGlobalOptionsHelp(root) {
|
|
|
422
633
|
}
|
|
423
634
|
|
|
424
635
|
// src/version.ts
|
|
425
|
-
var CLI_VERSION = true ? "0.
|
|
636
|
+
var CLI_VERSION = true ? "0.21.0" : "0.0.0-dev";
|
|
426
637
|
|
|
427
638
|
// src/commands/configure.ts
|
|
428
639
|
var import_commander2 = require("commander");
|
|
@@ -555,6 +766,13 @@ function toNhnCloudCliError(err) {
|
|
|
555
766
|
);
|
|
556
767
|
}
|
|
557
768
|
if (err instanceof Error) {
|
|
769
|
+
const cause = err.cause;
|
|
770
|
+
if (cause instanceof Error && cause.message !== "" && cause.message !== err.message) {
|
|
771
|
+
return new NhnCloudCliError(
|
|
772
|
+
`${err.message} (${sanitizeForTerminal(cause.message)})`,
|
|
773
|
+
EXIT_API_ERROR
|
|
774
|
+
);
|
|
775
|
+
}
|
|
558
776
|
return new NhnCloudCliError(err.message, EXIT_API_ERROR);
|
|
559
777
|
}
|
|
560
778
|
return new NhnCloudCliError(String(err), EXIT_API_ERROR);
|
|
@@ -2523,14 +2741,14 @@ function compareByCodePoint(left, right) {
|
|
|
2523
2741
|
return leftPoints.length - rightPoints.length;
|
|
2524
2742
|
}
|
|
2525
2743
|
function ensureRegularFile(filePath) {
|
|
2526
|
-
let
|
|
2744
|
+
let stat4;
|
|
2527
2745
|
try {
|
|
2528
|
-
|
|
2746
|
+
stat4 = (0, import_node_fs2.lstatSync)(filePath);
|
|
2529
2747
|
} catch (error) {
|
|
2530
2748
|
const reason = error instanceof Error ? error.message : String(error);
|
|
2531
2749
|
throw new NhnCloudCliError(`\uC2A4\uD0AC \uD30C\uC77C\uC744 \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${filePath} (${reason})`, EXIT_PARAM_ERROR);
|
|
2532
2750
|
}
|
|
2533
|
-
if (
|
|
2751
|
+
if (stat4.isSymbolicLink() || !stat4.isFile()) {
|
|
2534
2752
|
throw new NhnCloudCliError(`\uC2A4\uD0AC \uCF58\uD150\uCE20\uB294 \uC815\uADDC \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4: ${filePath}`, EXIT_PARAM_ERROR);
|
|
2535
2753
|
}
|
|
2536
2754
|
}
|
|
@@ -2547,21 +2765,21 @@ function collectReferenceFiles(referencesRoot, currentDir, files) {
|
|
|
2547
2765
|
}
|
|
2548
2766
|
for (const entry of entries) {
|
|
2549
2767
|
const entryPath = import_node_path4.default.join(currentDir, entry.name);
|
|
2550
|
-
let
|
|
2768
|
+
let stat4;
|
|
2551
2769
|
try {
|
|
2552
|
-
|
|
2770
|
+
stat4 = (0, import_node_fs2.lstatSync)(entryPath);
|
|
2553
2771
|
} catch (error) {
|
|
2554
2772
|
const reason = error instanceof Error ? error.message : String(error);
|
|
2555
2773
|
throw new NhnCloudCliError(`\uC2A4\uD0AC \uCF58\uD150\uCE20\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${entryPath} (${reason})`, EXIT_PARAM_ERROR);
|
|
2556
2774
|
}
|
|
2557
|
-
if (
|
|
2775
|
+
if (stat4.isSymbolicLink()) {
|
|
2558
2776
|
throw new NhnCloudCliError(`\uC2A4\uD0AC \uCF58\uD150\uCE20\uC5D0 \uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${entryPath}`, EXIT_PARAM_ERROR);
|
|
2559
2777
|
}
|
|
2560
|
-
if (
|
|
2778
|
+
if (stat4.isDirectory()) {
|
|
2561
2779
|
collectReferenceFiles(referencesRoot, entryPath, files);
|
|
2562
2780
|
continue;
|
|
2563
2781
|
}
|
|
2564
|
-
if (!
|
|
2782
|
+
if (!stat4.isFile()) {
|
|
2565
2783
|
throw new NhnCloudCliError(`\uC2A4\uD0AC \uCF58\uD150\uCE20\uB294 \uC815\uADDC \uD30C\uC77C \uB610\uB294 \uB514\uB809\uD130\uB9AC\uC5EC\uC57C \uD569\uB2C8\uB2E4: ${entryPath}`, EXIT_PARAM_ERROR);
|
|
2566
2784
|
}
|
|
2567
2785
|
files.push(`references/${import_node_path4.default.relative(referencesRoot, entryPath).split(import_node_path4.default.sep).join("/")}`);
|
|
@@ -2609,12 +2827,24 @@ function calculateSkillContentDigest(skillRoot) {
|
|
|
2609
2827
|
var PACKAGE_NAME3 = "@bifos/nhncloud-cli";
|
|
2610
2828
|
var SKILL_NAME2 = "nhncloud-cli";
|
|
2611
2829
|
var DIGEST_HEX_PATTERN = /^[0-9a-f]{64}$/;
|
|
2612
|
-
var
|
|
2830
|
+
var SKILL_AGENTS = ["claude", "codex"];
|
|
2831
|
+
var SKILL_AGENT_NAMES = { claude: "Claude Code", codex: "Codex" };
|
|
2832
|
+
var STATUS_PRIORITY = [
|
|
2833
|
+
"corrupt",
|
|
2834
|
+
"modified",
|
|
2835
|
+
"unmanaged",
|
|
2836
|
+
"broken",
|
|
2837
|
+
"outdated",
|
|
2838
|
+
"missing",
|
|
2839
|
+
"current"
|
|
2840
|
+
];
|
|
2841
|
+
var PROTECTED_STATUSES = ["unmanaged", "modified", "corrupt"];
|
|
2842
|
+
var defaultOperations = { rename: import_promises3.rename, rm: import_promises3.rm };
|
|
2613
2843
|
function sourcePath(context) {
|
|
2614
2844
|
return import_node_path5.default.join(context.packageRoot, "skills", SKILL_NAME2);
|
|
2615
2845
|
}
|
|
2616
|
-
function destinationPath(context) {
|
|
2617
|
-
return import_node_path5.default.join(context.homeDir, ".claude", "skills", SKILL_NAME2);
|
|
2846
|
+
function destinationPath(context, agent) {
|
|
2847
|
+
return agent === "claude" ? import_node_path5.default.join(context.homeDir, ".claude", "skills", SKILL_NAME2) : import_node_path5.default.join(context.homeDir, ".agents", "skills", SKILL_NAME2);
|
|
2618
2848
|
}
|
|
2619
2849
|
function resolveLinkTarget(linkPath, rawTarget) {
|
|
2620
2850
|
return import_node_path5.default.isAbsolute(rawTarget) ? import_node_path5.default.normalize(rawTarget) : import_node_path5.default.resolve(import_node_path5.default.dirname(linkPath), rawTarget);
|
|
@@ -2725,16 +2955,74 @@ async function inspectRepository(targetPath, expected) {
|
|
|
2725
2955
|
}
|
|
2726
2956
|
return { status: "valid", installedVersion: manifest.packageVersion };
|
|
2727
2957
|
}
|
|
2728
|
-
function statusBase(context) {
|
|
2958
|
+
function statusBase(context, agent) {
|
|
2729
2959
|
return {
|
|
2730
2960
|
schemaVersion: 1,
|
|
2731
|
-
destination: destinationPath(context),
|
|
2961
|
+
destination: destinationPath(context, agent),
|
|
2732
2962
|
source: sourcePath(context),
|
|
2733
2963
|
currentVersion: context.currentVersion
|
|
2734
2964
|
};
|
|
2735
2965
|
}
|
|
2736
|
-
async function
|
|
2737
|
-
const
|
|
2966
|
+
async function managedRepositoryStatus(context, base, linkTarget, repositoryLocation, isExpectedPath) {
|
|
2967
|
+
const repositoryName = parseRepositoryName(repositoryLocation);
|
|
2968
|
+
if (!repositoryName) {
|
|
2969
|
+
return { ...base, status: "corrupt", linkTarget, managed: true };
|
|
2970
|
+
}
|
|
2971
|
+
const repository = await inspectRepository(repositoryLocation, repositoryName);
|
|
2972
|
+
if (repository.status === "modified" || repository.status === "corrupt") {
|
|
2973
|
+
return {
|
|
2974
|
+
...base,
|
|
2975
|
+
status: repository.status,
|
|
2976
|
+
installedVersion: repository.installedVersion ?? repositoryName.version,
|
|
2977
|
+
linkTarget,
|
|
2978
|
+
managed: true
|
|
2979
|
+
};
|
|
2980
|
+
}
|
|
2981
|
+
if (repository.status === "missing") {
|
|
2982
|
+
return {
|
|
2983
|
+
...base,
|
|
2984
|
+
status: "broken",
|
|
2985
|
+
installedVersion: repositoryName.version,
|
|
2986
|
+
linkTarget,
|
|
2987
|
+
managed: true
|
|
2988
|
+
};
|
|
2989
|
+
}
|
|
2990
|
+
const currentDigest = calculateSkillContentDigest(base.source);
|
|
2991
|
+
const isCurrent = repositoryName.version === context.currentVersion && repositoryName.digest === currentDigest && await isExpectedPath(repositoryPath(context, currentDigest));
|
|
2992
|
+
return {
|
|
2993
|
+
...base,
|
|
2994
|
+
status: isCurrent ? "current" : "outdated",
|
|
2995
|
+
installedVersion: repository.installedVersion,
|
|
2996
|
+
linkTarget,
|
|
2997
|
+
managed: true
|
|
2998
|
+
};
|
|
2999
|
+
}
|
|
3000
|
+
async function optionalRealpath(targetPath) {
|
|
3001
|
+
try {
|
|
3002
|
+
return await (0, import_promises3.realpath)(targetPath);
|
|
3003
|
+
} catch (error) {
|
|
3004
|
+
if (isNodeError(error, "ENOENT")) {
|
|
3005
|
+
return void 0;
|
|
3006
|
+
}
|
|
3007
|
+
throw managerError(`\uC2A4\uD0AC \uACBD\uB85C\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${targetPath}`, error);
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
async function inspectIndirectManagedLink(context, base, linkTarget) {
|
|
3011
|
+
const realRoot = await optionalRealpath(repositoryRoot(context));
|
|
3012
|
+
if (!realRoot) {
|
|
3013
|
+
return void 0;
|
|
3014
|
+
}
|
|
3015
|
+
const realTarget = await optionalRealpath(linkTarget);
|
|
3016
|
+
if (!realTarget || import_node_path5.default.dirname(realTarget) !== realRoot) {
|
|
3017
|
+
return void 0;
|
|
3018
|
+
}
|
|
3019
|
+
return managedRepositoryStatus(context, base, linkTarget, realTarget, async (expectedPath) => {
|
|
3020
|
+
const realExpected = await optionalRealpath(expectedPath);
|
|
3021
|
+
return realExpected !== void 0 && realExpected === realTarget;
|
|
3022
|
+
});
|
|
3023
|
+
}
|
|
3024
|
+
async function inspectAgentSkill(context, agent) {
|
|
3025
|
+
const base = statusBase(context, agent);
|
|
2738
3026
|
const destinationStat = await optionalLstat(base.destination);
|
|
2739
3027
|
if (!destinationStat) {
|
|
2740
3028
|
return { ...base, status: "missing", managed: false };
|
|
@@ -2767,38 +3055,17 @@ async function inspectSkill(context) {
|
|
|
2767
3055
|
};
|
|
2768
3056
|
}
|
|
2769
3057
|
if (isManagedRepositoryLocation(context, linkTarget)) {
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
const repository = await inspectRepository(linkTarget, repositoryName);
|
|
2774
|
-
if (repository.status === "modified" || repository.status === "corrupt") {
|
|
2775
|
-
return {
|
|
2776
|
-
...base,
|
|
2777
|
-
status: repository.status,
|
|
2778
|
-
installedVersion: repository.installedVersion ?? repositoryName.version,
|
|
2779
|
-
linkTarget,
|
|
2780
|
-
managed: true
|
|
2781
|
-
};
|
|
2782
|
-
}
|
|
2783
|
-
if (repository.status === "missing") {
|
|
2784
|
-
return {
|
|
2785
|
-
...base,
|
|
2786
|
-
status: "broken",
|
|
2787
|
-
installedVersion: repositoryName.version,
|
|
2788
|
-
linkTarget,
|
|
2789
|
-
managed: true
|
|
2790
|
-
};
|
|
2791
|
-
}
|
|
2792
|
-
const currentDigest = calculateSkillContentDigest(base.source);
|
|
2793
|
-
const expectedPath = repositoryPath(context, currentDigest);
|
|
2794
|
-
const isCurrent = repositoryName.version === context.currentVersion && repositoryName.digest === currentDigest && import_node_path5.default.resolve(linkTarget) === import_node_path5.default.resolve(expectedPath);
|
|
2795
|
-
return {
|
|
2796
|
-
...base,
|
|
2797
|
-
status: isCurrent ? "current" : "outdated",
|
|
2798
|
-
installedVersion: repository.installedVersion,
|
|
3058
|
+
return managedRepositoryStatus(
|
|
3059
|
+
context,
|
|
3060
|
+
base,
|
|
2799
3061
|
linkTarget,
|
|
2800
|
-
|
|
2801
|
-
|
|
3062
|
+
linkTarget,
|
|
3063
|
+
async (expectedPath) => import_node_path5.default.resolve(linkTarget) === import_node_path5.default.resolve(expectedPath)
|
|
3064
|
+
);
|
|
3065
|
+
}
|
|
3066
|
+
const indirect = await inspectIndirectManagedLink(context, base, linkTarget);
|
|
3067
|
+
if (indirect) {
|
|
3068
|
+
return indirect;
|
|
2802
3069
|
}
|
|
2803
3070
|
const legacyPackage = targetStat.isDirectory() ? await readLegacyPackageMetadata(linkTarget) : void 0;
|
|
2804
3071
|
if (legacyPackage) {
|
|
@@ -2812,6 +3079,14 @@ async function inspectSkill(context) {
|
|
|
2812
3079
|
}
|
|
2813
3080
|
return { ...base, status: "unmanaged", linkTarget, managed: false };
|
|
2814
3081
|
}
|
|
3082
|
+
function aggregateStatus(statuses) {
|
|
3083
|
+
return STATUS_PRIORITY.find((token) => statuses.some((status) => status.status === token)) ?? "current";
|
|
3084
|
+
}
|
|
3085
|
+
async function inspectSkill(context) {
|
|
3086
|
+
const claude = await inspectAgentSkill(context, "claude");
|
|
3087
|
+
const codex = await inspectAgentSkill(context, "codex");
|
|
3088
|
+
return { ...claude, status: aggregateStatus([claude, codex]), agents: { claude, codex } };
|
|
3089
|
+
}
|
|
2815
3090
|
function utcBackupSuffix() {
|
|
2816
3091
|
return `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}-${(0, import_node_crypto3.randomUUID)()}`;
|
|
2817
3092
|
}
|
|
@@ -2908,35 +3183,123 @@ async function prepareRepository(context, force, operations) {
|
|
|
2908
3183
|
await (0, import_promises3.rm)(staging, { recursive: true, force: true });
|
|
2909
3184
|
}
|
|
2910
3185
|
}
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
const
|
|
2916
|
-
const
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
3186
|
+
function temporaryLinkPath(destination) {
|
|
3187
|
+
return import_node_path5.default.join(import_node_path5.default.dirname(destination), `.${SKILL_NAME2}.link-${(0, import_node_crypto3.randomUUID)()}`);
|
|
3188
|
+
}
|
|
3189
|
+
async function planLinkSwitches(context, previous) {
|
|
3190
|
+
const switches = [];
|
|
3191
|
+
for (const agent of SKILL_AGENTS) {
|
|
3192
|
+
const agentStatus = previous.agents[agent];
|
|
3193
|
+
if (agentStatus.status === "current") {
|
|
3194
|
+
continue;
|
|
3195
|
+
}
|
|
3196
|
+
const destination = destinationPath(context, agent);
|
|
3197
|
+
const parent = import_node_path5.default.dirname(destination);
|
|
3198
|
+
await (0, import_promises3.mkdir)(parent, { recursive: true });
|
|
3199
|
+
const resolvedDestination = import_node_path5.default.join(await (0, import_promises3.realpath)(parent), import_node_path5.default.basename(destination));
|
|
3200
|
+
const sameTarget = switches.find((entry) => entry.resolvedDestination === resolvedDestination);
|
|
3201
|
+
if (sameTarget) {
|
|
3202
|
+
sameTarget.agents.push(agent);
|
|
3203
|
+
continue;
|
|
3204
|
+
}
|
|
3205
|
+
let previousRawTarget;
|
|
3206
|
+
if (agentStatus.status !== "missing" && agentStatus.status !== "unmanaged") {
|
|
2925
3207
|
try {
|
|
2926
|
-
await
|
|
3208
|
+
previousRawTarget = await (0, import_promises3.readlink)(destination);
|
|
2927
3209
|
} catch (error) {
|
|
2928
|
-
|
|
3210
|
+
throw managerError(`\uC2A4\uD0AC \uB9C1\uD06C\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${destination}`, error);
|
|
2929
3211
|
}
|
|
2930
|
-
return backupPaths;
|
|
2931
3212
|
}
|
|
3213
|
+
switches.push({
|
|
3214
|
+
agents: [agent],
|
|
3215
|
+
destination,
|
|
3216
|
+
resolvedDestination,
|
|
3217
|
+
previous: agentStatus,
|
|
3218
|
+
previousRawTarget,
|
|
3219
|
+
temporaryLink: temporaryLinkPath(destination),
|
|
3220
|
+
activated: false
|
|
3221
|
+
});
|
|
3222
|
+
}
|
|
3223
|
+
return switches;
|
|
3224
|
+
}
|
|
3225
|
+
async function rollbackLinkSwitches(switches, operations, temporaryLinks) {
|
|
3226
|
+
const failed = [];
|
|
3227
|
+
const preservedBackups = [];
|
|
3228
|
+
const removeEntry = operations.rm ?? defaultOperations.rm;
|
|
3229
|
+
let firstError;
|
|
3230
|
+
for (const entry of [...switches].reverse()) {
|
|
3231
|
+
try {
|
|
3232
|
+
if (entry.activated && entry.backup) {
|
|
3233
|
+
await removeEntry(entry.destination, { force: true });
|
|
3234
|
+
await operations.rename(entry.backup, entry.destination);
|
|
3235
|
+
} else if (entry.activated && entry.previousRawTarget !== void 0) {
|
|
3236
|
+
const restoreLink = temporaryLinkPath(entry.destination);
|
|
3237
|
+
temporaryLinks.push(restoreLink);
|
|
3238
|
+
await (0, import_promises3.symlink)(entry.previousRawTarget, restoreLink);
|
|
3239
|
+
await operations.rename(restoreLink, entry.destination);
|
|
3240
|
+
} else if (entry.activated && entry.previous.status === "missing") {
|
|
3241
|
+
await removeEntry(entry.destination, { force: true });
|
|
3242
|
+
} else if (!entry.activated && entry.backup) {
|
|
3243
|
+
await operations.rename(entry.backup, entry.destination);
|
|
3244
|
+
}
|
|
3245
|
+
} catch (error) {
|
|
3246
|
+
failed.push(entry.destination);
|
|
3247
|
+
if (entry.backup) {
|
|
3248
|
+
preservedBackups.push(entry.backup);
|
|
3249
|
+
}
|
|
3250
|
+
firstError ??= error;
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
return { failed, preservedBackups, firstError };
|
|
3254
|
+
}
|
|
3255
|
+
async function switchActiveLinks(context, repository, previous, operations) {
|
|
3256
|
+
const switches = await planLinkSwitches(context, previous);
|
|
3257
|
+
const temporaryLinks = switches.map((entry) => entry.temporaryLink);
|
|
3258
|
+
const backupPaths = [];
|
|
3259
|
+
try {
|
|
3260
|
+
let failure;
|
|
3261
|
+
let failedAfterVerification = false;
|
|
2932
3262
|
try {
|
|
2933
|
-
|
|
3263
|
+
for (const entry of switches) {
|
|
3264
|
+
await (0, import_promises3.symlink)(repository, entry.temporaryLink);
|
|
3265
|
+
}
|
|
3266
|
+
for (const entry of switches) {
|
|
3267
|
+
if (entry.previous.status === "unmanaged") {
|
|
3268
|
+
entry.backup = await backupPath(entry.destination, operations);
|
|
3269
|
+
backupPaths.push(entry.backup);
|
|
3270
|
+
}
|
|
3271
|
+
await operations.rename(entry.temporaryLink, entry.destination);
|
|
3272
|
+
entry.activated = true;
|
|
3273
|
+
}
|
|
3274
|
+
const status = await inspectSkill(context);
|
|
3275
|
+
if (status.status === "current") {
|
|
3276
|
+
return { backupPaths, status };
|
|
3277
|
+
}
|
|
3278
|
+
failure = managerError(`\uC2A4\uD0AC \uC124\uCE58 \uD6C4 \uC0C1\uD0DC\uAC00 current\uAC00 \uC544\uB2D9\uB2C8\uB2E4: ${status.status}`);
|
|
3279
|
+
failedAfterVerification = true;
|
|
2934
3280
|
} catch (error) {
|
|
2935
|
-
|
|
3281
|
+
failure = error;
|
|
3282
|
+
}
|
|
3283
|
+
const rollback = await rollbackLinkSwitches(switches, operations, temporaryLinks);
|
|
3284
|
+
if (rollback.failed.length > 0) {
|
|
3285
|
+
throw managerError(
|
|
3286
|
+
`\uC2A4\uD0AC \uC804\uD658\uC5D0 \uC2E4\uD328\uD588\uACE0 \uC77C\uBD80 \uACBD\uB85C\uB97C \uB418\uB3CC\uB9AC\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${rollback.failed.join(", ")}; \uBCF4\uC874\uD55C \uBC31\uC5C5: ${rollback.preservedBackups.join(", ") || "\uC5C6\uC74C"}; \uC804\uD658 \uC624\uB958: ${toReason(failure)}`,
|
|
3287
|
+
rollback.firstError
|
|
3288
|
+
);
|
|
3289
|
+
}
|
|
3290
|
+
if (failedAfterVerification) {
|
|
3291
|
+
throw failure;
|
|
2936
3292
|
}
|
|
2937
|
-
|
|
3293
|
+
const changed = switches.filter((entry) => entry.activated || entry.backup !== void 0);
|
|
3294
|
+
if (changed.length === 0) {
|
|
3295
|
+
throw managerError("\uC2A4\uD0AC \uC804\uD658\uC744 \uC2DC\uC791\uD558\uC9C0 \uBABB\uD574 \uC5B4\uB5A4 \uACBD\uB85C\uB3C4 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4", failure);
|
|
3296
|
+
}
|
|
3297
|
+
throw managerError(
|
|
3298
|
+
`\uC2A4\uD0AC \uC804\uD658\uC5D0 \uC2E4\uD328\uD574 \uBC14\uAFBC \uACBD\uB85C\uB97C \uC774\uC804 \uC0C1\uD0DC\uB85C \uB418\uB3CC\uB838\uC2B5\uB2C8\uB2E4: ${changed.map((entry) => entry.destination).join(", ")}`,
|
|
3299
|
+
failure
|
|
3300
|
+
);
|
|
2938
3301
|
} finally {
|
|
2939
|
-
await (0, import_promises3.rm)(
|
|
3302
|
+
await Promise.all(temporaryLinks.map((link) => (0, import_promises3.rm)(link, { force: true })));
|
|
2940
3303
|
}
|
|
2941
3304
|
}
|
|
2942
3305
|
function installAction(status) {
|
|
@@ -2971,23 +3334,26 @@ async function installSkillInternal(context, options = {}, operations = defaultO
|
|
|
2971
3334
|
backupPaths: []
|
|
2972
3335
|
};
|
|
2973
3336
|
}
|
|
2974
|
-
if (
|
|
2975
|
-
|
|
3337
|
+
if (!force) {
|
|
3338
|
+
for (const agent of SKILL_AGENTS) {
|
|
3339
|
+
const agentStatus = previousStatus.agents[agent];
|
|
3340
|
+
if (PROTECTED_STATUSES.includes(agentStatus.status)) {
|
|
3341
|
+
throw managerError(
|
|
3342
|
+
`${SKILL_AGENT_NAMES[agent]} \uC2A4\uD0AC \uC0C1\uD0DC\uAC00 ${agentStatus.status}\uC785\uB2C8\uB2E4. --force\uB85C \uBC31\uC5C5 \uD6C4 \uAD50\uCCB4\uD558\uC138\uC694: ${agentStatus.destination}`
|
|
3343
|
+
);
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
2976
3346
|
}
|
|
2977
3347
|
const prepared = await prepareRepository(context, force, operations);
|
|
2978
|
-
const
|
|
2979
|
-
const status = await inspectSkill(context);
|
|
2980
|
-
if (status.status !== "current") {
|
|
2981
|
-
throw managerError(`\uC2A4\uD0AC \uC124\uCE58 \uD6C4 \uC0C1\uD0DC\uAC00 current\uAC00 \uC544\uB2D9\uB2C8\uB2E4: ${status.status}`);
|
|
2982
|
-
}
|
|
3348
|
+
const switched = await switchActiveLinks(context, prepared.repository, previousStatus, operations);
|
|
2983
3349
|
return {
|
|
2984
3350
|
schemaVersion: 1,
|
|
2985
3351
|
action: installAction(previousStatus.status),
|
|
2986
3352
|
changed: true,
|
|
2987
3353
|
previousStatus,
|
|
2988
|
-
status,
|
|
3354
|
+
status: switched.status,
|
|
2989
3355
|
repositoryPath: prepared.repository,
|
|
2990
|
-
backupPaths: [...prepared.backupPaths, ...
|
|
3356
|
+
backupPaths: [...prepared.backupPaths, ...switched.backupPaths]
|
|
2991
3357
|
};
|
|
2992
3358
|
}
|
|
2993
3359
|
async function installSkill(context, options = {}, operations = defaultOperations) {
|
|
@@ -3000,73 +3366,185 @@ async function installSkill(context, options = {}, operations = defaultOperation
|
|
|
3000
3366
|
throw managerError("\uC2A4\uD0AC\uC744 \uC124\uCE58\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", error);
|
|
3001
3367
|
}
|
|
3002
3368
|
}
|
|
3369
|
+
async function tryRestoreCandidate(candidate, destination, operations) {
|
|
3370
|
+
try {
|
|
3371
|
+
if (await optionalLstat(destination)) {
|
|
3372
|
+
return { restored: false, preserved: candidate };
|
|
3373
|
+
}
|
|
3374
|
+
await operations.rename(candidate, destination);
|
|
3375
|
+
return { restored: true };
|
|
3376
|
+
} catch (error) {
|
|
3377
|
+
return { restored: false, error, preserved: candidate };
|
|
3378
|
+
}
|
|
3379
|
+
}
|
|
3003
3380
|
async function restoreUninstallCandidate(candidate, destination, operations, originalError) {
|
|
3004
|
-
|
|
3381
|
+
const result = await tryRestoreCandidate(candidate, destination, operations);
|
|
3382
|
+
if (result.restored) {
|
|
3383
|
+
throw managerError(`\uD65C\uC131 \uC2A4\uD0AC \uB9C1\uD06C\uB97C \uC81C\uAC70\uD558\uC9C0 \uC54A\uACE0 \uC6D0\uB798 \uC704\uCE58\uB85C \uBCF5\uC6D0\uD588\uC2B5\uB2C8\uB2E4: ${destination}`, originalError);
|
|
3384
|
+
}
|
|
3385
|
+
if (result.error === void 0) {
|
|
3005
3386
|
throw managerError(
|
|
3006
3387
|
`\uD65C\uC131 \uC2A4\uD0AC \uACBD\uB85C\uAC00 \uB3D9\uC2DC\uC5D0 \uBCC0\uACBD\uB418\uC5B4 \uC81C\uAC70\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC774\uB3D9\uB41C \uD56D\uBAA9\uC744 \uBCF4\uC874\uD588\uC2B5\uB2C8\uB2E4: ${candidate}`,
|
|
3007
3388
|
originalError
|
|
3008
3389
|
);
|
|
3009
3390
|
}
|
|
3391
|
+
throw managerError(
|
|
3392
|
+
`\uD65C\uC131 \uC2A4\uD0AC \uB9C1\uD06C\uB97C \uC81C\uAC70\uD558\uC9C0 \uBABB\uD588\uACE0 \uC6D0\uB798 \uC704\uCE58\uB85C \uBCF5\uC6D0\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uC774\uB3D9\uB41C \uD56D\uBAA9: ${candidate}; \uC81C\uAC70 \uC624\uB958: ${toReason(originalError)}`,
|
|
3393
|
+
result.error
|
|
3394
|
+
);
|
|
3395
|
+
}
|
|
3396
|
+
async function tryRestoreRemovedLink(destination, rawTarget, operations) {
|
|
3397
|
+
const restoreLink = temporaryLinkPath(destination);
|
|
3010
3398
|
try {
|
|
3011
|
-
await
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3399
|
+
if (await optionalLstat(destination)) {
|
|
3400
|
+
return { restored: false };
|
|
3401
|
+
}
|
|
3402
|
+
await (0, import_promises3.symlink)(rawTarget, restoreLink);
|
|
3403
|
+
await operations.rename(restoreLink, destination);
|
|
3404
|
+
return { restored: true };
|
|
3405
|
+
} catch (error) {
|
|
3406
|
+
return { restored: false, error };
|
|
3407
|
+
} finally {
|
|
3408
|
+
await (0, import_promises3.rm)(restoreLink, { force: true });
|
|
3017
3409
|
}
|
|
3018
|
-
throw managerError(`\uD65C\uC131 \uC2A4\uD0AC \uB9C1\uD06C\uB97C \uC81C\uAC70\uD558\uC9C0 \uC54A\uACE0 \uC6D0\uB798 \uC704\uCE58\uB85C \uBCF5\uC6D0\uD588\uC2B5\uB2C8\uB2E4: ${destination}`, originalError);
|
|
3019
3410
|
}
|
|
3020
|
-
async function
|
|
3021
|
-
const
|
|
3022
|
-
const
|
|
3023
|
-
|
|
3024
|
-
|
|
3411
|
+
async function planUninstallTargets(context) {
|
|
3412
|
+
const statuses = [];
|
|
3413
|
+
for (const agent of SKILL_AGENTS) {
|
|
3414
|
+
const status = await inspectAgentSkill(context, agent);
|
|
3415
|
+
if (status.status !== "missing" && (!status.managed || !status.linkTarget)) {
|
|
3416
|
+
throw managerError(`\uAD00\uB9AC\uB418\uC9C0 \uC54A\uC740 \uC2A4\uD0AC \uD56D\uBAA9\uC774\uBBC0\uB85C \uC5B4\uB290 \uACBD\uB85C\uB3C4 \uC81C\uAC70\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4: ${status.destination}`);
|
|
3417
|
+
}
|
|
3418
|
+
statuses.push({ agent, status });
|
|
3025
3419
|
}
|
|
3026
|
-
|
|
3027
|
-
|
|
3420
|
+
const targets = [];
|
|
3421
|
+
for (const { agent, status } of statuses) {
|
|
3422
|
+
if (status.status === "missing" || !status.linkTarget) {
|
|
3423
|
+
continue;
|
|
3424
|
+
}
|
|
3425
|
+
const realParent = await optionalRealpath(import_node_path5.default.dirname(status.destination));
|
|
3426
|
+
if (!realParent) {
|
|
3427
|
+
continue;
|
|
3428
|
+
}
|
|
3429
|
+
const resolvedDestination = import_node_path5.default.join(realParent, import_node_path5.default.basename(status.destination));
|
|
3430
|
+
const sameTarget = targets.find((entry) => entry.resolvedDestination === resolvedDestination);
|
|
3431
|
+
if (sameTarget) {
|
|
3432
|
+
sameTarget.agents.push(agent);
|
|
3433
|
+
continue;
|
|
3434
|
+
}
|
|
3435
|
+
targets.push({
|
|
3436
|
+
agents: [agent],
|
|
3437
|
+
destination: status.destination,
|
|
3438
|
+
resolvedDestination,
|
|
3439
|
+
linkTarget: status.linkTarget
|
|
3440
|
+
});
|
|
3028
3441
|
}
|
|
3442
|
+
return targets;
|
|
3443
|
+
}
|
|
3444
|
+
function uninstallRollbackError(results, originalError, handledLabel) {
|
|
3445
|
+
const failed = results.filter(({ result }) => !result.restored);
|
|
3446
|
+
if (failed.length === 0) {
|
|
3447
|
+
return managerError(
|
|
3448
|
+
`\uC2A4\uD0AC \uC81C\uAC70\uC5D0 \uC2E4\uD328\uD574 ${handledLabel}\uB97C \uC774\uC804 \uC0C1\uD0DC\uB85C \uB418\uB3CC\uB838\uC2B5\uB2C8\uB2E4: ${results.map(({ destination }) => destination).join(", ")}`,
|
|
3449
|
+
originalError
|
|
3450
|
+
);
|
|
3451
|
+
}
|
|
3452
|
+
const failedText = failed.map(
|
|
3453
|
+
({ destination, result }) => result.preserved ? `${destination} (\uC774\uB3D9\uB41C \uD56D\uBAA9: ${result.preserved})` : destination
|
|
3454
|
+
).join(", ");
|
|
3455
|
+
return managerError(
|
|
3456
|
+
`\uC2A4\uD0AC \uC81C\uAC70\uC5D0 \uC2E4\uD328\uD588\uACE0 \uC77C\uBD80 \uACBD\uB85C\uB97C \uB418\uB3CC\uB9AC\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${failedText}; \uC81C\uAC70 \uC624\uB958: ${toReason(originalError)}`,
|
|
3457
|
+
failed.find(({ result }) => result.error !== void 0)?.result.error
|
|
3458
|
+
);
|
|
3459
|
+
}
|
|
3460
|
+
async function rollbackMovedCandidates(moved, operations, originalError) {
|
|
3461
|
+
const results = [];
|
|
3462
|
+
for (const target of [...moved].reverse()) {
|
|
3463
|
+
results.push({
|
|
3464
|
+
destination: target.destination,
|
|
3465
|
+
result: await tryRestoreCandidate(target.candidate, target.destination, operations)
|
|
3466
|
+
});
|
|
3467
|
+
}
|
|
3468
|
+
throw uninstallRollbackError(results, originalError, "\uC62E\uAE34 \uACBD\uB85C");
|
|
3469
|
+
}
|
|
3470
|
+
async function moveUninstallCandidate(target, moved, operations) {
|
|
3471
|
+
const { destination } = target;
|
|
3029
3472
|
const candidate = import_node_path5.default.join(import_node_path5.default.dirname(destination), `.${SKILL_NAME2}.uninstall-${(0, import_node_crypto3.randomUUID)()}`);
|
|
3030
3473
|
try {
|
|
3031
3474
|
await operations.rename(destination, candidate);
|
|
3032
3475
|
} catch (error) {
|
|
3033
3476
|
if (isNodeError(error, "ENOENT")) {
|
|
3034
|
-
return
|
|
3477
|
+
return void 0;
|
|
3478
|
+
}
|
|
3479
|
+
const moveError = managerError(`\uD65C\uC131 \uC2A4\uD0AC \uB9C1\uD06C\uB97C \uC81C\uAC70\uC6A9 \uC784\uC2DC \uACBD\uB85C\uB85C \uC774\uB3D9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${destination}`, error);
|
|
3480
|
+
if (moved.length === 0) {
|
|
3481
|
+
throw moveError;
|
|
3035
3482
|
}
|
|
3036
|
-
|
|
3483
|
+
return await rollbackMovedCandidates(moved, operations, moveError);
|
|
3037
3484
|
}
|
|
3038
|
-
let
|
|
3485
|
+
let rawTarget;
|
|
3486
|
+
let verificationError;
|
|
3039
3487
|
try {
|
|
3040
3488
|
const candidateStat = await (0, import_promises3.lstat)(candidate);
|
|
3041
3489
|
if (!candidateStat.isSymbolicLink()) {
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
new Error("\uAC80\uC0AC \uD6C4 \uD65C\uC131 \
|
|
3047
|
-
|
|
3490
|
+
verificationError = new Error("\uAC80\uC0AC \uD6C4 \uD65C\uC131 \uACBD\uB85C\uAC00 \uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uAC00 \uC544\uB2CC \uD56D\uBAA9\uC73C\uB85C \uBCC0\uACBD\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
3491
|
+
} else {
|
|
3492
|
+
rawTarget = await (0, import_promises3.readlink)(candidate);
|
|
3493
|
+
if (resolveLinkTarget(destination, rawTarget) !== target.linkTarget) {
|
|
3494
|
+
verificationError = new Error("\uAC80\uC0AC \uD6C4 \uD65C\uC131 \uC2A4\uD0AC \uB9C1\uD06C \uB300\uC0C1\uC774 \uBCC0\uACBD\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
3495
|
+
}
|
|
3048
3496
|
}
|
|
3049
|
-
candidateTarget = resolveLinkTarget(destination, await (0, import_promises3.readlink)(candidate));
|
|
3050
3497
|
} catch (error) {
|
|
3051
|
-
|
|
3052
|
-
|
|
3498
|
+
verificationError = error;
|
|
3499
|
+
}
|
|
3500
|
+
if (verificationError !== void 0 || rawTarget === void 0) {
|
|
3501
|
+
if (moved.length === 0) {
|
|
3502
|
+
return await restoreUninstallCandidate(candidate, destination, operations, verificationError);
|
|
3053
3503
|
}
|
|
3054
|
-
return await
|
|
3504
|
+
return await rollbackMovedCandidates([...moved, { destination, candidate }], operations, verificationError);
|
|
3055
3505
|
}
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3506
|
+
return { ...target, candidate, rawTarget };
|
|
3507
|
+
}
|
|
3508
|
+
async function removeUninstallCandidates(moved, operations) {
|
|
3509
|
+
const removeEntry = operations.rm ?? defaultOperations.rm;
|
|
3510
|
+
for (const [index, target] of moved.entries()) {
|
|
3511
|
+
try {
|
|
3512
|
+
await removeEntry(target.candidate, { force: true });
|
|
3513
|
+
} catch (originalError) {
|
|
3514
|
+
if (index === 0) {
|
|
3515
|
+
if (moved.length === 1) {
|
|
3516
|
+
return await restoreUninstallCandidate(target.candidate, target.destination, operations, originalError);
|
|
3517
|
+
}
|
|
3518
|
+
return await rollbackMovedCandidates(moved, operations, originalError);
|
|
3519
|
+
}
|
|
3520
|
+
const results = [];
|
|
3521
|
+
for (const [restoreIndex, entry] of moved.entries()) {
|
|
3522
|
+
const result = restoreIndex < index ? await tryRestoreRemovedLink(entry.destination, entry.rawTarget, operations) : await tryRestoreCandidate(entry.candidate, entry.destination, operations);
|
|
3523
|
+
results.push({ destination: entry.destination, result });
|
|
3524
|
+
}
|
|
3525
|
+
throw uninstallRollbackError(results, originalError, "\uC9C0\uC6B4 \uACBD\uB85C");
|
|
3526
|
+
}
|
|
3063
3527
|
}
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3528
|
+
}
|
|
3529
|
+
async function uninstallSkill(context, operations = defaultOperations) {
|
|
3530
|
+
const targets = await planUninstallTargets(context);
|
|
3531
|
+
const moved = [];
|
|
3532
|
+
for (const target of targets) {
|
|
3533
|
+
const movedTarget = await moveUninstallCandidate(target, moved, operations);
|
|
3534
|
+
if (movedTarget) {
|
|
3535
|
+
moved.push(movedTarget);
|
|
3536
|
+
}
|
|
3068
3537
|
}
|
|
3069
|
-
|
|
3538
|
+
await removeUninstallCandidates(moved, operations);
|
|
3539
|
+
const agentResult = (agent) => ({
|
|
3540
|
+
action: moved.some((target) => target.agents.includes(agent)) ? "removed" : "absent",
|
|
3541
|
+
destination: destinationPath(context, agent)
|
|
3542
|
+
});
|
|
3543
|
+
const agents = { claude: agentResult("claude"), codex: agentResult("codex") };
|
|
3544
|
+
return {
|
|
3545
|
+
action: SKILL_AGENTS.some((agent) => agents[agent].action === "removed") ? "removed" : "absent",
|
|
3546
|
+
agents
|
|
3547
|
+
};
|
|
3070
3548
|
}
|
|
3071
3549
|
|
|
3072
3550
|
// src/formatters/table.ts
|
|
@@ -3142,9 +3620,16 @@ function outputSkillStatus(opts, status) {
|
|
|
3142
3620
|
rows: [
|
|
3143
3621
|
["\uC0C1\uD0DC", status.status],
|
|
3144
3622
|
["\uD604\uC7AC \uBC84\uC804", status.currentVersion],
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3623
|
+
...SKILL_AGENTS.flatMap((agent) => {
|
|
3624
|
+
const name = SKILL_AGENT_NAMES[agent];
|
|
3625
|
+
const agentStatus = status.agents[agent];
|
|
3626
|
+
return [
|
|
3627
|
+
[`${name} \uC0C1\uD0DC`, agentStatus.status],
|
|
3628
|
+
[`${name} \uC124\uCE58 \uBC84\uC804`, terminalText(agentStatus.installedVersion)],
|
|
3629
|
+
[`${name} \uC124\uCE58 \uACBD\uB85C`, terminalText(agentStatus.destination)],
|
|
3630
|
+
[`${name} \uB9C1\uD06C \uB300\uC0C1`, terminalText(agentStatus.linkTarget)]
|
|
3631
|
+
];
|
|
3632
|
+
}),
|
|
3148
3633
|
["\uBCF5\uAD6C \uBA85\uB839", skillRecoveryCommand(status.status) ?? "\uC870\uCE58 \uC5C6\uC74C"]
|
|
3149
3634
|
],
|
|
3150
3635
|
raw: status,
|
|
@@ -3159,7 +3644,10 @@ function outputSkillInstallResult(opts, result) {
|
|
|
3159
3644
|
["\uBCC0\uACBD \uC5EC\uBD80", result.changed ? "\uBCC0\uACBD\uB428" : "\uBCC0\uACBD \uC5C6\uC74C"],
|
|
3160
3645
|
["\uC774\uC804 \uC0C1\uD0DC", result.previousStatus.status],
|
|
3161
3646
|
["\uD604\uC7AC \uC0C1\uD0DC", result.status.status],
|
|
3162
|
-
|
|
3647
|
+
...SKILL_AGENTS.map((agent) => [
|
|
3648
|
+
`${SKILL_AGENT_NAMES[agent]} \uC124\uCE58 \uACBD\uB85C`,
|
|
3649
|
+
terminalText(result.status.agents[agent].destination)
|
|
3650
|
+
]),
|
|
3163
3651
|
["\uAD00\uB9AC \uC800\uC7A5\uC18C", terminalText(result.repositoryPath)],
|
|
3164
3652
|
[
|
|
3165
3653
|
"\uBC31\uC5C5 \uACBD\uB85C",
|
|
@@ -3175,7 +3663,14 @@ function outputSkillUninstallResult(opts, result) {
|
|
|
3175
3663
|
headers: ["\uD56D\uBAA9", "\uAC12"],
|
|
3176
3664
|
rows: [
|
|
3177
3665
|
["\uC791\uC5C5", result.action === "removed" ? "\uD65C\uC131 \uB9C1\uD06C \uC81C\uAC70 \uC644\uB8CC" : "\uD65C\uC131 \uB9C1\uD06C \uC5C6\uC74C"],
|
|
3178
|
-
|
|
3666
|
+
...SKILL_AGENTS.flatMap((agent) => {
|
|
3667
|
+
const name = SKILL_AGENT_NAMES[agent];
|
|
3668
|
+
const agentResult = result.agents[agent];
|
|
3669
|
+
return [
|
|
3670
|
+
[`${name} \uC124\uCE58 \uACBD\uB85C`, terminalText(agentResult.destination)],
|
|
3671
|
+
[`${name} \uACB0\uACFC`, agentResult.action === "removed" ? "\uD65C\uC131 \uB9C1\uD06C \uC81C\uAC70" : "\uD65C\uC131 \uB9C1\uD06C \uC5C6\uC74C"]
|
|
3672
|
+
];
|
|
3673
|
+
}),
|
|
3179
3674
|
["\uAD00\uB9AC \uC800\uC7A5\uC18C", "\uBCF4\uC874\uB428"]
|
|
3180
3675
|
],
|
|
3181
3676
|
raw: result,
|
|
@@ -3198,7 +3693,7 @@ async function showStatus(cmd, dependencies) {
|
|
|
3198
3693
|
}
|
|
3199
3694
|
function createInstallCommand(name, dependencies) {
|
|
3200
3695
|
return new import_commander3.Command(name).description(
|
|
3201
|
-
name === "install" ? "Claude Code \uC2A4\uD0AC\uC744 \uAD00\uB9AC \uC800\uC7A5\uC18C\uC5D0 \uC124\uCE58\uD55C\uB2E4" : "Claude Code \uC2A4\uD0AC\uC744 \uD604\uC7AC CLI \uBC84\uC804\uC73C\uB85C \uAC31\uC2E0\uD55C\uB2E4"
|
|
3696
|
+
name === "install" ? "Claude Code\xB7Codex \uC2A4\uD0AC\uC744 \uAD00\uB9AC \uC800\uC7A5\uC18C\uC5D0 \uC124\uCE58\uD55C\uB2E4" : "Claude Code\xB7Codex \uC2A4\uD0AC\uC744 \uD604\uC7AC CLI \uBC84\uC804\uC73C\uB85C \uAC31\uC2E0\uD55C\uB2E4"
|
|
3202
3697
|
).option("--force", "\uC0AC\uC6A9\uC790 \uD56D\uBAA9\uC774\uB098 \uC218\uC815\xB7\uC190\uC0C1\uB41C \uAD00\uB9AC \uC800\uC7A5\uC18C\uB97C \uBC31\uC5C5 \uD6C4 \uAD50\uCCB4\uD55C\uB2E4").action(async (_localOpts, cmd) => {
|
|
3203
3698
|
const opts = cmd.optsWithGlobals();
|
|
3204
3699
|
const context = dependencies.createContext();
|
|
@@ -3207,96 +3702,280 @@ function createInstallCommand(name, dependencies) {
|
|
|
3207
3702
|
});
|
|
3208
3703
|
}
|
|
3209
3704
|
function createSkillsCommand(dependencies = defaultDependencies) {
|
|
3210
|
-
const statusCommand = new import_commander3.Command("status").description("Claude Code \uC2A4\uD0AC\uC758 \uAD00\uB9AC \uC0C1\uD0DC\uB97C \uC870\uD68C\uD55C\uB2E4").action(async (_opts, cmd) => showStatus(cmd, dependencies));
|
|
3211
|
-
const uninstallCommand = new import_commander3.Command("uninstall").description("\uD65C\uC131 Claude Code \uC2A4\uD0AC \uB9C1\uD06C\uB97C \uC81C\uAC70\uD55C\uB2E4").action(async (_opts, cmd) => {
|
|
3705
|
+
const statusCommand = new import_commander3.Command("status").description("Claude Code\xB7Codex \uC2A4\uD0AC\uC758 \uAD00\uB9AC \uC0C1\uD0DC\uB97C \uC870\uD68C\uD55C\uB2E4").action(async (_opts, cmd) => showStatus(cmd, dependencies));
|
|
3706
|
+
const uninstallCommand = new import_commander3.Command("uninstall").description("\uD65C\uC131 Claude Code\xB7Codex \uC2A4\uD0AC \uB9C1\uD06C\uB97C \uC81C\uAC70\uD55C\uB2E4").action(async (_opts, cmd) => {
|
|
3212
3707
|
const opts = cmd.optsWithGlobals();
|
|
3213
3708
|
const context = dependencies.createContext();
|
|
3214
|
-
const
|
|
3215
|
-
const action = await dependencies.uninstall(context);
|
|
3709
|
+
const uninstalled = await dependencies.uninstall(context);
|
|
3216
3710
|
const result = {
|
|
3217
3711
|
schemaVersion: 1,
|
|
3218
|
-
action,
|
|
3219
|
-
changed: action === "removed",
|
|
3712
|
+
action: uninstalled.action,
|
|
3713
|
+
changed: uninstalled.action === "removed",
|
|
3220
3714
|
status: "missing",
|
|
3221
|
-
destination:
|
|
3222
|
-
repositoryPreserved: true
|
|
3715
|
+
destination: uninstalled.agents.claude.destination,
|
|
3716
|
+
repositoryPreserved: true,
|
|
3717
|
+
agents: uninstalled.agents
|
|
3223
3718
|
};
|
|
3224
3719
|
outputSkillUninstallResult(opts, result);
|
|
3225
3720
|
});
|
|
3226
|
-
return new import_commander3.Command("skills").description(`Claude Code \uC2A4\uD0AC(${SKILL_NAME3}) \uC124\uCE58 \uAD00\uB9AC`).addCommand(statusCommand).addCommand(createInstallCommand("install", dependencies)).addCommand(createInstallCommand("update", dependencies)).addCommand(uninstallCommand).action(async (_opts, cmd) => showStatus(cmd, dependencies));
|
|
3721
|
+
return new import_commander3.Command("skills").description(`Claude Code\xB7Codex \uC2A4\uD0AC(${SKILL_NAME3}) \uC124\uCE58 \uAD00\uB9AC`).addCommand(statusCommand).addCommand(createInstallCommand("install", dependencies)).addCommand(createInstallCommand("update", dependencies)).addCommand(uninstallCommand).action(async (_opts, cmd) => showStatus(cmd, dependencies));
|
|
3227
3722
|
}
|
|
3228
3723
|
var skillsCommand = createSkillsCommand();
|
|
3229
3724
|
|
|
3230
3725
|
// src/commands/doctor.ts
|
|
3231
3726
|
var import_commander4 = require("commander");
|
|
3232
3727
|
var import_chalk3 = __toESM(require("chalk"));
|
|
3233
|
-
var
|
|
3234
|
-
var
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3728
|
+
var SKILL_ERROR_REASON = "\uACF5\uAC1C \uC2A4\uD0AC \uC0C1\uD0DC\uB97C \uD310\uC815\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4";
|
|
3729
|
+
var defaultDependencies2 = {
|
|
3730
|
+
inspectCredentials: inspectCredentialsFile,
|
|
3731
|
+
inspectConfig: inspectConfigFile,
|
|
3732
|
+
resolveProfile: resolveProfileName,
|
|
3733
|
+
createSkillContext: createSkillManagerContext,
|
|
3734
|
+
inspectSkill: inspectAgentSkill,
|
|
3735
|
+
connection: {
|
|
3736
|
+
getUserAccessKey,
|
|
3737
|
+
getIaasCredential,
|
|
3738
|
+
getOptionalServiceCredential,
|
|
3739
|
+
verifyUserAccessKey,
|
|
3740
|
+
verifyIaas,
|
|
3741
|
+
verifyLogncrash,
|
|
3742
|
+
verifyNcr,
|
|
3743
|
+
verifyNcs
|
|
3744
|
+
}
|
|
3745
|
+
};
|
|
3746
|
+
async function resolveTargetProfile(cliProfile, dependencies) {
|
|
3241
3747
|
try {
|
|
3242
|
-
|
|
3243
|
-
} catch {
|
|
3244
|
-
|
|
3748
|
+
return await dependencies.resolveProfile(cliProfile);
|
|
3749
|
+
} catch (err) {
|
|
3750
|
+
if (err instanceof NhnCloudCliError) return null;
|
|
3751
|
+
throw err;
|
|
3245
3752
|
}
|
|
3753
|
+
}
|
|
3754
|
+
async function inspectAgentSkillForDoctor(dependencies, agent) {
|
|
3246
3755
|
try {
|
|
3247
|
-
const
|
|
3248
|
-
return {
|
|
3249
|
-
} catch {
|
|
3250
|
-
|
|
3756
|
+
const status = await dependencies.inspectSkill(dependencies.createSkillContext(), agent);
|
|
3757
|
+
return { ...status, recoveryCommand: skillRecoveryCommand(status.status) ?? null };
|
|
3758
|
+
} catch (err) {
|
|
3759
|
+
const code = typeof err === "object" && err !== null && "code" in err && typeof err.code === "string" ? err.code : void 0;
|
|
3760
|
+
return { status: "error", reason: code ? `${SKILL_ERROR_REASON}: ${code}` : SKILL_ERROR_REASON };
|
|
3251
3761
|
}
|
|
3252
3762
|
}
|
|
3253
|
-
|
|
3763
|
+
function connectionHasFailure(connection) {
|
|
3764
|
+
return connection.checked && Object.values(connection.targets).some((target) => target.status === "failed");
|
|
3765
|
+
}
|
|
3766
|
+
var CONNECTION_TARGETS = ["userAccessKey", "iaas", "logncrash", "ncr", "ncs"];
|
|
3767
|
+
function skipAll(reason) {
|
|
3768
|
+
return Object.fromEntries(
|
|
3769
|
+
CONNECTION_TARGETS.map((target) => [target, { status: "skipped", reason }])
|
|
3770
|
+
);
|
|
3771
|
+
}
|
|
3772
|
+
async function runVerify(verify) {
|
|
3254
3773
|
try {
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
return null;
|
|
3774
|
+
return await verify() ? { status: "ok" } : { status: "failed", reason: "auth" };
|
|
3775
|
+
} catch (err) {
|
|
3776
|
+
const exitCode = err instanceof NhnCloudCliError ? err.exitCode : EXIT_API_ERROR;
|
|
3777
|
+
return { status: "failed", reason: "error", exitCode };
|
|
3260
3778
|
}
|
|
3261
3779
|
}
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
console.log(` ${import_chalk3.default.red("\u274C \uBBF8\uC124\uC815")} \u2014 ${CREDENTIALS_PATH2} \uC5C6\uC74C. nhncloud configure \uB85C \uC124\uC815\uD558\uC138\uC694.`);
|
|
3269
|
-
} else if (creds.parseError) {
|
|
3270
|
-
console.log(` ${import_chalk3.default.red("\u274C \uD30C\uC2F1 \uC624\uB958")} \u2014 ${CREDENTIALS_PATH2} \uAC00 \uC62C\uBC14\uB978 JSON \uC778\uC9C0 \uD655\uC778\uD558\uC138\uC694.`);
|
|
3271
|
-
} else if (creds.profiles.length === 0) {
|
|
3272
|
-
console.log(` ${import_chalk3.default.yellow("\u26A0 profile \uC5C6\uC74C")} \u2014 nhncloud configure \uB85C \uC124\uC815\uD558\uC138\uC694.`);
|
|
3273
|
-
} else {
|
|
3274
|
-
console.log(` ${import_chalk3.default.green("\u2713 \uC124\uC815\uB428")} \u2014 profile: ${creds.profiles.join(", ")}`);
|
|
3275
|
-
console.log(` \uAE30\uBCF8 profile: ${defaultProfile ? import_chalk3.default.green(defaultProfile) : import_chalk3.default.gray("\uBBF8\uC9C0\uC815 (default \uC0AC\uC6A9)")}`);
|
|
3780
|
+
async function readRequired(read) {
|
|
3781
|
+
try {
|
|
3782
|
+
return { value: await read() };
|
|
3783
|
+
} catch (err) {
|
|
3784
|
+
const reason = err instanceof NhnCloudCliError ? "not-configured" : "profile-unavailable";
|
|
3785
|
+
return { skipped: { status: "skipped", reason } };
|
|
3276
3786
|
}
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
}
|
|
3284
|
-
|
|
3285
|
-
|
|
3787
|
+
}
|
|
3788
|
+
async function readAppkey(service, profileName, deps) {
|
|
3789
|
+
try {
|
|
3790
|
+
const credential = await deps.getOptionalServiceCredential(service, profileName);
|
|
3791
|
+
if (!credential?.appkey) return { skipped: { status: "skipped", reason: "not-configured" } };
|
|
3792
|
+
return { appkey: credential.appkey };
|
|
3793
|
+
} catch {
|
|
3794
|
+
return { skipped: { status: "skipped", reason: "profile-unavailable" } };
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
async function checkConnection(profileName, credentials, profileSummary, deps) {
|
|
3798
|
+
if (credentials.state !== "ok" || profileName === null || profileSummary === void 0 || profileSummary.environment === "invalid") {
|
|
3799
|
+
return skipAll("profile-unavailable");
|
|
3800
|
+
}
|
|
3801
|
+
if (profileSummary.environment === "gov") return skipAll("gov-unsupported");
|
|
3802
|
+
const uakRead = await readRequired(() => deps.getUserAccessKey(profileName));
|
|
3803
|
+
const uak = "value" in uakRead ? uakRead.value : void 0;
|
|
3804
|
+
const userAccessKey = "value" in uakRead ? await runVerify(() => deps.verifyUserAccessKey(uakRead.value)) : uakRead.skipped;
|
|
3805
|
+
const iaasRead = await readRequired(() => deps.getIaasCredential(profileName));
|
|
3806
|
+
const iaasResult = "value" in iaasRead ? await runVerify(() => deps.verifyIaas(iaasRead.value)) : iaasRead.skipped;
|
|
3807
|
+
const checkAppkeyService = async (service, verify, usesOAuth) => {
|
|
3808
|
+
const read = await readAppkey(service, profileName, deps);
|
|
3809
|
+
if ("skipped" in read) return read.skipped;
|
|
3810
|
+
if (uak === void 0) return { status: "skipped", reason: "uak-missing" };
|
|
3811
|
+
if (usesOAuth && userAccessKey.status !== "ok") return { status: "skipped", reason: "uak-failed" };
|
|
3812
|
+
return runVerify(() => verify(uak, read.appkey));
|
|
3813
|
+
};
|
|
3814
|
+
const logncrash = await checkAppkeyService("logncrash", deps.verifyLogncrash, true);
|
|
3815
|
+
const ncr = await checkAppkeyService("ncr", deps.verifyNcr, false);
|
|
3816
|
+
const ncs = await checkAppkeyService("ncs", deps.verifyNcs, true);
|
|
3817
|
+
return { userAccessKey, iaas: iaasResult, logncrash, ncr, ncs };
|
|
3818
|
+
}
|
|
3819
|
+
async function buildDoctorReport(options, dependencies) {
|
|
3820
|
+
const credentials = await dependencies.inspectCredentials();
|
|
3821
|
+
const config = await dependencies.inspectConfig();
|
|
3822
|
+
const profileName = await resolveTargetProfile(options.profile, dependencies);
|
|
3823
|
+
const profileSummary = credentials.state === "ok" && profileName !== null ? credentials.profiles.find((summary) => summary.name === profileName) : void 0;
|
|
3824
|
+
const connection = options.checkConnection ? {
|
|
3825
|
+
checked: true,
|
|
3826
|
+
profile: profileName,
|
|
3827
|
+
targets: await checkConnection(profileName, credentials, profileSummary, dependencies.connection)
|
|
3828
|
+
} : { checked: false };
|
|
3829
|
+
const claude = await inspectAgentSkillForDoctor(dependencies, "claude");
|
|
3830
|
+
const codex = await inspectAgentSkillForDoctor(dependencies, "codex");
|
|
3831
|
+
const ready = profileSummary !== void 0 && profileSummary.environment !== "invalid" && profileSummary.blocks.length > 0 && !connectionHasFailure(connection);
|
|
3832
|
+
return {
|
|
3833
|
+
schemaVersion: 1,
|
|
3834
|
+
ready,
|
|
3835
|
+
credentials,
|
|
3836
|
+
config,
|
|
3837
|
+
profile: { name: profileName, exists: profileSummary !== void 0 },
|
|
3838
|
+
connection,
|
|
3839
|
+
skills: { agents: { claude, codex } }
|
|
3840
|
+
};
|
|
3841
|
+
}
|
|
3842
|
+
function line(text = "") {
|
|
3843
|
+
process.stdout.write(`${text}
|
|
3844
|
+
`);
|
|
3845
|
+
}
|
|
3846
|
+
function printCredentialsSection(credentials) {
|
|
3847
|
+
const filePath = sanitizeForTerminal(credentials.path);
|
|
3848
|
+
const reason = sanitizeForTerminal(credentials.reason ?? "");
|
|
3849
|
+
line(import_chalk3.default.bold("\uC790\uACA9\uC99D\uBA85"));
|
|
3850
|
+
switch (credentials.state) {
|
|
3851
|
+
case "missing":
|
|
3852
|
+
line(` ${import_chalk3.default.red("\u274C \uBBF8\uC124\uC815")} \u2014 ${filePath} \uC5C6\uC74C. nhncloud configure \uB85C \uC124\uC815\uD558\uC138\uC694.`);
|
|
3853
|
+
break;
|
|
3854
|
+
case "invalid":
|
|
3855
|
+
line(` ${import_chalk3.default.red("\u274C \uD615\uC2DD \uC624\uB958")} \u2014 ${filePath}: ${reason}`);
|
|
3856
|
+
break;
|
|
3857
|
+
case "unreadable":
|
|
3858
|
+
line(` ${import_chalk3.default.red("\u274C \uC77D\uAE30 \uC2E4\uD328")} \u2014 ${filePath}: ${reason}`);
|
|
3859
|
+
break;
|
|
3860
|
+
case "ok":
|
|
3861
|
+
if (credentials.profiles.length === 0) {
|
|
3862
|
+
line(` ${import_chalk3.default.yellow("\u26A0 profile \uC5C6\uC74C")} \u2014 nhncloud configure \uB85C \uC124\uC815\uD558\uC138\uC694.`);
|
|
3863
|
+
break;
|
|
3864
|
+
}
|
|
3865
|
+
line(` ${import_chalk3.default.green("\u2713 \uC124\uC815\uB428")} \u2014 profile:`);
|
|
3866
|
+
for (const summary of credentials.profiles) {
|
|
3867
|
+
const name = sanitizeForTerminal(summary.name);
|
|
3868
|
+
const blocks = summary.blocks.map(sanitizeForTerminal).join(", ") || "-";
|
|
3869
|
+
if (summary.environment === "invalid") {
|
|
3870
|
+
line(` ${name} ${import_chalk3.default.yellow("\u26A0 environment \uAC12\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4")} [${blocks}]`);
|
|
3871
|
+
} else {
|
|
3872
|
+
line(` ${name}${summary.environment === "gov" ? " (gov)" : ""} [${blocks}]`);
|
|
3873
|
+
}
|
|
3874
|
+
}
|
|
3875
|
+
break;
|
|
3876
|
+
}
|
|
3877
|
+
if (credentials.permissions === "too-open") {
|
|
3878
|
+
line(` ${import_chalk3.default.yellow("\u26A0 \uD30C\uC77C \uAD8C\uD55C\uC774 \uB113\uC2B5\uB2C8\uB2E4")} \u2014 chmod 600 ${filePath}`);
|
|
3879
|
+
}
|
|
3880
|
+
}
|
|
3881
|
+
function printConfigSection(config) {
|
|
3882
|
+
line(import_chalk3.default.bold("\n\uC124\uC815 \uD30C\uC77C"));
|
|
3883
|
+
if (config.state === "invalid" || config.state === "unreadable") {
|
|
3884
|
+
line(
|
|
3885
|
+
` ${import_chalk3.default.red(config.state === "invalid" ? "\u274C \uD615\uC2DD \uC624\uB958" : "\u274C \uC77D\uAE30 \uC2E4\uD328")} \u2014 ${sanitizeForTerminal(config.path)}: ${sanitizeForTerminal(config.reason ?? "")}`
|
|
3286
3886
|
);
|
|
3887
|
+
}
|
|
3888
|
+
line(
|
|
3889
|
+
` \uAE30\uBCF8 profile: ${config.defaultProfile ? import_chalk3.default.green(sanitizeForTerminal(config.defaultProfile)) : import_chalk3.default.gray("\uBBF8\uC9C0\uC815 (default \uC0AC\uC6A9)")}`
|
|
3890
|
+
);
|
|
3891
|
+
}
|
|
3892
|
+
function printProfileSection(profile) {
|
|
3893
|
+
line(import_chalk3.default.bold("\n\uB300\uC0C1 profile"));
|
|
3894
|
+
if (profile.name === null) {
|
|
3895
|
+
line(` ${import_chalk3.default.red("\u274C \uD574\uC11D \uC2E4\uD328")} \u2014 config.json \uC744 \uBA3C\uC800 \uACE0\uCE58\uC138\uC694.`);
|
|
3896
|
+
} else if (profile.exists) {
|
|
3897
|
+
line(` ${import_chalk3.default.green(`\u2713 ${sanitizeForTerminal(profile.name)}`)}`);
|
|
3287
3898
|
} else {
|
|
3288
|
-
|
|
3289
|
-
` ${
|
|
3899
|
+
line(
|
|
3900
|
+
` ${import_chalk3.default.yellow(`\u26A0 ${sanitizeForTerminal(profile.name)} \uC5C6\uC74C`)} \u2014 nhncloud configure \uB85C \uC124\uC815\uD558\uC138\uC694.`
|
|
3290
3901
|
);
|
|
3291
3902
|
}
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3903
|
+
}
|
|
3904
|
+
function printSkillLine(agent, skill) {
|
|
3905
|
+
const name = SKILL_AGENT_NAMES[agent];
|
|
3906
|
+
if (skill.status === "error") {
|
|
3907
|
+
line(` ${name}: ${import_chalk3.default.yellow("\u26A0 error")} \u2014 ${sanitizeForTerminal(skill.reason)}`);
|
|
3908
|
+
} else if (skill.status === "current") {
|
|
3909
|
+
const version = sanitizeForTerminal(skill.installedVersion ?? skill.currentVersion);
|
|
3910
|
+
line(` ${name}: ${import_chalk3.default.green(`\u2713 current (${version})`)}`);
|
|
3911
|
+
} else if (skill.status === "missing") {
|
|
3912
|
+
line(` ${name}: ${import_chalk3.default.gray(`\uBBF8\uC124\uCE58 \u2014 ${skill.recoveryCommand}`)}`);
|
|
3295
3913
|
} else {
|
|
3296
|
-
|
|
3914
|
+
line(` ${name}: ${import_chalk3.default.yellow(`\u26A0 ${skill.status}`)} \u2014 ${skill.recoveryCommand}`);
|
|
3297
3915
|
}
|
|
3298
|
-
|
|
3299
|
-
|
|
3916
|
+
}
|
|
3917
|
+
function printSkillSection(agents) {
|
|
3918
|
+
line(import_chalk3.default.bold("\n\uACF5\uAC1C \uC2A4\uD0AC"));
|
|
3919
|
+
for (const agent of SKILL_AGENTS) printSkillLine(agent, agents[agent]);
|
|
3920
|
+
}
|
|
3921
|
+
var SKIP_REASONS = {
|
|
3922
|
+
"not-configured": "\uC124\uC815 \uC5C6\uC74C",
|
|
3923
|
+
"uak-missing": "\uACF5\uD1B5 userAccessKey \uC5C6\uC74C",
|
|
3924
|
+
"uak-failed": "userAccessKey \uD655\uC778\uC774 \uC131\uACF5\uD558\uC9C0 \uC54A\uC544 \uAC74\uB108\uB700",
|
|
3925
|
+
"gov-unsupported": "\uACF5\uACF5\uB9DD profile \uC740 \uC5F0\uACB0 \uD655\uC778\uC744 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC74C",
|
|
3926
|
+
"profile-unavailable": "\uB300\uC0C1 profile \uC744 \uC77D\uC744 \uC218 \uC5C6\uC74C"
|
|
3927
|
+
};
|
|
3928
|
+
function printConnectionSection(connection) {
|
|
3929
|
+
if (!connection.checked) return;
|
|
3930
|
+
line(import_chalk3.default.bold("\n\uC5F0\uACB0 \uD655\uC778"));
|
|
3931
|
+
for (const target of CONNECTION_TARGETS) {
|
|
3932
|
+
const result = connection.targets[target];
|
|
3933
|
+
const label = ` ${target}:`;
|
|
3934
|
+
if (result.status === "ok") {
|
|
3935
|
+
const region = target === "ncr" || target === "ncs" ? " (kr1)" : "";
|
|
3936
|
+
line(`${label} ${import_chalk3.default.green(`\u2713 \uC131\uACF5${region}`)}`);
|
|
3937
|
+
} else if (result.status === "failed" && result.reason === "auth") {
|
|
3938
|
+
line(`${label} ${import_chalk3.default.red("\u274C \uC778\uC99D \uC2E4\uD328")} \u2014 \uD0A4\uB098 appkey \uB97C \uD655\uC778\uD558\uC138\uC694.`);
|
|
3939
|
+
} else if (result.status === "failed") {
|
|
3940
|
+
line(`${label} ${import_chalk3.default.red(`\u274C \uC624\uB958 (\uC885\uB8CC \uCF54\uB4DC ${result.exitCode ?? EXIT_API_ERROR})`)}`);
|
|
3941
|
+
} else {
|
|
3942
|
+
const reason = result.reason ? SKIP_REASONS[result.reason] ?? result.reason : "";
|
|
3943
|
+
line(`${label} ${import_chalk3.default.gray(`\uAC74\uB108\uB700 \u2014 ${reason}`)}`);
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
function printText(report) {
|
|
3948
|
+
line(import_chalk3.default.bold("\n\u{1F50D} nhncloud-cli \uC9C4\uB2E8\n"));
|
|
3949
|
+
printCredentialsSection(report.credentials);
|
|
3950
|
+
printConfigSection(report.config);
|
|
3951
|
+
printProfileSection(report.profile);
|
|
3952
|
+
printConnectionSection(report.connection);
|
|
3953
|
+
printSkillSection(report.skills.agents);
|
|
3954
|
+
line();
|
|
3955
|
+
if (report.ready) {
|
|
3956
|
+
line(import_chalk3.default.green("\u2713 \uAE30\uBCF8 \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
3957
|
+
} else {
|
|
3958
|
+
line(import_chalk3.default.yellow("\u26A0 \uC124\uC815\uC774 \uD544\uC694\uD569\uB2C8\uB2E4: nhncloud configure"));
|
|
3959
|
+
}
|
|
3960
|
+
line();
|
|
3961
|
+
}
|
|
3962
|
+
function createDoctorCommand(dependencies = defaultDependencies2) {
|
|
3963
|
+
return new import_commander4.Command("doctor").description("\uC790\uACA9\uC99D\uBA85\xB7\uC124\uC815\xB7\uC2A4\uD0AC \uC0C1\uD0DC\uB97C \uC9C4\uB2E8\uD55C\uB2E4(\uAE30\uBCF8 \uC624\uD504\uB77C\uC778, --check-connection \uC73C\uB85C \uC5F0\uACB0 \uD655\uC778)").option("--profile <name>", "\uC9C4\uB2E8\uD560 profile \uC774\uB984").option("--check-connection", "\uB300\uC0C1 profile \uC758 \uC790\uACA9\uC99D\uBA85\uC73C\uB85C \uC2E4\uC81C \uC5F0\uACB0\uC744 \uD655\uC778\uD55C\uB2E4 (\uC678\uBD80 API \uD638\uCD9C)").action(async (_opts, cmd) => {
|
|
3964
|
+
const opts = cmd.optsWithGlobals();
|
|
3965
|
+
const report = await buildDoctorReport(
|
|
3966
|
+
{ profile: opts.profile, checkConnection: opts.checkConnection },
|
|
3967
|
+
dependencies
|
|
3968
|
+
);
|
|
3969
|
+
if (opts.json) {
|
|
3970
|
+
printJson(report);
|
|
3971
|
+
} else if (opts.quiet) {
|
|
3972
|
+
process.stdout.write(report.ready ? "ready\n" : "not-ready\n");
|
|
3973
|
+
} else {
|
|
3974
|
+
printText(report);
|
|
3975
|
+
}
|
|
3976
|
+
});
|
|
3977
|
+
}
|
|
3978
|
+
var doctorCommand = createDoctorCommand();
|
|
3300
3979
|
|
|
3301
3980
|
// src/commands/logncrash/search.ts
|
|
3302
3981
|
var import_commander5 = require("commander");
|
|
@@ -3545,19 +4224,19 @@ var VALID_LEVELS = ["DEBUG", "INFO", "WARN", "ERROR", "FATAL"];
|
|
|
3545
4224
|
function resolveBody(opts) {
|
|
3546
4225
|
if (opts.body !== void 0) return opts.body;
|
|
3547
4226
|
if (opts.file !== void 0) {
|
|
3548
|
-
let
|
|
4227
|
+
let stat4;
|
|
3549
4228
|
try {
|
|
3550
|
-
|
|
4229
|
+
stat4 = (0, import_node_fs3.statSync)(opts.file);
|
|
3551
4230
|
} catch (e) {
|
|
3552
4231
|
const reason = e.code ?? (e instanceof Error ? e.message : String(e));
|
|
3553
4232
|
throw new NhnCloudCliError(`\uB85C\uADF8 \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${opts.file} (${reason})`, EXIT_PARAM_ERROR);
|
|
3554
4233
|
}
|
|
3555
|
-
if (!
|
|
4234
|
+
if (!stat4.isFile()) {
|
|
3556
4235
|
throw new NhnCloudCliError(`\uB85C\uADF8 \uD30C\uC77C\uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4: ${opts.file}`, EXIT_PARAM_ERROR);
|
|
3557
4236
|
}
|
|
3558
|
-
if (
|
|
4237
|
+
if (stat4.size > MAX_LOG_BYTES) {
|
|
3559
4238
|
throw new NhnCloudCliError(
|
|
3560
|
-
`\uB85C\uADF8 \uD30C\uC77C\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4: ${
|
|
4239
|
+
`\uB85C\uADF8 \uD30C\uC77C\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4: ${stat4.size} \uBC14\uC774\uD2B8 (\uD55C\uB3C4 ${MAX_LOG_BYTES} \uBC14\uC774\uD2B8).`,
|
|
3561
4240
|
EXIT_PARAM_ERROR
|
|
3562
4241
|
);
|
|
3563
4242
|
}
|
|
@@ -3628,22 +4307,22 @@ credentials.json \uC5D0 "appkey": "<appkey>" \uB97C \uCD94\uAC00\uD558\uC138\uC6
|
|
|
3628
4307
|
|
|
3629
4308
|
// src/commands/logncrash/export.ts
|
|
3630
4309
|
var import_commander7 = require("commander");
|
|
3631
|
-
var
|
|
4310
|
+
var import_promises4 = require("fs/promises");
|
|
3632
4311
|
var import_node_fs4 = require("fs");
|
|
3633
4312
|
var import_node_crypto4 = require("crypto");
|
|
3634
4313
|
var MAX_TOTAL = 1e5;
|
|
3635
|
-
var defaultExportFileOps = { appendFile:
|
|
3636
|
-
function assertWritable(
|
|
4314
|
+
var defaultExportFileOps = { appendFile: import_promises4.appendFile, rename: import_promises4.rename };
|
|
4315
|
+
function assertWritable(path4, force) {
|
|
3637
4316
|
if (force) return;
|
|
3638
4317
|
try {
|
|
3639
|
-
(0, import_node_fs4.statSync)(
|
|
4318
|
+
(0, import_node_fs4.statSync)(path4);
|
|
3640
4319
|
} catch (e) {
|
|
3641
4320
|
if (e.code === "ENOENT") return;
|
|
3642
4321
|
const reason = e.code ?? (e instanceof Error ? e.message : String(e));
|
|
3643
|
-
throw new NhnCloudCliError(`--output \uACBD\uB85C\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${
|
|
4322
|
+
throw new NhnCloudCliError(`--output \uACBD\uB85C\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${path4} (${reason})`, EXIT_PARAM_ERROR);
|
|
3644
4323
|
}
|
|
3645
4324
|
throw new NhnCloudCliError(
|
|
3646
|
-
`--output \uB300\uC0C1\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4: ${
|
|
4325
|
+
`--output \uB300\uC0C1\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4: ${path4}. \uB36E\uC5B4\uC4F0\uB824\uBA74 --force \uB97C \uC4F0\uC138\uC694.`,
|
|
3647
4326
|
EXIT_PARAM_ERROR
|
|
3648
4327
|
);
|
|
3649
4328
|
}
|
|
@@ -3754,7 +4433,7 @@ function createExportCommand(finalizeOps) {
|
|
|
3754
4433
|
} catch (err) {
|
|
3755
4434
|
if (failureOrigin !== "search" || !(err instanceof LogncrashServerError)) throw err;
|
|
3756
4435
|
await endAndClose(stream);
|
|
3757
|
-
await (0,
|
|
4436
|
+
await (0, import_promises4.truncate)(tmp, checkpoint.bytesWritten);
|
|
3758
4437
|
stream = (0, import_node_fs4.createWriteStream)(tmp, { encoding: "utf-8", flags: "a" });
|
|
3759
4438
|
bytePosition = checkpoint.bytesWritten;
|
|
3760
4439
|
count = checkpoint.count;
|
|
@@ -3781,14 +4460,14 @@ function createExportCommand(finalizeOps) {
|
|
|
3781
4460
|
stream.end();
|
|
3782
4461
|
});
|
|
3783
4462
|
if (count === 0) {
|
|
3784
|
-
await (0,
|
|
4463
|
+
await (0, import_promises4.rm)(tmp, { force: true }).catch(() => {
|
|
3785
4464
|
});
|
|
3786
4465
|
throw failure;
|
|
3787
4466
|
}
|
|
3788
4467
|
const partial = `${opts.output}.partial`;
|
|
3789
4468
|
try {
|
|
3790
|
-
if (format === "json") await (0,
|
|
3791
|
-
await (0,
|
|
4469
|
+
if (format === "json") await (0, import_promises4.appendFile)(tmp, "]\n");
|
|
4470
|
+
await (0, import_promises4.rename)(tmp, partial);
|
|
3792
4471
|
} catch {
|
|
3793
4472
|
process.stderr.write(
|
|
3794
4473
|
`\uACBD\uACE0: \uBD80\uBD84 \uACB0\uACFC\uB97C ${partial} \uC5D0 \uB0A8\uAE30\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uC784\uC2DC \uD30C\uC77C: ${tmp}
|
|
@@ -3830,7 +4509,7 @@ function createExportCommand(finalizeOps) {
|
|
|
3830
4509
|
throw new NhnCloudCliError(message, EXIT_PARAM_ERROR);
|
|
3831
4510
|
}
|
|
3832
4511
|
stopSpinner(true, `${count}\uAC74 \uCD94\uCD9C \uC644\uB8CC`);
|
|
3833
|
-
await (0,
|
|
4512
|
+
await (0, import_promises4.rm)(`${opts.output}.partial`, { force: true }).catch(() => {
|
|
3834
4513
|
});
|
|
3835
4514
|
if (count >= MAX_TOTAL && (total > MAX_TOTAL || hasUnqueriedWindows)) {
|
|
3836
4515
|
const totalDescription = hasUnqueriedWindows ? `\uC870\uD68C\uD55C \uCC3D\uC5D0\uC11C ${total}\uAC74\uC744 \uD655\uC778\uD588\uACE0 \uB0A8\uC740 \uCC3D\uC744 \uC870\uD68C\uD558\uC9C0 \uC54A\uC740 \uCC44` : `\uC804\uCCB4 ${total}\uAC74 \uC911`;
|
|
@@ -4448,7 +5127,7 @@ var binariesCommand = new import_commander15.Command("binaries").description("\u
|
|
|
4448
5127
|
// src/commands/deploy/upload.ts
|
|
4449
5128
|
var import_commander16 = require("commander");
|
|
4450
5129
|
var import_node_fs5 = require("fs");
|
|
4451
|
-
var
|
|
5130
|
+
var import_node_path6 = require("path");
|
|
4452
5131
|
var MAX_UPLOAD_BYTES = 512 * 1024 * 1024;
|
|
4453
5132
|
function parsePositiveInt2(value, flag) {
|
|
4454
5133
|
if (value === void 0) return void 0;
|
|
@@ -4468,9 +5147,9 @@ var uploadCommand = new import_commander16.Command("upload").description("\uB85C
|
|
|
4468
5147
|
}
|
|
4469
5148
|
const artifactId = requireCoordinate(opts.artifactId, "--artifact-id");
|
|
4470
5149
|
const filePath = opts.file;
|
|
4471
|
-
let
|
|
5150
|
+
let stat4;
|
|
4472
5151
|
try {
|
|
4473
|
-
|
|
5152
|
+
stat4 = (0, import_node_fs5.statSync)(filePath);
|
|
4474
5153
|
} catch (e) {
|
|
4475
5154
|
const reason = e.code ?? (e instanceof Error ? e.message : String(e));
|
|
4476
5155
|
throw new NhnCloudCliError(
|
|
@@ -4478,17 +5157,17 @@ var uploadCommand = new import_commander16.Command("upload").description("\uB85C
|
|
|
4478
5157
|
EXIT_PARAM_ERROR
|
|
4479
5158
|
);
|
|
4480
5159
|
}
|
|
4481
|
-
if (!
|
|
5160
|
+
if (!stat4.isFile()) {
|
|
4482
5161
|
throw new NhnCloudCliError(`--file \uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4: ${filePath}`, EXIT_PARAM_ERROR);
|
|
4483
5162
|
}
|
|
4484
|
-
if (
|
|
5163
|
+
if (stat4.size > MAX_UPLOAD_BYTES) {
|
|
4485
5164
|
throw new NhnCloudCliError(
|
|
4486
|
-
`--file \uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4 (${
|
|
5165
|
+
`--file \uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4 (${stat4.size} \uBC14\uC774\uD2B8). \uC5C5\uB85C\uB4DC \uD55C\uB3C4 ${MAX_UPLOAD_BYTES} \uBC14\uC774\uD2B8.`,
|
|
4487
5166
|
EXIT_PARAM_ERROR
|
|
4488
5167
|
);
|
|
4489
5168
|
}
|
|
4490
5169
|
const fileBuffer = (0, import_node_fs5.readFileSync)(filePath);
|
|
4491
|
-
const fileName = (0,
|
|
5170
|
+
const fileName = (0, import_node_path6.basename)(filePath);
|
|
4492
5171
|
const { client, profileName } = await createDeployClient(opts.profile);
|
|
4493
5172
|
const appKey = await resolveDeployAppKey(profileName);
|
|
4494
5173
|
startSpinner("\uBC14\uC774\uB108\uB9AC \uC5C5\uB85C\uB4DC \uC911...");
|
|
@@ -4534,20 +5213,20 @@ function parsePositiveInt3(value, flag) {
|
|
|
4534
5213
|
}
|
|
4535
5214
|
return Number(value);
|
|
4536
5215
|
}
|
|
4537
|
-
function assertWritable2(
|
|
5216
|
+
function assertWritable2(path4, force) {
|
|
4538
5217
|
if (force) return;
|
|
4539
5218
|
try {
|
|
4540
|
-
(0, import_node_fs6.statSync)(
|
|
5219
|
+
(0, import_node_fs6.statSync)(path4);
|
|
4541
5220
|
} catch (e) {
|
|
4542
5221
|
if (e.code === "ENOENT") return;
|
|
4543
5222
|
const reason = e.code ?? (e instanceof Error ? e.message : String(e));
|
|
4544
5223
|
throw new NhnCloudCliError(
|
|
4545
|
-
`-o \uACBD\uB85C\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${
|
|
5224
|
+
`-o \uACBD\uB85C\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${path4} (${reason})`,
|
|
4546
5225
|
EXIT_PARAM_ERROR
|
|
4547
5226
|
);
|
|
4548
5227
|
}
|
|
4549
5228
|
throw new NhnCloudCliError(
|
|
4550
|
-
`-o \uB300\uC0C1\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4: ${
|
|
5229
|
+
`-o \uB300\uC0C1\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4: ${path4}. \uB36E\uC5B4\uC4F0\uB824\uBA74 --force \uB97C \uC4F0\uC138\uC694.`,
|
|
4551
5230
|
EXIT_PARAM_ERROR
|
|
4552
5231
|
);
|
|
4553
5232
|
}
|
|
@@ -4890,8 +5569,8 @@ var InstanceClient = class {
|
|
|
4890
5569
|
return this.serverAction(id, { revertResize: null });
|
|
4891
5570
|
}
|
|
4892
5571
|
async listFlavors(params = {}) {
|
|
4893
|
-
const
|
|
4894
|
-
const url = `${this.computeEndpoint}${
|
|
5572
|
+
const path4 = params.detail ? "/flavors/detail" : "/flavors";
|
|
5573
|
+
const url = `${this.computeEndpoint}${path4}`;
|
|
4895
5574
|
const searchParams = {};
|
|
4896
5575
|
if (params.minDisk !== void 0) searchParams["minDisk"] = params.minDisk;
|
|
4897
5576
|
if (params.minRam !== void 0) searchParams["minRam"] = params.minRam;
|
|
@@ -6571,9 +7250,9 @@ var createCommand5 = new import_commander33.Command("create").description("\uC77
|
|
|
6571
7250
|
}
|
|
6572
7251
|
let userDataBase64;
|
|
6573
7252
|
if (opts.userData !== void 0) {
|
|
6574
|
-
let
|
|
7253
|
+
let stat4;
|
|
6575
7254
|
try {
|
|
6576
|
-
|
|
7255
|
+
stat4 = (0, import_node_fs7.statSync)(opts.userData);
|
|
6577
7256
|
} catch (e) {
|
|
6578
7257
|
const reason = e.code ?? (e instanceof Error ? e.message : String(e));
|
|
6579
7258
|
throw new NhnCloudCliError(
|
|
@@ -6581,15 +7260,15 @@ var createCommand5 = new import_commander33.Command("create").description("\uC77
|
|
|
6581
7260
|
EXIT_PARAM_ERROR
|
|
6582
7261
|
);
|
|
6583
7262
|
}
|
|
6584
|
-
if (!
|
|
7263
|
+
if (!stat4.isFile()) {
|
|
6585
7264
|
throw new NhnCloudCliError(
|
|
6586
7265
|
`--user-data \uAC00 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4: ${opts.userData}`,
|
|
6587
7266
|
EXIT_PARAM_ERROR
|
|
6588
7267
|
);
|
|
6589
7268
|
}
|
|
6590
|
-
if (
|
|
7269
|
+
if (stat4.size > 49149) {
|
|
6591
7270
|
throw new NhnCloudCliError(
|
|
6592
|
-
`--user-data \uAC00 \uB108\uBB34 \uD07D\uB2C8\uB2E4 (${
|
|
7271
|
+
`--user-data \uAC00 \uB108\uBB34 \uD07D\uB2C8\uB2E4 (${stat4.size} \uBC14\uC774\uD2B8). base64 \uC778\uCF54\uB529 \uD6C4 65535 \uBC14\uC774\uD2B8 \uD55C\uB3C4\uB77C raw 49149 \uBC14\uC774\uD2B8\uAE4C\uC9C0\uB9CC \uD5C8\uC6A9\uB429\uB2C8\uB2E4.`,
|
|
6593
7272
|
EXIT_PARAM_ERROR
|
|
6594
7273
|
);
|
|
6595
7274
|
}
|
|
@@ -6874,9 +7553,9 @@ var import_node_fs8 = require("fs");
|
|
|
6874
7553
|
var import_node_crypto5 = require("crypto");
|
|
6875
7554
|
var import_chalk12 = __toESM(require("chalk"));
|
|
6876
7555
|
function resolvePublicKey(value) {
|
|
6877
|
-
let
|
|
7556
|
+
let stat4;
|
|
6878
7557
|
try {
|
|
6879
|
-
|
|
7558
|
+
stat4 = (0, import_node_fs8.statSync)(value);
|
|
6880
7559
|
} catch (e) {
|
|
6881
7560
|
const err = e;
|
|
6882
7561
|
if (err.code && err.code !== "ENOENT") {
|
|
@@ -6887,7 +7566,7 @@ function resolvePublicKey(value) {
|
|
|
6887
7566
|
}
|
|
6888
7567
|
return value;
|
|
6889
7568
|
}
|
|
6890
|
-
if (!
|
|
7569
|
+
if (!stat4.isFile()) {
|
|
6891
7570
|
throw new NhnCloudCliError(`--public-key \uAC00 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4: ${value}`, EXIT_PARAM_ERROR);
|
|
6892
7571
|
}
|
|
6893
7572
|
return (0, import_node_fs8.readFileSync)(value, "utf-8").trim();
|
|
@@ -7194,12 +7873,12 @@ var HarborClient = class {
|
|
|
7194
7873
|
* ky.get() 이 Response 를 반환하므로 .json() 과 .headers.get("link") 를 함께 사용한다
|
|
7195
7874
|
* (체이닝하면 헤더를 못 본다 — 기존 NCR client 의 .json<T>() 체이닝 패턴과 다름).
|
|
7196
7875
|
*/
|
|
7197
|
-
async getAllPages(
|
|
7876
|
+
async getAllPages(path4) {
|
|
7198
7877
|
const acc = [];
|
|
7199
7878
|
let page = 1;
|
|
7200
7879
|
try {
|
|
7201
7880
|
for (; ; ) {
|
|
7202
|
-
const url = `https://${this.host}${
|
|
7881
|
+
const url = `https://${this.host}${path4}?page=${page}&page_size=${PAGE_SIZE}`;
|
|
7203
7882
|
const res = await import_ky13.default.get(url, {
|
|
7204
7883
|
headers: this.basicAuthHeaders(),
|
|
7205
7884
|
retry: 0,
|
|
@@ -7439,15 +8118,15 @@ function commandPath(command) {
|
|
|
7439
8118
|
return names.join(" ");
|
|
7440
8119
|
}
|
|
7441
8120
|
function collectCommand(command) {
|
|
7442
|
-
const
|
|
7443
|
-
if (!
|
|
8121
|
+
const path4 = commandPath(command);
|
|
8122
|
+
if (!path4 || path4 === "help") return null;
|
|
7444
8123
|
return {
|
|
7445
|
-
path:
|
|
8124
|
+
path: path4,
|
|
7446
8125
|
description: command.description() || command.summary() || "",
|
|
7447
8126
|
arguments: command.registeredArguments.map((arg) => arg.name()),
|
|
7448
8127
|
options: command.options.filter((option) => !option.hidden).map((option) => option.flags),
|
|
7449
8128
|
subcommands: command.commands.map((subcommand) => subcommand.name()).filter((name) => name !== "help"),
|
|
7450
|
-
...
|
|
8129
|
+
...path4 === "commands" ? { metadata: true } : {}
|
|
7451
8130
|
};
|
|
7452
8131
|
}
|
|
7453
8132
|
function collectCommandCatalog(program2) {
|
|
@@ -7486,7 +8165,7 @@ function createCommandsCommand(program2) {
|
|
|
7486
8165
|
var import_commander48 = require("commander");
|
|
7487
8166
|
|
|
7488
8167
|
// src/commands/nks/helpers.ts
|
|
7489
|
-
var
|
|
8168
|
+
var import_promises5 = require("fs/promises");
|
|
7490
8169
|
|
|
7491
8170
|
// src/services/nks/client.ts
|
|
7492
8171
|
var import_ky14 = __toESM(require("ky"));
|
|
@@ -7936,15 +8615,15 @@ var NksClient = class {
|
|
|
7936
8615
|
throw toNhnCloudCliError(err);
|
|
7937
8616
|
}
|
|
7938
8617
|
}
|
|
7939
|
-
async getFlatNamedResource(
|
|
7940
|
-
const raw = await this.getJson(
|
|
8618
|
+
async getFlatNamedResource(path4, errorMessage) {
|
|
8619
|
+
const raw = await this.getJson(path4);
|
|
7941
8620
|
if (!isNksNamedResource(raw)) {
|
|
7942
8621
|
throw new NhnCloudCliError(errorMessage, EXIT_API_ERROR);
|
|
7943
8622
|
}
|
|
7944
8623
|
return raw;
|
|
7945
8624
|
}
|
|
7946
|
-
async getJson(
|
|
7947
|
-
const url = `${this.nksEndpoint}${
|
|
8625
|
+
async getJson(path4, searchParams) {
|
|
8626
|
+
const url = `${this.nksEndpoint}${path4}`;
|
|
7948
8627
|
try {
|
|
7949
8628
|
return await import_ky14.default.get(url, {
|
|
7950
8629
|
headers: this.authHeaders(),
|
|
@@ -7956,15 +8635,15 @@ var NksClient = class {
|
|
|
7956
8635
|
throw toNhnCloudCliError(err);
|
|
7957
8636
|
}
|
|
7958
8637
|
}
|
|
7959
|
-
async requestUuid(method,
|
|
7960
|
-
const raw = await this.requestJson(method,
|
|
8638
|
+
async requestUuid(method, path4, payload, errorMessage) {
|
|
8639
|
+
const raw = await this.requestJson(method, path4, payload);
|
|
7961
8640
|
if (!isNksUuidResponse(raw)) {
|
|
7962
8641
|
throw new NhnCloudCliError(errorMessage, EXIT_API_ERROR);
|
|
7963
8642
|
}
|
|
7964
8643
|
return raw;
|
|
7965
8644
|
}
|
|
7966
|
-
async requestNoBody(method,
|
|
7967
|
-
const url = `${this.nksEndpoint}${
|
|
8645
|
+
async requestNoBody(method, path4, payload) {
|
|
8646
|
+
const url = `${this.nksEndpoint}${path4}`;
|
|
7968
8647
|
try {
|
|
7969
8648
|
if (method === "delete") {
|
|
7970
8649
|
await import_ky14.default.delete(url, { headers: this.authHeaders(), retry: 0, timeout: DEFAULT_TIMEOUT_MS });
|
|
@@ -7975,8 +8654,8 @@ var NksClient = class {
|
|
|
7975
8654
|
throw toNhnCloudCliError(err);
|
|
7976
8655
|
}
|
|
7977
8656
|
}
|
|
7978
|
-
async requestJson(method,
|
|
7979
|
-
const url = `${this.nksEndpoint}${
|
|
8657
|
+
async requestJson(method, path4, payload) {
|
|
8658
|
+
const url = `${this.nksEndpoint}${path4}`;
|
|
7980
8659
|
try {
|
|
7981
8660
|
const options = { headers: this.authHeaders(), json: payload, retry: 0, timeout: DEFAULT_TIMEOUT_MS };
|
|
7982
8661
|
return method === "post" ? await import_ky14.default.post(url, options).json() : await import_ky14.default.patch(url, options).json();
|
|
@@ -8015,13 +8694,13 @@ async function resolveClusterUuid(client, cluster) {
|
|
|
8015
8694
|
}
|
|
8016
8695
|
return uuid;
|
|
8017
8696
|
}
|
|
8018
|
-
async function readJsonFile(
|
|
8697
|
+
async function readJsonFile(path4) {
|
|
8019
8698
|
let raw;
|
|
8020
8699
|
try {
|
|
8021
|
-
raw = await (0,
|
|
8700
|
+
raw = await (0, import_promises5.readFile)(path4, "utf-8");
|
|
8022
8701
|
} catch (err) {
|
|
8023
8702
|
const message = err instanceof Error ? err.message : String(err);
|
|
8024
|
-
throw new NhnCloudCliError(`JSON \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${
|
|
8703
|
+
throw new NhnCloudCliError(`JSON \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${path4} (${message})`, EXIT_PARAM_ERROR);
|
|
8025
8704
|
}
|
|
8026
8705
|
try {
|
|
8027
8706
|
const parsed = JSON.parse(raw);
|
|
@@ -8031,15 +8710,15 @@ async function readJsonFile(path5) {
|
|
|
8031
8710
|
return parsed;
|
|
8032
8711
|
} catch (err) {
|
|
8033
8712
|
const message = err instanceof Error ? err.message : String(err);
|
|
8034
|
-
throw new NhnCloudCliError(`JSON \uD30C\uC77C \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: ${
|
|
8713
|
+
throw new NhnCloudCliError(`JSON \uD30C\uC77C \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: ${path4} (${message})`, EXIT_PARAM_ERROR);
|
|
8035
8714
|
}
|
|
8036
8715
|
}
|
|
8037
|
-
async function readTextFile(
|
|
8716
|
+
async function readTextFile(path4) {
|
|
8038
8717
|
try {
|
|
8039
|
-
return await (0,
|
|
8718
|
+
return await (0, import_promises5.readFile)(path4, "utf-8");
|
|
8040
8719
|
} catch (err) {
|
|
8041
8720
|
const message = err instanceof Error ? err.message : String(err);
|
|
8042
|
-
throw new NhnCloudCliError(`\uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${
|
|
8721
|
+
throw new NhnCloudCliError(`\uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${path4} (${message})`, EXIT_PARAM_ERROR);
|
|
8043
8722
|
}
|
|
8044
8723
|
}
|
|
8045
8724
|
function parsePositiveInteger(value, optionName) {
|
|
@@ -8080,7 +8759,7 @@ var supportsCommand = new import_commander48.Command("supports").description("NK
|
|
|
8080
8759
|
});
|
|
8081
8760
|
|
|
8082
8761
|
// src/commands/nks/cluster.ts
|
|
8083
|
-
var
|
|
8762
|
+
var import_promises6 = require("fs/promises");
|
|
8084
8763
|
var import_commander49 = require("commander");
|
|
8085
8764
|
var import_chalk14 = __toESM(require("chalk"));
|
|
8086
8765
|
var listCommand8 = new import_commander49.Command("list").description("NKS \uD074\uB7EC\uC2A4\uD130 \uBAA9\uB85D\uC744 \uC870\uD68C\uD55C\uB2E4").option("--region <region>", "region override (\uAE30\uBCF8: iaas \uC790\uACA9\uC99D\uBA85\uC758 region)").option("--profile <name>", "\uC0AC\uC6A9\uD560 profile \uC774\uB984").action(async (_opts, cmd) => {
|
|
@@ -8171,18 +8850,18 @@ async function confirmDangerousAction(message, yes) {
|
|
|
8171
8850
|
}
|
|
8172
8851
|
return ok;
|
|
8173
8852
|
}
|
|
8174
|
-
async function writeKubeconfigFile(
|
|
8853
|
+
async function writeKubeconfigFile(path4, contents, force) {
|
|
8175
8854
|
try {
|
|
8176
|
-
await (0,
|
|
8855
|
+
await (0, import_promises6.writeFile)(path4, contents, {
|
|
8177
8856
|
encoding: "utf-8",
|
|
8178
8857
|
mode: 384,
|
|
8179
8858
|
flag: force ? "w" : "wx"
|
|
8180
8859
|
});
|
|
8181
|
-
await (0,
|
|
8860
|
+
await (0, import_promises6.chmod)(path4, 384);
|
|
8182
8861
|
} catch (err) {
|
|
8183
8862
|
if (err instanceof Error && "code" in err && err.code === "EEXIST") {
|
|
8184
8863
|
throw new NhnCloudCliError(
|
|
8185
|
-
`\uD30C\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4: ${
|
|
8864
|
+
`\uD30C\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4: ${path4}. \uB36E\uC5B4\uC4F0\uB824\uBA74 --force \uB97C \uC9C0\uC815\uD558\uC138\uC694.`,
|
|
8186
8865
|
EXIT_PARAM_ERROR
|
|
8187
8866
|
);
|
|
8188
8867
|
}
|
|
@@ -9001,9 +9680,9 @@ async function resolveNcsClient(opts) {
|
|
|
9001
9680
|
return { client: new NcsClient(accessToken, region, appKey), profileName };
|
|
9002
9681
|
}
|
|
9003
9682
|
function readJsonPayload(filePath) {
|
|
9004
|
-
let
|
|
9683
|
+
let stat4;
|
|
9005
9684
|
try {
|
|
9006
|
-
|
|
9685
|
+
stat4 = (0, import_node_fs9.statSync)(filePath);
|
|
9007
9686
|
} catch (err) {
|
|
9008
9687
|
const reason = err.code ?? (err instanceof Error ? err.message : String(err));
|
|
9009
9688
|
throw new NhnCloudCliError(
|
|
@@ -9011,12 +9690,12 @@ function readJsonPayload(filePath) {
|
|
|
9011
9690
|
EXIT_PARAM_ERROR
|
|
9012
9691
|
);
|
|
9013
9692
|
}
|
|
9014
|
-
if (!
|
|
9693
|
+
if (!stat4.isFile()) {
|
|
9015
9694
|
throw new NhnCloudCliError(`--file \uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4: ${filePath}`, EXIT_PARAM_ERROR);
|
|
9016
9695
|
}
|
|
9017
|
-
if (
|
|
9696
|
+
if (stat4.size > MAX_JSON_INPUT_BYTES) {
|
|
9018
9697
|
throw new NhnCloudCliError(
|
|
9019
|
-
`--file \uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4 (${
|
|
9698
|
+
`--file \uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4 (${stat4.size} \uBC14\uC774\uD2B8). JSON spec \uD55C\uB3C4 ${MAX_JSON_INPUT_BYTES} \uBC14\uC774\uD2B8.`,
|
|
9020
9699
|
EXIT_PARAM_ERROR
|
|
9021
9700
|
);
|
|
9022
9701
|
}
|
|
@@ -9747,7 +10426,7 @@ var malwareCommand = new import_commander54.Command("malware").description("NCS
|
|
|
9747
10426
|
var import_commander55 = require("commander");
|
|
9748
10427
|
|
|
9749
10428
|
// src/commands/apigateway/helpers.ts
|
|
9750
|
-
var
|
|
10429
|
+
var import_promises7 = require("fs/promises");
|
|
9751
10430
|
|
|
9752
10431
|
// src/services/apigateway/client.ts
|
|
9753
10432
|
var import_ky15 = __toESM(require("ky"));
|
|
@@ -10358,21 +11037,21 @@ function requireYes2(yes, operation) {
|
|
|
10358
11037
|
}
|
|
10359
11038
|
return true;
|
|
10360
11039
|
}
|
|
10361
|
-
async function readPluginConfigFile(
|
|
11040
|
+
async function readPluginConfigFile(path4) {
|
|
10362
11041
|
let fileStat;
|
|
10363
11042
|
try {
|
|
10364
|
-
fileStat = await (0,
|
|
11043
|
+
fileStat = await (0, import_promises7.stat)(path4);
|
|
10365
11044
|
} catch (error) {
|
|
10366
11045
|
const reason = fileErrorReason(error);
|
|
10367
11046
|
throw new NhnCloudCliError(
|
|
10368
|
-
`\uD50C\uB7EC\uADF8\uC778 \uC124\uC815 \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${JSON.stringify(
|
|
11047
|
+
`\uD50C\uB7EC\uADF8\uC778 \uC124\uC815 \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${JSON.stringify(path4)} (${JSON.stringify(reason)}).`,
|
|
10369
11048
|
EXIT_PARAM_ERROR
|
|
10370
11049
|
);
|
|
10371
11050
|
}
|
|
10372
11051
|
if (!fileStat.isFile()) {
|
|
10373
11052
|
const reason = fileStat.isDirectory() ? "EISDIR" : "EINVAL";
|
|
10374
11053
|
throw new NhnCloudCliError(
|
|
10375
|
-
`\uD50C\uB7EC\uADF8\uC778 \uC124\uC815 \uACBD\uB85C\uAC00 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4: ${JSON.stringify(
|
|
11054
|
+
`\uD50C\uB7EC\uADF8\uC778 \uC124\uC815 \uACBD\uB85C\uAC00 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4: ${JSON.stringify(path4)} (${reason}).`,
|
|
10376
11055
|
EXIT_PARAM_ERROR
|
|
10377
11056
|
);
|
|
10378
11057
|
}
|
|
@@ -10384,11 +11063,11 @@ async function readPluginConfigFile(path5) {
|
|
|
10384
11063
|
}
|
|
10385
11064
|
let raw;
|
|
10386
11065
|
try {
|
|
10387
|
-
raw = await (0,
|
|
11066
|
+
raw = await (0, import_promises7.readFile)(path4, "utf-8");
|
|
10388
11067
|
} catch (error) {
|
|
10389
11068
|
const reason = fileErrorReason(error);
|
|
10390
11069
|
throw new NhnCloudCliError(
|
|
10391
|
-
`\uD50C\uB7EC\uADF8\uC778 \uC124\uC815 \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${JSON.stringify(
|
|
11070
|
+
`\uD50C\uB7EC\uADF8\uC778 \uC124\uC815 \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${JSON.stringify(path4)} (${JSON.stringify(reason)}).`,
|
|
10392
11071
|
EXIT_PARAM_ERROR
|
|
10393
11072
|
);
|
|
10394
11073
|
}
|
|
@@ -10399,7 +11078,7 @@ async function readPluginConfigFile(path5) {
|
|
|
10399
11078
|
error instanceof Error ? error.message : String(error)
|
|
10400
11079
|
);
|
|
10401
11080
|
throw new NhnCloudCliError(
|
|
10402
|
-
`\uD50C\uB7EC\uADF8\uC778 \uC124\uC815 JSON \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: ${JSON.stringify(
|
|
11081
|
+
`\uD50C\uB7EC\uADF8\uC778 \uC124\uC815 JSON \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: ${JSON.stringify(path4)} (${reason}).`,
|
|
10403
11082
|
EXIT_PARAM_ERROR
|
|
10404
11083
|
);
|
|
10405
11084
|
}
|
|
@@ -10843,7 +11522,7 @@ var setMethodPluginCommand = addApiGatewayOptions(
|
|
|
10843
11522
|
var resourceCommand = new import_commander56.Command("resource").description("API Gateway resource \uC870\uD68C \uBC0F \uBCC0\uACBD \uBA85\uB839").addCommand(listCommand13).addCommand(parametersCommand).addCommand(responsesCommand).addCommand(setPathPluginCommand).addCommand(setMethodPluginCommand);
|
|
10844
11523
|
|
|
10845
11524
|
// src/commands/apigateway/stage.ts
|
|
10846
|
-
var
|
|
11525
|
+
var import_promises8 = require("fs/promises");
|
|
10847
11526
|
var import_commander58 = require("commander");
|
|
10848
11527
|
|
|
10849
11528
|
// src/commands/apigateway/deploy.ts
|
|
@@ -11050,9 +11729,9 @@ function fileErrorReason2(error) {
|
|
|
11050
11729
|
}
|
|
11051
11730
|
return error instanceof Error ? error.message : String(error);
|
|
11052
11731
|
}
|
|
11053
|
-
async function writeStageSwaggerFile(
|
|
11732
|
+
async function writeStageSwaggerFile(path4, swagger, force) {
|
|
11054
11733
|
try {
|
|
11055
|
-
await (0,
|
|
11734
|
+
await (0, import_promises8.writeFile)(path4, JSON.stringify(swagger, null, 2) + "\n", {
|
|
11056
11735
|
encoding: "utf-8",
|
|
11057
11736
|
flag: force ? "w" : "wx"
|
|
11058
11737
|
});
|
|
@@ -11060,7 +11739,7 @@ async function writeStageSwaggerFile(path5, swagger, force) {
|
|
|
11060
11739
|
const reason = fileErrorReason2(error);
|
|
11061
11740
|
const guidance = reason === "EEXIST" ? " \uB36E\uC5B4\uC4F0\uB824\uBA74 --force \uB97C \uC9C0\uC815\uD558\uC138\uC694." : "";
|
|
11062
11741
|
throw new NhnCloudCliError(
|
|
11063
|
-
`Swagger \uD30C\uC77C \uC800\uC7A5 \uC2E4\uD328: ${JSON.stringify(
|
|
11742
|
+
`Swagger \uD30C\uC77C \uC800\uC7A5 \uC2E4\uD328: ${JSON.stringify(path4)} (${JSON.stringify(reason)}).${guidance}`,
|
|
11064
11743
|
EXIT_PARAM_ERROR
|
|
11065
11744
|
);
|
|
11066
11745
|
}
|
|
@@ -11394,10 +12073,10 @@ var SkmClient = class {
|
|
|
11394
12073
|
* 요청을 보내고 봉투 형태인지만 확인해 반환한다. 성공 판정은 호출부가 한다.
|
|
11395
12074
|
* 쓰기 요청도 중복 실행을 막으려고 재시도하지 않는다.
|
|
11396
12075
|
*/
|
|
11397
|
-
async send(method,
|
|
12076
|
+
async send(method, path4, options) {
|
|
11398
12077
|
let response;
|
|
11399
12078
|
try {
|
|
11400
|
-
response = await import_ky16.default[method](`${this.baseUrl}${
|
|
12079
|
+
response = await import_ky16.default[method](`${this.baseUrl}${path4}`, {
|
|
11401
12080
|
headers: this.headers,
|
|
11402
12081
|
...options,
|
|
11403
12082
|
retry: 0,
|
|
@@ -11415,8 +12094,8 @@ var SkmClient = class {
|
|
|
11415
12094
|
* 요청을 보내고 봉투를 벗긴 뒤 body 또는 body[field] 를 가드로 검사해 반환한다.
|
|
11416
12095
|
* field 가 null 이면 body 전체를 검사한다.
|
|
11417
12096
|
*/
|
|
11418
|
-
async request(method,
|
|
11419
|
-
const body = unwrap(await this.send(method,
|
|
12097
|
+
async request(method, path4, field, guard, options = {}) {
|
|
12098
|
+
const body = unwrap(await this.send(method, path4, options));
|
|
11420
12099
|
const value = field === null ? body : isRecord4(body) ? body[field] : void 0;
|
|
11421
12100
|
if (!guard(value)) {
|
|
11422
12101
|
throw new NhnCloudCliError(`Secure Key Manager \uC751\uB2F5 \uD615\uC2DD \uC624\uB958: ${field ?? "body"}`, EXIT_API_ERROR);
|
|
@@ -11427,8 +12106,8 @@ var SkmClient = class {
|
|
|
11427
12106
|
* body 가 null 이거나 없는 응답(키 저장소 수정·삭제)은 검사할 필드가 없어 헤더만 본다 (ADR-040).
|
|
11428
12107
|
* isSuccessful 이 false 면 unwrapHeader 가 NhnEnvelopeError 를 던진다.
|
|
11429
12108
|
*/
|
|
11430
|
-
async requestHeaderOnly(method,
|
|
11431
|
-
unwrapHeader(await this.send(method,
|
|
12109
|
+
async requestHeaderOnly(method, path4, options = {}) {
|
|
12110
|
+
unwrapHeader(await this.send(method, path4, options));
|
|
11432
12111
|
}
|
|
11433
12112
|
keyPath(prefix, keyId, action) {
|
|
11434
12113
|
return `/${prefix}/${encodeURIComponent(keyId)}/${action}`;
|
|
@@ -11476,12 +12155,12 @@ var SkmClient = class {
|
|
|
11476
12155
|
return this.request("get", `/keystores/${keyStoreId}/keys/${encodeURIComponent(keyId)}`, null, isSkmKey);
|
|
11477
12156
|
}
|
|
11478
12157
|
listAuths(keyStoreId, type) {
|
|
11479
|
-
const { path:
|
|
11480
|
-
return this.request("get", `/keystores/${keyStoreId}/${
|
|
12158
|
+
const { path: path4, field } = AUTH_PATHS[type];
|
|
12159
|
+
return this.request("get", `/keystores/${keyStoreId}/${path4}`, field, arrayOf(isString));
|
|
11481
12160
|
}
|
|
11482
12161
|
getAuth(keyStoreId, type, value) {
|
|
11483
|
-
const { path:
|
|
11484
|
-
return this.request("get", `/keystores/${keyStoreId}/${
|
|
12162
|
+
const { path: path4, field } = AUTH_PATHS[type];
|
|
12163
|
+
return this.request("get", `/keystores/${keyStoreId}/${path4}`, field, arrayOf(isSkmAuthDetail), {
|
|
11485
12164
|
searchParams: { value }
|
|
11486
12165
|
});
|
|
11487
12166
|
}
|
|
@@ -11845,17 +12524,17 @@ function assertWithinLimit(size, spec) {
|
|
|
11845
12524
|
}
|
|
11846
12525
|
}
|
|
11847
12526
|
function readInputFile(file, spec) {
|
|
11848
|
-
let
|
|
12527
|
+
let stat4;
|
|
11849
12528
|
try {
|
|
11850
|
-
|
|
12529
|
+
stat4 = (0, import_node_fs10.statSync)(file);
|
|
11851
12530
|
} catch (e) {
|
|
11852
12531
|
const reason = e.code ?? (e instanceof Error ? e.message : String(e));
|
|
11853
12532
|
throw new NhnCloudCliError(`${spec.label} \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${file} (${reason})`, EXIT_PARAM_ERROR);
|
|
11854
12533
|
}
|
|
11855
|
-
if (!
|
|
12534
|
+
if (!stat4.isFile()) {
|
|
11856
12535
|
throw new NhnCloudCliError(`${spec.label} \uD30C\uC77C\uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4: ${file}`, EXIT_PARAM_ERROR);
|
|
11857
12536
|
}
|
|
11858
|
-
assertWithinLimit(
|
|
12537
|
+
assertWithinLimit(stat4.size, spec);
|
|
11859
12538
|
return (0, import_node_fs10.readFileSync)(file);
|
|
11860
12539
|
}
|
|
11861
12540
|
function readStdin(stdin, spec) {
|
|
@@ -11868,7 +12547,7 @@ function readStdin(stdin, spec) {
|
|
|
11868
12547
|
}
|
|
11869
12548
|
function readSkmInput(source, spec, stdin = processStdin) {
|
|
11870
12549
|
const fileFlag = spec.fileFlag ?? "--file";
|
|
11871
|
-
if (source.text !== void 0 && source.file !== void 0) {
|
|
12550
|
+
if (spec.textFlag !== void 0 && source.text !== void 0 && source.file !== void 0) {
|
|
11872
12551
|
throw new NhnCloudCliError(`${spec.textFlag}\uC640 ${fileFlag}\uC740 \uD568\uAED8 \uC9C0\uC815\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`, EXIT_PARAM_ERROR);
|
|
11873
12552
|
}
|
|
11874
12553
|
let input;
|
|
@@ -11878,6 +12557,11 @@ function readSkmInput(source, spec, stdin = processStdin) {
|
|
|
11878
12557
|
input = readInputFile(source.file, spec);
|
|
11879
12558
|
} else if (!stdin.isTTY) {
|
|
11880
12559
|
input = readStdin(stdin, spec);
|
|
12560
|
+
} else if (spec.textFlag === void 0) {
|
|
12561
|
+
throw new NhnCloudCliError(
|
|
12562
|
+
`${spec.label}\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. ${fileFlag} <\uACBD\uB85C>\uB098 \uD45C\uC900 \uC785\uB825(\uD30C\uC774\uD504)\uC73C\uB85C \uC804\uB2EC\uD558\uC138\uC694.`,
|
|
12563
|
+
EXIT_PARAM_ERROR
|
|
12564
|
+
);
|
|
11881
12565
|
} else {
|
|
11882
12566
|
throw new NhnCloudCliError(
|
|
11883
12567
|
`${spec.label}\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. ${spec.textFlag} <\uAC12>, ${fileFlag} <\uACBD\uB85C>, \uD45C\uC900 \uC785\uB825(\uD30C\uC774\uD504) \uC911 \uD558\uB098\uB85C \uC804\uB2EC\uD558\uC138\uC694.`,
|
|
@@ -12333,18 +13017,153 @@ var keyCommand = new import_commander63.Command("key").description("SKM \uD0A4 \
|
|
|
12333
13017
|
|
|
12334
13018
|
// src/commands/skm/secret.ts
|
|
12335
13019
|
var import_commander64 = require("commander");
|
|
13020
|
+
|
|
13021
|
+
// src/commands/skm/secret-json.ts
|
|
13022
|
+
var import_node_crypto6 = require("crypto");
|
|
13023
|
+
var import_node_util = require("util");
|
|
13024
|
+
var NUMBER_LITERAL = /-?\d+(\.\d+)?([eE][+-]?\d+)?/y;
|
|
13025
|
+
var MAX_SIGNIFICANT_DIGITS = 15;
|
|
13026
|
+
function tryParseSecretObject(text) {
|
|
13027
|
+
let parsed;
|
|
13028
|
+
try {
|
|
13029
|
+
parsed = JSON.parse(text);
|
|
13030
|
+
} catch {
|
|
13031
|
+
return null;
|
|
13032
|
+
}
|
|
13033
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
|
|
13034
|
+
return parsed;
|
|
13035
|
+
}
|
|
13036
|
+
function parseSecretObject(text, usage) {
|
|
13037
|
+
const object = tryParseSecretObject(text);
|
|
13038
|
+
if (object === null) {
|
|
13039
|
+
throw new NhnCloudCliError(`\uAE30\uBC00 \uB370\uC774\uD130 \uAC12\uC774 JSON \uAC1D\uCCB4\uAC00 \uC544\uB2C8\uC5B4\uC11C ${usage}\uB97C \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`, EXIT_PARAM_ERROR);
|
|
13040
|
+
}
|
|
13041
|
+
return object;
|
|
13042
|
+
}
|
|
13043
|
+
function isLossyLiteral(literal) {
|
|
13044
|
+
const value = Number(literal);
|
|
13045
|
+
if (!Number.isFinite(value) || Object.is(value, -0)) return true;
|
|
13046
|
+
if (/^-?\d+$/.test(literal)) return !Number.isSafeInteger(value);
|
|
13047
|
+
const mantissa = literal.replace(/^-/, "").replace(/[eE].*$/, "").replace(".", "");
|
|
13048
|
+
return mantissa.replace(/^0+/, "").replace(/0+$/, "").length > MAX_SIGNIFICANT_DIGITS;
|
|
13049
|
+
}
|
|
13050
|
+
function hasLossyNumber(text) {
|
|
13051
|
+
let i = 0;
|
|
13052
|
+
while (i < text.length) {
|
|
13053
|
+
const ch = text[i];
|
|
13054
|
+
if (ch === '"') {
|
|
13055
|
+
i += 1;
|
|
13056
|
+
while (i < text.length && text[i] !== '"') i += text[i] === "\\" ? 2 : 1;
|
|
13057
|
+
i += 1;
|
|
13058
|
+
continue;
|
|
13059
|
+
}
|
|
13060
|
+
if (ch === "-" || ch >= "0" && ch <= "9") {
|
|
13061
|
+
NUMBER_LITERAL.lastIndex = i;
|
|
13062
|
+
const match = NUMBER_LITERAL.exec(text);
|
|
13063
|
+
if (match === null) {
|
|
13064
|
+
i += 1;
|
|
13065
|
+
continue;
|
|
13066
|
+
}
|
|
13067
|
+
if (isLossyLiteral(match[0])) return true;
|
|
13068
|
+
i += match[0].length;
|
|
13069
|
+
continue;
|
|
13070
|
+
}
|
|
13071
|
+
i += 1;
|
|
13072
|
+
}
|
|
13073
|
+
return false;
|
|
13074
|
+
}
|
|
13075
|
+
function assertNoLossyNumber(text, usage) {
|
|
13076
|
+
if (hasLossyNumber(text)) {
|
|
13077
|
+
throw new NhnCloudCliError(
|
|
13078
|
+
`\uAE30\uBC00 \uB370\uC774\uD130\uC5D0 \uB2E4\uC2DC \uC4F0\uBA74 \uAC12\uC774 \uBC14\uB00C\uB294 \uC22B\uC790\uAC00 \uC788\uC5B4 ${usage}\uB97C \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC804\uCCB4 \uAC12\uC740 --field \uC5C6\uC774 secret get\uC73C\uB85C \uBC1B\uACE0, \uBC14\uAFC0 \uB54C\uB294 secret update\uB85C \uC804\uCCB4 \uAC12\uC744 \uBCF4\uB0B4\uC138\uC694.`,
|
|
13079
|
+
EXIT_PARAM_ERROR
|
|
13080
|
+
);
|
|
13081
|
+
}
|
|
13082
|
+
}
|
|
13083
|
+
function formatFieldValue(value) {
|
|
13084
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
13085
|
+
}
|
|
13086
|
+
function parseFieldName(value, label) {
|
|
13087
|
+
if (value === "") {
|
|
13088
|
+
throw new NhnCloudCliError(`${label}\uB294 \uBE44\uC5B4 \uC788\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`, EXIT_PARAM_ERROR);
|
|
13089
|
+
}
|
|
13090
|
+
return value;
|
|
13091
|
+
}
|
|
13092
|
+
var DEFAULT_INDENT = " ";
|
|
13093
|
+
function serializeSecretObject(object, originalText) {
|
|
13094
|
+
if (!originalText.trimEnd().includes("\n")) return JSON.stringify(object);
|
|
13095
|
+
const indent = /\n([ \t]+)\S/.exec(originalText)?.[1] ?? DEFAULT_INDENT;
|
|
13096
|
+
const serialized = JSON.stringify(object, null, indent);
|
|
13097
|
+
return originalText.endsWith("\n") ? serialized + "\n" : serialized;
|
|
13098
|
+
}
|
|
13099
|
+
function sha256Hex(text) {
|
|
13100
|
+
return (0, import_node_crypto6.createHash)("sha256").update(text, "utf8").digest("hex");
|
|
13101
|
+
}
|
|
13102
|
+
function planSecretPatch(before, field, change) {
|
|
13103
|
+
const exists = Object.hasOwn(before, field);
|
|
13104
|
+
if (change.kind === "delete") {
|
|
13105
|
+
if (!exists) return { action: "unchanged", after: before };
|
|
13106
|
+
return { action: "deleted", after: Object.fromEntries(Object.entries(before).filter(([key]) => key !== field)) };
|
|
13107
|
+
}
|
|
13108
|
+
if (!exists) {
|
|
13109
|
+
return { action: "added", after: Object.fromEntries([...Object.entries(before), [field, change.value]]) };
|
|
13110
|
+
}
|
|
13111
|
+
if (before[field] === change.value) return { action: "unchanged", after: before };
|
|
13112
|
+
if (!change.replace) {
|
|
13113
|
+
throw new NhnCloudCliError(
|
|
13114
|
+
`\uD544\uB4DC ${JSON.stringify(field)}\uAC00 \uC774\uBBF8 \uC788\uC2B5\uB2C8\uB2E4. \uAC12\uC744 \uBC14\uAFB8\uB824\uBA74 --replace\uB97C \uBD99\uC774\uC138\uC694.`,
|
|
13115
|
+
EXIT_PARAM_ERROR
|
|
13116
|
+
);
|
|
13117
|
+
}
|
|
13118
|
+
return {
|
|
13119
|
+
action: "replaced",
|
|
13120
|
+
after: Object.fromEntries(
|
|
13121
|
+
Object.entries(before).map(([key, value]) => [key, key === field ? change.value : value])
|
|
13122
|
+
)
|
|
13123
|
+
};
|
|
13124
|
+
}
|
|
13125
|
+
function entriesWithout(object, field) {
|
|
13126
|
+
return Object.entries(object).filter(([key]) => key !== field);
|
|
13127
|
+
}
|
|
13128
|
+
function verifySecretPatch(before, fetched, field, change) {
|
|
13129
|
+
if (fetched === null) return { fieldVerified: false, othersVerified: false };
|
|
13130
|
+
let fieldVerified;
|
|
13131
|
+
if (change.kind === "delete") {
|
|
13132
|
+
fieldVerified = !Object.hasOwn(fetched, field);
|
|
13133
|
+
} else {
|
|
13134
|
+
const value = Object.hasOwn(fetched, field) ? fetched[field] : void 0;
|
|
13135
|
+
fieldVerified = typeof value === "string" && sha256Hex(value) === sha256Hex(change.value);
|
|
13136
|
+
}
|
|
13137
|
+
const expected = entriesWithout(before, field);
|
|
13138
|
+
const actual = new Map(entriesWithout(fetched, field));
|
|
13139
|
+
const othersVerified = expected.length === actual.size && expected.every(([key, value]) => actual.has(key) && (0, import_node_util.isDeepStrictEqual)(actual.get(key), value));
|
|
13140
|
+
return { fieldVerified, othersVerified };
|
|
13141
|
+
}
|
|
13142
|
+
|
|
13143
|
+
// src/commands/skm/secret.ts
|
|
12336
13144
|
var getCommand13 = withSkmOptions(
|
|
12337
|
-
new import_commander64.Command("get").description("\uAE30\uBC00 \uB370\uC774\uD130\uB97C \uC870\uD68C\uD55C\uB2E4 (\uC6D0\uBB38\uC744 stdout\uC5D0 \uCD9C\uB825)").argument("<key-id>", "\uD0A4 ID")
|
|
13145
|
+
new import_commander64.Command("get").description("\uAE30\uBC00 \uB370\uC774\uD130\uB97C \uC870\uD68C\uD55C\uB2E4 (\uC6D0\uBB38\uC744 stdout\uC5D0 \uCD9C\uB825, --field\uB85C JSON \uAC1D\uCCB4\uC758 \uD544\uB4DC \uD558\uB098\uB9CC)").argument("<key-id>", "\uD0A4 ID").option("--field <name>", "JSON \uAC1D\uCCB4 \uAC12\uC5D0\uC11C \uC774 \uD544\uB4DC\uC758 \uAC12\uB9CC \uCD9C\uB825\uD55C\uB2E4")
|
|
12338
13146
|
).action(async (keyId, _opts, command) => {
|
|
12339
13147
|
const opts = command.optsWithGlobals();
|
|
12340
13148
|
const parsedKeyId = parseRequiredArgument(keyId, "key-id");
|
|
12341
13149
|
const macAddress = parseMacAddressOption(opts.macAddress);
|
|
13150
|
+
const field = opts.field === void 0 ? void 0 : parseFieldName(opts.field, "--field");
|
|
12342
13151
|
const { client } = await resolveSkmClient({ profile: opts.profile, macAddress });
|
|
12343
13152
|
const secret = await withSkmSpinner(
|
|
12344
13153
|
`SKM \uAE30\uBC00 \uB370\uC774\uD130 ${formatCell(parsedKeyId)} \uC870\uD68C \uC911...`,
|
|
12345
13154
|
() => client.getSecret(parsedKeyId)
|
|
12346
13155
|
);
|
|
12347
|
-
|
|
13156
|
+
if (field === void 0) {
|
|
13157
|
+
printSkmValue(opts, secret, { secret });
|
|
13158
|
+
return;
|
|
13159
|
+
}
|
|
13160
|
+
const object = parseSecretObject(secret, "--field");
|
|
13161
|
+
if (!Object.hasOwn(object, field)) {
|
|
13162
|
+
throw new NhnCloudCliError(`\uAE30\uBC00 \uB370\uC774\uD130\uC5D0 \uD544\uB4DC ${JSON.stringify(field)}\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.`, EXIT_PARAM_ERROR);
|
|
13163
|
+
}
|
|
13164
|
+
const value = object[field];
|
|
13165
|
+
if (typeof value !== "string") assertNoLossyNumber(secret, "--field");
|
|
13166
|
+
printSkmValue(opts, formatFieldValue(value), { keyId: parsedKeyId, field, value });
|
|
12348
13167
|
});
|
|
12349
13168
|
var updateCommand5 = withSkmOptions(
|
|
12350
13169
|
new import_commander64.Command("update").description("\uAE30\uBC00 \uB370\uC774\uD130 \uAC12\uC744 \uBC14\uAFBC\uB2E4 (\uAC12\uC740 --value, --file, \uD45C\uC900 \uC785\uB825 \uC911 \uD558\uB098)").argument("<key-id>", "\uD0A4 ID").option("--value <value>", "\uC0C8 \uAE30\uBC00 \uB370\uC774\uD130 \uAC12").option("--file <path>", "\uC0C8 \uAE30\uBC00 \uB370\uC774\uD130 \uAC12\uC744 \uC77D\uC744 \uD30C\uC77C")
|
|
@@ -12365,7 +13184,94 @@ var updateCommand5 = withSkmOptions(
|
|
|
12365
13184
|
const { secretValue: _omitted, ...result } = updated;
|
|
12366
13185
|
outputSkmWriteResult(opts, result, [formatCell(updated.keyId)]);
|
|
12367
13186
|
});
|
|
12368
|
-
var
|
|
13187
|
+
var patchCommand2 = withSkmOptions(
|
|
13188
|
+
new import_commander64.Command("patch").description("JSON \uAC1D\uCCB4 \uAE30\uBC00 \uB370\uC774\uD130\uC758 \uD544\uB4DC \uD558\uB098\uB97C \uB354\uD558\uAC70\uB098 \uBC14\uAFB8\uAC70\uB098 \uC9C0\uC6B4\uB2E4 (\uAE30\uBCF8\uC740 \uBBF8\uB9AC\uBCF4\uAE30, --yes\uB85C \uBC18\uC601)").argument("<key-id>", "\uD0A4 ID").argument("<field>", "\uD544\uB4DC \uC774\uB984 (\uCD5C\uC0C1\uC704 \uD0A4)").option("--file <path>", "\uD544\uB4DC\uC5D0 \uB123\uC744 \uAC12\uC744 \uC77D\uC744 \uD30C\uC77C (\uC5C6\uC73C\uBA74 \uD45C\uC900 \uC785\uB825)").option("--replace", "\uC774\uBBF8 \uC788\uB294 \uD544\uB4DC\uC758 \uAC12\uC744 \uBC14\uAFBC\uB2E4").option("--delete", "\uD544\uB4DC\uB97C \uC9C0\uC6B4\uB2E4").option("--yes", "\uBBF8\uB9AC\uBCF4\uAE30 \uB300\uC2E0 \uBC18\uC601\uD55C\uB2E4")
|
|
13189
|
+
).action(async (keyId, field, _opts, command) => {
|
|
13190
|
+
const opts = command.optsWithGlobals();
|
|
13191
|
+
const parsedKeyId = parseRequiredArgument(keyId, "key-id");
|
|
13192
|
+
const parsedField = parseFieldName(field, "<field>");
|
|
13193
|
+
const macAddress = parseMacAddressOption(opts.macAddress);
|
|
13194
|
+
if (opts.delete && opts.replace) {
|
|
13195
|
+
throw new NhnCloudCliError("--delete\uC640 --replace\uB294 \uD568\uAED8 \uC9C0\uC815\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
|
|
13196
|
+
}
|
|
13197
|
+
if (opts.delete && opts.file !== void 0) {
|
|
13198
|
+
throw new NhnCloudCliError("--delete\uC640 --file\uC740 \uD568\uAED8 \uC9C0\uC815\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
|
|
13199
|
+
}
|
|
13200
|
+
let change;
|
|
13201
|
+
if (opts.delete) {
|
|
13202
|
+
change = { kind: "delete" };
|
|
13203
|
+
} else {
|
|
13204
|
+
const label = "\uD544\uB4DC\uC5D0 \uB123\uC744 \uB370\uC774\uD130";
|
|
13205
|
+
const input = readSkmInput({ file: opts.file }, { label, maxBytes: MAX_JSON_INPUT_BYTES });
|
|
13206
|
+
const value = decodeUtf8Input(input, label, "\uBC14\uC774\uB108\uB9AC\uB294 base64\uB85C \uC778\uCF54\uB529\uD574 \uC804\uB2EC\uD558\uC138\uC694.");
|
|
13207
|
+
if (value.endsWith("\n")) {
|
|
13208
|
+
process.stderr.write(
|
|
13209
|
+
"\uACBD\uACE0: \uD544\uB4DC\uC5D0 \uB123\uC744 \uB370\uC774\uD130\uAC00 \uC904\uBC14\uAFC8\uC73C\uB85C \uB05D\uB0A9\uB2C8\uB2E4. \uC904\uBC14\uAFC8\uB3C4 \uAC12\uC5D0 \uB4E4\uC5B4\uAC11\uB2C8\uB2E4. \uBE7C\uB824\uBA74 printf '%s'\uB85C \uB118\uAE30\uC138\uC694.\n"
|
|
13210
|
+
);
|
|
13211
|
+
}
|
|
13212
|
+
change = { kind: "set", value, replace: opts.replace === true };
|
|
13213
|
+
}
|
|
13214
|
+
const { client } = await resolveSkmClient({ profile: opts.profile, macAddress });
|
|
13215
|
+
const id = formatCell(parsedKeyId);
|
|
13216
|
+
const current2 = await withSkmSpinner(`SKM \uAE30\uBC00 \uB370\uC774\uD130 ${id} \uC870\uD68C \uC911...`, () => client.getSecret(parsedKeyId));
|
|
13217
|
+
const before = parseSecretObject(current2, "secret patch");
|
|
13218
|
+
assertNoLossyNumber(current2, "secret patch");
|
|
13219
|
+
const { action, after } = planSecretPatch(before, parsedField, change);
|
|
13220
|
+
const report = (applied, verified2) => {
|
|
13221
|
+
const result = {
|
|
13222
|
+
keyId: parsedKeyId,
|
|
13223
|
+
field: parsedField,
|
|
13224
|
+
action,
|
|
13225
|
+
applied,
|
|
13226
|
+
fieldVerified: verified2?.fieldVerified ?? null,
|
|
13227
|
+
othersVerified: verified2?.othersVerified ?? null
|
|
13228
|
+
};
|
|
13229
|
+
outputSkmWriteResult(opts, result, [action]);
|
|
13230
|
+
};
|
|
13231
|
+
if (!opts.yes || action === "unchanged") {
|
|
13232
|
+
report(false, null);
|
|
13233
|
+
if (!opts.yes && action !== "unchanged") {
|
|
13234
|
+
process.stderr.write("\uBBF8\uB9AC\uBCF4\uAE30\uC785\uB2C8\uB2E4. \uBC18\uC601\uD558\uB824\uBA74 --yes\uB97C \uBD99\uC774\uC138\uC694.\n");
|
|
13235
|
+
}
|
|
13236
|
+
return;
|
|
13237
|
+
}
|
|
13238
|
+
try {
|
|
13239
|
+
await withSkmSpinner(
|
|
13240
|
+
`SKM \uAE30\uBC00 \uB370\uC774\uD130 ${id} \uC218\uC815 \uC911...`,
|
|
13241
|
+
() => client.updateSecret(parsedKeyId, serializeSecretObject(after, current2))
|
|
13242
|
+
);
|
|
13243
|
+
} catch (err) {
|
|
13244
|
+
const e = toNhnCloudCliError(err);
|
|
13245
|
+
throw new NhnCloudCliError(
|
|
13246
|
+
`\uAE30\uBC00 \uB370\uC774\uD130 \uC218\uC815 \uC694\uCCAD\uC774 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4: ${e.message} \uBC18\uC601\uB410\uB294\uC9C0\uB294 \uAC19\uC740 \uBA85\uB839\uC744 --yes \uC5C6\uC774 \uB2E4\uC2DC \uC2E4\uD589\uD574 action\uC73C\uB85C \uD655\uC778\uD558\uC138\uC694.`,
|
|
13247
|
+
e.exitCode
|
|
13248
|
+
);
|
|
13249
|
+
}
|
|
13250
|
+
let fetchedText;
|
|
13251
|
+
try {
|
|
13252
|
+
fetchedText = await withSkmSpinner(`SKM \uAE30\uBC00 \uB370\uC774\uD130 ${id} \uB2E4\uC2DC \uC870\uD68C \uC911...`, () => client.getSecret(parsedKeyId));
|
|
13253
|
+
} catch (err) {
|
|
13254
|
+
const e = toNhnCloudCliError(err);
|
|
13255
|
+
report(true, null);
|
|
13256
|
+
throw new NhnCloudCliError(
|
|
13257
|
+
`\uAE30\uBC00 \uB370\uC774\uD130\uB294 \uBC14\uAFE8\uC9C0\uB9CC \uB2E4\uC2DC \uC870\uD68C\uD558\uC9C0 \uBABB\uD574 \uAC80\uC99D\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${e.message} skm secret get\uC73C\uB85C \uD604\uC7AC \uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.`,
|
|
13258
|
+
EXIT_API_ERROR
|
|
13259
|
+
);
|
|
13260
|
+
}
|
|
13261
|
+
const verified = verifySecretPatch(before, tryParseSecretObject(fetchedText), parsedField, change);
|
|
13262
|
+
report(true, verified);
|
|
13263
|
+
const mismatched = [
|
|
13264
|
+
...verified.fieldVerified ? [] : [`\uD544\uB4DC ${JSON.stringify(parsedField)}`],
|
|
13265
|
+
...verified.othersVerified ? [] : ["\uB2E4\uB978 \uD544\uB4DC"]
|
|
13266
|
+
];
|
|
13267
|
+
if (mismatched.length > 0) {
|
|
13268
|
+
throw new NhnCloudCliError(
|
|
13269
|
+
`\uBC18\uC601 \uB4A4 \uB2E4\uC2DC \uC870\uD68C\uD55C \uAE30\uBC00 \uB370\uC774\uD130\uAC00 \uAE30\uB300\uC640 \uB2E4\uB985\uB2C8\uB2E4 (${mismatched.join(", ")}). \uB2E4\uB978 \uC4F0\uAE30\uAC00 \uB07C\uC5B4\uB4E4\uC5C8\uAC70\uB098 \uC2B9\uC778 \uAE30\uB2A5 \uB54C\uBB38\uC5D0 \uBCC0\uACBD\uC774 \uB300\uAE30 \uC911\uC77C \uC218 \uC788\uC2B5\uB2C8\uB2E4. skm secret get\uC73C\uB85C \uD604\uC7AC \uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.`,
|
|
13270
|
+
EXIT_API_ERROR
|
|
13271
|
+
);
|
|
13272
|
+
}
|
|
13273
|
+
});
|
|
13274
|
+
var secretCommand = new import_commander64.Command("secret").description("SKM \uAE30\uBC00 \uB370\uC774\uD130 \uC870\uD68C\uC640 \uC218\uC815").addCommand(getCommand13).addCommand(updateCommand5).addCommand(patchCommand2);
|
|
12369
13275
|
|
|
12370
13276
|
// src/commands/skm/symmetric-key.ts
|
|
12371
13277
|
var import_commander65 = require("commander");
|
|
@@ -12747,8 +13653,8 @@ var LoadBalancerClient = class {
|
|
|
12747
13653
|
}
|
|
12748
13654
|
return raw;
|
|
12749
13655
|
}
|
|
12750
|
-
async getJson(
|
|
12751
|
-
const url = `${this.endpoint}${
|
|
13656
|
+
async getJson(path4, searchParams) {
|
|
13657
|
+
const url = `${this.endpoint}${path4}`;
|
|
12752
13658
|
try {
|
|
12753
13659
|
return await import_ky17.default.get(url, {
|
|
12754
13660
|
headers: this.authHeaders(),
|
|
@@ -12760,8 +13666,8 @@ var LoadBalancerClient = class {
|
|
|
12760
13666
|
throw toNhnCloudCliError(error);
|
|
12761
13667
|
}
|
|
12762
13668
|
}
|
|
12763
|
-
async postJson(
|
|
12764
|
-
const url = `${this.endpoint}${
|
|
13669
|
+
async postJson(path4, json) {
|
|
13670
|
+
const url = `${this.endpoint}${path4}`;
|
|
12765
13671
|
try {
|
|
12766
13672
|
return await import_ky17.default.post(url, {
|
|
12767
13673
|
headers: this.authHeaders(),
|
|
@@ -12773,8 +13679,8 @@ var LoadBalancerClient = class {
|
|
|
12773
13679
|
throw toNhnCloudCliError(error);
|
|
12774
13680
|
}
|
|
12775
13681
|
}
|
|
12776
|
-
async putJson(
|
|
12777
|
-
const url = `${this.endpoint}${
|
|
13682
|
+
async putJson(path4, json) {
|
|
13683
|
+
const url = `${this.endpoint}${path4}`;
|
|
12778
13684
|
try {
|
|
12779
13685
|
return await import_ky17.default.put(url, {
|
|
12780
13686
|
headers: this.authHeaders(),
|
|
@@ -12786,8 +13692,8 @@ var LoadBalancerClient = class {
|
|
|
12786
13692
|
throw toNhnCloudCliError(error);
|
|
12787
13693
|
}
|
|
12788
13694
|
}
|
|
12789
|
-
async deleteNoContent(
|
|
12790
|
-
const url = `${this.endpoint}${
|
|
13695
|
+
async deleteNoContent(path4) {
|
|
13696
|
+
const url = `${this.endpoint}${path4}`;
|
|
12791
13697
|
try {
|
|
12792
13698
|
await import_ky17.default.delete(url, {
|
|
12793
13699
|
headers: this.authHeaders(),
|
|
@@ -13479,8 +14385,8 @@ Agent workflow:
|
|
|
13479
14385
|
3. nhncloud ncs workload get <id> --json
|
|
13480
14386
|
`;
|
|
13481
14387
|
var program = new import_commander72.Command();
|
|
13482
|
-
program.name("nhncloud").description("NHN Cloud CLI \u2014 AI agent & terminal friendly").version(CLI_VERSION).option("--json", "JSON \uD615\uC2DD\uC73C\uB85C \uCD9C\uB825").option("--quiet", "\uCD5C\uC18C \uCD9C\uB825 (\uC790\uB3D9\uD654\uC6A9)").option("--no-color", "\uC0C9\uC0C1 \uBE44\uD65C\uC131\uD654").option("--request-timeout <sec>", "HTTP \uC694\uCCAD \uD0C0\uC784\uC544\uC6C3 (\uCD08, \uAE30\uBCF8 30, \uBC94\uC704 1~3600). NHNCLOUD_REQUEST_TIMEOUT \uB85C\uB3C4 \uC9C0\uC815").addHelpText("after", rootAgentHints);
|
|
13483
|
-
program.hook("preAction", () => {
|
|
14388
|
+
program.name("nhncloud").description("NHN Cloud CLI \u2014 AI agent & terminal friendly").version(CLI_VERSION).option("--json", "JSON \uD615\uC2DD\uC73C\uB85C \uCD9C\uB825").option("--quiet", "\uCD5C\uC18C \uCD9C\uB825 (\uC790\uB3D9\uD654\uC6A9)").option("--no-color", "\uC0C9\uC0C1 \uBE44\uD65C\uC131\uD654").option("--request-timeout <sec>", "HTTP \uC694\uCCAD \uD0C0\uC784\uC544\uC6C3 (\uCD08, \uAE30\uBCF8 30, \uBC94\uC704 1~3600). NHNCLOUD_REQUEST_TIMEOUT \uB85C\uB3C4 \uC9C0\uC815").option("--proxy <url>", "HTTP \uC694\uCCAD\uC5D0 \uC4F8 \uD504\uB85D\uC2DC URL. HTTPS_PROXY\xB7HTTP_PROXY \uBCF4\uB2E4 \uC6B0\uC120\uD558\uACE0 NO_PROXY \uB294 \uADF8\uB300\uB85C \uB530\uB978\uB2E4").addHelpText("after", rootAgentHints);
|
|
14389
|
+
program.hook("preAction", async () => {
|
|
13484
14390
|
const opts = program.opts();
|
|
13485
14391
|
const rawTimeout = opts.requestTimeout ?? process.env["NHNCLOUD_REQUEST_TIMEOUT"];
|
|
13486
14392
|
const timeoutValue = rawTimeout === "" ? void 0 : rawTimeout;
|
|
@@ -13489,6 +14395,7 @@ program.hook("preAction", () => {
|
|
|
13489
14395
|
opts.requestTimeout !== void 0 ? "--request-timeout" : "NHNCLOUD_REQUEST_TIMEOUT",
|
|
13490
14396
|
{ min: 1, max: 3600 }
|
|
13491
14397
|
);
|
|
14398
|
+
const proxySettings = resolveProxySettings(opts.proxy, process.env);
|
|
13492
14399
|
if (!opts.color || process.env["NO_COLOR"]) {
|
|
13493
14400
|
import_chalk18.default.level = 0;
|
|
13494
14401
|
}
|
|
@@ -13498,6 +14405,9 @@ program.hook("preAction", () => {
|
|
|
13498
14405
|
if (timeoutSec !== void 0) {
|
|
13499
14406
|
setRequestTimeoutMs(timeoutSec * 1e3);
|
|
13500
14407
|
}
|
|
14408
|
+
if (proxySettings) {
|
|
14409
|
+
await installProxy(proxySettings);
|
|
14410
|
+
}
|
|
13501
14411
|
});
|
|
13502
14412
|
program.addCommand(configureCommand);
|
|
13503
14413
|
var logncrashCommand = new import_commander72.Command("logncrash").description("Log & Crash \uAD00\uB828 \uBA85\uB839").addHelpText("after", logncrashAgentWorkflow);
|