create-claudeportal 0.3.5 → 0.3.7
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/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Claude Portal</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-Bc6yvEXv.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/assets/index-Bps4hEp0.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
package/package.json
CHANGED
|
@@ -208,14 +208,75 @@ function getInstalledMCPs() {
|
|
|
208
208
|
return installed
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
// Map business tools to MCPs that connect to them
|
|
212
|
+
const TOOL_TO_MCP = {
|
|
213
|
+
'hubspot': ['composio'],
|
|
214
|
+
'salesforce': ['composio'],
|
|
215
|
+
'pipedrive': ['composio'],
|
|
216
|
+
'zoho crm': ['composio'],
|
|
217
|
+
'monday crm': ['composio'],
|
|
218
|
+
'close': ['composio'],
|
|
219
|
+
'xero': ['composio'],
|
|
220
|
+
'quickbooks': ['composio'],
|
|
221
|
+
'myob': ['composio'],
|
|
222
|
+
'freshbooks': ['composio'],
|
|
223
|
+
'mailchimp': ['composio'],
|
|
224
|
+
'convertkit': ['composio'],
|
|
225
|
+
'activecampaign': ['composio'],
|
|
226
|
+
'klaviyo': ['composio'],
|
|
227
|
+
'mailerlite': ['composio'],
|
|
228
|
+
'calendly': ['composio'],
|
|
229
|
+
'cal.com': ['composio'],
|
|
230
|
+
'later': ['postiz', 'composio'],
|
|
231
|
+
'buffer': ['postiz', 'composio'],
|
|
232
|
+
'postiz': ['postiz'],
|
|
233
|
+
'hootsuite': ['postiz', 'composio'],
|
|
234
|
+
'metricool': ['postiz'],
|
|
235
|
+
'notion': ['notion'],
|
|
236
|
+
'asana': ['composio'],
|
|
237
|
+
'trello': ['composio'],
|
|
238
|
+
'clickup': ['composio'],
|
|
239
|
+
'monday': ['composio'],
|
|
240
|
+
'linear': ['linear'],
|
|
241
|
+
'slack': ['slack'],
|
|
242
|
+
'microsoft teams': ['composio'],
|
|
243
|
+
'discord': ['composio'],
|
|
244
|
+
'google chat': ['google-workspace'],
|
|
245
|
+
'google drive': ['google-workspace'],
|
|
246
|
+
'stripe': ['composio'],
|
|
247
|
+
'wordpress': ['firecrawl'],
|
|
248
|
+
'shopify': ['composio'],
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function getUserTools() {
|
|
252
|
+
const brainDir = path.join(os.homedir(), 'Claude', 'brain')
|
|
253
|
+
const businessPath = path.join(brainDir, 'business.md')
|
|
254
|
+
if (!fs.existsSync(businessPath)) return []
|
|
255
|
+
|
|
256
|
+
const content = fs.readFileSync(businessPath, 'utf8')
|
|
257
|
+
const match = content.match(/^- \*\*Tools:\*\*\s*(.+)$/m)
|
|
258
|
+
if (!match) return []
|
|
259
|
+
|
|
260
|
+
return match[1].split(',').map(t => t.trim().toLowerCase()).filter(Boolean)
|
|
261
|
+
}
|
|
262
|
+
|
|
211
263
|
function checkMCPs(outcomeKey) {
|
|
212
264
|
const installed = getInstalledMCPs()
|
|
265
|
+
const userTools = getUserTools()
|
|
266
|
+
|
|
267
|
+
// Find which MCPs are recommended based on user's business tools
|
|
268
|
+
const recommendedByTools = new Set()
|
|
269
|
+
for (const tool of userTools) {
|
|
270
|
+
const mcpIds = TOOL_TO_MCP[tool] || []
|
|
271
|
+
for (const id of mcpIds) recommendedByTools.add(id)
|
|
272
|
+
}
|
|
213
273
|
|
|
214
274
|
const mcps = RECOMMENDED_MCPS.map(mcp => {
|
|
215
275
|
const isInstalled = installed.has(mcp.id.toLowerCase()) ||
|
|
216
276
|
[...installed].some(k => k.includes(mcp.id.toLowerCase()) || mcp.id.toLowerCase().includes(k))
|
|
217
277
|
|
|
218
278
|
const isRelevant = !outcomeKey || mcp.usefulFor.includes(outcomeKey)
|
|
279
|
+
const isRecommended = recommendedByTools.has(mcp.id)
|
|
219
280
|
|
|
220
281
|
return {
|
|
221
282
|
id: mcp.id,
|
|
@@ -223,6 +284,7 @@ function checkMCPs(outcomeKey) {
|
|
|
223
284
|
description: mcp.description,
|
|
224
285
|
installed: isInstalled,
|
|
225
286
|
relevant: isRelevant,
|
|
287
|
+
recommended: isRecommended,
|
|
226
288
|
category: mcp.category,
|
|
227
289
|
categoryLabel: CATEGORY_LABELS[mcp.category] || mcp.category,
|
|
228
290
|
installHint: isInstalled ? undefined : mcp.installHint,
|
package/server/lib/scraper.js
CHANGED
|
@@ -92,13 +92,21 @@ function detectSocialLinks(links, html) {
|
|
|
92
92
|
twitter: /(twitter\.com|x\.com)\/([a-zA-Z0-9_]+)/i,
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
// Only search href links (not the full HTML) to avoid matching share buttons, SDKs, and tracking pixels
|
|
96
|
+
const linkText = links.join(' ')
|
|
97
|
+
|
|
98
|
+
// Patterns that indicate a link is NOT a real profile (share buttons, SDKs, login, etc.)
|
|
99
|
+
const falsePositives = /sharer|share\?|dialog\/|connect\.facebook|platform\.twitter|apis\.google|intent\/tweet|oauth|login|signup|widget/i
|
|
96
100
|
|
|
97
101
|
for (const [platform, regex] of Object.entries(patterns)) {
|
|
98
|
-
const match =
|
|
102
|
+
const match = linkText.match(regex)
|
|
99
103
|
if (match) {
|
|
100
|
-
const fullUrlMatch =
|
|
101
|
-
|
|
104
|
+
const fullUrlMatch = linkText.match(new RegExp(`https?://[^"'\\s]*${regex.source}`, 'i'))
|
|
105
|
+
const url = fullUrlMatch ? fullUrlMatch[0] : match[0]
|
|
106
|
+
// Skip if it looks like a share button or SDK, not a real profile
|
|
107
|
+
if (!falsePositives.test(url)) {
|
|
108
|
+
profiles[platform] = { url }
|
|
109
|
+
}
|
|
102
110
|
}
|
|
103
111
|
}
|
|
104
112
|
|
package/server/routes/brain.js
CHANGED
|
@@ -42,6 +42,92 @@ router.post('/brain/save', (req, res) => {
|
|
|
42
42
|
}
|
|
43
43
|
})
|
|
44
44
|
|
|
45
|
+
// Map ChatGPT natural language labels to Brain field names
|
|
46
|
+
const IMPORT_FIELD_MAP = {
|
|
47
|
+
business: {
|
|
48
|
+
'business name': 'Name',
|
|
49
|
+
'name': 'Name',
|
|
50
|
+
'what i sell': 'Description',
|
|
51
|
+
'products': 'Description',
|
|
52
|
+
'services': 'Description',
|
|
53
|
+
'products/services': 'Description',
|
|
54
|
+
'pricing': 'Pricing',
|
|
55
|
+
'my pricing': 'Pricing',
|
|
56
|
+
'price': 'Pricing',
|
|
57
|
+
'target audience': 'Target Audience',
|
|
58
|
+
'my target audience': 'Target Audience',
|
|
59
|
+
'location': 'Location',
|
|
60
|
+
'my location': 'Location',
|
|
61
|
+
'team size': 'Team Size',
|
|
62
|
+
'my team size': 'Team Size',
|
|
63
|
+
'revenue': 'Revenue Baseline',
|
|
64
|
+
'revenue range': 'Revenue Baseline',
|
|
65
|
+
'my revenue range': 'Revenue Baseline',
|
|
66
|
+
'dream outcome': 'Dream Outcome',
|
|
67
|
+
'unique offer': 'Dream Outcome',
|
|
68
|
+
'what makes my offer unique': 'Dream Outcome',
|
|
69
|
+
'guarantee': 'Guarantee',
|
|
70
|
+
'guarantees': 'Guarantee',
|
|
71
|
+
'bonuses': 'Bonuses',
|
|
72
|
+
'delivery model': 'Value Stack',
|
|
73
|
+
'my delivery model': 'Value Stack',
|
|
74
|
+
},
|
|
75
|
+
industry: {
|
|
76
|
+
'industry': 'Sector',
|
|
77
|
+
'niche': 'Sector',
|
|
78
|
+
'my industry': 'Sector',
|
|
79
|
+
'my industry/niche': 'Sector',
|
|
80
|
+
'seasonal patterns': 'Seasonal Patterns',
|
|
81
|
+
'common objections': 'Common Objections',
|
|
82
|
+
'customer objections': 'Common Objections',
|
|
83
|
+
'common customer objections': 'Common Objections',
|
|
84
|
+
'buying triggers': 'Buying Triggers',
|
|
85
|
+
'what triggers people to buy': 'Buying Triggers',
|
|
86
|
+
'customer lifetime value': 'Avg Customer Value',
|
|
87
|
+
'average customer lifetime value': 'Avg Customer Value',
|
|
88
|
+
},
|
|
89
|
+
voice: {
|
|
90
|
+
'communication style': 'Tone',
|
|
91
|
+
'how i like to communicate': 'Tone',
|
|
92
|
+
'tone': 'Tone',
|
|
93
|
+
'words or phrases i use often': 'Tone',
|
|
94
|
+
'things i\'d never say': 'Words To Avoid',
|
|
95
|
+
'words to avoid': 'Words To Avoid',
|
|
96
|
+
'preferred length': 'Preferred Length',
|
|
97
|
+
'my preferred email/content length': 'Preferred Length',
|
|
98
|
+
'brand personality': 'Template',
|
|
99
|
+
'my brand personality': 'Template',
|
|
100
|
+
},
|
|
101
|
+
competitors: {
|
|
102
|
+
'competitors': 'Identified',
|
|
103
|
+
'competitors i\'ve mentioned': 'Identified',
|
|
104
|
+
'how i position against them': 'Differentiator',
|
|
105
|
+
'positioning': 'Differentiator',
|
|
106
|
+
'what they do well': 'Their Strengths',
|
|
107
|
+
'where they fall short': 'Their Weaknesses',
|
|
108
|
+
},
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function extractFieldsFromText(category, text) {
|
|
112
|
+
const fieldMap = IMPORT_FIELD_MAP[category] || {}
|
|
113
|
+
const fields = {}
|
|
114
|
+
|
|
115
|
+
// Try to match "- Label: value" or "- **Label:** value" patterns from ChatGPT output
|
|
116
|
+
const lines = text.split('\n')
|
|
117
|
+
for (const line of lines) {
|
|
118
|
+
const match = line.match(/^[-•*]\s*\*{0,2}([^:*]+?)\*{0,2}\s*[:—–-]\s*(.+)$/i)
|
|
119
|
+
if (match) {
|
|
120
|
+
const label = match[1].trim().toLowerCase()
|
|
121
|
+
const value = match[2].trim()
|
|
122
|
+
if (value && fieldMap[label]) {
|
|
123
|
+
fields[fieldMap[label]] = value
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return fields
|
|
129
|
+
}
|
|
130
|
+
|
|
45
131
|
// Import ChatGPT export text
|
|
46
132
|
router.post('/brain/import', (req, res) => {
|
|
47
133
|
const { text } = req.body
|
|
@@ -53,6 +139,12 @@ router.post('/brain/import', (req, res) => {
|
|
|
53
139
|
const imported = []
|
|
54
140
|
for (const [category, content] of Object.entries(sections)) {
|
|
55
141
|
if (content.trim()) {
|
|
142
|
+
// Try to extract structured fields first
|
|
143
|
+
const fields = extractFieldsFromText(category, content)
|
|
144
|
+
if (Object.keys(fields).length > 0) {
|
|
145
|
+
saveBrainCategory(category, fields)
|
|
146
|
+
}
|
|
147
|
+
// Also save raw context as backup
|
|
56
148
|
appendRawContext(category, content)
|
|
57
149
|
imported.push(category)
|
|
58
150
|
}
|
|
@@ -87,12 +179,19 @@ router.post('/brain/documents', express.raw({ type: '*/*', limit: '50mb' }), (re
|
|
|
87
179
|
fs.writeFileSync(filePath, req.body)
|
|
88
180
|
|
|
89
181
|
const textExts = ['.txt', '.md', '.csv']
|
|
182
|
+
let extracted = false
|
|
90
183
|
if (textExts.includes(ext)) {
|
|
91
184
|
const content = req.body.toString('utf8')
|
|
92
185
|
const sections = parseImport(content)
|
|
93
186
|
let hadSections = false
|
|
94
187
|
for (const [category, text] of Object.entries(sections)) {
|
|
95
188
|
if (text.trim()) {
|
|
189
|
+
// Extract structured fields where possible
|
|
190
|
+
const fields = extractFieldsFromText(category, text)
|
|
191
|
+
if (Object.keys(fields).length > 0) {
|
|
192
|
+
saveBrainCategory(category, fields)
|
|
193
|
+
extracted = true
|
|
194
|
+
}
|
|
96
195
|
appendRawContext(category, text)
|
|
97
196
|
hadSections = true
|
|
98
197
|
}
|
|
@@ -101,11 +200,21 @@ router.post('/brain/documents', express.raw({ type: '*/*', limit: '50mb' }), (re
|
|
|
101
200
|
const guessed = guessCategoryFromFilename(filename)
|
|
102
201
|
appendRawContext(guessed, content.trim())
|
|
103
202
|
}
|
|
203
|
+
// hadSections means raw context was saved, extracted means structured fields were found
|
|
104
204
|
}
|
|
105
205
|
|
|
106
206
|
ensureClaudeMdReference()
|
|
107
207
|
const status = getBrainStatus()
|
|
108
|
-
|
|
208
|
+
const binaryFile = !textExts.includes(ext)
|
|
209
|
+
let message = 'File saved'
|
|
210
|
+
if (binaryFile) {
|
|
211
|
+
message = `${ext.toUpperCase().slice(1)} saved — Claude will read this when you start working`
|
|
212
|
+
} else if (extracted) {
|
|
213
|
+
message = 'Content extracted and added to Brain'
|
|
214
|
+
} else if (hadSections) {
|
|
215
|
+
message = 'Content saved as context'
|
|
216
|
+
}
|
|
217
|
+
res.json({ saved: true, filename, extracted, message, ...status })
|
|
109
218
|
} catch (err) {
|
|
110
219
|
res.status(500).json({ error: err.message })
|
|
111
220
|
}
|
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/app.tsx","./src/main.tsx","./src/components/brain/brainonboarding.tsx","./src/components/brain/brainstepdocuments.tsx","./src/components/brain/brainstepimport.tsx","./src/components/brain/brainstepwebsite.tsx","./src/components/chat/buildsidebar.tsx","./src/components/checklist/brainstatussection.tsx","./src/components/checklist/clistatussection.tsx","./src/components/checklist/featurebuilder.tsx","./src/components/checklist/futurebuildsection.tsx","./src/components/checklist/healthcheckitem.tsx","./src/components/checklist/healthsection.tsx","./src/components/checklist/prepushsection.tsx","./src/components/checklist/testingsection.tsx","./src/components/document/contextsection.tsx","./src/components/document/docsidebar.tsx","./src/components/document/foldersection.tsx","./src/components/document/mcpsection.tsx","./src/components/document/outcomesection.tsx","./src/components/document/outputpanel.tsx","./src/components/document/stylereferencesection.tsx","./src/components/layout/checklistdrawer.tsx","./src/components/layout/errorbanner.tsx","./src/components/layout/iconrail.tsx","./src/components/layout/topbar.tsx","./src/components/preview/previewpanel.tsx","./src/components/setup/howitworks.tsx","./src/components/setup/projectselector.tsx","./src/components/setup/setupwizard.tsx","./src/components/setup/tooldetection.tsx","./src/components/setup/toolinstaller.tsx","./src/components/terminal/terminalpanel.tsx","./src/context/docmodecontext.tsx","./src/context/projectcontext.tsx","./src/context/terminalcontext.tsx","./src/hooks/usedocevents.ts","./src/hooks/usehealthscan.ts","./src/hooks/useprojectinfo.ts","./src/hooks/usesse.ts","./src/lib/api.ts","./src/lib/doc-prompts.ts","./src/lib/storage.ts","./src/lib/style-templates.ts","./src/types/doc.ts","./src/types/index.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["./src/app.tsx","./src/main.tsx","./src/components/brain/brainonboarding.tsx","./src/components/brain/brainstepdocuments.tsx","./src/components/brain/brainstepimport.tsx","./src/components/brain/brainsteptools.tsx","./src/components/brain/brainstepwebsite.tsx","./src/components/chat/buildsidebar.tsx","./src/components/checklist/brainstatussection.tsx","./src/components/checklist/clistatussection.tsx","./src/components/checklist/featurebuilder.tsx","./src/components/checklist/futurebuildsection.tsx","./src/components/checklist/healthcheckitem.tsx","./src/components/checklist/healthsection.tsx","./src/components/checklist/prepushsection.tsx","./src/components/checklist/testingsection.tsx","./src/components/document/contextsection.tsx","./src/components/document/docsidebar.tsx","./src/components/document/foldersection.tsx","./src/components/document/mcpsection.tsx","./src/components/document/outcomesection.tsx","./src/components/document/outputpanel.tsx","./src/components/document/stylereferencesection.tsx","./src/components/layout/checklistdrawer.tsx","./src/components/layout/errorbanner.tsx","./src/components/layout/iconrail.tsx","./src/components/layout/topbar.tsx","./src/components/preview/previewpanel.tsx","./src/components/setup/howitworks.tsx","./src/components/setup/projectselector.tsx","./src/components/setup/setupwizard.tsx","./src/components/setup/tooldetection.tsx","./src/components/setup/toolinstaller.tsx","./src/components/terminal/terminalpanel.tsx","./src/context/docmodecontext.tsx","./src/context/projectcontext.tsx","./src/context/terminalcontext.tsx","./src/hooks/usedocevents.ts","./src/hooks/usehealthscan.ts","./src/hooks/useprojectinfo.ts","./src/hooks/usesse.ts","./src/lib/api.ts","./src/lib/doc-prompts.ts","./src/lib/storage.ts","./src/lib/style-templates.ts","./src/types/doc.ts","./src/types/index.ts"],"version":"5.9.3"}
|