democut 1.0.108 → 1.0.110

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 +4 -1
  2. package/dist/cli.js +224 -40
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -229,9 +229,12 @@ SSOT 는 `apps/api/app/mcp/auth.py` docstring.
229
229
  **CI 가 자동으로 한다.** 사람이 순서를 기억할 필요가 없다.
230
230
 
231
231
  ```
232
- promote(사람이 누르는 버튼) → npm-publish-cli → deploy-dgx
232
+ promote(사람이 누르는 버튼) → deploy-dgx → npm-publish-cli
233
233
  ```
234
234
 
235
+ 게시는 **API 배포가 끝난 뒤**다(2026-10-20) — 새 CLI 가 새 요청 필드를 아직 모르는 API 에 닿지 않는다. 배포가 실패하면
236
+ 게시하지 않는다. 레지스트리의 `latest` 가 이미 더 높은 버전이면(늦게 돈 옛 파이프라인) 게시하지 않는다.
237
+
235
238
  게시는 **trusted publishing(OIDC)** 으로 한다 — 장수명 토큰 없이 CI 가 짧은 수명 자격증명으로
236
239
  게시한다. npm 이 2027-01 부터 2FA 우회 토큰의 직접 publish 를 막기 때문이고, 그래서 CI 의 node
237
240
  이미지가 24 다(OIDC 는 npm 11.5.1+ 요구).
