@artillect/cli 0.1.0 → 0.1.1

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 +15 -43
  2. package/dist/index.js +56 -50
  3. package/package.json +3 -8
package/README.md CHANGED
@@ -1,58 +1,30 @@
1
1
  # `@artillect/cli`
2
2
 
3
- Fourth Artillect client (Studio / Public API / MCP / CLI). Thin Commander binary over Public API v1. The SDK is **bundled** into this package and is not published separately. **No local model list** — `artillect models` is `GET /api/v1/models`.
3
+ Artillect CLI генерация картинок и видео из терминала.
4
4
 
5
- ```bash
6
- npm i -g @artillect/cli
7
- # or, without a global install:
8
- npx @artillect/cli@latest --help
9
- ```
10
-
11
- Requires Node.js **≥ 20**. First publish of a scoped package uses `npm publish --access public` (already set in `publishConfig`).
5
+ ## Установка
12
6
 
13
7
  ```bash
14
- artillect auth login # device flow → ~/.config/artillect/config.json
15
- # or: export ARTILLECT_API_KEY=art_…
16
- # export ARTILLECT_BASE_URL=https://dev.artillect.pro # optional
17
-
18
- artillect balance
19
- artillect models list
20
- artillect generate image --prompt "a cat" --wait
21
- artillect generate video kling-3 --prompt "a cat walks" --start-image ./a.png --wait
8
+ npm install -g @artillect/cli
22
9
  ```
23
10
 
24
- `--json` prints the API envelope. `--wait` polls until `status=completed` and downloads media into `--out` (default cwd).
25
-
26
- ## Updates and hotfixes
11
+ Нужен Node.js 20+. Без глобальной установки: `npx @artillect/cli@latest --help`.
27
12
 
28
- npm **does not push** new versions to machines that already ran `npm i -g`. After install, the user keeps that exact tarball until they upgrade.
29
-
30
- | Who | What happens |
31
- | --------------------- | --------------------------------------------------------------------------------------------------------------- |
32
- | You ship a CLI hotfix | Bump **patch** (`0.1.0` → `0.1.1`), `pnpm --filter @artillect/cli publish`. |
33
- | You ship a feature | Bump **minor**. Breaking CLI flags → **major**. |
34
- | API/server hotfix | Users get it on the next request. No CLI reinstall. Catalog, billing, and generation bugs live on the server. |
35
- | SDK change | SDK is private and inlined in the CLI bundle. Republish `@artillect/cli` — there is no `@artillect/sdk` on npm. |
36
-
37
- How a user actually receives a new CLI:
13
+ ## Использование
38
14
 
39
15
  ```bash
40
- npm i -g @artillect/cli@latest
41
- # or one-shot without touching the global:
42
- npx @artillect/cli@latest models list
16
+ artillect auth login
17
+ artillect models list
18
+ artillect generate image --prompt "кот в космосе" --wait
19
+ artillect generate video kling-3 --prompt "кот идёт" --start-image ./a.png --wait
20
+ artillect --help
43
21
  ```
44
22
 
45
- There is no App Store review, no push notification, and no silent auto-update of globals. The CLI prints a **stderr hint at most once a day** when `registry.npmjs.org/@artillect/cli/latest` is newer than the running binary. Disable with `ARTILLECT_NO_UPDATE_CHECK=1`. Announce breaking changes in release notes / Discord / the product changelog — npm will not email end users.
23
+ Ключ также можно задать через `ARTILLECT_API_KEY`. `--wait` дожидается результата и сохраняет файлы в текущую папку (или `--out`).
46
24
 
47
- `npx @artillect/cli` without `@latest` may use a cached copy. Prefer `@latest` in docs.
25
+ Обновление: `npm i -g @artillect/cli@latest`.
48
26
 
