@ai-sdlc/orchestrator 0.1.0

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.
Files changed (203) hide show
  1. package/dist/adapters.d.ts +60 -0
  2. package/dist/adapters.js +160 -0
  3. package/dist/admission.d.ts +49 -0
  4. package/dist/admission.js +90 -0
  5. package/dist/analysis/analyzer.d.ts +10 -0
  6. package/dist/analysis/analyzer.js +67 -0
  7. package/dist/analysis/complexity-scorer.d.ts +24 -0
  8. package/dist/analysis/complexity-scorer.js +39 -0
  9. package/dist/analysis/context-builder.d.ts +14 -0
  10. package/dist/analysis/context-builder.js +79 -0
  11. package/dist/analysis/convention-detector.d.ts +9 -0
  12. package/dist/analysis/convention-detector.js +177 -0
  13. package/dist/analysis/dependency-parser.d.ts +17 -0
  14. package/dist/analysis/dependency-parser.js +167 -0
  15. package/dist/analysis/file-walker.d.ts +18 -0
  16. package/dist/analysis/file-walker.js +158 -0
  17. package/dist/analysis/hotspot-analyzer.d.ts +28 -0
  18. package/dist/analysis/hotspot-analyzer.js +85 -0
  19. package/dist/analysis/index.d.ts +13 -0
  20. package/dist/analysis/index.js +12 -0
  21. package/dist/analysis/pattern-detector.d.ts +10 -0
  22. package/dist/analysis/pattern-detector.js +86 -0
  23. package/dist/analysis/types.d.ts +94 -0
  24. package/dist/analysis/types.js +5 -0
  25. package/dist/audit-archival.d.ts +48 -0
  26. package/dist/audit-archival.js +72 -0
  27. package/dist/audit-export.d.ts +45 -0
  28. package/dist/audit-export.js +100 -0
  29. package/dist/audit-extended.d.ts +28 -0
  30. package/dist/audit-extended.js +38 -0
  31. package/dist/audit-scheduler.d.ts +32 -0
  32. package/dist/audit-scheduler.js +52 -0
  33. package/dist/audit-sqlite-sink.d.ts +11 -0
  34. package/dist/audit-sqlite-sink.js +51 -0
  35. package/dist/autonomy-tracker.d.ts +76 -0
  36. package/dist/autonomy-tracker.js +277 -0
  37. package/dist/check-runs.d.ts +37 -0
  38. package/dist/check-runs.js +72 -0
  39. package/dist/cli/commands/agents.d.ts +6 -0
  40. package/dist/cli/commands/agents.js +33 -0
  41. package/dist/cli/commands/complexity.d.ts +6 -0
  42. package/dist/cli/commands/complexity.js +35 -0
  43. package/dist/cli/commands/cost.d.ts +6 -0
  44. package/dist/cli/commands/cost.js +53 -0
  45. package/dist/cli/commands/dashboard.d.ts +9 -0
  46. package/dist/cli/commands/dashboard.js +50 -0
  47. package/dist/cli/commands/health.d.ts +6 -0
  48. package/dist/cli/commands/health.js +33 -0
  49. package/dist/cli/commands/init.d.ts +6 -0
  50. package/dist/cli/commands/init.js +127 -0
  51. package/dist/cli/commands/routing.d.ts +6 -0
  52. package/dist/cli/commands/routing.js +46 -0
  53. package/dist/cli/commands/run.d.ts +6 -0
  54. package/dist/cli/commands/run.js +36 -0
  55. package/dist/cli/commands/start.d.ts +6 -0
  56. package/dist/cli/commands/start.js +26 -0
  57. package/dist/cli/commands/status.d.ts +6 -0
  58. package/dist/cli/commands/status.js +34 -0
  59. package/dist/cli/dashboard-renderer.d.ts +24 -0
  60. package/dist/cli/dashboard-renderer.js +129 -0
  61. package/dist/cli/formatters/index.d.ts +6 -0
  62. package/dist/cli/formatters/index.js +18 -0
  63. package/dist/cli/formatters/json.d.ts +5 -0
  64. package/dist/cli/formatters/json.js +7 -0
  65. package/dist/cli/formatters/minimal.d.ts +5 -0
  66. package/dist/cli/formatters/minimal.js +36 -0
  67. package/dist/cli/formatters/table.d.ts +5 -0
  68. package/dist/cli/formatters/table.js +184 -0
  69. package/dist/cli/index.d.ts +6 -0
  70. package/dist/cli/index.js +35 -0
  71. package/dist/compliance-extended.d.ts +41 -0
  72. package/dist/compliance-extended.js +58 -0
  73. package/dist/config.d.ts +26 -0
  74. package/dist/config.js +66 -0
  75. package/dist/context-enrichment.d.ts +33 -0
  76. package/dist/context-enrichment.js +125 -0
  77. package/dist/cost-governance.d.ts +22 -0
  78. package/dist/cost-governance.js +106 -0
  79. package/dist/cost-tracker.d.ts +75 -0
  80. package/dist/cost-tracker.js +177 -0
  81. package/dist/defaults.d.ts +140 -0
  82. package/dist/defaults.js +218 -0
  83. package/dist/deploy/flyio-target.d.ts +19 -0
  84. package/dist/deploy/flyio-target.js +114 -0
  85. package/dist/deploy/index.d.ts +15 -0
  86. package/dist/deploy/index.js +11 -0
  87. package/dist/deploy/kubernetes-target.d.ts +25 -0
  88. package/dist/deploy/kubernetes-target.js +124 -0
  89. package/dist/deploy/metrics-collector.d.ts +31 -0
  90. package/dist/deploy/metrics-collector.js +75 -0
  91. package/dist/deploy/rollout-controller.d.ts +42 -0
  92. package/dist/deploy/rollout-controller.js +192 -0
  93. package/dist/deploy/rollout-types.d.ts +86 -0
  94. package/dist/deploy/rollout-types.js +5 -0
  95. package/dist/deploy/types.d.ts +47 -0
  96. package/dist/deploy/types.js +5 -0
  97. package/dist/deploy/vercel-target.d.ts +16 -0
  98. package/dist/deploy/vercel-target.js +115 -0
  99. package/dist/discovery.d.ts +26 -0
  100. package/dist/discovery.js +46 -0
  101. package/dist/episodic-enhanced.d.ts +88 -0
  102. package/dist/episodic-enhanced.js +212 -0
  103. package/dist/execute.d.ts +81 -0
  104. package/dist/execute.js +703 -0
  105. package/dist/fix-ci.d.ts +61 -0
  106. package/dist/fix-ci.js +380 -0
  107. package/dist/handoff-executor.d.ts +61 -0
  108. package/dist/handoff-executor.js +119 -0
  109. package/dist/index.d.ts +70 -0
  110. package/dist/index.js +87 -0
  111. package/dist/instrumented.d.ts +27 -0
  112. package/dist/instrumented.js +34 -0
  113. package/dist/logger.d.ts +17 -0
  114. package/dist/logger.js +37 -0
  115. package/dist/multi-repo/impact-analyzer.d.ts +22 -0
  116. package/dist/multi-repo/impact-analyzer.js +95 -0
  117. package/dist/multi-repo/index.d.ts +5 -0
  118. package/dist/multi-repo/index.js +4 -0
  119. package/dist/multi-repo/monorepo-detector.d.ts +16 -0
  120. package/dist/multi-repo/monorepo-detector.js +246 -0
  121. package/dist/multi-repo/service-map-builder.d.ts +24 -0
  122. package/dist/multi-repo/service-map-builder.js +235 -0
  123. package/dist/multi-repo/types.d.ts +54 -0
  124. package/dist/multi-repo/types.js +5 -0
  125. package/dist/notifications/index.d.ts +4 -0
  126. package/dist/notifications/index.js +4 -0
  127. package/dist/notifications/notification-router.d.ts +62 -0
  128. package/dist/notifications/notification-router.js +206 -0
  129. package/dist/notifications/slack-messenger.d.ts +26 -0
  130. package/dist/notifications/slack-messenger.js +69 -0
  131. package/dist/notifications/teams-messenger.d.ts +21 -0
  132. package/dist/notifications/teams-messenger.js +85 -0
  133. package/dist/notifications.d.ts +13 -0
  134. package/dist/notifications.js +15 -0
  135. package/dist/orchestration.d.ts +20 -0
  136. package/dist/orchestration.js +53 -0
  137. package/dist/orchestrator.d.ts +160 -0
  138. package/dist/orchestrator.js +372 -0
  139. package/dist/otel-exporter.d.ts +37 -0
  140. package/dist/otel-exporter.js +128 -0
  141. package/dist/plugin.d.ts +45 -0
  142. package/dist/plugin.js +8 -0
  143. package/dist/policy-evaluators.d.ts +40 -0
  144. package/dist/policy-evaluators.js +57 -0
  145. package/dist/process-escalation.d.ts +38 -0
  146. package/dist/process-escalation.js +129 -0
  147. package/dist/progressive-gates.d.ts +54 -0
  148. package/dist/progressive-gates.js +135 -0
  149. package/dist/provenance.d.ts +29 -0
  150. package/dist/provenance.js +61 -0
  151. package/dist/reconcilers.d.ts +28 -0
  152. package/dist/reconcilers.js +37 -0
  153. package/dist/runners/claude-code.d.ts +17 -0
  154. package/dist/runners/claude-code.js +200 -0
  155. package/dist/runners/codex.d.ts +19 -0
  156. package/dist/runners/codex.js +153 -0
  157. package/dist/runners/copilot-stub.d.ts +9 -0
  158. package/dist/runners/copilot-stub.js +15 -0
  159. package/dist/runners/copilot.d.ts +15 -0
  160. package/dist/runners/copilot.js +119 -0
  161. package/dist/runners/cursor-stub.d.ts +9 -0
  162. package/dist/runners/cursor-stub.js +15 -0
  163. package/dist/runners/cursor.d.ts +20 -0
  164. package/dist/runners/cursor.js +140 -0
  165. package/dist/runners/devin-stub.d.ts +9 -0
  166. package/dist/runners/devin-stub.js +15 -0
  167. package/dist/runners/generic-llm.d.ts +51 -0
  168. package/dist/runners/generic-llm.js +125 -0
  169. package/dist/runners/index.d.ts +8 -0
  170. package/dist/runners/index.js +7 -0
  171. package/dist/runners/runner-registry.d.ts +50 -0
  172. package/dist/runners/runner-registry.js +156 -0
  173. package/dist/runners/types.d.ts +59 -0
  174. package/dist/runners/types.js +7 -0
  175. package/dist/security.d.ts +51 -0
  176. package/dist/security.js +70 -0
  177. package/dist/shared.d.ts +134 -0
  178. package/dist/shared.js +284 -0
  179. package/dist/state/index.d.ts +4 -0
  180. package/dist/state/index.js +3 -0
  181. package/dist/state/schema.d.ts +16 -0
  182. package/dist/state/schema.js +264 -0
  183. package/dist/state/store.d.ts +109 -0
  184. package/dist/state/store.js +644 -0
  185. package/dist/state/types.d.ts +190 -0
  186. package/dist/state/types.js +5 -0
  187. package/dist/structured-logger.d.ts +20 -0
  188. package/dist/structured-logger.js +64 -0
  189. package/dist/task-decomposer.d.ts +61 -0
  190. package/dist/task-decomposer.js +265 -0
  191. package/dist/telemetry-extended.d.ts +24 -0
  192. package/dist/telemetry-extended.js +31 -0
  193. package/dist/types.d.ts +9 -0
  194. package/dist/types.js +7 -0
  195. package/dist/validate-agent-output.d.ts +30 -0
  196. package/dist/validate-agent-output.js +81 -0
  197. package/dist/validate-issue.d.ts +25 -0
  198. package/dist/validate-issue.js +102 -0
  199. package/dist/watch.d.ts +43 -0
  200. package/dist/watch.js +99 -0
  201. package/dist/webhook-manager.d.ts +38 -0
  202. package/dist/webhook-manager.js +66 -0
  203. package/package.json +59 -0
