mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
fix(landing): update broken links, change colors (#3687)
* fix(landing): update broken links, change colors * update integration pages * update icons * link to tag * fix(landing): resolve build errors and address PR review comments - Extract useEffect redirect into ExternalRedirect client component to fix fs/promises bundling error in privacy/terms server pages - Fix InfisicalIcon fill='black' → fill='currentColor' for theme compatibility - Add target="_blank" + rel="noopener noreferrer" to enterprise Typeform link - Install @types/micromatch to fix missing type declarations build error Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(icons): fix InfisicalIcon fill='black' → fill='currentColor' in docs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * remove hardcoded ff * fix(generate-docs): fix tool description extraction for two-step and name-mismatch patterns Replace the fragile first-id/first-description heuristic with a per-id window search: for each id: 'tool_id' match, scan the next 600 chars (stopping before any params: block) for description: and name: fields. This correctly handles the two-step pattern used by Intercom and others where the ToolConfig export comes after a separate base object whose params: would have cut off the old approach. Add an exact-name fallback that checks tools.access for a tool whose name matches the operation label — handles cases where block op IDs are short aliases (e.g. Slack 'send') while the tool ID is more descriptive ('slack_message') but the tool name 'Slack Message' still differs. Remove the word-overlap scoring fallback which was producing incorrect descriptions (Intercom all saying 'Intercom API access token', Reddit Save/Unsave inverted, etc.). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
6326353f5c
commit
fa181f0155
+51
-13
@@ -317,26 +317,48 @@ function extractOperationsFromContent(blockContent: string): { label: string; id
|
||||
* Scan all tool files under apps/sim/tools/ and build a map from tool ID to description.
|
||||
* Used to enrich operation entries with descriptions.
|
||||
*/
|
||||
async function buildToolDescriptionMap(): Promise<Map<string, string>> {
|
||||
interface ToolMaps {
|
||||
desc: Map<string, string>
|
||||
name: Map<string, string>
|
||||
}
|
||||
|
||||
async function buildToolDescriptionMap(): Promise<ToolMaps> {
|
||||
const toolsDir = path.join(rootDir, 'apps/sim/tools')
|
||||
const map = new Map<string, string>()
|
||||
const desc = new Map<string, string>()
|
||||
const name = new Map<string, string>()
|
||||
try {
|
||||
const toolFiles = await glob(`${toolsDir}/**/*.ts`)
|
||||
for (const file of toolFiles) {
|
||||
if (file.endsWith('index.ts') || file.endsWith('types.ts')) continue
|
||||
const content = fs.readFileSync(file, 'utf-8')
|
||||
// Match top-level id + description fields in ToolConfig objects
|
||||
const idMatches = [...content.matchAll(/\bid\s*:\s*['"]([^'"]+)['"]/g)]
|
||||
const descMatches = [...content.matchAll(/\bdescription\s*:\s*['"]([^'"]{5,})['"]/g)]
|
||||
if (idMatches.length > 0 && descMatches.length > 0) {
|
||||
// The first id match and first description match are the tool's own fields
|
||||
map.set(idMatches[0][1], descMatches[0][1])
|
||||
|
||||
// Find every `id: 'tool_id'` occurrence in the file. For each, search
|
||||
// the next ~600 characters for `name:` and `description:` fields, cutting
|
||||
// off at the first `params:` block within that window. This handles both
|
||||
// the simple inline pattern (id → description → params in one object) and
|
||||
// the two-step pattern (base object holds params, ToolConfig export holds
|
||||
// id + description after the base object).
|
||||
const idRegex = /\bid\s*:\s*['"]([^'"]+)['"]/g
|
||||
let idMatch: RegExpExecArray | null
|
||||
while ((idMatch = idRegex.exec(content)) !== null) {
|
||||
const toolId = idMatch[1]
|
||||
if (desc.has(toolId)) continue
|
||||
const windowStart = idMatch.index
|
||||
const windowEnd = Math.min(windowStart + 600, content.length)
|
||||
const window = content.substring(windowStart, windowEnd)
|
||||
// Stop before any params block so we don't pick up param-level values
|
||||
const paramsOffset = window.search(/\bparams\s*:\s*\{/)
|
||||
const searchWindow = paramsOffset > 0 ? window.substring(0, paramsOffset) : window
|
||||
const descMatch = searchWindow.match(/\bdescription\s*:\s*['"]([^'"]{5,})['"]/)
|
||||
const nameMatch = searchWindow.match(/\bname\s*:\s*['"]([^'"]+)['"]/)
|
||||
if (descMatch) desc.set(toolId, descMatch[1])
|
||||
if (nameMatch) name.set(toolId, nameMatch[1])
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Non-fatal: descriptions will be empty strings
|
||||
}
|
||||
return map
|
||||
return { desc, name }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -481,7 +503,7 @@ async function writeIntegrationsJson(iconMapping: Record<string, string>): Promi
|
||||
}
|
||||
|
||||
const triggerRegistry = await buildTriggerRegistry()
|
||||
const toolDescMap = await buildToolDescriptionMap()
|
||||
const { desc: toolDescMap, name: toolNameMap } = await buildToolDescriptionMap()
|
||||
const integrations: IntegrationEntry[] = []
|
||||
const seenBaseTypes = new Set<string>()
|
||||
const blockFiles = (await glob(`${BLOCKS_PATH}/*.ts`)).sort()
|
||||
@@ -517,11 +539,27 @@ async function writeIntegrationsJson(iconMapping: Record<string, string>): Promi
|
||||
const iconName = (config as any).iconName || iconMapping[blockType] || ''
|
||||
const rawOps: { label: string; id: string }[] = (config as any).operations || []
|
||||
|
||||
// Enrich each operation with a description from the tool registry
|
||||
// Enrich each operation with a description from the tool registry.
|
||||
// Primary lookup: derive toolId as `{baseType}_{operationId}` and check
|
||||
// the map directly. Fallback: some blocks use short op IDs that don't
|
||||
// match tool IDs (e.g. Slack uses "send" while the tool ID is
|
||||
// "slack_message"). In that case, find the tool in tools.access whose
|
||||
// name exactly matches the operation label.
|
||||
const toolsAccess: string[] = (config as any).tools?.access || []
|
||||
const operations: OperationInfo[] = rawOps.map(({ label, id }) => {
|
||||
const toolId = `${baseType}_${id}`
|
||||
const desc = toolDescMap.get(toolId) || toolDescMap.get(id) || ''
|
||||
return { name: label, description: desc }
|
||||
let opDesc = toolDescMap.get(toolId) || toolDescMap.get(id) || ''
|
||||
|
||||
if (!opDesc && toolsAccess.length > 0) {
|
||||
for (const tId of toolsAccess) {
|
||||
if (toolNameMap.get(tId)?.toLowerCase() === label.toLowerCase()) {
|
||||
opDesc = toolDescMap.get(tId) || ''
|
||||
if (opDesc) break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { name: label, description: opDesc }
|
||||
})
|
||||
|
||||
const triggerIds: string[] = (config as any).triggerIds || []
|
||||
|
||||
Reference in New Issue
Block a user