delivered-cli 0.1.0 → 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.
@@ -0,0 +1,4 @@
1
+
2
+ > delivered-cli@0.1.0 build /home/hyapadi/DeliveredConvexExpoJS/cli
3
+ > tsc
4
+
package/dist/index.js CHANGED
@@ -45,7 +45,9 @@ const readline = __importStar(require("readline"));
45
45
  const config = new conf_1.default({
46
46
  projectName: "delivered-cli",
47
47
  });
48
- const API_URL = config.get("apiUrl") || "https://delivered.md/api/v1";
48
+ // Convex HTTP endpoint URL
49
+ const DEFAULT_API_URL = "https://fabulous-chipmunk-797.convex.site/api";
50
+ const API_URL = config.get("apiUrl") || DEFAULT_API_URL;
49
51
  const program = new commander_1.Command();
50
52
  program
51
53
  .name("delivered")
@@ -68,6 +70,7 @@ async function apiRequest(endpoint, options = {}) {
68
70
  ...options,
69
71
  headers: {
70
72
  Authorization: `Bearer ${apiKey}`,
73
+ "Content-Type": "application/json",
71
74
  ...options.headers,
72
75
  },
73
76
  });
@@ -77,38 +80,51 @@ async function apiRequest(endpoint, options = {}) {
77
80
  program
78
81
  .command("login")
79
82
  .description("Login with your API key")
80
- .action(async () => {
81
- const rl = readline.createInterface({
82
- input: process.stdin,
83
- output: process.stdout,
84
- });
85
- console.log("\nTo get your API key:");
86
- console.log("1. Go to https://delivered.md/settings");
87
- console.log("2. Create a new API key");
88
- console.log("3. Copy and paste it below\n");
89
- rl.question("API Key: ", async (apiKey) => {
90
- rl.close();
83
+ .argument("[api-key]", "API key (or omit to enter interactively)")
84
+ .action(async (apiKeyArg) => {
85
+ const processLogin = async (apiKey) => {
91
86
  if (!apiKey || !apiKey.startsWith("dlv_")) {
92
87
  console.error("Error: Invalid API key format. Keys start with 'dlv_'");
93
88
  process.exit(1);
94
89
  }
95
- // Test the key
90
+ // Test the key by calling whoami
96
91
  try {
97
- const response = await fetch(`${API_URL}/page`, {
92
+ const response = await fetch(`${API_URL}/whoami`, {
98
93
  headers: { Authorization: `Bearer ${apiKey}` },
99
94
  });
100
95
  if (response.status === 401) {
101
96
  console.error("Error: Invalid API key");
102
97
  process.exit(1);
103
98
  }
99
+ const data = await response.json();
104
100
  config.set("apiKey", apiKey);
105
- console.log("\nLogged in successfully!");
101
+ console.log(`\nLogged in as ${data.username || data.email}!`);
102
+ if (data.pageUrl) {
103
+ console.log(`Your page: ${data.pageUrl}`);
104
+ }
106
105
  }
107
106
  catch (error) {
108
107
  console.error("Error: Failed to validate API key");
109
108
  process.exit(1);
110
109
  }
111
- });
110
+ };
111
+ if (apiKeyArg) {
112
+ await processLogin(apiKeyArg);
113
+ }
114
+ else {
115
+ const rl = readline.createInterface({
116
+ input: process.stdin,
117
+ output: process.stdout,
118
+ });
119
+ console.log("\nTo get your API key:");
120
+ console.log("1. Go to https://app.delivered.md/settings");
121
+ console.log("2. Create a new API key");
122
+ console.log("3. Copy and paste it below\n");
123
+ rl.question("API Key: ", async (apiKey) => {
124
+ rl.close();
125
+ await processLogin(apiKey);
126
+ });
127
+ }
112
128
  });
113
129
  // Logout command
114
130
  program
@@ -118,6 +134,31 @@ program
118
134
  config.delete("apiKey");
119
135
  console.log("Logged out successfully.");
120
136
  });
137
+ // Whoami command
138
+ program
139
+ .command("whoami")
140
+ .description("Show current user info")
141
+ .action(async () => {
142
+ try {
143
+ const response = await apiRequest("/whoami");
144
+ if (!response.ok) {
145
+ const error = await response.json();
146
+ console.error(`Error: ${error.error || "Failed to get user info"}`);
147
+ process.exit(1);
148
+ }
149
+ const data = await response.json();
150
+ console.log(`\nUsername: ${data.username || "(not set)"}`);
151
+ console.log(`Name: ${data.name || "(not set)"}`);
152
+ console.log(`Email: ${data.email || "(not set)"}`);
153
+ if (data.pageUrl) {
154
+ console.log(`Page URL: ${data.pageUrl}`);
155
+ }
156
+ }
157
+ catch (error) {
158
+ console.error("Error: Failed to get user info");
159
+ process.exit(1);
160
+ }
161
+ });
121
162
  // Pull command
122
163
  program
123
164
  .command("pull")
@@ -131,7 +172,8 @@ program
131
172
  console.error(`Error: ${error.error || "Failed to fetch page"}`);
132
173
  process.exit(1);
133
174
  }
134
- const markdown = await response.text();
175
+ const data = await response.json();
176
+ const markdown = data.content;
135
177
  if (options.output) {
136
178
  const outputPath = path.resolve(options.output);
137
179
  fs.writeFileSync(outputPath, markdown);
@@ -177,8 +219,7 @@ program
177
219
  }
178
220
  const response = await apiRequest("/page", {
179
221
  method: "PUT",
180
- headers: { "Content-Type": "text/markdown" },
181
- body: content,
222
+ body: JSON.stringify({ content }),
182
223
  });
183
224
  if (!response.ok) {
184
225
  const error = await response.json();
@@ -192,76 +233,28 @@ program
192
233
  process.exit(1);
193
234
  }
194
235
  });
