@vibe-assurance/cli 1.0.6 → 1.1.0
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/bin/vibe.js +5 -1
- package/nul +2 -0
- package/package.json +2 -1
- package/src/api/client.js +17 -6
- package/src/commands/login.js +68 -1
- package/src/commands/projects.js +211 -0
- package/src/config/credentials.js +39 -1
- package/src/mcp/tools.js +28 -2
package/bin/vibe.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// Load .env file if present (for local development)
|
|
4
4
|
const path = require('path');
|
|
@@ -12,6 +12,7 @@ const login = require('../src/commands/login');
|
|
|
12
12
|
const logout = require('../src/commands/logout');
|
|
13
13
|
const mcpServer = require('../src/commands/mcp-server');
|
|
14
14
|
const setupClaude = require('../src/commands/setup-claude');
|
|
15
|
+
const { registerProjectCommands } = require('../src/commands/projects');
|
|
15
16
|
|
|
16
17
|
program
|
|
17
18
|
.name('vibe')
|
|
@@ -38,4 +39,7 @@ program
|
|
|
38
39
|
.description('Configure Claude Code to use the Vibe Assurance MCP server')
|
|
39
40
|
.action(setupClaude);
|
|
40
41
|
|
|
42
|
+
// CR-2026-043: Register project management commands
|
|
43
|
+
registerProjectCommands(program);
|
|
44
|
+
|
|
41
45
|
program.parse();
|
package/nul
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibe-assurance/cli",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Vibe Assurance CLI - Connect AI coding agents to your governance platform via MCP",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"chalk": "^4.1.2",
|
|
32
32
|
"commander": "^12.0.0",
|
|
33
33
|
"dotenv": "^16.6.1",
|
|
34
|
+
"inquirer": "^8.2.6",
|
|
34
35
|
"keytar": "^7.9.0",
|
|
35
36
|
"open": "^8.4.2",
|
|
36
37
|
"ora": "^5.4.1"
|
package/src/api/client.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
const axios = require('axios');
|
|
2
|
-
const { getCredentials, storeCredentials, deleteCredentials } = require('../config/credentials');
|
|
2
|
+
const { getCredentials, storeCredentials, deleteCredentials, getProjectId } = require('../config/credentials');
|
|
3
3
|
|
|
4
4
|
// Default to dev Azure URL, can be overridden via environment variable
|
|
5
5
|
const API_BASE_URL = process.env.VIBE_API_URL || 'https://agent-platform-dev.azurewebsites.net';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Create an authenticated axios instance with token refresh handling
|
|
9
|
+
* CR-2026-043: Now includes X-Project-Id header for project scoping
|
|
9
10
|
* @returns {Promise<import('axios').AxiosInstance>}
|
|
10
11
|
*/
|
|
11
12
|
async function createClient() {
|
|
@@ -14,13 +15,23 @@ async function createClient() {
|
|
|
14
15
|
throw new Error('Not authenticated. Run: vibe login');
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
// CR-2026-043: Get current project ID for scoping
|
|
19
|
+
const projectId = await getProjectId();
|
|
20
|
+
|
|
21
|
+
const headers = {
|
|
22
|
+
'Authorization': `Bearer ${creds.accessToken}`,
|
|
23
|
+
'Content-Type': 'application/json',
|
|
24
|
+
'User-Agent': 'vibe-cli/1.0.0'
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// CR-2026-043: Add project header if available
|
|
28
|
+
if (projectId) {
|
|
29
|
+
headers['X-Project-Id'] = projectId;
|
|
30
|
+
}
|
|
31
|
+
|
|
17
32
|
const client = axios.create({
|
|
18
33
|
baseURL: API_BASE_URL,
|
|
19
|
-
headers
|
|
20
|
-
'Authorization': `Bearer ${creds.accessToken}`,
|
|
21
|
-
'Content-Type': 'application/json',
|
|
22
|
-
'User-Agent': 'vibe-cli/1.0.0'
|
|
23
|
-
},
|
|
34
|
+
headers,
|
|
24
35
|
timeout: 30000 // 30 second timeout
|
|
25
36
|
});
|
|
26
37
|
|
package/src/commands/login.js
CHANGED
|
@@ -3,7 +3,9 @@ const http = require('http');
|
|
|
3
3
|
const { URL } = require('url');
|
|
4
4
|
const chalk = require('chalk');
|
|
5
5
|
const ora = require('ora');
|
|
6
|
-
const
|
|
6
|
+
const inquirer = require('inquirer');
|
|
7
|
+
const axios = require('axios');
|
|
8
|
+
const { storeCredentials, hasValidCredentials, setProjectId } = require('../config/credentials');
|
|
7
9
|
const { API_BASE_URL } = require('../api/client');
|
|
8
10
|
|
|
9
11
|
// Local callback server port (chosen to be unlikely to conflict)
|
|
@@ -140,6 +142,10 @@ async function login() {
|
|
|
140
142
|
await authPromise;
|
|
141
143
|
cleanup();
|
|
142
144
|
spinner.succeed('Successfully authenticated!');
|
|
145
|
+
|
|
146
|
+
// CR-2026-043: Select project after successful login
|
|
147
|
+
await selectProject();
|
|
148
|
+
|
|
143
149
|
console.log(chalk.green('\nYou are now logged in to Vibe Assurance.'));
|
|
144
150
|
console.log('\nNext steps:');
|
|
145
151
|
console.log(' 1. Run `vibe setup-claude` to configure Claude Code');
|
|
@@ -153,6 +159,67 @@ async function login() {
|
|
|
153
159
|
}
|
|
154
160
|
}
|
|
155
161
|
|
|
162
|
+
/**
|
|
163
|
+
* CR-2026-043: Select project after successful authentication
|
|
164
|
+
* Fetches user's projects and prompts for selection if multiple exist
|
|
165
|
+
*/
|
|
166
|
+
async function selectProject() {
|
|
167
|
+
const spinner = ora('Fetching your projects...').start();
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
// Get credentials to make authenticated request
|
|
171
|
+
const { getCredentials } = require('../config/credentials');
|
|
172
|
+
const creds = await getCredentials();
|
|
173
|
+
|
|
174
|
+
// Fetch user profile which now includes projects (CR-2026-043 backend change)
|
|
175
|
+
const response = await axios.get(`${API_BASE_URL}/api/auth/me`, {
|
|
176
|
+
headers: {
|
|
177
|
+
'Authorization': `Bearer ${creds.accessToken}`,
|
|
178
|
+
'Content-Type': 'application/json'
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const { projects, defaultProjectId } = response.data;
|
|
183
|
+
spinner.stop();
|
|
184
|
+
|
|
185
|
+
if (!projects || projects.length === 0) {
|
|
186
|
+
console.log(chalk.yellow('\nNo projects found. A default project will be created when you first use the API.'));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (projects.length === 1) {
|
|
191
|
+
// Auto-select single project
|
|
192
|
+
await setProjectId(projects[0]._id, projects[0].name);
|
|
193
|
+
console.log(chalk.green(`\n✓ Selected project: ${projects[0].name}`));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Multiple projects - prompt for selection
|
|
198
|
+
console.log(''); // Empty line for spacing
|
|
199
|
+
const choices = projects.map(p => ({
|
|
200
|
+
name: `${p.name}${p.isDefault ? chalk.dim(' (default)') : ''}`,
|
|
201
|
+
value: { id: p._id, name: p.name }
|
|
202
|
+
}));
|
|
203
|
+
|
|
204
|
+
const { selected } = await inquirer.prompt([{
|
|
205
|
+
type: 'list',
|
|
206
|
+
name: 'selected',
|
|
207
|
+
message: 'Select a project to work with:',
|
|
208
|
+
choices,
|
|
209
|
+
default: choices.findIndex(c => c.value.id === defaultProjectId)
|
|
210
|
+
}]);
|
|
211
|
+
|
|
212
|
+
await setProjectId(selected.id, selected.name);
|
|
213
|
+
console.log(chalk.green(`✓ Selected project: ${selected.name}`));
|
|
214
|
+
|
|
215
|
+
} catch (err) {
|
|
216
|
+
spinner.stop();
|
|
217
|
+
// Non-fatal error - user can still use CLI with default project
|
|
218
|
+
console.log(chalk.yellow('\nCould not fetch projects. Using default project.'));
|
|
219
|
+
console.log(chalk.dim(` (You can run 'vibe project select' later to switch projects)`));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
156
223
|
/**
|
|
157
224
|
* Generate success HTML page
|
|
158
225
|
* Matches the main app's branding with Tailwind CSS and emerald colors
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CR-2026-043: Project management commands
|
|
3
|
+
*
|
|
4
|
+
* Provides CLI commands for listing and switching between projects:
|
|
5
|
+
* - vibe projects - List all accessible projects
|
|
6
|
+
* - vibe project current - Show current project
|
|
7
|
+
* - vibe project select - Switch to a different project
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const chalk = require('chalk');
|
|
11
|
+
const ora = require('ora');
|
|
12
|
+
const inquirer = require('inquirer');
|
|
13
|
+
const api = require('../api/client');
|
|
14
|
+
const { getProjectId, getProjectName, setProjectId, hasValidCredentials } = require('../config/credentials');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* List all accessible projects
|
|
18
|
+
* Command: vibe projects
|
|
19
|
+
*/
|
|
20
|
+
async function listProjects() {
|
|
21
|
+
// Check authentication
|
|
22
|
+
if (!await hasValidCredentials()) {
|
|
23
|
+
console.log(chalk.red('Not authenticated. Run: vibe login'));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const spinner = ora('Fetching projects...').start();
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const projects = await api.get('/api/projects');
|
|
31
|
+
const currentProjectId = await getProjectId();
|
|
32
|
+
spinner.stop();
|
|
33
|
+
|
|
34
|
+
if (!projects || projects.length === 0) {
|
|
35
|
+
console.log(chalk.yellow('\nNo projects found.'));
|
|
36
|
+
console.log(chalk.dim('Create a project in the Vibe Assurance web portal.'));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
console.log(chalk.bold('\nYour Projects:\n'));
|
|
41
|
+
|
|
42
|
+
for (const p of projects) {
|
|
43
|
+
const current = p._id === currentProjectId ? chalk.green(' ← current') : '';
|
|
44
|
+
const def = p.isDefault ? chalk.dim(' (default)') : '';
|
|
45
|
+
|
|
46
|
+
console.log(` ${p.name}${def}${current}`);
|
|
47
|
+
console.log(chalk.dim(` ID: ${p._id}`));
|
|
48
|
+
if (p.description) {
|
|
49
|
+
console.log(chalk.dim(` ${p.description}`));
|
|
50
|
+
}
|
|
51
|
+
console.log('');
|
|
52
|
+
}
|
|
53
|
+
} catch (err) {
|
|
54
|
+
spinner.stop();
|
|
55
|
+
console.error(chalk.red('Failed to fetch projects:'), err.message);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Show current project
|
|
62
|
+
* Command: vibe project current
|
|
63
|
+
*/
|
|
64
|
+
async function showCurrentProject() {
|
|
65
|
+
// Check authentication
|
|
66
|
+
if (!await hasValidCredentials()) {
|
|
67
|
+
console.log(chalk.red('Not authenticated. Run: vibe login'));
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const projectId = await getProjectId();
|
|
72
|
+
const projectName = await getProjectName();
|
|
73
|
+
|
|
74
|
+
if (!projectId) {
|
|
75
|
+
console.log(chalk.yellow('No project selected.'));
|
|
76
|
+
console.log(chalk.dim('Run "vibe login" or "vibe project select" to select a project.'));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const spinner = ora('Fetching project details...').start();
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const project = await api.get(`/api/projects/${projectId}`);
|
|
84
|
+
spinner.stop();
|
|
85
|
+
|
|
86
|
+
console.log(chalk.bold('\nCurrent Project:\n'));
|
|
87
|
+
console.log(` Name: ${project.name}`);
|
|
88
|
+
console.log(` ID: ${project._id}`);
|
|
89
|
+
if (project.description) {
|
|
90
|
+
console.log(` Description: ${project.description}`);
|
|
91
|
+
}
|
|
92
|
+
if (project.isDefault) {
|
|
93
|
+
console.log(chalk.dim(' (This is your default project)'));
|
|
94
|
+
}
|
|
95
|
+
} catch (err) {
|
|
96
|
+
spinner.stop();
|
|
97
|
+
// Fallback to cached info if API fails
|
|
98
|
+
if (projectName) {
|
|
99
|
+
console.log(chalk.bold('\nCurrent Project:\n'));
|
|
100
|
+
console.log(` Name: ${projectName}`);
|
|
101
|
+
console.log(` ID: ${projectId}`);
|
|
102
|
+
console.log(chalk.dim(' (Unable to fetch full details)'));
|
|
103
|
+
} else {
|
|
104
|
+
console.log(chalk.yellow(`Project ID: ${projectId}`));
|
|
105
|
+
console.log(chalk.dim('(Unable to fetch project details)'));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Select/switch project
|
|
112
|
+
* Command: vibe project select [projectId]
|
|
113
|
+
* @param {string} [projectIdArg] - Optional project ID or name to select
|
|
114
|
+
*/
|
|
115
|
+
async function selectProject(projectIdArg) {
|
|
116
|
+
// Check authentication
|
|
117
|
+
if (!await hasValidCredentials()) {
|
|
118
|
+
console.log(chalk.red('Not authenticated. Run: vibe login'));
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const spinner = ora('Fetching projects...').start();
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const projects = await api.get('/api/projects');
|
|
126
|
+
spinner.stop();
|
|
127
|
+
|
|
128
|
+
if (!projects || projects.length === 0) {
|
|
129
|
+
console.log(chalk.yellow('No projects found.'));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
let selected;
|
|
134
|
+
|
|
135
|
+
if (projectIdArg) {
|
|
136
|
+
// Find by ID or name (case-insensitive)
|
|
137
|
+
selected = projects.find(p =>
|
|
138
|
+
p._id === projectIdArg ||
|
|
139
|
+
p.name.toLowerCase() === projectIdArg.toLowerCase()
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
if (!selected) {
|
|
143
|
+
console.log(chalk.red(`Project not found: ${projectIdArg}`));
|
|
144
|
+
console.log(chalk.dim('\nAvailable projects:'));
|
|
145
|
+
projects.forEach(p => console.log(chalk.dim(` - ${p.name} (${p._id})`)));
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
// Interactive selection
|
|
150
|
+
const currentProjectId = await getProjectId();
|
|
151
|
+
const choices = projects.map(p => ({
|
|
152
|
+
name: `${p.name}${p.isDefault ? chalk.dim(' (default)') : ''}${p._id === currentProjectId ? chalk.green(' ← current') : ''}`,
|
|
153
|
+
value: p
|
|
154
|
+
}));
|
|
155
|
+
|
|
156
|
+
const result = await inquirer.prompt([{
|
|
157
|
+
type: 'list',
|
|
158
|
+
name: 'selected',
|
|
159
|
+
message: 'Select a project:',
|
|
160
|
+
choices
|
|
161
|
+
}]);
|
|
162
|
+
|
|
163
|
+
selected = result.selected;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Store the selected project
|
|
167
|
+
await setProjectId(selected._id, selected.name);
|
|
168
|
+
console.log(chalk.green(`✓ Switched to project: ${selected.name}`));
|
|
169
|
+
|
|
170
|
+
} catch (err) {
|
|
171
|
+
spinner.stop();
|
|
172
|
+
console.error(chalk.red('Failed to switch project:'), err.message);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Register project commands with Commander
|
|
179
|
+
* @param {import('commander').Command} program - Commander program instance
|
|
180
|
+
*/
|
|
181
|
+
function registerProjectCommands(program) {
|
|
182
|
+
// vibe projects - List all projects
|
|
183
|
+
program
|
|
184
|
+
.command('projects')
|
|
185
|
+
.description('List your accessible projects')
|
|
186
|
+
.action(listProjects);
|
|
187
|
+
|
|
188
|
+
// vibe project - Project subcommands
|
|
189
|
+
const projectCmd = program
|
|
190
|
+
.command('project')
|
|
191
|
+
.description('Manage project context');
|
|
192
|
+
|
|
193
|
+
// vibe project current
|
|
194
|
+
projectCmd
|
|
195
|
+
.command('current')
|
|
196
|
+
.description('Show current project')
|
|
197
|
+
.action(showCurrentProject);
|
|
198
|
+
|
|
199
|
+
// vibe project select [projectId]
|
|
200
|
+
projectCmd
|
|
201
|
+
.command('select [projectId]')
|
|
202
|
+
.description('Switch to a different project (by ID or name)')
|
|
203
|
+
.action(selectProject);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
module.exports = {
|
|
207
|
+
listProjects,
|
|
208
|
+
showCurrentProject,
|
|
209
|
+
selectProject,
|
|
210
|
+
registerProjectCommands
|
|
211
|
+
};
|
|
@@ -121,9 +121,47 @@ async function hasValidCredentials() {
|
|
|
121
121
|
return true;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
/**
|
|
125
|
+
* CR-2026-043: Get stored project ID
|
|
126
|
+
* @returns {Promise<string|null>} Project ID or null if not set
|
|
127
|
+
*/
|
|
128
|
+
async function getProjectId() {
|
|
129
|
+
const creds = await getCredentials();
|
|
130
|
+
return creds?.projectId || null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* CR-2026-043: Get stored project name
|
|
135
|
+
* @returns {Promise<string|null>} Project name or null if not set
|
|
136
|
+
*/
|
|
137
|
+
async function getProjectName() {
|
|
138
|
+
const creds = await getCredentials();
|
|
139
|
+
return creds?.projectName || null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* CR-2026-043: Set project ID (updates existing credentials)
|
|
144
|
+
* @param {string} projectId - Project ID to store
|
|
145
|
+
* @param {string} projectName - Project name for display
|
|
146
|
+
* @returns {Promise<void>}
|
|
147
|
+
*/
|
|
148
|
+
async function setProjectId(projectId, projectName) {
|
|
149
|
+
const creds = await getCredentials();
|
|
150
|
+
if (creds) {
|
|
151
|
+
await storeCredentials({
|
|
152
|
+
...creds,
|
|
153
|
+
projectId,
|
|
154
|
+
projectName
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
124
159
|
module.exports = {
|
|
125
160
|
storeCredentials,
|
|
126
161
|
getCredentials,
|
|
127
162
|
deleteCredentials,
|
|
128
|
-
hasValidCredentials
|
|
163
|
+
hasValidCredentials,
|
|
164
|
+
getProjectId,
|
|
165
|
+
getProjectName,
|
|
166
|
+
setProjectId
|
|
129
167
|
};
|
package/src/mcp/tools.js
CHANGED
|
@@ -226,7 +226,7 @@ const tools = [
|
|
|
226
226
|
|
|
227
227
|
{
|
|
228
228
|
name: 'vibe_update_artifact',
|
|
229
|
-
description: 'Update an existing artifact. You can update the status, content, title, or metadata.',
|
|
229
|
+
description: 'Update an existing artifact. You can update the status, content, title, or metadata. WARNING: If you provide a "files" array, it REPLACES ALL existing files. To safely add a single file without affecting others, use vibe_append_file instead.',
|
|
230
230
|
inputSchema: {
|
|
231
231
|
type: 'object',
|
|
232
232
|
properties: {
|
|
@@ -249,7 +249,7 @@ const tools = [
|
|
|
249
249
|
},
|
|
250
250
|
files: {
|
|
251
251
|
type: 'array',
|
|
252
|
-
description: '
|
|
252
|
+
description: 'WARNING: This REPLACES ALL existing files. Use vibe_append_file to safely add a single file.',
|
|
253
253
|
items: {
|
|
254
254
|
type: 'object',
|
|
255
255
|
properties: {
|
|
@@ -270,6 +270,32 @@ const tools = [
|
|
|
270
270
|
}
|
|
271
271
|
},
|
|
272
272
|
|
|
273
|
+
{
|
|
274
|
+
name: 'vibe_append_file',
|
|
275
|
+
description: 'Safely append or update a single file in an artifact WITHOUT affecting other files. Use this instead of vibe_update_artifact when you only need to add one file (e.g., adding verification-report.md to a CR). This is the SAFE way to add files - it will not destroy existing documentation.',
|
|
276
|
+
inputSchema: {
|
|
277
|
+
type: 'object',
|
|
278
|
+
properties: {
|
|
279
|
+
artifactId: {
|
|
280
|
+
type: 'string',
|
|
281
|
+
description: 'The artifact ID to add the file to (e.g., "CR-2025-024")'
|
|
282
|
+
},
|
|
283
|
+
name: {
|
|
284
|
+
type: 'string',
|
|
285
|
+
description: 'Filename to add or update (e.g., "verification-report.md")'
|
|
286
|
+
},
|
|
287
|
+
content: {
|
|
288
|
+
type: 'string',
|
|
289
|
+
description: 'Full file content (must be complete, not abbreviated)'
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
required: ['artifactId', 'name', 'content']
|
|
293
|
+
},
|
|
294
|
+
handler: async ({ artifactId, name, content }) => {
|
|
295
|
+
return await api.post(`/api/mcp/artifacts/${artifactId}/files`, { name, content });
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
|
|
273
299
|
{
|
|
274
300
|
name: 'vibe_list_artifacts',
|
|
275
301
|
description: 'List your stored artifacts with optional filters. Use this to see what governance documents you have stored.',
|