Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .cursor/rules/we-schema.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -1285,8 +1285,8 @@ AdamStore:
- currentPerspective: PerspectiveProxy | null (the perspective currently being viewed)
- currentPerspectiveModels: ModelManifestEntry[] (non-WE SHACL models from the current perspective; injected as externalModels into AI messages)
- isWeSpace: boolean — true once the current perspective is confirmed to have WE's Space SDNA installed (false for a joined-but-foreign perspective, e.g. one synced in from Flux)
- personalSpaces: array of Space objects (local/personal spaces)
- sharedSpaces: array of Space objects (shared/neighbourhood spaces)
- personalSpaces: array of Space objects (local/personal spaces; all Space fields)
- sharedSpaces: array of Space objects (shared/neighbourhood spaces; all Space fields)
- bootState: string
- passwordError: string | undefined
- loginLoading: boolean
Expand Down Expand Up @@ -1364,7 +1364,7 @@ SpaceStore:
- memberDids: string[] — DIDs of all members in the current space (includes own DID)
- members: AgentProfileSummary[] — cached profiles for all memberDids
- spaceDefaultTemplateId: string — the current space's default template ID (empty string when no space is active)
- currentSpace: Space | null — the current space model (uuid, name, description, avatar, defaultTemplateId)
- currentSpace: Space | null — the current space model (all Space fields: uuid, url, name, description, access, discovery, avatar, coverImage, defaultTemplateId, defaultThemeId, location, plus id/author/createdAt)
- foreignSpacePrefill: { name, description, avatar } | null — detected from a foreign app's own model (e.g. Flux's Community) for prefilling the "Initialize as WE space" gate; null once the perspective is a WE space or no recognized foreign model is found
- signalTypes: array of SignalType objects (community-created reaction/vote types)
- signalTypesBySlug: Record<slug, SignalType> — computed map; access via { $store: "spaceStore.signalTypesBySlug.<slug>" }; use .id for the UUID
Expand Down
6 changes: 3 additions & 3 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1285,8 +1285,8 @@ AdamStore:
- currentPerspective: PerspectiveProxy | null (the perspective currently being viewed)
- currentPerspectiveModels: ModelManifestEntry[] (non-WE SHACL models from the current perspective; injected as externalModels into AI messages)
- isWeSpace: boolean — true once the current perspective is confirmed to have WE's Space SDNA installed (false for a joined-but-foreign perspective, e.g. one synced in from Flux)
- personalSpaces: array of Space objects (local/personal spaces)
- sharedSpaces: array of Space objects (shared/neighbourhood spaces)
- personalSpaces: array of Space objects (local/personal spaces; all Space fields)
- sharedSpaces: array of Space objects (shared/neighbourhood spaces; all Space fields)
- bootState: string
- passwordError: string | undefined
- loginLoading: boolean
Expand Down Expand Up @@ -1364,7 +1364,7 @@ SpaceStore:
- memberDids: string[] — DIDs of all members in the current space (includes own DID)
- members: AgentProfileSummary[] — cached profiles for all memberDids
- spaceDefaultTemplateId: string — the current space's default template ID (empty string when no space is active)
- currentSpace: Space | null — the current space model (uuid, name, description, avatar, defaultTemplateId)
- currentSpace: Space | null — the current space model (all Space fields: uuid, url, name, description, access, discovery, avatar, coverImage, defaultTemplateId, defaultThemeId, location, plus id/author/createdAt)
- foreignSpacePrefill: { name, description, avatar } | null — detected from a foreign app's own model (e.g. Flux's Community) for prefilling the "Initialize as WE space" gate; null once the perspective is a WE space or no recognized foreign model is found
- signalTypes: array of SignalType objects (community-created reaction/vote types)
- signalTypesBySlug: Record<slug, SignalType> — computed map; access via { $store: "spaceStore.signalTypesBySlug.<slug>" }; use .id for the UUID
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1285,8 +1285,8 @@ AdamStore:
- currentPerspective: PerspectiveProxy | null (the perspective currently being viewed)
- currentPerspectiveModels: ModelManifestEntry[] (non-WE SHACL models from the current perspective; injected as externalModels into AI messages)
- isWeSpace: boolean — true once the current perspective is confirmed to have WE's Space SDNA installed (false for a joined-but-foreign perspective, e.g. one synced in from Flux)
- personalSpaces: array of Space objects (local/personal spaces)
- sharedSpaces: array of Space objects (shared/neighbourhood spaces)
- personalSpaces: array of Space objects (local/personal spaces; all Space fields)
- sharedSpaces: array of Space objects (shared/neighbourhood spaces; all Space fields)
- bootState: string
- passwordError: string | undefined
- loginLoading: boolean
Expand Down Expand Up @@ -1364,7 +1364,7 @@ SpaceStore:
- memberDids: string[] — DIDs of all members in the current space (includes own DID)
- members: AgentProfileSummary[] — cached profiles for all memberDids
- spaceDefaultTemplateId: string — the current space's default template ID (empty string when no space is active)
- currentSpace: Space | null — the current space model (uuid, name, description, avatar, defaultTemplateId)
- currentSpace: Space | null — the current space model (all Space fields: uuid, url, name, description, access, discovery, avatar, coverImage, defaultTemplateId, defaultThemeId, location, plus id/author/createdAt)
- foreignSpacePrefill: { name, description, avatar } | null — detected from a foreign app's own model (e.g. Flux's Community) for prefilling the "Initialize as WE space" gate; null once the perspective is a WE space or no recognized foreign model is found
- signalTypes: array of SignalType objects (community-created reaction/vote types)
- signalTypesBySlug: Record<slug, SignalType> — computed map; access via { $store: "spaceStore.signalTypesBySlug.<slug>" }; use .id for the UUID
Expand Down
144 changes: 144 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,115 @@ import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort';