@@ -0,0 +1,246 @@
1
+ /**
2
+ * Monorepo workspace detection — heuristic detection of workspace type
3
+ * by scanning for configuration files (pnpm-workspace.yaml, go.work, etc.).
4
+ *
5
+ * Design decision D3: Heuristic workspace detection.
6
+ */
7
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
8
+ import { join, basename, resolve, relative } from 'node:path';
9
+ /**
10
+ * Detect the monorepo layout of a directory by scanning for workspace config files.
11
+ */
12
+ export function detectMonorepoLayout(rootPath) {
13
+ // pnpm-workspace.yaml
14
+ if (existsSync(join(rootPath, 'pnpm-workspace.yaml'))) {
15
+ return 'pnpm-workspace';
16
+ }
17
+ // package.json workspaces (npm or yarn)
18
+ const pkgJsonPath = join(rootPath, 'package.json');
19
+ if (existsSync(pkgJsonPath)) {
20
+ try {
21
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
22
+ if (pkg.workspaces) {
23
+ // Yarn uses .yarnrc.yml or yarn.lock
24
+ if (existsSync(join(rootPath, '.yarnrc.yml')) || existsSync(join(rootPath, 'yarn.lock'))) {
25
+ return 'yarn-workspaces';
26
+ }
27
+ return 'npm-workspaces';
28
+ }
29
+ }
30
+ catch {
31
+ /* not valid JSON */
32
+ }
33
+ }
34
+ // go.work
35
+ if (existsSync(join(rootPath, 'go.work'))) {
36
+ return 'go-workspace';
37
+ }
38
+ // Cargo.toml with [workspace]
39
+ const cargoPath = join(rootPath, 'Cargo.toml');
40
+ if (existsSync(cargoPath)) {
41
+ try {
42
+ const content = readFileSync(cargoPath, 'utf-8');
43
+ if (content.includes('[workspace]')) {
44
+ return 'cargo-workspace';
45
+ }
46
+ }
47
+ catch {
48
+ /* ignore */
49
+ }
50
+ }
51
+ return 'single-repo';
52
+ }
53
+ /**
54
+ * Enumerate all packages in a workspace.
55
+ */
56
+ export function detectWorkspace(rootPath) {
57
+ const layout = detectMonorepoLayout(rootPath);
58
+ switch (layout) {
59
+ case 'pnpm-workspace':
60
+ return detectPnpmWorkspace(rootPath);
61
+ case 'npm-workspaces':
62
+ case 'yarn-workspaces':
63
+ return detectNpmWorkspace(rootPath, layout);
64
+ case 'go-workspace':
65
+ return detectGoWorkspace(rootPath);
66
+ case 'cargo-workspace':
67
+ return detectCargoWorkspace(rootPath);
68
+ default:
69
+ return { layout: 'single-repo', rootPath, packages: [detectSinglePackage(rootPath)] };
70
+ }
71
+ }
72
+ // ── Internal: pnpm ────────────────────────────────────────────────────
73
+ function detectPnpmWorkspace(rootPath) {
74
+ const configPath = join(rootPath, 'pnpm-workspace.yaml');
75
+ const content = readFileSync(configPath, 'utf-8');
76
+ // Simple YAML parsing for packages array
77
+ const patterns = parsePnpmWorkspaceYaml(content);
78
+ const packages = expandGlobPatterns(rootPath, patterns);
79
+ return { layout: 'pnpm-workspace', rootPath, packages };
80
+ }
81
+ function parsePnpmWorkspaceYaml(content) {
82
+ const patterns = [];
83
+ const lines = content.split('\n');
84
+ let inPackages = false;
85
+ for (const line of lines) {
86
+ const trimmed = line.trim();
87
+ if (trimmed === 'packages:') {
88
+ inPackages = true;
89
+ continue;
90
+ }
91
+ if (inPackages) {
92
+ if (trimmed.startsWith('- ')) {
93
+ patterns.push(trimmed.slice(2).replace(/['"]/g, '').trim());
94
+ }
95
+ else if (trimmed && !trimmed.startsWith('#')) {
96
+ break; // End of packages array
97
+ }
98
+ }
99
+ }
100
+ return patterns;
101
+ }
102
+ // ── Internal: npm/yarn ────────────────────────────────────────────────
103
+ function detectNpmWorkspace(rootPath, layout) {
104
+ const pkgJsonPath = join(rootPath, 'package.json');
105
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
106
+ const patterns = Array.isArray(pkg.workspaces)
107
+ ? pkg.workspaces
108
+ : (pkg.workspaces?.packages ?? []);
109
+ const packages = expandGlobPatterns(rootPath, patterns);
110
+ return { layout, rootPath, packages };
111
+ }
112
+ // ── Internal: Go ──────────────────────────────────────────────────────
113
+ function detectGoWorkspace(rootPath) {
114
+ const goWorkPath = join(rootPath, 'go.work');
115
+ const content = readFileSync(goWorkPath, 'utf-8');
116
+ const packages = [];
117
+ const lines = content.split('\n');
118
+ let inUse = false;
119
+ for (const line of lines) {
120
+ const trimmed = line.trim();
121
+ if (trimmed === 'use (') {
122
+ inUse = true;
123
+ continue;
124
+ }
125
+ if (trimmed === ')') {
126
+ inUse = false;
127
+ continue;
128
+ }
129
+ if (inUse && trimmed && !trimmed.startsWith('//')) {
130
+ const dirPath = trimmed.replace(/['"]/g, '');
131
+ const fullPath = resolve(rootPath, dirPath);
132
+ packages.push({
133
+ name: basename(dirPath),
134
+ path: fullPath,
135
+ relativePath: dirPath,
136
+ });
137
+ }
138
+ // Single-line use directive
139
+ if (trimmed.startsWith('use ') && !trimmed.includes('(')) {
140
+ const dirPath = trimmed.slice(4).trim().replace(/['"]/g, '');
141
+ const fullPath = resolve(rootPath, dirPath);
142
+ packages.push({
143
+ name: basename(dirPath),
144
+ path: fullPath,
145
+ relativePath: dirPath,
146
+ });
147
+ }
148
+ }
149
+ return { layout: 'go-workspace', rootPath, packages };
150
+ }
151
+ // ── Internal: Cargo ───────────────────────────────────────────────────
152
+ function detectCargoWorkspace(rootPath) {
153
+ const cargoPath = join(rootPath, 'Cargo.toml');
154
+ const content = readFileSync(cargoPath, 'utf-8');
155
+ // Parse members from [workspace] section
156
+ const membersMatch = content.match(/\[workspace\][\s\S]*?members\s*=\s*\[([\s\S]*?)\]/);
157
+ const patterns = [];
158
+ if (membersMatch) {
159
+ const members = membersMatch[1];
160
+ const memberRegex = /"([^"]+)"/g;
161
+ let match;
162
+ while ((match = memberRegex.exec(members)) !== null) {
163
+ patterns.push(match[1]);
164
+ }
165
+ }
166
+ const packages = expandGlobPatterns(rootPath, patterns);
167
+ return { layout: 'cargo-workspace', rootPath, packages };
168
+ }
169
+ // ── Internal: single repo ─────────────────────────────────────────────
170
+ function detectSinglePackage(rootPath) {
171
+ const pkgJsonPath = join(rootPath, 'package.json');
172
+ let name = basename(rootPath);
173
+ if (existsSync(pkgJsonPath)) {
174
+ try {
175
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
176
+ name = pkg.name ?? name;
177
+ }
178
+ catch {
179
+ /* ignore */
180
+ }
181
+ }
182
+ return { name, path: rootPath, relativePath: '.' };
183
+ }
184
+ // ── Internal: glob expansion ──────────────────────────────────────────
185
+ function expandGlobPatterns(rootPath, patterns) {
186
+ const packages = [];
187
+ const seen = new Set();
188
+ for (const pattern of patterns) {
189
+ // Handle simple directory patterns like "packages/*" or "apps/*"
190
+ if (pattern.includes('*')) {
191
+ const parts = pattern.split('*');
192
+ const prefix = parts[0];
193
+ const prefixPath = resolve(rootPath, prefix);
194
+ if (!existsSync(prefixPath))
195
+ continue;
196
+ try {
197
+ const entries = readdirSync(prefixPath);
198
+ for (const entry of entries) {
199
+ const fullPath = join(prefixPath, entry);
200
+ try {
201
+ if (statSync(fullPath).isDirectory()) {
202
+ const relativePath = relative(rootPath, fullPath);
203
+ const name = readPackageName(fullPath) ?? entry;
204
+ if (!seen.has(name)) {
205
+ seen.add(name);
206
+ packages.push({ name, path: fullPath, relativePath });
207
+ }
208
+ }
209
+ }
210
+ catch {
211
+ /* skip unreadable entries */
212
+ }
213
+ }
214
+ }
215
+ catch {
216
+ /* skip unreadable dirs */
217
+ }
218
+ }
219
+ else {
220
+ // Direct directory reference
221
+ const fullPath = resolve(rootPath, pattern);
222
+ if (existsSync(fullPath)) {
223
+ const relativePath = relative(rootPath, fullPath);
224
+ const name = readPackageName(fullPath) ?? basename(pattern);
225
+ if (!seen.has(name)) {
226
+ seen.add(name);
227
+ packages.push({ name, path: fullPath, relativePath });
228
+ }
229
+ }
230
+ }
231
+ }
232
+ return packages;
233
+ }
234
+ function readPackageName(dirPath) {
235
+ const pkgJsonPath = join(dirPath, 'package.json');
236
+ if (existsSync(pkgJsonPath)) {
237
+ try {
238
+ return JSON.parse(readFileSync(pkgJsonPath, 'utf-8')).name;
239
+ }
240
+ catch {
241
+ /* ignore */
242
+ }
243
+ }
244
+ return undefined;
245
+ }
246
+ //# sourceMappingURL=monorepo-detector.js.map
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Service map builder — constructs a dependency graph from workspace packages.
3
+ *
4
+ * Reads package.json (or go.mod/Cargo.toml) to discover inter-package
5
+ * dependencies and builds a ServiceMap graph.
6
+ */
7
+ import type { ServiceMap, WorkspaceConfig } from './types.js';
8
+ /**
9
+ * Build a service dependency graph from a workspace configuration.
10
+ */
11
+ export declare function buildServiceMap(config: WorkspaceConfig): ServiceMap;
12
+ /**
13
+ * Detect cycles in a service map. Returns arrays of service names forming cycles.
14
+ */
15
+ export declare function detectCycles(serviceMap: ServiceMap): string[][];
16
+ /**
17
+ * Get topologically sorted service names (leaf dependencies first).
18
+ */
19
+ export declare function topologicalOrder(serviceMap: ServiceMap): string[];
20
+ /**
21
+ * Get all transitive dependents of a service (downstream consumers).
22
+ */
23
+ export declare function getTransitiveDependents(serviceMap: ServiceMap, serviceName: string): string[];
24
+ //# sourceMappingURL=service-map-builder.d.ts.map
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Service map builder — constructs a dependency graph from workspace packages.
3
+ *
4
+ * Reads package.json (or go.mod/Cargo.toml) to discover inter-package
5
+ * dependencies and builds a ServiceMap graph.
6
+ */
7
+ import { existsSync, readFileSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ /**
10
+ * Build a service dependency graph from a workspace configuration.
11
+ */
12
+ export function buildServiceMap(config) {
13
+ const packageNames = new Set(config.packages.map((p) => p.name));
14
+ const nodes = [];
15
+ const edges = [];
16
+ const dependentsMap = new Map();
17
+ // Initialize dependents map
18
+ for (const pkg of config.packages) {
19
+ dependentsMap.set(pkg.name, []);
20
+ }
21
+ // Build nodes and discover edges
22
+ for (const pkg of config.packages) {
23
+ const deps = discoverDependencies(pkg, config.layout, packageNames);
24
+ const node = {
25
+ name: pkg.name,
26
+ path: pkg.path,
27
+ packageManager: layoutToPackageManager(config.layout),
28
+ dependencies: deps.map((d) => d.to),
29
+ dependents: [], // Filled in after all edges discovered
30
+ version: readVersion(pkg, config.layout),
31
+ };
32
+ nodes.push(node);
33
+ for (const dep of deps) {
34
+ edges.push(dep);
35
+ const existing = dependentsMap.get(dep.to);
36
+ if (existing)
37
+ existing.push(dep.from);
38
+ }
39
+ }
40
+ // Fill in dependents
41
+ for (const node of nodes) {
42
+ node.dependents = dependentsMap.get(node.name) ?? [];
43
+ }
44
+ return {
45
+ services: nodes,
46
+ edges,
47
+ rootPath: config.rootPath,
48
+ layout: config.layout,
49
+ };
50
+ }
51
+ /**
52
+ * Detect cycles in a service map. Returns arrays of service names forming cycles.
53
+ */
54
+ export function detectCycles(serviceMap) {
55
+ const cycles = [];
56
+ const visited = new Set();
57
+ const recursionStack = new Set();
58
+ const pathStack = [];
59
+ const adjacency = new Map();
60
+ for (const node of serviceMap.services) {
61
+ adjacency.set(node.name, node.dependencies);
62
+ }
63
+ function dfs(name) {
64
+ visited.add(name);
65
+ recursionStack.add(name);
66
+ pathStack.push(name);
67
+ for (const dep of adjacency.get(name) ?? []) {
68
+ if (!visited.has(dep)) {
69
+ dfs(dep);
70
+ }
71
+ else if (recursionStack.has(dep)) {
72
+ // Found a cycle
73
+ const cycleStart = pathStack.indexOf(dep);
74
+ if (cycleStart >= 0) {
75
+ cycles.push([...pathStack.slice(cycleStart), dep]);
76
+ }
77
+ }
78
+ }
79
+ pathStack.pop();
80
+ recursionStack.delete(name);
81
+ }
82
+ for (const node of serviceMap.services) {
83
+ if (!visited.has(node.name)) {
84
+ dfs(node.name);
85
+ }
86
+ }
87
+ return cycles;
88
+ }
89
+ /**
90
+ * Get topologically sorted service names (leaf dependencies first).
91
+ */
92
+ export function topologicalOrder(serviceMap) {
93
+ const sorted = [];
94
+ const visited = new Set();
95
+ const adjacency = new Map();
96
+ for (const node of serviceMap.services) {
97
+ adjacency.set(node.name, node.dependencies);
98
+ }
99
+ function visit(name) {
100
+ if (visited.has(name))
101
+ return;
102
+ visited.add(name);
103
+ for (const dep of adjacency.get(name) ?? []) {
104
+ visit(dep);
105
+ }
106
+ sorted.push(name);
107
+ }
108
+ for (const node of serviceMap.services) {
109
+ visit(node.name);
110
+ }
111
+ return sorted;
112
+ }
113
+ /**
114
+ * Get all transitive dependents of a service (downstream consumers).
115
+ */
116
+ export function getTransitiveDependents(serviceMap, serviceName) {
117
+ const result = new Set();
118
+ const queue = [serviceName];
119
+ const dependentsMap = new Map();
120
+ for (const node of serviceMap.services) {
121
+ dependentsMap.set(node.name, node.dependents);
122
+ }
123
+ while (queue.length > 0) {
124
+ const current = queue.shift();
125
+ for (const dependent of dependentsMap.get(current) ?? []) {
126
+ if (!result.has(dependent)) {
127
+ result.add(dependent);
128
+ queue.push(dependent);
129
+ }
130
+ }
131
+ }
132
+ return [...result];
133
+ }
134
+ // ── Internal ──────────────────────────────────────────────────────────
135
+ function discoverDependencies(pkg, layout, workspaceNames) {
136
+ const edges = [];
137
+ if (layout === 'go-workspace') {
138
+ return discoverGoDependencies(pkg, workspaceNames);
139
+ }
140
+ if (layout === 'cargo-workspace') {
141
+ return discoverCargoDependencies(pkg, workspaceNames);
142
+ }
143
+ // npm/pnpm/yarn: read package.json
144
+ const pkgJsonPath = join(pkg.path, 'package.json');
145
+ if (!existsSync(pkgJsonPath))
146
+ return edges;
147
+ try {
148
+ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
149
+ const allDeps = {
150
+ ...pkgJson.dependencies,
151
+ ...pkgJson.peerDependencies,
152
+ };
153
+ const devDeps = pkgJson.devDependencies ?? {};
154
+ for (const [dep] of Object.entries(allDeps)) {
155
+ if (workspaceNames.has(dep)) {
156
+ edges.push({ from: pkg.name, to: dep, type: 'workspace' });
157
+ }
158
+ }
159
+ for (const [dep] of Object.entries(devDeps)) {
160
+ if (workspaceNames.has(dep)) {
161
+ edges.push({ from: pkg.name, to: dep, type: 'dev' });
162
+ }
163
+ }
164
+ }
165
+ catch {
166
+ /* ignore bad JSON */
167
+ }
168
+ return edges;
169
+ }
170
+ function discoverGoDependencies(pkg, workspaceNames) {
171
+ const edges = [];
172
+ const goModPath = join(pkg.path, 'go.mod');
173
+ if (!existsSync(goModPath))
174
+ return edges;
175
+ try {
176
+ const content = readFileSync(goModPath, 'utf-8');
177
+ for (const name of workspaceNames) {
178
+ if (name !== pkg.name && content.includes(name)) {
179
+ edges.push({ from: pkg.name, to: name, type: 'workspace' });
180
+ }
181
+ }
182
+ }
183
+ catch {
184
+ /* ignore */
185
+ }
186
+ return edges;
187
+ }
188
+ function discoverCargoDependencies(pkg, workspaceNames) {
189
+ const edges = [];
190
+ const cargoPath = join(pkg.path, 'Cargo.toml');
191
+ if (!existsSync(cargoPath))
192
+ return edges;
193
+ try {
194
+ const content = readFileSync(cargoPath, 'utf-8');
195
+ for (const name of workspaceNames) {
196
+ if (name !== pkg.name && content.includes(`path = `) && content.includes(name)) {
197
+ edges.push({ from: pkg.name, to: name, type: 'workspace' });
198
+ }
199
+ }
200
+ }
201
+ catch {
202
+ /* ignore */
203
+ }
204
+ return edges;
205
+ }
206
+ function layoutToPackageManager(layout) {
207
+ switch (layout) {
208
+ case 'pnpm-workspace':
209
+ return 'pnpm';
210
+ case 'npm-workspaces':
211
+ return 'npm';
212
+ case 'yarn-workspaces':
213
+ return 'yarn';
214
+ case 'go-workspace':
215
+ return 'go';
216
+ case 'cargo-workspace':
217
+ return 'cargo';
218
+ default:
219
+ return 'unknown';
220
+ }
221
+ }
222
+ function readVersion(pkg, layout) {
223
+ if (layout === 'go-workspace' || layout === 'cargo-workspace')
224
+ return undefined;
225
+ const pkgJsonPath = join(pkg.path, 'package.json');
226
+ if (!existsSync(pkgJsonPath))
227
+ return undefined;
228
+ try {
229
+ return JSON.parse(readFileSync(pkgJsonPath, 'utf-8')).version;
230
+ }
231
+ catch {
232
+ return undefined;
233
+ }
234
+ }
235
+ //# sourceMappingURL=service-map-builder.js.map
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Types for multi-repo/monorepo orchestration.
3
+ */
4
+ export interface ServiceNode {
5
+ name: string;
6
+ path: string;
7
+ /** Package manager or build system. */
8
+ packageManager: 'npm' | 'pnpm' | 'yarn' | 'go' | 'cargo' | 'unknown';
9
+ /** Direct dependencies on other services in the workspace. */
10
+ dependencies: string[];
11
+ /** Services that depend on this one. */
12
+ dependents: string[];
13
+ /** Version from package.json or equivalent. */
14
+ version?: string;
15
+ }
16
+ export interface ServiceMap {
17
+ services: ServiceNode[];
18
+ /** Dependency edges between services. */
19
+ edges: ServiceEdge[];
20
+ /** Root directory of the workspace. */
21
+ rootPath: string;
22
+ /** Detected layout type. */
23
+ layout: MonorepoLayout;
24
+ }
25
+ export interface ServiceEdge {
26
+ from: string;
27
+ to: string;
28
+ /** Type of dependency. */
29
+ type: 'workspace' | 'external' | 'dev';
30
+ }
31
+ export type MonorepoLayout = 'pnpm-workspace' | 'npm-workspaces' | 'yarn-workspaces' | 'go-workspace' | 'cargo-workspace' | 'single-repo';
32
+ export interface WorkspaceConfig {
33
+ layout: MonorepoLayout;
34
+ rootPath: string;
35
+ packages: WorkspacePackage[];
36
+ }
37
+ export interface WorkspacePackage {
38
+ name: string;
39
+ path: string;
40
+ relativePath: string;
41
+ }
42
+ export interface ImpactResult {
43
+ /** Changed files that triggered the analysis. */
44
+ changedFiles: string[];
45
+ /** Directly affected services (contain changed files). */
46
+ directlyAffected: string[];
47
+ /** Transitively affected downstream services. */
48
+ transitivelyAffected: string[];
49
+ /** All affected services (union of direct + transitive). */
50
+ allAffected: string[];
51
+ /** Services that are safe / not affected. */
52
+ unaffected: string[];
53
+ }
54
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Types for multi-repo/monorepo orchestration.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,4 @@
1
+ export { SlackMessenger, type SlackConfig } from './slack-messenger.js';
2
+ export { TeamsMessenger, type TeamsConfig } from './teams-messenger.js';
3
+ export { NotificationRouter, type PipelineEvent, type PipelineEventType, type NotificationRoute, type NotificationTemplate, } from './notification-router.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,4 @@
1
+ export { SlackMessenger } from './slack-messenger.js';
2
+ export { TeamsMessenger } from './teams-messenger.js';
3
+ export { NotificationRouter, } from './notification-router.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Notification router — dispatches pipeline events to configured messengers.
3
+ *
4
+ * Routes events like pipeline-start, gate-failure, agent-complete, pr-created
5
+ * to one or more Messenger implementations with filtering and template rendering.
6
+ */
7
+ import type { Messenger } from '@ai-sdlc/reference';
8
+ export type PipelineEventType = 'pipeline-start' | 'pipeline-complete' | 'pipeline-failed' | 'gate-pass' | 'gate-failure' | 'agent-start' | 'agent-complete' | 'agent-failed' | 'pr-created' | 'approval-required' | 'promotion' | 'demotion' | 'cost-alert' | 'deploy-start' | 'deploy-complete' | 'deploy-failed' | 'rollout-progressing' | 'rollout-complete' | 'rollout-rollback';
9
+ export interface PipelineEvent {
10
+ type: PipelineEventType;
11
+ /** Context variables for template rendering. */
12
+ data: Record<string, string | number | boolean>;
13
+ /** Severity override. */
14
+ severity?: 'info' | 'warning' | 'error';
15
+ /** Timestamp. */
16
+ timestamp?: string;
17
+ }
18
+ export interface NotificationRoute {
19
+ /** Name of this route for identification. */
20
+ name: string;
21
+ /** Messenger to dispatch to. */
22
+ messenger: Messenger;
23
+ /** Channel to send to. */
24
+ channel: string;
25
+ /** Event types to route (empty = all events). */
26
+ events?: PipelineEventType[];
27
+ /** Minimum severity to route. */
28
+ minSeverity?: 'info' | 'warning' | 'error';
29
+ /** Whether to use threads for related events. */
30
+ useThreads?: boolean;
31
+ }
32
+ export interface NotificationTemplate {
33
+ title: string;
34
+ body: string;
35
+ }
36
+ export declare class NotificationRouter {
37
+ private routes;
38
+ private templates;
39
+ private activeThreads;
40
+ constructor(customTemplates?: Partial<Record<PipelineEventType, NotificationTemplate>>);
41
+ /**
42
+ * Add a notification route.
43
+ */
44
+ addRoute(route: NotificationRoute): void;
45
+ /**
46
+ * Remove a route by name.
47
+ */
48
+ removeRoute(name: string): void;
49
+ /**
50
+ * Dispatch a pipeline event to all matching routes.
51
+ */
52
+ dispatch(event: PipelineEvent): Promise<void>;
53
+ /**
54
+ * Get the count of configured routes.
55
+ */
56
+ get routeCount(): number;
57
+ private matchesRoute;
58
+ private sendToRoute;
59
+ private renderTemplate;
60
+ private defaultSeverity;
61
+ }
62
+ //# sourceMappingURL=notification-router.d.ts.map