Skip to content

Commit c59ebc2

Browse files
committed
Merge remote-tracking branch 'origin/staging' into feat/let-mothership-edit-views
2 parents 6adf211 + 9acf0f8 commit c59ebc2

6,815 files changed

Lines changed: 546146 additions & 532919 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-preview/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ A revealed block that is not globally GA (`enabled !== true`, or env-revealed) r
4141
- GA via config (code cleanup pending): `{ "enabled": true }` — suffix disappears everywhere within ~30s (AppConfig TTL) + client refetch.
4242

4343
Same runbook as `feature-flags`: edit the hosted document, `aws appconfig start-deployment` with the `sim-<env>-fast` strategy (see the infra README).
44-
5. **GA cleanup:** delete `preview: true` from the block (now visible to self-hosters on their next upgrade), add its `BlockMeta` + regen docs, and drop the AppConfig entry. For a v2 upgrade, this is also when v1 gets `hideFromToolbar: true` (the superseded-version paradigm).
44+
5. **GA cleanup:** delete `preview: true` from the block (now visible to self-hosters on their next upgrade), add its `BlockMeta` + regen docs, and drop the AppConfig entry. For a v2 upgrade, this is also when v1 gets `hideFromToolbar: true` **and** `sunset: { status: 'legacy', replacedBy: '<v2-type>' }` (the superseded-version paradigm). Both edits must land in the **same commit** as the `preview: true` removal — `check-block-registry` fails a sunset block whose `replacedBy` is still `preview`, so splitting them breaks the build in between. Also move the block's `BLOCK_DISPLAY_WORKFLOWS` entry (`apps/docs/components/workflow-preview/block-display-workflows.ts`) to the new type, or `BlockPreview` silently renders nothing on the docs page.
4545

4646
## Kill switch (shipped blocks)
4747

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

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ When the user asks you to create a block:
1919

2020
Blocks depend on tool outputs. If the underlying tool response schema is not documented or live-verified, you MUST tell the user instead of guessing block outputs.
2121

22+
When block work changes tool execution, same-process work must use a registered
23+
`InternalToolConfig.operation`. Never add a Sim `/api/...` self-hop or the retired
24+
`directExecution` property.
25+
2226
- Do NOT invent block outputs for undocumented tool responses
2327
- Do NOT describe unknown JSON shapes as if they were confirmed
2428
- Do NOT wire fields into the block just because they seem likely to exist
@@ -203,6 +207,7 @@ silently available.
203207
id: 'channel',
204208
title: 'Channel',
205209
type: 'channel-selector',
210+
selectorKey: '{service}.channels',
206211
serviceId: '{service}',
207212
placeholder: 'Select channel',
208213
dependsOn: ['credential'],
@@ -213,6 +218,7 @@ silently available.
213218
id: 'project',
214219
title: 'Project',
215220
type: 'project-selector',
221+
selectorKey: '{service}.projects',
216222
serviceId: '{service}',
217223
dependsOn: ['credential'],
218224
}
@@ -222,6 +228,7 @@ silently available.
222228
id: 'file',
223229
title: 'File',
224230
type: 'file-selector',
231+
selectorKey: '{service}.files',
225232
serviceId: '{service}',
226233
mimeType: 'application/pdf',
227234
dependsOn: ['credential'],
@@ -232,6 +239,7 @@ silently available.
232239
id: 'user',
233240
title: 'User',
234241
type: 'user-selector',
242+
selectorKey: '{service}.users',
235243
serviceId: '{service}',
236244
dependsOn: ['credential'],
237245
}
@@ -687,6 +695,10 @@ export const ServiceBlock: BlockConfig = {
687695
type: 'service',
688696
name: 'Service (Legacy)',
689697
hideFromToolbar: true, // Hide from toolbar
698+
// Required: drives the amber legacy badge and its click-to-upgrade action.
699+
// `check-block-registry` fails a legacy block with no `replacedBy`, one whose
700+
// target does not exist, or one whose target is itself sunset or still `preview`.
701+
sunset: { status: 'legacy', replacedBy: 'service_v2' },
690702
// ... rest of config
691703
}
692704

@@ -1052,12 +1064,20 @@ After creating the block, you MUST validate it against every tool it references:
10521064
4. **Verify conditions** — each subBlock should only show for the operations that actually use it
10531065
5. **Verify `{Service}BlockMeta` is exported** with at least 7 templates, each having `icon`, `title`, `prompt`, `modules`, `category`, and `tags`
10541066
6. **If any tool outputs are still unknown**, explicitly tell the user instead of guessing block outputs
1067+
7. **Verify the tool execution boundary** — blocks never create or call API routes. Every referenced
1068+
tool must already be either a registered `InternalToolConfig.operation` or an absolute external
1069+
HTTP(S) `ToolConfig.request`. If transport needs to change, use the `add-tools` skill; do not add a
1070+
same-origin `/api/...` hop from the block.
10551071