49
- ## Repo scripts
50
-
51
- ```bash
52
- pnpm --filter @artillect/sdk run build
53
- pnpm --filter @artillect/cli run build
54
- pnpm --filter @artillect/cli run pack:check # tarball + --help/--version
55
- pnpm --filter @artillect/cli run smoke # live health + models + device/code
56
- ```
27
+ ## Ссылки
57
28
 
58
- Not in v1: Homebrew, a second catalog, `@artillect/mcp` on npm (MCP is the hosted URL).
29
+ - Документация: https://app.artillect.pro/docs/cli
30
+ - Артиллект: https://app.artillect.pro
package/dist/index.js CHANGED
@@ -355,7 +355,7 @@ function loadCliConfig() {
355
355
  function requireApiKey() {
356
356
  const cfg = loadCliConfig();
357
357
  if (!cfg.apiKey) {
358
- throw new Error("Not logged in. Run `artillect auth login` or set ARTILLECT_API_KEY.");
358
+ throw new Error("\u041D\u0435\u0442 \u0432\u0445\u043E\u0434\u0430. \u0412\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u0435 `artillect auth login` \u0438\u043B\u0438 \u0437\u0430\u0434\u0430\u0439\u0442\u0435 ARTILLECT_API_KEY.");
359
359
  }
360
360
  return cfg;
361
361
  }
@@ -416,7 +416,9 @@ async function authLogin() {
416
416
  const { baseUrl } = loadCliConfig();
417
417
  const started = await postJson(baseUrl, "/api/v1/device/code", {});
418
418
  if (started.status >= 400) {
419
- throw new Error(String(started.json.error || `device code failed (${started.status})`));
419
+ throw new Error(
420
+ String(started.json.error || `\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u043A\u043E\u0434 \u0432\u0445\u043E\u0434\u0430 (${started.status})`)
421
+ );
420
422
  }
421
423
  const deviceCode = String(started.json.device_code || "");
422
424
  const userCode = String(started.json.user_code || "");
@@ -424,12 +426,12 @@ async function authLogin() {
424
426
  const intervalSec = Math.max(1, Number(started.json.interval) || 5);
425
427
  const expiresIn = Number(started.json.expires_in) || 600;
426
428
  if (!deviceCode || !verificationUrl) {
427
- throw new Error("Device authorization response missing device_code/verification_url");
429
+ throw new Error("\u0412 \u043E\u0442\u0432\u0435\u0442\u0435 \u043D\u0435\u0442 device_code \u0438\u043B\u0438 verification_url");
428
430
  }
429
- console.log("Open this URL in a browser where you are logged into Artillect:");
431
+ console.log("\u041E\u0442\u043A\u0440\u043E\u0439\u0442\u0435 \u0441\u0441\u044B\u043B\u043A\u0443 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u0433\u0434\u0435 \u0432\u044B \u0432\u043E\u0448\u043B\u0438 \u0432 \u0410\u0440\u0442\u0438\u043B\u043B\u0435\u043A\u0442:");
430
432
  console.log(` ${verificationUrl}`);
431
- if (userCode) console.log(`Confirm code: ${userCode}`);
432
- console.log("Waiting for approval\u2026");
433
+ if (userCode) console.log(`\u041A\u043E\u0434 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F: ${userCode}`);
434
+ console.log("\u0416\u0434\u0451\u043C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435\u2026");
433
435
  const deadline = Date.now() + expiresIn * 1e3;
434
436
  while (Date.now() < deadline) {
435
437
  await sleep(intervalSec * 1e3);
@@ -437,21 +439,21 @@ async function authLogin() {
437
439
  const status = String(polled.json.status || "");
438
440
  if (status === "pending") continue;
439
441
  if (status === "expired" || polled.status === 410) {
440
- throw new Error("Device code expired. Run `artillect auth login` again.");
442
+ throw new Error("\u041A\u043E\u0434 \u0438\u0441\u0442\u0435\u043A. \u0421\u043D\u043E\u0432\u0430 \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u0435 `artillect auth login`.");
441
443
  }
442
444
  const apiKey = String(polled.json.api_key || "");
443
445
  if (status === "completed" && apiKey) {
444
446
  const path = saveCliConfig({ apiKey, baseUrl });
445
- console.log(`Logged in. Key saved to ${path}`);
447
+ console.log(`\u0412\u0445\u043E\u0434 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D. \u041A\u043B\u044E\u0447 \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D \u0432 ${path}`);
446
448
  return;
447
449
  }
448
- throw new Error(String(polled.json.error || `login failed (${polled.status})`));
450
+ throw new Error(String(polled.json.error || `\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0432\u043E\u0439\u0442\u0438 (${polled.status})`));
449
451
  }
450
- throw new Error("Timed out waiting for browser approval.");
452
+ throw new Error("\u0412\u0440\u0435\u043C\u044F \u043D\u0430 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u0438\u0441\u0442\u0435\u043A\u043B\u043E.");
451
453
  }
452
454
  async function authLogout() {
453
455
  clearCliConfig();
454
- console.log("Logged out.");
456
+ console.log("\u0412\u044B \u0432\u044B\u0448\u043B\u0438.");
455
457
  }
456
458
  async function authStatus() {
457
459
  const envKey = Boolean(String(process.env.ARTILLECT_API_KEY || "").trim());
@@ -461,14 +463,14 @@ async function authStatus() {
461
463
  const me = await client.getMe();
462
464
  if (!me.ok) {
463
465
  console.log(
464
- `Configured (${envKey ? "ARTILLECT_API_KEY" : configPath()}), but /me failed: ${me.error}`
466
+ `\u041A\u043B\u044E\u0447 \u0437\u0430\u0434\u0430\u043D (${envKey ? "ARTILLECT_API_KEY" : configPath()}), \u043D\u043E /me \u043D\u0435 \u043E\u0442\u0432\u0435\u0442\u0438\u043B: ${me.error}`
465
467
  );
466
468
  process.exitCode = 1;
467
469
  return;
468
470
  }
469
471
  const body = me.body;
470
- console.log(`Logged in as ${body.email ?? body.user_id ?? "ok"}`);
471
- console.log(`Base URL: ${cfg.baseUrl}`);
472
+ console.log(`\u0412\u044B \u0432\u043E\u0448\u043B\u0438 \u043A\u0430\u043A ${body.email ?? body.user_id ?? "ok"}`);
473
+ console.log(`\u0421\u0435\u0440\u0432\u0435\u0440: ${cfg.baseUrl}`);
472
474
  } catch (err) {
473
475
  console.log(err instanceof Error ? err.message : String(err));
474
476
  process.exitCode = 1;
@@ -487,12 +489,12 @@ function asRecord(value) {
487
489
  }
488
490
  function formatModelsList(body, kind) {
489
491
  const groups = [
490
- ["images", "Images"],
491
- ["video", "Video"],
492
- ["chat", "Chat"],
493
- ["audio", "Audio"],
494
- ["upscale", "Upscale"],
495
- ["mesh", "Mesh"],
492
+ ["images", "\u041A\u0430\u0440\u0442\u0438\u043D\u043A\u0438"],
493
+ ["video", "\u0412\u0438\u0434\u0435\u043E"],
494
+ ["chat", "\u0427\u0430\u0442"],
495
+ ["audio", "\u0410\u0443\u0434\u0438\u043E"],
496
+ ["upscale", "\u0410\u043F\u0441\u043A\u0435\u0439\u043B"],
497
+ ["mesh", "3D"],
496
498
  ["switchx", "SwitchX"]
497
499
  ];
498
500
  const lines = [];
@@ -524,7 +526,7 @@ async function uploadLocal(client, filePath) {
524
526
  const up = await client.uploadFile({ bytes: file.bytes, filename: file.filename });
525
527
  if (!up.ok) fail(up);
526
528
  const url = String(asRecord(up.body).url || "").trim();
527
- if (!url) throw new Error(`Upload of ${basename2(filePath)} returned no url`);
529
+ if (!url) throw new Error(`\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 ${basename2(filePath)} \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B\u0430 url`);
528
530
  return url;
529
531
  }
530
532
  function mediaUrls(body) {
@@ -553,7 +555,11 @@ async function waitForTask(client, taskId, jsonMode) {
553
555
  const term = terminalStatus(body);
554
556
  if (term) {
555
557
  if (term !== "completed") {
556
- throw new Error(String(body.error || `generation ${term}`));
558
+ throw new Error(
559
+ String(
560
+ body.error || (term === "cancelled" ? "\u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430" : "\u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0430\u0441\u044C \u0441 \u043E\u0448\u0438\u0431\u043A\u043E\u0439")
561
+ )
562
+ );
557
563
  }
558
564
  return body;
559
565
  }
@@ -564,13 +570,13 @@ async function waitForTask(client, taskId, jsonMode) {
564
570
  }
565
571
  await sleep(interval * 1e3);
566
572
  }
567
- throw new Error("Timed out waiting for generation");
573
+ throw new Error("\u0412\u0440\u0435\u043C\u044F \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0441\u0442\u0435\u043A\u043B\u043E.");
568
574
  }
569
575
  async function downloadAll(urls, outDir) {
570
576
  const saved = [];
571
577
  for (const [i, url] of urls.entries()) {
572
578
  const res = await fetch(url);
573
- if (!res.ok || !res.body) throw new Error(`download failed HTTP ${res.status}`);
579
+ if (!res.ok || !res.body) throw new Error(`\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043A\u0430\u0447\u0430\u0442\u044C \u0444\u0430\u0439\u043B (HTTP ${res.status})`);
574
580
  const extGuess = url.includes(".mp4") ? "mp4" : url.includes(".webm") ? "webm" : "png";
575
581
  const dest = `${outDir.replace(/\/+$/, "") || "."}/artillect-${Date.now()}-${i + 1}.${extGuess}`;
576
582
  await pipeline(Readable.fromWeb(res.body), createWriteStream(dest));
@@ -591,7 +597,7 @@ async function cmdBalance(jsonMode) {
591
597
  const res = await client.getBalance();
592
598
  if (!res.ok) fail(res);
593
599
  const body = asRecord(res.body);
594
- printOrJson(jsonMode, body, [`Balance: ${body.token_balance ?? 0} tokens`]);
600
+ printOrJson(jsonMode, body, [`\u0411\u0430\u043B\u0430\u043D\u0441: ${body.token_balance ?? 0} \u0442\u043E\u043A\u0435\u043D\u043E\u0432`]);
595
601
  }
596
602
  async function cmdModels(kind, jsonMode) {
597
603
  const cfg = loadCliConfig();
@@ -599,7 +605,9 @@ async function cmdModels(kind, jsonMode) {
599
605
  if (cfg.apiKey) headers.Authorization = `Bearer ${cfg.apiKey}`;
600
606
  const res = await getJson(cfg.baseUrl, "/api/v1/models", headers);
601
607
  if (res.status >= 400) {
602
- throw new Error(String(res.json.error || `GET /api/v1/models failed (${res.status})`));
608
+ throw new Error(
609
+ String(res.json.error || `\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u043A\u0430\u0442\u0430\u043B\u043E\u0433 \u043C\u043E\u0434\u0435\u043B\u0435\u0439 (${res.status})`)
610
+ );
603
611
  }
604
612
  if (jsonMode) {
605
613
  console.log(JSON.stringify(kind ? res.json[kind] ?? res.json : res.json, null, 2));
@@ -625,16 +633,16 @@ async function cmdGenerateImage(opts) {
625
633
  const body = asRecord(res.body);
626
634
  const taskId = String(body.task_id || body.id || "");
627
635
  if (!opts.wait) {
628
- printOrJson(opts.json, body, [`Submitted ${taskId || "(no task_id)"}`]);
636
+ printOrJson(opts.json, body, [`\u041E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043E ${taskId || "(\u043D\u0435\u0442 task_id)"}`]);
629
637
  return;
630
638
  }
631
- if (!taskId) throw new Error("submit returned no task_id");
639
+ if (!taskId) throw new Error("\u0441\u0435\u0440\u0432\u0435\u0440 \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B task_id");
632
640
  const done = await waitForTask(client, taskId, opts.json);
633
641
  const urls = mediaUrls(done);
634
642
  const saved = urls.length ? await downloadAll(urls, opts.out) : [];
635
643
  printOrJson(opts.json, { ...done, saved }, [
636
- `Completed ${taskId}`,
637
- ...saved.map((p) => `Saved ${p}`),
644
+ `\u0413\u043E\u0442\u043E\u0432\u043E ${taskId}`,
645
+ ...saved.map((p) => `\u0421\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043E ${p}`),
638
646
  ...!saved.length ? urls.map((u) => u) : []
639
647
  ]);
640
648
  }
@@ -649,16 +657,16 @@ async function cmdGenerateVideo(opts) {
649
657
  const submitted = asRecord(res.body);
650
658
  const taskId = String(submitted.task_id || submitted.id || "");
651
659
  if (!opts.wait) {
652
- printOrJson(opts.json, submitted, [`Submitted ${taskId || "(no task_id)"}`]);
660
+ printOrJson(opts.json, submitted, [`\u041E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043E ${taskId || "(\u043D\u0435\u0442 task_id)"}`]);
653
661
  return;
654
662
  }
655
- if (!taskId) throw new Error("submit returned no task_id");
663
+ if (!taskId) throw new Error("\u0441\u0435\u0440\u0432\u0435\u0440 \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B task_id");
656
664
  const done = await waitForTask(client, taskId, opts.json);
657
665
  const urls = mediaUrls(done);
658
666
  const saved = urls.length ? await downloadAll(urls, opts.out) : [];
659
667
  printOrJson(opts.json, { ...done, saved }, [
660
- `Completed ${taskId}`,
661
- ...saved.map((p) => `Saved ${p}`),
668
+ `\u0413\u043E\u0442\u043E\u0432\u043E ${taskId}`,
669
+ ...saved.map((p) => `\u0421\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043E ${p}`),
662
670
  ...!saved.length ? urls.map((u) => u) : []
663
671
  ]);
664
672
  }
@@ -684,11 +692,11 @@ function parse(raw) {
684
692
  return [Number(m[1]), Number(m[2]), Number(m[3])];
685
693
  }
686
694
  function cliVersion() {
687
- return String("0.1.0");
695
+ return String("0.1.1");
688
696
  }
689
697
  function updateAvailableMessage(local, latest) {
690
- return `A new version of @artillect/cli is available (${latest}; you have ${local}).
691
- Update: npm i -g @artillect/cli@latest`;
698
+ return `\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F @artillect/cli (${latest}, \u0443 \u0432\u0430\u0441 ${local}).
699
+ \u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435: npm i -g @artillect/cli@latest`;
692
700
  }
693
701
 
694
702
  // src/updateCheck.ts
@@ -739,25 +747,23 @@ async function maybeNotifyUpdate() {
739
747
 
740
748
  // src/index.ts
741
749
  var program = new Command();
742
- program.name("artillect").description(
743
- "Artillect CLI \u2014 same Public API v1 as Studio, REST, and MCP. Models come from GET /api/v1/models."
744
- ).version(cliVersion());
750
+ program.name("artillect").description("Artillect CLI \u2014 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u043A\u0430\u0440\u0442\u0438\u043D\u043E\u043A \u0438 \u0432\u0438\u0434\u0435\u043E \u0438\u0437 \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B\u0430.").version(cliVersion());
745
751
  program.hook("preAction", async () => {
746
752
  await maybeNotifyUpdate();
747
753
  });
748
- var auth = program.command("auth").description("Device-flow login (or ARTILLECT_API_KEY)");
749
- auth.command("login").description("Open /connect, poll until an API key is issued").action(authLogin);
750
- auth.command("logout").description("Remove the saved API key").action(authLogout);
751
- auth.command("status").description("Show who the current key belongs to").action(authStatus);
752
- program.command("balance").description("Show token balance").option("--json", "print raw JSON", false).action(async (opts) => {
754
+ var auth = program.command("auth").description("\u0412\u0445\u043E\u0434 (\u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0438\u043B\u0438 ARTILLECT_API_KEY)");
755
+ auth.command("login").description("\u0412\u043E\u0439\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440").action(authLogin);
756
+ auth.command("logout").description("\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D\u043D\u044B\u0439 \u043A\u043B\u044E\u0447").action(authLogout);
757
+ auth.command("status").description("\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C, \u043F\u043E\u0434 \u043A\u0435\u043C \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D \u0432\u0445\u043E\u0434").action(authStatus);
758
+ program.command("balance").description("\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0431\u0430\u043B\u0430\u043D\u0441 \u0442\u043E\u043A\u0435\u043D\u043E\u0432").option("--json", "\u0432\u044B\u0432\u0435\u0441\u0442\u0438 \u0441\u044B\u0440\u043E\u0439 JSON", false).action(async (opts) => {
753
759
  await cmdBalance(Boolean(opts.json));
754
760
  });
755
- var models = program.command("models").description("Discovery from GET /api/v1/models (no local catalog)");
756
- models.command("list").description("List public model slugs").option("-k, --kind <kind>", "images | video | chat | audio | upscale | mesh").option("--json", "print raw JSON", false).action(async (opts) => {
761
+ var models = program.command("models").description("\u041A\u0430\u0442\u0430\u043B\u043E\u0433 \u043C\u043E\u0434\u0435\u043B\u0435\u0439 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430");
762
+ models.command("list").description("\u0421\u043F\u0438\u0441\u043E\u043A \u043C\u043E\u0434\u0435\u043B\u0435\u0439").option("-k, --kind <kind>", "images | video | chat | audio | upscale | mesh").option("--json", "\u0432\u044B\u0432\u0435\u0441\u0442\u0438 \u0441\u044B\u0440\u043E\u0439 JSON", false).action(async (opts) => {
757
763
  await cmdModels(opts.kind, Boolean(opts.json));
758
764
  });
759
- var generate = program.command("generate").description("Submit a generation");
760
- generate.command("image").description("Text-to-image or image edit").requiredOption("-p, --prompt <text>", "prompt").option("-m, --model <slug>", "public image slug (default: gpt-image-2)").option("-i, --input <file...>", "local image files to upload as input_urls").option("-w, --wait", "poll until complete and download results", false).option("-o, --out <dir>", "directory for downloads", ".").option("--json", "print raw JSON", false).action(
765
+ var generate = program.command("generate").description("\u0417\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044E");
766
+ generate.command("image").description("\u041A\u0430\u0440\u0442\u0438\u043D\u043A\u0430 \u043F\u043E \u0442\u0435\u043A\u0441\u0442\u0443 \u0438\u043B\u0438 \u043F\u0440\u0430\u0432\u043A\u0430 \u043F\u043E \u0440\u0435\u0444\u0435\u0440\u0435\u043D\u0441\u0430\u043C").requiredOption("-p, --prompt <text>", "\u043F\u0440\u043E\u043C\u043F\u0442").option("-m, --model <slug>", "\u0441\u043B\u0430\u0433 \u043C\u043E\u0434\u0435\u043B\u0438 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E gpt-image-2)").option("-i, --input <file...>", "\u043B\u043E\u043A\u0430\u043B\u044C\u043D\u044B\u0435 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438-\u0440\u0435\u0444\u0435\u0440\u0435\u043D\u0441\u044B").option("-w, --wait", "\u0434\u043E\u0436\u0434\u0430\u0442\u044C\u0441\u044F \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438 \u0438 \u0441\u043A\u0430\u0447\u0430\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442", false).option("-o, --out <dir>", "\u043F\u0430\u043F\u043A\u0430 \u0434\u043B\u044F \u0444\u0430\u0439\u043B\u043E\u0432", ".").option("--json", "\u0432\u044B\u0432\u0435\u0441\u0442\u0438 \u0441\u044B\u0440\u043E\u0439 JSON", false).action(
761
767
  async (opts) => {
762
768
  await cmdGenerateImage({
763
769
  prompt: opts.prompt,
@@ -769,7 +775,7 @@ generate.command("image").description("Text-to-image or image edit").requiredOpt
769
775
  });
770
776
  }
771
777
  );
772
- generate.command("video").description("Text/image-to-video").argument("[model]", "public video slug (default: kling-3-turbo)").requiredOption("-p, --prompt <text>", "prompt").option("-m, --model <slug>", "public video slug (overrides the positional model)").option("--start-image <file>", "local start-frame image").option("--end-image <file>", "local end-frame image").option("-w, --wait", "poll until complete and download results", false).option("-o, --out <dir>", "directory for downloads", ".").option("--json", "print raw JSON", false).action(
778
+ generate.command("video").description("\u0412\u0438\u0434\u0435\u043E \u043F\u043E \u0442\u0435\u043A\u0441\u0442\u0443 \u0438\u043B\u0438 \u043A\u0430\u0434\u0440\u0430\u043C").argument("[model]", "\u0441\u043B\u0430\u0433 \u0432\u0438\u0434\u0435\u043E\u043C\u043E\u0434\u0435\u043B\u0438 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E kling-3-turbo)").requiredOption("-p, --prompt <text>", "\u043F\u0440\u043E\u043C\u043F\u0442").option("-m, --model <slug>", "\u0441\u043B\u0430\u0433 \u043C\u043E\u0434\u0435\u043B\u0438 (\u0435\u0441\u043B\u0438 \u043D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u043C)").option("--start-image <file>", "\u043B\u043E\u043A\u0430\u043B\u044C\u043D\u044B\u0439 \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u044B\u0439 \u043A\u0430\u0434\u0440").option("--end-image <file>", "\u043B\u043E\u043A\u0430\u043B\u044C\u043D\u044B\u0439 \u0444\u0438\u043D\u0430\u043B\u044C\u043D\u044B\u0439 \u043A\u0430\u0434\u0440").option("-w, --wait", "\u0434\u043E\u0436\u0434\u0430\u0442\u044C\u0441\u044F \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438 \u0438 \u0441\u043A\u0430\u0447\u0430\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442", false).option("-o, --out <dir>", "\u043F\u0430\u043F\u043A\u0430 \u0434\u043B\u044F \u0444\u0430\u0439\u043B\u043E\u0432", ".").option("--json", "\u0432\u044B\u0432\u0435\u0441\u0442\u0438 \u0441\u044B\u0440\u043E\u0439 JSON", false).action(
773
779
  async (positionalModel, opts) => {
774
780
  const model = String(opts.model || positionalModel || "kling-3-turbo").trim();
775
781
  await cmdGenerateVideo({
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@artillect/cli",
3
- "version": "0.1.0",
4
- "description": "Artillect CLI — generate images and video via Public API v1.",
3
+ "version": "0.1.1",
4
+ "description": "Artillect CLI — генерация картинок и видео из терминала.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
7
7
  "bin": {
@@ -14,12 +14,7 @@
14
14
  "publishConfig": {
15
15
  "access": "public"
16
16
  },
17
- "repository": {
18
- "type": "git",
19
- "url": "https://git.krem.digital/diffusionbooth/artillect.git",
20
- "directory": "packages/artillect-cli"
21
- },
22
- "homepage": "https://app.artillect.pro/docs",
17
+ "homepage": "https://app.artillect.pro/docs/cli",
23
18
  "bugs": {
24
19
  "url": "https://app.artillect.pro/feedback"
25
20
  },