@task-shepherd/agent 1.0.6 → 1.0.8
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 +1054 -86
- package/dist/index.js +1 -1
- package/dist/meta.json +358 -67
- 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,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace Configuration Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for working with workspace configurations.
|
|
5
|
+
*/
|
|
6
|
+
import { WORKSPACE_TEMPLATES, COMMON_SERVICE_PORTS } from './constants.js';
|
|
7
|
+
/**
|
|
8
|
+
* Create a workspace configuration from a template
|
|
9
|
+
*/
|
|
10
|
+
export function createWorkspaceFromTemplate(templateId, options) {
|
|
11
|
+
const template = WORKSPACE_TEMPLATES[templateId];
|
|
12
|
+
if (!template) {
|
|
13
|
+
throw new Error(`Template '${templateId}' not found`);
|
|
14
|
+
}
|
|
15
|
+
const config = {
|
|
16
|
+
...template.config,
|
|
17
|
+
workspace: {
|
|
18
|
+
...template.config.workspace,
|
|
19
|
+
id: generateWorkspaceId(),
|
|
20
|
+
name: options.name,
|
|
21
|
+
description: options.description,
|
|
22
|
+
pattern: options.pattern || template.config.workspace?.pattern || 'monorepo',
|
|
23
|
+
version: template.config.workspace?.version || '1.0.0',
|
|
24
|
+
createdAt: new Date().toISOString(),
|
|
25
|
+
updatedAt: new Date().toISOString()
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
// Merge custom configuration
|
|
29
|
+
if (options.customConfig) {
|
|
30
|
+
return mergeWorkspaceConfigs(config, options.customConfig);
|
|
31
|
+
}
|
|
32
|
+
return config;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Merge workspace configurations
|
|
36
|
+
*/
|
|
37
|
+
export function mergeWorkspaceConfigs(base, override) {
|
|
38
|
+
return {
|
|
39
|
+
...base,
|
|
40
|
+
...override,
|
|
41
|
+
workspace: {
|
|
42
|
+
...base.workspace,
|
|
43
|
+
...override.workspace
|
|
44
|
+
},
|
|
45
|
+
services: {
|
|
46
|
+
...base.services,
|
|
47
|
+
...override.services
|
|
48
|
+
},
|
|
49
|
+
ai: base.ai && override.ai ? {
|
|
50
|
+
...base.ai,
|
|
51
|
+
...override.ai,
|
|
52
|
+
models: {
|
|
53
|
+
...base.ai?.models,
|
|
54
|
+
...override.ai?.models
|
|
55
|
+
},
|
|
56
|
+
capabilities: {
|
|
57
|
+
...base.ai?.capabilities,
|
|
58
|
+
...override.ai?.capabilities
|
|
59
|
+
}
|
|
60
|
+
} : (override.ai || base.ai),
|
|
61
|
+
paths: {
|
|
62
|
+
...base.paths,
|
|
63
|
+
...override.paths
|
|
64
|
+
},
|
|
65
|
+
development: {
|
|
66
|
+
...base.development,
|
|
67
|
+
...override.development
|
|
68
|
+
},
|
|
69
|
+
security: base.security && override.security ? {
|
|
70
|
+
...base.security,
|
|
71
|
+
...override.security,
|
|
72
|
+
filePermissions: {
|
|
73
|
+
...base.security?.filePermissions,
|
|
74
|
+
...override.security?.filePermissions
|
|
75
|
+
},
|
|
76
|
+
networkPermissions: {
|
|
77
|
+
...base.security?.networkPermissions,
|
|
78
|
+
...override.security?.networkPermissions
|
|
79
|
+
}
|
|
80
|
+
} : (override.security || base.security),
|
|
81
|
+
integrations: {
|
|
82
|
+
...base.integrations,
|
|
83
|
+
...override.integrations
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Generate a unique workspace ID
|
|
89
|
+
*/
|
|
90
|
+
export function generateWorkspaceId() {
|
|
91
|
+
return `ws_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Find available port for a service
|
|
95
|
+
*/
|
|
96
|
+
export function findAvailablePort(services, preferredPort, serviceType = 'backend') {
|
|
97
|
+
const usedPorts = new Set(Object.values(services).map(service => service.port));
|
|
98
|
+
// Try preferred port first
|
|
99
|
+
if (preferredPort && !usedPorts.has(preferredPort)) {
|
|
100
|
+
return preferredPort;
|
|
101
|
+
}
|
|
102
|
+
// Try common ports for the service type
|
|
103
|
+
const commonPorts = COMMON_SERVICE_PORTS.development[serviceType] || [];
|
|
104
|
+
for (const port of commonPorts) {
|
|
105
|
+
if (!usedPorts.has(port)) {
|
|
106
|
+
return port;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Fall back to finding any available port in common ranges
|
|
110
|
+
const portRanges = [
|
|
111
|
+
{ start: 3000, end: 3100 },
|
|
112
|
+
{ start: 4000, end: 4100 },
|
|
113
|
+
{ start: 5000, end: 5100 },
|
|
114
|
+
{ start: 8000, end: 8100 }
|
|
115
|
+
];
|
|
116
|
+
for (const range of portRanges) {
|
|
117
|
+
for (let port = range.start; port <= range.end; port++) {
|
|
118
|
+
if (!usedPorts.has(port)) {
|
|
119
|
+
return port;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
throw new Error('No available ports found');
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Resolve service dependencies in topological order
|
|
127
|
+
*/
|
|
128
|
+
export function resolveServiceDependencies(services) {
|
|
129
|
+
const resolved = [];
|
|
130
|
+
const visited = new Set();
|
|
131
|
+
const visiting = new Set();
|
|
132
|
+
const visit = (serviceId) => {
|
|
133
|
+
if (visiting.has(serviceId)) {
|
|
134
|
+
throw new Error(`Circular dependency detected involving service: ${serviceId}`);
|
|
135
|
+
}
|
|
136
|
+
if (visited.has(serviceId)) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
visiting.add(serviceId);
|
|
140
|
+
const service = services[serviceId];
|
|
141
|
+
if (service?.dependencies) {
|
|
142
|
+
for (const dep of service.dependencies) {
|
|
143
|
+
if (dep.type === 'required' && services[dep.service]) {
|
|
144
|
+
visit(dep.service);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
visiting.delete(serviceId);
|
|
149
|
+
visited.add(serviceId);
|
|
150
|
+
resolved.push(serviceId);
|
|
151
|
+
};
|
|
152
|
+
for (const serviceId of Object.keys(services)) {
|
|
153
|
+
if (!visited.has(serviceId)) {
|
|
154
|
+
visit(serviceId);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return resolved;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Get service startup order based on dependencies
|
|
161
|
+
*/
|
|
162
|
+
export function getServiceStartupOrder(services) {
|
|
163
|
+
const levels = new Map();
|
|
164
|
+
const visited = new Set();
|
|
165
|
+
const calculateLevel = (serviceId) => {
|
|
166
|
+
if (levels.has(serviceId)) {
|
|
167
|
+
return levels.get(serviceId);
|
|
168
|
+
}
|
|
169
|
+
if (visited.has(serviceId)) {
|
|
170
|
+
throw new Error(`Circular dependency detected involving service: ${serviceId}`);
|
|
171
|
+
}
|
|
172
|
+
visited.add(serviceId);
|
|
173
|
+
const service = services[serviceId];
|
|
174
|
+
let maxDepLevel = 0;
|
|
175
|
+
if (service?.dependencies) {
|
|
176
|
+
for (const dep of service.dependencies) {
|
|
177
|
+
if (dep.type === 'required' && services[dep.service]) {
|
|
178
|
+
const depLevel = calculateLevel(dep.service);
|
|
179
|
+
maxDepLevel = Math.max(maxDepLevel, depLevel + 1);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
levels.set(serviceId, maxDepLevel);
|
|
184
|
+
visited.delete(serviceId);
|
|
185
|
+
return maxDepLevel;
|
|
186
|
+
};
|
|
187
|
+
for (const serviceId of Object.keys(services)) {
|
|
188
|
+
calculateLevel(serviceId);
|
|
189
|
+
}
|
|
190
|
+
return Array.from(levels.entries())
|
|
191
|
+
.map(([service, level]) => ({ service, level }))
|
|
192
|
+
.sort((a, b) => a.level - b.level);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Validate service dependencies
|
|
196
|
+
*/
|
|
197
|
+
export function validateServiceDependencies(services) {
|
|
198
|
+
const issues = [];
|
|
199
|
+
for (const [serviceId, service] of Object.entries(services)) {
|
|
200
|
+
if (service.dependencies) {
|
|
201
|
+
for (const dep of service.dependencies) {
|
|
202
|
+
// Check if dependency exists
|
|
203
|
+
if (!services[dep.service]) {
|
|
204
|
+
issues.push({
|
|
205
|
+
service: serviceId,
|
|
206
|
+
dependency: dep.service,
|
|
207
|
+
issue: 'Dependency service not found'
|
|
208
|
+
});
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
// Check for self-dependency
|
|
212
|
+
if (dep.service === serviceId) {
|
|
213
|
+
issues.push({
|
|
214
|
+
service: serviceId,
|
|
215
|
+
dependency: dep.service,
|
|
216
|
+
issue: 'Service cannot depend on itself'
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
// Version compatibility check (if versions are specified)
|
|
220
|
+
if (dep.version && services[dep.service].version) {
|
|
221
|
+
if (!isVersionCompatible(services[dep.service].version, dep.version)) {
|
|
222
|
+
issues.push({
|
|
223
|
+
service: serviceId,
|
|
224
|
+
dependency: dep.service,
|
|
225
|
+
issue: `Version incompatibility: requires ${dep.version}, found ${services[dep.service].version}`
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return issues;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Check if two versions are compatible (simplified semver check)
|
|
236
|
+
*/
|
|
237
|
+
export function isVersionCompatible(available, required) {
|
|
238
|
+
// Simple version comparison - in practice, use a proper semver library
|
|
239
|
+
const parseVersion = (v) => v.split('.').map(Number);
|
|
240
|
+
try {
|
|
241
|
+
const availableVer = parseVersion(available);
|
|
242
|
+
const requiredVer = parseVersion(required);
|
|
243
|
+
// Major version must match
|
|
244
|
+
if (availableVer[0] !== requiredVer[0]) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
// Minor version must be >= required
|
|
248
|
+
if (availableVer[1] < requiredVer[1]) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
// Patch version must be >= required if minor versions match
|
|
252
|
+
if (availableVer[1] === requiredVer[1] && availableVer[2] < requiredVer[2]) {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
// If version parsing fails, assume compatible
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Generate service health check URLs
|
|
264
|
+
*/
|
|
265
|
+
export function generateHealthCheckUrls(services) {
|
|
266
|
+
const healthChecks = {};
|
|
267
|
+
for (const [serviceId, service] of Object.entries(services)) {
|
|
268
|
+
if (service.healthCheck) {
|
|
269
|
+
healthChecks[serviceId] = service.healthCheck;
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
// Generate default health check URL
|
|
273
|
+
const baseUrl = service.url.replace(/\/$/, '');
|
|
274
|
+
healthChecks[serviceId] = `${baseUrl}/health`;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return healthChecks;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Filter services by technology
|
|
281
|
+
*/
|
|
282
|
+
export function filterServicesByTechnology(services, technology) {
|
|
283
|
+
return Object.fromEntries(Object.entries(services).filter(([_, service]) => service.technology === technology));
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Filter services by environment
|
|
287
|
+
*/
|
|
288
|
+
export function filterServicesByEnvironment(services, environment) {
|
|
289
|
+
return Object.fromEntries(Object.entries(services).filter(([_, service]) => service.environment === environment));
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Get workspace summary
|
|
293
|
+
*/
|
|
294
|
+
export function getWorkspaceSummary(config) {
|
|
295
|
+
const services = Object.values(config.services);
|
|
296
|
+
const servicesByTechnology = services.reduce((acc, service) => {
|
|
297
|
+
acc[service.technology] = (acc[service.technology] || 0) + 1;
|
|
298
|
+
return acc;
|
|
299
|
+
}, {});
|
|
300
|
+
const servicesByEnvironment = services.reduce((acc, service) => {
|
|
301
|
+
acc[service.environment] = (acc[service.environment] || 0) + 1;
|
|
302
|
+
return acc;
|
|
303
|
+
}, {});
|
|
304
|
+
const totalDependencies = services.reduce((acc, service) => acc + (service.dependencies?.length || 0), 0);
|
|
305
|
+
return {
|
|
306
|
+
totalServices: services.length,
|
|
307
|
+
servicesByTechnology,
|
|
308
|
+
servicesByEnvironment,
|
|
309
|
+
dependencies: totalDependencies,
|
|
310
|
+
aiModels: Object.keys(config.ai.models).length,
|
|
311
|
+
pattern: config.workspace.pattern
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Convert workspace config to environment variables
|
|
316
|
+
*/
|
|
317
|
+
export function workspaceConfigToEnvVars(config, prefix = 'TASK_SHEPHERD_') {
|
|
318
|
+
const envVars = {};
|
|
319
|
+
// Workspace metadata
|
|
320
|
+
envVars[`${prefix}WORKSPACE_ID`] = config.workspace.id;
|
|
321
|
+
envVars[`${prefix}WORKSPACE_NAME`] = config.workspace.name;
|
|
322
|
+
envVars[`${prefix}WORKSPACE_PATTERN`] = config.workspace.pattern;
|
|
323
|
+
// Service URLs and ports
|
|
324
|
+
for (const [serviceId, service] of Object.entries(config.services)) {
|
|
325
|
+
const servicePrefix = `${prefix}SERVICE_${serviceId.toUpperCase()}_`;
|
|
326
|
+
envVars[`${servicePrefix}URL`] = service.url;
|
|
327
|
+
envVars[`${servicePrefix}PORT`] = service.port.toString();
|
|
328
|
+
envVars[`${servicePrefix}PROTOCOL`] = service.protocol;
|
|
329
|
+
}
|
|
330
|
+
// AI configuration
|
|
331
|
+
envVars[`${prefix}AI_DEFAULT_MODEL`] = config.ai.defaultModel;
|
|
332
|
+
envVars[`${prefix}AI_MAX_CONCURRENT`] = config.ai.capabilities.maxConcurrentOperations.toString();
|
|
333
|
+
return envVars;
|
|
334
|
+
}
|