@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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +429 -0
  3. package/dist/api/articles.d.ts +101 -0
  4. package/dist/api/articles.js +40 -0
  5. package/dist/api/client.d.ts +2 -0
  6. package/dist/api/client.js +48 -0
  7. package/dist/api/export.d.ts +6 -0
  8. package/dist/api/export.js +24 -0
  9. package/dist/api/folders.d.ts +18 -0
  10. package/dist/api/folders.js +14 -0
  11. package/dist/api/generate.d.ts +15 -0
  12. package/dist/api/generate.js +23 -0
  13. package/dist/api/project.d.ts +43 -0
  14. package/dist/api/project.js +19 -0
  15. package/dist/api/publish.d.ts +31 -0
  16. package/dist/api/publish.js +23 -0
  17. package/dist/api/templates.d.ts +17 -0
  18. package/dist/api/templates.js +8 -0
  19. package/dist/api/videos.d.ts +48 -0
  20. package/dist/api/videos.js +30 -0
  21. package/dist/commands/articles.d.ts +3 -0
  22. package/dist/commands/articles.js +297 -0
  23. package/dist/commands/completion.d.ts +2 -0
  24. package/dist/commands/completion.js +73 -0
  25. package/dist/commands/export.d.ts +3 -0
  26. package/dist/commands/export.js +76 -0
  27. package/dist/commands/folders.d.ts +3 -0
  28. package/dist/commands/folders.js +108 -0
  29. package/dist/commands/generate-batch.d.ts +3 -0
  30. package/dist/commands/generate-batch.js +158 -0
  31. package/dist/commands/generate.d.ts +3 -0
  32. package/dist/commands/generate.js +83 -0
  33. package/dist/commands/init.d.ts +3 -0
  34. package/dist/commands/init.js +25 -0
  35. package/dist/commands/project.d.ts +3 -0
  36. package/dist/commands/project.js +112 -0
  37. package/dist/commands/publish.d.ts +3 -0
  38. package/dist/commands/publish.js +74 -0
  39. package/dist/commands/templates.d.ts +3 -0
  40. package/dist/commands/templates.js +50 -0
  41. package/dist/commands/videos.d.ts +3 -0
  42. package/dist/commands/videos.js +176 -0
  43. package/dist/config.d.ts +7 -0
  44. package/dist/config.js +31 -0
  45. package/dist/errors.d.ts +5 -0
  46. package/dist/errors.js +16 -0
  47. package/dist/index.d.ts +2 -0
  48. package/dist/index.js +56 -0
  49. package/dist/output.d.ts +3 -0
  50. package/dist/output.js +43 -0
  51. package/dist/poll.d.ts +2 -0
  52. package/dist/poll.js +23 -0
  53. package/package.json +68 -0
