@wundam/orchex 1.0.0-rc.1
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/LICENSE +65 -0
- package/README.md +332 -0
- package/bin/orchex.js +2 -0
- package/dist/artifacts.d.ts +132 -0
- package/dist/artifacts.js +832 -0
- package/dist/claude-executor.d.ts +31 -0
- package/dist/claude-executor.js +200 -0
- package/dist/commands.d.ts +36 -0
- package/dist/commands.js +264 -0
- package/dist/config.d.ts +100 -0
- package/dist/config.js +172 -0
- package/dist/context-builder.d.ts +46 -0
- package/dist/context-builder.js +506 -0
- package/dist/cost.d.ts +29 -0
- package/dist/cost.js +60 -0
- package/dist/execution-broadcaster.d.ts +18 -0
- package/dist/execution-broadcaster.js +17 -0
- package/dist/executors/base.d.ts +99 -0
- package/dist/executors/base.js +206 -0
- package/dist/executors/circuit-breaker.d.ts +36 -0
- package/dist/executors/circuit-breaker.js +109 -0
- package/dist/executors/deepseek-executor.d.ts +22 -0
- package/dist/executors/deepseek-executor.js +145 -0
- package/dist/executors/gemini-executor.d.ts +20 -0
- package/dist/executors/gemini-executor.js +176 -0
- package/dist/executors/index.d.ts +81 -0
- package/dist/executors/index.js +193 -0
- package/dist/executors/ollama-executor.d.ts +25 -0
- package/dist/executors/ollama-executor.js +184 -0
- package/dist/executors/openai-executor.d.ts +22 -0
- package/dist/executors/openai-executor.js +142 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +115 -0
- package/dist/intelligence/anti-pattern-detector.d.ts +117 -0
- package/dist/intelligence/anti-pattern-detector.js +327 -0
- package/dist/intelligence/budget-enforcer.d.ts +119 -0
- package/dist/intelligence/budget-enforcer.js +226 -0
- package/dist/intelligence/context-optimizer.d.ts +111 -0
- package/dist/intelligence/context-optimizer.js +282 -0
- package/dist/intelligence/cost-tracker.d.ts +114 -0
- package/dist/intelligence/cost-tracker.js +183 -0
- package/dist/intelligence/deliverable-extractor.d.ts +134 -0
- package/dist/intelligence/deliverable-extractor.js +909 -0
- package/dist/intelligence/dependency-inferrer.d.ts +87 -0
- package/dist/intelligence/dependency-inferrer.js +403 -0
- package/dist/intelligence/diagnostics.d.ts +25 -0
- package/dist/intelligence/diagnostics.js +36 -0
- package/dist/intelligence/error-analyzer.d.ts +7 -0
- package/dist/intelligence/error-analyzer.js +76 -0
- package/dist/intelligence/file-chunker.d.ts +15 -0
- package/dist/intelligence/file-chunker.js +64 -0
- package/dist/intelligence/fix-stream-manager.d.ts +59 -0
- package/dist/intelligence/fix-stream-manager.js +212 -0
- package/dist/intelligence/heuristics.d.ts +23 -0
- package/dist/intelligence/heuristics.js +124 -0
- package/dist/intelligence/learning-engine.d.ts +157 -0
- package/dist/intelligence/learning-engine.js +433 -0
- package/dist/intelligence/learning-feedback.d.ts +96 -0
- package/dist/intelligence/learning-feedback.js +202 -0
- package/dist/intelligence/pattern-analyzer.d.ts +35 -0
- package/dist/intelligence/pattern-analyzer.js +189 -0
- package/dist/intelligence/plan-parser.d.ts +124 -0
- package/dist/intelligence/plan-parser.js +498 -0
- package/dist/intelligence/planner.d.ts +29 -0
- package/dist/intelligence/planner.js +86 -0
- package/dist/intelligence/self-healer.d.ts +16 -0
- package/dist/intelligence/self-healer.js +84 -0
- package/dist/intelligence/slicing-metrics.d.ts +62 -0
- package/dist/intelligence/slicing-metrics.js +202 -0
- package/dist/intelligence/slicing-templates.d.ts +81 -0
- package/dist/intelligence/slicing-templates.js +420 -0
- package/dist/intelligence/split-suggester.d.ts +69 -0
- package/dist/intelligence/split-suggester.js +176 -0
- package/dist/intelligence/stream-generator.d.ts +90 -0
- package/dist/intelligence/stream-generator.js +452 -0
- package/dist/logger.d.ts +34 -0
- package/dist/logger.js +83 -0
- package/dist/logging.d.ts +5 -0
- package/dist/logging.js +38 -0
- package/dist/manifest.d.ts +56 -0
- package/dist/manifest.js +254 -0
- package/dist/metrics.d.ts +35 -0
- package/dist/metrics.js +75 -0
- package/dist/orchestrator.d.ts +35 -0
- package/dist/orchestrator.js +723 -0
- package/dist/ownership.d.ts +44 -0
- package/dist/ownership.js +250 -0
- package/dist/semaphore.d.ts +12 -0
- package/dist/semaphore.js +34 -0
- package/dist/telemetry/telemetry-types.d.ts +85 -0
- package/dist/telemetry/telemetry-types.js +1 -0
- package/dist/tier-gating.d.ts +24 -0
- package/dist/tier-gating.js +88 -0
- package/dist/tiers.d.ts +92 -0
- package/dist/tiers.js +108 -0
- package/dist/tools.d.ts +18 -0
- package/dist/tools.js +1363 -0
- package/dist/types.d.ts +740 -0
- package/dist/types.js +160 -0
- package/dist/utils/ownership-validator.d.ts +6 -0
- package/dist/utils/ownership-validator.js +21 -0
- package/dist/waves.d.ts +21 -0
- package/dist/waves.js +146 -0
- package/package.json +120 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { analyzeError } from './error-analyzer.js';
|
|
2
|
+
const MAX_ATTEMPTS = 3;
|
|
3
|
+
/**
|
|
4
|
+
* Count total attempts in the fix chain by traversing parentStreamId.
|
|
5
|
+
*/
|
|
6
|
+
function countChainAttempts(manifest, streamId) {
|
|
7
|
+
let count = 0;
|
|
8
|
+
let currentId = streamId;
|
|
9
|
+
while (currentId) {
|
|
10
|
+
const current = manifest.streams[currentId];
|
|
11
|
+
if (!current)
|
|
12
|
+
break; // Orphaned fix stream, stop traversing
|
|
13
|
+
count += current.attempts ?? 0;
|
|
14
|
+
// Move to parent
|
|
15
|
+
currentId = current.parentStreamId;
|
|
16
|
+
}
|
|
17
|
+
return count;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Generate a fix stream for a failed stream.
|
|
21
|
+
* Returns null if the error is non-retryable or max attempts exceeded.
|
|
22
|
+
*
|
|
23
|
+
* Tracks fix chain depth via parentStreamId to prevent infinite fix-fix-fix chains.
|
|
24
|
+
*/
|
|
25
|
+
export function generateFixStream(manifest, failedStreamId) {
|
|
26
|
+
const stream = manifest.streams[failedStreamId];
|
|
27
|
+
if (!stream)
|
|
28
|
+
return null;
|
|
29
|
+
// Skip fix generation for setup failures (never entered in_progress).
|
|
30
|
+
// Setup failures have error messages prefixed with "Setup failed:" by the orchestrator.
|
|
31
|
+
if (stream.status === 'failed' && stream.error?.startsWith('Setup failed:')) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const errorString = stream.error ?? '';
|
|
35
|
+
const analysis = analyzeError(errorString);
|
|
36
|
+
if (!analysis.retryable)
|
|
37
|
+
return null;
|
|
38
|
+
// Count attempts across the entire fix chain
|
|
39
|
+
const totalChainAttempts = countChainAttempts(manifest, failedStreamId);
|
|
40
|
+
if (totalChainAttempts >= MAX_ATTEMPTS)
|
|
41
|
+
return null;
|
|
42
|
+
const attempts = stream.attempts ?? 0;
|
|
43
|
+
const fixNumber = attempts + 1;
|
|
44
|
+
const fixStreamId = `${failedStreamId}-fix-${fixNumber}`;
|
|
45
|
+
// Chain the fix stream to the immediate parent (the failed stream just prior)
|
|
46
|
+
const parentStreamId = failedStreamId;
|
|
47
|
+
const augmentedPlan = [
|
|
48
|
+
`## Fix Attempt #${fixNumber} for "${stream.name}"`,
|
|
49
|
+
'',
|
|
50
|
+
'### Original Plan',
|
|
51
|
+
stream.plan ?? '(no plan)',
|
|
52
|
+
'',
|
|
53
|
+
'### Error That Occurred',
|
|
54
|
+
'```',
|
|
55
|
+
errorString,
|
|
56
|
+
'```',
|
|
57
|
+
'',
|
|
58
|
+
`### Error Category: ${analysis.category}`,
|
|
59
|
+
'',
|
|
60
|
+
`### Suggestion: ${analysis.suggestion}`,
|
|
61
|
+
'',
|
|
62
|
+
'### Instructions',
|
|
63
|
+
`This is a retry of the failed stream "${failedStreamId}".`,
|
|
64
|
+
'Fix the issue described above. The original files are in your owns list.',
|
|
65
|
+
'Make sure to address the specific error before implementing the rest of the plan.',
|
|
66
|
+
].join('\n');
|
|
67
|
+
const fixStream = {
|
|
68
|
+
name: `${stream.name} (Fix #${fixNumber})`,
|
|
69
|
+
deps: stream.deps ?? [],
|
|
70
|
+
owns: stream.owns ?? [],
|
|
71
|
+
reads: stream.reads ?? [],
|
|
72
|
+
plan: augmentedPlan,
|
|
73
|
+
setup: stream.setup ?? [],
|
|
74
|
+
verify: stream.verify ?? [],
|
|
75
|
+
status: 'pending',
|
|
76
|
+
attempts: 0,
|
|
77
|
+
parentStreamId: parentStreamId, // Immediate parent is always failedStreamId
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
fixStreamId,
|
|
81
|
+
fixStream,
|
|
82
|
+
analysis: { category: analysis.category, suggestion: analysis.suggestion },
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slicing metrics for stream execution analysis.
|
|
3
|
+
* Provides category-specific timeout recommendations and execution insights.
|
|
4
|
+
*
|
|
5
|
+
* NOTE: StreamCategory and categorizeStream are imported from learning-engine.ts
|
|
6
|
+
* to maintain a single source of truth for stream categorization.
|
|
7
|
+
*/
|
|
8
|
+
import type { TelemetryEvent } from '../telemetry/telemetry-types.js';
|
|
9
|
+
import type { StreamResult } from '../types.js';
|
|
10
|
+
import { type StreamCategory, categorizeStream as categorizeStreamFromLearningEngine } from './learning-engine.js';
|
|
11
|
+
export type { StreamCategory };
|
|
12
|
+
export { categorizeStreamFromLearningEngine as categorizeStream };
|
|
13
|
+
/**
|
|
14
|
+
* Aggregated metrics for a specific stream category.
|
|
15
|
+
*/
|
|
16
|
+
export interface CategoryMetrics {
|
|
17
|
+
category: StreamCategory;
|
|
18
|
+
totalStreams: number;
|
|
19
|
+
successfulStreams: number;
|
|
20
|
+
failedStreams: number;
|
|
21
|
+
timeoutStreams: number;
|
|
22
|
+
successRate: number;
|
|
23
|
+
timeoutRate: number;
|
|
24
|
+
avgExecutionMs: number;
|
|
25
|
+
p50ExecutionMs: number;
|
|
26
|
+
p95ExecutionMs: number;
|
|
27
|
+
maxExecutionMs: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Insight or warning about stream execution patterns.
|
|
31
|
+
*/
|
|
32
|
+
export interface SlicingInsight {
|
|
33
|
+
category: StreamCategory;
|
|
34
|
+
type: 'warning' | 'info';
|
|
35
|
+
message: string;
|
|
36
|
+
metric: string;
|
|
37
|
+
value: number;
|
|
38
|
+
threshold: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Aggregate execution metrics by stream category.
|
|
42
|
+
* Calculates success rates, timeout rates, and execution time percentiles.
|
|
43
|
+
*/
|
|
44
|
+
export declare function aggregateMetricsByCategory(events: TelemetryEvent[], streamResults?: StreamResult[]): Map<StreamCategory, CategoryMetrics>;
|
|
45
|
+
/**
|
|
46
|
+
* Generate insights and warnings based on category metrics.
|
|
47
|
+
* Identifies categories with low success rates or high timeout rates.
|
|
48
|
+
*/
|
|
49
|
+
export declare function generateSlicingInsights(categoryMetrics: Map<StreamCategory, CategoryMetrics>): SlicingInsight[];
|
|
50
|
+
/**
|
|
51
|
+
* Get recommended timeout value for a stream category.
|
|
52
|
+
* Returns timeout in milliseconds with safety margin included.
|
|
53
|
+
*/
|
|
54
|
+
export declare function getRecommendedTimeout(category: StreamCategory): number;
|
|
55
|
+
/**
|
|
56
|
+
* Get recommended timeout for a specific stream based on its characteristics.
|
|
57
|
+
*/
|
|
58
|
+
export declare function getStreamTimeout(streamName: string, streamPlan?: string, customTimeout?: number): number;
|
|
59
|
+
/**
|
|
60
|
+
* Format category metrics into a human-readable report.
|
|
61
|
+
*/
|
|
62
|
+
export declare function formatCategoryReport(categoryMetrics: Map<StreamCategory, CategoryMetrics>): string;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slicing metrics for stream execution analysis.
|
|
3
|
+
* Provides category-specific timeout recommendations and execution insights.
|
|
4
|
+
*
|
|
5
|
+
* NOTE: StreamCategory and categorizeStream are imported from learning-engine.ts
|
|
6
|
+
* to maintain a single source of truth for stream categorization.
|
|
7
|
+
*/
|
|
8
|
+
import { categorizeStream as categorizeStreamFromLearningEngine, } from './learning-engine.js';
|
|
9
|
+
export { categorizeStreamFromLearningEngine as categorizeStream };
|
|
10
|
+
/**
|
|
11
|
+
* Recommended timeout values by category.
|
|
12
|
+
* Based on p95 execution times with safety margin.
|
|
13
|
+
*/
|
|
14
|
+
const RECOMMENDED_TIMEOUTS = {
|
|
15
|
+
code: 120000, // 2 minutes - typical code generation
|
|
16
|
+
docs: 60000, // 1 minute - documentation is usually faster
|
|
17
|
+
tutorial: 90000, // 1.5 minutes - tutorials with examples
|
|
18
|
+
'integration-guide': 90000, // 1.5 minutes - similar to tutorials
|
|
19
|
+
'api-reference': 60000, // 1 minute - structured API docs
|
|
20
|
+
test: 120000, // 2 minutes - test generation can be complex
|
|
21
|
+
migration: 180000, // 3 minutes - migrations are complex
|
|
22
|
+
other: 120000, // 2 minutes - default for uncategorized
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Thresholds for generating warnings.
|
|
26
|
+
*/
|
|
27
|
+
const WARNING_THRESHOLDS = {
|
|
28
|
+
lowSuccessRate: 0.8, // Warn if success rate < 80%
|
|
29
|
+
highTimeoutRate: 0.2, // Warn if timeout rate > 20%
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Aggregate execution metrics by stream category.
|
|
33
|
+
* Calculates success rates, timeout rates, and execution time percentiles.
|
|
34
|
+
*/
|
|
35
|
+
export function aggregateMetricsByCategory(events, streamResults = []) {
|
|
36
|
+
const categoryData = new Map();
|
|
37
|
+
// Initialize all categories
|
|
38
|
+
const categories = [
|
|
39
|
+
'code',
|
|
40
|
+
'docs',
|
|
41
|
+
'tutorial',
|
|
42
|
+
'integration-guide',
|
|
43
|
+
'api-reference',
|
|
44
|
+
'test',
|
|
45
|
+
'migration',
|
|
46
|
+
'other',
|
|
47
|
+
];
|
|
48
|
+
for (const cat of categories) {
|
|
49
|
+
categoryData.set(cat, {
|
|
50
|
+
total: 0,
|
|
51
|
+
success: 0,
|
|
52
|
+
failed: 0,
|
|
53
|
+
timeout: 0,
|
|
54
|
+
durations: [],
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
// Process telemetry events
|
|
58
|
+
const streamEvents = events.filter(e => e.eventType === 'stream_complete' || e.eventType === 'stream_failed');
|
|
59
|
+
for (const event of streamEvents) {
|
|
60
|
+
// Extract stream name from event (would need to be added to TelemetryEvent)
|
|
61
|
+
// For now, we'll primarily use streamResults which have names
|
|
62
|
+
}
|
|
63
|
+
// Process stream results (primary source)
|
|
64
|
+
for (const result of streamResults) {
|
|
65
|
+
const category = categorizeStreamFromLearningEngine(result.name, result.summary);
|
|
66
|
+
const data = categoryData.get(category);
|
|
67
|
+
data.total++;
|
|
68
|
+
if (result.status === 'complete') {
|
|
69
|
+
data.success++;
|
|
70
|
+
}
|
|
71
|
+
else if (result.status === 'failed') {
|
|
72
|
+
data.failed++;
|
|
73
|
+
// Check if it's a timeout error
|
|
74
|
+
if (result.error?.toLowerCase().includes('timeout')) {
|
|
75
|
+
data.timeout++;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Record execution time if available
|
|
79
|
+
if (result.executionTimeMs !== undefined) {
|
|
80
|
+
data.durations.push(result.executionTimeMs);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Calculate metrics for each category
|
|
84
|
+
const metrics = new Map();
|
|
85
|
+
for (const [category, data] of categoryData) {
|
|
86
|
+
const sortedDurations = data.durations.sort((a, b) => a - b);
|
|
87
|
+
const categoryMetrics = {
|
|
88
|
+
category,
|
|
89
|
+
totalStreams: data.total,
|
|
90
|
+
successfulStreams: data.success,
|
|
91
|
+
failedStreams: data.failed,
|
|
92
|
+
timeoutStreams: data.timeout,
|
|
93
|
+
successRate: data.total > 0 ? data.success / data.total : 0,
|
|
94
|
+
timeoutRate: data.total > 0 ? data.timeout / data.total : 0,
|
|
95
|
+
avgExecutionMs: sortedDurations.length > 0
|
|
96
|
+
? Math.round(sortedDurations.reduce((a, b) => a + b, 0) / sortedDurations.length)
|
|
97
|
+
: 0,
|
|
98
|
+
p50ExecutionMs: sortedDurations.length > 0
|
|
99
|
+
? sortedDurations[Math.floor(sortedDurations.length * 0.5)]
|
|
100
|
+
: 0,
|
|
101
|
+
p95ExecutionMs: sortedDurations.length > 0
|
|
102
|
+
? sortedDurations[Math.floor(sortedDurations.length * 0.95)]
|
|
103
|
+
: 0,
|
|
104
|
+
maxExecutionMs: sortedDurations.length > 0
|
|
105
|
+
? sortedDurations[sortedDurations.length - 1]
|
|
106
|
+
: 0,
|
|
107
|
+
};
|
|
108
|
+
metrics.set(category, categoryMetrics);
|
|
109
|
+
}
|
|
110
|
+
return metrics;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Generate insights and warnings based on category metrics.
|
|
114
|
+
* Identifies categories with low success rates or high timeout rates.
|
|
115
|
+
*/
|
|
116
|
+
export function generateSlicingInsights(categoryMetrics) {
|
|
117
|
+
const insights = [];
|
|
118
|
+
for (const [category, metrics] of categoryMetrics) {
|
|
119
|
+
// Skip categories with no data
|
|
120
|
+
if (metrics.totalStreams === 0) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
// Check for low success rate
|
|
124
|
+
if (metrics.successRate < WARNING_THRESHOLDS.lowSuccessRate) {
|
|
125
|
+
insights.push({
|
|
126
|
+
category,
|
|
127
|
+
type: 'warning',
|
|
128
|
+
message: `Low success rate for ${category} streams: ${(metrics.successRate * 100).toFixed(1)}%`,
|
|
129
|
+
metric: 'successRate',
|
|
130
|
+
value: metrics.successRate,
|
|
131
|
+
threshold: WARNING_THRESHOLDS.lowSuccessRate,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// Check for high timeout rate
|
|
135
|
+
if (metrics.timeoutRate > WARNING_THRESHOLDS.highTimeoutRate) {
|
|
136
|
+
insights.push({
|
|
137
|
+
category,
|
|
138
|
+
type: 'warning',
|
|
139
|
+
message: `High timeout rate for ${category} streams: ${(metrics.timeoutRate * 100).toFixed(1)}%. Consider increasing timeout to ${getRecommendedTimeout(category)}ms`,
|
|
140
|
+
metric: 'timeoutRate',
|
|
141
|
+
value: metrics.timeoutRate,
|
|
142
|
+
threshold: WARNING_THRESHOLDS.highTimeoutRate,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
// Informational insight if p95 is approaching recommended timeout
|
|
146
|
+
const recommendedTimeout = getRecommendedTimeout(category);
|
|
147
|
+
if (metrics.p95ExecutionMs > 0 &&
|
|
148
|
+
metrics.p95ExecutionMs > recommendedTimeout * 0.8) {
|
|
149
|
+
insights.push({
|
|
150
|
+
category,
|
|
151
|
+
type: 'info',
|
|
152
|
+
message: `${category} streams approaching timeout threshold. P95: ${metrics.p95ExecutionMs}ms, recommended: ${recommendedTimeout}ms`,
|
|
153
|
+
metric: 'p95ExecutionMs',
|
|
154
|
+
value: metrics.p95ExecutionMs,
|
|
155
|
+
threshold: recommendedTimeout,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return insights;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get recommended timeout value for a stream category.
|
|
163
|
+
* Returns timeout in milliseconds with safety margin included.
|
|
164
|
+
*/
|
|
165
|
+
export function getRecommendedTimeout(category) {
|
|
166
|
+
return RECOMMENDED_TIMEOUTS[category];
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Get recommended timeout for a specific stream based on its characteristics.
|
|
170
|
+
*/
|
|
171
|
+
export function getStreamTimeout(streamName, streamPlan, customTimeout) {
|
|
172
|
+
// Use custom timeout if provided
|
|
173
|
+
if (customTimeout !== undefined && customTimeout > 0) {
|
|
174
|
+
return customTimeout;
|
|
175
|
+
}
|
|
176
|
+
// Otherwise, use category-based recommendation
|
|
177
|
+
const category = categorizeStreamFromLearningEngine(streamName, streamPlan);
|
|
178
|
+
return getRecommendedTimeout(category);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Format category metrics into a human-readable report.
|
|
182
|
+
*/
|
|
183
|
+
export function formatCategoryReport(categoryMetrics) {
|
|
184
|
+
const lines = ['\n=== Stream Execution Metrics by Category ===\n'];
|
|
185
|
+
for (const [category, metrics] of categoryMetrics) {
|
|
186
|
+
if (metrics.totalStreams === 0)
|
|
187
|
+
continue;
|
|
188
|
+
lines.push(`${category.toUpperCase()}:`);
|
|
189
|
+
lines.push(` Total: ${metrics.totalStreams}`);
|
|
190
|
+
lines.push(` Success Rate: ${(metrics.successRate * 100).toFixed(1)}% (${metrics.successfulStreams}/${metrics.totalStreams})`);
|
|
191
|
+
if (metrics.timeoutStreams > 0) {
|
|
192
|
+
lines.push(` Timeout Rate: ${(metrics.timeoutRate * 100).toFixed(1)}% (${metrics.timeoutStreams}/${metrics.totalStreams})`);
|
|
193
|
+
}
|
|
194
|
+
if (metrics.avgExecutionMs > 0) {
|
|
195
|
+
lines.push(` Avg Execution: ${(metrics.avgExecutionMs / 1000).toFixed(1)}s`);
|
|
196
|
+
lines.push(` P95 Execution: ${(metrics.p95ExecutionMs / 1000).toFixed(1)}s`);
|
|
197
|
+
lines.push(` Recommended Timeout: ${(getRecommendedTimeout(category) / 1000).toFixed(0)}s`);
|
|
198
|
+
}
|
|
199
|
+
lines.push('');
|
|
200
|
+
}
|
|
201
|
+
return lines.join('\n');
|
|
202
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { StreamDefinition, StreamDefinitionInput } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A template for common stream patterns.
|
|
4
|
+
* Templates help guide automatic stream generation for typical tasks.
|
|
5
|
+
*/
|
|
6
|
+
export interface SlicingTemplate {
|
|
7
|
+
/** Template identifier */
|
|
8
|
+
id: string;
|
|
9
|
+
/** Human-readable name */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Description of when to use this template */
|
|
12
|
+
description: string;
|
|
13
|
+
/** Keywords that suggest this template applies */
|
|
14
|
+
keywords: string[];
|
|
15
|
+
/** Pattern indicators (e.g., "multiple files in same directory") */
|
|
16
|
+
patterns: string[];
|
|
17
|
+
/** Suggested stream structure */
|
|
18
|
+
streamStructure: TemplateStreamStructure[];
|
|
19
|
+
/** Guidelines for applying the template */
|
|
20
|
+
guidelines: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Structure for a stream in a template.
|
|
24
|
+
*/
|
|
25
|
+
export interface TemplateStreamStructure {
|
|
26
|
+
/** Stream name pattern (e.g., "setup-{component}") */
|
|
27
|
+
namePattern: string;
|
|
28
|
+
/** Description of what this stream does */
|
|
29
|
+
purpose: string;
|
|
30
|
+
/** Dependencies on other streams in the template */
|
|
31
|
+
dependsOn: string[];
|
|
32
|
+
/** Typical file ownership patterns */
|
|
33
|
+
ownsPatterns: string[];
|
|
34
|
+
/** Typical file reading patterns */
|
|
35
|
+
readsPatterns: string[];
|
|
36
|
+
/** Suggested plan outline */
|
|
37
|
+
planOutline: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Suggestion for splitting a stream into smaller streams.
|
|
41
|
+
*/
|
|
42
|
+
export interface SplitSuggestion {
|
|
43
|
+
/** Original stream name */
|
|
44
|
+
originalStream: string;
|
|
45
|
+
/** Reason for suggesting a split */
|
|
46
|
+
reason: string;
|
|
47
|
+
/** Matched template (if any) */
|
|
48
|
+
template?: SlicingTemplate;
|
|
49
|
+
/** Suggested new streams */
|
|
50
|
+
suggestedStreams: StreamDefinitionInput[];
|
|
51
|
+
/** Additional guidance */
|
|
52
|
+
guidance: string[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Find the best matching template for a stream description.
|
|
56
|
+
* Returns null if no good match is found.
|
|
57
|
+
*/
|
|
58
|
+
export declare function findMatchingTemplate(description: string): SlicingTemplate | null;
|
|
59
|
+
/**
|
|
60
|
+
* Apply a template to generate stream definitions.
|
|
61
|
+
* Returns suggested streams based on the template structure.
|
|
62
|
+
*/
|
|
63
|
+
export declare function applyTemplate(template: SlicingTemplate, context: {
|
|
64
|
+
featureName: string;
|
|
65
|
+
components?: string[];
|
|
66
|
+
topics?: string[];
|
|
67
|
+
modules?: string[];
|
|
68
|
+
}): StreamDefinitionInput[];
|
|
69
|
+
/**
|
|
70
|
+
* Analyze a stream and suggest how to split it if needed.
|
|
71
|
+
* Returns null if the stream seems appropriately sized.
|
|
72
|
+
*/
|
|
73
|
+
export declare function suggestSplit(stream: StreamDefinition | StreamDefinitionInput): SplitSuggestion | null;
|
|
74
|
+
/**
|
|
75
|
+
* Get all available templates.
|
|
76
|
+
*/
|
|
77
|
+
export declare function getAllTemplates(): SlicingTemplate[];
|
|
78
|
+
/**
|
|
79
|
+
* Get a specific template by ID.
|
|
80
|
+
*/
|
|
81
|
+
export declare function getTemplate(id: string): SlicingTemplate | null;
|