195
- // Snapshots command
196
- program
197
- .command("snapshots")
198
- .description("List your page snapshots")
199
- .action(async () => {
200
- try {
201
- const response = await apiRequest("/snapshots");
202
- if (!response.ok) {
203
- const error = await response.json();
204
- console.error(`Error: ${error.error || "Failed to fetch snapshots"}`);
205
- process.exit(1);
206
- }
207
- const data = await response.json();
208
- const snapshots = data.snapshots;
209
- if (snapshots.length === 0) {
210
- console.log("No snapshots found.");
211
- return;
212
- }
213
- console.log("\nSnapshots:\n");
214
- snapshots.forEach((snapshot, index) => {
215
- const date = new Date(snapshot.createdAt).toLocaleString();
216
- const accessIcon = snapshot.accessible ? " " : "[locked]";
217
- console.log(`${index + 1}. ${date} ${accessIcon}`);
218
- console.log(` ID: ${snapshot.id}\n`);
219
- });
220
- }
221
- catch (error) {
222
- console.error("Error: Failed to fetch snapshots");
223
- process.exit(1);
224
- }
225
- });
226
- // Revert command
227
- program
228
- .command("revert <snapshot-id>")
229
- .description("Revert to a specific snapshot")
230
- .action(async (snapshotId) => {
231
- try {
232
- const response = await apiRequest("/revert", {
233
- method: "POST",
234
- headers: { "Content-Type": "application/json" },
235
- body: JSON.stringify({ snapshotId }),
236
- });
237
- if (!response.ok) {
238
- const error = await response.json();
239
- console.error(`Error: ${error.error || "Failed to revert"}`);
240
- process.exit(1);
241
- }
242
- const data = await response.json();
243
- console.log(`Reverted successfully to snapshot from ${new Date(data.revertedTo).toLocaleString()}`);
244
- }
245
- catch (error) {
246
- console.error("Error: Failed to revert");
247
- process.exit(1);
248
- }
249
- });
236
+ // Note: snapshots and revert commands can be added later when HTTP endpoints are implemented
250
237
  // Config command
