Skip to content

Commit 93e4e13

Browse files
authored
v0.8.43: search improvements
2 parents 03dd370 + 1db2a00 commit 93e4e13

132 files changed

Lines changed: 34443 additions & 2305 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎apps/docs/app/robots.txt/route.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ export async function GET() {
1010
User-agent: *
1111
Disallow: /.next/
1212
Disallow: /api/internal/
13-
Disallow: /_next/static/
1413
Disallow: /admin/
1514
Allow: /
1615
Allow: /llms.txt

‎apps/docs/components/footer/footer.tsx‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const RESOURCES_LINKS: FooterItem[] = [
4141
{ label: 'Contact', href: `${SIM_SITE_URL}/contact`, external: true },
4242
]
4343

44-
/** Top model providers — mirrors the landing footer's top 8 catalog providers. */
44+
/** Top model providers — mirrors the landing footer's top 7 catalog providers. */
4545
const MODEL_LINKS: FooterItem[] = [
4646
{ label: 'All Models', href: `${SIM_SITE_URL}/models`, external: true },
4747
{ label: 'OpenAI', href: `${SIM_SITE_URL}/models/openai`, external: true },
@@ -51,7 +51,6 @@ const MODEL_LINKS: FooterItem[] = [
5151
{ label: 'xAI', href: `${SIM_SITE_URL}/models/xai`, external: true },
5252
{ label: 'Cerebras', href: `${SIM_SITE_URL}/models/cerebras`, external: true },
5353
{ label: 'Groq', href: `${SIM_SITE_URL}/models/groq`, external: true },
54-
{ label: 'Sakana AI', href: `${SIM_SITE_URL}/models/sakana`, external: true },
5554
]
5655

5756
const BLOCK_LINKS: FooterItem[] = [
@@ -84,7 +83,7 @@ const SOCIAL_LINKS: FooterItem[] = [
8483
{ label: 'X (Twitter)', href: 'https://x.com/simdotai', external: true },
8584
{
8685
label: 'LinkedIn',
87-
href: 'https://www.linkedin.com/company/simstudioai/',
86+
href: 'https://www.linkedin.com/company/simdotai/',
8887
external: true,
8988
},
9089
{

‎apps/docs/content/docs/integrations/file.mdx‎

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Read workspace file objects from selected files, canonical workspace file IDs, o
5555

5656
### File Get Content
5757

58-
Extract the text content of workspace files selected directly, identified by canonical file ID, or collected from one or more workspace folders.
58+
Extract workspace file text using the same parser mode as File Search. Use the returned fileId and offset/limit to read the matching line and surrounding context. For documents and spreadsheets, line numbers refer to extracted text, not page numbers or worksheet row numbers.
5959

6060
#### Input
6161

@@ -77,7 +77,7 @@ Extract the text content of workspace files selected directly, identified by can
7777

7878
### File Search
7979

80-
Search the indexed text of active workspace files for lines matching a query, and return each matching line once with its file ID and line number. By default the query is a regular expression; in exact mode it is matched verbatim and metacharacters are literal. Coverage is what the index currently holds. A term that is not found is only authoritative when "complete" is true AND "indexStatus" reports no skipped or partial files; otherwise it is unknown rather than absent, so re-check before creating something on the assumption it is missing. Narrow the search with folderPaths to confine it to one or more folder trees, which also narrows "indexStatus" to those trees.
80+
Search the indexed text of active workspace files for lines matching a query, and return each matching line once with its file ID and line number. By default the query is a regular expression; in exact mode it is matched verbatim and metacharacters are literal. Coverage is what the index currently holds. A term that is not found is only authoritative when "complete" is true AND "indexStatus" reports no skipped files; otherwise it is unknown rather than absent, so re-check before creating something on the assumption it is missing. Narrow the search with folderPaths to confine it to one or more folder trees, which also narrows "indexStatus" to those trees.
8181

8282
#### Input
8383

@@ -99,13 +99,13 @@ Search the indexed text of active workspace files for lines matching a query, an
9999
| ↳ `text` | string | Matching line or bounded match-centered preview. |
100100
| `count` | number | Number of returned matching lines. |
101101
| `truncated` | boolean | Whether more matching lines exist beyond the configured hard cap. |
102-
| `complete` | boolean | Whether indexing has no pending or failed current revisions; skipped and partial coverage is reported separately. |
102+
| `complete` | boolean | Whether indexing has no pending or failed current revisions; excluded files are reported separately. |
103103
| `indexStatus` | object | Current workspace search-index coverage by file status. |
104-
| ↳ `readyFiles` | number | Files whose current revision is searchable. |
104+
| ↳ `readyFiles` | number | Files whose entire current extracted text is searchable. |
105105
| ↳ `pendingFiles` | number | Files still waiting to be indexed. |
106106
| ↳ `failedFiles` | number | Files whose current indexing attempt failed. |
107-
| ↳ `skippedFiles` | number | Files intentionally excluded because they are unsupported or oversized. |
108-
| ↳ `partialFiles` | number | Searchable files whose extracted text was truncated by the parser or cap. |
107+
| ↳ `skippedFiles` | number | Files excluded in full because they are oversized, unsupported, or cannot be completely extracted. |
108+
| ↳ `partialFiles` | number | Always zero; retained for compatibility. Files are never partially indexed. |
109109

110110
### File Fetch
111111

@@ -380,4 +380,16 @@ Move an existing workspace file into a folder. Moves the file itself; use Move F
380380
| `fileId` | string | The file that was moved. |
381381
| `folderPath` | string | The folder the file now lives in. |
382382

383+
{/* MANUAL-CONTENT-START:search_limits */}
384+
## Search coverage and limits
383385

386+
Search indexes the complete extracted text of each eligible file. The source file and its extracted UTF-8 text must each be at most **25 MiB (26,214,400 bytes)**. Oversized files, unsupported binary formats, and documents that cannot be completely extracted within parser safety limits are excluded as whole files and counted in `skippedFiles`. Search never indexes only the first rows, lines, or characters. CSV search preserves decoded source text; spreadsheet search includes populated cells beyond the preview limits. Image-only documents require searchable text; search does not perform OCR.
387+
388+
Existing parser safeguards also apply to complete extraction. PDFs allow at most 10,000 pages, 20 MiB of extracted text, 250,000 characters on one page, and 60 seconds of extraction. Office archives allow at most 150 MiB expanded in total, 64 MiB for one archive entry, and 10,000 entries; malformed archives and excessive compression ratios are rejected. Hitting any of these limits excludes the whole file from search.
389+
390+
Updates are indexed asynchronously. `pendingFiles` and `failedFiles` indicate revisions that are not yet searchable; a new revision becomes searchable only when its full index is ready. An empty result proves absence only within the searched scope when `complete` is true and `skippedFiles` is zero.
391+
392+
Regex is evaluated against complete logical lines, including long lines, and cannot span line breaks. Returned lines may use a shortened preview. The result limit (up to 200 lines) and a 10-second query deadline limit an individual request, not the amount of text indexed. An expensive query fails explicitly instead of returning an apparently complete subset; narrow its literal text or folder scope and retry.
393+
394+
Search returns one result per matching logical line with `fileId`, 1-based `lineNumber`, and `text` (a bounded preview for long lines). An Agent can use **Search** to locate content, then **Get Content** with the returned `fileId`, `offset` near `lineNumber`, and a small `limit` to read surrounding context. These operations use the same complete-text parser mode. Line numbers for documents and spreadsheets refer to extracted text, not page numbers or worksheet row numbers. Re-run search if the file changes between calls.
395+
{/* MANUAL-CONTENT-END */}

‎apps/sim/app/(landing)/components/features/components/core-feature-card/core-feature-card.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export function CoreFeatureCard({
4848
const graphic = (
4949
<div
5050
aria-hidden={interactiveVisual ? undefined : true}
51+
inert={!interactiveVisual}
5152
className={cn(
5253
'relative aspect-[5/6] overflow-hidden border border-[var(--border)] transition-colors duration-300 group-hover:border-[var(--border)] motion-reduce:transition-none',
5354
LANDING_STAGE_RADIUS,

‎apps/sim/app/(landing)/components/features/components/features-rail/features-rail.test.tsx‎

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { act, StrictMode } from 'react'
55
import { createRoot, type Root } from 'react-dom/client'
66
import { renderToStaticMarkup } from 'react-dom/server'
7-
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest'
7+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
88
import {
99
FeaturesRail,
1010
foldScrollLeft,
@@ -74,6 +74,7 @@ afterEach(() => {
7474
root = null
7575
host?.remove()
7676
host = null
77+
vi.unstubAllGlobals()
7778
})
7879

7980
function mount(strict = false): HTMLElement {
@@ -106,6 +107,34 @@ describe('foldScrollLeft', () => {
106107
})
107108

108109
describe('FeaturesRail', () => {
110+
it('waits until the rail approaches the viewport before adding the loop copies', () => {
111+
let notify: IntersectionObserverCallback | undefined
112+
const disconnect = vi.fn()
113+
const observe = vi.fn()
114+
vi.stubGlobal(
115+
'IntersectionObserver',
116+
class {
117+
constructor(callback: IntersectionObserverCallback) {
118+
notify = callback
119+
}
120+
observe = observe
121+
disconnect = disconnect
122+
}
123+
)
124+
const rail = mount()
125+
expect(observe).toHaveBeenCalledWith(rail)
126+
expect(rail.children).toHaveLength(3)
127+
const observer = {} as IntersectionObserver
128+
act(() => notify?.([{ isIntersecting: false } as IntersectionObserverEntry], observer))
129+
expect(rail.children).toHaveLength(3)
130+
act(() => notify?.([{ isIntersecting: true } as IntersectionObserverEntry], observer))
131+
expect(rail.children).toHaveLength(9)
132+
expect(rail.scrollLeft).toBe(SET)
133+
expect(disconnect).toHaveBeenCalledOnce()
134+
act(() => notify?.([{ isIntersecting: false } as IntersectionObserverEntry], observer))
135+
expect(rail.children).toHaveLength(9)
136+
})
137+
109138
it('server-renders the finite rail once, with the scroll chrome', () => {
110139
const html = renderToStaticMarkup(
111140
<FeaturesRail label='Core Sim features'>{cards()}</FeaturesRail>

‎apps/sim/app/(landing)/components/features/components/features-rail/features-rail.tsx‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ interface FeaturesRailProps {
8686
/** Accessible name of the scrolling region. */
8787
label: string
8888
/**
89-
* The cards, in order. Each becomes one slot; once JS runs the whole set is
90-
* cloned on both sides so the rail loops.
89+
* The cards, in order. Each becomes one slot; as the rail approaches the
90+
* viewport the whole set is cloned on both sides so the rail loops.
9191
*/
9292
children: ReactNode
9393
}
@@ -96,7 +96,7 @@ interface FeaturesRailProps {
9696
* The homepage product rail: native horizontal scrolling that never ends.
9797
*
9898
* The server renders the set once, so the HTML - and any visit without JS - is
99-
* the plain finite rail with the first card under the heading. After hydration
99+
* the plain finite rail with the first card under the heading. Near the viewport
100100
* the set is cloned once on each side, the scroll position jumps one set width
101101
* before paint so nothing visibly moves (folded, so Strict Mode's second run of
102102
* the effect lands on the same spot), and a passive scroll listener folds the
@@ -124,7 +124,22 @@ export function FeaturesRail({ label, children }: FeaturesRailProps) {
124124
const cards = Children.toArray(children)
125125

126126
useEffect(() => {
127-
setLooping(true)
127+
const rail = railRef.current
128+
if (!rail) return
129+
if (typeof IntersectionObserver === 'undefined') {
130+
setLooping(true)
131+
return
132+
}
133+
const observer = new IntersectionObserver(
134+
(entries) => {
135+
if (!entries.some((entry) => entry.isIntersecting)) return
136+
setLooping(true)
137+
observer.disconnect()
138+
},
139+
{ rootMargin: '600px' }
140+
)
141+
observer.observe(rail)
142+
return () => observer.disconnect()
128143
}, [])
129144

130145
useLayoutEffect(() => {

‎apps/sim/app/(landing)/components/footer/footer.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ const RESOURCES_LINKS: FooterItem[] = [
8787
/** Top model providers, sourced from the catalog so labels/hrefs never drift. */
8888
const MODEL_LINKS: FooterItem[] = [
8989
{ label: 'All Models', href: '/models' },
90-
...MODEL_PROVIDERS_WITH_CATALOGS.slice(0, 8).map((provider) => ({
90+
...MODEL_PROVIDERS_WITH_CATALOGS.slice(0, 7).map((provider) => ({
9191
label: provider.name,
9292
href: provider.href,
9393
})),
@@ -119,7 +119,7 @@ const SOCIAL_LINKS: FooterItem[] = [
119119
{ label: 'X (Twitter)', href: 'https://x.com/simdotai', external: true },
120120
{
121121
label: 'LinkedIn',
122-
href: 'https://www.linkedin.com/company/simstudioai/',
122+
href: 'https://www.linkedin.com/company/simdotai/',
123123
external: true,
124124
},
125125
{

‎apps/sim/app/(landing)/components/hero/components/hero-platform-loop/production-workflow-stage.tsx‎

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -75,20 +75,20 @@ const EMPTY_IDS: ReadonlySet<string> = new Set()
7575
const ACTION_BUTTON_STYLES = [
7676
'size-[24px] rounded-md p-0',
7777
'border-none bg-transparent text-[var(--text-icon)]',
78-
'hover-hover:bg-[var(--surface-5)] hover-hover:!text-[var(--text-primary)]',
79-
'dark:hover-hover:bg-[var(--surface-4)]',
80-
'transition-[background-color,color,opacity,transform] duration-150 active:scale-[0.96]',
78+
'transition-[background-color,color,opacity,transform] duration-150',
8179
'group-data-[node-selected]:text-[var(--surface-2)]',
82-
'hover-hover:group-data-[node-selected]:bg-[var(--surface-2)]',
83-
'hover-hover:group-data-[node-selected]:!text-[var(--text-primary)]',
8480
].join(' ')
8581

8682
const FIRST_ACTION_STYLES =
8783
"!w-[40px] [clip-path:path('M23.75_0A8_8_0_0_0_17.6_2.88L3.41_19.9A2.5_2.5_0_0_0_5.34_24L36_24A4_4_0_0_0_40_20L40_4A4_4_0_0_0_36_0Z')] [&>svg]:translate-x-[8px] [&>svg]:translate-y-px"
8884

85+
/** A 24px target even at MIN_ZOOM, extending above/left of the unchanged 40px painted slot. */
86+
const RUN_ACTION_HIT_STYLES =
87+
'group/run relative -ml-[14px] size-[54px] shrink-0 border-none bg-transparent! p-0'
88+
8989
/** The running run slot: graphite fill, inverse glyph - the editor's own treatment. */
9090
const RUNNING_RUN_STYLES =
91-
'!bg-[var(--text-secondary)] !text-[var(--text-inverse)] hover-hover:!bg-[var(--white)] hover-hover:!text-[var(--surface-inverted)]'
91+
'!bg-[var(--text-secondary)] !text-[var(--text-inverse)] group-hover-hover/run:!bg-[var(--white)] group-hover-hover/run:!text-[var(--surface-inverted)]'
9292
/** A bystander card's actions dim mid-run; the run/stop slot keeps its ordinary chrome. */
9393
const BYSTANDER_ACTION_STYLES =
9494
'!bg-transparent !opacity-25 hover-hover:!bg-transparent dark:hover-hover:!bg-transparent'
@@ -227,7 +227,7 @@ function PreviewActionBar({ block, running, workflowRunning, onRunToggle }: Prev
227227
return (
228228
<div
229229
data-workflow-action-bar-swell=''
230-
className='-top-[28px] pointer-events-auto absolute right-[24px] z-[40] h-[28px] w-fit overflow-hidden rounded-lg px-[0.2rem] py-0.5'
230+
className='-top-[28px] pointer-events-auto absolute right-[24px] z-[40] h-[28px] w-fit rounded-lg px-[0.2rem] py-0.5'
231231
>
232232
<div className='pointer-events-none relative flex h-full flex-row items-center gap-[2px] opacity-0 transition-opacity duration-[30ms] [transition-timing-function:cubic-bezier(0.23,1,0.32,1)] group-data-[action-menu-ready]:pointer-events-auto group-data-[action-menu-ready]:opacity-100 group-data-[action-menu-ready]:duration-100'>
233233
{sweeping && (
@@ -250,35 +250,42 @@ function PreviewActionBar({ block, running, workflowRunning, onRunToggle }: Prev
250250
)}
251251
<Tooltip.Root preferAbove>
252252
<Tooltip.Trigger asChild>
253-
<span className='inline-flex'>
253+
<span className='inline-flex h-full items-end'>
254254
<Button
255255
type='button'
256256
variant='ghost'
257257
aria-label={workflowRunning ? 'Stop workflow' : `Run ${block.name}`}
258-
className={cn(
259-
ACTION_BUTTON_STYLES,
260-
FIRST_ACTION_STYLES,
261-
running && RUNNING_RUN_STYLES,
262-
workflowRunning && 'group/run'
263-
)}
258+
className={RUN_ACTION_HIT_STYLES}
264259
onClick={(event) => {
265260
event.stopPropagation()
266261
onRunToggle()
267262
}}
268263
>
269-
{workflowRunning ? (
270-
running ? (
271-
<RunningActionIcon />
264+
<span
265+
className={cn(
266+
'pointer-events-none absolute right-0 bottom-0 flex items-center justify-center',
267+
ACTION_BUTTON_STYLES,
268+
FIRST_ACTION_STYLES,
269+
'group-hover-hover/run:!text-[var(--text-primary)] group-hover-hover/run:bg-[var(--surface-5)] dark:group-hover-hover/run:bg-[var(--surface-4)]',
270+
'group-hover-hover/run:group-data-[node-selected]:!text-[var(--text-primary)] group-hover-hover/run:group-data-[node-selected]:bg-[var(--surface-2)]',
271+
'group-active/run:scale-[0.96]',
272+
running && RUNNING_RUN_STYLES
273+
)}
274+
>
275+
{workflowRunning ? (
276+
running ? (
277+
<RunningActionIcon />
278+
) : (
279+
<Square
280+
className='size-[11px] fill-current'
281+
aria-hidden='true'
282+
strokeWidth={0}
283+
/>
284+
)
272285
) : (
273-
<Square
274-
className='size-[11px] fill-current'
275-
aria-hidden='true'
276-
strokeWidth={0}
277-
/>
278-
)
279-
) : (
280-
<PlayOutline className='size-[14px]' />
281-
)}
286+
<PlayOutline className='size-[14px]' />
287+
)}
288+
</span>
282289
</Button>
283290
</span>
284291
</Tooltip.Trigger>
@@ -288,23 +295,22 @@ function PreviewActionBar({ block, running, workflowRunning, onRunToggle }: Prev
288295
{inertActions.map(({ label, Icon }) => (
289296
<Tooltip.Root key={label} preferAbove>
290297
<Tooltip.Trigger asChild>
291-
<Button
292-
type='button'
293-
variant='ghost'
294-
aria-label={label}
295-
className={cn(
296-
ACTION_BUTTON_STYLES,
297-
label === 'Delete' && LAST_ACTION_STYLES,
298-
workflowRunning && !running && BYSTANDER_ACTION_STYLES,
299-
sweeping && SWEEP_SLOT_STYLES
300-
)}
301-
onClick={(event) => {
302-
event.preventDefault()
303-
event.stopPropagation()
304-
}}
305-
>
306-
<Icon className='size-[14px]' />
307-
</Button>
298+
<span className='inline-flex'>
299+
<Button
300+
type='button'
301+
variant='ghost'
302+
disabled
303+
aria-label={`${label} unavailable in preview`}
304+
className={cn(
305+
ACTION_BUTTON_STYLES,
306+
label === 'Delete' && LAST_ACTION_STYLES,
307+
workflowRunning && !running && BYSTANDER_ACTION_STYLES,
308+
sweeping && SWEEP_SLOT_STYLES
309+
)}
310+
>
311+
<Icon className='size-[14px]' />
312+
</Button>
313+
</span>
308314
</Tooltip.Trigger>
309315
{!workflowRunning && <Tooltip.Content side='top'>{label}</Tooltip.Content>}
310316
</Tooltip.Root>

0 commit comments

Comments
 (0)