package/dist/cli.js CHANGED
@@ -505,17 +505,17 @@ var require_codegen = __commonJS({
505
505
  this.nodes = nodes;
506
506
  }
507
507
  render(opts) {
508
- return this.nodes.reduce((code, n) => code + n.render(opts), "");
508
+ return this.nodes.reduce((code, n2) => code + n2.render(opts), "");
509
509
  }
510
510
  optimizeNodes() {
511
511
  const { nodes } = this;
512
512
  let i = nodes.length;
513
513
  while (i--) {
514
- const n = nodes[i].optimizeNodes();
515
- if (Array.isArray(n))
516
- nodes.splice(i, 1, ...n);
517
- else if (n)
518
- nodes[i] = n;
514
+ const n2 = nodes[i].optimizeNodes();
515
+ if (Array.isArray(n2))
516
+ nodes.splice(i, 1, ...n2);
517
+ else if (n2)
518
+ nodes[i] = n2;
519
519
  else
520
520
  nodes.splice(i, 1);
521
521
  }
@@ -525,16 +525,16 @@ var require_codegen = __commonJS({
525
525
  const { nodes } = this;
526
526
  let i = nodes.length;
527
527
  while (i--) {
528
- const n = nodes[i];
529
- if (n.optimizeNames(names, constants))
528
+ const n2 = nodes[i];
529
+ if (n2.optimizeNames(names, constants))
530
530
  continue;
531
- subtractNames(names, n.names);
531
+ subtractNames(names, n2.names);
532
532
  nodes.splice(i, 1);
533
533
  }
534
534
  return nodes.length > 0 ? this : void 0;
535
535
  }
536
536
  get names() {
537
- return this.nodes.reduce((names, n) => addNames(names, n.names), {});
537
+ return this.nodes.reduce((names, n2) => addNames(names, n2.names), {});
538
538
  }
539
539
  };
540
540
  var BlockNode = class extends ParentNode {
@@ -945,8 +945,8 @@ var require_codegen = __commonJS({
945
945
  endFunc() {
946
946
  return this._endBlockNode(Func);
947
947
  }
948
- optimize(n = 1) {
949
- while (n-- > 0) {
948
+ optimize(n2 = 1) {
949
+ while (n2-- > 0) {
950
950
  this._root.optimizeNodes();
951
951
  this._root.optimizeNames(this._root.names, this._constants);
952
952
  }
@@ -960,19 +960,19 @@ var require_codegen = __commonJS({
960
960
  this._nodes.push(node);
961
961
  }
962
962
  _endBlockNode(N1, N2) {
963
- const n = this._currNode;
964
- if (n instanceof N1 || N2 && n instanceof N2) {
963
+ const n2 = this._currNode;
964
+ if (n2 instanceof N1 || N2 && n2 instanceof N2) {
965
965
  this._nodes.pop();
966
966
  return this;
967
967
  }
968
968
  throw new Error(`CodeGen: not in block "${N2 ? `${N1.kind}/${N2.kind}` : N1.kind}"`);
969
969
  }
970
970
  _elseNode(node) {
971
- const n = this._currNode;
972
- if (!(n instanceof If)) {
971
+ const n2 = this._currNode;
972
+ if (!(n2 instanceof If)) {
973
973
  throw new Error('CodeGen: "else" without "if"');
974
974
  }
975
- this._currNode = n.else = node;
975
+ this._currNode = n2.else = node;
976
976
  return this;
977
977
  }
978
978
  get _root() {
@@ -989,8 +989,8 @@ var require_codegen = __commonJS({
989
989
  };
990
990
  exports.CodeGen = CodeGen;
991
991
  function addNames(names, from) {
992
- for (const n in from)
993
- names[n] = (names[n] || 0) + (from[n] || 0);
992
+ for (const n2 in from)
993
+ names[n2] = (names[n2] || 0) + (from[n2] || 0);
994
994
  return names;
995
995
  }
996
996
  function addExprNames(names, from) {
@@ -1010,11 +1010,11 @@ var require_codegen = __commonJS({
1010
1010
  items.push(c);
1011
1011
  return items;
1012
1012
  }, []));
1013
- function replaceName(n) {
1014
- const c = constants[n.str];
1015
- if (c === void 0 || names[n.str] !== 1)
1016
- return n;
1017
- delete names[n.str];
1013
+ function replaceName(n2) {
1014
+ const c = constants[n2.str];
1015
+ if (c === void 0 || names[n2.str] !== 1)
1016
+ return n2;
1017
+ delete names[n2.str];
1018
1018
  return c;
1019
1019
  }
1020
1020
  function canOptimize(e) {
@@ -1022,8 +1022,8 @@ var require_codegen = __commonJS({
1022
1022
  }
1023
1023
  }
1024
1024
  function subtractNames(names, from) {
1025
- for (const n in from)
1026
- names[n] = (names[n] || 0) - (from[n] || 0);
1025
+ for (const n2 in from)
1026
+ names[n2] = (names[n2] || 0) - (from[n2] || 0);
1027
1027
  }
1028
1028
  function not(x) {
1029
1029
  return typeof x == "boolean" || typeof x == "number" || x === null ? !x : (0, code_1._)`!${par(x)}`;
@@ -6916,7 +6916,7 @@ import { realpathSync } from "fs";
6916
6916
  import { fileURLToPath } from "url";
6917
6917
 
6918
6918
  // src/version.ts
6919
- var VERSION = "1.0.108";
6919
+ var VERSION = "1.0.110";
6920
6920
 
6921
6921
  // src/device-flow.ts
6922
6922
  var DeviceFlowError = class extends Error {
@@ -9339,6 +9339,112 @@ var GENERATED_TOOLS = [
9339
9339
  "openWorldHint": false
9340
9340
  }
9341
9341
  },
9342
+ {
9343
+ "name": "democut_channel_stats",
9344
+ "description": "\uC5F0\uACB0\uD55C \uC720\uD29C\uBE0C \uCC44\uB110\uC758 \uC131\uACFC(0\uC6D0, \uBD80\uC791\uC6A9 \uC5C6\uC74C). \u300C\uC62C\uB9B0 \uC601\uC0C1\uC774 \uC5BC\uB9C8\uB098 \uBD24\uB098\xB7\uAD6C\uB3C5\uC790\uAC00 \uB298\uC5C8\uB098\u300D \uB97C \uB2F5\uD560 \uB54C \uC4F4\uB2E4 \u2014 \uCC44\uB110 \uC694\uC57D(\uAD6C\uB3C5\uC790\xB7\uB204\uC801 \uC870\uD68C\xB7\uACF5\uAC1C \uC601\uC0C1 \uC218), \uAE30\uAC04 \uD569\uACC4\uC640 \uC77C\uBCC4 \uCD94\uC774, DemoCut \uC73C\uB85C \uC62C\uB9B0 \uC601\uC0C1\uBCC4 \uC870\uD68C\xB7\uC88B\uC544\uC694\xB7\uB313\uAE00. range: 28d(\uAE30\uBCF8)\xB790d. \uC218\uCE58\uB294 \uC8FC\uAE30 \uC218\uC9D1\uD55C \uC2A4\uB0C5\uC0F7\uC774\uB77C \uC2E4\uC2DC\uAC04\uC774 \uC544\uB2C8\uB2E4 \u2014 `collected_at` \uC774 \uAE30\uC900 \uC2DC\uAC01\uC774\uACE0 `stale`\xB7`last_error` \uAC00 \uAC31\uC2E0\uC774 \uBA48\uCD98 \uAC83\uC744 \uB9D0\uD55C\uB2E4. \u2605 \uAD6C\uB3C5\uC790 \uC218\uB294 \uC720\uD29C\uBE0C\uAC00 \uC138 \uC790\uB9AC \uC720\uD6A8\uC22B\uC790\uB85C \uB0B4\uB9BC\uD55C \uAC12\uC774\uB77C \uC99D\uAC10\uACFC \uB354\uD574 \uB9DE\uCD94\uB824 \uD558\uBA74 \uC5B4\uAE0B\uB09C\uB2E4(\uC815\uD655\uD55C \uC99D\uAC10\uC740 subscribers_gained\xB7subscribers_lost). \u2605 \uBE44\uACF5\uAC1C\xB7\uC77C\uBD80 \uACF5\uAC1C\uB85C \uC62C\uB9B0 \uC601\uC0C1\uC740 \uC218\uCE58\uAC00 0 \uC778 \uAC83\uC774 \uC815\uC0C1\uC774\uB2E4(\uAC80\uC0C9\xB7\uCD94\uCC9C\uC5D0 \uB728\uC9C0 \uC54A\uB294\uB2E4). \uC378\uB124\uC77C \uB178\uCD9C\uC218\xB7\uB178\uCD9C \uD074\uB9AD\uB960\uC740 \uC720\uD29C\uBE0C\uAC00 API \uB85C \uC8FC\uC9C0 \uC54A\uC544 \uB2F5\uD560 \uC218 \uC5C6\uB2E4.",
9345
+ "inputSchema": {
9346
+ "type": "object",
9347
+ "properties": {
9348
+ "range": {
9349
+ "default": "28d",
9350
+ "description": "28d = \uC624\uB298\uAE4C\uC9C0 28\uC77C(\uAE30\uBCF8), 90d = \uC624\uB298\uAE4C\uC9C0 90\uC77C. \uBE44\uAD50 \uAE30\uAC04\uC740 \uBC14\uB85C \uC55E\uC758 \uAC19\uC740 \uAE38\uC774\uB2E4",
9351
+ "enum": [
9352
+ "28d",
9353
+ "90d"
9354
+ ],
9355
+ "type": "string"
9356
+ }
9357
+ },
9358
+ "required": [],
9359
+ "additionalProperties": false
9360
+ },
9361
+ "outputSchema": {
9362
+ "type": "object",
9363
+ "properties": {
9364
+ "connected": {
9365
+ "type": "boolean"
9366
+ },
9367
+ "channel_id": {},
9368
+ "channel_title": {},
9369
+ "channel_url": {},
9370
+ "collected_at": {},
9371
+ "stale": {
9372
+ "type": "boolean"
9373
+ },
9374
+ "last_error": {},
9375
+ "subscriber_count": {},
9376
+ "subscriber_count_hidden": {
9377
+ "type": "boolean"
9378
+ },
9379
+ "lifetime_view_count": {},
9380
+ "public_video_count": {},
9381
+ "range": {
9382
+ "type": "string"
9383
+ },
9384
+ "start_date": {
9385
+ "type": "string"
9386
+ },
9387
+ "end_date": {
9388
+ "type": "string"
9389
+ },
9390
+ "views": {
9391
+ "type": "integer"
9392
+ },
9393
+ "minutes_watched": {
9394
+ "type": "integer"
9395
+ },
9396
+ "subscribers_gained": {
9397
+ "type": "integer"
9398
+ },
9399
+ "subscribers_lost": {
9400
+ "type": "integer"
9401
+ },
9402
+ "likes": {
9403
+ "type": "integer"
9404
+ },
9405
+ "comments": {
9406
+ "type": "integer"
9407
+ },
9408
+ "shares": {
9409
+ "type": "integer"
9410
+ },
9411
+ "compare_start_date": {
9412
+ "type": "string"
9413
+ },
9414
+ "compare_end_date": {
9415
+ "type": "string"
9416
+ },
9417
+ "compare_views": {
9418
+ "type": "integer"
9419
+ },
9420
+ "daily": {
9421
+ "type": "array"
9422
+ },
9423
+ "videos": {
9424
+ "type": "array"
9425
+ },
9426
+ "published_count": {
9427
+ "type": "integer"
9428
+ },
9429
+ "not_public_count": {
9430
+ "type": "integer"
9431
+ }
9432
+ },
9433
+ "required": [
9434
+ "range",
9435
+ "start_date",
9436
+ "end_date",
9437
+ "compare_start_date",
9438
+ "compare_end_date"
9439
+ ]
9440
+ },
9441
+ "annotations": {
9442
+ "readOnlyHint": true,
9443
+ "destructiveHint": false,
9444
+ "idempotentHint": true,
9445
+ "openWorldHint": false
9446
+ }
9447
+ },
9342
9448
  {
9343
9449
  "name": "democut_list_characters",
9344
9450
  "description": "\uC544\uBC14\uD0C0 \uBAA9\uB85D.",
@@ -10916,7 +11022,7 @@ var GENERATED_TOOLS = [
10916
11022
  },
10917
11023
  {
10918
11024
  "name": "democut_set_cut_bgm",
10919
- "description": "\uCEF7\uC5D0 \uAE54 \uBC30\uACBD\uC74C\uC545\uC744 \uC815\uD55C\uB2E4(0\uC6D0). \uCEF7 \uC601\uC0C1\uC740 \uADF8\uB300\uB85C\uC774\uACE0 \uC644\uC131\uBCF8\uC744 \uB9CC\uB4E4 \uB54C \uC11E\uC778\uB2E4 \u2014 \uBC14\uAFBC \uB4A4 democut_make_export \uB9CC \uB2E4\uC2DC \uD558\uBA74 \uB41C\uB2E4. bgm = {asset_id(\uC62C\uB824 \uB454 audio \uC790\uC0B0 \u2014 democut_upload_asset kind=audio), cut_start_ms\xB7cut_end_ms(\uCEF7\uC758 \uC5B4\uB514\uBD80\uD130 \uC5B4\uB514\uAE4C\uC9C0, \uBE44\uC6B0\uBA74 \uCEF7 \uC804\uCCB4), song_start_ms\xB7song_end_ms(\uACE1\uC758 \uC5B4\uB514\uBD80\uD130 \uC5B4\uB514\uAE4C\uC9C0), volume(0~2, \uAE30\uBCF8 1)}. song_start_ms \uB97C \uBE44\uC6B0\uBA74 \uC790\uB3D9\uC774\uB2E4: \uBC14\uB85C \uC55E \uCEF7\uC774 \uAC19\uC740 \uACE1\uC774\uBA74 \uADF8 \uACE1\uC774 \uB4E4\uB9B0 \uC790\uB9AC\uC5D0\uC11C \uC774\uC5B4\uC9C0\uACE0(\uD55C \uACE1\uC744 \uC5EC\uB7EC \uCEF7\uC5D0 \uAC78\uCCD0 \uAE54 \uB54C \uADF8\uB0E5 \uAC19\uC740 asset_id \uB9CC \uC8FC\uBA74 \uB41C\uB2E4), \uC544\uB2C8\uBA74 \uCC98\uC74C\uBD80\uD130\uB2E4. 0 \uC744 \uC8FC\uBA74 \uCC98\uC74C\uBD80\uD130 \uB2E4\uC2DC \uD2BC\uB2E4. \uACE1\uC774 \uBAA8\uC790\uB77C\uBA74 \uBC18\uBCF5\uD558\uC9C0 \uC54A\uACE0 \uC870\uC6A9\uD574\uC9C4\uB2E4. \uADF8 \uCEF7\uC758 \uC55E\uB4A4 \uC790\uB974\uAE30\xB7\uBB34\uC74C \uC790\uB974\uAE30(democut_set_cut_edit)\uB294 \uC74C\uC545\uC5D0\uB3C4 \uAC19\uC774 \uAC78\uB9B0\uB2E4(\uC798\uB9B0 \uD654\uBA74\uC758 \uC74C\uC545\uC740 \uD568\uAED8 \uBE60\uC9C4\uB2E4). \uBC30\uC18D\uC740 \uC601\uC0C1\uC5D0\uB9CC \uAC78\uB9AC\uACE0 \uC74C\uC545\uC740 \uC81C \uC18D\uB3C4\uB85C \uD750\uB978\uB2E4. \uB9D0\uC18C\uB9AC\uAC00 \uC788\uB294 \uAD6C\uAC04\uC5D0\uC11C\uB294 \uC74C\uC545\uC774 \uC790\uB3D9\uC73C\uB85C \uB0AE\uC544\uC9C4\uB2E4. bgm \uC744 null \uB85C \uC8FC\uBA74 \uC74C\uC545\uC744 \uBE80\uB2E4. democut_set_cut_edit\xB7democut_put_cut_draft \uC640 \uB2E4\uB978 \uAC12\uC774\uB77C \uC11C\uB85C \uC9C0\uC6B0\uC9C0 \uC54A\uB294\uB2E4.",
11025
+ "description": "\uCEF7\uC5D0 \uAE54 \uBC30\uACBD\uC74C\uC545\uC744 \uC815\uD55C\uB2E4(0\uC6D0). \uCEF7 \uC601\uC0C1\uC740 \uADF8\uB300\uB85C\uC774\uACE0 \uC644\uC131\uBCF8\uC744 \uB9CC\uB4E4 \uB54C \uC11E\uC778\uB2E4 \u2014 \uBC14\uAFBC \uB4A4 democut_make_export \uB9CC \uB2E4\uC2DC \uD558\uBA74 \uB41C\uB2E4. bgm = {asset_id(\uC62C\uB824 \uB454 audio \uC790\uC0B0 \u2014 democut_upload_asset kind=audio), cut_start_ms\xB7cut_end_ms(\uCEF7\uC758 \uC5B4\uB514\uBD80\uD130 \uC5B4\uB514\uAE4C\uC9C0, \uBE44\uC6B0\uBA74 \uCEF7 \uC804\uCCB4), song_start_ms\xB7song_end_ms(\uACE1\uC758 \uC5B4\uB514\uBD80\uD130 \uC5B4\uB514\uAE4C\uC9C0), volume(0~2, \uAE30\uBCF8 1)}. song_start_ms \uB97C \uBE44\uC6B0\uBA74 \uC790\uB3D9\uC774\uB2E4: \uBC14\uB85C \uC55E \uCEF7\uC774 \uAC19\uC740 \uACE1\uC774\uBA74 \uADF8 \uACE1\uC774 \uB4E4\uB9B0 \uC790\uB9AC\uC5D0\uC11C \uC774\uC5B4\uC9C0\uACE0(\uD55C \uACE1\uC744 \uC5EC\uB7EC \uCEF7\uC5D0 \uAC78\uCCD0 \uAE54 \uB54C \uADF8\uB0E5 \uAC19\uC740 asset_id \uB9CC \uC8FC\uBA74 \uB41C\uB2E4), \uC544\uB2C8\uBA74 \uCC98\uC74C\uBD80\uD130\uB2E4. 0 \uC744 \uC8FC\uBA74 \uCC98\uC74C\uBD80\uD130 \uB2E4\uC2DC \uD2BC\uB2E4. \uACE1\uC774 \uBAA8\uC790\uB77C\uBA74 \uBC18\uBCF5\uD558\uC9C0 \uC54A\uACE0 \uC870\uC6A9\uD574\uC9C4\uB2E4. \u2605 \uBBA4\uC9C1\uBE44\uB514\uC624 \uCEF7(host=music)\uC5D0\uC11C\uB294 \uB2E4\uB974\uB2E4 \u2014 \uC601\uC0C1\uC774 \uADF8 \uACE1 \uAD6C\uAC04\uC744 \uB4E4\uACE0 \uB9CC\uB4E4\uC5B4\uC9C0\uBBC0\uB85C \uC11C\uBC84\uAC00 **\uC800\uC7A5\uD560 \uB54C** \uADF8 \uC790\uB9AC\uB97C \uC22B\uC790\uB85C \uD655\uC815\uD574 \uB3CC\uB824\uC900\uB2E4. \uD655\uC815\uB41C \uB4A4\uC5D0\uB294 \uC21C\uC11C\uB098 \uC55E \uCEF7 \uAE38\uC774\uB97C \uBC14\uAFD4\uB3C4 \uB530\uB77C \uC6C0\uC9C1\uC774\uC9C0 \uC54A\uC73C\uB2C8, \uBC14\uAFE8\uC73C\uBA74 \uADF8 \uCEF7\uC5D0 \uACE1\uC744 \uB2E4\uC2DC \uC9C0\uC815\uD558\uB77C. \uACE1 \uAE38\uC774\uB97C \uBAA8\uB974\uBA74 \uD655\uC815\uD558\uC9C0 \uC54A\uACE0, \uADF8 \uCEF7\uC740 \uB9CC\uB4E4 \uB54C MUSIC_START_REQUIRED \uB85C \uB9C9\uD78C\uB2E4. \uADF8 \uCEF7\uC758 \uC55E\uB4A4 \uC790\uB974\uAE30\xB7\uBB34\uC74C \uC790\uB974\uAE30(democut_set_cut_edit)\uB294 \uC74C\uC545\uC5D0\uB3C4 \uAC19\uC774 \uAC78\uB9B0\uB2E4(\uC798\uB9B0 \uD654\uBA74\uC758 \uC74C\uC545\uC740 \uD568\uAED8 \uBE60\uC9C4\uB2E4). \uBC30\uC18D\uC740 \uC601\uC0C1\uC5D0\uB9CC \uAC78\uB9AC\uACE0 \uC74C\uC545\uC740 \uC81C \uC18D\uB3C4\uB85C \uD750\uB978\uB2E4. \uB9D0\uC18C\uB9AC\uAC00 \uC788\uB294 \uAD6C\uAC04\uC5D0\uC11C\uB294 \uC74C\uC545\uC774 \uC790\uB3D9\uC73C\uB85C \uB0AE\uC544\uC9C4\uB2E4. bgm \uC744 null \uB85C \uC8FC\uBA74 \uC74C\uC545\uC744 \uBE80\uB2E4. democut_set_cut_edit\xB7democut_put_cut_draft \uC640 \uB2E4\uB978 \uAC12\uC774\uB77C \uC11C\uB85C \uC9C0\uC6B0\uC9C0 \uC54A\uB294\uB2E4.",
10920
11026
  "inputSchema": {
10921
11027
  "type": "object",
10922
11028
  "properties": {
@@ -13174,6 +13280,12 @@ var TOOL_META = {
13174
13280
  "method": "GET",
13175
13281
  "path": "/api/workspaces/{workspace_id}/credits/summary"
13176
13282
  },
13283
+ "democut_channel_stats": {
13284
+ "cost": "none",
13285
+ "group": "export",
13286
+ "method": "GET",
13287
+ "path": "/api/workspaces/{workspace_id}/youtube/stats"
13288
+ },
13177
13289
  "democut_list_characters": {
13178
13290
  "cost": "none",
13179
13291
  "group": "character",
@@ -13935,6 +14047,16 @@ function summary(baseUrl, workspaceId, range, deps = {}) {
13935
14047
  );
13936
14048
  }
13937
14049
 
14050
+ // src/channel-stats.ts
14051
+ function channelStats(baseUrl, workspaceId, range, deps = {}) {
14052
+ return apiRequest(
14053
+ baseUrl,
14054
+ `/api/workspaces/${encodeURIComponent(workspaceId)}/youtube/stats?range=${range}`,
14055
+ {},
14056
+ deps
14057
+ );
14058
+ }
14059
+
13938
14060
  // src/projects.ts
13939
14061
  var PROJECTS_DEFAULT_LIMIT = 30;
13940
14062
  var PROJECTS_MAX_LIMIT = 100;
@@ -14183,6 +14305,66 @@ function creditSummary(a = {}, deps = {}) {
14183
14305
  return { text: lines.join("\n"), structured: callableStructured(out4) };
14184
14306
  });
14185
14307
  }
14308
+ var STATS_RANGES = ["28d", "90d"];
14309
+ function n(value) {
14310
+ return value == null ? "-" : value.toLocaleString("en-US");
14311
+ }
14312
+ function channelStats2(a = {}, deps = {}) {
14313
+ return guarded(READ_ONLY, async () => {
14314
+ const range = a.range ?? "28d";
14315
+ if (!STATS_RANGES.includes(range)) {
14316
+ return { isError: true, text: `range \uB294 ${STATS_RANGES.join(", ")} \uC911 \uD558\uB098\uC785\uB2C8\uB2E4: ${JSON.stringify(range)}` };
14317
+ }
14318
+ const r = range;
14319
+ const base = resolveBaseUrl(deps.baseUrl);
14320
+ const ws = await resolveWorkspace(base, deps);
14321
+ if (!ws) return NO_WORKSPACE;
14322
+ const out4 = await channelStats(base, ws, r, deps);
14323
+ if (!out4.connected) {
14324
+ return {
14325
+ text: "\uC774 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uC5D0 \uC5F0\uACB0\uB41C \uC720\uD29C\uBE0C \uCC44\uB110\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC124\uC815 > \uCC44\uB110 \uC5F0\uACB0\uC5D0\uC11C \uC0AC\uB78C\uC774 \uBA3C\uC800 \uC5F0\uACB0\uD574\uC57C \uC131\uACFC\uB97C \uC77D\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4(\uC5F0\uACB0\uC740 \uBE0C\uB77C\uC6B0\uC800 \uB3D9\uC758\uAC00 \uD544\uC694\uD574 \uB3C4\uAD6C\uB85C \uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4).",
14326
+ structured: callableStructured(out4)
14327
+ };
14328
+ }
14329
+ if (out4.collected_at == null) {
14330
+ return {
14331
+ text: "\uCC44\uB110\uC740 \uC5F0\uACB0\uB3FC \uC788\uC9C0\uB9CC \uC544\uC9C1 \uD55C \uBC88\uB3C4 \uC218\uC9D1\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4" + (out4.last_error ? ` (\uB9C8\uC9C0\uB9C9 \uC2DC\uB3C4 \uC2E4\uD328: ${out4.last_error})` : " (\uCCAB \uC218\uC9D1\uC744 \uAE30\uB2E4\uB9AC\uB294 \uC911\uC785\uB2C8\uB2E4)") + ". \uC218\uC9D1\uC740 6\uC2DC\uAC04\uB9C8\uB2E4 \uB3D5\uB2C8\uB2E4.",
14332
+ structured: callableStructured(out4)
14333
+ };
14334
+ }
14335
+ const lines = [
14336
+ `${out4.channel_title ?? "\uCC44\uB110"} \xB7 \uAD6C\uB3C5\uC790 ${n(out4.subscriber_count)}` + (out4.subscriber_count_hidden ? "(\uC228\uAE40)" : "(\uC720\uD29C\uBE0C\uAC00 \uC138 \uC790\uB9AC\uB85C \uB0B4\uB9B0 \uAC12)") + ` \xB7 \uB204\uC801 \uC870\uD68C ${n(out4.lifetime_view_count)} \xB7 \uACF5\uAC1C \uC601\uC0C1 ${n(out4.public_video_count)}\uD3B8`,
14337
+ `${out4.start_date} ~ ${out4.end_date}: \uC870\uD68C ${n(out4.views)} \xB7 \uC2DC\uCCAD ${n(out4.minutes_watched)}\uBD84 \xB7 \uAD6C\uB3C5 +${n(out4.subscribers_gained)}/-${n(out4.subscribers_lost)} \xB7 \uC88B\uC544\uC694 ${n(out4.likes)} \xB7 \uB313\uAE00 ${n(out4.comments)} \xB7 \uACF5\uC720 ${n(out4.shares)}`,
14338
+ `\uBE44\uAD50 \uAE30\uAC04(${out4.compare_start_date} ~ ${out4.compare_end_date}) \uC870\uD68C ${n(out4.compare_views)}`,
14339
+ `\uAE30\uC900 \uC2DC\uAC01 ${out4.collected_at}` + (out4.stale ? " \u2605 \uAC31\uC2E0\uC774 \uB2A6\uACE0 \uC788\uC2B5\uB2C8\uB2E4" : "")
14340
+ ];
14341
+ if (out4.last_error) {
14342
+ lines.push(`\u2605 \uB9C8\uC9C0\uB9C9 \uC218\uC9D1 \uC2E4\uD328: ${out4.last_error} \u2014 \uCC44\uB110\uC744 \uB2E4\uC2DC \uC5F0\uACB0\uD574\uC57C \uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`);
14343
+ }
14344
+ const videos = out4.videos ?? [];
14345
+ if (videos.length) {
14346
+ lines.push("", `DemoCut \uC73C\uB85C \uC62C\uB9B0 \uC601\uC0C1 ${n(out4.published_count)}\uD3B8(\uAE30\uAC04 \uC870\uD68C\uC218 \uD070 \uC21C):`);
14347
+ for (const video of videos.slice(0, 20)) {
14348
+ const mark = video.privacy === "public" ? "" : ` [${video.privacy ?? "\uACF5\uAC1C \uBC94\uC704 \uBAA8\uB984"}]`;
14349
+ lines.push(
14350
+ `- ${video.title ?? video.video_id}${mark} \xB7 \uAE30\uAC04 \uC870\uD68C ${n(video.window_views)} \xB7 \uB204\uC801 \uC870\uD68C ${n(video.lifetime_views)} \xB7 \uC88B\uC544\uC694 ${n(video.lifetime_likes)} \xB7 \uB313\uAE00 ${n(video.lifetime_comments)} \xB7 ${video.url}`
14351
+ );
14352
+ }
14353
+ if (videos.length > 20) {
14354
+ lines.push(`- \u2026 \uADF8\uB9AC\uACE0 ${videos.length - 20}\uD3B8 \uB354(structuredContent \uC5D0 \uC804\uBD80 \uC788\uC2B5\uB2C8\uB2E4)`);
14355
+ }
14356
+ if (out4.not_public_count) {
14357
+ lines.push(
14358
+ `\u2605 \uADF8\uC911 ${n(out4.not_public_count)}\uD3B8\uC740 \uBE44\uACF5\uAC1C\xB7\uC77C\uBD80 \uACF5\uAC1C\uC785\uB2C8\uB2E4 \u2014 \uAC80\uC0C9\xB7\uCD94\uCC9C\uC5D0 \uB728\uC9C0 \uC54A\uC544 \uC218\uCE58\uAC00 0 \uC778 \uAC83\uC774 \uC815\uC0C1\uC785\uB2C8\uB2E4.`
14359
+ );
14360
+ }
14361
+ } else {
14362
+ lines.push("", "DemoCut \uC73C\uB85C \uC62C\uB9B0 \uC601\uC0C1\uC774 \uC544\uC9C1 \uC5C6\uC2B5\uB2C8\uB2E4(\uCC44\uB110 \uC218\uCE58\uB9CC \uBCF4\uC785\uB2C8\uB2E4).");
14363
+ }
14364
+ lines.push("", "\uC378\uB124\uC77C \uB178\uCD9C\uC218\xB7\uB178\uCD9C \uD074\uB9AD\uB960\uC740 \uC720\uD29C\uBE0C\uAC00 API \uB85C \uC8FC\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2014 Studio \uC5D0\uC11C\uB9CC \uBCF4\uC785\uB2C8\uB2E4.");
14365
+ return { text: lines.join("\n"), structured: callableStructured(out4) };
14366
+ });
14367
+ }
14186
14368
  function projectLine(p) {
14187
14369
  const parts = [p.slug, p.title || "(\uC81C\uBAA9 \uC5C6\uC74C)", `\uCEF7 ${p.cut_count ?? 0}\uAC1C`];
14188
14370
  const updated = (p.updated_at ?? "").slice(0, 10);
@@ -14538,16 +14720,16 @@ function makeCutImage(a = {}, deps = {}) {
14538
14720
  });
14539
14721
  }
14540
14722
  function cutImageLine(cut) {
14541
- const n = cut.images?.length ?? 0;
14723
+ const n2 = cut.images?.length ?? 0;
14542
14724
  const firstFrame = (cut.mode ?? "ai_video") === "ai_video";
14543
- if (!n) return `${cut.id}: \uC774\uBBF8\uC9C0 \uC5C6\uC74C${firstFrame ? " \u2014 \uB2E4\uC74C \uC601\uC0C1\uC740 \uD14D\uC2A4\uD2B8\uB9CC\uC73C\uB85C \uB9CC\uB4ED\uB2C8\uB2E4(t2v)." : "."}`;
14725
+ if (!n2) return `${cut.id}: \uC774\uBBF8\uC9C0 \uC5C6\uC74C${firstFrame ? " \u2014 \uB2E4\uC74C \uC601\uC0C1\uC740 \uD14D\uC2A4\uD2B8\uB9CC\uC73C\uB85C \uB9CC\uB4ED\uB2C8\uB2E4(t2v)." : "."}`;
14544
14726
  let cover = cut.current_image_id ? `\uC120\uD0DD\uB41C \uC774\uBBF8\uC9C0 ${cut.current_image_id}` : "\uC120\uD0DD\uB41C \uC774\uBBF8\uC9C0 \uC5C6\uC74C";
14545
14727
  if (cut.current_image_id) {
14546
14728
  const current = cut.images?.find((i) => i.id === cut.current_image_id);
14547
14729
  if (current?.model) cover += ` (${current.model}${current.quality ? ` \xB7 ${current.quality}` : ""})`;
14548
14730
  }
14549
14731
  const tail = !firstFrame ? "" : cut.current_image_id ? " \u2014 \uB2E4\uC74C \uC601\uC0C1\uC758 \uCCAB \uD504\uB808\uC784\uC774 \uB429\uB2C8\uB2E4." : " \uCCAB \uC7A5\uBA74\uC774 \uC5C6\uC5B4 \uB2E4\uC74C \uC601\uC0C1\uC740 \uD14D\uC2A4\uD2B8\uB9CC\uC73C\uB85C \uB9CC\uB4ED\uB2C8\uB2E4(t2v).";
14550
- return `${cut.id}: \uC774\uBBF8\uC9C0 ${n}\uC7A5 \xB7 ${cover}${tail}`;
14732
+ return `${cut.id}: \uC774\uBBF8\uC9C0 ${n2}\uC7A5 \xB7 ${cover}${tail}`;
14551
14733
  }
14552
14734
  function setCutImage(a = {}, deps = {}) {
14553
14735
  return guarded(READ_ONLY, async () => {
@@ -16331,6 +16513,8 @@ function dispatch(name, args, deps = {}) {
16331
16513
  return creditLedger(args, deps);
16332
16514
  case "democut_credit_summary":
16333
16515
  return creditSummary(args, deps);
16516
+ case "democut_channel_stats":
16517
+ return channelStats2(args, deps);
16334
16518
  case "democut_list_projects":
16335
16519
  return listProjects(args, deps);
16336
16520
  case "democut_get_project":
@@ -16549,9 +16733,9 @@ function coerce(raw, kind, flag) {
16549
16733
  if (!/^-?\d+$/.test(raw.trim())) throw new UsageError(`${flag} \uB294 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4 \u2014 \uBC1B\uC740 \uAC12: ${raw}`);
16550
16734
  return Number(raw);
16551
16735
  case "number": {
16552
- const n = Number(raw);
16553
- if (raw.trim() === "" || !Number.isFinite(n)) throw new UsageError(`${flag} \uB294 \uC22B\uC790\uC5EC\uC57C \uD569\uB2C8\uB2E4 \u2014 \uBC1B\uC740 \uAC12: ${raw}`);
16554
- return n;
16736
+ const n2 = Number(raw);
16737
+ if (raw.trim() === "" || !Number.isFinite(n2)) throw new UsageError(`${flag} \uB294 \uC22B\uC790\uC5EC\uC57C \uD569\uB2C8\uB2E4 \u2014 \uBC1B\uC740 \uAC12: ${raw}`);
16738
+ return n2;
16555
16739
  }
16556
16740
  case "boolean":
16557
16741
  if (raw === "true" || raw === "false") return raw === "true";
@@ -21686,17 +21870,17 @@ var ZodArray = /* @__PURE__ */ $constructor("ZodArray", (inst, def) => {
21686
21870
  inst._zod.processJSONSchema = (ctx, json, params) => arrayProcessor(inst, ctx, json, params);
21687
21871
  inst.element = def.element;
21688
21872
  _installLazyMethods(inst, "ZodArray", {
21689
- min(n, params) {
21690
- return this.check(_minLength(n, params));
21873
+ min(n2, params) {
21874
+ return this.check(_minLength(n2, params));
21691
21875
  },
21692
21876
  nonempty(params) {
21693
21877
  return this.check(_minLength(1, params));
21694
21878
  },
21695
- max(n, params) {
21696
- return this.check(_maxLength(n, params));
21879
+ max(n2, params) {
21880
+ return this.check(_maxLength(n2, params));
21697
21881
  },
21698
- length(n, params) {
21699
- return this.check(_length(n, params));
21882
+ length(n2, params) {
21883
+ return this.check(_length(n2, params));
21700
21884
  },
21701
21885
  unwrap() {
21702
21886
  return this.element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "democut",
3
- "version": "1.0.108",
3
+ "version": "1.0.110",
4
4
  "description": "DemoCut 에이전트 CLI — device flow 로그인(RFC 8628) + 영상 생성",
5
5
  "license": "MIT",
6
6
  "author": "InfoGrab",