@lovelybunch/cli 1.0.75-alpha.8 → 1.0.75

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.
@@ -0,0 +1,274 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { table } from 'table';
5
+ import inquirer from 'inquirer';
6
+ import { listMail, getMail, setMailStatus, replyToMail, addMailAction, } from '@lovelybunch/core';
7
+ // ============================================================================
8
+ // Helpers
9
+ // ============================================================================
10
+ const VALID_FOLDERS = ['inbox', 'read', 'sent'];
11
+ function validateFolder(folder) {
12
+ const normalized = folder.toLowerCase();
13
+ if (!VALID_FOLDERS.includes(normalized)) {
14
+ throw new Error(`Invalid folder "${folder}". Must be one of: ${VALID_FOLDERS.join(', ')}`);
15
+ }
16
+ return normalized;
17
+ }
18
+ function truncate(str, maxLen) {
19
+ if (str.length <= maxLen)
20
+ return str;
21
+ return str.slice(0, maxLen - 1) + '…';
22
+ }
23
+ function formatDate(dateStr) {
24
+ if (!dateStr)
25
+ return '-';
26
+ try {
27
+ const date = new Date(dateStr);
28
+ return date.toLocaleDateString('en-US', {
29
+ month: 'short',
30
+ day: 'numeric',
31
+ hour: '2-digit',
32
+ minute: '2-digit',
33
+ });
34
+ }
35
+ catch {
36
+ return dateStr;
37
+ }
38
+ }
39
+ // ============================================================================
40
+ // Parent Command
41
+ // ============================================================================
42
+ export const mailCommand = new Command('mail')
43
+ .description('Manage emails')
44
+ .addHelpText('after', `
45
+ Examples:
46
+ ${chalk.gray('# List emails in inbox (default)')}
47
+ nut mail list
48
+ nut mail list read
49
+ nut mail list sent
50
+
51
+ ${chalk.gray('# View a specific email')}
52
+ nut mail get <id>
53
+
54
+ ${chalk.gray('# Mark email as read or unread')}
55
+ nut mail set <id> --status read
56
+ nut mail set <id> --status unread
57
+
58
+ ${chalk.gray('# Add an agent action summary to an email')}
59
+ nut mail action <id> "Summary of actions taken"
60
+
61
+ ${chalk.gray('# Reply to an email')}
62
+ nut mail reply <id>
63
+
64
+ ${chalk.gray('# Send an email (coming soon)')}
65
+ nut mail send
66
+ `);
67
+ // ============================================================================
68
+ // mail list [folder]
69
+ // ============================================================================
70
+ mailCommand
71
+ .command('list')
72
+ .description('List emails in a folder (default: inbox)')
73
+ .argument('[folder]', 'Folder to list (inbox, read, sent)', 'inbox')
74
+ .option('--json', 'Output as JSON')
75
+ .action(async (folder, options) => {
76
+ const spinner = ora('Loading emails...').start();
77
+ try {
78
+ const validFolder = validateFolder(folder);
79
+ const messages = await listMail(validFolder);
80
+ spinner.stop();
81
+ if (options.json) {
82
+ console.log(JSON.stringify(messages, null, 2));
83
+ return;
84
+ }
85
+ if (messages.length === 0) {
86
+ console.log(chalk.gray(`No emails in ${validFolder}.`));
87
+ return;
88
+ }
89
+ console.log(chalk.bold(`\n📧 ${validFolder.charAt(0).toUpperCase() + validFolder.slice(1)} (${messages.length})\n`));
90
+ const tableData = [
91
+ [
92
+ chalk.bold('ID'),
93
+ chalk.bold('From'),
94
+ chalk.bold('Subject'),
95
+ chalk.bold('Date'),
96
+ ],
97
+ ...messages.map((msg) => [
98
+ chalk.cyan(truncate(msg.id, 20)),
99
+ truncate(msg.from, 30),
100
+ truncate(msg.subject, 40),
101
+ chalk.gray(formatDate(msg.receivedAt)),
102
+ ]),
103
+ ];
104
+ console.log(table(tableData, {
105
+ border: {
106
+ topBody: '',
107
+ topJoin: '',
108
+ topLeft: '',
109
+ topRight: '',
110
+ bottomBody: '',
111
+ bottomJoin: '',
112
+ bottomLeft: '',
113
+ bottomRight: '',
114
+ bodyLeft: '',
115
+ bodyRight: '',
116
+ bodyJoin: ' ',
117
+ joinBody: '',
118
+ joinLeft: '',
119
+ joinRight: '',
120
+ joinJoin: '',
121
+ },
122
+ drawHorizontalLine: () => false,
123
+ }));
124
+ }
125
+ catch (error) {
126
+ spinner.fail('Failed to list emails');
127
+ console.error(chalk.red('Error:'), error.message);
128
+ process.exit(1);
129
+ }
130
+ });
131
+ // ============================================================================
132
+ // mail get <id>
133
+ // ============================================================================
134
+ mailCommand
135
+ .command('get')
136
+ .description('View a specific email')
137
+ .argument('<id>', 'Email ID')
138
+ .option('--json', 'Output as JSON')
139
+ .action(async (id, options) => {
140
+ const spinner = ora('Loading email...').start();
141
+ try {
142
+ const message = await getMail(id);
143
+ spinner.stop();
144
+ if (!message) {
145
+ console.error(chalk.red(`Email "${id}" not found.`));
146
+ process.exit(1);
147
+ }
148
+ if (options.json) {
149
+ console.log(JSON.stringify(message, null, 2));
150
+ return;
151
+ }
152
+ console.log('');
153
+ console.log(chalk.bold('Subject: ') + message.subject);
154
+ console.log(chalk.bold('From: ') + message.from);
155
+ console.log(chalk.bold('To: ') + message.to.join(', '));
156
+ if (message.cc.length > 0) {
157
+ console.log(chalk.bold('CC: ') + message.cc.join(', '));
158
+ }
159
+ console.log(chalk.bold('Date: ') + formatDate(message.receivedAt));
160
+ console.log(chalk.bold('Folder: ') + message.folder);
161
+ console.log(chalk.bold('ID: ') + chalk.gray(message.id));
162
+ if (message.attachments.length > 0) {
163
+ console.log(chalk.bold('Attach: ') + message.attachments.map(a => a.filename).join(', '));
164
+ }
165
+ console.log(chalk.gray('\n' + '─'.repeat(60) + '\n'));
166
+ console.log(message.content || chalk.gray('(no body)'));
167
+ console.log('');
168
+ }
169
+ catch (error) {
170
+ spinner.fail('Failed to load email');
171
+ console.error(chalk.red('Error:'), error.message);
172
+ process.exit(1);
173
+ }
174
+ });
175
+ // ============================================================================
176
+ // mail set <id> --status <read|unread>
177
+ // ============================================================================
178
+ mailCommand
179
+ .command('set')
180
+ .description('Set email status (read or unread)')
181
+ .argument('<id>', 'Email ID')
182
+ .requiredOption('-s, --status <status>', 'Status to set: "read" or "unread"')
183
+ .action(async (id, options) => {
184
+ const status = options.status.toLowerCase();
185
+ if (status !== 'read' && status !== 'unread') {
186
+ console.error(chalk.red('Error: --status must be "read" or "unread"'));
187
+ process.exit(1);
188
+ }
189
+ const spinner = ora(`Marking email as ${status}...`).start();
190
+ try {
191
+ const message = await setMailStatus(id, status);
192
+ spinner.succeed(chalk.green(`Email marked as ${status} (now in ${message.folder})`));
193
+ }
194
+ catch (error) {
195
+ spinner.fail(`Failed to set email status`);
196
+ console.error(chalk.red('Error:'), error.message);
197
+ process.exit(1);
198
+ }
199
+ });
200
+ // ============================================================================
201
+ // mail reply <id>
202
+ // ============================================================================
203
+ mailCommand
204
+ .command('reply')
205
+ .description('Reply to an email')
206
+ .argument('<id>', 'Email ID to reply to')
207
+ .option('-m, --message <message>', 'Reply message (skips interactive prompt)')
208
+ .action(async (id, options) => {
209
+ try {
210
+ const original = await getMail(id);
211
+ if (!original) {
212
+ console.error(chalk.red(`Email "${id}" not found.`));
213
+ process.exit(1);
214
+ }
215
+ console.log('');
216
+ console.log(chalk.gray(`Replying to: ${original.subject}`));
217
+ console.log(chalk.gray(`From: ${original.from}`));
218
+ console.log('');
219
+ let replyContent = options.message;
220
+ if (!replyContent) {
221
+ const answers = await inquirer.prompt([
222
+ {
223
+ type: 'editor',
224
+ name: 'content',
225
+ message: 'Write your reply:',
226
+ },
227
+ ]);
228
+ replyContent = answers.content;
229
+ }
230
+ if (!replyContent || replyContent.trim().length === 0) {
231
+ console.log(chalk.yellow('Reply cancelled (empty message).'));
232
+ return;
233
+ }
234
+ const spinner = ora('Sending reply...').start();
235
+ const reply = await replyToMail(id, { content: replyContent });
236
+ spinner.succeed(chalk.green(`Reply saved to sent folder (${reply.id})`));
237
+ }
238
+ catch (error) {
239
+ console.error(chalk.red('Error:'), error.message);
240
+ process.exit(1);
241
+ }
242
+ });
243
+ // ============================================================================
244
+ // mail action <id> <message>
245
+ // ============================================================================
246
+ mailCommand
247
+ .command('action')
248
+ .description('Add an agent action summary to an email')
249
+ .argument('<id>', 'Email ID')
250
+ .argument('<message>', 'Action summary message')
251
+ .action(async (id, message) => {
252
+ const spinner = ora('Adding action to email...').start();
253
+ try {
254
+ const updated = await addMailAction(id, message);
255
+ spinner.succeed(chalk.green(`Action added to email "${id}" (${updated.folder})`));
256
+ }
257
+ catch (error) {
258
+ spinner.fail('Failed to add action');
259
+ console.error(chalk.red('Error:'), error.message);
260
+ process.exit(1);
261
+ }
262
+ });
263
+ // ============================================================================
264
+ // mail send
265
+ // ============================================================================
266
+ mailCommand
267
+ .command('send')
268
+ .description('Send an email (coming soon)')
269
+ .action(async () => {
270
+ console.log(chalk.yellow('\n📧 Send email is coming soon.\n'));
271
+ console.log(chalk.gray('This feature will allow you to compose and send emails directly from the CLI.'));
272
+ console.log(chalk.gray('Stay tuned for updates!\n'));
273
+ });
274
+ //# sourceMappingURL=mail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail.js","sourceRoot":"","sources":["../../src/commands/mail.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const notifyCommand: Command;
3
+ //# sourceMappingURL=notify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../../src/commands/notify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,aAAa,SASxB,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { getSlackService } from '@lovelybunch/core';
5
+ export const notifyCommand = new Command('notify')
6
+ .description('Send notifications to external services')
7
+ .addHelpText('after', `
8
+ Examples:
9
+ ${chalk.gray('# Send a message to Slack')}
10
+ nut notify slack "Deployment to staging complete"
11
+
12
+ ${chalk.gray('# Send with a title')}
13
+ nut notify slack "All systems operational" --title "Health Check"
14
+ `);
15
+ // nut notify slack <message>
16
+ notifyCommand
17
+ .command('slack')
18
+ .description('Send a message to the configured Slack channel')
19
+ .argument('<message>', 'Message text to send')
20
+ .option('-t, --title <title>', 'Optional bold title/heading for the message')
21
+ .action(async (message, options) => {
22
+ const spinner = ora('Sending Slack message...').start();
23
+ try {
24
+ const slackService = getSlackService();
25
+ await slackService.sendFreeformMessage(message, {
26
+ title: options.title,
27
+ });
28
+ spinner.succeed(chalk.green('Message sent to Slack'));
29
+ }
30
+ catch (error) {
31
+ spinner.fail('Failed to send Slack message');
32
+ console.error(chalk.red('Error:'), error.message);
33
+ process.exit(1);
34
+ }
35
+ });
36
+ //# sourceMappingURL=notify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notify.js","sourceRoot":"","sources":["../../src/commands/notify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,yCAAyC,CAAC;KACtD,WAAW,CAAC,OAAO,EAAE;;IAEpB,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC;;;IAGvC,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC;;CAEpC,CAAC,CAAC;AAEH,6BAA6B;AAC7B,aAAa;KACV,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,gDAAgD,CAAC;KAC7D,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;KAC7C,MAAM,CAAC,qBAAqB,EAAE,6CAA6C,CAAC;KAC5E,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,OAA2B,EAAE,EAAE;IAC7D,MAAM,OAAO,GAAG,GAAG,CAAC,0BAA0B,CAAC,CAAC,KAAK,EAAE,CAAC;IAExD,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;QACvC,MAAM,YAAY,CAAC,mBAAmB,CAAC,OAAO,EAAE;YAC9C,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC,CAAC;QAEH,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QAC7C,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -3,7 +3,7 @@ import chalk from 'chalk';
3
3
  import ora from 'ora';
