@task-shepherd/agent 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +1 -1
- package/dist/index.js +1 -1
- package/dist/meta.json +5 -5
- package/package.json +2 -2
- package/shared/dist/index.d.ts +15 -0
- package/shared/dist/index.js +12 -0
- package/shared/dist/mcp-client/client.d.ts +18 -0
- package/shared/dist/mcp-client/client.js +49 -0
- package/shared/dist/mcp-client/index.d.ts +7 -0
- package/shared/dist/mcp-client/index.js +7 -0
- package/shared/dist/mcp-client/types.d.ts +822 -0
- package/shared/dist/mcp-client/types.js +193 -0
- package/shared/dist/schema/index.d.ts +189 -0
- package/shared/dist/schema/index.js +142 -0
- package/shared/dist/schema/mcp-mappings.d.ts +50 -0
- package/shared/dist/schema/mcp-mappings.js +563 -0
- package/shared/dist/schema/validation.d.ts +91 -0
- package/shared/dist/schema/validation.js +282 -0
- package/shared/dist/work-queue/index.d.ts +7 -0
- package/shared/dist/work-queue/index.js +7 -0
- package/shared/dist/work-queue/types.d.ts +147 -0
- package/shared/dist/work-queue/types.js +4 -0
- package/shared/dist/work-queue/validation.d.ts +24 -0
- package/shared/dist/work-queue/validation.js +160 -0
- package/shared/dist/workspace/constants.d.ts +148 -0
- package/shared/dist/workspace/constants.js +432 -0
- package/shared/dist/workspace/index.d.ts +10 -0
- package/shared/dist/workspace/index.js +10 -0
- package/shared/dist/workspace/types.d.ts +477 -0
- package/shared/dist/workspace/types.js +9 -0
- package/shared/dist/workspace/utils.d.ts +79 -0
- package/shared/dist/workspace/utils.js +334 -0
- package/shared/dist/workspace/validation.d.ts +1312 -0
- package/shared/dist/workspace/validation.js +467 -0
- package/shared/graphql/generated-internal.ts +3629 -0
- package/shared/graphql/generated-public.ts +773 -0
- package/shared/graphql/generated.d.ts +7456 -0
- package/shared/graphql/generated.js +11799 -0
- package/shared/graphql/generated.ts +27569 -0
- package/shared/graphql/generated.ts.backup +16531 -0
- package/shared/graphql/generated.ts.working +4828 -0
- package/shared/graphql/introspection-internal.json +15845 -0
- package/shared/graphql/introspection-public.json +9658 -0
- package/shared/graphql/introspection.json +44263 -0
- package/shared/graphql/operations/ai-service.graphql +131 -0
- package/shared/graphql/operations/ai-work-queue.graphql +31 -0
- package/shared/graphql/operations/analytics.graphql +283 -0
- package/shared/graphql/operations/analytics.ts +3 -0
- package/shared/graphql/operations/api-keys.graphql +126 -0
- package/shared/graphql/operations/attachments.graphql +53 -0
- package/shared/graphql/operations/attachments.ts +39 -0
- package/shared/graphql/operations/audit.graphql +46 -0
- package/shared/graphql/operations/auth.graphql +83 -0
- package/shared/graphql/operations/claude-usage.graphql +178 -0
- package/shared/graphql/operations/comments.graphql +4 -0
- package/shared/graphql/operations/dashboard.graphql +29 -0
- package/shared/graphql/operations/development-plans.graphql +408 -0
- package/shared/graphql/operations/early-access.graphql.disabled +21 -0
- package/shared/graphql/operations/errors.graphql.disabled +83 -0
- package/shared/graphql/operations/internal-api.graphql +931 -0
- package/shared/graphql/operations/notifications.graphql +4 -0
- package/shared/graphql/operations/organization-invites.graphql.disabled +32 -0
- package/shared/graphql/operations/performance.graphql +4 -0
- package/shared/graphql/operations/project-reviews.graphql +610 -0
- package/shared/graphql/operations/projects.graphql +98 -0
- package/shared/graphql/operations/settings.graphql +4 -0
- package/shared/graphql/operations/stories.graphql +113 -0
- package/shared/graphql/operations/subscriptions.graphql +235 -0
- package/shared/graphql/operations/subscriptions.graphql.disabled +96 -0
- package/shared/graphql/operations/tasks.graphql +257 -0
- package/shared/graphql/operations/team.graphql +111 -0
- package/shared/graphql/operations/team.ts +226 -0
- package/shared/graphql/operations/time-tracking.graphql.disabled +96 -0
- package/shared/graphql/operations/work-queue.graphql +210 -0
- package/shared/graphql/operations/work-queue.graphql.disabled +474 -0
- package/shared/graphql/operations/workspace.graphql +146 -0
- package/shared/graphql/schema-internal.graphql +1085 -0
- package/shared/graphql/schema-public.graphql +709 -0
- package/shared/graphql/schema.graphql +3473 -0
- package/shared/package.json +23 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod Validation Schemas for Workspace Configuration
|
|
3
|
+
*
|
|
4
|
+
* Provides runtime type safety and validation for all workspace configuration types.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
/**
|
|
8
|
+
* Base validation schemas
|
|
9
|
+
*/
|
|
10
|
+
export const WorkspacePatternSchema = z.enum(['monorepo', 'multi-repo', 'hybrid']);
|
|
11
|
+
export const ServiceTechnologySchema = z.enum([
|
|
12
|
+
'nodejs', 'python', 'go', 'rust', 'java', 'dotnet', 'php', 'ruby',
|
|
13
|
+
'react', 'vue', 'angular', 'static', 'database', 'cache', 'queue', 'other'
|
|
14
|
+
]);
|
|
15
|
+
export const EnvironmentSchema = z.enum(['development', 'staging', 'production', 'test']);
|
|
16
|
+
export const ProtocolSchema = z.enum([
|
|
17
|
+
'http', 'https', 'ws', 'wss', 'tcp', 'udp', 'grpc',
|
|
18
|
+
'postgresql', 'redis', 'mongodb'
|
|
19
|
+
]);
|
|
20
|
+
export const AuthTypeSchema = z.enum([
|
|
21
|
+
'none', 'basic', 'bearer', 'apikey', 'oauth2', 'custom'
|
|
22
|
+
]);
|
|
23
|
+
export const PackageManagerSchema = z.enum([
|
|
24
|
+
'npm', 'yarn', 'pnpm', 'pip', 'go mod', 'cargo', 'maven', 'gradle'
|
|
25
|
+
]);
|
|
26
|
+
export const AIProviderSchema = z.enum([
|
|
27
|
+
'claude', 'openai', 'gemini', 'azure', 'custom'
|
|
28
|
+
]);
|
|
29
|
+
export const IsolationLevelSchema = z.enum(['strict', 'moderate', 'relaxed']);
|
|
30
|
+
export const SeverityLevelSchema = z.enum(['error', 'warning', 'info']);
|
|
31
|
+
/**
|
|
32
|
+
* Service dependency validation schema
|
|
33
|
+
*/
|
|
34
|
+
export const ServiceDependencySchema = z.object({
|
|
35
|
+
service: z.string().min(1, 'Service name is required'),
|
|
36
|
+
type: z.enum(['required', 'optional', 'development']),
|
|
37
|
+
version: z.string().optional(),
|
|
38
|
+
description: z.string().optional()
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* Service authentication validation schema
|
|
42
|
+
*/
|
|
43
|
+
export const ServiceAuthenticationSchema = z.object({
|
|
44
|
+
type: AuthTypeSchema,
|
|
45
|
+
credentials: z.record(z.string(), z.string()).optional(),
|
|
46
|
+
headers: z.record(z.string(), z.string()).optional()
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* Service endpoint validation schema
|
|
50
|
+
*/
|
|
51
|
+
export const ServiceEndpointSchema = z.object({
|
|
52
|
+
id: z.string().min(1, 'Service ID is required'),
|
|
53
|
+
name: z.string().min(1, 'Service name is required'),
|
|
54
|
+
description: z.string().optional(),
|
|
55
|
+
url: z.string().url('Invalid service URL'),
|
|
56
|
+
port: z.number().int().min(1).max(65535, 'Port must be between 1 and 65535'),
|
|
57
|
+
protocol: ProtocolSchema,
|
|
58
|
+
technology: ServiceTechnologySchema,
|
|
59
|
+
environment: EnvironmentSchema,
|
|
60
|
+
healthCheck: z.string().optional(),
|
|
61
|
+
version: z.string().optional(),
|
|
62
|
+
dependencies: z.array(ServiceDependencySchema).default([]),
|
|
63
|
+
auth: ServiceAuthenticationSchema.optional(),
|
|
64
|
+
metadata: z.record(z.string(), z.any()).optional()
|
|
65
|
+
});
|
|
66
|
+
/**
|
|
67
|
+
* Repository configuration validation schema
|
|
68
|
+
*/
|
|
69
|
+
export const RepositoryConfigSchema = z.object({
|
|
70
|
+
id: z.string().min(1, 'Repository ID is required'),
|
|
71
|
+
name: z.string().min(1, 'Repository name is required'),
|
|
72
|
+
url: z.string().url('Invalid repository URL'),
|
|
73
|
+
path: z.string().min(1, 'Repository path is required'),
|
|
74
|
+
branch: z.string().min(1, 'Default branch is required').default('main'),
|
|
75
|
+
type: z.enum(['primary', 'service', 'library', 'config']),
|
|
76
|
+
services: z.array(z.string()).default([]),
|
|
77
|
+
config: z.object({
|
|
78
|
+
packageManager: PackageManagerSchema.optional(),
|
|
79
|
+
buildCommands: z.array(z.string()).optional(),
|
|
80
|
+
testCommands: z.array(z.string()).optional(),
|
|
81
|
+
lintCommands: z.array(z.string()).optional()
|
|
82
|
+
}).optional()
|
|
83
|
+
});
|
|
84
|
+
/**
|
|
85
|
+
* AI model configuration validation schema
|
|
86
|
+
*/
|
|
87
|
+
export const AIModelConfigSchema = z.object({
|
|
88
|
+
provider: AIProviderSchema,
|
|
89
|
+
model: z.string().min(1, 'Model name is required'),
|
|
90
|
+
apiKey: z.string().min(1, 'API key is required'),
|
|
91
|
+
config: z.record(z.string(), z.any()).optional(),
|
|
92
|
+
rateLimit: z.object({
|
|
93
|
+
requestsPerMinute: z.number().int().positive().optional(),
|
|
94
|
+
tokensPerMinute: z.number().int().positive().optional(),
|
|
95
|
+
requestsPerDay: z.number().int().positive().optional()
|
|
96
|
+
}).optional()
|
|
97
|
+
});
|
|
98
|
+
/**
|
|
99
|
+
* AI capabilities validation schema
|
|
100
|
+
*/
|
|
101
|
+
export const AICapabilitiesSchema = z.object({
|
|
102
|
+
maxConcurrentOperations: z.number().int().positive().default(3),
|
|
103
|
+
supportedAnalysisTypes: z.array(z.string()).min(1, 'At least one analysis type is required'),
|
|
104
|
+
isolationLevel: IsolationLevelSchema.default('moderate'),
|
|
105
|
+
serviceCapabilities: z.record(z.string(), z.array(z.string())).optional(),
|
|
106
|
+
customCapabilities: z.record(z.string(), z.any()).optional()
|
|
107
|
+
});
|
|
108
|
+
/**
|
|
109
|
+
* Workspace paths validation schema
|
|
110
|
+
*/
|
|
111
|
+
export const WorkspacePathsSchema = z.object({
|
|
112
|
+
root: z.string().min(1, 'Root path is required').default('.'),
|
|
113
|
+
src: z.array(z.string()).default(['src']),
|
|
114
|
+
tests: z.array(z.string()).default(['test', 'tests']),
|
|
115
|
+
docs: z.array(z.string()).default(['docs']),
|
|
116
|
+
config: z.array(z.string()).default(['config']),
|
|
117
|
+
build: z.array(z.string()).default(['build', 'dist']),
|
|
118
|
+
temp: z.array(z.string()).default(['tmp', 'temp']),
|
|
119
|
+
logs: z.array(z.string()).default(['logs']),
|
|
120
|
+
cache: z.array(z.string()).default(['cache', '.cache']),
|
|
121
|
+
assets: z.array(z.string()).default(['assets', 'public']),
|
|
122
|
+
excluded: z.array(z.string()).default(['node_modules', '.git', '.env']),
|
|
123
|
+
servicePaths: z.record(z.string(), z.array(z.string())).optional()
|
|
124
|
+
});
|
|
125
|
+
/**
|
|
126
|
+
* Security configuration validation schema
|
|
127
|
+
*/
|
|
128
|
+
export const SecurityConfigSchema = z.object({
|
|
129
|
+
filePermissions: z.object({
|
|
130
|
+
read: z.boolean().default(true),
|
|
131
|
+
write: z.boolean().default(true),
|
|
132
|
+
execute: z.boolean().default(false),
|
|
133
|
+
restricted: z.array(z.string()).default(['.env', '.env.local', '.env.production']),
|
|
134
|
+
readOnly: z.array(z.string()).default([])
|
|
135
|
+
}),
|
|
136
|
+
networkPermissions: z.object({
|
|
137
|
+
http: z.boolean().default(true),
|
|
138
|
+
https: z.boolean().default(true),
|
|
139
|
+
allowedDomains: z.array(z.string()).default(['api.anthropic.com', 'api.openai.com']),
|
|
140
|
+
blockedDomains: z.array(z.string()).default([]),
|
|
141
|
+
allowedPorts: z.array(z.number().int().min(1).max(65535)).optional()
|
|
142
|
+
}),
|
|
143
|
+
apiAccess: z.object({
|
|
144
|
+
allowedEndpoints: z.array(z.string()),
|
|
145
|
+
rateLimits: z.record(z.string(), z.number().positive()).optional()
|
|
146
|
+
}).optional()
|
|
147
|
+
});
|
|
148
|
+
/**
|
|
149
|
+
* Development configuration validation schema
|
|
150
|
+
*/
|
|
151
|
+
export const DevelopmentConfigSchema = z.object({
|
|
152
|
+
packageManager: PackageManagerSchema.default('npm'),
|
|
153
|
+
runtimeVersions: z.object({
|
|
154
|
+
node: z.string().optional(),
|
|
155
|
+
python: z.string().optional(),
|
|
156
|
+
go: z.string().optional(),
|
|
157
|
+
rust: z.string().optional(),
|
|
158
|
+
java: z.string().optional(),
|
|
159
|
+
dotnet: z.string().optional()
|
|
160
|
+
}).optional(),
|
|
161
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
162
|
+
scripts: z.object({
|
|
163
|
+
start: z.string().optional(),
|
|
164
|
+
build: z.string().optional(),
|
|
165
|
+
test: z.string().optional(),
|
|
166
|
+
lint: z.string().optional(),
|
|
167
|
+
typeCheck: z.string().optional(),
|
|
168
|
+
dbSetup: z.string().optional(),
|
|
169
|
+
clean: z.string().optional()
|
|
170
|
+
}).optional(),
|
|
171
|
+
tools: z.object({
|
|
172
|
+
formatter: z.enum(['prettier', 'black', 'gofmt', 'rustfmt', 'custom']).optional(),
|
|
173
|
+
linter: z.enum(['eslint', 'pylint', 'golangci-lint', 'clippy', 'custom']).optional(),
|
|
174
|
+
testFramework: z.enum(['jest', 'vitest', 'pytest', 'go test', 'cargo test', 'custom']).optional()
|
|
175
|
+
}).optional()
|
|
176
|
+
});
|
|
177
|
+
/**
|
|
178
|
+
* Integrations configuration validation schema
|
|
179
|
+
*/
|
|
180
|
+
export const IntegrationsConfigSchema = z.object({
|
|
181
|
+
tasqhub: z.object({
|
|
182
|
+
apiUrl: z.string().url('Invalid TasqHub API URL'),
|
|
183
|
+
apiKey: z.string().min(1, 'TasqHub API key is required'),
|
|
184
|
+
projectId: z.string().optional(),
|
|
185
|
+
workspaceId: z.string().optional()
|
|
186
|
+
}).optional(),
|
|
187
|
+
git: z.object({
|
|
188
|
+
remotes: z.record(z.string(), z.string().url('Invalid repository URL')),
|
|
189
|
+
defaultBranch: z.string().default('main'),
|
|
190
|
+
hooks: z.object({
|
|
191
|
+
preCommit: z.array(z.string()).optional(),
|
|
192
|
+
postCommit: z.array(z.string()).optional(),
|
|
193
|
+
prePush: z.array(z.string()).optional(),
|
|
194
|
+
postMerge: z.array(z.string()).optional()
|
|
195
|
+
}).optional()
|
|
196
|
+
}).optional(),
|
|
197
|
+
cicd: z.object({
|
|
198
|
+
provider: z.enum(['github-actions', 'gitlab-ci', 'jenkins', 'azure-devops', 'custom']),
|
|
199
|
+
configPath: z.string().optional(),
|
|
200
|
+
pipelines: z.record(z.string(), z.any()).optional()
|
|
201
|
+
}).optional(),
|
|
202
|
+
containers: z.object({
|
|
203
|
+
runtime: z.enum(['docker', 'podman', 'containerd']),
|
|
204
|
+
registry: z.object({
|
|
205
|
+
url: z.string().url(),
|
|
206
|
+
credentials: z.record(z.string(), z.string()).optional()
|
|
207
|
+
}).optional(),
|
|
208
|
+
composeFiles: z.array(z.string()).optional()
|
|
209
|
+
}).optional(),
|
|
210
|
+
cloud: z.object({
|
|
211
|
+
provider: z.enum(['aws', 'gcp', 'azure', 'custom']),
|
|
212
|
+
config: z.record(z.string(), z.any()).optional()
|
|
213
|
+
}).optional()
|
|
214
|
+
});
|
|
215
|
+
/**
|
|
216
|
+
* Workspace metadata validation schema
|
|
217
|
+
*/
|
|
218
|
+
export const WorkspaceMetadataSchema = z.object({
|
|
219
|
+
id: z.string().uuid('Invalid workspace ID format'),
|
|
220
|
+
name: z.string().min(1, 'Workspace name is required').max(100, 'Workspace name too long'),
|
|
221
|
+
description: z.string().max(500, 'Description too long').optional(),
|
|
222
|
+
pattern: WorkspacePatternSchema,
|
|
223
|
+
version: z.string().regex(/^\d+\.\d+\.\d+$/, 'Invalid version format (use semver)'),
|
|
224
|
+
createdAt: z.string().datetime('Invalid creation timestamp'),
|
|
225
|
+
updatedAt: z.string().datetime('Invalid update timestamp'),
|
|
226
|
+
tags: z.array(z.string()).optional(),
|
|
227
|
+
owner: z.object({
|
|
228
|
+
name: z.string().min(1),
|
|
229
|
+
email: z.string().email('Invalid owner email')
|
|
230
|
+
}).optional(),
|
|
231
|
+
team: z.array(z.object({
|
|
232
|
+
name: z.string().min(1),
|
|
233
|
+
email: z.string().email('Invalid team member email'),
|
|
234
|
+
role: z.string().min(1)
|
|
235
|
+
})).optional()
|
|
236
|
+
});
|
|
237
|
+
/**
|
|
238
|
+
* Complete workspace configuration validation schema
|
|
239
|
+
*/
|
|
240
|
+
export const WorkspaceConfigSchema = z.object({
|
|
241
|
+
workspace: WorkspaceMetadataSchema,
|
|
242
|
+
services: z.record(z.string(), ServiceEndpointSchema).refine((services) => Object.keys(services).length > 0, 'At least one service must be defined'),
|
|
243
|
+
repositories: z.record(z.string(), RepositoryConfigSchema).optional(),
|
|
244
|
+
ai: z.object({
|
|
245
|
+
models: z.record(z.string(), AIModelConfigSchema).refine((models) => Object.keys(models).length > 0, 'At least one AI model must be configured'),
|
|
246
|
+
defaultModel: z.string().min(1, 'Default AI model is required'),
|
|
247
|
+
capabilities: AICapabilitiesSchema
|
|
248
|
+
}),
|
|
249
|
+
paths: WorkspacePathsSchema,
|
|
250
|
+
development: DevelopmentConfigSchema,
|
|
251
|
+
security: SecurityConfigSchema,
|
|
252
|
+
integrations: IntegrationsConfigSchema.optional(),
|
|
253
|
+
extensions: z.record(z.string(), z.any()).optional()
|
|
254
|
+
}).refine((config) => {
|
|
255
|
+
// Validate that default AI model exists in models
|
|
256
|
+
return config.ai.defaultModel in config.ai.models;
|
|
257
|
+
}, {
|
|
258
|
+
message: 'Default AI model must be defined in models configuration',
|
|
259
|
+
path: ['ai', 'defaultModel']
|
|
260
|
+
}).refine((config) => {
|
|
261
|
+
// Validate service dependencies reference existing services
|
|
262
|
+
const serviceIds = Object.keys(config.services);
|
|
263
|
+
for (const [serviceId, service] of Object.entries(config.services)) {
|
|
264
|
+
for (const dep of service.dependencies) {
|
|
265
|
+
if (!serviceIds.includes(dep.service)) {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return true;
|
|
271
|
+
}, {
|
|
272
|
+
message: 'Service dependencies must reference existing services',
|
|
273
|
+
path: ['services']
|
|
274
|
+
});
|
|
275
|
+
/**
|
|
276
|
+
* Service discovery configuration validation schema
|
|
277
|
+
*/
|
|
278
|
+
export const ServiceDiscoveryConfigSchema = z.object({
|
|
279
|
+
enabled: z.boolean().default(true),
|
|
280
|
+
methods: z.array(z.enum(['filesystem', 'docker-compose', 'kubernetes', 'consul', 'custom'])).min(1),
|
|
281
|
+
patterns: z.object({
|
|
282
|
+
files: z.array(z.string()).default(['package.json', 'Dockerfile', 'docker-compose.yml']),
|
|
283
|
+
directories: z.array(z.string()).default(['src', 'app', 'services']),
|
|
284
|
+
portRanges: z.array(z.object({
|
|
285
|
+
start: z.number().int().min(1).max(65535),
|
|
286
|
+
end: z.number().int().min(1).max(65535)
|
|
287
|
+
})).optional()
|
|
288
|
+
}),
|
|
289
|
+
overrides: z.record(z.string(), ServiceEndpointSchema).optional()
|
|
290
|
+
});
|
|
291
|
+
/**
|
|
292
|
+
* Workspace validation configuration schema
|
|
293
|
+
*/
|
|
294
|
+
export const WorkspaceValidationConfigSchema = z.object({
|
|
295
|
+
rules: z.object({
|
|
296
|
+
requiredServices: z.array(z.string()).optional(),
|
|
297
|
+
validateDependencies: z.boolean().default(true),
|
|
298
|
+
validatePaths: z.boolean().default(true),
|
|
299
|
+
detectPortConflicts: z.boolean().default(true),
|
|
300
|
+
customRules: z.array(z.object({
|
|
301
|
+
name: z.string().min(1),
|
|
302
|
+
description: z.string().min(1),
|
|
303
|
+
validator: z.string().min(1)
|
|
304
|
+
})).optional()
|
|
305
|
+
}),
|
|
306
|
+
severity: z.object({
|
|
307
|
+
missingServices: SeverityLevelSchema.default('error'),
|
|
308
|
+
circularDependencies: SeverityLevelSchema.default('error'),
|
|
309
|
+
portConflicts: SeverityLevelSchema.default('warning'),
|
|
310
|
+
invalidPaths: SeverityLevelSchema.default('warning')
|
|
311
|
+
})
|
|
312
|
+
});
|
|
313
|
+
/**
|
|
314
|
+
* Workspace initialization options validation schema
|
|
315
|
+
*/
|
|
316
|
+
export const WorkspaceInitOptionsSchema = z.object({
|
|
317
|
+
directory: z.string().optional(),
|
|
318
|
+
name: z.string().min(1).max(100).optional(),
|
|
319
|
+
description: z.string().max(500).optional(),
|
|
320
|
+
pattern: WorkspacePatternSchema.optional(),
|
|
321
|
+
template: z.string().optional(),
|
|
322
|
+
interactive: z.boolean().default(false),
|
|
323
|
+
force: z.boolean().default(false),
|
|
324
|
+
services: z.array(z.string()).optional(),
|
|
325
|
+
aiProvider: z.string().optional(),
|
|
326
|
+
repositories: z.array(z.string().url()).optional(),
|
|
327
|
+
discovery: ServiceDiscoveryConfigSchema.partial().optional()
|
|
328
|
+
});
|
|
329
|
+
/**
|
|
330
|
+
* Workspace template validation schema
|
|
331
|
+
*/
|
|
332
|
+
export const WorkspaceTemplateSchema = z.object({
|
|
333
|
+
id: z.string().min(1, 'Template ID is required'),
|
|
334
|
+
name: z.string().min(1, 'Template name is required'),
|
|
335
|
+
description: z.string().min(1, 'Template description is required'),
|
|
336
|
+
patterns: z.array(WorkspacePatternSchema).min(1, 'At least one pattern must be supported'),
|
|
337
|
+
config: WorkspaceConfigSchema.partial(),
|
|
338
|
+
requiredServices: z.array(z.string()).default([]),
|
|
339
|
+
optionalServices: z.array(z.string()).default([]),
|
|
340
|
+
setupSteps: z.array(z.string()).optional(),
|
|
341
|
+
variables: z.record(z.string(), z.object({
|
|
342
|
+
description: z.string().min(1),
|
|
343
|
+
type: z.enum(['string', 'number', 'boolean', 'array']),
|
|
344
|
+
default: z.any().optional(),
|
|
345
|
+
required: z.boolean().optional()
|
|
346
|
+
})).optional()
|
|
347
|
+
});
|
|
348
|
+
/**
|
|
349
|
+
* Validation helper functions
|
|
350
|
+
*/
|
|
351
|
+
export class WorkspaceValidator {
|
|
352
|
+
/**
|
|
353
|
+
* Validate workspace configuration
|
|
354
|
+
*/
|
|
355
|
+
static validateWorkspaceConfig(config) {
|
|
356
|
+
const result = WorkspaceConfigSchema.safeParse(config);
|
|
357
|
+
if (result.success) {
|
|
358
|
+
return {
|
|
359
|
+
success: true,
|
|
360
|
+
data: result.data,
|
|
361
|
+
errors: []
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
return {
|
|
365
|
+
success: false,
|
|
366
|
+
errors: result.error.issues.map(err => ({
|
|
367
|
+
path: err.path.map(String),
|
|
368
|
+
message: err.message,
|
|
369
|
+
code: err.code
|
|
370
|
+
}))
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Validate service endpoint configuration
|
|
375
|
+
*/
|
|
376
|
+
static validateServiceEndpoint(endpoint) {
|
|
377
|
+
const result = ServiceEndpointSchema.safeParse(endpoint);
|
|
378
|
+
if (result.success) {
|
|
379
|
+
return {
|
|
380
|
+
success: true,
|
|
381
|
+
data: result.data,
|
|
382
|
+
errors: []
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
return {
|
|
386
|
+
success: false,
|
|
387
|
+
errors: result.error.issues.map(err => ({
|
|
388
|
+
path: err.path.map(String),
|
|
389
|
+
message: err.message,
|
|
390
|
+
code: err.code
|
|
391
|
+
}))
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Validate workspace initialization options
|
|
396
|
+
*/
|
|
397
|
+
static validateInitOptions(options) {
|
|
398
|
+
const result = WorkspaceInitOptionsSchema.safeParse(options);
|
|
399
|
+
if (result.success) {
|
|
400
|
+
return {
|
|
401
|
+
success: true,
|
|
402
|
+
data: result.data,
|
|
403
|
+
errors: []
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
return {
|
|
407
|
+
success: false,
|
|
408
|
+
errors: result.error.issues.map(err => ({
|
|
409
|
+
path: err.path.map(String),
|
|
410
|
+
message: err.message,
|
|
411
|
+
code: err.code
|
|
412
|
+
}))
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Check for circular dependencies in services
|
|
417
|
+
*/
|
|
418
|
+
static checkCircularDependencies(services) {
|
|
419
|
+
const visited = new Set();
|
|
420
|
+
const recursionStack = new Set();
|
|
421
|
+
const cycles = [];
|
|
422
|
+
const dfs = (serviceId, path = []) => {
|
|
423
|
+
if (recursionStack.has(serviceId)) {
|
|
424
|
+
const cycleStart = path.indexOf(serviceId);
|
|
425
|
+
const cycle = [...path.slice(cycleStart), serviceId];
|
|
426
|
+
cycles.push(cycle.join(' -> '));
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
if (visited.has(serviceId)) {
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
visited.add(serviceId);
|
|
433
|
+
recursionStack.add(serviceId);
|
|
434
|
+
const service = services[serviceId];
|
|
435
|
+
if (service?.dependencies) {
|
|
436
|
+
for (const dep of service.dependencies) {
|
|
437
|
+
if (dep.type === 'required') {
|
|
438
|
+
dfs(dep.service, [...path, serviceId]);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
recursionStack.delete(serviceId);
|
|
443
|
+
};
|
|
444
|
+
for (const serviceId of Object.keys(services)) {
|
|
445
|
+
if (!visited.has(serviceId)) {
|
|
446
|
+
dfs(serviceId);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return cycles;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Check for port conflicts
|
|
453
|
+
*/
|
|
454
|
+
static checkPortConflicts(services) {
|
|
455
|
+
const portMap = new Map();
|
|
456
|
+
for (const [serviceId, service] of Object.entries(services)) {
|
|
457
|
+
const port = service.port;
|
|
458
|
+
if (!portMap.has(port)) {
|
|
459
|
+
portMap.set(port, []);
|
|
460
|
+
}
|
|
461
|
+
portMap.get(port).push(serviceId);
|
|
462
|
+
}
|
|
463
|
+
return Array.from(portMap.entries())
|
|
464
|
+
.filter(([_, serviceIds]) => serviceIds.length > 1)
|
|
465
|
+
.map(([port, serviceIds]) => ({ port, services: serviceIds }));
|
|
466
|
+
}
|
|
467
|
+
}
|