Skip to content

Commit 13a9119

Browse files
authored
v0.7.52: span sanitization, highlight tables and files text to chat, settings UX improvements, security hardening
2 parents 86486d5 + 25e6091 commit 13a9119

506 files changed

Lines changed: 34270 additions & 3313 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.

.agents/skills/add-block/SKILL.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,12 @@ Derive templates from the service's real use cases. Each prompt should name a co
919919
- **Ground every skill in operations the block actually exposes** — cross-check each skill's steps against `tools.access`. Never describe an action the integration cannot perform.
920920
- **Derive skills from real, popular use cases found online — never invent them.** Web-search the service's documented use cases (vendor use-case/solutions pages, official docs describing the workflow, reputable "top automations for X" articles) and only add a skill you can source as something people genuinely do with the service. Do not hallucinate skills.
921921

922+
## Generated tool metadata
923+
924+
Adding a block on its own needs **no** regeneration — a block references existing tool IDs through `tools.access` and does not change any tool's shape.
925+
926+
But if the same change also adds, edits **or removes** a tool, run `bun run tool-metadata:generate` and commit the result, or CI fails on stale artifacts. That matters here because a block's `outputs` are authored to match its tools' outputs, and the UI now reads those from the generated metadata rather than the executable registry — an unregenerated tool change makes the block's outputs disagree with what the panel renders. See `.agents/skills/tool-registry-boundary/SKILL.md`.
927+
922928
## Checklist Before Finishing
923929

924930
- [ ] `integrationType` is set to the correct `IntegrationType` enum value
@@ -933,6 +939,7 @@ Derive templates from the service's real use cases. Each prompt should name a co
933939
- [ ] Tools.config.tool returns correct tool ID (snake_case)
934940
- [ ] Outputs match tool outputs
935941
- [ ] Block + meta registered in registry-maps.ts (`BLOCK_REGISTRY` / `BLOCK_META_REGISTRY`)
942+
- [ ] If any tool was added, changed or removed alongside the block: ran `bun run tool-metadata:generate` and committed the artifacts
936943
- [ ] If icon missing: asked user to provide SVG
937944
- [ ] If triggers exist: `triggers` config set, trigger subBlocks spread
938945
- [ ] Optional/rarely-used fields set to `mode: 'advanced'`

.agents/skills/add-integration/SKILL.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,16 @@ export const tools: Record<string, ToolConfig> = {
415415
}
416416
```
417417

418+
Then regenerate the generated tool metadata and commit it:
419+
420+
```bash
421+
bun run tool-metadata:generate
422+
```
423+
424+
Client code reads `params`/`outputs` from these artifacts rather than importing
425+
the registry, so a tool you add, change or remove is invisible to the UI until they are regenerated,
426+
and CI fails on stale ones. See `.agents/skills/tool-registry-boundary/SKILL.md`.
427+
418428
### Block Registry (`apps/sim/blocks/registry-maps.ts`)
419429

420430
The data maps (`BLOCK_REGISTRY` + `BLOCK_META_REGISTRY`) live in `registry-maps.ts`; `registry.ts` holds only the accessor functions. Add the import and an entry to each map alphabetically:
@@ -490,6 +500,7 @@ If creating V2 versions (API-aligned outputs):
490500
- [ ] All optional outputs have `optional: true`
491501
- [ ] Created `index.ts` barrel export
492502
- [ ] Registered all tools in `tools/registry.ts`
503+
- [ ] Ran `bun run tool-metadata:generate` and committed the regenerated artifacts
493504

494505
### Block
495506
- [ ] Created `blocks/blocks/{service}.ts`

.agents/skills/add-tools/SKILL.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,17 @@ export const tools = {
296296
}
297297
```
298298

299+
3. Regenerate the tool metadata artifacts:
300+
301+
```bash
302+
bun run tool-metadata:generate
303+
```
304+
305+
Client code reads a tool's `params`/`outputs` from generated metadata rather than
306+
importing the registry, so a tool you add, change or remove is invisible to the UI until
307+
these are regenerated — and CI fails on stale artifacts. Commit the result. See
308+
`.agents/skills/tool-registry-boundary/SKILL.md`.
309+
299310
## Wiring Tools into the Block (Required)
300311

