democut 0.6.1 → 0.6.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +8 -4
  2. package/dist/cli.js +3000 -965
  3. package/package.json +3 -2
package/dist/cli.js CHANGED
@@ -1298,21 +1298,21 @@ var require_errors = __commonJS({
1298
1298
  function extendErrors({ gen, keyword, schemaValue, data, errsCount, it }) {
1299
1299
  if (errsCount === void 0)
1300
1300
  throw new Error("ajv implementation error");
1301
- const err3 = gen.name("err");
1301
+ const err2 = gen.name("err");
1302
1302
  gen.forRange("i", errsCount, names_1.default.errors, (i) => {
1303
- gen.const(err3, (0, codegen_1._)`${names_1.default.vErrors}[${i}]`);
1304
- gen.if((0, codegen_1._)`${err3}.instancePath === undefined`, () => gen.assign((0, codegen_1._)`${err3}.instancePath`, (0, codegen_1.strConcat)(names_1.default.instancePath, it.errorPath)));
1305
- gen.assign((0, codegen_1._)`${err3}.schemaPath`, (0, codegen_1.str)`${it.errSchemaPath}/${keyword}`);
1303
+ gen.const(err2, (0, codegen_1._)`${names_1.default.vErrors}[${i}]`);
1304
+ gen.if((0, codegen_1._)`${err2}.instancePath === undefined`, () => gen.assign((0, codegen_1._)`${err2}.instancePath`, (0, codegen_1.strConcat)(names_1.default.instancePath, it.errorPath)));
1305
+ gen.assign((0, codegen_1._)`${err2}.schemaPath`, (0, codegen_1.str)`${it.errSchemaPath}/${keyword}`);
1306
1306
  if (it.opts.verbose) {
1307
- gen.assign((0, codegen_1._)`${err3}.schema`, schemaValue);
1308
- gen.assign((0, codegen_1._)`${err3}.data`, data);
1307
+ gen.assign((0, codegen_1._)`${err2}.schema`, schemaValue);
1308
+ gen.assign((0, codegen_1._)`${err2}.data`, data);
1309
1309
  }
1310
1310
  });
1311
1311
  }
1312
1312
  exports.extendErrors = extendErrors;
1313
1313
  function addError(gen, errObj) {
1314
- const err3 = gen.const("err", errObj);
1315
- gen.if((0, codegen_1._)`${names_1.default.vErrors} === null`, () => gen.assign(names_1.default.vErrors, (0, codegen_1._)`[${err3}]`), (0, codegen_1._)`${names_1.default.vErrors}.push(${err3})`);
1314
+ const err2 = gen.const("err", errObj);
1315
+ gen.if((0, codegen_1._)`${names_1.default.vErrors} === null`, () => gen.assign(names_1.default.vErrors, (0, codegen_1._)`[${err2}]`), (0, codegen_1._)`${names_1.default.vErrors}.push(${err2})`);
1316
1316
  gen.code((0, codegen_1._)`${names_1.default.errors}++`);
1317
1317
  }
1318
1318
  function returnErrors(it, errs) {
@@ -6916,7 +6916,7 @@ import { realpathSync } from "fs";
6916
6916
  import { fileURLToPath } from "url";
6917
6917
 
6918
6918
  // src/version.ts
6919
- var VERSION = "0.6.1";
6919
+ var VERSION = "0.6.15";
6920
6920
 
6921
6921
  // src/device-flow.ts
6922
6922
  var DeviceFlowError = class extends Error {
@@ -6956,19 +6956,19 @@ function oauthError(json) {
6956
6956
  return "invalid_grant";
6957
6957
  }
6958
6958
  async function requestDeviceAuthorization(baseUrl, fetchImpl = fetch) {
6959
- const { ok, status: status2, json } = await postJson(
6959
+ const { ok, status, json } = await postJson(
6960
6960
  `${baseUrl}/api/oauth/device/authorize`,
6961
6961
  {},
6962
6962
  fetchImpl
6963
6963
  );
6964
6964
  if (!ok) {
6965
- if (status2 === 503) {
6965
+ if (status === 503) {
6966
6966
  throw new DeviceFlowError(
6967
6967
  "disabled",
6968
6968
  "\uC11C\uBC84\uC5D0\uC11C device flow \uAC00 \uBE44\uD65C\uC131\uD654\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 (DEMOCUT_DEVICE_TOKEN_SECRET \uBBF8\uC124\uC815)."
6969
6969
  );
6970
6970
  }
6971
- throw new DeviceFlowError("authorize_failed", `device authorize \uC2E4\uD328 (HTTP ${status2}).`);
6971
+ throw new DeviceFlowError("authorize_failed", `device authorize \uC2E4\uD328 (HTTP ${status}).`);
6972
6972
  }
6973
6973
  return json;
6974
6974
  }
@@ -6979,10 +6979,10 @@ async function pollTokenOnce(baseUrl, deviceCode, fetchImpl = fetch) {
6979
6979
  fetchImpl
6980
6980
  );
6981
6981
  if (ok) return { status: "approved", tokens: json };
6982
- const err3 = oauthError(json);
6983
- if (err3 === "authorization_pending") return { status: "pending" };
6984
- if (err3 === "slow_down") return { status: "slow_down" };
6985
- throw new DeviceFlowError(err3, describeError(err3));
6982
+ const err2 = oauthError(json);
6983
+ if (err2 === "authorization_pending") return { status: "pending" };
6984
+ if (err2 === "slow_down") return { status: "slow_down" };
6985
+ throw new DeviceFlowError(err2, describeError(err2));
6986
6986
  }
6987
6987
  async function refreshToken(baseUrl, refresh, fetchImpl = fetch) {
6988
6988
  const { ok, json } = await postJson(
@@ -7001,9 +7001,9 @@ async function pollUntilApproved(baseUrl, auth, deps = {}) {
7001
7001
  const deadline = now() + auth.expires_in;
7002
7002
  while (now() < deadline) {
7003
7003
  await sleep(intervalMs);
7004
- const out3 = await pollTokenOnce(baseUrl, auth.device_code, fetchImpl);
7005
- if (out3.status === "approved") return out3.tokens;
7006
- if (out3.status === "slow_down") intervalMs += SLOW_DOWN_INCREMENT_MS;
7004
+ const out2 = await pollTokenOnce(baseUrl, auth.device_code, fetchImpl);
7005
+ if (out2.status === "approved") return out2.tokens;
7006
+ if (out2.status === "slow_down") intervalMs += SLOW_DOWN_INCREMENT_MS;
7007
7007
  deps.onPending?.();
7008
7008
  }
7009
7009
  throw new DeviceFlowError("expired_token", describeError("expired_token"));
@@ -7244,247 +7244,7 @@ function logoutCommand(opts) {
7244
7244
  return 0;
7245
7245
  }
7246
7246
 
7247
- // src/api-client.ts
7248
- var ApiError = class extends Error {
7249
- constructor(status2, code, message, retriable, extra = {}) {
7250
- super(message);
7251
- this.status = status2;
7252
- this.code = code;
7253
- this.retriable = retriable;
7254
- this.extra = extra;
7255
- this.name = "ApiError";
7256
- }
7257
- status;
7258
- code;
7259
- retriable;
7260
- extra;
7261
- };
7262
- function parseDetail(status2, body) {
7263
- const detail = body?.detail;
7264
- if (detail && typeof detail === "object" && !Array.isArray(detail)) {
7265
- const d = detail;
7266
- if (typeof d.code === "string" || typeof d.message === "string") {
7267
- const { code, message, retriable, ...extra } = d;
7268
- return new ApiError(
7269
- status2,
7270
- typeof code === "string" ? code : `HTTP_${status2}`,
7271
- typeof message === "string" ? message : `HTTP ${status2}`,
7272
- typeof retriable === "boolean" ? retriable : null,
7273
- extra
7274
- );
7275
- }
7276
- }
7277
- if (typeof detail === "string") {
7278
- return new ApiError(status2, `HTTP_${status2}`, detail, null);
7279
- }
7280
- if (Array.isArray(detail)) {
7281
- const lines = detail.map((e) => {
7282
- const item = e;
7283
- const where = Array.isArray(item.loc) ? item.loc.filter((p) => p !== "body").join(".") : "";
7284
- const msg = typeof item.msg === "string" ? item.msg : JSON.stringify(e);
7285
- return where ? `${where}: ${msg}` : msg;
7286
- });
7287
- return new ApiError(status2, "VALIDATION_ERROR", lines.join("\n"), true);
7288
- }
7289
- return new ApiError(status2, `HTTP_${status2}`, `\uC694\uCCAD\uC774 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4 (HTTP ${status2}).`, null);
7290
- }
7291
- async function apiRequest(baseUrl, path, init = {}, deps = {}) {
7292
- const fetchImpl = deps.fetchImpl ?? fetch;
7293
- const token = await getValidAccessToken(baseUrl, deps);
7294
- const headers = {
7295
- Authorization: `Bearer ${token}`,
7296
- "User-Agent": `democut/${VERSION}`
7297
- };
7298
- if (init.body !== void 0) headers["Content-Type"] = "application/json";
7299
- const res = await fetchImpl(`${baseUrl}${path}`, {
7300
- method: init.method ?? "GET",
7301
- headers,
7302
- ...init.body === void 0 ? {} : { body: JSON.stringify(init.body) }
7303
- });
7304
- const text = await res.text();
7305
- let json = null;
7306
- if (text) {
7307
- try {
7308
- json = JSON.parse(text);
7309
- } catch {
7310
- json = null;
7311
- }
7312
- }
7313
- if (!res.ok) {
7314
- if (res.status === 401) {
7315
- throw new ApiError(
7316
- 401,
7317
- "UNAUTHENTICATED",
7318
- "\uC778\uC99D\uC774 \uB9CC\uB8CC\uB418\uC5C8\uAC70\uB098 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. 'democut auth login' \uC73C\uB85C \uB2E4\uC2DC \uB85C\uADF8\uC778\uD558\uC138\uC694.",
7319
- false
7320
- );
7321
- }
7322
- throw parseDetail(res.status, json);
7323
- }
7324
- return json;
7325
- }
7326
-
7327
- // src/api-errors.ts
7328
- function usd(v) {
7329
- return v < 0.01 ? `$${v.toFixed(4)}` : `$${v.toFixed(2)}`;
7330
- }
7331
- function classifyApiError(e, ctx) {
7332
- const hint = ctx.statusHint ?? "\uC0C1\uD0DC \uC870\uD68C";
7333
- if (e.status === 422 && e.code === "VIDEOGEN_UPSTREAM_REJECTED") {
7334
- return {
7335
- safety: "unsafe",
7336
- // 돈이 나갔다가 돌아왔다 — "애초에 과금이 없었다" 와는 다르다. 그 구분을 흐리면
7337
- // 원장을 보는 사람이 이 거래를 설명하지 못한다.
7338
- notCharged: false,
7339
- lines: [
7340
- "\uC5C5\uC2A4\uD2B8\uB9BC\uC774 \uC774 \uC791\uC5C5\uC744 \uC601\uAD6C \uAC70\uBD80\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC870\uD68C\uD574\uB3C4 \uBCF5\uAD6C\uB418\uC9C0 \uC54A\uC73C\uBA70, \uACFC\uAE08\uC740 \uD658\uBD88\uB410\uC2B5\uB2C8\uB2E4.",
7341
- "\uACE0\uCE60 \uD30C\uB77C\uBBF8\uD130\uAC00 \uC788\uB294 \uC624\uB958\uAC00 \uC544\uB2D9\uB2C8\uB2E4 \u2014 \uC0C8\uB85C \uB9CC\uB4E4\uB824\uBA74 \uD504\uB86C\uD504\uD2B8\xB7\uC124\uC815\uC744 \uBC14\uAFD4 **\uC0C8\uB85C \uC81C\uCD9C**\uD574\uC57C \uD558\uACE0, \uADF8\uAC74 \uB2E4\uC2DC \uACFC\uAE08\uB429\uB2C8\uB2E4(\uC0AC\uC6A9\uC790 \uB3D9\uC758\uB97C \uBC1B\uC73C\uC138\uC694)."
7342
- ]
7343
- };
7344
- }
7345
- if (e.status === 404 && e.code === "VIDEOGEN_JOB_NOT_FOUND") {
7346
- return {
7347
- safety: "unsafe",
7348
- notCharged: false,
7349
- lines: [
7350
- "\uADF8 \uC791\uC5C5\uC744 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. job_id \uAC00 \uB9DE\uB294\uC9C0 \uBA3C\uC800 \uD655\uC778\uD558\uC138\uC694.",
7351
- "\u26A0\uFE0F \uC791\uC5C5\uC774 \uC0B4\uC544 \uC788\uB294\uB370 \uC870\uD68C\uB9CC \uC5B4\uAE0B\uB0AC\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uC0C8\uB85C \uC81C\uCD9C\uD558\uBA74 **\uBCC4\uB3C4 \uC791\uC5C5\uC73C\uB85C \uB2E4\uC2DC \uACFC\uAE08**\uB429\uB2C8\uB2E4."
7352
- ]
7353
- };
7354
- }
7355
- if (e.status === 402) {
7356
- const lines = [];
7357
- const limit = e.extra.limit_usd;
7358
- const would = e.extra.would_cost_usd;
7359
- if (typeof limit === "number" && typeof would === "number") {
7360
- lines.push(`\uC0C1\uD55C ${usd(limit)} \xB7 \uC774 \uC694\uCCAD ${usd(would)}`);
7361
- }
7362
- lines.push("\uD574\uC0C1\uB3C4\uB098 \uAE38\uC774\uB97C \uB0AE\uCDB0 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694. \uC544\uC9C1 \uACFC\uAE08\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
7363
- return { safety: "fixable", notCharged: true, lines };
7364
- }
7365
- if (e.status === 422) {
7366
- return {
7367
- safety: "fixable",
7368
- notCharged: true,
7369
- lines: ["\uD30C\uB77C\uBBF8\uD130\uB97C \uACE0\uCCD0 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694. \uC544\uC9C1 \uACFC\uAE08\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4."]
7370
- };
7371
- }
7372
- if (e.status === 503) {
7373
- return {
7374
- safety: "safe",
7375
- notCharged: true,
7376
- lines: ["\uC77C\uC2DC\uC801\uC778 \uC624\uB958\uC785\uB2C8\uB2E4. \uC7A0\uC2DC \uD6C4 \uADF8\uB300\uB85C \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uB3C4 \uC548\uC804\uD569\uB2C8\uB2E4."]
7377
- };
7378
- }
7379
- if (e.status === 502) {
7380
- return ctx.submitted ? {
7381
- safety: "unsafe",
7382
- notCharged: false,
7383
- lines: [
7384
- "\u26A0\uFE0F \uC81C\uCD9C\uC774 \uC774\uBBF8 \uC811\uC218\uB410\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC81C\uCD9C\uD558\uBA74 \uB450 \uBC88 \uACFC\uAE08\uB429\uB2C8\uB2E4 \u2014",
7385
- `\uC7AC\uC2DC\uB3C4\uD558\uC9C0 \uB9D0\uACE0 ${hint} \uB85C \uD655\uC778\uD558\uAC70\uB098 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBB38\uC758\uD558\uC138\uC694.`
7386
- ]
7387
- } : {
7388
- safety: "safe",
7389
- notCharged: true,
7390
- lines: [
7391
- "\uC5C5\uC2A4\uD2B8\uB9BC \uC624\uB958\uC785\uB2C8\uB2E4. \uC774 \uC694\uCCAD\uC740 \uBD80\uC791\uC6A9\uC774 \uC5C6\uC73C\uBBC0\uB85C \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uB3C4 \uC548\uC804\uD569\uB2C8\uB2E4."
7392
- ]
7393
- };
7394
- }
7395
- if (e.status === 404) {
7396
- const lines = [];
7397
- if (e.code === "VIDEOGEN_PROJECT_NOT_FOUND") {
7398
- lines.push(
7399
- "democut_list_projects \uB85C \uC774 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uC758 \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D\uC744 \uD655\uC778\uD558\uACE0 \uADF8\uC911 \uD558\uB098\uC758 \uC2AC\uB7EC\uADF8\uB97C \uC4F0\uC138\uC694. \uBAA9\uB85D\uC774 \uBE44\uC5B4 \uC788\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uD504\uB85C\uC81D\uD2B8\uB97C \uBA3C\uC800 \uB9CC\uB4E4\uC5B4 \uB2EC\uB77C\uACE0 \uC54C\uB9AC\uC138\uC694."
7400
- );
7401
- }
7402
- lines.push("\uC544\uC9C1 \uACFC\uAE08\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4 \u2014 \uAC12\uC744 \uACE0\uCCD0 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.");
7403
- return { safety: "fixable", notCharged: true, lines };
7404
- }
7405
- if (e.status === 403) {
7406
- return {
7407
- safety: "unknown",
7408
- notCharged: true,
7409
- lines: ["\uC774 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uC5D0\uC11C \uC601\uC0C1\uC744 \uC0DD\uC131\uD560 \uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(\uBA64\uBC84 \uC774\uC0C1 \uD544\uC694)."]
7410
- };
7411
- }
7412
- return { safety: "unknown", notCharged: false, lines: [] };
7413
- }
7414
-
7415
- // src/confirm.ts
7416
- import { createInterface } from "readline/promises";
7417
- function isInteractive() {
7418
- return Boolean(process.stdin.isTTY && process.stdout.isTTY);
7419
- }
7420
- async function confirm(question) {
7421
- const rl = createInterface({ input: process.stdin, output: process.stdout });
7422
- try {
7423
- const answer = await rl.question(`${question} [y/N] `);
7424
- return /^y(es)?$/i.test(answer.trim());
7425
- } finally {
7426
- rl.close();
7427
- }
7428
- }
7429
-
7430
- // src/videogen.ts
7431
- var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["succeeded", "failed", "cancelled"]);
7432
- function isTerminal(status2) {
7433
- return TERMINAL_STATUSES.has(status2);
7434
- }
7435
- function estimate(baseUrl, body, deps = {}) {
7436
- return apiRequest(baseUrl, "/api/videogen/estimate", { method: "POST", body }, deps);
7437
- }
7438
- function submit(baseUrl, body, deps = {}) {
7439
- return apiRequest(baseUrl, "/api/videogen", { method: "POST", body }, deps);
7440
- }
7441
- function status(baseUrl, jobId, projectSlug, deps = {}) {
7442
- const q = projectSlug ? `?project_slug=${encodeURIComponent(projectSlug)}` : "";
7443
- return apiRequest(
7444
- baseUrl,
7445
- `/api/videogen/${encodeURIComponent(jobId)}${q}`,
7446
- {},
7447
- deps
7448
- );
7449
- }
7450
- var WaitTimeout = class extends Error {
7451
- constructor(jobId, waitedS) {
7452
- super(
7453
- `${waitedS}\uCD08 \uC548\uC5D0 \uC644\uB8CC\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC791\uC5C5\uC740 \uC11C\uBC84\uC5D0\uC11C \uACC4\uC18D \uC9C4\uD589\uB429\uB2C8\uB2E4 \u2014 'democut video status ${jobId}' \uB85C \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694 (\uC0C8\uB85C \uC81C\uCD9C\uD558\uBA74 \uB2E4\uC2DC \uACFC\uAE08\uB429\uB2C8\uB2E4).`
7454
- );
7455
- this.jobId = jobId;
7456
- this.waitedS = waitedS;
7457
- this.name = "WaitTimeout";
7458
- }
7459
- jobId;
7460
- waitedS;
7461
- };
7462
- var POLL_INTERVAL_S = 5;
7463
- async function waitForCompletion(baseUrl, jobId, projectSlug, timeoutS, deps = {}) {
7464
- const sleep = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
7465
- const now = deps.now ?? (() => Math.floor(Date.now() / 1e3));
7466
- const deadline = now() + timeoutS;
7467
- for (; ; ) {
7468
- const job = await status(baseUrl, jobId, projectSlug, deps);
7469
- if (isTerminal(job.status)) return job;
7470
- deps.onTick?.(job);
7471
- if (now() >= deadline) throw new WaitTimeout(jobId, timeoutS);
7472
- await sleep(POLL_INTERVAL_S * 1e3);
7473
- }
7474
- }
7475
- async function download(videoUrl, outPath, fetchImpl = fetch) {
7476
- const { writeFile } = await import("fs/promises");
7477
- const res = await fetchImpl(videoUrl);
7478
- if (!res.ok) {
7479
- throw new Error(
7480
- `\uC0B0\uCD9C\uBB3C \uB0B4\uB824\uBC1B\uAE30 \uC2E4\uD328 (HTTP ${res.status}).`
7481
- );
7482
- }
7483
- await writeFile(outPath, Buffer.from(await res.arrayBuffer()));
7484
- }
7485
-
7486
- // src/commands/video.ts
7487
- var MOCK_NOTICE = "\u26A0\uFE0F mock \uBAA8\uB4DC \u2014 \uC774 \uBC30\uD3EC\uB294 \uC601\uC0C1\uC744 \uC2E4\uC81C\uB85C \uC0DD\uC131\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (API \uD0A4 \uBBF8\uC124\uC815). \uC544\uB798 \uAE08\uC561\xB7job id\xB7URL \uC740 \uC804\uBD80 \uAC00\uC9DC\uC774\uBA70 \uACFC\uAE08\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.";
7247
+ // src/commands/common.ts
7488
7248
  var EXIT = {
7489
7249
  OK: 0,
7490
7250
  /** 일반 오류 — 미로그인·사용자 취소·생성 실패·알 수 없음. */
@@ -7503,335 +7263,62 @@ var EXIT = {
7503
7263
  */
7504
7264
  WAIT_TIMEOUT: 5
7505
7265
  };
7506
- var out2 = (s) => process.stdout.write(`${s}
7507
- `);
7508
- var err2 = (s) => process.stderr.write(`${s}
7509
- `);
7510
- function emit(opts, ok, payload) {
7511
- if (opts.json) out2(JSON.stringify({ ok, ...payload }));
7512
- }
7513
- function usd2(v) {
7514
- return v < 0.01 ? `$${v.toFixed(4)}` : `$${v.toFixed(2)}`;
7515
- }
7516
- function parseIntOpt(raw, name) {
7517
- if (raw === void 0) return void 0;
7518
- const n = Number(raw);
7519
- if (!Number.isInteger(n)) throw new UsageError(`--${name} \uC740 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4: ${raw}`);
7520
- return n;
7521
- }
7522
7266
  var UsageError = class extends Error {
7523
7267
  };
7524
- var EXIT_BY_SAFETY = {
7525
- fixable: 2,
7526
- // EXIT.FIXABLE
7527
- safe: 3,
7528
- // EXIT.TRANSIENT
7529
- unsafe: 4,
7530
- // EXIT.UPSTREAM_REJECTED
7531
- unknown: 1
7532
- // EXIT.GENERAL
7533
- };
7534
- function renderApiError(e, opts) {
7535
- const g = classifyApiError(e, { submitted: true, statusHint: "democut video status <job_id>" });
7536
- const code = EXIT_BY_SAFETY[g.safety];
7537
- if (opts.json) {
7538
- emit(opts, false, {
7539
- error: { status: e.status, code: e.code, message: e.message, retriable: e.retriable, ...e.extra },
7540
- exit_code: code
7541
- });
7542
- return code;
7543
- }
7544
- err2(`\uC624\uB958 [${e.code}] ${e.message}`);
7545
- for (const line of g.lines) err2(` ${line}`);
7546
- return code;
7547
- }
7548
- async function guarded(opts, fn) {
7549
- try {
7550
- return await fn();
7551
- } catch (e) {
7552
- if (e instanceof NotLoggedInError) {
7553
- if (opts.json) emit(opts, false, { error: { code: "NOT_LOGGED_IN", message: e.message } });
7554
- else err2(e.message);
7555
- return EXIT.GENERAL;
7268
+
7269
+ // node_modules/zod/v4/core/core.js
7270
+ var _a;
7271
+ // @__NO_SIDE_EFFECTS__
7272
+ function $constructor(name, initializer3, params) {
7273
+ function init(inst, def) {
7274
+ if (!inst._zod) {
7275
+ Object.defineProperty(inst, "_zod", {
7276
+ value: {
7277
+ def,
7278
+ constr: _,
7279
+ traits: /* @__PURE__ */ new Set()
7280
+ },
7281
+ enumerable: false
7282
+ });
7556
7283
  }
7557
- if (e instanceof ApiError) return renderApiError(e, opts);
7558
- if (e instanceof UsageError) {
7559
- if (opts.json) emit(opts, false, { error: { code: "USAGE", message: e.message } });
7560
- else err2(`\uC0AC\uC6A9\uBC95 \uC624\uB958: ${e.message}`);
7561
- return EXIT.FIXABLE;
7284
+ if (inst._zod.traits.has(name)) {
7285
+ return;
7562
7286
  }
7563
- if (e instanceof WaitTimeout) {
7564
- if (opts.json) {
7565
- emit(opts, false, {
7566
- error: { code: "WAIT_TIMEOUT", message: e.message, retriable: false },
7567
- job_id: e.jobId,
7568
- still_running: true
7569
- });
7570
- } else {
7571
- err2(e.message);
7287
+ inst._zod.traits.add(name);
7288
+ initializer3(inst, def);
7289
+ const proto = _.prototype;
7290
+ const keys = Object.keys(proto);
7291
+ for (let i = 0; i < keys.length; i++) {
7292
+ const k = keys[i];
7293
+ if (!(k in inst)) {
7294
+ inst[k] = proto[k].bind(inst);
7572
7295
  }
7573
- return EXIT.WAIT_TIMEOUT;
7574
7296
  }
7575
- const msg = e?.message ?? String(e);
7576
- if (opts.json) emit(opts, false, { error: { code: "UNKNOWN", message: msg } });
7577
- else err2(`\uC624\uB958: ${msg}`);
7578
- return EXIT.GENERAL;
7579
7297
  }
7580
- }
7581
- function buildEstimateIn(opts) {
7582
- return {
7583
- duration_s: parseIntOpt(opts.duration, "duration") ?? 5,
7584
- resolution: opts.resolution ?? "720p",
7585
- ratio: opts.ratio ?? "16:9",
7586
- ...opts.model ? { model: opts.model } : {},
7587
- // ★ 이미지 유무가 모델 계열을, 계열이 단가를 정한다 — 추정과 생성이 같은 값을 봐야
7588
- // 승인받은 금액과 실제 청구가 일치한다.
7589
- has_image: Boolean(opts.imageUrls?.length)
7590
- };
7591
- }
7592
- function estimateCommand(opts, deps = {}) {
7593
- return guarded(opts, async () => {
7594
- const base = resolveBaseUrl(opts.baseUrl);
7595
- const r = await estimate(base, buildEstimateIn(opts), deps);
7596
- if (opts.json) {
7597
- emit(opts, true, { tokens: r.tokens, cost_usd: r.cost_usd, model: r.model, mock: r.mock });
7598
- } else {
7599
- if (r.mock) err2(MOCK_NOTICE);
7600
- out2(`\uC608\uC0C1 \uBE44\uC6A9: ${usd2(r.cost_usd)} (${r.tokens.toLocaleString()} tokens \xB7 ${r.model})`);
7298
+ const Parent = params?.Parent ?? Object;
7299
+ class Definition extends Parent {
7300
+ }
7301
+ Object.defineProperty(Definition, "name", { value: name });
7302
+ function _(def) {
7303
+ var _a3;
7304
+ const inst = params?.Parent ? new Definition() : this;
7305
+ init(inst, def);
7306
+ (_a3 = inst._zod).deferred ?? (_a3.deferred = []);
7307
+ for (const fn of inst._zod.deferred) {
7308
+ fn();
7309
+ }
7310
+ return inst;
7311
+ }
7312
+ Object.defineProperty(_, "init", { value: init });
7313
+ Object.defineProperty(_, Symbol.hasInstance, {
7314
+ value: (inst) => {
7315
+ if (params?.Parent && inst instanceof params.Parent)
7316
+ return true;
7317
+ return inst?._zod?.traits?.has(name);
7601
7318
  }
7602
- return EXIT.OK;
7603
7319
  });
7604
- }
7605
- function generateCommand(prompt, opts, deps = {}) {
7606
- return guarded(opts, async () => {
7607
- if (!prompt || !prompt.trim()) {
7608
- throw new UsageError('\uD504\uB86C\uD504\uD2B8\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \uC608: democut video generate "\uACE0\uC591\uC774\uAC00 \uCDA4\uCD98\uB2E4"');
7609
- }
7610
- if (!opts.project || !opts.project.trim()) {
7611
- throw new UsageError(
7612
- "--project <slug> \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \uBE44\uC6A9\uC774 \uADC0\uC18D\uB420 \uBCF8\uC778 \uC18C\uC720 \uD504\uB85C\uC81D\uD2B8\uB97C \uC9C0\uC815\uD558\uC138\uC694. \uC2AC\uB7EC\uADF8\uB294 \uC6F9\uC758 \uD504\uB85C\uC81D\uD2B8 \uC8FC\uC18C `/projects/<\uC2AC\uB7EC\uADF8>` \uC5D0\uC11C \uD655\uC778\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4."
7613
- );
7614
- }
7615
- const base = resolveBaseUrl(opts.baseUrl);
7616
- const est = buildEstimateIn(opts);
7617
- const quote = await estimate(base, est, deps);
7618
- if (!opts.json) {
7619
- if (quote.mock) err2(MOCK_NOTICE);
7620
- out2(`\uC608\uC0C1 \uBE44\uC6A9: ${usd2(quote.cost_usd)} (${quote.tokens.toLocaleString()} tokens \xB7 ${quote.model})`);
7621
- out2(` ${est.duration_s}\uCD08 \xB7 ${est.resolution} \xB7 ${est.ratio}`);
7622
- }
7623
- if (!opts.yes) {
7624
- if (!(deps.isInteractiveImpl ?? isInteractive)()) {
7625
- const message = `\uBE44\uB300\uD654\uD615 \uD658\uACBD\uC774\uB77C \uBE44\uC6A9 \uC2B9\uC778\uC744 \uBC1B\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (\uC608\uC0C1 ${usd2(quote.cost_usd)}). \uD655\uC778\uD588\uB2E4\uBA74 --yes \uB97C \uBD99\uC5EC \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`;
7626
- if (opts.json) {
7627
- emit(opts, false, {
7628
- error: { code: "CONFIRMATION_REQUIRED", message },
7629
- estimated_cost_usd: quote.cost_usd
7630
- });
7631
- } else {
7632
- err2(message);
7633
- }
7634
- return EXIT.FIXABLE;
7635
- }
7636
- if (opts.json) {
7637
- const message = `--json \uBAA8\uB4DC\uC5D0\uC11C\uB294 --yes \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4 (\uC608\uC0C1 ${usd2(quote.cost_usd)}).`;
7638
- emit(opts, false, {
7639
- error: { code: "CONFIRMATION_REQUIRED", message },
7640
- estimated_cost_usd: quote.cost_usd
7641
- });
7642
- return EXIT.FIXABLE;
7643
- }
7644
- const ask = deps.confirmImpl ?? confirm;
7645
- const question = quote.mock ? "mock \uBAA8\uB4DC\uC785\uB2C8\uB2E4 \u2014 \uC2E4\uC81C \uC601\uC0C1\uC740 \uC0DD\uC131\uB418\uC9C0 \uC54A\uACE0 \uACFC\uAE08\uB3C4 \uC5C6\uC2B5\uB2C8\uB2E4. \uADF8\uB798\uB3C4 \uC9C4\uD589\uD560\uAE4C\uC694?" : `${usd2(quote.cost_usd)} \uAC00 \uCCAD\uAD6C\uB429\uB2C8\uB2E4. \uC0DD\uC131\uD560\uAE4C\uC694?`;
7646
- if (!await ask(question)) {
7647
- out2("\uCDE8\uC18C\uD588\uC2B5\uB2C8\uB2E4. \uACFC\uAE08\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
7648
- return EXIT.GENERAL;
7649
- }
7650
- }
7651
- const body = {
7652
- prompt,
7653
- duration_s: est.duration_s,
7654
- resolution: est.resolution,
7655
- ratio: est.ratio,
7656
- generate_audio: Boolean(opts.audio),
7657
- watermark: Boolean(opts.watermark),
7658
- ...opts.model ? { model: opts.model } : {},
7659
- ...opts.seed !== void 0 ? { seed: parseIntOpt(opts.seed, "seed") } : {},
7660
- ...opts.imageUrls?.length ? { image_urls: opts.imageUrls } : {},
7661
- project_slug: opts.project
7662
- };
7663
- const job = await submit(base, body, deps);
7664
- if (job.duplicate) {
7665
- if (job.pending) {
7666
- const message = "\uAC19\uC740 \uC694\uCCAD\uC774 \uBC29\uAE08 \uC81C\uCD9C\uB418\uC5B4 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4. \uC7A0\uC2DC \uD6C4 'democut video status <job_id>' \uB85C \uD655\uC778\uD558\uC138\uC694.";
7667
- if (opts.json) emit(opts, true, { duplicate: true, pending: true, job_id: null, message });
7668
- else out2(message);
7669
- return EXIT.OK;
7670
- }
7671
- if (!opts.json) out2(`\uAC19\uC740 \uC694\uCCAD\uC774 \uC774\uBBF8 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4 (job ${job.job_id}). \uC0C8\uB85C \uACFC\uAE08\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`);
7672
- } else if (!opts.json) {
7673
- if (job.mock) err2(MOCK_NOTICE);
7674
- out2(`\uC81C\uCD9C\uB428: job ${job.job_id} (\uC608\uC0C1 ${usd2(job.estimated_cost_usd)})`);
7675
- }
7676
- if (!opts.wait) {
7677
- if (opts.json) {
7678
- emit(opts, true, {
7679
- job_id: job.job_id,
7680
- status: job.status,
7681
- model: job.model,
7682
- estimated_cost_usd: job.estimated_cost_usd,
7683
- duplicate: job.duplicate,
7684
- pending: job.pending,
7685
- mock: job.mock
7686
- });
7687
- } else {
7688
- out2(`\uC644\uB8CC \uD655\uC778: democut video status ${job.job_id}`);
7689
- }
7690
- return EXIT.OK;
7691
- }
7692
- return finishWithWait(base, job.job_id, opts, deps);
7693
- });
7694
- }
7695
- function statusCommand2(jobId, opts, deps = {}) {
7696
- return guarded(opts, async () => {
7697
- if (!jobId) throw new UsageError("job_id \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \uC608: democut video status <job_id>");
7698
- const base = resolveBaseUrl(opts.baseUrl);
7699
- if (opts.wait) return finishWithWait(base, jobId, opts, deps);
7700
- const job = await status(base, jobId, opts.project, deps);
7701
- return report(job, opts, deps);
7702
- });
7703
- }
7704
- async function finishWithWait(base, jobId, opts, deps) {
7705
- const timeoutS = parseIntOpt(opts.timeout, "timeout") ?? 900;
7706
- if (!opts.json) process.stderr.write(" \uC0DD\uC131 \uB300\uAE30 \uC911");
7707
- const job = await waitForCompletion(base, jobId, opts.project, timeoutS, {
7708
- ...deps,
7709
- onTick: () => {
7710
- if (!opts.json) process.stderr.write(".");
7711
- }
7712
- });
7713
- if (!opts.json) err2("");
7714
- return report(job, opts, deps);
7715
- }
7716
- async function report(job, opts, deps = {}) {
7717
- if (job.status === "failed" || job.status === "cancelled") {
7718
- if (opts.json) {
7719
- emit(opts, false, { job_id: job.job_id, status: job.status, error: job.error });
7720
- } else {
7721
- err2(`\uC0DD\uC131 \uC2E4\uD328 (${job.status}): ${job.error ?? "\uC0AC\uC720 \uBBF8\uC0C1"}`);
7722
- }
7723
- return EXIT.GENERAL;
7724
- }
7725
- if (job.mock) {
7726
- if (opts.json) {
7727
- emit(opts, true, {
7728
- job_id: job.job_id,
7729
- status: job.status,
7730
- model: job.model,
7731
- video_url: job.video_url ?? null,
7732
- saved_to: null,
7733
- mock: true
7734
- });
7735
- } else {
7736
- err2(MOCK_NOTICE);
7737
- out2(`\uC0C1\uD0DC: ${job.status} (\uAC00\uC9DC)`);
7738
- if (job.video_url) out2(` URL : ${job.video_url} \u2190 \uC2E4\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`);
7739
- out2(" \uB0B4\uB824\uBC1B\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC2E4\uC81C \uC0DD\uC131\uC744 \uD558\uB824\uBA74 \uC6B4\uC601\uC790\uC5D0\uAC8C API \uD0A4 \uC124\uC815\uC744 \uC694\uCCAD\uD558\uC138\uC694.");
7740
- }
7741
- return EXIT.OK;
7742
- }
7743
- let saved = null;
7744
- let downloadError = null;
7745
- if (job.video_url && opts.output) {
7746
- try {
7747
- await (deps.downloadImpl ?? download)(job.video_url, opts.output);
7748
- saved = opts.output;
7749
- } catch (e) {
7750
- downloadError = e?.message ?? String(e);
7751
- }
7752
- }
7753
- if (opts.json) {
7754
- emit(opts, downloadError === null, {
7755
- job_id: job.job_id,
7756
- status: job.status,
7757
- model: job.model,
7758
- video_url: job.video_url ?? null,
7759
- tokens: job.tokens ?? null,
7760
- cost_usd: job.cost_usd ?? null,
7761
- seed: job.seed ?? null,
7762
- saved_to: saved,
7763
- ...downloadError ? { download_error: downloadError } : {}
7764
- });
7765
- } else {
7766
- out2(`\uC0C1\uD0DC: ${job.status}`);
7767
- if (job.cost_usd != null) out2(` \uBE44\uC6A9: ${usd2(job.cost_usd)}${job.tokens != null ? ` (${job.tokens.toLocaleString()} tokens)` : ""}`);
7768
- if (saved) out2(` \uC800\uC7A5\uB428: ${saved}`);
7769
- else if (job.video_url) {
7770
- out2(` URL : ${job.video_url}`);
7771
- if (downloadError) {
7772
- err2(` \uB0B4\uB824\uBC1B\uAE30 \uC2E4\uD328: ${downloadError}`);
7773
- err2(" \u26A0\uFE0F \uC704 URL \uB85C \uC9C1\uC811 \uBC1B\uC73C\uC138\uC694 \u2014 \uC11C\uBC84\uB294 \uBCF4\uAD00\uD558\uC9C0 \uC54A\uC73C\uBA70, \uB2E4\uC2DC \uB9CC\uB4E4\uBA74 \uB610 \uACFC\uAE08\uB429\uB2C8\uB2E4.");
7774
- } else {
7775
- out2(" \u26A0\uFE0F \uC11C\uBC84\uB294 \uC774 \uC0B0\uCD9C\uBB3C\uC744 \uBCF4\uAD00\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2014 \uC9C0\uAE08 \uB0B4\uB824\uBC1B\uC73C\uC138\uC694 (--output <\uACBD\uB85C>).");
7776
- }
7777
- }
7778
- }
7779
- return downloadError === null ? EXIT.OK : EXIT.GENERAL;
7780
- }
7781
-
7782
- // node_modules/zod/v4/core/core.js
7783
- var _a;
7784
- // @__NO_SIDE_EFFECTS__
7785
- function $constructor(name, initializer3, params) {
7786
- function init(inst, def) {
7787
- if (!inst._zod) {
7788
- Object.defineProperty(inst, "_zod", {
7789
- value: {
7790
- def,
7791
- constr: _,
7792
- traits: /* @__PURE__ */ new Set()
7793
- },
7794
- enumerable: false
7795
- });
7796
- }
7797
- if (inst._zod.traits.has(name)) {
7798
- return;
7799
- }
7800
- inst._zod.traits.add(name);
7801
- initializer3(inst, def);
7802
- const proto = _.prototype;
7803
- const keys = Object.keys(proto);
7804
- for (let i = 0; i < keys.length; i++) {
7805
- const k = keys[i];
7806
- if (!(k in inst)) {
7807
- inst[k] = proto[k].bind(inst);
7808
- }
7809
- }
7810
- }
7811
- const Parent = params?.Parent ?? Object;
7812
- class Definition extends Parent {
7813
- }
7814
- Object.defineProperty(Definition, "name", { value: name });
7815
- function _(def) {
7816
- var _a3;
7817
- const inst = params?.Parent ? new Definition() : this;
7818
- init(inst, def);
7819
- (_a3 = inst._zod).deferred ?? (_a3.deferred = []);
7820
- for (const fn of inst._zod.deferred) {
7821
- fn();
7822
- }
7823
- return inst;
7824
- }
7825
- Object.defineProperty(_, "init", { value: init });
7826
- Object.defineProperty(_, Symbol.hasInstance, {
7827
- value: (inst) => {
7828
- if (params?.Parent && inst instanceof params.Parent)
7829
- return true;
7830
- return inst?._zod?.traits?.has(name);
7831
- }
7832
- });
7833
- Object.defineProperty(_, "name", { value: name });
7834
- return _;
7320
+ Object.defineProperty(_, "name", { value: name });
7321
+ return _;
7835
7322
  }
7836
7323
  var $ZodAsyncError = class extends Error {
7837
7324
  constructor() {
@@ -13000,11 +12487,11 @@ var ZodPipe = /* @__PURE__ */ $constructor("ZodPipe", (inst, def) => {
13000
12487
  inst.in = def.in;
13001
12488
  inst.out = def.out;
13002
12489
  });
13003
- function pipe(in_, out3) {
12490
+ function pipe(in_, out2) {
13004
12491
  return new ZodPipe({
13005
12492
  type: "pipe",
13006
12493
  in: in_,
13007
- out: out3
12494
+ out: out2
13008
12495
  // ...util.normalizeParams(params),
13009
12496
  });
13010
12497
  }
@@ -14569,8 +14056,8 @@ var UrlElicitationRequiredError = class extends McpError {
14569
14056
  };
14570
14057
 
14571
14058
  // node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
14572
- function isTerminal2(status2) {
14573
- return status2 === "completed" || status2 === "failed" || status2 === "cancelled";
14059
+ function isTerminal(status) {
14060
+ return status === "completed" || status === "failed" || status === "cancelled";
14574
14061
  }
14575
14062
 
14576
14063
  // node_modules/zod-to-json-schema/dist/esm/parsers/string.js
@@ -14667,11 +14154,11 @@ var Protocol = class {
14667
14154
  if (!task) {
14668
14155
  throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
14669
14156
  }
14670
- if (!isTerminal2(task.status)) {
14157
+ if (!isTerminal(task.status)) {
14671
14158
  await this._waitForTaskUpdate(taskId, extra.signal);
14672
14159
  return await handleTaskResult();
14673
14160
  }
14674
- if (isTerminal2(task.status)) {
14161
+ if (isTerminal(task.status)) {
14675
14162
  const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
14676
14163
  this._clearTaskQueue(taskId);
14677
14164
  return {
@@ -14706,7 +14193,7 @@ var Protocol = class {
14706
14193
  if (!task) {
14707
14194
  throw new McpError(ErrorCode.InvalidParams, `Task not found: ${request.params.taskId}`);
14708
14195
  }
14709
- if (isTerminal2(task.status)) {
14196
+ if (isTerminal(task.status)) {
14710
14197
  throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
14711
14198
  }
14712
14199
  await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
@@ -15074,7 +14561,7 @@ var Protocol = class {
15074
14561
  while (true) {
15075
14562
  const task2 = await this.getTask({ taskId }, options);
15076
14563
  yield { type: "taskStatus", task: task2 };
15077
- if (isTerminal2(task2.status)) {
14564
+ if (isTerminal(task2.status)) {
15078
14565
  if (task2.status === "completed") {
15079
14566
  const result = await this.getTaskResult({ taskId }, resultSchema, options);
15080
14567
  yield { type: "result", result };
@@ -15487,8 +14974,8 @@ var Protocol = class {
15487
14974
  }
15488
14975
  return task;
15489
14976
  },
15490
- storeTaskResult: async (taskId, status2, result) => {
15491
- await taskStore.storeTaskResult(taskId, status2, result, sessionId);
14977
+ storeTaskResult: async (taskId, status, result) => {
14978
+ await taskStore.storeTaskResult(taskId, status, result, sessionId);
15492
14979
  const task = await taskStore.getTask(taskId, sessionId);
15493
14980
  if (task) {
15494
14981
  const notification = TaskStatusNotificationSchema.parse({
@@ -15496,7 +14983,7 @@ var Protocol = class {
15496
14983
  params: task
15497
14984
  });
15498
14985
  await this.notification(notification);
15499
- if (isTerminal2(task.status)) {
14986
+ if (isTerminal(task.status)) {
15500
14987
  this._cleanupTaskProgressHandler(taskId);
15501
14988
  }
15502
14989
  }
@@ -15504,15 +14991,15 @@ var Protocol = class {
15504
14991
  getTaskResult: (taskId) => {
15505
14992
  return taskStore.getTaskResult(taskId, sessionId);
15506
14993
  },
15507
- updateTaskStatus: async (taskId, status2, statusMessage) => {
14994
+ updateTaskStatus: async (taskId, status, statusMessage) => {
15508
14995
  const task = await taskStore.getTask(taskId, sessionId);
15509
14996
  if (!task) {
15510
14997
  throw new McpError(ErrorCode.InvalidParams, `Task "${taskId}" not found - it may have been cleaned up`);
15511
14998
  }
15512
- if (isTerminal2(task.status)) {
15513
- throw new McpError(ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${status2}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);
14999
+ if (isTerminal(task.status)) {
15000
+ throw new McpError(ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${status}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);
15514
15001
  }
15515
- await taskStore.updateTaskStatus(taskId, status2, statusMessage, sessionId);
15002
+ await taskStore.updateTaskStatus(taskId, status, statusMessage, sessionId);
15516
15003
  const updatedTask = await taskStore.getTask(taskId, sessionId);
15517
15004
  if (updatedTask) {
15518
15005
  const notification = TaskStatusNotificationSchema.parse({
@@ -15520,7 +15007,7 @@ var Protocol = class {
15520
15007
  params: updatedTask
15521
15008
  });
15522
15009
  await this.notification(notification);
15523
- if (isTerminal2(updatedTask.status)) {
15010
+ if (isTerminal(updatedTask.status)) {
15524
15011
  this._cleanupTaskProgressHandler(taskId);
15525
15012
  }
15526
15013
  }
@@ -16345,8 +15832,2526 @@ var StdioServerTransport = class {
16345
15832
  }
16346
15833
  };
16347
15834
 
16348
- // src/mcp/tools.ts
16349
- import { existsSync as existsSync2 } from "fs";
15835
+ // src/mcp/tools.generated.ts
15836
+ var GENERATED_TOOLS = [
15837
+ {
15838
+ "name": "democut_auth_status",
15839
+ "description": "\uB85C\uADF8\uC778 \uC0C1\uD0DC\xB7\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\xB7\uC5ED\uD560\xB7\uD2F0\uC5B4\uB97C \uD655\uC778\uD55C\uB2E4. \uBD80\uC791\uC6A9\uB3C4 \uACFC\uAE08\uB3C4 \uC5C6\uB2E4. \uB2E4\uB978 \uB3C4\uAD6C\uAC00 \uAD8C\uD55C \uC624\uB958\uB97C \uB0B4\uBA74 \uBA3C\uC800 \uC774\uAC78\uB85C \uD655\uC778\uD558\uB77C. \uB2E4\uC74C \uD638\uCD9C: democut_list_projects, democut_create_project.",
15840
+ "inputSchema": {
15841
+ "type": "object",
15842
+ "properties": {},
15843
+ "required": [],
15844
+ "additionalProperties": false
15845
+ },
15846
+ "annotations": {
15847
+ "readOnlyHint": true,
15848
+ "destructiveHint": false,
15849
+ "idempotentHint": true,
15850
+ "openWorldHint": false
15851
+ }
15852
+ },
15853
+ {
15854
+ "name": "democut_list_projects",
15855
+ "description": "\uC774 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uC758 \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D(\uCD5C\uADFC \uC218\uC815\uC21C). \uBD80\uC791\uC6A9\uB3C4 \uACFC\uAE08\uB3C4 \uC5C6\uB2E4. \uCEF7\uC740 \uD504\uB85C\uC81D\uD2B8 \uC5C6\uC774 \uBABB \uB9CC\uB4E0\uB2E4(\uBE44\uC6A9 \uADC0\uC18D \uB2E8\uC704) \u2014 \uC5C6\uC73C\uBA74 democut_create_project. \uD504\uB85C\uC81D\uD2B8\uB97C \uC694\uAD6C\uD558\uB294 \uB3C4\uAD6C\uC758 slug \uB294 \uC2E4\uC7AC\uD558\uB294 \uBCF8\uC778 \uAC83\uC774\uC5B4\uC57C \uD558\uACE0 \uD2C0\uB9AC\uBA74 404 \uB2E4 \u2014 \uC2AC\uB7EC\uADF8\uB97C \uBAA8\uB974\uBA74 \uCD94\uCE21\uD558\uC9C0 \uB9D0\uACE0 \uC774\uAC78\uB85C \uBA3C\uC800 \uD655\uC778\uD558\uB77C. \uB2E4\uC74C \uD638\uCD9C: democut_create_project, democut_get_options.",
15856
+ "inputSchema": {
15857
+ "type": "object",
15858
+ "properties": {
15859
+ "limit": {
15860
+ "default": 30,
15861
+ "description": "\uAC00\uC838\uC62C \uAC74\uC218 1~100",
15862
+ "maximum": 100,
15863
+ "minimum": 1,
15864
+ "title": "Limit",
15865
+ "type": "integer"
15866
+ },
15867
+ "query": {
15868
+ "anyOf": [
15869
+ {
15870
+ "maxLength": 200,
15871
+ "type": "string"
15872
+ },
15873
+ {
15874
+ "type": "null"
15875
+ }
15876
+ ],
15877
+ "default": null,
15878
+ "description": "\uC2AC\uB7EC\uADF8\xB7\uC81C\uBAA9 \uBD80\uBD84 \uC77C\uCE58(\uB300\uC18C\uBB38\uC790 \uBB34\uC2DC). \uC774\uB984\uC744 \uC54C \uB54C\uB9CC \uC4F4\uB2E4 \u2014 \uBE44\uC6B0\uBA74 \uCD5C\uADFC \uC218\uC815\uC21C \uC804\uCCB4",
15879
+ "title": "Query"
15880
+ }
15881
+ },
15882
+ "required": [],
15883
+ "additionalProperties": false
15884
+ },
15885
+ "annotations": {
15886
+ "readOnlyHint": true,
15887
+ "destructiveHint": false,
15888
+ "idempotentHint": true,
15889
+ "openWorldHint": false
15890
+ }
15891
+ },
15892
+ {
15893
+ "name": "democut_create_project",
15894
+ "description": "\uD504\uB85C\uC81D\uD2B8\uB97C \uB9CC\uB4E0\uB2E4 \u2014 \uACFC\uAE08\uC740 \uC5C6\uC9C0\uB9CC \uACC4\uC815\uC5D0 \uB0A8\uB294 **\uC4F0\uAE30** \uC791\uC5C5\uC774\uB2E4. \uBE44\uC728(16:9|9:16|1:1)\uC740 \uC0DD\uC131 \uD6C4 \uBC14\uAFC0 \uC218 \uC5C6\uB2E4. \uAC19\uC740 \uC81C\uBAA9\uC73C\uB85C \uB2E4\uC2DC \uBD80\uB974\uBA74 \uC0C8\uB85C \uB9CC\uB4E4\uC9C0 \uC54A\uACE0 \uAE30\uC874 \uAC83\uC744 \uB3CC\uB824\uC900\uB2E4(\uC7AC\uC2DC\uB3C4 \uC548\uC804). \u2605 \uBA3C\uC800 democut_list_projects \uB85C \uC4F8 \uB9CC\uD55C \uAC83\uC774 \uC774\uBBF8 \uC788\uB294\uC9C0 \uBCF4\uACE0 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC5B4\uB290 \uAC83\uC5D0 \uB123\uC744\uC9C0 \uBB3C\uC5B4\uB77C \u2014 \uBB3B\uC9C0 \uC54A\uACE0 \uB9CC\uB4E4\uBA74 \uBE44\uC2B7\uD55C \uD504\uB85C\uC81D\uD2B8\uAC00 \uC313\uC778\uB2E4. \uB2E4\uC74C \uD638\uCD9C: democut_get_options, democut_upload_asset, democut_estimate_cuts.",
15895
+ "inputSchema": {
15896
+ "type": "object",
15897
+ "properties": {
15898
+ "title": {
15899
+ "maxLength": 200,
15900
+ "minLength": 1,
15901
+ "title": "Title",
15902
+ "type": "string"
15903
+ },
15904
+ "ratio": {
15905
+ "default": "16:9",
15906
+ "description": "\uC0DD\uC131 \uD6C4 \uACE0\uC815(R24)",
15907
+ "enum": [
15908
+ "16:9",
15909
+ "9:16",
15910
+ "1:1"
15911
+ ],
15912
+ "title": "Ratio",
15913
+ "type": "string"
15914
+ },
15915
+ "resolution": {
15916
+ "default": "1080p",
15917
+ "enum": [
15918
+ "720p",
15919
+ "1080p"
15920
+ ],
15921
+ "title": "Resolution",
15922
+ "type": "string"
15923
+ },
15924
+ "folder_id": {
15925
+ "anyOf": [
15926
+ {
15927
+ "type": "string"
15928
+ },
15929
+ {
15930
+ "type": "null"
15931
+ }
15932
+ ],
15933
+ "default": null,
15934
+ "title": "Folder Id"
15935
+ },
15936
+ "defaults": {
15937
+ "anyOf": [
15938
+ {
15939
+ "$ref": "#/$defs/ProjectDefaults"
15940
+ },
15941
+ {
15942
+ "type": "null"
15943
+ }
15944
+ ],
15945
+ "default": null
15946
+ }
15947
+ },
15948
+ "required": [
15949
+ "title"
15950
+ ],
15951
+ "additionalProperties": false,
15952
+ "$defs": {
15953
+ "Brand": {
15954
+ "additionalProperties": false,
15955
+ "properties": {
15956
+ "accent_hex": {
15957
+ "anyOf": [
15958
+ {
15959
+ "pattern": "^#[0-9A-Fa-f]{6}$",
15960
+ "type": "string"
15961
+ },
15962
+ {
15963
+ "type": "null"
15964
+ }
15965
+ ],
15966
+ "default": null,
15967
+ "title": "Accent Hex"
15968
+ },
15969
+ "heading_font": {
15970
+ "anyOf": [
15971
+ {
15972
+ "type": "string"
15973
+ },
15974
+ {
15975
+ "type": "null"
15976
+ }
15977
+ ],
15978
+ "default": null,
15979
+ "title": "Heading Font"
15980
+ },
15981
+ "body_font": {
15982
+ "anyOf": [
15983
+ {
15984
+ "type": "string"
15985
+ },
15986
+ {
15987
+ "type": "null"
15988
+ }
15989
+ ],
15990
+ "default": null,
15991
+ "title": "Body Font"
15992
+ },
15993
+ "logo_asset_id": {
15994
+ "anyOf": [
15995
+ {
15996
+ "type": "string"
15997
+ },
15998
+ {
15999
+ "type": "null"
16000
+ }
16001
+ ],
16002
+ "default": null,
16003
+ "title": "Logo Asset Id"
16004
+ }
16005
+ },
16006
+ "title": "Brand",
16007
+ "type": "object"
16008
+ },
16009
+ "ProjectDefaults": {
16010
+ "additionalProperties": false,
16011
+ "properties": {
16012
+ "voice_id": {
16013
+ "anyOf": [
16014
+ {
16015
+ "type": "string"
16016
+ },
16017
+ {
16018
+ "type": "null"
16019
+ }
16020
+ ],
16021
+ "default": null,
16022
+ "title": "Voice Id"
16023
+ },
16024
+ "character_id": {
16025
+ "anyOf": [
16026
+ {
16027
+ "type": "string"
16028
+ },
16029
+ {
16030
+ "type": "null"
16031
+ }
16032
+ ],
16033
+ "default": null,
16034
+ "title": "Character Id"
16035
+ },
16036
+ "subtitles": {
16037
+ "default": false,
16038
+ "title": "Subtitles",
16039
+ "type": "boolean"
16040
+ },
16041
+ "brand": {
16042
+ "$ref": "#/$defs/Brand"
16043
+ }
16044
+ },
16045
+ "title": "ProjectDefaults",
16046
+ "type": "object"
16047
+ }
16048
+ }
16049
+ },
16050
+ "annotations": {
16051
+ "readOnlyHint": false,
16052
+ "destructiveHint": false,
16053
+ "idempotentHint": false,
16054
+ "openWorldHint": false
16055
+ }
16056
+ },
16057
+ {
16058
+ "name": "democut_get_options",
16059
+ "description": "\uC774 \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C \uC4F8 \uC218 \uC788\uB294 \uBC29\uC2DD\xB7\uC9C4\uD589(host)\xB7\uD544\uC218 \uD544\uB4DC\xB7BYO \uD544\uB4DC\xB7\uBCF4\uC774\uC2A4\xB7\uC544\uBC14\uD0C0\xB7\uBC30\uACBD\xB7\uB2E8\uAC00\xB7\uC794\uC561. recommended_mode=ai_video. \uB2E8\uAC00\uB294 \uCC38\uACE0\uAC12\uC774\uB2E4 \u2014 \uCCAD\uAD6C\uB294 democut_estimate_cuts \uC758 \uAC12\uC73C\uB85C. \uB2E4\uC74C \uD638\uCD9C: democut_upload_asset, democut_estimate_cuts.",
16060
+ "inputSchema": {
16061
+ "type": "object",
16062
+ "properties": {
16063
+ "slug": {
16064
+ "type": "string",
16065
+ "description": "\uD504\uB85C\uC81D\uD2B8 \uC2AC\uB7EC\uADF8(list_projects)"
16066
+ }
16067
+ },
16068
+ "required": [
16069
+ "slug"
16070
+ ],
16071
+ "additionalProperties": false
16072
+ },
16073
+ "annotations": {
16074
+ "readOnlyHint": true,
16075
+ "destructiveHint": false,
16076
+ "idempotentHint": true,
16077
+ "openWorldHint": false
16078
+ }
16079
+ },
16080
+ {
16081
+ "name": "democut_upload_asset",
16082
+ "description": "\uC774\uBBF8\uC9C0\xB7\uB098\uB808\uC774\uC158 wav\xB7\uC6D0\uBCF8 \uC601\uC0C1\xB7tsx\xB7\uC644\uC131 \uCEF7 \uC601\uC0C1\uC744 \uC790\uC0B0\uC73C\uB85C \uC62C\uB9B0\uB2E4(0\uC6D0). \uC751\uB2F5\uC758 state \uAC00 ready \uC5EC\uC57C spec \uC5D0 \uC4F8 \uC218 \uC788\uB2E4. \uB2E4\uC74C \uD638\uCD9C: democut_estimate_cuts, democut_import_cut.",
16083
+ "inputSchema": {
16084
+ "type": "object",
16085
+ "properties": {
16086
+ "kind": {
16087
+ "enum": [
16088
+ "image",
16089
+ "video",
16090
+ "audio",
16091
+ "subtitle",
16092
+ "code",
16093
+ "archive"
16094
+ ],
16095
+ "title": "Kind",
16096
+ "type": "string"
16097
+ },
16098
+ "project_slug": {
16099
+ "anyOf": [
16100
+ {
16101
+ "type": "string"
16102
+ },
16103
+ {
16104
+ "type": "null"
16105
+ }
16106
+ ],
16107
+ "default": null,
16108
+ "title": "Project Slug"
16109
+ },
16110
+ "source_url": {
16111
+ "anyOf": [
16112
+ {
16113
+ "minLength": 1,
16114
+ "type": "string"
16115
+ },
16116
+ {
16117
+ "type": "null"
16118
+ }
16119
+ ],
16120
+ "default": null,
16121
+ "description": "\uC6D0\uACA9: https \uACF5\uAC1C \uC8FC\uC18C\uC5D0\uC11C \uAC00\uC838\uC628\uB2E4(202, \uC7A1). stdio \uB294 local_path",
16122
+ "title": "Source Url"
16123
+ },
16124
+ "filename": {
16125
+ "anyOf": [
16126
+ {
16127
+ "type": "string"
16128
+ },
16129
+ {
16130
+ "type": "null"
16131
+ }
16132
+ ],
16133
+ "default": null,
16134
+ "title": "Filename"
16135
+ },
16136
+ "local_path": {
16137
+ "type": "string",
16138
+ "description": "\uC62C\uB9B4 \uD30C\uC77C\uC758 \uB85C\uCEEC \uACBD\uB85C(stdio \uC804\uC6A9). source_url \uACFC \uB458 \uC911 \uD558\uB098"
16139
+ }
16140
+ },
16141
+ "required": [
16142
+ "kind"
16143
+ ],
16144
+ "additionalProperties": false,
16145
+ "oneOf": [
16146
+ {
16147
+ "required": [
16148
+ "local_path"
16149
+ ]
16150
+ },
16151
+ {
16152
+ "required": [
16153
+ "source_url"
16154
+ ]
16155
+ }
16156
+ ]
16157
+ },
16158
+ "annotations": {
16159
+ "readOnlyHint": false,
16160
+ "destructiveHint": false,
16161
+ "idempotentHint": false,
16162
+ "openWorldHint": false
16163
+ }
16164
+ },
16165
+ {
16166
+ "name": "democut_estimate_cuts",
16167
+ "description": "\uCEF7 N \uAC1C\uC758 \uACAC\uC801(0\uC6D0, \uBD80\uC791\uC6A9 \uC5C6\uC74C). \uC751\uB2F5\uC758 total_krw\xB7rate_version\xB7can_afford \uB97C \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBCF4\uC5EC \uC8FC\uACE0 \uADF8\uB300\uB85C democut_make_cuts \uC5D0 \uB123\uC5B4\uB77C. BYO \uD544\uB4DC(image_asset_id\xB7narration_asset_id\xB7tsx\xB7source.asset_id)\uB97C \uC8FC\uBA74 \uADF8 \uD589\uC740 0\uC6D0\uC774\uB2E4. \uB2E4\uC74C \uD638\uCD9C: democut_make_cuts.",
16168
+ "inputSchema": {
16169
+ "type": "object",
16170
+ "properties": {
16171
+ "slug": {
16172
+ "type": "string",
16173
+ "description": "\uD504\uB85C\uC81D\uD2B8 \uC2AC\uB7EC\uADF8(list_projects)"
16174
+ },
16175
+ "items": {
16176
+ "items": {
16177
+ "$ref": "#/$defs/EstimateItem"
16178
+ },
16179
+ "maxItems": 50,
16180
+ "title": "Items",
16181
+ "type": "array"
16182
+ },
16183
+ "imports": {
16184
+ "items": {
16185
+ "$ref": "#/$defs/ImportEstimateItem"
16186
+ },
16187
+ "maxItems": 50,
16188
+ "title": "Imports",
16189
+ "type": "array"
16190
+ }
16191
+ },
16192
+ "required": [
16193
+ "slug"
16194
+ ],
16195
+ "additionalProperties": false,
16196
+ "$defs": {
16197
+ "AiVideoSpec": {
16198
+ "additionalProperties": false,
16199
+ "properties": {
16200
+ "dialogue": {
16201
+ "items": {
16202
+ "$ref": "#/$defs/DialogueLine"
16203
+ },
16204
+ "title": "Dialogue",
16205
+ "type": "array"
16206
+ },
16207
+ "narration_asset_id": {
16208
+ "anyOf": [
16209
+ {
16210
+ "minLength": 1,
16211
+ "type": "string"
16212
+ },
16213
+ {
16214
+ "type": "null"
16215
+ }
16216
+ ],
16217
+ "default": null,
16218
+ "description": "BYO: \uCEF7 \uC804\uCCB4 \uB098\uB808\uC774\uC158 wav \uD55C \uAC1C(\uB300\uC0AC\uAC00 \uC788\uC5B4\uC57C \uD55C\uB2E4 \u2014 \uC790\uB9C9\xB7\uD0C0\uC774\uBC0D\uC758 \uADFC\uAC70). \uC904\uBCC4 audio_asset_id \uC640 \uB3D9\uC2DC \uC9C0\uC815 422",
16219
+ "title": "Narration Asset Id"
16220
+ },
16221
+ "subtitles": {
16222
+ "default": false,
16223
+ "title": "Subtitles",
16224
+ "type": "boolean"
16225
+ },
16226
+ "host": {
16227
+ "anyOf": [
16228
+ {
16229
+ "type": "string"
16230
+ },
16231
+ {
16232
+ "type": "null"
16233
+ }
16234
+ ],
16235
+ "default": null,
16236
+ "description": "\uC9C4\uD589 \u2014 \uD5C8\uC6A9 \uC9D1\uD569\uC740 \uCE74\uD0C8\uB85C\uADF8(\uBC29\uC2DD\uBCC4). \uBAA8\uC158\uADF8\uB798\uD53D\uC740 \uD544\uC218",
16237
+ "title": "Host"
16238
+ },
16239
+ "voice_id": {
16240
+ "anyOf": [
16241
+ {
16242
+ "minLength": 1,
16243
+ "type": "string"
16244
+ },
16245
+ {
16246
+ "type": "null"
16247
+ }
16248
+ ],
16249
+ "default": null,
16250
+ "description": "host\u2208{voice,avatar} \uC774\uACE0 BYO \uC624\uB514\uC624\uAC00 \uC5C6\uC744 \uB54C \uD544\uC218",
16251
+ "title": "Voice Id"
16252
+ },
16253
+ "pip": {
16254
+ "anyOf": [
16255
+ {
16256
+ "$ref": "#/$defs/PipSpec"
16257
+ },
16258
+ {
16259
+ "type": "null"
16260
+ }
16261
+ ],
16262
+ "default": null,
16263
+ "description": "host=avatar \uC77C \uB54C \uD544\uC218"
16264
+ },
16265
+ "image_asset_id": {
16266
+ "anyOf": [
16267
+ {
16268
+ "minLength": 1,
16269
+ "type": "string"
16270
+ },
16271
+ {
16272
+ "type": "null"
16273
+ }
16274
+ ],
16275
+ "default": null,
16276
+ "description": "\uCEF7 \uC774\uBBF8\uC9C0\uB97C spec \uC5D0\uC11C \uC9C1\uC811 \uC9C0\uC815(\uC5D0\uC774\uC804\uD2B8 \uC6D0\uC0F7\uC6A9)",
16277
+ "title": "Image Asset Id"
16278
+ },
16279
+ "duration_s": {
16280
+ "default": 5,
16281
+ "maximum": 15,
16282
+ "minimum": 4,
16283
+ "title": "Duration S",
16284
+ "type": "number"
16285
+ },
16286
+ "mode": {
16287
+ "const": "ai_video",
16288
+ "default": "ai_video",
16289
+ "title": "Mode",
16290
+ "type": "string"
16291
+ },
16292
+ "image_prompt": {
16293
+ "maxLength": 4e3,
16294
+ "minLength": 1,
16295
+ "title": "Image Prompt",
16296
+ "type": "string"
16297
+ },
16298
+ "seed": {
16299
+ "anyOf": [
16300
+ {
16301
+ "minimum": 0,
16302
+ "type": "integer"
16303
+ },
16304
+ {
16305
+ "type": "null"
16306
+ }
16307
+ ],
16308
+ "default": null,
16309
+ "title": "Seed"
16310
+ },
16311
+ "image": {
16312
+ "anyOf": [
16313
+ {
16314
+ "discriminator": {
16315
+ "mapping": {
16316
+ "asset": "#/$defs/AssetImageRef",
16317
+ "from_cut": "#/$defs/FromCutImageRef",
16318
+ "from_version": "#/$defs/FromVersionImageRef"
16319
+ },
16320
+ "propertyName": "kind"
16321
+ },
16322
+ "oneOf": [
16323
+ {
16324
+ "$ref": "#/$defs/AssetImageRef"
16325
+ },
16326
+ {
16327
+ "$ref": "#/$defs/FromCutImageRef"
16328
+ },
16329
+ {
16330
+ "$ref": "#/$defs/FromVersionImageRef"
16331
+ }
16332
+ ]
16333
+ },
16334
+ {
16335
+ "type": "null"
16336
+ }
16337
+ ],
16338
+ "default": null,
16339
+ "description": "\uCCAB \uD504\uB808\uC784. \uC5C6\uC73C\uBA74 image_asset_id \u2192 \uCEF7 \uC774\uBBF8\uC9C0 \u2192 t2v \uC21C",
16340
+ "title": "Image"
16341
+ },
16342
+ "end_image": {
16343
+ "anyOf": [
16344
+ {
16345
+ "discriminator": {
16346
+ "mapping": {
16347
+ "asset": "#/$defs/AssetImageRef",
16348
+ "from_cut": "#/$defs/FromCutImageRef",
16349
+ "from_version": "#/$defs/FromVersionImageRef"
16350
+ },
16351
+ "propertyName": "kind"
16352
+ },
16353
+ "oneOf": [
16354
+ {
16355
+ "$ref": "#/$defs/AssetImageRef"
16356
+ },
16357
+ {
16358
+ "$ref": "#/$defs/FromCutImageRef"
16359
+ },
16360
+ {
16361
+ "$ref": "#/$defs/FromVersionImageRef"
16362
+ }
16363
+ ]
16364
+ },
16365
+ {
16366
+ "type": "null"
16367
+ }
16368
+ ],
16369
+ "default": null,
16370
+ "title": "End Image"
16371
+ }
16372
+ },
16373
+ "required": [
16374
+ "image_prompt"
16375
+ ],
16376
+ "title": "AiVideoSpec",
16377
+ "type": "object"
16378
+ },
16379
+ "AssetImageRef": {
16380
+ "additionalProperties": false,
16381
+ "properties": {
16382
+ "kind": {
16383
+ "const": "asset",
16384
+ "default": "asset",
16385
+ "title": "Kind",
16386
+ "type": "string"
16387
+ },
16388
+ "asset_id": {
16389
+ "minLength": 1,
16390
+ "title": "Asset Id",
16391
+ "type": "string"
16392
+ }
16393
+ },
16394
+ "required": [
16395
+ "asset_id"
16396
+ ],
16397
+ "title": "AssetImageRef",
16398
+ "type": "object"
16399
+ },
16400
+ "DialogueLine": {
16401
+ "additionalProperties": false,
16402
+ "properties": {
16403
+ "id": {
16404
+ "description": "\uC904 id ln_<6> \u2014 \uC81C\uC548 diff \uC758 \uB300\uC870 \uD0A4",
16405
+ "pattern": "^ln_[a-z0-9]{6}$",
16406
+ "title": "Id",
16407
+ "type": "string",
16408
+ "x-diff": "ignore"
16409
+ },
16410
+ "text": {
16411
+ "description": "\uBC1C\uD654 \uD14D\uC2A4\uD2B8(\uC22B\uC790\uB294 \uC11C\uBC84\uAC00 \uC77D\uB294 \uBC95\uC744 \uC815\uD55C\uB2E4 \u2014 \uD480\uC5B4\uC4F0\uC9C0 \uC54A\uB294\uB2E4)",
16412
+ "maxLength": 2e3,
16413
+ "minLength": 1,
16414
+ "title": "Text",
16415
+ "type": "string"
16416
+ },
16417
+ "subtitle_text": {
16418
+ "anyOf": [
16419
+ {
16420
+ "maxLength": 2e3,
16421
+ "type": "string"
16422
+ },
16423
+ {
16424
+ "type": "null"
16425
+ }
16426
+ ],
16427
+ "default": null,
16428
+ "description": "\uC790\uB9C9 \uD45C\uAE30(\uC6D0\uBB38 \uD45C\uAE30). \uC5C6\uC73C\uBA74 text",
16429
+ "title": "Subtitle Text"
16430
+ },
16431
+ "audio_asset_id": {
16432
+ "anyOf": [
16433
+ {
16434
+ "minLength": 1,
16435
+ "type": "string"
16436
+ },
16437
+ {
16438
+ "type": "null"
16439
+ }
16440
+ ],
16441
+ "default": null,
16442
+ "description": "BYO: \uC774 \uC904\uC758 \uB098\uB808\uC774\uC158 \uC624\uB514\uC624 \uC790\uC0B0 \u2014 TTS \uD589 0\uC6D0, \uC815\uB82C \uD589\uB9CC",
16443
+ "title": "Audio Asset Id"
16444
+ }
16445
+ },
16446
+ "required": [
16447
+ "id",
16448
+ "text"
16449
+ ],
16450
+ "title": "DialogueLine",
16451
+ "type": "object"
16452
+ },
16453
+ "EstimateItem": {
16454
+ "additionalProperties": false,
16455
+ "properties": {
16456
+ "cut_id": {
16457
+ "anyOf": [
16458
+ {
16459
+ "type": "string"
16460
+ },
16461
+ {
16462
+ "type": "null"
16463
+ }
16464
+ ],
16465
+ "default": null,
16466
+ "description": "\uC5C6\uC73C\uBA74 \uC0C8 \uCEF7(\uC11C\uBC84\uAC00 ULID \uB97C \uB9CC\uB4E0\uB2E4)",
16467
+ "title": "Cut Id"
16468
+ },
16469
+ "spec": {
16470
+ "discriminator": {
16471
+ "mapping": {
16472
+ "ai_video": "#/$defs/AiVideoSpec",
16473
+ "motion_graphic": "#/$defs/MotionGraphicSpec",
16474
+ "youtube_clip": "#/$defs/YoutubeClipSpec"
16475
+ },
16476
+ "propertyName": "mode"
16477
+ },
16478
+ "oneOf": [
16479
+ {
16480
+ "$ref": "#/$defs/MotionGraphicSpec"
16481
+ },
16482
+ {
16483
+ "$ref": "#/$defs/AiVideoSpec"
16484
+ },
16485
+ {
16486
+ "$ref": "#/$defs/YoutubeClipSpec"
16487
+ }
16488
+ ],
16489
+ "title": "Spec"
16490
+ }
16491
+ },
16492
+ "required": [
16493
+ "spec"
16494
+ ],
16495
+ "title": "EstimateItem",
16496
+ "type": "object"
16497
+ },
16498
+ "FromCutImageRef": {
16499
+ "additionalProperties": false,
16500
+ "properties": {
16501
+ "kind": {
16502
+ "const": "from_cut",
16503
+ "default": "from_cut",
16504
+ "title": "Kind",
16505
+ "type": "string"
16506
+ },
16507
+ "from_cut": {
16508
+ "description": "\uB2E4\uB978 \uCEF7\uC758 \uB300\uD45C \uBC84\uC804 \uD504\uB808\uC784(\uC5F0\uC18D\uC131 \uB3C4\uC6B0\uBBF8)",
16509
+ "minLength": 1,
16510
+ "title": "From Cut",
16511
+ "type": "string"
16512
+ },
16513
+ "frame": {
16514
+ "default": "last",
16515
+ "enum": [
16516
+ "first",
16517
+ "last"
16518
+ ],
16519
+ "title": "Frame",
16520
+ "type": "string"
16521
+ }
16522
+ },
16523
+ "required": [
16524
+ "from_cut"
16525
+ ],
16526
+ "title": "FromCutImageRef",
16527
+ "type": "object"
16528
+ },
16529
+ "FromVersionImageRef": {
16530
+ "additionalProperties": false,
16531
+ "properties": {
16532
+ "kind": {
16533
+ "const": "from_version",
16534
+ "default": "from_version",
16535
+ "title": "Kind",
16536
+ "type": "string"
16537
+ },
16538
+ "from_version": {
16539
+ "description": "\uC774 \uCEF7\uC758 \uD2B9\uC815 \uBC84\uC804 \uD504\uB808\uC784",
16540
+ "minimum": 1,
16541
+ "title": "From Version",
16542
+ "type": "integer"
16543
+ },
16544
+ "frame": {
16545
+ "default": "last",
16546
+ "enum": [
16547
+ "first",
16548
+ "last"
16549
+ ],
16550
+ "title": "Frame",
16551
+ "type": "string"
16552
+ }
16553
+ },
16554
+ "required": [
16555
+ "from_version"
16556
+ ],
16557
+ "title": "FromVersionImageRef",
16558
+ "type": "object"
16559
+ },
16560
+ "ImportEstimateItem": {
16561
+ "additionalProperties": false,
16562
+ "properties": {
16563
+ "cut_id": {
16564
+ "title": "Cut Id",
16565
+ "type": "string"
16566
+ },
16567
+ "video_asset_id": {
16568
+ "title": "Video Asset Id",
16569
+ "type": "string"
16570
+ },
16571
+ "transcribe": {
16572
+ "default": false,
16573
+ "title": "Transcribe",
16574
+ "type": "boolean"
16575
+ }
16576
+ },
16577
+ "required": [
16578
+ "cut_id",
16579
+ "video_asset_id"
16580
+ ],
16581
+ "title": "ImportEstimateItem",
16582
+ "type": "object"
16583
+ },
16584
+ "MotionGraphicSpec": {
16585
+ "additionalProperties": false,
16586
+ "properties": {
16587
+ "dialogue": {
16588
+ "items": {
16589
+ "$ref": "#/$defs/DialogueLine"
16590
+ },
16591
+ "title": "Dialogue",
16592
+ "type": "array"
16593
+ },
16594
+ "narration_asset_id": {
16595
+ "anyOf": [
16596
+ {
16597
+ "minLength": 1,
16598
+ "type": "string"
16599
+ },
16600
+ {
16601
+ "type": "null"
16602
+ }
16603
+ ],
16604
+ "default": null,
16605
+ "description": "BYO: \uCEF7 \uC804\uCCB4 \uB098\uB808\uC774\uC158 wav \uD55C \uAC1C(\uB300\uC0AC\uAC00 \uC788\uC5B4\uC57C \uD55C\uB2E4 \u2014 \uC790\uB9C9\xB7\uD0C0\uC774\uBC0D\uC758 \uADFC\uAC70). \uC904\uBCC4 audio_asset_id \uC640 \uB3D9\uC2DC \uC9C0\uC815 422",
16606
+ "title": "Narration Asset Id"
16607
+ },
16608
+ "subtitles": {
16609
+ "default": false,
16610
+ "title": "Subtitles",
16611
+ "type": "boolean"
16612
+ },
16613
+ "host": {
16614
+ "anyOf": [
16615
+ {
16616
+ "type": "string"
16617
+ },
16618
+ {
16619
+ "type": "null"
16620
+ }
16621
+ ],
16622
+ "default": null,
16623
+ "description": "\uC9C4\uD589 \u2014 \uD5C8\uC6A9 \uC9D1\uD569\uC740 \uCE74\uD0C8\uB85C\uADF8(\uBC29\uC2DD\uBCC4). \uBAA8\uC158\uADF8\uB798\uD53D\uC740 \uD544\uC218",
16624
+ "title": "Host"
16625
+ },
16626
+ "voice_id": {
16627
+ "anyOf": [
16628
+ {
16629
+ "minLength": 1,
16630
+ "type": "string"
16631
+ },
16632
+ {
16633
+ "type": "null"
16634
+ }
16635
+ ],
16636
+ "default": null,
16637
+ "description": "host\u2208{voice,avatar} \uC774\uACE0 BYO \uC624\uB514\uC624\uAC00 \uC5C6\uC744 \uB54C \uD544\uC218",
16638
+ "title": "Voice Id"
16639
+ },
16640
+ "pip": {
16641
+ "anyOf": [
16642
+ {
16643
+ "$ref": "#/$defs/PipSpec"
16644
+ },
16645
+ {
16646
+ "type": "null"
16647
+ }
16648
+ ],
16649
+ "default": null,
16650
+ "description": "host=avatar \uC77C \uB54C \uD544\uC218"
16651
+ },
16652
+ "image_asset_id": {
16653
+ "anyOf": [
16654
+ {
16655
+ "minLength": 1,
16656
+ "type": "string"
16657
+ },
16658
+ {
16659
+ "type": "null"
16660
+ }
16661
+ ],
16662
+ "default": null,
16663
+ "description": "\uCEF7 \uC774\uBBF8\uC9C0\uB97C spec \uC5D0\uC11C \uC9C1\uC811 \uC9C0\uC815(\uC5D0\uC774\uC804\uD2B8 \uC6D0\uC0F7\uC6A9)",
16664
+ "title": "Image Asset Id"
16665
+ },
16666
+ "duration_s": {
16667
+ "anyOf": [
16668
+ {
16669
+ "exclusiveMinimum": 0,
16670
+ "maximum": 600,
16671
+ "type": "number"
16672
+ },
16673
+ {
16674
+ "type": "null"
16675
+ }
16676
+ ],
16677
+ "default": null,
16678
+ "title": "Duration S"
16679
+ },
16680
+ "mode": {
16681
+ "const": "motion_graphic",
16682
+ "default": "motion_graphic",
16683
+ "title": "Mode",
16684
+ "type": "string"
16685
+ },
16686
+ "motion_prompt": {
16687
+ "anyOf": [
16688
+ {
16689
+ "maxLength": 4e3,
16690
+ "type": "string"
16691
+ },
16692
+ {
16693
+ "type": "null"
16694
+ }
16695
+ ],
16696
+ "default": null,
16697
+ "title": "Motion Prompt"
16698
+ },
16699
+ "tsx": {
16700
+ "anyOf": [
16701
+ {
16702
+ "maxLength": 2e5,
16703
+ "type": "string"
16704
+ },
16705
+ {
16706
+ "type": "null"
16707
+ }
16708
+ ],
16709
+ "default": null,
16710
+ "description": "BYO Remotion \uCF54\uB4DC(UTF-8 \u2264 200KB) \u2014 codegen \uD589 0\uC6D0, \uAC8C\uC774\uD2B8\uB294 codegen \uACFC \uB3D9\uAE09",
16711
+ "title": "Tsx"
16712
+ },
16713
+ "brand_override": {
16714
+ "anyOf": [
16715
+ {
16716
+ "additionalProperties": true,
16717
+ "type": "object"
16718
+ },
16719
+ {
16720
+ "type": "null"
16721
+ }
16722
+ ],
16723
+ "default": null,
16724
+ "title": "Brand Override"
16725
+ }
16726
+ },
16727
+ "title": "MotionGraphicSpec",
16728
+ "type": "object"
16729
+ },
16730
+ "PipSpec": {
16731
+ "additionalProperties": false,
16732
+ "properties": {
16733
+ "avatar_id": {
16734
+ "minLength": 1,
16735
+ "title": "Avatar Id",
16736
+ "type": "string"
16737
+ },
16738
+ "background_asset_id": {
16739
+ "description": "\uBC30\uACBD\uC740 \uC5B8\uC81C\uB098 \uC790\uC0B0(origin=background \uCE74\uD0C8\uB85C\uADF8 \uB610\uB294 \uC62C\uB9B0 \uC774\uBBF8\uC9C0)",
16740
+ "minLength": 1,
16741
+ "title": "Background Asset Id",
16742
+ "type": "string"
16743
+ },
16744
+ "position": {
16745
+ "default": "br",
16746
+ "enum": [
16747
+ "tl",
16748
+ "tr",
16749
+ "bl",
16750
+ "br"
16751
+ ],
16752
+ "title": "Position",
16753
+ "type": "string"
16754
+ },
16755
+ "size": {
16756
+ "default": "m",
16757
+ "enum": [
16758
+ "s",
16759
+ "m",
16760
+ "l"
16761
+ ],
16762
+ "title": "Size",
16763
+ "type": "string"
16764
+ }
16765
+ },
16766
+ "required": [
16767
+ "avatar_id",
16768
+ "background_asset_id"
16769
+ ],
16770
+ "title": "PipSpec",
16771
+ "type": "object"
16772
+ },
16773
+ "YoutubeAssetSource": {
16774
+ "additionalProperties": false,
16775
+ "properties": {
16776
+ "kind": {
16777
+ "const": "asset",
16778
+ "default": "asset",
16779
+ "title": "Kind",
16780
+ "type": "string"
16781
+ },
16782
+ "asset_id": {
16783
+ "description": "BYO: \uC62C\uB9B0 \uC6D0\uBCF8 \uC601\uC0C1 \u2014 \uB0B4\uB824\uBC1B\uAE30 \uD589 0\uC6D0",
16784
+ "minLength": 1,
16785
+ "title": "Asset Id",
16786
+ "type": "string"
16787
+ },
16788
+ "start_s": {
16789
+ "anyOf": [
16790
+ {
16791
+ "minimum": 0,
16792
+ "type": "number"
16793
+ },
16794
+ {
16795
+ "type": "null"
16796
+ }
16797
+ ],
16798
+ "default": null,
16799
+ "title": "Start S"
16800
+ },
16801
+ "end_s": {
16802
+ "anyOf": [
16803
+ {
16804
+ "exclusiveMinimum": 0,
16805
+ "type": "number"
16806
+ },
16807
+ {
16808
+ "type": "null"
16809
+ }
16810
+ ],
16811
+ "default": null,
16812
+ "title": "End S"
16813
+ }
16814
+ },
16815
+ "required": [
16816
+ "asset_id"
16817
+ ],
16818
+ "title": "YoutubeAssetSource",
16819
+ "type": "object"
16820
+ },
16821
+ "YoutubeClipSpec": {
16822
+ "additionalProperties": false,
16823
+ "properties": {
16824
+ "dialogue": {
16825
+ "items": {
16826
+ "$ref": "#/$defs/DialogueLine"
16827
+ },
16828
+ "title": "Dialogue",
16829
+ "type": "array"
16830
+ },
16831
+ "narration_asset_id": {
16832
+ "anyOf": [
16833
+ {
16834
+ "minLength": 1,
16835
+ "type": "string"
16836
+ },
16837
+ {
16838
+ "type": "null"
16839
+ }
16840
+ ],
16841
+ "default": null,
16842
+ "description": "BYO: \uCEF7 \uC804\uCCB4 \uB098\uB808\uC774\uC158 wav \uD55C \uAC1C(\uB300\uC0AC\uAC00 \uC788\uC5B4\uC57C \uD55C\uB2E4 \u2014 \uC790\uB9C9\xB7\uD0C0\uC774\uBC0D\uC758 \uADFC\uAC70). \uC904\uBCC4 audio_asset_id \uC640 \uB3D9\uC2DC \uC9C0\uC815 422",
16843
+ "title": "Narration Asset Id"
16844
+ },
16845
+ "subtitles": {
16846
+ "default": false,
16847
+ "title": "Subtitles",
16848
+ "type": "boolean"
16849
+ },
16850
+ "host": {
16851
+ "anyOf": [
16852
+ {
16853
+ "type": "string"
16854
+ },
16855
+ {
16856
+ "type": "null"
16857
+ }
16858
+ ],
16859
+ "default": null,
16860
+ "description": "\uC9C4\uD589 \u2014 \uD5C8\uC6A9 \uC9D1\uD569\uC740 \uCE74\uD0C8\uB85C\uADF8(\uBC29\uC2DD\uBCC4). \uBAA8\uC158\uADF8\uB798\uD53D\uC740 \uD544\uC218",
16861
+ "title": "Host"
16862
+ },
16863
+ "voice_id": {
16864
+ "anyOf": [
16865
+ {
16866
+ "minLength": 1,
16867
+ "type": "string"
16868
+ },
16869
+ {
16870
+ "type": "null"
16871
+ }
16872
+ ],
16873
+ "default": null,
16874
+ "description": "host\u2208{voice,avatar} \uC774\uACE0 BYO \uC624\uB514\uC624\uAC00 \uC5C6\uC744 \uB54C \uD544\uC218",
16875
+ "title": "Voice Id"
16876
+ },
16877
+ "pip": {
16878
+ "anyOf": [
16879
+ {
16880
+ "$ref": "#/$defs/PipSpec"
16881
+ },
16882
+ {
16883
+ "type": "null"
16884
+ }
16885
+ ],
16886
+ "default": null,
16887
+ "description": "host=avatar \uC77C \uB54C \uD544\uC218"
16888
+ },
16889
+ "image_asset_id": {
16890
+ "anyOf": [
16891
+ {
16892
+ "minLength": 1,
16893
+ "type": "string"
16894
+ },
16895
+ {
16896
+ "type": "null"
16897
+ }
16898
+ ],
16899
+ "default": null,
16900
+ "description": "\uCEF7 \uC774\uBBF8\uC9C0\uB97C spec \uC5D0\uC11C \uC9C1\uC811 \uC9C0\uC815(\uC5D0\uC774\uC804\uD2B8 \uC6D0\uC0F7\uC6A9)",
16901
+ "title": "Image Asset Id"
16902
+ },
16903
+ "duration_s": {
16904
+ "anyOf": [
16905
+ {
16906
+ "exclusiveMinimum": 0,
16907
+ "maximum": 600,
16908
+ "type": "number"
16909
+ },
16910
+ {
16911
+ "type": "null"
16912
+ }
16913
+ ],
16914
+ "default": null,
16915
+ "title": "Duration S"
16916
+ },
16917
+ "mode": {
16918
+ "const": "youtube_clip",
16919
+ "default": "youtube_clip",
16920
+ "title": "Mode",
16921
+ "type": "string"
16922
+ },
16923
+ "source": {
16924
+ "discriminator": {
16925
+ "mapping": {
16926
+ "asset": "#/$defs/YoutubeAssetSource",
16927
+ "url": "#/$defs/YoutubeUrlSource"
16928
+ },
16929
+ "propertyName": "kind"
16930
+ },
16931
+ "oneOf": [
16932
+ {
16933
+ "$ref": "#/$defs/YoutubeUrlSource"
16934
+ },
16935
+ {
16936
+ "$ref": "#/$defs/YoutubeAssetSource"
16937
+ }
16938
+ ],
16939
+ "title": "Source"
16940
+ }
16941
+ },
16942
+ "required": [
16943
+ "source"
16944
+ ],
16945
+ "title": "YoutubeClipSpec",
16946
+ "type": "object"
16947
+ },
16948
+ "YoutubeUrlSource": {
16949
+ "additionalProperties": false,
16950
+ "properties": {
16951
+ "kind": {
16952
+ "const": "url",
16953
+ "default": "url",
16954
+ "title": "Kind",
16955
+ "type": "string"
16956
+ },
16957
+ "url": {
16958
+ "description": "https://youtube.com|youtu.be \uACF5\uAC1C \uC8FC\uC18C\uB9CC",
16959
+ "minLength": 1,
16960
+ "title": "Url",
16961
+ "type": "string"
16962
+ },
16963
+ "start_s": {
16964
+ "minimum": 0,
16965
+ "title": "Start S",
16966
+ "type": "number"
16967
+ },
16968
+ "end_s": {
16969
+ "exclusiveMinimum": 0,
16970
+ "title": "End S",
16971
+ "type": "number"
16972
+ }
16973
+ },
16974
+ "required": [
16975
+ "url",
16976
+ "start_s",
16977
+ "end_s"
16978
+ ],
16979
+ "title": "YoutubeUrlSource",
16980
+ "type": "object"
16981
+ }
16982
+ }
16983
+ },
16984
+ "annotations": {
16985
+ "readOnlyHint": false,
16986
+ "destructiveHint": false,
16987
+ "idempotentHint": false,
16988
+ "openWorldHint": false
16989
+ }
16990
+ },
16991
+ {
16992
+ "name": "democut_make_cuts",
16993
+ "description": "\uCEF7 N \uAC1C\uB97C \uB9CC\uB4E0\uB2E4(\uCCAD\uAD6C \u2014 \uC81C\uCD9C \uC2DC \uC794\uC561\uC5D0\uC11C \uCC28\uAC10, \uC2E4\uD328 \uC2DC \uD658\uBD88). \uAE30\uBCF8 \uBC29\uC2DD\uC740 ai_video. items \uB294 all-or-nothing \uC774\uB2E4. \uB3C8\uC774 \uB098\uAC00\uB294 \uB3C4\uAD6C\uB2E4: estimate_cuts(\uB610\uB294 \uC9DD\uC774 \uB418\uB294 estimate \uB3C4\uAD6C)\uB85C \uAE08\uC561\uC744 \uBCF4\uACE0 \uC0AC\uC6A9\uC790 \uB3D9\uC758\uB97C \uBC1B\uC740 \uB4A4 confirmed_*_krw \uC640 rate_version \uC744 \uADF8\uB300\uB85C \uB123\uC5B4\uB77C. \uC5B4\uAE0B\uB098\uBA74 409 QUOTE_MISMATCH \uB85C \uC0C8 \uACAC\uC801\uC744 \uC900\uB2E4(\uACFC\uAE08 \uC5C6\uC74C). \uC2E4\uD328\uD574\uB3C4 \uC7AC\uC81C\uCD9C\uD558\uC9C0 \uB9C8\uB77C \u2014 \uAC19\uC740 spec \uC774 \uD65C\uC131\uC774\uBA74 \uC11C\uBC84\uAC00 \uAE30\uC874 \uC7A1\uC744 \uB3CC\uB824\uC900\uB2E4(deduplicated=true). \uC751\uB2F5\uC740 202 \u2014 \uACB0\uACFC\uB294 democut_wait_jobs \uB85C \uBC1B\uB294\uB2E4. \uB2E4\uC74C \uD638\uCD9C: democut_wait_jobs.",
16994
+ "inputSchema": {
16995
+ "type": "object",
16996
+ "properties": {
16997
+ "slug": {
16998
+ "type": "string",
16999
+ "description": "\uD504\uB85C\uC81D\uD2B8 \uC2AC\uB7EC\uADF8(list_projects)"
17000
+ },
17001
+ "items": {
17002
+ "items": {
17003
+ "$ref": "#/$defs/MakeItem"
17004
+ },
17005
+ "maxItems": 50,
17006
+ "minItems": 1,
17007
+ "title": "Items",
17008
+ "type": "array"
17009
+ },
17010
+ "confirmed_total_krw": {
17011
+ "description": "estimate_cuts \uC758 total_krw \uADF8\uB300\uB85C",
17012
+ "minimum": 0,
17013
+ "title": "Confirmed Total Krw",
17014
+ "type": "integer"
17015
+ },
17016
+ "rate_version": {
17017
+ "description": "estimate_cuts \uC758 rate_version \uADF8\uB300\uB85C",
17018
+ "minimum": 1,
17019
+ "title": "Rate Version",
17020
+ "type": "integer"
17021
+ }
17022
+ },
17023
+ "required": [
17024
+ "slug",
17025
+ "items",
17026
+ "confirmed_total_krw",
17027
+ "rate_version"
17028
+ ],
17029
+ "additionalProperties": false,
17030
+ "$defs": {
17031
+ "AiVideoSpec": {
17032
+ "additionalProperties": false,
17033
+ "properties": {
17034
+ "dialogue": {
17035
+ "items": {
17036
+ "$ref": "#/$defs/DialogueLine"
17037
+ },
17038
+ "title": "Dialogue",
17039
+ "type": "array"
17040
+ },
17041
+ "narration_asset_id": {
17042
+ "anyOf": [
17043
+ {
17044
+ "minLength": 1,
17045
+ "type": "string"
17046
+ },
17047
+ {
17048
+ "type": "null"
17049
+ }
17050
+ ],
17051
+ "default": null,
17052
+ "description": "BYO: \uCEF7 \uC804\uCCB4 \uB098\uB808\uC774\uC158 wav \uD55C \uAC1C(\uB300\uC0AC\uAC00 \uC788\uC5B4\uC57C \uD55C\uB2E4 \u2014 \uC790\uB9C9\xB7\uD0C0\uC774\uBC0D\uC758 \uADFC\uAC70). \uC904\uBCC4 audio_asset_id \uC640 \uB3D9\uC2DC \uC9C0\uC815 422",
17053
+ "title": "Narration Asset Id"
17054
+ },
17055
+ "subtitles": {
17056
+ "default": false,
17057
+ "title": "Subtitles",
17058
+ "type": "boolean"
17059
+ },
17060
+ "host": {
17061
+ "anyOf": [
17062
+ {
17063
+ "type": "string"
17064
+ },
17065
+ {
17066
+ "type": "null"
17067
+ }
17068
+ ],
17069
+ "default": null,
17070
+ "description": "\uC9C4\uD589 \u2014 \uD5C8\uC6A9 \uC9D1\uD569\uC740 \uCE74\uD0C8\uB85C\uADF8(\uBC29\uC2DD\uBCC4). \uBAA8\uC158\uADF8\uB798\uD53D\uC740 \uD544\uC218",
17071
+ "title": "Host"
17072
+ },
17073
+ "voice_id": {
17074
+ "anyOf": [
17075
+ {
17076
+ "minLength": 1,
17077
+ "type": "string"
17078
+ },
17079
+ {
17080
+ "type": "null"
17081
+ }
17082
+ ],
17083
+ "default": null,
17084
+ "description": "host\u2208{voice,avatar} \uC774\uACE0 BYO \uC624\uB514\uC624\uAC00 \uC5C6\uC744 \uB54C \uD544\uC218",
17085
+ "title": "Voice Id"
17086
+ },
17087
+ "pip": {
17088
+ "anyOf": [
17089
+ {
17090
+ "$ref": "#/$defs/PipSpec"
17091
+ },
17092
+ {
17093
+ "type": "null"
17094
+ }
17095
+ ],
17096
+ "default": null,
17097
+ "description": "host=avatar \uC77C \uB54C \uD544\uC218"
17098
+ },
17099
+ "image_asset_id": {
17100
+ "anyOf": [
17101
+ {
17102
+ "minLength": 1,
17103
+ "type": "string"
17104
+ },
17105
+ {
17106
+ "type": "null"
17107
+ }
17108
+ ],
17109
+ "default": null,
17110
+ "description": "\uCEF7 \uC774\uBBF8\uC9C0\uB97C spec \uC5D0\uC11C \uC9C1\uC811 \uC9C0\uC815(\uC5D0\uC774\uC804\uD2B8 \uC6D0\uC0F7\uC6A9)",
17111
+ "title": "Image Asset Id"
17112
+ },
17113
+ "duration_s": {
17114
+ "default": 5,
17115
+ "maximum": 15,
17116
+ "minimum": 4,
17117
+ "title": "Duration S",
17118
+ "type": "number"
17119
+ },
17120
+ "mode": {
17121
+ "const": "ai_video",
17122
+ "default": "ai_video",
17123
+ "title": "Mode",
17124
+ "type": "string"
17125
+ },
17126
+ "image_prompt": {
17127
+ "maxLength": 4e3,
17128
+ "minLength": 1,
17129
+ "title": "Image Prompt",
17130
+ "type": "string"
17131
+ },
17132
+ "seed": {
17133
+ "anyOf": [
17134
+ {
17135
+ "minimum": 0,
17136
+ "type": "integer"
17137
+ },
17138
+ {
17139
+ "type": "null"
17140
+ }
17141
+ ],
17142
+ "default": null,
17143
+ "title": "Seed"
17144
+ },
17145
+ "image": {
17146
+ "anyOf": [
17147
+ {
17148
+ "discriminator": {
17149
+ "mapping": {
17150
+ "asset": "#/$defs/AssetImageRef",
17151
+ "from_cut": "#/$defs/FromCutImageRef",
17152
+ "from_version": "#/$defs/FromVersionImageRef"
17153
+ },
17154
+ "propertyName": "kind"
17155
+ },
17156
+ "oneOf": [
17157
+ {
17158
+ "$ref": "#/$defs/AssetImageRef"
17159
+ },
17160
+ {
17161
+ "$ref": "#/$defs/FromCutImageRef"
17162
+ },
17163
+ {
17164
+ "$ref": "#/$defs/FromVersionImageRef"
17165
+ }
17166
+ ]
17167
+ },
17168
+ {
17169
+ "type": "null"
17170
+ }
17171
+ ],
17172
+ "default": null,
17173
+ "description": "\uCCAB \uD504\uB808\uC784. \uC5C6\uC73C\uBA74 image_asset_id \u2192 \uCEF7 \uC774\uBBF8\uC9C0 \u2192 t2v \uC21C",
17174
+ "title": "Image"
17175
+ },
17176
+ "end_image": {
17177
+ "anyOf": [
17178
+ {
17179
+ "discriminator": {
17180
+ "mapping": {
17181
+ "asset": "#/$defs/AssetImageRef",
17182
+ "from_cut": "#/$defs/FromCutImageRef",
17183
+ "from_version": "#/$defs/FromVersionImageRef"
17184
+ },
17185
+ "propertyName": "kind"
17186
+ },
17187
+ "oneOf": [
17188
+ {
17189
+ "$ref": "#/$defs/AssetImageRef"
17190
+ },
17191
+ {
17192
+ "$ref": "#/$defs/FromCutImageRef"
17193
+ },
17194
+ {
17195
+ "$ref": "#/$defs/FromVersionImageRef"
17196
+ }
17197
+ ]
17198
+ },
17199
+ {
17200
+ "type": "null"
17201
+ }
17202
+ ],
17203
+ "default": null,
17204
+ "title": "End Image"
17205
+ }
17206
+ },
17207
+ "required": [
17208
+ "image_prompt"
17209
+ ],
17210
+ "title": "AiVideoSpec",
17211
+ "type": "object"
17212
+ },
17213
+ "AssetImageRef": {
17214
+ "additionalProperties": false,
17215
+ "properties": {
17216
+ "kind": {
17217
+ "const": "asset",
17218
+ "default": "asset",
17219
+ "title": "Kind",
17220
+ "type": "string"
17221
+ },
17222
+ "asset_id": {
17223
+ "minLength": 1,
17224
+ "title": "Asset Id",
17225
+ "type": "string"
17226
+ }
17227
+ },
17228
+ "required": [
17229
+ "asset_id"
17230
+ ],
17231
+ "title": "AssetImageRef",
17232
+ "type": "object"
17233
+ },
17234
+ "DialogueLine": {
17235
+ "additionalProperties": false,
17236
+ "properties": {
17237
+ "id": {
17238
+ "description": "\uC904 id ln_<6> \u2014 \uC81C\uC548 diff \uC758 \uB300\uC870 \uD0A4",
17239
+ "pattern": "^ln_[a-z0-9]{6}$",
17240
+ "title": "Id",
17241
+ "type": "string",
17242
+ "x-diff": "ignore"
17243
+ },
17244
+ "text": {
17245
+ "description": "\uBC1C\uD654 \uD14D\uC2A4\uD2B8(\uC22B\uC790\uB294 \uC11C\uBC84\uAC00 \uC77D\uB294 \uBC95\uC744 \uC815\uD55C\uB2E4 \u2014 \uD480\uC5B4\uC4F0\uC9C0 \uC54A\uB294\uB2E4)",
17246
+ "maxLength": 2e3,
17247
+ "minLength": 1,
17248
+ "title": "Text",
17249
+ "type": "string"
17250
+ },
17251
+ "subtitle_text": {
17252
+ "anyOf": [
17253
+ {
17254
+ "maxLength": 2e3,
17255
+ "type": "string"
17256
+ },
17257
+ {
17258
+ "type": "null"
17259
+ }
17260
+ ],
17261
+ "default": null,
17262
+ "description": "\uC790\uB9C9 \uD45C\uAE30(\uC6D0\uBB38 \uD45C\uAE30). \uC5C6\uC73C\uBA74 text",
17263
+ "title": "Subtitle Text"
17264
+ },
17265
+ "audio_asset_id": {
17266
+ "anyOf": [
17267
+ {
17268
+ "minLength": 1,
17269
+ "type": "string"
17270
+ },
17271
+ {
17272
+ "type": "null"
17273
+ }
17274
+ ],
17275
+ "default": null,
17276
+ "description": "BYO: \uC774 \uC904\uC758 \uB098\uB808\uC774\uC158 \uC624\uB514\uC624 \uC790\uC0B0 \u2014 TTS \uD589 0\uC6D0, \uC815\uB82C \uD589\uB9CC",
17277
+ "title": "Audio Asset Id"
17278
+ }
17279
+ },
17280
+ "required": [
17281
+ "id",
17282
+ "text"
17283
+ ],
17284
+ "title": "DialogueLine",
17285
+ "type": "object"
17286
+ },
17287
+ "FromCutImageRef": {
17288
+ "additionalProperties": false,
17289
+ "properties": {
17290
+ "kind": {
17291
+ "const": "from_cut",
17292
+ "default": "from_cut",
17293
+ "title": "Kind",
17294
+ "type": "string"
17295
+ },
17296
+ "from_cut": {
17297
+ "description": "\uB2E4\uB978 \uCEF7\uC758 \uB300\uD45C \uBC84\uC804 \uD504\uB808\uC784(\uC5F0\uC18D\uC131 \uB3C4\uC6B0\uBBF8)",
17298
+ "minLength": 1,
17299
+ "title": "From Cut",
17300
+ "type": "string"
17301
+ },
17302
+ "frame": {
17303
+ "default": "last",
17304
+ "enum": [
17305
+ "first",
17306
+ "last"
17307
+ ],
17308
+ "title": "Frame",
17309
+ "type": "string"
17310
+ }
17311
+ },
17312
+ "required": [
17313
+ "from_cut"
17314
+ ],
17315
+ "title": "FromCutImageRef",
17316
+ "type": "object"
17317
+ },
17318
+ "FromVersionImageRef": {
17319
+ "additionalProperties": false,
17320
+ "properties": {
17321
+ "kind": {
17322
+ "const": "from_version",
17323
+ "default": "from_version",
17324
+ "title": "Kind",
17325
+ "type": "string"
17326
+ },
17327
+ "from_version": {
17328
+ "description": "\uC774 \uCEF7\uC758 \uD2B9\uC815 \uBC84\uC804 \uD504\uB808\uC784",
17329
+ "minimum": 1,
17330
+ "title": "From Version",
17331
+ "type": "integer"
17332
+ },
17333
+ "frame": {
17334
+ "default": "last",
17335
+ "enum": [
17336
+ "first",
17337
+ "last"
17338
+ ],
17339
+ "title": "Frame",
17340
+ "type": "string"
17341
+ }
17342
+ },
17343
+ "required": [
17344
+ "from_version"
17345
+ ],
17346
+ "title": "FromVersionImageRef",
17347
+ "type": "object"
17348
+ },
17349
+ "MakeItem": {
17350
+ "additionalProperties": false,
17351
+ "properties": {
17352
+ "cut_id": {
17353
+ "anyOf": [
17354
+ {
17355
+ "type": "string"
17356
+ },
17357
+ {
17358
+ "type": "null"
17359
+ }
17360
+ ],
17361
+ "default": null,
17362
+ "title": "Cut Id"
17363
+ },
17364
+ "spec": {
17365
+ "discriminator": {
17366
+ "mapping": {
17367
+ "ai_video": "#/$defs/AiVideoSpec",
17368
+ "motion_graphic": "#/$defs/MotionGraphicSpec",
17369
+ "youtube_clip": "#/$defs/YoutubeClipSpec"
17370
+ },
17371
+ "propertyName": "mode"
17372
+ },
17373
+ "oneOf": [
17374
+ {
17375
+ "$ref": "#/$defs/MotionGraphicSpec"
17376
+ },
17377
+ {
17378
+ "$ref": "#/$defs/AiVideoSpec"
17379
+ },
17380
+ {
17381
+ "$ref": "#/$defs/YoutubeClipSpec"
17382
+ }
17383
+ ],
17384
+ "title": "Spec"
17385
+ },
17386
+ "note": {
17387
+ "anyOf": [
17388
+ {
17389
+ "maxLength": 500,
17390
+ "type": "string"
17391
+ },
17392
+ {
17393
+ "type": "null"
17394
+ }
17395
+ ],
17396
+ "default": null,
17397
+ "title": "Note"
17398
+ }
17399
+ },
17400
+ "required": [
17401
+ "spec"
17402
+ ],
17403
+ "title": "MakeItem",
17404
+ "type": "object"
17405
+ },
17406
+ "MotionGraphicSpec": {
17407
+ "additionalProperties": false,
17408
+ "properties": {
17409
+ "dialogue": {
17410
+ "items": {
17411
+ "$ref": "#/$defs/DialogueLine"
17412
+ },
17413
+ "title": "Dialogue",
17414
+ "type": "array"
17415
+ },
17416
+ "narration_asset_id": {
17417
+ "anyOf": [
17418
+ {
17419
+ "minLength": 1,
17420
+ "type": "string"
17421
+ },
17422
+ {
17423
+ "type": "null"
17424
+ }
17425
+ ],
17426
+ "default": null,
17427
+ "description": "BYO: \uCEF7 \uC804\uCCB4 \uB098\uB808\uC774\uC158 wav \uD55C \uAC1C(\uB300\uC0AC\uAC00 \uC788\uC5B4\uC57C \uD55C\uB2E4 \u2014 \uC790\uB9C9\xB7\uD0C0\uC774\uBC0D\uC758 \uADFC\uAC70). \uC904\uBCC4 audio_asset_id \uC640 \uB3D9\uC2DC \uC9C0\uC815 422",
17428
+ "title": "Narration Asset Id"
17429
+ },
17430
+ "subtitles": {
17431
+ "default": false,
17432
+ "title": "Subtitles",
17433
+ "type": "boolean"
17434
+ },
17435
+ "host": {
17436
+ "anyOf": [
17437
+ {
17438
+ "type": "string"
17439
+ },
17440
+ {
17441
+ "type": "null"
17442
+ }
17443
+ ],
17444
+ "default": null,
17445
+ "description": "\uC9C4\uD589 \u2014 \uD5C8\uC6A9 \uC9D1\uD569\uC740 \uCE74\uD0C8\uB85C\uADF8(\uBC29\uC2DD\uBCC4). \uBAA8\uC158\uADF8\uB798\uD53D\uC740 \uD544\uC218",
17446
+ "title": "Host"
17447
+ },
17448
+ "voice_id": {
17449
+ "anyOf": [
17450
+ {
17451
+ "minLength": 1,
17452
+ "type": "string"
17453
+ },
17454
+ {
17455
+ "type": "null"
17456
+ }
17457
+ ],
17458
+ "default": null,
17459
+ "description": "host\u2208{voice,avatar} \uC774\uACE0 BYO \uC624\uB514\uC624\uAC00 \uC5C6\uC744 \uB54C \uD544\uC218",
17460
+ "title": "Voice Id"
17461
+ },
17462
+ "pip": {
17463
+ "anyOf": [
17464
+ {
17465
+ "$ref": "#/$defs/PipSpec"
17466
+ },
17467
+ {
17468
+ "type": "null"
17469
+ }
17470
+ ],
17471
+ "default": null,
17472
+ "description": "host=avatar \uC77C \uB54C \uD544\uC218"
17473
+ },
17474
+ "image_asset_id": {
17475
+ "anyOf": [
17476
+ {
17477
+ "minLength": 1,
17478
+ "type": "string"
17479
+ },
17480
+ {
17481
+ "type": "null"
17482
+ }
17483
+ ],
17484
+ "default": null,
17485
+ "description": "\uCEF7 \uC774\uBBF8\uC9C0\uB97C spec \uC5D0\uC11C \uC9C1\uC811 \uC9C0\uC815(\uC5D0\uC774\uC804\uD2B8 \uC6D0\uC0F7\uC6A9)",
17486
+ "title": "Image Asset Id"
17487
+ },
17488
+ "duration_s": {
17489
+ "anyOf": [
17490
+ {
17491
+ "exclusiveMinimum": 0,
17492
+ "maximum": 600,
17493
+ "type": "number"
17494
+ },
17495
+ {
17496
+ "type": "null"
17497
+ }
17498
+ ],
17499
+ "default": null,
17500
+ "title": "Duration S"
17501
+ },
17502
+ "mode": {
17503
+ "const": "motion_graphic",
17504
+ "default": "motion_graphic",
17505
+ "title": "Mode",
17506
+ "type": "string"
17507
+ },
17508
+ "motion_prompt": {
17509
+ "anyOf": [
17510
+ {
17511
+ "maxLength": 4e3,
17512
+ "type": "string"
17513
+ },
17514
+ {
17515
+ "type": "null"
17516
+ }
17517
+ ],
17518
+ "default": null,
17519
+ "title": "Motion Prompt"
17520
+ },
17521
+ "tsx": {
17522
+ "anyOf": [
17523
+ {
17524
+ "maxLength": 2e5,
17525
+ "type": "string"
17526
+ },
17527
+ {
17528
+ "type": "null"
17529
+ }
17530
+ ],
17531
+ "default": null,
17532
+ "description": "BYO Remotion \uCF54\uB4DC(UTF-8 \u2264 200KB) \u2014 codegen \uD589 0\uC6D0, \uAC8C\uC774\uD2B8\uB294 codegen \uACFC \uB3D9\uAE09",
17533
+ "title": "Tsx"
17534
+ },
17535
+ "brand_override": {
17536
+ "anyOf": [
17537
+ {
17538
+ "additionalProperties": true,
17539
+ "type": "object"
17540
+ },
17541
+ {
17542
+ "type": "null"
17543
+ }
17544
+ ],
17545
+ "default": null,
17546
+ "title": "Brand Override"
17547
+ }
17548
+ },
17549
+ "title": "MotionGraphicSpec",
17550
+ "type": "object"
17551
+ },
17552
+ "PipSpec": {
17553
+ "additionalProperties": false,
17554
+ "properties": {
17555
+ "avatar_id": {
17556
+ "minLength": 1,
17557
+ "title": "Avatar Id",
17558
+ "type": "string"
17559
+ },
17560
+ "background_asset_id": {
17561
+ "description": "\uBC30\uACBD\uC740 \uC5B8\uC81C\uB098 \uC790\uC0B0(origin=background \uCE74\uD0C8\uB85C\uADF8 \uB610\uB294 \uC62C\uB9B0 \uC774\uBBF8\uC9C0)",
17562
+ "minLength": 1,
17563
+ "title": "Background Asset Id",
17564
+ "type": "string"
17565
+ },
17566
+ "position": {
17567
+ "default": "br",
17568
+ "enum": [
17569
+ "tl",
17570
+ "tr",
17571
+ "bl",
17572
+ "br"
17573
+ ],
17574
+ "title": "Position",
17575
+ "type": "string"
17576
+ },
17577
+ "size": {
17578
+ "default": "m",
17579
+ "enum": [
17580
+ "s",
17581
+ "m",
17582
+ "l"
17583
+ ],
17584
+ "title": "Size",
17585
+ "type": "string"
17586
+ }
17587
+ },
17588
+ "required": [
17589
+ "avatar_id",
17590
+ "background_asset_id"
17591
+ ],
17592
+ "title": "PipSpec",
17593
+ "type": "object"
17594
+ },
17595
+ "YoutubeAssetSource": {
17596
+ "additionalProperties": false,
17597
+ "properties": {
17598
+ "kind": {
17599
+ "const": "asset",
17600
+ "default": "asset",
17601
+ "title": "Kind",
17602
+ "type": "string"
17603
+ },
17604
+ "asset_id": {
17605
+ "description": "BYO: \uC62C\uB9B0 \uC6D0\uBCF8 \uC601\uC0C1 \u2014 \uB0B4\uB824\uBC1B\uAE30 \uD589 0\uC6D0",
17606
+ "minLength": 1,
17607
+ "title": "Asset Id",
17608
+ "type": "string"
17609
+ },
17610
+ "start_s": {
17611
+ "anyOf": [
17612
+ {
17613
+ "minimum": 0,
17614
+ "type": "number"
17615
+ },
17616
+ {
17617
+ "type": "null"
17618
+ }
17619
+ ],
17620
+ "default": null,
17621
+ "title": "Start S"
17622
+ },
17623
+ "end_s": {
17624
+ "anyOf": [
17625
+ {
17626
+ "exclusiveMinimum": 0,
17627
+ "type": "number"
17628
+ },
17629
+ {
17630
+ "type": "null"
17631
+ }
17632
+ ],
17633
+ "default": null,
17634
+ "title": "End S"
17635
+ }
17636
+ },
17637
+ "required": [
17638
+ "asset_id"
17639
+ ],
17640
+ "title": "YoutubeAssetSource",
17641
+ "type": "object"
17642
+ },
17643
+ "YoutubeClipSpec": {
17644
+ "additionalProperties": false,
17645
+ "properties": {
17646
+ "dialogue": {
17647
+ "items": {
17648
+ "$ref": "#/$defs/DialogueLine"
17649
+ },
17650
+ "title": "Dialogue",
17651
+ "type": "array"
17652
+ },
17653
+ "narration_asset_id": {
17654
+ "anyOf": [
17655
+ {
17656
+ "minLength": 1,
17657
+ "type": "string"
17658
+ },
17659
+ {
17660
+ "type": "null"
17661
+ }
17662
+ ],
17663
+ "default": null,
17664
+ "description": "BYO: \uCEF7 \uC804\uCCB4 \uB098\uB808\uC774\uC158 wav \uD55C \uAC1C(\uB300\uC0AC\uAC00 \uC788\uC5B4\uC57C \uD55C\uB2E4 \u2014 \uC790\uB9C9\xB7\uD0C0\uC774\uBC0D\uC758 \uADFC\uAC70). \uC904\uBCC4 audio_asset_id \uC640 \uB3D9\uC2DC \uC9C0\uC815 422",
17665
+ "title": "Narration Asset Id"
17666
+ },
17667
+ "subtitles": {
17668
+ "default": false,
17669
+ "title": "Subtitles",
17670
+ "type": "boolean"
17671
+ },
17672
+ "host": {
17673
+ "anyOf": [
17674
+ {
17675
+ "type": "string"
17676
+ },
17677
+ {
17678
+ "type": "null"
17679
+ }
17680
+ ],
17681
+ "default": null,
17682
+ "description": "\uC9C4\uD589 \u2014 \uD5C8\uC6A9 \uC9D1\uD569\uC740 \uCE74\uD0C8\uB85C\uADF8(\uBC29\uC2DD\uBCC4). \uBAA8\uC158\uADF8\uB798\uD53D\uC740 \uD544\uC218",
17683
+ "title": "Host"
17684
+ },
17685
+ "voice_id": {
17686
+ "anyOf": [
17687
+ {
17688
+ "minLength": 1,
17689
+ "type": "string"
17690
+ },
17691
+ {
17692
+ "type": "null"
17693
+ }
17694
+ ],
17695
+ "default": null,
17696
+ "description": "host\u2208{voice,avatar} \uC774\uACE0 BYO \uC624\uB514\uC624\uAC00 \uC5C6\uC744 \uB54C \uD544\uC218",
17697
+ "title": "Voice Id"
17698
+ },
17699
+ "pip": {
17700
+ "anyOf": [
17701
+ {
17702
+ "$ref": "#/$defs/PipSpec"
17703
+ },
17704
+ {
17705
+ "type": "null"
17706
+ }
17707
+ ],
17708
+ "default": null,
17709
+ "description": "host=avatar \uC77C \uB54C \uD544\uC218"
17710
+ },
17711
+ "image_asset_id": {
17712
+ "anyOf": [
17713
+ {
17714
+ "minLength": 1,
17715
+ "type": "string"
17716
+ },
17717
+ {
17718
+ "type": "null"
17719
+ }
17720
+ ],
17721
+ "default": null,
17722
+ "description": "\uCEF7 \uC774\uBBF8\uC9C0\uB97C spec \uC5D0\uC11C \uC9C1\uC811 \uC9C0\uC815(\uC5D0\uC774\uC804\uD2B8 \uC6D0\uC0F7\uC6A9)",
17723
+ "title": "Image Asset Id"
17724
+ },
17725
+ "duration_s": {
17726
+ "anyOf": [
17727
+ {
17728
+ "exclusiveMinimum": 0,
17729
+ "maximum": 600,
17730
+ "type": "number"
17731
+ },
17732
+ {
17733
+ "type": "null"
17734
+ }
17735
+ ],
17736
+ "default": null,
17737
+ "title": "Duration S"
17738
+ },
17739
+ "mode": {
17740
+ "const": "youtube_clip",
17741
+ "default": "youtube_clip",
17742
+ "title": "Mode",
17743
+ "type": "string"
17744
+ },
17745
+ "source": {
17746
+ "discriminator": {
17747
+ "mapping": {
17748
+ "asset": "#/$defs/YoutubeAssetSource",
17749
+ "url": "#/$defs/YoutubeUrlSource"
17750
+ },
17751
+ "propertyName": "kind"
17752
+ },
17753
+ "oneOf": [
17754
+ {
17755
+ "$ref": "#/$defs/YoutubeUrlSource"
17756
+ },
17757
+ {
17758
+ "$ref": "#/$defs/YoutubeAssetSource"
17759
+ }
17760
+ ],
17761
+ "title": "Source"
17762
+ }
17763
+ },
17764
+ "required": [
17765
+ "source"
17766
+ ],
17767
+ "title": "YoutubeClipSpec",
17768
+ "type": "object"
17769
+ },
17770
+ "YoutubeUrlSource": {
17771
+ "additionalProperties": false,
17772
+ "properties": {
17773
+ "kind": {
17774
+ "const": "url",
17775
+ "default": "url",
17776
+ "title": "Kind",
17777
+ "type": "string"
17778
+ },
17779
+ "url": {
17780
+ "description": "https://youtube.com|youtu.be \uACF5\uAC1C \uC8FC\uC18C\uB9CC",
17781
+ "minLength": 1,
17782
+ "title": "Url",
17783
+ "type": "string"
17784
+ },
17785
+ "start_s": {
17786
+ "minimum": 0,
17787
+ "title": "Start S",
17788
+ "type": "number"
17789
+ },
17790
+ "end_s": {
17791
+ "exclusiveMinimum": 0,
17792
+ "title": "End S",
17793
+ "type": "number"
17794
+ }
17795
+ },
17796
+ "required": [
17797
+ "url",
17798
+ "start_s",
17799
+ "end_s"
17800
+ ],
17801
+ "title": "YoutubeUrlSource",
17802
+ "type": "object"
17803
+ }
17804
+ }
17805
+ },
17806
+ "annotations": {
17807
+ "readOnlyHint": false,
17808
+ "destructiveHint": false,
17809
+ "idempotentHint": false,
17810
+ "openWorldHint": false
17811
+ }
17812
+ },
17813
+ {
17814
+ "name": "democut_wait_jobs",
17815
+ "description": "\uC7A1\uC774 \uB05D\uB0A0 \uB54C\uAE4C\uC9C0 \uAE30\uB2E4\uB9B0\uB2E4(\uC694\uCCAD\uD55C \uBAA8\uB4E0 id \uC758 \uC2A4\uB0C5\uC0F7 + all_done). all_done=false \uBA74 \uC544\uC9C1 \uC548 \uB05D\uB09C id \uB9CC \uAC19\uC740 \uB3C4\uAD6C\uB85C \uB2E4\uC2DC \uBD80\uB978\uB2E4. \uB05D\uB09C \uC7A1\uC758 result.download \uB85C \uBC14\uB85C \uB0B4\uB824\uBC1B\uB294\uB2E4. job_ids\xB7batch_id\xB7project \uC911 \uD558\uB098\uB294 \uC788\uC5B4\uC57C \uD55C\uB2E4. \uB2E4\uC74C \uD638\uCD9C: democut_download, democut_get_cut.",
17816
+ "inputSchema": {
17817
+ "type": "object",
17818
+ "properties": {
17819
+ "job_ids": {
17820
+ "anyOf": [
17821
+ {
17822
+ "items": {
17823
+ "type": "string"
17824
+ },
17825
+ "maxItems": 100,
17826
+ "minItems": 1,
17827
+ "type": "array"
17828
+ },
17829
+ {
17830
+ "type": "null"
17831
+ }
17832
+ ],
17833
+ "default": null,
17834
+ "title": "Job Ids"
17835
+ },
17836
+ "batch_id": {
17837
+ "anyOf": [
17838
+ {
17839
+ "type": "string"
17840
+ },
17841
+ {
17842
+ "type": "null"
17843
+ }
17844
+ ],
17845
+ "default": null,
17846
+ "title": "Batch Id"
17847
+ },
17848
+ "project": {
17849
+ "anyOf": [
17850
+ {
17851
+ "type": "string"
17852
+ },
17853
+ {
17854
+ "type": "null"
17855
+ }
17856
+ ],
17857
+ "default": null,
17858
+ "title": "Project"
17859
+ },
17860
+ "state": {
17861
+ "anyOf": [
17862
+ {
17863
+ "enum": [
17864
+ "queued",
17865
+ "running",
17866
+ "done",
17867
+ "error",
17868
+ "cancelled"
17869
+ ],
17870
+ "type": "string"
17871
+ },
17872
+ {
17873
+ "type": "null"
17874
+ }
17875
+ ],
17876
+ "default": null,
17877
+ "title": "State"
17878
+ },
17879
+ "timeout_s": {
17880
+ "default": 600,
17881
+ "description": "0 = \uAE30\uB2E4\uB9AC\uC9C0 \uC54A\uACE0 \uC9C0\uAE08 \uC0C1\uD0DC\uB9CC. all_done=false \uBA74 \uB0A8\uC740 id \uB9CC \uB2E4\uC2DC \uBD80\uB978\uB2E4",
17882
+ "maximum": 600,
17883
+ "minimum": 0,
17884
+ "title": "Timeout S",
17885
+ "type": "integer"
17886
+ }
17887
+ },
17888
+ "required": [],
17889
+ "additionalProperties": false,
17890
+ "anyOf": [
17891
+ {
17892
+ "required": [
17893
+ "job_ids"
17894
+ ]
17895
+ },
17896
+ {
17897
+ "required": [
17898
+ "batch_id"
17899
+ ]
17900
+ },
17901
+ {
17902
+ "required": [
17903
+ "project"
17904
+ ]
17905
+ }
17906
+ ]
17907
+ },
17908
+ "annotations": {
17909
+ "readOnlyHint": true,
17910
+ "destructiveHint": false,
17911
+ "idempotentHint": true,
17912
+ "openWorldHint": false
17913
+ }
17914
+ },
17915
+ {
17916
+ "name": "democut_get_cut",
17917
+ "description": "\uCEF7 \uD558\uB098 \u2014 \uBC84\uC804 \uBAA9\uB85D\uACFC \uBC84\uC804\uB9C8\uB2E4 download{video,audio,subtitle,still} \uC11C\uBA85 URL. \uD0C0\uC774\uBC0D\uC740 versions[].timing \uC5D0 \uC778\uB77C\uC778. current_version \uC774 \uC5C6\uC73C\uBA74 \uACC4\uD68D \uCEF7\uC774\uB2E4. \uB2E4\uC74C \uD638\uCD9C: democut_download, democut_make_cuts.",
17918
+ "inputSchema": {
17919
+ "type": "object",
17920
+ "properties": {
17921
+ "slug": {
17922
+ "type": "string",
17923
+ "description": "\uD504\uB85C\uC81D\uD2B8 \uC2AC\uB7EC\uADF8(list_projects)"
17924
+ },
17925
+ "cut_id": {
17926
+ "type": "string",
17927
+ "description": "\uCEF7 id(cut_\u2026)"
17928
+ }
17929
+ },
17930
+ "required": [
17931
+ "slug",
17932
+ "cut_id"
17933
+ ],
17934
+ "additionalProperties": false
17935
+ },
17936
+ "annotations": {
17937
+ "readOnlyHint": true,
17938
+ "destructiveHint": false,
17939
+ "idempotentHint": true,
17940
+ "openWorldHint": false
17941
+ }
17942
+ },
17943
+ {
17944
+ "name": "democut_download",
17945
+ "description": "\uBC84\uC804 \uC0B0\uCD9C\uBB3C \uD558\uB098\uB97C \uB0B4\uB824\uBC1B\uB294\uB2E4(kind: video|audio|subtitle|still). stdio \uB294 output_path \uC5D0 \uC800\uC7A5, \uC6D0\uACA9\uC740 \uC11C\uBA85 URL(1\uC2DC\uAC04).",
17946
+ "inputSchema": {
17947
+ "type": "object",
17948
+ "properties": {
17949
+ "slug": {
17950
+ "type": "string",
17951
+ "description": "\uD504\uB85C\uC81D\uD2B8 \uC2AC\uB7EC\uADF8(list_projects)"
17952
+ },
17953
+ "cut_id": {
17954
+ "type": "string",
17955
+ "description": "\uCEF7 id(cut_\u2026)"
17956
+ },
17957
+ "version": {
17958
+ "type": "string",
17959
+ "description": "\uBC84\uC804 \uBC88\uD638(1\uBD80\uD130)"
17960
+ },
17961
+ "kind": {
17962
+ "default": "video",
17963
+ "enum": [
17964
+ "video",
17965
+ "audio",
17966
+ "subtitle",
17967
+ "still"
17968
+ ],
17969
+ "title": "Kind",
17970
+ "type": "string"
17971
+ },
17972
+ "output_path": {
17973
+ "type": "string",
17974
+ "description": "\uC800\uC7A5\uD560 \uB85C\uCEEC \uACBD\uB85C(stdio \uC804\uC6A9). \uC5C6\uC73C\uBA74 URL \uB9CC \uB3CC\uB824\uC900\uB2E4"
17975
+ }
17976
+ },
17977
+ "required": [
17978
+ "slug",
17979
+ "cut_id",
17980
+ "version"
17981
+ ],
17982
+ "additionalProperties": false
17983
+ },
17984
+ "annotations": {
17985
+ "readOnlyHint": true,
17986
+ "destructiveHint": false,
17987
+ "idempotentHint": true,
17988
+ "openWorldHint": false
17989
+ }
17990
+ },
17991
+ {
17992
+ "name": "democut_import_cut",
17993
+ "description": "\uC0AC\uC6A9\uC790\uAC00 \uB9CC\uB4E0 \uC644\uC131 \uCEF7 \uC601\uC0C1\uC744 0\uC6D0 \uBC84\uC804\uC73C\uB85C \uB4F1\uB85D\uD55C\uB2E4(S3: \uC7AC\uB8CC\uB294 \uB0B4\uAC00, \uC870\uB9BD\uC740 DemoCut). transcribe=true \uBA74 \uC790\uB9C9 \uC804\uC0AC \uD589\uB9CC \uCCAD\uAD6C(democut_estimate_cuts \uC758 imports \uB85C \uBA3C\uC800 \uBCF8\uB2E4). \uC751\uB2F5\uC740 202 \u2014 \uACB0\uACFC\uB294 democut_wait_jobs \uB85C \uBC1B\uB294\uB2E4. \uB2E4\uC74C \uD638\uCD9C: democut_wait_jobs, democut_get_cut.",
17994
+ "inputSchema": {
17995
+ "type": "object",
17996
+ "properties": {
17997
+ "slug": {
17998
+ "type": "string",
17999
+ "description": "\uD504\uB85C\uC81D\uD2B8 \uC2AC\uB7EC\uADF8(list_projects)"
18000
+ },
18001
+ "cut_id": {
18002
+ "type": "string",
18003
+ "description": "\uCEF7 id(cut_\u2026)"
18004
+ },
18005
+ "video_asset_id": {
18006
+ "title": "Video Asset Id",
18007
+ "type": "string"
18008
+ },
18009
+ "dialogue": {
18010
+ "anyOf": [
18011
+ {
18012
+ "items": {
18013
+ "additionalProperties": true,
18014
+ "type": "object"
18015
+ },
18016
+ "type": "array"
18017
+ },
18018
+ {
18019
+ "type": "null"
18020
+ }
18021
+ ],
18022
+ "default": null,
18023
+ "description": "[{id?, text}] \u2014 \uC790\uB9C9\xB7\uD0C0\uC774\uBC0D \uADFC\uAC70",
18024
+ "title": "Dialogue"
18025
+ },
18026
+ "transcribe": {
18027
+ "default": false,
18028
+ "description": "True \uBA74 asr:transcribe \uD589 \uCCAD\uAD6C",
18029
+ "title": "Transcribe",
18030
+ "type": "boolean"
18031
+ },
18032
+ "confirmed_total_krw": {
18033
+ "default": 0,
18034
+ "minimum": 0,
18035
+ "title": "Confirmed Total Krw",
18036
+ "type": "integer"
18037
+ },
18038
+ "rate_version": {
18039
+ "anyOf": [
18040
+ {
18041
+ "type": "integer"
18042
+ },
18043
+ {
18044
+ "type": "null"
18045
+ }
18046
+ ],
18047
+ "default": null,
18048
+ "title": "Rate Version"
18049
+ }
18050
+ },
18051
+ "required": [
18052
+ "slug",
18053
+ "cut_id",
18054
+ "video_asset_id"
18055
+ ],
18056
+ "additionalProperties": false
18057
+ },
18058
+ "annotations": {
18059
+ "readOnlyHint": false,
18060
+ "destructiveHint": false,
18061
+ "idempotentHint": false,
18062
+ "openWorldHint": false
18063
+ }
18064
+ },
18065
+ {
18066
+ "name": "democut_cancel_job",
18067
+ "description": "\uC7A1\uC744 \uCDE8\uC18C\uD55C\uB2E4. queued \uB294 \uC989\uC2DC \uD658\uBD88, running \uC740 \uC2E4\uD589\uAE30\uAC00 1\uCD08 \uC548\uC5D0 \uBA48\uCD94\uACE0 \uC815\uC0B0(\uACF5\uAE09\uC790\uAC00 \uACFC\uAE08\uD55C \uD589\uC740 \uBE44\uD658\uBD88). AI \uC601\uC0C1\uC740 \uACF5\uAE09\uC790 \uC81C\uCD9C \uB4A4 \uCDE8\uC18C \uBD88\uAC00(409 NOT_CANCELLABLE).",
18068
+ "inputSchema": {
18069
+ "type": "object",
18070
+ "properties": {
18071
+ "job_id": {
18072
+ "type": "string",
18073
+ "description": "\uC7A1 id(job_\u2026)"
18074
+ }
18075
+ },
18076
+ "required": [
18077
+ "job_id"
18078
+ ],
18079
+ "additionalProperties": false
18080
+ },
18081
+ "annotations": {
18082
+ "readOnlyHint": false,
18083
+ "destructiveHint": true,
18084
+ "idempotentHint": true,
18085
+ "openWorldHint": false
18086
+ }
18087
+ },
18088
+ {
18089
+ "name": "democut_credit_balance",
18090
+ "description": "\uB0B4 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uC758 \uD06C\uB808\uB527 \uC794\uC561. \uBD80\uC791\uC6A9\uB3C4 \uACFC\uAE08\uB3C4 \uC5C6\uB2E4. \uB3C8\uC774 \uB098\uAC00\uB294 \uC791\uC5C5(democut_make_cuts \uB4F1)\uC744 \uC81C\uCD9C\uD558\uAE30 **\uC804\uC5D0** \uD655\uC778\uD558\uB77C \u2014 \uBD80\uC871\uD558\uBA74 \uC81C\uCD9C\uC774 402 \uB85C \uAC70\uBD80\uB418\uACE0, \uADF8\uAC83\uC744 \uBBF8\uB9AC \uC544\uB294 \uD3B8\uC774 \uB0AB\uB2E4(democut_estimate_cuts \uC758 can_afford \uAC00 \uC788\uC73C\uBA74 \uB9E4\uBC88 \uBD80\uB97C \uD544\uC694\uB294 \uC5C6\uB2E4). \uBAA8\uC790\uB77C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC54C\uB9AC\uACE0 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uAD00\uB9AC\uC790\uC5D0\uAC8C \uCDA9\uC804\uC744 \uC694\uCCAD\uD558\uB3C4\uB85D \uC548\uB0B4\uD558\uB77C \u2014 \uB124\uAC00 \uC9C1\uC811 \uCDA9\uC804\uD560 \uC218\uB294 \uC5C6\uB2E4.",
18091
+ "inputSchema": {
18092
+ "type": "object",
18093
+ "properties": {},
18094
+ "required": [],
18095
+ "additionalProperties": false
18096
+ },
18097
+ "annotations": {
18098
+ "readOnlyHint": true,
18099
+ "destructiveHint": false,
18100
+ "idempotentHint": true,
18101
+ "openWorldHint": false
18102
+ }
18103
+ },
18104
+ {
18105
+ "name": "democut_credit_ledger",
18106
+ "description": "\uD06C\uB808\uB527 \uC0AC\uC6A9 \uB0B4\uC5ED(\uCD5C\uC2E0\uC21C, keyset). \u300C\uC65C \uC794\uC561\uC774 \uC774\uB9CC\uD07C \uC904\uC5C8\uB098\u300D \uB97C \uB2F5\uD560 \uB54C \uC4F4\uB2E4 \u2014 \uD589\uB9C8\uB2E4 \uBB34\uC5C7\uC5D0\xB7\uC5B8\uC81C\xB7\uC5BC\uB9C8\uC778\uC9C0\uAC00 \uC788\uB2E4.",
18107
+ "inputSchema": {
18108
+ "type": "object",
18109
+ "properties": {
18110
+ "cursor": {
18111
+ "anyOf": [
18112
+ {
18113
+ "type": "string"
18114
+ },
18115
+ {
18116
+ "type": "null"
18117
+ }
18118
+ ],
18119
+ "default": null,
18120
+ "title": "Cursor"
18121
+ },
18122
+ "limit": {
18123
+ "default": 50,
18124
+ "maximum": 200,
18125
+ "minimum": 1,
18126
+ "title": "Limit",
18127
+ "type": "integer"
18128
+ }
18129
+ },
18130
+ "required": [],
18131
+ "additionalProperties": false
18132
+ },
18133
+ "annotations": {
18134
+ "readOnlyHint": true,
18135
+ "destructiveHint": false,
18136
+ "idempotentHint": true,
18137
+ "openWorldHint": false
18138
+ }
18139
+ }
18140
+ ];
18141
+
18142
+ // src/api-errors.ts
18143
+ var TOOL_BASE_NAMES = GENERATED_TOOLS.map((t) => t.name.replace(/^democut_/, "")).sort((a, b) => b.length - a.length);
18144
+ var escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
18145
+ var NAME_PATTERNS = TOOL_BASE_NAMES.map((name) => [
18146
+ new RegExp(`(?<!democut_)(?<![\\w.])${escapeRe(name)}(?![\\w{(])`, "g"),
18147
+ `democut_${name}`
18148
+ ]);
18149
+ function callableToolNames(text) {
18150
+ let out2 = text;
18151
+ for (const [re, replacement] of NAME_PATTERNS) out2 = out2.replace(re, replacement);
18152
+ return out2;
18153
+ }
18154
+ function usd(v) {
18155
+ return v < 0.01 ? `$${v.toFixed(4)}` : `$${v.toFixed(2)}`;
18156
+ }
18157
+ function classifyApiError(e, ctx) {
18158
+ const hint = ctx.statusHint ?? "\uC0C1\uD0DC \uC870\uD68C";
18159
+ const contractHint = typeof e.extra.hint === "string" ? callableToolNames(e.extra.hint) : null;
18160
+ if (contractHint) {
18161
+ const lines = [contractHint];
18162
+ if (ctx.submitted) {
18163
+ lines.push(
18164
+ e.status < 500 ? "\uC544\uC9C1 \uC544\uBB34\uAC83\uB3C4 \uC81C\uCD9C\uB418\uC9C0 \uC54A\uC558\uACE0 \uACFC\uAE08\uB3C4 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uC694\uCCAD\uC744 \uACE0\uCCD0 \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694." : `\u26A0\uFE0F \uC81C\uCD9C\uC774 \uC811\uC218\uB410\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uB2E4\uC2DC \uBCF4\uB0B4\uC9C0 \uB9D0\uACE0 ${hint} \uB85C \uC0C1\uD0DC\uB97C \uBA3C\uC800 \uD655\uC778\uD558\uC138\uC694.`
18165
+ );
18166
+ }
18167
+ return {
18168
+ safety: e.status >= 500 && ctx.submitted ? "unsafe" : e.retriable === false ? "fixable" : "safe",
18169
+ notCharged: e.status < 500,
18170
+ lines
18171
+ };
18172
+ }
18173
+ if (e.status === 422 && e.code === "VIDEOGEN_UPSTREAM_REJECTED") {
18174
+ return {
18175
+ safety: "unsafe",
18176
+ // 돈이 나갔다가 돌아왔다 — "애초에 과금이 없었다" 와는 다르다. 그 구분을 흐리면
18177
+ // 원장을 보는 사람이 이 거래를 설명하지 못한다.
18178
+ notCharged: false,
18179
+ lines: [
18180
+ "\uC5C5\uC2A4\uD2B8\uB9BC\uC774 \uC774 \uC791\uC5C5\uC744 \uC601\uAD6C \uAC70\uBD80\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC870\uD68C\uD574\uB3C4 \uBCF5\uAD6C\uB418\uC9C0 \uC54A\uC73C\uBA70, \uACFC\uAE08\uC740 \uD658\uBD88\uB410\uC2B5\uB2C8\uB2E4.",
18181
+ "\uACE0\uCE60 \uD30C\uB77C\uBBF8\uD130\uAC00 \uC788\uB294 \uC624\uB958\uAC00 \uC544\uB2D9\uB2C8\uB2E4 \u2014 \uC0C8\uB85C \uB9CC\uB4E4\uB824\uBA74 \uD504\uB86C\uD504\uD2B8\xB7\uC124\uC815\uC744 \uBC14\uAFD4 **\uC0C8\uB85C \uC81C\uCD9C**\uD574\uC57C \uD558\uACE0, \uADF8\uAC74 \uB2E4\uC2DC \uACFC\uAE08\uB429\uB2C8\uB2E4(\uC0AC\uC6A9\uC790 \uB3D9\uC758\uB97C \uBC1B\uC73C\uC138\uC694)."
18182
+ ]
18183
+ };
18184
+ }
18185
+ if (e.status === 404 && e.code === "VIDEOGEN_JOB_NOT_FOUND") {
18186
+ return {
18187
+ safety: "unsafe",
18188
+ notCharged: false,
18189
+ lines: [
18190
+ "\uADF8 \uC791\uC5C5\uC744 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. job_id \uAC00 \uB9DE\uB294\uC9C0 \uBA3C\uC800 \uD655\uC778\uD558\uC138\uC694.",
18191
+ "\u26A0\uFE0F \uC791\uC5C5\uC774 \uC0B4\uC544 \uC788\uB294\uB370 \uC870\uD68C\uB9CC \uC5B4\uAE0B\uB0AC\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uC0C8\uB85C \uC81C\uCD9C\uD558\uBA74 **\uBCC4\uB3C4 \uC791\uC5C5\uC73C\uB85C \uB2E4\uC2DC \uACFC\uAE08**\uB429\uB2C8\uB2E4."
18192
+ ]
18193
+ };
18194
+ }
18195
+ if (e.status === 402) {
18196
+ const lines = [];
18197
+ const limit = e.extra.limit_usd;
18198
+ const would = e.extra.would_cost_usd;
18199
+ if (typeof limit === "number" && typeof would === "number") {
18200
+ lines.push(`\uC0C1\uD55C ${usd(limit)} \xB7 \uC774 \uC694\uCCAD ${usd(would)}`);
18201
+ }
18202
+ lines.push("\uD574\uC0C1\uB3C4\uB098 \uAE38\uC774\uB97C \uB0AE\uCDB0 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694. \uC544\uC9C1 \uACFC\uAE08\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
18203
+ return { safety: "fixable", notCharged: true, lines };
18204
+ }
18205
+ if (e.status === 422) {
18206
+ return {
18207
+ safety: "fixable",
18208
+ notCharged: true,
18209
+ lines: ["\uD30C\uB77C\uBBF8\uD130\uB97C \uACE0\uCCD0 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694. \uC544\uC9C1 \uACFC\uAE08\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4."]
18210
+ };
18211
+ }
18212
+ if (e.status === 503) {
18213
+ return {
18214
+ safety: "safe",
18215
+ notCharged: true,
18216
+ lines: ["\uC77C\uC2DC\uC801\uC778 \uC624\uB958\uC785\uB2C8\uB2E4. \uC7A0\uC2DC \uD6C4 \uADF8\uB300\uB85C \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uB3C4 \uC548\uC804\uD569\uB2C8\uB2E4."]
18217
+ };
18218
+ }
18219
+ if (e.status === 502) {
18220
+ return ctx.submitted ? {
18221
+ safety: "unsafe",
18222
+ notCharged: false,
18223
+ lines: [
18224
+ "\u26A0\uFE0F \uC81C\uCD9C\uC774 \uC774\uBBF8 \uC811\uC218\uB410\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC81C\uCD9C\uD558\uBA74 \uB450 \uBC88 \uACFC\uAE08\uB429\uB2C8\uB2E4 \u2014",
18225
+ `\uC7AC\uC2DC\uB3C4\uD558\uC9C0 \uB9D0\uACE0 ${hint} \uB85C \uD655\uC778\uD558\uAC70\uB098 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBB38\uC758\uD558\uC138\uC694.`
18226
+ ]
18227
+ } : {
18228
+ safety: "safe",
18229
+ notCharged: true,
18230
+ lines: [
18231
+ "\uC5C5\uC2A4\uD2B8\uB9BC \uC624\uB958\uC785\uB2C8\uB2E4. \uC774 \uC694\uCCAD\uC740 \uBD80\uC791\uC6A9\uC774 \uC5C6\uC73C\uBBC0\uB85C \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uB3C4 \uC548\uC804\uD569\uB2C8\uB2E4."
18232
+ ]
18233
+ };
18234
+ }
18235
+ if (e.status === 404) {
18236
+ const lines = [];
18237
+ if (e.code === "VIDEOGEN_PROJECT_NOT_FOUND") {
18238
+ lines.push(
18239
+ "democut_list_projects \uB85C \uC774 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uC758 \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D\uC744 \uD655\uC778\uD558\uACE0 \uADF8\uC911 \uD558\uB098\uC758 \uC2AC\uB7EC\uADF8\uB97C \uC4F0\uC138\uC694. \uBAA9\uB85D\uC774 \uBE44\uC5B4 \uC788\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uD504\uB85C\uC81D\uD2B8\uB97C \uBA3C\uC800 \uB9CC\uB4E4\uC5B4 \uB2EC\uB77C\uACE0 \uC54C\uB9AC\uC138\uC694."
18240
+ );
18241
+ }
18242
+ lines.push("\uC544\uC9C1 \uACFC\uAE08\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4 \u2014 \uAC12\uC744 \uACE0\uCCD0 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.");
18243
+ return { safety: "fixable", notCharged: true, lines };
18244
+ }
18245
+ if (e.status === 403) {
18246
+ return {
18247
+ safety: "unknown",
18248
+ notCharged: true,
18249
+ lines: ["\uC774 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uC5D0\uC11C \uC601\uC0C1\uC744 \uC0DD\uC131\uD560 \uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(\uBA64\uBC84 \uC774\uC0C1 \uD544\uC694)."]
18250
+ };
18251
+ }
18252
+ return { safety: "unknown", notCharged: false, lines: [] };
18253
+ }
18254
+
18255
+ // src/mcp/tools.ts
18256
+ import { createWriteStream, existsSync as existsSync2 } from "fs";
18257
+ import { readFile } from "fs/promises";
18258
+ import { basename } from "path";
18259
+ import { Readable } from "stream";
18260
+ import { pipeline as streamPipeline } from "stream/promises";
18261
+
18262
+ // src/api-client.ts
18263
+ var ApiError = class extends Error {
18264
+ constructor(status, code, message, retriable, extra = {}) {
18265
+ super(message);
18266
+ this.status = status;
18267
+ this.code = code;
18268
+ this.retriable = retriable;
18269
+ this.extra = extra;
18270
+ this.name = "ApiError";
18271
+ }
18272
+ status;
18273
+ code;
18274
+ retriable;
18275
+ extra;
18276
+ };
18277
+ function parseDetail(status, body) {
18278
+ const wrapped = body?.error;
18279
+ if (wrapped && typeof wrapped === "object" && !Array.isArray(wrapped)) {
18280
+ const w = wrapped;
18281
+ if (typeof w.code === "string") {
18282
+ const data = w.data && typeof w.data === "object" ? w.data : {};
18283
+ return new ApiError(
18284
+ status,
18285
+ w.code,
18286
+ typeof w.message === "string" ? w.message : `HTTP ${status}`,
18287
+ typeof w.retry_safe === "boolean" ? w.retry_safe : null,
18288
+ { ...data, ...typeof w.hint === "string" ? { hint: w.hint } : {} }
18289
+ );
18290
+ }
18291
+ }
18292
+ const detail = body?.detail;
18293
+ if (detail && typeof detail === "object" && !Array.isArray(detail)) {
18294
+ const d = detail;
18295
+ if (typeof d.code === "string" || typeof d.message === "string") {
18296
+ const { code, message, retriable, ...extra } = d;
18297
+ return new ApiError(
18298
+ status,
18299
+ typeof code === "string" ? code : `HTTP_${status}`,
18300
+ typeof message === "string" ? message : `HTTP ${status}`,
18301
+ typeof retriable === "boolean" ? retriable : null,
18302
+ extra
18303
+ );
18304
+ }
18305
+ }
18306
+ if (typeof detail === "string") {
18307
+ return new ApiError(status, `HTTP_${status}`, detail, null);
18308
+ }
18309
+ if (Array.isArray(detail)) {
18310
+ const lines = detail.map((e) => {
18311
+ const item = e;
18312
+ const where = Array.isArray(item.loc) ? item.loc.filter((p) => p !== "body").join(".") : "";
18313
+ const msg = typeof item.msg === "string" ? item.msg : JSON.stringify(e);
18314
+ return where ? `${where}: ${msg}` : msg;
18315
+ });
18316
+ return new ApiError(status, "VALIDATION_ERROR", lines.join("\n"), true);
18317
+ }
18318
+ return new ApiError(status, `HTTP_${status}`, `\uC694\uCCAD\uC774 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4 (HTTP ${status}).`, null);
18319
+ }
18320
+ async function apiRequest(baseUrl, path, init = {}, deps = {}) {
18321
+ const fetchImpl = deps.fetchImpl ?? fetch;
18322
+ const token = await getValidAccessToken(baseUrl, deps);
18323
+ const headers = {
18324
+ Authorization: `Bearer ${token}`,
18325
+ "User-Agent": `democut/${VERSION}`
18326
+ };
18327
+ if (init.body !== void 0) headers["Content-Type"] = "application/json";
18328
+ const res = await fetchImpl(`${baseUrl}${path}`, {
18329
+ method: init.method ?? "GET",
18330
+ headers,
18331
+ ...init.body === void 0 ? {} : { body: JSON.stringify(init.body) }
18332
+ });
18333
+ const text = await res.text();
18334
+ let json = null;
18335
+ if (text) {
18336
+ try {
18337
+ json = JSON.parse(text);
18338
+ } catch {
18339
+ json = null;
18340
+ }
18341
+ }
18342
+ if (!res.ok) {
18343
+ if (res.status === 401) {
18344
+ throw new ApiError(
18345
+ 401,
18346
+ "UNAUTHENTICATED",
18347
+ "\uC778\uC99D\uC774 \uB9CC\uB8CC\uB418\uC5C8\uAC70\uB098 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. 'democut auth login' \uC73C\uB85C \uB2E4\uC2DC \uB85C\uADF8\uC778\uD558\uC138\uC694.",
18348
+ false
18349
+ );
18350
+ }
18351
+ throw parseDetail(res.status, json);
18352
+ }
18353
+ return json;
18354
+ }
16350
18355
 
16351
18356
  // src/credits.ts
16352
18357
  var LEDGER_MAX_LIMIT = 200;
@@ -16362,7 +18367,7 @@ function balance(baseUrl, workspaceId, deps = {}) {
16362
18367
  function ledger(baseUrl, workspaceId, opts = {}, deps = {}) {
16363
18368
  const q = new URLSearchParams();
16364
18369
  q.set("limit", String(opts.limit ?? LEDGER_DEFAULT_LIMIT));
16365
- if (opts.beforeId !== void 0) q.set("before_id", String(opts.beforeId));
18370
+ if (opts.cursor !== void 0) q.set("cursor", opts.cursor);
16366
18371
  return apiRequest(
16367
18372
  baseUrl,
16368
18373
  `/api/workspaces/${encodeURIComponent(workspaceId)}/credits/ledger?${q}`,
@@ -16381,13 +18386,13 @@ function create(baseUrl, body, deps = {}) {
16381
18386
  return apiRequest(baseUrl, "/api/projects", { method: "POST", body }, deps);
16382
18387
  }
16383
18388
  async function defaultVoiceId(baseUrl, deps = {}) {
16384
- const out3 = await apiRequest(
18389
+ const out2 = await apiRequest(
16385
18390
  baseUrl,
16386
18391
  "/api/projects/voices",
16387
18392
  {},
16388
18393
  deps
16389
18394
  );
16390
- const id = out3.default_voice_id;
18395
+ const id = out2.default_voice_id;
16391
18396
  if (!id) {
16392
18397
  throw new Error("\uC11C\uBC84\uAC00 \uAE30\uBCF8 \uC74C\uC131\uC744 \uC54C\uB824\uC8FC\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4 (default_voice_id \uC5C6\uC74C).");
16393
18398
  }
@@ -16395,10 +18400,6 @@ async function defaultVoiceId(baseUrl, deps = {}) {
16395
18400
  }
16396
18401
 
16397
18402
  // src/mcp/tools.ts
16398
- var COST_TOLERANCE_USD = 5e-3;
16399
- function usd3(v) {
16400
- return v < 0.01 ? `$${v.toFixed(4)}` : `$${v.toFixed(2)}`;
16401
- }
16402
18403
  function describeError2(e, ctx) {
16403
18404
  if (e instanceof NotLoggedInError) {
16404
18405
  return {
@@ -16412,7 +18413,39 @@ function describeError2(e, ctx) {
16412
18413
  }
16413
18414
  return { isError: true, text: `\uC624\uB958: ${e?.message ?? String(e)}` };
16414
18415
  }
16415
- async function guarded2(ctx, fn) {
18416
+ async function saveUrlToFile(url, outPath, fetchImpl = fetch) {
18417
+ const res = await fetchImpl(url);
18418
+ if (!res.ok || !res.body) {
18419
+ throw new Error(`\uB0B4\uB824\uBC1B\uAE30 \uC2E4\uD328: ${res.status} ${res.statusText}`);
18420
+ }
18421
+ await streamPipeline(Readable.fromWeb(res.body), createWriteStream(outPath));
18422
+ }
18423
+ async function uploadFile(base, path, meta2, deps) {
18424
+ const fetchImpl = deps.fetchImpl ?? fetch;
18425
+ const token = await getValidAccessToken(base, deps);
18426
+ const bytes = await readFile(path);
18427
+ const form = new FormData();
18428
+ form.set("kind", meta2.kind);
18429
+ if (meta2.projectSlug) form.set("project_slug", meta2.projectSlug);
18430
+ form.set("file", new Blob([bytes]), meta2.filename ?? basename(path));
18431
+ const res = await fetchImpl(`${base}/api/assets`, {
18432
+ method: "POST",
18433
+ headers: { Authorization: `Bearer ${token}`, "User-Agent": `democut/${VERSION}` },
18434
+ body: form
18435
+ });
18436
+ const text = await res.text();
18437
+ let json = null;
18438
+ if (text) {
18439
+ try {
18440
+ json = JSON.parse(text);
18441
+ } catch {
18442
+ json = null;
18443
+ }
18444
+ }
18445
+ if (!res.ok) throw parseDetail(res.status, json);
18446
+ return json;
18447
+ }
18448
+ async function guarded(ctx, fn) {
16416
18449
  try {
16417
18450
  return await fn();
16418
18451
  } catch (e) {
@@ -16422,10 +18455,10 @@ async function guarded2(ctx, fn) {
16422
18455
  var READ_ONLY = { submitted: false };
16423
18456
  var SUBMITTING = {
16424
18457
  submitted: true,
16425
- statusHint: "democut_get_video_status"
18458
+ statusHint: "democut_credit_ledger"
16426
18459
  };
16427
18460
  function authStatus(deps = {}) {
16428
- return guarded2(READ_ONLY, async () => {
18461
+ return guarded(READ_ONLY, async () => {
16429
18462
  const base = resolveBaseUrl(deps.baseUrl);
16430
18463
  const token = await getValidAccessToken(base, deps);
16431
18464
  const me = await whoami(base, token, deps.fetchImpl);
@@ -16438,162 +18471,6 @@ function authStatus(deps = {}) {
16438
18471
  };
16439
18472
  });
16440
18473
  }
16441
- function toEstimateIn(a) {
16442
- return {
16443
- duration_s: a.duration_s ?? 5,
16444
- resolution: a.resolution ?? "720p",
16445
- ratio: a.ratio ?? "16:9",
16446
- ...a.model ? { model: a.model } : {},
16447
- // ★ 추정과 생성이 **같은 모델 계열**을 봐야 confirmed_cost_usd 대조가 성립한다.
16448
- // 생성 경로는 `image_urls` 를, 추정 전용 호출은 `has_image` 를 준다.
16449
- has_image: Boolean(a.has_image || a.image_urls?.length)
16450
- };
16451
- }
16452
- var MOCK_BANNER = "\u26A0\uFE0F \uC774 \uBC30\uD3EC\uB294 mock \uBAA8\uB4DC\uC785\uB2C8\uB2E4 \u2014 \uC601\uC0C1\uC774 **\uC2E4\uC81C\uB85C \uC0DD\uC131\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4**. \uC544\uB798 \uAE08\uC561\xB7job_id\xB7URL \uC740 \uC804\uBD80 \uAC00\uC9DC\uC774\uBA70 \uC2E4\uC81C\uB85C \uACFC\uAE08\uB418\uC9C0\uB3C4 \uC54A\uC2B5\uB2C8\uB2E4. \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC0DD\uC131\uC774 \uB418\uC5C8\uB2E4\uACE0 \uBCF4\uACE0\uD558\uC9C0 \uB9C8\uC138\uC694.";
16453
- function estimateCost(a, deps = {}) {
16454
- return guarded2(READ_ONLY, async () => {
16455
- const base = resolveBaseUrl(deps.baseUrl);
16456
- const r = await estimate(base, toEstimateIn(a), deps);
16457
- if (r.mock) {
16458
- return {
16459
- text: [
16460
- MOCK_BANNER,
16461
- "",
16462
- `(\uCC38\uACE0\uC6A9 \uCD94\uC815\uCE58: ${usd3(r.cost_usd)} \xB7 ${r.model})`,
16463
- "",
16464
- "\uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBE44\uC6A9 \uB3D9\uC758\uB97C \uAD6C\uD558\uC9C0 \uB9C8\uC138\uC694 \u2014 \uC774 \uBC30\uD3EC\uC5D0\uC11C\uB294 \uC81C\uCD9C\uD574\uB3C4 \uC2E4\uC81C \uC601\uC0C1\uC774 \uB9CC\uB4E4\uC5B4\uC9C0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC6B4\uC601\uC790\uC5D0\uAC8C API \uD0A4 \uC124\uC815\uC744 \uC694\uCCAD\uD558\uC138\uC694."
16465
- ].join("\n")
16466
- };
16467
- }
16468
- return {
16469
- text: [
16470
- `\uC608\uC0C1 \uBE44\uC6A9: ${usd3(r.cost_usd)} (${r.tokens.toLocaleString()} tokens \xB7 ${r.model})`,
16471
- `cost_usd \uC6D0\uAC12: ${r.cost_usd}`,
16472
- "",
16473
- `\uC0DD\uC131\uD558\uB824\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC774 \uAE08\uC561\uC744 \uC54C\uB9AC\uACE0 \uB3D9\uC758\uB97C \uBC1B\uC740 \uB4A4, generate_video \uC5D0 confirmed_cost_usd=${r.cost_usd} \uB97C \uADF8\uB300\uB85C \uB123\uC5B4 \uD638\uCD9C\uD558\uC138\uC694.`
16474
- ].join("\n")
16475
- };
16476
- });
16477
- }
16478
- function generateVideo(a, deps = {}) {
16479
- return guarded2(SUBMITTING, async () => {
16480
- if (!a.prompt?.trim()) {
16481
- return { isError: true, text: "prompt \uAC00 \uBE44\uC5B4 \uC788\uC2B5\uB2C8\uB2E4." };
16482
- }
16483
- if (typeof a.project_slug !== "string" || !a.project_slug.trim()) {
16484
- return {
16485
- isError: true,
16486
- text: "project_slug \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \uBE44\uC6A9\uC744 \uADC0\uC18D\uC2DC\uD0AC \uBCF8\uC778 \uC18C\uC720 \uD504\uB85C\uC81D\uD2B8\uC758 \uC2AC\uB7EC\uADF8\uB97C \uB123\uC5B4 \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694. \uC544\uC9C1 \uACFC\uAE08\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.\n\uC2AC\uB7EC\uADF8\uB97C \uBAA8\uB974\uBA74 democut_list_projects \uB85C \uC774 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uC758 \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D\uC744 \uD655\uC778\uD558\uC138\uC694. \uBAA9\uB85D\uC774 \uBE44\uC5B4 \uC788\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uD504\uB85C\uC81D\uD2B8\uB97C \uBA3C\uC800 \uB9CC\uB4E4\uC5B4 \uB2EC\uB77C\uACE0 \uC54C\uB9AC\uC138\uC694."
16487
- };
16488
- }
16489
- const base = resolveBaseUrl(deps.baseUrl);
16490
- const est = toEstimateIn(a);
16491
- const quote = await estimate(base, est, deps);
16492
- if (typeof a.confirmed_cost_usd !== "number") {
16493
- return {
16494
- isError: true,
16495
- text: `confirmed_cost_usd \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \uC774 \uC694\uCCAD\uC758 \uC608\uC0C1 \uBE44\uC6A9\uC740 ${usd3(quote.cost_usd)} (\uC6D0\uAC12 ${quote.cost_usd}) \uC785\uB2C8\uB2E4. \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC54C\uB9AC\uACE0 \uB3D9\uC758\uB97C \uBC1B\uC740 \uB4A4 \uADF8 \uAC12\uC744 \uB123\uC5B4 \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694.`
16496
- };
16497
- }
16498
- if (Math.abs(a.confirmed_cost_usd - quote.cost_usd) > COST_TOLERANCE_USD) {
16499
- return {
16500
- isError: true,
16501
- text: `\uD655\uC778\uD55C \uAE08\uC561(${usd3(a.confirmed_cost_usd)})\uC774 \uC2E4\uC81C \uC608\uC0C1 \uBE44\uC6A9(${usd3(quote.cost_usd)})\uACFC \uB2E4\uB985\uB2C8\uB2E4. \uD30C\uB77C\uBBF8\uD130\uAC00 \uADF8 \uC0AC\uC774 \uBC14\uB00C\uC5C8\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4. estimate_video_cost \uB97C \uB2E4\uC2DC \uD638\uCD9C\uD574 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC0C8 \uAE08\uC561\uC744 \uD655\uC778\uBC1B\uC73C\uC138\uC694. \uC544\uC9C1 \uACFC\uAE08\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`
16502
- };
16503
- }
16504
- const body = {
16505
- prompt: a.prompt,
16506
- duration_s: est.duration_s,
16507
- resolution: est.resolution,
16508
- ratio: est.ratio,
16509
- generate_audio: Boolean(a.generate_audio),
16510
- watermark: Boolean(a.watermark),
16511
- ...a.model ? { model: a.model } : {},
16512
- ...a.seed !== void 0 ? { seed: a.seed } : {},
16513
- ...a.image_urls?.length ? { image_urls: a.image_urls } : {},
16514
- project_slug: a.project_slug.trim()
16515
- };
16516
- const job = await submit(base, body, deps);
16517
- if (job.duplicate) {
16518
- return {
16519
- text: job.pending ? "\uAC19\uC740 \uC694\uCCAD\uC774 \uBC29\uAE08 \uC81C\uCD9C\uB418\uC5B4 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4. job_id \uAC00 \uC544\uC9C1 \uC5C6\uC73C\uB2C8 \uC7A0\uC2DC \uD6C4 \uAC19\uC740 \uD30C\uB77C\uBBF8\uD130\uB85C \uB2E4\uC2DC \uD638\uCD9C\uD558\uC9C0 \uB9D0\uACE0 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC54C\uB9AC\uC138\uC694(\uC0C8\uB85C \uB9CC\uB4E4\uBA74 \uB2E4\uC2DC \uACFC\uAE08\uB429\uB2C8\uB2E4)." : `\uAC19\uC740 \uC694\uCCAD\uC774 \uC774\uBBF8 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4 (job_id: ${job.job_id}). \uC0C8\uB85C \uACFC\uAE08\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. get_video_status \uB85C \uD655\uC778\uD558\uC138\uC694.`
16520
- };
16521
- }
16522
- if (job.mock) {
16523
- return {
16524
- text: [
16525
- MOCK_BANNER,
16526
- "",
16527
- `(\uAC00\uC9DC job_id: ${job.job_id} \xB7 \uBAA8\uB378 ${job.model})`,
16528
- "",
16529
- "\uC2E4\uC81C\uB85C \uC81C\uCD9C\uB418\uC9C0 \uC54A\uC558\uACE0 \uACFC\uAE08\uB3C4 \uC5C6\uC2B5\uB2C8\uB2E4. \uC774 job_id \uB85C \uC0C1\uD0DC\uB97C \uC870\uD68C\uD558\uBA74 \uAC00\uC9DC URL \uC774 \uB098\uC635\uB2C8\uB2E4 \u2014 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC601\uC0C1\uC774 \uB9CC\uB4E4\uC5B4\uC84C\uB2E4\uACE0 \uB9D0\uD558\uC9C0 \uB9C8\uC138\uC694."
16530
- ].join("\n")
16531
- };
16532
- }
16533
- return {
16534
- text: [
16535
- `\uC81C\uCD9C\uB428 \u2014 job_id: ${job.job_id}`,
16536
- `\uC608\uC0C1 \uBE44\uC6A9 ${usd3(job.estimated_cost_usd)} \xB7 \uBAA8\uB378 ${job.model}`,
16537
- "",
16538
- "\uC0DD\uC131\uC5D0\uB294 \uBCF4\uD1B5 90\uCD08 \uC774\uC0C1 \uAC78\uB9BD\uB2C8\uB2E4. get_video_status \uB85C \uD655\uC778\uD558\uC138\uC694.",
16539
- "\u26A0\uFE0F \uC2E4\uD328\uD574 \uBCF4\uC5EC\uB3C4 \uB2E4\uC2DC \uC81C\uCD9C\uD558\uC9C0 \uB9C8\uC138\uC694 \u2014 \uC7AC\uC81C\uCD9C\uC740 \uBCC4\uAC1C \uC0DD\uC131\uC774\uB77C \uB2E4\uC2DC \uACFC\uAE08\uB429\uB2C8\uB2E4."
16540
- ].join("\n")
16541
- };
16542
- });
16543
- }
16544
- function videoStatus(a, deps = {}) {
16545
- return guarded2(READ_ONLY, async () => {
16546
- if (!a.job_id?.trim()) return { isError: true, text: "job_id \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4." };
16547
- const base = resolveBaseUrl(deps.baseUrl);
16548
- const job = await status(base, a.job_id, a.project_slug, deps);
16549
- if (job.mock) {
16550
- return {
16551
- text: [
16552
- MOCK_BANNER,
16553
- "",
16554
- `(\uAC00\uC9DC \uC0C1\uD0DC: ${job.status} \xB7 \uAC00\uC9DC \uACB0\uACFC: ${job.video_url ?? "\uC5C6\uC74C"})`,
16555
- "",
16556
- "\uC774 URL \uC740 \uC2E4\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uB0B4\uB824\uBC1B\uC9C0 \uC54A\uC558\uACE0, \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC804\uB2EC\uD558\uC9C0 \uB9C8\uC138\uC694. \uC644\uB8CC\uB97C \uAE30\uB2E4\uB9AC\uBA70 \uB2E4\uC2DC \uC870\uD68C\uD558\uC9C0\uB3C4 \uB9C8\uC138\uC694."
16557
- ].join("\n")
16558
- };
16559
- }
16560
- if (job.status === "failed" || job.status === "cancelled") {
16561
- return {
16562
- isError: true,
16563
- text: `\uC0DD\uC131 \uC2E4\uD328 (${job.status}): ${job.error ?? "\uC0AC\uC720 \uBBF8\uC0C1"}`
16564
- };
16565
- }
16566
- if (job.status !== "succeeded") {
16567
- return { text: `\uC544\uC9C1 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4 (${job.status}). \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.` };
16568
- }
16569
- const lines = [`\uC644\uB8CC \u2014 ${job.status}`];
16570
- if (job.cost_usd != null) {
16571
- lines.push(
16572
- `\uC2E4\uC81C \uBE44\uC6A9 ${usd3(job.cost_usd)}${job.tokens != null ? ` (${job.tokens.toLocaleString()} tokens)` : ""}`
16573
- );
16574
- }
16575
- if (job.video_url && a.output_path) {
16576
- if (existsSync2(a.output_path)) {
16577
- lines.push(`\uC800\uC7A5\uD558\uC9C0 \uC54A\uC74C: ${a.output_path} \uC5D0 \uC774\uBBF8 \uD30C\uC77C\uC774 \uC788\uC2B5\uB2C8\uB2E4(\uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4).`);
16578
- lines.push(`URL: ${job.video_url}`);
16579
- lines.push("\uB2E4\uB978 \uACBD\uB85C\uB97C \uC9C0\uC815\uD558\uAC70\uB098 \uC704 URL \uB85C \uC9C1\uC811 \uBC1B\uC73C\uC138\uC694 \u2014 \uC11C\uBC84\uB294 \uBCF4\uAD00\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
16580
- return { text: lines.join("\n") };
16581
- }
16582
- try {
16583
- await (deps.downloadImpl ?? download)(job.video_url, a.output_path);
16584
- lines.push(`\uC800\uC7A5\uB428: ${a.output_path}`);
16585
- } catch (e) {
16586
- lines.push(`\uB0B4\uB824\uBC1B\uAE30 \uC2E4\uD328: ${e?.message ?? String(e)}`);
16587
- lines.push(`URL: ${job.video_url}`);
16588
- lines.push("\u26A0\uFE0F \uC704 URL \uB85C \uC9C1\uC811 \uBC1B\uC73C\uC138\uC694 \u2014 \uC11C\uBC84\uB294 \uBCF4\uAD00\uD558\uC9C0 \uC54A\uC73C\uBA70 \uB2E4\uC2DC \uB9CC\uB4E4\uBA74 \uB610 \uACFC\uAE08\uB429\uB2C8\uB2E4.");
16589
- }
16590
- } else if (job.video_url) {
16591
- lines.push(`URL: ${job.video_url}`);
16592
- lines.push("\u26A0\uFE0F \uC11C\uBC84\uB294 \uC774 \uC0B0\uCD9C\uBB3C\uC744 \uBCF4\uAD00\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2014 output_path \uB97C \uC8FC\uBA74 \uBC14\uB85C \uC800\uC7A5\uD569\uB2C8\uB2E4.");
16593
- }
16594
- return { text: lines.join("\n") };
16595
- });
16596
- }
16597
18474
  var krw = (v) => `${v.toLocaleString("ko-KR")}\uC6D0`;
16598
18475
  var NO_WORKSPACE = {
16599
18476
  isError: true,
@@ -16605,7 +18482,7 @@ async function resolveWorkspace(base, deps) {
16605
18482
  return me.workspace_id ?? null;
16606
18483
  }
16607
18484
  function creditBalance(deps = {}) {
16608
- return guarded2(READ_ONLY, async () => {
18485
+ return guarded(READ_ONLY, async () => {
16609
18486
  const base = resolveBaseUrl(deps.baseUrl);
16610
18487
  const ws = await resolveWorkspace(base, deps);
16611
18488
  if (!ws) return NO_WORKSPACE;
@@ -16630,46 +18507,53 @@ function creditBalance(deps = {}) {
16630
18507
  );
16631
18508
  } else {
16632
18509
  lines.push(
16633
- "\uB3C8\uC774 \uB098\uAC00\uB294 \uC791\uC5C5 \uC804\uC5D0 democut_estimate_video_cost \uB85C \uAE08\uC561\uC744 \uD655\uC778\uD558\uACE0 \uC774 \uC794\uC561\uACFC \uACAC\uC8FC\uC138\uC694. \uD06C\uB808\uB527\uC740 \uC6D0(KRW)\uC774\uACE0 \uACAC\uC801\uC740 USD \uB77C \uB2E8\uC704\uAC00 \uB2E4\uB985\uB2C8\uB2E4 \u2014 \uD655\uC2E4\uD558\uC9C0 \uC54A\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uB450 \uAC12\uC744 \uADF8\uB300\uB85C \uBCF4\uC5EC \uC8FC\uC138\uC694."
18510
+ "\uB3C8\uC774 \uB098\uAC00\uB294 \uC791\uC5C5 \uC804\uC5D0 \uACAC\uC801 \uB3C4\uAD6C(S1 \uC5D0\uC11C \uC81C\uACF5)\uB85C \uAE08\uC561\uC744 \uD655\uC778\uD558\uACE0 \uC774 \uC794\uC561\uACFC \uACAC\uC8FC\uC138\uC694. \uD06C\uB808\uB527\uC740 \uC6D0(KRW)\uC774\uACE0 \uACAC\uC801\uC740 USD \uB77C \uB2E8\uC704\uAC00 \uB2E4\uB985\uB2C8\uB2E4 \u2014 \uD655\uC2E4\uD558\uC9C0 \uC54A\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uB450 \uAC12\uC744 \uADF8\uB300\uB85C \uBCF4\uC5EC \uC8FC\uC138\uC694."
16634
18511
  );
16635
18512
  }
16636
18513
  return { text: lines.join("\n") };
16637
18514
  });
16638
18515
  }
18516
+ function nextPage(out2) {
18517
+ if (out2.next_cursor != null) return out2.next_cursor;
18518
+ return out2.next_before_id != null ? String(out2.next_before_id) : null;
18519
+ }
16639
18520
  function creditLedger(a = {}, deps = {}) {
16640
- return guarded2(READ_ONLY, async () => {
18521
+ return guarded(READ_ONLY, async () => {
16641
18522
  if (a.limit !== void 0 && !Number.isFinite(a.limit)) {
16642
18523
  return { isError: true, text: `limit \uC740 \uC22B\uC790\uC5EC\uC57C \uD569\uB2C8\uB2E4: ${JSON.stringify(a.limit)}` };
16643
18524
  }
16644
- if (a.before_id !== void 0 && !Number.isFinite(a.before_id)) {
18525
+ const pageKey = a.cursor !== void 0 ? "cursor" : "before_id";
18526
+ const rawPage = a.cursor !== void 0 ? a.cursor : a.before_id;
18527
+ const pageNum = rawPage === void 0 ? void 0 : Number(rawPage);
18528
+ if (pageNum !== void 0 && (!Number.isFinite(pageNum) || typeof rawPage === "boolean")) {
16645
18529
  return {
16646
18530
  isError: true,
16647
- text: `before_id \uB294 \uC22B\uC790\uC5EC\uC57C \uD569\uB2C8\uB2E4: ${JSON.stringify(a.before_id)}`
18531
+ text: `${pageKey} \uB294 \uC774\uC804 \uC751\uB2F5\uC774 \uC900 \uAC12\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4: ${JSON.stringify(rawPage)}`
16648
18532
  };
16649
18533
  }
16650
18534
  const limit = Math.max(
16651
18535
  1,
16652
18536
  Math.min(Math.trunc(a.limit ?? LEDGER_DEFAULT_LIMIT), LEDGER_MAX_LIMIT)
16653
18537
  );
16654
- if (a.before_id !== void 0 && a.before_id < 1) {
16655
- return { isError: true, text: "before_id \uB294 1 \uC774\uC0C1\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4." };
18538
+ if (pageNum !== void 0 && (!Number.isInteger(pageNum) || pageNum < 1)) {
18539
+ return { isError: true, text: `${pageKey} \uB294 1 \uC774\uC0C1\uC758 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4.` };
16656
18540
  }
16657
18541
  const base = resolveBaseUrl(deps.baseUrl);
16658
18542
  const ws = await resolveWorkspace(base, deps);
16659
18543
  if (!ws) return NO_WORKSPACE;
16660
- const out3 = await ledger(
18544
+ const out2 = await ledger(
16661
18545
  base,
16662
18546
  ws,
16663
- { limit, ...a.before_id !== void 0 ? { beforeId: Math.trunc(a.before_id) } : {} },
18547
+ { limit, ...pageNum !== void 0 ? { cursor: String(pageNum) } : {} },
16664
18548
  deps
16665
18549
  );
16666
- if (out3.entries.length === 0) {
18550
+ if (out2.entries.length === 0) {
16667
18551
  return {
16668
- text: !out3.enabled && out3.next_before_id == null ? "\uC774 \uBC30\uD3EC\uC5D0\uB294 \uD06C\uB808\uB527 \uAE30\uB2A5\uC774 \uC5C6\uC5B4 \uC0AC\uC6A9 \uB0B4\uC5ED\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(0\uAC74\uC774 \uC544\uB2C8\uB77C \uAC1C\uB150 \uBD80\uC7AC)." : "\uC0AC\uC6A9 \uB0B4\uC5ED\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."
18552
+ text: !out2.enabled && nextPage(out2) == null ? "\uC774 \uBC30\uD3EC\uC5D0\uB294 \uD06C\uB808\uB527 \uAE30\uB2A5\uC774 \uC5C6\uC5B4 \uC0AC\uC6A9 \uB0B4\uC5ED\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(0\uAC74\uC774 \uC544\uB2C8\uB77C \uAC1C\uB150 \uBD80\uC7AC)." : "\uC0AC\uC6A9 \uB0B4\uC5ED\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."
16669
18553
  };
16670
18554
  }
16671
18555
  const lines = ["\uD06C\uB808\uB527 \uC0AC\uC6A9 \uB0B4\uC5ED (\uCD5C\uC2E0\uC21C)", ""];
16672
- for (const e of out3.entries) {
18556
+ for (const e of out2.entries) {
16673
18557
  const when = (e.created_at ?? "").slice(0, 16).replace("T", " ");
16674
18558
  const parts = [e.display_name];
16675
18559
  if (e.units_label) parts.push(e.units_label);
@@ -16680,8 +18564,9 @@ function creditLedger(a = {}, deps = {}) {
16680
18564
  `${when} \xB7 ${parts.join(" \xB7 ")} \xB7 ${sign}${e.amount_krw.toLocaleString("ko-KR")}\uC6D0 (\uC794\uC561 ${e.balance_after_krw.toLocaleString("ko-KR")}\uC6D0)`
16681
18565
  );
16682
18566
  }
16683
- if (out3.next_before_id != null) {
16684
- lines.push("", `\uB354 \uC788\uC2B5\uB2C8\uB2E4 \u2014 before_id=${out3.next_before_id} \uB85C \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694.`);
18567
+ const next = nextPage(out2);
18568
+ if (next != null) {
18569
+ lines.push("", `\uB354 \uC788\uC2B5\uB2C8\uB2E4 \u2014 ${pageKey}=${next} \uB85C \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694.`);
16685
18570
  }
16686
18571
  return { text: lines.join("\n") };
16687
18572
  });
@@ -16695,7 +18580,7 @@ function projectLine(p) {
16695
18580
  return parts.join(" \xB7 ");
16696
18581
  }
16697
18582
  function listProjects(a = {}, deps = {}) {
16698
- return guarded2(READ_ONLY, async () => {
18583
+ return guarded(READ_ONLY, async () => {
16699
18584
  if (a.limit !== void 0 && !Number.isFinite(a.limit)) {
16700
18585
  return { isError: true, text: `limit \uC740 \uC22B\uC790\uC5EC\uC57C \uD569\uB2C8\uB2E4: ${JSON.stringify(a.limit)}` };
16701
18586
  }
@@ -16705,8 +18590,8 @@ function listProjects(a = {}, deps = {}) {
16705
18590
  );
16706
18591
  const query = (a.query ?? "").trim().toLowerCase();
16707
18592
  const base = resolveBaseUrl(deps.baseUrl);
16708
- const out3 = await list(base, deps);
16709
- const all = out3.projects ?? [];
18593
+ const out2 = await list(base, deps);
18594
+ const all = out2.projects ?? [];
16710
18595
  const total = all.length;
16711
18596
  const matched = query ? all.filter(
16712
18597
  (p) => (p.slug ?? "").toLowerCase().includes(query) || (p.title ?? "").toLowerCase().includes(query)
@@ -16727,13 +18612,26 @@ function listProjects(a = {}, deps = {}) {
16727
18612
  );
16728
18613
  }
16729
18614
  lines.push(
16730
- "democut_generate_video \uC758 project_slug \uC5D0\uB294 \uC704 **slug**(\uB9E8 \uC55E \uAC12)\uB97C \uADF8\uB300\uB85C \uB123\uC73C\uC138\uC694. \uC5B4\uB290 \uAC83\uC5D0 \uADC0\uC18D\uC2DC\uD0AC\uC9C0 \uBD84\uBA85\uD558\uC9C0 \uC54A\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBB3C\uC73C\uC138\uC694."
18615
+ "\uD504\uB85C\uC81D\uD2B8\uB97C \uC694\uAD6C\uD558\uB294 \uB3C4\uAD6C\uC758 project_slug \uC5D0\uB294 \uC704 **slug**(\uB9E8 \uC55E \uAC12)\uB97C \uADF8\uB300\uB85C \uB123\uC73C\uC138\uC694. \uC5B4\uB290 \uAC83\uC5D0 \uADC0\uC18D\uC2DC\uD0AC\uC9C0 \uBD84\uBA85\uD558\uC9C0 \uC54A\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBB3C\uC73C\uC138\uC694."
16731
18616
  );
16732
18617
  return { text: lines.join("\n") };
16733
18618
  });
16734
18619
  }
18620
+ var PROJECT_FIELD_DEFAULTS = {
18621
+ ratio: "16:9",
18622
+ resolution: "1080p",
18623
+ folder_id: null,
18624
+ defaults: null
18625
+ };
18626
+ function unsupportedProjectFields(a) {
18627
+ const given = a;
18628
+ return Object.keys(PROJECT_FIELD_DEFAULTS).filter((key) => {
18629
+ const v = given[key];
18630
+ return v !== void 0 && v !== null && v !== PROJECT_FIELD_DEFAULTS[key];
18631
+ });
18632
+ }
16735
18633
  function createProject(a = {}, deps = {}) {
16736
- return guarded2(READ_ONLY, async () => {
18634
+ return guarded(READ_ONLY, async () => {
16737
18635
  const title = (a.title ?? "").trim();
16738
18636
  if (!title) {
16739
18637
  return {
@@ -16741,6 +18639,13 @@ function createProject(a = {}, deps = {}) {
16741
18639
  text: "title \uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uC0AC\uC6A9\uC790\uAC00 \uC54C\uC544\uBCFC \uC218 \uC788\uB294 \uD504\uB85C\uC81D\uD2B8 \uC774\uB984\uC744 \uB123\uC5B4 \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694."
16742
18640
  };
16743
18641
  }
18642
+ const unsupported = unsupportedProjectFields(a);
18643
+ if (unsupported.length > 0) {
18644
+ return {
18645
+ isError: true,
18646
+ text: `${unsupported.join(", ")} \uC740 \uC544\uC9C1 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(\uAE30\uBCF8\uAC12\uB9CC \uAC00\uB2A5). \uADF8 \uC778\uC790\uB97C \uBE7C\uACE0 \uB2E4\uC2DC \uD638\uCD9C\uD558\uBA74 ${PROJECT_FIELD_DEFAULTS.ratio}\xB7${PROJECT_FIELD_DEFAULTS.resolution} \uB85C \uB9CC\uB4E4\uC5B4\uC9D1\uB2C8\uB2E4.`
18647
+ };
18648
+ }
16744
18649
  const base = resolveBaseUrl(deps.baseUrl);
16745
18650
  const voiceId = await defaultVoiceId(base, deps);
16746
18651
  const p = await create(
@@ -16753,156 +18658,315 @@ function createProject(a = {}, deps = {}) {
16753
18658
  `\uD504\uB85C\uC81D\uD2B8 \uC900\uBE44\uB428 \u2014 slug: ${p.slug}`,
16754
18659
  `\uC81C\uBAA9: ${p.title}`,
16755
18660
  "",
16756
- "democut_generate_video \uC758 project_slug \uC5D0 \uC704 slug \uB97C \uADF8\uB300\uB85C \uB123\uC73C\uC138\uC694.",
18661
+ "\uD504\uB85C\uC81D\uD2B8\uB97C \uC694\uAD6C\uD558\uB294 \uB3C4\uAD6C\uC758 project_slug \uC5D0 \uC704 slug \uB97C \uADF8\uB300\uB85C \uB123\uC73C\uC138\uC694.",
16757
18662
  "\uAC19\uC740 \uC81C\uBAA9\uC73C\uB85C \uC774 \uB3C4\uAD6C\uB97C \uB2E4\uC2DC \uBD88\uB7EC\uB3C4 \uC0C8\uB85C \uB9CC\uB4E4\uC9C0 \uC54A\uACE0 \uC774 \uD504\uB85C\uC81D\uD2B8\uAC00 \uB098\uC635\uB2C8\uB2E4."
16758
18663
  ].join("\n")
16759
18664
  };
16760
18665
  });
16761
18666
  }
16762
-
16763
- // src/mcp/server.ts
16764
- var RESOLUTIONS = ["480p", "720p", "1080p", "4k"];
16765
- var RATIOS = ["16:9", "9:16", "1:1", "4:3", "21:9", "adaptive"];
16766
- var GENERATION_PARAMS = {
16767
- duration_s: {
16768
- type: "number",
16769
- description: "\uC601\uC0C1 \uAE38\uC774(\uCD08). \uAE30\uBCF8 5. \uBAA8\uB378\uBCC4 \uD5C8\uC6A9 \uBC94\uC704\uAC00 \uB2E4\uB974\uB2E4(2.0 \uACC4\uC5F4 4~15, 2.5 \uACC4\uC5F4 4~30)."
16770
- },
16771
- resolution: { type: "string", enum: RESOLUTIONS, description: "\uAE30\uBCF8 720p." },
16772
- ratio: { type: "string", enum: RATIOS, description: "\uAE30\uBCF8 16:9." },
16773
- model: {
16774
- type: "string",
16775
- description: "\uC0DD\uB7B5\uD558\uBA74 image_urls \uC720\uBB34\uB85C \uC790\uB3D9 \uC120\uD0DD\uB41C\uB2E4(\uC788\uC73C\uBA74 image-to-video, \uC5C6\uC73C\uBA74 text-to-video). \uBA85\uC2DC\uD558\uBA74 \uADF8 \uBAA8\uB378\uC744 \uC4F0\uB418 \uACC4\uC5F4\uC774 \uC5B4\uAE0B\uB098\uBA74 \uAC70\uBD80\uB41C\uB2E4."
18667
+ var projectPath = (slug, tail) => `/api/projects/${encodeURIComponent(slug)}${tail}`;
18668
+ function needSlug(a) {
18669
+ const slug = (a.slug ?? "").trim();
18670
+ if (!slug) {
18671
+ return { isError: true, text: "slug \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4 \u2014 democut_list_projects \uB85C \uD655\uC778\uD558\uC138\uC694." };
16776
18672
  }
16777
- };
16778
- var TOOLS = [
16779
- {
16780
- name: "democut_auth_status",
16781
- description: "DemoCut \uB85C\uADF8\uC778 \uC0C1\uD0DC\uC640 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\xB7\uC5ED\uD560\xB7\uD2F0\uC5B4\uB97C \uD655\uC778\uD55C\uB2E4. \uBD80\uC791\uC6A9\uB3C4 \uACFC\uAE08\uB3C4 \uC5C6\uB2E4. \uB2E4\uB978 \uB3C4\uAD6C\uAC00 '\uAD8C\uD55C \uC5C6\uC74C' \uC73C\uB85C \uC2E4\uD328\uD558\uBA74 \uC774\uAC78\uB85C \uC0C1\uD0DC\uB97C \uBA3C\uC800 \uD655\uC778\uD558\uB77C.",
16782
- inputSchema: { type: "object", properties: {}, additionalProperties: false }
16783
- },
16784
- {
16785
- name: "democut_estimate_video_cost",
16786
- description: "\uC601\uC0C1 \uC0DD\uC131 \uC608\uC0C1 \uBE44\uC6A9\uC744 \uACC4\uC0B0\uD55C\uB2E4. **\uBD80\uC791\uC6A9\uB3C4 \uACFC\uAE08\uB3C4 \uC5C6\uB2E4.** \uBE44\uC6A9\uC740 \uD574\uC0C1\uB3C4\xB7\uAE38\uC774\xB7\uBE44\uC728\uC5D0 \uB354\uD574 **\uBAA8\uB378 \uACC4\uC5F4**\uB85C \uACB0\uC815\uB41C\uB2E4 \u2014 \uCC38\uC870 \uC774\uBBF8\uC9C0\uB97C \uB123\uC744 \uAC70\uBA74 has_image=true \uB85C \uACC4\uC0B0\uD574\uC57C \uC2E4\uC81C \uCCAD\uAD6C\uC640 \uB9DE\uB294\uB2E4(\uACC4\uC5F4\uB9C8\uB2E4 \uD1A0\uD070 \uB2E8\uAC00\uAC00 \uB2E4\uB974\uB2E4). democut_generate_video \uB97C \uBD80\uB974\uAE30 \uC804\uC5D0 \uBA3C\uC800 \uD638\uCD9C\uD574 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uAE08\uC561\uC744 \uC54C\uB9AC\uACE0 \uB3D9\uC758\uB97C \uBC1B\uC544\uB77C.",
16787
- inputSchema: {
16788
- type: "object",
16789
- properties: {
16790
- ...GENERATION_PARAMS,
16791
- has_image: {
16792
- type: "boolean",
16793
- description: "\uC0DD\uC131 \uC2DC \uCC38\uC870 \uC774\uBBF8\uC9C0\uB97C \uB123\uC744 \uC608\uC815\uC778\uAC00(\uAE30\uBCF8 false). \u2605 \uAE08\uC561\uC774 \uB2EC\uB77C\uC9C4\uB2E4 \u2014 \uC774\uBBF8\uC9C0 \uC720\uBB34\uAC00 \uBAA8\uB378 \uACC4\uC5F4\uC744 \uC815\uD558\uACE0 \uACC4\uC5F4\uB9C8\uB2E4 \uD1A0\uD070 \uB2E8\uAC00\uAC00 \uB2E4\uB974\uB2E4. \uC0DD\uC131 \uB54C image_urls \uB97C \uB123\uC744 \uAC70\uBA74 \uC5EC\uAE30\uC11C\uB3C4 true \uB85C \uB450\uC5B4\uC57C \uCD94\uC815 \uAE08\uC561\uACFC \uC2E4\uC81C \uCCAD\uAD6C\uAC00 \uC77C\uCE58\uD55C\uB2E4."
16794
- }
16795
- },
16796
- additionalProperties: false
18673
+ return slug;
18674
+ }
18675
+ function getOptions(a = {}, deps = {}) {
18676
+ return guarded(READ_ONLY, async () => {
18677
+ const slug = needSlug(a);
18678
+ if (typeof slug !== "string") return slug;
18679
+ const base = resolveBaseUrl(deps.baseUrl);
18680
+ const out2 = await apiRequest(base, projectPath(slug, "/options"), {}, deps);
18681
+ const modes = (out2.modes ?? []).map((m) => String(m.mode ?? "?")).join(", ") || "-";
18682
+ return {
18683
+ text: [
18684
+ `\uD504\uB85C\uC81D\uD2B8 ${out2.project.slug} \u2014 ${out2.project.ratio} ${out2.project.resolution}`,
18685
+ `\uAD8C\uC7A5 \uBC29\uC2DD: ${out2.recommended_mode} \xB7 \uAC00\uB2A5\uD55C \uBC29\uC2DD: ${modes}`,
18686
+ `\uBCF4\uC774\uC2A4 ${(out2.voices ?? []).length}\uAC1C \xB7 \uC544\uBC14\uD0C0 ${(out2.characters ?? []).length}\uAC1C \xB7 \uBC30\uACBD ${(out2.backgrounds ?? []).length}\uAC1C`,
18687
+ `\uC794\uC561 ${krw(out2.balance_krw)} \xB7 \uC694\uC728 v${out2.rate_version}`,
18688
+ "\uB2E8\uAC00\uB294 \uCC38\uACE0\uAC12\uC785\uB2C8\uB2E4 \u2014 \uCCAD\uAD6C\uB294 democut_estimate_cuts \uAC00 \uC900 total_krw\xB7rate_version \uC73C\uB85C \uD569\uB2C8\uB2E4."
18689
+ ].join("\n")
18690
+ };
18691
+ });
18692
+ }
18693
+ function uploadAsset(a = {}, deps = {}) {
18694
+ return guarded(READ_ONLY, async () => {
18695
+ const base = resolveBaseUrl(deps.baseUrl);
18696
+ if (!a.kind) return { isError: true, text: "kind \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4 (image\xB7audio\xB7video\xB7subtitle\xB7code \uB4F1)." };
18697
+ if (a.local_path && a.source_url) {
18698
+ return { isError: true, text: "local_path \uC640 source_url \uC911 \uD558\uB098\uB9CC \uC8FC\uC138\uC694." };
16797
18699
  }
16798
- },
16799
- {
16800
- name: "democut_generate_video",
16801
- description: "\uC601\uC0C1 \uC0DD\uC131\uC744 \uC81C\uCD9C\uD55C\uB2E4. **\uC2E4\uC81C\uB85C \uB3C8\uC774 \uB098\uAC04\uB2E4.** \uBA3C\uC800 democut_estimate_video_cost \uB85C \uAE08\uC561\uC744 \uD655\uC778\uD558\uACE0 \uC0AC\uC6A9\uC790 \uB3D9\uC758\uB97C \uBC1B\uC740 \uB4A4, \uADF8 \uAE08\uC561\uC744 confirmed_cost_usd \uC5D0 \uADF8\uB300\uB85C \uB123\uC5B4 \uD638\uCD9C\uD558\uB77C \u2014 \uC11C\uBC84\uAC00 \uB2E4\uC2DC \uACC4\uC0B0\uD574 \uB300\uC870\uD558\uACE0 \uC5B4\uAE0B\uB098\uBA74 \uAC70\uBD80\uD55C\uB2E4. \uC2E4\uD328\uD574\uB3C4 **\uB2E4\uC2DC \uC81C\uCD9C\uD558\uC9C0 \uB9C8\uB77C**: \uC7AC\uC81C\uCD9C\uC740 \uBCC4\uAC1C \uC0DD\uC131\uC774\uB77C \uB2E4\uC2DC \uACFC\uAE08\uB41C\uB2E4. \uC911\uBCF5 \uC81C\uCD9C \uBC29\uC5B4\uB294 \uC11C\uBC84 \uD504\uB85C\uC138\uC2A4 \uC548\uC5D0\uC11C\uB9CC \uB3D9\uC791\uD558\uBBC0\uB85C, \uAC19\uC740 \uC694\uCCAD\uC744 \uB3D9\uC2DC\uC5D0 \uB450 \uBC88 \uBCF4\uB0B4\uBA74 \uB450 \uAC74\uC774 \uC81C\uCD9C\uB420 \uC218 \uC788\uB2E4 \u2014 \uD55C \uBC88\uB9CC \uBCF4\uB0B4\uACE0 \uACB0\uACFC\uB97C \uC870\uD68C\uD558\uB77C.",
16802
- inputSchema: {
16803
- type: "object",
16804
- properties: {
16805
- prompt: { type: "string", description: "\uC0DD\uC131\uD560 \uC601\uC0C1 \uC124\uBA85." },
16806
- confirmed_cost_usd: {
16807
- type: "number",
16808
- description: "democut_estimate_video_cost \uAC00 \uB3CC\uB824\uC900 cost_usd \uC6D0\uAC12. \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC774 \uAE08\uC561\uC744 \uC54C\uB9AC\uACE0 \uB3D9\uC758\uB97C \uBC1B\uC740 \uB4A4\uC5D0 \uB123\uC5B4\uB77C."
16809
- },
16810
- ...GENERATION_PARAMS,
16811
- seed: { type: "number", description: "\uACB0\uC815\uB860\uC801 \uC0DD\uC131\uC6A9 seed." },
16812
- image_urls: {
16813
- type: "array",
16814
- items: { type: "string" },
16815
- description: "\uCC38\uC870 \uC774\uBBF8\uC9C0. **\uACF5\uAC1C HTTPS URL** \uB9CC \uAC00\uB2A5(\uC2DC\uC791 \uD504\uB808\uC784 1\uC7A5 + \uB05D \uD504\uB808\uC784 1\uC7A5, \uCD5C\uB300 2\uAC1C). \u2605 \uC774 \uAC12\uC774 **\uBAA8\uB378\uACFC \uB2E8\uAC00\uB97C \uC815\uD55C\uB2E4** \u2014 \uC8FC\uBA74 image-to-video, \uBE44\uC6B0\uBA74 text-to-video \uB85C \uC790\uB3D9 \uC120\uD0DD\uB418\uACE0 \uD1A0\uD070 \uB2E8\uAC00\uAC00 \uB2E4\uB974\uB2E4. \uC778\uBB3C\xB7\uC81C\uD488 \uB4F1 \uD2B9\uC815 \uB300\uC0C1\uC744 \uC720\uC9C0\uD574\uC57C \uD558\uBA74 \uBC18\uB4DC\uC2DC \uB123\uC5B4\uB77C."
16816
- },
16817
- generate_audio: { type: "boolean", description: "\uC624\uB514\uC624 \uD568\uAED8 \uC0DD\uC131. \uAE30\uBCF8 false." },
16818
- watermark: { type: "boolean", description: "\uC6CC\uD130\uB9C8\uD06C. \uAE30\uBCF8 false." },
16819
- project_slug: {
16820
- type: "string",
16821
- description: "\uBE44\uC6A9\uC774 \uADC0\uC18D\uB420 \uD504\uB85C\uC81D\uD2B8 \uC2AC\uB7EC\uADF8 \u2014 **\uD544\uC218**. \uBCF8\uC778 \uC18C\uC720\uAC00 \uC544\uB2C8\uBA74 404. \uC601\uC0C1 \uC0DD\uC131\uC740 \uACFC\uAE08 \uB300\uC0C1\uC774\uB77C \uADC0\uC18D \uC5C6\uB294 \uC9C0\uCD9C\uC740 \uB300\uC870\xB7\uC815\uC0B0\uC774 \uBD88\uAC00\uB2A5\uD558\uB2E4. \uC2AC\uB7EC\uADF8\uB97C \uBAA8\uB974\uBA74 democut_list_projects \uB85C \uBA3C\uC800 \uD655\uC778\uD558\uB77C \u2014 \uCD94\uCE21\uD558\uC9C0 \uB9C8\uB77C."
16822
- }
16823
- },
16824
- required: ["prompt", "confirmed_cost_usd", "project_slug"],
16825
- additionalProperties: false
18700
+ if (a.local_path) {
18701
+ const path = a.local_path;
18702
+ if (!existsSync2(path)) {
18703
+ return { isError: true, text: `\uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4: ${path}` };
18704
+ }
18705
+ const view2 = await uploadFile(base, path, { kind: a.kind, projectSlug: a.project_slug, filename: a.filename }, deps);
18706
+ return {
18707
+ text: [
18708
+ `\uC790\uC0B0 ${view2.id} (${view2.kind}) \uB97C \uC62C\uB838\uC2B5\uB2C8\uB2E4 \u2014 state=${view2.state}`,
18709
+ `${view2.mime} \xB7 ${view2.bytes.toLocaleString("ko-KR")} \uBC14\uC774\uD2B8`,
18710
+ "\uC774 id \uB97C spec \uC758 BYO \uD544\uB4DC(image_asset_id\xB7narration_asset_id\xB7source.asset_id \uB4F1)\uC5D0 \uC4F0\uC138\uC694."
18711
+ ].join("\n")
18712
+ };
16826
18713
  }
16827
- },
16828
- {
16829
- name: "democut_get_video_status",
16830
- description: "\uC0DD\uC131 \uC791\uC5C5 \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uACE0, \uC644\uB8CC\uB410\uC73C\uBA74 \uC0B0\uCD9C\uBB3C\uC744 \uB0B4\uB824\uBC1B\uB294\uB2E4. \uBD80\uC791\uC6A9\uB3C4 \uACFC\uAE08\uB3C4 \uC5C6\uB2E4. \uC11C\uBC84\uB294 \uC0B0\uCD9C\uBB3C\uC744 \uBCF4\uAD00\uD558\uC9C0 \uC54A\uC73C\uBBC0\uB85C \uC644\uB8CC \uC989\uC2DC output_path \uB85C \uC800\uC7A5\uD558\uB77C.",
16831
- inputSchema: {
16832
- type: "object",
16833
- properties: {
16834
- job_id: { type: "string", description: "democut_generate_video \uAC00 \uB3CC\uB824\uC900 job_id." },
16835
- output_path: { type: "string", description: "\uC800\uC7A5\uD560 \uB85C\uCEEC \uACBD\uB85C(\uC808\uB300\uACBD\uB85C \uAD8C\uC7A5)." },
16836
- project_slug: {
16837
- type: "string",
16838
- description: "(\uBB34\uC2DC\uB428) \uADC0\uC18D\uC740 \uC81C\uCD9C \uC2DC\uC810 \uAC12\uC73C\uB85C \uC11C\uBC84\uAC00 \uACB0\uC815\uD55C\uB2E4."
16839
- }
16840
- },
16841
- required: ["job_id"],
16842
- additionalProperties: false
18714
+ if (!a.source_url) {
18715
+ return { isError: true, text: "local_path \uB610\uB294 source_url \uC774 \uD544\uC694\uD569\uB2C8\uB2E4." };
16843
18716
  }
16844
- },
16845
- {
16846
- name: "democut_credit_balance",
16847
- description: "DemoCut \uD06C\uB808\uB527 \uC794\uC561\uC744 \uD655\uC778\uD55C\uB2E4. \uBD80\uC791\uC6A9\uB3C4 \uACFC\uAE08\uB3C4 \uC5C6\uB2E4. \uB3C8\uC774 \uB098\uAC00\uB294 \uC791\uC5C5(democut_generate_video)\uC744 \uC81C\uCD9C\uD558\uAE30 **\uC804\uC5D0** \uD638\uCD9C\uD574 \uC794\uC561\uC774 \uCDA9\uBD84\uD55C\uC9C0 \uBCF4\uB77C \u2014 \uBD80\uC871\uD558\uBA74 \uC81C\uCD9C\uC774 402 \uB85C \uAC70\uBD80\uB418\uACE0, \uADF8\uAC83\uC744 \uBBF8\uB9AC \uC544\uB294 \uD3B8\uC774 \uB0AB\uB2E4. \uC794\uC561\uC774 \uBAA8\uC790\uB77C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC54C\uB9AC\uACE0 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uAD00\uB9AC\uC790\uC5D0\uAC8C \uCDA9\uC804\uC744 \uC694\uCCAD\uD558\uB3C4\uB85D \uC548\uB0B4\uD558\uB77C. \uB124\uAC00 \uC9C1\uC811 \uCDA9\uC804\uD560 \uC218\uB294 \uC5C6\uB2E4.",
16848
- inputSchema: { type: "object", properties: {}, additionalProperties: false }
16849
- },
16850
- {
16851
- name: "democut_credit_ledger",
16852
- description: '\uD06C\uB808\uB527 \uC0AC\uC6A9 \uB0B4\uC5ED\uC744 \uCD5C\uC2E0\uC21C\uC73C\uB85C \uD655\uC778\uD55C\uB2E4. \uBD80\uC791\uC6A9\uB3C4 \uACFC\uAE08\uB3C4 \uC5C6\uB2E4. "\uC65C \uC794\uC561\uC774 \uC774\uB9CC\uD07C \uC904\uC5C8\uB098" \uB97C \uB2F5\uD560 \uB54C \uC4F4\uB2E4 \u2014 \uAC01 \uD589\uC740 \uBB34\uC5C7\uC5D0\xB7\uC5B8\uC81C\xB7\uC5BC\uB9C8\uC640, \uAC00\uB2A5\uD558\uBA74 \uC0AC\uC6A9\uB7C9(\uC608: 40,594 tokens)\uAE4C\uC9C0 \uB9D0\uD55C\uB2E4.',
16853
- inputSchema: {
16854
- type: "object",
16855
- properties: {
16856
- limit: { type: "number", description: "\uAC00\uC838\uC62C \uAC74\uC218 1~200. \uAE30\uBCF8 10." },
16857
- before_id: {
16858
- type: "number",
16859
- description: "\uC774\uC804 \uD638\uCD9C\uC774 \uB3CC\uB824\uC900 next_before_id. \uB2E4\uC74C \uD398\uC774\uC9C0\uB97C \uBCFC \uB54C\uB9CC \uB123\uC5B4\uB77C."
16860
- }
16861
- },
16862
- additionalProperties: false
18717
+ const view = await apiRequest(
18718
+ base,
18719
+ "/api/assets/fetch",
18720
+ { method: "POST", body: { kind: a.kind, project_slug: a.project_slug, filename: a.filename, source_url: a.source_url } },
18721
+ deps
18722
+ );
18723
+ return {
18724
+ text: [
18725
+ `\uC790\uC0B0 ${view.id} (${view.kind}) \uB97C \uAC00\uC838\uC624\uB294 \uC911\uC785\uB2C8\uB2E4 \u2014 state=${view.state}`,
18726
+ "democut_get_cut \uC774 \uC544\uB2C8\uB77C \uC790\uC0B0 \uC870\uD68C\uB85C state \uAC00 ready \uAC00 \uB420 \uB54C\uAE4C\uC9C0 \uAE30\uB2E4\uB9B0 \uB4A4 \uC4F0\uC138\uC694.",
18727
+ "\uC2E4\uD328\uD558\uBA74 state=deleted \uAC00 \uB418\uACE0 \uC0AC\uC720\uB294 meta.error \uC5D0 \uB0A8\uC2B5\uB2C8\uB2E4."
18728
+ ].join("\n")
18729
+ };
18730
+ });
18731
+ }
18732
+ function estimateCuts(a = {}, deps = {}) {
18733
+ return guarded(READ_ONLY, async () => {
18734
+ const slug = needSlug(a);
18735
+ if (typeof slug !== "string") return slug;
18736
+ const base = resolveBaseUrl(deps.baseUrl);
18737
+ const out2 = await apiRequest(
18738
+ base,
18739
+ projectPath(slug, "/cuts/estimate"),
18740
+ { method: "POST", body: { items: a.items ?? [], imports: a.imports ?? [] } },
18741
+ deps
18742
+ );
18743
+ const lines = [`\uACAC\uC801 (\uC694\uC728 v${out2.rate_version}) \u2014 \uBD80\uC791\uC6A9\uB3C4 \uACFC\uAE08\uB3C4 \uC5C6\uC2B5\uB2C8\uB2E4`];
18744
+ for (const item of out2.items ?? []) {
18745
+ const label = item.cut_id ?? "(\uC0C8 \uCEF7)";
18746
+ if (item.blocked_reason) {
18747
+ lines.push(` ${label}: \uACAC\uC801 \uBD88\uAC00 \u2014 ${item.blocked_reason}`);
18748
+ continue;
18749
+ }
18750
+ const rows = (item.rows ?? []).map((r) => `${r.key} ${krw(r.krw)}`).join(", ") || "\uD589 \uC5C6\uC74C";
18751
+ lines.push(` ${label}: ${krw(item.total_krw ?? 0)} (${rows})`);
16863
18752
  }
16864
- },
16865
- {
16866
- name: "democut_list_projects",
16867
- description: "\uC774 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uC758 \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D\uC744 \uCD5C\uADFC \uC218\uC815\uC21C\uC73C\uB85C \uD655\uC778\uD55C\uB2E4. \uBD80\uC791\uC6A9\uB3C4 \uACFC\uAE08\uB3C4 \uC5C6\uB2E4. democut_generate_video \uC758 project_slug \uB294 **\uC2E4\uC7AC\uD558\uB294 \uBCF8\uC778 \uD504\uB85C\uC81D\uD2B8\uC5EC\uC57C** \uD558\uACE0 \uD2C0\uB9AC\uBA74 404 \uB2E4 \u2014 \uC2AC\uB7EC\uADF8\uB97C \uBAA8\uB974\uBA74 \uCD94\uCE21\uD558\uC9C0 \uB9D0\uACE0 \uC774\uAC78\uB85C \uBA3C\uC800 \uD655\uC778\uD558\uB77C. \uBAA9\uB85D\uC774 \uBE44\uC5B4 \uC788\uAC70\uB098 \uB9C8\uB545\uD55C \uAC83\uC774 \uC5C6\uC73C\uBA74 democut_create_project \uB85C \uB9CC\uB4E4 \uC218 \uC788\uB2E4 \u2014 \uB2E8 \uBA3C\uC800 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC5B4\uB290 \uAC83\uC5D0 \uB123\uC744\uC9C0, \uC0C8\uB85C \uB9CC\uB4E0\uB2E4\uBA74 \uC5B4\uB5A4 \uC774\uB984\uC73C\uB85C \uD560\uC9C0 \uBB3C\uC5B4\uB77C.",
16868
- inputSchema: {
16869
- type: "object",
16870
- properties: {
16871
- limit: { type: "number", description: "\uAC00\uC838\uC62C \uAC74\uC218 1~100. \uAE30\uBCF8 30." },
16872
- query: {
16873
- type: "string",
16874
- description: "\uC2AC\uB7EC\uADF8\xB7\uC81C\uBAA9\uC5D0 \uC774 \uBB38\uC790\uC5F4\uC774 \uB4E0 \uAC83\uB9CC (\uB300\uC18C\uBB38\uC790 \uBB34\uC2DC). \uCC3E\uB294 \uD504\uB85C\uC81D\uD2B8 \uC774\uB984\uC744 \uC54C \uB54C\uB9CC \uC4F0\uB77C \u2014 \uBE44\uC6B0\uBA74 \uCD5C\uADFC \uC218\uC815\uC21C \uC804\uCCB4\uB2E4."
18753
+ lines.push(
18754
+ `\uCD1D\uC561 ${krw(out2.total_krw)} \xB7 \uC794\uC561 ${krw(out2.balance_krw)} \u2192 \uB0A8\uC744 \uC794\uC561 ${krw(out2.balance_after_krw)}`,
18755
+ out2.can_afford ? "\uCDA9\uBD84\uD569\uB2C8\uB2E4." : "\u26A0\uFE0F \uC794\uC561\uC774 \uBD80\uC871\uD569\uB2C8\uB2E4 \u2014 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uAD00\uB9AC\uC790\uC5D0\uAC8C \uCDA9\uC804\uC744 \uC694\uCCAD\uD558\uC138\uC694.",
18756
+ "\uC774 total_krw\xB7rate_version \uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBCF4\uC5EC \uC8FC\uACE0 **\uADF8\uB300\uB85C** democut_make_cuts \uC5D0 \uB123\uC73C\uC138\uC694."
18757
+ );
18758
+ if (out2.mock) lines.push("(mock \uB2E8\uAC00\uC785\uB2C8\uB2E4 \u2014 \uC2E4\uC81C \uCCAD\uAD6C\uC640 \uB2E4\uB97C \uC218 \uC788\uC2B5\uB2C8\uB2E4.)");
18759
+ return { text: lines.join("\n") };
18760
+ });
18761
+ }
18762
+ function makeCuts(a = {}, deps = {}) {
18763
+ return guarded(SUBMITTING, async () => {
18764
+ const slug = needSlug(a);
18765
+ if (typeof slug !== "string") return slug;
18766
+ const base = resolveBaseUrl(deps.baseUrl);
18767
+ const out2 = await apiRequest(
18768
+ base,
18769
+ projectPath(slug, "/cuts/make"),
18770
+ {
18771
+ method: "POST",
18772
+ body: {
18773
+ items: a.items ?? [],
18774
+ confirmed_total_krw: a.confirmed_total_krw,
18775
+ rate_version: a.rate_version
16875
18776
  }
16876
18777
  },
16877
- additionalProperties: false
18778
+ deps
18779
+ );
18780
+ const lines = [`\uCEF7 ${(out2.jobs ?? []).length}\uAC1C\uB97C \uC81C\uCD9C\uD588\uC2B5\uB2C8\uB2E4 (batch ${out2.batch_id}) \u2014 \uC794\uC561\uC5D0\uC11C \uCC28\uAC10\uB410\uC2B5\uB2C8\uB2E4`];
18781
+ for (const ref of out2.jobs ?? []) {
18782
+ const tail = ref.deduplicated ? " (\uC774\uBBF8 \uAC19\uC740 \uC791\uC5C5\uC774 \uB3CC\uACE0 \uC788\uC5B4 \uC7AC\uC0AC\uC6A9)" : "";
18783
+ lines.push(` ${ref.cut_id} \u2192 ${ref.job_id} ${krw(ref.quote.total_krw)}${tail}`);
16878
18784
  }
16879
- },
16880
- {
16881
- name: "democut_create_project",
16882
- description: "\uD504\uB85C\uC81D\uD2B8\uB97C \uC0C8\uB85C \uB9CC\uB4E0\uB2E4. **\uACFC\uAE08\uC740 \uC5C6\uC9C0\uB9CC \uACC4\uC815\uC5D0 \uB0A8\uB294 \uC4F0\uAE30 \uC791\uC5C5\uC774\uB2E4.** \uC601\uC0C1 \uC0DD\uC131\uC740 \uBE44\uC6A9\uC744 \uADC0\uC18D\uC2DC\uD0AC \uD504\uB85C\uC81D\uD2B8\uAC00 \uC788\uC5B4\uC57C \uD558\uBBC0\uB85C, democut_list_projects \uAC00 \uBE44\uC5B4 \uC788\uAC70\uB098 \uB9C8\uB545\uD55C \uAC83\uC774 \uC5C6\uC744 \uB54C \uC4F4\uB2E4. \u2605 \uBA3C\uC800 democut_list_projects \uB85C **\uC4F8 \uB9CC\uD55C \uAC83\uC774 \uC774\uBBF8 \uC788\uB294\uC9C0 \uBCF4\uACE0**, \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC5B4\uB290 \uAC83\uC5D0 \uB123\uC744\uC9C0 \uBB3C\uC5B4\uB77C \u2014 \uBB3C\uC5B4\uBCF4\uC9C0 \uC54A\uACE0 \uC0C8\uB85C \uB9CC\uB4E4\uBA74 \uBE44\uC2B7\uD55C \uD504\uB85C\uC81D\uD2B8\uAC00 \uC313\uC778\uB2E4. \uAC19\uC740 \uC81C\uBAA9\uC73C\uB85C \uB2E4\uC2DC \uBD80\uB974\uBA74 \uC0C8\uB85C \uB9CC\uB4E4\uC9C0 \uC54A\uACE0 **\uAE30\uC874 \uAC83\uC744 \uB3CC\uB824\uC900\uB2E4**(\uC7AC\uC2DC\uB3C4 \uC548\uC804).",
16883
- inputSchema: {
16884
- type: "object",
16885
- properties: {
16886
- title: {
16887
- type: "string",
16888
- description: "\uD504\uB85C\uC81D\uD2B8 \uC774\uB984 1~100\uC790. \uC0AC\uC6A9\uC790\uAC00 \uC54C\uC544\uBCFC \uC218 \uC788\uAC8C \uC9D3\uACE0, \uAC00\uB2A5\uD558\uBA74 \uC0AC\uC6A9\uC790\uAC00 \uBD80\uB978 \uC774\uB984\uC744 \uADF8\uB300\uB85C \uC4F0\uB77C."
18785
+ lines.push("\uB2E4\uC74C \uD638\uCD9C: democut_wait_jobs \uC5D0 \uC704 job_id \uB4E4\uC744 \uB123\uC73C\uC138\uC694.");
18786
+ return { text: lines.join("\n") };
18787
+ });
18788
+ }
18789
+ var WAIT_CHUNK_S = 30;
18790
+ var LIST_LINES = 20;
18791
+ function listing(lines) {
18792
+ if (lines.length <= LIST_LINES) return lines;
18793
+ return [...lines.slice(0, LIST_LINES), ` \u2026\uC678 ${lines.length - LIST_LINES}\uAC1C`];
18794
+ }
18795
+ var ACTIVE_JOB_STATES = /* @__PURE__ */ new Set(["queued", "running"]);
18796
+ function jobLine(j) {
18797
+ const bits = [`${j.job_id} [${j.state}] ${j.kind}`];
18798
+ if (j.progress?.pct != null) bits.push(`${Math.round(j.progress.pct)}%`);
18799
+ if (j.error) bits.push(`\uC624\uB958 ${j.error.code}: ${j.error.message}`);
18800
+ if (j.result?.version != null) bits.push(`\u2192 v${j.result.version}`);
18801
+ return bits.join(" \xB7 ");
18802
+ }
18803
+ function waitJobs(a = {}, deps = {}) {
18804
+ return guarded(READ_ONLY, async () => {
18805
+ const base = resolveBaseUrl(deps.baseUrl);
18806
+ const budget = Math.max(0, Math.min(Math.trunc(a.timeout_s ?? 600), 600));
18807
+ const deadline = Date.now() + budget * 1e3;
18808
+ let ids = [...a.job_ids ?? []];
18809
+ let narrowed = false;
18810
+ const settled = /* @__PURE__ */ new Map();
18811
+ let pending = [];
18812
+ const exploreState = ids.length ? void 0 : a.state;
18813
+ const ignoredState = ids.length && a.state ? a.state : void 0;
18814
+ for (; ; ) {
18815
+ const left = Math.max(0, Math.floor((deadline - Date.now()) / 1e3));
18816
+ const q = new URLSearchParams();
18817
+ if (ids.length) q.set("ids", ids.join(","));
18818
+ if (!narrowed && a.batch_id) q.set("batch_id", a.batch_id);
18819
+ if (!narrowed && a.project) q.set("project", a.project);
18820
+ if (!narrowed && exploreState) q.set("state", exploreState);
18821
+ q.set("wait", String(Math.min(WAIT_CHUNK_S, left)));
18822
+ const out2 = await apiRequest(base, `/api/jobs?${q}`, {}, deps);
18823
+ pending = (out2.jobs ?? []).filter((j) => ACTIVE_JOB_STATES.has(j.state));
18824
+ for (const j of out2.jobs ?? []) {
18825
+ if (!ACTIVE_JOB_STATES.has(j.state)) settled.set(j.job_id, j);
18826
+ }
18827
+ if (pending.length === 0 || left <= 0) break;
18828
+ ids = pending.map((j) => j.job_id);
18829
+ narrowed = true;
18830
+ }
18831
+ const jobs = [...settled.values(), ...pending];
18832
+ const allDone = pending.length === 0;
18833
+ const ordered = [...jobs].sort(
18834
+ (x, y) => Number(!ACTIVE_JOB_STATES.has(x.state)) - Number(!ACTIVE_JOB_STATES.has(y.state))
18835
+ );
18836
+ const lines = [`\uC7A1 ${jobs.length}\uAC1C \u2014 ${allDone ? "\uC804\uBD80 \uB05D\uB0AC\uC2B5\uB2C8\uB2E4" : "\uC544\uC9C1 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4"}`];
18837
+ lines.push(...listing(ordered.map((j) => ` ${jobLine(j)}`)));
18838
+ if (ignoredState !== void 0) {
18839
+ lines.push(`(job_ids \uB97C \uC8FC\uC168\uC73C\uBBC0\uB85C state=${ignoredState} \uD544\uD130\uB294 \uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4 \u2014 \uC694\uCCAD\uD55C id \uC804\uBD80\uB97C \uBD05\uB2C8\uB2E4.)`);
18840
+ }
18841
+ lines.push(
18842
+ allDone ? "\uB05D\uB09C \uC7A1\uC758 \uACB0\uACFC\uB294 democut_get_cut \uC758 versions \uB85C \uD655\uC778\uD558\uACE0 democut_download \uB85C \uB0B4\uB824\uBC1B\uC2B5\uB2C8\uB2E4." : "\uC544\uC9C1 \uC548 \uB05D\uB09C job_ids \uB85C democut_wait_jobs \uB97C \uB2E4\uC2DC \uBD80\uB974\uC138\uC694."
18843
+ );
18844
+ return { text: lines.join("\n") };
18845
+ });
18846
+ }
18847
+ function getCut(a = {}, deps = {}) {
18848
+ return guarded(READ_ONLY, async () => {
18849
+ const slug = needSlug(a);
18850
+ if (typeof slug !== "string") return slug;
18851
+ const cutId = (a.cut_id ?? "").trim();
18852
+ if (!cutId) return { isError: true, text: "cut_id \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4." };
18853
+ const base = resolveBaseUrl(deps.baseUrl);
18854
+ const cut = await apiRequest(base, projectPath(slug, `/cuts/${encodeURIComponent(cutId)}`), {}, deps);
18855
+ const head = [`${cut.id} [${cut.state}] ${cut.mode}`];
18856
+ if (cut.title) head.push(`\u300C${cut.title}\u300D`);
18857
+ if (cut.current_version != null) head.push(`\uB300\uD45C v${cut.current_version}`);
18858
+ if (cut.dirty_fields?.length) head.push(`\uB2EC\uB77C\uC9C4 \uD544\uB4DC: ${cut.dirty_fields.join(", ")}`);
18859
+ if (cut.estimated_cost_krw != null) head.push(`\uC608\uC0C1 ${krw(cut.estimated_cost_krw)}`);
18860
+ if (cut.blocked_reason) head.push(`\uB9C9\uD798: ${cut.blocked_reason}`);
18861
+ const versions = [...cut.versions ?? []].sort((x, y) => y.version - x.version);
18862
+ const lines = [head.join(" \xB7 ")];
18863
+ lines.push(
18864
+ ...listing(
18865
+ versions.map((v) => {
18866
+ const roles = ["video", "audio", "subtitle", "still"].filter((r) => v.download?.[r]);
18867
+ return ` v${v.version} (${v.origin}) ${v.width}x${v.height} ${v.duration_ms}ms \xB7 \uB0B4\uB824\uBC1B\uAE30: ${roles.join(", ") || "\uC5C6\uC74C"}`;
18868
+ })
18869
+ )
18870
+ );
18871
+ if (cut.next_calls?.length) lines.push(`\uB2E4\uC74C \uD638\uCD9C: ${cut.next_calls.join(", ")}`);
18872
+ return { text: lines.join("\n") };
18873
+ });
18874
+ }
18875
+ function download(a = {}, deps = {}) {
18876
+ return guarded(READ_ONLY, async () => {
18877
+ const slug = needSlug(a);
18878
+ if (typeof slug !== "string") return slug;
18879
+ const cutId = (a.cut_id ?? "").trim();
18880
+ if (!cutId) return { isError: true, text: "cut_id \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4." };
18881
+ if (typeof a.version === "boolean" || !Number.isInteger(Number(a.version)) || Number(a.version) < 1) {
18882
+ return { isError: true, text: `version \uC740 1 \uC774\uC0C1\uC758 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4: ${JSON.stringify(a.version)}` };
18883
+ }
18884
+ const version2 = Number(a.version);
18885
+ const kind = a.kind ?? "video";
18886
+ const base = resolveBaseUrl(deps.baseUrl);
18887
+ const q = new URLSearchParams({ kind });
18888
+ const out2 = await apiRequest(
18889
+ base,
18890
+ projectPath(slug, `/cuts/${encodeURIComponent(cutId)}/versions/${version2}/download?${q}`),
18891
+ {},
18892
+ deps
18893
+ );
18894
+ if (a.output_path) {
18895
+ await (deps.downloadImpl ? deps.downloadImpl(out2.url, a.output_path) : saveUrlToFile(out2.url, a.output_path, deps.fetchImpl ?? fetch));
18896
+ return { text: `${kind} \uB97C \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4: ${a.output_path}` };
18897
+ }
18898
+ return {
18899
+ text: [
18900
+ `${kind} \uB0B4\uB824\uBC1B\uAE30 \uC8FC\uC18C (\uB9CC\uB8CC ${out2.expires_at}):`,
18901
+ out2.url,
18902
+ "output_path \uB97C \uC8FC\uBA74 \uC774 \uD30C\uC77C\uC744 \uADF8 \uACBD\uB85C\uC5D0 \uBC14\uB85C \uC800\uC7A5\uD569\uB2C8\uB2E4."
18903
+ ].join("\n")
18904
+ };
18905
+ });
18906
+ }
18907
+ function importCut(a = {}, deps = {}) {
18908
+ return guarded(SUBMITTING, async () => {
18909
+ const slug = needSlug(a);
18910
+ if (typeof slug !== "string") return slug;
18911
+ const cutId = (a.cut_id ?? "").trim();
18912
+ if (!cutId) return { isError: true, text: "cut_id \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4 \u2014 \uB4F1\uB85D\uD560 \uCEF7\uC774 \uC774\uBBF8 \uC788\uC5B4\uC57C \uD569\uB2C8\uB2E4." };
18913
+ const base = resolveBaseUrl(deps.baseUrl);
18914
+ const out2 = await apiRequest(
18915
+ base,
18916
+ projectPath(slug, `/cuts/${encodeURIComponent(cutId)}/import`),
18917
+ {
18918
+ method: "POST",
18919
+ body: {
18920
+ video_asset_id: a.video_asset_id,
18921
+ dialogue: a.dialogue,
18922
+ transcribe: a.transcribe ?? false,
18923
+ confirmed_total_krw: a.confirmed_total_krw ?? 0,
18924
+ rate_version: a.rate_version
16889
18925
  }
16890
18926
  },
16891
- required: ["title"],
16892
- additionalProperties: false
18927
+ deps
18928
+ );
18929
+ const total = out2.quote?.total_krw ?? 0;
18930
+ return {
18931
+ text: [
18932
+ `\uCEF7 ${out2.cut_id} \uC5D0 \uC601\uC0C1\uC744 \uB4F1\uB85D\uD558\uB294 \uC911\uC785\uB2C8\uB2E4 \u2014 ${out2.job_id}`,
18933
+ `\uCCAD\uAD6C ${krw(total)}${total === 0 ? " (\uD569\uC131\uC740 \uD558\uC9C0 \uC54A\uC73C\uBBC0\uB85C 0\uC6D0\uC785\uB2C8\uB2E4)" : " (\uC790\uB9C9 \uC804\uC0AC)"}`,
18934
+ "democut_wait_jobs \uB85C \uB05D\uB098\uBA74 democut_get_cut \uC758 versions \uC5D0 \uC0C8 \uBC84\uC804\uC774 \uC0DD\uAE41\uB2C8\uB2E4."
18935
+ ].join("\n")
18936
+ };
18937
+ });
18938
+ }
18939
+ function cancelJob(a = {}, deps = {}) {
18940
+ return guarded(READ_ONLY, async () => {
18941
+ const jobId = (a.job_id ?? "").trim();
18942
+ if (!jobId) return { isError: true, text: "job_id \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4." };
18943
+ const base = resolveBaseUrl(deps.baseUrl);
18944
+ const out2 = await apiRequest(
18945
+ base,
18946
+ `/api/jobs/${encodeURIComponent(jobId)}`,
18947
+ { method: "DELETE" },
18948
+ deps
18949
+ );
18950
+ const lines = [];
18951
+ if (out2.cancelled?.length) lines.push(`\uCDE8\uC18C\uD588\uC2B5\uB2C8\uB2E4: ${out2.cancelled.join(", ")}`);
18952
+ if (out2.not_cancellable?.length) lines.push(`\uCDE8\uC18C\uD560 \uC218 \uC5C6\uC5C8\uC2B5\uB2C8\uB2E4: ${out2.not_cancellable.join(", ")}`);
18953
+ if (lines.length === 0) {
18954
+ lines.push("\uC774\uBBF8 \uB05D\uB09C \uC7A1\uC785\uB2C8\uB2E4 \u2014 \uCDE8\uC18C\uD560 \uAC83\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(\uAC19\uC740 \uC694\uCCAD\uC744 \uB2E4\uC2DC \uBCF4\uB0B4\uB3C4 \uC548\uC804\uD569\uB2C8\uB2E4).");
16893
18955
  }
16894
- }
16895
- ];
18956
+ lines.push(
18957
+ `\uD658\uBD88 ${krw(out2.refunded_krw ?? 0)}`,
18958
+ "queued \uC600\uB2E4\uBA74 \uC804\uC561, running \uC774\uBA74 \uC2E4\uD589\uAE30\uAC00 \uBA48\uCD98 \uB4A4 \uC815\uC0B0\uD569\uB2C8\uB2E4 \u2014 \uACF5\uAE09\uC790\uAC00 \uC774\uBBF8 \uACFC\uAE08\uD55C \uD589\uC740 \uD658\uBD88\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(AI \uC601\uC0C1\uC740 \uC81C\uCD9C \uB4A4 \uCDE8\uC18C\uAC00 \uB9C9\uD799\uB2C8\uB2E4)."
18959
+ );
18960
+ return { text: lines.join("\n") };
18961
+ });
18962
+ }
18963
+
18964
+ // src/mcp/server.ts
18965
+ var TOOLS = GENERATED_TOOLS;
16896
18966
  function dispatch(name, args, deps = {}) {
16897
18967
  switch (name) {
16898
18968
  case "democut_auth_status":
16899
18969
  return authStatus(deps);
16900
- case "democut_estimate_video_cost":
16901
- return estimateCost(args, deps);
16902
- case "democut_generate_video":
16903
- return generateVideo(args, deps);
16904
- case "democut_get_video_status":
16905
- return videoStatus(args, deps);
16906
18970
  case "democut_credit_balance":
16907
18971
  return creditBalance(deps);
16908
18972
  case "democut_credit_ledger":
@@ -16911,6 +18975,24 @@ function dispatch(name, args, deps = {}) {
16911
18975
  return listProjects(args, deps);
16912
18976
  case "democut_create_project":
16913
18977
  return createProject(args, deps);
18978
+ case "democut_get_options":
18979
+ return getOptions(args, deps);
18980
+ case "democut_upload_asset":
18981
+ return uploadAsset(args, deps);
18982
+ case "democut_estimate_cuts":
18983
+ return estimateCuts(args, deps);
18984
+ case "democut_make_cuts":
18985
+ return makeCuts(args, deps);
18986
+ case "democut_wait_jobs":
18987
+ return waitJobs(args, deps);
18988
+ case "democut_get_cut":
18989
+ return getCut(args, deps);
18990
+ case "democut_download":
18991
+ return download(args, deps);
18992
+ case "democut_import_cut":
18993
+ return importCut(args, deps);
18994
+ case "democut_cancel_job":
18995
+ return cancelJob(args, deps);
16914
18996
  default:
16915
18997
  return Promise.resolve({ isError: true, text: `\uC54C \uC218 \uC5C6\uB294 \uB3C4\uAD6C: ${name}` });
16916
18998
  }
@@ -16938,37 +19020,18 @@ async function runMcpServer(deps = {}) {
16938
19020
  }
16939
19021
 
16940
19022
  // src/cli.ts
16941
- var HELP = `democut \u2014 DemoCut \uC5D0\uC774\uC804\uD2B8 CLI (OAuth2 device flow + \uC601\uC0C1 \uC0DD\uC131)
19023
+ var HELP = `democut \u2014 DemoCut \uC5D0\uC774\uC804\uD2B8 CLI (OAuth2 device flow + MCP)
16942
19024
 
16943
19025
  \uC0AC\uC6A9\uBC95:
16944
19026
  democut auth login [--no-browser] [--json] [--base-url <url>]
16945
19027
  democut auth status [--json] [--base-url <url>]
16946
19028
  democut auth logout [--base-url <url>]
16947
19029
 
16948
- democut video estimate [--duration <\uCD08>] [--resolution <\uD574\uC0C1\uB3C4>] [--ratio <\uBE44\uC728>] [--model <id>]
16949
- democut video generate "<\uD504\uB86C\uD504\uD2B8>" --project <slug> [--yes] [--wait] [--output <\uACBD\uB85C>] [\uC0DD\uC131 \uC635\uC158\u2026]
16950
- democut video status <job_id> [--wait] [--output <\uACBD\uB85C>]
16951
-
16952
19030
  democut mcp MCP \uC11C\uBC84(stdio) \u2014 \uC5D0\uC774\uC804\uD2B8\uC5D0 \uB3C4\uAD6C\uB85C \uBD99\uC778\uB2E4
16953
19031
  \uB4F1\uB85D: claude mcp add democut -- npx -y democut@latest mcp
16954
19032
  (@latest \uD544\uC218 \u2014 -y \uB294 npx \uCE90\uC2DC\uC758 \uC61B \uBC84\uC804\uC744 \uADF8\uB300\uB85C \uB744\uC6B4\uB2E4)
16955
19033
 
16956
- \uC0DD\uC131 \uC635\uC158:
16957
- --duration <\uCD08> \uAE30\uBCF8 5 (\uBAA8\uB378\uBCC4 \uD5C8\uC6A9 \uBC94\uC704 \uB2E4\uB984: 2.0=4~15, 2.5=4~30)
16958
- --resolution <r> 480p | 720p(\uAE30\uBCF8) | 1080p | 4k
16959
- --ratio <a> 16:9(\uAE30\uBCF8) | 9:16 | 1:1 | 4:3 | 21:9 | adaptive
16960
- --model <id> \uAE30\uBCF8 \uC11C\uBC84 \uC124\uC815\uAC12
16961
- --seed <n> \uACB0\uC815\uB860\uC801 \uC0DD\uC131\uC6A9 seed
16962
- --image-url <url> image\u2192video \uCC38\uC870 (\uACF5\uAC1C HTTPS URL, \uCD5C\uB300 4\uD68C \uBC18\uBCF5)
16963
- --audio \uC624\uB514\uC624 \uD568\uAED8 \uC0DD\uC131
16964
- --watermark \uC6CC\uD130\uB9C8\uD06C \uB123\uAE30
16965
- --project <slug> \uBE44\uC6A9\uC744 \uC774 \uD504\uB85C\uC81D\uD2B8\uB85C \uADC0\uC18D (generate \uD544\uC218 \u2014 \uBCF8\uC778 \uC18C\uC720 \uC2AC\uB7EC\uADF8)
16966
-
16967
19034
  \uACF5\uD1B5 \uC635\uC158:
16968
- -y, --yes \uBE44\uC6A9 \uD655\uC778 \uC5C6\uC774 \uC9C4\uD589 (\uBE44\uB300\uD654\uD615\uC5D0\uC11C\uB294 \uD544\uC218)
16969
- --wait \uC644\uB8CC\uAE4C\uC9C0 \uAE30\uB2E4\uB9BC
16970
- --timeout <\uCD08> --wait \uC2DC\uD55C (\uAE30\uBCF8 900)
16971
- -o, --output <\uACBD\uB85C> \uC0B0\uCD9C\uBB3C \uC800\uC7A5 (\uC11C\uBC84\uB294 \uBCF4\uAD00\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2014 \uBC1B\uC544 \uB450\uC138\uC694)
16972
19035
  --json \uAE30\uACC4 \uD310\uB3C5\uC6A9 JSON \uD55C \uC904
16973
19036
  --base-url <u> DemoCut \uC11C\uBC84 URL (\uAE30\uBCF8: $DEMOCUT_BASE_URL \uB610\uB294 prod)
16974
19037
  -h, --help \uB3C4\uC6C0\uB9D0
@@ -16977,32 +19040,18 @@ var HELP = `democut \u2014 DemoCut \uC5D0\uC774\uC804\uD2B8 CLI (OAuth2 device f
16977
19040
  \uC885\uB8CC \uCF54\uB4DC:
16978
19041
  0 \uC131\uACF5 1 \uC77C\uBC18 \uC624\uB958(\uBBF8\uB85C\uADF8\uC778\xB7\uCDE8\uC18C\xB7\uC0DD\uC131 \uC2E4\uD328) 2 \uACE0\uCCD0\uC11C \uC7AC\uC2DC\uB3C4 \uAC00\uB2A5(\uACFC\uAE08 \uC5C6\uC74C)
16979
19042
  3 \uC77C\uC2DC \uC624\uB958(\uADF8\uB300\uB85C \uC7AC\uC2DC\uB3C4 \uC548\uC804) 4 \uC5C5\uC2A4\uD2B8\uB9BC \uAC70\uBD80(\uC7AC\uC2DC\uB3C4 \uC2DC \uC7AC\uACFC\uAE08 \uC704\uD5D8)
16980
- 5 --wait \uC2DC\uD55C \uCD08\uACFC \u2014 \uC2E4\uD328 \uC544\uB2D8. \uC791\uC5C5\uC740 \uACC4\uC18D \uC9C4\uD589 \uC911\uC774\uB2C8 status \uB85C \uD655\uC778(\uC7AC\uC81C\uCD9C \uAE08\uC9C0)`;
19043
+ 5 \uB300\uAE30 \uC2DC\uD55C \uCD08\uACFC(\uC608\uC57D \u2014 \uC61B video --wait \uC758 \uCF54\uB4DC, \uC2E4\uD328 \uC544\uB2D8\xB7\uC7AC\uC81C\uCD9C \uAE08\uC9C0 \uC758\uBBF8\uB294 \uC720\uC9C0)`;
16981
19044
  var VALUE_FLAGS = {
16982
- "--base-url": "baseUrl",
16983
- "--duration": "duration",
16984
- "--resolution": "resolution",
16985
- "--ratio": "ratio",
16986
- "--model": "model",
16987
- "--seed": "seed",
16988
- "--project": "project",
16989
- "--output": "output",
16990
- "-o": "output",
16991
- "--timeout": "timeout"
19045
+ "--base-url": "baseUrl"
16992
19046
  };
16993
19047
  var BOOL_FLAGS = {
16994
19048
  "--no-browser": "noBrowser",
16995
19049
  "--device": "noBrowser",
16996
- "--json": "json",
16997
- "--yes": "yes",
16998
- "-y": "yes",
16999
- "--wait": "wait",
17000
- "--audio": "audio",
17001
- "--watermark": "watermark"
19050
+ "--json": "json"
17002
19051
  };
17003
19052
  var HELP_FLAGS = /* @__PURE__ */ new Set(["-h", "--help", "-v", "--version"]);
17004
19053
  function isKnownFlag(token) {
17005
- return token in VALUE_FLAGS || token in BOOL_FLAGS || HELP_FLAGS.has(token) || token === "--image-url" || token.startsWith("--image-url=");
19054
+ return token in VALUE_FLAGS || token in BOOL_FLAGS || HELP_FLAGS.has(token);
17006
19055
  }
17007
19056
  function parseArgs(argv) {
17008
19057
  const positional = [];
@@ -17020,11 +19069,6 @@ function parseArgs(argv) {
17020
19069
  version2 = true;
17021
19070
  continue;
17022
19071
  }
17023
- if (a === "--image-url" || a.startsWith("--image-url=")) {
17024
- const v = a.startsWith("--image-url=") ? a.slice("--image-url=".length) : argv[++i];
17025
- if (v) (options.imageUrls ??= []).push(v);
17026
- continue;
17027
- }
17028
19072
  const boolKey = BOOL_FLAGS[a];
17029
19073
  if (boolKey) {
17030
19074
  options[boolKey] = true;
@@ -17085,15 +19129,6 @@ ${HELP}
17085
19129
  return EXIT.FIXABLE;
17086
19130
  }
17087
19131
  if (group === "mcp") return runMcpServer({ ...deps, baseUrl: options.baseUrl });
17088
- if (group === "video") {
17089
- if (sub === "estimate") return estimateCommand(options, deps);
17090
- if (sub === "generate") return generateCommand(arg, options, deps);
17091
- if (sub === "status") return statusCommand2(arg, options, deps);
17092
- process.stderr.write(`\uC54C \uC218 \uC5C6\uB294 video \uBA85\uB839: ${sub ?? "(\uC5C6\uC74C)"}
17093
- ${HELP}
17094
- `);
17095
- return EXIT.FIXABLE;
17096
- }
17097
19132
  process.stderr.write(`\uC54C \uC218 \uC5C6\uB294 \uBA85\uB839: ${group}
17098
19133
  ${HELP}
17099
19134
  `);