import prettierConfig from './.prettierrc.json' with { type: 'json' };

/**
* CSS properties (in both camelCase and kebab-case spellings) that have a design-system
* prop of the same meaning. Sourced from the DS prop layers in
* `packages/design-system/utils/src/index.ts`.
*
* Properties with no DS equivalent — white-space, filter, clip-path, backdrop-filter,
* mix-blend-mode, grid-template-*, object-fit — are deliberately absent: `styles` is the
* correct tool for those.
*/
const DS_PROP_EQUIVALENTS = [
'width',
'height',
'minWidth',
'min-width',
'maxWidth',
'max-width',
'minHeight',
'min-height',
'maxHeight',
'max-height',
'position',
'top',
'right',
'bottom',
'left',
'zIndex',
'z-index',
'display',
'overflow',
'flex',
'alignSelf',
'align-self',
'margin',
'marginTop',
'margin-top',
'marginRight',
'margin-right',
'marginBottom',
'margin-bottom',
'marginLeft',
'margin-left',
'padding',
'paddingTop',
'padding-top',
'paddingRight',
'padding-right',
'paddingBottom',
'padding-bottom',
'paddingLeft',
'padding-left',
'gap',
'background',
'backgroundColor',
'background-color',
'color',
'opacity',
'border',
'borderColor',
'border-color',
'borderRadius',
'border-radius',
'boxShadow',
'box-shadow',
'cursor',
'pointerEvents',
'pointer-events',
'transform',
'transition',
'fontSize',
'font-size',
'fontWeight',
'font-weight',
'lineHeight',
'line-height',
'letterSpacing',
'letter-spacing',
'textAlign',
'text-align',
'textDecoration',
'text-decoration',
'textTransform',
'text-transform',
'fontFamily',
'font-family',
'flexDirection',
'flex-direction',
'alignItems',
'align-items',
'justifyContent',
'justify-content',
];

/** Elements that accept DS props: `we-*` primitives and the layout/composite components. */
const DS_ELEMENTS = '^(we-|Column$|Row$|Grid$|Card$)';

