@vibe-assurance/cli 1.7.9 → 1.10.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/package.json +1 -1
- package/src/api/client.js +34 -3
- package/src/mcp/tools.js +39 -151
package/package.json
CHANGED
package/src/api/client.js
CHANGED
|
@@ -29,7 +29,7 @@ const API_BASE_URL = process.env.VIBE_API_URL || getEnvironmentUrl(DEFAULT_ENVIR
|
|
|
29
29
|
* @returns {Promise<import('axios').AxiosInstance>}
|
|
30
30
|
*/
|
|
31
31
|
async function createClient() {
|
|
32
|
-
|
|
32
|
+
let creds = await getCredentials();
|
|
33
33
|
if (!creds || !creds.accessToken) {
|
|
34
34
|
throw new Error('Not authenticated. Run: vibe login');
|
|
35
35
|
}
|
|
@@ -37,13 +37,37 @@ async function createClient() {
|
|
|
37
37
|
// CR-2026-061: Get API URL from stored environment
|
|
38
38
|
const apiBaseUrl = await getApiBaseUrl();
|
|
39
39
|
|
|
40
|
+
// Pre-emptive token refresh: If token expires within 5 minutes, refresh now
|
|
41
|
+
// This avoids race conditions where the token expires during an API call
|
|
42
|
+
if (creds.expiresAt && creds.refreshToken) {
|
|
43
|
+
const expiresAt = new Date(creds.expiresAt);
|
|
44
|
+
const now = new Date();
|
|
45
|
+
const bufferMs = 5 * 60 * 1000; // 5 minutes
|
|
46
|
+
|
|
47
|
+
if (expiresAt.getTime() - bufferMs < now.getTime()) {
|
|
48
|
+
try {
|
|
49
|
+
const newTokens = await refreshToken(creds.refreshToken);
|
|
50
|
+
// Preserve existing credentials (environment, projectId, user info)
|
|
51
|
+
creds = {
|
|
52
|
+
...creds,
|
|
53
|
+
...newTokens
|
|
54
|
+
};
|
|
55
|
+
await storeCredentials(creds);
|
|
56
|
+
} catch (refreshError) {
|
|
57
|
+
// Pre-emptive refresh failed - will try again on 401
|
|
58
|
+
// Don't throw here, let the request proceed with old token
|
|
59
|
+
console.error('Pre-emptive token refresh failed, will retry on 401');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
40
64
|
// CR-2026-043: Get current project ID for scoping
|
|
41
65
|
const projectId = await getProjectId();
|
|
42
66
|
|
|
43
67
|
const headers = {
|
|
44
68
|
'Authorization': `Bearer ${creds.accessToken}`,
|
|
45
69
|
'Content-Type': 'application/json',
|
|
46
|
-
'User-Agent': 'vibe-cli/1.
|
|
70
|
+
'User-Agent': 'vibe-cli/1.10.0'
|
|
47
71
|
};
|
|
48
72
|
|
|
49
73
|
// CR-2026-043: Add project header if available
|
|
@@ -69,7 +93,14 @@ async function createClient() {
|
|
|
69
93
|
|
|
70
94
|
try {
|
|
71
95
|
const newTokens = await refreshToken(creds.refreshToken);
|
|
72
|
-
|
|
96
|
+
|
|
97
|
+
// CRITICAL: Preserve existing credentials (environment, projectId, user info)
|
|
98
|
+
// when storing new tokens. Only update token-related fields.
|
|
99
|
+
const currentCreds = await getCredentials();
|
|
100
|
+
await storeCredentials({
|
|
101
|
+
...currentCreds, // Preserve environment, projectId, username, email, role, etc.
|
|
102
|
+
...newTokens // Update accessToken, refreshToken, expiresAt
|
|
103
|
+
});
|
|
73
104
|
|
|
74
105
|
// Update the failed request with new token
|
|
75
106
|
originalRequest.headers['Authorization'] = `Bearer ${newTokens.accessToken}`;
|
package/src/mcp/tools.js
CHANGED
|
@@ -223,7 +223,7 @@ const tools = [
|
|
|
223
223
|
properties: {
|
|
224
224
|
type: {
|
|
225
225
|
type: 'string',
|
|
226
|
-
enum: ['CR', 'RISK', 'VULNERABILITY', 'REPORT', '
|
|
226
|
+
enum: ['CR', 'RISK', 'VULNERABILITY', 'REPORT', 'STANDARD', 'PLAN', 'ARCHITECTURE', 'CONFIG'],
|
|
227
227
|
description: 'Type of artifact'
|
|
228
228
|
},
|
|
229
229
|
artifactId: {
|
|
@@ -348,7 +348,7 @@ const tools = [
|
|
|
348
348
|
properties: {
|
|
349
349
|
type: {
|
|
350
350
|
type: 'string',
|
|
351
|
-
enum: ['CR', 'RISK', 'VULNERABILITY', 'REPORT', '
|
|
351
|
+
enum: ['CR', 'RISK', 'VULNERABILITY', 'REPORT', 'STANDARD', 'PLAN', 'ARCHITECTURE', 'CONFIG'],
|
|
352
352
|
description: 'Filter by artifact type. Use "PLAN" to find strategic plans.'
|
|
353
353
|
},
|
|
354
354
|
status: {
|
|
@@ -755,6 +755,10 @@ const tools = [
|
|
|
755
755
|
location: {
|
|
756
756
|
type: 'string',
|
|
757
757
|
description: 'File path or component where vulnerability exists'
|
|
758
|
+
},
|
|
759
|
+
remediationPlanId: {
|
|
760
|
+
type: 'string',
|
|
761
|
+
description: 'Link to remediation plan (e.g., "RMP-VUL-001")'
|
|
758
762
|
}
|
|
759
763
|
},
|
|
760
764
|
required: ['vulId', 'title', 'description', 'severity']
|
|
@@ -784,7 +788,7 @@ const tools = [
|
|
|
784
788
|
|
|
785
789
|
{
|
|
786
790
|
name: 'vibe_update_vulnerability',
|
|
787
|
-
description: 'Update a vulnerability\'s status, severity,
|
|
791
|
+
description: 'Update a vulnerability\'s status, severity, link it to a remediation CR, or link to a remediation plan.',
|
|
788
792
|
inputSchema: {
|
|
789
793
|
type: 'object',
|
|
790
794
|
properties: {
|
|
@@ -805,6 +809,10 @@ const tools = [
|
|
|
805
809
|
relatedCR: {
|
|
806
810
|
type: 'string',
|
|
807
811
|
description: 'Link to remediation CR (e.g., "CR-2026-042")'
|
|
812
|
+
},
|
|
813
|
+
remediationPlanId: {
|
|
814
|
+
type: 'string',
|
|
815
|
+
description: 'Link to remediation plan (e.g., "RMP-VUL-001")'
|
|
808
816
|
}
|
|
809
817
|
},
|
|
810
818
|
required: ['vulId']
|
|
@@ -815,139 +823,19 @@ const tools = [
|
|
|
815
823
|
},
|
|
816
824
|
|
|
817
825
|
// ============================================================================
|
|
818
|
-
//
|
|
819
|
-
// ============================================================================
|
|
820
|
-
|
|
821
|
-
{
|
|
822
|
-
name: 'vibe_list_sops',
|
|
823
|
-
description: 'List all Standard Operating Procedures (SOPs) for the project. SOPs define step-by-step procedures for operational tasks.',
|
|
824
|
-
inputSchema: {
|
|
825
|
-
type: 'object',
|
|
826
|
-
properties: {
|
|
827
|
-
status: {
|
|
828
|
-
type: 'string',
|
|
829
|
-
enum: ['Draft', 'Active', 'Completed', 'Closed'],
|
|
830
|
-
description: 'Filter by SOP status'
|
|
831
|
-
},
|
|
832
|
-
category: {
|
|
833
|
-
type: 'string',
|
|
834
|
-
description: 'Filter by category (e.g., "Security", "HR", "SDLC", "Change Management")'
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
},
|
|
838
|
-
handler: async (params = {}) => {
|
|
839
|
-
const query = new URLSearchParams();
|
|
840
|
-
if (params.status) query.set('status', params.status);
|
|
841
|
-
if (params.category) query.set('category', params.category);
|
|
842
|
-
const queryString = query.toString();
|
|
843
|
-
const path = queryString ? `/api/mcp/sops?${queryString}` : '/api/mcp/sops';
|
|
844
|
-
return await api.get(path);
|
|
845
|
-
}
|
|
846
|
-
},
|
|
847
|
-
|
|
848
|
-
{
|
|
849
|
-
name: 'vibe_store_sop',
|
|
850
|
-
description: 'Create a new Standard Operating Procedure (SOP). SOPs define step-by-step procedures for operational tasks like onboarding, offboarding, access reviews, etc.',
|
|
851
|
-
inputSchema: {
|
|
852
|
-
type: 'object',
|
|
853
|
-
properties: {
|
|
854
|
-
sopId: {
|
|
855
|
-
type: 'string',
|
|
856
|
-
description: 'Unique SOP ID (e.g., "SOP-001", "SOP-SDLC-001")'
|
|
857
|
-
},
|
|
858
|
-
title: {
|
|
859
|
-
type: 'string',
|
|
860
|
-
description: 'Title of the SOP (e.g., "Employee Onboarding Checklist")'
|
|
861
|
-
},
|
|
862
|
-
content: {
|
|
863
|
-
type: 'string',
|
|
864
|
-
description: 'Full SOP content in markdown format'
|
|
865
|
-
},
|
|
866
|
-
status: {
|
|
867
|
-
type: 'string',
|
|
868
|
-
enum: ['Draft', 'Active', 'Completed', 'Closed'],
|
|
869
|
-
description: 'SOP status (default: Active)'
|
|
870
|
-
},
|
|
871
|
-
metadata: {
|
|
872
|
-
type: 'object',
|
|
873
|
-
description: 'Additional metadata (e.g., category, version, owner)',
|
|
874
|
-
additionalProperties: true
|
|
875
|
-
}
|
|
876
|
-
},
|
|
877
|
-
required: ['sopId', 'title', 'content']
|
|
878
|
-
},
|
|
879
|
-
handler: async (params) => {
|
|
880
|
-
return await api.post('/api/mcp/sops', params);
|
|
881
|
-
}
|
|
882
|
-
},
|
|
883
|
-
|
|
884
|
-
{
|
|
885
|
-
name: 'vibe_get_sop',
|
|
886
|
-
description: 'Get a specific SOP by ID with full content.',
|
|
887
|
-
inputSchema: {
|
|
888
|
-
type: 'object',
|
|
889
|
-
properties: {
|
|
890
|
-
sopId: {
|
|
891
|
-
type: 'string',
|
|
892
|
-
description: 'The SOP ID to retrieve (e.g., "SOP-001")'
|
|
893
|
-
}
|
|
894
|
-
},
|
|
895
|
-
required: ['sopId']
|
|
896
|
-
},
|
|
897
|
-
handler: async ({ sopId }) => {
|
|
898
|
-
return await api.get(`/api/mcp/sops/${sopId}`);
|
|
899
|
-
}
|
|
900
|
-
},
|
|
901
|
-
|
|
902
|
-
{
|
|
903
|
-
name: 'vibe_update_sop',
|
|
904
|
-
description: 'Update an existing SOP\'s content, status, or metadata.',
|
|
905
|
-
inputSchema: {
|
|
906
|
-
type: 'object',
|
|
907
|
-
properties: {
|
|
908
|
-
sopId: {
|
|
909
|
-
type: 'string',
|
|
910
|
-
description: 'The SOP ID to update'
|
|
911
|
-
},
|
|
912
|
-
title: {
|
|
913
|
-
type: 'string',
|
|
914
|
-
description: 'Updated title'
|
|
915
|
-
},
|
|
916
|
-
content: {
|
|
917
|
-
type: 'string',
|
|
918
|
-
description: 'Updated content'
|
|
919
|
-
},
|
|
920
|
-
status: {
|
|
921
|
-
type: 'string',
|
|
922
|
-
enum: ['Draft', 'Active', 'Completed', 'Closed'],
|
|
923
|
-
description: 'Updated status'
|
|
924
|
-
},
|
|
925
|
-
metadata: {
|
|
926
|
-
type: 'object',
|
|
927
|
-
description: 'Updated metadata'
|
|
928
|
-
}
|
|
929
|
-
},
|
|
930
|
-
required: ['sopId']
|
|
931
|
-
},
|
|
932
|
-
handler: async ({ sopId, ...updates }) => {
|
|
933
|
-
return await api.put(`/api/mcp/sops/${sopId}`, updates);
|
|
934
|
-
}
|
|
935
|
-
},
|
|
936
|
-
|
|
937
|
-
// ============================================================================
|
|
938
|
-
// POLICY MANAGEMENT TOOLS (CR-2026-054)
|
|
826
|
+
// STANDARDS MANAGEMENT TOOLS (CR-2026-063: Renamed from Policies)
|
|
939
827
|
// ============================================================================
|
|
940
828
|
|
|
941
829
|
{
|
|
942
|
-
name: '
|
|
943
|
-
description: 'List all
|
|
830
|
+
name: 'vibe_list_standards',
|
|
831
|
+
description: 'List all standards for the project. Standards define organizational coding standards, security guidelines, and best practices.',
|
|
944
832
|
inputSchema: {
|
|
945
833
|
type: 'object',
|
|
946
834
|
properties: {
|
|
947
835
|
status: {
|
|
948
836
|
type: 'string',
|
|
949
837
|
enum: ['Draft', 'Active', 'Completed', 'Closed'],
|
|
950
|
-
description: 'Filter by
|
|
838
|
+
description: 'Filter by standard status'
|
|
951
839
|
},
|
|
952
840
|
category: {
|
|
953
841
|
type: 'string',
|
|
@@ -960,33 +848,33 @@ const tools = [
|
|
|
960
848
|
if (params.status) query.set('status', params.status);
|
|
961
849
|
if (params.category) query.set('category', params.category);
|
|
962
850
|
const queryString = query.toString();
|
|
963
|
-
const path = queryString ? `/api/mcp/
|
|
851
|
+
const path = queryString ? `/api/mcp/standards?${queryString}` : '/api/mcp/standards';
|
|
964
852
|
return await api.get(path);
|
|
965
853
|
}
|
|
966
854
|
},
|
|
967
855
|
|
|
968
856
|
{
|
|
969
|
-
name: '
|
|
970
|
-
description: 'Create a new
|
|
857
|
+
name: 'vibe_store_standard',
|
|
858
|
+
description: 'Create a new standard document. Standards define organizational coding standards, security guidelines, and best practices.',
|
|
971
859
|
inputSchema: {
|
|
972
860
|
type: 'object',
|
|
973
861
|
properties: {
|
|
974
|
-
|
|
862
|
+
standardId: {
|
|
975
863
|
type: 'string',
|
|
976
|
-
description: 'Unique
|
|
864
|
+
description: 'Unique standard ID (e.g., "STD-001", "STD-SEC-001")'
|
|
977
865
|
},
|
|
978
866
|
title: {
|
|
979
867
|
type: 'string',
|
|
980
|
-
description: 'Title of the
|
|
868
|
+
description: 'Title of the standard (e.g., "Secure Coding Standard")'
|
|
981
869
|
},
|
|
982
870
|
content: {
|
|
983
871
|
type: 'string',
|
|
984
|
-
description: 'Full
|
|
872
|
+
description: 'Full standard content in markdown format'
|
|
985
873
|
},
|
|
986
874
|
status: {
|
|
987
875
|
type: 'string',
|
|
988
876
|
enum: ['Draft', 'Active', 'Completed', 'Closed'],
|
|
989
|
-
description: '
|
|
877
|
+
description: 'Standard status (default: Active)'
|
|
990
878
|
},
|
|
991
879
|
metadata: {
|
|
992
880
|
type: 'object',
|
|
@@ -994,40 +882,40 @@ const tools = [
|
|
|
994
882
|
additionalProperties: true
|
|
995
883
|
}
|
|
996
884
|
},
|
|
997
|
-
required: ['
|
|
885
|
+
required: ['standardId', 'title', 'content']
|
|
998
886
|
},
|
|
999
887
|
handler: async (params) => {
|
|
1000
|
-
return await api.post('/api/mcp/
|
|
888
|
+
return await api.post('/api/mcp/standards', params);
|
|
1001
889
|
}
|
|
1002
890
|
},
|
|
1003
891
|
|
|
1004
892
|
{
|
|
1005
|
-
name: '
|
|
1006
|
-
description: 'Get a specific
|
|
893
|
+
name: 'vibe_get_standard',
|
|
894
|
+
description: 'Get a specific standard by ID with full content.',
|
|
1007
895
|
inputSchema: {
|
|
1008
896
|
type: 'object',
|
|
1009
897
|
properties: {
|
|
1010
|
-
|
|
898
|
+
standardId: {
|
|
1011
899
|
type: 'string',
|
|
1012
|
-
description: 'The
|
|
900
|
+
description: 'The standard ID to retrieve (e.g., "STD-001")'
|
|
1013
901
|
}
|
|
1014
902
|
},
|
|
1015
|
-
required: ['
|
|
903
|
+
required: ['standardId']
|
|
1016
904
|
},
|
|
1017
|
-
handler: async ({
|
|
1018
|
-
return await api.get(`/api/mcp/
|
|
905
|
+
handler: async ({ standardId }) => {
|
|
906
|
+
return await api.get(`/api/mcp/standards/${standardId}`);
|
|
1019
907
|
}
|
|
1020
908
|
},
|
|
1021
909
|
|
|
1022
910
|
{
|
|
1023
|
-
name: '
|
|
1024
|
-
description: 'Update an existing
|
|
911
|
+
name: 'vibe_update_standard',
|
|
912
|
+
description: 'Update an existing standard\'s content, status, or metadata.',
|
|
1025
913
|
inputSchema: {
|
|
1026
914
|
type: 'object',
|
|
1027
915
|
properties: {
|
|
1028
|
-
|
|
916
|
+
standardId: {
|
|
1029
917
|
type: 'string',
|
|
1030
|
-
description: 'The
|
|
918
|
+
description: 'The standard ID to update'
|
|
1031
919
|
},
|
|
1032
920
|
title: {
|
|
1033
921
|
type: 'string',
|
|
@@ -1047,10 +935,10 @@ const tools = [
|
|
|
1047
935
|
description: 'Updated metadata'
|
|
1048
936
|
}
|
|
1049
937
|
},
|
|
1050
|
-
required: ['
|
|
938
|
+
required: ['standardId']
|
|
1051
939
|
},
|
|
1052
|
-
handler: async ({
|
|
1053
|
-
return await api.put(`/api/mcp/
|
|
940
|
+
handler: async ({ standardId, ...updates }) => {
|
|
941
|
+
return await api.put(`/api/mcp/standards/${standardId}`, updates);
|
|
1054
942
|
}
|
|
1055
943
|
}
|
|
1056
944
|
];
|