@supacortex/cli 0.1.3 → 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 (2) hide show
  1. package/dist/index.js +248 -1
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -188,11 +188,12 @@ var registerWhoamiCommand = (program2) => {
188
188
  // src/commands/bookmarks.ts
189
189
  var registerBookmarksCommand = (program2) => {
190
190
  const bookmarks = program2.command("bookmarks");
191
- bookmarks.command("list").option("-l, --limit <number>", "Max results", "20").option("-o, --offset <number>", "Skip results").option("-s, --search <string>", "Search bookmarks").option("-j, --json", "Output raw JSON").description("List all bookmarks").action(async (option) => {
191
+ bookmarks.command("list").option("-l, --limit <number>", "Max results", "20").option("-o, --offset <number>", "Skip results").option("-s, --search <string>", "Search bookmarks").option("-t, --type <string>", "Filter by type (tweet, link, youtube)").option("-j, --json", "Output raw JSON").description("List all bookmarks").action(async (option) => {
192
192
  const searchParams = new URLSearchParams();
193
193
  if (option.limit) searchParams.append("limit", String(parseInt(option.limit, 10)));
194
194
  if (option.offset) searchParams.append("offset", String(parseInt(option.offset, 10)));
195
195
  if (option.search) searchParams.append("search", option.search);
196
+ if (option.type) searchParams.append("type", option.type);
196
197
  const result = await apiRequest(
197
198
  `bookmarks?${searchParams.toString()}`,
198
199
  "GET"
@@ -220,6 +221,20 @@ var registerBookmarksCommand = (program2) => {
220
221
  }
221
222
  console.log(`Bookmark added: ${result.title || result.url}`);
222
223
  });
224
+ bookmarks.command("get").description("Get a bookmark by ID").argument("<id>", "Bookmark ID").option("-j, --json", "Output raw JSON").action(async (id, option) => {
225
+ const data = await apiRequest(`bookmarks/${id}`, "GET");
226
+ if (option.json) {
227
+ console.log(JSON.stringify(data, null, 2));
228
+ return;
229
+ }
230
+ console.log(`ID: ${data.id}`);
231
+ console.log(`Type: ${data.type}`);
232
+ console.log(`Title: ${data.title || "(none)"}`);
233
+ console.log(`URL: ${data.url}`);
234
+ if (data.author) console.log(`Author: ${data.author}`);
235
+ if (data.content) console.log(`Content: ${data.content.slice(0, 200)}${data.content.length > 200 ? "\u2026" : ""}`);
236
+ console.log(`Created: ${data.createdAt}`);
237
+ });
223
238
  bookmarks.command("delete").description("Delete a bookmark").argument("<id>", "Bookmark ID to delete").option("-j, --json", "Output raw JSON").action(async (id, option) => {
224
239
  const result = await apiRequest(`bookmarks/${id}`, "DELETE");
225
240
  if (option.json) {
@@ -341,6 +356,236 @@ var registerUpdateCommand = (program2, version) => {
341
356
  });
342
357
  };
343
358
 
359
+ // src/commands/conversation.ts
360
+ var TIERS = ["brief", "summary", "detailed"];
361
+ var tierType = (tier) => `conversation_${tier}`;
362
+ var registerConversationCommand = (program2) => {
363
+ const convo = program2.command("conversation").description("Manage conversation memories \u2014 summaries of AI chat sessions");
364
+ convo.command("list").option("-s, --search <string>", "Search conversations").option("--tier <tier>", "Filter by tier (brief, summary, detailed)").option("-l, --limit <number>", "Max results", "20").option("-o, --offset <number>", "Skip results").option("-j, --json", "Output raw JSON").description("List saved conversations").action(async (option) => {
365
+ const searchParams = new URLSearchParams();
366
+ if (option.limit) searchParams.append("limit", String(parseInt(option.limit, 10)));
367
+ if (option.offset) searchParams.append("offset", String(parseInt(option.offset, 10)));
368
+ if (option.search) searchParams.append("search", option.search);
369
+ if (option.tier) {
370
+ if (!TIERS.includes(option.tier)) {
371
+ console.error(`Error: --tier must be one of: ${TIERS.join(", ")}`);
372
+ process.exit(1);
373
+ }
374
+ searchParams.append("type", tierType(option.tier));
375
+ } else {
376
+ searchParams.append("type", "conversation_brief");
377
+ searchParams.delete("type");
378
+ }
379
+ const result = await apiRequest(`memory?${searchParams.toString()}`, "GET");
380
+ if (option.json) {
381
+ console.log(JSON.stringify(result, null, 2));
382
+ return;
383
+ }
384
+ const { data } = result;
385
+ const conversations = option.tier ? data : data.filter((m) => String(m.type).startsWith("conversation_"));
386
+ if (conversations.length === 0) {
387
+ console.log("No conversations found.");
388
+ return;
389
+ }
390
+ for (const m of conversations) {
391
+ const title = m.title || m.content?.slice(0, 80) || "Untitled";
392
+ const truncated = title.length > 80 ? title.slice(0, 80) + "..." : title;
393
+ const tier = String(m.type).replace("conversation_", "");
394
+ const date = m.createdAt ? new Date(m.createdAt).toISOString().slice(0, 10) : "";
395
+ console.log(` ${truncated}`);
396
+ console.log(` ${tier} \xB7 ${date}`);
397
+ console.log();
398
+ }
399
+ console.log(`Showing ${conversations.length} conversations`);
400
+ });
401
+ convo.command("add").description("Save a conversation summary").argument("<content>", "Conversation summary text").requiredOption("--tier <tier>", "Tier: brief (1 sentence), summary (bullet points), detailed (full document)").option("-t, --title <string>", "Title for the conversation").option("-m, --metadata <json>", "Metadata as JSON (e.g. source, sessionId, tags)").option("-j, --json", "Output raw JSON").action(async (content, option) => {
402
+ if (!TIERS.includes(option.tier)) {
403
+ console.error(`Error: --tier must be one of: ${TIERS.join(", ")}`);
404
+ process.exit(1);
405
+ }
406
+ const body = {
407
+ type: tierType(option.tier),
408
+ content
409
+ };
410
+ if (option.title) body.title = option.title;
411
+ if (option.metadata) {
412
+ try {
413
+ body.metadata = JSON.parse(option.metadata);
414
+ } catch {
415
+ console.error("Error: --metadata must be valid JSON");
416
+ process.exit(1);
417
+ }
418
+ }
419
+ const result = await apiRequest("memory", "POST", body);
420
+ if (option.json) {
421
+ console.log(JSON.stringify(result, null, 2));
422
+ return;
423
+ }
424
+ console.log(`Conversation saved: ${result.title || result.content?.slice(0, 60) || result.id}`);
425
+ });
426
+ convo.command("get").description("Get a conversation by ID").argument("<id>", "Conversation ID").option("-j, --json", "Output raw JSON").action(async (id, option) => {
427
+ const data = await apiRequest(`memory/${id}`, "GET");
428
+ if (option.json) {
429
+ console.log(JSON.stringify(data, null, 2));
430
+ return;
431
+ }
432
+ const tier = String(data.type).replace("conversation_", "");
433
+ console.log(`ID: ${data.id}`);
434
+ console.log(`Tier: ${tier}`);
435
+ console.log(`Title: ${data.title || "(none)"}`);
436
+ console.log(`Content: ${data.content?.slice(0, 500)}${data.content?.length > 500 ? "\u2026" : ""}`);
437
+ if (data.metadata) console.log(`Metadata: ${JSON.stringify(data.metadata)}`);
438
+ console.log(`Created: ${data.createdAt}`);
439
+ if (data.updatedAt) console.log(`Updated: ${data.updatedAt}`);
440
+ });
441
+ convo.command("update").description("Update a saved conversation").argument("<id>", "Conversation ID").option("-t, --title <string>", "New title").option("-c, --content <string>", "New content").option("--tier <tier>", "Change tier (brief, summary, detailed)").option("-m, --metadata <json>", "New metadata as JSON").option("-j, --json", "Output raw JSON").action(async (id, option) => {
442
+ const body = {};
443
+ if (option.title) body.title = option.title;
444
+ if (option.content) body.content = option.content;
445
+ if (option.tier) {
446
+ if (!TIERS.includes(option.tier)) {
447
+ console.error(`Error: --tier must be one of: ${TIERS.join(", ")}`);
448
+ process.exit(1);
449
+ }
450
+ body.type = tierType(option.tier);
451
+ }
452
+ if (option.metadata) {
453
+ try {
454
+ body.metadata = JSON.parse(option.metadata);
455
+ } catch {
456
+ console.error("Error: --metadata must be valid JSON");
457
+ process.exit(1);
458
+ }
459
+ }
460
+ if (Object.keys(body).length === 0) {
461
+ console.error("Error: provide at least one field to update (--title, --content, --tier, --metadata)");
462
+ process.exit(1);
463
+ }
464
+ const result = await apiRequest(`memory/${id}`, "PATCH", body);
465
+ if (option.json) {
466
+ console.log(JSON.stringify(result, null, 2));
467
+ return;
468
+ }
469
+ console.log(`Conversation updated: ${result.title || result.id}`);
470
+ });
471
+ convo.command("delete").description("Delete a saved conversation").argument("<id>", "Conversation ID").option("-j, --json", "Output raw JSON").action(async (id, option) => {
472
+ const result = await apiRequest(`memory/${id}`, "DELETE");
473
+ if (option.json) {
474
+ console.log(JSON.stringify(result, null, 2));
475
+ return;
476
+ }
477
+ console.log("Conversation deleted.");
478
+ });
479
+ };
480
+
481
+ // src/commands/identity.ts
482
+ var CATEGORIES = ["core", "goals", "preferences", "interests"];
483
+ var registerIdentityCommand = (program2) => {
484
+ const identity = program2.command("identity").description("Manage identity \u2014 persistent context about the user (name, goals, preferences, interests)");
485
+ identity.command("list").option("-s, --search <string>", "Search identity entries").option("--category <category>", "Filter by category (core, goals, preferences, interests)").option("-l, --limit <number>", "Max results", "20").option("-o, --offset <number>", "Skip results").option("-j, --json", "Output raw JSON").description("List identity entries").action(async (option) => {
486
+ const searchParams = new URLSearchParams();
487
+ searchParams.append("type", "identity");
488
+ if (option.limit) searchParams.append("limit", String(parseInt(option.limit, 10)));
489
+ if (option.offset) searchParams.append("offset", String(parseInt(option.offset, 10)));
490
+ if (option.search) searchParams.append("search", option.search);
491
+ const result = await apiRequest(`memory?${searchParams.toString()}`, "GET");
492
+ if (option.json) {
493
+ console.log(JSON.stringify(result, null, 2));
494
+ return;
495
+ }
496
+ let { data } = result;
497
+ if (option.category) {
498
+ data = data.filter(
499
+ (m) => m.metadata?.category === option.category
500
+ );
501
+ }
502
+ if (data.length === 0) {
503
+ console.log("No identity entries found.");
504
+ return;
505
+ }
506
+ for (const m of data) {
507
+ const category = m.metadata?.category || "uncategorized";
508
+ const title = m.title || m.content?.slice(0, 80) || "Untitled";
509
+ const truncated = title.length > 80 ? title.slice(0, 80) + "..." : title;
510
+ console.log(` ${truncated}`);
511
+ console.log(` ${category}`);
512
+ console.log();
513
+ }
514
+ console.log(`Showing ${data.length} entries`);
515
+ });
516
+ identity.command("add").description("Add an identity entry").argument("<content>", 'Identity content (e.g. "Solo founder based in Nepal, building Supacortex")').option("-t, --title <string>", 'Title (e.g. "Core profile", "Tech preferences")').option("--category <category>", "Category: core, goals, preferences, interests").option("-m, --metadata <json>", "Additional metadata as JSON").option("-j, --json", "Output raw JSON").action(async (content, option) => {
517
+ const metadata = option.metadata ? JSON.parse(option.metadata) : {};
518
+ if (option.category) {
519
+ if (!CATEGORIES.includes(option.category)) {
520
+ console.error(`Error: --category must be one of: ${CATEGORIES.join(", ")}`);
521
+ process.exit(1);
522
+ }
523
+ metadata.category = option.category;
524
+ }
525
+ const body = {
526
+ type: "identity",
527
+ content,
528
+ metadata: Object.keys(metadata).length > 0 ? metadata : void 0
529
+ };
530
+ if (option.title) body.title = option.title;
531
+ const result = await apiRequest("memory", "POST", body);
532
+ if (option.json) {
533
+ console.log(JSON.stringify(result, null, 2));
534
+ return;
535
+ }
536
+ console.log(`Identity added: ${result.title || result.content?.slice(0, 60) || result.id}`);
537
+ });
538
+ identity.command("get").description("Get an identity entry by ID").argument("<id>", "Identity entry ID").option("-j, --json", "Output raw JSON").action(async (id, option) => {
539
+ const data = await apiRequest(`memory/${id}`, "GET");
540
+ if (option.json) {
541
+ console.log(JSON.stringify(data, null, 2));
542
+ return;
543
+ }
544
+ const category = data.metadata?.category || "uncategorized";
545
+ console.log(`ID: ${data.id}`);
546
+ console.log(`Category: ${category}`);
547
+ console.log(`Title: ${data.title || "(none)"}`);
548
+ console.log(`Content: ${data.content}`);
549
+ if (data.metadata) console.log(`Metadata: ${JSON.stringify(data.metadata)}`);
550
+ console.log(`Created: ${data.createdAt}`);
551
+ if (data.updatedAt) console.log(`Updated: ${data.updatedAt}`);
552
+ });
553
+ identity.command("update").description("Update an identity entry").argument("<id>", "Identity entry ID").option("-t, --title <string>", "New title").option("-c, --content <string>", "New content").option("--category <category>", "Change category (core, goals, preferences, interests)").option("-m, --metadata <json>", "New metadata as JSON").option("-j, --json", "Output raw JSON").action(async (id, option) => {
554
+ const body = {};
555
+ if (option.title) body.title = option.title;
556
+ if (option.content) body.content = option.content;
557
+ if (option.category || option.metadata) {
558
+ const metadata = option.metadata ? JSON.parse(option.metadata) : {};
559
+ if (option.category) {
560
+ if (!CATEGORIES.includes(option.category)) {
561
+ console.error(`Error: --category must be one of: ${CATEGORIES.join(", ")}`);
562
+ process.exit(1);
563
+ }
564
+ metadata.category = option.category;
565
+ }
566
+ body.metadata = metadata;
567
+ }
568
+ if (Object.keys(body).length === 0) {
569
+ console.error("Error: provide at least one field to update (--title, --content, --category, --metadata)");
570
+ process.exit(1);
571
+ }
572
+ const result = await apiRequest(`memory/${id}`, "PATCH", body);
573
+ if (option.json) {
574
+ console.log(JSON.stringify(result, null, 2));
575
+ return;
576
+ }
577
+ console.log(`Identity updated: ${result.title || result.id}`);
578
+ });
579
+ identity.command("delete").description("Delete an identity entry").argument("<id>", "Identity entry ID").option("-j, --json", "Output raw JSON").action(async (id, option) => {
580
+ const result = await apiRequest(`memory/${id}`, "DELETE");
581
+ if (option.json) {
582
+ console.log(JSON.stringify(result, null, 2));
583
+ return;
584
+ }
585
+ console.log("Identity entry deleted.");
586
+ });
587
+ };
588
+
344
589
  // src/lib/update-notifier.ts
345
590
  var NPM_REGISTRY_URL2 = "https://registry.npmjs.org/@supacortex/cli/latest";
346
591
  var CHECK_INTERVAL = 24 * 60 * 60 * 1e3;
@@ -391,6 +636,8 @@ registerWhoamiCommand(program);
391
636
  registerBookmarksCommand(program);
392
637
  registerGroupsCommand(program);
393
638
  registerSyncCommand(program);
639
+ registerConversationCommand(program);
640
+ registerIdentityCommand(program);
394
641
  registerUpdateCommand(program, pkg.version);
395
642
  checkForUpdates(pkg.version);
396
643
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacortex/cli",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "Supacortex CLI — your second brain from the terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,7 +21,7 @@
21
21
  ],
22
22
  "repository": {
23
23
  "type": "git",
24
- "url": "https://github.com/monorepo-labs/supacortex"
24
+ "url": "git+https://github.com/monorepo-labs/supacortex.git"
25
25
  },
26
26
  "license": "MIT",
27
27
  "dependencies": {