@sage-protocol/cli 0.4.1 ā 0.4.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.
- package/dist/cli/commands/prompts.js +243 -87
- package/dist/cli/commands/wallet.js +34 -15
- package/dist/cli/config.js +13 -0
- package/dist/cli/index.js +2 -2
- package/dist/cli/mcp-server-stdio.js +226 -165
- package/dist/cli/services/artifact-manager.js +198 -0
- package/dist/cli/services/mcp/prompt-result-formatter.js +9 -1
- package/dist/cli/services/mcp/sage-tool-registry.js +25 -33
- package/dist/cli/services/mcp/tool-args-validator.js +12 -0
- package/dist/cli/services/project-context.js +98 -0
- package/dist/cli/utils/aliases.js +0 -6
- package/package.json +1 -1
- package/dist/cli/commands/prompt-test.js +0 -176
- package/dist/cli/commands/prompt.js +0 -2531
|
@@ -59,6 +59,7 @@ const {
|
|
|
59
59
|
getToolMeta,
|
|
60
60
|
} = require('./services/mcp/sage-tool-registry');
|
|
61
61
|
const { createToolDispatcher } = require('./services/mcp/tool-dispatcher');
|
|
62
|
+
const ProjectContextService = require('./services/project-context');
|
|
62
63
|
const { createProposalLister } = require('./services/mcp/proposal-lister');
|
|
63
64
|
const fs = require('fs');
|
|
64
65
|
const path = require('path');
|
|
@@ -84,6 +85,18 @@ class SageMCPServer {
|
|
|
84
85
|
};
|
|
85
86
|
|
|
86
87
|
this.tools = [
|
|
88
|
+
{
|
|
89
|
+
name: 'get_project_context',
|
|
90
|
+
description: `Get context about the current Sage project (root, DAO, counts, etc).
|
|
91
|
+
When to use:
|
|
92
|
+
- At the start of a session to understand where you are
|
|
93
|
+
- Before suggesting tools to check if workspace/wallet is available`,
|
|
94
|
+
inputSchema: {
|
|
95
|
+
type: 'object',
|
|
96
|
+
properties: {},
|
|
97
|
+
required: []
|
|
98
|
+
}
|
|
99
|
+
},
|
|
87
100
|
{
|
|
88
101
|
name: 'suggest_sage_tools',
|
|
89
102
|
description: `Suggest the most relevant Sage MCP tools for a given goal.
|
|
@@ -255,7 +268,7 @@ Next steps:
|
|
|
255
268
|
properties: {
|
|
256
269
|
query: { type: 'string', description: 'Free-text search applied to names, descriptions, and tags' },
|
|
257
270
|
source: { type: 'string', enum: ['local', 'onchain', 'all'], description: 'Data source preference (default: all)' },
|
|
258
|
-
subdao: { type: 'string', description: 'Optional
|
|
271
|
+
subdao: { type: 'string', description: 'Optional DAO address when source=onchain' },
|
|
259
272
|
tags: { type: 'array', items: { type: 'string' }, description: 'Optional tag filters (matches any tag)' },
|
|
260
273
|
includeContent: { type: 'boolean', description: 'Include raw prompt content when supported (default: false)' },
|
|
261
274
|
page: { type: 'number', description: 'Results page (default: 1)' },
|
|
@@ -349,7 +362,7 @@ Next steps:
|
|
|
349
362
|
},
|
|
350
363
|
{
|
|
351
364
|
name: 'search_onchain_prompts',
|
|
352
|
-
description: 'Search for prompts directly on-chain from LibraryRegistry and
|
|
365
|
+
description: 'Search for prompts directly on-chain from LibraryRegistry and DAO registries',
|
|
353
366
|
inputSchema: {
|
|
354
367
|
type: 'object',
|
|
355
368
|
properties: {
|
|
@@ -359,7 +372,7 @@ Next steps:
|
|
|
359
372
|
},
|
|
360
373
|
subdao: {
|
|
361
374
|
type: 'string',
|
|
362
|
-
description: 'Filter by specific
|
|
375
|
+
description: 'Filter by specific DAO address (optional)'
|
|
363
376
|
},
|
|
364
377
|
tags: {
|
|
365
378
|
type: 'array',
|
|
@@ -503,13 +516,13 @@ Next steps:
|
|
|
503
516
|
},
|
|
504
517
|
{
|
|
505
518
|
name: 'list_subdaos',
|
|
506
|
-
description: 'List all available
|
|
519
|
+
description: 'List all available DAOs in the Sage Protocol',
|
|
507
520
|
inputSchema: {
|
|
508
521
|
type: 'object',
|
|
509
522
|
properties: {
|
|
510
523
|
limit: {
|
|
511
524
|
type: 'number',
|
|
512
|
-
description: 'Maximum number of
|
|
525
|
+
description: 'Maximum number of DAOs to return (default: 20)'
|
|
513
526
|
}
|
|
514
527
|
},
|
|
515
528
|
required: []
|
|
@@ -531,10 +544,10 @@ Next steps:
|
|
|
531
544
|
},
|
|
532
545
|
{
|
|
533
546
|
name: 'refresh_library_bindings',
|
|
534
|
-
description: 'Refresh cached per-library registry mappings (optional: target a specific
|
|
547
|
+
description: 'Refresh cached per-library registry mappings (optional: target a specific DAO)',
|
|
535
548
|
inputSchema: {
|
|
536
549
|
type: 'object',
|
|
537
|
-
properties: { subdao: { type: 'string', description: 'Optional
|
|
550
|
+
properties: { subdao: { type: 'string', description: 'Optional DAO address (0x...)' } },
|
|
538
551
|
required: []
|
|
539
552
|
}
|
|
540
553
|
},
|
|
@@ -558,10 +571,10 @@ Next steps:
|
|
|
558
571
|
},
|
|
559
572
|
{
|
|
560
573
|
name: 'list_subdao_libraries',
|
|
561
|
-
description: 'List per-library PromptRegistry mappings for a
|
|
574
|
+
description: 'List per-library PromptRegistry mappings for a DAO',
|
|
562
575
|
inputSchema: {
|
|
563
576
|
type: 'object',
|
|
564
|
-
properties: { subdao: { type: 'string', description: '
|
|
577
|
+
properties: { subdao: { type: 'string', description: 'DAO address (0x...)' } },
|
|
565
578
|
required: ['subdao']
|
|
566
579
|
}
|
|
567
580
|
},
|
|
@@ -589,13 +602,13 @@ Next steps:
|
|
|
589
602
|
},
|
|
590
603
|
{
|
|
591
604
|
name: 'propose_manifest',
|
|
592
|
-
description: `Generate the proposal payload and CLI commands for a
|
|
605
|
+
description: `Generate the proposal payload and CLI commands for a DAO governance update.
|
|
593
606
|
Note: This tool does NOT sign transactions. It generates the hex data and CLI commands for you to execute in your terminal.`,
|
|
594
607
|
inputSchema: {
|
|
595
608
|
type: 'object',
|
|
596
609
|
properties: {
|
|
597
610
|
cid: { type: 'string', description: 'IPFS CID of the manifest' },
|
|
598
|
-
subdao: { type: 'string', description: '
|
|
611
|
+
subdao: { type: 'string', description: 'DAO address' },
|
|
599
612
|
description: { type: 'string', description: 'Proposal description' },
|
|
600
613
|
promptCount: { type: 'number', description: 'Number of prompts (optional override)' },
|
|
601
614
|
manifest: { type: 'object', description: 'Optional manifest object for context' }
|
|
@@ -639,11 +652,11 @@ Note: This tool does NOT sign transactions. It generates the hex data and CLI co
|
|
|
639
652
|
},
|
|
640
653
|
{
|
|
641
654
|
name: 'list_proposals',
|
|
642
|
-
description: 'List active proposals for a
|
|
655
|
+
description: 'List active governance proposals for a DAO',
|
|
643
656
|
inputSchema: {
|
|
644
657
|
type: 'object',
|
|
645
658
|
properties: {
|
|
646
|
-
subdao: { type: 'string', description: '
|
|
659
|
+
subdao: { type: 'string', description: 'DAO address' },
|
|
647
660
|
state: { type: 'string', description: 'Filter by state (Active, Executed, etc)' },
|
|
648
661
|
limit: { type: 'number', description: 'Max items (default 10)' }
|
|
649
662
|
},
|
|
@@ -662,7 +675,7 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
662
675
|
type: 'object',
|
|
663
676
|
properties: {
|
|
664
677
|
manifest: { type: 'object', description: 'Manifest JSON' },
|
|
665
|
-
subdao: { type: 'string', description: 'Optional
|
|
678
|
+
subdao: { type: 'string', description: 'Optional DAO address for hints' },
|
|
666
679
|
description: { type: 'string', description: 'Optional description override' },
|
|
667
680
|
dry_run: { type: 'boolean', description: 'Validate and build proposal payload without uploading to IPFS (no network calls)' }
|
|
668
681
|
},
|
|
@@ -813,7 +826,7 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
813
826
|
},
|
|
814
827
|
{
|
|
815
828
|
name: 'suggest_subdaos_for_library',
|
|
816
|
-
description: 'Suggest
|
|
829
|
+
description: 'Suggest DAOs that might be a good fit for publishing a given local library, and provide CLI workflows for creating your own DAO and pushing the library.',
|
|
817
830
|
inputSchema: {
|
|
818
831
|
type: 'object',
|
|
819
832
|
properties: {
|
|
@@ -823,7 +836,7 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
823
836
|
},
|
|
824
837
|
limit: {
|
|
825
838
|
type: 'number',
|
|
826
|
-
description: 'Max
|
|
839
|
+
description: 'Max DAOs to return (default 5)',
|
|
827
840
|
default: 5
|
|
828
841
|
},
|
|
829
842
|
mode_filter: {
|
|
@@ -848,36 +861,15 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
848
861
|
},
|
|
849
862
|
target: {
|
|
850
863
|
type: 'string',
|
|
851
|
-
description: 'Target
|
|
864
|
+
description: 'Target DAO address or "auto" to pick a likely candidate',
|
|
852
865
|
default: 'auto'
|
|
853
866
|
}
|
|
854
867
|
},
|
|
855
868
|
required: ['library']
|
|
856
869
|
}
|
|
857
870
|
},
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
description: 'List local workspace skills from prompts/ (e.g. prompts/skills/*.md)',
|
|
861
|
-
inputSchema: {
|
|
862
|
-
type: 'object',
|
|
863
|
-
properties: {},
|
|
864
|
-
required: []
|
|
865
|
-
}
|
|
866
|
-
},
|
|
867
|
-
{
|
|
868
|
-
name: 'get_workspace_skill',
|
|
869
|
-
description: 'Load a workspace skill by key and return its content',
|
|
870
|
-
inputSchema: {
|
|
871
|
-
type: 'object',
|
|
872
|
-
properties: {
|
|
873
|
-
key: {
|
|
874
|
-
type: 'string',
|
|
875
|
-
description: 'Skill key relative to prompts dir (e.g. skills/backend-dev-guidelines)'
|
|
876
|
-
}
|
|
877
|
-
},
|
|
878
|
-
required: ['key']
|
|
879
|
-
}
|
|
880
|
-
}
|
|
871
|
+
// NOTE: list_workspace_skills and get_workspace_skill have been removed.
|
|
872
|
+
// Use list_prompts({ kind: 'skill' }) and get_prompt({ key }) instead.
|
|
881
873
|
];
|
|
882
874
|
|
|
883
875
|
// Structured logger to stderr (stdout must remain JSON-RPC only)
|
|
@@ -905,12 +897,19 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
905
897
|
'function getLibraryRegistry(string) view returns (address)'
|
|
906
898
|
];
|
|
907
899
|
|
|
908
|
-
// Prefer subgraph endpoint from
|
|
909
|
-
|
|
900
|
+
// Prefer subgraph endpoint from config (includes default Goldsky endpoint)
|
|
901
|
+
const config = require('./config');
|
|
902
|
+
this.subgraphUrl = config.resolveSubgraphUrl ? config.resolveSubgraphUrl() : (
|
|
903
|
+
process.env.SUBGRAPH_URL || process.env.NEXT_PUBLIC_GRAPH_ENDPOINT || process.env.NEXT_PUBLIC_SUBGRAPH_URL ||
|
|
904
|
+
'https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.2/gn'
|
|
905
|
+
);
|
|
910
906
|
|
|
911
907
|
// Local library helper for unified search
|
|
912
908
|
this.libraryManager = new LibraryManager();
|
|
913
909
|
|
|
910
|
+
// Project context service for get_project_context tool
|
|
911
|
+
this.projectContextService = new ProjectContextService();
|
|
912
|
+
|
|
914
913
|
// Simple rate limiter (token bucket per tool)
|
|
915
914
|
this.rateConfig = { capacity: 20, refillPerSec: 0.33 }; // ~20/min
|
|
916
915
|
this.rateLimiter = createRateLimiter(this.rateConfig);
|
|
@@ -1104,8 +1103,6 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1104
1103
|
'tool:list_proposals': (params) => this.listProposals(params),
|
|
1105
1104
|
'tool:publish_manifest_flow': (params) => this.publishManifestFlow(params),
|
|
1106
1105
|
'tool:refresh_library_bindings': (params) => this.refreshLibraryBindings(params),
|
|
1107
|
-
'tool:list_workspace_skills': (params) => this.listWorkspaceSkills(params),
|
|
1108
|
-
'tool:get_workspace_skill': (params) => this.getWorkspaceSkill(params),
|
|
1109
1106
|
'tool:update_library_metadata': (params) => this.updateLibraryMetadata(params),
|
|
1110
1107
|
'tool:bulk_update_prompts': (params) => this.bulkUpdatePrompts(params),
|
|
1111
1108
|
'tool:list_templates': (params) => this.listTemplates(params),
|
|
@@ -1115,6 +1112,7 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1115
1112
|
'tool:suggest_subdaos_for_library': (params) => this.suggestSubdaosForLibrary(params),
|
|
1116
1113
|
'tool:generate_publishing_commands': (params) => this.generatePublishingCommands(params),
|
|
1117
1114
|
'tool:suggest_sage_tools': (params) => this.suggestSageTools(params),
|
|
1115
|
+
'tool:get_project_context': (params) => this.getProjectContext(params),
|
|
1118
1116
|
});
|
|
1119
1117
|
|
|
1120
1118
|
const toolHandlers = {
|
|
@@ -1282,93 +1280,9 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1282
1280
|
}
|
|
1283
1281
|
|
|
1284
1282
|
// āāāāāāāāāāāāāāāāāāāāāāāāā Workspace skills (repo-tied skills) āāāāāāāāāāāāāāāāāāāāāāāāā
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
* Convention:
|
|
1289
|
-
* - Workspace file: .sage/workspace.json (optional)
|
|
1290
|
-
* - Prompts dir: workspace.promptsDir or "prompts"
|
|
1291
|
-
* - Skill files live under promptsDir/skills/*.md
|
|
1292
|
-
*/
|
|
1293
|
-
listWorkspaceSkills() {
|
|
1294
|
-
try {
|
|
1295
|
-
const { readWorkspace, DEFAULT_DIR } = require('./services/prompts/workspace');
|
|
1296
|
-
const { findWorkspaceSkills } = require('./services/skills/discovery');
|
|
1297
|
-
const ws = readWorkspace() || {};
|
|
1298
|
-
const promptsDir = ws.promptsDir || DEFAULT_DIR || 'prompts';
|
|
1299
|
-
const results = findWorkspaceSkills({ promptsDir });
|
|
1300
|
-
if (!results.length) {
|
|
1301
|
-
return {
|
|
1302
|
-
content: [
|
|
1303
|
-
{
|
|
1304
|
-
type: 'text',
|
|
1305
|
-
text: 'No skills found. Create prompts/skills/<name>.md or prompts/skills/<name>/SKILL.md to define skills for this repo.',
|
|
1306
|
-
},
|
|
1307
|
-
{ type: 'text', text: '```json\n' + JSON.stringify({ skills: [] }, null, 2) + '\n```' },
|
|
1308
|
-
],
|
|
1309
|
-
};
|
|
1310
|
-
}
|
|
1311
|
-
const textLines = results
|
|
1312
|
-
.map(
|
|
1313
|
-
(s, idx) =>
|
|
1314
|
-
`${idx + 1}. **${s.name}** (${s.key})\n š ${path.relative(process.cwd(), s.path)}${s.summary ? `\n š ${s.summary}` : ''
|
|
1315
|
-
}${s.tags && s.tags.length ? `\n š ${s.tags.join(', ')}` : ''}`,
|
|
1316
|
-
)
|
|
1317
|
-
.join('\n\n');
|
|
1318
|
-
return {
|
|
1319
|
-
content: [
|
|
1320
|
-
{ type: 'text', text: `Workspace skills (${results.length})\n\n${textLines}` },
|
|
1321
|
-
{ type: 'text', text: '```json\n' + JSON.stringify({ skills: results }, null, 2) + '\n```' },
|
|
1322
|
-
],
|
|
1323
|
-
};
|
|
1324
|
-
} catch (error) {
|
|
1325
|
-
return {
|
|
1326
|
-
content: [{ type: 'text', text: `Error listing workspace skills: ${error.message}` }],
|
|
1327
|
-
};
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
/**
|
|
1332
|
-
* Load a workspace skill by key and return its content.
|
|
1333
|
-
* Key is relative to prompts dir, e.g. "skills/backend-dev-guidelines".
|
|
1334
|
-
*/
|
|
1335
|
-
getWorkspaceSkill({ key }) {
|
|
1336
|
-
try {
|
|
1337
|
-
if (!key || !String(key).trim()) {
|
|
1338
|
-
return { content: [{ type: 'text', text: 'get_workspace_skill: key is required' }] };
|
|
1339
|
-
}
|
|
1340
|
-
const { readWorkspace, DEFAULT_DIR } = require('./services/prompts/workspace');
|
|
1341
|
-
const { resolveSkillFileByKey } = require('./services/skills/discovery');
|
|
1342
|
-
const ws = readWorkspace() || {};
|
|
1343
|
-
const promptsDir = ws.promptsDir || DEFAULT_DIR || 'prompts';
|
|
1344
|
-
const safeKey = String(key).trim().replace(/^\/+/, '').replace(/\.md$/i, '');
|
|
1345
|
-
const resolved = resolveSkillFileByKey({ promptsDir, key: safeKey });
|
|
1346
|
-
if (!resolved || !fs.existsSync(resolved.path)) {
|
|
1347
|
-
const expectedFlat = path.join(process.cwd(), promptsDir, `${safeKey}.md`);
|
|
1348
|
-
const expectedDir = path.join(process.cwd(), promptsDir, safeKey, 'SKILL.md');
|
|
1349
|
-
return {
|
|
1350
|
-
content: [
|
|
1351
|
-
{
|
|
1352
|
-
type: 'text',
|
|
1353
|
-
text: `Workspace skill not found for key '${safeKey}'. Expected at ${path.relative(process.cwd(), expectedFlat)} or ${path.relative(process.cwd(), expectedDir)}`,
|
|
1354
|
-
},
|
|
1355
|
-
],
|
|
1356
|
-
};
|
|
1357
|
-
}
|
|
1358
|
-
const body = fs.readFileSync(resolved.path, 'utf8');
|
|
1359
|
-
return {
|
|
1360
|
-
content: [
|
|
1361
|
-
{
|
|
1362
|
-
type: 'text',
|
|
1363
|
-
text: `Loaded workspace skill '${safeKey}' from ${path.relative(process.cwd(), resolved.path)}.\n\n${body}`,
|
|
1364
|
-
},
|
|
1365
|
-
{ type: 'text', text: '```json\n' + JSON.stringify({ key: safeKey, path: resolved.path, baseDir: resolved.baseDir, body }, null, 2) + '\n```' },
|
|
1366
|
-
],
|
|
1367
|
-
};
|
|
1368
|
-
} catch (error) {
|
|
1369
|
-
return { content: [{ type: 'text', text: `Error loading workspace skill: ${error.message}` }] };
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1283
|
+
// NOTE: listWorkspaceSkills and getWorkspaceSkill have been removed.
|
|
1284
|
+
// Use list_prompts({ kind: 'skill' }) and get_prompt({ key }) instead.
|
|
1285
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
1372
1286
|
|
|
1373
1287
|
async getPromptByName(params = {}) {
|
|
1374
1288
|
const name = String(params.name || '').trim();
|
|
@@ -1461,38 +1375,88 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1461
1375
|
return this.searchPromptsUnifiedHandler(options);
|
|
1462
1376
|
}
|
|
1463
1377
|
|
|
1464
|
-
async listPrompts({ source = 'local', library = '', limit = 20 } = {}) {
|
|
1378
|
+
async listPrompts({ source = 'local', library = '', limit = 20, kind, publishable } = {}) {
|
|
1465
1379
|
try {
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1380
|
+
// If source is 'workspace' or we want to include workspace artifacts, use ArtifactManager
|
|
1381
|
+
const includeWorkspace = source === 'local' || source === 'workspace' || source === 'all';
|
|
1382
|
+
|
|
1383
|
+
let workspaceResults = [];
|
|
1384
|
+
if (includeWorkspace) {
|
|
1385
|
+
const ArtifactManager = require('./services/artifact-manager');
|
|
1386
|
+
const artifactManager = new ArtifactManager();
|
|
1387
|
+
const filter = {};
|
|
1388
|
+
if (kind) filter.kind = kind;
|
|
1389
|
+
if (publishable !== undefined) filter.publishable = publishable;
|
|
1390
|
+
|
|
1391
|
+
const artifacts = await artifactManager.listArtifacts(filter);
|
|
1392
|
+
workspaceResults = artifacts.map(a => ({
|
|
1393
|
+
resultType: 'prompt',
|
|
1394
|
+
origin: 'workspace',
|
|
1395
|
+
source: 'Workspace',
|
|
1396
|
+
key: a.key,
|
|
1397
|
+
name: a.meta?.title || a.key,
|
|
1398
|
+
description: a.meta?.summary || '',
|
|
1399
|
+
tags: a.meta?.tags || [],
|
|
1400
|
+
content: a.body,
|
|
1401
|
+
kind: a.kind,
|
|
1402
|
+
publishable: a.publishable,
|
|
1403
|
+
publishing: a.publishing,
|
|
1404
|
+
targets: a.targets,
|
|
1405
|
+
tools: a.meta?.tools || [],
|
|
1406
|
+
filePath: a.filePath,
|
|
1407
|
+
}));
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
// Also get library prompts if not workspace-only
|
|
1411
|
+
let libraryResults = [];
|
|
1412
|
+
if (source !== 'workspace') {
|
|
1413
|
+
const results = await this.searchPromptsUnifiedHandler({
|
|
1414
|
+
query: '',
|
|
1415
|
+
source: source === 'workspace' ? 'local' : source,
|
|
1416
|
+
includeContent: false,
|
|
1417
|
+
page: 1,
|
|
1418
|
+
pageSize: limit
|
|
1419
|
+
});
|
|
1484
1420
|
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1421
|
+
if (results?.content?.[1]?.text) {
|
|
1422
|
+
const jsonMatch = results.content[1].text.match(/```json\n([\s\S]+)\n```/);
|
|
1423
|
+
if (jsonMatch) {
|
|
1424
|
+
const data = JSON.parse(jsonMatch[1]);
|
|
1425
|
+
libraryResults = (data.results || []).map(r => ({
|
|
1426
|
+
...r,
|
|
1427
|
+
kind: r.kind || 'prompt',
|
|
1428
|
+
publishable: true, // library prompts are published
|
|
1429
|
+
publishing: { status: 'published' }
|
|
1430
|
+
}));
|
|
1431
|
+
}
|
|
1492
1432
|
}
|
|
1493
1433
|
}
|
|
1494
1434
|
|
|
1495
|
-
|
|
1435
|
+
// Merge and filter
|
|
1436
|
+
let allResults = [...workspaceResults, ...libraryResults];
|
|
1437
|
+
|
|
1438
|
+
// Filter by library if specified
|
|
1439
|
+
if (library) {
|
|
1440
|
+
const libraryLower = library.toLowerCase();
|
|
1441
|
+
allResults = allResults.filter(r =>
|
|
1442
|
+
r.library?.name?.toLowerCase().includes(libraryLower) ||
|
|
1443
|
+
r.library?.cid?.toLowerCase().includes(libraryLower) ||
|
|
1444
|
+
r.origin === 'workspace' // workspace prompts don't have library
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
// Apply limit
|
|
1449
|
+
allResults = allResults.slice(0, limit);
|
|
1450
|
+
|
|
1451
|
+
const data = { results: allResults, total: allResults.length, page: 1, pageSize: limit };
|
|
1452
|
+
const formatted = this.formatUnifiedResults(allResults, { total: data.total, page: 1, pageSize: limit });
|
|
1453
|
+
|
|
1454
|
+
return {
|
|
1455
|
+
content: [
|
|
1456
|
+
{ type: 'text', text: formatted },
|
|
1457
|
+
{ type: 'text', text: '```json\n' + JSON.stringify(data, null, 2) + '\n```' }
|
|
1458
|
+
]
|
|
1459
|
+
};
|
|
1496
1460
|
} catch (error) {
|
|
1497
1461
|
return { content: [{ type: 'text', text: `Error listing prompts: ${error.message}` }] };
|
|
1498
1462
|
}
|
|
@@ -1504,6 +1468,43 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1504
1468
|
return { content: [{ type: 'text', text: 'Error: key parameter is required' }] };
|
|
1505
1469
|
}
|
|
1506
1470
|
|
|
1471
|
+
// First try workspace artifacts (ArtifactManager)
|
|
1472
|
+
const ArtifactManager = require('./services/artifact-manager');
|
|
1473
|
+
const artifactManager = new ArtifactManager();
|
|
1474
|
+
const artifact = await artifactManager.getArtifact(key);
|
|
1475
|
+
|
|
1476
|
+
if (artifact) {
|
|
1477
|
+
const prompt = {
|
|
1478
|
+
resultType: 'prompt',
|
|
1479
|
+
origin: 'workspace',
|
|
1480
|
+
source: 'Workspace',
|
|
1481
|
+
key: artifact.key,
|
|
1482
|
+
name: artifact.meta?.title || artifact.key,
|
|
1483
|
+
description: artifact.meta?.summary || '',
|
|
1484
|
+
tags: artifact.meta?.tags || [],
|
|
1485
|
+
content: artifact.body,
|
|
1486
|
+
kind: artifact.kind,
|
|
1487
|
+
publishable: artifact.publishable,
|
|
1488
|
+
publishing: artifact.publishing,
|
|
1489
|
+
targets: artifact.targets,
|
|
1490
|
+
tools: artifact.meta?.tools || [],
|
|
1491
|
+
filePath: artifact.filePath,
|
|
1492
|
+
};
|
|
1493
|
+
|
|
1494
|
+
const kindBadge = prompt.kind !== 'prompt' ? ` [${prompt.kind}]` : '';
|
|
1495
|
+
const publishBadge = prompt.publishable ? '' : ' (local only)';
|
|
1496
|
+
const toolsLine = prompt.tools?.length ? `\nš ļø Tools: ${prompt.tools.join(', ')}` : '';
|
|
1497
|
+
const text = `**${prompt.name}**${kindBadge}${publishBadge}\n\nš Key: ${prompt.key}\nš Source: Workspace\nš ${prompt.description || 'No description'}\nš·ļø Tags: ${prompt.tags?.join(', ') || 'None'}${toolsLine}\nš Kind: ${prompt.kind}\nš¤ Publishable: ${prompt.publishable}\nš Status: ${prompt.publishing?.status || 'unknown'}\n\n**Content:**\n\`\`\`\n${prompt.content || '(No content)'}\n\`\`\``;
|
|
1498
|
+
|
|
1499
|
+
return {
|
|
1500
|
+
content: [
|
|
1501
|
+
{ type: 'text', text },
|
|
1502
|
+
{ type: 'text', text: '```json\n' + JSON.stringify(prompt, null, 2) + '\n```' }
|
|
1503
|
+
]
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// Fall back to library search
|
|
1507
1508
|
const results = await this.searchPromptsUnifiedHandler({
|
|
1508
1509
|
query: key,
|
|
1509
1510
|
source: 'local',
|
|
@@ -1532,7 +1533,12 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1532
1533
|
return { content: [{ type: 'text', text: `No prompt found with key "${key}"` }] };
|
|
1533
1534
|
}
|
|
1534
1535
|
|
|
1535
|
-
|
|
1536
|
+
// Add kind/publishable for library prompts
|
|
1537
|
+
prompt.kind = prompt.kind || 'prompt';
|
|
1538
|
+
prompt.publishable = true;
|
|
1539
|
+
prompt.publishing = { status: 'published' };
|
|
1540
|
+
|
|
1541
|
+
const text = `**${prompt.name}**\n\nš Key: ${prompt.key}\nš Library: ${prompt.library?.name || 'Unknown'}\nš ${prompt.description || 'No description'}\nš·ļø Tags: ${prompt.tags?.join(', ') || 'None'}\nš Kind: ${prompt.kind}\n\n**Content:**\n\`\`\`\n${prompt.content || '(No content)'}\n\`\`\``;
|
|
1536
1542
|
|
|
1537
1543
|
return {
|
|
1538
1544
|
content: [
|
|
@@ -1665,6 +1671,61 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1665
1671
|
}
|
|
1666
1672
|
}
|
|
1667
1673
|
|
|
1674
|
+
async getProjectContext(params) {
|
|
1675
|
+
try {
|
|
1676
|
+
const ctx = await this.projectContextService.getProjectContext(params || {});
|
|
1677
|
+
const lines = [];
|
|
1678
|
+
lines.push('ā
Project context');
|
|
1679
|
+
lines.push(`Project root: ${ctx.projectRoot || 'not found'}`);
|
|
1680
|
+
lines.push(`Prompts dir: ${ctx.promptsDir || 'prompts'}`);
|
|
1681
|
+
if (ctx.subdao) {
|
|
1682
|
+
lines.push(`SubDAO: ${ctx.subdao}`);
|
|
1683
|
+
}
|
|
1684
|
+
if (ctx.registry) {
|
|
1685
|
+
lines.push(`Library registry: ${ctx.registry}`);
|
|
1686
|
+
}
|
|
1687
|
+
if (ctx.network) {
|
|
1688
|
+
lines.push(`Network: ${ctx.network}`);
|
|
1689
|
+
}
|
|
1690
|
+
if (ctx.rpcUrl) {
|
|
1691
|
+
lines.push(`RPC URL: ${ctx.rpcUrl}`);
|
|
1692
|
+
}
|
|
1693
|
+
if (ctx.workspace) {
|
|
1694
|
+
lines.push(
|
|
1695
|
+
`Workspace artifacts: prompts=${ctx.workspace.promptCount}, skills=${ctx.workspace.skillCount}, snippets=${ctx.workspace.snippetCount}, total=${ctx.workspace.total}`
|
|
1696
|
+
);
|
|
1697
|
+
}
|
|
1698
|
+
if (ctx.agentSurfaces) {
|
|
1699
|
+
const surfaces = [];
|
|
1700
|
+
if (ctx.agentSurfaces.cursorRulesDir) {
|
|
1701
|
+
surfaces.push(`cursor rules at ${ctx.agentSurfaces.cursorRulesDir}`);
|
|
1702
|
+
}
|
|
1703
|
+
if (ctx.agentSurfaces.claudeManifest) {
|
|
1704
|
+
surfaces.push(`CLAUDE manifest at ${ctx.agentSurfaces.claudeManifest}`);
|
|
1705
|
+
}
|
|
1706
|
+
if (ctx.agentSurfaces.copilotPromptsDir) {
|
|
1707
|
+
surfaces.push(`Copilot prompts at ${ctx.agentSurfaces.copilotPromptsDir}`);
|
|
1708
|
+
}
|
|
1709
|
+
if (Array.isArray(ctx.agentSurfaces.agentsFiles) && ctx.agentSurfaces.agentsFiles.length) {
|
|
1710
|
+
surfaces.push(`AGENTS files: ${ctx.agentSurfaces.agentsFiles.join(', ')}`);
|
|
1711
|
+
}
|
|
1712
|
+
if (surfaces.length) {
|
|
1713
|
+
lines.push('Agent surfaces:');
|
|
1714
|
+
surfaces.forEach((s) => lines.push(`- ${s}`));
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
return {
|
|
1719
|
+
content: [
|
|
1720
|
+
{ type: 'text', text: lines.join('\n') },
|
|
1721
|
+
{ type: 'text', text: '```json\n' + JSON.stringify(ctx, null, 2) + '\n```' },
|
|
1722
|
+
],
|
|
1723
|
+
};
|
|
1724
|
+
} catch (error) {
|
|
1725
|
+
return { content: [{ type: 'text', text: `Error retrieving project context: ${error.message}` }] };
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1668
1729
|
async listTemplates(params = {}) {
|
|
1669
1730
|
try {
|
|
1670
1731
|
const result = this.templateManager.listTemplates(params || {});
|
|
@@ -3207,7 +3268,7 @@ Use \`help(topic="create")\` for more details.
|
|
|
3207
3268
|
description: t.description,
|
|
3208
3269
|
recommended_slots: t.recommended_slots?.map(s => s.label) || []
|
|
3209
3270
|
}));
|
|
3210
|
-
|
|
3271
|
+
|
|
3211
3272
|
return {
|
|
3212
3273
|
content: [
|
|
3213
3274
|
{
|
|
@@ -3234,7 +3295,7 @@ Use \`help(topic="create")\` for more details.
|
|
|
3234
3295
|
|
|
3235
3296
|
// 1. Validate Template
|
|
3236
3297
|
const templateDef = templates[template] || templates['custom'];
|
|
3237
|
-
|
|
3298
|
+
|
|
3238
3299
|
// 2. Build Prompt (One-Shot)
|
|
3239
3300
|
// Note: run_persona_interview assumes the *agent* has already done the planning/filling.
|
|
3240
3301
|
// It bypasses the SlotPlanner and just builds the artifact.
|
|
@@ -3242,7 +3303,7 @@ Use \`help(topic="create")\` for more details.
|
|
|
3242
3303
|
// We need the full slot definitions to build dynamic sections.
|
|
3243
3304
|
// Since we skipped the planner, we'll use the template's recommended slots as the definition.
|
|
3244
3305
|
const slots = templateDef.recommended_slots || [];
|
|
3245
|
-
|
|
3306
|
+
|
|
3246
3307
|
const systemPrompt = builder.buildSystemPrompt(template, slots, answers || {});
|
|
3247
3308
|
|
|
3248
3309
|
let result = {
|
|
@@ -3255,17 +3316,17 @@ Use \`help(topic="create")\` for more details.
|
|
|
3255
3316
|
if (save) {
|
|
3256
3317
|
const persistence = new MetapromptPersistence(config);
|
|
3257
3318
|
const slug = saveKey || `${template}-${Date.now().toString().slice(-6)}`;
|
|
3258
|
-
|
|
3319
|
+
|
|
3259
3320
|
// Save dummy history so the artifact exists
|
|
3260
3321
|
const historyPaths = persistence.saveMetaprompt(slug, {
|
|
3261
3322
|
templateKey: template,
|
|
3262
3323
|
transcript: [{ role: 'system', content: 'Generated via MCP run_persona_interview (one-shot).' }],
|
|
3263
3324
|
answers: answers || {}
|
|
3264
3325
|
});
|
|
3265
|
-
|
|
3326
|
+
|
|
3266
3327
|
// Save Skill
|
|
3267
3328
|
const skillPath = persistence.saveSkill(slug, systemPrompt);
|
|
3268
|
-
|
|
3329
|
+
|
|
3269
3330
|
result.slug = slug;
|
|
3270
3331
|
result.paths = {
|
|
3271
3332
|
metaprompt: historyPaths.metaprompt,
|