251
238
  program
252
239
  .command("config")
253
240
  .description("View or set configuration")
254
241
  .option("--api-url <url>", "Set custom API URL")
255
- .option("--show", "Show current configuration")
242
+ .option("--reset", "Reset to default configuration")
256
243
  .action((options) => {
244
+ if (options.reset) {
245
+ config.delete("apiUrl");
246
+ console.log("Configuration reset to defaults.");
247
+ }
257
248
  if (options.apiUrl) {
258
249
  config.set("apiUrl", options.apiUrl);
259
250
  console.log(`API URL set to: ${options.apiUrl}`);
260
251
  }
261
- if (options.show || (!options.apiUrl)) {
252
+ if (!options.apiUrl && !options.reset) {
253
+ const customUrl = config.get("apiUrl");
262
254
  console.log("\nConfiguration:");
263
- console.log(` API URL: ${config.get("apiUrl") || API_URL} (default)`);
255
+ console.log(` API URL: ${customUrl || DEFAULT_API_URL}${customUrl ? "" : " (default)"}`);
264
256
  console.log(` Logged in: ${config.get("apiKey") ? "Yes" : "No"}`);
257
+ console.log(` Config file: ${config.path}`);
265
258
  }
266
259
  });
267
260
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "delivered-cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "CLI for delivered.md - Focus. Ship. Repeat.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -9,21 +9,27 @@
9
9
  "scripts": {
10
10
  "build": "tsc",
11
11
  "dev": "tsc -w",
12
- "start": "node dist/index.js"
12
+ "start": "node dist/index.js",
13
+ "prepublishOnly": "npm run build"
13
14
  },
14
15
  "keywords": [
15
16
  "delivered",
16
17
  "markdown",
17
18
  "productivity",
18
19
  "goals",
19
- "cli"
20
+ "cli",
21
+ "accountability"
20
22
  ],
21
- "author": "",
23
+ "author": "hyapadi",
22
24
  "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/anomalyco/delivered"
28
+ },
29
+ "homepage": "https://delivered.md",
23
30
  "dependencies": {
24
31
  "commander": "^12.1.0",
25
- "conf": "^12.0.0",
26
- "node-fetch": "^3.3.2"
32
+ "conf": "^12.0.0"
27
33
  },
