@sage-protocol/cli 0.4.0 → 0.4.1
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/dist/cli/browser-wallet-integration.js +0 -1
- package/dist/cli/cast-wallet-manager.js +0 -1
- package/dist/cli/commands/interview.js +149 -0
- package/dist/cli/commands/personal.js +138 -79
- package/dist/cli/commands/stake-status.js +0 -2
- package/dist/cli/config.js +28 -8
- package/dist/cli/governance-manager.js +28 -19
- package/dist/cli/index.js +32 -8
- package/dist/cli/library-manager.js +16 -6
- package/dist/cli/mcp-server-stdio.js +549 -0
- package/dist/cli/mcp-server.js +4 -30
- package/dist/cli/metamask-integration.js +0 -1
- package/dist/cli/privy-wallet-manager.js +2 -2
- package/dist/cli/prompt-manager.js +0 -1
- package/dist/cli/services/doctor/fixers.js +1 -1
- package/dist/cli/services/mcp/env-loader.js +2 -0
- package/dist/cli/services/mcp/quick-start.js +14 -15
- package/dist/cli/services/mcp/sage-tool-registry.js +330 -0
- package/dist/cli/services/mcp/tool-args-validator.js +31 -0
- package/dist/cli/services/metaprompt/anthropic-client.js +87 -0
- package/dist/cli/services/metaprompt/interview-driver.js +161 -0
- package/dist/cli/services/metaprompt/model-client.js +49 -0
- package/dist/cli/services/metaprompt/openai-client.js +67 -0
- package/dist/cli/services/metaprompt/persistence.js +86 -0
- package/dist/cli/services/metaprompt/prompt-builder.js +186 -0
- package/dist/cli/services/metaprompt/session.js +18 -80
- package/dist/cli/services/metaprompt/slot-planner.js +115 -0
- package/dist/cli/services/metaprompt/templates.json +130 -0
- package/dist/cli/subdao.js +0 -3
- package/dist/cli/sxxx-manager.js +0 -1
- package/dist/cli/utils/tx-wait.js +0 -3
- package/dist/cli/wallet-manager.js +18 -19
- package/dist/cli/walletconnect-integration.js +0 -1
- package/dist/cli/wizard-manager.js +0 -1
- package/package.json +3 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
const { Command } = require('commander');
|
|
2
|
+
const readline = require('readline');
|
|
3
|
+
const InterviewDriver = require('../services/metaprompt/interview-driver');
|
|
4
|
+
const MetapromptPersistence = require('../services/metaprompt/persistence');
|
|
5
|
+
const config = require('../config');
|
|
6
|
+
const templates = require('../services/metaprompt/templates.json');
|
|
7
|
+
|
|
8
|
+
function register(program) {
|
|
9
|
+
program
|
|
10
|
+
.command('interview')
|
|
11
|
+
.description('Create a new AI persona via an interactive interview')
|
|
12
|
+
.alias('persona')
|
|
13
|
+
.option('-t, --template <key>', 'Persona template (coding-assistant, governance-helper, research-analyst, custom)', 'custom')
|
|
14
|
+
.option('-g, --goal <description>', 'Initial goal or description to seed the interview')
|
|
15
|
+
.option('-p, --provider <name>', 'AI provider (anthropic, openai)')
|
|
16
|
+
.option('-m, --model <name>', 'Specific model name')
|
|
17
|
+
.option('-k, --api-key <key>', 'API key override')
|
|
18
|
+
.option('--save-key <name>', 'Name for the generated skill file (defaults to template name + timestamp)')
|
|
19
|
+
.option('--list-templates', 'List available persona templates and exit')
|
|
20
|
+
.action(async (options) => {
|
|
21
|
+
if (options.listTemplates) {
|
|
22
|
+
listTemplates();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
await runInterview(options);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function listTemplates() {
|
|
30
|
+
console.log('\nAvailable Persona Templates:\n');
|
|
31
|
+
for (const [key, tmpl] of Object.entries(templates)) {
|
|
32
|
+
console.log(` ${key}`);
|
|
33
|
+
console.log(` ${tmpl.description}`);
|
|
34
|
+
console.log(` Default goal: ${tmpl.default_goal}`);
|
|
35
|
+
console.log('');
|
|
36
|
+
}
|
|
37
|
+
console.log('Usage: sage interview --template <key>');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function runInterview(options) {
|
|
41
|
+
// 1. Check Config
|
|
42
|
+
const aiConfig = config.readAIConfig();
|
|
43
|
+
if (!aiConfig.anthropicApiKey && !aiConfig.openaiApiKey && !options.apiKey) {
|
|
44
|
+
console.log('⚠️ No AI keys found.');
|
|
45
|
+
console.log('Please run `sage config ai set --provider anthropic --key sk-...`');
|
|
46
|
+
console.log('Or provide --api-key and --provider flags.');
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 2. Select Template
|
|
51
|
+
let templateKey = options.template;
|
|
52
|
+
if (!templates[templateKey]) {
|
|
53
|
+
console.warn(`⚠️ Template '${templateKey}' not found. Falling back to 'custom'.`);
|
|
54
|
+
console.log('Use --list-templates to see available templates.\n');
|
|
55
|
+
templateKey = 'custom';
|
|
56
|
+
}
|
|
57
|
+
const template = templates[templateKey];
|
|
58
|
+
|
|
59
|
+
console.log(`\n🎤 Starting Interview: ${template.name}`);
|
|
60
|
+
console.log(`ℹ️ ${template.description}`);
|
|
61
|
+
if (options.goal) {
|
|
62
|
+
console.log(`📝 Initial context: "${options.goal}"`);
|
|
63
|
+
}
|
|
64
|
+
console.log('\nType /quit to abort the interview.\n');
|
|
65
|
+
|
|
66
|
+
const rl = readline.createInterface({
|
|
67
|
+
input: process.stdin,
|
|
68
|
+
output: process.stdout
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// 3. Initialize Driver with initial description from --goal
|
|
72
|
+
const driver = new InterviewDriver(config, {
|
|
73
|
+
templateKey,
|
|
74
|
+
initialDescription: options.goal || '',
|
|
75
|
+
provider: options.provider,
|
|
76
|
+
model: options.model,
|
|
77
|
+
apiKey: options.apiKey
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
console.log('🔄 Planning session...');
|
|
81
|
+
await driver.init();
|
|
82
|
+
|
|
83
|
+
// Show which slots were pre-filled from the goal
|
|
84
|
+
const preFilledCount = Object.keys(driver.answers).length;
|
|
85
|
+
if (preFilledCount > 0) {
|
|
86
|
+
console.log(`✅ Pre-filled ${preFilledCount} slot(s) from your initial context.`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 4. Interview Loop
|
|
90
|
+
while (true) {
|
|
91
|
+
const question = await driver.getNextQuestion();
|
|
92
|
+
|
|
93
|
+
if (!question) {
|
|
94
|
+
console.log('\n✅ Interview complete! Generating persona...');
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Show progress
|
|
99
|
+
const filled = Object.keys(driver.answers).length;
|
|
100
|
+
const total = driver.slots.length;
|
|
101
|
+
const progress = `[${filled}/${total}]`;
|
|
102
|
+
|
|
103
|
+
// Ask
|
|
104
|
+
const answer = await new Promise(resolve => {
|
|
105
|
+
rl.question(`\n${progress} 🤖 ${question}\n> `, resolve);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (!answer.trim()) {
|
|
109
|
+
console.log('(Skipping...)');
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (answer.trim().toLowerCase() === '/quit') {
|
|
114
|
+
console.log('⚠️ Interview aborted.');
|
|
115
|
+
rl.close();
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
await driver.processAnswer(answer);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
rl.close();
|
|
123
|
+
|
|
124
|
+
// 5. Generate and Save
|
|
125
|
+
const systemPrompt = driver.generateSystemPrompt();
|
|
126
|
+
const persistence = new MetapromptPersistence(config);
|
|
127
|
+
|
|
128
|
+
const slug = options.saveKey || `${templateKey}-${Date.now().toString().slice(-6)}`;
|
|
129
|
+
|
|
130
|
+
// Save Artifacts
|
|
131
|
+
const paths = persistence.saveMetaprompt(slug, {
|
|
132
|
+
templateKey,
|
|
133
|
+
transcript: driver.transcript,
|
|
134
|
+
answers: driver.answers
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Save Skill
|
|
138
|
+
const skillPath = persistence.saveSkill(slug, systemPrompt);
|
|
139
|
+
persistence.appendToAgentsList(slug);
|
|
140
|
+
|
|
141
|
+
console.log(`\n🎉 Persona Created: ${slug}`);
|
|
142
|
+
console.log(` 📄 Skill: ${skillPath}`);
|
|
143
|
+
console.log(` 📝 History: ${paths.metaprompt}`);
|
|
144
|
+
console.log(`\nNext Steps:`);
|
|
145
|
+
console.log(` sage prompts list-workspace-skills`);
|
|
146
|
+
console.log(` sage prompts export skills/${slug} --as cursor`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
module.exports = { register };
|
|
@@ -94,13 +94,134 @@ function resolveGateway(pref) {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
function resolveSubgraphUrl(override) {
|
|
97
|
-
return override
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
if (override) return override;
|
|
98
|
+
|
|
99
|
+
// Prefer profile-configured subgraph URLs (addresses) over raw env
|
|
100
|
+
try {
|
|
101
|
+
const profiles = ConfigManager.readProfiles();
|
|
102
|
+
const active = profiles.activeProfile || 'default';
|
|
103
|
+
const profile = profiles.profiles?.[active] || {};
|
|
104
|
+
const addresses = profile.addresses || {};
|
|
105
|
+
const fromProfile = addresses.SAGE_SUBGRAPH_URL || addresses.SUBGRAPH_URL;
|
|
106
|
+
if (fromProfile && typeof fromProfile === 'string') {
|
|
107
|
+
return fromProfile;
|
|
108
|
+
}
|
|
109
|
+
} catch (_) {
|
|
110
|
+
// fall through to env-based resolution
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
process.env.SAGE_SUBGRAPH_URL ||
|
|
115
|
+
process.env.SUBGRAPH_URL ||
|
|
116
|
+
process.env.NEXT_PUBLIC_GRAPH_ENDPOINT ||
|
|
117
|
+
process.env.NEXT_PUBLIC_SUBGRAPH_URL ||
|
|
118
|
+
null
|
|
119
|
+
);
|
|
102
120
|
}
|
|
103
121
|
|
|
122
|
+
// Centralised subgraph queries for personal marketplace flows
|
|
123
|
+
const PERSONAL_LISTINGS_QUERY = `
|
|
124
|
+
query($creator: Bytes!, $first: Int!) {
|
|
125
|
+
personalListings(
|
|
126
|
+
where: { creator: $creator, listed: true }
|
|
127
|
+
first: $first
|
|
128
|
+
orderBy: updatedAt
|
|
129
|
+
orderDirection: desc
|
|
130
|
+
) {
|
|
131
|
+
id
|
|
132
|
+
creator
|
|
133
|
+
key
|
|
134
|
+
price
|
|
135
|
+
listed
|
|
136
|
+
createdAt
|
|
137
|
+
updatedAt
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
`;
|
|
141
|
+
|
|
142
|
+
const PERSONAL_PURCHASES_QUERY = `
|
|
143
|
+
query($creator: Bytes!, $first: Int!) {
|
|
144
|
+
licensePurchases(
|
|
145
|
+
where: { creator: $creator }
|
|
146
|
+
first: $first
|
|
147
|
+
orderBy: blockTimestamp
|
|
148
|
+
orderDirection: desc
|
|
149
|
+
) {
|
|
150
|
+
key
|
|
151
|
+
price
|
|
152
|
+
receiptId
|
|
153
|
+
buyer
|
|
154
|
+
blockTimestamp
|
|
155
|
+
encryptedCid
|
|
156
|
+
metadata
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
`;
|
|
160
|
+
|
|
161
|
+
const PERSONAL_RESOURCES_BY_RECEIPT_QUERY = `
|
|
162
|
+
query($ids: [BigInt!]) {
|
|
163
|
+
personalResources(
|
|
164
|
+
where: { receiptId_in: $ids }
|
|
165
|
+
first: 200
|
|
166
|
+
orderBy: recordedAt
|
|
167
|
+
orderDirection: desc
|
|
168
|
+
) {
|
|
169
|
+
key
|
|
170
|
+
receiptId
|
|
171
|
+
encryptedCid
|
|
172
|
+
metadata
|
|
173
|
+
recordedAt
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
`;
|
|
177
|
+
|
|
178
|
+
const MY_LICENSES_QUERY = `
|
|
179
|
+
query($holder: Bytes!, $first: Int!) {
|
|
180
|
+
receiptBalances(
|
|
181
|
+
where: { holder: $holder, balance_gt: 0 }
|
|
182
|
+
first: $first
|
|
183
|
+
orderBy: updatedAt
|
|
184
|
+
orderDirection: desc
|
|
185
|
+
) {
|
|
186
|
+
receiptId
|
|
187
|
+
balance
|
|
188
|
+
updatedAt
|
|
189
|
+
}
|
|
190
|
+
licensePurchases(
|
|
191
|
+
where: { buyer: $holder }
|
|
192
|
+
first: $first
|
|
193
|
+
orderBy: blockTimestamp
|
|
194
|
+
orderDirection: desc
|
|
195
|
+
) {
|
|
196
|
+
creator
|
|
197
|
+
key
|
|
198
|
+
price
|
|
199
|
+
netToCreator
|
|
200
|
+
fee
|
|
201
|
+
receiptId
|
|
202
|
+
blockTimestamp
|
|
203
|
+
encryptedCid
|
|
204
|
+
metadata
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
`;
|
|
208
|
+
|
|
209
|
+
const PERSONAL_RESOURCES_FOR_BALANCES_QUERY = `
|
|
210
|
+
query($ids: [BigInt!]) {
|
|
211
|
+
personalResources(
|
|
212
|
+
where: { receiptId_in: $ids }
|
|
213
|
+
first: 100
|
|
214
|
+
orderBy: recordedAt
|
|
215
|
+
orderDirection: desc
|
|
216
|
+
) {
|
|
217
|
+
receiptId
|
|
218
|
+
encryptedCid
|
|
219
|
+
metadata
|
|
220
|
+
recordedAt
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
`;
|
|
224
|
+
|
|
104
225
|
async function createAction(opts) {
|
|
105
226
|
const provider = await getProvider();
|
|
106
227
|
const wallet = await getWallet(provider);
|
|
@@ -436,21 +557,8 @@ async function listAction(opts = {}) {
|
|
|
436
557
|
|
|
437
558
|
if (!explicitKeys.length && subgraphUrl) {
|
|
438
559
|
// First try to get all listings (PriceSet events)
|
|
439
|
-
const listingsQuery = `
|
|
440
|
-
query($creator: Bytes!, $first: Int!) {
|
|
441
|
-
personalListings(where: { creator: $creator, listed: true }, first: $first, orderBy: updatedAt, orderDirection: desc) {
|
|
442
|
-
id
|
|
443
|
-
creator
|
|
444
|
-
key
|
|
445
|
-
price
|
|
446
|
-
listed
|
|
447
|
-
createdAt
|
|
448
|
-
updatedAt
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
`;
|
|
452
560
|
try {
|
|
453
|
-
const listingsData = await subgraphQuery(subgraphUrl,
|
|
561
|
+
const listingsData = await subgraphQuery(subgraphUrl, PERSONAL_LISTINGS_QUERY, {
|
|
454
562
|
creator: creatorAddress.toLowerCase(),
|
|
455
563
|
first: limit,
|
|
456
564
|
});
|
|
@@ -476,21 +584,8 @@ async function listAction(opts = {}) {
|
|
|
476
584
|
}
|
|
477
585
|
|
|
478
586
|
// Also fetch purchases for additional metadata
|
|
479
|
-
const purchasesQuery = `
|
|
480
|
-
query($creator: Bytes!, $first: Int!) {
|
|
481
|
-
licensePurchases(where: { creator: $creator }, first: $first, orderBy: blockTimestamp, orderDirection: desc) {
|
|
482
|
-
key
|
|
483
|
-
price
|
|
484
|
-
receiptId
|
|
485
|
-
buyer
|
|
486
|
-
blockTimestamp
|
|
487
|
-
encryptedCid
|
|
488
|
-
metadata
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
`;
|
|
492
587
|
try {
|
|
493
|
-
const data = await subgraphQuery(subgraphUrl,
|
|
588
|
+
const data = await subgraphQuery(subgraphUrl, PERSONAL_PURCHASES_QUERY, {
|
|
494
589
|
creator: creatorAddress.toLowerCase(),
|
|
495
590
|
first: limit,
|
|
496
591
|
});
|
|
@@ -524,18 +619,7 @@ async function listAction(opts = {}) {
|
|
|
524
619
|
.filter(Boolean);
|
|
525
620
|
|
|
526
621
|
if (receiptIdsForResources.length) {
|
|
527
|
-
const
|
|
528
|
-
query($ids: [BigInt!]) {
|
|
529
|
-
personalResources(where: { receiptId_in: $ids }, first: 200, orderBy: recordedAt, orderDirection: desc) {
|
|
530
|
-
key
|
|
531
|
-
receiptId
|
|
532
|
-
encryptedCid
|
|
533
|
-
metadata
|
|
534
|
-
recordedAt
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
`;
|
|
538
|
-
const resData = await subgraphQuery(subgraphUrl, resQuery, { ids: receiptIdsForResources });
|
|
622
|
+
const resData = await subgraphQuery(subgraphUrl, PERSONAL_RESOURCES_BY_RECEIPT_QUERY, { ids: receiptIdsForResources });
|
|
539
623
|
personalResourceMap = new Map((resData?.personalResources || []).map((r) => {
|
|
540
624
|
const keyHash = String(r.key);
|
|
541
625
|
const receiptId = r.receiptId ? String(r.receiptId) : '';
|
|
@@ -640,33 +724,12 @@ async function myLicensesAction(opts = {}) {
|
|
|
640
724
|
const holderAddress = opts.holder ? getAddress(opts.holder) : getAddress(await wallet.getAddress());
|
|
641
725
|
const subgraphUrl = resolveSubgraphUrl(opts.subgraph);
|
|
642
726
|
if (!subgraphUrl) {
|
|
643
|
-
throw new Error('Subgraph URL not configured. Pass --subgraph or
|
|
727
|
+
throw new Error('Subgraph URL not configured. Pass --subgraph or configure SUBGRAPH_URL/SAGE_SUBGRAPH_URL via sage config addresses/import.');
|
|
644
728
|
}
|
|
645
729
|
|
|
646
730
|
const limit = opts.limit ? Math.max(1, parseInt(opts.limit, 10)) : DEFAULT_LIST_LIMIT;
|
|
647
731
|
|
|
648
|
-
const
|
|
649
|
-
query($holder: Bytes!, $first: Int!) {
|
|
650
|
-
receiptBalances(where: { holder: $holder, balance_gt: 0 }, first: $first, orderBy: updatedAt, orderDirection: desc) {
|
|
651
|
-
receiptId
|
|
652
|
-
balance
|
|
653
|
-
updatedAt
|
|
654
|
-
}
|
|
655
|
-
licensePurchases(where: { buyer: $holder }, first: $first, orderBy: blockTimestamp, orderDirection: desc) {
|
|
656
|
-
creator
|
|
657
|
-
key
|
|
658
|
-
price
|
|
659
|
-
netToCreator
|
|
660
|
-
fee
|
|
661
|
-
receiptId
|
|
662
|
-
blockTimestamp
|
|
663
|
-
encryptedCid
|
|
664
|
-
metadata
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
`;
|
|
668
|
-
|
|
669
|
-
const data = await subgraphQuery(subgraphUrl, document, {
|
|
732
|
+
const data = await subgraphQuery(subgraphUrl, MY_LICENSES_QUERY, {
|
|
670
733
|
holder: holderAddress.toLowerCase(),
|
|
671
734
|
first: limit,
|
|
672
735
|
});
|
|
@@ -680,16 +743,7 @@ async function myLicensesAction(opts = {}) {
|
|
|
680
743
|
|
|
681
744
|
let resourceByReceipt = new Map();
|
|
682
745
|
if (balanceIds.length) {
|
|
683
|
-
const enriched = await subgraphQuery(subgraphUrl,
|
|
684
|
-
query($ids: [BigInt!]) {
|
|
685
|
-
personalResources(where: { receiptId_in: $ids }, first: 100, orderBy: recordedAt, orderDirection: desc) {
|
|
686
|
-
receiptId
|
|
687
|
-
encryptedCid
|
|
688
|
-
metadata
|
|
689
|
-
recordedAt
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
`, { ids: balanceIds });
|
|
746
|
+
const enriched = await subgraphQuery(subgraphUrl, PERSONAL_RESOURCES_FOR_BALANCES_QUERY, { ids: balanceIds });
|
|
693
747
|
resourceByReceipt = new Map((enriched?.personalResources || []).map((res) => [String(res.receiptId), res]));
|
|
694
748
|
}
|
|
695
749
|
|
|
@@ -1216,7 +1270,12 @@ function register(program) {
|
|
|
1216
1270
|
cmd.addCommand(premium);
|
|
1217
1271
|
}
|
|
1218
1272
|
|
|
1219
|
-
module.exports = { register };
|
|
1220
1273
|
const { query: subgraphQuery } = sdk.subgraph;
|
|
1221
1274
|
|
|
1222
1275
|
const DEFAULT_LIST_LIMIT = 25;
|
|
1276
|
+
|
|
1277
|
+
module.exports = {
|
|
1278
|
+
register,
|
|
1279
|
+
// exposed for unit tests
|
|
1280
|
+
resolveSubgraphUrl,
|
|
1281
|
+
};
|
|
@@ -12,8 +12,6 @@ function register(program) {
|
|
|
12
12
|
const WalletManager = require('@sage-protocol/wallet-manager');
|
|
13
13
|
const { resolveGovContext } = require('../utils/gov-context');
|
|
14
14
|
|
|
15
|
-
// Load environment
|
|
16
|
-
require('dotenv').config();
|
|
17
15
|
const rpcUrl = process.env.RPC_URL || process.env.BASE_SEPOLIA_RPC || 'https://base-sepolia.publicnode.com';
|
|
18
16
|
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
19
17
|
|
package/dist/cli/config.js
CHANGED
|
@@ -32,6 +32,15 @@ function collectAliasKeys(key) {
|
|
|
32
32
|
return ADDRESS_ALIAS_MAP.get(upper) || [upper];
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
function isVerbose() {
|
|
36
|
+
return (
|
|
37
|
+
process.env.SAGE_VERBOSE === '1' ||
|
|
38
|
+
process.env.VERBOSE === 'true' ||
|
|
39
|
+
process.env.DEBUG === '*' ||
|
|
40
|
+
process.env.DEBUG === 'sage'
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
35
44
|
function isQuiet() {
|
|
36
45
|
return (
|
|
37
46
|
process.env.SAGE_SUPPRESS_CONFIG_LOGS === '1' ||
|
|
@@ -285,13 +294,14 @@ function createLocalConfig() {
|
|
|
285
294
|
|
|
286
295
|
loadEnv() {
|
|
287
296
|
const envPath = path.join(this.projectDir, '.env');
|
|
297
|
+
const quietJson = String(process.env.SAGE_QUIET_JSON || '').trim() === '1';
|
|
288
298
|
if (fs.existsSync(envPath)) {
|
|
289
299
|
const override = process.env.SAGE_CLI_TEST_MODE === '1' ? false : true;
|
|
290
300
|
try {
|
|
291
301
|
require('dotenv').config({ path: envPath, override, quiet: true });
|
|
292
302
|
} catch (_) {}
|
|
293
|
-
if (
|
|
294
|
-
} else if (
|
|
303
|
+
if (isVerbose() && !quietJson) console.log('📁 Loaded .env from project directory');
|
|
304
|
+
} else if (isVerbose() && !quietJson) {
|
|
295
305
|
console.log('⚠️ .env file not found in project directory');
|
|
296
306
|
}
|
|
297
307
|
|
|
@@ -327,9 +337,9 @@ function createLocalConfig() {
|
|
|
327
337
|
process.env.GITHUB_TOKEN = git.githubToken;
|
|
328
338
|
}
|
|
329
339
|
}
|
|
330
|
-
if (
|
|
340
|
+
if (isVerbose() && !quietJson) console.log(`🧭 Loaded config profile: ${active}`);
|
|
331
341
|
} catch (e) {
|
|
332
|
-
console.log('⚠️ Failed to load config profile:', e.message);
|
|
342
|
+
if (isVerbose() && !quietJson) console.log('⚠️ Failed to load config profile:', e.message);
|
|
333
343
|
}
|
|
334
344
|
return true;
|
|
335
345
|
},
|
|
@@ -524,13 +534,19 @@ function createLocalConfig() {
|
|
|
524
534
|
},
|
|
525
535
|
|
|
526
536
|
getWalletConfig() {
|
|
527
|
-
|
|
537
|
+
const verbose = process.env.SAGE_VERBOSE === '1';
|
|
538
|
+
const quietJson = String(process.env.SAGE_QUIET_JSON || '').trim() === '1';
|
|
539
|
+
if (verbose && !quietJson) {
|
|
540
|
+
console.log('🔍 getWalletConfig called');
|
|
541
|
+
}
|
|
528
542
|
try {
|
|
529
543
|
const profiles = this.readProfiles();
|
|
530
544
|
const activeProfile = profiles.activeProfile || 'default';
|
|
531
545
|
const profile = profiles.profiles?.[activeProfile];
|
|
532
546
|
const walletType = (profile?.wallet?.type || 'cast').toLowerCase();
|
|
533
|
-
|
|
547
|
+
if (verbose && !quietJson) {
|
|
548
|
+
console.log('🔍 Debug: walletType =', walletType, 'defaultAccount =', profile?.wallet?.defaultAccount);
|
|
549
|
+
}
|
|
534
550
|
const defaultAccount = profile?.wallet?.defaultAccount;
|
|
535
551
|
if (walletType === 'cast' && defaultAccount) {
|
|
536
552
|
return { type: 'cast', account: defaultAccount, castFlag: `--from ${defaultAccount}` };
|
|
@@ -547,10 +563,14 @@ function createLocalConfig() {
|
|
|
547
563
|
}
|
|
548
564
|
if (walletType === 'privy' && defaultAccount) return { type: 'privy', account: defaultAccount, castFlag: '' };
|
|
549
565
|
if (walletType === 'web3auth' && defaultAccount) return { type: 'web3auth', account: defaultAccount, castFlag: '' };
|
|
550
|
-
|
|
566
|
+
if (!quietJson) {
|
|
567
|
+
console.log('⚠️ No default account configured. Using deployment-wallet. Set with: sage wallet use <address>');
|
|
568
|
+
}
|
|
551
569
|
return { type: walletType, account: defaultAccount || 'deployment-wallet', castFlag: walletType === 'cast' ? '--account deployment-wallet' : '' };
|
|
552
570
|
} catch (e) {
|
|
553
|
-
|
|
571
|
+
if (String(process.env.SAGE_QUIET_JSON || '').trim() !== '1') {
|
|
572
|
+
console.log('⚠️ Failed to load wallet config:', e.message);
|
|
573
|
+
}
|
|
554
574
|
return { type: 'cast', account: 'deployment-wallet', castFlag: '--account deployment-wallet' };
|
|
555
575
|
}
|
|
556
576
|
},
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const { ethers } = require('ethers');
|
|
2
2
|
const { resolveArtifact } = require('./utils/artifacts');
|
|
3
|
-
try { require('dotenv').config({ quiet: true }); } catch (_) {}
|
|
4
3
|
let colors; try { colors = (require('chalk').default || require('chalk')); } catch (e) { colors = { blue: (s)=>s, green: (s)=>s, red: (s)=>s, yellow: (s)=>s, cyan: (s)=>s }; }
|
|
5
4
|
const fs = require('fs');
|
|
6
5
|
const path = require('path');
|
|
@@ -1284,6 +1283,8 @@ class GovernanceManager {
|
|
|
1284
1283
|
}
|
|
1285
1284
|
|
|
1286
1285
|
async executeProposal(id, opts = {}) {
|
|
1286
|
+
const verbose = process.env.SAGE_VERBOSE === '1';
|
|
1287
|
+
const quietJson = String(process.env.SAGE_QUIET_JSON || '').trim() === '1';
|
|
1287
1288
|
try {
|
|
1288
1289
|
const { simulate } = opts;
|
|
1289
1290
|
if (simulate) {
|
|
@@ -1352,19 +1353,23 @@ class GovernanceManager {
|
|
|
1352
1353
|
throw new Error('Cached tuple has mismatched array lengths');
|
|
1353
1354
|
}
|
|
1354
1355
|
const descriptionHash = ethers.keccak256(ethers.toUtf8Bytes(description));
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1356
|
+
if (!quietJson) {
|
|
1357
|
+
console.log('🔎 Using cached proposal tuple for execute');
|
|
1358
|
+
if (verbose) {
|
|
1359
|
+
console.log(' targets:', targets);
|
|
1360
|
+
console.log(' values:', values.map(v => v.toString()));
|
|
1361
|
+
console.log(' calldatas:', calldatas);
|
|
1362
|
+
console.log(' descriptionHash:', descriptionHash);
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1360
1365
|
// Optional: verify readiness
|
|
1361
1366
|
try {
|
|
1362
1367
|
const st = await this.governor.state(this.normalizeProposalId(proposalId));
|
|
1363
1368
|
const nm = this.getStateName(st);
|
|
1364
1369
|
let eta = 0n;
|
|
1365
1370
|
try { eta = await this.governor.proposalEta(this.normalizeProposalId(proposalId)); } catch {}
|
|
1366
|
-
if (eta && eta > 0n) console.log(`🔍 Debug: ETA=${eta.toString()}`);
|
|
1367
|
-
console.log(`🔍 Debug: Proposal state: ${nm} (${st})`);
|
|
1371
|
+
if (verbose && !quietJson && eta && eta > 0n) console.log(`🔍 Debug: ETA=${eta.toString()}`);
|
|
1372
|
+
if (verbose && !quietJson) console.log(`🔍 Debug: Proposal state: ${nm} (${st})`);
|
|
1368
1373
|
} catch {}
|
|
1369
1374
|
|
|
1370
1375
|
if (simulate) {
|
|
@@ -1447,7 +1452,9 @@ class GovernanceManager {
|
|
|
1447
1452
|
|
|
1448
1453
|
// Fallback: if no indexed events found, try broader query
|
|
1449
1454
|
if (!logs.length) {
|
|
1450
|
-
|
|
1455
|
+
if (verbose && !quietJson) {
|
|
1456
|
+
console.log('Debug - No indexed events found, trying all ProposalCreated events...');
|
|
1457
|
+
}
|
|
1451
1458
|
const allLogs = await this.provider.getLogs({
|
|
1452
1459
|
topics: [eventSig],
|
|
1453
1460
|
address: governorAddr,
|
|
@@ -1508,26 +1515,28 @@ class GovernanceManager {
|
|
|
1508
1515
|
// Compute descriptionHash exactly like the working script
|
|
1509
1516
|
const descriptionHash = ethers.keccak256(ethers.toUtf8Bytes(description));
|
|
1510
1517
|
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1518
|
+
if (verbose && !quietJson) {
|
|
1519
|
+
console.log('Governor:', governorAddr);
|
|
1520
|
+
console.log('Executing with:');
|
|
1521
|
+
console.log(' targets:', targets);
|
|
1522
|
+
console.log(' values:', values.map(v => v.toString()));
|
|
1523
|
+
console.log(' calldatas[0..]:', calldatas.length);
|
|
1524
|
+
console.log(' descriptionHash:', descriptionHash);
|
|
1525
|
+
}
|
|
1517
1526
|
|
|
1518
1527
|
// Check proposal state before executing
|
|
1519
|
-
console.log('🔍 Debug: Checking proposal state...');
|
|
1528
|
+
if (verbose && !quietJson) console.log('🔍 Debug: Checking proposal state...');
|
|
1520
1529
|
const state = await this.governor.state(this.normalizeProposalId(id));
|
|
1521
1530
|
const stateNum = Number(state);
|
|
1522
1531
|
const stateName = this.getStateName(stateNum);
|
|
1523
|
-
console.log(`🔍 Debug: Proposal state: ${stateName} (${stateNum})`);
|
|
1532
|
+
if (verbose && !quietJson) console.log(`🔍 Debug: Proposal state: ${stateName} (${stateNum})`);
|
|
1524
1533
|
|
|
1525
1534
|
if (stateNum !== 4) { // 4 = Succeeded
|
|
1526
1535
|
console.log(`⚠️ Warning: Proposal is in state ${stateName}, not Succeeded. Execution may fail.`);
|
|
1527
1536
|
}
|
|
1528
1537
|
|
|
1529
1538
|
// Execute using tuple (like the working script)
|
|
1530
|
-
console.log('🔍 Debug: Executing proposal...');
|
|
1539
|
+
if (verbose && !quietJson) console.log('🔍 Debug: Executing proposal...');
|
|
1531
1540
|
try {
|
|
1532
1541
|
const tx = await this.governor.execute(targets, values, calldatas, descriptionHash);
|
|
1533
1542
|
console.log('⏳ Waiting for transaction confirmation...');
|
|
@@ -1559,7 +1568,7 @@ class GovernanceManager {
|
|
|
1559
1568
|
|
|
1560
1569
|
// Check for LibraryUpdated events if this was a library proposal
|
|
1561
1570
|
if (this.currentSubDAO) {
|
|
1562
|
-
console.log('🔍 Debug: Checking for LibraryUpdated events...');
|
|
1571
|
+
if (verbose && !quietJson) console.log('🔍 Debug: Checking for LibraryUpdated events...');
|
|
1563
1572
|
try {
|
|
1564
1573
|
const { resolveRegistryAddress } = require('./utils/address-resolution');
|
|
1565
1574
|
const registryAddress = resolveRegistryAddress().registry;
|