301312
After registering in `tools/registry.ts`, you MUST also update the block definition at `apps/sim/blocks/blocks/{service}.ts`. This is not optional — tools are only usable from the UI if they are wired into the block.
@@ -443,6 +454,7 @@ All tool IDs MUST use `snake_case`: `{service}_{action}` (e.g., `x_create_tweet`
443454
- [ ] Types file has all interfaces
444455
- [ ] Index.ts exports all tools and re-exports types (`export * from './types'`)
445456
- [ ] Tools registered in `tools/registry.ts`
457+
- [ ] `bun run tool-metadata:generate` run and the regenerated artifacts committed
446458
- [ ] Block wired: `tools.access`, dropdown options, subBlocks, `tools.config`, outputs, inputs
447459

448460
## Final Validation (Required)
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
---
2+
name: tool-registry-boundary
3+
description: Keep the executable tool registry out of client-reachable module graphs — when to read `@/tools/metadata` instead of `getTool`, how to measure whether an import edge pulls the registry, and how to regenerate the metadata artifacts. Use when touching `apps/sim/tools/registry.ts`, `tools/utils.ts`, `tools/params.ts`, or anything that calls `getTool`.
4+
---
5+
6+
# Tool Registry Boundary Skill
7+
8+
You keep the 4,300-tool executable registry out of module graphs that don't execute tools.
9+
10+
## The rule
11+
12+
> Client-reachable code reads tool **metadata**. Only code that actually executes a tool imports the **registry**.
13+
14+
`@/tools/registry` is a ~9,000-line barrel importing every tool. Each `ToolConfig` mixes plain data (`params`, `outputs`, `name`) with closures — `request.url`, `request.headers`, `transformResponse`, `directExecution`, `postProcess`. Those closures reach the SDK clients, API helpers and parsers each integration needs, and that is what makes the barrel expensive: reaching it costs ~4,700 additional modules.
15+
16+
`getTool()` returns the whole `ToolConfig`, so a single `getTool` import anywhere in a client-reachable file drags all of it in.
17+
18+
## Which module to import
19+
20+
| you need | import | notes |
21+
| --- | --- | --- |
22+
| whether a tool id exists | `hasToolId` from `@/tools/tool-ids` | ~110 KB — the cheapest module |
23+
| to resolve an unversioned name | `resolveToolId` from `@/tools/tool-ids` | |
24+
| every tool id | `getToolIds` from `@/tools/tool-ids` | |
25+
| a tool's params | `getToolParams` / `getToolMetadata` from `@/tools/metadata` | ~4 MB |
26+
| a tool's declared outputs | `getToolOutputsMetadata` from `@/tools/metadata-outputs` | ~4 MB, separate on purpose |
27+
| to **execute** a tool | `getTool` from `@/tools/utils`, or `@/tools/utils.server` | server paths only |
28+
29+
Three modules, cheapest first. Ids are their own artifact because resolution and existence checks need only the key set; outputs are their own because they are the larger half of the data with a single consumer. `@/tools/metadata` and `@/tools/metadata-outputs` both resolve ids through `@/tools/tool-ids`, which is what keeps them independent of each other — do not "helpfully" re-export one from another, or every caller pays for all three.
30+
31+
All lookups guard with `Object.hasOwn`. `JSON.parse` yields an object with the normal prototype, so a bare bracket lookup returns inherited members: `getToolMetadata('constructor')` returned a *function* typed as tool metadata before that was fixed.
32+
33+
## The generated artifacts
34+
35+
`apps/sim/tools/generated/tool-ids.ts`, `tool-metadata.ts` and `tool-outputs.ts` are produced by `scripts/sync-tool-metadata.ts`:
36+
37+
```bash
38+
bun run tool-metadata:generate # after adding/changing a tool
39+
bun run tool-metadata:check # what CI runs; fails if stale
40+
```
41+
42+
Never hand-edit them. If you add a tool or change a tool's `params`/`outputs`, regenerate and commit the result, or CI fails.
43+
44+
Three non-obvious properties, each of which was measured and is easy to undo by accident:
45+
46+
- **The data is a JSON string parsed at runtime, not an imported `.json` and not an object literal.** With `resolveJsonModule` (which this repo enables), a `.json` import makes TypeScript infer a literal type for all 4,300+ entries and takes `tsc --noEmit` from **12.6s to 8m07s** — a 38x regression. An ambient `declare module` does *not* short-circuit it, and an object literal costs the same. A single string literal is one cheap token for both the compiler and the bundler, and `JSON.parse` beats evaluating the equivalent literal at runtime. Do not "clean this up" into a `.json` import.
47+
- **The generator refuses to emit function values.** If you add a field to `METADATA_FIELDS` that contains a closure, generation fails loudly rather than shipping executable config to the client. `hosting` and `schemaEnrichment` are excluded for exactly this reason (`hosting.enabled`, `pricing`, and `enrichSchema` are functions) — they are server-only.
48+
- **Empty param entries are stripped.** The registry contains one (`stt_deepgram_v2`), which crashes callers that read `param.type` while iterating.
49+
- **Lookups resolve versions.** `getTool` maps an unversioned name onto the newest version, and 246 tools are versioned. A plain key lookup would silently report them missing — a quiet correctness bug, not a crash. `resolveToolId` reproduces that against the id set and is differentially tested against the original.
50+
51+
## Testing code that reads tool metadata
52+
53+
Mock the module the code under test actually reads. `vi.mock('@/tools/utils', () => toolsUtilsMock)` only controls `getTool`; code that reads `params`/`outputs`/`name` goes through `@/tools/metadata`, so mocking `tools/utils` there is a **no-op that still passes** — because the real generated artifacts happen to agree with the mock fixtures. The test looks green while controlling nothing.
54+
55+
```ts
56+
import { blocksMock, toolsMetadataMock, toolsUtilsMock } from '@sim/testing/mocks'
57+
58+
vi.mock('@/tools/utils', () => toolsUtilsMock) // executable lookup
59+
vi.mock('@/tools/metadata', () => toolsMetadataMock) // params / outputs / name
60+
```
61+
62+
Both are backed by the same `mockToolConfigs`, so mocking both gives one consistent tool universe. If you are unsure whether a mock is load-bearing, change a fixture value to a sentinel and confirm the test fails.
63+
## The guard
64+
65+
`bun run check:tool-registry-boundary` (CI: "Tool registry client-boundary audit") walks the module graph from each workspace route and fails if `@/tools/registry` is reachable, printing the exact import chain that reintroduced it.
66+
67+
If it fails, do not add the entry to an allowlist — there isn't one. Find the symbol the offending file actually needs and move it to a registry-free module, exactly as `mergeToolParameters` and `formatParameterLabel` were.
68+
69+
Run it with `--verbose` to print per-route module counts, which is also the quickest way to see whether a change moved the graph.
70+
71+
## How to verify an edge actually got cut
72+
73+
Do not eyeball imports — the registry is reached through several redundant paths, so cutting one buys nothing while another survives. Walk the graph:
74+
75+
1. From the entry you care about, follow `import` and `export … from` (skipping `import type`), resolving `@/` against `apps/sim`.
76+
2. Check whether `apps/sim/tools/registry.ts` is in the reachable set, and print the parent chain if it is.
77+
3. Compare the reachable module count before and after.
78+
79+
Reference points measured on this repo:
80+
81+
| entry | modules |
82+
| --- | --- |
83+
| `tools/registry.ts` reachable | ~4,900 |
84+
| `tools/merge-params.ts` (leaf) | 2 |
85+
| `providers/utils.ts` after cutting its `params` edge | 22 |
86+
| `app/workspace/[workspaceId]/w/page.tsx` (canvas) | 6,592 before, 1,908 after |
87+
88+
The canvas route reached the registry through **four** redundant edges — `providers/utils` (via `tools/params`), `lib/workflows/blocks/block-outputs`, `lib/workflows/sanitization/validation`, and `serializer/index`. Cutting any one alone moved the module count by ~1. They all had to go before anything improved; measure the route, not the file you edited.
89+
90+
## When adding a new caller
91+
92+
Ask what the caller does with the config. If it reads `params`, `outputs`, `name`, `description` or just checks existence, it belongs on `@/tools/metadata` — no exceptions, even on a path you believe is server-only today, because a future client import will silently re-attach the registry to the graph.
93+
94+
If it genuinely executes — builds a request, transforms a response, runs `directExecution` — use `getTool`, and keep that file off client-reachable paths.

.agents/skills/validate-integration/SKILL.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,13 +295,31 @@ Group findings by severity:
295295

296296
After reporting, fix every **critical** and **warning** issue. Apply **suggestions** where they don't add unnecessary complexity.
297297

298+
### Regenerate Derived Artifacts
299+
300+
Several files are generated from tool and block definitions. Editing a tool or block WITHOUT regenerating them fails CI, so run these before pushing:
301+
302+
```bash
303+
bun run tool-metadata:generate # repo root — apps/sim/tools/generated/*
304+
cd apps/sim && bun run generate-docs # docs .mdx + lib/integrations/integrations.json + docs icons
305+
```
306+
307+
- **`tool-metadata:generate`** — required whenever a tool's `outputs`, `params`, or descriptions change. CI enforces this with `bun run tool-metadata:check`, which fails with *"Generated tool metadata is stale"*. This is the easiest gate to miss, because nothing in the tool file hints that a generated artifact mirrors it.
308+
- **`generate-docs`** — required whenever block metadata changes (`bgColor`, `name`, `description`, operations, outputs). Regenerates the integration `.mdx`, `integrations.json`, and the docs copy of `components/icons.tsx`.
309+
310+
**Always diff the regen output before committing.** These generators rewrite every file they own, so they will also sweep in unrelated drift that accumulated on the base branch — pages losing sections, unrelated icons appearing. Keep only the hunks belonging to the integration under validation and `git checkout --` the rest, otherwise an unrelated doc regression rides along in the PR. Verify no page was silently dropped by comparing the directory listing before and after.
311+
312+
If an icon changed, `apps/sim/components/icons.tsx` is the source of truth and `apps/docs/components/icons.tsx` is its generated mirror — they must end up byte-identical for that component.
313+
298314
### Validation Output
299315

300316
After fixing, confirm:
301317
1. `bun run lint` passes with no fixes needed
302-
2. TypeScript compiles clean (no type errors)
303-
3. Re-read all modified files to verify fixes are correct
304-
4. Any remaining unknown response schemas were explicitly reported to the user instead of guessed
318+
2. TypeScript compiles clean (no type errors) — check the error list is empty for the files you touched; pre-existing unrelated errors in a worktree usually mean workspace packages resolve to the main checkout
319+
3. The integration's tests pass, and any test you added actually fails without its fix (revert it once and watch it go red)
320+
4. Derived artifacts regenerated and their diffs reviewed (see above)
321+
5. Re-read all modified files to verify fixes are correct
322+
6. Any remaining unknown response schemas were explicitly reported to the user instead of guessed
305323

306324
## Checklist Summary
307325

@@ -322,5 +340,8 @@ After fixing, confirm:
322340
- [ ] Validated `{Service}BlockMeta` exported with at least 7 templates
323341
- [ ] Reported all issues grouped by severity
324342
- [ ] Fixed all critical and warning issues
343+
- [ ] Ran `bun run tool-metadata:generate` if any tool outputs/params changed, and confirmed `bun run tool-metadata:check` passes
344+
- [ ] Ran `bun run generate-docs` if any block metadata changed, and reverted unrelated drift the generator swept in
325345
- [ ] Ran `bun run lint` after fixes
326346
- [ ] Verified TypeScript compiles clean
347+
- [ ] Verified added tests fail without their fix

.claude/commands/add-block.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,12 @@ Derive templates from the service's real use cases. Each prompt should name a co
918918
- **Ground every skill in operations the block actually exposes** — cross-check each skill's steps against `tools.access`. Never describe an action the integration cannot perform.
919919
- **Derive skills from real, popular use cases found online — never invent them.** Web-search the service's documented use cases (vendor use-case/solutions pages, official docs describing the workflow, reputable "top automations for X" articles) and only add a skill you can source as something people genuinely do with the service. Do not hallucinate skills.
920920

921+
## Generated tool metadata
922+
923+
Adding a block on its own needs **no** regeneration — a block references existing tool IDs through `tools.access` and does not change any tool's shape.
924+
925+
But if the same change also adds, edits **or removes** a tool, run `bun run tool-metadata:generate` and commit the result, or CI fails on stale artifacts. That matters here because a block's `outputs` are authored to match its tools' outputs, and the UI now reads those from the generated metadata rather than the executable registry — an unregenerated tool change makes the block's outputs disagree with what the panel renders. See `.agents/skills/tool-registry-boundary/SKILL.md`.
926+
921927
## Checklist Before Finishing
922928

923929
- [ ] `integrationType` is set to the correct `IntegrationType` enum value
@@ -932,6 +938,7 @@ Derive templates from the service's real use cases. Each prompt should name a co
932938
- [ ] Tools.config.tool returns correct tool ID (snake_case)
933939
- [ ] Outputs match tool outputs
934940
- [ ] Block + meta registered in registry-maps.ts (`BLOCK_REGISTRY` / `BLOCK_META_REGISTRY`)
941+
- [ ] If any tool was added, changed or removed alongside the block: ran `bun run tool-metadata:generate` and committed the artifacts
935942
- [ ] If icon missing: asked user to provide SVG
936943
- [ ] If triggers exist: `triggers` config set, trigger subBlocks spread
937944
- [ ] Optional/rarely-used fields set to `mode: 'advanced'`

.claude/commands/add-integration.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,16 @@ export const tools: Record<string, ToolConfig> = {
414414
}
415415
```
416416

417+
Then regenerate the generated tool metadata and commit it:
418+
419+
```bash
420+
bun run tool-metadata:generate
421+
```
422+
423+
Client code reads `params`/`outputs` from these artifacts rather than importing
424+
the registry, so a tool you add, change or remove is invisible to the UI until they are regenerated,
425+
and CI fails on stale ones. See `.agents/skills/tool-registry-boundary/SKILL.md`.
426+
417427
### Block Registry (`apps/sim/blocks/registry-maps.ts`)
418428

419429
The data maps (`BLOCK_REGISTRY` + `BLOCK_META_REGISTRY`) live in `registry-maps.ts`; `registry.ts` holds only the accessor functions. Add the import and an entry to each map alphabetically:
@@ -489,6 +499,7 @@ If creating V2 versions (API-aligned outputs):
489499
- [ ] All optional outputs have `optional: true`
490500
- [ ] Created `index.ts` barrel export
491501
- [ ] Registered all tools in `tools/registry.ts`
502+
- [ ] Ran `bun run tool-metadata:generate` and committed the regenerated artifacts
492503

493504
### Block
494505
- [ ] Created `blocks/blocks/{service}.ts`

.claude/commands/add-tools.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,17 @@ export const tools = {
295295
}
296296
```
297297

298+
3. Regenerate the tool metadata artifacts:
299+
300+
```bash
301+
bun run tool-metadata:generate
302+
```
303+
304+
Client code reads a tool's `params`/`outputs` from generated metadata rather than
305+
importing the registry, so a tool you add, change or remove is invisible to the UI until
306+
these are regenerated — and CI fails on stale artifacts. Commit the result. See
307+
`.agents/skills/tool-registry-boundary/SKILL.md`.
308+
298309
## Wiring Tools into the Block (Required)
299310

300311
After registering in `tools/registry.ts`, you MUST also update the block definition at `apps/sim/blocks/blocks/{service}.ts`. This is not optional — tools are only usable from the UI if they are wired into the block.
@@ -442,6 +453,7 @@ All tool IDs MUST use `snake_case`: `{service}_{action}` (e.g., `x_create_tweet`
442453
- [ ] Types file has all interfaces
443454
- [ ] Index.ts exports all tools and re-exports types (`export * from './types'`)
444455
- [ ] Tools registered in `tools/registry.ts`
456+
- [ ] `bun run tool-metadata:generate` run and the regenerated artifacts committed
445457
- [ ] Block wired: `tools.access`, dropdown options, subBlocks, `tools.config`, outputs, inputs
446458

447459
## Final Validation (Required)

0 commit comments

Comments
 (0)