@sage-protocol/cli 0.4.0 → 0.4.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/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/prompts.js +242 -87
- 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 +759 -156
- 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/artifact-manager.js +198 -0
- package/dist/cli/services/doctor/fixers.js +1 -1
- package/dist/cli/services/mcp/env-loader.js +2 -0
- package/dist/cli/services/mcp/prompt-result-formatter.js +8 -1
- package/dist/cli/services/mcp/quick-start.js +14 -15
- package/dist/cli/services/mcp/sage-tool-registry.js +322 -0
- package/dist/cli/services/mcp/tool-args-validator.js +43 -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/services/project-context.js +98 -0
- package/dist/cli/subdao.js +0 -3
- package/dist/cli/sxxx-manager.js +0 -1
- package/dist/cli/utils/aliases.js +0 -6
- 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
- package/dist/cli/commands/prompt-test.js +0 -176
- package/dist/cli/commands/prompt.js +0 -2531
|
@@ -136,98 +136,222 @@ async function importOnchainPrompt(nameOrKey, opts) {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
roots.push(path.join(cwd, '.claude', 'skills'));
|
|
153
|
-
if (home) {
|
|
154
|
-
roots.push(path.join(home, '.agent', 'skills'));
|
|
155
|
-
roots.push(path.join(home, '.claude', 'skills'));
|
|
156
|
-
}
|
|
157
|
-
for (const root of roots) {
|
|
158
|
-
candidates.push(path.join(root, name));
|
|
159
|
-
}
|
|
139
|
+
|
|
140
|
+
// --- Unified Artifact Commands ---
|
|
141
|
+
|
|
142
|
+
async function createArtifact(opts) {
|
|
143
|
+
const ArtifactManager = require('../services/artifact-manager');
|
|
144
|
+
const manager = new ArtifactManager();
|
|
145
|
+
await manager.initialize();
|
|
146
|
+
|
|
147
|
+
const kind = opts.kind || 'prompt';
|
|
148
|
+
const name = opts.name;
|
|
149
|
+
if (!name) {
|
|
150
|
+
console.error('❌ Name is required');
|
|
151
|
+
process.exit(1);
|
|
160
152
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
153
|
+
|
|
154
|
+
const targets = opts.targets ? opts.targets.split(',') : [];
|
|
155
|
+
|
|
156
|
+
const artifact = await manager.saveArtifact({
|
|
157
|
+
key: name,
|
|
158
|
+
kind,
|
|
159
|
+
body: opts.content || `You are a ${kind}...`,
|
|
160
|
+
meta: {
|
|
161
|
+
description: opts.description || '',
|
|
162
|
+
tags: opts.tags ? opts.tags.split(',') : []
|
|
163
|
+
},
|
|
164
|
+
targets
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
console.log(`✅ Created ${kind}: ${artifact.key}`);
|
|
168
|
+
console.log(` Path: ${artifact.filePath}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function listArtifacts(opts) {
|
|
172
|
+
const ArtifactManager = require('../services/artifact-manager');
|
|
173
|
+
const manager = new ArtifactManager();
|
|
174
|
+
await manager.initialize();
|
|
175
|
+
|
|
176
|
+
const filter = {};
|
|
177
|
+
if (opts.kind) filter.kind = opts.kind;
|
|
178
|
+
if (opts.scope) filter.scope = opts.scope;
|
|
179
|
+
|
|
180
|
+
const artifacts = await manager.listArtifacts(filter);
|
|
181
|
+
|
|
182
|
+
if (opts.json) {
|
|
183
|
+
console.log(JSON.stringify(artifacts, null, 2));
|
|
184
|
+
return;
|
|
169
185
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
186
|
+
|
|
187
|
+
console.log(`Found ${artifacts.length} artifacts:`);
|
|
188
|
+
const grouped = {};
|
|
189
|
+
artifacts.forEach(a => {
|
|
190
|
+
if (!grouped[a.kind]) grouped[a.kind] = [];
|
|
191
|
+
grouped[a.kind].push(a);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
Object.keys(grouped).forEach(kind => {
|
|
195
|
+
console.log(`\n${kind.toUpperCase()}:`);
|
|
196
|
+
grouped[kind].forEach(a => {
|
|
197
|
+
console.log(` - ${a.key} [${a.scope}] ${a.targets.length ? `(targets: ${a.targets.join(',')})` : ''}`);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async function exportArtifacts(opts) {
|
|
203
|
+
const ArtifactManager = require('../services/artifact-manager');
|
|
204
|
+
const manager = new ArtifactManager();
|
|
205
|
+
await manager.initialize();
|
|
206
|
+
|
|
207
|
+
const target = opts.target;
|
|
208
|
+
if (!target) {
|
|
209
|
+
console.error('❌ Target is required (cursor, claude)');
|
|
177
210
|
process.exit(1);
|
|
178
211
|
}
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const header = raw.slice(3, end).split(/\r?\n/);
|
|
187
|
-
header.forEach((line) => {
|
|
188
|
-
const m = line.match(/^(\w+)\s*:\s*(.+)$/);
|
|
189
|
-
if (m) {
|
|
190
|
-
const key = m[1].trim();
|
|
191
|
-
const value = m[2].trim();
|
|
192
|
-
frontmatter[key] = value;
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
body = raw.slice(end + 4);
|
|
196
|
-
}
|
|
212
|
+
|
|
213
|
+
const artifacts = await manager.listArtifacts();
|
|
214
|
+
const relevant = artifacts.filter(a => a.targets.includes(target) || (a.meta && a.meta.targets && a.meta.targets.includes(target)));
|
|
215
|
+
|
|
216
|
+
if (relevant.length === 0) {
|
|
217
|
+
console.log(`No artifacts found for target: ${target}`);
|
|
218
|
+
return;
|
|
197
219
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
220
|
+
|
|
221
|
+
console.log(`Exporting ${relevant.length} artifacts to ${target}...`);
|
|
222
|
+
|
|
223
|
+
if (target === 'cursor') {
|
|
224
|
+
const cursorDir = path.join(process.cwd(), '.cursor', 'rules');
|
|
225
|
+
if (!fs.existsSync(cursorDir)) fs.mkdirSync(cursorDir, { recursive: true });
|
|
226
|
+
|
|
227
|
+
for (const a of relevant) {
|
|
228
|
+
const filename = `${a.key.replace(/\//g, '-')}.mdc`;
|
|
229
|
+
const content = `---\ndescription: ${a.meta.description || a.key}\nglobs: ${a.meta.globs || '*'}\n---\n\n${a.body}`;
|
|
230
|
+
fs.writeFileSync(path.join(cursorDir, filename), content);
|
|
231
|
+
console.log(` - Wrote ${filename}`);
|
|
232
|
+
}
|
|
233
|
+
} else if (target === 'claude') {
|
|
234
|
+
const claudeFile = path.join(process.cwd(), 'CLAUDE.md');
|
|
235
|
+
let content = fs.existsSync(claudeFile) ? fs.readFileSync(claudeFile, 'utf8') : '';
|
|
236
|
+
|
|
237
|
+
// Simple append for now, ideally we use markers
|
|
238
|
+
const markerStart = '<!-- SAGE_START -->';
|
|
239
|
+
const markerEnd = '<!-- SAGE_END -->';
|
|
240
|
+
|
|
241
|
+
let newSection = `${markerStart}\n\n`;
|
|
242
|
+
for (const a of relevant) {
|
|
243
|
+
newSection += `## ${a.key}\n${a.body}\n\n`;
|
|
244
|
+
}
|
|
245
|
+
newSection += `${markerEnd}`;
|
|
246
|
+
|
|
247
|
+
if (content.includes(markerStart)) {
|
|
248
|
+
const regex = new RegExp(`${markerStart}[\\s\\S]*?${markerEnd}`);
|
|
249
|
+
content = content.replace(regex, newSection);
|
|
250
|
+
} else {
|
|
251
|
+
content += `\n\n${newSection}`;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
fs.writeFileSync(claudeFile, content);
|
|
255
|
+
console.log(` - Updated CLAUDE.md`);
|
|
225
256
|
}
|
|
226
257
|
}
|
|
227
258
|
|
|
228
259
|
function register(program) {
|
|
229
260
|
const cmd = new Command('prompts').description('Prompt-first workspace commands');
|
|
230
261
|
|
|
262
|
+
cmd
|
|
263
|
+
.command('new')
|
|
264
|
+
.description('Create a new artifact (prompt, snippet, skill)')
|
|
265
|
+
.option('--kind <kind>', 'Artifact kind (prompt, snippet, skill)', 'prompt')
|
|
266
|
+
.option('--name <name>', 'Artifact name/key (required)')
|
|
267
|
+
.option('--content <content>', 'Initial content')
|
|
268
|
+
.option('--description <desc>', 'Description')
|
|
269
|
+
.option('--tags <tags>', 'Comma-separated tags')
|
|
270
|
+
.option('--targets <targets>', 'Export targets (cursor, claude)')
|
|
271
|
+
.option('--publishable', 'Mark as publishable (default: true for prompts, false for others)')
|
|
272
|
+
.option('--no-publishable', 'Mark as not publishable')
|
|
273
|
+
.action(async (opts) => {
|
|
274
|
+
// Handle publishable flag: if --publishable is set, true. If --no-publishable, false.
|
|
275
|
+
// If neither, undefined (let ArtifactManager decide based on kind).
|
|
276
|
+
let publishable = undefined;
|
|
277
|
+
if (opts.publishable === true) publishable = true;
|
|
278
|
+
if (opts.publishable === false) publishable = false; // commander handles --no-X as false
|
|
279
|
+
|
|
280
|
+
const ArtifactManager = require('../services/artifact-manager');
|
|
281
|
+
const manager = new ArtifactManager();
|
|
282
|
+
await manager.initialize();
|
|
283
|
+
|
|
284
|
+
const kind = opts.kind || 'prompt';
|
|
285
|
+
const name = opts.name;
|
|
286
|
+
if (!name) {
|
|
287
|
+
console.error('❌ Name is required');
|
|
288
|
+
process.exit(1);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const targets = opts.targets ? opts.targets.split(',') : [];
|
|
292
|
+
|
|
293
|
+
const artifact = await manager.saveArtifact({
|
|
294
|
+
key: name,
|
|
295
|
+
kind,
|
|
296
|
+
body: opts.content || `You are a ${kind}...`,
|
|
297
|
+
meta: {
|
|
298
|
+
description: opts.description || '',
|
|
299
|
+
tags: opts.tags ? opts.tags.split(',') : []
|
|
300
|
+
},
|
|
301
|
+
targets,
|
|
302
|
+
publishable
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
console.log(`✅ Created ${kind}: ${artifact.key}`);
|
|
306
|
+
console.log(` Path: ${artifact.filePath}`);
|
|
307
|
+
console.log(` Publishable: ${artifact.publishable}`);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
cmd
|
|
311
|
+
.command('list')
|
|
312
|
+
.description('List all artifacts in the project')
|
|
313
|
+
.option('--kind <kind>', 'Filter by kind')
|
|
314
|
+
.option('--publishable', 'Filter by publishable status')
|
|
315
|
+
.option('--no-publishable', 'Filter by non-publishable status')
|
|
316
|
+
.option('--json', 'Output JSON')
|
|
317
|
+
.action(async (opts) => {
|
|
318
|
+
const ArtifactManager = require('../services/artifact-manager');
|
|
319
|
+
const manager = new ArtifactManager();
|
|
320
|
+
await manager.initialize();
|
|
321
|
+
|
|
322
|
+
const filter = {};
|
|
323
|
+
if (opts.kind) filter.kind = opts.kind;
|
|
324
|
+
if (opts.publishable === true) filter.publishable = true;
|
|
325
|
+
if (opts.publishable === false) filter.publishable = false;
|
|
326
|
+
|
|
327
|
+
const artifacts = await manager.listArtifacts(filter);
|
|
328
|
+
|
|
329
|
+
if (opts.json) {
|
|
330
|
+
console.log(JSON.stringify(artifacts, null, 2));
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
console.log(`Found ${artifacts.length} artifacts:`);
|
|
335
|
+
const grouped = {};
|
|
336
|
+
artifacts.forEach(a => {
|
|
337
|
+
if (!grouped[a.kind]) grouped[a.kind] = [];
|
|
338
|
+
grouped[a.kind].push(a);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
Object.keys(grouped).forEach(kind => {
|
|
342
|
+
console.log(`\n${kind.toUpperCase()}:`);
|
|
343
|
+
grouped[kind].forEach(a => {
|
|
344
|
+
const statusIcon = a.publishable ? '📡' : '🔒';
|
|
345
|
+
const syncStatus = a.publishing?.status === 'published' ? '✅' :
|
|
346
|
+
a.publishing?.status === 'modified' ? '📝' :
|
|
347
|
+
a.publishing?.status === 'new' ? '✨' : '❓';
|
|
348
|
+
|
|
349
|
+
console.log(` ${statusIcon} ${syncStatus} ${a.key} ${a.targets.length ? `(targets: ${a.targets.join(',')})` : ''}`);
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
console.log('\nLegend: 📡 Publishable, 🔒 Local-only | ✅ Synced, 📝 Modified, ✨ New');
|
|
353
|
+
});
|
|
354
|
+
|
|
231
355
|
cmd
|
|
232
356
|
.command('init')
|
|
233
357
|
.description('Initialize a prompt workspace (prompts/ + .sage/workspace.json)')
|
|
@@ -639,7 +763,7 @@ function register(program) {
|
|
|
639
763
|
prompts.length,
|
|
640
764
|
opts.title,
|
|
641
765
|
opts.desc || `Manifest CID: ${manifestCID}`,
|
|
642
|
-
{
|
|
766
|
+
{
|
|
643
767
|
libraryId: opts.libraryId || 'main',
|
|
644
768
|
ctx: { subdaoOpt: opts.dao || opts.subdao }
|
|
645
769
|
}
|
|
@@ -881,11 +1005,14 @@ function register(program) {
|
|
|
881
1005
|
.option('--yes', 'Skip interactive confirmations', false)
|
|
882
1006
|
.option('--json', 'Emit JSON output', false)
|
|
883
1007
|
.action(async (opts) => {
|
|
1008
|
+
// Declare ws and dest outside try block so they're accessible in catch
|
|
1009
|
+
let ws = null;
|
|
1010
|
+
let dest = null;
|
|
884
1011
|
try {
|
|
885
1012
|
const { enterJsonMode, withJsonVersion } = require('../utils/json-output');
|
|
886
1013
|
const { isTTY, isJSONMode } = require('../utils/output-mode');
|
|
887
1014
|
enterJsonMode(opts);
|
|
888
|
-
|
|
1015
|
+
ws = readWorkspace();
|
|
889
1016
|
if (!ws) throw new Error('Workspace not found. Run `sage prompts init`.');
|
|
890
1017
|
const scan = computeChangeSet(ws);
|
|
891
1018
|
const changed = [...scan.added, ...scan.modified];
|
|
@@ -895,7 +1022,30 @@ function register(program) {
|
|
|
895
1022
|
console.log(msg);
|
|
896
1023
|
return;
|
|
897
1024
|
}
|
|
898
|
-
const prompts =
|
|
1025
|
+
const prompts = [];
|
|
1026
|
+
const ArtifactManager = require('../services/artifact-manager');
|
|
1027
|
+
const am = new ArtifactManager();
|
|
1028
|
+
await am.initialize();
|
|
1029
|
+
|
|
1030
|
+
for (const key of changed) {
|
|
1031
|
+
const artifact = await am.getArtifact(key);
|
|
1032
|
+
if (artifact && artifact.publishable) {
|
|
1033
|
+
prompts.push({ key, name: key.split('/').pop(), files: [path.join(ws.promptsDir, `${key}.md`)] });
|
|
1034
|
+
} else if (artifact) {
|
|
1035
|
+
if (!opts.json) console.log(`ℹ️ Skipping non-publishable artifact: ${key}`);
|
|
1036
|
+
} else {
|
|
1037
|
+
// Fallback for non-artifact files if any (shouldn't happen with strict mode but safe to keep)
|
|
1038
|
+
prompts.push({ key, name: key.split('/').pop(), files: [path.join(ws.promptsDir, `${key}.md`)] });
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
if (!prompts.length) {
|
|
1043
|
+
const msg = 'No publishable changes detected.';
|
|
1044
|
+
if (opts.json) return console.log(JSON.stringify(withJsonVersion({ ok: false, reason: msg })));
|
|
1045
|
+
console.log(msg);
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
899
1049
|
// Workspace size warning & plan details
|
|
900
1050
|
const fs = require('fs');
|
|
901
1051
|
let totalBytes = 0;
|
|
@@ -952,7 +1102,7 @@ function register(program) {
|
|
|
952
1102
|
throw new Error(msg);
|
|
953
1103
|
}
|
|
954
1104
|
const provider = process.env.RPC_URL ? new ethers.JsonRpcProvider(process.env.RPC_URL) : null;
|
|
955
|
-
|
|
1105
|
+
dest = await deriveDestination({ provider, subdaoOpt: subdaoInput, workspaceSubdao: ws.subdao, aliasResolver: resolveAliasOrAddress });
|
|
956
1106
|
// Apply --dest override (CI-oriented)
|
|
957
1107
|
if (opts.dest) {
|
|
958
1108
|
const v = String(opts.dest).toLowerCase();
|
|
@@ -1167,8 +1317,14 @@ function register(program) {
|
|
|
1167
1317
|
}
|
|
1168
1318
|
});
|
|
1169
1319
|
|
|
1320
|
+
// --- Unified Commands ---
|
|
1321
|
+
|
|
1322
|
+
|
|
1323
|
+
|
|
1324
|
+
// --- Legacy / Specific Commands ---
|
|
1325
|
+
|
|
1170
1326
|
cmd
|
|
1171
|
-
.command('export')
|
|
1327
|
+
.command('export-legacy')
|
|
1172
1328
|
.description('Render a skill for a target environment')
|
|
1173
1329
|
.argument('<key>', 'Skill key')
|
|
1174
1330
|
.option('--as <target>', 'Target (cursor|claude|browser|json)', 'cursor')
|
|
@@ -1255,7 +1411,6 @@ function register(program) {
|
|
|
1255
1411
|
process.exit(1);
|
|
1256
1412
|
}
|
|
1257
1413
|
});
|
|
1258
|
-
|
|
1259
1414
|
program.addCommand(cmd);
|
|
1260
1415
|
}
|
|
1261
1416
|
|
|
@@ -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;
|