@ginkoai/cli 1.6.2 → 1.7.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/dist/commands/agent/agent-client.d.ts +150 -0
- package/dist/commands/agent/agent-client.d.ts.map +1 -0
- package/dist/commands/agent/agent-client.js +170 -0
- package/dist/commands/agent/agent-client.js.map +1 -0
- package/dist/commands/agent/index.d.ts +22 -0
- package/dist/commands/agent/index.d.ts.map +1 -0
- package/dist/commands/agent/index.js +121 -0
- package/dist/commands/agent/index.js.map +1 -0
- package/dist/commands/agent/list.d.ts +22 -0
- package/dist/commands/agent/list.d.ts.map +1 -0
- package/dist/commands/agent/list.js +119 -0
- package/dist/commands/agent/list.js.map +1 -0
- package/dist/commands/agent/register.d.ts +21 -0
- package/dist/commands/agent/register.d.ts.map +1 -0
- package/dist/commands/agent/register.js +97 -0
- package/dist/commands/agent/register.js.map +1 -0
- package/dist/commands/agent/status.d.ts +19 -0
- package/dist/commands/agent/status.d.ts.map +1 -0
- package/dist/commands/agent/status.js +271 -0
- package/dist/commands/agent/status.js.map +1 -0
- package/dist/commands/agent/work.d.ts +22 -0
- package/dist/commands/agent/work.d.ts.map +1 -0
- package/dist/commands/agent/work.js +459 -0
- package/dist/commands/agent/work.js.map +1 -0
- package/dist/commands/checkpoint/create.d.ts +27 -0
- package/dist/commands/checkpoint/create.d.ts.map +1 -0
- package/dist/commands/checkpoint/create.js +82 -0
- package/dist/commands/checkpoint/create.js.map +1 -0
- package/dist/commands/checkpoint/index.d.ts +23 -0
- package/dist/commands/checkpoint/index.d.ts.map +1 -0
- package/dist/commands/checkpoint/index.js +91 -0
- package/dist/commands/checkpoint/index.js.map +1 -0
- package/dist/commands/checkpoint/list.d.ts +27 -0
- package/dist/commands/checkpoint/list.d.ts.map +1 -0
- package/dist/commands/checkpoint/list.js +115 -0
- package/dist/commands/checkpoint/list.js.map +1 -0
- package/dist/commands/checkpoint/show.d.ts +23 -0
- package/dist/commands/checkpoint/show.d.ts.map +1 -0
- package/dist/commands/checkpoint/show.js +102 -0
- package/dist/commands/checkpoint/show.js.map +1 -0
- package/dist/commands/dlq.d.ts +24 -0
- package/dist/commands/dlq.d.ts.map +1 -0
- package/dist/commands/dlq.js +172 -0
- package/dist/commands/dlq.js.map +1 -0
- package/dist/commands/escalation/create.d.ts +22 -0
- package/dist/commands/escalation/create.d.ts.map +1 -0
- package/dist/commands/escalation/create.js +122 -0
- package/dist/commands/escalation/create.js.map +1 -0
- package/dist/commands/escalation/escalation-client.d.ts +101 -0
- package/dist/commands/escalation/escalation-client.d.ts.map +1 -0
- package/dist/commands/escalation/escalation-client.js +129 -0
- package/dist/commands/escalation/escalation-client.js.map +1 -0
- package/dist/commands/escalation/index.d.ts +22 -0
- package/dist/commands/escalation/index.d.ts.map +1 -0
- package/dist/commands/escalation/index.js +94 -0
- package/dist/commands/escalation/index.js.map +1 -0
- package/dist/commands/escalation/list.d.ts +24 -0
- package/dist/commands/escalation/list.d.ts.map +1 -0
- package/dist/commands/escalation/list.js +170 -0
- package/dist/commands/escalation/list.js.map +1 -0
- package/dist/commands/escalation/resolve.d.ts +20 -0
- package/dist/commands/escalation/resolve.d.ts.map +1 -0
- package/dist/commands/escalation/resolve.js +102 -0
- package/dist/commands/escalation/resolve.js.map +1 -0
- package/dist/commands/graph/api-client.d.ts +21 -1
- package/dist/commands/graph/api-client.d.ts.map +1 -1
- package/dist/commands/graph/api-client.js +23 -0
- package/dist/commands/graph/api-client.js.map +1 -1
- package/dist/commands/handoff.d.ts.map +1 -1
- package/dist/commands/handoff.js +9 -1
- package/dist/commands/handoff.js.map +1 -1
- package/dist/commands/log.d.ts +3 -0
- package/dist/commands/log.d.ts.map +1 -1
- package/dist/commands/log.js +73 -14
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/notifications/history.d.ts +21 -0
- package/dist/commands/notifications/history.d.ts.map +1 -0
- package/dist/commands/notifications/history.js +160 -0
- package/dist/commands/notifications/history.js.map +1 -0
- package/dist/commands/notifications/index.d.ts +22 -0
- package/dist/commands/notifications/index.d.ts.map +1 -0
- package/dist/commands/notifications/index.js +87 -0
- package/dist/commands/notifications/index.js.map +1 -0
- package/dist/commands/notifications/list.d.ts +19 -0
- package/dist/commands/notifications/list.d.ts.map +1 -0
- package/dist/commands/notifications/list.js +132 -0
- package/dist/commands/notifications/list.js.map +1 -0
- package/dist/commands/notifications/test.d.ts +19 -0
- package/dist/commands/notifications/test.d.ts.map +1 -0
- package/dist/commands/notifications/test.js +217 -0
- package/dist/commands/notifications/test.js.map +1 -0
- package/dist/commands/orchestrate.d.ts +25 -0
- package/dist/commands/orchestrate.d.ts.map +1 -0
- package/dist/commands/orchestrate.js +858 -0
- package/dist/commands/orchestrate.js.map +1 -0
- package/dist/commands/sprint/deps.d.ts +29 -0
- package/dist/commands/sprint/deps.d.ts.map +1 -0
- package/dist/commands/sprint/deps.js +269 -0
- package/dist/commands/sprint/deps.js.map +1 -0
- package/dist/commands/sprint/index.d.ts +10 -5
- package/dist/commands/sprint/index.d.ts.map +1 -1
- package/dist/commands/sprint/index.js +26 -5
- package/dist/commands/sprint/index.js.map +1 -1
- package/dist/commands/start/index.d.ts.map +1 -1
- package/dist/commands/start/index.js +6 -0
- package/dist/commands/start/index.js.map +1 -1
- package/dist/commands/start/start-reflection.d.ts.map +1 -1
- package/dist/commands/start/start-reflection.js +8 -0
- package/dist/commands/start/start-reflection.js.map +1 -1
- package/dist/commands/verify.d.ts +17 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +232 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/core/session-log-manager.d.ts +1 -1
- package/dist/core/session-log-manager.d.ts.map +1 -1
- package/dist/index.js +78 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/__tests__/task-timeout.test.d.ts +12 -0
- package/dist/lib/__tests__/task-timeout.test.d.ts.map +1 -0
- package/dist/lib/__tests__/task-timeout.test.js +278 -0
- package/dist/lib/__tests__/task-timeout.test.js.map +1 -0
- package/dist/lib/agent-heartbeat.d.ts +68 -0
- package/dist/lib/agent-heartbeat.d.ts.map +1 -0
- package/dist/lib/agent-heartbeat.js +117 -0
- package/dist/lib/agent-heartbeat.js.map +1 -0
- package/dist/lib/checkpoint.d.ts +85 -0
- package/dist/lib/checkpoint.d.ts.map +1 -0
- package/dist/lib/checkpoint.js +323 -0
- package/dist/lib/checkpoint.js.map +1 -0
- package/dist/lib/context-metrics.d.ts +230 -0
- package/dist/lib/context-metrics.d.ts.map +1 -0
- package/dist/lib/context-metrics.js +372 -0
- package/dist/lib/context-metrics.js.map +1 -0
- package/dist/lib/dead-letter-queue.d.ts +108 -0
- package/dist/lib/dead-letter-queue.d.ts.map +1 -0
- package/dist/lib/dead-letter-queue.js +378 -0
- package/dist/lib/dead-letter-queue.js.map +1 -0
- package/dist/lib/event-logger.d.ts +9 -1
- package/dist/lib/event-logger.d.ts.map +1 -1
- package/dist/lib/event-logger.js +45 -3
- package/dist/lib/event-logger.js.map +1 -1
- package/dist/lib/event-queue.d.ts.map +1 -1
- package/dist/lib/event-queue.js +13 -2
- package/dist/lib/event-queue.js.map +1 -1
- package/dist/lib/examples/timeout-demo.d.ts +13 -0
- package/dist/lib/examples/timeout-demo.d.ts.map +1 -0
- package/dist/lib/examples/timeout-demo.js +102 -0
- package/dist/lib/examples/timeout-demo.js.map +1 -0
- package/dist/lib/examples/timeout-integration-example.d.ts +17 -0
- package/dist/lib/examples/timeout-integration-example.d.ts.map +1 -0
- package/dist/lib/examples/timeout-integration-example.js +223 -0
- package/dist/lib/examples/timeout-integration-example.js.map +1 -0
- package/dist/lib/notification-hooks.d.ts +103 -0
- package/dist/lib/notification-hooks.d.ts.map +1 -0
- package/dist/lib/notification-hooks.js +223 -0
- package/dist/lib/notification-hooks.js.map +1 -0
- package/dist/lib/notifications/discord.d.ts +20 -0
- package/dist/lib/notifications/discord.d.ts.map +1 -0
- package/dist/lib/notifications/discord.js +140 -0
- package/dist/lib/notifications/discord.js.map +1 -0
- package/dist/lib/notifications/index.d.ts +66 -0
- package/dist/lib/notifications/index.d.ts.map +1 -0
- package/dist/lib/notifications/index.js +120 -0
- package/dist/lib/notifications/index.js.map +1 -0
- package/dist/lib/notifications/slack.d.ts +20 -0
- package/dist/lib/notifications/slack.d.ts.map +1 -0
- package/dist/lib/notifications/slack.js +186 -0
- package/dist/lib/notifications/slack.js.map +1 -0
- package/dist/lib/notifications/teams.d.ts +20 -0
- package/dist/lib/notifications/teams.d.ts.map +1 -0
- package/dist/lib/notifications/teams.js +146 -0
- package/dist/lib/notifications/teams.js.map +1 -0
- package/dist/lib/notifications/webhook.d.ts +23 -0
- package/dist/lib/notifications/webhook.d.ts.map +1 -0
- package/dist/lib/notifications/webhook.js +65 -0
- package/dist/lib/notifications/webhook.js.map +1 -0
- package/dist/lib/orchestrator-state.d.ts +194 -0
- package/dist/lib/orchestrator-state.d.ts.map +1 -0
- package/dist/lib/orchestrator-state.js +332 -0
- package/dist/lib/orchestrator-state.js.map +1 -0
- package/dist/lib/realtime-cursor.d.ts +107 -0
- package/dist/lib/realtime-cursor.d.ts.map +1 -0
- package/dist/lib/realtime-cursor.js +260 -0
- package/dist/lib/realtime-cursor.js.map +1 -0
- package/dist/lib/rollback.d.ts +86 -0
- package/dist/lib/rollback.d.ts.map +1 -0
- package/dist/lib/rollback.js +405 -0
- package/dist/lib/rollback.js.map +1 -0
- package/dist/lib/sprint-loader.d.ts +39 -2
- package/dist/lib/sprint-loader.d.ts.map +1 -1
- package/dist/lib/sprint-loader.js +269 -5
- package/dist/lib/sprint-loader.js.map +1 -1
- package/dist/lib/stale-agent-detector.d.ts +102 -0
- package/dist/lib/stale-agent-detector.d.ts.map +1 -0
- package/dist/lib/stale-agent-detector.js +156 -0
- package/dist/lib/stale-agent-detector.js.map +1 -0
- package/dist/lib/task-dependencies.d.ts +143 -0
- package/dist/lib/task-dependencies.d.ts.map +1 -0
- package/dist/lib/task-dependencies.js +357 -0
- package/dist/lib/task-dependencies.js.map +1 -0
- package/dist/lib/task-timeout.d.ts +153 -0
- package/dist/lib/task-timeout.d.ts.map +1 -0
- package/dist/lib/task-timeout.js +505 -0
- package/dist/lib/task-timeout.js.map +1 -0
- package/dist/lib/verification/build-check.d.ts +55 -0
- package/dist/lib/verification/build-check.d.ts.map +1 -0
- package/dist/lib/verification/build-check.js +111 -0
- package/dist/lib/verification/build-check.js.map +1 -0
- package/dist/lib/verification/index.d.ts +19 -0
- package/dist/lib/verification/index.d.ts.map +1 -0
- package/dist/lib/verification/index.js +17 -0
- package/dist/lib/verification/index.js.map +1 -0
- package/dist/lib/verification/lint-check.d.ts +34 -0
- package/dist/lib/verification/lint-check.d.ts.map +1 -0
- package/dist/lib/verification/lint-check.js +215 -0
- package/dist/lib/verification/lint-check.js.map +1 -0
- package/dist/lib/verification/test-runner.d.ts +50 -0
- package/dist/lib/verification/test-runner.d.ts.map +1 -0
- package/dist/lib/verification/test-runner.js +225 -0
- package/dist/lib/verification/test-runner.js.map +1 -0
- package/dist/utils/command-helpers.d.ts.map +1 -1
- package/dist/utils/command-helpers.js +7 -0
- package/dist/utils/command-helpers.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileType: utility
|
|
3
|
+
* @status: current
|
|
4
|
+
* @updated: 2025-12-07
|
|
5
|
+
* @tags: [agent, stale-detection, epic-004, multi-agent, resilience]
|
|
6
|
+
* @related: [agent-heartbeat.ts, ../commands/graph/api-client.ts]
|
|
7
|
+
* @priority: high
|
|
8
|
+
* @complexity: medium
|
|
9
|
+
* @dependencies: []
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Default configuration
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_CONFIG = {
|
|
15
|
+
gracePeriodMinutes: 5,
|
|
16
|
+
graphId: process.env.GINKO_GRAPH_ID || '',
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Detect stale agents
|
|
20
|
+
*
|
|
21
|
+
* Identifies agents that haven't sent a heartbeat within the grace period
|
|
22
|
+
* and are not already marked as offline.
|
|
23
|
+
*
|
|
24
|
+
* @param config - Optional configuration overrides
|
|
25
|
+
* @returns Array of stale agents with their claimed tasks
|
|
26
|
+
*/
|
|
27
|
+
export async function detectStaleAgents(config) {
|
|
28
|
+
const finalConfig = { ...DEFAULT_CONFIG, ...config };
|
|
29
|
+
if (!finalConfig.graphId) {
|
|
30
|
+
throw new Error('Graph ID not configured. Set GINKO_GRAPH_ID environment variable.');
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
// Import graph API client lazily
|
|
34
|
+
const { GraphApiClient } = await import('../commands/graph/api-client.js');
|
|
35
|
+
const client = new GraphApiClient();
|
|
36
|
+
// Call stale detection API
|
|
37
|
+
const response = await client.request('GET', `/api/v1/agent/stale?graphId=${finalConfig.graphId}&gracePeriod=${finalConfig.gracePeriodMinutes}`);
|
|
38
|
+
// Convert to StaleAgent objects
|
|
39
|
+
return response.staleAgents.map((agent) => ({
|
|
40
|
+
agentId: agent.agentId,
|
|
41
|
+
lastHeartbeat: new Date(agent.lastHeartbeat),
|
|
42
|
+
staleSince: new Date(agent.staleSince),
|
|
43
|
+
claimedTasks: agent.claimedTasks,
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
48
|
+
console.warn('[StaleAgentDetector] Failed to detect stale agents:', errorMessage);
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Release tasks claimed by a stale agent
|
|
54
|
+
*
|
|
55
|
+
* Marks agent as offline and releases all tasks it has claimed,
|
|
56
|
+
* making them available for other agents to claim.
|
|
57
|
+
*
|
|
58
|
+
* @param agentId - Agent ID to release tasks for
|
|
59
|
+
* @param config - Optional configuration overrides
|
|
60
|
+
* @returns Array of released tasks
|
|
61
|
+
*/
|
|
62
|
+
export async function releaseStaleAgentTasks(agentId, config) {
|
|
63
|
+
const finalConfig = { ...DEFAULT_CONFIG, ...config };
|
|
64
|
+
if (!finalConfig.graphId) {
|
|
65
|
+
throw new Error('Graph ID not configured. Set GINKO_GRAPH_ID environment variable.');
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
// Import graph API client lazily
|
|
69
|
+
const { GraphApiClient } = await import('../commands/graph/api-client.js');
|
|
70
|
+
const client = new GraphApiClient();
|
|
71
|
+
// Call release API
|
|
72
|
+
const response = await client.request('POST', `/api/v1/agent/stale/release?graphId=${finalConfig.graphId}`, { agentId });
|
|
73
|
+
if (!response.success) {
|
|
74
|
+
throw new Error(`Failed to release tasks for agent ${agentId}`);
|
|
75
|
+
}
|
|
76
|
+
// Convert to ReleasedTask objects
|
|
77
|
+
return response.releasedTasks.map((task) => ({
|
|
78
|
+
taskId: task.taskId,
|
|
79
|
+
previousAgent: task.previousAgent,
|
|
80
|
+
releasedAt: new Date(task.releasedAt),
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
85
|
+
console.warn('[StaleAgentDetector] Failed to release stale agent tasks:', errorMessage);
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get last heartbeat timestamp for an agent
|
|
91
|
+
*
|
|
92
|
+
* @param agentId - Agent ID to check
|
|
93
|
+
* @param config - Optional configuration overrides
|
|
94
|
+
* @returns Last heartbeat timestamp or null if not found
|
|
95
|
+
*/
|
|
96
|
+
export async function getAgentLastHeartbeat(agentId, config) {
|
|
97
|
+
const finalConfig = { ...DEFAULT_CONFIG, ...config };
|
|
98
|
+
if (!finalConfig.graphId) {
|
|
99
|
+
throw new Error('Graph ID not configured. Set GINKO_GRAPH_ID environment variable.');
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
// Import graph API client lazily
|
|
103
|
+
const { GraphApiClient } = await import('../commands/graph/api-client.js');
|
|
104
|
+
const client = new GraphApiClient();
|
|
105
|
+
// Call agent details API
|
|
106
|
+
const response = await client.request('GET', `/api/v1/agent/${agentId}?graphId=${finalConfig.graphId}`);
|
|
107
|
+
if (!response.agent.lastHeartbeat) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
return new Date(response.agent.lastHeartbeat);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
114
|
+
console.warn('[StaleAgentDetector] Failed to get agent heartbeat:', errorMessage);
|
|
115
|
+
// If agent not found, return null instead of throwing
|
|
116
|
+
if (errorMessage.includes('not found') || errorMessage.includes('404')) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Detect and release all stale agents
|
|
124
|
+
*
|
|
125
|
+
* Convenience method that detects stale agents and releases their tasks.
|
|
126
|
+
* Typically used in periodic cleanup jobs.
|
|
127
|
+
*
|
|
128
|
+
* @param config - Optional configuration overrides
|
|
129
|
+
* @returns Summary of stale agents and released tasks
|
|
130
|
+
*/
|
|
131
|
+
export async function detectAndReleaseStaleAgents(config) {
|
|
132
|
+
console.log('[StaleAgentDetector] Starting stale agent detection...');
|
|
133
|
+
const staleAgents = await detectStaleAgents(config);
|
|
134
|
+
if (staleAgents.length === 0) {
|
|
135
|
+
console.log('[StaleAgentDetector] No stale agents detected');
|
|
136
|
+
return { staleAgents: [], releasedTasks: [] };
|
|
137
|
+
}
|
|
138
|
+
console.log(`[StaleAgentDetector] Found ${staleAgents.length} stale agent(s)`);
|
|
139
|
+
const allReleasedTasks = [];
|
|
140
|
+
for (const agent of staleAgents) {
|
|
141
|
+
console.log(`[StaleAgentDetector] Releasing tasks for stale agent ${agent.agentId}...`);
|
|
142
|
+
try {
|
|
143
|
+
const releasedTasks = await releaseStaleAgentTasks(agent.agentId, config);
|
|
144
|
+
allReleasedTasks.push(...releasedTasks);
|
|
145
|
+
console.log(`[StaleAgentDetector] Released ${releasedTasks.length} task(s) from ${agent.agentId}`);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
149
|
+
console.error(`[StaleAgentDetector] Failed to release tasks for ${agent.agentId}:`, errorMessage);
|
|
150
|
+
// Continue with other agents even if one fails
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
console.log(`[StaleAgentDetector] Complete: ${staleAgents.length} stale agent(s), ${allReleasedTasks.length} task(s) released`);
|
|
154
|
+
return { staleAgents, releasedTasks: allReleasedTasks };
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=stale-agent-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stale-agent-detector.js","sourceRoot":"","sources":["../../src/lib/stale-agent-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileType: utility
|
|
3
|
+
* @status: current
|
|
4
|
+
* @updated: 2025-12-07
|
|
5
|
+
* @tags: [task, dependencies, topological-sort, orchestration, epic-004, sprint-4]
|
|
6
|
+
* @related: [sprint-loader.ts, ../commands/orchestrate.ts, ../commands/sprint/deps.ts]
|
|
7
|
+
* @priority: high
|
|
8
|
+
* @complexity: medium
|
|
9
|
+
* @dependencies: []
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Task Dependencies (EPIC-004 Sprint 4 TASK-6)
|
|
13
|
+
*
|
|
14
|
+
* Provides topological ordering and dependency management for tasks:
|
|
15
|
+
* - Compute execution order in waves (parallel execution within waves)
|
|
16
|
+
* - Detect circular dependencies
|
|
17
|
+
* - Find available tasks (dependencies satisfied)
|
|
18
|
+
* - Validate dependency graph
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Task with dependency information
|
|
22
|
+
*/
|
|
23
|
+
export interface Task {
|
|
24
|
+
id: string;
|
|
25
|
+
dependsOn: string[];
|
|
26
|
+
status?: 'pending' | 'in_progress' | 'complete' | 'blocked';
|
|
27
|
+
title?: string;
|
|
28
|
+
effort?: string;
|
|
29
|
+
priority?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Group of tasks that can execute in parallel
|
|
33
|
+
*/
|
|
34
|
+
export interface ExecutionWave {
|
|
35
|
+
wave: number;
|
|
36
|
+
tasks: Task[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Dependency validation error
|
|
40
|
+
*/
|
|
41
|
+
export interface DependencyError {
|
|
42
|
+
type: 'missing' | 'self_reference' | 'circular';
|
|
43
|
+
taskId: string;
|
|
44
|
+
details: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Dependency graph statistics
|
|
48
|
+
*/
|
|
49
|
+
export interface DependencyStats {
|
|
50
|
+
totalTasks: number;
|
|
51
|
+
tasksWithDeps: number;
|
|
52
|
+
tasksWithoutDeps: number;
|
|
53
|
+
maxDepth: number;
|
|
54
|
+
avgDepsPerTask: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Detect circular dependencies using three-color DFS
|
|
58
|
+
*
|
|
59
|
+
* Colors:
|
|
60
|
+
* - white (0): Not visited
|
|
61
|
+
* - gray (1): Currently in recursion stack (visiting)
|
|
62
|
+
* - black (2): Fully processed
|
|
63
|
+
*
|
|
64
|
+
* A back edge to a gray node indicates a cycle.
|
|
65
|
+
*
|
|
66
|
+
* @param tasks - Array of tasks with dependencies
|
|
67
|
+
* @returns Array of cycles found, e.g., [['TASK-1', 'TASK-2', 'TASK-1']]
|
|
68
|
+
*/
|
|
69
|
+
export declare function detectCircularDependencies(tasks: Task[]): string[][];
|
|
70
|
+
/**
|
|
71
|
+
* Validate dependencies for common errors
|
|
72
|
+
*
|
|
73
|
+
* Checks for:
|
|
74
|
+
* - Self-referential dependencies (TASK-1 depends on TASK-1)
|
|
75
|
+
* - Missing dependencies (depends on non-existent task)
|
|
76
|
+
*
|
|
77
|
+
* @param tasks - Array of tasks with dependencies
|
|
78
|
+
* @returns Array of validation errors
|
|
79
|
+
*/
|
|
80
|
+
export declare function validateDependencies(tasks: Task[]): DependencyError[];
|
|
81
|
+
/**
|
|
82
|
+
* Compute execution order using modified Kahn's algorithm
|
|
83
|
+
*
|
|
84
|
+
* Groups tasks into waves where:
|
|
85
|
+
* - Wave 1: Tasks with no dependencies
|
|
86
|
+
* - Wave N: Tasks that depend only on tasks in waves 1..N-1
|
|
87
|
+
*
|
|
88
|
+
* Tasks within a wave can execute in parallel.
|
|
89
|
+
*
|
|
90
|
+
* @param tasks - Array of tasks with dependencies
|
|
91
|
+
* @returns Array of execution waves
|
|
92
|
+
* @throws Error if circular dependencies detected
|
|
93
|
+
*/
|
|
94
|
+
export declare function getExecutionOrder(tasks: Task[]): ExecutionWave[];
|
|
95
|
+
/**
|
|
96
|
+
* Get tasks that are ready to execute
|
|
97
|
+
*
|
|
98
|
+
* A task is available if:
|
|
99
|
+
* - Status is 'pending' or undefined
|
|
100
|
+
* - All dependencies have status 'complete'
|
|
101
|
+
*
|
|
102
|
+
* @param tasks - Array of tasks with dependencies and status
|
|
103
|
+
* @returns Tasks ready for execution
|
|
104
|
+
*/
|
|
105
|
+
export declare function getAvailableTasks(tasks: Task[]): Task[];
|
|
106
|
+
/**
|
|
107
|
+
* Get tasks that are blocked (have incomplete dependencies)
|
|
108
|
+
*
|
|
109
|
+
* @param tasks - Array of tasks with dependencies and status
|
|
110
|
+
* @returns Tasks that cannot start due to incomplete dependencies
|
|
111
|
+
*/
|
|
112
|
+
export declare function getBlockedTasks(tasks: Task[]): Task[];
|
|
113
|
+
/**
|
|
114
|
+
* Compute dependency graph statistics
|
|
115
|
+
*
|
|
116
|
+
* @param tasks - Array of tasks with dependencies
|
|
117
|
+
* @returns Statistics about the dependency graph
|
|
118
|
+
*/
|
|
119
|
+
export declare function getDependencyStats(tasks: Task[]): DependencyStats;
|
|
120
|
+
/**
|
|
121
|
+
* Build reverse dependency map (who depends on this task)
|
|
122
|
+
*
|
|
123
|
+
* @param tasks - Array of tasks with dependencies
|
|
124
|
+
* @returns Map from task ID to array of dependent task IDs
|
|
125
|
+
*/
|
|
126
|
+
export declare function buildReverseDependencyMap(tasks: Task[]): Map<string, string[]>;
|
|
127
|
+
/**
|
|
128
|
+
* Get all downstream tasks (tasks that transitively depend on this task)
|
|
129
|
+
*
|
|
130
|
+
* @param taskId - Starting task ID
|
|
131
|
+
* @param tasks - Array of tasks with dependencies
|
|
132
|
+
* @returns Array of downstream task IDs
|
|
133
|
+
*/
|
|
134
|
+
export declare function getDownstreamTasks(taskId: string, tasks: Task[]): string[];
|
|
135
|
+
/**
|
|
136
|
+
* Get all upstream tasks (tasks that this task transitively depends on)
|
|
137
|
+
*
|
|
138
|
+
* @param taskId - Starting task ID
|
|
139
|
+
* @param tasks - Array of tasks with dependencies
|
|
140
|
+
* @returns Array of upstream task IDs
|
|
141
|
+
*/
|
|
142
|
+
export declare function getUpstreamTasks(taskId: string, tasks: Task[]): string[];
|
|
143
|
+
//# sourceMappingURL=task-dependencies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-dependencies.d.ts","sourceRoot":"","sources":["../../src/lib/task-dependencies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;;GAQG;AAEH;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,GAAG,aAAa,GAAG,UAAU,GAAG,SAAS,CAAC;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,GAAG,gBAAgB,GAAG,UAAU,CAAC;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,EAAE,CAiDpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,eAAe,EAAE,CAsCrE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,aAAa,EAAE,CA2EhE;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAuBvD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAsBrD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,eAAe,CA+BjE;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAmB9E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAkB1E;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAwBxE"}
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileType: utility
|
|
3
|
+
* @status: current
|
|
4
|
+
* @updated: 2025-12-07
|
|
5
|
+
* @tags: [task, dependencies, topological-sort, orchestration, epic-004, sprint-4]
|
|
6
|
+
* @related: [sprint-loader.ts, ../commands/orchestrate.ts, ../commands/sprint/deps.ts]
|
|
7
|
+
* @priority: high
|
|
8
|
+
* @complexity: medium
|
|
9
|
+
* @dependencies: []
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Detect circular dependencies using three-color DFS
|
|
13
|
+
*
|
|
14
|
+
* Colors:
|
|
15
|
+
* - white (0): Not visited
|
|
16
|
+
* - gray (1): Currently in recursion stack (visiting)
|
|
17
|
+
* - black (2): Fully processed
|
|
18
|
+
*
|
|
19
|
+
* A back edge to a gray node indicates a cycle.
|
|
20
|
+
*
|
|
21
|
+
* @param tasks - Array of tasks with dependencies
|
|
22
|
+
* @returns Array of cycles found, e.g., [['TASK-1', 'TASK-2', 'TASK-1']]
|
|
23
|
+
*/
|
|
24
|
+
export function detectCircularDependencies(tasks) {
|
|
25
|
+
const cycles = [];
|
|
26
|
+
const taskMap = new Map();
|
|
27
|
+
const color = new Map(); // 0=white, 1=gray, 2=black
|
|
28
|
+
// Build task map
|
|
29
|
+
for (const task of tasks) {
|
|
30
|
+
taskMap.set(task.id, task);
|
|
31
|
+
color.set(task.id, 0); // white
|
|
32
|
+
}
|
|
33
|
+
function dfs(taskId, path) {
|
|
34
|
+
const task = taskMap.get(taskId);
|
|
35
|
+
if (!task)
|
|
36
|
+
return false;
|
|
37
|
+
color.set(taskId, 1); // gray - visiting
|
|
38
|
+
path.push(taskId);
|
|
39
|
+
for (const depId of task.dependsOn) {
|
|
40
|
+
const depColor = color.get(depId);
|
|
41
|
+
if (depColor === 1) {
|
|
42
|
+
// Back edge found - cycle detected
|
|
43
|
+
const cycleStart = path.indexOf(depId);
|
|
44
|
+
const cycle = [...path.slice(cycleStart), depId];
|
|
45
|
+
cycles.push(cycle);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
if (depColor === 0) {
|
|
49
|
+
// White node - recurse
|
|
50
|
+
dfs(depId, path);
|
|
51
|
+
}
|
|
52
|
+
// Black nodes are fully processed, skip
|
|
53
|
+
}
|
|
54
|
+
path.pop();
|
|
55
|
+
color.set(taskId, 2); // black - done
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
// Run DFS from each unvisited node
|
|
59
|
+
for (const task of tasks) {
|
|
60
|
+
if (color.get(task.id) === 0) {
|
|
61
|
+
dfs(task.id, []);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return cycles;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Validate dependencies for common errors
|
|
68
|
+
*
|
|
69
|
+
* Checks for:
|
|
70
|
+
* - Self-referential dependencies (TASK-1 depends on TASK-1)
|
|
71
|
+
* - Missing dependencies (depends on non-existent task)
|
|
72
|
+
*
|
|
73
|
+
* @param tasks - Array of tasks with dependencies
|
|
74
|
+
* @returns Array of validation errors
|
|
75
|
+
*/
|
|
76
|
+
export function validateDependencies(tasks) {
|
|
77
|
+
const errors = [];
|
|
78
|
+
const taskIds = new Set(tasks.map(t => t.id));
|
|
79
|
+
for (const task of tasks) {
|
|
80
|
+
for (const depId of task.dependsOn) {
|
|
81
|
+
// Self-reference check
|
|
82
|
+
if (depId === task.id) {
|
|
83
|
+
errors.push({
|
|
84
|
+
type: 'self_reference',
|
|
85
|
+
taskId: task.id,
|
|
86
|
+
details: `Task ${task.id} depends on itself`,
|
|
87
|
+
});
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
// Missing dependency check
|
|
91
|
+
if (!taskIds.has(depId)) {
|
|
92
|
+
errors.push({
|
|
93
|
+
type: 'missing',
|
|
94
|
+
taskId: task.id,
|
|
95
|
+
details: `Task ${task.id} depends on non-existent task ${depId}`,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Also check for circular dependencies
|
|
101
|
+
const cycles = detectCircularDependencies(tasks);
|
|
102
|
+
for (const cycle of cycles) {
|
|
103
|
+
errors.push({
|
|
104
|
+
type: 'circular',
|
|
105
|
+
taskId: cycle[0],
|
|
106
|
+
details: `Circular dependency: ${cycle.join(' → ')}`,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return errors;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Compute execution order using modified Kahn's algorithm
|
|
113
|
+
*
|
|
114
|
+
* Groups tasks into waves where:
|
|
115
|
+
* - Wave 1: Tasks with no dependencies
|
|
116
|
+
* - Wave N: Tasks that depend only on tasks in waves 1..N-1
|
|
117
|
+
*
|
|
118
|
+
* Tasks within a wave can execute in parallel.
|
|
119
|
+
*
|
|
120
|
+
* @param tasks - Array of tasks with dependencies
|
|
121
|
+
* @returns Array of execution waves
|
|
122
|
+
* @throws Error if circular dependencies detected
|
|
123
|
+
*/
|
|
124
|
+
export function getExecutionOrder(tasks) {
|
|
125
|
+
if (tasks.length === 0) {
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
// Validate first
|
|
129
|
+
const errors = validateDependencies(tasks);
|
|
130
|
+
const circularErrors = errors.filter(e => e.type === 'circular');
|
|
131
|
+
if (circularErrors.length > 0) {
|
|
132
|
+
throw new Error(`Cannot compute execution order: ${circularErrors[0].details}`);
|
|
133
|
+
}
|
|
134
|
+
const taskMap = new Map();
|
|
135
|
+
const inDegree = new Map();
|
|
136
|
+
const dependents = new Map(); // task -> tasks that depend on it
|
|
137
|
+
// Initialize
|
|
138
|
+
for (const task of tasks) {
|
|
139
|
+
taskMap.set(task.id, task);
|
|
140
|
+
inDegree.set(task.id, 0);
|
|
141
|
+
dependents.set(task.id, []);
|
|
142
|
+
}
|
|
143
|
+
// Build in-degree and dependents
|
|
144
|
+
for (const task of tasks) {
|
|
145
|
+
let validDeps = 0;
|
|
146
|
+
for (const depId of task.dependsOn) {
|
|
147
|
+
if (taskMap.has(depId)) {
|
|
148
|
+
validDeps++;
|
|
149
|
+
dependents.get(depId).push(task.id);
|
|
150
|
+
}
|
|
151
|
+
// Skip missing dependencies (already warned in validation)
|
|
152
|
+
}
|
|
153
|
+
inDegree.set(task.id, validDeps);
|
|
154
|
+
}
|
|
155
|
+
const waves = [];
|
|
156
|
+
const processed = new Set();
|
|
157
|
+
// Process waves until all tasks are assigned
|
|
158
|
+
while (processed.size < tasks.length) {
|
|
159
|
+
// Find all tasks with in-degree 0 that haven't been processed
|
|
160
|
+
const waveTasks = [];
|
|
161
|
+
for (const task of tasks) {
|
|
162
|
+
if (!processed.has(task.id) && inDegree.get(task.id) === 0) {
|
|
163
|
+
waveTasks.push(task);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (waveTasks.length === 0) {
|
|
167
|
+
// This shouldn't happen if validation passed, but safety check
|
|
168
|
+
const remaining = tasks.filter(t => !processed.has(t.id));
|
|
169
|
+
throw new Error(`Cannot assign remaining tasks to waves: ${remaining.map(t => t.id).join(', ')}`);
|
|
170
|
+
}
|
|
171
|
+
// Add wave
|
|
172
|
+
waves.push({
|
|
173
|
+
wave: waves.length + 1,
|
|
174
|
+
tasks: waveTasks,
|
|
175
|
+
});
|
|
176
|
+
// Mark as processed and update in-degrees
|
|
177
|
+
for (const task of waveTasks) {
|
|
178
|
+
processed.add(task.id);
|
|
179
|
+
// Decrement in-degree of all dependents
|
|
180
|
+
for (const depId of dependents.get(task.id)) {
|
|
181
|
+
const currentDegree = inDegree.get(depId);
|
|
182
|
+
inDegree.set(depId, currentDegree - 1);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return waves;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get tasks that are ready to execute
|
|
190
|
+
*
|
|
191
|
+
* A task is available if:
|
|
192
|
+
* - Status is 'pending' or undefined
|
|
193
|
+
* - All dependencies have status 'complete'
|
|
194
|
+
*
|
|
195
|
+
* @param tasks - Array of tasks with dependencies and status
|
|
196
|
+
* @returns Tasks ready for execution
|
|
197
|
+
*/
|
|
198
|
+
export function getAvailableTasks(tasks) {
|
|
199
|
+
const taskMap = new Map();
|
|
200
|
+
for (const task of tasks) {
|
|
201
|
+
taskMap.set(task.id, task);
|
|
202
|
+
}
|
|
203
|
+
return tasks.filter(task => {
|
|
204
|
+
// Must be pending (not started, not complete, not blocked)
|
|
205
|
+
const status = task.status || 'pending';
|
|
206
|
+
if (status !== 'pending') {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
// All dependencies must be complete
|
|
210
|
+
for (const depId of task.dependsOn) {
|
|
211
|
+
const dep = taskMap.get(depId);
|
|
212
|
+
if (!dep || dep.status !== 'complete') {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return true;
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Get tasks that are blocked (have incomplete dependencies)
|
|
221
|
+
*
|
|
222
|
+
* @param tasks - Array of tasks with dependencies and status
|
|
223
|
+
* @returns Tasks that cannot start due to incomplete dependencies
|
|
224
|
+
*/
|
|
225
|
+
export function getBlockedTasks(tasks) {
|
|
226
|
+
const taskMap = new Map();
|
|
227
|
+
for (const task of tasks) {
|
|
228
|
+
taskMap.set(task.id, task);
|
|
229
|
+
}
|
|
230
|
+
return tasks.filter(task => {
|
|
231
|
+
const status = task.status || 'pending';
|
|
232
|
+
if (status !== 'pending') {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
// Check if any dependency is incomplete
|
|
236
|
+
for (const depId of task.dependsOn) {
|
|
237
|
+
const dep = taskMap.get(depId);
|
|
238
|
+
if (!dep || dep.status !== 'complete') {
|
|
239
|
+
return true; // Blocked
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return false; // All deps complete, not blocked
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Compute dependency graph statistics
|
|
247
|
+
*
|
|
248
|
+
* @param tasks - Array of tasks with dependencies
|
|
249
|
+
* @returns Statistics about the dependency graph
|
|
250
|
+
*/
|
|
251
|
+
export function getDependencyStats(tasks) {
|
|
252
|
+
if (tasks.length === 0) {
|
|
253
|
+
return {
|
|
254
|
+
totalTasks: 0,
|
|
255
|
+
tasksWithDeps: 0,
|
|
256
|
+
tasksWithoutDeps: 0,
|
|
257
|
+
maxDepth: 0,
|
|
258
|
+
avgDepsPerTask: 0,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
const tasksWithDeps = tasks.filter(t => t.dependsOn.length > 0).length;
|
|
262
|
+
const totalDeps = tasks.reduce((sum, t) => sum + t.dependsOn.length, 0);
|
|
263
|
+
// Compute max depth (longest path in DAG)
|
|
264
|
+
let maxDepth = 0;
|
|
265
|
+
try {
|
|
266
|
+
const waves = getExecutionOrder(tasks);
|
|
267
|
+
maxDepth = waves.length;
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
// Circular dependency - can't compute depth
|
|
271
|
+
maxDepth = -1;
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
totalTasks: tasks.length,
|
|
275
|
+
tasksWithDeps,
|
|
276
|
+
tasksWithoutDeps: tasks.length - tasksWithDeps,
|
|
277
|
+
maxDepth,
|
|
278
|
+
avgDepsPerTask: totalDeps / tasks.length,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Build reverse dependency map (who depends on this task)
|
|
283
|
+
*
|
|
284
|
+
* @param tasks - Array of tasks with dependencies
|
|
285
|
+
* @returns Map from task ID to array of dependent task IDs
|
|
286
|
+
*/
|
|
287
|
+
export function buildReverseDependencyMap(tasks) {
|
|
288
|
+
const reverseMap = new Map();
|
|
289
|
+
// Initialize all tasks
|
|
290
|
+
for (const task of tasks) {
|
|
291
|
+
reverseMap.set(task.id, []);
|
|
292
|
+
}
|
|
293
|
+
// Build reverse relationships
|
|
294
|
+
for (const task of tasks) {
|
|
295
|
+
for (const depId of task.dependsOn) {
|
|
296
|
+
const dependents = reverseMap.get(depId);
|
|
297
|
+
if (dependents) {
|
|
298
|
+
dependents.push(task.id);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return reverseMap;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Get all downstream tasks (tasks that transitively depend on this task)
|
|
306
|
+
*
|
|
307
|
+
* @param taskId - Starting task ID
|
|
308
|
+
* @param tasks - Array of tasks with dependencies
|
|
309
|
+
* @returns Array of downstream task IDs
|
|
310
|
+
*/
|
|
311
|
+
export function getDownstreamTasks(taskId, tasks) {
|
|
312
|
+
const reverseMap = buildReverseDependencyMap(tasks);
|
|
313
|
+
const visited = new Set();
|
|
314
|
+
const result = [];
|
|
315
|
+
function dfs(id) {
|
|
316
|
+
const dependents = reverseMap.get(id) || [];
|
|
317
|
+
for (const depId of dependents) {
|
|
318
|
+
if (!visited.has(depId)) {
|
|
319
|
+
visited.add(depId);
|
|
320
|
+
result.push(depId);
|
|
321
|
+
dfs(depId);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
dfs(taskId);
|
|
326
|
+
return result;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Get all upstream tasks (tasks that this task transitively depends on)
|
|
330
|
+
*
|
|
331
|
+
* @param taskId - Starting task ID
|
|
332
|
+
* @param tasks - Array of tasks with dependencies
|
|
333
|
+
* @returns Array of upstream task IDs
|
|
334
|
+
*/
|
|
335
|
+
export function getUpstreamTasks(taskId, tasks) {
|
|
336
|
+
const taskMap = new Map();
|
|
337
|
+
for (const task of tasks) {
|
|
338
|
+
taskMap.set(task.id, task);
|
|
339
|
+
}
|
|
340
|
+
const visited = new Set();
|
|
341
|
+
const result = [];
|
|
342
|
+
function dfs(id) {
|
|
343
|
+
const task = taskMap.get(id);
|
|
344
|
+
if (!task)
|
|
345
|
+
return;
|
|
346
|
+
for (const depId of task.dependsOn) {
|
|
347
|
+
if (!visited.has(depId)) {
|
|
348
|
+
visited.add(depId);
|
|
349
|
+
result.push(depId);
|
|
350
|
+
dfs(depId);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
dfs(taskId);
|
|
355
|
+
return result;
|
|
356
|
+
}
|
|
357
|
+
//# sourceMappingURL=task-dependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-dependencies.js","sourceRoot":"","sources":["../../src/lib/task-dependencies.ts"],"names":[],"mappings":"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"}
|