From 3b16333dc95630460a375cd1d0df3ed22d4e607b Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Fri, 10 Apr 2026 01:48:31 +0000 Subject: [PATCH 1/3] Initial plan Co-authored-by: xuyushun441-sys <255036401+xuyushun441-sys@users.noreply.github.com> From 256383d509d0d1854aab6c7ff8f6dbbd44bc78e2 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Fri, 10 Apr 2026 01:52:12 +0000 Subject: [PATCH 2/3] Standardize metadata types to singular form across Studio frontend Agent-Logs-Url: https://github.com/objectstack-ai/framework/sessions/4b4cd0a2-3590-43af-8b11-0e6b59c0e99a Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> Co-authored-by: xuyushun441-sys <255036401+xuyushun441-sys@users.noreply.github.com> --- apps/studio/src/components/app-sidebar.tsx | 46 ++++++++----------- .../src/plugins/built-in/api-plugin.tsx | 10 ++-- .../plugins/built-in/automation-plugin.tsx | 18 ++++---- .../src/plugins/built-in/default-plugin.tsx | 8 +--- .../src/plugins/built-in/object-plugin.tsx | 18 ++++---- .../src/plugins/built-in/security-plugin.tsx | 22 ++++----- .../studio/src/plugins/built-in/ui-plugin.tsx | 26 +++++------ 7 files changed, 67 insertions(+), 81 deletions(-) diff --git a/apps/studio/src/components/app-sidebar.tsx b/apps/studio/src/components/app-sidebar.tsx index 126a36f9a..2c3570a47 100644 --- a/apps/studio/src/components/app-sidebar.tsx +++ b/apps/studio/src/components/app-sidebar.tsx @@ -73,38 +73,32 @@ import { // ─── Icon & label hints ────────────────────────────────────────────── const META_TYPE_HINTS: Record = { object: { label: 'Objects', icon: Package }, - objects: { label: 'Objects', icon: Package }, - hooks: { label: 'Hooks', icon: Anchor }, - mappings: { label: 'Mappings', icon: Map }, - analyticsCubes: { label: 'Analytics Cubes', icon: PieChart }, + hook: { label: 'Hooks', icon: Anchor }, + mapping: { label: 'Mappings', icon: Map }, + analyticsCube: { label: 'Analytics Cubes', icon: PieChart }, data: { label: 'Seed Data', icon: Database }, app: { label: 'Apps', icon: AppWindow }, - apps: { label: 'Apps', icon: AppWindow }, - actions: { label: 'Actions', icon: Zap }, - views: { label: 'Views', icon: Eye }, - pages: { label: 'Pages', icon: FileCode }, - dashboards: { label: 'Dashboards', icon: BarChart3 }, - reports: { label: 'Reports', icon: FileText }, - themes: { label: 'Themes', icon: Palette }, - flows: { label: 'Flows', icon: Workflow }, - workflows: { label: 'Workflows', icon: Workflow }, - approvals: { label: 'Approvals', icon: CheckSquare }, - webhooks: { label: 'Webhooks', icon: Webhook }, - roles: { label: 'Roles', icon: UserCog }, - permissions: { label: 'Permissions', icon: Lock }, - profiles: { label: 'Profiles', icon: Shield }, - sharingRules: { label: 'Sharing Rules', icon: Shield }, - policies: { label: 'Policies', icon: Shield }, + action: { label: 'Actions', icon: Zap }, + view: { label: 'Views', icon: Eye }, + page: { label: 'Pages', icon: FileCode }, + dashboard: { label: 'Dashboards', icon: BarChart3 }, + report: { label: 'Reports', icon: FileText }, + theme: { label: 'Themes', icon: Palette }, + flow: { label: 'Flows', icon: Workflow }, + workflow: { label: 'Workflows', icon: Workflow }, + approval: { label: 'Approvals', icon: CheckSquare }, + webhook: { label: 'Webhooks', icon: Webhook }, + role: { label: 'Roles', icon: UserCog }, + permission: { label: 'Permissions', icon: Lock }, + profile: { label: 'Profiles', icon: Shield }, + sharingRule: { label: 'Sharing Rules', icon: Shield }, + policy: { label: 'Policies', icon: Shield }, agent: { label: 'Agents', icon: Bot }, - agents: { label: 'Agents', icon: Bot }, tool: { label: 'Tools', icon: Wrench }, - tools: { label: 'Tools', icon: Wrench }, ragPipeline: { label: 'RAG Pipelines', icon: BookOpen }, - ragPipelines: { label: 'RAG Pipelines', icon: BookOpen }, - apis: { label: 'APIs', icon: Globe }, - connectors: { label: 'Connectors', icon: Link2 }, + api: { label: 'APIs', icon: Globe }, + connector: { label: 'Connectors', icon: Link2 }, plugin: { label: 'Plugins', icon: Layers }, - plugins: { label: 'Plugins', icon: Layers }, kind: { label: 'Kinds', icon: Database }, }; diff --git a/apps/studio/src/plugins/built-in/api-plugin.tsx b/apps/studio/src/plugins/built-in/api-plugin.tsx index 5388853ab..c1c63c047 100644 --- a/apps/studio/src/plugins/built-in/api-plugin.tsx +++ b/apps/studio/src/plugins/built-in/api-plugin.tsx @@ -23,19 +23,19 @@ export const apiProtocolPlugin: StudioPlugin = { key: 'api', label: 'API', icon: 'globe', - metadataTypes: ['apis', 'connectors'], + metadataTypes: ['api', 'connector'], order: 60, }, ], metadataIcons: [ - { metadataType: 'apis', label: 'APIs', icon: 'globe' }, - { metadataType: 'connectors', label: 'Connectors', icon: 'link-2' }, + { metadataType: 'api', label: 'APIs', icon: 'globe' }, + { metadataType: 'connector', label: 'Connectors', icon: 'link-2' }, ], }, }), activate(api) { - api.registerMetadataIcon('apis', Globe, 'APIs'); - api.registerMetadataIcon('connectors', Link2, 'Connectors'); + api.registerMetadataIcon('api', Globe, 'APIs'); + api.registerMetadataIcon('connector', Link2, 'Connectors'); }, }; diff --git a/apps/studio/src/plugins/built-in/automation-plugin.tsx b/apps/studio/src/plugins/built-in/automation-plugin.tsx index 760de44e3..2745176ce 100644 --- a/apps/studio/src/plugins/built-in/automation-plugin.tsx +++ b/apps/studio/src/plugins/built-in/automation-plugin.tsx @@ -23,23 +23,23 @@ export const automationProtocolPlugin: StudioPlugin = { key: 'automation', label: 'Automation', icon: 'workflow', - metadataTypes: ['flows', 'workflows', 'approvals', 'webhooks'], + metadataTypes: ['flow', 'workflow', 'approval', 'webhook'], order: 30, }, ], metadataIcons: [ - { metadataType: 'flows', label: 'Flows', icon: 'workflow' }, - { metadataType: 'workflows', label: 'Workflows', icon: 'workflow' }, - { metadataType: 'approvals', label: 'Approvals', icon: 'check-square' }, - { metadataType: 'webhooks', label: 'Webhooks', icon: 'webhook' }, + { metadataType: 'flow', label: 'Flows', icon: 'workflow' }, + { metadataType: 'workflow', label: 'Workflows', icon: 'workflow' }, + { metadataType: 'approval', label: 'Approvals', icon: 'check-square' }, + { metadataType: 'webhook', label: 'Webhooks', icon: 'webhook' }, ], }, }), activate(api) { - api.registerMetadataIcon('flows', Workflow, 'Flows'); - api.registerMetadataIcon('workflows', Workflow, 'Workflows'); - api.registerMetadataIcon('approvals', CheckSquare, 'Approvals'); - api.registerMetadataIcon('webhooks', Webhook, 'Webhooks'); + api.registerMetadataIcon('flow', Workflow, 'Flows'); + api.registerMetadataIcon('workflow', Workflow, 'Workflows'); + api.registerMetadataIcon('approval', CheckSquare, 'Approvals'); + api.registerMetadataIcon('webhook', Webhook, 'Webhooks'); }, }; diff --git a/apps/studio/src/plugins/built-in/default-plugin.tsx b/apps/studio/src/plugins/built-in/default-plugin.tsx index 57877bad2..517effa97 100644 --- a/apps/studio/src/plugins/built-in/default-plugin.tsx +++ b/apps/studio/src/plugins/built-in/default-plugin.tsx @@ -20,20 +20,14 @@ import type { StudioPlugin, MetadataViewerProps } from '../types'; // ─── Helpers ───────────────────────────────────────────────────────── -/** Map Studio metadataType (often plural) to CodeExporter's ExportType (singular). */ +/** Map Studio metadataType to CodeExporter's ExportType (all now use singular). */ const METADATA_TO_EXPORT_TYPE: Record = { object: 'object', - objects: 'object', view: 'view', - views: 'view', flow: 'flow', - flows: 'flow', agent: 'agent', - agents: 'agent', tool: 'tool', - tools: 'tool', app: 'app', - apps: 'app', }; // ─── Preview Viewer (JSON Inspector) ───────────────────────────────── diff --git a/apps/studio/src/plugins/built-in/object-plugin.tsx b/apps/studio/src/plugins/built-in/object-plugin.tsx index fd8daca72..1b220aac6 100644 --- a/apps/studio/src/plugins/built-in/object-plugin.tsx +++ b/apps/studio/src/plugins/built-in/object-plugin.tsx @@ -32,7 +32,7 @@ export const objectDesignerPlugin: StudioPlugin = { metadataViewers: [ { id: 'object-explorer', - metadataTypes: ['object', 'objects'], + metadataTypes: ['object'], label: 'Object Explorer', priority: 100, modes: ['preview', 'data', 'code'], @@ -43,16 +43,15 @@ export const objectDesignerPlugin: StudioPlugin = { key: 'data', label: 'Data', icon: 'database', - metadataTypes: ['object', 'objects', 'hooks', 'mappings', 'analyticsCubes', 'data'], + metadataTypes: ['object', 'hook', 'mapping', 'analyticsCube', 'data'], order: 10, }, ], metadataIcons: [ { metadataType: 'object', label: 'Objects', icon: 'package' }, - { metadataType: 'objects', label: 'Objects', icon: 'package' }, - { metadataType: 'hooks', label: 'Hooks', icon: 'anchor' }, - { metadataType: 'mappings', label: 'Mappings', icon: 'map' }, - { metadataType: 'analyticsCubes', label: 'Analytics Cubes', icon: 'pie-chart' }, + { metadataType: 'hook', label: 'Hooks', icon: 'anchor' }, + { metadataType: 'mapping', label: 'Mappings', icon: 'map' }, + { metadataType: 'analyticsCube', label: 'Analytics Cubes', icon: 'pie-chart' }, { metadataType: 'data', label: 'Seed Data', icon: 'database' }, ], }, @@ -64,10 +63,9 @@ export const objectDesignerPlugin: StudioPlugin = { // Register Lucide icons for metadata types api.registerMetadataIcon('object', Package, 'Objects'); - api.registerMetadataIcon('objects', Package, 'Objects'); - api.registerMetadataIcon('hooks', Anchor, 'Hooks'); - api.registerMetadataIcon('mappings', Map, 'Mappings'); - api.registerMetadataIcon('analyticsCubes', PieChart, 'Analytics Cubes'); + api.registerMetadataIcon('hook', Anchor, 'Hooks'); + api.registerMetadataIcon('mapping', Map, 'Mappings'); + api.registerMetadataIcon('analyticsCube', PieChart, 'Analytics Cubes'); api.registerMetadataIcon('data', Database, 'Seed Data'); }, }; diff --git a/apps/studio/src/plugins/built-in/security-plugin.tsx b/apps/studio/src/plugins/built-in/security-plugin.tsx index a13e35018..0f1ad26ca 100644 --- a/apps/studio/src/plugins/built-in/security-plugin.tsx +++ b/apps/studio/src/plugins/built-in/security-plugin.tsx @@ -23,25 +23,25 @@ export const securityProtocolPlugin: StudioPlugin = { key: 'security', label: 'Security', icon: 'shield', - metadataTypes: ['roles', 'permissions', 'profiles', 'sharingRules', 'policies'], + metadataTypes: ['role', 'permission', 'profile', 'sharingRule', 'policy'], order: 40, }, ], metadataIcons: [ - { metadataType: 'roles', label: 'Roles', icon: 'user-cog' }, - { metadataType: 'permissions', label: 'Permissions', icon: 'lock' }, - { metadataType: 'profiles', label: 'Profiles', icon: 'shield' }, - { metadataType: 'sharingRules', label: 'Sharing Rules', icon: 'shield' }, - { metadataType: 'policies', label: 'Policies', icon: 'shield' }, + { metadataType: 'role', label: 'Roles', icon: 'user-cog' }, + { metadataType: 'permission', label: 'Permissions', icon: 'lock' }, + { metadataType: 'profile', label: 'Profiles', icon: 'shield' }, + { metadataType: 'sharingRule', label: 'Sharing Rules', icon: 'shield' }, + { metadataType: 'policy', label: 'Policies', icon: 'shield' }, ], }, }), activate(api) { - api.registerMetadataIcon('roles', UserCog, 'Roles'); - api.registerMetadataIcon('permissions', Lock, 'Permissions'); - api.registerMetadataIcon('profiles', Shield, 'Profiles'); - api.registerMetadataIcon('sharingRules', Shield, 'Sharing Rules'); - api.registerMetadataIcon('policies', Shield, 'Policies'); + api.registerMetadataIcon('role', UserCog, 'Roles'); + api.registerMetadataIcon('permission', Lock, 'Permissions'); + api.registerMetadataIcon('profile', Shield, 'Profiles'); + api.registerMetadataIcon('sharingRule', Shield, 'Sharing Rules'); + api.registerMetadataIcon('policy', Shield, 'Policies'); }, }; diff --git a/apps/studio/src/plugins/built-in/ui-plugin.tsx b/apps/studio/src/plugins/built-in/ui-plugin.tsx index dc6097702..c3f45bc94 100644 --- a/apps/studio/src/plugins/built-in/ui-plugin.tsx +++ b/apps/studio/src/plugins/built-in/ui-plugin.tsx @@ -25,27 +25,27 @@ export const uiProtocolPlugin: StudioPlugin = { key: 'ui', label: 'UI', icon: 'app-window', - metadataTypes: ['actions', 'views', 'pages', 'dashboards', 'reports', 'themes'], + metadataTypes: ['action', 'view', 'page', 'dashboard', 'report', 'theme'], order: 20, }, ], metadataIcons: [ - { metadataType: 'actions', label: 'Actions', icon: 'zap' }, - { metadataType: 'views', label: 'Views', icon: 'eye' }, - { metadataType: 'pages', label: 'Pages', icon: 'file-code' }, - { metadataType: 'dashboards', label: 'Dashboards', icon: 'bar-chart-3' }, - { metadataType: 'reports', label: 'Reports', icon: 'file-text' }, - { metadataType: 'themes', label: 'Themes', icon: 'palette' }, + { metadataType: 'action', label: 'Actions', icon: 'zap' }, + { metadataType: 'view', label: 'Views', icon: 'eye' }, + { metadataType: 'page', label: 'Pages', icon: 'file-code' }, + { metadataType: 'dashboard', label: 'Dashboards', icon: 'bar-chart-3' }, + { metadataType: 'report', label: 'Reports', icon: 'file-text' }, + { metadataType: 'theme', label: 'Themes', icon: 'palette' }, ], }, }), activate(api) { - api.registerMetadataIcon('actions', Zap, 'Actions'); - api.registerMetadataIcon('views', Eye, 'Views'); - api.registerMetadataIcon('pages', FileCode, 'Pages'); - api.registerMetadataIcon('dashboards', BarChart3, 'Dashboards'); - api.registerMetadataIcon('reports', FileText, 'Reports'); - api.registerMetadataIcon('themes', Palette, 'Themes'); + api.registerMetadataIcon('action', Zap, 'Actions'); + api.registerMetadataIcon('view', Eye, 'Views'); + api.registerMetadataIcon('page', FileCode, 'Pages'); + api.registerMetadataIcon('dashboard', BarChart3, 'Dashboards'); + api.registerMetadataIcon('report', FileText, 'Reports'); + api.registerMetadataIcon('theme', Palette, 'Themes'); }, }; From 1422393f74fd44d5eb8c056875009edb539438cb Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Fri, 10 Apr 2026 01:55:54 +0000 Subject: [PATCH 3/3] Document singular metadata type naming convention Agent-Logs-Url: https://github.com/objectstack-ai/framework/sessions/4b4cd0a2-3590-43af-8b11-0e6b59c0e99a Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> Co-authored-by: xuyushun441-sys <255036401+xuyushun441-sys@users.noreply.github.com> --- .github/copilot-instructions.md | 2 ++ packages/spec/src/kernel/metadata-plugin.zod.ts | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 0c5388bf9..e60b611ce 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -15,6 +15,8 @@ 3. **Naming Convention:** - **Configuration Keys (TS Props):** `camelCase` — e.g., `maxLength`, `referenceFilters`, `defaultValue`. - **Machine Names (Data Values):** `snake_case` — e.g., `name: 'first_name'`, `object: 'project_task'`. + - **Metadata Type Names:** `singular` — e.g., `'agent'`, `'tool'`, `'view'`, `'flow'` (NOT `'agents'`, `'tools'`, `'views'`, `'flows'`). This aligns with the canonical `MetadataTypeSchema` enum in `packages/spec/src/kernel/metadata-plugin.zod.ts`. + - **REST API Endpoints:** `plural` — e.g., `/api/v1/ai/agents`, `/api/v1/ai/conversations` (per REST convention for resource collections). 4. **Namespace Imports:** Use `import { Data, UI, System } from '@objectstack/spec'` or subpath `import { Field } from '@objectstack/spec/data'`. Never use relative paths like `../../packages/spec`. 5. **Best Practice Mandate:** - Benchmark against industry leaders (Salesforce, ServiceNow, Kubernetes) for structural decisions. diff --git a/packages/spec/src/kernel/metadata-plugin.zod.ts b/packages/spec/src/kernel/metadata-plugin.zod.ts index 7f52dfc8c..37bd38368 100644 --- a/packages/spec/src/kernel/metadata-plugin.zod.ts +++ b/packages/spec/src/kernel/metadata-plugin.zod.ts @@ -52,6 +52,20 @@ import { MergeStrategyConfigSchema, CustomizationPolicySchema } from './metadata * The canonical list of all metadata types managed by the platform. * Each type maps to a specific Zod schema (e.g., ObjectSchema, ViewSchema). * Plugins can extend this registry via `contributes.kinds` in the manifest. + * + * ## Naming Convention + * **IMPORTANT:** All metadata type names are in **SINGULAR** form: + * - ✅ Use: `'agent'`, `'tool'`, `'skill'`, `'view'`, `'flow'`, `'action'` + * - ❌ NOT: `'agents'`, `'tools'`, `'skills'`, `'views'`, `'flows'`, `'actions'` + * + * This convention applies to: + * - Protocol definitions (this enum) + * - UI plugin registrations (`metadataTypes`, `metadataIcons`) + * - Metadata service operations + * - File patterns (`*.agent.ts`, `*.tool.ts`) + * + * REST API endpoints continue to use plural forms per REST conventions: + * - `/api/v1/ai/agents`, `/api/v1/ai/conversations` */ export const MetadataTypeSchema = z.enum([ // Data Protocol