10561072
## Option Lists: `selectorKey` or `options`, never a per-block fetcher
10571073

10581074
A sub-block gets its choices from exactly one of two places. There is no third.
10591075

1060-
**`selectorKey` — every remote list.** Register the list in `hooks/selectors/providers/<service>/selectors.ts`, add its key to `SelectorKey`, and point the sub-block at it. A selector is parameterized by an explicit `SelectorContext`, so the same definition serves the canvas, the workspace-fork sync modal, and anything added later.
1076+
**`selectorKey` — every remote list.** Use the `add-selector` skill to add browser-safe metadata in
1077+
`apps/sim/lib/selectors/manifest.ts`. Attach `provider-server` selectors under
1078+
`apps/sim/lib/selectors/server/providers/` and `internal-server` selectors in
1079+
`apps/sim/lib/selectors/server/internal.ts`. Point the sub-block at that key. All remote selectors
1080+
execute through `selectors.execute`; never add a client provider module or selector-only fetch route.
10611081

10621082
```ts
10631083
{ id: 'triggerCredentials', type: 'oauth-input', canonicalParamId: 'oauthCredential', mode: 'trigger' },
@@ -1066,7 +1086,13 @@ A sub-block gets its choices from exactly one of two places. There is no third.
10661086
{ id: 'manualLabelIds', type: 'short-input', mode: 'trigger-advanced' },
10671087
```
10681088

1069-
`canonicalParamId: 'oauthCredential'` on the credential sub-block is the line people forget. `buildSelectorContextFromBlock` keys the context on a sub-block's CANONICAL id, so without it `context.oauthCredential` is never set and the picker looks unfixable without reading the store. (A credential field is also recognised by its `oauth-input` TYPE as a fallback, so a block whose shipped param is already named something else does not have to rename it.)
1089+
`canonicalParamId: 'oauthCredential'` on the credential sub-block is the line people forget. The
1090+
shared context builder projects only active `dependsOn` values and keys canonical pairs by their
1091+
canonical id. Exact environment references such as `{{GMAIL_CREDENTIAL_ID}}` stay unresolved in the
1092+
browser and are resolved only by the authorized server executor. The builder does not infer a
1093+
nonstandard credential id from `type: 'oauth-input'`; give it
1094+
`canonicalParamId: 'oauthCredential'`, or declare an explicit manifest `sourceFields` alias when a
1095+
legacy source id must be retained.
10701096

10711097
**`options` — everything else.** A static array, or a pure function of the block's own values for a list that narrows to a sibling's selection. No I/O.
10721098