function dsPropSelectors() {
const props = `^(${DS_PROP_EQUIVALENTS.join('|')})$`;
const message =
'This CSS property has a design-system prop — use it instead of the style/styles escape hatch ' +
'(e.g. width="130px", maxHeight="250px"). Reserve styles for CSS with no DS equivalent.';
// Object keys appear as identifiers (width) or string literals ('max-height').
return ['key.name', 'key.value'].map((keyPath) => ({
selector:
`JSXOpeningElement[name.name=/${DS_ELEMENTS}/] > JSXAttribute[name.name=/^styles?$/] ` +
`> JSXExpressionContainer > ObjectExpression > Property[${keyPath}=/${props}/]`,
message,
}));
}

export default [
{
ignores: [
Expand Down Expand Up @@ -85,4 +194,39 @@ export default [
'@typescript-eslint/no-empty-object-type': 'off',
},
},
{
// Design-system props over the style/styles escape hatch.
//
// CLAUDE.md ("Using the Design System in TypeScript Components") says to use `styles`
// only for CSS with no DS equivalent — but that only held while people remembered it,
// and the editor panels drifted a long way. This makes the common half mechanical:
// if a CSS property has a DS prop of the same meaning, writing it through style/styles
// is an error.
//
// Scoped deliberately:
// - only elements that accept DS props (we-* primitives, Column/Row/Grid/Card).
// A raw <div style> has no DS prop to use instead, so it is out of scope.
// - only DS-consuming packages. @we/components and @we/widgets *implement* DS props
// and legitimately write raw CSS; the React playgrounds have no DS at all.
name: 'design-system/prefer-ds-props',
files: ['packages/app-framework/**/*.tsx', 'packages/block-system/**/*.tsx', 'packages/schema-system/**/*.tsx'],
rules: {
'no-restricted-syntax': ['error', ...dsPropSelectors()],
},
},
{
// Pre-existing violations, to be swept file by file. Delete entries as they are
// cleaned — the list only ever shrinks, and new files get the rule from birth.
name: 'design-system/prefer-ds-props-debt',
files: [
'packages/app-framework/src/frameworks/solid/components/editor/AiPanel.tsx',
'packages/app-framework/src/frameworks/solid/components/editor/DesignToolbar.tsx',
'packages/app-framework/src/frameworks/solid/components/editor/InspectorPanel.tsx',
'packages/app-framework/src/frameworks/solid/components/editor/RightPanelContainer.tsx',
'packages/app-framework/src/frameworks/solid/components/editor/ThemePanel.tsx',
'packages/app-framework/src/frameworks/solid/components/marketplace/TemplateCard.tsx',
'packages/block-system/frameworks/solid/src/components/VideoBlock/VideoDisplay.tsx',
],
rules: { 'no-restricted-syntax': 'off' },
},
];
7 changes: 4 additions & 3 deletions packages/ai-context/context.json
Original file line number Diff line number Diff line change
Expand Up @@ -5335,11 +5335,11 @@
},
"personalSpaces": {
"type": "array",
"properties": ["uuid", "name", "description", "url", "visibility"]
"model": "Space"
},
"sharedSpaces": {
"type": "array",
"properties": ["uuid", "name", "description", "url", "visibility"]
"model": "Space"
},
"bootState": {
"type": "string"
Expand Down Expand Up @@ -5512,14 +5512,15 @@
},
"currentSpace": {
"type": "object",
"properties": ["uuid", "name", "description", "avatar", "defaultTemplateId"]
"model": "Space"
},
"foreignSpacePrefill": {
"type": "object",
"properties": ["name", "description", "avatar"]
},
"signalTypes": {
"type": "array",
"model": "SignalType",
"properties": [
"id",
"name",
Expand Down
7 changes: 4 additions & 3 deletions packages/ai-context/src/contextData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2019,8 +2019,8 @@ export const contextData: ContextData = {
currentPerspective: { type: 'object', properties: ['uuid', 'name', 'sharedUrl'] },
currentPerspectiveModels: { type: 'array' },
isWeSpace: { type: 'boolean' },
personalSpaces: { type: 'array', properties: ['uuid', 'name', 'description', 'url', 'visibility'] },
sharedSpaces: { type: 'array', properties: ['uuid', 'name', 'description', 'url', 'visibility'] },
personalSpaces: { type: 'array', model: 'Space' },
sharedSpaces: { type: 'array', model: 'Space' },
bootState: { type: 'string' },
passwordError: { type: 'string' },
loginLoading: { type: 'boolean' },
Expand Down Expand Up @@ -2120,10 +2120,11 @@ export const contextData: ContextData = {
properties: ['did', 'firstName', 'lastName', 'handle', 'bio', 'avatar', 'coverImage', 'location'],
},
spaceDefaultTemplateId: { type: 'string' },
currentSpace: { type: 'object', properties: ['uuid', 'name', 'description', 'avatar', 'defaultTemplateId'] },
currentSpace: { type: 'object', model: 'Space' },
foreignSpacePrefill: { type: 'object', properties: ['name', 'description', 'avatar'] },
signalTypes: {
type: 'array',
model: 'SignalType',
properties: [
'id',
'name',
Expand Down
14 changes: 8 additions & 6 deletions packages/ai-context/src/fragments/stores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export const storeEntries: StoreEntry[] = [
currentPerspective: { type: 'object', properties: ['uuid', 'name', 'sharedUrl'] },
currentPerspectiveModels: { type: 'array' },
isWeSpace: { type: 'boolean' },
personalSpaces: { type: 'array', properties: ['uuid', 'name', 'description', 'url', 'visibility'] },
sharedSpaces: { type: 'array', properties: ['uuid', 'name', 'description', 'url', 'visibility'] },
personalSpaces: { type: 'array', model: 'Space' },
sharedSpaces: { type: 'array', model: 'Space' },
bootState: { type: 'string' },
passwordError: { type: 'string' },
loginLoading: { type: 'boolean' },
Expand Down Expand Up @@ -124,10 +124,11 @@ export const storeEntries: StoreEntry[] = [
properties: ['did', 'firstName', 'lastName', 'handle', 'bio', 'avatar', 'coverImage', 'location'],
},
spaceDefaultTemplateId: { type: 'string' },
currentSpace: { type: 'object', properties: ['uuid', 'name', 'description', 'avatar', 'defaultTemplateId'] },
currentSpace: { type: 'object', model: 'Space' },
foreignSpacePrefill: { type: 'object', properties: ['name', 'description', 'avatar'] },
signalTypes: {
type: 'array',
model: 'SignalType',
properties: [
'id',
'name',
Expand Down Expand Up @@ -243,8 +244,8 @@ function generateStoresText(entries: StoreEntry[]): string {
'ModelManifestEntry[] (non-WE SHACL models from the current perspective; injected as externalModels into AI messages)',
isWeSpace:
"boolean — true once the current perspective is confirmed to have WE's Space SDNA installed (false for a joined-but-foreign perspective, e.g. one synced in from Flux)",
personalSpaces: 'array of Space objects (local/personal spaces)',
sharedSpaces: 'array of Space objects (shared/neighbourhood spaces)',
personalSpaces: 'array of Space objects (local/personal spaces; all Space fields)',
sharedSpaces: 'array of Space objects (shared/neighbourhood spaces; all Space fields)',
bootState: 'string',
passwordError: 'string | undefined',
loginLoading: 'boolean',
Expand Down Expand Up @@ -347,7 +348,8 @@ function generateStoresText(entries: StoreEntry[]): string {
members: 'AgentProfileSummary[] — cached profiles for all memberDids',
spaceDefaultTemplateId:
"string — the current space's default template ID (empty string when no space is active)",
currentSpace: 'Space | null — the current space model (uuid, name, description, avatar, defaultTemplateId)',
currentSpace:
'Space | null — the current space model (all Space fields: uuid, url, name, description, access, discovery, avatar, coverImage, defaultTemplateId, defaultThemeId, location, plus id/author/createdAt)',
foreignSpacePrefill:
'{ name, description, avatar } | null — detected from a foreign app\'s own model (e.g. Flux\'s Community) for prefilling the "Initialize as WE space" gate; null once the perspective is a WE space or no recognized foreign model is found',
signalTypes: 'array of SignalType objects (community-created reaction/vote types)',
Expand Down
2 changes: 1 addition & 1 deletion packages/ai-context/src/schemaContext.ts

Large diffs are not rendered by default.

Loading
Loading