@supacortex/cli 0.1.4 → 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 +232 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -233,7 +233,6 @@ var registerBookmarksCommand = (program2) => {
233
233
  console.log(`URL: ${data.url}`);
234
234
  if (data.author) console.log(`Author: ${data.author}`);
235
235
  if (data.content) console.log(`Content: ${data.content.slice(0, 200)}${data.content.length > 200 ? "\u2026" : ""}`);
236
- console.log(`Read: ${data.isRead ? "yes" : "no"}`);
237
236
  console.log(`Created: ${data.createdAt}`);
238
237
  });
239
238
  bookmarks.command("delete").description("Delete a bookmark").argument("<id>", "Bookmark ID to delete").option("-j, --json", "Output raw JSON").action(async (id, option) => {
@@ -357,6 +356,236 @@ var registerUpdateCommand = (program2, version) => {
357
356
  });
358
357
  };
359
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
+
360
589
  // src/lib/update-notifier.ts
361
590
  var NPM_REGISTRY_URL2 = "https://registry.npmjs.org/@supacortex/cli/latest";
362
591
  var CHECK_INTERVAL = 24 * 60 * 60 * 1e3;
@@ -407,6 +636,8 @@ registerWhoamiCommand(program);
407
636
  registerBookmarksCommand(program);
408
637
  registerGroupsCommand(program);
409
638
  registerSyncCommand(program);
639
+ registerConversationCommand(program);
640
+ registerIdentityCommand(program);
410
641
  registerUpdateCommand(program, pkg.version);
411
642
  checkForUpdates(pkg.version);
412
643
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacortex/cli",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "Supacortex CLI — your second brain from the terminal",
5
5
  "type": "module",
6
6
  "bin": {