@@ -1081,5 +1107,6 @@ options: (params) => {
10811107

10821108
Two rules the checks enforce:
10831109

1084-
- **A secret never enters a selector's `getQueryKey`.** A query key identifies a resource; a credential authorizes access to it. A credential *id* is fine; a typed password is not (see `imap.mailboxes`).
1110+
- **Selector query keys contain no context values.** This includes credential IDs, raw secrets,
1111+
unresolved references, and hashes of those values; the shared facade uses an opaque local revision.
10851112
- **A sub-block that `dependsOn` a credential / knowledge-base / table selector must be reconfigurable at fork-sync time** — a `selectorKey`, a canonical pair whose basic member is a selector, or a `short-input`/`long-input`. `bun run check:fork-dependent-coverage` fails otherwise, because a fork sync clears those fields on every push and an unofferable one can never be set anywhere that sticks.

‎.agents/skills/add-column-type/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ Registering the *type* is compiler-enforced. Registering its *metadata* is not,
149149
- [ ] `migrateCellsTo` / `migrateCellsFrom` added if the stored bytes change
150150
- [ ] New metadata keys added to `TYPE_SPECIFIC_COLUMN_KEYS` + `FOREIGN_METADATA_VERB`
151151
- [ ] Unit tests for `coerce` / `isCompatibleWith` round-trips, verified to fail without the code
152-
- [ ] Docs row added to `apps/docs/content/docs/en/tables/index.mdx`
152+
- [ ] Docs row added to `apps/docs/content/docs/tables/index.mdx`
153153

154154
## Final Validation (Required)
155155

‎.agents/skills/add-connector/SKILL.md‎

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,14 @@ Three field types are supported: `short-input`, `dropdown`, and `selector`.
197197

198198
## Dynamic Selectors (Canonical Pairs)
199199

200-
Use `type: 'selector'` to fetch options dynamically from the existing selector registry (`hooks/selectors/registry.ts`). Selectors are always paired with a manual fallback input using the **canonical pair** pattern — a `selector` field (basic mode) and a `short-input` field (advanced mode) linked by `canonicalParamId`.
200+
Use `type: 'selector'` for a key declared in the browser-safe selector manifest at
201+
`apps/sim/lib/selectors/manifest.ts`. Remote selectors execute through the authorized
202+
`selectors.execute` server operation and a server attachment; connectors never call providers or
203+
resolve credentials in the browser. Apply the `add-selector` skill when the key does not exist.
204+
205+
Selectors are paired with a manual fallback input using the **canonical pair** pattern — a
206+
`selector` field (basic mode) and a `short-input` field (advanced mode) linked by
207+
`canonicalParamId`.
201208

202209
The user sees a toggle button (ArrowLeftRight) to switch between the selector dropdown and manual text input. On submit, the modal resolves each canonical pair to the active mode's value, keyed by `canonicalParamId`.
203210

@@ -217,7 +224,7 @@ configFields: [
217224
id: 'baseSelector',
218225
title: 'Base',
219226
type: 'selector',
220-
selectorKey: 'airtable.bases', // Must exist in hooks/selectors/registry.ts
227+
selectorKey: 'airtable.bases', // Must exist in lib/selectors/manifest.ts
221228
canonicalParamId: 'baseId',
222229
mode: 'basic',
223230
placeholder: 'Select a base',
@@ -260,7 +267,9 @@ configFields: [
260267

261268
### Selector with domain dependency (Jira/Confluence pattern)
262269

263-
When a selector depends on a plain `short-input` field (no canonical pair), `dependsOn` references that field's `id` directly. The `domain` field's value maps to `SelectorContext.domain` automatically via `SELECTOR_CONTEXT_FIELDS`.
270+
When a selector depends on a plain `short-input` field (no canonical pair), `dependsOn` references
271+
that field's `id` directly. Exact references such as `{{JIRA_DOMAIN}}` remain unresolved in the
272+
browser and are resolved only after workspace authorization on the server.
264273

265274
```typescript
266275
configFields: [
@@ -296,16 +305,16 @@ configFields: [
296305

297306
### How `dependsOn` maps to `SelectorContext`
298307

299-
The connector selector field builds a `SelectorContext` from dependency values. For the mapping to work, each dependency's `canonicalParamId` (or field `id` for non-canonical fields) must exist in `SELECTOR_CONTEXT_FIELDS` (`lib/workflows/subblocks/context.ts`):
300-
301-
```
302-
oauthCredential, domain, teamId, projectId, knowledgeBaseId, planId,
303-
siteId, collectionId, spreadsheetId, fileId, baseId, datasetId, serviceDeskId
304-
```
308+
The shared connector context builder projects only active dependencies. A canonical dependency uses
309+
its active basic or advanced value under `canonicalParamId`; a non-canonical dependency uses its
310+
field `id`. The resulting key must be a `SelectorContextKey` in
311+
`apps/sim/lib/selectors/types.ts` and must be explicitly allowed by that selector's manifest entry.
312+
The browser sends the connector's workspace scope, not the complete connector configuration.
305313

306314
### Available selector keys
307315

308-
Check `hooks/selectors/types.ts` for the full `SelectorKey` union. Common ones for connectors:
316+
Check `apps/sim/lib/selectors/manifest.ts` for the exhaustive selector keys. Common ones for
317+
connectors:
309318

310319
| SelectorKey | Context Deps | Returns |
311320
|-------------|-------------|---------|
@@ -607,9 +616,13 @@ export const CONNECTOR_META_REGISTRY: ConnectorMetaRegistry = {
607616
- [ ] **Selector fields configured correctly (if applicable):**
608617
- Every `type: 'selector'` field has a canonical pair (`short-input` or `dropdown` with same `canonicalParamId` and `mode: 'advanced'`)
609618
- `required` is identical on both fields in each canonical pair
610-
- `selectorKey` exists in `hooks/selectors/registry.ts`
619+
- `selectorKey` exists in `apps/sim/lib/selectors/manifest.ts`
611620
- `dependsOn` references selector field IDs (not `canonicalParamId`)
612-
- Dependency `canonicalParamId` values exist in `SELECTOR_CONTEXT_FIELDS`
621+
- Each projected dependency key is a `SelectorContextKey` allowed by the selector manifest
622+
- Every remote key has one server attachment with credential provider binding and a reviewed
623+
`fixed`, `credential-bound`, or `user-controlled` destination policy
624+
- No connector selector adds a client provider module, browser token request, or selector-only
625+
API route
613626
- [ ] `listDocuments` handles pagination with metadata-based content hashes
614627
- [ ] `syncContext.listingCapped = true` set whenever the listing is truncated (max-items cap or transient per-item error) — required to prevent the engine's deletion reconciliation from removing unseen documents
615628
- [ ] `contentDeferred: true` used if content requires per-doc API calls (file download, export, blocks fetch)

0 commit comments

Comments
 (0)