@hintoai/cli 0.2.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.
- package/LICENSE +21 -0
- package/README.md +429 -0
- package/dist/api/articles.d.ts +101 -0
- package/dist/api/articles.js +40 -0
- package/dist/api/client.d.ts +2 -0
- package/dist/api/client.js +48 -0
- package/dist/api/export.d.ts +6 -0
- package/dist/api/export.js +24 -0
- package/dist/api/folders.d.ts +18 -0
- package/dist/api/folders.js +14 -0
- package/dist/api/generate.d.ts +15 -0
- package/dist/api/generate.js +23 -0
- package/dist/api/project.d.ts +43 -0
- package/dist/api/project.js +19 -0
- package/dist/api/publish.d.ts +31 -0
- package/dist/api/publish.js +23 -0
- package/dist/api/templates.d.ts +17 -0
- package/dist/api/templates.js +8 -0
- package/dist/api/videos.d.ts +48 -0
- package/dist/api/videos.js +30 -0
- package/dist/commands/articles.d.ts +3 -0
- package/dist/commands/articles.js +297 -0
- package/dist/commands/completion.d.ts +2 -0
- package/dist/commands/completion.js +73 -0
- package/dist/commands/export.d.ts +3 -0
- package/dist/commands/export.js +76 -0
- package/dist/commands/folders.d.ts +3 -0
- package/dist/commands/folders.js +108 -0
- package/dist/commands/generate-batch.d.ts +3 -0
- package/dist/commands/generate-batch.js +158 -0
- package/dist/commands/generate.d.ts +3 -0
- package/dist/commands/generate.js +83 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.js +25 -0
- package/dist/commands/project.d.ts +3 -0
- package/dist/commands/project.js +112 -0
- package/dist/commands/publish.d.ts +3 -0
- package/dist/commands/publish.js +74 -0
- package/dist/commands/templates.d.ts +3 -0
- package/dist/commands/templates.js +50 -0
- package/dist/commands/videos.d.ts +3 -0
- package/dist/commands/videos.js +176 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.js +31 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +16 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +56 -0
- package/dist/output.d.ts +3 -0
- package/dist/output.js +43 -0
- package/dist/poll.d.ts +2 -0
- package/dist/poll.js +23 -0
- package/package.json +68 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerTemplates = registerTemplates;
|
|
4
|
+
const templates_1 = require("../api/templates");
|
|
5
|
+
const errors_1 = require("../errors");
|
|
6
|
+
const output_1 = require("../output");
|
|
7
|
+
function registerTemplates(program, client) {
|
|
8
|
+
const templates = program.command('templates').description('Browse templates');
|
|
9
|
+
const api = (0, templates_1.templatesApi)(client);
|
|
10
|
+
templates
|
|
11
|
+
.command('article')
|
|
12
|
+
.description('List article generation templates for this project type')
|
|
13
|
+
.option('--json', 'Output as JSON')
|
|
14
|
+
.action(async (opts) => {
|
|
15
|
+
try {
|
|
16
|
+
const data = await api.articleTemplates();
|
|
17
|
+
if (opts.json)
|
|
18
|
+
return (0, output_1.printJson)(data);
|
|
19
|
+
(0, output_1.printTable)(['ID', 'Name', 'Requires Video', 'Description'], data.templates.map((t) => [
|
|
20
|
+
String(t.id),
|
|
21
|
+
t.name,
|
|
22
|
+
t.requires_video ? 'yes' : 'no',
|
|
23
|
+
t.description ?? '—',
|
|
24
|
+
]));
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
(0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
templates
|
|
31
|
+
.command('structure')
|
|
32
|
+
.description('List structure generation templates for this project type')
|
|
33
|
+
.option('--json', 'Output as JSON')
|
|
34
|
+
.action(async (opts) => {
|
|
35
|
+
try {
|
|
36
|
+
const data = await api.structureTemplates();
|
|
37
|
+
if (opts.json)
|
|
38
|
+
return (0, output_1.printJson)(data);
|
|
39
|
+
(0, output_1.printTable)(['ID', 'Name', 'Requires Video', 'Description'], data.templates.map((t) => [
|
|
40
|
+
String(t.id),
|
|
41
|
+
t.name,
|
|
42
|
+
t.requires_video ? 'yes' : 'no',
|
|
43
|
+
t.description ?? '—',
|
|
44
|
+
]));
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
(0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.registerVideos = registerVideos;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const axios_1 = __importDefault(require("axios"));
|
|
43
|
+
const videos_1 = require("../api/videos");
|
|
44
|
+
const errors_1 = require("../errors");
|
|
45
|
+
const output_1 = require("../output");
|
|
46
|
+
function registerVideos(program, client) {
|
|
47
|
+
const videos = program.command('videos').description('Manage videos');
|
|
48
|
+
const api = (0, videos_1.videosApi)(client);
|
|
49
|
+
videos
|
|
50
|
+
.command('list')
|
|
51
|
+
.description('List all videos')
|
|
52
|
+
.option('--offset <n>', 'Number of videos to skip', '0')
|
|
53
|
+
.option('--limit <n>', 'Results per page', '20')
|
|
54
|
+
.option('--json', 'Output as JSON')
|
|
55
|
+
.action(async (opts) => {
|
|
56
|
+
try {
|
|
57
|
+
const data = await api.list({ offset: Number(opts.offset), limit: Number(opts.limit) });
|
|
58
|
+
if (opts.json)
|
|
59
|
+
return (0, output_1.printJson)(data);
|
|
60
|
+
(0, output_1.printTable)(['Video ID', 'Filename', 'Status', 'Created'], data.videos.map((v) => [v.videoId, v.filename ?? '—', v.status, v.createdAt]));
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
(0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
videos
|
|
67
|
+
.command('import')
|
|
68
|
+
.description('Import a video from a URL')
|
|
69
|
+
.requiredOption('--url <url>', 'Video URL to import')
|
|
70
|
+
.option('--name <name>', 'Display name for the imported video')
|
|
71
|
+
.option('--callback-url <url>', 'URL to receive a webhook when the import job completes')
|
|
72
|
+
.option('--callback-secret <secret>', 'HMAC-SHA256 signing secret for the callback webhook')
|
|
73
|
+
.option('--json', 'Output as JSON')
|
|
74
|
+
.action(async (opts) => {
|
|
75
|
+
try {
|
|
76
|
+
const data = await api.import(opts.url, opts.name, opts.callbackUrl, opts.callbackSecret);
|
|
77
|
+
if (opts.json)
|
|
78
|
+
return (0, output_1.printJson)(data);
|
|
79
|
+
(0, output_1.printKeyValue)(data);
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
(0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
videos
|
|
86
|
+
.command('get <videoId>')
|
|
87
|
+
.description('Get a video by ID')
|
|
88
|
+
.option('--json', 'Output as JSON')
|
|
89
|
+
.action(async (videoId, opts) => {
|
|
90
|
+
try {
|
|
91
|
+
const data = await api.get(videoId);
|
|
92
|
+
if (opts.json)
|
|
93
|
+
return (0, output_1.printJson)(data);
|
|
94
|
+
(0, output_1.printKeyValue)(data);
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
(0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
videos
|
|
101
|
+
.command('status <videoId>')
|
|
102
|
+
.description('Get video processing status')
|
|
103
|
+
.option('--json', 'Output as JSON')
|
|
104
|
+
.action(async (videoId, opts) => {
|
|
105
|
+
try {
|
|
106
|
+
const data = await api.status(videoId);
|
|
107
|
+
if (opts.json)
|
|
108
|
+
return (0, output_1.printJson)(data);
|
|
109
|
+
(0, output_1.printKeyValue)(data);
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
(0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
videos
|
|
116
|
+
.command('delete <videoId>')
|
|
117
|
+
.description('Delete a video')
|
|
118
|
+
.option('--json', 'Output as JSON')
|
|
119
|
+
.action(async (videoId, opts) => {
|
|
120
|
+
try {
|
|
121
|
+
await api.delete(videoId);
|
|
122
|
+
if (opts.json)
|
|
123
|
+
return (0, output_1.printJson)({ deleted: true });
|
|
124
|
+
process.stdout.write(`Video ${videoId} deleted.\n`);
|
|
125
|
+
}
|
|
126
|
+
catch (e) {
|
|
127
|
+
(0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
videos
|
|
131
|
+
.command('upload')
|
|
132
|
+
.description('Upload a video file from disk (3-step presigned flow)')
|
|
133
|
+
.requiredOption('--file <path>', 'Path to the video file')
|
|
134
|
+
.option('--json', 'Output as JSON')
|
|
135
|
+
.action(async (opts) => {
|
|
136
|
+
try {
|
|
137
|
+
const filePath = path.resolve(opts.file);
|
|
138
|
+
if (!fs.existsSync(filePath)) {
|
|
139
|
+
(0, errors_1.exitWithError)(`File not found: ${filePath}`);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const filename = path.basename(filePath);
|
|
143
|
+
const ext = path.extname(filename).toLowerCase();
|
|
144
|
+
const contentTypeMap = {
|
|
145
|
+
'.mp4': 'video/mp4',
|
|
146
|
+
'.mov': 'video/quicktime',
|
|
147
|
+
'.webm': 'video/webm',
|
|
148
|
+
'.avi': 'video/avi',
|
|
149
|
+
'.mkv': 'video/x-matroska',
|
|
150
|
+
};
|
|
151
|
+
const contentType = contentTypeMap[ext] ?? 'video/mp4';
|
|
152
|
+
// Step 1: get presigned URL
|
|
153
|
+
process.stderr.write('Requesting presigned upload URL...\n');
|
|
154
|
+
const { videoId, uploadUrl, key: s3Key } = await api.uploadPresigned(filename, contentType);
|
|
155
|
+
// Step 2: PUT file to S3
|
|
156
|
+
process.stderr.write(`Uploading ${filename}...\n`);
|
|
157
|
+
const fileStream = fs.createReadStream(filePath);
|
|
158
|
+
const { size } = fs.statSync(filePath);
|
|
159
|
+
await axios_1.default.put(uploadUrl, fileStream, {
|
|
160
|
+
headers: { 'Content-Type': contentType, 'Content-Length': size },
|
|
161
|
+
maxBodyLength: Number.POSITIVE_INFINITY,
|
|
162
|
+
maxContentLength: Number.POSITIVE_INFINITY,
|
|
163
|
+
});
|
|
164
|
+
// Step 3: complete upload
|
|
165
|
+
process.stderr.write('Completing upload...\n');
|
|
166
|
+
const result = await api.uploadComplete(videoId, s3Key, filename);
|
|
167
|
+
if (opts.json)
|
|
168
|
+
return (0, output_1.printJson)(result);
|
|
169
|
+
process.stdout.write(`Uploaded: videoId=${result.videoId} status=pending\n`);
|
|
170
|
+
process.stdout.write(`Track: hinto videos status ${result.videoId}\n`);
|
|
171
|
+
}
|
|
172
|
+
catch (e) {
|
|
173
|
+
(0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CONFIG_PATH = void 0;
|
|
7
|
+
exports.saveConfig = saveConfig;
|
|
8
|
+
exports.loadConfig = loadConfig;
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const os_1 = __importDefault(require("os"));
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
exports.CONFIG_PATH = path_1.default.join(os_1.default.homedir(), '.hinto', 'config.json');
|
|
13
|
+
function saveConfig(config) {
|
|
14
|
+
const dir = path_1.default.dirname(exports.CONFIG_PATH);
|
|
15
|
+
if (!fs_1.default.existsSync(dir))
|
|
16
|
+
fs_1.default.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
17
|
+
fs_1.default.writeFileSync(exports.CONFIG_PATH, JSON.stringify(config, null, 2), {
|
|
18
|
+
encoding: 'utf-8',
|
|
19
|
+
mode: 0o600,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function loadConfig() {
|
|
23
|
+
if (!fs_1.default.existsSync(exports.CONFIG_PATH)) {
|
|
24
|
+
throw new Error('Run `hinto init --key <your-api-key>` to get started.');
|
|
25
|
+
}
|
|
26
|
+
const raw = JSON.parse(fs_1.default.readFileSync(exports.CONFIG_PATH, 'utf-8'));
|
|
27
|
+
return {
|
|
28
|
+
...raw,
|
|
29
|
+
apiKey: process.env.HINTO_API_KEY ?? raw.apiKey,
|
|
30
|
+
};
|
|
31
|
+
}
|
package/dist/errors.d.ts
ADDED
package/dist/errors.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CliError = void 0;
|
|
4
|
+
exports.exitWithError = exitWithError;
|
|
5
|
+
class CliError extends Error {
|
|
6
|
+
constructor(code, message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.name = 'CliError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.CliError = CliError;
|
|
13
|
+
function exitWithError(message) {
|
|
14
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const client_1 = require("./api/client");
|
|
6
|
+
const articles_1 = require("./commands/articles");
|
|
7
|
+
const completion_1 = require("./commands/completion");
|
|
8
|
+
const export_1 = require("./commands/export");
|
|
9
|
+
const folders_1 = require("./commands/folders");
|
|
10
|
+
const generate_1 = require("./commands/generate");
|
|
11
|
+
const init_1 = require("./commands/init");
|
|
12
|
+
const project_1 = require("./commands/project");
|
|
13
|
+
const publish_1 = require("./commands/publish");
|
|
14
|
+
const templates_1 = require("./commands/templates");
|
|
15
|
+
const videos_1 = require("./commands/videos");
|
|
16
|
+
const config_1 = require("./config");
|
|
17
|
+
const errors_1 = require("./errors");
|
|
18
|
+
// Read version from package.json so `hinto --version` never drifts from the
|
|
19
|
+
// published package version (package.json sits one level above dist/index.js).
|
|
20
|
+
const { version } = require('../package.json');
|
|
21
|
+
const program = new commander_1.Command();
|
|
22
|
+
program
|
|
23
|
+
.name('hinto')
|
|
24
|
+
.description('Hinto AI CLI — manage videos, articles, and publishing')
|
|
25
|
+
.version(version)
|
|
26
|
+
.option('--api-url <url>', 'Override the Hinto base URL');
|
|
27
|
+
// init and completion don't need auth — register first
|
|
28
|
+
(0, init_1.registerInit)(program);
|
|
29
|
+
(0, completion_1.registerCompletion)(program);
|
|
30
|
+
// Load config eagerly. If missing, fall back to empty key so --help still
|
|
31
|
+
// works on all subcommands. The client's interceptor returns a helpful
|
|
32
|
+
// UNAUTHORIZED message when a command is actually invoked without a valid key.
|
|
33
|
+
const config = (() => {
|
|
34
|
+
try {
|
|
35
|
+
return (0, config_1.loadConfig)();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return { apiKey: process.env.HINTO_API_KEY ?? '', baseUrl: 'https://app.hinto.ai' };
|
|
39
|
+
}
|
|
40
|
+
})();
|
|
41
|
+
const apiUrl = (() => {
|
|
42
|
+
const idx = process.argv.indexOf('--api-url');
|
|
43
|
+
return idx !== -1 ? (process.argv[idx + 1] ?? config.baseUrl) : config.baseUrl;
|
|
44
|
+
})();
|
|
45
|
+
const client = (0, client_1.createClient)(config.apiKey, apiUrl);
|
|
46
|
+
(0, videos_1.registerVideos)(program, client);
|
|
47
|
+
(0, articles_1.registerArticles)(program, client);
|
|
48
|
+
(0, folders_1.registerFolders)(program, client);
|
|
49
|
+
(0, generate_1.registerGenerate)(program, client);
|
|
50
|
+
(0, project_1.registerProject)(program, client);
|
|
51
|
+
(0, publish_1.registerPublish)(program, client);
|
|
52
|
+
(0, templates_1.registerTemplates)(program, client);
|
|
53
|
+
(0, export_1.registerExport)(program, client);
|
|
54
|
+
program.parseAsync(process.argv).catch((e) => {
|
|
55
|
+
(0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
|
|
56
|
+
});
|
package/dist/output.d.ts
ADDED
package/dist/output.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.printJson = printJson;
|
|
7
|
+
exports.printTable = printTable;
|
|
8
|
+
exports.printKeyValue = printKeyValue;
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
11
|
+
function printJson(data) {
|
|
12
|
+
process.stdout.write(`${JSON.stringify(data, null, 2)}\n`);
|
|
13
|
+
}
|
|
14
|
+
function printTable(headers, rows) {
|
|
15
|
+
const table = new cli_table3_1.default({ head: headers.map((h) => chalk_1.default.bold(h)) });
|
|
16
|
+
rows.forEach((row) => table.push(row));
|
|
17
|
+
process.stdout.write(`${table.toString()}\n`);
|
|
18
|
+
}
|
|
19
|
+
function printKeyValue(obj) {
|
|
20
|
+
if (obj == null || typeof obj !== 'object') {
|
|
21
|
+
process.stdout.write(`${String(obj)}\n`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const lines = Object.entries(obj)
|
|
25
|
+
.map(([k, v]) => `${chalk_1.default.bold(k)}: ${formatValue(k, v)}`)
|
|
26
|
+
.join('\n');
|
|
27
|
+
process.stdout.write(`${lines}\n`);
|
|
28
|
+
}
|
|
29
|
+
function formatValue(key, value) {
|
|
30
|
+
if ((key === 'status' || key === 'ingest_status') && typeof value === 'string') {
|
|
31
|
+
if (['ready', 'completed'].includes(value))
|
|
32
|
+
return chalk_1.default.green(value);
|
|
33
|
+
if (['pending', 'processing'].includes(value))
|
|
34
|
+
return chalk_1.default.yellow(value);
|
|
35
|
+
if (value === 'failed')
|
|
36
|
+
return chalk_1.default.red(value);
|
|
37
|
+
}
|
|
38
|
+
if (value === null || value === undefined)
|
|
39
|
+
return chalk_1.default.dim('—');
|
|
40
|
+
if (typeof value === 'object')
|
|
41
|
+
return JSON.stringify(value, null, 2);
|
|
42
|
+
return String(value);
|
|
43
|
+
}
|
package/dist/poll.d.ts
ADDED
package/dist/poll.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pollJob = pollJob;
|
|
4
|
+
async function pollJob(client, jobId, intervalMs = 2000, timeoutMs = 300000) {
|
|
5
|
+
process.stderr.write(`Waiting for job ${jobId}…\n`);
|
|
6
|
+
const deadline = Date.now() + timeoutMs;
|
|
7
|
+
while (Date.now() < deadline) {
|
|
8
|
+
const { data } = await client.get(`/generate/${jobId}`);
|
|
9
|
+
if (data.status === 'completed') {
|
|
10
|
+
process.stderr.write(`Job ${jobId} completed\n`);
|
|
11
|
+
return data.output;
|
|
12
|
+
}
|
|
13
|
+
if (data.status === 'failed') {
|
|
14
|
+
process.stderr.write(`Job ${jobId} failed\n`);
|
|
15
|
+
throw new Error(data.error ?? 'Job failed with no error message');
|
|
16
|
+
}
|
|
17
|
+
await sleep(intervalMs);
|
|
18
|
+
}
|
|
19
|
+
throw new Error(`Job ${jobId} timed out after ${timeoutMs / 1000}s`);
|
|
20
|
+
}
|
|
21
|
+
function sleep(ms) {
|
|
22
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
23
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hintoai/cli",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Hinto AI CLI — manage videos, articles, and publishing via the Hinto API",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"hinto": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=18"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"homepage": "https://github.com/hintoai/hinto-cli#readme",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/hintoai/hinto-cli.git"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/hintoai/hinto-cli/issues"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"hinto",
|
|
26
|
+
"cli",
|
|
27
|
+
"video",
|
|
28
|
+
"articles",
|
|
29
|
+
"publishing",
|
|
30
|
+
"ai",
|
|
31
|
+
"agent-skill"
|
|
32
|
+
],
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public",
|
|
35
|
+
"provenance": true
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc",
|
|
39
|
+
"dev": "ts-node src/index.ts",
|
|
40
|
+
"test": "jest",
|
|
41
|
+
"test:watch": "jest --watch",
|
|
42
|
+
"lint": "biome check .",
|
|
43
|
+
"format": "biome format --write .",
|
|
44
|
+
"validate:skill": "node scripts/validate-skill.mjs",
|
|
45
|
+
"changeset": "changeset",
|
|
46
|
+
"version-packages": "changeset version",
|
|
47
|
+
"release": "npm run build && changeset publish",
|
|
48
|
+
"prepublishOnly": "npm run build"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"axios": "^1.7.0",
|
|
52
|
+
"chalk": "^4.1.2",
|
|
53
|
+
"cli-table3": "^0.6.5",
|
|
54
|
+
"commander": "^12.1.0",
|
|
55
|
+
"ora": "^8.1.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@biomejs/biome": "1.9.4",
|
|
59
|
+
"@changesets/cli": "^2.31.0",
|
|
60
|
+
"@types/jest": "^30.0.0",
|
|
61
|
+
"@types/node": "^25.9.2",
|
|
62
|
+
"jest": "^30.4.2",
|
|
63
|
+
"nock": "^13.5.0",
|
|
64
|
+
"ts-jest": "^29.4.11",
|
|
65
|
+
"ts-node": "^10.9.0",
|
|
66
|
+
"typescript": "^5.5.0"
|
|
67
|
+
}
|
|
68
|
+
}
|