delivered-cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +72 -40
  2. package/package.json +1 -1
  3. package/src/index.ts +94 -39
package/dist/index.js CHANGED
@@ -52,7 +52,7 @@ const program = new commander_1.Command();
52
52
  program
53
53
  .name("delivered")
54
54
  .description("CLI for delivered.md - Focus. Ship. Repeat.")
55
- .version("0.1.0");
55
+ .version("0.3.0");
56
56
  // Helper to get API key
57
57
  function getApiKey() {
58
58
  const apiKey = config.get("apiKey");
@@ -159,13 +159,25 @@ program
159
159
  process.exit(1);
160
160
  }
161
161
  });
162
- // Pull command
162
+ // Download command
163
163
  program
164
- .command("pull")
165
- .description("Download your page as markdown")
166
- .option("-o, --output <file>", "Output file path")
167
- .action(async (options) => {
164
+ .command("download")
165
+ .description("Download your page as markdown to current directory")
166
+ .action(async () => {
168
167
  try {
168
+ // Get username first
169
+ const whoamiResponse = await apiRequest("/whoami");
170
+ if (!whoamiResponse.ok) {
171
+ console.error("Error: Failed to get user info");
172
+ process.exit(1);
173
+ }
174
+ const userInfo = await whoamiResponse.json();
175
+ const username = userInfo.username;
176
+ if (!username) {
177
+ console.error("Error: No username set. Visit https://app.delivered.md to claim a username first.");
178
+ process.exit(1);
179
+ }
180
+ // Fetch page content
169
181
  const response = await apiRequest("/page");
170
182
  if (!response.ok) {
171
183
  const error = await response.json();
@@ -174,62 +186,82 @@ program
174
186
  }
175
187
  const data = await response.json();
176
188
  const markdown = data.content;
177
- if (options.output) {
178
- const outputPath = path.resolve(options.output);
179
- fs.writeFileSync(outputPath, markdown);
180
- console.log(`Page saved to ${outputPath}`);
181
- }
182
- else {
183
- // Output to stdout
184
- console.log(markdown);
185
- }
189
+ // Save to current directory as {username}.md
190
+ const filename = `${username}.md`;
191
+ const outputPath = path.resolve(process.cwd(), filename);
192
+ fs.writeFileSync(outputPath, markdown);
193
+ console.log(`\nDownloaded your page to ./${filename}`);
186
194
  }
187
195
  catch (error) {
188
- console.error("Error: Failed to pull page");
196
+ console.error("Error: Failed to download page");
189
197
  process.exit(1);
190
198
  }
191
199
  });
192
- // Push command
200
+ // Upload command
193
201
  program
194
- .command("push [file]")
195
- .description("Upload markdown content to your page")
202
+ .command("upload")
203
+ .description("Upload a markdown file to your page")
204
+ .argument("<file>", "Path to markdown file")
196
205
  .action(async (file) => {
197
206
  try {
198
- let content;
199
- if (file) {
200
- // Read from file
201
- const filePath = path.resolve(file);
202
- if (!fs.existsSync(filePath)) {
203
- console.error(`Error: File not found: ${filePath}`);
204
- process.exit(1);
205
- }
206
- content = fs.readFileSync(filePath, "utf-8");
207
- }
208
- else {
209
- // Read from stdin
210
- const chunks = [];
211
- for await (const chunk of process.stdin) {
212
- chunks.push(chunk);
213
- }
214
- content = Buffer.concat(chunks).toString("utf-8");
207
+ // Read from file
208
+ const filePath = path.resolve(file);
209
+ if (!fs.existsSync(filePath)) {
210
+ console.error(`Error: File not found: ${filePath}`);
211
+ process.exit(1);
215
212
  }
213
+ const content = fs.readFileSync(filePath, "utf-8");
216
214
  if (!content.trim()) {
217
- console.error("Error: Content cannot be empty");
215
+ console.error("Error: File is empty");
218
216
  process.exit(1);
219
217
  }
218
+ // Check file size locally first (100KB limit)
219
+ const sizeBytes = Buffer.byteLength(content, "utf-8");
220
+ const maxSizeBytes = 100 * 1024;
221
+ if (sizeBytes > maxSizeBytes) {
222
+ const wordCount = content.trim().split(/\s+/).filter(Boolean).length;
223
+ const maxWords = Math.floor(maxSizeBytes / 6);
224
+ console.error(`\nError: File too large.`);
225
+ console.error(`Your file: ~${wordCount.toLocaleString()} words (${Math.round(sizeBytes / 1024)}KB)`);
226
+ console.error(`Maximum: ~${maxWords.toLocaleString()} words (100KB)`);
227
+ process.exit(1);
228
+ }
229
+ // Upload
220
230
  const response = await apiRequest("/page", {
221
231
  method: "PUT",
222
232
  body: JSON.stringify({ content }),
223
233
  });
224
234
  if (!response.ok) {
225
235
  const error = await response.json();
226
- console.error(`Error: ${error.error || "Failed to push page"}`);
236
+ // Handle specific error types
237
+ if (error.error === "FILE_TOO_LARGE") {
238
+ console.error(`\nError: File too large.`);
239
+ console.error(`Your file: ~${error.wordCount?.toLocaleString() || "?"} words (${Math.round((error.currentSize || 0) / 1024)}KB)`);
240
+ console.error(`Maximum: ~${error.maxWords?.toLocaleString() || "16,000"} words (100KB)`);
241
+ process.exit(1);
242
+ }
243
+ if (error.error === "RATE_LIMIT") {
244
+ console.error(`\nError: Upload limit reached (${error.maxUploads || 50}/day).`);
245
+ console.error(`You can upload again in ${error.nextUploadIn || "a while"}.`);
246
+ process.exit(1);
247
+ }
248
+ console.error(`Error: ${error.message || error.error || "Failed to upload"}`);
227
249
  process.exit(1);
228
250
  }
229
- console.log("Page updated successfully!");
251
+ // Get username for the success message
252
+ const whoamiResponse = await apiRequest("/whoami");
253
+ let pageUrl = "https://delivered.md";
254
+ if (whoamiResponse.ok) {
255
+ const userInfo = await whoamiResponse.json();
256
+ if (userInfo.username) {
257
+ pageUrl = `https://delivered.md/${userInfo.username}`;
258
+ }
259
+ }
260
+ console.log(`\nUploaded successfully!`);
261
+ console.log(`View your page: ${pageUrl}`);
230
262
  }
231
263
  catch (error) {
232
- console.error("Error: Failed to push page");
264
+ console.error("Error: Failed to upload page");
233
265
  process.exit(1);
234
266
  }
235
267
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "delivered-cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "CLI for delivered.md - Focus. Ship. Repeat.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -19,7 +19,7 @@ const program = new Command();
19
19
  program
20
20
  .name("delivered")
21
21
  .description("CLI for delivered.md - Focus. Ship. Repeat.")
22
- .version("0.1.0");
22
+ .version("0.3.0");
23
23
 
24
24
  // Helper to get API key
25
25
  function getApiKey(): string {
@@ -142,13 +142,29 @@ program
142
142
  }
143
143
  });
144
144
 
145
- // Pull command
145
+ // Download command
146
146
  program
147
- .command("pull")
148
- .description("Download your page as markdown")
149
- .option("-o, --output <file>", "Output file path")
150
- .action(async (options) => {
147
+ .command("download")
148
+ .description("Download your page as markdown to current directory")
149
+ .action(async () => {
151
150
  try {
151
+ // Get username first
152
+ const whoamiResponse = await apiRequest("/whoami");
153
+ if (!whoamiResponse.ok) {
154
+ console.error("Error: Failed to get user info");
155
+ process.exit(1);
156
+ }
157
+ const userInfo = await whoamiResponse.json();
158
+ const username = userInfo.username;
159
+
160
+ if (!username) {
161
+ console.error(
162
+ "Error: No username set. Visit https://app.delivered.md to claim a username first.",
163
+ );
164
+ process.exit(1);
165
+ }
166
+
167
+ // Fetch page content
152
168
  const response = await apiRequest("/page");
153
169
 
154
170
  if (!response.ok) {
@@ -160,50 +176,53 @@ program
160
176
  const data = await response.json();
161
177
  const markdown = data.content;
162
178
 
163
- if (options.output) {
164
- const outputPath = path.resolve(options.output);
165
- fs.writeFileSync(outputPath, markdown);
166
- console.log(`Page saved to ${outputPath}`);
167
- } else {
168
- // Output to stdout
169
- console.log(markdown);
170
- }
179
+ // Save to current directory as {username}.md
180
+ const filename = `${username}.md`;
181
+ const outputPath = path.resolve(process.cwd(), filename);
182
+ fs.writeFileSync(outputPath, markdown);
183
+
184
+ console.log(`\nDownloaded your page to ./${filename}`);
171
185
  } catch (error) {
172
- console.error("Error: Failed to pull page");
186
+ console.error("Error: Failed to download page");
173
187
  process.exit(1);
174
188
  }
175
189
  });
176
190
 
177
- // Push command
191
+ // Upload command
178
192
  program
179
- .command("push [file]")
180
- .description("Upload markdown content to your page")
193
+ .command("upload")
194
+ .description("Upload a markdown file to your page")
195
+ .argument("<file>", "Path to markdown file")
181
196
  .action(async (file) => {
182
197
  try {
183
- let content: string;
184
-
185
- if (file) {
186
- // Read from file
187
- const filePath = path.resolve(file);
188
- if (!fs.existsSync(filePath)) {
189
- console.error(`Error: File not found: ${filePath}`);
190
- process.exit(1);
191
- }
192
- content = fs.readFileSync(filePath, "utf-8");
193
- } else {
194
- // Read from stdin
195
- const chunks: Buffer[] = [];
196
- for await (const chunk of process.stdin) {
197
- chunks.push(chunk);
198
- }
199
- content = Buffer.concat(chunks).toString("utf-8");
198
+ // Read from file
199
+ const filePath = path.resolve(file);
200
+ if (!fs.existsSync(filePath)) {
201
+ console.error(`Error: File not found: ${filePath}`);
202
+ process.exit(1);
200
203
  }
204
+ const content = fs.readFileSync(filePath, "utf-8");
201
205
 
202
206
  if (!content.trim()) {
203
- console.error("Error: Content cannot be empty");
207
+ console.error("Error: File is empty");
204
208
  process.exit(1);
205
209
  }
206
210
 
211
+ // Check file size locally first (100KB limit)
212
+ const sizeBytes = Buffer.byteLength(content, "utf-8");
213
+ const maxSizeBytes = 100 * 1024;
214
+ if (sizeBytes > maxSizeBytes) {
215
+ const wordCount = content.trim().split(/\s+/).filter(Boolean).length;
216
+ const maxWords = Math.floor(maxSizeBytes / 6);
217
+ console.error(`\nError: File too large.`);
218
+ console.error(
219
+ `Your file: ~${wordCount.toLocaleString()} words (${Math.round(sizeBytes / 1024)}KB)`,
220
+ );
221
+ console.error(`Maximum: ~${maxWords.toLocaleString()} words (100KB)`);
222
+ process.exit(1);
223
+ }
224
+
225
+ // Upload
207
226
  const response = await apiRequest("/page", {
208
227
  method: "PUT",
209
228
  body: JSON.stringify({ content }),
@@ -211,13 +230,49 @@ program
211
230
 
212
231
  if (!response.ok) {
213
232
  const error = await response.json();
214
- console.error(`Error: ${error.error || "Failed to push page"}`);
233
+
234
+ // Handle specific error types
235
+ if (error.error === "FILE_TOO_LARGE") {
236
+ console.error(`\nError: File too large.`);
237
+ console.error(
238
+ `Your file: ~${error.wordCount?.toLocaleString() || "?"} words (${Math.round((error.currentSize || 0) / 1024)}KB)`,
239
+ );
240
+ console.error(
241
+ `Maximum: ~${error.maxWords?.toLocaleString() || "16,000"} words (100KB)`,
242
+ );
243
+ process.exit(1);
244
+ }
245
+
246
+ if (error.error === "RATE_LIMIT") {
247
+ console.error(
248
+ `\nError: Upload limit reached (${error.maxUploads || 50}/day).`,
249
+ );
250
+ console.error(
251
+ `You can upload again in ${error.nextUploadIn || "a while"}.`,
252
+ );
253
+ process.exit(1);
254
+ }
255
+
256
+ console.error(
257
+ `Error: ${error.message || error.error || "Failed to upload"}`,
258
+ );
215
259
  process.exit(1);
216
260
  }
217
261
 
218
- console.log("Page updated successfully!");
262
+ // Get username for the success message
263
+ const whoamiResponse = await apiRequest("/whoami");
264
+ let pageUrl = "https://delivered.md";
265
+ if (whoamiResponse.ok) {
266
+ const userInfo = await whoamiResponse.json();
267
+ if (userInfo.username) {
268
+ pageUrl = `https://delivered.md/${userInfo.username}`;
269
+ }
270
+ }
271
+
272
+ console.log(`\nUploaded successfully!`);
273
+ console.log(`View your page: ${pageUrl}`);
219
274
  } catch (error) {
220
- console.error("Error: Failed to push page");
275
+ console.error("Error: Failed to upload page");
221
276
  process.exit(1);
222
277
  }
223
278
  });