agent-media-cli 1.0.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 (139) hide show
  1. package/LICENSE +199 -0
  2. package/README.md +59 -0
  3. package/dist/commands/alias.d.ts +3 -0
  4. package/dist/commands/alias.d.ts.map +1 -0
  5. package/dist/commands/alias.js +245 -0
  6. package/dist/commands/alias.js.map +1 -0
  7. package/dist/commands/apikey.d.ts +3 -0
  8. package/dist/commands/apikey.d.ts.map +1 -0
  9. package/dist/commands/apikey.js +282 -0
  10. package/dist/commands/apikey.js.map +1 -0
  11. package/dist/commands/cancel.d.ts +9 -0
  12. package/dist/commands/cancel.d.ts.map +1 -0
  13. package/dist/commands/cancel.js +101 -0
  14. package/dist/commands/cancel.js.map +1 -0
  15. package/dist/commands/completions.d.ts +15 -0
  16. package/dist/commands/completions.d.ts.map +1 -0
  17. package/dist/commands/completions.js +293 -0
  18. package/dist/commands/completions.js.map +1 -0
  19. package/dist/commands/config.d.ts +3 -0
  20. package/dist/commands/config.d.ts.map +1 -0
  21. package/dist/commands/config.js +327 -0
  22. package/dist/commands/config.js.map +1 -0
  23. package/dist/commands/credits.d.ts +18 -0
  24. package/dist/commands/credits.d.ts.map +1 -0
  25. package/dist/commands/credits.js +459 -0
  26. package/dist/commands/credits.js.map +1 -0
  27. package/dist/commands/debug.d.ts +20 -0
  28. package/dist/commands/debug.d.ts.map +1 -0
  29. package/dist/commands/debug.js +291 -0
  30. package/dist/commands/debug.js.map +1 -0
  31. package/dist/commands/delete.d.ts +3 -0
  32. package/dist/commands/delete.d.ts.map +1 -0
  33. package/dist/commands/delete.js +273 -0
  34. package/dist/commands/delete.js.map +1 -0
  35. package/dist/commands/doctor.d.ts +14 -0
  36. package/dist/commands/doctor.d.ts.map +1 -0
  37. package/dist/commands/doctor.js +468 -0
  38. package/dist/commands/doctor.js.map +1 -0
  39. package/dist/commands/download.d.ts +3 -0
  40. package/dist/commands/download.d.ts.map +1 -0
  41. package/dist/commands/download.js +165 -0
  42. package/dist/commands/download.js.map +1 -0
  43. package/dist/commands/generate.d.ts +3 -0
  44. package/dist/commands/generate.d.ts.map +1 -0
  45. package/dist/commands/generate.js +358 -0
  46. package/dist/commands/generate.js.map +1 -0
  47. package/dist/commands/inspect.d.ts +10 -0
  48. package/dist/commands/inspect.d.ts.map +1 -0
  49. package/dist/commands/inspect.js +376 -0
  50. package/dist/commands/inspect.js.map +1 -0
  51. package/dist/commands/list.d.ts +13 -0
  52. package/dist/commands/list.d.ts.map +1 -0
  53. package/dist/commands/list.js +198 -0
  54. package/dist/commands/list.js.map +1 -0
  55. package/dist/commands/login.d.ts +15 -0
  56. package/dist/commands/login.d.ts.map +1 -0
  57. package/dist/commands/login.js +123 -0
  58. package/dist/commands/login.js.map +1 -0
  59. package/dist/commands/logout.d.ts +12 -0
  60. package/dist/commands/logout.d.ts.map +1 -0
  61. package/dist/commands/logout.js +85 -0
  62. package/dist/commands/logout.js.map +1 -0
  63. package/dist/commands/models.d.ts +10 -0
  64. package/dist/commands/models.d.ts.map +1 -0
  65. package/dist/commands/models.js +137 -0
  66. package/dist/commands/models.js.map +1 -0
  67. package/dist/commands/plan.d.ts +13 -0
  68. package/dist/commands/plan.d.ts.map +1 -0
  69. package/dist/commands/plan.js +134 -0
  70. package/dist/commands/plan.js.map +1 -0
  71. package/dist/commands/pricing.d.ts +14 -0
  72. package/dist/commands/pricing.d.ts.map +1 -0
  73. package/dist/commands/pricing.js +166 -0
  74. package/dist/commands/pricing.js.map +1 -0
  75. package/dist/commands/profile.d.ts +9 -0
  76. package/dist/commands/profile.d.ts.map +1 -0
  77. package/dist/commands/profile.js +236 -0
  78. package/dist/commands/profile.js.map +1 -0
  79. package/dist/commands/retry.d.ts +3 -0
  80. package/dist/commands/retry.d.ts.map +1 -0
  81. package/dist/commands/retry.js +424 -0
  82. package/dist/commands/retry.js.map +1 -0
  83. package/dist/commands/status.d.ts +9 -0
  84. package/dist/commands/status.d.ts.map +1 -0
  85. package/dist/commands/status.js +182 -0
  86. package/dist/commands/status.js.map +1 -0
  87. package/dist/commands/subscribe.d.ts +3 -0
  88. package/dist/commands/subscribe.d.ts.map +1 -0
  89. package/dist/commands/subscribe.js +263 -0
  90. package/dist/commands/subscribe.js.map +1 -0
  91. package/dist/commands/text.d.ts +3 -0
  92. package/dist/commands/text.d.ts.map +1 -0
  93. package/dist/commands/text.js +263 -0
  94. package/dist/commands/text.js.map +1 -0
  95. package/dist/commands/update.d.ts +13 -0
  96. package/dist/commands/update.d.ts.map +1 -0
  97. package/dist/commands/update.js +211 -0
  98. package/dist/commands/update.js.map +1 -0
  99. package/dist/commands/usage.d.ts +13 -0
  100. package/dist/commands/usage.d.ts.map +1 -0
  101. package/dist/commands/usage.js +344 -0
  102. package/dist/commands/usage.js.map +1 -0
  103. package/dist/commands/version.d.ts +8 -0
  104. package/dist/commands/version.d.ts.map +1 -0
  105. package/dist/commands/version.js +26 -0
  106. package/dist/commands/version.js.map +1 -0
  107. package/dist/commands/whoami.d.ts +9 -0
  108. package/dist/commands/whoami.d.ts.map +1 -0
  109. package/dist/commands/whoami.js +76 -0
  110. package/dist/commands/whoami.js.map +1 -0
  111. package/dist/index.d.ts +3 -0
  112. package/dist/index.d.ts.map +1 -0
  113. package/dist/index.js +85 -0
  114. package/dist/index.js.map +1 -0
  115. package/dist/lib/api.d.ts +518 -0
  116. package/dist/lib/api.d.ts.map +1 -0
  117. package/dist/lib/api.js +582 -0
  118. package/dist/lib/api.js.map +1 -0
  119. package/dist/lib/config.d.ts +33 -0
  120. package/dist/lib/config.d.ts.map +1 -0
  121. package/dist/lib/config.js +91 -0
  122. package/dist/lib/config.js.map +1 -0
  123. package/dist/lib/credentials.d.ts +60 -0
  124. package/dist/lib/credentials.d.ts.map +1 -0
  125. package/dist/lib/credentials.js +152 -0
  126. package/dist/lib/credentials.js.map +1 -0
  127. package/dist/lib/errors.d.ts +20 -0
  128. package/dist/lib/errors.d.ts.map +1 -0
  129. package/dist/lib/errors.js +77 -0
  130. package/dist/lib/errors.js.map +1 -0
  131. package/dist/lib/output.d.ts +33 -0
  132. package/dist/lib/output.d.ts.map +1 -0
  133. package/dist/lib/output.js +77 -0
  134. package/dist/lib/output.js.map +1 -0
  135. package/dist/types.d.ts +12 -0
  136. package/dist/types.d.ts.map +1 -0
  137. package/dist/types.js +3 -0
  138. package/dist/types.js.map +1 -0
  139. package/package.json +48 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscribe.d.ts","sourceRoot":"","sources":["../../src/commands/subscribe.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsDzC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuP/D"}
