@clack-platform/cli 0.3.1 → 0.3.3
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 +5 -2
- package/dist/cli.js +477 -200
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -7,16 +7,18 @@ import { z as z2 } from "zod";
|
|
|
7
7
|
|
|
8
8
|
// src/core/errors.ts
|
|
9
9
|
var CliError = class extends Error {
|
|
10
|
-
constructor(message, code = "VALIDATION_ERROR", status = 400, retryAfter) {
|
|
10
|
+
constructor(message, code = "VALIDATION_ERROR", status = 400, retryAfter, recovery) {
|
|
11
11
|
super(message);
|
|
12
12
|
this.code = code;
|
|
13
13
|
this.status = status;
|
|
14
14
|
this.retryAfter = retryAfter;
|
|
15
|
+
this.recovery = recovery;
|
|
15
16
|
this.name = "CliError";
|
|
16
17
|
}
|
|
17
18
|
code;
|
|
18
19
|
status;
|
|
19
20
|
retryAfter;
|
|
21
|
+
recovery;
|
|
20
22
|
get exitCode() {
|
|
21
23
|
if (this.code === "USER_API_UNAVAILABLE") return 8;
|
|
22
24
|
if (this.status === 401) return 3;
|
|
@@ -28,6 +30,31 @@ var CliError = class extends Error {
|
|
|
28
30
|
return 1;
|
|
29
31
|
}
|
|
30
32
|
};
|
|
33
|
+
function describeDetails(details) {
|
|
34
|
+
if (!details || typeof details !== "object" || Array.isArray(details)) return [];
|
|
35
|
+
const d = details;
|
|
36
|
+
const text = (v) => typeof v === "string" && v ? v.replace(/[\p{C}]/gu, "").slice(0, 160) : typeof v === "number" || typeof v === "boolean" ? String(v) : void 0;
|
|
37
|
+
const lines = [];
|
|
38
|
+
const reason = text(d.reason);
|
|
39
|
+
if (reason) lines.push(`\uC0AC\uC720: ${reason}`);
|
|
40
|
+
const file = text(d.file);
|
|
41
|
+
if (file) lines.push(`\uD30C\uC77C: ${file}`);
|
|
42
|
+
if (Array.isArray(d.issues)) {
|
|
43
|
+
for (const issue of d.issues.slice(0, 5)) {
|
|
44
|
+
if (!issue || typeof issue !== "object") continue;
|
|
45
|
+
const i = issue;
|
|
46
|
+
const parts = [["\uD30C\uC77C", i.file], ["\uC704\uCE58", i.pointer], ["\uADDC\uCE59", i.rule], ["\uAC12", i.param]].flatMap(([label, v]) => {
|
|
47
|
+
const t = text(v);
|
|
48
|
+
return t ? [`${label}=${t}`] : [];
|
|
49
|
+
});
|
|
50
|
+
if (parts.length) lines.push(`\uBB38\uC81C: ${parts.join(" ")}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const expected = text(d.expected);
|
|
54
|
+
const actual = text(d.actual);
|
|
55
|
+
if (expected !== void 0 || actual !== void 0) lines.push(`\uAE30\uB300: ${expected ?? "-"} / \uC2E4\uC81C: ${actual ?? "-"}`);
|
|
56
|
+
return lines;
|
|
57
|
+
}
|
|
31
58
|
function apiError(status, body, retryAfter) {
|
|
32
59
|
const value2 = body && typeof body === "object" ? body : {};
|
|
33
60
|
const code = typeof value2.code === "string" ? value2.code : `HTTP_${status}`;
|
|
@@ -47,6 +74,9 @@ function apiError(status, body, retryAfter) {
|
|
|
47
74
|
if (code === "CONTENT_METADATA_EXTRAS_DISABLED") message += " \uC774 \uD658\uACBD\uC5D0\uC11C\uB294 \uC5B8\uC5B4\uBCC4 \uBA54\uD0C0\uB370\uC774\uD130\xB7\uD0DC\uADF8\uB97C \uC544\uC9C1 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.";
|
|
48
75
|
if (status === 423 || code === "USER_BANNED") message += " \uACC4\uC815 \uC81C\uD55C \uC0C1\uD0DC\uB97C \uC571\uC5D0\uC11C \uD655\uC778\uD558\uC138\uC694.";
|
|
49
76
|
if (status === 503 && code.endsWith("DISABLED")) message += " \uD604\uC7AC \uC678\uBD80 \uB3C4\uAD6C \uC811\uADFC\uC774 \uC77C\uC2DC \uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4.";
|
|
77
|
+
const located = describeDetails(value2.details);
|
|
78
|
+
if (located.length) message += `
|
|
79
|
+
${located.map((line) => ` ${line}`).join("\n")}`;
|
|
50
80
|
const raw = Number(value2.retry_after ?? retryAfter);
|
|
51
81
|
const retry = Number.isFinite(raw) && raw > 0 ? Math.ceil(raw) : void 0;
|
|
52
82
|
return new CliError(message, code, status, retry);
|
|
@@ -156,7 +186,7 @@ function redact(value2) {
|
|
|
156
186
|
// package.json
|
|
157
187
|
var package_default = {
|
|
158
188
|
name: "@clack-platform/cli",
|
|
159
|
-
version: "0.3.
|
|
189
|
+
version: "0.3.3",
|
|
160
190
|
description: "\uD074\uB799 \uACC4\uC815\uC758 \uC0C1\uD488\xB7\uCF58\uD150\uCE20\xB7\uD504\uB85C\uD544\uC744 \uAD00\uB9AC\uD558\uB294 CLI",
|
|
161
191
|
type: "module",
|
|
162
192
|
bin: {
|
|
@@ -195,7 +225,7 @@ var package_default = {
|
|
|
195
225
|
test: "node scripts/test.mjs",
|
|
196
226
|
build: "tsup src/cli.ts --format esm --target node20 --clean",
|
|
197
227
|
check: "pnpm typecheck && node scripts/check-schema-sync.mjs && pnpm test && pnpm build",
|
|
198
|
-
"check:release": "pnpm typecheck && node scripts/check-schema-sync.mjs --strict && pnpm test && pnpm build",
|
|
228
|
+
"check:release": "pnpm typecheck && node scripts/check-schema-sync.mjs --strict && node scripts/sync-vendor-types.mjs --check && pnpm test && pnpm build",
|
|
199
229
|
prepack: "pnpm build"
|
|
200
230
|
},
|
|
201
231
|
dependencies: {
|
|
@@ -607,8 +637,8 @@ async function authoringRequest(client, raw, surface = "cli") {
|
|
|
607
637
|
if (input.action === "tool") return client.request("GET", `${path}/tools/${input.call_id}`);
|
|
608
638
|
if (input.action === "fill-status") return client.request("GET", `${path}/fill/${input.job_id}`);
|
|
609
639
|
if (input.action === "upload") {
|
|
610
|
-
const
|
|
611
|
-
if (!
|
|
640
|
+
const stat4 = await lstat2(input.file);
|
|
641
|
+
if (!stat4.isFile() || stat4.isSymbolicLink() || stat4.size > 4 * 1024 * 1024 || !stat4.size) throw new CliError("\uC774\uBBF8\uC9C0\uB294 \uC77C\uBC18 \uD30C\uC77C\uC774\uBA70 4 MiB \uC774\uD558\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
|
|
612
642
|
const bytes2 = await readFile2(input.file);
|
|
613
643
|
const body2 = new FormData();
|
|
614
644
|
body2.append("field", input.field);
|
|
@@ -698,8 +728,8 @@ var ConfigStore = class {
|
|
|
698
728
|
async read(name2) {
|
|
699
729
|
const path = join(this.directory, name2);
|
|
700
730
|
try {
|
|
701
|
-
const
|
|
702
|
-
if (!
|
|
731
|
+
const stat4 = await lstat3(path);
|
|
732
|
+
if (!stat4.isFile() || stat4.isSymbolicLink()) throw new CliError("\uC124\uC815 \uD30C\uC77C\uC740 \uC77C\uBC18 \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.", "CONFIG_UNSAFE");
|
|
703
733
|
if ((name2 === "credentials.json" || name2 === "device-request.json") && process.platform !== "win32") await chmod(path, 384);
|
|
704
734
|
const body = JSON.parse(await readFile3(path, "utf8"));
|
|
705
735
|
if (!body || typeof body !== "object" || !("profiles" in body) || !body.profiles || typeof body.profiles !== "object" || Array.isArray(body.profiles)) throw new Error("\uD615\uC2DD");
|
|
@@ -2017,22 +2047,87 @@ import { Option as Option2 } from "commander";
|
|
|
2017
2047
|
|
|
2018
2048
|
// src/lib/platform-mcp.ts
|
|
2019
2049
|
import { createInterface } from "readline";
|
|
2020
|
-
import { z as
|
|
2050
|
+
import { z as z11 } from "zod";
|
|
2021
2051
|
|
|
2022
2052
|
// src/commands/skill.ts
|
|
2023
2053
|
import { spawn } from "child_process";
|
|
2024
2054
|
import { existsSync } from "fs";
|
|
2025
2055
|
import { writeFile as writeFile2 } from "fs/promises";
|
|
2026
2056
|
import { createRequire } from "module";
|
|
2027
|
-
import { join as join3, resolve as
|
|
2028
|
-
import { z as
|
|
2057
|
+
import { join as join3, resolve as resolve9 } from "path";
|
|
2058
|
+
import { z as z10 } from "zod";
|
|
2059
|
+
|
|
2060
|
+
// src/lib/content-thumbnail.ts
|
|
2061
|
+
import { readFile as readFile8, stat as stat2 } from "fs/promises";
|
|
2062
|
+
import { basename as basename3, resolve as resolve6 } from "path";
|
|
2063
|
+
import { imageSize as imageSize2 } from "image-size";
|
|
2064
|
+
import { z as z8 } from "zod";
|
|
2065
|
+
var policySchema = z8.object({
|
|
2066
|
+
thumbnail_upload_enabled: z8.boolean(),
|
|
2067
|
+
thumbnail_upload: z8.object({
|
|
2068
|
+
max_upload_bytes: z8.number().int().positive(),
|
|
2069
|
+
max_input_pixels: z8.number().int().positive(),
|
|
2070
|
+
formats: z8.array(z8.enum(["image/png", "image/jpeg", "image/webp"])).min(1)
|
|
2071
|
+
})
|
|
2072
|
+
});
|
|
2073
|
+
var thumbnailSchema = z8.object({ id: z8.uuid(), status: z8.literal("succeeded"), image_url: z8.url() });
|
|
2074
|
+
async function prepareContentThumbnail(ctx, source) {
|
|
2075
|
+
const response = await ctx.api.request("GET", "/v4/creator/config", { auth: false });
|
|
2076
|
+
const result = policySchema.safeParse(response.data);
|
|
2077
|
+
if (!result.success) throw new CliError("\uC11C\uBC84 \uC378\uB124\uC77C \uC5C5\uB85C\uB4DC \uC124\uC815\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uC11C\uBC84 \uC5C5\uB370\uC774\uD2B8 \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.", "THUMBNAIL_CONFIG_REQUIRED", 409);
|
|
2078
|
+
if (!result.data.thumbnail_upload_enabled) throw new CliError("\uC774 \uD658\uACBD\uC5D0\uC11C\uB294 \uC378\uB124\uC77C \uC5C5\uB85C\uB4DC\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. content config\uB85C \uAE30\uB2A5 \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694.", "THUMBNAIL_UPLOAD_DISABLED", 503);
|
|
2079
|
+
const policy = result.data.thumbnail_upload;
|
|
2080
|
+
const path = resolve6(source);
|
|
2081
|
+
const info = await stat2(path).catch(() => {
|
|
2082
|
+
throw new CliError("\uC378\uB124\uC77C \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", "THUMBNAIL_FILE_NOT_FOUND", 400);
|
|
2083
|
+
});
|
|
2084
|
+
if (!info.isFile() || !info.size) throw new CliError("\uBE44\uC5B4 \uC788\uC9C0 \uC54A\uC740 \uB85C\uCEEC \uC774\uBBF8\uC9C0 \uD30C\uC77C\uC744 \uC9C0\uC815\uD558\uC138\uC694.", "THUMBNAIL_EMPTY_FILE", 400);
|
|
2085
|
+
if (info.size > policy.max_upload_bytes) throw new CliError(`\uC378\uB124\uC77C\uC740 ${policy.max_upload_bytes}\uBC14\uC774\uD2B8 \uC774\uD558\uC5EC\uC57C \uD569\uB2C8\uB2E4.`, "THUMBNAIL_TOO_LARGE", 413);
|
|
2086
|
+
const bytes2 = await readFile8(path).catch(() => {
|
|
2087
|
+
throw new CliError("\uC378\uB124\uC77C \uD30C\uC77C\uC744 \uC77D\uC744 \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.", "THUMBNAIL_FILE_UNREADABLE", 400);
|
|
2088
|
+
});
|
|
2089
|
+
if (!bytes2.length || bytes2.length > policy.max_upload_bytes) throw new CliError("\uC77D\uB294 \uB3D9\uC548 \uC378\uB124\uC77C \uD06C\uAE30\uAC00 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uD30C\uC77C\uC744 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.", "THUMBNAIL_TOO_LARGE", 413);
|
|
2090
|
+
let mime;
|
|
2091
|
+
try {
|
|
2092
|
+
const image2 = imageSize2(bytes2);
|
|
2093
|
+
mime = { png: "image/png", jpg: "image/jpeg", webp: "image/webp" }[image2.type ?? ""] ?? "";
|
|
2094
|
+
if (!policy.formats.includes(mime) || !image2.width || !image2.height || image2.width * image2.height > policy.max_input_pixels) throw new Error();
|
|
2095
|
+
} catch {
|
|
2096
|
+
throw new CliError("\uC11C\uBC84\uAC00 \uC9C0\uC6D0\uD558\uB294 PNG\xB7JPEG\xB7WebP \uC774\uBBF8\uC9C0\uC640 \uC720\uD6A8\uD55C \uD06C\uAE30\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \uC190\uC0C1\uB41C \uD30C\uC77C\uC740 \uB2E4\uC2DC \uC800\uC7A5\uD558\uC138\uC694.", "THUMBNAIL_INVALID_IMAGE", 422);
|
|
2097
|
+
}
|
|
2098
|
+
return { path, bytes: bytes2, mime };
|
|
2099
|
+
}
|
|
2100
|
+
async function uploadContentThumbnail(ctx, image2) {
|
|
2101
|
+
const body = new FormData();
|
|
2102
|
+
body.append("file", new Blob([new Uint8Array(image2.bytes)], { type: image2.mime }), basename3(image2.path));
|
|
2103
|
+
const response = await ctx.api.request("POST", "/v4/creator/thumbnails", { body });
|
|
2104
|
+
const parsed = thumbnailSchema.safeParse(response.data);
|
|
2105
|
+
if (!parsed.success) throw new CliError("\uC644\uB8CC\uB41C \uC378\uB124\uC77C \uC791\uC5C5 ID\uB97C \uC751\uB2F5\uC5D0\uC11C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC790\uB3D9 \uC7AC\uC5C5\uB85C\uB4DC\uD558\uC9C0 \uB9C8\uC138\uC694.", "INVALID_RESPONSE", 502);
|
|
2106
|
+
return { data: parsed.data, time_contract: response.time_contract };
|
|
2107
|
+
}
|
|
2108
|
+
function thumbnailLinkFailure(ctx, cause, thumbnailId, contentId, creation) {
|
|
2109
|
+
const failure = asCliError(cause);
|
|
2110
|
+
const quote = (value2) => `'${value2.replaceAll("'", "'\\''")}'`;
|
|
2111
|
+
const prefix = `clack --base-url ${quote(ctx.api.settings.baseUrl)}${ctx.options.profile ? ` --profile ${quote(ctx.options.profile)}` : ""}`;
|
|
2112
|
+
const createArgs = ["title", "description", "kind", "policy_version"].flatMap((key) => creation?.[key] === void 0 ? [] : [`--${key.replaceAll("_", "-")} ${quote(String(creation[key]))}`]).join(" ");
|
|
2113
|
+
const command = contentId ? `${prefix} content update ${contentId} --thumbnail-id ${thumbnailId}` : `${prefix} content create ${createArgs} --thumbnail-id ${thumbnailId}`;
|
|
2114
|
+
const verify = contentId ? `${prefix} content status ${contentId}` : `${prefix} content list`;
|
|
2115
|
+
return new CliError(
|
|
2116
|
+
`${failure.message}
|
|
2117
|
+
\uC378\uB124\uC77C \uC5C5\uB85C\uB4DC\uB294 \uC644\uB8CC\uB410\uC2B5\uB2C8\uB2E4 (ID: ${thumbnailId}). ${verify}\uB85C \uC800\uC7A5 \uC5EC\uBD80\uB97C \uD655\uC778\uD55C \uB4A4 ${command}\uB85C \uC5F0\uACB0\uD558\uC138\uC694.`,
|
|
2118
|
+
failure.code,
|
|
2119
|
+
failure.status,
|
|
2120
|
+
failure.retryAfter,
|
|
2121
|
+
{ thumbnail_id: thumbnailId, ...contentId ? { content_id: contentId } : {}, verification_command: verify, retry_command: command }
|
|
2122
|
+
);
|
|
2123
|
+
}
|
|
2029
2124
|
|
|
2030
2125
|
// src/commands/content.ts
|
|
2031
2126
|
import { createHash as createHash2 } from "crypto";
|
|
2032
|
-
import { readFile as
|
|
2033
|
-
import { basename as
|
|
2127
|
+
import { readFile as readFile9, stat as stat3 } from "fs/promises";
|
|
2128
|
+
import { basename as basename4, extname, resolve as resolve7 } from "path";
|
|
2034
2129
|
import { Option } from "commander";
|
|
2035
|
-
import { z as
|
|
2130
|
+
import { z as z9 } from "zod";
|
|
2036
2131
|
|
|
2037
2132
|
// src/lib/content-package.ts
|
|
2038
2133
|
import { unzipSync } from "fflate";
|
|
@@ -2164,28 +2259,29 @@ function inspectContentPackage(bytes2) {
|
|
|
2164
2259
|
|
|
2165
2260
|
// src/commands/content.ts
|
|
2166
2261
|
var MAX_BYTES = 30 * 1024 * 1024;
|
|
2167
|
-
var uuid = (value2) => parse(
|
|
2168
|
-
var createSchema =
|
|
2169
|
-
title:
|
|
2170
|
-
description:
|
|
2171
|
-
kind:
|
|
2172
|
-
policy_version:
|
|
2262
|
+
var uuid = (value2) => parse(z9.uuid(), value2);
|
|
2263
|
+
var createSchema = z9.object({
|
|
2264
|
+
title: z9.string().trim().min(1).max(120),
|
|
2265
|
+
description: z9.string().trim().max(2e3).default(""),
|
|
2266
|
+
kind: z9.enum(["html", "gallery", "slideshow", "video"]).default("html"),
|
|
2267
|
+
policy_version: z9.literal("2026-09-22"),
|
|
2268
|
+
thumbnail_id: z9.uuid().nullable().optional()
|
|
2173
2269
|
}).strict();
|
|
2174
2270
|
var METADATA_LANGS = ["ko", "en"];
|
|
2175
2271
|
var TAG_PATTERN = /^[\p{L}\p{M}\p{N}_]{1,30}$/u;
|
|
2176
|
-
var localizedEntry =
|
|
2177
|
-
title:
|
|
2178
|
-
description:
|
|
2272
|
+
var localizedEntry = z9.object({
|
|
2273
|
+
title: z9.string().trim().max(120),
|
|
2274
|
+
description: z9.string().trim().max(2e3).optional()
|
|
2179
2275
|
}).strict();
|
|
2180
|
-
var updateSchema =
|
|
2181
|
-
title:
|
|
2182
|
-
description:
|
|
2183
|
-
kind:
|
|
2184
|
-
thumbnail_id:
|
|
2185
|
-
metadata_mode:
|
|
2186
|
-
metadata_lang:
|
|
2187
|
-
localized_metadata:
|
|
2188
|
-
tags:
|
|
2276
|
+
var updateSchema = z9.object({
|
|
2277
|
+
title: z9.string().trim().max(120).optional(),
|
|
2278
|
+
description: z9.string().trim().max(2e3).optional(),
|
|
2279
|
+
kind: z9.enum(["html", "gallery", "slideshow", "video"]).optional(),
|
|
2280
|
+
thumbnail_id: z9.uuid().nullable().optional(),
|
|
2281
|
+
metadata_mode: z9.enum(["single", "localized"]).optional(),
|
|
2282
|
+
metadata_lang: z9.enum(METADATA_LANGS).nullable().optional(),
|
|
2283
|
+
localized_metadata: z9.partialRecord(z9.enum(METADATA_LANGS), localizedEntry).nullable().optional(),
|
|
2284
|
+
tags: z9.array(z9.string().max(64)).max(50).optional()
|
|
2189
2285
|
}).strict().superRefine((value2, ctx) => {
|
|
2190
2286
|
const issue = (message) => ctx.addIssue({ code: "custom", message });
|
|
2191
2287
|
if (!Object.values(value2).some((entry) => entry !== void 0)) issue("\uBCC0\uACBD\uD560 \uD544\uB4DC\uB97C \uD558\uB098 \uC774\uC0C1 \uC9C0\uC815\uD558\uC138\uC694.");
|
|
@@ -2221,14 +2317,14 @@ function jsonOption(name2, value2) {
|
|
|
2221
2317
|
}
|
|
2222
2318
|
}
|
|
2223
2319
|
async function prepareContentFile(source) {
|
|
2224
|
-
const file =
|
|
2320
|
+
const file = resolve7(source);
|
|
2225
2321
|
const extension = extname(file).toLowerCase();
|
|
2226
2322
|
if (![".html", ".htm", ".zip"].includes(extension)) throw new CliError("HTML \uB610\uB294 ZIP \uD30C\uC77C\uC744 \uC9C0\uC815\uD558\uC138\uC694.");
|
|
2227
2323
|
let bytes2;
|
|
2228
2324
|
try {
|
|
2229
|
-
const info = await
|
|
2325
|
+
const info = await stat3(file);
|
|
2230
2326
|
if (!info.isFile() || info.size === 0 || info.size > MAX_BYTES) throw new Error();
|
|
2231
|
-
bytes2 = await
|
|
2327
|
+
bytes2 = await readFile9(file);
|
|
2232
2328
|
if (!bytes2.length || bytes2.length > MAX_BYTES) throw new Error();
|
|
2233
2329
|
} catch {
|
|
2234
2330
|
throw new CliError("30 MiB \uC774\uD558\uC758 \uBE44\uC5B4 \uC788\uC9C0 \uC54A\uC740 \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC788\uC5B4\uC57C \uD569\uB2C8\uB2E4.");
|
|
@@ -2237,7 +2333,7 @@ async function prepareContentFile(source) {
|
|
|
2237
2333
|
bytes: bytes2,
|
|
2238
2334
|
warnings: extension === ".zip" ? inspectContentPackage(bytes2) : [],
|
|
2239
2335
|
metadata: {
|
|
2240
|
-
filename:
|
|
2336
|
+
filename: basename4(file),
|
|
2241
2337
|
content_type: extension === ".zip" ? "application/zip" : "text/html",
|
|
2242
2338
|
byte_size: bytes2.length,
|
|
2243
2339
|
sha256: createHash2("sha256").update(bytes2).digest("hex")
|
|
@@ -2272,8 +2368,25 @@ async function putContentFile(session2, bytes2, fetcher = fetch) {
|
|
|
2272
2368
|
throw new CliError("\uD30C\uC77C \uC5C5\uB85C\uB4DC\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uC0C8 \uC5C5\uB85C\uB4DC\uB97C \uC2DC\uC791\uD558\uC138\uC694.", "CONTENT_UPLOAD_FAILED", 0);
|
|
2273
2369
|
}
|
|
2274
2370
|
}
|
|
2371
|
+
async function saveWithThumbnail(ctx, method, path, body, file, contentId) {
|
|
2372
|
+
if (!file) {
|
|
2373
|
+
await mutate(ctx, method, path, body);
|
|
2374
|
+
return;
|
|
2375
|
+
}
|
|
2376
|
+
const image2 = await prepareContentThumbnail(ctx, file);
|
|
2377
|
+
if (ctx.options.dryRun) {
|
|
2378
|
+
ctx.output({ dry_run: true, method, path, body: { ...body, thumbnail_id: "<\uC5C5\uB85C\uB4DC \uD6C4 \uBC1C\uAE09>" }, thumbnail: { file: image2.path, byte_size: image2.bytes.length } });
|
|
2379
|
+
return;
|
|
2380
|
+
}
|
|
2381
|
+
const uploaded = await uploadContentThumbnail(ctx, image2);
|
|
2382
|
+
try {
|
|
2383
|
+
ctx.output(await ctx.api.request(method, path, { body: { ...body, thumbnail_id: uploaded.data.id } }));
|
|
2384
|
+
} catch (failure) {
|
|
2385
|
+
throw thumbnailLinkFailure(ctx, failure, uploaded.data.id, contentId, method === "POST" ? body : void 0);
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2275
2388
|
var SERVER_KEY_CENTER_ONLY = "\uC11C\uBC84 \uD0A4 \uBC1C\uAE09\xB7\uD68C\uC804\uC740 \uD06C\uB9AC\uC5D0\uC774\uD130 \uC13C\uD130(\uB0B4 \uCF58\uD150\uCE20 \u2192 \uC11C\uBC84 \uD0A4)\uC5D0\uC11C\uB9CC \uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. CLI\xB7MCP\uC758 \uAC1C\uC778 \uC561\uC138\uC2A4 \uD1A0\uD070\uC73C\uB85C\uB294 \uC11C\uBC84 \uD0A4 \uC870\uD68C\xB7\uD3D0\uAE30\uB9CC \uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.";
|
|
2276
|
-
var collection =
|
|
2389
|
+
var collection = z9.string().regex(/^[A-Za-z0-9_-]{1,64}$/, "\uC774\uB984\uC740 \uC601\uC22B\uC790\xB7\uBC11\uC904\xB7\uBD99\uC784\uD45C 64\uC790 \uC774\uD558\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
|
|
2277
2390
|
var documentKey = collection;
|
|
2278
2391
|
var keyId = (value2) => {
|
|
2279
2392
|
const id2 = String(value2);
|
|
@@ -2285,22 +2398,41 @@ function registerContentCommands(program2, runtime2) {
|
|
|
2285
2398
|
runtime2.action(content.command("config").description("\uCF58\uD150\uCE20 \uAE30\uB2A5 \uC81C\uACF5 \uC5EC\uBD80\xB7\uC124\uC815 \uC870\uD68C (\uB85C\uADF8\uC778 \uBD88\uD544\uC694)"), async (ctx) => ctx.output(await ctx.api.request("GET", "/v4/creator/config", { auth: false })));
|
|
2286
2399
|
runtime2.action(content.command("list").description("\uB0B4 \uCF58\uD150\uCE20 \uBAA9\uB85D (creator-content:read)"), async (ctx) => ctx.output(await ctx.api.request("GET", "/v4/creator/contents")));
|
|
2287
2400
|
runtime2.action(content.command("status <id>").description("\uCF58\uD150\uCE20\uC640 \uBC84\uC804\uBCC4 \uC5C5\uB85C\uB4DC\xB7\uC2EC\uC0AC\xB7\uACF5\uAC1C \uC0C1\uD0DC (creator-content:read)"), async (ctx, [id2]) => ctx.output(await ctx.api.request("GET", `/v4/creator/contents/${uuid(id2)}`)));
|
|
2288
|
-
runtime2.action(content.command("create").description("\uCF58\uD150\uCE20 \uCD08\uC548 \uB4F1\uB85D (creator-content:write)").requiredOption("--title <text>", "\uC81C\uBAA9").option("--description <text>", "\uC124\uBA85", "").option("--kind <kind>", "html|gallery|slideshow|video", "html").requiredOption("--policy-version <version>", "\uB3D9\uC758\uD55C \uCF58\uD150\uCE20 \uC81C\uACF5 \uC815\uCC45 \uBC84\uC804"), async (ctx, _args, opts) => {
|
|
2289
|
-
const body = parse(createSchema, { title: opts.title, description: opts.description, kind: opts.kind, policy_version: opts.policyVersion });
|
|
2290
|
-
await
|
|
2401
|
+
runtime2.action(content.command("create").description("\uCF58\uD150\uCE20 \uCD08\uC548 \uB4F1\uB85D (creator-content:write)").requiredOption("--title <text>", "\uC81C\uBAA9").option("--description <text>", "\uC124\uBA85", "").option("--kind <kind>", "html|gallery|slideshow|video", "html").requiredOption("--policy-version <version>", "\uB3D9\uC758\uD55C \uCF58\uD150\uCE20 \uC81C\uACF5 \uC815\uCC45 \uBC84\uC804").addOption(new Option("--thumbnail-file <file>", "\uB85C\uCEEC \uC378\uB124\uC77C \uC774\uBBF8\uC9C0 \uC5C5\uB85C\uB4DC \uD6C4 \uC5F0\uACB0").conflicts("thumbnailId")).addOption(new Option("--thumbnail-id <uuid|none>", "\uBC1C\uAE09\uBC1B\uC740 \uC378\uB124\uC77C ID \uB610\uB294 \uAE30\uBCF8 \uC774\uBBF8\uC9C0").conflicts("thumbnailFile")), async (ctx, _args, opts) => {
|
|
2402
|
+
const body = parse(createSchema, { title: opts.title, description: opts.description, kind: opts.kind, policy_version: opts.policyVersion, thumbnail_id: opts.thumbnailId === void 0 ? void 0 : opts.thumbnailId === "none" ? null : opts.thumbnailId });
|
|
2403
|
+
await saveWithThumbnail(ctx, "POST", "/v4/creator/contents", body, opts.thumbnailFile);
|
|
2291
2404
|
});
|
|
2292
|
-
runtime2.action(content.command("update <id>").description("\uCF58\uD150\uCE20 \uC815\uBCF4(\uC81C\uBAA9\xB7\uC124\uBA85\xB7\uC885\uB958\xB7\uC378\uB124\uC77C\xB7\uBA54\uD0C0\uB370\uC774\uD130\xB7\uD0DC\uADF8) \uC218\uC815 (creator-content:write)").option("--title <text>", "\uC81C\uBAA9 (120\uC790 \uC774\uD558, \uBE48 \uAC12\uC774\uBA74 \uC81C\uBAA9 \uC5C6\uC74C)").option("--description <text>", "\uC124\uBA85 (2000\uC790 \uC774\uD558)").addOption(new Option("--kind <kind>", "\uCF58\uD150\uCE20 \uC885\uB958").choices(["html", "gallery", "slideshow", "video"])).
|
|
2405
|
+
runtime2.action(content.command("update <id>").description("\uCF58\uD150\uCE20 \uC815\uBCF4(\uC81C\uBAA9\xB7\uC124\uBA85\xB7\uC885\uB958\xB7\uC378\uB124\uC77C\xB7\uBA54\uD0C0\uB370\uC774\uD130\xB7\uD0DC\uADF8) \uC218\uC815 (creator-content:write)").option("--title <text>", "\uC81C\uBAA9 (120\uC790 \uC774\uD558, \uBE48 \uAC12\uC774\uBA74 \uC81C\uBAA9 \uC5C6\uC74C)").option("--description <text>", "\uC124\uBA85 (2000\uC790 \uC774\uD558)").addOption(new Option("--kind <kind>", "\uCF58\uD150\uCE20 \uC885\uB958").choices(["html", "gallery", "slideshow", "video"])).addOption(new Option("--thumbnail-id <uuid|none>", "\uC378\uB124\uC77C \uC791\uC5C5 ID, none\uC774\uBA74 \uAE30\uBCF8 \uC774\uBBF8\uC9C0\uB85C \uB418\uB3CC\uB9BC").conflicts("thumbnailFile")).addOption(new Option("--thumbnail-file <file>", "\uB85C\uCEEC \uC378\uB124\uC77C \uC774\uBBF8\uC9C0 \uC5C5\uB85C\uB4DC \uD6C4 \uC5F0\uACB0").conflicts("thumbnailId")).addOption(new Option("--metadata-mode <mode>", "\uBA54\uD0C0\uB370\uC774\uD130 \uC785\uB825 \uBC29\uC2DD").choices(["single", "localized"])).option("--metadata-lang <ko|en|none>", "\uB300\uD45C \uC5B8\uC5B4").option("--localized-metadata <json|none>", `\uB300\uD45C \uC5B8\uC5B4 \uC678 \uC5B8\uC5B4\uBCC4 \uC81C\uBAA9\xB7\uC124\uBA85 JSON, \uC608: '{"en":{"title":"Title","description":"About"}}'`).option("--tags <list>", "\uD574\uC2DC\uD0DC\uADF8\uB97C \uC27C\uD45C\uB85C \uAD6C\uBD84\uD574 \uD1B5\uC9F8 \uAD50\uCCB4, \uBE48 \uBB38\uC790\uC5F4\uC774\uBA74 \uBAA8\uB450 \uC0AD\uC81C"), async (ctx, [id2], opts) => {
|
|
2293
2406
|
const body = parse(updateSchema, {
|
|
2294
2407
|
title: opts.title,
|
|
2295
2408
|
description: opts.description,
|
|
2296
2409
|
kind: opts.kind,
|
|
2297
|
-
thumbnail_id: opts.thumbnailId === void 0 ? void 0 : opts.thumbnailId === "none" ? null : opts.thumbnailId,
|
|
2410
|
+
thumbnail_id: opts.thumbnailFile ? null : opts.thumbnailId === void 0 ? void 0 : opts.thumbnailId === "none" ? null : opts.thumbnailId,
|
|
2298
2411
|
metadata_mode: opts.metadataMode,
|
|
2299
2412
|
metadata_lang: opts.metadataLang === void 0 ? void 0 : opts.metadataLang === "none" ? null : opts.metadataLang,
|
|
2300
2413
|
localized_metadata: opts.localizedMetadata === void 0 ? void 0 : jsonOption("--localized-metadata", opts.localizedMetadata),
|
|
2301
2414
|
tags: opts.tags === void 0 ? void 0 : csv(opts.tags)
|
|
2302
2415
|
});
|
|
2303
|
-
await
|
|
2416
|
+
await saveWithThumbnail(ctx, "PATCH", `/v4/creator/contents/${uuid(id2)}`, body, opts.thumbnailFile, uuid(id2));
|
|
2417
|
+
});
|
|
2418
|
+
runtime2.action(content.command("thumbnail <file>").description("\uB85C\uCEEC \uC378\uB124\uC77C \uC5C5\uB85C\uB4DC\uC640 \uC120\uD0DD\uC801 \uCF58\uD150\uCE20 \uC5F0\uACB0 (creator-content:write)").option("--content <uuid>", "\uC5C5\uB85C\uB4DC \uD6C4 \uC774 \uCF58\uD150\uCE20\uC5D0 \uC5F0\uACB0"), async (ctx, [file], opts) => {
|
|
2419
|
+
const contentId = opts.content === void 0 ? void 0 : uuid(opts.content);
|
|
2420
|
+
const image2 = await prepareContentThumbnail(ctx, file);
|
|
2421
|
+
if (ctx.options.dryRun) {
|
|
2422
|
+
ctx.output({ dry_run: true, path: "/v4/creator/thumbnails", file: image2.path, byte_size: image2.bytes.length, ...contentId ? { content_id: contentId } : {} });
|
|
2423
|
+
return;
|
|
2424
|
+
}
|
|
2425
|
+
const uploaded = await uploadContentThumbnail(ctx, image2);
|
|
2426
|
+
if (!contentId) {
|
|
2427
|
+
ctx.output(uploaded);
|
|
2428
|
+
return;
|
|
2429
|
+
}
|
|
2430
|
+
try {
|
|
2431
|
+
const result = await ctx.api.request("PATCH", `/v4/creator/contents/${contentId}`, { body: { thumbnail_id: uploaded.data.id } });
|
|
2432
|
+
ctx.output({ ...result, thumbnail: uploaded.data });
|
|
2433
|
+
} catch (failure) {
|
|
2434
|
+
throw thumbnailLinkFailure(ctx, failure, uploaded.data.id, contentId);
|
|
2435
|
+
}
|
|
2304
2436
|
});
|
|
2305
2437
|
runtime2.action(content.command("upload <id> <file>").description("HTML/ZIP \uC5C5\uB85C\uB4DC\uB85C \uC0C8 \uBE44\uACF5\uAC1C \uBC84\uC804 \uC0DD\uC131 (creator-content:write)").addOption(new Option("--header <mode>", "\uD5E4\uB354 \uD45C\uC2DC").choices(["fixed", "scroll_hide", "translucent_scroll_hide", "floating_close", "floating_close_safe_area"])).addOption(new Option("--color <scheme>", "\uD5E4\uB354 \uC0C9\uC0C1").choices(["light", "dark"])), async (ctx, [id2, file], opts) => {
|
|
2306
2438
|
const path = `/v4/creator/contents/${uuid(id2)}`;
|
|
@@ -2406,15 +2538,52 @@ function dataRootField(schema, name2) {
|
|
|
2406
2538
|
}
|
|
2407
2539
|
return field2;
|
|
2408
2540
|
}
|
|
2409
|
-
|
|
2541
|
+
var SEMANTICS_NOTES = {
|
|
2542
|
+
// 스킬 에디터 선언
|
|
2543
|
+
editor_document_permissions: () => "\uC5D0\uB514\uD130\uC5D0\uB294 document.read\uC640 document.write \uAD8C\uD55C\uC774 \uBAA8\uB450 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2544
|
+
ai_suggest_needs_ai_fill: () => "ai.suggest \uAD8C\uD55C\uC5D0\uB294 authoring.ai_fill.enabled\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2545
|
+
image_permission_needs_tool: () => "tools.image.generate \uAD8C\uD55C\uC5D0\uB294 authoring.tools\uC758 image.generate \uC120\uC5B8\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2546
|
+
editor_slot_aspect: () => "\uC5D0\uB514\uD130 \uC2A4\uD0AC\uC740 \uC2AC\uB86F \uBE44\uC728(aspect: slot)\uC744 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC790\uC0B0 \uB178\uB4DC\uC758 x-clack-asset.aspect\uB97C \uC4F0\uC138\uC694.",
|
|
2547
|
+
asset_limits_missing: () => "\uC790\uC0B0 \uB178\uB4DC\uAC00 \uC788\uB294 \uB370\uC774\uD130 \uC2A4\uD0A4\uB9C8\uC5D0\uB294 output.data.assets \uD55C\uB3C4\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2548
|
+
asset_limits_unused: () => "\uC790\uC0B0 \uB178\uB4DC\uAC00 \uC5C6\uB294\uB370 \uC790\uC0B0 \uD55C\uB3C4\uB97C \uC120\uC5B8\uD588\uC2B5\uB2C8\uB2E4.",
|
|
2549
|
+
image_permission_no_asset: () => "\uC774\uBBF8\uC9C0\uB97C \uB123\uC744 \uC790\uC0B0 \uB178\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2550
|
+
ai_suggest_no_node: () => "x-clack-ai.suggest\uAC00 \uCF1C\uC9C4 \uB178\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2551
|
+
metadata_text_key: () => "\uACF5\uAC1C \uBB38\uC790\uC5F4 \uB8E8\uD2B8 \uD0A4\uB97C \uAC00\uB9AC\uCF1C\uC57C \uD569\uB2C8\uB2E4.",
|
|
2552
|
+
metadata_asset_key: () => "\uACF5\uAC1C \uC790\uC0B0 \uB8E8\uD2B8 \uD0A4\uB97C \uAC00\uB9AC\uCF1C\uC57C \uD569\uB2C8\uB2E4(\uC778\uB371\uC2A4 \uD45C\uAE30 \uBD88\uAC00).",
|
|
2553
|
+
// 콘텐츠 인트로
|
|
2554
|
+
intro_image_not_slot: () => "\uC778\uD2B8\uB85C \uC774\uBBF8\uC9C0\uB294 output.asset_slots\uC758 \uD544\uB4DC\uB9CC \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
2555
|
+
intro_images_over: ({ max }) => `\uC778\uD2B8\uB85C \uC774\uBBF8\uC9C0\uB294 \uC2AC\uB86F \uCD5C\uB300 \uC7A5\uC218 \uD569\uACC4\uAC00 ${max}\uC7A5 \uC774\uD558\uC5EC\uC57C \uD569\uB2C8\uB2E4.`,
|
|
2556
|
+
intro_text_field: () => "\uACF5\uAC1C \uBB38\uC790\uC5F4(text\xB7textarea) \uD3FC \uD544\uB4DC\uB97C \uAC00\uB9AC\uCF1C\uC57C \uD569\uB2C8\uB2E4.",
|
|
2557
|
+
intro_text_too_long: ({ max }) => `\uAC00\uB9AC\uD0A4\uB294 \uD3FC \uD544\uB4DC\uC758 \uCD5C\uB300 \uAE38\uC774\uAC00 ${max}\uC790 \uC774\uD558\uC5EC\uC57C \uD569\uB2C8\uB2E4.`,
|
|
2558
|
+
intro_section_field: () => "\uC18C\uAC1C \uC139\uC158\uC740 \uACF5\uAC1C \uBB38\uC790\uC5F4(text\xB7textarea) \uD3FC \uD544\uB4DC\uB9CC \uAC00\uB9AC\uD0AC \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
2559
|
+
intro_section_too_long: () => "\uC18C\uAC1C \uC139\uC158\uC758 \uCD5C\uB300 \uAE38\uC774\uB294 2,000\uC790\uC785\uB2C8\uB2E4.",
|
|
2560
|
+
intro_sections_total: () => "\uC18C\uAC1C \uC139\uC158\uC758 \uCD5C\uB300 \uAE38\uC774 \uD569\uACC4\uB294 6,000\uC790\uC785\uB2C8\uB2E4.",
|
|
2561
|
+
intro_fallback_field: () => "\uBB38\uC790\uC5F4(text\xB7textarea) \uD3FC \uD544\uB4DC\uB9CC \uC790\uB3D9 \uAD6C\uC131\uC5D0 \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
2562
|
+
intro_fallback_too_long: ({ max }) => `\uC790\uB3D9 \uAD6C\uC131 \uCD5C\uB300 \uAE38\uC774(\uB77C\uBCA8 \uD3EC\uD568)\uAC00 ${max}\uC790\uB97C \uB118\uC2B5\uB2C8\uB2E4.`,
|
|
2563
|
+
// 도구·이미지 슬롯
|
|
2564
|
+
tool_duplicate: () => "\uB3C4\uAD6C \uC774\uB984\uC744 \uC911\uBCF5 \uC120\uC5B8\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2565
|
+
tool_batch_over_calls: () => "\uC77C\uAD04 \uC0DD\uC131 \uC218\uB294 \uC138\uC158 \uD638\uCD9C \uC218\uB97C \uB118\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2566
|
+
slot_field_duplicate: () => "\uC2AC\uB86F \uD544\uB4DC\uB294 \uC911\uBCF5\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2567
|
+
slot_multiple_range: () => "\uB2E4\uC911 \uC2AC\uB86F \uCD5C\uC18C \uC218\uB294 \uCD5C\uB300 \uC218\uBCF4\uB2E4 \uD074 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2568
|
+
slot_path_duplicate: () => "\uC2AC\uB86F \uD30C\uC77C \uACBD\uB85C\uB294 \uC911\uBCF5\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2569
|
+
slot_widget_mismatch: () => "\uC2AC\uB86F\uACFC \uC774\uBBF8\uC9C0 \uC704\uC82F \uC885\uB958\uAC00 \uC77C\uCE58\uD574\uC57C \uD569\uB2C8\uB2E4.",
|
|
2570
|
+
// 폼 필드 참조
|
|
2571
|
+
form_field_missing: () => "\uC120\uC5B8\uD55C \uD3FC \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2572
|
+
slot_index_invalid: () => "\uB2E4\uC911 \uC774\uBBF8\uC9C0 \uC2AC\uB86F\uC758 \uC720\uD6A8\uD55C \uC778\uB371\uC2A4\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2573
|
+
content_ref_declaration: () => "content_ref\uC5D0\uB294 \uBB38\uC790\uC5F4\uACFC x-clack-source \uC120\uC5B8\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2574
|
+
content_ref_import_chain: () => "\uB2E4\uB978 content_ref \uD544\uB4DC\uB85C \uAC00\uC838\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2575
|
+
source_without_content_ref: () => "x-clack-source\uB294 content_ref\uC5D0\uB9CC \uC120\uC5B8\uD569\uB2C8\uB2E4.",
|
|
2576
|
+
image_list_declaration: () => "image_list\uC5D0\uB294 \uAC1D\uCCB4 \uBC30\uC5F4\uACFC \uC790\uC0B0 \uC120\uC5B8\uC774 \uD544\uC694\uD569\uB2C8\uB2E4."
|
|
2577
|
+
};
|
|
2578
|
+
function inspectEditorSemantics(skill, data, fail) {
|
|
2410
2579
|
const editor = skill.authoring?.editor;
|
|
2411
2580
|
if (!editor) return;
|
|
2412
2581
|
const permissions = new Set(editor.permissions ?? []);
|
|
2413
|
-
if (!permissions.has("document.read") || !permissions.has("document.write"))
|
|
2414
|
-
if (permissions.has("ai.suggest") && skill.authoring?.ai_fill?.enabled !== true)
|
|
2582
|
+
if (!permissions.has("document.read") || !permissions.has("document.write")) fail("/authoring/editor/permissions", "editor_document_permissions");
|
|
2583
|
+
if (permissions.has("ai.suggest") && skill.authoring?.ai_fill?.enabled !== true) fail("/authoring/editor/permissions", "ai_suggest_needs_ai_fill");
|
|
2415
2584
|
const imageTool = (skill.authoring?.tools ?? []).find((tool) => tool.tool === "image.generate");
|
|
2416
|
-
if (permissions.has("tools.image.generate") && !imageTool)
|
|
2417
|
-
if (imageTool?.aspect === "slot")
|
|
2585
|
+
if (permissions.has("tools.image.generate") && !imageTool) fail("/authoring/editor/permissions", "image_permission_needs_tool");
|
|
2586
|
+
if (imageTool?.aspect === "slot") fail("/authoring/tools", "editor_slot_aspect");
|
|
2418
2587
|
if (!data) return;
|
|
2419
2588
|
let assets = 0;
|
|
2420
2589
|
let suggest = 0;
|
|
@@ -2422,20 +2591,20 @@ function inspectEditorSemantics(skill, data, fail2) {
|
|
|
2422
2591
|
if (node["x-clack-asset"]) assets++;
|
|
2423
2592
|
if (node["x-clack-ai"]?.suggest === true) suggest++;
|
|
2424
2593
|
});
|
|
2425
|
-
if (assets > 0 && !skill.output?.data?.assets)
|
|
2426
|
-
if (assets === 0 && skill.output?.data?.assets)
|
|
2427
|
-
if (assets === 0 && permissions.has("tools.image.generate"))
|
|
2428
|
-
if (suggest === 0 && permissions.has("ai.suggest"))
|
|
2594
|
+
if (assets > 0 && !skill.output?.data?.assets) fail("/output/data/assets", "asset_limits_missing");
|
|
2595
|
+
if (assets === 0 && skill.output?.data?.assets) fail("/output/data/assets", "asset_limits_unused");
|
|
2596
|
+
if (assets === 0 && permissions.has("tools.image.generate")) fail("/authoring/editor/permissions", "image_permission_no_asset");
|
|
2597
|
+
if (suggest === 0 && permissions.has("ai.suggest")) fail("/authoring/editor/permissions", "ai_suggest_no_node");
|
|
2429
2598
|
const metadata = skill.output?.metadata ?? {};
|
|
2430
2599
|
for (const key of ["title", "description"]) {
|
|
2431
2600
|
if (metadata[key] === void 0) continue;
|
|
2432
2601
|
const field2 = dataRootField(data, metadata[key]);
|
|
2433
|
-
if (!field2 || field2.type !== "string" || field2["x-clack-asset"] || field2["x-clack-visibility"] !== "public")
|
|
2602
|
+
if (!field2 || field2.type !== "string" || field2["x-clack-asset"] || field2["x-clack-visibility"] !== "public") fail(`/output/metadata/${key}`, "metadata_text_key");
|
|
2434
2603
|
}
|
|
2435
2604
|
for (const key of ["thumbnail", "thumbnail_fallback"]) {
|
|
2436
2605
|
if (metadata[key] === void 0) continue;
|
|
2437
2606
|
const field2 = dataRootField(data, metadata[key]);
|
|
2438
|
-
if (!field2 || !field2["x-clack-asset"] || field2["x-clack-visibility"] !== "public")
|
|
2607
|
+
if (!field2 || !field2["x-clack-asset"] || field2["x-clack-visibility"] !== "public") fail(`/output/metadata/${key}`, "metadata_asset_key");
|
|
2439
2608
|
}
|
|
2440
2609
|
}
|
|
2441
2610
|
var INTRO_MAX_IMAGES = 8;
|
|
@@ -2452,19 +2621,19 @@ function introFieldLabelMaxLength(name2, field2) {
|
|
|
2452
2621
|
}
|
|
2453
2622
|
return Math.max(...lengths);
|
|
2454
2623
|
}
|
|
2455
|
-
function inspectIntroSemantics(skill, form, slots,
|
|
2624
|
+
function inspectIntroSemantics(skill, form, slots, fail) {
|
|
2456
2625
|
const intro = skill.output?.intro;
|
|
2457
2626
|
if (!intro) return;
|
|
2458
2627
|
let images = 0;
|
|
2459
2628
|
for (const name2 of intro.images ?? []) {
|
|
2460
2629
|
const slot = slots.find((entry) => entry.field === name2);
|
|
2461
2630
|
if (!slot) {
|
|
2462
|
-
|
|
2631
|
+
fail("/output/intro/images", "intro_image_not_slot");
|
|
2463
2632
|
continue;
|
|
2464
2633
|
}
|
|
2465
2634
|
images += slot.multiple ? slot.multiple.max : 1;
|
|
2466
2635
|
}
|
|
2467
|
-
if (images > INTRO_MAX_IMAGES)
|
|
2636
|
+
if (images > INTRO_MAX_IMAGES) fail("/output/intro/images", "intro_images_over", { max: INTRO_MAX_IMAGES });
|
|
2468
2637
|
if (!form) return;
|
|
2469
2638
|
const properties = form.properties ?? {};
|
|
2470
2639
|
const textField = (name2) => {
|
|
@@ -2474,54 +2643,64 @@ function inspectIntroSemantics(skill, form, slots, fail2) {
|
|
|
2474
2643
|
for (const [key, max] of [["creator_comment", INTRO_CREATOR_COMMENT_MAX], ["description", INTRO_DESCRIPTION_MAX]]) {
|
|
2475
2644
|
if (intro[key] === void 0) continue;
|
|
2476
2645
|
const field2 = textField(intro[key]);
|
|
2477
|
-
if (!field2 || field2["x-clack-visibility"] !== "public")
|
|
2478
|
-
else if (field2.maxLength > max)
|
|
2646
|
+
if (!field2 || field2["x-clack-visibility"] !== "public") fail(`/output/intro/${key}`, "intro_text_field");
|
|
2647
|
+
else if (field2.maxLength > max) fail(`/output/intro/${key}`, "intro_text_too_long", { max });
|
|
2648
|
+
}
|
|
2649
|
+
let sectionLength = 0;
|
|
2650
|
+
for (const [key, name2] of Object.entries(intro.sections ?? {})) {
|
|
2651
|
+
const field2 = textField(name2);
|
|
2652
|
+
if (!field2 || field2["x-clack-visibility"] !== "public") fail(`/output/intro/sections/${key}`, "intro_section_field");
|
|
2653
|
+
else {
|
|
2654
|
+
if (field2.maxLength > 2e3) fail(`/output/intro/sections/${key}`, "intro_section_too_long");
|
|
2655
|
+
sectionLength += field2.maxLength;
|
|
2656
|
+
}
|
|
2479
2657
|
}
|
|
2658
|
+
if (sectionLength > 6e3) fail("/output/intro/sections", "intro_sections_total");
|
|
2480
2659
|
const fallback = intro.description_fallback ?? [];
|
|
2481
2660
|
let composed = 0;
|
|
2482
2661
|
for (const name2 of fallback) {
|
|
2483
2662
|
const field2 = textField(name2);
|
|
2484
2663
|
if (!field2) {
|
|
2485
|
-
|
|
2664
|
+
fail("/output/intro/description_fallback", "intro_fallback_field");
|
|
2486
2665
|
continue;
|
|
2487
2666
|
}
|
|
2488
2667
|
composed += introFieldLabelMaxLength(name2, field2) + 1 + field2.maxLength;
|
|
2489
2668
|
}
|
|
2490
2669
|
composed += Math.max(0, fallback.length - 1) * 2;
|
|
2491
|
-
if (composed > INTRO_DESCRIPTION_MAX)
|
|
2670
|
+
if (composed > INTRO_DESCRIPTION_MAX) fail("/output/intro/description_fallback", "intro_fallback_too_long", { max: INTRO_DESCRIPTION_MAX });
|
|
2492
2671
|
}
|
|
2493
2672
|
function inspectAuthoringSemantics(skill, form, data) {
|
|
2494
2673
|
const errors = [];
|
|
2495
|
-
const
|
|
2496
|
-
inspectEditorSemantics(skill, data,
|
|
2674
|
+
const fail = (path, code, args) => errors.push({ path, message: SEMANTICS_NOTES[code](args ?? {}), code, ...args ? { args } : {} });
|
|
2675
|
+
inspectEditorSemantics(skill, data, fail);
|
|
2497
2676
|
const tools = skill.authoring?.tools ?? [];
|
|
2498
|
-
if (new Set(tools.map((tool) => tool.tool)).size !== tools.length)
|
|
2499
|
-
for (const tool of tools) if (tool.batch_max > tool.max_calls)
|
|
2677
|
+
if (new Set(tools.map((tool) => tool.tool)).size !== tools.length) fail("/authoring/tools", "tool_duplicate");
|
|
2678
|
+
for (const tool of tools) if (tool.batch_max > tool.max_calls) fail("/authoring/tools", "tool_batch_over_calls");
|
|
2500
2679
|
const slots = skill.output?.asset_slots ?? [];
|
|
2501
2680
|
const paths = /* @__PURE__ */ new Set();
|
|
2502
2681
|
const fields3 = /* @__PURE__ */ new Set();
|
|
2503
2682
|
for (const slot of slots) {
|
|
2504
|
-
if (fields3.has(slot.field))
|
|
2683
|
+
if (fields3.has(slot.field)) fail("/output/asset_slots", "slot_field_duplicate");
|
|
2505
2684
|
fields3.add(slot.field);
|
|
2506
|
-
if (slot.multiple && slot.multiple.min > slot.multiple.max)
|
|
2685
|
+
if (slot.multiple && slot.multiple.min > slot.multiple.max) fail("/output/asset_slots", "slot_multiple_range");
|
|
2507
2686
|
for (let index = 0; index < (slot.multiple?.max ?? 1); index++) {
|
|
2508
2687
|
const path = slot.multiple ? slot.multiple.path.replace("{n}", String(index)) : slot.path;
|
|
2509
|
-
if (paths.has(path))
|
|
2688
|
+
if (paths.has(path)) fail("/output/asset_slots", "slot_path_duplicate");
|
|
2510
2689
|
paths.add(path);
|
|
2511
2690
|
}
|
|
2512
2691
|
}
|
|
2513
|
-
inspectIntroSemantics(skill, form, slots,
|
|
2692
|
+
inspectIntroSemantics(skill, form, slots, fail);
|
|
2514
2693
|
if (!form) return errors;
|
|
2515
2694
|
const properties = form.properties ?? {};
|
|
2516
2695
|
const exists = (expression, path) => {
|
|
2517
2696
|
const match = /^([a-z][a-z0-9_-]*)(?:\[(\d+)\])?$/.exec(expression);
|
|
2518
2697
|
if (!match || !Object.hasOwn(properties, match[1])) {
|
|
2519
|
-
|
|
2698
|
+
fail(path, "form_field_missing");
|
|
2520
2699
|
return;
|
|
2521
2700
|
}
|
|
2522
2701
|
if (match[2] !== void 0) {
|
|
2523
2702
|
const slot = slots.find((value2) => value2.field === match[1]);
|
|
2524
|
-
if (!slot?.multiple || Number(match[2]) >= slot.multiple.max)
|
|
2703
|
+
if (!slot?.multiple || Number(match[2]) >= slot.multiple.max) fail(path, "slot_index_invalid");
|
|
2525
2704
|
}
|
|
2526
2705
|
};
|
|
2527
2706
|
const entity = skill.output?.entity_map;
|
|
@@ -2531,17 +2710,17 @@ function inspectAuthoringSemantics(skill, form, data) {
|
|
|
2531
2710
|
}
|
|
2532
2711
|
for (const slot of slots) {
|
|
2533
2712
|
const node = properties[slot.field];
|
|
2534
|
-
if (!node || node["x-clack-widget"] !== (slot.multiple ? "image_list" : "image"))
|
|
2713
|
+
if (!node || node["x-clack-widget"] !== (slot.multiple ? "image_list" : "image")) fail("/output/asset_slots", "slot_widget_mismatch");
|
|
2535
2714
|
}
|
|
2536
2715
|
for (const [name2, node] of Object.entries(properties)) {
|
|
2537
2716
|
if (node["x-clack-widget"] === "content_ref") {
|
|
2538
|
-
if (node.type !== "string" || !node["x-clack-source"])
|
|
2717
|
+
if (node.type !== "string" || !node["x-clack-source"]) fail(`/properties/${name2}`, "content_ref_declaration");
|
|
2539
2718
|
for (const target of Object.keys(node["x-clack-source"]?.import ?? {})) {
|
|
2540
2719
|
exists(target, `/properties/${name2}/x-clack-source/import`);
|
|
2541
|
-
if (properties[target]?.["x-clack-widget"] === "content_ref")
|
|
2720
|
+
if (properties[target]?.["x-clack-widget"] === "content_ref") fail(`/properties/${name2}`, "content_ref_import_chain");
|
|
2542
2721
|
}
|
|
2543
|
-
} else if (node["x-clack-source"])
|
|
2544
|
-
if (node["x-clack-widget"] === "image_list" && (node.type !== "array" || node.items?.type !== "object" || !node["x-clack-asset"]))
|
|
2722
|
+
} else if (node["x-clack-source"]) fail(`/properties/${name2}`, "source_without_content_ref");
|
|
2723
|
+
if (node["x-clack-widget"] === "image_list" && (node.type !== "array" || node.items?.type !== "object" || !node["x-clack-asset"])) fail(`/properties/${name2}`, "image_list_declaration");
|
|
2545
2724
|
}
|
|
2546
2725
|
return errors;
|
|
2547
2726
|
}
|
|
@@ -2550,7 +2729,7 @@ function inspectAuthoringSemantics(skill, form, data) {
|
|
|
2550
2729
|
import { createHash as createHash4 } from "crypto";
|
|
2551
2730
|
import { lstat as lstat4, open as open3, readdir } from "fs/promises";
|
|
2552
2731
|
import { constants } from "fs";
|
|
2553
|
-
import { basename as
|
|
2732
|
+
import { basename as basename5, extname as extname2, join as join2, resolve as resolve8 } from "path";
|
|
2554
2733
|
import { Ajv2020 as Ajv20202 } from "ajv/dist/2020.js";
|
|
2555
2734
|
import { unzipSync as unzipSync2, zipSync } from "fflate";
|
|
2556
2735
|
import { parseDocument } from "yaml";
|
|
@@ -2561,7 +2740,6 @@ import { Ajv2020 } from "ajv/dist/2020.js";
|
|
|
2561
2740
|
|
|
2562
2741
|
// src/vendor/clack-api-v4-contracts/output-data-inspect.mjs
|
|
2563
2742
|
var bytes = (value2) => Buffer.byteLength(JSON.stringify(value2), "utf8");
|
|
2564
|
-
var fail = (path, message) => ({ path, message });
|
|
2565
2743
|
var OUTPUT_DATA_LIMITS = { schema_bytes: 65536, depth: 6, properties: 400, public_bytes: 262144, private_bytes: 65536, ui_state_bytes: 262144 };
|
|
2566
2744
|
var SCALAR_TYPES = /* @__PURE__ */ new Set(["string", "integer", "number", "boolean"]);
|
|
2567
2745
|
var SCALAR_KEYS = {
|
|
@@ -2573,84 +2751,115 @@ var SCALAR_KEYS = {
|
|
|
2573
2751
|
boolean: []
|
|
2574
2752
|
};
|
|
2575
2753
|
var TYPED_KEYS = new Set(Object.values(SCALAR_KEYS).flat());
|
|
2754
|
+
var RANGE_LABELS = { length: "\uAE38\uC774", items: "\uD56D\uBAA9 \uC218", value: "\uAC12" };
|
|
2755
|
+
var OUTPUT_DATA_NOTES = {
|
|
2756
|
+
schema_too_large: () => "\uB370\uC774\uD130 \uC2A4\uD0A4\uB9C8\uB294 64 KiB \uC774\uD558\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
2757
|
+
root_required_undeclared: ({ key }) => `\uC120\uC5B8\uD558\uC9C0 \uC54A\uC740 \uB8E8\uD2B8 \uD0A4 ${key}\uC785\uB2C8\uB2E4.`,
|
|
2758
|
+
public_root_key_missing: () => "\uACF5\uAC1C \uB8E8\uD2B8 \uD0A4\uAC00 \uD558\uB098 \uC774\uC0C1 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2759
|
+
ref_cycle: () => "\uC21C\uD658 \uCC38\uC870\uB294 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
2760
|
+
ref_not_local: () => "\uB85C\uCEEC $defs \uCC38\uC870\uB9CC \uD5C8\uC6A9\uD569\uB2C8\uB2E4.",
|
|
2761
|
+
depth_over: () => "\uB370\uC774\uD130 \uBB38\uC11C \uAE4A\uC774\uB294 \uB8E8\uD2B8 \uC544\uB798 6 \uC774\uD558\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
2762
|
+
ref_extra_keys: () => "$ref\uC5D0\uB294 \uC124\uBA85 \uD0A4\uB9CC \uD568\uAED8 \uB458 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
2763
|
+
one_of_discriminator_missing: () => "oneOf\uC5D0\uB294 x-clack-discriminator\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2764
|
+
one_of_typed_keys: () => "oneOf \uB178\uB4DC\uC5D0\uB294 \uD615\uC2DD \uD0A4\uB97C \uD568\uAED8 \uB458 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2765
|
+
one_of_branch_shape: () => "\uAC01 oneOf \uBD84\uAE30\uB294 \uD310\uBCC4\uC790 \uBB38\uC790\uC5F4 const\uB97C \uD544\uC218\uB85C \uAC00\uC9C4 \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
|
|
2766
|
+
discriminator_duplicate: ({ value: value2 }) => `\uD310\uBCC4\uC790 \uAC12 ${value2}\uC774 \uC911\uBCF5\uB429\uB2C8\uB2E4.`,
|
|
2767
|
+
discriminator_misplaced: () => "x-clack-discriminator\uB294 oneOf\uC5D0\uB9CC \uB461\uB2C8\uB2E4.",
|
|
2768
|
+
type_missing: () => "type\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2769
|
+
key_not_for_type: ({ type }) => `${type}\uC5D0 \uC4F8 \uC218 \uC5C6\uB294 \uD0A4\uC785\uB2C8\uB2E4.`,
|
|
2770
|
+
range_invalid: ({ range }) => `${RANGE_LABELS[range]} \uBC94\uC704\uAC00 \uC798\uBABB\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`,
|
|
2771
|
+
string_max_length_missing: () => "\uBB38\uC790\uC5F4 maxLength\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2772
|
+
array_items_missing: () => "\uBC30\uC5F4\uC5D0\uB294 items\uC640 maxItems\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2773
|
+
unique_items_not_scalar: () => "uniqueItems\uB294 \uC2A4\uCE7C\uB77C \uBC30\uC5F4\uC5D0\uB9CC \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
2774
|
+
object_shape: () => "\uAC1D\uCCB4\uC5D0\uB294 properties\uC640 additionalProperties: false\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2775
|
+
required_undeclared: ({ key }) => `\uC120\uC5B8\uD558\uC9C0 \uC54A\uC740 \uD0A4 ${key}\uC744 required\uC5D0 \uB450\uC5C8\uC2B5\uB2C8\uB2E4.`,
|
|
2776
|
+
enum_type_mismatch: () => "enum \uAC12\uC758 \uD615\uC2DD\uC774 type\uACFC \uB2E4\uB985\uB2C8\uB2E4.",
|
|
2777
|
+
asset_node_shape: () => "\uC790\uC0B0 \uB178\uB4DC\uB294 {type:string, format:uuid, maxLength:36}\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
2778
|
+
asset_in_private: () => "\uBE44\uACF5\uAC1C \uD0A4\uC5D0\uB294 \uC790\uC0B0\uC744 \uB458 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2779
|
+
format_not_string: () => "format\uC740 \uBB38\uC790\uC5F4\uC5D0\uB9CC \uC501\uB2C8\uB2E4.",
|
|
2780
|
+
ai_suggest_private: () => "AI \uC81C\uC548\uC740 \uACF5\uAC1C \uD0A4\uC5D0\uB9CC \uCF24 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
2781
|
+
properties_over: () => "\uB370\uC774\uD130 \uC2A4\uD0A4\uB9C8 \uC18D\uC131\uC740 400\uAC1C \uC774\uD558\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
2782
|
+
ai_suggest_has_asset: () => "AI \uC81C\uC548 \uD558\uC704 \uD2B8\uB9AC\uC5D0 \uC790\uC0B0 \uB178\uB4DC\uB97C \uB458 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
|
|
2783
|
+
};
|
|
2576
2784
|
function inspectOutputData(schema) {
|
|
2577
2785
|
const errors = [];
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
if (!Object.
|
|
2786
|
+
const note = (path, code, args) => errors.push({ path, message: OUTPUT_DATA_NOTES[code](args ?? {}), code, ...args ? { args } : {} });
|
|
2787
|
+
if (bytes(schema) > OUTPUT_DATA_LIMITS.schema_bytes) note("/", "schema_too_large");
|
|
2788
|
+
for (const name2 of schema.required ?? []) if (!Object.hasOwn(schema.properties, name2)) note("/required", "root_required_undeclared", { key: name2 });
|
|
2789
|
+
if (!Object.values(schema.properties).some((field2) => field2["x-clack-visibility"] === "public")) note("/properties", "public_root_key_missing");
|
|
2581
2790
|
const defs = schema.$defs ?? {};
|
|
2582
|
-
const
|
|
2791
|
+
const resolve10 = (node) => typeof node?.$ref === "string" ? defs[node.$ref.slice("#/$defs/".length)] : node;
|
|
2583
2792
|
let properties = 0;
|
|
2584
2793
|
const suggestRoots = [];
|
|
2585
2794
|
const assetPointers = [];
|
|
2586
2795
|
walkDataSchema(schema, (node, info) => {
|
|
2587
2796
|
const at = info.pointer || "/";
|
|
2588
2797
|
if (info.cycle) {
|
|
2589
|
-
|
|
2798
|
+
note(at, "ref_cycle");
|
|
2590
2799
|
return;
|
|
2591
2800
|
}
|
|
2592
2801
|
if (info.unresolved) {
|
|
2593
|
-
|
|
2802
|
+
note(at, "ref_not_local");
|
|
2594
2803
|
return;
|
|
2595
2804
|
}
|
|
2596
|
-
if (info.depth > OUTPUT_DATA_LIMITS.depth)
|
|
2805
|
+
if (info.depth > OUTPUT_DATA_LIMITS.depth) note(at, "depth_over");
|
|
2597
2806
|
if (info.depth === 0) return;
|
|
2598
2807
|
if (typeof node.$ref === "string") {
|
|
2599
|
-
if (Object.keys(node).some((key) => !["$ref", "title", "description", "x-clack-i18n", "x-clack-visibility"].includes(key)))
|
|
2808
|
+
if (Object.keys(node).some((key) => !["$ref", "title", "description", "x-clack-i18n", "x-clack-visibility"].includes(key))) note(at, "ref_extra_keys");
|
|
2600
2809
|
return;
|
|
2601
2810
|
}
|
|
2602
2811
|
if (!info.branch) properties++;
|
|
2603
2812
|
if (Array.isArray(node.oneOf)) {
|
|
2604
2813
|
const discriminator = node["x-clack-discriminator"];
|
|
2605
|
-
if (!discriminator)
|
|
2606
|
-
if (node.type || node.properties || node.items || node.enum || Object.hasOwn(node, "const"))
|
|
2814
|
+
if (!discriminator) note(at, "one_of_discriminator_missing");
|
|
2815
|
+
if (node.type || node.properties || node.items || node.enum || Object.hasOwn(node, "const")) note(at, "one_of_typed_keys");
|
|
2607
2816
|
const seen = /* @__PURE__ */ new Set();
|
|
2608
2817
|
for (const raw of node.oneOf) {
|
|
2609
|
-
const branch =
|
|
2818
|
+
const branch = resolve10(raw);
|
|
2610
2819
|
const tag = branch?.properties?.[discriminator];
|
|
2611
2820
|
if (branch?.type !== "object" || typeof tag?.const !== "string" || tag.type !== "string" || !(branch.required ?? []).includes(discriminator)) {
|
|
2612
|
-
|
|
2613
|
-
} else if (seen.has(tag.const))
|
|
2821
|
+
note(at, "one_of_branch_shape");
|
|
2822
|
+
} else if (seen.has(tag.const)) note(at, "discriminator_duplicate", { value: tag.const });
|
|
2614
2823
|
else seen.add(tag.const);
|
|
2615
2824
|
}
|
|
2616
2825
|
return;
|
|
2617
2826
|
}
|
|
2618
|
-
if (node["x-clack-discriminator"] !== void 0)
|
|
2827
|
+
if (node["x-clack-discriminator"] !== void 0) note(at, "discriminator_misplaced");
|
|
2619
2828
|
if (!node.type) {
|
|
2620
|
-
|
|
2829
|
+
note(at, "type_missing");
|
|
2621
2830
|
return;
|
|
2622
2831
|
}
|
|
2623
|
-
for (const key of Object.keys(node)) if (TYPED_KEYS.has(key) && !SCALAR_KEYS[node.type].includes(key))
|
|
2624
|
-
const range = (low, high,
|
|
2625
|
-
if (typeof node[low] === "number" && typeof node[high] === "number" && node[low] > node[high])
|
|
2832
|
+
for (const key of Object.keys(node)) if (TYPED_KEYS.has(key) && !SCALAR_KEYS[node.type].includes(key)) note(`${at}/${key}`, "key_not_for_type", { type: node.type });
|
|
2833
|
+
const range = (low, high, kind) => {
|
|
2834
|
+
if (typeof node[low] === "number" && typeof node[high] === "number" && node[low] > node[high]) note(at, "range_invalid", { range: kind });
|
|
2626
2835
|
};
|
|
2627
|
-
range("minLength", "maxLength", "
|
|
2628
|
-
range("minItems", "maxItems", "
|
|
2629
|
-
range("minimum", "maximum", "
|
|
2630
|
-
if (node.type === "string" && typeof node.maxLength !== "number")
|
|
2631
|
-
if (node.type === "array" && (!node.items || typeof node.maxItems !== "number"))
|
|
2836
|
+
range("minLength", "maxLength", "length");
|
|
2837
|
+
range("minItems", "maxItems", "items");
|
|
2838
|
+
range("minimum", "maximum", "value");
|
|
2839
|
+
if (node.type === "string" && typeof node.maxLength !== "number") note(at, "string_max_length_missing");
|
|
2840
|
+
if (node.type === "array" && (!node.items || typeof node.maxItems !== "number")) note(at, "array_items_missing");
|
|
2632
2841
|
if (node.type === "array" && node.uniqueItems === true) {
|
|
2633
2842
|
let items = node.items;
|
|
2634
|
-
for (let hops = 0; typeof items?.$ref === "string" && hops < 64; hops++) items =
|
|
2635
|
-
if (!items || Array.isArray(items.oneOf) || !SCALAR_TYPES.has(items.type))
|
|
2843
|
+
for (let hops = 0; typeof items?.$ref === "string" && hops < 64; hops++) items = resolve10(items);
|
|
2844
|
+
if (!items || Array.isArray(items.oneOf) || !SCALAR_TYPES.has(items.type)) note(`${at}/uniqueItems`, "unique_items_not_scalar");
|
|
2636
2845
|
}
|
|
2637
2846
|
if (node.type === "object") {
|
|
2638
|
-
if (node.additionalProperties !== false || !node.properties || !Object.keys(node.properties).length)
|
|
2639
|
-
for (const name2 of node.required ?? []) if (!Object.hasOwn(node.properties ?? {}, name2))
|
|
2847
|
+
if (node.additionalProperties !== false || !node.properties || !Object.keys(node.properties).length) note(at, "object_shape");
|
|
2848
|
+
for (const name2 of node.required ?? []) if (!Object.hasOwn(node.properties ?? {}, name2)) note(at, "required_undeclared", { key: name2 });
|
|
2640
2849
|
}
|
|
2641
|
-
for (const value2 of node.enum ?? []) if (typeof value2 !== (node.type === "integer" ? "number" : node.type))
|
|
2850
|
+
for (const value2 of node.enum ?? []) if (typeof value2 !== (node.type === "integer" ? "number" : node.type)) note(at, "enum_type_mismatch");
|
|
2642
2851
|
if (node["x-clack-asset"]) {
|
|
2643
2852
|
assetPointers.push(at);
|
|
2644
|
-
if (node.type !== "string" || node.format !== "uuid" || node.maxLength !== 36 || node.enum)
|
|
2645
|
-
if (info.visibility === "private")
|
|
2646
|
-
} else if (node.format === "uuid" && node.type !== "string")
|
|
2853
|
+
if (node.type !== "string" || node.format !== "uuid" || node.maxLength !== 36 || node.enum) note(at, "asset_node_shape");
|
|
2854
|
+
if (info.visibility === "private") note(at, "asset_in_private");
|
|
2855
|
+
} else if (node.format === "uuid" && node.type !== "string") note(at, "format_not_string");
|
|
2647
2856
|
if (node["x-clack-ai"]?.suggest === true) {
|
|
2648
|
-
if (info.visibility !== "public")
|
|
2857
|
+
if (info.visibility !== "public") note(at, "ai_suggest_private");
|
|
2649
2858
|
suggestRoots.push(at);
|
|
2650
2859
|
}
|
|
2651
2860
|
});
|
|
2652
|
-
if (properties > OUTPUT_DATA_LIMITS.properties)
|
|
2653
|
-
for (const root of suggestRoots) if (assetPointers.some((asset) => asset === root || asset.startsWith(`${root}/`)))
|
|
2861
|
+
if (properties > OUTPUT_DATA_LIMITS.properties) note("/", "properties_over");
|
|
2862
|
+
for (const root of suggestRoots) if (assetPointers.some((asset) => asset === root || asset.startsWith(`${root}/`))) note(root, "ai_suggest_has_asset");
|
|
2654
2863
|
return errors;
|
|
2655
2864
|
}
|
|
2656
2865
|
var ZWJ_AFTER = new RegExp("\\p{Extended_Pictographic}", "u");
|
|
@@ -3831,6 +4040,37 @@ var clack_skill_v1_schema_default = {
|
|
|
3831
4040
|
minItems: 1,
|
|
3832
4041
|
maxItems: 8,
|
|
3833
4042
|
uniqueItems: true
|
|
4043
|
+
},
|
|
4044
|
+
sections: {
|
|
4045
|
+
type: "object",
|
|
4046
|
+
additionalProperties: false,
|
|
4047
|
+
description: "\uACF5\uAC1C \uBB38\uC790\uC5F4 \uD3FC \uD544\uB4DC\uB97C \uC18C\uAC1C \uC139\uC158\uC5D0 \uB9E4\uD551\uD569\uB2C8\uB2E4. \uD56D\uBAA9\uBCC4 \uCD5C\uB300 2,000\uC790, \uC120\uC5B8\uB41C \uD544\uB4DC \uCD5C\uB300 \uAE38\uC774 \uD569\uACC4 6,000\uC790\uC785\uB2C8\uB2E4.",
|
|
4048
|
+
properties: {
|
|
4049
|
+
how_to: {
|
|
4050
|
+
type: "string",
|
|
4051
|
+
pattern: "^[a-z][a-z0-9_-]{0,31}$"
|
|
4052
|
+
},
|
|
4053
|
+
notice: {
|
|
4054
|
+
type: "string",
|
|
4055
|
+
pattern: "^[a-z][a-z0-9_-]{0,31}$"
|
|
4056
|
+
},
|
|
4057
|
+
character: {
|
|
4058
|
+
type: "string",
|
|
4059
|
+
pattern: "^[a-z][a-z0-9_-]{0,31}$"
|
|
4060
|
+
},
|
|
4061
|
+
setting: {
|
|
4062
|
+
type: "string",
|
|
4063
|
+
pattern: "^[a-z][a-z0-9_-]{0,31}$"
|
|
4064
|
+
},
|
|
4065
|
+
relationship: {
|
|
4066
|
+
type: "string",
|
|
4067
|
+
pattern: "^[a-z][a-z0-9_-]{0,31}$"
|
|
4068
|
+
},
|
|
4069
|
+
first_scene: {
|
|
4070
|
+
type: "string",
|
|
4071
|
+
pattern: "^[a-z][a-z0-9_-]{0,31}$"
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
3834
4074
|
}
|
|
3835
4075
|
}
|
|
3836
4076
|
}
|
|
@@ -5135,6 +5375,7 @@ var clack_content_v1_schema_default = {
|
|
|
5135
5375
|
var MAX_ZIP = 10 * 1024 * 1024;
|
|
5136
5376
|
var MAX_EXPANDED = 30 * 1024 * 1024;
|
|
5137
5377
|
var MAX_FILES2 = 500;
|
|
5378
|
+
var MAX_ZIP_ENTRIES = 2e3;
|
|
5138
5379
|
var textDecoder2 = new TextDecoder("utf-8", { fatal: true });
|
|
5139
5380
|
var ajv = new Ajv20202({ allErrors: true, strict: false });
|
|
5140
5381
|
ajv.addSchema(clack_content_v1_schema_default);
|
|
@@ -5179,6 +5420,14 @@ function skillPathAllowed(path) {
|
|
|
5179
5420
|
if (parts.includes("scripts") || /\.(?:sh|bash|zsh|fish|bat|cmd|ps1|exe|dll|so|dylib|wasm|py|rb|php|jar)$/i.test(path)) return false;
|
|
5180
5421
|
return true;
|
|
5181
5422
|
}
|
|
5423
|
+
function isArchiveMetadata(path) {
|
|
5424
|
+
const parts = path.split("/");
|
|
5425
|
+
const name2 = parts.at(-1) ?? "";
|
|
5426
|
+
return parts[0] === "__MACOSX" || name2 === ".DS_Store" || name2.startsWith("._");
|
|
5427
|
+
}
|
|
5428
|
+
function unsafeArchivePath(path) {
|
|
5429
|
+
return path.startsWith("/") || /[\p{Cc}]/u.test(path) || path.split("/").includes("..");
|
|
5430
|
+
}
|
|
5182
5431
|
async function collectFiles(directory) {
|
|
5183
5432
|
const files = {};
|
|
5184
5433
|
let totalBytes = 0;
|
|
@@ -5186,6 +5435,7 @@ async function collectFiles(directory) {
|
|
|
5186
5435
|
const entries = await readdir(join2(directory, relative), { withFileTypes: true });
|
|
5187
5436
|
for (const entry of entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
|
|
5188
5437
|
const path = relative ? `${relative}/${entry.name}` : entry.name;
|
|
5438
|
+
if (isArchiveMetadata(path)) continue;
|
|
5189
5439
|
if (!skillPathAllowed(path)) invalid2(`\uD5C8\uC6A9\uB418\uC9C0 \uC54A\uB294 \uD328\uD0A4\uC9C0 \uACBD\uB85C: ${path}`);
|
|
5190
5440
|
if (entry.isSymbolicLink() || !(entry.isDirectory() || entry.isFile())) invalid2(`\uC77C\uBC18 \uD30C\uC77C\xB7\uD3F4\uB354\uB9CC \uD5C8\uC6A9\uB429\uB2C8\uB2E4: ${path}`);
|
|
5191
5441
|
if (entry.isDirectory()) {
|
|
@@ -5204,22 +5454,47 @@ async function collectFiles(directory) {
|
|
|
5204
5454
|
}
|
|
5205
5455
|
function inspectZip(bytes2, expectedDirectory, hashMismatch) {
|
|
5206
5456
|
if (!bytes2.length || bytes2.length > MAX_ZIP) invalid2("\uC2A4\uD0AC ZIP\uC740 \uBE44\uC5B4 \uC788\uC9C0 \uC54A\uC740 10 MiB \uC774\uD558 \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.");
|
|
5457
|
+
const raw = [];
|
|
5458
|
+
try {
|
|
5459
|
+
unzipSync2(bytes2, { filter(entry) {
|
|
5460
|
+
if (raw.length >= MAX_ZIP_ENTRIES) invalid2("ZIP \uD56D\uBAA9 \uC218\uAC00 2,000\uAC1C\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
|
|
5461
|
+
const dir = entry.name.endsWith("/");
|
|
5462
|
+
raw.push({ name: dir ? entry.name.slice(0, -1) : entry.name, dir });
|
|
5463
|
+
return false;
|
|
5464
|
+
} });
|
|
5465
|
+
} catch (error2) {
|
|
5466
|
+
if (error2 instanceof CliError) throw error2;
|
|
5467
|
+
return invalid2("ZIP \uAD6C\uC870\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
5468
|
+
}
|
|
5469
|
+
for (const { name: name2 } of raw) if (unsafeArchivePath(name2)) invalid2(`\uD5C8\uC6A9\uB418\uC9C0 \uC54A\uB294 ZIP \uACBD\uB85C: ${name2.replace(new RegExp("\\p{C}", "gu"), "").slice(0, 160)}`);
|
|
5470
|
+
const kept = raw.filter(({ name: name2 }) => !isArchiveMetadata(name2));
|
|
5471
|
+
const keptFiles = kept.filter(({ dir }) => !dir);
|
|
5472
|
+
if (keptFiles.length > MAX_FILES2) invalid2("\uC2A4\uD0AC \uD30C\uC77C \uC218\uAC00 500\uAC1C\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
|
|
5473
|
+
let prefix = "";
|
|
5474
|
+
const top = keptFiles[0]?.name.split("/")[0];
|
|
5475
|
+
if (top && keptFiles.every(({ name: name2 }) => name2.startsWith(`${top}/`))) {
|
|
5476
|
+
const names = new Set(keptFiles.map(({ name: name2 }) => name2));
|
|
5477
|
+
if (names.has(`${top}/SKILL.md`) && names.has(`${top}/clack.skill.json`)) prefix = `${top}/`;
|
|
5478
|
+
}
|
|
5207
5479
|
const seen = /* @__PURE__ */ new Set();
|
|
5208
|
-
|
|
5480
|
+
const wanted = /* @__PURE__ */ new Map();
|
|
5481
|
+
for (const { name: name2, dir } of kept) {
|
|
5482
|
+
if (dir && prefix && name2 === prefix.slice(0, -1)) continue;
|
|
5483
|
+
const path = prefix && name2.startsWith(prefix) ? name2.slice(prefix.length) : name2;
|
|
5484
|
+
if (!skillPathAllowed(path) || seen.has(path.toLowerCase())) invalid2(`\uD5C8\uC6A9\uB418\uC9C0 \uC54A\uB294 ZIP \uACBD\uB85C: ${path}`);
|
|
5485
|
+
seen.add(path.toLowerCase());
|
|
5486
|
+
if (!dir) wanted.set(name2, path);
|
|
5487
|
+
}
|
|
5209
5488
|
let totalBytes = 0;
|
|
5210
|
-
|
|
5489
|
+
const extracted = {};
|
|
5211
5490
|
try {
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
if (entries > MAX_FILES2) invalid2("\uC2A4\uD0AC \uD30C\uC77C \uC218\uAC00 500\uAC1C\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
|
|
5215
|
-
const path = entry.name.endsWith("/") ? entry.name.slice(0, -1) : entry.name;
|
|
5216
|
-
if (!skillPathAllowed(path) || seen.has(path.toLowerCase())) invalid2(`\uD5C8\uC6A9\uB418\uC9C0 \uC54A\uB294 ZIP \uACBD\uB85C: ${path}`);
|
|
5217
|
-
seen.add(path.toLowerCase());
|
|
5218
|
-
if (entry.name.endsWith("/")) return false;
|
|
5491
|
+
const content = unzipSync2(bytes2, { filter(entry) {
|
|
5492
|
+
if (!wanted.has(entry.name)) return false;
|
|
5219
5493
|
totalBytes += entry.originalSize;
|
|
5220
5494
|
if (totalBytes > MAX_EXPANDED) invalid2("\uC2A4\uD0AC \uC555\uCD95 \uD574\uC81C \uC6A9\uB7C9\uC774 30 MiB\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
|
|
5221
5495
|
return true;
|
|
5222
5496
|
} });
|
|
5497
|
+
for (const [name2, data] of Object.entries(content)) extracted[wanted.get(name2)] = data;
|
|
5223
5498
|
} catch (error2) {
|
|
5224
5499
|
if (error2 instanceof CliError) throw error2;
|
|
5225
5500
|
return invalid2("ZIP \uAD6C\uC870\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
@@ -5322,7 +5597,7 @@ function fillEditorHash(files) {
|
|
|
5322
5597
|
return new TextEncoder().encode(next);
|
|
5323
5598
|
}
|
|
5324
5599
|
async function prepareSkillPackage(source, options2 = {}) {
|
|
5325
|
-
const path =
|
|
5600
|
+
const path = resolve8(source);
|
|
5326
5601
|
let info;
|
|
5327
5602
|
try {
|
|
5328
5603
|
info = await lstat4(path);
|
|
@@ -5347,34 +5622,34 @@ async function prepareSkillPackage(source, options2 = {}) {
|
|
|
5347
5622
|
else return invalid2("\uC2A4\uD0AC \uB514\uB809\uD130\uB9AC \uB610\uB294 ZIP \uD30C\uC77C\uC744 \uC9C0\uC815\uD558\uC138\uC694.");
|
|
5348
5623
|
const inspected = inspectZip(
|
|
5349
5624
|
bytes2,
|
|
5350
|
-
info.isDirectory() ?
|
|
5625
|
+
info.isDirectory() ? basename5(path) : void 0,
|
|
5351
5626
|
info.isDirectory() && !options2.fillEditorHash ? "warn" : "error"
|
|
5352
5627
|
);
|
|
5353
5628
|
return { bytes: bytes2, sha256: hash(bytes2), ...inspected, ...filledManifest ? { filled_manifest: filledManifest } : {} };
|
|
5354
5629
|
}
|
|
5355
5630
|
|
|
5356
5631
|
// src/commands/skill.ts
|
|
5357
|
-
var uuid2 =
|
|
5358
|
-
var createdSchema =
|
|
5359
|
-
var uploadSchema =
|
|
5632
|
+
var uuid2 = z10.uuid();
|
|
5633
|
+
var createdSchema = z10.object({ id: uuid2, slug: z10.string(), type: z10.string() });
|
|
5634
|
+
var uploadSchema = z10.object({
|
|
5360
5635
|
version_id: uuid2,
|
|
5361
|
-
upload_url:
|
|
5362
|
-
headers:
|
|
5363
|
-
expires_at:
|
|
5364
|
-
max_upload_bytes:
|
|
5636
|
+
upload_url: z10.url(),
|
|
5637
|
+
headers: z10.record(z10.string(), z10.string()),
|
|
5638
|
+
expires_at: z10.string(),
|
|
5639
|
+
max_upload_bytes: z10.number().int().positive()
|
|
5365
5640
|
});
|
|
5366
|
-
var versionSchema =
|
|
5367
|
-
var skillSlug =
|
|
5368
|
-
var semver =
|
|
5369
|
-
var category =
|
|
5370
|
-
var visibility =
|
|
5371
|
-
var managedVersionSchema =
|
|
5641
|
+
var versionSchema = z10.object({ id: uuid2, skill_id: uuid2, version: z10.string(), review_status: z10.string() });
|
|
5642
|
+
var skillSlug = z10.string().regex(/^[a-z][a-z0-9-]{0,63}$/);
|
|
5643
|
+
var semver = z10.string().regex(/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?$/);
|
|
5644
|
+
var category = z10.enum(["character_chat", "quiz", "worldbuilding", "gallery", "story", "agent_tool"]);
|
|
5645
|
+
var visibility = z10.enum(["private", "unlisted", "public"]);
|
|
5646
|
+
var managedVersionSchema = z10.object({
|
|
5372
5647
|
id: uuid2,
|
|
5373
5648
|
skill_id: uuid2,
|
|
5374
|
-
version:
|
|
5375
|
-
review_status:
|
|
5376
|
-
release_status:
|
|
5377
|
-
package_hash:
|
|
5649
|
+
version: z10.string(),
|
|
5650
|
+
review_status: z10.string(),
|
|
5651
|
+
release_status: z10.string(),
|
|
5652
|
+
package_hash: z10.string().nullable()
|
|
5378
5653
|
});
|
|
5379
5654
|
function serverData(schema, value2) {
|
|
5380
5655
|
const parsed = schema.safeParse(value2);
|
|
@@ -5462,18 +5737,19 @@ async function pushSkillVersion(client, prepared, skillId) {
|
|
|
5462
5737
|
if (error2 instanceof CliError && error2.code === "SKILL_VERSION_MAJOR_REQUIRED") {
|
|
5463
5738
|
throw new CliError(`${error2.message} (\uCDE8\uC18C: clack skill cancel ${resolvedSkillId} ${session2.version_id})`, error2.code, error2.status);
|
|
5464
5739
|
}
|
|
5465
|
-
if (error2 instanceof CliError)
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
error2.
|
|
5469
|
-
|
|
5740
|
+
if (error2 instanceof CliError) {
|
|
5741
|
+
const judged = error2.status >= 400 && error2.status < 500 && error2.status !== 429;
|
|
5742
|
+
const hint = judged ? "\uD328\uD0A4\uC9C0\uB97C \uACE0\uCE5C \uB4A4 \uAC19\uC740 \uBC84\uC804\uC73C\uB85C \uB2E4\uC2DC clack skill push\uD558\uC138\uC694." : `\uC644\uB8CC \uC7AC\uC2DC\uB3C4: clack skill complete ${resolvedSkillId} ${session2.version_id}`;
|
|
5743
|
+
throw new CliError(`${error2.message}
|
|
5744
|
+
${hint}`, error2.code, error2.status, error2.retryAfter);
|
|
5745
|
+
}
|
|
5470
5746
|
throw error2;
|
|
5471
5747
|
}
|
|
5472
5748
|
}
|
|
5473
5749
|
function registerSkillCommands(program2, runtime2) {
|
|
5474
5750
|
const skill = program2.command("skill").description("\uC2A4\uD0AC \uD328\uD0A4\uC9C0 \uAC80\uC0AC\xB7\uC5C5\uB85C\uB4DC\xB7\uC2EC\uC0AC\xB7\uAC8C\uC2DC (skill:read\xB7write\xB7publish)");
|
|
5475
5751
|
runtime2.action(skill.command("list").description("\uC2A4\uD0AC \uBAA9\uB85D \uAC80\uC0C9 (skill:read)").option("-q, --query <text>", "\uC2A4\uD0AC \uC774\uB984 \uAC80\uC0C9").option("--category <category>", "\uBD84\uB958").option("--entity <entity>", "\uC0B0\uCD9C\uBB3C \uC5D4\uD2F0\uD2F0(character)").option("--type <type>", "\uC2A4\uD0AC \uC720\uD615(template|instruction|tool)").option("--official <value>", "\uACF5\uC2DD \uC2A4\uD0AC\uB9CC true \uB610\uB294 false").option("--cursor <id>", "\uB2E4\uC74C \uD398\uC774\uC9C0 UUID").option("--all", "\uBAA8\uB4E0 \uD398\uC774\uC9C0 \uC870\uD68C"), async (ctx, _args, opts) => {
|
|
5476
|
-
const query = opts.query === void 0 ? void 0 :
|
|
5752
|
+
const query = opts.query === void 0 ? void 0 : z10.string().trim().min(1).max(100).safeParse(opts.query);
|
|
5477
5753
|
if (query && !query.success) throw new CliError("\uAC80\uC0C9\uC5B4\uB294 1~100\uC790\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
|
|
5478
5754
|
const selectedCategory = opts.category === void 0 ? void 0 : category.safeParse(opts.category);
|
|
5479
5755
|
if (selectedCategory && !selectedCategory.success) throw new CliError("\uC2A4\uD0AC \uBD84\uB958\uB97C \uD655\uC778\uD558\uC138\uC694.");
|
|
@@ -5548,11 +5824,11 @@ function registerSkillCommands(program2, runtime2) {
|
|
|
5548
5824
|
runtime2.action(skill.command("pack [dir]").description("\uC2A4\uD0AC \uD328\uD0A4\uC9C0 ZIP \uB9CC\uB4E4\uAE30 (\uB85C\uADF8\uC778 \uBD88\uD544\uC694, \uC5D0\uB514\uD130 \uC2A4\uD0AC\uC740 authoring.editor.sha256\uC744 \uCC44\uC6C0)").option("-o, --out <file>", "ZIP \uC800\uC7A5 \uACBD\uB85C (\uAE30\uBCF8: <\uC774\uB984>-<\uBC84\uC804>.zip)").option("--write-manifest", "\uCC44\uC6B4 sha256\uC744 \uB514\uB809\uD130\uB9AC\uC758 clack.skill.json\uC5D0\uB3C4 \uAE30\uB85D"), async (ctx, [dir], opts) => {
|
|
5549
5825
|
const source = dir ?? ".";
|
|
5550
5826
|
const prepared = await prepareSkillPackage(source, { fillEditorHash: true });
|
|
5551
|
-
const out =
|
|
5827
|
+
const out = resolve9(opts.out ?? `${prepared.manifest.name}-${prepared.manifest.version}.zip`);
|
|
5552
5828
|
const writeManifest = Boolean(opts.writeManifest && prepared.filled_manifest);
|
|
5553
5829
|
if (!ctx.options.dryRun) {
|
|
5554
5830
|
await writeFile2(out, prepared.bytes);
|
|
5555
|
-
if (writeManifest) await writeFile2(join3(
|
|
5831
|
+
if (writeManifest) await writeFile2(join3(resolve9(source), "clack.skill.json"), prepared.filled_manifest);
|
|
5556
5832
|
}
|
|
5557
5833
|
ctx.output({
|
|
5558
5834
|
...ctx.options.dryRun ? { dry_run: true } : {},
|
|
@@ -5582,7 +5858,7 @@ ${SDK_LOCATION_HELP}
|
|
|
5582
5858
|
]) {
|
|
5583
5859
|
if (value2 === void 0) continue;
|
|
5584
5860
|
if ((flag === "host-port" || flag === "editor-port") && !/^\d{2,5}$/.test(value2)) throw new CliError("\uD3EC\uD2B8\uB294 \uC22B\uC790\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
|
|
5585
|
-
args.push(`--${flag}`, flag.endsWith("port") ? value2 :
|
|
5861
|
+
args.push(`--${flag}`, flag.endsWith("port") ? value2 : resolve9(value2));
|
|
5586
5862
|
}
|
|
5587
5863
|
const sdkDir = resolveSdkDir(opts.sdkDir);
|
|
5588
5864
|
const serve = join3(sdkDir, "mock-host/serve.mjs");
|
|
@@ -5590,10 +5866,10 @@ ${SDK_LOCATION_HELP}
|
|
|
5590
5866
|
ctx.output({ dry_run: true, sdk_dir: sdkDir, command: ["node", serve, ...args] });
|
|
5591
5867
|
return;
|
|
5592
5868
|
}
|
|
5593
|
-
await new Promise((done,
|
|
5869
|
+
await new Promise((done, fail) => {
|
|
5594
5870
|
const child = spawn(process.execPath, [serve, ...args], { stdio: "inherit" });
|
|
5595
|
-
child.on("error", () =>
|
|
5596
|
-
child.on("exit", (code) => code ?
|
|
5871
|
+
child.on("error", () => fail(new CliError("\uBAA8\uC758 \uD638\uC2A4\uD2B8\uB97C \uC2E4\uD589\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.", "SKILL_EDITOR_DEV_FAILED")));
|
|
5872
|
+
child.on("exit", (code) => code ? fail(new CliError(`\uBAA8\uC758 \uD638\uC2A4\uD2B8\uAC00 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4(\uCF54\uB4DC ${code}). SDK\uC5D0\uC11C pnpm build\uB97C \uBA3C\uC800 \uC2E4\uD589\uD588\uB294\uC9C0 \uD655\uC778\uD558\uC138\uC694.`, "SKILL_EDITOR_DEV_FAILED")) : done());
|
|
5597
5873
|
});
|
|
5598
5874
|
}
|
|
5599
5875
|
);
|
|
@@ -5722,14 +5998,14 @@ function editorReport(prepared) {
|
|
|
5722
5998
|
var SDK_LOCATION_HELP = "SDK\uB294 \uC544\uC9C1 npm\uC5D0 \uACF5\uAC1C\uB418\uC9C0 \uC54A\uC544 CLI\uC5D0 \uD3EC\uD568\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. SDK \uC18C\uC2A4 \uB514\uB809\uD130\uB9AC(\uD074\uB799 \uB0B4\uBD80 \uC791\uC5C5\uC790\uB294 \uB0B4\uBD80 \uC800\uC7A5\uC18C\uC758 clack-skill-editor-sdk)\uC5D0\uC11C pnpm install && pnpm build\uB97C \uC2E4\uD589\uD55C \uB4A4 --sdk-dir <SDK \uB514\uB809\uD130\uB9AC>, CLACK_SKILL_EDITOR_SDK_DIR=<SDK \uB514\uB809\uD130\uB9AC>, CLACK_MONOREPO_DIR=<\uB0B4\uBD80 \uC800\uC7A5\uC18C> \uC911 \uD558\uB098\uB85C \uC704\uCE58\uB97C \uC9C0\uC815\uD558\uC138\uC694.";
|
|
5723
5999
|
function resolveSdkDir(option) {
|
|
5724
6000
|
const candidates = [];
|
|
5725
|
-
if (option) candidates.push(
|
|
6001
|
+
if (option) candidates.push(resolve9(option));
|
|
5726
6002
|
else {
|
|
5727
|
-
if (process.env.CLACK_SKILL_EDITOR_SDK_DIR) candidates.push(
|
|
6003
|
+
if (process.env.CLACK_SKILL_EDITOR_SDK_DIR) candidates.push(resolve9(process.env.CLACK_SKILL_EDITOR_SDK_DIR));
|
|
5728
6004
|
try {
|
|
5729
|
-
candidates.push(
|
|
6005
|
+
candidates.push(resolve9(createRequire(join3(process.cwd(), "noop.js")).resolve("@clack/skill-editor-sdk/package.json"), ".."));
|
|
5730
6006
|
} catch {
|
|
5731
6007
|
}
|
|
5732
|
-
if (process.env.CLACK_MONOREPO_DIR) candidates.push(
|
|
6008
|
+
if (process.env.CLACK_MONOREPO_DIR) candidates.push(resolve9(process.env.CLACK_MONOREPO_DIR, "clack-skill-editor-sdk"));
|
|
5733
6009
|
}
|
|
5734
6010
|
const found = candidates.find((dir) => existsSync(join3(dir, "mock-host/serve.mjs")));
|
|
5735
6011
|
if (!found) throw new CliError(`\uC2A4\uD0AC \uC5D0\uB514\uD130 SDK(@clack/skill-editor-sdk)\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. ${SDK_LOCATION_HELP}`, "SKILL_EDITOR_SDK_NOT_FOUND");
|
|
@@ -5745,24 +6021,24 @@ function skillVersionIds(skillId, versionId) {
|
|
|
5745
6021
|
// src/lib/platform-mcp.ts
|
|
5746
6022
|
var protocolVersions = /* @__PURE__ */ new Set(["2024-11-05", "2025-03-26", "2025-06-18", "2025-11-25"]);
|
|
5747
6023
|
var maxLineBytes = 1024 * 1024;
|
|
5748
|
-
var collectionKey =
|
|
6024
|
+
var collectionKey = z11.string().regex(/^[A-Za-z0-9_-]{1,64}$/);
|
|
5749
6025
|
var patSchemas = {
|
|
5750
|
-
skillList:
|
|
5751
|
-
skillGet:
|
|
5752
|
-
skillPush:
|
|
5753
|
-
skillVersionRef:
|
|
5754
|
-
skillSubmit:
|
|
5755
|
-
skillRelease:
|
|
5756
|
-
skill_id:
|
|
5757
|
-
version_id:
|
|
5758
|
-
visibility:
|
|
5759
|
-
confirm:
|
|
6026
|
+
skillList: z11.object({ q: z11.string().trim().min(1).max(100).optional() }).strict(),
|
|
6027
|
+
skillGet: z11.object({ slug: z11.string().regex(/^[a-z][a-z0-9-]{0,63}$/) }).strict(),
|
|
6028
|
+
skillPush: z11.object({ dir: z11.string().min(1).max(4096).optional(), skill_id: z11.uuid().optional() }).strict(),
|
|
6029
|
+
skillVersionRef: z11.object({ skill_id: z11.uuid(), version_id: z11.uuid() }).strict(),
|
|
6030
|
+
skillSubmit: z11.object({ skill_id: z11.uuid(), version_id: z11.uuid(), confirm: z11.boolean().optional() }).strict(),
|
|
6031
|
+
skillRelease: z11.object({
|
|
6032
|
+
skill_id: z11.uuid(),
|
|
6033
|
+
version_id: z11.uuid(),
|
|
6034
|
+
visibility: z11.enum(["private", "unlisted", "public"]),
|
|
6035
|
+
confirm: z11.boolean().optional()
|
|
5760
6036
|
}).strict(),
|
|
5761
|
-
contentPublish:
|
|
5762
|
-
sharedCollections:
|
|
5763
|
-
sharedList:
|
|
5764
|
-
sharedDocument:
|
|
5765
|
-
sharedModerate:
|
|
6037
|
+
contentPublish: z11.object({ content_id: z11.uuid(), version_id: z11.uuid(), confirm: z11.boolean().optional() }).strict(),
|
|
6038
|
+
sharedCollections: z11.object({ content_id: z11.uuid() }).strict(),
|
|
6039
|
+
sharedList: z11.object({ content_id: z11.uuid(), collection: collectionKey, limit: z11.number().int().min(1).max(100).optional() }).strict(),
|
|
6040
|
+
sharedDocument: z11.object({ content_id: z11.uuid(), collection: collectionKey, key: collectionKey }).strict(),
|
|
6041
|
+
sharedModerate: z11.object({ content_id: z11.uuid(), collection: collectionKey, key: collectionKey, confirm: z11.boolean().optional() }).strict()
|
|
5766
6042
|
};
|
|
5767
6043
|
var patToolNames = /* @__PURE__ */ new Set([
|
|
5768
6044
|
"platform_authoring",
|
|
@@ -5792,120 +6068,120 @@ function parsePat(schema, input, label) {
|
|
|
5792
6068
|
return parsed.data;
|
|
5793
6069
|
}
|
|
5794
6070
|
var toolDefinitions = [
|
|
5795
|
-
{ name: "platform_authoring", description: "\uACF5\uAC1C \uC2A4\uD0AC \uC81C\uC791 \uC138\uC158\xB7\uD3FC\xB7\uC790\uC0B0\xB7\uC774\uBBF8\uC9C0 \uC0DD\uC131\xB7\uD328\uD0A4\uC9D5\xB7\uC644\uB8CC\xB7\uD3EC\uAE30\uB97C \uCC98\uB9AC\uD569\uB2C8\uB2E4. complete/abandon\uC740 \uD3FC \uC138\uC158 \uC804\uC6A9\uC774\uBA70 complete\uB294 \uD604\uC7AC revision \uD328\uD0A4\uC9D5, abandon\uC740 confirm:true\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \uC5D0\uB514\uD130\xB7\uC9C0\uCE68\uD615\uC740 \uC13C\uD130\uC5D0\uC11C \uC791\uC5C5\uD569\uB2C8\uB2E4. \uC774\uBBF8\uC9C0 \uC0DD\uC131\uC5D0\uB294 \uACAC\uC801 \uC2B9\uC778 \uAC00\uACA9\uACFC \uBA71\uB4F1\uC131 \uD0A4\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. creator-content:write \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.", inputSchema: { type: "object", ...
|
|
6071
|
+
{ name: "platform_authoring", description: "\uACF5\uAC1C \uC2A4\uD0AC \uC81C\uC791 \uC138\uC158\xB7\uD3FC\xB7\uC790\uC0B0\xB7\uC774\uBBF8\uC9C0 \uC0DD\uC131\xB7\uD328\uD0A4\uC9D5\xB7\uC644\uB8CC\xB7\uD3EC\uAE30\uB97C \uCC98\uB9AC\uD569\uB2C8\uB2E4. complete/abandon\uC740 \uD3FC \uC138\uC158 \uC804\uC6A9\uC774\uBA70 complete\uB294 \uD604\uC7AC revision \uD328\uD0A4\uC9D5, abandon\uC740 confirm:true\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \uC5D0\uB514\uD130\xB7\uC9C0\uCE68\uD615\uC740 \uC13C\uD130\uC5D0\uC11C \uC791\uC5C5\uD569\uB2C8\uB2E4. \uC774\uBBF8\uC9C0 \uC0DD\uC131\uC5D0\uB294 \uACAC\uC801 \uC2B9\uC778 \uAC00\uACA9\uACFC \uBA71\uB4F1\uC131 \uD0A4\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. creator-content:write \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.", inputSchema: { type: "object", ...z11.toJSONSchema(authoringInput) }, annotations: { readOnlyHint: false, destructiveHint: true } },
|
|
5796
6072
|
{
|
|
5797
6073
|
name: "platform_usage_get",
|
|
5798
6074
|
description: "\uC11C\uBC84 \uD0A4\uAC00 \uC18D\uD55C \uCF58\uD150\uCE20\uC758 \uD50C\uB7AB\uD3FC \uC0AC\uC6A9\uB7C9\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4.",
|
|
5799
|
-
inputSchema:
|
|
6075
|
+
inputSchema: z11.toJSONSchema(platformReadSchemas.usage),
|
|
5800
6076
|
annotations: { readOnlyHint: true, destructiveHint: false }
|
|
5801
6077
|
},
|
|
5802
6078
|
{
|
|
5803
6079
|
name: "platform_server_data_get",
|
|
5804
6080
|
description: "\uC11C\uBC84 \uD0A4\uB85C \uCF58\uD150\uCE20 \uB370\uC774\uD130 \uBB38\uC11C\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4. data:read \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5805
|
-
inputSchema:
|
|
6081
|
+
inputSchema: z11.toJSONSchema(platformReadSchemas.get),
|
|
5806
6082
|
annotations: { readOnlyHint: true, destructiveHint: false }
|
|
5807
6083
|
},
|
|
5808
6084
|
{
|
|
5809
6085
|
name: "platform_server_data_list",
|
|
5810
6086
|
description: "\uC11C\uBC84 \uD0A4\uB85C \uCF58\uD150\uCE20 \uB370\uC774\uD130 \uBB38\uC11C \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. data:read \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5811
|
-
inputSchema:
|
|
6087
|
+
inputSchema: z11.toJSONSchema(platformReadSchemas.list),
|
|
5812
6088
|
annotations: { readOnlyHint: true, destructiveHint: false }
|
|
5813
6089
|
},
|
|
5814
6090
|
{
|
|
5815
6091
|
name: "platform_server_data_leaderboard",
|
|
5816
6092
|
description: "\uC11C\uBC84 \uD0A4\uB85C \uACF5\uC720 \uB370\uC774\uD130 \uC21C\uC704\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4. data:read \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5817
|
-
inputSchema:
|
|
6093
|
+
inputSchema: z11.toJSONSchema(platformReadSchemas.leaderboard),
|
|
5818
6094
|
annotations: { readOnlyHint: true, destructiveHint: false }
|
|
5819
6095
|
},
|
|
5820
6096
|
{
|
|
5821
6097
|
name: "platform_server_data_put",
|
|
5822
6098
|
description: "\uC11C\uBC84 \uD0A4\uB85C \uB2E8\uC77C \uBB38\uC11C \uC804\uCCB4\uB97C \uC800\uC7A5\uD569\uB2C8\uB2E4. \uAC1C\uC815 \uBC88\uD638 \uB610\uB294 \uBD80\uC7AC \uC870\uAC74\uACFC confirm:true\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5823
|
-
inputSchema:
|
|
6099
|
+
inputSchema: z11.toJSONSchema(platformReadSchemas.put),
|
|
5824
6100
|
annotations: { readOnlyHint: false, destructiveHint: true }
|
|
5825
6101
|
},
|
|
5826
6102
|
{
|
|
5827
6103
|
name: "platform_server_data_patch",
|
|
5828
6104
|
description: "\uC11C\uBC84 \uD0A4\uB85C \uB2E8\uC77C \uBB38\uC11C\uB97C \uBCD1\uD569 \uC218\uC815\uD569\uB2C8\uB2E4. \uAC1C\uC815 \uBC88\uD638\uC640 confirm:true\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5829
|
-
inputSchema:
|
|
6105
|
+
inputSchema: z11.toJSONSchema(platformReadSchemas.patch),
|
|
5830
6106
|
annotations: { readOnlyHint: false, destructiveHint: true }
|
|
5831
6107
|
},
|
|
5832
6108
|
{
|
|
5833
6109
|
name: "platform_server_data_delete",
|
|
5834
6110
|
description: "\uC11C\uBC84 \uD0A4\uB85C \uB2E8\uC77C \uBB38\uC11C\uB97C \uC0AD\uC81C\uD558\uAC70\uB098 \uC228\uAE41\uB2C8\uB2E4. confirm:true\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5835
|
-
inputSchema:
|
|
6111
|
+
inputSchema: z11.toJSONSchema(platformReadSchemas.delete),
|
|
5836
6112
|
annotations: { readOnlyHint: false, destructiveHint: true }
|
|
5837
6113
|
},
|
|
5838
6114
|
// 아래는 개인 액세스 토큰(CLACK_TOKEN, pat_)으로 동작하는 개인 도구다. 서버 키 도구와 인증 평면이 다르다.
|
|
5839
6115
|
{
|
|
5840
6116
|
name: "platform_skill_list",
|
|
5841
6117
|
description: "\uACF5\uAC1C \uC2A4\uD0AC \uBAA9\uB85D\uC744 \uC774\uB984\uC73C\uB85C \uAC80\uC0C9\uD569\uB2C8\uB2E4. skill:read \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5842
|
-
inputSchema:
|
|
6118
|
+
inputSchema: z11.toJSONSchema(patSchemas.skillList),
|
|
5843
6119
|
annotations: { readOnlyHint: true, destructiveHint: false }
|
|
5844
6120
|
},
|
|
5845
6121
|
{
|
|
5846
6122
|
name: "platform_skill_get",
|
|
5847
6123
|
description: "\uC2A4\uD0AC \uC0C1\uC138\uB97C \uC774\uB984(slug)\uC73C\uB85C \uC870\uD68C\uD569\uB2C8\uB2E4. skill:read \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5848
|
-
inputSchema:
|
|
6124
|
+
inputSchema: z11.toJSONSchema(patSchemas.skillGet),
|
|
5849
6125
|
annotations: { readOnlyHint: true, destructiveHint: false }
|
|
5850
6126
|
},
|
|
5851
6127
|
{
|
|
5852
6128
|
name: "platform_skill_push",
|
|
5853
6129
|
description: "\uB85C\uCEEC \uC2A4\uD0AC \uB514\uB809\uD130\uB9AC\uB97C \uAC80\uC99D\uD558\uACE0 \uC0C8 \uBC84\uC804\uC73C\uB85C \uC5C5\uB85C\uB4DC\uD569\uB2C8\uB2E4. dir\uC744 \uC0DD\uB7B5\uD558\uBA74 \uD604\uC7AC \uB514\uB809\uD130\uB9AC\uB97C \uC0AC\uC6A9\uD569\uB2C8\uB2E4. skill:write \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5854
|
-
inputSchema:
|
|
6130
|
+
inputSchema: z11.toJSONSchema(patSchemas.skillPush),
|
|
5855
6131
|
annotations: { readOnlyHint: false, destructiveHint: false }
|
|
5856
6132
|
},
|
|
5857
6133
|
{
|
|
5858
6134
|
name: "platform_skill_status",
|
|
5859
6135
|
description: "\uB0B4 \uC2A4\uD0AC \uBC84\uC804\uC758 \uC2EC\uC0AC\xB7\uAC8C\uC2DC \uC0C1\uD0DC\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4. skill:read \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5860
|
-
inputSchema:
|
|
6136
|
+
inputSchema: z11.toJSONSchema(patSchemas.skillVersionRef),
|
|
5861
6137
|
annotations: { readOnlyHint: true, destructiveHint: false }
|
|
5862
6138
|
},
|
|
5863
6139
|
{
|
|
5864
6140
|
name: "platform_skill_submit",
|
|
5865
6141
|
description: "\uAC80\uC99D \uC644\uB8CC\uD55C \uC2A4\uD0AC \uBC84\uC804\uC744 \uC2EC\uC0AC\uC5D0 \uC81C\uCD9C\uD569\uB2C8\uB2E4. skill:write\uC640 skill:publish \uAD8C\uD55C(\uB458 \uB2E4)\uACFC confirm:true\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5866
|
-
inputSchema:
|
|
6142
|
+
inputSchema: z11.toJSONSchema(patSchemas.skillSubmit),
|
|
5867
6143
|
annotations: { readOnlyHint: false, destructiveHint: true }
|
|
5868
6144
|
},
|
|
5869
6145
|
{
|
|
5870
6146
|
name: "platform_skill_release",
|
|
5871
6147
|
description: "\uC2B9\uC778\uB41C \uC2A4\uD0AC \uBC84\uC804\uC744 \uACF5\uAC1C \uBC94\uC704\uB85C \uAC8C\uC2DC\uD569\uB2C8\uB2E4. skill:publish \uAD8C\uD55C\uACFC confirm:true\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5872
|
-
inputSchema:
|
|
6148
|
+
inputSchema: z11.toJSONSchema(patSchemas.skillRelease),
|
|
5873
6149
|
annotations: { readOnlyHint: false, destructiveHint: true }
|
|
5874
6150
|
},
|
|
5875
6151
|
{
|
|
5876
6152
|
name: "platform_content_publish",
|
|
5877
6153
|
description: "\uC2B9\uC778\uB41C \uB0B4 HTML \uCF58\uD150\uCE20 \uBC84\uC804\uC744 \uACF5\uAC1C\uD569\uB2C8\uB2E4. creator-content:publish \uAD8C\uD55C\uACFC confirm:true\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5878
|
-
inputSchema:
|
|
6154
|
+
inputSchema: z11.toJSONSchema(patSchemas.contentPublish),
|
|
5879
6155
|
annotations: { readOnlyHint: false, destructiveHint: true }
|
|
5880
6156
|
},
|
|
5881
6157
|
{
|
|
5882
6158
|
name: "platform_shared_collections_list",
|
|
5883
6159
|
description: "\uB0B4 \uCF58\uD150\uCE20\uC758 \uC774\uC6A9\uC790 \uACF5\uAC1C(shared) \uBB38\uC11C \uCEEC\uB809\uC158 \uC774\uB984\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. platform:read \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5884
|
-
inputSchema:
|
|
6160
|
+
inputSchema: z11.toJSONSchema(patSchemas.sharedCollections),
|
|
5885
6161
|
annotations: { readOnlyHint: true, destructiveHint: false }
|
|
5886
6162
|
},
|
|
5887
6163
|
{
|
|
5888
6164
|
name: "platform_shared_documents_list",
|
|
5889
6165
|
description: "\uB0B4 \uCF58\uD150\uCE20\uC758 \uACF5\uC720 \uBB38\uC11C \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. platform:read \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5890
|
-
inputSchema:
|
|
6166
|
+
inputSchema: z11.toJSONSchema(patSchemas.sharedList),
|
|
5891
6167
|
annotations: { readOnlyHint: true, destructiveHint: false }
|
|
5892
6168
|
},
|
|
5893
6169
|
{
|
|
5894
6170
|
name: "platform_shared_document_get",
|
|
5895
6171
|
description: "\uB0B4 \uCF58\uD150\uCE20\uC758 \uACF5\uC720 \uBB38\uC11C \uD558\uB098\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4. platform:read \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5896
|
-
inputSchema:
|
|
6172
|
+
inputSchema: z11.toJSONSchema(patSchemas.sharedDocument),
|
|
5897
6173
|
annotations: { readOnlyHint: true, destructiveHint: false }
|
|
5898
6174
|
},
|
|
5899
6175
|
{
|
|
5900
6176
|
name: "platform_shared_document_hide",
|
|
5901
6177
|
description: "\uC774\uC6A9\uC790\uAC00 \uC4F4 \uACF5\uC720 \uBB38\uC11C\uB97C \uC228\uAE41\uB2C8\uB2E4. platform:write \uAD8C\uD55C\uACFC confirm:true\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5902
|
-
inputSchema:
|
|
6178
|
+
inputSchema: z11.toJSONSchema(patSchemas.sharedModerate),
|
|
5903
6179
|
annotations: { readOnlyHint: false, destructiveHint: true }
|
|
5904
6180
|
},
|
|
5905
6181
|
{
|
|
5906
6182
|
name: "platform_shared_document_delete",
|
|
5907
6183
|
description: "\uC774\uC6A9\uC790\uAC00 \uC4F4 \uACF5\uC720 \uBB38\uC11C\uB97C \uC601\uAD6C \uC0AD\uC81C\uD569\uB2C8\uB2E4. platform:write \uAD8C\uD55C\uACFC confirm:true\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
5908
|
-
inputSchema:
|
|
6184
|
+
inputSchema: z11.toJSONSchema(patSchemas.sharedModerate),
|
|
5909
6185
|
annotations: { readOnlyHint: false, destructiveHint: true }
|
|
5910
6186
|
}
|
|
5911
6187
|
];
|
|
@@ -6146,14 +6422,14 @@ function registerIntegrationCommands(program2, runtime2) {
|
|
|
6146
6422
|
|
|
6147
6423
|
// src/commands/page.ts
|
|
6148
6424
|
import { Option as Option3 } from "commander";
|
|
6149
|
-
import { z as
|
|
6150
|
-
var uuid3 = (value2) => parse(
|
|
6151
|
-
var revision3 = (value2) => parse(
|
|
6425
|
+
import { z as z12 } from "zod";
|
|
6426
|
+
var uuid3 = (value2) => parse(z12.uuid(), value2);
|
|
6427
|
+
var revision3 = (value2) => parse(z12.coerce.number().int().nonnegative().max(4294967295), value2);
|
|
6152
6428
|
var base = "/v4/creator/custom-pages";
|
|
6153
|
-
var presentationSchema =
|
|
6154
|
-
schema_version:
|
|
6155
|
-
header_mode:
|
|
6156
|
-
color_scheme:
|
|
6429
|
+
var presentationSchema = z12.object({
|
|
6430
|
+
schema_version: z12.literal(1),
|
|
6431
|
+
header_mode: z12.enum(["fixed", "scroll_hide", "translucent_scroll_hide", "floating_close", "floating_close_safe_area"]),
|
|
6432
|
+
color_scheme: z12.enum(["light", "dark"])
|
|
6157
6433
|
}).strict();
|
|
6158
6434
|
function registerPageCommands(program2, runtime2) {
|
|
6159
6435
|
const page = program2.command("page").description("\uC138\uACC4\uAD00\xB7\uB0B4 \uACF5\uAC1C \uD648 HTML \uAFB8\uBBF8\uAE30 (custom-page:read\xB7write\xB7publish)");
|
|
@@ -6161,7 +6437,7 @@ function registerPageCommands(program2, runtime2) {
|
|
|
6161
6437
|
runtime2.action(page.command("status <id>").description("\uD398\uC774\uC9C0\uC640 \uBC84\uC804\xB7\uC218\uC815 \uBC88\uD638 \uC0C1\uD0DC (custom-page:read)"), async (ctx, [id2]) => ctx.output(await ctx.api.request("GET", `${base}/${uuid3(id2)}`)));
|
|
6162
6438
|
runtime2.action(page.command("create").description("\uAFB8\uBC00 \uD398\uC774\uC9C0 \uB4F1\uB85D (custom-page:write)").addOption(new Option3("--target <type>", "\uAFB8\uBC00 \uB300\uC0C1").choices(["profile", "space"]).makeOptionMandatory()).option("--space-id <uuid>", "\uC138\uACC4\uAD00 ID").requiredOption("--policy-version <version>", "\uB3D9\uC758\uD55C \uCF58\uD150\uCE20 \uC81C\uACF5 \uC815\uCC45 \uBC84\uC804"), async (ctx, _args, opts) => {
|
|
6163
6439
|
if (opts.target === "profile" && opts.spaceId) throw new CliError("\uB0B4 \uACF5\uAC1C \uD648\uC5D0\uB294 \uC138\uACC4\uAD00 ID\uB97C \uC9C0\uC815\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
|
|
6164
|
-
const policy = parse(
|
|
6440
|
+
const policy = parse(z12.literal("2026-09-22"), opts.policyVersion);
|
|
6165
6441
|
await mutate(ctx, "POST", base, { target_type: opts.target, ...opts.target === "space" ? { space_id: uuid3(opts.spaceId) } : {}, policy_version: policy });
|
|
6166
6442
|
});
|
|
6167
6443
|
runtime2.action(page.command("upload <id> <file>").description("HTML/ZIP \uC5C5\uB85C\uB4DC\uB85C \uC0C8 \uBE44\uACF5\uAC1C \uBC84\uC804 \uC0DD\uC131 (custom-page:write)").addOption(new Option3("--header <mode>", "\uD5E4\uB354 \uD45C\uC2DC").choices(["fixed", "scroll_hide", "translucent_scroll_hide", "floating_close", "floating_close_safe_area"]).default("fixed")).addOption(new Option3("--color <scheme>", "\uD5E4\uB354 \uC0C9\uC0C1").choices(["light", "dark"]).default("light")), async (ctx, [id2, file], opts) => {
|
|
@@ -6226,7 +6502,8 @@ try {
|
|
|
6226
6502
|
status: failure.status,
|
|
6227
6503
|
code: failure.code,
|
|
6228
6504
|
message: failure.message,
|
|
6229
|
-
...failure.retryAfter ? { retry_after: failure.retryAfter } : {}
|
|
6505
|
+
...failure.retryAfter ? { retry_after: failure.retryAfter } : {},
|
|
6506
|
+
...failure.recovery ? { recovery: failure.recovery } : {}
|
|
6230
6507
|
});
|
|
6231
6508
|
const json2 = program.opts().json || process.argv.includes("--json") || await store.resolve(program.opts(), true).then((value2) => value2.options.json).catch(() => false);
|
|
6232
6509
|
if (json2) process.stdout.write(JSON.stringify(envelope) + "\n");
|