@substrate-ai/sdlc 0.19.54
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/events.d.ts +336 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +11 -0
- package/dist/events.js.map +1 -0
- package/dist/gating/conflict-detector.d.ts +59 -0
- package/dist/gating/conflict-detector.d.ts.map +1 -0
- package/dist/gating/conflict-detector.js +101 -0
- package/dist/gating/conflict-detector.js.map +1 -0
- package/dist/gating/dispatch-gate.d.ts +42 -0
- package/dist/gating/dispatch-gate.d.ts.map +1 -0
- package/dist/gating/dispatch-gate.js +197 -0
- package/dist/gating/dispatch-gate.js.map +1 -0
- package/dist/gating/index.d.ts +9 -0
- package/dist/gating/index.d.ts.map +1 -0
- package/dist/gating/index.js +8 -0
- package/dist/gating/index.js.map +1 -0
- package/dist/gating/types.d.ts +98 -0
- package/dist/gating/types.d.ts.map +1 -0
- package/dist/gating/types.js +8 -0
- package/dist/gating/types.js.map +1 -0
- package/dist/handlers/event-bridge.d.ts +56 -0
- package/dist/handlers/event-bridge.d.ts.map +1 -0
- package/dist/handlers/event-bridge.js +140 -0
- package/dist/handlers/event-bridge.js.map +1 -0
- package/dist/handlers/index.d.ts +15 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +14 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/sdlc-code-review-handler.d.ts +119 -0
- package/dist/handlers/sdlc-code-review-handler.d.ts.map +1 -0
- package/dist/handlers/sdlc-code-review-handler.js +131 -0
- package/dist/handlers/sdlc-code-review-handler.js.map +1 -0
- package/dist/handlers/sdlc-create-story-handler.d.ts +97 -0
- package/dist/handlers/sdlc-create-story-handler.d.ts.map +1 -0
- package/dist/handlers/sdlc-create-story-handler.js +91 -0
- package/dist/handlers/sdlc-create-story-handler.js.map +1 -0
- package/dist/handlers/sdlc-dev-story-handler.d.ts +121 -0
- package/dist/handlers/sdlc-dev-story-handler.d.ts.map +1 -0
- package/dist/handlers/sdlc-dev-story-handler.js +288 -0
- package/dist/handlers/sdlc-dev-story-handler.js.map +1 -0
- package/dist/handlers/sdlc-phase-handler.d.ts +32 -0
- package/dist/handlers/sdlc-phase-handler.d.ts.map +1 -0
- package/dist/handlers/sdlc-phase-handler.js +166 -0
- package/dist/handlers/sdlc-phase-handler.js.map +1 -0
- package/dist/handlers/types.d.ts +132 -0
- package/dist/handlers/types.d.ts.map +1 -0
- package/dist/handlers/types.js +10 -0
- package/dist/handlers/types.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/learning/failure-classifier.d.ts +23 -0
- package/dist/learning/failure-classifier.d.ts.map +1 -0
- package/dist/learning/failure-classifier.js +75 -0
- package/dist/learning/failure-classifier.js.map +1 -0
- package/dist/learning/finding-classifier.d.ts +25 -0
- package/dist/learning/finding-classifier.d.ts.map +1 -0
- package/dist/learning/finding-classifier.js +37 -0
- package/dist/learning/finding-classifier.js.map +1 -0
- package/dist/learning/finding-lifecycle.d.ts +69 -0
- package/dist/learning/finding-lifecycle.d.ts.map +1 -0
- package/dist/learning/finding-lifecycle.js +162 -0
- package/dist/learning/finding-lifecycle.js.map +1 -0
- package/dist/learning/finding-store.d.ts +16 -0
- package/dist/learning/finding-store.d.ts.map +1 -0
- package/dist/learning/finding-store.js +26 -0
- package/dist/learning/finding-store.js.map +1 -0
- package/dist/learning/findings-injector.d.ts +34 -0
- package/dist/learning/findings-injector.d.ts.map +1 -0
- package/dist/learning/findings-injector.js +140 -0
- package/dist/learning/findings-injector.js.map +1 -0
- package/dist/learning/index.d.ts +8 -0
- package/dist/learning/index.d.ts.map +1 -0
- package/dist/learning/index.js +10 -0
- package/dist/learning/index.js.map +1 -0
- package/dist/learning/relevance-scorer.d.ts +25 -0
- package/dist/learning/relevance-scorer.d.ts.map +1 -0
- package/dist/learning/relevance-scorer.js +49 -0
- package/dist/learning/relevance-scorer.js.map +1 -0
- package/dist/learning/types.d.ts +55 -0
- package/dist/learning/types.d.ts.map +1 -0
- package/dist/learning/types.js +36 -0
- package/dist/learning/types.js.map +1 -0
- package/dist/orchestrator/graph-orchestrator.d.ts +208 -0
- package/dist/orchestrator/graph-orchestrator.d.ts.map +1 -0
- package/dist/orchestrator/graph-orchestrator.js +213 -0
- package/dist/orchestrator/graph-orchestrator.js.map +1 -0
- package/dist/run-manifest/cli-flags.d.ts +11 -0
- package/dist/run-manifest/cli-flags.d.ts.map +1 -0
- package/dist/run-manifest/cli-flags.js +10 -0
- package/dist/run-manifest/cli-flags.js.map +1 -0
- package/dist/run-manifest/index.d.ts +10 -0
- package/dist/run-manifest/index.d.ts.map +1 -0
- package/dist/run-manifest/index.js +10 -0
- package/dist/run-manifest/index.js.map +1 -0
- package/dist/run-model/cli-flags.d.ts +27 -0
- package/dist/run-model/cli-flags.d.ts.map +1 -0
- package/dist/run-model/cli-flags.js +31 -0
- package/dist/run-model/cli-flags.js.map +1 -0
- package/dist/run-model/index.d.ts +21 -0
- package/dist/run-model/index.d.ts.map +1 -0
- package/dist/run-model/index.js +19 -0
- package/dist/run-model/index.js.map +1 -0
- package/dist/run-model/per-story-state.d.ts +62 -0
- package/dist/run-model/per-story-state.d.ts.map +1 -0
- package/dist/run-model/per-story-state.js +70 -0
- package/dist/run-model/per-story-state.js.map +1 -0
- package/dist/run-model/recovery-history.d.ts +56 -0
- package/dist/run-model/recovery-history.d.ts.map +1 -0
- package/dist/run-model/recovery-history.js +83 -0
- package/dist/run-model/recovery-history.js.map +1 -0
- package/dist/run-model/run-manifest.d.ts +146 -0
- package/dist/run-model/run-manifest.d.ts.map +1 -0
- package/dist/run-model/run-manifest.js +481 -0
- package/dist/run-model/run-manifest.js.map +1 -0
- package/dist/run-model/schemas.d.ts +117 -0
- package/dist/run-model/schemas.d.ts.map +1 -0
- package/dist/run-model/schemas.js +83 -0
- package/dist/run-model/schemas.js.map +1 -0
- package/dist/run-model/supervisor-lock.d.ts +104 -0
- package/dist/run-model/supervisor-lock.d.ts.map +1 -0
- package/dist/run-model/supervisor-lock.js +284 -0
- package/dist/run-model/supervisor-lock.js.map +1 -0
- package/dist/run-model/types.d.ts +74 -0
- package/dist/run-model/types.d.ts.map +1 -0
- package/dist/run-model/types.js +8 -0
- package/dist/run-model/types.js.map +1 -0
- package/dist/run-model/verification-result.d.ts +60 -0
- package/dist/run-model/verification-result.d.ts.map +1 -0
- package/dist/run-model/verification-result.js +55 -0
- package/dist/run-model/verification-result.js.map +1 -0
- package/dist/verification/checks/acceptance-criteria-evidence-check.d.ts +21 -0
- package/dist/verification/checks/acceptance-criteria-evidence-check.d.ts.map +1 -0
- package/dist/verification/checks/acceptance-criteria-evidence-check.js +159 -0
- package/dist/verification/checks/acceptance-criteria-evidence-check.js.map +1 -0
- package/dist/verification/checks/build-check.d.ts +52 -0
- package/dist/verification/checks/build-check.d.ts.map +1 -0
- package/dist/verification/checks/build-check.js +160 -0
- package/dist/verification/checks/build-check.js.map +1 -0
- package/dist/verification/checks/index.d.ts +15 -0
- package/dist/verification/checks/index.d.ts.map +1 -0
- package/dist/verification/checks/index.js +15 -0
- package/dist/verification/checks/index.js.map +1 -0
- package/dist/verification/checks/phantom-review-check.d.ts +29 -0
- package/dist/verification/checks/phantom-review-check.d.ts.map +1 -0
- package/dist/verification/checks/phantom-review-check.js +70 -0
- package/dist/verification/checks/phantom-review-check.js.map +1 -0
- package/dist/verification/checks/trivial-output-check.d.ts +47 -0
- package/dist/verification/checks/trivial-output-check.d.ts.map +1 -0
- package/dist/verification/checks/trivial-output-check.js +72 -0
- package/dist/verification/checks/trivial-output-check.js.map +1 -0
- package/dist/verification/index.d.ts +13 -0
- package/dist/verification/index.d.ts.map +1 -0
- package/dist/verification/index.js +13 -0
- package/dist/verification/index.js.map +1 -0
- package/dist/verification/types.d.ts +149 -0
- package/dist/verification/types.d.ts.map +1 -0
- package/dist/verification/types.js +12 -0
- package/dist/verification/types.js.map +1 -0
- package/dist/verification/verification-pipeline.d.ts +65 -0
- package/dist/verification/verification-pipeline.d.ts.map +1 -0
- package/dist/verification/verification-pipeline.js +149 -0
- package/dist/verification/verification-pipeline.js.map +1 -0
- package/graphs/sdlc-pipeline.dot +42 -0
- package/package.json +22 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DispatchGate — pre-dispatch conflict gating for story dispatch.
|
|
3
|
+
*
|
|
4
|
+
* Story 53-9: Dispatch Pre-Condition Gating
|
|
5
|
+
*
|
|
6
|
+
* Evaluates three gating conditions in order:
|
|
7
|
+
* 1. Learning pre-emption (AC6): high-confidence namespace-collision findings
|
|
8
|
+
* from the learning store that overlap with the pending story's files.
|
|
9
|
+
* 2. File-level overlap (AC2): completed-story modified files overlap with
|
|
10
|
+
* the pending story's target files (warn, no block).
|
|
11
|
+
* 3. Namespace collision (AC3): a symbol targeted by the pending story already
|
|
12
|
+
* exists in a file modified by a completed story.
|
|
13
|
+
*
|
|
14
|
+
* All DB and file I/O is wrapped in a single outer try-catch so that gate
|
|
15
|
+
* failures never block the pipeline (AC7 — graceful degradation).
|
|
16
|
+
*/
|
|
17
|
+
import { getDecisionsByCategory, LEARNING_FINDING } from '@substrate-ai/core';
|
|
18
|
+
import { FindingSchema } from '../learning/types.js';
|
|
19
|
+
import { ConflictDetector } from './conflict-detector.js';
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// DispatchGate
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
export class DispatchGate {
|
|
24
|
+
/**
|
|
25
|
+
* Evaluate all pre-dispatch gating conditions for a pending story.
|
|
26
|
+
*
|
|
27
|
+
* Entry point: called once per story before agent dispatch.
|
|
28
|
+
*
|
|
29
|
+
* Steps (in order):
|
|
30
|
+
* 1. Learning pre-emption check (AC6)
|
|
31
|
+
* 2. Per-completed-story file overlap + collision scan (AC2/AC3)
|
|
32
|
+
* 3. Return proceed if no issues found
|
|
33
|
+
*
|
|
34
|
+
* Outer try-catch ensures any unexpected error returns `{ decision: 'proceed' }`
|
|
35
|
+
* so the pipeline is never blocked by gate failures (AC7).
|
|
36
|
+
*/
|
|
37
|
+
static async check(options) {
|
|
38
|
+
try {
|
|
39
|
+
const { storyKey, storyContent, pendingFiles, completedStories, db, projectRoot } = options;
|
|
40
|
+
// -----------------------------------------------------------------------
|
|
41
|
+
// Step 1 — Learning pre-emption (AC6)
|
|
42
|
+
// Query the learning store for high-confidence namespace-collision findings
|
|
43
|
+
// whose affected_files overlap with the pending story's target files.
|
|
44
|
+
// -----------------------------------------------------------------------
|
|
45
|
+
try {
|
|
46
|
+
const rows = await getDecisionsByCategory(db, LEARNING_FINDING);
|
|
47
|
+
for (const row of rows) {
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(row.value);
|
|
50
|
+
const result = FindingSchema.safeParse(parsed);
|
|
51
|
+
if (!result.success)
|
|
52
|
+
continue;
|
|
53
|
+
const finding = result.data;
|
|
54
|
+
// Only consider high-confidence namespace-collision findings
|
|
55
|
+
if (finding.root_cause !== 'namespace-collision')
|
|
56
|
+
continue;
|
|
57
|
+
if (finding.confidence !== 'high')
|
|
58
|
+
continue;
|
|
59
|
+
// Skip tombstoned findings
|
|
60
|
+
if (finding.contradicted_by !== undefined)
|
|
61
|
+
continue;
|
|
62
|
+
// Check file overlap between finding's affected_files and pending files
|
|
63
|
+
const overlap = ConflictDetector.findOverlappingFiles(pendingFiles, finding.affected_files);
|
|
64
|
+
if (overlap.length === 0)
|
|
65
|
+
continue;
|
|
66
|
+
// Pre-emptive block via auto-resolution
|
|
67
|
+
const extensionNote = `${storyKey} already exists in ${overlap[0]}. Extend the existing implementation instead of creating a new class.`;
|
|
68
|
+
const autoResolved = DispatchGate.attemptAutoResolution(storyContent, extensionNote);
|
|
69
|
+
if (autoResolved !== null) {
|
|
70
|
+
return {
|
|
71
|
+
decision: 'block',
|
|
72
|
+
conflictType: 'learning-preemption',
|
|
73
|
+
reason: `learning-preemption: high-confidence finding — ${finding.description}`,
|
|
74
|
+
modifiedPrompt: autoResolved,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
// Auto-resolution failed
|
|
78
|
+
return {
|
|
79
|
+
decision: 'gated',
|
|
80
|
+
conflictType: 'learning-preemption',
|
|
81
|
+
reason: `learning-preemption: high-confidence finding — ${finding.description}`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Non-fatal: malformed row — skip
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Non-fatal: DB error during learning query — proceed to next step (AC7)
|
|
92
|
+
}
|
|
93
|
+
// -----------------------------------------------------------------------
|
|
94
|
+
// Step 2 — File overlap + namespace collision (AC2/AC3)
|
|
95
|
+
// Iterate completed stories and check for file overlaps.
|
|
96
|
+
// For each overlap, check if any target symbol already exists in those files.
|
|
97
|
+
// -----------------------------------------------------------------------
|
|
98
|
+
// Extract symbols declared / targeted in the pending story
|
|
99
|
+
const targetSymbols = ConflictDetector.extractTargetSymbols(storyContent);
|
|
100
|
+
let warnResult = null;
|
|
101
|
+
for (const completed of completedStories) {
|
|
102
|
+
const overlappingFiles = ConflictDetector.findOverlappingFiles(pendingFiles, completed.modifiedFiles);
|
|
103
|
+
if (overlappingFiles.length === 0)
|
|
104
|
+
continue;
|
|
105
|
+
// If storyContent is empty we cannot extract symbols to verify whether
|
|
106
|
+
// a namespace collision exists. Gate proactively — cannot proceed without
|
|
107
|
+
// knowing whether auto-resolution would be needed (AC5: "story content
|
|
108
|
+
// cannot be retrieved or modified").
|
|
109
|
+
if (storyContent.trim().length === 0) {
|
|
110
|
+
return {
|
|
111
|
+
decision: 'gated',
|
|
112
|
+
conflictType: 'namespace-collision',
|
|
113
|
+
reason: `namespace-collision: story content is empty — cannot verify conflict with files from story ${completed.key}`,
|
|
114
|
+
completedStoryKey: completed.key,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// File overlap detected — check for namespace collisions in overlapping files
|
|
118
|
+
for (const symbol of targetSymbols) {
|
|
119
|
+
let collision = null;
|
|
120
|
+
try {
|
|
121
|
+
collision = await ConflictDetector.detectNamespaceCollision(symbol, overlappingFiles, projectRoot);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Non-fatal: file-read error — skip this symbol (AC7)
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (collision !== null) {
|
|
128
|
+
// Namespace collision found — attempt auto-resolution (AC4)
|
|
129
|
+
const extensionNote = `${collision.symbol} already exists in ${collision.file}. Extend the existing implementation instead of creating a new class.`;
|
|
130
|
+
const autoResolved = DispatchGate.attemptAutoResolution(storyContent, extensionNote);
|
|
131
|
+
if (autoResolved !== null) {
|
|
132
|
+
return {
|
|
133
|
+
decision: 'block',
|
|
134
|
+
conflictType: 'namespace-collision',
|
|
135
|
+
reason: `namespace-collision: ${collision.symbol} exists in ${collision.file} from story ${completed.key}`,
|
|
136
|
+
modifiedPrompt: autoResolved,
|
|
137
|
+
completedStoryKey: completed.key,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// Auto-resolution failed (AC5)
|
|
141
|
+
return {
|
|
142
|
+
decision: 'gated',
|
|
143
|
+
conflictType: 'namespace-collision',
|
|
144
|
+
reason: `namespace-collision: ${collision.symbol} exists in ${collision.file} from story ${completed.key}`,
|
|
145
|
+
completedStoryKey: completed.key,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// File overlap with no collision — record a warn result (AC2)
|
|
150
|
+
// We'll emit the warning but continue checking other completed stories for collisions.
|
|
151
|
+
if (warnResult === null) {
|
|
152
|
+
warnResult = {
|
|
153
|
+
decision: 'warn',
|
|
154
|
+
conflictType: 'file-overlap',
|
|
155
|
+
reason: `file-overlap: pending story shares files with completed story ${completed.key}`,
|
|
156
|
+
completedStoryKey: completed.key,
|
|
157
|
+
overlappingFiles,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Return warn if we found overlap but no collision
|
|
162
|
+
if (warnResult !== null) {
|
|
163
|
+
return warnResult;
|
|
164
|
+
}
|
|
165
|
+
// -----------------------------------------------------------------------
|
|
166
|
+
// Step 3 — No issues found
|
|
167
|
+
// -----------------------------------------------------------------------
|
|
168
|
+
return { decision: 'proceed' };
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// AC7: outer catch — any unexpected error degrades gracefully to proceed
|
|
172
|
+
return { decision: 'proceed' };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
// Private helpers
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
/**
|
|
179
|
+
* Attempt to auto-resolve a conflict by appending an extension note to the
|
|
180
|
+
* story content.
|
|
181
|
+
*
|
|
182
|
+
* Returns the modified prompt string on success, or null if the content is
|
|
183
|
+
* empty or the append fails for any reason (AC4/AC5).
|
|
184
|
+
*/
|
|
185
|
+
static attemptAutoResolution(storyContent, extensionNote) {
|
|
186
|
+
if (storyContent.trim().length === 0) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
return `${storyContent}\n\n${extensionNote}`;
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=dispatch-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch-gate.js","sourceRoot":"","sources":["../../src/gating/dispatch-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gating module barrel — Story 53-9: Dispatch Pre-Condition Gating
|
|
3
|
+
*
|
|
4
|
+
* Public API for the dispatch pre-condition gating system.
|
|
5
|
+
*/
|
|
6
|
+
export { DispatchGate } from './dispatch-gate.js';
|
|
7
|
+
export { ConflictDetector } from './conflict-detector.js';
|
|
8
|
+
export type { ConflictType, GateDecision, GateResult, DispatchGateOptions, PipelineDispatchWarnPayload, PipelineStoryGatedPayload, } from './types.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gating/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,mBAAmB,EACnB,2BAA2B,EAC3B,yBAAyB,GAC1B,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gating module barrel — Story 53-9: Dispatch Pre-Condition Gating
|
|
3
|
+
*
|
|
4
|
+
* Public API for the dispatch pre-condition gating system.
|
|
5
|
+
*/
|
|
6
|
+
export { DispatchGate } from './dispatch-gate.js';
|
|
7
|
+
export { ConflictDetector } from './conflict-detector.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gating/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gating module types — Story 53-9: Dispatch Pre-Condition Gating
|
|
3
|
+
*
|
|
4
|
+
* Defines the type system for the dispatch gate: ConflictType, GateDecision,
|
|
5
|
+
* GateResult, DispatchGateOptions, and the new pipeline event payloads.
|
|
6
|
+
*/
|
|
7
|
+
import type { DatabaseAdapter } from '@substrate-ai/core';
|
|
8
|
+
/**
|
|
9
|
+
* Discriminant for the kind of conflict the gate detected.
|
|
10
|
+
*
|
|
11
|
+
* - `namespace-collision`: a symbol defined in the pending story already exists
|
|
12
|
+
* in a file modified by a completed story.
|
|
13
|
+
* - `file-overlap`: the pending story's target files overlap with a completed
|
|
14
|
+
* story's modified files, but no namespace collision was found.
|
|
15
|
+
* - `learning-preemption`: the learning store contains a high-confidence
|
|
16
|
+
* namespace-collision finding for the pending story's target files, even
|
|
17
|
+
* without a direct completed-story overlap in this run.
|
|
18
|
+
*/
|
|
19
|
+
export type ConflictType = 'namespace-collision' | 'file-overlap' | 'learning-preemption';
|
|
20
|
+
/**
|
|
21
|
+
* The gate's verdict for a pending story dispatch.
|
|
22
|
+
*
|
|
23
|
+
* - `proceed`: no conflict detected; dispatch normally.
|
|
24
|
+
* - `warn`: file overlap found but no collision; dispatch proceeds with a warning event.
|
|
25
|
+
* - `block`: collision resolved via auto-resolution; dispatch with modified prompt.
|
|
26
|
+
* - `gated`: non-resolvable conflict; story is placed in the `gated` phase and
|
|
27
|
+
* excluded from future dispatch attempts until operator review.
|
|
28
|
+
*/
|
|
29
|
+
export type GateDecision = 'proceed' | 'warn' | 'block' | 'gated';
|
|
30
|
+
/**
|
|
31
|
+
* Structured result returned by `DispatchGate.check()`.
|
|
32
|
+
*/
|
|
33
|
+
export interface GateResult {
|
|
34
|
+
/** The gate's verdict. */
|
|
35
|
+
decision: GateDecision;
|
|
36
|
+
/** Type of conflict detected (absent when decision is 'proceed'). */
|
|
37
|
+
conflictType?: ConflictType;
|
|
38
|
+
/** Human-readable reason string for the gate decision. */
|
|
39
|
+
reason?: string;
|
|
40
|
+
/** Modified story prompt with extension note appended (present when decision is 'block'). */
|
|
41
|
+
modifiedPrompt?: string;
|
|
42
|
+
/** Completed-story key that triggered the conflict. */
|
|
43
|
+
completedStoryKey?: string;
|
|
44
|
+
/** Files shared between pending and completed story (present when decision is 'warn'). */
|
|
45
|
+
overlappingFiles?: string[];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Options passed to `DispatchGate.check()` for a single pending story.
|
|
49
|
+
*/
|
|
50
|
+
export interface DispatchGateOptions {
|
|
51
|
+
/** Story key being evaluated (e.g. '53-9'). */
|
|
52
|
+
storyKey: string;
|
|
53
|
+
/** Raw content of the story file — used for symbol extraction. */
|
|
54
|
+
storyContent: string;
|
|
55
|
+
/** Files referenced / targeted by the pending story. */
|
|
56
|
+
pendingFiles: string[];
|
|
57
|
+
/** Completed stories with their modified file lists. */
|
|
58
|
+
completedStories: Array<{
|
|
59
|
+
key: string;
|
|
60
|
+
modifiedFiles: string[];
|
|
61
|
+
}>;
|
|
62
|
+
/** Database adapter for learning store queries. */
|
|
63
|
+
db: DatabaseAdapter;
|
|
64
|
+
/** Project root path — used for file content reads during collision detection. */
|
|
65
|
+
projectRoot: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Payload for the `pipeline:dispatch-warn` event (AC2).
|
|
69
|
+
*
|
|
70
|
+
* Emitted when a file overlap is detected between the pending story and a
|
|
71
|
+
* completed story, but no namespace collision was found. Dispatch proceeds
|
|
72
|
+
* normally after this event.
|
|
73
|
+
*/
|
|
74
|
+
export interface PipelineDispatchWarnPayload {
|
|
75
|
+
/** Pending story key. */
|
|
76
|
+
storyKey: string;
|
|
77
|
+
/** Completed story whose modified files overlap with the pending story. */
|
|
78
|
+
completedStoryKey: string;
|
|
79
|
+
/** Files that exist in both pending and completed story file sets. */
|
|
80
|
+
overlappingFiles: string[];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Payload for the `pipeline:story-gated` event (AC5).
|
|
84
|
+
*
|
|
85
|
+
* Emitted when the gate cannot resolve a conflict and places the story in the
|
|
86
|
+
* `gated` phase for operator review.
|
|
87
|
+
*/
|
|
88
|
+
export interface PipelineStoryGatedPayload {
|
|
89
|
+
/** Story key being gated. */
|
|
90
|
+
storyKey: string;
|
|
91
|
+
/** Type of conflict that triggered the gate. */
|
|
92
|
+
conflictType: ConflictType;
|
|
93
|
+
/** Human-readable reason for gating. */
|
|
94
|
+
reason: string;
|
|
95
|
+
/** Completed story that triggered the conflict (if applicable). */
|
|
96
|
+
completedStoryKey?: string;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/gating/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAMzD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,YAAY,GAAG,qBAAqB,GAAG,cAAc,GAAG,qBAAqB,CAAA;AAMzF;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAMjE;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,0BAA0B;IAC1B,QAAQ,EAAE,YAAY,CAAA;IACtB,qEAAqE;IACrE,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,6FAA6F;IAC7F,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,0FAA0F;IAC1F,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;CAC5B;AAMD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAA;IAChB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAA;IACpB,wDAAwD;IACxD,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,wDAAwD;IACxD,gBAAgB,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;IACjE,mDAAmD;IACnD,EAAE,EAAE,eAAe,CAAA;IACnB,kFAAkF;IAClF,WAAW,EAAE,MAAM,CAAA;CACpB;AAMD;;;;;;GAMG;AACH,MAAM,WAAW,2BAA2B;IAC1C,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,CAAA;IACzB,sEAAsE;IACtE,gBAAgB,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACxC,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,YAAY,EAAE,YAAY,CAAA;IAC1B,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAA;IACd,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gating module types — Story 53-9: Dispatch Pre-Condition Gating
|
|
3
|
+
*
|
|
4
|
+
* Defines the type system for the dispatch gate: ConflictType, GateDecision,
|
|
5
|
+
* GateResult, DispatchGateOptions, and the new pipeline event payloads.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/gating/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDLC Event Bridge — translates factory graph executor lifecycle events into
|
|
3
|
+
* SDLC orchestrator events for backward compatibility with existing consumers.
|
|
4
|
+
*
|
|
5
|
+
* Story 43-9: SDLC-as-Graph NDJSON Event Compatibility.
|
|
6
|
+
*
|
|
7
|
+
* ADR-003: This file MUST NOT import any runtime value from `@substrate-ai/factory`.
|
|
8
|
+
* All coupling to the factory event bus shape is via local duck-typed interfaces.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Structurally compatible with Node.js EventEmitter or TypedEventBus<FactoryEvents>.
|
|
12
|
+
* Only `on` and `off` are required — the bridge never emits on the graph bus.
|
|
13
|
+
*/
|
|
14
|
+
export interface GraphEventEmitter {
|
|
15
|
+
on(event: string, handler: (data: unknown) => void): this;
|
|
16
|
+
off(event: string, handler: (data: unknown) => void): this;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Structurally compatible with TypedEventBus<SdlcEvents>.emit.
|
|
20
|
+
* The bridge emits translated events onto this bus.
|
|
21
|
+
*/
|
|
22
|
+
export interface SdlcEventBus {
|
|
23
|
+
emit(event: string, payload: unknown): void;
|
|
24
|
+
}
|
|
25
|
+
/** Options for `createSdlcEventBridge`. */
|
|
26
|
+
export interface SdlcEventBridgeOptions {
|
|
27
|
+
/** Story key for all emitted SDLC events. */
|
|
28
|
+
storyKey: string;
|
|
29
|
+
/** Optional pipeline run ID forwarded to phase start/complete payloads. */
|
|
30
|
+
pipelineRunId?: string;
|
|
31
|
+
/** SDLC event bus that receives translated orchestrator events. */
|
|
32
|
+
sdlcBus: SdlcEventBus;
|
|
33
|
+
/** Factory graph event emitter (source of raw graph lifecycle events). */
|
|
34
|
+
graphEvents: GraphEventEmitter;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates an event bridge that translates factory graph executor lifecycle events
|
|
38
|
+
* into SDLC orchestrator events for backward compatibility with existing consumers
|
|
39
|
+
* (supervisor, CLI polling, telemetry).
|
|
40
|
+
*
|
|
41
|
+
* Supported translations:
|
|
42
|
+
* - `graph:node-started` → `orchestrator:story-phase-start` (AC1)
|
|
43
|
+
* - `graph:node-completed` → `orchestrator:story-phase-complete` (AC2)
|
|
44
|
+
* - `graph:node-retried` → (counter only — tracks review cycles)
|
|
45
|
+
* - `graph:completed` (SUCCESS) → `orchestrator:story-complete` (AC3)
|
|
46
|
+
* - `graph:goal-gate-unsatisfied` → `orchestrator:story-escalated` (AC4)
|
|
47
|
+
* - Non-SDLC node IDs → silently ignored (AC5)
|
|
48
|
+
*
|
|
49
|
+
* @returns An object with a `teardown()` function that removes all registered
|
|
50
|
+
* graph event listeners (AC7). Must be called after story execution
|
|
51
|
+
* completes (use try/finally).
|
|
52
|
+
*/
|
|
53
|
+
export declare function createSdlcEventBridge(opts: SdlcEventBridgeOptions): {
|
|
54
|
+
teardown(): void;
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=event-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bridge.d.ts","sourceRoot":"","sources":["../../src/handlers/event-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAA;IACzD,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAA;CAC3D;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;CAC5C;AAMD,2CAA2C;AAC3C,MAAM,WAAW,sBAAsB;IACrC,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAA;IAChB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,mEAAmE;IACnE,OAAO,EAAE,YAAY,CAAA;IACrB,0EAA0E;IAC1E,WAAW,EAAE,iBAAiB,CAAA;CAC/B;AAkCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,sBAAsB,GAAG;IAAE,QAAQ,IAAI,IAAI,CAAA;CAAE,CAkGxF"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDLC Event Bridge — translates factory graph executor lifecycle events into
|
|
3
|
+
* SDLC orchestrator events for backward compatibility with existing consumers.
|
|
4
|
+
*
|
|
5
|
+
* Story 43-9: SDLC-as-Graph NDJSON Event Compatibility.
|
|
6
|
+
*
|
|
7
|
+
* ADR-003: This file MUST NOT import any runtime value from `@substrate-ai/factory`.
|
|
8
|
+
* All coupling to the factory event bus shape is via local duck-typed interfaces.
|
|
9
|
+
*/
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// SDLC node phase map
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
/**
|
|
14
|
+
* Maps factory graph node IDs to SDLC phase names.
|
|
15
|
+
* Node IDs not present here are silently ignored by the bridge (AC5).
|
|
16
|
+
*
|
|
17
|
+
* | Graph Node ID | SDLC Phase Name |
|
|
18
|
+
* |----------------|-----------------|
|
|
19
|
+
* | analysis | 'analysis' |
|
|
20
|
+
* | planning | 'planning' |
|
|
21
|
+
* | solutioning | 'solutioning' |
|
|
22
|
+
* | create_story | 'create' |
|
|
23
|
+
* | dev_story | 'dev' |
|
|
24
|
+
* | code_review | 'review' |
|
|
25
|
+
* | start | (ignored) |
|
|
26
|
+
* | exit | (ignored) |
|
|
27
|
+
*/
|
|
28
|
+
const SDLC_NODE_PHASE_MAP = {
|
|
29
|
+
analysis: 'analysis',
|
|
30
|
+
planning: 'planning',
|
|
31
|
+
solutioning: 'solutioning',
|
|
32
|
+
create_story: 'create',
|
|
33
|
+
dev_story: 'dev',
|
|
34
|
+
code_review: 'review',
|
|
35
|
+
};
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Factory function
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
/**
|
|
40
|
+
* Creates an event bridge that translates factory graph executor lifecycle events
|
|
41
|
+
* into SDLC orchestrator events for backward compatibility with existing consumers
|
|
42
|
+
* (supervisor, CLI polling, telemetry).
|
|
43
|
+
*
|
|
44
|
+
* Supported translations:
|
|
45
|
+
* - `graph:node-started` → `orchestrator:story-phase-start` (AC1)
|
|
46
|
+
* - `graph:node-completed` → `orchestrator:story-phase-complete` (AC2)
|
|
47
|
+
* - `graph:node-retried` → (counter only — tracks review cycles)
|
|
48
|
+
* - `graph:completed` (SUCCESS) → `orchestrator:story-complete` (AC3)
|
|
49
|
+
* - `graph:goal-gate-unsatisfied` → `orchestrator:story-escalated` (AC4)
|
|
50
|
+
* - Non-SDLC node IDs → silently ignored (AC5)
|
|
51
|
+
*
|
|
52
|
+
* @returns An object with a `teardown()` function that removes all registered
|
|
53
|
+
* graph event listeners (AC7). Must be called after story execution
|
|
54
|
+
* completes (use try/finally).
|
|
55
|
+
*/
|
|
56
|
+
export function createSdlcEventBridge(opts) {
|
|
57
|
+
const { storyKey, pipelineRunId, sdlcBus, graphEvents } = opts;
|
|
58
|
+
// Tracks dev_story retry count — used for reviewCycles in complete/escalated events (AC3, AC4).
|
|
59
|
+
// Each dev_story retry corresponds to one additional code review dispatch (a failed code_review
|
|
60
|
+
// triggers a dev_story retry before the next code_review is run). Adding 1 converts the retry
|
|
61
|
+
// count into the total code-review dispatch count (Story 53-13).
|
|
62
|
+
let devStoryRetries = 0;
|
|
63
|
+
// -------------------------------------------------------------------------
|
|
64
|
+
// Event handlers
|
|
65
|
+
// -------------------------------------------------------------------------
|
|
66
|
+
const onNodeStarted = (data) => {
|
|
67
|
+
const { nodeId } = data;
|
|
68
|
+
const phase = SDLC_NODE_PHASE_MAP[nodeId];
|
|
69
|
+
if (!phase)
|
|
70
|
+
return; // silently ignore non-SDLC nodes (AC5)
|
|
71
|
+
sdlcBus.emit('orchestrator:story-phase-start', { storyKey, phase, pipelineRunId });
|
|
72
|
+
};
|
|
73
|
+
const onNodeCompleted = (data) => {
|
|
74
|
+
const { nodeId, outcome } = data;
|
|
75
|
+
const phase = SDLC_NODE_PHASE_MAP[nodeId];
|
|
76
|
+
if (!phase)
|
|
77
|
+
return; // silently ignore non-SDLC nodes (AC5)
|
|
78
|
+
sdlcBus.emit('orchestrator:story-phase-complete', {
|
|
79
|
+
storyKey,
|
|
80
|
+
phase,
|
|
81
|
+
result: outcome,
|
|
82
|
+
pipelineRunId,
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
const onNodeRetried = (data) => {
|
|
86
|
+
const { nodeId } = data;
|
|
87
|
+
if (nodeId === 'dev_story') {
|
|
88
|
+
devStoryRetries++;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const onGraphCompleted = (data) => {
|
|
92
|
+
const { finalOutcome } = data;
|
|
93
|
+
if (finalOutcome.status === 'SUCCESS') {
|
|
94
|
+
// devStoryRetries counts additional dev_story dispatches after failed code reviews.
|
|
95
|
+
// Adding 1 converts the retry count into the total code-review dispatch count:
|
|
96
|
+
// 0 retries (first-pass SHIP_IT) → reviewCycles: 1 (Story 53-13)
|
|
97
|
+
// 1 retry (NEEDS_MINOR_FIXES → SHIP_IT) → reviewCycles: 2
|
|
98
|
+
sdlcBus.emit('orchestrator:story-complete', {
|
|
99
|
+
storyKey,
|
|
100
|
+
reviewCycles: devStoryRetries + 1,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const onGoalGateUnsatisfied = (data) => {
|
|
105
|
+
const evt = data;
|
|
106
|
+
if (evt.nodeId === 'dev_story') {
|
|
107
|
+
sdlcBus.emit('orchestrator:story-escalated', {
|
|
108
|
+
storyKey,
|
|
109
|
+
lastVerdict: evt.lastVerdict ?? 'NEEDS_MAJOR_REWORK',
|
|
110
|
+
reviewCycles: evt.reviewCycles ?? devStoryRetries,
|
|
111
|
+
issues: evt.issues ?? [],
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
// -------------------------------------------------------------------------
|
|
116
|
+
// Register all listeners
|
|
117
|
+
// -------------------------------------------------------------------------
|
|
118
|
+
graphEvents.on('graph:node-started', onNodeStarted);
|
|
119
|
+
graphEvents.on('graph:node-completed', onNodeCompleted);
|
|
120
|
+
graphEvents.on('graph:node-retried', onNodeRetried);
|
|
121
|
+
graphEvents.on('graph:completed', onGraphCompleted);
|
|
122
|
+
graphEvents.on('graph:goal-gate-unsatisfied', onGoalGateUnsatisfied);
|
|
123
|
+
// -------------------------------------------------------------------------
|
|
124
|
+
// Teardown
|
|
125
|
+
// -------------------------------------------------------------------------
|
|
126
|
+
return {
|
|
127
|
+
/**
|
|
128
|
+
* Removes all graph event listeners registered by this bridge (AC7).
|
|
129
|
+
* Call this after story execution completes (use try/finally).
|
|
130
|
+
*/
|
|
131
|
+
teardown() {
|
|
132
|
+
graphEvents.off('graph:node-started', onNodeStarted);
|
|
133
|
+
graphEvents.off('graph:node-completed', onNodeCompleted);
|
|
134
|
+
graphEvents.off('graph:node-retried', onNodeRetried);
|
|
135
|
+
graphEvents.off('graph:completed', onGraphCompleted);
|
|
136
|
+
graphEvents.off('graph:goal-gate-unsatisfied', onGoalGateUnsatisfied);
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=event-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bridge.js","sourceRoot":"","sources":["../../src/handlers/event-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barrel export for the SDLC handlers module.
|
|
3
|
+
* Stories 43-2, 43-3, 43-4, 43-9.
|
|
4
|
+
*/
|
|
5
|
+
export { createSdlcCreateStoryHandler } from './sdlc-create-story-handler.js';
|
|
6
|
+
export type { SdlcCreateStoryHandlerOptions, CreateStoryParams, CreateStoryResult, RunCreateStoryFn, } from './sdlc-create-story-handler.js';
|
|
7
|
+
export { createSdlcPhaseHandler } from './sdlc-phase-handler.js';
|
|
8
|
+
export type { SdlcPhaseHandlerDeps, SdlcNodeHandler, SdlcOutcome, PhaseOrchestrator, PhaseRunnerFn, PhaseRunners, EntryGateResult, GateFailure, } from './types.js';
|
|
9
|
+
export { createSdlcDevStoryHandler } from './sdlc-dev-story-handler.js';
|
|
10
|
+
export type { SdlcDevStoryHandlerOptions, DevStoryParams, DevStoryResult, RunDevStoryFn, BuildVerifyResult, BuildVerifierFn, } from './sdlc-dev-story-handler.js';
|
|
11
|
+
export { createSdlcCodeReviewHandler } from './sdlc-code-review-handler.js';
|
|
12
|
+
export type { SdlcCodeReviewHandlerOptions, CodeReviewParams, CodeReviewResult, CodeReviewIssue, RunCodeReviewFn, } from './sdlc-code-review-handler.js';
|
|
13
|
+
export { createSdlcEventBridge } from './event-bridge.js';
|
|
14
|
+
export type { SdlcEventBridgeOptions, GraphEventEmitter, SdlcEventBus, } from './event-bridge.js';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAA;AAC7E,YAAY,EACV,6BAA6B,EAC7B,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,gCAAgC,CAAA;AAGvC,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAChE,YAAY,EACV,oBAAoB,EACpB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,YAAY,EAEZ,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA;AACvE,YAAY,EACV,0BAA0B,EAC1B,cAAc,EACd,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,eAAe,GAChB,MAAM,6BAA6B,CAAA;AAGpC,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAA;AAC3E,YAAY,EACV,4BAA4B,EAC5B,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,eAAe,GAChB,MAAM,+BAA+B,CAAA;AAGtC,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AACzD,YAAY,EACV,sBAAsB,EACtB,iBAAiB,EACjB,YAAY,GACb,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barrel export for the SDLC handlers module.
|
|
3
|
+
* Stories 43-2, 43-3, 43-4, 43-9.
|
|
4
|
+
*/
|
|
5
|
+
export { createSdlcCreateStoryHandler } from './sdlc-create-story-handler.js';
|
|
6
|
+
// Story 43-2: SDLC phase handler
|
|
7
|
+
export { createSdlcPhaseHandler } from './sdlc-phase-handler.js';
|
|
8
|
+
// Story 43-4: SDLC dev-story handler
|
|
9
|
+
export { createSdlcDevStoryHandler } from './sdlc-dev-story-handler.js';
|
|
10
|
+
// Story 43-5: SDLC code-review handler
|
|
11
|
+
export { createSdlcCodeReviewHandler } from './sdlc-code-review-handler.js';
|
|
12
|
+
// Story 43-9: SDLC event bridge
|
|
13
|
+
export { createSdlcEventBridge } from './event-bridge.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAA;AAQ7E,iCAAiC;AACjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAahE,qCAAqC;AACrC,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA;AAUvE,uCAAuC;AACvC,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAA;AAS3E,gCAAgC;AAChC,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA"}
|