4
4
  import inquirer from 'inquirer';
5
5
  import { promises as fs } from 'fs';
6
- import { createProposal } from '@lovelybunch/core';
6
+ import { createTask } from '@lovelybunch/core';
7
7
  import os from 'os';
8
8
  const VALID_PRIORITIES = ['low', 'medium', 'high', 'critical'];
9
9
  function parseTags(tagsString) {
@@ -32,18 +32,18 @@ function interpretEscapeSequences(str) {
32
32
  .replace(/\\\\/g, '\\');
33
33
  }
34
34
  export const proposeCommand = new Command('propose')
35
- .description('Create a new Change Proposal')
36
- .argument('<intent>', 'The intent of the change')
35
+ .description('Create a new task (deprecated: use "nut task create")')
36
+ .argument('<intent>', 'The intent of the task')
37
37
  .option('--author <name>', 'Author name')
38
38
  .option('--email <email>', 'Author email')
39
39
  .option('--type <type>', 'Author type (human/agent)', 'human')
40
- .option('--description <text>', 'Detailed description or context for the proposal')
40
+ .option('--description <text>', 'Detailed description or context for the task')
41
41
  .option('--file <path>', 'Read description from a file')
42
42
  .option('--tags <tags>', 'Comma-separated tags (e.g., "ui,feature,priority")')
43
43
  .option('--priority <level>', 'Priority (low|medium|high|critical)')
44
44
  .option('--spec <ref>', 'Product specification reference')
45
45
  .action(async (intent, options) => {
46
- const spinner = ora('Creating Change Proposal...').start();
46
+ const spinner = ora('Creating task...').start();
47
47
  try {
48
48
  // Get author information
49
49
  spinner.stop();
@@ -90,9 +90,9 @@ export const proposeCommand = new Command('propose')
90
90
  // Parse and validate options
91
91
  const tags = parseTags(options.tags);
92
92
  const priority = validatePriority(options.priority);
93
- spinner.start('Creating proposal...');
94
- // Create the proposal (directly persisted to storage)
95
- const proposal = await createProposal({
93
+ spinner.start('Creating task...');
94
+ // Create the task (directly persisted to storage)
95
+ const task = await createTask({
96
96
  intent,
97
97
  content: content || intent, // Use intent as content if no description provided
98
98
  author,
@@ -103,12 +103,12 @@ export const proposeCommand = new Command('propose')
103
103
  },
104
104
  productSpecRef: options.spec,
105
105
  });
106
- spinner.succeed(`Change Proposal created: ${chalk.cyan(proposal.id)}`);
107
- console.log('\n' + chalk.bold('Change Proposal Details:'));
108
- console.log(' ID: ' + chalk.cyan(proposal.id));
109
- console.log(' Title: ' + chalk.white(proposal.title || proposal.intent));
106
+ spinner.succeed(`Task created: ${chalk.cyan(task.id)}`);
107
+ console.log('\n' + chalk.bold('Task Details:'));
108
+ console.log(' ID: ' + chalk.cyan(task.id));
109
+ console.log(' Title: ' + chalk.white(task.title || task.intent));
110
110
  console.log(' Author: ' + chalk.white(`${author.name} (${author.type})`));
111
- console.log(' Status: ' + chalk.yellow(proposal.status));
111
+ console.log(' Status: ' + chalk.yellow(task.status));
112
112
  if (priority) {
113
113
  const priorityColors = {
114
114
  low: chalk.gray,
@@ -127,14 +127,14 @@ export const proposeCommand = new Command('propose')
127
127
  if (content) {
128
128
  console.log(' Content: ' + chalk.gray(`${content.length} characters`));
129
129
  }
130
- console.log(' Created: ' + chalk.gray(proposal.metadata.createdAt.toLocaleString()));
130
+ console.log(' Created: ' + chalk.gray(task.metadata.createdAt.toLocaleString()));
131
131
  console.log('\n' + chalk.cyan('Next steps:'));
132
- console.log(' • View proposal details: ' + chalk.yellow(`nut show ${proposal.id}`));
133
- console.log(' • Add plan steps: ' + chalk.yellow(`nut plan ${proposal.id}`));
134
- console.log(' • List all proposals: ' + chalk.yellow('nut list'));
132
+ console.log(' • View task details: ' + chalk.yellow(`nut show ${task.id}`));
133
+ console.log(' • Add plan steps: ' + chalk.yellow(`nut task step ${task.id}`));
134
+ console.log(' • List all tasks: ' + chalk.yellow('nut task list'));
135
135
  }
136
136
  catch (error) {
137
- spinner.fail('Failed to create Change Proposal');
137
+ spinner.fail('Failed to create task');
138
138
  console.error(chalk.red('Error:'), error);
139
139
  process.exit(1);
140
140
  }
@@ -1 +1 @@
1
- {"version":3,"file":"propose.js","sourceRoot":"","sources":["../../src/commands/propose.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"propose.js","sourceRoot":"","sources":["../../src/commands/propose.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/commands/resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAitCpC,QAAA,MAAM,QAAQ,SAEO,CAAC;AActB,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/commands/resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2yCpC,QAAA,MAAM,QAAQ,SAEO,CAAC;AActB,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,CAAC"}
@@ -798,10 +798,55 @@ Examples:
798
798
  // ============================================================================
799
799
  // Add Resource Command
800
800
  // ============================================================================
801
+ /**
802
+ * Check if a string looks like a URL
803
+ */
804
+ function isUrl(input) {
805
+ return /^https?:\/\//i.test(input);
806
+ }
807
+ /**
808
+ * Download a URL to a temp file and return the temp path, filename, and MIME type.
809
+ * Caller is responsible for cleaning up the temp file/directory.
810
+ */
811
+ async function downloadUrlToTemp(url) {
812
+ const response = await fetch(url);
813
+ if (!response.ok) {
814
+ throw new Error(`Failed to download ${url}: ${response.statusText}`);
815
+ }
816
+ const buffer = Buffer.from(await response.arrayBuffer());
817
+ const contentType = response.headers.get('content-type') || '';
818
+ // Derive a filename from the URL path, falling back to a timestamp-based name
819
+ const urlPath = new URL(url).pathname;
820
+ let fileName = path.basename(urlPath);
821
+ if (!fileName || fileName === '/' || !path.extname(fileName)) {
822
+ // Try to infer extension from content-type
823
+ const extMap = {
824
+ 'image/png': '.png',
825
+ 'image/jpeg': '.jpg',
826
+ 'image/webp': '.webp',
827
+ 'image/gif': '.gif',
828
+ 'image/svg+xml': '.svg',
829
+ 'audio/mpeg': '.mp3',
830
+ 'audio/wav': '.wav',
831
+ 'audio/ogg': '.ogg',
832
+ 'video/mp4': '.mp4',
833
+ 'video/webm': '.webm',
834
+ 'application/pdf': '.pdf',
835
+ 'application/json': '.json',
836
+ };
837
+ const ext = Object.entries(extMap).find(([ct]) => contentType.includes(ct))?.[1] || '.bin';
838
+ fileName = `downloaded-${Date.now()}${ext}`;
839
+ }
840
+ const mimeType = contentType.split(';')[0].trim() || getMimeType(fileName);
841
+ const tempDir = mkdtempSync(path.join(tmpdir(), 'coconut-add-'));
842
+ const tempFilePath = path.join(tempDir, fileName);
843
+ writeFileSync(tempFilePath, buffer);
844
+ return { tempDir, tempFilePath, fileName, mimeType };
845
+ }
801
846
  const addResourceCommand = new Command('add')
802
- .description('Upload a file to resources')
847
+ .description('Upload a file or URL to resources')
803
848
  .alias('upload')
804
- .argument('<file...>', 'File path(s) to upload')
849
+ .argument('<file...>', 'File path(s) or URL(s) to upload')
805
850
  .option('-t, --tags <tags>', 'Comma-separated tags')
806
851
  .option('-d, --description <text>', 'Description of the resource')
807
852
  .option('--json', 'Output as JSON')
@@ -811,6 +856,7 @@ Examples:
811
856
  $ nut resource add ./screenshot.png
812
857
  $ nut resource upload ./logo.svg -t "branding, logo" -d "Company logo"
813
858
  $ nut resource add ./image1.png ./image2.png -t "batch"
859
+ $ nut resource add https://example.com/photo.png
814
860
  $ nut resource add ./data.json --json
815
861
  `)
816
862
  .action(async (files, options) => {
@@ -822,18 +868,42 @@ Examples:
822
868
  }
823
869
  const results = [];
824
870
  for (const filePath of files) {
825
- const resolvedPath = path.resolve(filePath);
826
- // Check file exists
827
- if (!existsSync(resolvedPath)) {
828
- console.error(chalk.red(`File not found: ${resolvedPath}`));
829
- process.exit(1);
871
+ let localPath;
872
+ let fileName;
873
+ let mimeType;
874
+ let tempDir = null;
875
+ if (isUrl(filePath)) {
876
+ // ── URL: download to temp file first ──
877
+ const spinner = ora(`Downloading ${filePath}...`).start();
878
+ try {
879
+ const downloaded = await downloadUrlToTemp(filePath);
880
+ tempDir = downloaded.tempDir;
881
+ localPath = downloaded.tempFilePath;
882
+ fileName = downloaded.fileName;
883
+ mimeType = downloaded.mimeType;
884
+ spinner.succeed(`Downloaded ${chalk.cyan(fileName)}`);
885
+ }
886
+ catch (error) {
887
+ spinner.fail('Failed to download URL');
888
+ console.error(chalk.red(error instanceof Error ? error.message : 'Unknown error'));
889
+ process.exit(1);
890
+ }
830
891
  }
831
- const spinner = ora(`Uploading ${path.basename(filePath)}...`).start();
892
+ else {
893
+ // ── Local file ──
894
+ localPath = path.resolve(filePath);
895
+ if (!existsSync(localPath)) {
896
+ console.error(chalk.red(`File not found: ${localPath}`));
897
+ process.exit(1);
898
+ }
899
+ fileName = path.basename(filePath);
900
+ mimeType = getMimeType(localPath);
901
+ }
902
+ const uploadSpinner = ora(`Uploading ${fileName}...`).start();
832
903
  try {
833
904
  const formData = new FormData();
834
- const mimeType = getMimeType(resolvedPath);
835
- const file = fileFromSync(resolvedPath, mimeType);
836
- formData.set('file', file, path.basename(filePath));
905
+ const file = fileFromSync(localPath, mimeType);
906
+ formData.set('file', file, fileName);
837
907
  if (options.tags) {
838
908
  formData.set('tags', options.tags);
839
909
  }
@@ -847,13 +917,13 @@ Examples:
847
917
  const result = await response.json();
848
918
  if (!response.ok || !result.success || !result.data) {
849
919
  const errorMessage = result.error?.message || 'Upload failed';
850
- spinner.fail(`Failed to upload ${path.basename(filePath)}`);
920
+ uploadSpinner.fail(`Failed to upload ${fileName}`);
851
921
  console.error(chalk.red(errorMessage));
852
922
  process.exit(1);
853
923
  }
854
924
  const resource = result.data;
855
925
  results.push(resource);
856
- spinner.succeed(`Uploaded ${chalk.cyan(resource.name)}`);
926
+ uploadSpinner.succeed(`Uploaded ${chalk.cyan(resource.name)}`);
857
927
  if (!options.json) {
858
928
  console.log();
859
929
  console.log(` ${chalk.gray('ID:')} ${resource.id}`);
@@ -875,10 +945,22 @@ Examples:
875
945
  }
876
946
  }
877
947
  catch (error) {
878
- spinner.fail(`Failed to upload ${path.basename(filePath)}`);
948
+ uploadSpinner.fail(`Failed to upload ${fileName}`);
879
949
  console.error(chalk.red(error instanceof Error ? error.message : 'Unknown error'));
880
950
  process.exit(1);
881
951
  }
952
+ finally {
953
+ // Clean up temp directory if we downloaded from a URL
954
+ if (tempDir) {
955
+ try {
956
+ unlinkSync(localPath);
957
+ fs.rmdir(tempDir).catch(() => { });
958
+ }
959
+ catch {
960
+ // Ignore cleanup errors
961
+ }
962
+ }
963
+ }
882
964
  }
883
965
  if (options.json) {
884
966
  console.log(JSON.stringify(results.length === 1 ? results[0] : results, null, 2));