@sage-protocol/cli 0.3.0 → 0.3.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/doctor.js +87 -8
- package/dist/cli/commands/gov-config.js +81 -0
- package/dist/cli/commands/governance.js +152 -72
- package/dist/cli/commands/library.js +9 -0
- package/dist/cli/commands/proposals.js +187 -17
- package/dist/cli/commands/skills.js +175 -21
- package/dist/cli/commands/subdao.js +22 -2
- package/dist/cli/config/playbooks.json +15 -0
- package/dist/cli/governance-manager.js +25 -4
- package/dist/cli/index.js +5 -6
- package/dist/cli/library-manager.js +79 -0
- package/dist/cli/mcp-server-stdio.js +1655 -82
- package/dist/cli/schemas/manifest.schema.json +55 -0
- package/dist/cli/services/doctor/fixers.js +134 -0
- package/dist/cli/services/mcp/bulk-operations.js +272 -0
- package/dist/cli/services/mcp/dependency-analyzer.js +202 -0
- package/dist/cli/services/mcp/library-listing.js +2 -2
- package/dist/cli/services/mcp/local-prompt-collector.js +1 -0
- package/dist/cli/services/mcp/manifest-downloader.js +5 -3
- package/dist/cli/services/mcp/manifest-fetcher.js +17 -1
- package/dist/cli/services/mcp/manifest-workflows.js +127 -15
- package/dist/cli/services/mcp/quick-start.js +287 -0
- package/dist/cli/services/mcp/stdio-runner.js +30 -5
- package/dist/cli/services/mcp/template-manager.js +156 -0
- package/dist/cli/services/mcp/templates/default-templates.json +84 -0
- package/dist/cli/services/mcp/tool-args-validator.js +66 -0
- package/dist/cli/services/mcp/trending-formatter.js +1 -1
- package/dist/cli/services/mcp/unified-prompt-search.js +2 -2
- package/dist/cli/services/metaprompt/designer.js +12 -5
- package/dist/cli/services/subdao/applier.js +208 -196
- package/dist/cli/services/subdao/planner.js +41 -6
- package/dist/cli/subdao-manager.js +14 -0
- package/dist/cli/utils/aliases.js +17 -2
- package/dist/cli/utils/contract-error-decoder.js +61 -0
- package/dist/cli/utils/suggestions.js +17 -12
- package/package.json +3 -2
- package/src/schemas/manifest.schema.json +55 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Simple prompt template manager for MCP flows.
|
|
6
|
+
*
|
|
7
|
+
* Templates are defined as JSON data and rendered into concrete prompts
|
|
8
|
+
* which are persisted using quickStart.quickCreatePrompt.
|
|
9
|
+
*/
|
|
10
|
+
function createTemplateManager({
|
|
11
|
+
quickStart,
|
|
12
|
+
fsModule = fs,
|
|
13
|
+
pathModule = path,
|
|
14
|
+
logger = console,
|
|
15
|
+
} = {}) {
|
|
16
|
+
if (!quickStart || typeof quickStart.quickCreatePrompt !== 'function') {
|
|
17
|
+
throw new Error('TemplateManager requires quickStart.quickCreatePrompt');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const defaultTemplatePath = pathModule.join(__dirname, 'templates', 'default-templates.json');
|
|
21
|
+
let templatesCache = null;
|
|
22
|
+
|
|
23
|
+
function loadTemplates() {
|
|
24
|
+
if (templatesCache) return templatesCache;
|
|
25
|
+
try {
|
|
26
|
+
const raw = fsModule.readFileSync(defaultTemplatePath, 'utf8');
|
|
27
|
+
const parsed = JSON.parse(raw);
|
|
28
|
+
const list = Array.isArray(parsed) ? parsed : parsed.templates || [];
|
|
29
|
+
templatesCache = list;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
logger?.warn?.('template_manager_load_failed', { path: defaultTemplatePath, err: error.message || String(error) });
|
|
32
|
+
templatesCache = [];
|
|
33
|
+
}
|
|
34
|
+
return templatesCache;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function listTemplates({ category, search } = {}) {
|
|
38
|
+
const all = loadTemplates();
|
|
39
|
+
const cat = (category || '').toLowerCase();
|
|
40
|
+
const term = (search || '').toLowerCase();
|
|
41
|
+
const filtered = all.filter((tpl) => {
|
|
42
|
+
if (cat && String(tpl.category || '').toLowerCase() !== cat) return false;
|
|
43
|
+
if (!term) return true;
|
|
44
|
+
const haystack = [
|
|
45
|
+
tpl.key || '',
|
|
46
|
+
tpl.name || '',
|
|
47
|
+
tpl.description || '',
|
|
48
|
+
(tpl.metadata && tpl.metadata.suggested_description) || '',
|
|
49
|
+
]
|
|
50
|
+
.join(' ')
|
|
51
|
+
.toLowerCase();
|
|
52
|
+
return haystack.includes(term);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const items = filtered.map((tpl) => {
|
|
56
|
+
const vars = Array.isArray(tpl.variables) ? tpl.variables : [];
|
|
57
|
+
return {
|
|
58
|
+
key: tpl.key,
|
|
59
|
+
name: tpl.name,
|
|
60
|
+
category: tpl.category || '',
|
|
61
|
+
summary: tpl.description || (tpl.metadata && tpl.metadata.suggested_description) || '',
|
|
62
|
+
requiredVariables: vars.filter((v) => v && v.required).map((v) => v.name),
|
|
63
|
+
optionalVariables: vars.filter((v) => v && !v.required).map((v) => v.name),
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return { templates: items };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function getTemplate({ key }) {
|
|
71
|
+
const all = loadTemplates();
|
|
72
|
+
const id = String(key || '').trim();
|
|
73
|
+
if (!id) {
|
|
74
|
+
throw new Error('template key is required');
|
|
75
|
+
}
|
|
76
|
+
const tpl = all.find((t) => t.key === id);
|
|
77
|
+
if (!tpl) {
|
|
78
|
+
throw new Error(`Template not found for key "${key}"`);
|
|
79
|
+
}
|
|
80
|
+
return { template: tpl };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function renderWithVars(templateString, customize, variables) {
|
|
84
|
+
let result = String(templateString || '');
|
|
85
|
+
const vars = Array.isArray(variables) ? variables : [];
|
|
86
|
+
for (const v of vars) {
|
|
87
|
+
if (!v || !v.name) continue;
|
|
88
|
+
const value = customize && Object.prototype.hasOwnProperty.call(customize, v.name)
|
|
89
|
+
? String(customize[v.name])
|
|
90
|
+
: (v.default !== undefined ? String(v.default) : `\${${v.name}}`);
|
|
91
|
+
const pattern = new RegExp(`\\$\\{${v.name}\\}`, 'g');
|
|
92
|
+
result = result.replace(pattern, value);
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function createFromTemplate({ template, customize, library, name } = {}) {
|
|
98
|
+
const { template: tpl } = getTemplate({ key: template });
|
|
99
|
+
const vars = Array.isArray(tpl.variables) ? tpl.variables : [];
|
|
100
|
+
const missing = vars
|
|
101
|
+
.filter((v) => v && v.required)
|
|
102
|
+
.filter((v) => !customize || customize[v.name] === undefined || customize[v.name] === null || customize[v.name] === '');
|
|
103
|
+
|
|
104
|
+
if (missing.length) {
|
|
105
|
+
const names = missing.map((v) => v.name).join(', ');
|
|
106
|
+
throw new Error(`Missing required variables for template "${tpl.key}": ${names}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const content = renderWithVars(tpl.content_template || '', customize, vars);
|
|
110
|
+
|
|
111
|
+
const promptName =
|
|
112
|
+
name ||
|
|
113
|
+
tpl.name ||
|
|
114
|
+
(customize && customize.title) ||
|
|
115
|
+
(customize && customize.project_type && `${customize.project_type} Prompt`) ||
|
|
116
|
+
tpl.key;
|
|
117
|
+
|
|
118
|
+
let description = '';
|
|
119
|
+
if (tpl.metadata && tpl.metadata.suggested_description) {
|
|
120
|
+
description = renderWithVars(tpl.metadata.suggested_description, customize, vars);
|
|
121
|
+
} else {
|
|
122
|
+
description = tpl.description || '';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const defaultTags = Array.isArray(tpl.metadata?.default_tags)
|
|
126
|
+
? tpl.metadata.default_tags.map((t) => String(t).trim()).filter(Boolean)
|
|
127
|
+
: [];
|
|
128
|
+
const tags = defaultTags;
|
|
129
|
+
|
|
130
|
+
const quickResult = await quickStart.quickCreatePrompt({
|
|
131
|
+
name: promptName,
|
|
132
|
+
content,
|
|
133
|
+
description,
|
|
134
|
+
library,
|
|
135
|
+
tags,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
success: true,
|
|
140
|
+
template: tpl.key,
|
|
141
|
+
variables: customize || {},
|
|
142
|
+
tags,
|
|
143
|
+
quickCreate: quickResult,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
listTemplates,
|
|
149
|
+
getTemplate,
|
|
150
|
+
createFromTemplate,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = {
|
|
155
|
+
createTemplateManager,
|
|
156
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"key": "landscape-design-planner",
|
|
4
|
+
"name": "Landscape Design Planner",
|
|
5
|
+
"category": "design",
|
|
6
|
+
"description": "Structured planner for landscape and courtyard design projects.",
|
|
7
|
+
"variables": [
|
|
8
|
+
{ "name": "project_type", "required": true, "description": "courtyard, garden, patio, deck, etc." },
|
|
9
|
+
{ "name": "region", "required": true, "description": "location or climate zone" },
|
|
10
|
+
{ "name": "style", "required": false, "description": "modern, traditional, cottage, etc.", "default": "modern" },
|
|
11
|
+
{ "name": "budget_range", "required": false, "description": "low, medium, high, or numeric range" }
|
|
12
|
+
],
|
|
13
|
+
"content_template": "You are an experienced landscape designer specializing in ${project_type} projects in ${region}.\n\nYour tasks:\n1. Analyze the site conditions and constraints.\n2. Propose a high-level layout for the ${project_type}.\n3. Recommend materials, planting zones, and functional zones.\n4. Highlight tradeoffs given the budget range (${budget_range}).\n\nRespond with:\n- Site assumptions\n- Layout description\n- Material and planting recommendations\n- Risks and open questions.",
|
|
14
|
+
"metadata": {
|
|
15
|
+
"default_tags": ["design", "landscape", "courtyard"],
|
|
16
|
+
"suggested_description": "${project_type} planning prompt for projects in ${region}."
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"key": "code-review-assistant",
|
|
21
|
+
"name": "Code Review Assistant",
|
|
22
|
+
"category": "development",
|
|
23
|
+
"description": "Prompt for structured, actionable code review feedback.",
|
|
24
|
+
"variables": [
|
|
25
|
+
{ "name": "language", "required": true, "description": "primary language or stack" },
|
|
26
|
+
{ "name": "context", "required": false, "description": "repository or feature context", "default": "general" },
|
|
27
|
+
{ "name": "focus_areas", "required": false, "description": "performance, readability, security, etc." }
|
|
28
|
+
],
|
|
29
|
+
"content_template": "You are a senior ${language} engineer performing a code review.\n\nContext: ${context}\nFocus areas: ${focus_areas}\n\nFor the given code, provide:\n1. High-level summary of what the code does.\n2. Strengths.\n3. Issues grouped by severity (critical, important, minor).\n4. Concrete suggestions and examples for improvement.\n5. Any follow-up questions.\n\nBe concise but specific; avoid restating the code.",
|
|
30
|
+
"metadata": {
|
|
31
|
+
"default_tags": ["code-review", "development"],
|
|
32
|
+
"suggested_description": "Structured ${language} code review assistant prompt."
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"key": "data-analysis-brief",
|
|
37
|
+
"name": "Data Analysis Brief",
|
|
38
|
+
"category": "analysis",
|
|
39
|
+
"description": "Briefing prompt for exploratory or explanatory data analysis.",
|
|
40
|
+
"variables": [
|
|
41
|
+
{ "name": "dataset_description", "required": true, "description": "what the data represents" },
|
|
42
|
+
{ "name": "audience", "required": false, "description": "decision makers, technical team, etc.", "default": "mixed" },
|
|
43
|
+
{ "name": "primary_question", "required": true, "description": "main question to answer" }
|
|
44
|
+
],
|
|
45
|
+
"content_template": "You are a data analyst preparing a structured analysis plan.\n\nDataset: ${dataset_description}\nAudience: ${audience}\nPrimary question: ${primary_question}\n\nProvide:\n1. Clarifying questions you would ask before analysis.\n2. Proposed analysis steps and methods.\n3. Key metrics and visualizations you would produce.\n4. Potential risks, caveats, or biases.\n5. How you would communicate results to the audience.",
|
|
46
|
+
"metadata": {
|
|
47
|
+
"default_tags": ["analysis", "planning"],
|
|
48
|
+
"suggested_description": "Plan an analysis for ${dataset_description} focusing on ${primary_question}."
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"key": "writing-assistant",
|
|
53
|
+
"name": "Writing Assistant",
|
|
54
|
+
"category": "writing",
|
|
55
|
+
"description": "General-purpose structured writing assistant prompt.",
|
|
56
|
+
"variables": [
|
|
57
|
+
{ "name": "piece_type", "required": true, "description": "blog post, email, announcement, etc." },
|
|
58
|
+
{ "name": "topic", "required": true, "description": "subject of the piece" },
|
|
59
|
+
{ "name": "tone", "required": false, "description": "professional, friendly, playful, etc.", "default": "professional" }
|
|
60
|
+
],
|
|
61
|
+
"content_template": "You are an assistant helping draft a ${piece_type} about ${topic} in a ${tone} tone.\n\nProvide:\n1. A suggested outline.\n2. A draft introduction paragraph.\n3. 2–3 key points with short supporting paragraphs.\n4. A concise conclusion or call to action.\n\nKeep the language clear and accessible.",
|
|
62
|
+
"metadata": {
|
|
63
|
+
"default_tags": ["writing", "content"],
|
|
64
|
+
"suggested_description": "${piece_type} assistant prompt for ${topic}."
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"key": "governance-library-publish-helper",
|
|
69
|
+
"name": "Governance Library Publish Helper",
|
|
70
|
+
"category": "governance",
|
|
71
|
+
"description": "Helper prompt to plan publishing a Sage library to a SubDAO.",
|
|
72
|
+
"variables": [
|
|
73
|
+
{ "name": "library_name", "required": true, "description": "name of the library being published" },
|
|
74
|
+
{ "name": "subdao_name", "required": false, "description": "name of the target SubDAO" },
|
|
75
|
+
{ "name": "risk_level", "required": false, "description": "low, medium, high", "default": "medium" }
|
|
76
|
+
],
|
|
77
|
+
"content_template": "You are assisting with publishing the \"${library_name}\" library to a Sage SubDAO (${subdao_name}).\n\nFor this publication, outline:\n1. Why this library is valuable to the SubDAO.\n2. Any risks or tradeoffs (risk level: ${risk_level}).\n3. Preconditions for a safe rollout (tests, review, etc.).\n4. A short, clear proposal description for governance.\n\nRespond as a structured brief the proposer can paste into their governance proposal.",
|
|
78
|
+
"metadata": {
|
|
79
|
+
"default_tags": ["governance", "library", "publish"],
|
|
80
|
+
"suggested_description": "Governance brief helper for publishing ${library_name}."
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
|
|
@@ -61,6 +61,7 @@ function createToolArgsValidator({ zodModule } = {}) {
|
|
|
61
61
|
manifest: Z.record(Z.any()),
|
|
62
62
|
subdao: Z.string().regex(/^0x[a-fA-F0-9]{40}$/).optional().or(Z.literal('')).default(''),
|
|
63
63
|
description: Z.string().max(280).optional().default(''),
|
|
64
|
+
dry_run: Z.boolean().optional().default(false),
|
|
64
65
|
}),
|
|
65
66
|
propose_manifest: Z.object({
|
|
66
67
|
cid: Z.string().min(10).max(200),
|
|
@@ -69,6 +70,71 @@ function createToolArgsValidator({ zodModule } = {}) {
|
|
|
69
70
|
promptCount: Z.number().int().min(0).optional(),
|
|
70
71
|
manifest: Z.record(Z.any()).optional(),
|
|
71
72
|
}),
|
|
73
|
+
improve_prompt: Z.object({
|
|
74
|
+
key: Z.string().min(1).max(200),
|
|
75
|
+
library: Z.string().min(1).max(200).optional(),
|
|
76
|
+
pass: Z.enum(['single', 'deep']).optional(),
|
|
77
|
+
depth: Z.enum(['single', 'deep']).optional(),
|
|
78
|
+
focus: Z.enum(['variables', 'edge-cases', 'output-quality', 'reusability', 'all']).optional().default('all'),
|
|
79
|
+
}).transform((obj) => ({
|
|
80
|
+
key: obj.key,
|
|
81
|
+
library: obj.library,
|
|
82
|
+
pass: obj.depth || obj.pass || 'single',
|
|
83
|
+
focus: obj.focus,
|
|
84
|
+
})),
|
|
85
|
+
rename_prompt: Z.object({
|
|
86
|
+
key: Z.string().min(1).max(200),
|
|
87
|
+
newKey: Z.string().min(1).max(200).optional(),
|
|
88
|
+
name: Z.string().min(1).max(200).optional(),
|
|
89
|
+
}),
|
|
90
|
+
update_library_metadata: Z.object({
|
|
91
|
+
library: Z.string().min(1).max(200),
|
|
92
|
+
name: Z.string().min(1).max(200).optional(),
|
|
93
|
+
description: Z.string().max(1000).optional(),
|
|
94
|
+
tags: Z.array(Z.string().max(64)).optional(),
|
|
95
|
+
apply_to_prompts: Z.boolean().optional().default(false),
|
|
96
|
+
merge_mode: Z.enum(['replace', 'merge']).optional().default('merge'),
|
|
97
|
+
}),
|
|
98
|
+
bulk_update_prompts: Z.object({
|
|
99
|
+
library: Z.string().min(1).max(200),
|
|
100
|
+
updates: Z.array(
|
|
101
|
+
Z.object({
|
|
102
|
+
key: Z.string().min(1).max(200),
|
|
103
|
+
name: Z.string().min(1).max(200).optional(),
|
|
104
|
+
description: Z.string().max(2000).optional(),
|
|
105
|
+
tags: Z.array(Z.string().max(64)).optional(),
|
|
106
|
+
content: Z.string().optional(),
|
|
107
|
+
}),
|
|
108
|
+
)
|
|
109
|
+
.min(1),
|
|
110
|
+
dry_run: Z.boolean().optional().default(false),
|
|
111
|
+
}),
|
|
112
|
+
list_templates: Z.object({
|
|
113
|
+
category: Z.string().max(200).optional(),
|
|
114
|
+
search: Z.string().max(500).optional(),
|
|
115
|
+
}),
|
|
116
|
+
get_template: Z.object({
|
|
117
|
+
key: Z.string().min(1).max(200),
|
|
118
|
+
}),
|
|
119
|
+
create_from_template: Z.object({
|
|
120
|
+
template: Z.string().min(1).max(200),
|
|
121
|
+
customize: Z.record(Z.any()),
|
|
122
|
+
library: Z.string().min(1).max(200).optional(),
|
|
123
|
+
name: Z.string().min(1).max(200).optional(),
|
|
124
|
+
}),
|
|
125
|
+
analyze_dependencies: Z.object({
|
|
126
|
+
library: Z.string().min(1).max(200),
|
|
127
|
+
analysis_type: Z.enum(['variables', 'all']).optional().default('variables'),
|
|
128
|
+
}),
|
|
129
|
+
suggest_subdaos_for_library: Z.object({
|
|
130
|
+
library: Z.string().min(1).max(200),
|
|
131
|
+
limit: Z.number().int().min(1).max(20).optional().default(5),
|
|
132
|
+
mode_filter: Z.enum(['any', 'creator', 'squad', 'community']).optional().default('any'),
|
|
133
|
+
}),
|
|
134
|
+
generate_publishing_commands: Z.object({
|
|
135
|
+
library: Z.string().min(1).max(200),
|
|
136
|
+
target: Z.string().max(200).optional().default('auto'),
|
|
137
|
+
}),
|
|
72
138
|
};
|
|
73
139
|
|
|
74
140
|
return function validate(name, args) {
|
|
@@ -14,7 +14,7 @@ function buildTrendingResponse(suggestions = [], limit = 10) {
|
|
|
14
14
|
return {
|
|
15
15
|
content: [
|
|
16
16
|
{ type: 'text', text },
|
|
17
|
-
{ type: '
|
|
17
|
+
{ type: 'text', text: '```json\n' + JSON.stringify({ items }, null, 2) + '\n```' },
|
|
18
18
|
],
|
|
19
19
|
};
|
|
20
20
|
}
|
|
@@ -76,8 +76,8 @@ function createUnifiedPromptSearcher({
|
|
|
76
76
|
content: [
|
|
77
77
|
{ type: 'text', text },
|
|
78
78
|
{
|
|
79
|
-
type: '
|
|
80
|
-
text: JSON.stringify({ total, page: normalizedPage, pageSize: normalizedPageSize, results: pageResults }, null, DEFAULT_INDENT),
|
|
79
|
+
type: 'text',
|
|
80
|
+
text: '```json\n' + JSON.stringify({ total, page: normalizedPage, pageSize: normalizedPageSize, results: pageResults }, null, DEFAULT_INDENT) + '\n```',
|
|
81
81
|
},
|
|
82
82
|
],
|
|
83
83
|
};
|
|
@@ -57,7 +57,7 @@ class MetapromptDesigner {
|
|
|
57
57
|
const history = this.path.join(base, 'history');
|
|
58
58
|
try {
|
|
59
59
|
this.fs.mkdirSync(history, { recursive: true });
|
|
60
|
-
} catch (_) {}
|
|
60
|
+
} catch (_) { }
|
|
61
61
|
return history;
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -103,7 +103,7 @@ class MetapromptDesigner {
|
|
|
103
103
|
if (value.startsWith('[') && value.endsWith(']')) {
|
|
104
104
|
try {
|
|
105
105
|
value = JSON.parse(value.replace(/'/g, '"'));
|
|
106
|
-
} catch (_) {}
|
|
106
|
+
} catch (_) { }
|
|
107
107
|
}
|
|
108
108
|
meta[key] = value;
|
|
109
109
|
});
|
|
@@ -197,9 +197,10 @@ class MetapromptDesigner {
|
|
|
197
197
|
goal = 'Design a system prompt for an AI assistant that specialises in Sage Protocol development and prompt operations.',
|
|
198
198
|
model = 'gpt-5',
|
|
199
199
|
interviewStyle = 'one-question-at-a-time',
|
|
200
|
+
additionalInstructions = '',
|
|
200
201
|
} = options;
|
|
201
202
|
|
|
202
|
-
|
|
203
|
+
const lines = [
|
|
203
204
|
'You are facilitating a metaprompt interview.',
|
|
204
205
|
'Interview me one question at a time.',
|
|
205
206
|
'Use each answer to decide the very next question.',
|
|
@@ -211,13 +212,19 @@ class MetapromptDesigner {
|
|
|
211
212
|
'Offer optional follow-up artifacts (e.g., user prompt template, evaluation checklist).',
|
|
212
213
|
'End by suggesting how to save or launch the prompt (e.g., via ChatGPT link).',
|
|
213
214
|
`Interview cadence preference: ${interviewStyle}.`,
|
|
214
|
-
]
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
if (additionalInstructions) {
|
|
218
|
+
lines.push(additionalInstructions);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return lines.join('\n');
|
|
215
222
|
}
|
|
216
223
|
|
|
217
224
|
saveTranscript(transcriptPath, payload) {
|
|
218
225
|
try {
|
|
219
226
|
this.fs.mkdirSync(this.path.dirname(transcriptPath), { recursive: true });
|
|
220
|
-
} catch (_) {}
|
|
227
|
+
} catch (_) { }
|
|
221
228
|
this.fs.writeFileSync(transcriptPath, JSON.stringify(payload, null, 2));
|
|
222
229
|
}
|
|
223
230
|
}
|