@webpresso/agent-kit 0.21.4 → 0.23.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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +93 -66
- package/bin/_run.js +143 -1
- package/bin/runtime-manifest.json +40 -0
- package/catalog/AGENTS.md.tpl +7 -6
- package/catalog/agent/commands/plan-refine.md +3 -3
- package/catalog/agent/commands/pll.md +2 -0
- package/catalog/agent/guides/parallel-execution.md +2 -0
- package/catalog/agent/rules/extraction-parity.md +27 -1
- package/catalog/agent/rules/public-package-safety.md +24 -1
- package/catalog/agent/skills/plan-refine/SKILL.md +5 -4
- package/catalog/agent/skills/pll/SKILL.md +1 -0
- package/catalog/base-kit/.github/workflows/ci.webpresso.yml.tmpl +33 -0
- package/catalog/base-kit/commitlint.config.ts.tmpl +1 -3
- package/catalog/base-kit/e2e/fixtures/smoke.html.tmpl +13 -0
- package/catalog/base-kit/e2e/smoke.spec.ts.tmpl +13 -0
- package/catalog/base-kit/oxlint.config.ts.tmpl +26 -0
- package/catalog/base-kit/playwright.config.ts.tmpl +10 -0
- package/catalog/base-kit/src/quality-sample.test.ts.tmpl +19 -0
- package/catalog/base-kit/src/quality-sample.ts.tmpl +11 -0
- package/catalog/base-kit/stryker.config.ts.tmpl +14 -0
- package/catalog/base-kit/tsconfig.json.tmpl +9 -0
- package/catalog/base-kit/vitest.config.ts.tmpl +10 -0
- package/catalog/docs/templates/adr.md +1 -1
- package/catalog/docs/templates/blueprint.md +2 -0
- package/catalog/docs/templates/blueprint.yaml +16 -15
- package/catalog/docs/templates/guide.md +1 -1
- package/catalog/docs/templates/postmortem.md +1 -1
- package/catalog/docs/templates/research.md +1 -1
- package/catalog/docs/templates/runbook.md +1 -1
- package/catalog/docs/templates/system.md +12 -3
- package/catalog/docs/templates/tech-debt.md +1 -0
- package/commands/blueprint.md +10 -12
- package/dist/esm/audit/blueprint-db-consistency.d.ts +1 -1
- package/dist/esm/audit/blueprint-db-consistency.js +6 -8
- package/dist/esm/audit/blueprint-lifecycle-sql.js +10 -3
- package/dist/esm/audit/cloudflare-deploy-contract.d.ts +3 -0
- package/dist/esm/audit/cloudflare-deploy-contract.js +64 -0
- package/dist/esm/audit/no-legacy-cli-bin.d.ts +3 -0
- package/dist/esm/audit/no-legacy-cli-bin.js +100 -0
- package/dist/esm/audit/package-surface.js +14 -1
- package/dist/esm/audit/repo-guardrails.js +40 -13
- package/dist/esm/audit/resolve-audit-script.d.ts +24 -0
- package/dist/esm/audit/resolve-audit-script.js +27 -0
- package/dist/esm/audit/roadmap-links.js +23 -10
- package/dist/esm/blueprint/core/schema.d.ts +8 -8
- package/dist/esm/blueprint/core/schema.js +2 -2
- package/dist/esm/blueprint/db/enums.d.ts +1 -1
- package/dist/esm/blueprint/db/ingester.js +18 -10
- package/dist/esm/blueprint/index.d.ts +0 -1
- package/dist/esm/blueprint/index.js +0 -2
- package/dist/esm/blueprint/lifecycle/audit.js +9 -2
- package/dist/esm/blueprint/lifecycle/local.js +15 -4
- package/dist/esm/blueprint/local.d.ts +0 -3
- package/dist/esm/blueprint/local.js +0 -2
- package/dist/esm/blueprint/service/BlueprintCreationService.js +16 -8
- package/dist/esm/blueprint/service/BlueprintService.js +37 -19
- package/dist/esm/blueprint/service/scanner.js +73 -9
- package/dist/esm/blueprint/tracked-document/schema.d.ts +2 -2
- package/dist/esm/blueprint/utils/document-paths.d.ts +23 -0
- package/dist/esm/blueprint/utils/document-paths.js +91 -0
- package/dist/esm/blueprint/utils/package-assets.d.ts +11 -0
- package/dist/esm/blueprint/utils/package-assets.js +33 -4
- package/dist/esm/build/package-manifest.js +7 -0
- package/dist/esm/build/release-policy.d.ts +27 -0
- package/dist/esm/build/release-policy.js +29 -0
- package/dist/esm/build/runtime-targets.d.ts +13 -0
- package/dist/esm/build/runtime-targets.js +48 -0
- package/dist/esm/build/sync-catalog-doc-templates.d.ts +23 -0
- package/dist/esm/build/sync-catalog-doc-templates.js +93 -0
- package/dist/esm/cli/auto-update/detect-pm.d.ts +15 -0
- package/dist/esm/cli/auto-update/detect-pm.js +24 -9
- package/dist/esm/cli/auto-update/skip.js +9 -1
- package/dist/esm/cli/bundle/agent-command-inventory.d.ts +120 -0
- package/dist/esm/cli/bundle/agent-command-inventory.js +100 -0
- package/dist/esm/cli/bundle/index.d.ts +17 -0
- package/dist/esm/cli/bundle/index.js +15 -0
- package/dist/esm/cli/cli.d.ts +1 -1
- package/dist/esm/cli/cli.js +49 -5
- package/dist/esm/cli/commands/audit-core.d.ts +1 -1
- package/dist/esm/cli/commands/audit.js +4 -7
- package/dist/esm/cli/commands/blueprint/router.js +16 -10
- package/dist/esm/cli/commands/blueprint/template-resolver.js +8 -4
- package/dist/esm/cli/commands/hook.d.ts +8 -0
- package/dist/esm/cli/commands/hook.js +47 -0
- package/dist/esm/cli/commands/init/host-visibility.js +4 -2
- package/dist/esm/cli/commands/init/index.js +80 -7
- package/dist/esm/cli/commands/init/scaffold-base-kit.d.ts +12 -0
- package/dist/esm/cli/commands/init/scaffold-base-kit.js +142 -7
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/codex-ownership.js +9 -1
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.js +130 -20
- package/dist/esm/cli/commands/init/scaffolders/agent-kit-global/index.d.ts +65 -0
- package/dist/esm/cli/commands/init/scaffolders/agent-kit-global/index.js +64 -0
- package/dist/esm/cli/commands/package-manager.d.ts +15 -0
- package/dist/esm/cli/commands/package-manager.js +42 -0
- package/dist/esm/cli/commands/test.d.ts +1 -0
- package/dist/esm/cli/commands/test.js +2 -1
- package/dist/esm/cli/commands/typecheck.js +10 -19
- package/dist/esm/cli/package-scripts.d.ts +12 -0
- package/dist/esm/cli/package-scripts.js +59 -0
- package/dist/esm/cli/utils.js +3 -22
- package/dist/esm/cli/wp-extensions.d.ts +14 -0
- package/dist/esm/cli/wp-extensions.js +34 -0
- package/dist/esm/config/docs-lint/schemas/common.d.ts +1 -1
- package/dist/esm/config/docs-lint/schemas/implementation-plan.d.ts +2 -2
- package/dist/esm/config/docs-lint/schemas/parent-roadmap.d.ts +1 -1
- package/dist/esm/config/stryker/index.d.ts +85 -0
- package/dist/esm/config/stryker/index.js +31 -0
- package/dist/esm/e2e/command-builder.js +35 -7
- package/dist/esm/e2e/config.d.ts +56 -0
- package/dist/esm/e2e/config.js +114 -0
- package/dist/esm/e2e/execution.js +8 -0
- package/dist/esm/e2e/run-planner.js +2 -0
- package/dist/esm/e2e/types.d.ts +3 -0
- package/dist/esm/format/index.js +5 -1
- package/dist/esm/hooks/guard-switch/index.d.ts +1 -1
- package/dist/esm/hooks/guard-switch/index.js +22 -14
- package/dist/esm/hooks/post-tool/lint-after-edit.d.ts +1 -0
- package/dist/esm/hooks/post-tool/lint-after-edit.js +5 -2
- package/dist/esm/hooks/pretool-guard/validators/file-conventions.js +1 -1
- package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.d.ts +6 -0
- package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.js +27 -2
- package/dist/esm/hooks/pretool-guard/validators/path-contract.d.ts +2 -1
- package/dist/esm/hooks/pretool-guard/validators/path-contract.js +59 -34
- package/dist/esm/hooks/pretool-guard/validators/plan-frontmatter.js +3 -3
- package/dist/esm/hooks/shared/routing-block.js +18 -4
- package/dist/esm/hooks/shared/validators/blueprint.js +3 -0
- package/dist/esm/hooks/stop/qa-changed-files.d.ts +1 -0
- package/dist/esm/hooks/stop/qa-changed-files.js +5 -2
- package/dist/esm/lint/index.js +3 -1
- package/dist/esm/mcp/auto-discover.d.ts +2 -0
- package/dist/esm/mcp/auto-discover.js +14 -6
- package/dist/esm/mcp/blueprint-server.js +379 -80
- package/dist/esm/mcp/cli.js +21 -0
- package/dist/esm/mcp/runners/test.js +15 -0
- package/dist/esm/mcp/server.d.ts +7 -0
- package/dist/esm/mcp/server.js +16 -27
- package/dist/esm/mcp/tools/_registry.d.ts +3 -0
- package/dist/esm/mcp/tools/_registry.js +21 -0
- package/dist/esm/mcp/tools/audit.d.ts +1 -0
- package/dist/esm/mcp/tools/audit.js +13 -8
- package/dist/esm/mcp/tools/typecheck.js +4 -2
- package/dist/esm/mutation/affected.d.ts +9 -0
- package/dist/esm/mutation/affected.js +36 -0
- package/dist/esm/package.json +8 -0
- package/dist/esm/runtime/package-version.d.ts +2 -0
- package/dist/esm/runtime/package-version.js +43 -0
- package/dist/esm/test/command-builder.d.ts +4 -0
- package/dist/esm/test/command-builder.js +28 -3
- package/dist/esm/test-helpers/hermetic-env.d.ts +25 -0
- package/dist/esm/test-helpers/hermetic-env.js +31 -0
- package/dist/esm/tool-runtime/index.d.ts +5 -0
- package/dist/esm/tool-runtime/index.js +24 -0
- package/dist/esm/tool-runtime/resolve-runner.d.ts +16 -0
- package/dist/esm/tool-runtime/resolve-runner.js +42 -0
- package/dist/esm/typecheck/index.js +4 -2
- package/dist/esm/wp-extension/index.d.ts +50 -0
- package/dist/esm/wp-extension/index.js +268 -0
- package/package.json +75 -46
- package/skills/plan-refine/SKILL.md +5 -4
- package/skills/pll/SKILL.md +1 -0
- package/dist/esm/blueprint/dag/cycle-detector.d.ts +0 -12
- package/dist/esm/blueprint/dag/cycle-detector.js +0 -46
- package/dist/esm/blueprint/dag/executor.d.ts +0 -140
- package/dist/esm/blueprint/dag/executor.js +0 -292
- package/dist/esm/blueprint/dag/index.d.ts +0 -20
- package/dist/esm/blueprint/dag/index.js +0 -17
- package/dist/esm/blueprint/dag/interfaces.d.ts +0 -56
- package/dist/esm/blueprint/dag/interfaces.js +0 -13
- package/dist/esm/blueprint/dag/local/independence.d.ts +0 -107
- package/dist/esm/blueprint/dag/local/independence.js +0 -231
- package/dist/esm/blueprint/dag/local/index.d.ts +0 -14
- package/dist/esm/blueprint/dag/local/index.js +0 -14
- package/dist/esm/blueprint/dag/local/package-graph.d.ts +0 -66
- package/dist/esm/blueprint/dag/local/package-graph.js +0 -148
- package/dist/esm/blueprint/dag/plan-parser.d.ts +0 -54
- package/dist/esm/blueprint/dag/plan-parser.js +0 -236
- package/dist/esm/blueprint/dag/task-graph-algorithms.d.ts +0 -13
- package/dist/esm/blueprint/dag/task-graph-algorithms.js +0 -236
- package/dist/esm/blueprint/dag/task-graph.d.ts +0 -171
- package/dist/esm/blueprint/dag/task-graph.js +0 -370
- package/dist/esm/blueprint/dag/types.d.ts +0 -17
- package/dist/esm/blueprint/dag/types.js +0 -2
- package/dist/esm/blueprint/graph/index.d.ts +0 -5
- package/dist/esm/blueprint/graph/index.js +0 -5
- package/dist/esm/blueprint/graph/mermaid-parser.d.ts +0 -3
- package/dist/esm/blueprint/graph/mermaid-parser.js +0 -93
- package/dist/esm/blueprint/graph/mermaid-serializer.d.ts +0 -3
- package/dist/esm/blueprint/graph/mermaid-serializer.js +0 -20
- package/dist/esm/blueprint/graph/schema.d.ts +0 -89
- package/dist/esm/blueprint/graph/schema.js +0 -104
- package/dist/esm/blueprint/graph/task-graph-adapter.d.ts +0 -6
- package/dist/esm/blueprint/graph/task-graph-adapter.js +0 -30
|
@@ -1,370 +0,0 @@
|
|
|
1
|
-
import { CycleDetector } from './cycle-detector.js';
|
|
2
|
-
import { detectCyclesInGraph, getCriticalPathForGraph, getGraphStatsForGraph, getTopologicalOrderForGraph, getWavesForGraph, topologicalSortTasksInput, validateGraph, } from './task-graph-algorithms.js';
|
|
3
|
-
/**
|
|
4
|
-
* DAG (Directed Acyclic Graph) analysis for parallel task execution.
|
|
5
|
-
*
|
|
6
|
-
* Provides:
|
|
7
|
-
* - Topological sorting (Kahn's Algorithm)
|
|
8
|
-
* - Cycle detection (DFS)
|
|
9
|
-
* - Critical path analysis (longest dependency chain)
|
|
10
|
-
* - Wave grouping (parallel execution batches)
|
|
11
|
-
* - Parallelization metrics
|
|
12
|
-
* - Validation and statistics
|
|
13
|
-
*
|
|
14
|
-
* Zero dependencies. Works with Bun, Node.js, Deno.
|
|
15
|
-
*
|
|
16
|
-
* @template T - The type of additional data attached to tasks
|
|
17
|
-
*/
|
|
18
|
-
export class TaskGraph {
|
|
19
|
-
nodes;
|
|
20
|
-
edges; // from -> to[]
|
|
21
|
-
reverseEdges; // to -> from[] (for validation)
|
|
22
|
-
constructor() {
|
|
23
|
-
this.nodes = new Map();
|
|
24
|
-
this.edges = new Map();
|
|
25
|
-
this.reverseEdges = new Map();
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Add a task to the graph.
|
|
29
|
-
* Must be called before adding dependencies.
|
|
30
|
-
*/
|
|
31
|
-
addTask(task) {
|
|
32
|
-
if (this.nodes.has(task.id)) {
|
|
33
|
-
throw new Error(`Task "${task.id}" already exists in the graph`);
|
|
34
|
-
}
|
|
35
|
-
this.nodes.set(task.id, {
|
|
36
|
-
task,
|
|
37
|
-
inDegree: 0,
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Add a task and automatically wire up its dependencies.
|
|
42
|
-
* This is the preferred method for LLM agents - single call instead of addTask + addDependency.
|
|
43
|
-
*
|
|
44
|
-
* @param task - Task with dependencies array populated
|
|
45
|
-
* @throws {Error} If task already exists or dependencies reference non-existent tasks
|
|
46
|
-
*/
|
|
47
|
-
addTaskWithDependencies(task) {
|
|
48
|
-
this.addTask(task);
|
|
49
|
-
for (const depId of task.dependencies) {
|
|
50
|
-
if (!this.nodes.has(depId)) {
|
|
51
|
-
// Remove the task we just added to maintain consistency
|
|
52
|
-
this.nodes.delete(task.id);
|
|
53
|
-
throw new Error(`Cannot add task "${task.id}": dependency "${depId}" does not exist. ` +
|
|
54
|
-
`Add dependencies first, or use addTask() + addDependency() for more control.`);
|
|
55
|
-
}
|
|
56
|
-
this.addDependency(depId, task.id);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Bulk add tasks with automatic dependency wiring.
|
|
61
|
-
* Tasks are sorted by dependency depth before adding.
|
|
62
|
-
*
|
|
63
|
-
* @param tasks - Array of tasks to add
|
|
64
|
-
* @throws {Error} If circular dependencies detected or tasks reference non-existent dependencies
|
|
65
|
-
*/
|
|
66
|
-
addTasksWithDependencies(tasks) {
|
|
67
|
-
// Build a map for quick lookup
|
|
68
|
-
const taskMap = new Map(tasks.map((t) => [t.id, t]));
|
|
69
|
-
// Topological sort the input tasks
|
|
70
|
-
const sorted = topologicalSortTasksInput(tasks, taskMap);
|
|
71
|
-
// Add in sorted order
|
|
72
|
-
for (const task of sorted) {
|
|
73
|
-
this.addTaskWithDependencies(task);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Add a dependency between two tasks.
|
|
78
|
-
* @param from - The task that must complete first
|
|
79
|
-
* @param to - The task that depends on `from`
|
|
80
|
-
* @throws {Error} If tasks don't exist, self-loop detected
|
|
81
|
-
*/
|
|
82
|
-
addDependency(from, to) {
|
|
83
|
-
this.validateDependencyNodes(from, to);
|
|
84
|
-
if (this.edgeExists(from, to))
|
|
85
|
-
return;
|
|
86
|
-
this.addForwardEdge(from, to);
|
|
87
|
-
this.addReverseEdge(from, to);
|
|
88
|
-
this.incrementInDegree(to);
|
|
89
|
-
}
|
|
90
|
-
validateDependencyNodes(from, to) {
|
|
91
|
-
if (!this.nodes.has(from)) {
|
|
92
|
-
throw new Error(`Cannot add dependency: source task "${from}" does not exist`);
|
|
93
|
-
}
|
|
94
|
-
if (!this.nodes.has(to)) {
|
|
95
|
-
throw new Error(`Cannot add dependency: target task "${to}" does not exist`);
|
|
96
|
-
}
|
|
97
|
-
if (from === to) {
|
|
98
|
-
throw new Error(`Cannot add self-loop: task "${from}" cannot depend on itself`);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
edgeExists(from, to) {
|
|
102
|
-
return this.edges.get(from)?.has(to) ?? false;
|
|
103
|
-
}
|
|
104
|
-
addForwardEdge(from, to) {
|
|
105
|
-
if (!this.edges.has(from)) {
|
|
106
|
-
this.edges.set(from, new Set());
|
|
107
|
-
}
|
|
108
|
-
this.edges.get(from)?.add(to);
|
|
109
|
-
}
|
|
110
|
-
addReverseEdge(from, to) {
|
|
111
|
-
if (!this.reverseEdges.has(to)) {
|
|
112
|
-
this.reverseEdges.set(to, new Set());
|
|
113
|
-
}
|
|
114
|
-
this.reverseEdges.get(to)?.add(from);
|
|
115
|
-
}
|
|
116
|
-
incrementInDegree(taskId) {
|
|
117
|
-
const node = this.nodes.get(taskId);
|
|
118
|
-
if (node)
|
|
119
|
-
node.inDegree++;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Remove a dependency between two tasks.
|
|
123
|
-
* @param from - The source task
|
|
124
|
-
* @param to - The dependent task
|
|
125
|
-
* @returns true if dependency was removed, false if it didn't exist
|
|
126
|
-
*/
|
|
127
|
-
removeDependency(from, to) {
|
|
128
|
-
const edges = this.edges.get(from);
|
|
129
|
-
if (!edges?.has(to)) {
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
edges.delete(to);
|
|
133
|
-
if (edges.size === 0) {
|
|
134
|
-
this.edges.delete(from);
|
|
135
|
-
}
|
|
136
|
-
// Remove reverse edge
|
|
137
|
-
const revEdges = this.reverseEdges.get(to);
|
|
138
|
-
if (revEdges) {
|
|
139
|
-
revEdges.delete(from);
|
|
140
|
-
if (revEdges.size === 0) {
|
|
141
|
-
this.reverseEdges.delete(to);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
// Decrement in-degree
|
|
145
|
-
const toNode = this.nodes.get(to);
|
|
146
|
-
if (toNode && toNode.inDegree > 0) {
|
|
147
|
-
toNode.inDegree--;
|
|
148
|
-
}
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Get the in-degree (number of dependencies) for a task.
|
|
153
|
-
*/
|
|
154
|
-
getInDegree(taskId) {
|
|
155
|
-
const node = this.nodes.get(taskId);
|
|
156
|
-
return node?.inDegree ?? 0;
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Get the out-degree (number of dependents) for a task.
|
|
160
|
-
*/
|
|
161
|
-
getOutDegree(taskId) {
|
|
162
|
-
return this.edges.get(taskId)?.size ?? 0;
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Get all task IDs in the graph.
|
|
166
|
-
*/
|
|
167
|
-
getTaskIds() {
|
|
168
|
-
return Array.from(this.nodes.keys());
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Get a task by ID.
|
|
172
|
-
*/
|
|
173
|
-
getTask(taskId) {
|
|
174
|
-
return this.nodes.get(taskId)?.task;
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Check if a task exists in the graph.
|
|
178
|
-
*/
|
|
179
|
-
hasTask(taskId) {
|
|
180
|
-
return this.nodes.has(taskId);
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Get the number of tasks in the graph.
|
|
184
|
-
*/
|
|
185
|
-
get size() {
|
|
186
|
-
return this.nodes.size;
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Get the number of edges in the graph.
|
|
190
|
-
*/
|
|
191
|
-
get edgeCount() {
|
|
192
|
-
let count = 0;
|
|
193
|
-
for (const edges of this.edges.values()) {
|
|
194
|
-
count += edges.size;
|
|
195
|
-
}
|
|
196
|
-
return count;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Validate the graph structure.
|
|
200
|
-
* Checks for cycles, missing dependencies, and other issues.
|
|
201
|
-
*/
|
|
202
|
-
validate() {
|
|
203
|
-
return validateGraph(this.nodes, this.edges, this.reverseEdges);
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Get comprehensive statistics about the graph.
|
|
207
|
-
*/
|
|
208
|
-
getStats() {
|
|
209
|
-
return getGraphStatsForGraph(this.nodes, this.edges);
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Get tasks in topological order (Kahn's Algorithm).
|
|
213
|
-
* Tasks appear before their dependents.
|
|
214
|
-
* @throws {Error} If circular dependency detected
|
|
215
|
-
*/
|
|
216
|
-
getTopologicalOrder() {
|
|
217
|
-
return getTopologicalOrderForGraph(this.nodes, this.edges);
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Detect circular dependencies using DFS.
|
|
221
|
-
* @returns Array of cycles (each cycle is an array of task IDs), or null if acyclic
|
|
222
|
-
*/
|
|
223
|
-
detectCycles() {
|
|
224
|
-
return detectCyclesInGraph(this.nodes, this.edges);
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Check if the graph contains any cycles.
|
|
228
|
-
* @returns true if cycles exist, false if acyclic
|
|
229
|
-
*/
|
|
230
|
-
hasCycle() {
|
|
231
|
-
const cycles = this.detectCycles();
|
|
232
|
-
return cycles !== null && cycles.length > 0;
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Get the critical path (longest dependency chain).
|
|
236
|
-
* This is the sequence of tasks that determines the minimum execution time.
|
|
237
|
-
*
|
|
238
|
-
* IMPORTANT: For optimal parallel scheduling, the invariant |waves| = |critical_path| must hold.
|
|
239
|
-
*
|
|
240
|
-
* Returns:
|
|
241
|
-
* - Empty array for empty graph
|
|
242
|
-
* - Single task for single-node graph (critical path length = 1)
|
|
243
|
-
* - Single task if all tasks are independent (critical path length = 1, same as wave count)
|
|
244
|
-
* - Longest dependency chain for graphs with dependencies
|
|
245
|
-
*/
|
|
246
|
-
getCriticalPath() {
|
|
247
|
-
return getCriticalPathForGraph(this.nodes, this.edges);
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Get the maximum number of tasks that can run in parallel.
|
|
251
|
-
*/
|
|
252
|
-
getMaxParallelWidth() {
|
|
253
|
-
const waves = getWavesForGraph(this.nodes, this.edges);
|
|
254
|
-
let maxWidth = 0;
|
|
255
|
-
for (const wave of waves) {
|
|
256
|
-
maxWidth = Math.max(maxWidth, wave.length);
|
|
257
|
-
}
|
|
258
|
-
return maxWidth;
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Group tasks into waves (batches) for parallel execution.
|
|
262
|
-
* Tasks in the same wave have no dependencies on each other.
|
|
263
|
-
* Each wave must complete before the next wave starts.
|
|
264
|
-
*/
|
|
265
|
-
getWaves() {
|
|
266
|
-
return getWavesForGraph(this.nodes, this.edges);
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Get direct dependencies of a task.
|
|
270
|
-
*/
|
|
271
|
-
getDependencies(taskId) {
|
|
272
|
-
return Array.from(this.reverseEdges.get(taskId) ?? []);
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Get direct dependents of a task (tasks that depend on this one).
|
|
276
|
-
*/
|
|
277
|
-
getDependents(taskId) {
|
|
278
|
-
return Array.from(this.edges.get(taskId) ?? []);
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Get all transitive dependencies of a task (including indirect).
|
|
282
|
-
*/
|
|
283
|
-
getTransitiveDependencies(taskId) {
|
|
284
|
-
const visited = new Set();
|
|
285
|
-
const stack = [...(this.reverseEdges.get(taskId) ?? [])];
|
|
286
|
-
while (stack.length > 0) {
|
|
287
|
-
// Safe: loop condition ensures stack is non-empty
|
|
288
|
-
const dep = stack.pop();
|
|
289
|
-
if (!dep)
|
|
290
|
-
break;
|
|
291
|
-
if (visited.has(dep))
|
|
292
|
-
continue;
|
|
293
|
-
visited.add(dep);
|
|
294
|
-
stack.push(...(this.reverseEdges.get(dep) ?? []));
|
|
295
|
-
}
|
|
296
|
-
return Array.from(visited);
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* Get all transitive dependents of a task (including indirect).
|
|
300
|
-
*/
|
|
301
|
-
getTransitiveDependents(taskId) {
|
|
302
|
-
const visited = new Set();
|
|
303
|
-
const stack = [...(this.edges.get(taskId) ?? [])];
|
|
304
|
-
while (stack.length > 0) {
|
|
305
|
-
// Safe: loop condition ensures stack is non-empty
|
|
306
|
-
const dep = stack.pop();
|
|
307
|
-
if (!dep)
|
|
308
|
-
break;
|
|
309
|
-
if (visited.has(dep))
|
|
310
|
-
continue;
|
|
311
|
-
visited.add(dep);
|
|
312
|
-
stack.push(...(this.edges.get(dep) ?? []));
|
|
313
|
-
}
|
|
314
|
-
return Array.from(visited);
|
|
315
|
-
}
|
|
316
|
-
/**
|
|
317
|
-
* Create a subgraph containing only the specified tasks and their edges.
|
|
318
|
-
*/
|
|
319
|
-
subgraph(taskIds) {
|
|
320
|
-
const sub = new TaskGraph();
|
|
321
|
-
const idSet = new Set(taskIds);
|
|
322
|
-
this.copyTasksToSubgraph(taskIds, sub);
|
|
323
|
-
this.copyEdgesToSubgraph(taskIds, idSet, sub);
|
|
324
|
-
return sub;
|
|
325
|
-
}
|
|
326
|
-
copyTasksToSubgraph(taskIds, sub) {
|
|
327
|
-
for (const id of taskIds) {
|
|
328
|
-
const node = this.nodes.get(id);
|
|
329
|
-
if (node)
|
|
330
|
-
sub.addTask({ ...node.task, dependencies: [] });
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
copyEdgesToSubgraph(taskIds, idSet, sub) {
|
|
334
|
-
for (const id of taskIds) {
|
|
335
|
-
this.copyNodeEdgesToSubgraph(id, idSet, sub);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
copyNodeEdgesToSubgraph(id, idSet, sub) {
|
|
339
|
-
const edges = this.edges.get(id);
|
|
340
|
-
if (!edges)
|
|
341
|
-
return;
|
|
342
|
-
for (const to of edges) {
|
|
343
|
-
if (idSet.has(to))
|
|
344
|
-
sub.addDependency(id, to);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* Clone the graph.
|
|
349
|
-
*/
|
|
350
|
-
clone() {
|
|
351
|
-
const cloned = new TaskGraph();
|
|
352
|
-
this.copyAllTasks(cloned);
|
|
353
|
-
this.copyAllEdges(cloned);
|
|
354
|
-
return cloned;
|
|
355
|
-
}
|
|
356
|
-
copyAllTasks(target) {
|
|
357
|
-
for (const [, node] of this.nodes) {
|
|
358
|
-
target.addTask({ ...node.task });
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
copyAllEdges(target) {
|
|
362
|
-
for (const [from, edges] of this.edges) {
|
|
363
|
-
for (const to of edges) {
|
|
364
|
-
target.addDependency(from, to);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
export { CycleDetector };
|
|
370
|
-
//# sourceMappingURL=task-graph.js.map
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generic task interface for DAG analysis.
|
|
3
|
-
* Applications should extend this with their specific task data.
|
|
4
|
-
*/
|
|
5
|
-
export interface Task<T = unknown> {
|
|
6
|
-
id: string;
|
|
7
|
-
data?: T;
|
|
8
|
-
dependencies: string[];
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Internal node representation in the graph.
|
|
12
|
-
*/
|
|
13
|
-
export interface TaskNode<T = unknown> {
|
|
14
|
-
task: Task<T>;
|
|
15
|
-
inDegree: number;
|
|
16
|
-
}
|
|
17
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { graphEdgeSchema, graphEdgeTypeSchema, graphLayoutSchema, graphNodeSchema, graphNodeTypeSchema, normalizedGraphSchema, type GraphEdge, type GraphEdgeType, type GraphLayout, type GraphNode, type GraphNodeType, type NormalizedGraph, } from './schema.js';
|
|
2
|
-
export { parseMermaidToGraph } from './mermaid-parser.js';
|
|
3
|
-
export { serializeGraphToMermaid } from './mermaid-serializer.js';
|
|
4
|
-
export { taskGraphToNormalizedGraph } from './task-graph-adapter.js';
|
|
5
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { graphEdgeSchema, graphEdgeTypeSchema, graphLayoutSchema, graphNodeSchema, graphNodeTypeSchema, normalizedGraphSchema, } from './schema.js';
|
|
2
|
-
export { parseMermaidToGraph } from './mermaid-parser.js';
|
|
3
|
-
export { serializeGraphToMermaid } from './mermaid-serializer.js';
|
|
4
|
-
export { taskGraphToNormalizedGraph } from './task-graph-adapter.js';
|
|
5
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { normalizedGraphSchema, } from '#graph/schema';
|
|
2
|
-
const DIRECTION_LINE = /^graph\s+(TD|LR|BT|RL)$/;
|
|
3
|
-
const EDGE_WITH_LABEL = /^([A-Za-z0-9_-]+)(?:\[([^\]]+)\])?\s*--\|([^|]+)\|\s*([A-Za-z0-9_-]+)(?:\[([^\]]+)\])?$/;
|
|
4
|
-
const EDGE_SIMPLE = /^([A-Za-z0-9_-]+)(?:\[([^\]]+)\])?\s*-->\s*([A-Za-z0-9_-]+)(?:\[([^\]]+)\])?$/;
|
|
5
|
-
const NODE_ONLY = /^([A-Za-z0-9_-]+)\[([^\]]+)\]$/;
|
|
6
|
-
function upsertNode(nodes, id, label) {
|
|
7
|
-
const existing = nodes.get(id);
|
|
8
|
-
if (existing) {
|
|
9
|
-
if (label && existing.label === id) {
|
|
10
|
-
nodes.set(id, { ...existing, label });
|
|
11
|
-
}
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
nodes.set(id, {
|
|
15
|
-
id,
|
|
16
|
-
type: 'task',
|
|
17
|
-
label: label ?? id,
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
function parseEdge(line, nodes, edges) {
|
|
21
|
-
const labeled = line.match(EDGE_WITH_LABEL);
|
|
22
|
-
if (labeled) {
|
|
23
|
-
const source = labeled[1] ?? '';
|
|
24
|
-
const sourceLabel = labeled[2];
|
|
25
|
-
const edgeLabel = (labeled[3] ?? '').trim();
|
|
26
|
-
const target = labeled[4] ?? '';
|
|
27
|
-
const targetLabel = labeled[5];
|
|
28
|
-
upsertNode(nodes, source, sourceLabel);
|
|
29
|
-
upsertNode(nodes, target, targetLabel);
|
|
30
|
-
edges.push({
|
|
31
|
-
source,
|
|
32
|
-
target,
|
|
33
|
-
type: 'depends_on',
|
|
34
|
-
label: edgeLabel,
|
|
35
|
-
});
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
const simple = line.match(EDGE_SIMPLE);
|
|
39
|
-
if (!simple) {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
const source = simple[1] ?? '';
|
|
43
|
-
const sourceLabel = simple[2];
|
|
44
|
-
const target = simple[3] ?? '';
|
|
45
|
-
const targetLabel = simple[4];
|
|
46
|
-
upsertNode(nodes, source, sourceLabel);
|
|
47
|
-
upsertNode(nodes, target, targetLabel);
|
|
48
|
-
edges.push({
|
|
49
|
-
source,
|
|
50
|
-
target,
|
|
51
|
-
type: 'depends_on',
|
|
52
|
-
});
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
export function parseMermaidToGraph(mermaid) {
|
|
56
|
-
const lines = mermaid
|
|
57
|
-
.split('\n')
|
|
58
|
-
.map((line) => line.trim())
|
|
59
|
-
.filter((line) => line.length > 0 && !line.startsWith('%%'))
|
|
60
|
-
.map((line) => (line.endsWith(';') ? line.slice(0, -1).trim() : line));
|
|
61
|
-
if (!lines.length) {
|
|
62
|
-
throw new Error('Mermaid input is empty');
|
|
63
|
-
}
|
|
64
|
-
const directionMatch = lines[0]?.match(DIRECTION_LINE);
|
|
65
|
-
if (!directionMatch?.[1]) {
|
|
66
|
-
throw new Error('Mermaid must start with "graph <direction>"');
|
|
67
|
-
}
|
|
68
|
-
const direction = directionMatch[1];
|
|
69
|
-
const nodes = new Map();
|
|
70
|
-
const edges = [];
|
|
71
|
-
for (const line of lines.slice(1)) {
|
|
72
|
-
if (line === '' || line.startsWith('subgraph') || line === 'end') {
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
if (parseEdge(line, nodes, edges)) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
const nodeOnly = line.match(NODE_ONLY);
|
|
79
|
-
if (nodeOnly) {
|
|
80
|
-
const id = nodeOnly[1] ?? '';
|
|
81
|
-
const label = nodeOnly[2] ?? id;
|
|
82
|
-
upsertNode(nodes, id, label);
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
throw new Error(`Unsupported Mermaid line: ${line}`);
|
|
86
|
-
}
|
|
87
|
-
return normalizedGraphSchema.parse({
|
|
88
|
-
nodes: [...nodes.values()],
|
|
89
|
-
edges,
|
|
90
|
-
layout: { direction },
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
//# sourceMappingURL=mermaid-parser.js.map
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
function escapeLabel(label) {
|
|
2
|
-
return label.replace(/\[/g, '(').replace(/\]/g, ')');
|
|
3
|
-
}
|
|
4
|
-
export function serializeGraphToMermaid(graph) {
|
|
5
|
-
const direction = graph.layout?.direction ?? 'TD';
|
|
6
|
-
const lines = [`graph ${direction}`];
|
|
7
|
-
for (const node of graph.nodes) {
|
|
8
|
-
lines.push(` ${node.id}[${escapeLabel(node.label)}]`);
|
|
9
|
-
}
|
|
10
|
-
for (const edge of graph.edges) {
|
|
11
|
-
if (edge.label) {
|
|
12
|
-
lines.push(` ${edge.source} --|${escapeLabel(edge.label)}| ${edge.target}`);
|
|
13
|
-
}
|
|
14
|
-
else {
|
|
15
|
-
lines.push(` ${edge.source} --> ${edge.target}`);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
return `${lines.join('\n')}\n`;
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=mermaid-serializer.js.map
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
export declare const graphNodeTypeSchema: z.ZodEnum<{
|
|
3
|
-
blueprint: "blueprint";
|
|
4
|
-
decision: "decision";
|
|
5
|
-
external: "external";
|
|
6
|
-
task: "task";
|
|
7
|
-
milestone: "milestone";
|
|
8
|
-
tech_debt: "tech_debt";
|
|
9
|
-
}>;
|
|
10
|
-
export declare const graphEdgeTypeSchema: z.ZodEnum<{
|
|
11
|
-
depends_on: "depends_on";
|
|
12
|
-
blocks: "blocks";
|
|
13
|
-
relates_to: "relates_to";
|
|
14
|
-
}>;
|
|
15
|
-
export declare const graphNodeSchema: z.ZodObject<{
|
|
16
|
-
id: z.ZodString;
|
|
17
|
-
type: z.ZodEnum<{
|
|
18
|
-
blueprint: "blueprint";
|
|
19
|
-
decision: "decision";
|
|
20
|
-
external: "external";
|
|
21
|
-
task: "task";
|
|
22
|
-
milestone: "milestone";
|
|
23
|
-
tech_debt: "tech_debt";
|
|
24
|
-
}>;
|
|
25
|
-
label: z.ZodString;
|
|
26
|
-
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
27
|
-
}, z.core.$strip>;
|
|
28
|
-
export declare const graphEdgeSchema: z.ZodObject<{
|
|
29
|
-
source: z.ZodString;
|
|
30
|
-
target: z.ZodString;
|
|
31
|
-
type: z.ZodEnum<{
|
|
32
|
-
depends_on: "depends_on";
|
|
33
|
-
blocks: "blocks";
|
|
34
|
-
relates_to: "relates_to";
|
|
35
|
-
}>;
|
|
36
|
-
label: z.ZodOptional<z.ZodString>;
|
|
37
|
-
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
38
|
-
}, z.core.$strip>;
|
|
39
|
-
export declare const graphLayoutSchema: z.ZodObject<{
|
|
40
|
-
direction: z.ZodDefault<z.ZodEnum<{
|
|
41
|
-
TD: "TD";
|
|
42
|
-
LR: "LR";
|
|
43
|
-
BT: "BT";
|
|
44
|
-
RL: "RL";
|
|
45
|
-
}>>;
|
|
46
|
-
rankdir: z.ZodOptional<z.ZodString>;
|
|
47
|
-
}, z.core.$strip>;
|
|
48
|
-
export declare const normalizedGraphSchema: z.ZodObject<{
|
|
49
|
-
nodes: z.ZodArray<z.ZodObject<{
|
|
50
|
-
id: z.ZodString;
|
|
51
|
-
type: z.ZodEnum<{
|
|
52
|
-
blueprint: "blueprint";
|
|
53
|
-
decision: "decision";
|
|
54
|
-
external: "external";
|
|
55
|
-
task: "task";
|
|
56
|
-
milestone: "milestone";
|
|
57
|
-
tech_debt: "tech_debt";
|
|
58
|
-
}>;
|
|
59
|
-
label: z.ZodString;
|
|
60
|
-
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
61
|
-
}, z.core.$strip>>;
|
|
62
|
-
edges: z.ZodArray<z.ZodObject<{
|
|
63
|
-
source: z.ZodString;
|
|
64
|
-
target: z.ZodString;
|
|
65
|
-
type: z.ZodEnum<{
|
|
66
|
-
depends_on: "depends_on";
|
|
67
|
-
blocks: "blocks";
|
|
68
|
-
relates_to: "relates_to";
|
|
69
|
-
}>;
|
|
70
|
-
label: z.ZodOptional<z.ZodString>;
|
|
71
|
-
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
72
|
-
}, z.core.$strip>>;
|
|
73
|
-
layout: z.ZodOptional<z.ZodObject<{
|
|
74
|
-
direction: z.ZodDefault<z.ZodEnum<{
|
|
75
|
-
TD: "TD";
|
|
76
|
-
LR: "LR";
|
|
77
|
-
BT: "BT";
|
|
78
|
-
RL: "RL";
|
|
79
|
-
}>>;
|
|
80
|
-
rankdir: z.ZodOptional<z.ZodString>;
|
|
81
|
-
}, z.core.$strip>>;
|
|
82
|
-
}, z.core.$strip>;
|
|
83
|
-
export type GraphNodeType = z.infer<typeof graphNodeTypeSchema>;
|
|
84
|
-
export type GraphEdgeType = z.infer<typeof graphEdgeTypeSchema>;
|
|
85
|
-
export type GraphNode = z.infer<typeof graphNodeSchema>;
|
|
86
|
-
export type GraphEdge = z.infer<typeof graphEdgeSchema>;
|
|
87
|
-
export type GraphLayout = z.infer<typeof graphLayoutSchema>;
|
|
88
|
-
export type NormalizedGraph = z.infer<typeof normalizedGraphSchema>;
|
|
89
|
-
//# sourceMappingURL=schema.d.ts.map
|