@@ -0,0 +1,76 @@
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.registerExport = registerExport;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const export_1 = require("../api/export");
9
+ const errors_1 = require("../errors");
10
+ function registerExport(program, client) {
11
+ const exportCmd = program.command('export').description('Export content');
12
+ const api = (0, export_1.exportApi)(client);
13
+ exportCmd
14
+ .command('article <id>')
15
+ .description('Export an article')
16
+ .option('--format <fmt>', 'Output format: md (default), html, or pdf', 'md')
17
+ .option('--out <path>', 'Save to file instead of stdout')
18
+ .option('--lang <code>', 'Export a translated version by language code (e.g. fr, de)')
19
+ .action(async (id, opts) => {
20
+ try {
21
+ // API accepts 'markdown' not 'md'
22
+ const apiFormat = (opts.format === 'md' ? 'markdown' : opts.format);
23
+ const isPdf = apiFormat === 'pdf';
24
+ if (isPdf && !opts.out) {
25
+ (0, errors_1.exitWithError)('--out <path> is required for PDF export (binary output cannot be printed to stdout)');
26
+ return;
27
+ }
28
+ const data = await api.article(id, apiFormat, opts.lang);
29
+ if (opts.out) {
30
+ if (isPdf) {
31
+ fs_1.default.writeFileSync(opts.out, data);
32
+ }
33
+ else {
34
+ fs_1.default.writeFileSync(opts.out, data, 'utf-8');
35
+ }
36
+ process.stdout.write(`Saved to ${opts.out}\n`);
37
+ }
38
+ else {
39
+ process.stdout.write(`${data}\n`);
40
+ }
41
+ }
42
+ catch (e) {
43
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
44
+ }
45
+ });
46
+ exportCmd
47
+ .command('folder <id>')
48
+ .description('Export a folder as PDF')
49
+ .requiredOption('--out <path>', 'Output zip file path')
50
+ .action(async (id, opts) => {
51
+ try {
52
+ const data = await api.folder(id);
53
+ fs_1.default.writeFileSync(opts.out, data);
54
+ process.stdout.write(`Folder exported to ${opts.out}\n`);
55
+ }
56
+ catch (e) {
57
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
58
+ }
59
+ });
60
+ exportCmd
61
+ .command('project')
62
+ .description('Export the full project as zip')
63
+ .requiredOption('--out <path>', 'Output zip file path')
64
+ .option('--format <fmt>', 'Export format: markdown (default), html, pdf, or llm-text', 'markdown')
65
+ .action(async (opts) => {
66
+ try {
67
+ const fmt = opts.format;
68
+ const data = await api.project(fmt);
69
+ fs_1.default.writeFileSync(opts.out, data);
70
+ process.stdout.write(`Project exported to ${opts.out}\n`);
71
+ }
72
+ catch (e) {
73
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
74
+ }
75
+ });
76
+ }
@@ -0,0 +1,3 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ import type { Command } from 'commander';
3
+ export declare function registerFolders(program: Command, client: AxiosInstance): void;
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerFolders = registerFolders;
4
+ const folders_1 = require("../api/folders");
5
+ const errors_1 = require("../errors");
6
+ const output_1 = require("../output");
7
+ function registerFolders(program, client) {
8
+ const folders = program.command('folders').description('Manage folders');
9
+ const api = (0, folders_1.foldersApi)(client);
10
+ folders
11
+ .command('list')
12
+ .description('List all folders')
13
+ .option('--json', 'Output as JSON')
14
+ .action(async (opts) => {
15
+ try {
16
+ const data = await api.list();
17
+ if (opts.json)
18
+ return (0, output_1.printJson)(data);
19
+ (0, output_1.printTable)(['ID', 'Name', 'Parent'], data.folders.map((f) => [
20
+ String(f.id),
21
+ f.name,
22
+ f.parentId != null ? String(f.parentId) : '—',
23
+ ]));
24
+ }
25
+ catch (e) {
26
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
27
+ }
28
+ });
29
+ folders
30
+ .command('get <id>')
31
+ .description('Get a folder by ID')
32
+ .option('--json', 'Output as JSON')
33
+ .action(async (id, opts) => {
34
+ try {
35
+ const data = await api.get(id);
36
+ if (opts.json)
37
+ return (0, output_1.printJson)(data);
38
+ (0, output_1.printKeyValue)(data);
39
+ }
40
+ catch (e) {
41
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
42
+ }
43
+ });
44
+ folders
45
+ .command('create')
46
+ .description('Create a folder')
47
+ .requiredOption('--name <name>', 'Folder name')
48
+ .option('--parent <id>', 'Parent folder ID (omit for root)')
49
+ .option('--json', 'Output as JSON')
50
+ .action(async (opts) => {
51
+ try {
52
+ const data = await api.create(opts.name, opts.parent);
53
+ if (opts.json)
54
+ return (0, output_1.printJson)(data);
55
+ (0, output_1.printKeyValue)(data);
56
+ }
57
+ catch (e) {
58
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
59
+ }
60
+ });
61
+ folders
62
+ .command('update <id>')
63
+ .description('Rename a folder')
64
+ .requiredOption('--name <name>', 'New folder name')
65
+ .option('--json', 'Output as JSON')
66
+ .action(async (id, opts) => {
67
+ try {
68
+ const data = await api.update(id, opts.name);
69
+ if (opts.json)
70
+ return (0, output_1.printJson)(data);
71
+ (0, output_1.printKeyValue)(data);
72
+ }
73
+ catch (e) {
74
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
75
+ }
76
+ });
77
+ folders
78
+ .command('delete <id>')
79
+ .description('Delete a folder')
80
+ .option('--json', 'Output as JSON')
81
+ .action(async (id, opts) => {
82
+ try {
83
+ await api.delete(id);
84
+ if (opts.json)
85
+ return (0, output_1.printJson)({ deleted: true });
86
+ process.stdout.write(`Folder ${id} deleted.\n`);
87
+ }
88
+ catch (e) {
89
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
90
+ }
91
+ });
92
+ folders
93
+ .command('move <id>')
94
+ .description('Move a folder (omit --parent to move to root)')
95
+ .option('--parent <id>', 'Target parent folder ID')
96
+ .option('--json', 'Output as JSON')
97
+ .action(async (id, opts) => {
98
+ try {
99
+ const data = await api.move(id, opts.parent ?? null);
100
+ if (opts.json)
101
+ return (0, output_1.printJson)(data);
102
+ (0, output_1.printKeyValue)(data);
103
+ }
104
+ catch (e) {
105
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
106
+ }
107
+ });
108
+ }
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ import { AxiosInstance } from 'axios';
3
+ export declare function registerGenerateBatch(generate: Command, client: AxiosInstance): void;
@@ -0,0 +1,158 @@
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
+ }
@@ -0,0 +1,3 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ import type { Command } from 'commander';
3
+ export declare function registerGenerate(program: Command, client: AxiosInstance): void;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerGenerate = registerGenerate;
4
+ const generate_1 = require("../api/generate");
5
+ const errors_1 = require("../errors");
6
+ const output_1 = require("../output");
7
+ const poll_1 = require("../poll");
8
+ function registerGenerate(program, client) {
9
+ const generate = program.command('generate').description('Generate content from videos');
10
+ const api = (0, generate_1.generateApi)(client);
11
+ generate
12
+ .command('start')
13
+ .description('Start a generation job')
14
+ .requiredOption('--video <videoId>', 'Video ID to generate from')
15
+ .option('--template <templateId>', 'Template ID (optional — server auto-selects if omitted)')
16
+ .option('--callback-url <url>', 'URL to receive a webhook when the job completes')
17
+ .option('--callback-secret <secret>', 'HMAC-SHA256 signing secret for the callback webhook')
18
+ .option('--wait', 'Wait for completion')
19
+ .option('--json', 'Output as JSON')
20
+ .action(async (opts) => {
21
+ try {
22
+ const data = await api.start(opts.video, opts.template ? Number(opts.template) : undefined, opts.callbackUrl, opts.callbackSecret);
23
+ if (opts.wait) {
24
+ const output = await (0, poll_1.pollJob)(client, data.jobId);
25
+ if (opts.json)
26
+ return (0, output_1.printJson)(output);
27
+ (0, output_1.printKeyValue)(output);
28
+ }
29
+ else {
30
+ if (opts.json)
31
+ return (0, output_1.printJson)(data);
32
+ process.stdout.write(`Job started: ${data.jobId}\n`);
33
+ }
34
+ }
35
+ catch (e) {
36
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
37
+ }
38
+ });
39
+ generate
40
+ .command('status <jobId>')
41
+ .description('Check generation job status')
42
+ .option('--json', 'Output as JSON')
43
+ .action(async (jobId, opts) => {
44
+ try {
45
+ const data = await api.status(jobId);
46
+ if (opts.json)
47
+ return (0, output_1.printJson)(data);
48
+ const display = Object.fromEntries(Object.entries(data).filter(([k, v]) => !(k === 'error' && (v === null || v === undefined))));
49
+ (0, output_1.printKeyValue)(display);
50
+ }
51
+ catch (e) {
52
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
53
+ }
54
+ });
55
+ generate
56
+ .command('structure')
57
+ .description('Generate project structure from a video')
58
+ .requiredOption('--video <videoId>', 'Video ID to generate structure from')
59
+ .option('--template <id>', 'Template ID (optional — server auto-selects if omitted)')
60
+ .option('--callback-url <url>', 'URL to receive a webhook when the job completes')
61
+ .option('--callback-secret <secret>', 'HMAC-SHA256 signing secret for the callback webhook')
62
+ .option('--wait', 'Wait for completion')
63
+ .option('--json', 'Output as JSON')
64
+ .action(async (opts) => {
65
+ try {
66
+ const data = await api.structure(opts.video, opts.template ? Number(opts.template) : undefined, opts.callbackUrl, opts.callbackSecret);
67
+ if (opts.wait) {
68
+ const output = await (0, poll_1.pollJob)(client, data.jobId);
69
+ if (opts.json)
70
+ return (0, output_1.printJson)(output);
71
+ (0, output_1.printKeyValue)(output);
72
+ }
73
+ else {
74
+ if (opts.json)
75
+ return (0, output_1.printJson)(data);
76
+ process.stdout.write(`Structure job started: ${data.jobId}\n`);
77
+ }
78
+ }
79
+ catch (e) {
80
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
81
+ }
82
+ });
83
+ }
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function runInit(apiKey: string, baseUrl: string): void;
3
+ export declare function registerInit(program: Command): void;
@@ -0,0 +1,25 @@
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.runInit = runInit;
7
+ exports.registerInit = registerInit;
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const config_1 = require("../config");
10
+ function runInit(apiKey, baseUrl) {
11
+ (0, config_1.saveConfig)({ apiKey, baseUrl });
12
+ process.stdout.write(chalk_1.default.green('✓ Authenticated. Config saved to ~/.hinto/config.json\n'));
13
+ }
14
+ function registerInit(program) {
15
+ program
16
+ .command('init')
17
+ .description('Authenticate with your Hinto API key')
18
+ .requiredOption('--key <apiKey>', 'Your Hinto API key')
19
+ .option('--api-url <url>', 'Override the Hinto base URL', 'https://app.hinto.ai')
20
+ .action((opts) => {
21
+ // Prefer the root program's --api-url (passed globally) over the local default
22
+ const baseUrl = program.opts().apiUrl ?? opts.apiUrl;
23
+ runInit(opts.key, baseUrl);
24
+ });
25
+ }
@@ -0,0 +1,3 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ import type { Command } from 'commander';
3
+ export declare function registerProject(program: Command, client: AxiosInstance): void;
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerProject = registerProject;
4
+ const project_1 = require("../api/project");
5
+ const errors_1 = require("../errors");
6
+ const output_1 = require("../output");
7
+ function registerProject(program, client) {
8
+ const project = program.command('project').description('Manage project settings');
9
+ const api = (0, project_1.projectApi)(client);
10
+ project
11
+ .command('get')
12
+ .description('Get project details')
13
+ .option('--json', 'Output as JSON')
14
+ .action(async (opts) => {
15
+ try {
16
+ const data = await api.get();
17
+ if (opts.json)
18
+ return (0, output_1.printJson)(data);
19
+ (0, output_1.printKeyValue)(data.project);
20
+ }
21
+ catch (e) {
22
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
23
+ }
24
+ });
25
+ project
26
+ .command('update')
27
+ .description('Update project settings')
28
+ .option('--name <name>', 'New project name')
29
+ .option('--json', 'Output as JSON')
30
+ .action(async (opts) => {
31
+ try {
32
+ const data = await api.update({ name: opts.name });
33
+ if (opts.json)
34
+ return (0, output_1.printJson)(data);
35
+ (0, output_1.printKeyValue)(data.project);
36
+ }
37
+ catch (e) {
38
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
39
+ }
40
+ });
41
+ project
42
+ .command('structure')
43
+ .description('Get project folder/article hierarchy')
44
+ .option('--json', 'Output as JSON')
45
+ .action(async (opts) => {
46
+ try {
47
+ const data = await api.structure();
48
+ if (opts.json)
49
+ return (0, output_1.printJson)(data);
50
+ (0, output_1.printKeyValue)(data);
51
+ }
52
+ catch (e) {
53
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
54
+ }
55
+ });
56
+ project
57
+ .command('languages')
58
+ .description('List languages enabled for this project')
59
+ .option('--json', 'Output as JSON')
60
+ .action(async (opts) => {
61
+ try {
62
+ const data = await api.listLanguages();
63
+ if (opts.json)
64
+ return (0, output_1.printJson)(data);
65
+ (0, output_1.printTable)(['Code', 'Label', 'Translated', 'Total', 'Translating'], data.languages.map((l) => [
66
+ l.code,
67
+ l.label,
68
+ String(l.translatedArticles),
69
+ String(l.totalArticles),
70
+ String(l.isTranslating),
71
+ ]));
72
+ }
73
+ catch (e) {
74
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
75
+ }
76
+ });
77
+ project
78
+ .command('retranslate')
79
+ .description('Retranslate all articles to a language')
80
+ .requiredOption('--lang <code>', 'Language code (e.g. fr, de, es)')
81
+ .option('--json', 'Output as JSON')
82
+ .option('--callback-url <url>', 'Webhook URL to call when the job completes')
83
+ .option('--callback-secret <secret>', 'Secret to include in the webhook callback')
84
+ .action(async (opts) => {
85
+ try {
86
+ const data = await api.retranslate(opts.lang, opts.callbackUrl, opts.callbackSecret);
87
+ if (opts.json)
88
+ return (0, output_1.printJson)(data);
89
+ const queued = data.output?.queued ?? 0;
90
+ process.stdout.write(`Retranslation queued. ${queued} articles enqueued.\n`);
91
+ }
92
+ catch (e) {
93
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
94
+ }
95
+ });
96
+ project
97
+ .command('add-language')
98
+ .description('Add a language to this project')
99
+ .requiredOption('--code <code>', 'Language code to add (e.g. fr, de, es)')
100
+ .option('--json', 'Output as JSON')
101
+ .action(async (opts) => {
102
+ try {
103
+ const data = await api.addLanguage(opts.code);
104
+ if (opts.json)
105
+ return (0, output_1.printJson)(data);
106
+ process.stdout.write(`Language ${data.languageCode} added. ${data.message}\n`);
107
+ }
108
+ catch (e) {
109
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
110
+ }
111
+ });
112
+ }
@@ -0,0 +1,3 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ import type { Command } from 'commander';
3
+ export declare function registerPublish(program: Command, client: AxiosInstance): void;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerPublish = registerPublish;
4
+ const publish_1 = require("../api/publish");
5
+ const errors_1 = require("../errors");
6
+ const output_1 = require("../output");
7
+ function registerPublish(program, client) {
8
+ const publish = program.command('publish').description('Publish your project');
9
+ const api = (0, publish_1.publishApi)(client);
10
+ publish
11
+ .command('now')
12
+ .description('Publish the project (synchronous)')
13
+ .option('--json', 'Output as JSON')
14
+ .option('--callback-url <url>', 'Webhook URL to call when the job completes')
15
+ .option('--callback-secret <secret>', 'Secret to include in the webhook callback')
16
+ .action(async (opts) => {
17
+ try {
18
+ const data = await api.now(opts.callbackUrl, opts.callbackSecret);
19
+ if (opts.json)
20
+ return (0, output_1.printJson)(data);
21
+ process.stdout.write(`Publish job started. Job ID: ${data.jobId}\nPoll status: hinto generate status ${data.jobId}\n`);
22
+ }
23
+ catch (e) {
24
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
25
+ }
26
+ });
27
+ publish
28
+ .command('republish')
29
+ .description('Republish the project after content changes')
30
+ .option('--json', 'Output as JSON')
31
+ .option('--callback-url <url>', 'Webhook URL to call when the job completes')
32
+ .option('--callback-secret <secret>', 'Secret to include in the webhook callback')
33
+ .action(async (opts) => {
34
+ try {
35
+ const data = await api.republish(opts.callbackUrl, opts.callbackSecret);
36
+ if (opts.json)
37
+ return (0, output_1.printJson)(data);
38
+ process.stdout.write(`Republish job started. Job ID: ${data.jobId}\nPoll status: hinto generate status ${data.jobId}\n`);
39
+ }
40
+ catch (e) {
41
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
42
+ }
43
+ });
44
+ publish
45
+ .command('status')
46
+ .description('Show whether the project is currently published')
47
+ .option('--json', 'Output as JSON')
48
+ .action(async (opts) => {
49
+ try {
50
+ const data = await api.status();
51
+ if (opts.json)
52
+ return (0, output_1.printJson)(data);
53
+ (0, output_1.printKeyValue)(data);
54
+ }
55
+ catch (e) {
56
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
57
+ }
58
+ });
59
+ publish
60
+ .command('unpublish')
61
+ .description('Unpublish the project')
62
+ .option('--json', 'Output as JSON')
63
+ .action(async (opts) => {
64
+ try {
65
+ const data = await api.unpublish();
66
+ if (opts.json)
67
+ return (0, output_1.printJson)(data);
68
+ process.stdout.write(`${data.message}\n`);
69
+ }
70
+ catch (e) {
71
+ (0, errors_1.exitWithError)(e instanceof Error ? e.message : String(e));
72
+ }
73
+ });
74
+ }
@@ -0,0 +1,3 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ import type { Command } from 'commander';
3
+ export declare function registerTemplates(program: Command, client: AxiosInstance): void;