@sage-protocol/cli 0.4.1 ā 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/commands/prompts.js +242 -87
- package/dist/cli/index.js +2 -2
- package/dist/cli/mcp-server-stdio.js +217 -163
- package/dist/cli/services/artifact-manager.js +198 -0
- package/dist/cli/services/mcp/prompt-result-formatter.js +8 -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)
|
|
@@ -911,6 +903,9 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
911
903
|
// Local library helper for unified search
|
|
912
904
|
this.libraryManager = new LibraryManager();
|
|
913
905
|
|
|
906
|
+
// Project context service for get_project_context tool
|
|
907
|
+
this.projectContextService = new ProjectContextService();
|
|
908
|
+
|
|
914
909
|
// Simple rate limiter (token bucket per tool)
|
|
915
910
|
this.rateConfig = { capacity: 20, refillPerSec: 0.33 }; // ~20/min
|
|
916
911
|
this.rateLimiter = createRateLimiter(this.rateConfig);
|
|
@@ -1104,8 +1099,6 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1104
1099
|
'tool:list_proposals': (params) => this.listProposals(params),
|
|
1105
1100
|
'tool:publish_manifest_flow': (params) => this.publishManifestFlow(params),
|
|
1106
1101
|
'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
1102
|
'tool:update_library_metadata': (params) => this.updateLibraryMetadata(params),
|
|
1110
1103
|
'tool:bulk_update_prompts': (params) => this.bulkUpdatePrompts(params),
|
|
1111
1104
|
'tool:list_templates': (params) => this.listTemplates(params),
|
|
@@ -1115,6 +1108,7 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1115
1108
|
'tool:suggest_subdaos_for_library': (params) => this.suggestSubdaosForLibrary(params),
|
|
1116
1109
|
'tool:generate_publishing_commands': (params) => this.generatePublishingCommands(params),
|
|
1117
1110
|
'tool:suggest_sage_tools': (params) => this.suggestSageTools(params),
|
|
1111
|
+
'tool:get_project_context': (params) => this.getProjectContext(params),
|
|
1118
1112
|
});
|
|
1119
1113
|
|
|
1120
1114
|
const toolHandlers = {
|
|
@@ -1282,93 +1276,9 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1282
1276
|
}
|
|
1283
1277
|
|
|
1284
1278
|
// āāāāāāāāāāāāāāāāāāāāāāāāā 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
|
-
}
|
|
1279
|
+
// NOTE: listWorkspaceSkills and getWorkspaceSkill have been removed.
|
|
1280
|
+
// Use list_prompts({ kind: 'skill' }) and get_prompt({ key }) instead.
|
|
1281
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
1372
1282
|
|
|
1373
1283
|
async getPromptByName(params = {}) {
|
|
1374
1284
|
const name = String(params.name || '').trim();
|
|
@@ -1461,38 +1371,87 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1461
1371
|
return this.searchPromptsUnifiedHandler(options);
|
|
1462
1372
|
}
|
|
1463
1373
|
|
|
1464
|
-
async listPrompts({ source = 'local', library = '', limit = 20 } = {}) {
|
|
1374
|
+
async listPrompts({ source = 'local', library = '', limit = 20, kind, publishable } = {}) {
|
|
1465
1375
|
try {
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1376
|
+
// If source is 'workspace' or we want to include workspace artifacts, use ArtifactManager
|
|
1377
|
+
const includeWorkspace = source === 'local' || source === 'workspace' || source === 'all';
|
|
1378
|
+
|
|
1379
|
+
let workspaceResults = [];
|
|
1380
|
+
if (includeWorkspace) {
|
|
1381
|
+
const ArtifactManager = require('./services/artifact-manager');
|
|
1382
|
+
const artifactManager = new ArtifactManager();
|
|
1383
|
+
const filter = {};
|
|
1384
|
+
if (kind) filter.kind = kind;
|
|
1385
|
+
if (publishable !== undefined) filter.publishable = publishable;
|
|
1386
|
+
|
|
1387
|
+
const artifacts = await artifactManager.listArtifacts(filter);
|
|
1388
|
+
workspaceResults = artifacts.map(a => ({
|
|
1389
|
+
resultType: 'prompt',
|
|
1390
|
+
origin: 'workspace',
|
|
1391
|
+
source: 'Workspace',
|
|
1392
|
+
key: a.key,
|
|
1393
|
+
name: a.meta?.title || a.key,
|
|
1394
|
+
description: a.meta?.summary || '',
|
|
1395
|
+
tags: a.meta?.tags || [],
|
|
1396
|
+
content: a.body,
|
|
1397
|
+
kind: a.kind,
|
|
1398
|
+
publishable: a.publishable,
|
|
1399
|
+
publishing: a.publishing,
|
|
1400
|
+
targets: a.targets,
|
|
1401
|
+
filePath: a.filePath,
|
|
1402
|
+
}));
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
// Also get library prompts if not workspace-only
|
|
1406
|
+
let libraryResults = [];
|
|
1407
|
+
if (source !== 'workspace') {
|
|
1408
|
+
const results = await this.searchPromptsUnifiedHandler({
|
|
1409
|
+
query: '',
|
|
1410
|
+
source: source === 'workspace' ? 'local' : source,
|
|
1411
|
+
includeContent: false,
|
|
1412
|
+
page: 1,
|
|
1413
|
+
pageSize: limit
|
|
1414
|
+
});
|
|
1484
1415
|
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1416
|
+
if (results?.content?.[1]?.text) {
|
|
1417
|
+
const jsonMatch = results.content[1].text.match(/```json\n([\s\S]+)\n```/);
|
|
1418
|
+
if (jsonMatch) {
|
|
1419
|
+
const data = JSON.parse(jsonMatch[1]);
|
|
1420
|
+
libraryResults = (data.results || []).map(r => ({
|
|
1421
|
+
...r,
|
|
1422
|
+
kind: r.kind || 'prompt',
|
|
1423
|
+
publishable: true, // library prompts are published
|
|
1424
|
+
publishing: { status: 'published' }
|
|
1425
|
+
}));
|
|
1426
|
+
}
|
|
1492
1427
|
}
|
|
1493
1428
|
}
|
|
1494
1429
|
|
|
1495
|
-
|
|
1430
|
+
// Merge and filter
|
|
1431
|
+
let allResults = [...workspaceResults, ...libraryResults];
|
|
1432
|
+
|
|
1433
|
+
// Filter by library if specified
|
|
1434
|
+
if (library) {
|
|
1435
|
+
const libraryLower = library.toLowerCase();
|
|
1436
|
+
allResults = allResults.filter(r =>
|
|
1437
|
+
r.library?.name?.toLowerCase().includes(libraryLower) ||
|
|
1438
|
+
r.library?.cid?.toLowerCase().includes(libraryLower) ||
|
|
1439
|
+
r.origin === 'workspace' // workspace prompts don't have library
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
// Apply limit
|
|
1444
|
+
allResults = allResults.slice(0, limit);
|
|
1445
|
+
|
|
1446
|
+
const data = { results: allResults, total: allResults.length, page: 1, pageSize: limit };
|
|
1447
|
+
const formatted = this.formatUnifiedResults(allResults, { total: data.total, page: 1, pageSize: limit });
|
|
1448
|
+
|
|
1449
|
+
return {
|
|
1450
|
+
content: [
|
|
1451
|
+
{ type: 'text', text: formatted },
|
|
1452
|
+
{ type: 'text', text: '```json\n' + JSON.stringify(data, null, 2) + '\n```' }
|
|
1453
|
+
]
|
|
1454
|
+
};
|
|
1496
1455
|
} catch (error) {
|
|
1497
1456
|
return { content: [{ type: 'text', text: `Error listing prompts: ${error.message}` }] };
|
|
1498
1457
|
}
|
|
@@ -1504,6 +1463,41 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1504
1463
|
return { content: [{ type: 'text', text: 'Error: key parameter is required' }] };
|
|
1505
1464
|
}
|
|
1506
1465
|
|
|
1466
|
+
// First try workspace artifacts (ArtifactManager)
|
|
1467
|
+
const ArtifactManager = require('./services/artifact-manager');
|
|
1468
|
+
const artifactManager = new ArtifactManager();
|
|
1469
|
+
const artifact = await artifactManager.getArtifact(key);
|
|
1470
|
+
|
|
1471
|
+
if (artifact) {
|
|
1472
|
+
const prompt = {
|
|
1473
|
+
resultType: 'prompt',
|
|
1474
|
+
origin: 'workspace',
|
|
1475
|
+
source: 'Workspace',
|
|
1476
|
+
key: artifact.key,
|
|
1477
|
+
name: artifact.meta?.title || artifact.key,
|
|
1478
|
+
description: artifact.meta?.summary || '',
|
|
1479
|
+
tags: artifact.meta?.tags || [],
|
|
1480
|
+
content: artifact.body,
|
|
1481
|
+
kind: artifact.kind,
|
|
1482
|
+
publishable: artifact.publishable,
|
|
1483
|
+
publishing: artifact.publishing,
|
|
1484
|
+
targets: artifact.targets,
|
|
1485
|
+
filePath: artifact.filePath,
|
|
1486
|
+
};
|
|
1487
|
+
|
|
1488
|
+
const kindBadge = prompt.kind !== 'prompt' ? ` [${prompt.kind}]` : '';
|
|
1489
|
+
const publishBadge = prompt.publishable ? '' : ' (local only)';
|
|
1490
|
+
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'}\nš Kind: ${prompt.kind}\nš¤ Publishable: ${prompt.publishable}\nš Status: ${prompt.publishing?.status || 'unknown'}\n\n**Content:**\n\`\`\`\n${prompt.content || '(No content)'}\n\`\`\``;
|
|
1491
|
+
|
|
1492
|
+
return {
|
|
1493
|
+
content: [
|
|
1494
|
+
{ type: 'text', text },
|
|
1495
|
+
{ type: 'text', text: '```json\n' + JSON.stringify(prompt, null, 2) + '\n```' }
|
|
1496
|
+
]
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
// Fall back to library search
|
|
1507
1501
|
const results = await this.searchPromptsUnifiedHandler({
|
|
1508
1502
|
query: key,
|
|
1509
1503
|
source: 'local',
|
|
@@ -1532,7 +1526,12 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1532
1526
|
return { content: [{ type: 'text', text: `No prompt found with key "${key}"` }] };
|
|
1533
1527
|
}
|
|
1534
1528
|
|
|
1535
|
-
|
|
1529
|
+
// Add kind/publishable for library prompts
|
|
1530
|
+
prompt.kind = prompt.kind || 'prompt';
|
|
1531
|
+
prompt.publishable = true;
|
|
1532
|
+
prompt.publishing = { status: 'published' };
|
|
1533
|
+
|
|
1534
|
+
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
1535
|
|
|
1537
1536
|
return {
|
|
1538
1537
|
content: [
|
|
@@ -1665,6 +1664,61 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
|
|
|
1665
1664
|
}
|
|
1666
1665
|
}
|
|
1667
1666
|
|
|
1667
|
+
async getProjectContext(params) {
|
|
1668
|
+
try {
|
|
1669
|
+
const ctx = await this.projectContextService.getProjectContext(params || {});
|
|
1670
|
+
const lines = [];
|
|
1671
|
+
lines.push('ā
Project context');
|
|
1672
|
+
lines.push(`Project root: ${ctx.projectRoot || 'not found'}`);
|
|
1673
|
+
lines.push(`Prompts dir: ${ctx.promptsDir || 'prompts'}`);
|
|
1674
|
+
if (ctx.subdao) {
|
|
1675
|
+
lines.push(`SubDAO: ${ctx.subdao}`);
|
|
1676
|
+
}
|
|
1677
|
+
if (ctx.registry) {
|
|
1678
|
+
lines.push(`Library registry: ${ctx.registry}`);
|
|
1679
|
+
}
|
|
1680
|
+
if (ctx.network) {
|
|
1681
|
+
lines.push(`Network: ${ctx.network}`);
|
|
1682
|
+
}
|
|
1683
|
+
if (ctx.rpcUrl) {
|
|
1684
|
+
lines.push(`RPC URL: ${ctx.rpcUrl}`);
|
|
1685
|
+
}
|
|
1686
|
+
if (ctx.workspace) {
|
|
1687
|
+
lines.push(
|
|
1688
|
+
`Workspace artifacts: prompts=${ctx.workspace.promptCount}, skills=${ctx.workspace.skillCount}, snippets=${ctx.workspace.snippetCount}, total=${ctx.workspace.total}`
|
|
1689
|
+
);
|
|
1690
|
+
}
|
|
1691
|
+
if (ctx.agentSurfaces) {
|
|
1692
|
+
const surfaces = [];
|
|
1693
|
+
if (ctx.agentSurfaces.cursorRulesDir) {
|
|
1694
|
+
surfaces.push(`cursor rules at ${ctx.agentSurfaces.cursorRulesDir}`);
|
|
1695
|
+
}
|
|
1696
|
+
if (ctx.agentSurfaces.claudeManifest) {
|
|
1697
|
+
surfaces.push(`CLAUDE manifest at ${ctx.agentSurfaces.claudeManifest}`);
|
|
1698
|
+
}
|
|
1699
|
+
if (ctx.agentSurfaces.copilotPromptsDir) {
|
|
1700
|
+
surfaces.push(`Copilot prompts at ${ctx.agentSurfaces.copilotPromptsDir}`);
|
|
1701
|
+
}
|
|
1702
|
+
if (Array.isArray(ctx.agentSurfaces.agentsFiles) && ctx.agentSurfaces.agentsFiles.length) {
|
|
1703
|
+
surfaces.push(`AGENTS files: ${ctx.agentSurfaces.agentsFiles.join(', ')}`);
|
|
1704
|
+
}
|
|
1705
|
+
if (surfaces.length) {
|
|
1706
|
+
lines.push('Agent surfaces:');
|
|
1707
|
+
surfaces.forEach((s) => lines.push(`- ${s}`));
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
return {
|
|
1712
|
+
content: [
|
|
1713
|
+
{ type: 'text', text: lines.join('\n') },
|
|
1714
|
+
{ type: 'text', text: '```json\n' + JSON.stringify(ctx, null, 2) + '\n```' },
|
|
1715
|
+
],
|
|
1716
|
+
};
|
|
1717
|
+
} catch (error) {
|
|
1718
|
+
return { content: [{ type: 'text', text: `Error retrieving project context: ${error.message}` }] };
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1668
1722
|
async listTemplates(params = {}) {
|
|
1669
1723
|
try {
|
|
1670
1724
|
const result = this.templateManager.listTemplates(params || {});
|
|
@@ -3207,7 +3261,7 @@ Use \`help(topic="create")\` for more details.
|
|
|
3207
3261
|
description: t.description,
|
|
3208
3262
|
recommended_slots: t.recommended_slots?.map(s => s.label) || []
|
|
3209
3263
|
}));
|
|
3210
|
-
|
|
3264
|
+
|
|
3211
3265
|
return {
|
|
3212
3266
|
content: [
|
|
3213
3267
|
{
|
|
@@ -3234,7 +3288,7 @@ Use \`help(topic="create")\` for more details.
|
|
|
3234
3288
|
|
|
3235
3289
|
// 1. Validate Template
|
|
3236
3290
|
const templateDef = templates[template] || templates['custom'];
|
|
3237
|
-
|
|
3291
|
+
|
|
3238
3292
|
// 2. Build Prompt (One-Shot)
|
|
3239
3293
|
// Note: run_persona_interview assumes the *agent* has already done the planning/filling.
|
|
3240
3294
|
// It bypasses the SlotPlanner and just builds the artifact.
|
|
@@ -3242,7 +3296,7 @@ Use \`help(topic="create")\` for more details.
|
|
|
3242
3296
|
// We need the full slot definitions to build dynamic sections.
|
|
3243
3297
|
// Since we skipped the planner, we'll use the template's recommended slots as the definition.
|
|
3244
3298
|
const slots = templateDef.recommended_slots || [];
|
|
3245
|
-
|
|
3299
|
+
|
|
3246
3300
|
const systemPrompt = builder.buildSystemPrompt(template, slots, answers || {});
|
|
3247
3301
|
|
|
3248
3302
|
let result = {
|
|
@@ -3255,17 +3309,17 @@ Use \`help(topic="create")\` for more details.
|
|
|
3255
3309
|
if (save) {
|
|
3256
3310
|
const persistence = new MetapromptPersistence(config);
|
|
3257
3311
|
const slug = saveKey || `${template}-${Date.now().toString().slice(-6)}`;
|
|
3258
|
-
|
|
3312
|
+
|
|
3259
3313
|
// Save dummy history so the artifact exists
|
|
3260
3314
|
const historyPaths = persistence.saveMetaprompt(slug, {
|
|
3261
3315
|
templateKey: template,
|
|
3262
3316
|
transcript: [{ role: 'system', content: 'Generated via MCP run_persona_interview (one-shot).' }],
|
|
3263
3317
|
answers: answers || {}
|
|
3264
3318
|
});
|
|
3265
|
-
|
|
3319
|
+
|
|
3266
3320
|
// Save Skill
|
|
3267
3321
|
const skillPath = persistence.saveSkill(slug, systemPrompt);
|
|
3268
|
-
|
|
3322
|
+
|
|
3269
3323
|
result.slug = slug;
|
|
3270
3324
|
result.paths = {
|
|
3271
3325
|
metaprompt: historyPaths.metaprompt,
|