@hintoai/cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,10 +21,10 @@ _hinto() {
21
21
  cur="\${COMP_WORDS[COMP_CWORD]}"
22
22
  groups="${GROUPS.join(' ')}"
23
23
  flags="${GLOBAL_FLAGS.join(' ')}"
24
- if [ "\$COMP_CWORD" -eq 1 ]; then
25
- COMPREPLY=( \$(compgen -W "\$groups" -- "\$cur") )
24
+ if [ "$COMP_CWORD" -eq 1 ]; then
25
+ COMPREPLY=( $(compgen -W "$groups" -- "$cur") )
26
26
  else
27
- COMPREPLY=( \$(compgen -W "\$flags" -- "\$cur") )
27
+ COMPREPLY=( $(compgen -W "$flags" -- "$cur") )
28
28
  fi
29
29
  }
30
30
  complete -F _hinto hinto
@@ -37,9 +37,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.registerVideos = registerVideos;
40
+ const axios_1 = __importDefault(require("axios"));
40
41
  const fs = __importStar(require("fs"));
41
42
  const path = __importStar(require("path"));
42
- const axios_1 = __importDefault(require("axios"));
43
43
  const videos_1 = require("../api/videos");
44
44
  const errors_1 = require("../errors");
45
45
  const output_1 = require("../output");
package/dist/index.js CHANGED
File without changes
package/dist/output.js CHANGED
@@ -13,7 +13,9 @@ function printJson(data) {
13
13
  }
14
14
  function printTable(headers, rows) {
15
15
  const table = new cli_table3_1.default({ head: headers.map((h) => chalk_1.default.bold(h)) });
16
- rows.forEach((row) => table.push(row));
16
+ rows.forEach((row) => {
17
+ table.push(row);
18
+ });
17
19
  process.stdout.write(`${table.toString()}\n`);
18
20
  }
19
21
  function printKeyValue(obj) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hintoai/cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Hinto AI CLI — manage videos, articles, and publishing via the Hinto API",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -10,7 +10,7 @@
10
10
  "dist/"
11
11
  ],
12
12
  "engines": {
13
- "node": ">=18"
13
+ "node": ">=20"
14
14
  },
15
15
  "license": "MIT",
16
16
  "homepage": "https://github.com/hintoai/hinto-cli#readme",
@@ -51,11 +51,11 @@
51
51
  "axios": "^1.7.0",
52
52
  "chalk": "^4.1.2",
53
53
  "cli-table3": "^0.6.5",
54
- "commander": "^12.1.0",
54
+ "commander": "^15.0.0",
55
55
  "ora": "^8.1.0"
56
56
  },