28
34
  "devDependencies": {
29
35
  "@types/node": "^20.10.0",
package/src/index.ts CHANGED
@@ -10,7 +10,9 @@ const config = new Conf<{ apiKey?: string; apiUrl?: string }>({
10
10
  projectName: "delivered-cli",
11
11
  });
12
12
 
13
- const API_URL = config.get("apiUrl") || "https://delivered.md/api/v1";
13
+ // Convex HTTP endpoint URL
14
+ const DEFAULT_API_URL = "https://fabulous-chipmunk-797.convex.site/api";
15
+ const API_URL = config.get("apiUrl") || DEFAULT_API_URL;
14
16
 
15
17
  const program = new Command();
16
18
 
@@ -32,7 +34,7 @@ function getApiKey(): string {
32
34
  // Helper for API requests
33
35
  async function apiRequest(
34
36
  endpoint: string,
35
- options: RequestInit = {}
37
+ options: RequestInit = {},
36
38
  ): Promise<Response> {
37
39
  const apiKey = getApiKey();
38
40
  const url = `${API_URL}${endpoint}`;
@@ -41,6 +43,7 @@ async function apiRequest(
41
43
  ...options,
42
44
  headers: {
43
45
  Authorization: `Bearer ${apiKey}`,
46
+ "Content-Type": "application/json",
44
47
  ...options.headers,
45
48
  },
46
49
  });
@@ -52,28 +55,17 @@ async function apiRequest(
52
55
  program
53
56
  .command("login")
54
57
  .description("Login with your API key")
55
- .action(async () => {
56
- const rl = readline.createInterface({
57
- input: process.stdin,
58
- output: process.stdout,
59
- });
60
-
61
- console.log("\nTo get your API key:");
62
- console.log("1. Go to https://delivered.md/settings");
63
- console.log("2. Create a new API key");
64
- console.log("3. Copy and paste it below\n");
65
-
66
- rl.question("API Key: ", async (apiKey) => {
67
- rl.close();
68
-
58
+ .argument("[api-key]", "API key (or omit to enter interactively)")
59
+ .action(async (apiKeyArg?: string) => {
60
+ const processLogin = async (apiKey: string) => {
69
61
  if (!apiKey || !apiKey.startsWith("dlv_")) {
70
62
  console.error("Error: Invalid API key format. Keys start with 'dlv_'");
71
63
  process.exit(1);
72
64
  }
73
65
 
74
- // Test the key
66
+ // Test the key by calling whoami
75
67
  try {
76
- const response = await fetch(`${API_URL}/page`, {
68
+ const response = await fetch(`${API_URL}/whoami`, {
77
69
  headers: { Authorization: `Bearer ${apiKey}` },
78
70
  });
79
71
 
@@ -82,13 +74,36 @@ program
82
74
  process.exit(1);
83
75
  }
84
76
 
77
+ const data = await response.json();
85
78
  config.set("apiKey", apiKey);
86
- console.log("\nLogged in successfully!");
79
+ console.log(`\nLogged in as ${data.username || data.email}!`);
80
+ if (data.pageUrl) {
81
+ console.log(`Your page: ${data.pageUrl}`);
82
+ }
87
83
  } catch (error) {
88
84
  console.error("Error: Failed to validate API key");
89
85
  process.exit(1);
90
86
  }
91
- });
87
+ };
88
+
89
+ if (apiKeyArg) {
90
+ await processLogin(apiKeyArg);
91
+ } else {
92
+ const rl = readline.createInterface({
93
+ input: process.stdin,
94
+ output: process.stdout,
95
+ });
96
+
97
+ console.log("\nTo get your API key:");
98
+ console.log("1. Go to https://app.delivered.md/settings");
99
+ console.log("2. Create a new API key");
100
+ console.log("3. Copy and paste it below\n");
101
+
102
+ rl.question("API Key: ", async (apiKey) => {
103
+ rl.close();
104
+ await processLogin(apiKey);
105
+ });
106
+ }
92
107
  });
93
108
 
94
109
  // Logout command
@@ -100,6 +115,33 @@ program
100
115
  console.log("Logged out successfully.");
101
116
  });
102
117
 
118
+ // Whoami command
119
+ program
120
+ .command("whoami")
121
+ .description("Show current user info")
122
+ .action(async () => {
123
+ try {
124
+ const response = await apiRequest("/whoami");
125
+
126
+ if (!response.ok) {
127
+ const error = await response.json();
128
+ console.error(`Error: ${error.error || "Failed to get user info"}`);
129
+ process.exit(1);
130
+ }
131
+
132
+ const data = await response.json();
133
+ console.log(`\nUsername: ${data.username || "(not set)"}`);
134
+ console.log(`Name: ${data.name || "(not set)"}`);
135
+ console.log(`Email: ${data.email || "(not set)"}`);
136
+ if (data.pageUrl) {
137
+ console.log(`Page URL: ${data.pageUrl}`);
138
+ }
139
+ } catch (error) {
140
+ console.error("Error: Failed to get user info");
141
+ process.exit(1);
142
+ }
143
+ });
144
+
103
145
  // Pull command
104
146
  program
105
147
  .command("pull")
@@ -115,7 +157,8 @@ program
115
157
  process.exit(1);
116
158
  }
117
159
 
118
- const markdown = await response.text();
160
+ const data = await response.json();
161
+ const markdown = data.content;
119
162
 
120
163
  if (options.output) {
121
164
  const outputPath = path.resolve(options.output);
@@ -163,8 +206,7 @@ program
163
206
 
164
207
  const response = await apiRequest("/page", {
165
208
  method: "PUT",
166
- headers: { "Content-Type": "text/markdown" },
167
- body: content,
209
+ body: JSON.stringify({ content }),
168
210
  });
169
211
 
170
212
  if (!response.ok) {
@@ -180,90 +222,33 @@ program
180
222
  }
181
223
  });
182
224
 
183
- // Snapshots command
184
- program
185
- .command("snapshots")
186
- .description("List your page snapshots")
187
- .action(async () => {
188
- try {
189
- const response = await apiRequest("/snapshots");
190
-
191
- if (!response.ok) {
192
- const error = await response.json();
193
- console.error(`Error: ${error.error || "Failed to fetch snapshots"}`);
194
- process.exit(1);
195
- }
196
-
197
- const data = await response.json();
198
- const snapshots = data.snapshots;
199
-
200
- if (snapshots.length === 0) {
201
- console.log("No snapshots found.");
202
- return;
203
- }
204
-
205
- console.log("\nSnapshots:\n");
206
- snapshots.forEach(
207
- (
208
- snapshot: { id: string; createdAt: number; accessible: boolean },
209
- index: number
210
- ) => {
211
- const date = new Date(snapshot.createdAt).toLocaleString();
212
- const accessIcon = snapshot.accessible ? " " : "[locked]";
213
- console.log(`${index + 1}. ${date} ${accessIcon}`);
214
- console.log(` ID: ${snapshot.id}\n`);
215
- }
216
- );
217
- } catch (error) {
218
- console.error("Error: Failed to fetch snapshots");
219
- process.exit(1);
220
- }
221
- });
222
-
223
- // Revert command
224
- program
225
- .command("revert <snapshot-id>")
226
- .description("Revert to a specific snapshot")
227
- .action(async (snapshotId) => {
228
- try {
229
- const response = await apiRequest("/revert", {
230
- method: "POST",
231
- headers: { "Content-Type": "application/json" },
232
- body: JSON.stringify({ snapshotId }),
233
- });
234
-
235
- if (!response.ok) {
236
- const error = await response.json();
237
- console.error(`Error: ${error.error || "Failed to revert"}`);
238
- process.exit(1);
239
- }
240
-
241
- const data = await response.json();
242
- console.log(
243
- `Reverted successfully to snapshot from ${new Date(data.revertedTo).toLocaleString()}`
244
- );
245
- } catch (error) {
246
- console.error("Error: Failed to revert");
247
- process.exit(1);
248
- }
249
- });
225
+ // Note: snapshots and revert commands can be added later when HTTP endpoints are implemented
250
226
 
251
227
  // Config command
252
228
  program
253
229
  .command("config")
254
230
  .description("View or set configuration")
255
231
  .option("--api-url <url>", "Set custom API URL")
256
- .option("--show", "Show current configuration")
232
+ .option("--reset", "Reset to default configuration")
257
233
  .action((options) => {
234
+ if (options.reset) {
235
+ config.delete("apiUrl");
236
+ console.log("Configuration reset to defaults.");
237
+ }
238
+
258
239
  if (options.apiUrl) {
259
240
  config.set("apiUrl", options.apiUrl);
260
241
  console.log(`API URL set to: ${options.apiUrl}`);
261
242
  }
262
243
 
263
- if (options.show || (!options.apiUrl)) {
244
+ if (!options.apiUrl && !options.reset) {
245
+ const customUrl = config.get("apiUrl");
264
246
  console.log("\nConfiguration:");
265
- console.log(` API URL: ${config.get("apiUrl") || API_URL} (default)`);
247
+ console.log(
248
+ ` API URL: ${customUrl || DEFAULT_API_URL}${customUrl ? "" : " (default)"}`,
249
+ );
266
250
  console.log(` Logged in: ${config.get("apiKey") ? "Yes" : "No"}`);
251
+ console.log(` Config file: ${config.path}`);
267
252
  }
268
253
  });
269
254