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