57
57
  "devDependencies": {
58
- "@biomejs/biome": "1.9.4",
58
+ "@biomejs/biome": "2.4.16",
59
59
  "@changesets/cli": "^2.31.0",
60
60
  "@types/jest": "^30.0.0",
61
61
  "@types/node": "^25.9.2",
@@ -1,3 +0,0 @@
1
- import { Command } from 'commander';
2
- import { AxiosInstance } from 'axios';
3
- export declare function registerGenerateBatch(generate: Command, client: AxiosInstance): void;
@@ -1,158 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.registerGenerateBatch = registerGenerateBatch;
37
- const fs = __importStar(require("fs"));
38
- const path = __importStar(require("path"));
39
- const crypto = __importStar(require("crypto"));
40
- const output_1 = require("../output");
41
- const errors_1 = require("../errors");
42
- function makeClientKey(filePath) {
43
- const stat = fs.statSync(filePath);
44
- return crypto
45
- .createHash('sha256')
46
- .update(`${path.resolve(filePath)}:${stat.size}:${stat.mtimeMs}`)
47
- .digest('hex');
48
- }
49
- async function uploadFile(client, filePath, clientKey) {
50
- const filename = path.basename(filePath);
51
- const contentType = 'video/mp4';
52
- const { data: presigned } = await client.post('/videos/upload/presigned', { filename, contentType, clientKey });
53
- if (presigned.alreadyExists) {
54
- process.stderr.write(` (reused existing video for ${filename})\n`);
55
- return presigned.videoId;
56
- }
57
- const fileBuffer = fs.readFileSync(filePath);
58
- const axios = (await Promise.resolve().then(() => __importStar(require('axios')))).default;
59
- await axios.put(presigned.uploadUrl, fileBuffer, {
60
- headers: { 'Content-Type': contentType },
61
- maxBodyLength: Infinity,
62
- timeout: 300000,
63
- });
64
- const { data: completed } = await client.post('/videos/upload/complete', { key: presigned.key, fileId: presigned.videoId, filename, clientKey });
65
- return completed.videoId;
66
- }
67
- function registerGenerateBatch(generate, client) {
68
- generate
69
- .command('batch')
70
- .description('Upload video files and generate structure for each in batch')
71
- .option('-f, --file <path>', 'video file to include (repeatable)', (v, acc) => { acc.push(v); return acc; }, [])
72
- .option('-v, --video <id>', 'already-uploaded video ID (repeatable)', (v, acc) => { acc.push(v); return acc; }, [])
73
- .option('-t, --template <id>', 'article template ID')
74
- .option('-s, --structure-template <id>', 'structure template ID')
75
- .option('--wait', 'poll until batch completes')
76
- .option('--json', 'output JSON')
77
- .option('--callback-url <url>', 'webhook URL')
78
- .option('--callback-secret <secret>', 'webhook HMAC secret')
79
- .action(async (opts) => {
80
- try {
81
- const files = opts.file ?? [];
82
- const videoIds = opts.video ?? [];
83
- if (!files.length && !videoIds.length) {
84
- (0, errors_1.exitWithError)('Provide at least one --file or --video');
85
- return;
86
- }
87
- const templateId = opts.template ? Number(opts.template) : undefined;
88
- const structureTemplateId = opts.structureTemplate ? Number(opts.structureTemplate) : undefined;
89
- const jobs = [];
90
- for (const filePath of files) {
91
- if (!fs.existsSync(filePath)) {
92
- (0, errors_1.exitWithError)(`File not found: ${filePath}`);
93
- return;
94
- }
95
- const clientKey = makeClientKey(filePath);
96
- process.stderr.write(`Uploading ${path.basename(filePath)}...\n`);
97
- const videoId = await uploadFile(client, filePath, clientKey);
98
- jobs.push({
99
- type: 'generate/structure',
100
- input: {
101
- videoId,
102
- ...(templateId !== undefined ? { templateId } : {}),
103
- ...(structureTemplateId !== undefined ? { structureTemplateId } : {}),
104
- },
105
- });
106
- }
107
- for (const videoId of videoIds) {
108
- jobs.push({
109
- type: 'generate/structure',
110
- input: {
111
- videoId,
112
- ...(templateId !== undefined ? { templateId } : {}),
113
- ...(structureTemplateId !== undefined ? { structureTemplateId } : {}),
114
- },
115
- });
116
- }
117
- const { data: batchRes } = await client.post('/batches', {
118
- jobs,
119
- ...(opts.callbackUrl ? { callbackUrl: opts.callbackUrl } : {}),
120
- ...(opts.callbackSecret ? { callbackSecret: opts.callbackSecret } : {}),
121
- });
122
- const { jobId } = batchRes;
123
- if (!opts.wait) {
124
- if (opts.json) {
125
- (0, output_1.printJson)({ jobId });
126
- }
127
- else {
128
- process.stdout.write(`Batch started: ${jobId}\n`);
129
- process.stdout.write(`${jobs.length} job(s) queued.\n`);
130
- process.stdout.write(`Poll status: hinto generate status ${jobId}\n`);
131
- }
132
- return;
133
- }
134
- process.stderr.write(`Waiting for batch ${jobId}...\n`);
135
- const result = await pollBatch(client, jobId);
136
- if (opts.json) {
137
- (0, output_1.printJson)(result);
138
- }
139
- else {
140
- process.stdout.write(`Batch ${result.status}.\n`);
141
- }
142
- }
143
- catch (e) {
144
- (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
145
- }
146
- });
147
- }
148
- async function pollBatch(client, jobId, intervalMs = 3000, timeoutMs = 600000) {
149
- const deadline = Date.now() + timeoutMs;
150
- while (Date.now() < deadline) {
151
- const { data } = await client.get(`/jobs/${jobId}`);
152
- if (data.status === 'completed' || data.status === 'failed') {
153
- return data;
154
- }
155
- await new Promise(resolve => setTimeout(resolve, intervalMs));
156
- }
157
- throw new Error(`Batch ${jobId} timed out after ${timeoutMs / 1000}s`);
158
- }