vibecodingmachine-core 2025.12.1-534 ā 2025.12.22-2230
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 +4 -1
- package/scripts/setup-database.js +108 -0
- package/src/auth/shared-auth-storage.js +43 -6
- package/src/compliance/compliance-manager.js +249 -0
- package/src/compliance/compliance-prompt.js +183 -0
- package/src/database/migrations.js +289 -0
- package/src/database/user-database-client.js +266 -0
- package/src/database/user-schema.js +118 -0
- package/src/ide-integration/applescript-manager.cjs +199 -145
- package/src/ide-integration/applescript-manager.js +234 -96
- package/src/ide-integration/claude-code-cli-manager.cjs +120 -1
- package/src/ide-integration/provider-manager.cjs +67 -1
- package/src/index.cjs +2 -0
- package/src/index.js +6 -0
- package/src/llm/direct-llm-manager.cjs +110 -73
- package/src/quota-management/index.js +108 -0
- package/src/sync/aws-setup.js +445 -0
- package/src/sync/sync-engine.js +410 -0
- package/src/utils/download-with-progress.js +92 -0
- package/src/utils/electron-update-checker.js +7 -0
- package/src/utils/env-helpers.js +54 -0
- package/src/utils/requirement-helpers.js +865 -100
- package/src/utils/requirements-parser.js +324 -0
- package/src/utils/update-checker.js +7 -0
- package/test-quota-system.js +67 -0
- package/test-requirement-stats.js +66 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibecodingmachine-core",
|
|
3
|
-
"version": "2025.12.
|
|
3
|
+
"version": "2025.12.22-2230",
|
|
4
4
|
"description": "Shared core logic for Vibe Coding Machine IDE integration",
|
|
5
5
|
"main": "src/index.cjs",
|
|
6
6
|
"module": "src/index.js",
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@aws-sdk/client-bedrock-runtime": "^3.932.0",
|
|
16
|
+
"@aws-sdk/client-dynamodb": "^3.600.0",
|
|
17
|
+
"@aws-sdk/lib-dynamodb": "^3.600.0",
|
|
18
|
+
"@aws-sdk/client-cognito-identity-provider": "^3.600.0",
|
|
16
19
|
"chrome-remote-interface": "^0.33.0",
|
|
17
20
|
"fs-extra": "^11.1.1",
|
|
18
21
|
"jsonwebtoken": "^9.0.2",
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Database Setup Script for VibeCodingMachine Enhanced User Tracking
|
|
5
|
+
*
|
|
6
|
+
* This script creates the necessary DynamoDB tables for the enhanced
|
|
7
|
+
* user tracking system.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const DatabaseMigrations = require('../src/database/migrations')
|
|
11
|
+
|
|
12
|
+
async function main() {
|
|
13
|
+
console.log('š VibeCodingMachine Database Setup')
|
|
14
|
+
console.log('=====================================\n')
|
|
15
|
+
|
|
16
|
+
const migrations = new DatabaseMigrations()
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
// Check current table status
|
|
20
|
+
console.log('š Checking current database status...')
|
|
21
|
+
const tableStatuses = await migrations.getAllTableStatus()
|
|
22
|
+
|
|
23
|
+
console.log('\nCurrent Table Status:')
|
|
24
|
+
tableStatuses.forEach(status => {
|
|
25
|
+
const statusIcon = status.status === 'ACTIVE' ? 'ā
' :
|
|
26
|
+
status.status === 'NOT_FOUND' ? 'ā' : 'ā³'
|
|
27
|
+
console.log(` ${statusIcon} ${status.name}: ${status.status}`)
|
|
28
|
+
if (status.itemCount !== undefined) {
|
|
29
|
+
console.log(` Items: ${status.itemCount}, Size: ${Math.round(status.sizeBytes / 1024)} KB`)
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
console.log('\nš Running database migrations...')
|
|
34
|
+
await migrations.runMigrations()
|
|
35
|
+
|
|
36
|
+
// Check final status
|
|
37
|
+
console.log('\nš Final database status...')
|
|
38
|
+
const finalStatuses = await migrations.getAllTableStatus()
|
|
39
|
+
|
|
40
|
+
console.log('\nFinal Table Status:')
|
|
41
|
+
finalStatuses.forEach(status => {
|
|
42
|
+
const statusIcon = status.status === 'ACTIVE' ? 'ā
' :
|
|
43
|
+
status.status === 'CREATING' ? 'ā³' : 'ā'
|
|
44
|
+
console.log(` ${statusIcon} ${status.name}: ${status.status}`)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
console.log('\nš Database setup completed successfully!')
|
|
48
|
+
console.log('\nNext steps:')
|
|
49
|
+
console.log('1. Update your application environment variables with AWS credentials')
|
|
50
|
+
console.log('2. Test the user registration flow')
|
|
51
|
+
console.log('3. Deploy the admin dashboard')
|
|
52
|
+
console.log('4. Configure compliance policies')
|
|
53
|
+
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('\nā Database setup failed:', error.message)
|
|
56
|
+
console.error('\nTroubleshooting:')
|
|
57
|
+
console.error('1. Check your AWS credentials and permissions')
|
|
58
|
+
console.error('2. Ensure you have DynamoDB access in your AWS region')
|
|
59
|
+
console.error('3. Verify your AWS region is set correctly')
|
|
60
|
+
console.error('4. Check for any existing tables with the same names')
|
|
61
|
+
process.exit(1)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Handle command line arguments
|
|
66
|
+
const args = process.argv.slice(2)
|
|
67
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
68
|
+
console.log('VibeCodingMachine Database Setup')
|
|
69
|
+
console.log('')
|
|
70
|
+
console.log('Usage: node setup-database.js [options]')
|
|
71
|
+
console.log('')
|
|
72
|
+
console.log('Options:')
|
|
73
|
+
console.log(' --help, -h Show this help message')
|
|
74
|
+
console.log(' --status Show current table status only')
|
|
75
|
+
console.log('')
|
|
76
|
+
console.log('Environment Variables:')
|
|
77
|
+
console.log(' AWS_REGION AWS region (default: us-east-1)')
|
|
78
|
+
console.log(' AWS_ACCESS_KEY_ID AWS access key')
|
|
79
|
+
console.log(' AWS_SECRET_ACCESS_KEY AWS secret key')
|
|
80
|
+
console.log('')
|
|
81
|
+
console.log('Required AWS Permissions:')
|
|
82
|
+
console.log(' - dynamodb:CreateTable')
|
|
83
|
+
console.log(' - dynamodb:DescribeTable')
|
|
84
|
+
console.log(' - dynamodb:ListTables')
|
|
85
|
+
process.exit(0)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (args.includes('--status')) {
|
|
89
|
+
// Just show status, don't run migrations
|
|
90
|
+
const migrations = new DatabaseMigrations()
|
|
91
|
+
migrations.getAllTableStatus().then(statuses => {
|
|
92
|
+
console.log('Current Table Status:')
|
|
93
|
+
statuses.forEach(status => {
|
|
94
|
+
const statusIcon = status.status === 'ACTIVE' ? 'ā
' :
|
|
95
|
+
status.status === 'NOT_FOUND' ? 'ā' : 'ā³'
|
|
96
|
+
console.log(` ${statusIcon} ${status.name}: ${status.status}`)
|
|
97
|
+
if (status.itemCount !== undefined) {
|
|
98
|
+
console.log(` Items: ${status.itemCount}, Size: ${Math.round(status.sizeBytes / 1024)} KB`)
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
}).catch(error => {
|
|
102
|
+
console.error('Error checking table status:', error.message)
|
|
103
|
+
process.exit(1)
|
|
104
|
+
})
|
|
105
|
+
} else {
|
|
106
|
+
// Run full setup
|
|
107
|
+
main()
|
|
108
|
+
}
|
|
@@ -46,13 +46,15 @@ class SharedAuthStorage {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* Get stored token
|
|
49
|
+
* Get stored token (returns id_token for backward compatibility)
|
|
50
50
|
*/
|
|
51
51
|
async getToken() {
|
|
52
52
|
try {
|
|
53
53
|
if (await fs.pathExists(TOKEN_FILE)) {
|
|
54
54
|
const data = await fs.readJson(TOKEN_FILE);
|
|
55
|
-
|
|
55
|
+
// If data.token exists (old format), return it
|
|
56
|
+
// If data.id_token exists (new format), return it
|
|
57
|
+
return data.id_token || data.token;
|
|
56
58
|
}
|
|
57
59
|
} catch (error) {
|
|
58
60
|
console.error('Failed to read token:', error);
|
|
@@ -61,15 +63,50 @@ class SharedAuthStorage {
|
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
/**
|
|
64
|
-
*
|
|
66
|
+
* Get stored refresh token
|
|
65
67
|
*/
|
|
66
|
-
async
|
|
68
|
+
async getRefreshToken() {
|
|
69
|
+
try {
|
|
70
|
+
if (await fs.pathExists(TOKEN_FILE)) {
|
|
71
|
+
const data = await fs.readJson(TOKEN_FILE);
|
|
72
|
+
return data.refresh_token;
|
|
73
|
+
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error('Failed to read refresh token:', error);
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Save token (supports both string token and object with tokens)
|
|
82
|
+
*/
|
|
83
|
+
async saveToken(tokenOrTokens) {
|
|
67
84
|
await fs.ensureDir(CONFIG_DIR);
|
|
68
|
-
|
|
85
|
+
|
|
86
|
+
let tokenData = {};
|
|
87
|
+
let idToken = '';
|
|
88
|
+
|
|
89
|
+
if (typeof tokenOrTokens === 'string') {
|
|
90
|
+
// Legacy format: just the ID token
|
|
91
|
+
tokenData = { token: tokenOrTokens, id_token: tokenOrTokens };
|
|
92
|
+
idToken = tokenOrTokens;
|
|
93
|
+
} else {
|
|
94
|
+
// New format: object with id_token, access_token, refresh_token
|
|
95
|
+
tokenData = {
|
|
96
|
+
id_token: tokenOrTokens.id_token,
|
|
97
|
+
access_token: tokenOrTokens.access_token,
|
|
98
|
+
refresh_token: tokenOrTokens.refresh_token,
|
|
99
|
+
// Keep legacy field for backward compatibility
|
|
100
|
+
token: tokenOrTokens.id_token
|
|
101
|
+
};
|
|
102
|
+
idToken = tokenOrTokens.id_token;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
await fs.writeJson(TOKEN_FILE, tokenData, { spaces: 2 });
|
|
69
106
|
|
|
70
107
|
// Also save user profile from token
|
|
71
108
|
try {
|
|
72
|
-
const payload = this.decodeJWT(
|
|
109
|
+
const payload = this.decodeJWT(idToken);
|
|
73
110
|
const email = payload.email;
|
|
74
111
|
|
|
75
112
|
// Note: Beta access control is handled server-side by Cognito Pre-Auth Lambda
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compliance Manager for Terms of Service and Privacy Policy
|
|
3
|
+
*
|
|
4
|
+
* This module handles checking and managing user compliance with
|
|
5
|
+
* terms of service and privacy policy requirements.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const UserDatabase = require('../database/user-schema')
|
|
9
|
+
const fs = require('fs').promises
|
|
10
|
+
const path = require('path')
|
|
11
|
+
|
|
12
|
+
class ComplianceManager {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.userDb = new UserDatabase()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Check if user needs to acknowledge terms/privacy
|
|
19
|
+
* Returns what needs to be acknowledged
|
|
20
|
+
*/
|
|
21
|
+
async checkComplianceStatus(userId) {
|
|
22
|
+
const user = await this.userDb.getUser(userId)
|
|
23
|
+
|
|
24
|
+
if (!user) {
|
|
25
|
+
throw new Error('User not found')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const status = {
|
|
29
|
+
termsAccepted: user.termsAccepted || false,
|
|
30
|
+
privacyAccepted: user.privacyAccepted || false,
|
|
31
|
+
termsAcceptedDate: user.termsAcceptedDate,
|
|
32
|
+
privacyAcceptedDate: user.privacyAcceptedDate,
|
|
33
|
+
needsAcknowledgment: false,
|
|
34
|
+
requiredActions: []
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check if terms need to be acknowledged
|
|
38
|
+
if (!status.termsAccepted) {
|
|
39
|
+
status.needsAcknowledgment = true
|
|
40
|
+
status.requiredActions.push('terms')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Check if privacy policy needs to be acknowledged
|
|
44
|
+
if (!status.privacyAccepted) {
|
|
45
|
+
status.needsAcknowledgment = true
|
|
46
|
+
status.requiredActions.push('privacy')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return status
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Record user's acknowledgment of terms and/or privacy policy
|
|
54
|
+
*/
|
|
55
|
+
async recordAcknowledgment(userId, acknowledgments) {
|
|
56
|
+
const { terms, privacy } = acknowledgments
|
|
57
|
+
|
|
58
|
+
const updateData = {}
|
|
59
|
+
|
|
60
|
+
if (terms !== undefined) {
|
|
61
|
+
updateData.termsAccepted = terms
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (privacy !== undefined) {
|
|
65
|
+
updateData.privacyAccepted = privacy
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
await this.userDb.updateComplianceStatus(userId, updateData)
|
|
69
|
+
|
|
70
|
+
// Log the acknowledgment activity
|
|
71
|
+
await this.userDb.trackActivity(userId, {
|
|
72
|
+
action: 'compliance_acknowledgment',
|
|
73
|
+
interface: 'system',
|
|
74
|
+
duration: 0,
|
|
75
|
+
metadata: {
|
|
76
|
+
termsAccepted: terms,
|
|
77
|
+
privacyAccepted: privacy,
|
|
78
|
+
timestamp: Date.now()
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
return await this.checkComplianceStatus(userId)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get terms of service content
|
|
87
|
+
*/
|
|
88
|
+
async getTermsOfService() {
|
|
89
|
+
try {
|
|
90
|
+
const termsPath = path.join(__dirname, '../../admin/src/content/terms-of-service.md')
|
|
91
|
+
const content = await fs.readFile(termsPath, 'utf8')
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
content,
|
|
95
|
+
version: '1.0',
|
|
96
|
+
effectiveDate: '2025-12-09',
|
|
97
|
+
lastUpdated: '2025-12-09'
|
|
98
|
+
}
|
|
99
|
+
} catch (error) {
|
|
100
|
+
// Fallback content if file not found
|
|
101
|
+
return {
|
|
102
|
+
content: this.getFallbackTerms(),
|
|
103
|
+
version: '1.0',
|
|
104
|
+
effectiveDate: '2025-12-09',
|
|
105
|
+
lastUpdated: '2025-12-09'
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get privacy policy content
|
|
112
|
+
*/
|
|
113
|
+
async getPrivacyPolicy() {
|
|
114
|
+
try {
|
|
115
|
+
const privacyPath = path.join(__dirname, '../../admin/src/content/privacy-policy.md')
|
|
116
|
+
const content = await fs.readFile(privacyPath, 'utf8')
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
content,
|
|
120
|
+
version: '1.0',
|
|
121
|
+
effectiveDate: '2025-12-09',
|
|
122
|
+
lastUpdated: '2025-12-09'
|
|
123
|
+
}
|
|
124
|
+
} catch (error) {
|
|
125
|
+
// Fallback content if file not found
|
|
126
|
+
return {
|
|
127
|
+
content: this.getFallbackPrivacy(),
|
|
128
|
+
version: '1.0',
|
|
129
|
+
effectiveDate: '2025-12-09',
|
|
130
|
+
lastUpdated: '2025-12-09'
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get compliance summary for all users (admin function)
|
|
137
|
+
*/
|
|
138
|
+
async getComplianceSummary() {
|
|
139
|
+
// This would typically scan all users, but for now return mock data
|
|
140
|
+
// In a real implementation, you'd scan the users table
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
totalUsers: 0,
|
|
144
|
+
compliantUsers: 0,
|
|
145
|
+
termsAcceptanceRate: 0,
|
|
146
|
+
privacyAcceptanceRate: 0,
|
|
147
|
+
recentAcknowledgments: [],
|
|
148
|
+
nonCompliantUsers: []
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Generate compliance report for admin dashboard
|
|
154
|
+
*/
|
|
155
|
+
async generateComplianceReport(options = {}) {
|
|
156
|
+
const { startDate, endDate, format = 'json' } = options
|
|
157
|
+
|
|
158
|
+
// This would generate a detailed compliance report
|
|
159
|
+
// For now, return a basic structure
|
|
160
|
+
|
|
161
|
+
const report = {
|
|
162
|
+
generatedAt: new Date().toISOString(),
|
|
163
|
+
period: {
|
|
164
|
+
start: startDate || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString(),
|
|
165
|
+
end: endDate || new Date().toISOString()
|
|
166
|
+
},
|
|
167
|
+
summary: await this.getComplianceSummary(),
|
|
168
|
+
details: {
|
|
169
|
+
termsAcceptances: [],
|
|
170
|
+
privacyAcceptances: [],
|
|
171
|
+
pendingUsers: []
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (format === 'csv') {
|
|
176
|
+
return this.convertReportToCSV(report)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return report
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Fallback terms of service content
|
|
184
|
+
*/
|
|
185
|
+
getFallbackTerms() {
|
|
186
|
+
return `# Terms of Service
|
|
187
|
+
|
|
188
|
+
By using VibeCodingMachine, you agree to these terms:
|
|
189
|
+
|
|
190
|
+
1. Use the service responsibly and legally
|
|
191
|
+
2. Respect intellectual property rights
|
|
192
|
+
3. Do not attempt to harm or disrupt the service
|
|
193
|
+
4. We may collect usage data to improve the service
|
|
194
|
+
5. We reserve the right to modify these terms
|
|
195
|
+
|
|
196
|
+
For full terms, visit: https://vibecodingmachine.com/terms
|
|
197
|
+
|
|
198
|
+
Effective Date: December 9, 2025`
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Fallback privacy policy content
|
|
203
|
+
*/
|
|
204
|
+
getFallbackPrivacy() {
|
|
205
|
+
return `# Privacy Policy
|
|
206
|
+
|
|
207
|
+
VibeCodingMachine collects and uses your information to provide our service:
|
|
208
|
+
|
|
209
|
+
**Information We Collect:**
|
|
210
|
+
- Account information (email, name)
|
|
211
|
+
- Computer and system information
|
|
212
|
+
- Usage statistics and activity logs
|
|
213
|
+
- Project information you provide
|
|
214
|
+
|
|
215
|
+
**How We Use Information:**
|
|
216
|
+
- To provide and improve our service
|
|
217
|
+
- For authentication and security
|
|
218
|
+
- To track usage and performance
|
|
219
|
+
- For customer support
|
|
220
|
+
|
|
221
|
+
**Data Protection:**
|
|
222
|
+
- We use industry-standard security measures
|
|
223
|
+
- We do not sell your personal information
|
|
224
|
+
- You can request data deletion
|
|
225
|
+
|
|
226
|
+
For full privacy policy, visit: https://vibecodingmachine.com/privacy
|
|
227
|
+
|
|
228
|
+
Effective Date: December 9, 2025`
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Convert compliance report to CSV format
|
|
233
|
+
*/
|
|
234
|
+
convertReportToCSV(report) {
|
|
235
|
+
// Basic CSV conversion - would be more detailed in real implementation
|
|
236
|
+
const headers = ['User ID', 'Email', 'Terms Accepted', 'Privacy Accepted', 'Date']
|
|
237
|
+
const rows = report.details.termsAcceptances.map(item => [
|
|
238
|
+
item.userId,
|
|
239
|
+
item.email,
|
|
240
|
+
item.termsAccepted,
|
|
241
|
+
item.privacyAccepted,
|
|
242
|
+
item.date
|
|
243
|
+
])
|
|
244
|
+
|
|
245
|
+
return [headers, ...rows].map(row => row.join(',')).join('\n')
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
module.exports = ComplianceManager
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compliance Prompt Utility
|
|
3
|
+
*
|
|
4
|
+
* Handles prompting users for terms and privacy acceptance
|
|
5
|
+
* across CLI and Electron interfaces
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const ComplianceManager = require('./compliance-manager')
|
|
9
|
+
|
|
10
|
+
class CompliancePrompt {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.complianceManager = new ComplianceManager()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Check and prompt for compliance if needed
|
|
17
|
+
* Returns true if compliant, false if user declined
|
|
18
|
+
*/
|
|
19
|
+
async checkAndPrompt(userId, interfaceType = 'cli') {
|
|
20
|
+
try {
|
|
21
|
+
const status = await this.complianceManager.checkComplianceStatus(userId)
|
|
22
|
+
|
|
23
|
+
if (!status.needsAcknowledgment) {
|
|
24
|
+
return true
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Prompt based on interface
|
|
28
|
+
if (interfaceType === 'cli') {
|
|
29
|
+
return await this.promptCLI(userId, status)
|
|
30
|
+
} else if (interfaceType === 'electron') {
|
|
31
|
+
return await this.promptElectron(userId, status)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return false
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error('Error checking compliance:', error)
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* CLI prompt for compliance
|
|
43
|
+
*/
|
|
44
|
+
async promptCLI(userId, status) {
|
|
45
|
+
const chalk = require('chalk')
|
|
46
|
+
|
|
47
|
+
// Dynamically require inquirer (only available in CLI context)
|
|
48
|
+
let inquirer
|
|
49
|
+
try {
|
|
50
|
+
inquirer = require('inquirer')
|
|
51
|
+
} catch (error) {
|
|
52
|
+
throw new Error('inquirer module not available - CLI prompting not supported in this context')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log(chalk.cyan('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'))
|
|
56
|
+
console.log(chalk.cyan.bold(' š Terms & Privacy Acknowledgment Required'))
|
|
57
|
+
console.log(chalk.cyan('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'))
|
|
58
|
+
|
|
59
|
+
console.log(chalk.white('Before continuing, please review and accept:\n'))
|
|
60
|
+
|
|
61
|
+
const questions = []
|
|
62
|
+
|
|
63
|
+
if (status.requiredActions.includes('terms')) {
|
|
64
|
+
const terms = await this.complianceManager.getTermsOfService()
|
|
65
|
+
|
|
66
|
+
console.log(chalk.yellow('š Terms of Service'))
|
|
67
|
+
console.log(chalk.gray('ā'.repeat(70)))
|
|
68
|
+
console.log(this.formatForCLI(terms.content))
|
|
69
|
+
console.log(chalk.gray('ā'.repeat(70)))
|
|
70
|
+
console.log(chalk.gray(`Version ${terms.version} | Effective: ${terms.effectiveDate}\n`))
|
|
71
|
+
|
|
72
|
+
questions.push({
|
|
73
|
+
type: 'confirm',
|
|
74
|
+
name: 'acceptTerms',
|
|
75
|
+
message: 'Do you accept the Terms of Service?',
|
|
76
|
+
default: false
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (status.requiredActions.includes('privacy')) {
|
|
81
|
+
const privacy = await this.complianceManager.getPrivacyPolicy()
|
|
82
|
+
|
|
83
|
+
console.log(chalk.yellow('š Privacy Policy'))
|
|
84
|
+
console.log(chalk.gray('ā'.repeat(70)))
|
|
85
|
+
console.log(this.formatForCLI(privacy.content))
|
|
86
|
+
console.log(chalk.gray('ā'.repeat(70)))
|
|
87
|
+
console.log(chalk.gray(`Version ${privacy.version} | Effective: ${privacy.effectiveDate}\n`))
|
|
88
|
+
|
|
89
|
+
questions.push({
|
|
90
|
+
type: 'confirm',
|
|
91
|
+
name: 'acceptPrivacy',
|
|
92
|
+
message: 'Do you accept the Privacy Policy?',
|
|
93
|
+
default: false
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const answers = await inquirer.prompt(questions)
|
|
98
|
+
|
|
99
|
+
// Check if user accepted all required items
|
|
100
|
+
const allAccepted =
|
|
101
|
+
(!status.requiredActions.includes('terms') || answers.acceptTerms) &&
|
|
102
|
+
(!status.requiredActions.includes('privacy') || answers.acceptPrivacy)
|
|
103
|
+
|
|
104
|
+
if (!allAccepted) {
|
|
105
|
+
console.log(chalk.red('\nā You must accept the Terms and Privacy Policy to use VibeCodingMachine.\n'))
|
|
106
|
+
return false
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Record acceptance
|
|
110
|
+
await this.complianceManager.recordAcknowledgment(userId, {
|
|
111
|
+
terms: answers.acceptTerms || undefined,
|
|
112
|
+
privacy: answers.acceptPrivacy || undefined
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
console.log(chalk.green('\nā
Thank you! Your acceptance has been recorded.\n'))
|
|
116
|
+
return true
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Electron prompt for compliance (returns HTML dialog)
|
|
121
|
+
*/
|
|
122
|
+
async promptElectron(userId, status) {
|
|
123
|
+
// For Electron, we'll return the data needed to show a dialog
|
|
124
|
+
// The actual dialog will be handled by the Electron renderer
|
|
125
|
+
const data = {
|
|
126
|
+
needsTerms: status.requiredActions.includes('terms'),
|
|
127
|
+
needsPrivacy: status.requiredActions.includes('privacy')
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (data.needsTerms) {
|
|
131
|
+
data.terms = await this.complianceManager.getTermsOfService()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (data.needsPrivacy) {
|
|
135
|
+
data.privacy = await this.complianceManager.getPrivacyPolicy()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return data
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Record acceptance from Electron
|
|
143
|
+
*/
|
|
144
|
+
async recordElectronAcceptance(userId, acceptTerms, acceptPrivacy) {
|
|
145
|
+
await this.complianceManager.recordAcknowledgment(userId, {
|
|
146
|
+
terms: acceptTerms,
|
|
147
|
+
privacy: acceptPrivacy
|
|
148
|
+
})
|
|
149
|
+
return true
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Format markdown content for CLI display
|
|
154
|
+
*/
|
|
155
|
+
formatForCLI(content) {
|
|
156
|
+
// Simple markdown formatting for terminal
|
|
157
|
+
return content
|
|
158
|
+
.split('\n')
|
|
159
|
+
.map(line => {
|
|
160
|
+
// Headers
|
|
161
|
+
if (line.startsWith('# ')) {
|
|
162
|
+
return ' ' + line.substring(2).toUpperCase()
|
|
163
|
+
}
|
|
164
|
+
if (line.startsWith('## ')) {
|
|
165
|
+
return ' ' + line.substring(3)
|
|
166
|
+
}
|
|
167
|
+
// Bold
|
|
168
|
+
line = line.replace(/\*\*(.*?)\*\*/g, '$1')
|
|
169
|
+
// Lists
|
|
170
|
+
if (line.startsWith('- ')) {
|
|
171
|
+
return ' ⢠' + line.substring(2)
|
|
172
|
+
}
|
|
173
|
+
if (/^\d+\./.test(line)) {
|
|
174
|
+
return ' ' + line
|
|
175
|
+
}
|
|
176
|
+
// Regular text
|
|
177
|
+
return line ? ' ' + line : ''
|
|
178
|
+
})
|
|
179
|
+
.join('\n')
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
module.exports = CompliancePrompt
|