From 0bc965b7539ce3314b389ffe9b7e8fa8d36a7f27 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 3 Feb 2026 08:23:20 +0000
Subject: [PATCH 1/3] Initial plan
From 5d837af21e6e74bb8a304049151b51d012b73021 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 3 Feb 2026 08:29:18 +0000
Subject: [PATCH 2/3] Add distributed state, WASM sandbox, registry federation,
and AI low-code features
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
---
content/docs/references/ai/index.mdx | 1 +
content/docs/references/ai/meta.json | 3 +-
.../spec/json-schema/ai/AIOpsAgentConfig.json | 7 +
.../ai/AnomalyDetectionConfig.json | 7 +
.../json-schema/ai/AutoScalingPolicy.json | 7 +
.../ai/PerformanceOptimization.json | 7 +
.../ai/RootCauseAnalysisRequest.json | 7 +
.../ai/RootCauseAnalysisResult.json | 7 +
.../json-schema/ai/SelfHealingAction.json | 7 +
.../json-schema/ai/SelfHealingConfig.json | 7 +
.../spec/json-schema/hub/RegistryConfig.json | 7 +
.../json-schema/hub/RegistrySyncPolicy.json | 7 +
.../json-schema/hub/RegistryUpstream.json | 7 +
.../system/DistributedStateConfig.json | 7 +
.../json-schema/system/RuntimeConfig.json | 7 +
packages/spec/src/ai/index.ts | 3 +
.../spec/src/ai/plugin-development.zod.ts | 71 +-
packages/spec/src/ai/runtime-ops.zod.ts | 679 ++++++++++++++++++
.../spec/src/hub/marketplace-enhanced.zod.ts | 171 +++++
.../system/plugin-lifecycle-advanced.zod.ts | 63 +-
.../system/plugin-security-advanced.zod.ts | 131 ++++
21 files changed, 1205 insertions(+), 8 deletions(-)
create mode 100644 packages/spec/json-schema/ai/AIOpsAgentConfig.json
create mode 100644 packages/spec/json-schema/ai/AnomalyDetectionConfig.json
create mode 100644 packages/spec/json-schema/ai/AutoScalingPolicy.json
create mode 100644 packages/spec/json-schema/ai/PerformanceOptimization.json
create mode 100644 packages/spec/json-schema/ai/RootCauseAnalysisRequest.json
create mode 100644 packages/spec/json-schema/ai/RootCauseAnalysisResult.json
create mode 100644 packages/spec/json-schema/ai/SelfHealingAction.json
create mode 100644 packages/spec/json-schema/ai/SelfHealingConfig.json
create mode 100644 packages/spec/json-schema/hub/RegistryConfig.json
create mode 100644 packages/spec/json-schema/hub/RegistrySyncPolicy.json
create mode 100644 packages/spec/json-schema/hub/RegistryUpstream.json
create mode 100644 packages/spec/json-schema/system/DistributedStateConfig.json
create mode 100644 packages/spec/json-schema/system/RuntimeConfig.json
create mode 100644 packages/spec/src/ai/runtime-ops.zod.ts
diff --git a/content/docs/references/ai/index.mdx b/content/docs/references/ai/index.mdx
index 4aaa0c929..37920a4b7 100644
--- a/content/docs/references/ai/index.mdx
+++ b/content/docs/references/ai/index.mdx
@@ -20,5 +20,6 @@ This section contains all protocol schemas for the ai layer of ObjectStack.
+
diff --git a/content/docs/references/ai/meta.json b/content/docs/references/ai/meta.json
index 41830cd58..cd6ee502e 100644
--- a/content/docs/references/ai/meta.json
+++ b/content/docs/references/ai/meta.json
@@ -12,6 +12,7 @@
"orchestration",
"plugin-development",
"predictive",
- "rag-pipeline"
+ "rag-pipeline",
+ "runtime-ops"
]
}
\ No newline at end of file
diff --git a/packages/spec/json-schema/ai/AIOpsAgentConfig.json b/packages/spec/json-schema/ai/AIOpsAgentConfig.json
new file mode 100644
index 000000000..6cf8012e2
--- /dev/null
+++ b/packages/spec/json-schema/ai/AIOpsAgentConfig.json
@@ -0,0 +1,7 @@
+{
+ "$ref": "#/definitions/AIOpsAgentConfig",
+ "definitions": {
+ "AIOpsAgentConfig": {}
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/ai/AnomalyDetectionConfig.json b/packages/spec/json-schema/ai/AnomalyDetectionConfig.json
new file mode 100644
index 000000000..76cc97425
--- /dev/null
+++ b/packages/spec/json-schema/ai/AnomalyDetectionConfig.json
@@ -0,0 +1,7 @@
+{
+ "$ref": "#/definitions/AnomalyDetectionConfig",
+ "definitions": {
+ "AnomalyDetectionConfig": {}
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/ai/AutoScalingPolicy.json b/packages/spec/json-schema/ai/AutoScalingPolicy.json
new file mode 100644
index 000000000..cb1556141
--- /dev/null
+++ b/packages/spec/json-schema/ai/AutoScalingPolicy.json
@@ -0,0 +1,7 @@
+{
+ "$ref": "#/definitions/AutoScalingPolicy",
+ "definitions": {
+ "AutoScalingPolicy": {}
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/ai/PerformanceOptimization.json b/packages/spec/json-schema/ai/PerformanceOptimization.json
new file mode 100644
index 000000000..f15310ad3
--- /dev/null
+++ b/packages/spec/json-schema/ai/PerformanceOptimization.json
@@ -0,0 +1,7 @@
+{
+ "$ref": "#/definitions/PerformanceOptimization",
+ "definitions": {
+ "PerformanceOptimization": {}
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/ai/RootCauseAnalysisRequest.json b/packages/spec/json-schema/ai/RootCauseAnalysisRequest.json
new file mode 100644
index 000000000..0df85a99a
--- /dev/null
+++ b/packages/spec/json-schema/ai/RootCauseAnalysisRequest.json
@@ -0,0 +1,7 @@
+{
+ "$ref": "#/definitions/RootCauseAnalysisRequest",
+ "definitions": {
+ "RootCauseAnalysisRequest": {}
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/ai/RootCauseAnalysisResult.json b/packages/spec/json-schema/ai/RootCauseAnalysisResult.json
new file mode 100644
index 000000000..4f2fda9c3
--- /dev/null
+++ b/packages/spec/json-schema/ai/RootCauseAnalysisResult.json
@@ -0,0 +1,7 @@
+{
+ "$ref": "#/definitions/RootCauseAnalysisResult",
+ "definitions": {
+ "RootCauseAnalysisResult": {}
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/ai/SelfHealingAction.json b/packages/spec/json-schema/ai/SelfHealingAction.json
new file mode 100644
index 000000000..2322213b1
--- /dev/null
+++ b/packages/spec/json-schema/ai/SelfHealingAction.json
@@ -0,0 +1,7 @@
+{
+ "$ref": "#/definitions/SelfHealingAction",
+ "definitions": {
+ "SelfHealingAction": {}
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/ai/SelfHealingConfig.json b/packages/spec/json-schema/ai/SelfHealingConfig.json
new file mode 100644
index 000000000..bb77bef75
--- /dev/null
+++ b/packages/spec/json-schema/ai/SelfHealingConfig.json
@@ -0,0 +1,7 @@
+{
+ "$ref": "#/definitions/SelfHealingConfig",
+ "definitions": {
+ "SelfHealingConfig": {}
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/hub/RegistryConfig.json b/packages/spec/json-schema/hub/RegistryConfig.json
new file mode 100644
index 000000000..66d678ce4
--- /dev/null
+++ b/packages/spec/json-schema/hub/RegistryConfig.json
@@ -0,0 +1,7 @@
+{
+ "$ref": "#/definitions/RegistryConfig",
+ "definitions": {
+ "RegistryConfig": {}
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/hub/RegistrySyncPolicy.json b/packages/spec/json-schema/hub/RegistrySyncPolicy.json
new file mode 100644
index 000000000..e3500e1db
--- /dev/null
+++ b/packages/spec/json-schema/hub/RegistrySyncPolicy.json
@@ -0,0 +1,7 @@
+{
+ "$ref": "#/definitions/RegistrySyncPolicy",
+ "definitions": {
+ "RegistrySyncPolicy": {}
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/hub/RegistryUpstream.json b/packages/spec/json-schema/hub/RegistryUpstream.json
new file mode 100644
index 000000000..53c1725bd
--- /dev/null
+++ b/packages/spec/json-schema/hub/RegistryUpstream.json
@@ -0,0 +1,7 @@
+{
+ "$ref": "#/definitions/RegistryUpstream",
+ "definitions": {
+ "RegistryUpstream": {}
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/system/DistributedStateConfig.json b/packages/spec/json-schema/system/DistributedStateConfig.json
new file mode 100644
index 000000000..1419e4cb4
--- /dev/null
+++ b/packages/spec/json-schema/system/DistributedStateConfig.json
@@ -0,0 +1,7 @@
+{
+ "$ref": "#/definitions/DistributedStateConfig",
+ "definitions": {
+ "DistributedStateConfig": {}
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/system/RuntimeConfig.json b/packages/spec/json-schema/system/RuntimeConfig.json
new file mode 100644
index 000000000..99de6df88
--- /dev/null
+++ b/packages/spec/json-schema/system/RuntimeConfig.json
@@ -0,0 +1,7 @@
+{
+ "$ref": "#/definitions/RuntimeConfig",
+ "definitions": {
+ "RuntimeConfig": {}
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/src/ai/index.ts b/packages/spec/src/ai/index.ts
index 17f0ddb5e..8350c0044 100644
--- a/packages/spec/src/ai/index.ts
+++ b/packages/spec/src/ai/index.ts
@@ -11,12 +11,15 @@
* - Predictive Analytics
* - Conversation Memory & Token Management
* - Cost Tracking & Budget Management
+ * - Plugin Development (AI-assisted)
+ * - Runtime Operations (AIOps)
*/
export * from './agent.zod';
export * from './agent-action.zod';
export * from './devops-agent.zod';
export * from './plugin-development.zod';
+export * from './runtime-ops.zod';
export * from './model-registry.zod';
export * from './rag-pipeline.zod';
export * from './nlq.zod';
diff --git a/packages/spec/src/ai/plugin-development.zod.ts b/packages/spec/src/ai/plugin-development.zod.ts
index 029497bd3..6e4c5d9e1 100644
--- a/packages/spec/src/ai/plugin-development.zod.ts
+++ b/packages/spec/src/ai/plugin-development.zod.ts
@@ -36,7 +36,17 @@ export const CodeGenerationRequestSchema = z.object({
]),
/**
- * Target programming language
+ * Output format for generated code
+ */
+ outputFormat: z.enum([
+ 'source-code', // Generate TypeScript/JavaScript source code
+ 'low-code-schema', // Generate ObjectStack JSON/YAML schema definitions
+ 'dsl', // Generate domain-specific language definitions
+ ]).default('source-code')
+ .describe('Format of the generated output'),
+
+ /**
+ * Target programming language (for source-code format)
*/
language: z.enum(['typescript', 'javascript', 'python']).default('typescript'),
@@ -69,7 +79,7 @@ export const CodeGenerationRequestSchema = z.object({
})).optional(),
/**
- * Code style preferences
+ * Code style preferences (for source-code format)
*/
style: z.object({
indentation: z.enum(['tab', '2spaces', '4spaces']).default('2spaces'),
@@ -78,6 +88,39 @@ export const CodeGenerationRequestSchema = z.object({
trailingComma: z.boolean().default(true),
}).optional(),
+ /**
+ * Low-code schema preferences (for low-code-schema format)
+ */
+ schemaOptions: z.object({
+ /**
+ * Schema format
+ */
+ format: z.enum(['json', 'yaml', 'typescript']).default('typescript')
+ .describe('Output schema format'),
+
+ /**
+ * Include example data
+ */
+ includeExamples: z.boolean().default(true),
+
+ /**
+ * Validation strictness
+ */
+ strictValidation: z.boolean().default(true),
+
+ /**
+ * Generate UI definitions
+ */
+ generateUI: z.boolean().default(true)
+ .describe('Generate view, dashboard, and page definitions'),
+
+ /**
+ * Generate data models
+ */
+ generateDataModels: z.boolean().default(true)
+ .describe('Generate object and field definitions'),
+ }).optional(),
+
/**
* Additional context
*/
@@ -135,14 +178,30 @@ export const CodeGenerationRequestSchema = z.object({
*/
export const GeneratedCodeSchema = z.object({
/**
- * Main plugin code
+ * Output format used
*/
- code: z.string(),
+ outputFormat: z.enum(['source-code', 'low-code-schema', 'dsl']),
/**
- * Language used
+ * Main plugin code (for source-code format)
*/
- language: z.string(),
+ code: z.string().optional(),
+
+ /**
+ * Language used (for source-code format)
+ */
+ language: z.string().optional(),
+
+ /**
+ * Low-code schema definitions (for low-code-schema format)
+ */
+ schemas: z.array(z.object({
+ type: z.enum(['object', 'view', 'dashboard', 'app', 'workflow', 'api', 'page']),
+ path: z.string().describe('File path for the schema'),
+ content: z.string().describe('Schema content (JSON/YAML/TypeScript)'),
+ description: z.string().optional(),
+ })).optional()
+ .describe('Generated low-code schema files'),
/**
* File structure
diff --git a/packages/spec/src/ai/runtime-ops.zod.ts b/packages/spec/src/ai/runtime-ops.zod.ts
new file mode 100644
index 000000000..bd82d0c66
--- /dev/null
+++ b/packages/spec/src/ai/runtime-ops.zod.ts
@@ -0,0 +1,679 @@
+import { z } from 'zod';
+import { PluginHealthStatusSchema } from '../system/plugin-lifecycle-advanced.zod';
+
+/**
+ * # Runtime AI Operations (AIOps) Protocol
+ *
+ * Defines protocols for AI-powered runtime operations including:
+ * - Self-healing and automatic recovery
+ * - Intelligent auto-scaling
+ * - Anomaly detection and prediction
+ * - Performance optimization
+ * - Root cause analysis
+ */
+
+/**
+ * Anomaly Detection Configuration
+ * Configuration for detecting anomalies in plugin behavior
+ */
+export const AnomalyDetectionConfigSchema = z.object({
+ /**
+ * Enable anomaly detection
+ */
+ enabled: z.boolean().default(true),
+
+ /**
+ * Metrics to monitor
+ */
+ metrics: z.array(z.enum([
+ 'cpu-usage',
+ 'memory-usage',
+ 'response-time',
+ 'error-rate',
+ 'throughput',
+ 'latency',
+ 'connection-count',
+ 'queue-depth',
+ ])),
+
+ /**
+ * Detection algorithm
+ */
+ algorithm: z.enum([
+ 'statistical', // Statistical thresholds
+ 'machine-learning', // ML-based detection
+ 'heuristic', // Rule-based heuristics
+ 'hybrid', // Combination of methods
+ ]).default('hybrid'),
+
+ /**
+ * Sensitivity level
+ */
+ sensitivity: z.enum(['low', 'medium', 'high']).default('medium')
+ .describe('How aggressively to detect anomalies'),
+
+ /**
+ * Time window for analysis (seconds)
+ */
+ timeWindow: z.number().int().min(60).default(300)
+ .describe('Historical data window for anomaly detection'),
+
+ /**
+ * Confidence threshold (0-100)
+ */
+ confidenceThreshold: z.number().min(0).max(100).default(80)
+ .describe('Minimum confidence to flag as anomaly'),
+
+ /**
+ * Alert on detection
+ */
+ alertOnDetection: z.boolean().default(true),
+});
+
+/**
+ * Self-Healing Action
+ * Defines an automated recovery action
+ */
+export const SelfHealingActionSchema = z.object({
+ /**
+ * Action identifier
+ */
+ id: z.string(),
+
+ /**
+ * Action type
+ */
+ type: z.enum([
+ 'restart', // Restart the plugin
+ 'scale', // Scale resources
+ 'rollback', // Rollback to previous version
+ 'clear-cache', // Clear caches
+ 'adjust-config', // Adjust configuration
+ 'execute-script', // Run custom script
+ 'notify', // Notify administrators
+ ]),
+
+ /**
+ * Trigger condition
+ */
+ trigger: z.object({
+ /**
+ * Health status that triggers this action
+ */
+ healthStatus: z.array(PluginHealthStatusSchema).optional(),
+
+ /**
+ * Anomaly types that trigger this action
+ */
+ anomalyTypes: z.array(z.string()).optional(),
+
+ /**
+ * Error patterns that trigger this action
+ */
+ errorPatterns: z.array(z.string()).optional(),
+
+ /**
+ * Custom condition expression
+ */
+ customCondition: z.string().optional()
+ .describe('Custom trigger condition (e.g., "errorRate > 0.1")'),
+ }),
+
+ /**
+ * Action parameters
+ */
+ parameters: z.record(z.string(), z.any()).optional(),
+
+ /**
+ * Maximum number of attempts
+ */
+ maxAttempts: z.number().int().min(1).default(3),
+
+ /**
+ * Cooldown period between attempts (seconds)
+ */
+ cooldown: z.number().int().min(0).default(60),
+
+ /**
+ * Timeout for action execution (seconds)
+ */
+ timeout: z.number().int().min(1).default(300),
+
+ /**
+ * Require manual approval
+ */
+ requireApproval: z.boolean().default(false),
+
+ /**
+ * Priority
+ */
+ priority: z.number().int().min(1).default(5)
+ .describe('Action priority (lower number = higher priority)'),
+});
+
+/**
+ * Self-Healing Configuration
+ * Complete configuration for self-healing capabilities
+ */
+export const SelfHealingConfigSchema = z.object({
+ /**
+ * Enable self-healing
+ */
+ enabled: z.boolean().default(true),
+
+ /**
+ * Healing strategy
+ */
+ strategy: z.enum([
+ 'conservative', // Only safe, proven actions
+ 'moderate', // Balanced approach
+ 'aggressive', // Try more recovery options
+ ]).default('moderate'),
+
+ /**
+ * Recovery actions
+ */
+ actions: z.array(SelfHealingActionSchema),
+
+ /**
+ * Anomaly detection
+ */
+ anomalyDetection: AnomalyDetectionConfigSchema.optional(),
+
+ /**
+ * Maximum concurrent healing operations
+ */
+ maxConcurrentHealing: z.number().int().min(1).default(1)
+ .describe('Maximum number of simultaneous healing attempts'),
+
+ /**
+ * Learning mode
+ */
+ learning: z.object({
+ enabled: z.boolean().default(true)
+ .describe('Learn from successful/failed healing attempts'),
+
+ feedbackLoop: z.boolean().default(true)
+ .describe('Adjust strategy based on outcomes'),
+ }).optional(),
+});
+
+/**
+ * Auto-Scaling Policy
+ * Defines how to automatically scale plugin resources
+ */
+export const AutoScalingPolicySchema = z.object({
+ /**
+ * Enable auto-scaling
+ */
+ enabled: z.boolean().default(false),
+
+ /**
+ * Scaling metric
+ */
+ metric: z.enum([
+ 'cpu-usage',
+ 'memory-usage',
+ 'request-rate',
+ 'response-time',
+ 'queue-depth',
+ 'custom',
+ ]),
+
+ /**
+ * Custom metric query (when metric is "custom")
+ */
+ customMetric: z.string().optional(),
+
+ /**
+ * Target value for the metric
+ */
+ targetValue: z.number()
+ .describe('Desired metric value (e.g., 70 for 70% CPU)'),
+
+ /**
+ * Scaling bounds
+ */
+ bounds: z.object({
+ /**
+ * Minimum instances
+ */
+ minInstances: z.number().int().min(1).default(1),
+
+ /**
+ * Maximum instances
+ */
+ maxInstances: z.number().int().min(1).default(10),
+
+ /**
+ * Minimum resources per instance
+ */
+ minResources: z.object({
+ cpu: z.string().optional().describe('CPU limit (e.g., "0.5", "1")'),
+ memory: z.string().optional().describe('Memory limit (e.g., "512Mi", "1Gi")'),
+ }).optional(),
+
+ /**
+ * Maximum resources per instance
+ */
+ maxResources: z.object({
+ cpu: z.string().optional(),
+ memory: z.string().optional(),
+ }).optional(),
+ }),
+
+ /**
+ * Scale up behavior
+ */
+ scaleUp: z.object({
+ /**
+ * Threshold to trigger scale up
+ */
+ threshold: z.number()
+ .describe('Metric value that triggers scale up'),
+
+ /**
+ * Stabilization window (seconds)
+ */
+ stabilizationWindow: z.number().int().min(0).default(60)
+ .describe('How long metric must exceed threshold'),
+
+ /**
+ * Cooldown period (seconds)
+ */
+ cooldown: z.number().int().min(0).default(300)
+ .describe('Minimum time between scale-up operations'),
+
+ /**
+ * Step size
+ */
+ stepSize: z.number().int().min(1).default(1)
+ .describe('Number of instances to add'),
+ }),
+
+ /**
+ * Scale down behavior
+ */
+ scaleDown: z.object({
+ /**
+ * Threshold to trigger scale down
+ */
+ threshold: z.number()
+ .describe('Metric value that triggers scale down'),
+
+ /**
+ * Stabilization window (seconds)
+ */
+ stabilizationWindow: z.number().int().min(0).default(300)
+ .describe('How long metric must be below threshold'),
+
+ /**
+ * Cooldown period (seconds)
+ */
+ cooldown: z.number().int().min(0).default(600)
+ .describe('Minimum time between scale-down operations'),
+
+ /**
+ * Step size
+ */
+ stepSize: z.number().int().min(1).default(1)
+ .describe('Number of instances to remove'),
+ }),
+
+ /**
+ * Predictive scaling
+ */
+ predictive: z.object({
+ enabled: z.boolean().default(false)
+ .describe('Use ML to predict future load'),
+
+ lookAhead: z.number().int().min(60).default(300)
+ .describe('How far ahead to predict (seconds)'),
+
+ confidence: z.number().min(0).max(100).default(80)
+ .describe('Minimum confidence for prediction-based scaling'),
+ }).optional(),
+});
+
+/**
+ * Root Cause Analysis Request
+ * Request for AI to analyze root cause of issues
+ */
+export const RootCauseAnalysisRequestSchema = z.object({
+ /**
+ * Incident identifier
+ */
+ incidentId: z.string(),
+
+ /**
+ * Plugin identifier
+ */
+ pluginId: z.string(),
+
+ /**
+ * Symptoms observed
+ */
+ symptoms: z.array(z.object({
+ type: z.string().describe('Symptom type'),
+ description: z.string(),
+ severity: z.enum(['low', 'medium', 'high', 'critical']),
+ timestamp: z.string().datetime(),
+ })),
+
+ /**
+ * Time range for analysis
+ */
+ timeRange: z.object({
+ start: z.string().datetime(),
+ end: z.string().datetime(),
+ }),
+
+ /**
+ * Include log analysis
+ */
+ analyzeLogs: z.boolean().default(true),
+
+ /**
+ * Include metric analysis
+ */
+ analyzeMetrics: z.boolean().default(true),
+
+ /**
+ * Include dependency analysis
+ */
+ analyzeDependencies: z.boolean().default(true),
+
+ /**
+ * Context information
+ */
+ context: z.record(z.string(), z.any()).optional(),
+});
+
+/**
+ * Root Cause Analysis Result
+ * Result of root cause analysis
+ */
+export const RootCauseAnalysisResultSchema = z.object({
+ /**
+ * Analysis identifier
+ */
+ analysisId: z.string(),
+
+ /**
+ * Incident identifier
+ */
+ incidentId: z.string(),
+
+ /**
+ * Identified root causes
+ */
+ rootCauses: z.array(z.object({
+ /**
+ * Cause identifier
+ */
+ id: z.string(),
+
+ /**
+ * Description
+ */
+ description: z.string(),
+
+ /**
+ * Confidence score (0-100)
+ */
+ confidence: z.number().min(0).max(100),
+
+ /**
+ * Category
+ */
+ category: z.enum([
+ 'code-defect',
+ 'configuration',
+ 'resource-exhaustion',
+ 'dependency-failure',
+ 'network-issue',
+ 'data-corruption',
+ 'security-breach',
+ 'other',
+ ]),
+
+ /**
+ * Evidence
+ */
+ evidence: z.array(z.object({
+ type: z.enum(['log', 'metric', 'trace', 'event']),
+ content: z.string(),
+ timestamp: z.string().datetime().optional(),
+ })),
+
+ /**
+ * Impact assessment
+ */
+ impact: z.enum(['low', 'medium', 'high', 'critical']),
+
+ /**
+ * Recommended actions
+ */
+ recommendations: z.array(z.string()),
+ })),
+
+ /**
+ * Contributing factors
+ */
+ contributingFactors: z.array(z.object({
+ description: z.string(),
+ confidence: z.number().min(0).max(100),
+ })).optional(),
+
+ /**
+ * Timeline of events
+ */
+ timeline: z.array(z.object({
+ timestamp: z.string().datetime(),
+ event: z.string(),
+ significance: z.enum(['low', 'medium', 'high']),
+ })).optional(),
+
+ /**
+ * Remediation plan
+ */
+ remediation: z.object({
+ /**
+ * Immediate actions
+ */
+ immediate: z.array(z.string()),
+
+ /**
+ * Short-term fixes
+ */
+ shortTerm: z.array(z.string()),
+
+ /**
+ * Long-term improvements
+ */
+ longTerm: z.array(z.string()),
+ }).optional(),
+
+ /**
+ * Overall confidence in analysis
+ */
+ overallConfidence: z.number().min(0).max(100),
+
+ /**
+ * Analysis timestamp
+ */
+ timestamp: z.string().datetime(),
+});
+
+/**
+ * Performance Optimization Suggestion
+ * AI-generated performance optimization suggestion
+ */
+export const PerformanceOptimizationSchema = z.object({
+ /**
+ * Optimization identifier
+ */
+ id: z.string(),
+
+ /**
+ * Plugin identifier
+ */
+ pluginId: z.string(),
+
+ /**
+ * Optimization type
+ */
+ type: z.enum([
+ 'caching',
+ 'query-optimization',
+ 'resource-allocation',
+ 'code-refactoring',
+ 'architecture-change',
+ 'configuration-tuning',
+ ]),
+
+ /**
+ * Description
+ */
+ description: z.string(),
+
+ /**
+ * Expected impact
+ */
+ expectedImpact: z.object({
+ /**
+ * Performance improvement percentage
+ */
+ performanceGain: z.number().min(0).max(100)
+ .describe('Expected performance improvement (%)'),
+
+ /**
+ * Resource savings
+ */
+ resourceSavings: z.object({
+ cpu: z.number().optional().describe('CPU reduction (%)'),
+ memory: z.number().optional().describe('Memory reduction (%)'),
+ network: z.number().optional().describe('Network reduction (%)'),
+ }).optional(),
+
+ /**
+ * Cost reduction
+ */
+ costReduction: z.number().optional()
+ .describe('Estimated cost reduction (%)'),
+ }),
+
+ /**
+ * Implementation difficulty
+ */
+ difficulty: z.enum(['trivial', 'easy', 'moderate', 'complex', 'very-complex']),
+
+ /**
+ * Implementation steps
+ */
+ steps: z.array(z.string()),
+
+ /**
+ * Risks and considerations
+ */
+ risks: z.array(z.string()).optional(),
+
+ /**
+ * Confidence score
+ */
+ confidence: z.number().min(0).max(100),
+
+ /**
+ * Priority
+ */
+ priority: z.enum(['low', 'medium', 'high', 'critical']),
+});
+
+/**
+ * AIOps Agent Configuration
+ * Configuration for AI operations agent
+ */
+export const AIOpsAgentConfigSchema = z.object({
+ /**
+ * Agent identifier
+ */
+ agentId: z.string(),
+
+ /**
+ * Plugin identifier
+ */
+ pluginId: z.string(),
+
+ /**
+ * Self-healing configuration
+ */
+ selfHealing: SelfHealingConfigSchema.optional(),
+
+ /**
+ * Auto-scaling policies
+ */
+ autoScaling: z.array(AutoScalingPolicySchema).optional(),
+
+ /**
+ * Continuous monitoring
+ */
+ monitoring: z.object({
+ enabled: z.boolean().default(true),
+ interval: z.number().int().min(1000).default(60000)
+ .describe('Monitoring interval in milliseconds'),
+
+ /**
+ * Metrics to collect
+ */
+ metrics: z.array(z.string()).optional(),
+ }).optional(),
+
+ /**
+ * Proactive optimization
+ */
+ optimization: z.object({
+ enabled: z.boolean().default(true),
+
+ /**
+ * Scan interval (seconds)
+ */
+ scanInterval: z.number().int().min(3600).default(86400)
+ .describe('How often to scan for optimization opportunities'),
+
+ /**
+ * Auto-apply optimizations
+ */
+ autoApply: z.boolean().default(false)
+ .describe('Automatically apply low-risk optimizations'),
+ }).optional(),
+
+ /**
+ * Incident response
+ */
+ incidentResponse: z.object({
+ enabled: z.boolean().default(true),
+
+ /**
+ * Auto-trigger root cause analysis
+ */
+ autoRCA: z.boolean().default(true),
+
+ /**
+ * Notification channels
+ */
+ notifications: z.array(z.object({
+ channel: z.enum(['email', 'slack', 'webhook', 'sms']),
+ config: z.record(z.string(), z.any()),
+ })).optional(),
+ }).optional(),
+});
+
+// Export types
+export type AnomalyDetectionConfig = z.infer;
+export type SelfHealingAction = z.infer;
+export type SelfHealingConfig = z.infer;
+export type AutoScalingPolicy = z.infer;
+export type RootCauseAnalysisRequest = z.infer;
+export type RootCauseAnalysisResult = z.infer;
+export type PerformanceOptimization = z.infer;
+export type AIOpsAgentConfig = z.infer;
diff --git a/packages/spec/src/hub/marketplace-enhanced.zod.ts b/packages/spec/src/hub/marketplace-enhanced.zod.ts
index c844b5bd9..1760a9a89 100644
--- a/packages/spec/src/hub/marketplace-enhanced.zod.ts
+++ b/packages/spec/src/hub/marketplace-enhanced.zod.ts
@@ -15,8 +15,176 @@ import { PluginVersionMetadataSchema } from '../system/plugin-versioning.zod';
* - Automated installation and updates
* - License management
* - Revenue sharing for plugin developers
+ * - Registry federation for hybrid cloud deployments
*/
+/**
+ * Registry Sync Policy
+ * Defines how registries synchronize with upstreams
+ */
+export const RegistrySyncPolicySchema = z.enum([
+ 'manual', // Manual synchronization only
+ 'auto', // Automatic synchronization
+ 'proxy', // Proxy requests to upstream without caching
+]).describe('Registry synchronization strategy');
+
+/**
+ * Registry Upstream Configuration
+ * Configuration for upstream registry connection
+ */
+export const RegistryUpstreamSchema = z.object({
+ /**
+ * Upstream registry URL
+ */
+ url: z.string().url()
+ .describe('Upstream registry endpoint'),
+
+ /**
+ * Synchronization policy
+ */
+ syncPolicy: RegistrySyncPolicySchema.default('auto'),
+
+ /**
+ * Sync interval in seconds (for auto sync)
+ */
+ syncInterval: z.number().int().min(60).optional()
+ .describe('Auto-sync interval in seconds'),
+
+ /**
+ * Authentication credentials
+ */
+ auth: z.object({
+ type: z.enum(['none', 'basic', 'bearer', 'api-key', 'oauth2']).default('none'),
+ username: z.string().optional(),
+ password: z.string().optional(),
+ token: z.string().optional(),
+ apiKey: z.string().optional(),
+ }).optional(),
+
+ /**
+ * TLS/SSL configuration
+ */
+ tls: z.object({
+ enabled: z.boolean().default(true),
+ verifyCertificate: z.boolean().default(true),
+ certificate: z.string().optional(),
+ privateKey: z.string().optional(),
+ }).optional(),
+
+ /**
+ * Timeout settings
+ */
+ timeout: z.number().int().min(1000).default(30000)
+ .describe('Request timeout in milliseconds'),
+
+ /**
+ * Retry configuration
+ */
+ retry: z.object({
+ maxAttempts: z.number().int().min(0).default(3),
+ backoff: z.enum(['fixed', 'linear', 'exponential']).default('exponential'),
+ }).optional(),
+});
+
+/**
+ * Registry Configuration
+ * Complete registry configuration supporting federation
+ */
+export const RegistryConfigSchema = z.object({
+ /**
+ * Registry type
+ */
+ type: z.enum([
+ 'public', // Public marketplace (e.g., plugins.objectstack.com)
+ 'private', // Private enterprise registry
+ 'hybrid', // Hybrid with upstream federation
+ ]).describe('Registry deployment type'),
+
+ /**
+ * Upstream registries (for hybrid/private registries)
+ */
+ upstream: z.array(RegistryUpstreamSchema).optional()
+ .describe('Upstream registries to sync from or proxy to'),
+
+ /**
+ * Scopes managed by this registry
+ */
+ scope: z.array(z.string()).optional()
+ .describe('npm-style scopes managed by this registry (e.g., @my-corp, @enterprise)'),
+
+ /**
+ * Default scope for new plugins
+ */
+ defaultScope: z.string().optional()
+ .describe('Default scope prefix for new plugins'),
+
+ /**
+ * Registry storage configuration
+ */
+ storage: z.object({
+ /**
+ * Storage backend type
+ */
+ backend: z.enum(['local', 's3', 'gcs', 'azure-blob', 'oss']).default('local'),
+
+ /**
+ * Storage path or bucket name
+ */
+ path: z.string().optional(),
+
+ /**
+ * Credentials
+ */
+ credentials: z.record(z.string(), z.any()).optional(),
+ }).optional(),
+
+ /**
+ * Registry visibility
+ */
+ visibility: z.enum(['public', 'private', 'internal']).default('private')
+ .describe('Who can access this registry'),
+
+ /**
+ * Access control
+ */
+ accessControl: z.object({
+ /**
+ * Require authentication for read
+ */
+ requireAuthForRead: z.boolean().default(false),
+
+ /**
+ * Require authentication for write
+ */
+ requireAuthForWrite: z.boolean().default(true),
+
+ /**
+ * Allowed users/teams
+ */
+ allowedPrincipals: z.array(z.string()).optional(),
+ }).optional(),
+
+ /**
+ * Caching configuration
+ */
+ cache: z.object({
+ enabled: z.boolean().default(true),
+ ttl: z.number().int().min(0).default(3600)
+ .describe('Cache TTL in seconds'),
+ maxSize: z.number().int().optional()
+ .describe('Maximum cache size in bytes'),
+ }).optional(),
+
+ /**
+ * Mirroring configuration (for high availability)
+ */
+ mirrors: z.array(z.object({
+ url: z.string().url(),
+ priority: z.number().int().min(1).default(1),
+ })).optional()
+ .describe('Mirror registries for redundancy'),
+});
+
/**
* Plugin Category
* Categorization for better discovery
@@ -679,6 +847,9 @@ export const PluginRevenueSharingSchema = z.object({
});
// Export types
+export type RegistrySyncPolicy = z.infer;
+export type RegistryUpstream = z.infer;
+export type RegistryConfig = z.infer;
export type PluginCategory = z.infer;
export type PluginTag = z.infer;
export type PluginRating = z.infer;
diff --git a/packages/spec/src/system/plugin-lifecycle-advanced.zod.ts b/packages/spec/src/system/plugin-lifecycle-advanced.zod.ts
index 2117bffee..561088094 100644
--- a/packages/spec/src/system/plugin-lifecycle-advanced.zod.ts
+++ b/packages/spec/src/system/plugin-lifecycle-advanced.zod.ts
@@ -132,6 +132,60 @@ export const PluginHealthReportSchema = z.object({
})).optional(),
});
+/**
+ * Distributed State Configuration
+ * Configuration for distributed state management in cluster environments
+ */
+export const DistributedStateConfigSchema = z.object({
+ /**
+ * Distributed cache provider
+ */
+ provider: z.enum(['redis', 'etcd', 'custom'])
+ .describe('Distributed state backend provider'),
+
+ /**
+ * Connection URL or endpoints
+ */
+ endpoints: z.array(z.string()).optional()
+ .describe('Backend connection endpoints'),
+
+ /**
+ * Key prefix for namespacing
+ */
+ keyPrefix: z.string().optional()
+ .describe('Prefix for all keys (e.g., "plugin:my-plugin:")'),
+
+ /**
+ * Time to live in seconds
+ */
+ ttl: z.number().int().min(0).optional()
+ .describe('State expiration time in seconds'),
+
+ /**
+ * Authentication configuration
+ */
+ auth: z.object({
+ username: z.string().optional(),
+ password: z.string().optional(),
+ token: z.string().optional(),
+ certificate: z.string().optional(),
+ }).optional(),
+
+ /**
+ * Replication settings
+ */
+ replication: z.object({
+ enabled: z.boolean().default(true),
+ minReplicas: z.number().int().min(1).default(1),
+ }).optional(),
+
+ /**
+ * Custom provider configuration
+ */
+ customConfig: z.record(z.string(), z.any()).optional()
+ .describe('Provider-specific configuration'),
+});
+
/**
* Hot Reload Configuration
* Controls how plugins handle live updates
@@ -163,9 +217,15 @@ export const HotReloadConfigSchema = z.object({
/**
* State serialization strategy
*/
- stateStrategy: z.enum(['memory', 'disk', 'none']).default('memory')
+ stateStrategy: z.enum(['memory', 'disk', 'distributed', 'none']).default('memory')
.describe('How to preserve state during reload'),
+ /**
+ * Distributed state configuration (required when stateStrategy is "distributed")
+ */
+ distributedConfig: DistributedStateConfigSchema.optional()
+ .describe('Configuration for distributed state management'),
+
/**
* Graceful shutdown timeout
*/
@@ -412,6 +472,7 @@ export const AdvancedPluginLifecycleConfigSchema = z.object({
export type PluginHealthStatus = z.infer;
export type PluginHealthCheck = z.infer;
export type PluginHealthReport = z.infer;
+export type DistributedStateConfig = z.infer;
export type HotReloadConfig = z.infer;
export type GracefulDegradation = z.infer;
export type PluginUpdateStrategy = z.infer;
diff --git a/packages/spec/src/system/plugin-security-advanced.zod.ts b/packages/spec/src/system/plugin-security-advanced.zod.ts
index a416e1c8e..2b80b5269 100644
--- a/packages/spec/src/system/plugin-security-advanced.zod.ts
+++ b/packages/spec/src/system/plugin-security-advanced.zod.ts
@@ -158,6 +158,130 @@ export const PermissionSetSchema = z.object({
]).default('prompt'),
});
+/**
+ * Runtime Configuration
+ * Defines the execution environment for plugin isolation
+ */
+export const RuntimeConfigSchema = z.object({
+ /**
+ * Runtime engine type
+ */
+ engine: z.enum([
+ 'v8-isolate', // V8 isolate-based isolation (lightweight, fast)
+ 'wasm', // WebAssembly-based isolation (secure, portable)
+ 'container', // Container-based isolation (Docker, podman)
+ 'process', // Process-based isolation (traditional)
+ ]).default('v8-isolate')
+ .describe('Execution environment engine'),
+
+ /**
+ * Engine-specific configuration
+ */
+ engineConfig: z.object({
+ /**
+ * WASM-specific settings (when engine is "wasm")
+ */
+ wasm: z.object({
+ /**
+ * Maximum memory pages (64KB per page)
+ */
+ maxMemoryPages: z.number().int().min(1).max(65536).optional()
+ .describe('Maximum WASM memory pages (64KB each)'),
+
+ /**
+ * Instruction execution limit
+ */
+ instructionLimit: z.number().int().min(1).optional()
+ .describe('Maximum instructions before timeout'),
+
+ /**
+ * Enable SIMD instructions
+ */
+ enableSimd: z.boolean().default(false)
+ .describe('Enable WebAssembly SIMD support'),
+
+ /**
+ * Enable threads
+ */
+ enableThreads: z.boolean().default(false)
+ .describe('Enable WebAssembly threads'),
+
+ /**
+ * Enable bulk memory operations
+ */
+ enableBulkMemory: z.boolean().default(true)
+ .describe('Enable bulk memory operations'),
+ }).optional(),
+
+ /**
+ * Container-specific settings (when engine is "container")
+ */
+ container: z.object({
+ /**
+ * Container image
+ */
+ image: z.string().optional()
+ .describe('Container image to use'),
+
+ /**
+ * Container runtime
+ */
+ runtime: z.enum(['docker', 'podman', 'containerd']).default('docker'),
+
+ /**
+ * Resource limits
+ */
+ resources: z.object({
+ cpuLimit: z.string().optional().describe('CPU limit (e.g., "0.5", "2")'),
+ memoryLimit: z.string().optional().describe('Memory limit (e.g., "512m", "1g")'),
+ }).optional(),
+
+ /**
+ * Network mode
+ */
+ networkMode: z.enum(['none', 'bridge', 'host']).default('bridge'),
+ }).optional(),
+
+ /**
+ * V8 Isolate-specific settings (when engine is "v8-isolate")
+ */
+ v8Isolate: z.object({
+ /**
+ * Heap size limit in MB
+ */
+ heapSizeMb: z.number().int().min(1).optional(),
+
+ /**
+ * Enable snapshot
+ */
+ enableSnapshot: z.boolean().default(true),
+ }).optional(),
+ }).optional(),
+
+ /**
+ * General resource limits (applies to all engines)
+ */
+ resourceLimits: z.object({
+ /**
+ * Maximum memory in bytes
+ */
+ maxMemory: z.number().int().optional()
+ .describe('Maximum memory allocation'),
+
+ /**
+ * Maximum CPU percentage
+ */
+ maxCpu: z.number().min(0).max(100).optional()
+ .describe('Maximum CPU usage percentage'),
+
+ /**
+ * Execution timeout in milliseconds
+ */
+ timeout: z.number().int().min(0).optional()
+ .describe('Maximum execution time'),
+ }).optional(),
+});
+
/**
* Sandbox Configuration
* Defines how plugin is isolated
@@ -179,6 +303,12 @@ export const SandboxConfigSchema = z.object({
'paranoid', // Maximum isolation
]).default('standard'),
+ /**
+ * Runtime environment configuration
+ */
+ runtime: RuntimeConfigSchema.optional()
+ .describe('Execution environment and isolation settings'),
+
/**
* File system access
*/
@@ -547,6 +677,7 @@ export type PermissionAction = z.infer;
export type ResourceType = z.infer;
export type Permission = z.infer;
export type PermissionSet = z.infer;
+export type RuntimeConfig = z.infer;
export type SandboxConfig = z.infer;
export type SecurityVulnerability = z.infer;
export type SecurityScanResult = z.infer;
From f5a4002269535581a477631d5a4abcf9d3fc07b8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 3 Feb 2026 08:34:22 +0000
Subject: [PATCH 3/3] Add comprehensive tests for all enterprise plugin
enhancements
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
---
.../spec/src/ai/plugin-development.test.ts | 289 ++++++++++++
packages/spec/src/ai/runtime-ops.test.ts | 422 ++++++++++++++++++
.../spec/src/hub/marketplace-enhanced.test.ts | 371 +++++++++++++++
.../system/plugin-lifecycle-advanced.test.ts | 66 +++
.../system/plugin-security-advanced.test.ts | 308 +++++++++++++
5 files changed, 1456 insertions(+)
create mode 100644 packages/spec/src/ai/plugin-development.test.ts
create mode 100644 packages/spec/src/ai/runtime-ops.test.ts
create mode 100644 packages/spec/src/hub/marketplace-enhanced.test.ts
create mode 100644 packages/spec/src/system/plugin-security-advanced.test.ts
diff --git a/packages/spec/src/ai/plugin-development.test.ts b/packages/spec/src/ai/plugin-development.test.ts
new file mode 100644
index 000000000..99ba464ff
--- /dev/null
+++ b/packages/spec/src/ai/plugin-development.test.ts
@@ -0,0 +1,289 @@
+import { describe, expect, it } from 'vitest';
+import {
+ CodeGenerationRequestSchema,
+ GeneratedCodeSchema,
+ AICodeReviewResultSchema,
+ PluginCompositionRequestSchema,
+ PluginRecommendationRequestSchema,
+} from './plugin-development.zod';
+
+describe('AI Plugin Development Schemas', () => {
+ describe('CodeGenerationRequestSchema', () => {
+ it('should validate basic code generation request', () => {
+ const request = {
+ description: 'Create a plugin to connect to PostgreSQL database',
+ pluginType: 'driver' as const,
+ };
+ const result = CodeGenerationRequestSchema.parse(request);
+ expect(result.description).toBe('Create a plugin to connect to PostgreSQL database');
+ expect(result.pluginType).toBe('driver');
+ expect(result.outputFormat).toBe('source-code');
+ expect(result.language).toBe('typescript');
+ });
+
+ it('should validate low-code schema generation request', () => {
+ const request = {
+ description: 'Create a CRM app with contacts and deals management',
+ pluginType: 'app' as const,
+ outputFormat: 'low-code-schema' as const,
+ schemaOptions: {
+ format: 'typescript' as const,
+ includeExamples: true,
+ strictValidation: true,
+ generateUI: true,
+ generateDataModels: true,
+ },
+ options: {
+ generateTests: true,
+ generateDocs: true,
+ },
+ };
+ const result = CodeGenerationRequestSchema.parse(request);
+ expect(result.outputFormat).toBe('low-code-schema');
+ expect(result.schemaOptions?.format).toBe('typescript');
+ expect(result.schemaOptions?.generateUI).toBe(true);
+ expect(result.schemaOptions?.generateDataModels).toBe(true);
+ });
+
+ it('should validate DSL generation request', () => {
+ const request = {
+ description: 'Create a workflow automation plugin',
+ pluginType: 'automation' as const,
+ outputFormat: 'dsl' as const,
+ capabilities: ['flow-execution', 'trigger-management'],
+ examples: [
+ {
+ input: 'When a new contact is created',
+ expectedOutput: 'Send welcome email',
+ description: 'Welcome email automation',
+ },
+ ],
+ };
+ const result = CodeGenerationRequestSchema.parse(request);
+ expect(result.outputFormat).toBe('dsl');
+ expect(result.capabilities).toHaveLength(2);
+ expect(result.examples).toHaveLength(1);
+ });
+
+ it('should validate source code generation with framework preferences', () => {
+ const request = {
+ description: 'Create a UI widget for data visualization',
+ pluginType: 'widget' as const,
+ outputFormat: 'source-code' as const,
+ language: 'typescript' as const,
+ framework: {
+ runtime: 'browser' as const,
+ uiFramework: 'react' as const,
+ testing: 'vitest' as const,
+ },
+ style: {
+ indentation: '2spaces' as const,
+ quotes: 'single' as const,
+ semicolons: true,
+ trailingComma: true,
+ },
+ options: {
+ generateTests: true,
+ generateDocs: true,
+ targetCoverage: 90,
+ optimizationLevel: 'aggressive' as const,
+ },
+ };
+ const result = CodeGenerationRequestSchema.parse(request);
+ expect(result.framework?.uiFramework).toBe('react');
+ expect(result.style?.quotes).toBe('single');
+ expect(result.options?.targetCoverage).toBe(90);
+ });
+ });
+
+ describe('GeneratedCodeSchema', () => {
+ it('should validate source code output', () => {
+ const generated = {
+ outputFormat: 'source-code' as const,
+ code: 'export class PostgresDriver implements Driver { ... }',
+ language: 'typescript',
+ files: [
+ {
+ path: 'src/index.ts',
+ content: 'export * from "./driver";',
+ },
+ {
+ path: 'src/driver.ts',
+ content: 'export class PostgresDriver { ... }',
+ },
+ ],
+ tests: [
+ {
+ path: 'src/driver.test.ts',
+ content: 'describe("PostgresDriver", () => { ... })',
+ coverage: 85,
+ },
+ ],
+ confidence: 92,
+ };
+ const result = GeneratedCodeSchema.parse(generated);
+ expect(result.outputFormat).toBe('source-code');
+ expect(result.files).toHaveLength(2);
+ expect(result.tests).toHaveLength(1);
+ expect(result.confidence).toBe(92);
+ });
+
+ it('should validate low-code schema output', () => {
+ const generated = {
+ outputFormat: 'low-code-schema' as const,
+ schemas: [
+ {
+ type: 'object' as const,
+ path: 'src/objects/contact.object.ts',
+ content: 'export const ContactObject = defineObject({ ... })',
+ description: 'Contact data model',
+ },
+ {
+ type: 'view' as const,
+ path: 'src/views/contact-list.view.ts',
+ content: 'export const ContactListView = defineView({ ... })',
+ description: 'Contact list view',
+ },
+ {
+ type: 'dashboard' as const,
+ path: 'src/dashboards/crm.dashboard.ts',
+ content: 'export const CRMDashboard = defineDashboard({ ... })',
+ description: 'CRM dashboard',
+ },
+ ],
+ files: [
+ {
+ path: 'package.json',
+ content: '{ "name": "@acme/crm-plugin", ... }',
+ },
+ ],
+ confidence: 88,
+ suggestions: [
+ 'Consider adding more field validations',
+ 'Add relationship to Deal object',
+ ],
+ };
+ const result = GeneratedCodeSchema.parse(generated);
+ expect(result.outputFormat).toBe('low-code-schema');
+ expect(result.schemas).toHaveLength(3);
+ expect(result.schemas?.[0].type).toBe('object');
+ expect(result.schemas?.[1].type).toBe('view');
+ expect(result.suggestions).toHaveLength(2);
+ });
+
+ it('should validate DSL output', () => {
+ const generated = {
+ outputFormat: 'dsl' as const,
+ files: [
+ {
+ path: 'workflows/welcome-email.flow',
+ content: 'trigger: contact.created\nactions:\n - send-email\n',
+ description: 'Welcome email workflow',
+ },
+ ],
+ confidence: 90,
+ };
+ const result = GeneratedCodeSchema.parse(generated);
+ expect(result.outputFormat).toBe('dsl');
+ expect(result.files).toHaveLength(1);
+ });
+ });
+
+ describe('AICodeReviewResultSchema', () => {
+ it('should validate code review result', () => {
+ const review = {
+ assessment: 'good' as const,
+ score: 85,
+ issues: [
+ {
+ severity: 'warning' as const,
+ category: 'performance' as const,
+ file: 'src/driver.ts',
+ line: 42,
+ message: 'Consider using connection pooling',
+ suggestion: 'Implement pg.Pool instead of creating new connections',
+ autoFixable: false,
+ },
+ {
+ severity: 'info' as const,
+ category: 'documentation' as const,
+ file: 'src/driver.ts',
+ line: 15,
+ message: 'Missing JSDoc comment',
+ autoFixable: true,
+ autoFix: '/** Query execution method */',
+ },
+ ],
+ recommendations: [
+ {
+ priority: 'medium' as const,
+ title: 'Add error handling',
+ description: 'Implement comprehensive error handling for connection failures',
+ effort: 'small' as const,
+ },
+ ],
+ };
+ const result = AICodeReviewResultSchema.parse(review);
+ expect(result.assessment).toBe('good');
+ expect(result.score).toBe(85);
+ expect(result.issues).toHaveLength(2);
+ });
+ });
+
+ describe('PluginCompositionRequestSchema', () => {
+ it('should validate plugin composition request', () => {
+ const request = {
+ goal: 'Create a complete CRM system with email integration',
+ availablePlugins: [
+ {
+ pluginId: 'com.objectstack.crm',
+ version: '1.0.0',
+ capabilities: ['contact-management', 'deal-tracking'],
+ },
+ {
+ pluginId: 'com.objectstack.email',
+ version: '2.0.0',
+ capabilities: ['send-email', 'email-templates'],
+ },
+ ],
+ constraints: {
+ maxPlugins: 3,
+ requiredPlugins: ['com.objectstack.crm'],
+ performance: {
+ maxLatency: 500,
+ maxMemory: 536870912, // 512MB
+ },
+ },
+ optimize: 'reliability' as const,
+ };
+ const result = PluginCompositionRequestSchema.parse(request);
+ expect(result.goal).toBeDefined();
+ expect(result.availablePlugins).toHaveLength(2);
+ expect(result.constraints?.maxPlugins).toBe(3);
+ });
+ });
+
+ describe('PluginRecommendationRequestSchema', () => {
+ it('should validate plugin recommendation request', () => {
+ const request = {
+ context: {
+ installedPlugins: ['com.objectstack.core'],
+ industry: 'healthcare',
+ useCases: ['patient-management', 'appointment-scheduling'],
+ teamSize: 25,
+ budget: 'medium' as const,
+ },
+ criteria: {
+ prioritize: 'compatibility' as const,
+ certifiedOnly: true,
+ minRating: 4.5,
+ maxResults: 10,
+ },
+ };
+ const result = PluginRecommendationRequestSchema.parse(request);
+ expect(result.context.industry).toBe('healthcare');
+ expect(result.criteria?.certifiedOnly).toBe(true);
+ expect(result.criteria?.minRating).toBe(4.5);
+ });
+ });
+});
diff --git a/packages/spec/src/ai/runtime-ops.test.ts b/packages/spec/src/ai/runtime-ops.test.ts
new file mode 100644
index 000000000..96f34859f
--- /dev/null
+++ b/packages/spec/src/ai/runtime-ops.test.ts
@@ -0,0 +1,422 @@
+import { describe, expect, it } from 'vitest';
+import {
+ AnomalyDetectionConfigSchema,
+ SelfHealingActionSchema,
+ SelfHealingConfigSchema,
+ AutoScalingPolicySchema,
+ RootCauseAnalysisRequestSchema,
+ RootCauseAnalysisResultSchema,
+ PerformanceOptimizationSchema,
+ AIOpsAgentConfigSchema,
+} from './runtime-ops.zod';
+
+describe('Runtime AI Operations (AIOps) Schemas', () => {
+ describe('AnomalyDetectionConfigSchema', () => {
+ it('should validate basic anomaly detection config', () => {
+ const config = {
+ enabled: true,
+ metrics: ['cpu-usage' as const, 'memory-usage' as const, 'error-rate' as const],
+ };
+ const result = AnomalyDetectionConfigSchema.parse(config);
+ expect(result.enabled).toBe(true);
+ expect(result.metrics).toHaveLength(3);
+ expect(result.algorithm).toBe('hybrid');
+ expect(result.sensitivity).toBe('medium');
+ });
+
+ it('should validate advanced anomaly detection config', () => {
+ const config = {
+ enabled: true,
+ metrics: ['response-time' as const, 'throughput' as const, 'latency' as const],
+ algorithm: 'machine-learning' as const,
+ sensitivity: 'high' as const,
+ timeWindow: 600,
+ confidenceThreshold: 90,
+ alertOnDetection: true,
+ };
+ const result = AnomalyDetectionConfigSchema.parse(config);
+ expect(result.algorithm).toBe('machine-learning');
+ expect(result.sensitivity).toBe('high');
+ expect(result.timeWindow).toBe(600);
+ expect(result.confidenceThreshold).toBe(90);
+ });
+ });
+
+ describe('SelfHealingActionSchema', () => {
+ it('should validate restart action', () => {
+ const action = {
+ id: 'auto-restart',
+ type: 'restart' as const,
+ trigger: {
+ healthStatus: ['failed' as const, 'unhealthy' as const],
+ },
+ maxAttempts: 3,
+ cooldown: 60,
+ timeout: 300,
+ };
+ const result = SelfHealingActionSchema.parse(action);
+ expect(result.type).toBe('restart');
+ expect(result.maxAttempts).toBe(3);
+ expect(result.requireApproval).toBe(false);
+ expect(result.priority).toBe(5);
+ });
+
+ it('should validate scale action with custom condition', () => {
+ const action = {
+ id: 'scale-up',
+ type: 'scale' as const,
+ trigger: {
+ customCondition: 'cpuUsage > 80 AND duration > 300',
+ },
+ parameters: {
+ direction: 'up',
+ instances: 2,
+ },
+ maxAttempts: 5,
+ cooldown: 300,
+ timeout: 600,
+ requireApproval: true,
+ priority: 3,
+ };
+ const result = SelfHealingActionSchema.parse(action);
+ expect(result.type).toBe('scale');
+ expect(result.requireApproval).toBe(true);
+ expect(result.priority).toBe(3);
+ });
+
+ it('should validate adjust-config action', () => {
+ const action = {
+ id: 'tune-memory',
+ type: 'adjust-config' as const,
+ trigger: {
+ anomalyTypes: ['memory-leak', 'high-memory-usage'],
+ },
+ parameters: {
+ config: {
+ maxHeap: 1073741824, // 1GB
+ gcStrategy: 'aggressive',
+ },
+ },
+ };
+ const result = SelfHealingActionSchema.parse(action);
+ expect(result.type).toBe('adjust-config');
+ expect(result.trigger.anomalyTypes).toHaveLength(2);
+ });
+ });
+
+ describe('SelfHealingConfigSchema', () => {
+ it('should validate basic self-healing config', () => {
+ const config = {
+ enabled: true,
+ actions: [
+ {
+ id: 'restart-on-failure',
+ type: 'restart' as const,
+ trigger: {
+ healthStatus: ['failed' as const],
+ },
+ },
+ ],
+ };
+ const result = SelfHealingConfigSchema.parse(config);
+ expect(result.enabled).toBe(true);
+ expect(result.strategy).toBe('moderate');
+ expect(result.actions).toHaveLength(1);
+ expect(result.maxConcurrentHealing).toBe(1);
+ });
+
+ it('should validate comprehensive self-healing config', () => {
+ const config = {
+ enabled: true,
+ strategy: 'aggressive' as const,
+ actions: [
+ {
+ id: 'restart',
+ type: 'restart' as const,
+ trigger: { healthStatus: ['failed' as const] },
+ },
+ {
+ id: 'scale',
+ type: 'scale' as const,
+ trigger: { customCondition: 'load > 90' },
+ parameters: { instances: 2 },
+ },
+ ],
+ anomalyDetection: {
+ enabled: true,
+ metrics: ['cpu-usage' as const, 'memory-usage' as const],
+ algorithm: 'machine-learning' as const,
+ },
+ maxConcurrentHealing: 3,
+ learning: {
+ enabled: true,
+ feedbackLoop: true,
+ },
+ };
+ const result = SelfHealingConfigSchema.parse(config);
+ expect(result.strategy).toBe('aggressive');
+ expect(result.actions).toHaveLength(2);
+ expect(result.anomalyDetection?.enabled).toBe(true);
+ expect(result.learning?.enabled).toBe(true);
+ });
+ });
+
+ describe('AutoScalingPolicySchema', () => {
+ it('should validate CPU-based auto-scaling', () => {
+ const policy = {
+ enabled: true,
+ metric: 'cpu-usage' as const,
+ targetValue: 70,
+ bounds: {
+ minInstances: 2,
+ maxInstances: 10,
+ },
+ scaleUp: {
+ threshold: 80,
+ stabilizationWindow: 60,
+ cooldown: 300,
+ stepSize: 2,
+ },
+ scaleDown: {
+ threshold: 50,
+ stabilizationWindow: 300,
+ cooldown: 600,
+ stepSize: 1,
+ },
+ };
+ const result = AutoScalingPolicySchema.parse(policy);
+ expect(result.metric).toBe('cpu-usage');
+ expect(result.targetValue).toBe(70);
+ expect(result.bounds.minInstances).toBe(2);
+ expect(result.scaleUp.threshold).toBe(80);
+ });
+
+ it('should validate predictive auto-scaling', () => {
+ const policy = {
+ enabled: true,
+ metric: 'request-rate' as const,
+ targetValue: 1000,
+ bounds: {
+ minInstances: 1,
+ maxInstances: 20,
+ minResources: {
+ cpu: '0.5',
+ memory: '512Mi',
+ },
+ maxResources: {
+ cpu: '2',
+ memory: '2Gi',
+ },
+ },
+ scaleUp: {
+ threshold: 1200,
+ stabilizationWindow: 120,
+ cooldown: 180,
+ stepSize: 3,
+ },
+ scaleDown: {
+ threshold: 800,
+ stabilizationWindow: 600,
+ cooldown: 900,
+ stepSize: 1,
+ },
+ predictive: {
+ enabled: true,
+ lookAhead: 600,
+ confidence: 85,
+ },
+ };
+ const result = AutoScalingPolicySchema.parse(policy);
+ expect(result.predictive?.enabled).toBe(true);
+ expect(result.predictive?.lookAhead).toBe(600);
+ expect(result.bounds.minResources?.cpu).toBe('0.5');
+ });
+ });
+
+ describe('RootCauseAnalysisRequestSchema', () => {
+ it('should validate RCA request', () => {
+ const request = {
+ incidentId: 'INC-2024-001',
+ pluginId: 'com.acme.analytics',
+ symptoms: [
+ {
+ type: 'high-error-rate',
+ description: 'Error rate increased to 15%',
+ severity: 'critical' as const,
+ timestamp: new Date().toISOString(),
+ },
+ {
+ type: 'slow-response',
+ description: 'Response time degraded to 5s',
+ severity: 'high' as const,
+ timestamp: new Date().toISOString(),
+ },
+ ],
+ timeRange: {
+ start: new Date(Date.now() - 3600000).toISOString(),
+ end: new Date().toISOString(),
+ },
+ analyzeLogs: true,
+ analyzeMetrics: true,
+ analyzeDependencies: true,
+ };
+ const result = RootCauseAnalysisRequestSchema.parse(request);
+ expect(result.incidentId).toBe('INC-2024-001');
+ expect(result.symptoms).toHaveLength(2);
+ expect(result.analyzeLogs).toBe(true);
+ });
+ });
+
+ describe('RootCauseAnalysisResultSchema', () => {
+ it('should validate RCA result', () => {
+ const result = {
+ analysisId: 'RCA-2024-001',
+ incidentId: 'INC-2024-001',
+ rootCauses: [
+ {
+ id: 'cause-1',
+ description: 'Database connection pool exhausted',
+ confidence: 95,
+ category: 'resource-exhaustion' as const,
+ evidence: [
+ {
+ type: 'log' as const,
+ content: 'Connection pool timeout after 30s',
+ timestamp: new Date().toISOString(),
+ },
+ {
+ type: 'metric' as const,
+ content: 'active_connections: 100/100',
+ },
+ ],
+ impact: 'critical' as const,
+ recommendations: [
+ 'Increase connection pool size to 200',
+ 'Implement connection timeout handling',
+ 'Add connection pooling metrics',
+ ],
+ },
+ ],
+ remediation: {
+ immediate: ['Restart plugin to clear connections'],
+ shortTerm: ['Increase pool size', 'Add monitoring'],
+ longTerm: ['Implement adaptive pooling', 'Add auto-scaling'],
+ },
+ overallConfidence: 92,
+ timestamp: new Date().toISOString(),
+ };
+ const parsed = RootCauseAnalysisResultSchema.parse(result);
+ expect(parsed.rootCauses).toHaveLength(1);
+ expect(parsed.rootCauses[0].confidence).toBe(95);
+ expect(parsed.remediation?.immediate).toHaveLength(1);
+ });
+ });
+
+ describe('PerformanceOptimizationSchema', () => {
+ it('should validate performance optimization suggestion', () => {
+ const optimization = {
+ id: 'opt-001',
+ pluginId: 'com.acme.analytics',
+ type: 'caching' as const,
+ description: 'Implement Redis caching for frequently accessed data',
+ expectedImpact: {
+ performanceGain: 40,
+ resourceSavings: {
+ cpu: 25,
+ memory: 15,
+ },
+ costReduction: 20,
+ },
+ difficulty: 'moderate' as const,
+ steps: [
+ 'Install Redis adapter',
+ 'Configure cache TTL policies',
+ 'Implement cache invalidation',
+ 'Add cache metrics',
+ ],
+ risks: [
+ 'Cache invalidation complexity',
+ 'Additional memory overhead',
+ ],
+ confidence: 88,
+ priority: 'high' as const,
+ };
+ const result = PerformanceOptimizationSchema.parse(optimization);
+ expect(result.type).toBe('caching');
+ expect(result.expectedImpact.performanceGain).toBe(40);
+ expect(result.steps).toHaveLength(4);
+ expect(result.priority).toBe('high');
+ });
+ });
+
+ describe('AIOpsAgentConfigSchema', () => {
+ it('should validate complete AIOps agent config', () => {
+ const config = {
+ agentId: 'aiops-001',
+ pluginId: 'com.acme.analytics',
+ selfHealing: {
+ enabled: true,
+ strategy: 'moderate' as const,
+ actions: [
+ {
+ id: 'restart',
+ type: 'restart' as const,
+ trigger: { healthStatus: ['failed' as const] },
+ },
+ ],
+ },
+ autoScaling: [
+ {
+ enabled: true,
+ metric: 'cpu-usage' as const,
+ targetValue: 70,
+ bounds: {
+ minInstances: 1,
+ maxInstances: 5,
+ },
+ scaleUp: {
+ threshold: 80,
+ stabilizationWindow: 60,
+ cooldown: 300,
+ stepSize: 1,
+ },
+ scaleDown: {
+ threshold: 50,
+ stabilizationWindow: 300,
+ cooldown: 600,
+ stepSize: 1,
+ },
+ },
+ ],
+ monitoring: {
+ enabled: true,
+ interval: 30000,
+ metrics: ['cpu', 'memory', 'latency'],
+ },
+ optimization: {
+ enabled: true,
+ scanInterval: 86400,
+ autoApply: false,
+ },
+ incidentResponse: {
+ enabled: true,
+ autoRCA: true,
+ notifications: [
+ {
+ channel: 'slack' as const,
+ config: {
+ webhook: 'https://hooks.slack.com/...',
+ },
+ },
+ ],
+ },
+ };
+ const result = AIOpsAgentConfigSchema.parse(config);
+ expect(result.agentId).toBe('aiops-001');
+ expect(result.selfHealing?.enabled).toBe(true);
+ expect(result.autoScaling).toHaveLength(1);
+ expect(result.monitoring?.enabled).toBe(true);
+ expect(result.incidentResponse?.autoRCA).toBe(true);
+ });
+ });
+});
diff --git a/packages/spec/src/hub/marketplace-enhanced.test.ts b/packages/spec/src/hub/marketplace-enhanced.test.ts
new file mode 100644
index 000000000..f678599f3
--- /dev/null
+++ b/packages/spec/src/hub/marketplace-enhanced.test.ts
@@ -0,0 +1,371 @@
+import { describe, expect, it } from 'vitest';
+import {
+ RegistrySyncPolicySchema,
+ RegistryUpstreamSchema,
+ RegistryConfigSchema,
+ PluginCategorySchema,
+ PluginLicenseSchema,
+ PluginMarketplaceListingSchema,
+ PluginSearchQuerySchema,
+ PluginInstallationRequestSchema,
+} from './marketplace-enhanced.zod';
+
+describe('Marketplace Enhanced Schemas', () => {
+ describe('RegistrySyncPolicySchema', () => {
+ it('should validate sync policies', () => {
+ expect(() => RegistrySyncPolicySchema.parse('manual')).not.toThrow();
+ expect(() => RegistrySyncPolicySchema.parse('auto')).not.toThrow();
+ expect(() => RegistrySyncPolicySchema.parse('proxy')).not.toThrow();
+ });
+
+ it('should reject invalid sync policy', () => {
+ expect(() => RegistrySyncPolicySchema.parse('invalid')).toThrow();
+ });
+ });
+
+ describe('RegistryUpstreamSchema', () => {
+ it('should validate basic upstream configuration', () => {
+ const upstream = {
+ url: 'https://plugins.objectstack.com',
+ syncPolicy: 'auto' as const,
+ };
+ const result = RegistryUpstreamSchema.parse(upstream);
+ expect(result.url).toBe('https://plugins.objectstack.com');
+ expect(result.syncPolicy).toBe('auto');
+ expect(result.timeout).toBe(30000);
+ });
+
+ it('should validate upstream with authentication', () => {
+ const upstream = {
+ url: 'https://registry.acme.com',
+ syncPolicy: 'auto' as const,
+ syncInterval: 3600,
+ auth: {
+ type: 'bearer' as const,
+ token: 'eyJhbGciOiJIUzI1NiIs...',
+ },
+ tls: {
+ enabled: true,
+ verifyCertificate: true,
+ },
+ retry: {
+ maxAttempts: 5,
+ backoff: 'exponential' as const,
+ },
+ };
+ const result = RegistryUpstreamSchema.parse(upstream);
+ expect(result.auth?.type).toBe('bearer');
+ expect(result.syncInterval).toBe(3600);
+ expect(result.retry?.maxAttempts).toBe(5);
+ });
+
+ it('should validate upstream with API key authentication', () => {
+ const upstream = {
+ url: 'https://private-registry.example.com',
+ syncPolicy: 'manual' as const,
+ auth: {
+ type: 'api-key' as const,
+ apiKey: 'sk-1234567890abcdef',
+ },
+ };
+ const result = RegistryUpstreamSchema.parse(upstream);
+ expect(result.auth?.type).toBe('api-key');
+ expect(result.auth?.apiKey).toBe('sk-1234567890abcdef');
+ });
+ });
+
+ describe('RegistryConfigSchema', () => {
+ it('should validate public registry', () => {
+ const config = {
+ type: 'public' as const,
+ storage: {
+ backend: 's3' as const,
+ path: 'objectstack-plugins',
+ },
+ visibility: 'public' as const,
+ cache: {
+ enabled: true,
+ ttl: 3600,
+ },
+ };
+ const result = RegistryConfigSchema.parse(config);
+ expect(result.type).toBe('public');
+ expect(result.visibility).toBe('public');
+ });
+
+ it('should validate private registry with scopes', () => {
+ const config = {
+ type: 'private' as const,
+ scope: ['@acme', '@enterprise'],
+ defaultScope: '@acme',
+ storage: {
+ backend: 'local' as const,
+ path: '/var/lib/objectstack/plugins',
+ },
+ visibility: 'private' as const,
+ accessControl: {
+ requireAuthForRead: true,
+ requireAuthForWrite: true,
+ allowedPrincipals: ['team:engineering', 'team:platform'],
+ },
+ };
+ const result = RegistryConfigSchema.parse(config);
+ expect(result.type).toBe('private');
+ expect(result.scope).toHaveLength(2);
+ expect(result.defaultScope).toBe('@acme');
+ expect(result.accessControl?.requireAuthForRead).toBe(true);
+ });
+
+ it('should validate hybrid registry with federation', () => {
+ const config = {
+ type: 'hybrid' as const,
+ upstream: [
+ {
+ url: 'https://plugins.objectstack.com',
+ syncPolicy: 'auto' as const,
+ syncInterval: 7200,
+ },
+ {
+ url: 'https://npmjs.org',
+ syncPolicy: 'proxy' as const,
+ },
+ ],
+ scope: ['@my-company'],
+ storage: {
+ backend: 's3' as const,
+ path: 'my-company-plugins',
+ },
+ visibility: 'internal' as const,
+ cache: {
+ enabled: true,
+ ttl: 7200,
+ maxSize: 10737418240, // 10GB
+ },
+ mirrors: [
+ {
+ url: 'https://mirror1.example.com',
+ priority: 1,
+ },
+ {
+ url: 'https://mirror2.example.com',
+ priority: 2,
+ },
+ ],
+ };
+ const result = RegistryConfigSchema.parse(config);
+ expect(result.type).toBe('hybrid');
+ expect(result.upstream).toHaveLength(2);
+ expect(result.upstream?.[0].syncPolicy).toBe('auto');
+ expect(result.upstream?.[1].syncPolicy).toBe('proxy');
+ expect(result.mirrors).toHaveLength(2);
+ });
+
+ it('should validate registry with GCS storage', () => {
+ const config = {
+ type: 'private' as const,
+ storage: {
+ backend: 'gcs' as const,
+ path: 'my-bucket/plugins',
+ credentials: {
+ projectId: 'my-project',
+ keyFile: '/path/to/keyfile.json',
+ },
+ },
+ };
+ const result = RegistryConfigSchema.parse(config);
+ expect(result.storage?.backend).toBe('gcs');
+ });
+ });
+
+ describe('PluginCategorySchema', () => {
+ it('should validate all plugin categories', () => {
+ const categories = [
+ 'data-integration',
+ 'analytics',
+ 'ai-ml',
+ 'automation',
+ 'communication',
+ 'crm',
+ 'erp',
+ 'productivity',
+ 'security',
+ 'ui-components',
+ 'utilities',
+ 'developer-tools',
+ 'other',
+ ];
+
+ categories.forEach(category => {
+ expect(() => PluginCategorySchema.parse(category)).not.toThrow();
+ });
+ });
+ });
+
+ describe('PluginLicenseSchema', () => {
+ it('should validate free license', () => {
+ const license = {
+ type: 'free' as const,
+ spdxId: 'MIT',
+ commercialUse: true,
+ attributionRequired: false,
+ };
+ const result = PluginLicenseSchema.parse(license);
+ expect(result.type).toBe('free');
+ expect(result.commercialUse).toBe(true);
+ });
+
+ it('should validate freemium license with pricing', () => {
+ const license = {
+ type: 'freemium' as const,
+ pricing: {
+ freeTier: true,
+ trialDays: 30,
+ model: 'per-user' as const,
+ pricePerUnit: 999, // $9.99
+ billingPeriod: 'monthly' as const,
+ currency: 'USD',
+ },
+ };
+ const result = PluginLicenseSchema.parse(license);
+ expect(result.type).toBe('freemium');
+ expect(result.pricing?.trialDays).toBe(30);
+ expect(result.pricing?.pricePerUnit).toBe(999);
+ });
+
+ it('should validate enterprise license', () => {
+ const license = {
+ type: 'enterprise' as const,
+ commercialUse: true,
+ licenseUrl: 'https://acme.com/license',
+ };
+ const result = PluginLicenseSchema.parse(license);
+ expect(result.type).toBe('enterprise');
+ });
+ });
+
+ describe('PluginSearchQuerySchema', () => {
+ it('should validate basic search query', () => {
+ const query = {
+ query: 'analytics dashboard',
+ };
+ const result = PluginSearchQuerySchema.parse(query);
+ expect(result.query).toBe('analytics dashboard');
+ expect(result.sortOrder).toBe('desc');
+ expect(result.page).toBe(1);
+ expect(result.pageSize).toBe(20);
+ });
+
+ it('should validate advanced search query', () => {
+ const query = {
+ query: 'data connector',
+ category: 'data-integration' as const,
+ tags: ['sql', 'postgres', 'mysql'],
+ minRating: 4.0,
+ minQualityScore: 80,
+ certifiedOnly: true,
+ freeOnly: false,
+ sortBy: 'popularity' as const,
+ sortOrder: 'desc' as const,
+ page: 2,
+ pageSize: 50,
+ };
+ const result = PluginSearchQuerySchema.parse(query);
+ expect(result.category).toBe('data-integration');
+ expect(result.tags).toHaveLength(3);
+ expect(result.minRating).toBe(4.0);
+ expect(result.certifiedOnly).toBe(true);
+ });
+ });
+
+ describe('PluginInstallationRequestSchema', () => {
+ it('should validate basic installation request', () => {
+ const request = {
+ pluginId: 'com.acme.analytics',
+ acceptLicense: true,
+ };
+ const result = PluginInstallationRequestSchema.parse(request);
+ expect(result.pluginId).toBe('com.acme.analytics');
+ expect(result.autoEnable).toBe(true);
+ expect(result.scope).toBe('global');
+ });
+
+ it('should validate installation with specific version and config', () => {
+ const request = {
+ pluginId: 'com.acme.crm-connector',
+ version: '2.1.0',
+ config: {
+ apiKey: 'sk-...',
+ endpoint: 'https://api.acme.com',
+ },
+ acceptLicense: true,
+ grantPermissions: ['read-data', 'write-data'],
+ autoEnable: true,
+ scope: 'tenant' as const,
+ tenantId: 'tenant-123',
+ };
+ const result = PluginInstallationRequestSchema.parse(request);
+ expect(result.version).toBe('2.1.0');
+ expect(result.scope).toBe('tenant');
+ expect(result.tenantId).toBe('tenant-123');
+ expect(result.grantPermissions).toHaveLength(2);
+ });
+ });
+
+ describe('PluginMarketplaceListingSchema', () => {
+ it('should validate complete marketplace listing', () => {
+ const listing = {
+ pluginId: 'com.objectstack.analytics',
+ name: 'ObjectStack Analytics',
+ shortDescription: 'Advanced analytics and reporting for ObjectStack',
+ description: '# ObjectStack Analytics\n\nComprehensive analytics solution...',
+ publisher: {
+ id: 'objectstack',
+ name: 'ObjectStack Inc.',
+ website: 'https://objectstack.com',
+ verified: true,
+ },
+ categories: ['analytics' as const, 'productivity' as const],
+ tags: [
+ { name: 'analytics', category: 'feature' as const },
+ { name: 'reporting', category: 'feature' as const },
+ ],
+ versions: [
+ {
+ pluginId: 'com.objectstack.analytics',
+ version: {
+ major: 1,
+ minor: 0,
+ patch: 0,
+ },
+ versionString: '1.0.0',
+ releaseDate: new Date().toISOString(),
+ support: {
+ status: 'active' as const,
+ securitySupport: true,
+ },
+ },
+ ],
+ latestVersion: '1.0.0',
+ icon: 'https://cdn.objectstack.com/plugins/analytics/icon.png',
+ license: {
+ type: 'freemium' as const,
+ pricing: {
+ freeTier: true,
+ model: 'per-user' as const,
+ },
+ },
+ statistics: {
+ downloads: 5000,
+ activeInstallations: 1500,
+ },
+ publishedDate: new Date().toISOString(),
+ lastUpdated: new Date().toISOString(),
+ };
+ const result = PluginMarketplaceListingSchema.parse(listing);
+ expect(result.name).toBe('ObjectStack Analytics');
+ expect(result.publisher.verified).toBe(true);
+ expect(result.categories).toHaveLength(2);
+ expect(result.statistics.downloads).toBe(5000);
+ });
+ });
+});
diff --git a/packages/spec/src/system/plugin-lifecycle-advanced.test.ts b/packages/spec/src/system/plugin-lifecycle-advanced.test.ts
index 1632a5834..182278cd9 100644
--- a/packages/spec/src/system/plugin-lifecycle-advanced.test.ts
+++ b/packages/spec/src/system/plugin-lifecycle-advanced.test.ts
@@ -3,6 +3,7 @@ import {
PluginHealthStatusSchema,
PluginHealthCheckSchema,
PluginHealthReportSchema,
+ DistributedStateConfigSchema,
HotReloadConfigSchema,
GracefulDegradationSchema,
PluginUpdateStrategySchema,
@@ -135,6 +136,71 @@ describe('Plugin Lifecycle Advanced Schemas', () => {
const result = HotReloadConfigSchema.parse(config);
expect(result).toEqual(config);
});
+
+ it('should validate distributed state strategy', () => {
+ const config = {
+ enabled: true,
+ stateStrategy: 'distributed' as const,
+ distributedConfig: {
+ provider: 'redis' as const,
+ endpoints: ['redis://localhost:6379'],
+ keyPrefix: 'plugin:my-plugin:',
+ ttl: 3600,
+ },
+ };
+ const result = HotReloadConfigSchema.parse(config);
+ expect(result.stateStrategy).toBe('distributed');
+ expect(result.distributedConfig?.provider).toBe('redis');
+ expect(result.distributedConfig?.keyPrefix).toBe('plugin:my-plugin:');
+ });
+ });
+
+ describe('DistributedStateConfigSchema', () => {
+ it('should validate Redis configuration', () => {
+ const config = {
+ provider: 'redis' as const,
+ endpoints: ['redis://localhost:6379', 'redis://localhost:6380'],
+ keyPrefix: 'objectstack:',
+ ttl: 7200,
+ auth: {
+ username: 'admin',
+ password: 'secret',
+ },
+ replication: {
+ enabled: true,
+ minReplicas: 2,
+ },
+ };
+ const result = DistributedStateConfigSchema.parse(config);
+ expect(result.provider).toBe('redis');
+ expect(result.endpoints).toHaveLength(2);
+ expect(result.ttl).toBe(7200);
+ });
+
+ it('should validate Etcd configuration', () => {
+ const config = {
+ provider: 'etcd' as const,
+ endpoints: ['http://localhost:2379'],
+ auth: {
+ certificate: '/path/to/cert.pem',
+ },
+ };
+ const result = DistributedStateConfigSchema.parse(config);
+ expect(result.provider).toBe('etcd');
+ });
+
+ it('should validate custom provider configuration', () => {
+ const config = {
+ provider: 'custom' as const,
+ customConfig: {
+ type: 'consul',
+ address: 'consul.example.com:8500',
+ },
+ };
+ const result = DistributedStateConfigSchema.parse(config);
+ expect(result.provider).toBe('custom');
+ expect(result.customConfig).toBeDefined();
+ });
});
describe('GracefulDegradationSchema', () => {
diff --git a/packages/spec/src/system/plugin-security-advanced.test.ts b/packages/spec/src/system/plugin-security-advanced.test.ts
new file mode 100644
index 000000000..6a3fbf5b5
--- /dev/null
+++ b/packages/spec/src/system/plugin-security-advanced.test.ts
@@ -0,0 +1,308 @@
+import { describe, expect, it } from 'vitest';
+import {
+ RuntimeConfigSchema,
+ SandboxConfigSchema,
+ PermissionSchema,
+ PermissionSetSchema,
+ SecurityPolicySchema,
+ PluginSecurityManifestSchema,
+} from './plugin-security-advanced.zod';
+
+describe('Plugin Security Advanced Schemas', () => {
+ describe('RuntimeConfigSchema', () => {
+ it('should validate default V8 isolate runtime', () => {
+ const config = RuntimeConfigSchema.parse({});
+ expect(config.engine).toBe('v8-isolate');
+ });
+
+ it('should validate WASM runtime with memory pages', () => {
+ const config = {
+ engine: 'wasm' as const,
+ engineConfig: {
+ wasm: {
+ maxMemoryPages: 256,
+ instructionLimit: 1000000,
+ enableSimd: true,
+ enableThreads: false,
+ enableBulkMemory: true,
+ },
+ },
+ resourceLimits: {
+ maxMemory: 16777216, // 16MB
+ maxCpu: 50,
+ timeout: 30000,
+ },
+ };
+ const result = RuntimeConfigSchema.parse(config);
+ expect(result.engine).toBe('wasm');
+ expect(result.engineConfig?.wasm?.maxMemoryPages).toBe(256);
+ expect(result.engineConfig?.wasm?.instructionLimit).toBe(1000000);
+ expect(result.resourceLimits?.maxMemory).toBe(16777216);
+ });
+
+ it('should validate container runtime', () => {
+ const config = {
+ engine: 'container' as const,
+ engineConfig: {
+ container: {
+ image: 'objectstack/plugin-runtime:latest',
+ runtime: 'docker' as const,
+ resources: {
+ cpuLimit: '0.5',
+ memoryLimit: '512m',
+ },
+ networkMode: 'bridge' as const,
+ },
+ },
+ };
+ const result = RuntimeConfigSchema.parse(config);
+ expect(result.engine).toBe('container');
+ expect(result.engineConfig?.container?.image).toBe('objectstack/plugin-runtime:latest');
+ expect(result.engineConfig?.container?.runtime).toBe('docker');
+ });
+
+ it('should validate process runtime', () => {
+ const config = {
+ engine: 'process' as const,
+ resourceLimits: {
+ maxMemory: 1073741824, // 1GB
+ maxCpu: 100,
+ timeout: 60000,
+ },
+ };
+ const result = RuntimeConfigSchema.parse(config);
+ expect(result.engine).toBe('process');
+ });
+
+ it('should validate V8 isolate with custom settings', () => {
+ const config = {
+ engine: 'v8-isolate' as const,
+ engineConfig: {
+ v8Isolate: {
+ heapSizeMb: 128,
+ enableSnapshot: true,
+ },
+ },
+ };
+ const result = RuntimeConfigSchema.parse(config);
+ expect(result.engineConfig?.v8Isolate?.heapSizeMb).toBe(128);
+ });
+ });
+
+ describe('SandboxConfigSchema', () => {
+ it('should validate sandbox with defaults', () => {
+ const config = SandboxConfigSchema.parse({});
+ expect(config.enabled).toBe(true);
+ expect(config.level).toBe('standard');
+ });
+
+ it('should validate strict sandbox with WASM runtime', () => {
+ const config = {
+ enabled: true,
+ level: 'strict' as const,
+ runtime: {
+ engine: 'wasm' as const,
+ engineConfig: {
+ wasm: {
+ maxMemoryPages: 128,
+ instructionLimit: 500000,
+ },
+ },
+ },
+ filesystem: {
+ mode: 'readonly' as const,
+ allowedPaths: ['/data/readonly'],
+ },
+ network: {
+ mode: 'restricted' as const,
+ allowedHosts: ['api.objectstack.com'],
+ allowedPorts: [443],
+ },
+ memory: {
+ maxHeap: 67108864, // 64MB
+ },
+ cpu: {
+ maxCpuPercent: 25,
+ maxThreads: 2,
+ },
+ };
+ const result = SandboxConfigSchema.parse(config);
+ expect(result.level).toBe('strict');
+ expect(result.runtime?.engine).toBe('wasm');
+ expect(result.filesystem?.mode).toBe('readonly');
+ });
+
+ it('should validate paranoid sandbox', () => {
+ const config = {
+ enabled: true,
+ level: 'paranoid' as const,
+ runtime: {
+ engine: 'wasm' as const,
+ },
+ filesystem: {
+ mode: 'none' as const,
+ },
+ network: {
+ mode: 'none' as const,
+ },
+ process: {
+ allowSpawn: false,
+ },
+ environment: {
+ mode: 'none' as const,
+ },
+ };
+ const result = SandboxConfigSchema.parse(config);
+ expect(result.level).toBe('paranoid');
+ expect(result.filesystem?.mode).toBe('none');
+ expect(result.network?.mode).toBe('none');
+ });
+ });
+
+ describe('PermissionSchema', () => {
+ it('should validate basic permission', () => {
+ const permission = {
+ id: 'read-objects',
+ resource: 'data.object' as const,
+ actions: ['read' as const],
+ description: 'Read access to data objects',
+ };
+ const result = PermissionSchema.parse(permission);
+ expect(result.id).toBe('read-objects');
+ expect(result.scope).toBe('plugin');
+ expect(result.required).toBe(true);
+ });
+
+ it('should validate permission with filter', () => {
+ const permission = {
+ id: 'manage-user-records',
+ resource: 'data.record' as const,
+ actions: ['read' as const, 'update' as const],
+ scope: 'user' as const,
+ filter: {
+ condition: 'owner = currentUser',
+ fields: ['name', 'email', 'preferences'],
+ },
+ description: 'Manage user records',
+ justification: 'Required for user profile management',
+ };
+ const result = PermissionSchema.parse(permission);
+ expect(result.scope).toBe('user');
+ expect(result.filter?.fields).toHaveLength(3);
+ });
+ });
+
+ describe('PermissionSetSchema', () => {
+ it('should validate permission set', () => {
+ const permissionSet = {
+ permissions: [
+ {
+ id: 'read-data',
+ resource: 'data.object' as const,
+ actions: ['read' as const],
+ description: 'Read data',
+ },
+ ],
+ groups: [
+ {
+ name: 'data-access',
+ description: 'Data access permissions',
+ permissions: ['read-data'],
+ },
+ ],
+ defaultGrant: 'prompt' as const,
+ };
+ const result = PermissionSetSchema.parse(permissionSet);
+ expect(result.permissions).toHaveLength(1);
+ expect(result.groups).toHaveLength(1);
+ });
+ });
+
+ describe('SecurityPolicySchema', () => {
+ it('should validate comprehensive security policy', () => {
+ const policy = {
+ csp: {
+ directives: {
+ 'default-src': ["'self'"],
+ 'script-src': ["'self'", "'unsafe-inline'"],
+ },
+ reportOnly: false,
+ },
+ cors: {
+ allowedOrigins: ['https://app.objectstack.com'],
+ allowedMethods: ['GET', 'POST'],
+ allowedHeaders: ['Content-Type', 'Authorization'],
+ allowCredentials: true,
+ },
+ rateLimit: {
+ enabled: true,
+ maxRequests: 100,
+ windowMs: 60000,
+ strategy: 'sliding' as const,
+ },
+ authentication: {
+ required: true,
+ methods: ['jwt' as const, 'api-key' as const],
+ tokenExpiration: 3600,
+ },
+ encryption: {
+ dataAtRest: true,
+ dataInTransit: true,
+ algorithm: 'AES-256-GCM',
+ minKeyLength: 256,
+ },
+ auditLog: {
+ enabled: true,
+ events: ['auth', 'data-access', 'config-change'],
+ retention: 90,
+ },
+ };
+ const result = SecurityPolicySchema.parse(policy);
+ expect(result.rateLimit?.enabled).toBe(true);
+ expect(result.authentication?.required).toBe(true);
+ expect(result.encryption?.dataAtRest).toBe(true);
+ });
+ });
+
+ describe('PluginSecurityManifestSchema', () => {
+ it('should validate complete security manifest', () => {
+ const manifest = {
+ pluginId: 'com.acme.analytics',
+ trustLevel: 'trusted' as const,
+ permissions: {
+ permissions: [
+ {
+ id: 'read-analytics',
+ resource: 'data.object' as const,
+ actions: ['read' as const],
+ description: 'Read analytics data',
+ },
+ ],
+ defaultGrant: 'prompt' as const,
+ },
+ sandbox: {
+ enabled: true,
+ level: 'strict' as const,
+ runtime: {
+ engine: 'wasm' as const,
+ engineConfig: {
+ wasm: {
+ maxMemoryPages: 256,
+ },
+ },
+ },
+ },
+ codeSigning: {
+ signed: true,
+ signature: 'sha256:abc123...',
+ algorithm: 'RSA-SHA256',
+ timestamp: new Date().toISOString(),
+ },
+ };
+ const result = PluginSecurityManifestSchema.parse(manifest);
+ expect(result.trustLevel).toBe('trusted');
+ expect(result.sandbox.level).toBe('strict');
+ expect(result.codeSigning?.signed).toBe(true);
+ });
+ });
+});