@@ -0,0 +1,263 @@
1
+ // Copyright 2026 agent-media contributors. Apache-2.0 license.
2
+ /**
3
+ * `agent-media subscribe` command.
4
+ *
5
+ * Interactive command for purchasing subscription plans and credit packs.
6
+ * Opens Stripe Checkout in the user's browser.
7
+ *
8
+ * Usage:
9
+ * agent-media subscribe # Interactive menu
10
+ * agent-media subscribe --plan starter
11
+ * agent-media subscribe --credits 500
12
+ * agent-media subscribe --manage # Opens Stripe Customer Portal
13
+ */
14
+ import { createInterface } from 'node:readline';
15
+ import chalk from 'chalk';
16
+ import { detectOutputMode, printJson, printQuiet, createSpinner, } from '../lib/output.js';
17
+ import { getApiKey, resolveProfileName } from '../lib/credentials.js';
18
+ import { AgentMediaAPI } from '../lib/api.js';
19
+ import { CLIError, handleError } from '../lib/errors.js';
20
+ /** Available subscription plans. */
21
+ const PLANS = [
22
+ { tier: 'starter', name: 'Starter', price: '$49/mo', credits: '2,000 credits/mo' },
23
+ { tier: 'creator', name: 'Creator', price: '$69/mo', credits: '5,000 credits/mo' },
24
+ { tier: 'pro_plus', name: 'Pro+', price: '$119/mo', credits: '15,000 credits/mo' },
25
+ ];
26
+ /** Available PAYG credit packs. */
27
+ const CREDIT_PACKS = [
28
+ { packId: 'pack_500', credits: 500, price: '$5.00' },
29
+ { packId: 'pack_2000', credits: 2000, price: '$18.00' },
30
+ { packId: 'pack_5000', credits: 5000, price: '$40.00' },
31
+ ];
32
+ /**
33
+ * Ask a question on stdin and return the trimmed answer.
34
+ */
35
+ function ask(question) {
36
+ return new Promise((resolve) => {
37
+ const rl = createInterface({
38
+ input: process.stdin,
39
+ output: process.stdout,
40
+ });
41
+ rl.question(question, (answer) => {
42
+ rl.close();
43
+ resolve(answer.trim());
44
+ });
45
+ });
46
+ }
47
+ /**
48
+ * Open a URL in the user's default browser.
49
+ */
50
+ async function openInBrowser(url) {
51
+ try {
52
+ const open = (await import('open')).default;
53
+ await open(url);
54
+ }
55
+ catch {
56
+ // Silently fail if browser can't be opened
57
+ }
58
+ }
59
+ export function registerSubscribeCommand(program) {
60
+ program
61
+ .command('subscribe')
62
+ .description('Subscribe to a plan or buy credits')
63
+ .option('--plan <tier>', 'Subscribe to a plan (starter, creator, pro_plus)')
64
+ .option('--credits <amount>', 'Buy a credit pack (500, 2000, 5000)')
65
+ .option('--manage', 'Open Stripe Customer Portal to manage subscription')
66
+ .action(async (cmdOpts) => {
67
+ const globalOpts = program.opts();
68
+ const mode = detectOutputMode(globalOpts);
69
+ const profileName = resolveProfileName(globalOpts.profile);
70
+ const apiKey = getApiKey(profileName);
71
+ if (!apiKey) {
72
+ throw new CLIError('Not logged in.', {
73
+ code: 'NOT_AUTHENTICATED',
74
+ suggestion: "Run 'agent-media login' to authenticate.",
75
+ });
76
+ }
77
+ try {
78
+ const api = new AgentMediaAPI(apiKey);
79
+ // ── --manage: Open Stripe Portal ──────────────────────────────
80
+ if (cmdOpts.manage) {
81
+ const spinner = createSpinner('Opening billing portal...');
82
+ if (mode === 'human')
83
+ spinner.start();
84
+ const { portal_url } = await api.createPortalSession();
85
+ if (mode === 'human') {
86
+ spinner.succeed('Billing portal opened');
87
+ console.log();
88
+ console.log(` ${chalk.cyan.underline(portal_url)}`);
89
+ console.log();
90
+ }
91
+ if (mode === 'json') {
92
+ printJson({ portal_url });
93
+ }
94
+ else if (mode === 'quiet') {
95
+ printQuiet(portal_url);
96
+ }
97
+ await openInBrowser(portal_url);
98
+ return;
99
+ }
100
+ // ── --plan: Direct plan subscription ──────────────────────────
101
+ if (cmdOpts.plan) {
102
+ const tier = cmdOpts.plan.toLowerCase();
103
+ const plan = PLANS.find((p) => p.tier === tier);
104
+ if (!plan) {
105
+ throw new CLIError(`Unknown plan: ${cmdOpts.plan}`, {
106
+ code: 'INVALID_ARGUMENT',
107
+ suggestion: `Valid plans: ${PLANS.map((p) => p.tier).join(', ')}`,
108
+ });
109
+ }
110
+ const spinner = createSpinner(`Creating checkout for ${plan.name}...`);
111
+ if (mode === 'human')
112
+ spinner.start();
113
+ const { checkout_url } = await api.createPlanCheckout(tier);
114
+ if (mode === 'human') {
115
+ spinner.succeed(`Checkout ready for ${plan.name}`);
116
+ console.log();
117
+ console.log(chalk.bold(' Complete payment in your browser:'));
118
+ console.log(` ${chalk.cyan.underline(checkout_url)}`);
119
+ console.log();
120
+ }
121
+ if (mode === 'json') {
122
+ printJson({ checkout_url, plan: tier });
123
+ }
124
+ else if (mode === 'quiet') {
125
+ printQuiet(checkout_url);
126
+ }
127
+ await openInBrowser(checkout_url);
128
+ return;
129
+ }
130
+ // ── --credits: Direct credit pack purchase ────────────────────
131
+ if (cmdOpts.credits) {
132
+ const amount = parseInt(cmdOpts.credits, 10);
133
+ const pack = CREDIT_PACKS.find((p) => p.credits === amount);
134
+ if (!pack) {
135
+ throw new CLIError(`Unknown credit amount: ${cmdOpts.credits}`, {
136
+ code: 'INVALID_ARGUMENT',
137
+ suggestion: `Valid amounts: ${CREDIT_PACKS.map((p) => p.credits).join(', ')}`,
138
+ });
139
+ }
140
+ const spinner = createSpinner(`Creating checkout for ${pack.credits} credits...`);
141
+ if (mode === 'human')
142
+ spinner.start();
143
+ const { checkout_url } = await api.createPaygCheckout(pack.packId);
144
+ if (mode === 'human') {
145
+ spinner.succeed(`Checkout ready for ${pack.credits} credits`);
146
+ console.log();
147
+ console.log(chalk.bold(' Complete payment in your browser:'));
148
+ console.log(` ${chalk.cyan.underline(checkout_url)}`);
149
+ console.log();
150
+ }
151
+ if (mode === 'json') {
152
+ printJson({ checkout_url, credits: pack.credits });
153
+ }
154
+ else if (mode === 'quiet') {
155
+ printQuiet(checkout_url);
156
+ }
157
+ await openInBrowser(checkout_url);
158
+ return;
159
+ }
160
+ // ── Interactive mode ──────────────────────────────────────────
161
+ if (mode !== 'human') {
162
+ throw new CLIError('Interactive mode requires a terminal.', {
163
+ code: 'NOT_INTERACTIVE',
164
+ suggestion: 'Use --plan, --credits, or --manage flags.',
165
+ });
166
+ }
167
+ // Show current plan
168
+ const whoamiSpinner = createSpinner('Fetching account info...');
169
+ whoamiSpinner.start();
170
+ const info = await api.whoami();
171
+ whoamiSpinner.stop();
172
+ console.log();
173
+ console.log(chalk.bold(' Current Plan'));
174
+ console.log(` ${info.plan.name} (${info.credits.total} credits available)`);
175
+ console.log();
176
+ // Show menu
177
+ console.log(chalk.bold(' What would you like to do?'));
178
+ console.log();
179
+ console.log(' 1) Subscribe to a plan');
180
+ console.log(' 2) Buy credits');
181
+ console.log(' 3) Manage subscription (Stripe portal)');
182
+ console.log(' 4) Cancel');
183
+ console.log();
184
+ const choice = await ask(' Choose [1-4]: ');
185
+ if (choice === '4' || choice === '') {
186
+ console.log(chalk.dim(' Cancelled.'));
187
+ return;
188
+ }
189
+ if (choice === '3') {
190
+ const spinner = createSpinner('Opening billing portal...');
191
+ spinner.start();
192
+ const { portal_url } = await api.createPortalSession();
193
+ spinner.succeed('Billing portal opened');
194
+ console.log();
195
+ console.log(` ${chalk.cyan.underline(portal_url)}`);
196
+ console.log();
197
+ await openInBrowser(portal_url);
198
+ return;
199
+ }
200
+ if (choice === '1') {
201
+ // Plan selection
202
+ console.log();
203
+ console.log(chalk.bold(' Available Plans'));
204
+ console.log();
205
+ for (let i = 0; i < PLANS.length; i++) {
206
+ const p = PLANS[i];
207
+ console.log(` ${i + 1}) ${chalk.cyan(p.name.padEnd(12))} ${p.price.padEnd(10)} ${chalk.dim(p.credits)}`);
208
+ }
209
+ console.log();
210
+ const planChoice = await ask(' Choose plan [1-3]: ');
211
+ const planIdx = parseInt(planChoice, 10) - 1;
212
+ const selectedPlan = PLANS[planIdx];
213
+ if (!selectedPlan) {
214
+ console.log(chalk.dim(' Cancelled.'));
215
+ return;
216
+ }
217
+ const spinner = createSpinner(`Creating checkout for ${selectedPlan.name}...`);
218
+ spinner.start();
219
+ const { checkout_url } = await api.createPlanCheckout(selectedPlan.tier);
220
+ spinner.succeed(`Checkout ready for ${selectedPlan.name}`);
221
+ console.log();
222
+ console.log(chalk.bold(' Complete payment in your browser:'));
223
+ console.log(` ${chalk.cyan.underline(checkout_url)}`);
224
+ console.log();
225
+ await openInBrowser(checkout_url);
226
+ return;
227
+ }
228
+ if (choice === '2') {
229
+ // Credit pack selection
230
+ console.log();
231
+ console.log(chalk.bold(' Credit Packs'));
232
+ console.log();
233
+ for (let i = 0; i < CREDIT_PACKS.length; i++) {
234
+ const p = CREDIT_PACKS[i];
235
+ console.log(` ${i + 1}) ${chalk.yellow(String(p.credits).padEnd(8))} credits ${p.price}`);
236
+ }
237
+ console.log();
238
+ const packChoice = await ask(' Choose pack [1-3]: ');
239
+ const packIdx = parseInt(packChoice, 10) - 1;
240
+ const selectedPack = CREDIT_PACKS[packIdx];
241
+ if (!selectedPack) {
242
+ console.log(chalk.dim(' Cancelled.'));
243
+ return;
244
+ }
245
+ const spinner = createSpinner(`Creating checkout for ${selectedPack.credits} credits...`);
246
+ spinner.start();
247
+ const { checkout_url } = await api.createPaygCheckout(selectedPack.packId);
248
+ spinner.succeed(`Checkout ready for ${selectedPack.credits} credits`);
249
+ console.log();
250
+ console.log(chalk.bold(' Complete payment in your browser:'));
251
+ console.log(` ${chalk.cyan.underline(checkout_url)}`);
252
+ console.log();
253
+ await openInBrowser(checkout_url);
254
+ return;
255
+ }
256
+ console.log(chalk.dim(' Invalid choice.'));
257
+ }
258
+ catch (error) {
259
+ handleError(error);
260
+ }
261
+ });
262
+ }
263
+ //# sourceMappingURL=subscribe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscribe.js","sourceRoot":"","sources":["../../src/commands/subscribe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerTextCommand(program: Command): void;
3
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/commands/text.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqJzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA8J1D"}
@@ -0,0 +1,263 @@
1
+ // Copyright 2026 agent-media contributors. Apache-2.0 license.
2
+ /**
3
+ * `agent-media text` command.
4
+ *
5
+ * Overlays text onto a local media file (video or image) using ffmpeg.
6
+ * This is a LOCAL-ONLY command — it does NOT call the API, does NOT
7
+ * require authentication, and does NOT cost credits. All processing
8
+ * is performed on the local machine via ffmpeg.
9
+ *
10
+ * Supported input formats: .mp4, .webm, .mov, .jpg, .jpeg, .png, .webp
11
+ *
12
+ * Flow:
13
+ * 1. Validate input file exists and has a supported extension.
14
+ * 2. Check that ffmpeg is available on the system PATH.
15
+ * 3. Build an ffmpeg drawtext filter command based on options.
16
+ * 4. Execute ffmpeg with a progress spinner.
17
+ * 5. Report the output file path and size.
18
+ */
19
+ import { existsSync, statSync } from 'node:fs';
20
+ import { basename, dirname, extname, join, resolve } from 'node:path';
21
+ import { execFile } from 'node:child_process';
22
+ import { promisify } from 'node:util';
23
+ import chalk from 'chalk';
24
+ import { detectOutputMode, printJson, printQuiet, createSpinner, } from '../lib/output.js';
25
+ import { CLIError, handleError } from '../lib/errors.js';
26
+ const execFileAsync = promisify(execFile);
27
+ /** Supported media file extensions. */
28
+ const SUPPORTED_VIDEO_EXTS = new Set(['.mp4', '.webm', '.mov']);
29
+ const SUPPORTED_IMAGE_EXTS = new Set(['.jpg', '.jpeg', '.png', '.webp']);
30
+ const SUPPORTED_EXTS = new Set([...SUPPORTED_VIDEO_EXTS, ...SUPPORTED_IMAGE_EXTS]);
31
+ /** Text position presets mapping to ffmpeg y-coordinate expressions. */
32
+ const POSITION_Y_EXPR = {
33
+ top: 'th+__PADDING__',
34
+ center: '(h-th)/2',
35
+ bottom: 'h-th-__PADDING__',
36
+ };
37
+ /**
38
+ * Check whether ffmpeg is available on the system PATH.
39
+ *
40
+ * Runs `ffmpeg -version` and returns `true` if it exits successfully.
41
+ */
42
+ async function isFfmpegAvailable() {
43
+ try {
44
+ await execFileAsync('ffmpeg', ['-version']);
45
+ return true;
46
+ }
47
+ catch {
48
+ return false;
49
+ }
50
+ }
51
+ /**
52
+ * Determine whether the input file is a video or an image based on extension.
53
+ */
54
+ function isVideoFile(ext) {
55
+ return SUPPORTED_VIDEO_EXTS.has(ext.toLowerCase());
56
+ }
57
+ /**
58
+ * Build the default output file path by inserting `_text` before the extension.
59
+ *
60
+ * Example: `/path/to/video.mp4` -> `/path/to/video_text.mp4`
61
+ */
62
+ function buildDefaultOutputPath(inputPath) {
63
+ const dir = dirname(inputPath);
64
+ const ext = extname(inputPath);
65
+ const base = basename(inputPath, ext);
66
+ return join(dir, `${base}_text${ext}`);
67
+ }
68
+ /**
69
+ * Parse a hex color string to an ffmpeg-compatible color value.
70
+ *
71
+ * Accepts `#RRGGBB` or `#RRGGBBAA` formats. Returns an ffmpeg color
72
+ * string like `0xRRGGBBAA` or `0xRRGGBB`.
73
+ */
74
+ function hexToFfmpegColor(hex) {
75
+ const cleaned = hex.replace(/^#/, '');
76
+ return `0x${cleaned}`;
77
+ }
78
+ /**
79
+ * Parse a hex color with alpha to separate color and opacity for boxcolor.
80
+ *
81
+ * Accepts `#RRGGBB` or `#RRGGBBAA`. Returns `color@opacity` for ffmpeg.
82
+ */
83
+ function hexToFfmpegBoxColor(hex) {
84
+ const cleaned = hex.replace(/^#/, '');
85
+ if (cleaned.length === 8) {
86
+ const rgb = cleaned.slice(0, 6);
87
+ const alpha = parseInt(cleaned.slice(6, 8), 16) / 255;
88
+ return `0x${rgb}@${alpha.toFixed(2)}`;
89
+ }
90
+ return `0x${cleaned}`;
91
+ }
92
+ /**
93
+ * Escape special characters in text for ffmpeg drawtext filter.
94
+ *
95
+ * ffmpeg drawtext requires escaping colons, backslashes, and single quotes.
96
+ */
97
+ function escapeDrawtext(text) {
98
+ return text
99
+ .replace(/\\/g, '\\\\\\\\')
100
+ .replace(/'/g, "'\\\\\\'")
101
+ .replace(/:/g, '\\\\:')
102
+ .replace(/%/g, '%%');
103
+ }
104
+ /**
105
+ * Format bytes to a human-readable string (e.g., "15.2 MB").
106
+ */
107
+ function formatBytes(bytes) {
108
+ if (bytes < 1024)
109
+ return `${bytes} B`;
110
+ if (bytes < 1024 * 1024)
111
+ return `${(bytes / 1024).toFixed(1)} KB`;
112
+ if (bytes < 1024 * 1024 * 1024)
113
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
114
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
115
+ }
116
+ /**
117
+ * Build the ffmpeg drawtext filter string.
118
+ */
119
+ function buildDrawtextFilter(opts) {
120
+ const escapedText = escapeDrawtext(opts.text);
121
+ const color = hexToFfmpegColor(opts.fontColor);
122
+ const boxColor = hexToFfmpegBoxColor(opts.bgColor);
123
+ const yExpr = (POSITION_Y_EXPR[opts.position] ?? POSITION_Y_EXPR['bottom'])
124
+ .replace(/__PADDING__/g, String(opts.padding));
125
+ const parts = [
126
+ `text='${escapedText}'`,
127
+ `fontsize=${opts.fontSize}`,
128
+ `fontcolor=${color}`,
129
+ `x=(w-text_w)/2`,
130
+ `y=${yExpr}`,
131
+ `box=1`,
132
+ `boxcolor=${boxColor}`,
133
+ `boxborderw=${opts.padding}`,
134
+ ];
135
+ return `drawtext=${parts.join(':')}`;
136
+ }
137
+ export function registerTextCommand(program) {
138
+ program
139
+ .command('text')
140
+ .description('Overlay text on a local media file using ffmpeg (no API, no auth, no cost)')
141
+ .requiredOption('-m, --media <file>', 'Input media file path')
142
+ .requiredOption('-t, --text <text>', 'Text to overlay')
143
+ .option('--position <pos>', 'Text position: top, center, bottom', 'bottom')
144
+ .option('--font-size <n>', 'Font size in pixels (default: 48 for video, 36 for images)')
145
+ .option('--color <hex>', 'Text color as hex (e.g., #FFFFFF)', '#FFFFFF')
146
+ .option('--bg-color <hex>', 'Background color for text box (e.g., #000000AA)', '#000000AA')
147
+ .option('--padding <n>', 'Padding around text in pixels', '20')
148
+ .option('-o, --output <file>', 'Output file path (default: input with _text suffix)')
149
+ .action(async (cmdOpts) => {
150
+ const globalOpts = program.opts();
151
+ const mode = detectOutputMode(globalOpts);
152
+ try {
153
+ const startTime = Date.now();
154
+ // ── Step 1: Validate input file ───────────────────────────────
155
+ const inputPath = resolve(cmdOpts.media);
156
+ if (!existsSync(inputPath)) {
157
+ throw new CLIError(`Input file not found: ${inputPath}`, {
158
+ code: 'FILE_NOT_FOUND',
159
+ suggestion: 'Check the file path and try again.',
160
+ });
161
+ }
162
+ const ext = extname(inputPath).toLowerCase();
163
+ if (!SUPPORTED_EXTS.has(ext)) {
164
+ throw new CLIError(`Unsupported file format: ${ext}`, {
165
+ code: 'UNSUPPORTED_FORMAT',
166
+ suggestion: `Supported formats: ${[...SUPPORTED_EXTS].join(', ')}`,
167
+ });
168
+ }
169
+ // ── Step 2: Check ffmpeg availability ─────────────────────────
170
+ const ffmpegOk = await isFfmpegAvailable();
171
+ if (!ffmpegOk) {
172
+ throw new CLIError('ffmpeg is not installed.', {
173
+ code: 'FFMPEG_NOT_FOUND',
174
+ suggestion: 'Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)',
175
+ });
176
+ }
177
+ // ── Step 3: Resolve options ───────────────────────────────────
178
+ const isVideo = isVideoFile(ext);
179
+ const defaultFontSize = isVideo ? 48 : 36;
180
+ const fontSize = cmdOpts.fontSize
181
+ ? parseInt(cmdOpts.fontSize, 10)
182
+ : defaultFontSize;
183
+ const padding = parseInt(cmdOpts.padding, 10);
184
+ const position = cmdOpts.position.toLowerCase();
185
+ if (!POSITION_Y_EXPR[position]) {
186
+ throw new CLIError(`Invalid position: "${cmdOpts.position}"`, {
187
+ code: 'INVALID_OPTION',
188
+ suggestion: 'Valid positions: top, center, bottom',
189
+ });
190
+ }
191
+ const outputPath = cmdOpts.output
192
+ ? resolve(cmdOpts.output)
193
+ : buildDefaultOutputPath(inputPath);
194
+ // ── Step 4: Build and execute ffmpeg command ──────────────────
195
+ const filter = buildDrawtextFilter({
196
+ text: cmdOpts.text,
197
+ fontSize,
198
+ fontColor: cmdOpts.color,
199
+ bgColor: cmdOpts.bgColor,
200
+ padding,
201
+ position,
202
+ });
203
+ const ffmpegArgs = [
204
+ '-i', inputPath,
205
+ '-vf', filter,
206
+ ];
207
+ if (isVideo) {
208
+ // Copy audio stream without re-encoding
209
+ ffmpegArgs.push('-codec:a', 'copy');
210
+ }
211
+ // Overwrite output file without prompting
212
+ ffmpegArgs.push('-y', outputPath);
213
+ const spinner = createSpinner(`Overlaying text on ${basename(inputPath)}...`);
214
+ if (mode === 'human')
215
+ spinner.start();
216
+ try {
217
+ await execFileAsync('ffmpeg', ffmpegArgs);
218
+ }
219
+ catch (error) {
220
+ if (mode === 'human')
221
+ spinner.fail('ffmpeg failed');
222
+ const message = error instanceof Error ? error.message : 'Unknown ffmpeg error';
223
+ throw new CLIError(`ffmpeg processing failed: ${message}`, {
224
+ code: 'FFMPEG_ERROR',
225
+ suggestion: 'Verify the input file is valid and ffmpeg supports the format.',
226
+ });
227
+ }
228
+ // ── Step 5: Report results ────────────────────────────────────
229
+ if (!existsSync(outputPath)) {
230
+ if (mode === 'human')
231
+ spinner.fail('Output file was not created');
232
+ throw new CLIError('ffmpeg completed but output file was not created.', {
233
+ code: 'OUTPUT_MISSING',
234
+ suggestion: 'Check ffmpeg output for warnings or errors.',
235
+ });
236
+ }
237
+ const outputStat = statSync(outputPath);
238
+ const durationMs = Date.now() - startTime;
239
+ switch (mode) {
240
+ case 'json':
241
+ printJson({
242
+ input: inputPath,
243
+ output: outputPath,
244
+ text: cmdOpts.text,
245
+ position,
246
+ fileSize: outputStat.size,
247
+ duration_ms: durationMs,
248
+ });
249
+ break;
250
+ case 'quiet':
251
+ printQuiet(outputPath);
252
+ break;
253
+ default:
254
+ spinner.succeed(`Created: ${chalk.cyan(outputPath)} (${formatBytes(outputStat.size)})`);
255
+ break;
256
+ }
257
+ }
258
+ catch (error) {
259
+ handleError(error);
260
+ }
261
+ });
262
+ }
263
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/commands/text.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * `agent-media update` command.
3
+ *
4
+ * Checks the npm registry for the latest published version of the
5
+ * agent-media package, compares it against the locally installed version,
6
+ * and optionally offers to install the update.
7
+ *
8
+ * Flags:
9
+ * --check Check-only mode (do not prompt or install).
10
+ */
11
+ import type { Command } from 'commander';
12
+ export declare function registerUpdateCommand(program: Command): void;
13
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+HzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2H5D"}