You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .agents/skills/add-block-preview/SKILL.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -53,7 +53,7 @@ To pull an already-GA block from discovery surfaces on hosted (incident, depreca
53
53
-**Clone-not-remove:** gated blocks stay in `getAllBlocks()` output as clones with `hideFromToolbar: true` — `.find`-by-type consumers rely on this. Never filter them out.
54
54
-**Keys are registry block types.** Never `custom_block_*` (parse drops them — custom blocks have their own enabled/disabled lifecycle).
55
55
-**The shared hidden-predicate is `isHiddenUnder`** (`apps/sim/blocks/visibility/context.ts`). Never restate the preview/disabled rule inline at a new consumer.
56
-
-**Process-global caches stay ungated.**`getStaticComponentFiles` (VFS) and `getExposedIntegrationTools` build the ungated universe; per-viewer filtering happens at stamp/consumer time. Never move gating into a shared builder.
56
+
-**Process-global caches stay ungated.**Shared builders such as `getExposedIntegrationTools`(`apps/sim/lib/integrations/tool-catalog.ts`) build the ungated universe; per-viewer filtering happens at consumer time via `isHiddenUnder`. Never move gating into a shared builder.
57
57
- Gating is **surface hiding, not secrecy** — the full config ships in the client JS bundle. Anything truly secret cannot be a registered block.
**Critical:**Every subblock `id` must be unique within the block. Duplicate IDs cause conflicts even with different conditions.
76
+
**Critical:**Give every subblock a unique `id`: duplicates collide silently (the last definition wins). `blocks.test.ts` fails a duplicate within one condition unless the copies are a basic/advanced mode-swap pair, one basic plus trigger-mode copies, or all carry `canonicalParamId`. The only sanctioned cross-condition reuse is the hosted-key `apiKey` pair (`add-hosted-key` skill), where both fields deliberately share one value.
serviceId: '{service}', // Must match OAuth provider service key
133
133
requiredScopes: getScopesForService('{service}'), // Import from @/lib/oauth/utils
134
134
placeholder: 'Select account',
@@ -310,7 +310,7 @@ When several fields are mutually exclusive alternatives, mark them all `required
310
310
other paths ever get a chance to supply the value.
311
311
312
312
**Constraints (block-wide):**
313
-
-`canonicalParamId` must not equal any subblock `id` in the block.
313
+
-`canonicalParamId`may equal only the `id` of a member of its own group, as `channel` does in the canonicalParamId Pattern below; it must never equal any other subblock's`id`. (`blocks.test.ts` enforces the case of a subblock with no `canonicalParamId`.)
314
314
- One canonical id links exactly one basic/advanced pair for one logical parameter. Groups are keyed by canonical id across every subblock and hold one `basicId`, so two operations that each need a pair need two canonical ids.
315
315
- All members of a group share the same `required` status.
316
316
@@ -370,8 +370,6 @@ Declare the **canonical** id with `type: 'json'` — the subblock ids never reac
370
370
```typescript
371
371
inputs: {
372
372
file: { type: 'json', description: 'File to upload (UserFile or reference)' },
@@ -902,16 +921,16 @@ Every block declares a one-line prose summary that replaces its card's field row
902
921
903
922
```
904
923
Slack ← header (already names the block)
905
-
Posts ⟨Ship it 🚀⟩ to ⟨#eng⟩ ← the sentence; ⟨…⟩ are live value chips
924
+
Post ⟨Ship it 🚀⟩ to ⟨#eng⟩ ← the sentence; ⟨…⟩ are live value chips
906
925
```
907
926
908
927
Write one `byOperation` entry per operation dropdown option (or a single `default`
909
928
when the block has no operation dropdown).
910
929
911
-
**The full authoring contract — voice, structure, and the two mistakes that break
930
+
**The full authoring contract — voice, structure, and the four mistakes that break
912
931
cards silently — is `apps/sim/blocks/AGENTS.md` → "Canvas sentences". Read it
913
-
before writing any.**The two failures worth repeating here, because both are
914
-
invisible at runtime:
932
+
before writing any.**Two of those four are worth repeating here, because both
933
+
are invisible at runtime:
915
934
916
935
1. A clause naming only one member of a `canonicalParamId` pair drops the sentence
917
936
for every advanced-mode user. List all members:
@@ -927,35 +946,27 @@ bun run apps/sim/scripts/check-canvas-sentences.ts --block={service}
927
946
928
947
## Generated artifacts
929
948
949
+
When adding or changing `sunset.replacedBy`, run `bun run generate:block-successors` and commit
950
+
`apps/sim/lib/permission-groups/block-successors.generated.ts`. Authorization uses this generated
951
+
map to resolve legacy and current block IDs consistently without importing the executable registry.
952
+
Verify it with `bun run check:block-successors`.
953
+
930
954
Adding a block on its own needs no **tool metadata** regeneration — a block references existing
931
955
tool IDs through `tools.access` and does not change any tool's shape.
932
956
933
957
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 reads those from the generated metadata, not 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`.
934
958
935
-
A visible integration block does require the generated integration catalog and docs to be refreshed.
936
-
After adding or changing one, run:
937
-
938
-
```bash
939
-
bun run scripts/generate-docs.ts
940
-
bun run deployment-config:generate
941
-
bun run integration-catalog:check
942
-
bun run deployment-config:check
943
-
bun run docs:check
944
-
```
945
-
946
-
The catalog check independently derives deployment metadata from the executable block registry and
947
-
compares it with the committed `packages/deployment-config/src/integrations.json`. The deployment
948
-
config check verifies the generated service-account facts against the canonical OAuth registry and
949
-
catalog. `docs:check` re-renders every generated docs artifact in memory and fails on any committed
950
-
file that differs — it runs in CI via `check:audits`, so commit the full generator output. If the
951
-
generator also trues up pages an earlier PR left stale, commit that catch-up too; reverting it as
952
-
"unrelated drift" makes `docs:check` fail. Review the generated diff and keep only intentional
953
-
changes.
959
+
A visible integration block does require the generated integration catalog and docs to be refreshed:
960
+
`bun run tool-metadata:generate` (only when a tool changed), `bun run scripts/generate-docs.ts`,
961
+
`bun run deployment-config:generate`, then `bun run check:audits`. Also run
962
+
`bun run apps/sim/scripts/check-block-registry.ts origin/staging` (CI runs it outside `check:audits`). Commit the
963
+
full generator output. For what each check verifies, see the `validate-integration` skill →
964
+
Regenerate Derived Artifacts.
954
965
955
966
## Checklist Before Finishing
956
967
957
968
-[ ]`integrationType` is set to the correct `IntegrationType` enum value
958
-
-[ ]`tags`array includes all applicable `IntegrationTag`values
969
+
-[ ]`{Service}BlockMeta.tags`lists every applicable `IntegrationTag`(tags live on the meta, not the block)
959
970
-[ ] All subBlocks have `id`, `title` (except switch), and `type`
960
971
-[ ] Conditions use correct syntax (field, value, not, and)
961
972
-[ ] DependsOn set for fields that need other values
@@ -969,6 +980,7 @@ changes.
969
980
-[ ] Tools.config.tool returns correct tool ID (snake_case)
970
981
-[ ] Outputs match tool outputs
971
982
-[ ] Block + meta registered in registry-maps.ts (`BLOCK_REGISTRY` / `BLOCK_META_REGISTRY`)
983
+
-[ ] If `sunset.replacedBy` changed: regenerated and committed the block successor map; `bun run check:block-successors` passes
972
984
-[ ] If any tool was added, changed or removed alongside the block: ran `bun run tool-metadata:generate` and committed the artifacts
973
985
-[ ] Ran `bun run scripts/generate-docs.ts`, reviewed the generated diff, and committed the integration catalog changes
974
986
-[ ]`bun run integration-catalog:check` passes
@@ -990,7 +1002,7 @@ Validate the block against every tool in `tools.access`:
990
1002
2.**For each tool, verify the block has correct:**
991
1003
- SubBlock inputs that cover all required tool params (with correct `condition` to show for that operation)
992
1004
- SubBlock input types that match the tool param types (e.g., dropdown for enums, short-input for strings)
993
-
-`tools.config.params`correctly maps subBlock IDs to tool param names (if they differ)
1005
+
-Each subBlock (or its `canonicalParamId`) is named exactly after the tool param it fills. A required `user-only` param that is only renamed in `tools.config.params`fails `bun run apps/sim/scripts/check-block-registry.ts origin/staging`; remap only optional or `user-or-llm` params
994
1006
- Type coercions in `tools.config.params` for any params that need conversion (Number(), Boolean(), JSON.parse())
995
1007
3.**Verify block outputs** cover the key fields returned by all tools
996
1008
4.**Verify conditions** — each subBlock should only show for the operations that actually use it
Copy file name to clipboardExpand all lines: .agents/skills/add-column-type/SKILL.md
+9-9Lines changed: 9 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,7 +12,7 @@ A `case 'yourtype':` outside `column-types/` fails **silently** when missed (a w
12
12
13
13
## Hard Rule: the compiler tells you what to do
14
14
15
-
Do **not** hunt for places to edit. Add your typeto the `ColumnType` union first and let `tsc` produce the list:
15
+
Do **not** hunt for places to edit. Append your type's id to the `COLUMN_TYPES` array in `column-types/types.ts`first (`ColumnType` derives from it) and let `tsc` produce the list:
16
16
17
17
```bash
18
18
cd apps/sim && bun run type-check
@@ -86,7 +86,7 @@ export function Type{Pascal}(props: SVGProps<SVGSVGElement>) {
86
86
87
87
## Step 3: Write the type file
88
88
89
-
`apps/sim/lib/table/column-types/{name}.ts`. Copy the closest existing type and change what differs. Every field is required by the interface, so the compiler enumerates them for you — read the TSDoc in `types.ts`rather than guessing.
89
+
`apps/sim/lib/table/column-types/{name}.ts`. Copy the closest existing type and change what differs. Required fields are compiler-enforced; optional hooks (`isCompatibleWith`, `salvage`, `valueForEquality`, `filterOperatorsFor`, …) default sensibly — read the TSDoc in `types.ts`before overriding.
90
90
91
91
The three that are easy to get wrong:
92
92
@@ -132,29 +132,29 @@ Registering the *type* is compiler-enforced. Registering its *metadata* is not,
132
132
|`column-types/types.ts``TYPE_SPECIFIC_COLUMN_KEYS`| it is never stripped on conversion, and poisons the target type |
133
133
|`lib/api/contracts/tables.ts` — the schema slot in all three column schemas, plus `refineColumnOptions`| zod strips it at the boundary; silently never saved |
134
134
|`columns/service.ts``addTableColumn` param type | callers cannot pass it |
135
-
| A metadata-only update path (`updateColumnCurrency` is the model) + a branch in both column routes + the copilot tool| changing it on an existing column is a silent 200 no-op |
135
+
| A metadata-only update in `lib/table/columns/service.ts`(`updateColumnCurrency` is the model) + a branch in `performUpdateTableColumn` in `lib/table/orchestration/columns.ts`| changing it on an existing column is a silent 200 no-op |
136
136
|`column-config-sidebar.tsx`| no UI to set it |
137
137
|`table-grid.tsx` delete-column undo + `use-table-undo.ts` restore | undo silently resets it to the default |
138
138
139
139
`normalizeColumn`, `buildConvertedColumn`, and the undo snapshot read `TYPE_SPECIFIC_COLUMN_KEYS` generically, so those three are already zero-edit.
140
140
141
-
**Known gap:** the metadata-only update path is ~6 near-identical copies (service + 2 routes + copilot). A `metadataUpdate` descriptor on `ColumnTypeServerDefinition` would collapse them; until that exists, copy `currency`'s.
141
+
Copy `currency`'s service function and orchestration branch.
142
142
143
143
## Checklist Before Finishing
144
144
145
-
-[ ]Added to the `ColumnType` union in `column-types/types.ts`
146
-
-[ ]`column-types/{id}.ts` created, every interface field filled in
145
+
-[ ]Id appended to `COLUMN_TYPES` in `column-types/types.ts`
146
+
-[ ]`column-types/{id}.ts` created, every required field filled in
147
147
-[ ] Registered in **both**`registry.ts` and `registry.server.ts`
148
148
-[ ] Icon added, centered on the family's optical center, exported alphabetically
149
149
-[ ]`migrateCellsTo` / `migrateCellsFrom` added if the stored bytes change
150
150
-[ ] New metadata keys added to `TYPE_SPECIFIC_COLUMN_KEYS` + `FOREIGN_METADATA_VERB`
151
-
-[ ] Unit tests for `coerce` / `isCompatibleWith` round-trips, verified to fail without the code
151
+
-[ ] Unit tests for `coerce` / `isCompatibleWith` round-trips only if they pass the `test-audit` authoring gate, verified to fail without the code
152
152
-[ ] Docs row added to `apps/docs/content/docs/tables/index.mdx`
153
153
154
154
## Final Validation (Required)
155
155
156
156
1.**`cd apps/sim && bun run type-check`** — must be clean. If any file *outside*`column-types/` errors, that file has a hardcoded type list; fix it to read the registry.
157
157
2.**Grep for leaks** — `grep -rnE "(===|!==) '{id}'|case '{id}':" apps/sim --include='*.ts' --include='*.tsx' | grep -v column-types/`. (All three forms: a plain `!==` and a `case` are how half of `currency`'s real branches are written.) Hits are expected; judge each. A hit is fine when it mounts a specific React component or encodes a genuinely one-off behavior (`json`'s mono textarea, `date`'s timezone-aware parsing). A hit is a **leak** when it restates something the registry could answer — an icon, a label, a colour, an operator set, a cast, a coercion. Leaks get a registry field, not a new branch.
158
-
3.**Run the suite** — `bunx vitest run lib/table 'app/workspace/[workspaceId]/tables' lib/api app/api/table app/api/v1 lib/copilot/tools/server/table`. Existing tests must pass **unchanged**; needing to edit one means you changed behavior for the other types.
159
-
4.**`bun run lint:check`, `bun run check:api-validation`, `bun run check:client-boundary`** from the repo root.
158
+
3.**Run the suite** — `bun run --cwd apps/sim test lib/table 'app/workspace/[workspaceId]/tables' lib/api app/api/table app/api/v1`. Existing tests must pass **unchanged**; needing to edit one means you changed behavior for the other types.
159
+
4.**`bun run lint`, `bun run check:api-validation:strict`, `bun run check:client-boundary`** from the repo root.
160
160
5.**Exercise it in the running app** on a table with one column of every type: create, edit inline / in the expanded popover / in the row modal, paste from a spreadsheet, filter, sort, convert to and from other types, export CSV, undo a column delete.
0 commit comments