@sage-protocol/cli 0.8.0 → 0.8.2
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.
- package/README.md +12 -11
- package/dist/cli/commands/dao.js +1 -1
- package/dist/cli/commands/install.js +178 -36
- package/dist/cli/commands/library.js +275 -267
- package/dist/cli/commands/personal.js +69 -2
- package/dist/cli/commands/wallet.js +5 -10
- package/dist/cli/index.js +5 -0
- package/dist/cli/privy-auth-wallet-manager.js +3 -2
- package/dist/cli/services/config/chain-defaults.js +1 -1
- package/dist/cli/services/config/manager.js +3 -0
- package/dist/cli/services/config/schema.js +1 -0
- package/dist/cli/services/ipfs/onboarding.js +11 -0
- package/dist/cli/utils/aliases.js +1 -0
- package/dist/cli/utils/cli-ui.js +1 -1
- package/dist/cli/utils/provider.js +7 -3
- package/dist/cli/wallet-manager.js +7 -12
- package/dist/prompts/e2e-test-prompt.md +22 -0
- package/dist/prompts/skills/build-web3/plugin.json +11 -0
- package/package.json +1 -1
|
@@ -490,323 +490,331 @@ QUICK START
|
|
|
490
490
|
}
|
|
491
491
|
});
|
|
492
492
|
|
|
493
|
-
// ===== Personal Library Commands (Three-Tier Model) =====
|
|
493
|
+
// ===== Personal/Vault Library Commands (Three-Tier Model) =====
|
|
494
494
|
// These use SIWE auth and the worker API at /git/personal/:libraryId/*
|
|
495
495
|
|
|
496
|
-
|
|
497
|
-
|
|
496
|
+
function buildPersonalCommands({ name, label }) {
|
|
497
|
+
const personal = new Command(name)
|
|
498
|
+
.description(`${label} library management (wallet-owned, no on-chain governance)`);
|
|
499
|
+
|
|
500
|
+
personal
|
|
501
|
+
.command('create')
|
|
502
|
+
.description(`Create a ${label.toLowerCase()} library`)
|
|
503
|
+
.requiredOption('-n, --name <name>', 'Library name')
|
|
504
|
+
.option('-d, --description <desc>', 'Library description')
|
|
505
|
+
.option('--id <libraryId>', 'Custom library ID (default: slugified name)')
|
|
506
|
+
.option('--json', 'Output JSON', false)
|
|
507
|
+
.action(async (opts) => {
|
|
508
|
+
try {
|
|
509
|
+
const { getSignerSession, getSiweAuth } = require('../utils/cli-session');
|
|
510
|
+
const baseUrl = process.env.SAGE_IPFS_WORKER_URL || 'https://api.sageprotocol.io';
|
|
498
511
|
|
|
499
|
-
|
|
500
|
-
.command('create')
|
|
501
|
-
.description('Create a personal library')
|
|
502
|
-
.requiredOption('-n, --name <name>', 'Library name')
|
|
503
|
-
.option('-d, --description <desc>', 'Library description')
|
|
504
|
-
.option('--id <libraryId>', 'Custom library ID (default: slugified name)')
|
|
505
|
-
.option('--json', 'Output JSON', false)
|
|
506
|
-
.action(async (opts) => {
|
|
507
|
-
try {
|
|
508
|
-
const { getSignerSession, getSiweAuth } = require('../utils/cli-session');
|
|
509
|
-
const baseUrl = process.env.SAGE_IPFS_WORKER_URL || 'https://api.sageprotocol.io';
|
|
512
|
+
ui.info(`Creating ${label.toLowerCase()} library...`);
|
|
510
513
|
|
|
511
|
-
|
|
514
|
+
// Get SIWE auth
|
|
515
|
+
const { signer } = await getSignerSession();
|
|
516
|
+
const walletAddress = await signer.getAddress();
|
|
517
|
+
const { signature, message, nonce } = await getSiweAuth(signer, baseUrl);
|
|
512
518
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
name: opts.name,
|
|
530
|
-
description: opts.description || '',
|
|
531
|
-
visibility: 'public',
|
|
532
|
-
}),
|
|
533
|
-
});
|
|
519
|
+
// Initialize library via worker API
|
|
520
|
+
const response = await fetch(`${baseUrl}/git/personal/libraries`, {
|
|
521
|
+
method: 'POST',
|
|
522
|
+
headers: {
|
|
523
|
+
'Content-Type': 'application/json',
|
|
524
|
+
'X-Wallet-Address': walletAddress,
|
|
525
|
+
'X-Wallet-Signature': signature,
|
|
526
|
+
'X-Wallet-Nonce': nonce,
|
|
527
|
+
'X-Wallet-Message': Buffer.from(message).toString('base64'),
|
|
528
|
+
},
|
|
529
|
+
body: JSON.stringify({
|
|
530
|
+
name: opts.name,
|
|
531
|
+
description: opts.description || '',
|
|
532
|
+
visibility: 'public',
|
|
533
|
+
}),
|
|
534
|
+
});
|
|
534
535
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
536
|
+
if (!response.ok) {
|
|
537
|
+
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
538
|
+
throw new Error(error.error || `Failed to create library: ${response.status}`);
|
|
539
|
+
}
|
|
539
540
|
|
|
540
|
-
|
|
541
|
-
|
|
541
|
+
const result = await response.json();
|
|
542
|
+
const libraryId = result.libraryId;
|
|
542
543
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
544
|
+
if (opts.json) {
|
|
545
|
+
ui.json({ ...result, owner: walletAddress });
|
|
546
|
+
} else {
|
|
547
|
+
ui.success(`${label} library created: ${libraryId}`);
|
|
548
|
+
ui.keyValue([
|
|
549
|
+
['Library ID', libraryId],
|
|
550
|
+
['Name', result.name || opts.name],
|
|
551
|
+
['Owner', walletAddress],
|
|
552
|
+
]);
|
|
553
|
+
}
|
|
553
554
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
555
|
+
} catch (e) {
|
|
556
|
+
handleCLIError('library:personal:create', e, { exit: true });
|
|
557
|
+
}
|
|
558
|
+
});
|
|
558
559
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
560
|
+
personal
|
|
561
|
+
.command('list')
|
|
562
|
+
.description(`List your ${label.toLowerCase()} libraries`)
|
|
563
|
+
.option('--json', 'Output JSON', false)
|
|
564
|
+
.action(async (opts) => {
|
|
565
|
+
try {
|
|
566
|
+
const { getSignerSession, getSiweAuth } = require('../utils/cli-session');
|
|
567
|
+
const baseUrl = process.env.SAGE_IPFS_WORKER_URL || 'https://api.sageprotocol.io';
|
|
567
568
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
const response = await fetch(`${baseUrl}/git/personal/libraries`, {
|
|
573
|
-
method: 'GET',
|
|
574
|
-
headers: {
|
|
575
|
-
'X-Wallet-Address': walletAddress,
|
|
576
|
-
'X-Wallet-Signature': signature,
|
|
577
|
-
'X-Wallet-Nonce': nonce,
|
|
578
|
-
'X-Wallet-Message': Buffer.from(message).toString('base64'),
|
|
579
|
-
},
|
|
580
|
-
});
|
|
569
|
+
const { signer } = await getSignerSession();
|
|
570
|
+
const walletAddress = await signer.getAddress();
|
|
571
|
+
const { signature, message, nonce } = await getSiweAuth(signer, baseUrl);
|
|
581
572
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
573
|
+
const response = await fetch(`${baseUrl}/git/personal/libraries`, {
|
|
574
|
+
method: 'GET',
|
|
575
|
+
headers: {
|
|
576
|
+
'X-Wallet-Address': walletAddress,
|
|
577
|
+
'X-Wallet-Signature': signature,
|
|
578
|
+
'X-Wallet-Nonce': nonce,
|
|
579
|
+
'X-Wallet-Message': Buffer.from(message).toString('base64'),
|
|
580
|
+
},
|
|
581
|
+
});
|
|
586
582
|
|
|
587
|
-
|
|
588
|
-
|
|
583
|
+
if (!response.ok) {
|
|
584
|
+
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
585
|
+
throw new Error(error.error || `Failed to list libraries: ${response.status}`);
|
|
586
|
+
}
|
|
589
587
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
588
|
+
const result = await response.json();
|
|
589
|
+
const libraries = result.libraries || [];
|
|
590
|
+
|
|
591
|
+
if (opts.json) {
|
|
592
|
+
ui.json(libraries);
|
|
593
|
+
} else if (libraries.length === 0) {
|
|
594
|
+
ui.info(`No ${label.toLowerCase()} libraries found.`);
|
|
595
|
+
ui.output(`Create one with: sage library ${name} create --name "My Library"`);
|
|
596
|
+
} else {
|
|
597
|
+
ui.header(`${label} Libraries`);
|
|
598
|
+
for (const lib of libraries) {
|
|
599
|
+
ui.output(` ${lib.libraryId}: ${lib.name || '(unnamed)'}`);
|
|
600
|
+
}
|
|
599
601
|
}
|
|
602
|
+
|
|
603
|
+
} catch (e) {
|
|
604
|
+
handleCLIError('library:personal:list', e, { exit: true });
|
|
600
605
|
}
|
|
606
|
+
});
|
|
601
607
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
}
|
|
605
|
-
|
|
608
|
+
personal
|
|
609
|
+
.command('info')
|
|
610
|
+
.description(`Show ${label.toLowerCase()} library info`)
|
|
611
|
+
.argument('<libraryId>', 'Library ID')
|
|
612
|
+
.option('--json', 'Output JSON', false)
|
|
613
|
+
.action(async (libraryId, opts) => {
|
|
614
|
+
try {
|
|
615
|
+
const { getSignerSession, getSiweAuth } = require('../utils/cli-session');
|
|
616
|
+
const baseUrl = process.env.SAGE_IPFS_WORKER_URL || 'https://api.sageprotocol.io';
|
|
606
617
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
.argument('<libraryId>', 'Library ID')
|
|
611
|
-
.option('--json', 'Output JSON', false)
|
|
612
|
-
.action(async (libraryId, opts) => {
|
|
613
|
-
try {
|
|
614
|
-
const { getSignerSession, getSiweAuth } = require('../utils/cli-session');
|
|
615
|
-
const baseUrl = process.env.SAGE_IPFS_WORKER_URL || 'https://api.sageprotocol.io';
|
|
618
|
+
const { signer } = await getSignerSession();
|
|
619
|
+
const walletAddress = await signer.getAddress();
|
|
620
|
+
const { signature, message, nonce } = await getSiweAuth(signer, baseUrl);
|
|
616
621
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
'X-Wallet-Nonce': nonce,
|
|
627
|
-
'X-Wallet-Message': Buffer.from(message).toString('base64'),
|
|
628
|
-
},
|
|
629
|
-
});
|
|
622
|
+
const response = await fetch(`${baseUrl}/git/personal/${encodeURIComponent(libraryId)}`, {
|
|
623
|
+
method: 'GET',
|
|
624
|
+
headers: {
|
|
625
|
+
'X-Wallet-Address': walletAddress,
|
|
626
|
+
'X-Wallet-Signature': signature,
|
|
627
|
+
'X-Wallet-Nonce': nonce,
|
|
628
|
+
'X-Wallet-Message': Buffer.from(message).toString('base64'),
|
|
629
|
+
},
|
|
630
|
+
});
|
|
630
631
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
632
|
+
if (!response.ok) {
|
|
633
|
+
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
634
|
+
throw new Error(error.error || `Library not found: ${response.status}`);
|
|
635
|
+
}
|
|
635
636
|
|
|
636
|
-
|
|
637
|
+
const result = await response.json();
|
|
637
638
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
639
|
+
if (opts.json) {
|
|
640
|
+
ui.json(result);
|
|
641
|
+
} else {
|
|
642
|
+
ui.header(`${label} Library: ${libraryId}`);
|
|
643
|
+
ui.keyValue([
|
|
644
|
+
['Name', result.name || '(unnamed)'],
|
|
645
|
+
['Description', result.description || '(none)'],
|
|
646
|
+
['Owner', result.owner || walletAddress],
|
|
647
|
+
['Created', result.createdAt ? new Date(result.createdAt).toISOString() : 'unknown'],
|
|
648
|
+
]);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
} catch (e) {
|
|
652
|
+
handleCLIError('library:personal:info', e, { exit: true });
|
|
648
653
|
}
|
|
654
|
+
});
|
|
649
655
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
}
|
|
653
|
-
|
|
656
|
+
personal
|
|
657
|
+
.command('push')
|
|
658
|
+
.description(`Push files to a ${label.toLowerCase()} library`)
|
|
659
|
+
.argument('<libraryId>', 'Library ID')
|
|
660
|
+
.option('--from-dir <path>', 'Directory to push (default: .)', '.')
|
|
661
|
+
.option('-m, --message <msg>', 'Commit message', 'Update library')
|
|
662
|
+
.option('--json', 'Output JSON', false)
|
|
663
|
+
.action(async (libraryId, opts) => {
|
|
664
|
+
try {
|
|
665
|
+
const { getSignerSession, getSiweAuth } = require('../utils/cli-session');
|
|
666
|
+
const IPFSManager = require('../ipfs-manager');
|
|
667
|
+
const baseUrl = process.env.SAGE_IPFS_WORKER_URL || 'https://api.sageprotocol.io';
|
|
654
668
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
.argument('<libraryId>', 'Library ID')
|
|
659
|
-
.option('--from-dir <path>', 'Directory to push (default: .)', '.')
|
|
660
|
-
.option('-m, --message <msg>', 'Commit message', 'Update library')
|
|
661
|
-
.option('--json', 'Output JSON', false)
|
|
662
|
-
.action(async (libraryId, opts) => {
|
|
663
|
-
try {
|
|
664
|
-
const { getSignerSession, getSiweAuth } = require('../utils/cli-session');
|
|
665
|
-
const IPFSManager = require('../ipfs-manager');
|
|
666
|
-
const baseUrl = process.env.SAGE_IPFS_WORKER_URL || 'https://api.sageprotocol.io';
|
|
669
|
+
const { signer } = await getSignerSession();
|
|
670
|
+
const walletAddress = await signer.getAddress();
|
|
671
|
+
const { signature, message, nonce } = await getSiweAuth(signer, baseUrl);
|
|
667
672
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
673
|
+
// Scan directory for files
|
|
674
|
+
const scanDir = path.isAbsolute(opts.fromDir)
|
|
675
|
+
? opts.fromDir
|
|
676
|
+
: path.join(process.cwd(), opts.fromDir);
|
|
671
677
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
? opts.fromDir
|
|
675
|
-
: path.join(process.cwd(), opts.fromDir);
|
|
678
|
+
ui.info(`Scanning ${scanDir}...`);
|
|
679
|
+
const files = scanDirectory(scanDir);
|
|
676
680
|
|
|
677
|
-
|
|
678
|
-
|
|
681
|
+
if (files.length === 0) {
|
|
682
|
+
ui.warn('No .md files found to push');
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
679
685
|
|
|
680
|
-
|
|
681
|
-
ui.warn('No .md files found to push');
|
|
682
|
-
return;
|
|
683
|
-
}
|
|
686
|
+
ui.success(`Found ${files.length} file(s)`);
|
|
684
687
|
|
|
685
|
-
|
|
688
|
+
// Upload files to IPFS
|
|
689
|
+
ui.info('Uploading to IPFS...');
|
|
690
|
+
const ipfs = new IPFSManager();
|
|
691
|
+
await ipfs.initialize();
|
|
686
692
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
693
|
+
for (const f of files) {
|
|
694
|
+
const content = fs.readFileSync(f.path, 'utf8');
|
|
695
|
+
f.cid = await ipfs.uploadText(content, path.basename(f.path));
|
|
696
|
+
f.files = [path.relative(scanDir, f.path)];
|
|
697
|
+
}
|
|
691
698
|
|
|
692
|
-
|
|
693
|
-
const
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
699
|
+
// Build manifest
|
|
700
|
+
const manifest = buildManifest(libraryId, '', files);
|
|
701
|
+
let manifestCID;
|
|
702
|
+
if (typeof ipfs.uploadRawJson === 'function') {
|
|
703
|
+
const result = await ipfs.uploadRawJson(manifest, { name: 'manifest.json' });
|
|
704
|
+
manifestCID = result.cid;
|
|
705
|
+
} else {
|
|
706
|
+
manifestCID = await ipfs.uploadJson(manifest, 'manifest.json');
|
|
707
|
+
}
|
|
697
708
|
|
|
698
|
-
|
|
699
|
-
const manifest = buildManifest(libraryId, '', files);
|
|
700
|
-
let manifestCID;
|
|
701
|
-
if (typeof ipfs.uploadRawJson === 'function') {
|
|
702
|
-
const result = await ipfs.uploadRawJson(manifest, { name: 'manifest.json' });
|
|
703
|
-
manifestCID = result.cid;
|
|
704
|
-
} else {
|
|
705
|
-
manifestCID = await ipfs.uploadJson(manifest, 'manifest.json');
|
|
706
|
-
}
|
|
709
|
+
ui.success(`Manifest: ${manifestCID}`);
|
|
707
710
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
'X-Wallet-Nonce': nonce,
|
|
719
|
-
'X-Wallet-Message': Buffer.from(message).toString('base64'),
|
|
720
|
-
},
|
|
721
|
-
body: JSON.stringify({
|
|
722
|
-
ref: 'refs/heads/main',
|
|
723
|
-
message: opts.message,
|
|
724
|
-
manifestCid: manifestCID,
|
|
725
|
-
author: {
|
|
726
|
-
name: walletAddress.slice(0, 10),
|
|
727
|
-
address: walletAddress,
|
|
711
|
+
// Push to library via worker API
|
|
712
|
+
ui.info('Pushing to library...');
|
|
713
|
+
const response = await fetch(`${baseUrl}/git/personal/${encodeURIComponent(libraryId)}/push`, {
|
|
714
|
+
method: 'POST',
|
|
715
|
+
headers: {
|
|
716
|
+
'Content-Type': 'application/json',
|
|
717
|
+
'X-Wallet-Address': walletAddress,
|
|
718
|
+
'X-Wallet-Signature': signature,
|
|
719
|
+
'X-Wallet-Nonce': nonce,
|
|
720
|
+
'X-Wallet-Message': Buffer.from(message).toString('base64'),
|
|
728
721
|
},
|
|
729
|
-
|
|
730
|
-
|
|
722
|
+
body: JSON.stringify({
|
|
723
|
+
ref: 'refs/heads/main',
|
|
724
|
+
message: opts.message,
|
|
725
|
+
manifestCid: manifestCID,
|
|
726
|
+
author: {
|
|
727
|
+
name: walletAddress.slice(0, 10),
|
|
728
|
+
address: walletAddress,
|
|
729
|
+
},
|
|
730
|
+
}),
|
|
731
|
+
});
|
|
731
732
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
733
|
+
if (!response.ok) {
|
|
734
|
+
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
735
|
+
throw new Error(error.error || `Push failed: ${response.status}`);
|
|
736
|
+
}
|
|
736
737
|
|
|
737
|
-
|
|
738
|
+
const result = await response.json();
|
|
738
739
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
740
|
+
if (opts.json) {
|
|
741
|
+
ui.json({ libraryId, manifestCID, ...result });
|
|
742
|
+
} else {
|
|
743
|
+
ui.success(`Pushed to ${libraryId}`);
|
|
744
|
+
ui.keyValue([
|
|
745
|
+
['Commit', result.commitHash || result.oid || 'created'],
|
|
746
|
+
['Manifest CID', manifestCID],
|
|
747
|
+
['Files', `${files.length}`],
|
|
748
|
+
]);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
} catch (e) {
|
|
752
|
+
handleCLIError('library:personal:push', e, { exit: true });
|
|
748
753
|
}
|
|
754
|
+
});
|
|
749
755
|
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
}
|
|
753
|
-
|
|
756
|
+
personal
|
|
757
|
+
.command('delete')
|
|
758
|
+
.description(`Delete a ${label.toLowerCase()} library`)
|
|
759
|
+
.argument('<libraryId>', 'Library ID')
|
|
760
|
+
.option('--json', 'Output JSON', false)
|
|
761
|
+
.option('--force', 'Skip confirmation')
|
|
762
|
+
.action(async (libraryId, opts) => {
|
|
763
|
+
try {
|
|
764
|
+
const { getSignerSession, getSiweAuth } = require('../utils/cli-session');
|
|
765
|
+
const baseUrl = process.env.SAGE_IPFS_WORKER_URL || 'https://api.sageprotocol.io';
|
|
766
|
+
|
|
767
|
+
if (!opts.force && !process.env.SAGE_FORCE) {
|
|
768
|
+
const readline = require('readline');
|
|
769
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
770
|
+
const answer = await new Promise((resolve) => {
|
|
771
|
+
rl.question(`Delete library "${libraryId}"? This cannot be undone. (y/N) `, resolve);
|
|
772
|
+
});
|
|
773
|
+
rl.close();
|
|
774
|
+
if (answer.toLowerCase() !== 'y') {
|
|
775
|
+
ui.info('Aborted.');
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
754
779
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
const readline = require('readline');
|
|
768
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
769
|
-
const answer = await new Promise((resolve) => {
|
|
770
|
-
rl.question(`Delete library "${libraryId}"? This cannot be undone. (y/N) `, resolve);
|
|
780
|
+
const { signer } = await getSignerSession();
|
|
781
|
+
const walletAddress = await signer.getAddress();
|
|
782
|
+
const { signature, message, nonce } = await getSiweAuth(signer, baseUrl);
|
|
783
|
+
|
|
784
|
+
const response = await fetch(`${baseUrl}/git/personal/${encodeURIComponent(libraryId)}`, {
|
|
785
|
+
method: 'DELETE',
|
|
786
|
+
headers: {
|
|
787
|
+
'X-Wallet-Address': walletAddress,
|
|
788
|
+
'X-Wallet-Signature': signature,
|
|
789
|
+
'X-Wallet-Nonce': nonce,
|
|
790
|
+
'X-Wallet-Message': Buffer.from(message).toString('base64'),
|
|
791
|
+
},
|
|
771
792
|
});
|
|
772
|
-
|
|
773
|
-
if (
|
|
774
|
-
|
|
775
|
-
|
|
793
|
+
|
|
794
|
+
if (!response.ok) {
|
|
795
|
+
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
796
|
+
throw new Error(error.error || `Delete failed: ${response.status}`);
|
|
776
797
|
}
|
|
777
|
-
}
|
|
778
798
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
method: 'DELETE',
|
|
785
|
-
headers: {
|
|
786
|
-
'X-Wallet-Address': walletAddress,
|
|
787
|
-
'X-Wallet-Signature': signature,
|
|
788
|
-
'X-Wallet-Nonce': nonce,
|
|
789
|
-
'X-Wallet-Message': Buffer.from(message).toString('base64'),
|
|
790
|
-
},
|
|
791
|
-
});
|
|
799
|
+
if (opts.json) {
|
|
800
|
+
ui.json({ deleted: true, libraryId });
|
|
801
|
+
} else {
|
|
802
|
+
ui.success(`Deleted library: ${libraryId}`);
|
|
803
|
+
}
|
|
792
804
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
throw new Error(error.error || `Delete failed: ${response.status}`);
|
|
805
|
+
} catch (e) {
|
|
806
|
+
handleCLIError('library:personal:delete', e, { exit: true });
|
|
796
807
|
}
|
|
808
|
+
});
|
|
797
809
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
} else {
|
|
801
|
-
ui.success(`Deleted library: ${libraryId}`);
|
|
802
|
-
}
|
|
810
|
+
return personal;
|
|
811
|
+
}
|
|
803
812
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
}
|
|
807
|
-
});
|
|
813
|
+
const personal = buildPersonalCommands({ name: 'personal', label: 'Personal' });
|
|
814
|
+
const vault = buildPersonalCommands({ name: 'vault', label: 'Vault' });
|
|
808
815
|
|
|
809
816
|
cmd.addCommand(personal);
|
|
817
|
+
cmd.addCommand(vault);
|
|
810
818
|
|
|
811
819
|
return cmd;
|
|
812
820
|
};
|