@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.
Files changed (194) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +93 -66
  4. package/bin/_run.js +143 -1
  5. package/bin/runtime-manifest.json +40 -0
  6. package/catalog/AGENTS.md.tpl +7 -6
  7. package/catalog/agent/commands/plan-refine.md +3 -3
  8. package/catalog/agent/commands/pll.md +2 -0
  9. package/catalog/agent/guides/parallel-execution.md +2 -0
  10. package/catalog/agent/rules/extraction-parity.md +27 -1
  11. package/catalog/agent/rules/public-package-safety.md +24 -1
  12. package/catalog/agent/skills/plan-refine/SKILL.md +5 -4
  13. package/catalog/agent/skills/pll/SKILL.md +1 -0
  14. package/catalog/base-kit/.github/workflows/ci.webpresso.yml.tmpl +33 -0
  15. package/catalog/base-kit/commitlint.config.ts.tmpl +1 -3
  16. package/catalog/base-kit/e2e/fixtures/smoke.html.tmpl +13 -0
  17. package/catalog/base-kit/e2e/smoke.spec.ts.tmpl +13 -0
  18. package/catalog/base-kit/oxlint.config.ts.tmpl +26 -0
  19. package/catalog/base-kit/playwright.config.ts.tmpl +10 -0
  20. package/catalog/base-kit/src/quality-sample.test.ts.tmpl +19 -0
  21. package/catalog/base-kit/src/quality-sample.ts.tmpl +11 -0
  22. package/catalog/base-kit/stryker.config.ts.tmpl +14 -0
  23. package/catalog/base-kit/tsconfig.json.tmpl +9 -0
  24. package/catalog/base-kit/vitest.config.ts.tmpl +10 -0
  25. package/catalog/docs/templates/adr.md +1 -1
  26. package/catalog/docs/templates/blueprint.md +2 -0
  27. package/catalog/docs/templates/blueprint.yaml +16 -15
  28. package/catalog/docs/templates/guide.md +1 -1
  29. package/catalog/docs/templates/postmortem.md +1 -1
  30. package/catalog/docs/templates/research.md +1 -1
  31. package/catalog/docs/templates/runbook.md +1 -1
  32. package/catalog/docs/templates/system.md +12 -3
  33. package/catalog/docs/templates/tech-debt.md +1 -0
  34. package/commands/blueprint.md +10 -12
  35. package/dist/esm/audit/blueprint-db-consistency.d.ts +1 -1
  36. package/dist/esm/audit/blueprint-db-consistency.js +6 -8
  37. package/dist/esm/audit/blueprint-lifecycle-sql.js +10 -3
  38. package/dist/esm/audit/cloudflare-deploy-contract.d.ts +3 -0
  39. package/dist/esm/audit/cloudflare-deploy-contract.js +64 -0
  40. package/dist/esm/audit/no-legacy-cli-bin.d.ts +3 -0
  41. package/dist/esm/audit/no-legacy-cli-bin.js +100 -0
  42. package/dist/esm/audit/package-surface.js +14 -1
  43. package/dist/esm/audit/repo-guardrails.js +40 -13
  44. package/dist/esm/audit/resolve-audit-script.d.ts +24 -0
  45. package/dist/esm/audit/resolve-audit-script.js +27 -0
  46. package/dist/esm/audit/roadmap-links.js +23 -10
  47. package/dist/esm/blueprint/core/schema.d.ts +8 -8
  48. package/dist/esm/blueprint/core/schema.js +2 -2
  49. package/dist/esm/blueprint/db/enums.d.ts +1 -1
  50. package/dist/esm/blueprint/db/ingester.js +18 -10
  51. package/dist/esm/blueprint/index.d.ts +0 -1
  52. package/dist/esm/blueprint/index.js +0 -2
  53. package/dist/esm/blueprint/lifecycle/audit.js +9 -2
  54. package/dist/esm/blueprint/lifecycle/local.js +15 -4
  55. package/dist/esm/blueprint/local.d.ts +0 -3
  56. package/dist/esm/blueprint/local.js +0 -2
  57. package/dist/esm/blueprint/service/BlueprintCreationService.js +16 -8
  58. package/dist/esm/blueprint/service/BlueprintService.js +37 -19
  59. package/dist/esm/blueprint/service/scanner.js +73 -9
  60. package/dist/esm/blueprint/tracked-document/schema.d.ts +2 -2
  61. package/dist/esm/blueprint/utils/document-paths.d.ts +23 -0
  62. package/dist/esm/blueprint/utils/document-paths.js +91 -0
  63. package/dist/esm/blueprint/utils/package-assets.d.ts +11 -0
  64. package/dist/esm/blueprint/utils/package-assets.js +33 -4
  65. package/dist/esm/build/package-manifest.js +7 -0
  66. package/dist/esm/build/release-policy.d.ts +27 -0
  67. package/dist/esm/build/release-policy.js +29 -0
  68. package/dist/esm/build/runtime-targets.d.ts +13 -0
  69. package/dist/esm/build/runtime-targets.js +48 -0
  70. package/dist/esm/build/sync-catalog-doc-templates.d.ts +23 -0
  71. package/dist/esm/build/sync-catalog-doc-templates.js +93 -0
  72. package/dist/esm/cli/auto-update/detect-pm.d.ts +15 -0
  73. package/dist/esm/cli/auto-update/detect-pm.js +24 -9
  74. package/dist/esm/cli/auto-update/skip.js +9 -1
  75. package/dist/esm/cli/bundle/agent-command-inventory.d.ts +120 -0
  76. package/dist/esm/cli/bundle/agent-command-inventory.js +100 -0
  77. package/dist/esm/cli/bundle/index.d.ts +17 -0
  78. package/dist/esm/cli/bundle/index.js +15 -0
  79. package/dist/esm/cli/cli.d.ts +1 -1
  80. package/dist/esm/cli/cli.js +49 -5
  81. package/dist/esm/cli/commands/audit-core.d.ts +1 -1
  82. package/dist/esm/cli/commands/audit.js +4 -7
  83. package/dist/esm/cli/commands/blueprint/router.js +16 -10
  84. package/dist/esm/cli/commands/blueprint/template-resolver.js +8 -4
  85. package/dist/esm/cli/commands/hook.d.ts +8 -0
  86. package/dist/esm/cli/commands/hook.js +47 -0
  87. package/dist/esm/cli/commands/init/host-visibility.js +4 -2
  88. package/dist/esm/cli/commands/init/index.js +80 -7
  89. package/dist/esm/cli/commands/init/scaffold-base-kit.d.ts +12 -0
  90. package/dist/esm/cli/commands/init/scaffold-base-kit.js +142 -7
  91. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/codex-ownership.js +9 -1
  92. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.js +130 -20
  93. package/dist/esm/cli/commands/init/scaffolders/agent-kit-global/index.d.ts +65 -0
  94. package/dist/esm/cli/commands/init/scaffolders/agent-kit-global/index.js +64 -0
  95. package/dist/esm/cli/commands/package-manager.d.ts +15 -0
  96. package/dist/esm/cli/commands/package-manager.js +42 -0
  97. package/dist/esm/cli/commands/test.d.ts +1 -0
  98. package/dist/esm/cli/commands/test.js +2 -1
  99. package/dist/esm/cli/commands/typecheck.js +10 -19
  100. package/dist/esm/cli/package-scripts.d.ts +12 -0
  101. package/dist/esm/cli/package-scripts.js +59 -0
  102. package/dist/esm/cli/utils.js +3 -22
  103. package/dist/esm/cli/wp-extensions.d.ts +14 -0
  104. package/dist/esm/cli/wp-extensions.js +34 -0
  105. package/dist/esm/config/docs-lint/schemas/common.d.ts +1 -1
  106. package/dist/esm/config/docs-lint/schemas/implementation-plan.d.ts +2 -2
  107. package/dist/esm/config/docs-lint/schemas/parent-roadmap.d.ts +1 -1
  108. package/dist/esm/config/stryker/index.d.ts +85 -0
  109. package/dist/esm/config/stryker/index.js +31 -0
  110. package/dist/esm/e2e/command-builder.js +35 -7
  111. package/dist/esm/e2e/config.d.ts +56 -0
  112. package/dist/esm/e2e/config.js +114 -0
  113. package/dist/esm/e2e/execution.js +8 -0
  114. package/dist/esm/e2e/run-planner.js +2 -0
  115. package/dist/esm/e2e/types.d.ts +3 -0
  116. package/dist/esm/format/index.js +5 -1
  117. package/dist/esm/hooks/guard-switch/index.d.ts +1 -1
  118. package/dist/esm/hooks/guard-switch/index.js +22 -14
  119. package/dist/esm/hooks/post-tool/lint-after-edit.d.ts +1 -0
  120. package/dist/esm/hooks/post-tool/lint-after-edit.js +5 -2
  121. package/dist/esm/hooks/pretool-guard/validators/file-conventions.js +1 -1
  122. package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.d.ts +6 -0
  123. package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.js +27 -2
  124. package/dist/esm/hooks/pretool-guard/validators/path-contract.d.ts +2 -1
  125. package/dist/esm/hooks/pretool-guard/validators/path-contract.js +59 -34
  126. package/dist/esm/hooks/pretool-guard/validators/plan-frontmatter.js +3 -3
  127. package/dist/esm/hooks/shared/routing-block.js +18 -4
  128. package/dist/esm/hooks/shared/validators/blueprint.js +3 -0
  129. package/dist/esm/hooks/stop/qa-changed-files.d.ts +1 -0
  130. package/dist/esm/hooks/stop/qa-changed-files.js +5 -2
  131. package/dist/esm/lint/index.js +3 -1
  132. package/dist/esm/mcp/auto-discover.d.ts +2 -0
  133. package/dist/esm/mcp/auto-discover.js +14 -6
  134. package/dist/esm/mcp/blueprint-server.js +379 -80
  135. package/dist/esm/mcp/cli.js +21 -0
  136. package/dist/esm/mcp/runners/test.js +15 -0
  137. package/dist/esm/mcp/server.d.ts +7 -0
  138. package/dist/esm/mcp/server.js +16 -27
  139. package/dist/esm/mcp/tools/_registry.d.ts +3 -0
  140. package/dist/esm/mcp/tools/_registry.js +21 -0
  141. package/dist/esm/mcp/tools/audit.d.ts +1 -0
  142. package/dist/esm/mcp/tools/audit.js +13 -8
  143. package/dist/esm/mcp/tools/typecheck.js +4 -2
  144. package/dist/esm/mutation/affected.d.ts +9 -0
  145. package/dist/esm/mutation/affected.js +36 -0
  146. package/dist/esm/package.json +8 -0
  147. package/dist/esm/runtime/package-version.d.ts +2 -0
  148. package/dist/esm/runtime/package-version.js +43 -0
  149. package/dist/esm/test/command-builder.d.ts +4 -0
  150. package/dist/esm/test/command-builder.js +28 -3
  151. package/dist/esm/test-helpers/hermetic-env.d.ts +25 -0
  152. package/dist/esm/test-helpers/hermetic-env.js +31 -0
  153. package/dist/esm/tool-runtime/index.d.ts +5 -0
  154. package/dist/esm/tool-runtime/index.js +24 -0
  155. package/dist/esm/tool-runtime/resolve-runner.d.ts +16 -0
  156. package/dist/esm/tool-runtime/resolve-runner.js +42 -0
  157. package/dist/esm/typecheck/index.js +4 -2
  158. package/dist/esm/wp-extension/index.d.ts +50 -0
  159. package/dist/esm/wp-extension/index.js +268 -0
  160. package/package.json +75 -46
  161. package/skills/plan-refine/SKILL.md +5 -4
  162. package/skills/pll/SKILL.md +1 -0
  163. package/dist/esm/blueprint/dag/cycle-detector.d.ts +0 -12
  164. package/dist/esm/blueprint/dag/cycle-detector.js +0 -46
  165. package/dist/esm/blueprint/dag/executor.d.ts +0 -140
  166. package/dist/esm/blueprint/dag/executor.js +0 -292
  167. package/dist/esm/blueprint/dag/index.d.ts +0 -20
  168. package/dist/esm/blueprint/dag/index.js +0 -17
  169. package/dist/esm/blueprint/dag/interfaces.d.ts +0 -56
  170. package/dist/esm/blueprint/dag/interfaces.js +0 -13
  171. package/dist/esm/blueprint/dag/local/independence.d.ts +0 -107
  172. package/dist/esm/blueprint/dag/local/independence.js +0 -231
  173. package/dist/esm/blueprint/dag/local/index.d.ts +0 -14
  174. package/dist/esm/blueprint/dag/local/index.js +0 -14
  175. package/dist/esm/blueprint/dag/local/package-graph.d.ts +0 -66
  176. package/dist/esm/blueprint/dag/local/package-graph.js +0 -148
  177. package/dist/esm/blueprint/dag/plan-parser.d.ts +0 -54
  178. package/dist/esm/blueprint/dag/plan-parser.js +0 -236
  179. package/dist/esm/blueprint/dag/task-graph-algorithms.d.ts +0 -13
  180. package/dist/esm/blueprint/dag/task-graph-algorithms.js +0 -236
  181. package/dist/esm/blueprint/dag/task-graph.d.ts +0 -171
  182. package/dist/esm/blueprint/dag/task-graph.js +0 -370
  183. package/dist/esm/blueprint/dag/types.d.ts +0 -17
  184. package/dist/esm/blueprint/dag/types.js +0 -2
  185. package/dist/esm/blueprint/graph/index.d.ts +0 -5
  186. package/dist/esm/blueprint/graph/index.js +0 -5
  187. package/dist/esm/blueprint/graph/mermaid-parser.d.ts +0 -3
  188. package/dist/esm/blueprint/graph/mermaid-parser.js +0 -93
  189. package/dist/esm/blueprint/graph/mermaid-serializer.d.ts +0 -3
  190. package/dist/esm/blueprint/graph/mermaid-serializer.js +0 -20
  191. package/dist/esm/blueprint/graph/schema.d.ts +0 -89
  192. package/dist/esm/blueprint/graph/schema.js +0 -104
  193. package/dist/esm/blueprint/graph/task-graph-adapter.d.ts +0 -6
  194. package/dist/esm/blueprint/graph/task-graph-adapter.js +0 -30
@@ -1,140 +0,0 @@
1
- import type { IClock } from './interfaces.js';
2
- import type { Task } from './types.js';
3
- import { TaskGraph } from './task-graph.js';
4
- /**
5
- * Task execution result
6
- */
7
- export interface TaskResult<T = unknown> {
8
- taskId: string;
9
- status: 'completed' | 'failed' | 'skipped';
10
- output?: T;
11
- error?: Error;
12
- durationMs: number;
13
- startedAt: number;
14
- completedAt: number;
15
- }
16
- /**
17
- * Concurrency configuration by task type
18
- */
19
- export interface ConcurrencyConfig {
20
- /** Global max concurrent tasks across all types */
21
- global?: number;
22
- /** Default max concurrent tasks per type (when no type-specific limit) */
23
- default: number;
24
- /** Per-type limits (overrides default) */
25
- byType?: Record<string, number>;
26
- }
27
- /**
28
- * Task executor function signature
29
- * Receives task and returns result (or throws)
30
- */
31
- export type TaskExecutorFn<T, R> = (task: Task<T>) => Promise<R>;
32
- /**
33
- * Execution progress callback
34
- */
35
- export interface ExecutionProgress<T = unknown> {
36
- totalTasks: number;
37
- completedTasks: number;
38
- failedTasks: number;
39
- runningTasks: string[];
40
- pendingTasks: number;
41
- currentWave: number;
42
- totalWaves: number;
43
- latestResult?: TaskResult<T>;
44
- }
45
- export type ProgressCallback<T = unknown> = (progress: ExecutionProgress<T>) => void;
46
- /**
47
- * Executor options
48
- */
49
- export interface ExecutorOptions<R> {
50
- concurrency?: ConcurrencyConfig;
51
- onProgress?: ProgressCallback<R>;
52
- /** Clock for time operations (injectable for testing) */
53
- clock?: IClock;
54
- /** Skip tasks whose dependencies failed */
55
- skipOnFailedDependency?: boolean;
56
- /** Timeout for individual tasks in milliseconds (0 = no timeout) */
57
- taskTimeoutMs?: number;
58
- /** AbortSignal for cancellation */
59
- signal?: AbortSignal;
60
- }
61
- /**
62
- * Parallel DAG executor with concurrency controls.
63
- *
64
- * Uses Kahn's algorithm for topological execution order.
65
- * Supports per-task-type concurrency limits.
66
- *
67
- * Runtime-agnostic - works in Node.js, Bun, Deno, Cloudflare Workers.
68
- */
69
- export declare class ParallelExecutor<T = unknown, R = unknown> {
70
- private graph;
71
- private concurrency;
72
- private executorFn;
73
- private onProgress?;
74
- private clock;
75
- private skipOnFailedDependency;
76
- private taskTimeoutMs;
77
- private completed;
78
- private failed;
79
- private skipped;
80
- private running;
81
- private results;
82
- private signal?;
83
- private abortController?;
84
- constructor(graph: TaskGraph<T>, executorFn: TaskExecutorFn<T, R>, options?: ExecutorOptions<R>);
85
- /**
86
- * Execute all tasks in parallel, respecting dependencies and concurrency limits.
87
- * Returns results in completion order.
88
- * @throws {Error} If graph is invalid or execution is aborted
89
- */
90
- execute(): Promise<TaskResult<R>[]>;
91
- /**
92
- * Check if execution has been aborted and throw if so.
93
- * Checks both internal controller and external signal.
94
- */
95
- private throwIfAborted;
96
- /**
97
- * Get current execution state.
98
- */
99
- getState(): {
100
- completed: string[];
101
- failed: string[];
102
- skipped: string[];
103
- running: string[];
104
- };
105
- private executeWave;
106
- private startPendingTasks;
107
- private shouldSkipTask;
108
- private skipTask;
109
- private canStartTask;
110
- private getTaskType;
111
- /**
112
- * Count running tasks of a specific type.
113
- * FIX: Now properly tracks task types.
114
- */
115
- private countRunningByType;
116
- private startTask;
117
- /**
118
- * Execute task with optional timeout support.
119
- * State-of-the-art: proper timeout handling with AbortController pattern.
120
- */
121
- private executeWithTimeout;
122
- private createTimeoutPromise;
123
- private emitTaskStart;
124
- private waitForAny;
125
- private emitProgress;
126
- }
127
- /**
128
- * Create executor from task array with dependencies.
129
- * Convenience function for common use case.
130
- */
131
- export declare function createExecutor<T, R>(tasks: Array<{
132
- task: Task<T>;
133
- dependsOn?: string[];
134
- }>, executorFn: TaskExecutorFn<T, R>, options?: ExecutorOptions<R>): ParallelExecutor<T, R>;
135
- /**
136
- * Create executor directly from tasks using their dependencies arrays.
137
- * Most convenient for LLM agents.
138
- */
139
- export declare function createExecutorFromTasks<T, R>(tasks: Task<T>[], executorFn: TaskExecutorFn<T, R>, options?: ExecutorOptions<R>): ParallelExecutor<T, R>;
140
- //# sourceMappingURL=executor.d.ts.map
@@ -1,292 +0,0 @@
1
- import { realClock } from './interfaces.js';
2
- import { TaskGraph } from './task-graph.js';
3
- /**
4
- * Parallel DAG executor with concurrency controls.
5
- *
6
- * Uses Kahn's algorithm for topological execution order.
7
- * Supports per-task-type concurrency limits.
8
- *
9
- * Runtime-agnostic - works in Node.js, Bun, Deno, Cloudflare Workers.
10
- */
11
- export class ParallelExecutor {
12
- graph;
13
- concurrency;
14
- executorFn;
15
- onProgress;
16
- clock;
17
- skipOnFailedDependency;
18
- taskTimeoutMs;
19
- // Execution state
20
- completed = new Set();
21
- failed = new Set();
22
- skipped = new Set();
23
- running = new Map();
24
- results = [];
25
- signal;
26
- abortController;
27
- constructor(graph, executorFn, options = {}) {
28
- this.graph = graph;
29
- this.executorFn = executorFn;
30
- this.concurrency = options.concurrency ?? { default: 6 };
31
- this.onProgress = options.onProgress;
32
- this.clock = options.clock ?? realClock;
33
- this.skipOnFailedDependency = options.skipOnFailedDependency ?? true;
34
- this.taskTimeoutMs = options.taskTimeoutMs ?? 0;
35
- this.signal = options.signal;
36
- // Create internal abort controller for cleanup
37
- this.abortController = new AbortController();
38
- // Link external signal if provided
39
- if (options.signal) {
40
- options.signal.addEventListener('abort', () => {
41
- this.abortController?.abort(options.signal?.reason);
42
- });
43
- }
44
- }
45
- /**
46
- * Execute all tasks in parallel, respecting dependencies and concurrency limits.
47
- * Returns results in completion order.
48
- * @throws {Error} If graph is invalid or execution is aborted
49
- */
50
- async execute() {
51
- // Check for abort before starting
52
- this.throwIfAborted();
53
- // Validate graph first
54
- const validation = this.graph.validate();
55
- if (!validation.valid) {
56
- throw new Error(`Cannot execute invalid graph: ${validation.errors.join('; ')}`);
57
- }
58
- const waves = this.graph.getWaves();
59
- const totalTasks = waves.flat().length;
60
- for (let waveIdx = 0; waveIdx < waves.length; waveIdx++) {
61
- this.throwIfAborted();
62
- const wave = waves[waveIdx];
63
- if (!wave)
64
- continue;
65
- await this.executeWave(wave, waveIdx + 1, waves.length, totalTasks);
66
- }
67
- return this.results;
68
- }
69
- /**
70
- * Check if execution has been aborted and throw if so.
71
- * Checks both internal controller and external signal.
72
- */
73
- throwIfAborted() {
74
- // Check external signal first (passed in via options)
75
- if (this.signal?.aborted) {
76
- throw new Error(`Execution aborted: ${this.signal.reason || 'user request'}`);
77
- }
78
- // Check internal controller
79
- if (this.abortController?.signal.aborted) {
80
- throw new Error(`Execution aborted: ${this.abortController.signal.reason || 'user request'}`);
81
- }
82
- }
83
- /**
84
- * Get current execution state.
85
- */
86
- getState() {
87
- return {
88
- completed: Array.from(this.completed),
89
- failed: Array.from(this.failed),
90
- skipped: Array.from(this.skipped),
91
- running: Array.from(this.running.keys()),
92
- };
93
- }
94
- async executeWave(tasks, waveNum, totalWaves, totalTasks) {
95
- const pending = [...tasks];
96
- while (pending.length > 0 || this.running.size > 0) {
97
- this.startPendingTasks(pending, waveNum, totalWaves, totalTasks);
98
- if (this.running.size === 0)
99
- break;
100
- const result = await this.waitForAny();
101
- this.results.push(result);
102
- this.emitProgress(waveNum, totalWaves, totalTasks, result);
103
- }
104
- }
105
- startPendingTasks(pending, waveNum, totalWaves, totalTasks) {
106
- while (pending[0] && this.canStartTask(pending[0])) {
107
- const task = pending.shift();
108
- if (!task)
109
- break;
110
- if (this.shouldSkipTask(task)) {
111
- this.skipTask(task, waveNum, totalWaves, totalTasks);
112
- }
113
- else {
114
- this.startTask(task);
115
- }
116
- }
117
- }
118
- shouldSkipTask(task) {
119
- if (!this.skipOnFailedDependency)
120
- return false;
121
- // Check if any dependency failed
122
- const deps = this.graph.getDependencies(task.id);
123
- for (const dep of deps) {
124
- if (this.failed.has(dep) || this.skipped.has(dep)) {
125
- return true;
126
- }
127
- }
128
- return false;
129
- }
130
- skipTask(task, waveNum, totalWaves, totalTasks) {
131
- const now = this.clock.now();
132
- this.skipped.add(task.id);
133
- const result = {
134
- taskId: task.id,
135
- status: 'skipped',
136
- durationMs: 0,
137
- startedAt: now,
138
- completedAt: now,
139
- error: new Error('Skipped due to failed dependency'),
140
- };
141
- this.results.push(result);
142
- this.emitProgress(waveNum, totalWaves, totalTasks, result);
143
- }
144
- canStartTask(task) {
145
- const taskType = this.getTaskType(task);
146
- const typeLimit = this.concurrency.byType?.[taskType] ?? this.concurrency.default;
147
- const currentOfType = this.countRunningByType(taskType);
148
- // Check type-specific limit
149
- if (currentOfType >= typeLimit)
150
- return false;
151
- // Check global limit (defaults to default if not specified)
152
- const globalLimit = this.concurrency.global ?? this.concurrency.default;
153
- if (this.running.size >= globalLimit)
154
- return false;
155
- return true;
156
- }
157
- getTaskType(task) {
158
- // Extract type from task metadata if available
159
- const meta = task.data;
160
- const typeValue = meta?.type;
161
- // Validate type is a string
162
- if (typeof typeValue === 'string' && typeValue.length > 0) {
163
- return typeValue;
164
- }
165
- return 'default';
166
- }
167
- /**
168
- * Count running tasks of a specific type.
169
- * FIX: Now properly tracks task types.
170
- */
171
- countRunningByType(type) {
172
- let count = 0;
173
- for (const info of this.running.values()) {
174
- if (info.taskType === type) {
175
- count++;
176
- }
177
- }
178
- return count;
179
- }
180
- startTask(task) {
181
- const startTime = this.clock.now();
182
- const taskType = this.getTaskType(task);
183
- // Emit task start via progress callback (state-of-the-art observability)
184
- this.emitTaskStart(task.id, taskType);
185
- const promise = this.executeWithTimeout(task, startTime)
186
- .then((output) => ({
187
- taskId: task.id,
188
- status: 'completed',
189
- output,
190
- durationMs: this.clock.now() - startTime,
191
- startedAt: startTime,
192
- completedAt: this.clock.now(),
193
- }))
194
- .catch((error) => ({
195
- taskId: task.id,
196
- status: 'failed',
197
- error: error instanceof Error ? error : new Error(String(error)),
198
- durationMs: this.clock.now() - startTime,
199
- startedAt: startTime,
200
- completedAt: this.clock.now(),
201
- }))
202
- .finally(() => {
203
- this.running.delete(task.id);
204
- });
205
- // Track completion status (fire-and-forget)
206
- void promise.then((r) => {
207
- if (r.status === 'completed') {
208
- this.completed.add(task.id);
209
- }
210
- else {
211
- this.failed.add(task.id);
212
- }
213
- return;
214
- });
215
- this.running.set(task.id, {
216
- taskId: task.id,
217
- taskType,
218
- promise,
219
- });
220
- }
221
- /**
222
- * Execute task with optional timeout support.
223
- * State-of-the-art: proper timeout handling with AbortController pattern.
224
- */
225
- executeWithTimeout(task, _startTime) {
226
- if (this.taskTimeoutMs <= 0) {
227
- return this.executorFn(task);
228
- }
229
- return Promise.race([this.executorFn(task), this.createTimeoutPromise(task.id)]);
230
- }
231
- createTimeoutPromise(taskId) {
232
- return new Promise((resolve) => {
233
- setTimeout(() => resolve(), this.taskTimeoutMs);
234
- }).then(() => {
235
- throw new Error(`Task "${taskId}" timed out after ${this.taskTimeoutMs}ms`);
236
- });
237
- }
238
- emitTaskStart(_taskId, _taskType) {
239
- if (!this.onProgress)
240
- return;
241
- // Progress callback gets task start info via runningTasks update
242
- // This is called before the task is added to running, so it appears in next progress update
243
- }
244
- waitForAny() {
245
- const promises = Array.from(this.running.values()).map((info) => info.promise);
246
- return Promise.race(promises);
247
- }
248
- emitProgress(currentWave, totalWaves, totalTasks, latestResult) {
249
- if (!this.onProgress)
250
- return;
251
- this.onProgress({
252
- totalTasks,
253
- completedTasks: this.completed.size,
254
- failedTasks: this.failed.size,
255
- runningTasks: Array.from(this.running.keys()),
256
- pendingTasks: totalTasks - this.completed.size - this.failed.size - this.skipped.size - this.running.size,
257
- currentWave,
258
- totalWaves,
259
- latestResult,
260
- });
261
- }
262
- }
263
- /**
264
- * Create executor from task array with dependencies.
265
- * Convenience function for common use case.
266
- */
267
- export function createExecutor(tasks, executorFn, options) {
268
- const graph = new TaskGraph();
269
- // Add all tasks first
270
- for (const { task } of tasks) {
271
- graph.addTask(task);
272
- }
273
- // Add dependencies
274
- for (const { task, dependsOn } of tasks) {
275
- if (dependsOn) {
276
- for (const dep of dependsOn) {
277
- graph.addDependency(dep, task.id);
278
- }
279
- }
280
- }
281
- return new ParallelExecutor(graph, executorFn, options);
282
- }
283
- /**
284
- * Create executor directly from tasks using their dependencies arrays.
285
- * Most convenient for LLM agents.
286
- */
287
- export function createExecutorFromTasks(tasks, executorFn, options) {
288
- const graph = new TaskGraph();
289
- graph.addTasksWithDependencies(tasks);
290
- return new ParallelExecutor(graph, executorFn, options);
291
- }
292
- //# sourceMappingURL=executor.js.map
@@ -1,20 +0,0 @@
1
- /**
2
- * webpresso blueprint/dag
3
- *
4
- * Workers-safe DAG (Directed Acyclic Graph) analysis utilities.
5
- * Zero Node.js dependencies — safe for Cloudflare Workers, Deno, Bun, and Node.js.
6
- *
7
- * For Node-only utilities (PackageGraph, IndependenceDetector),
8
- * use the `dag/local` subpath instead.
9
- *
10
- * @packageDocumentation
11
- */
12
- export type { ConcurrencyConfig, ExecutionProgress, ExecutorOptions, ProgressCallback, TaskExecutorFn, TaskResult, } from './executor.js';
13
- export { createExecutor, createExecutorFromTasks, ParallelExecutor } from './executor.js';
14
- export type { GraphStats, IClock, IFileSystem, IPackageGraph, ValidationResult, } from './interfaces.js';
15
- export { realClock } from './interfaces.js';
16
- export type { ParsedPlan, PlanTask } from './plan-parser.js';
17
- export { parsePlan, planTasksToGraphTasks } from './plan-parser.js';
18
- export { CycleDetector, TaskGraph } from './task-graph.js';
19
- export type { Task, TaskNode } from './types.js';
20
- //# sourceMappingURL=index.d.ts.map
@@ -1,17 +0,0 @@
1
- /**
2
- * webpresso blueprint/dag
3
- *
4
- * Workers-safe DAG (Directed Acyclic Graph) analysis utilities.
5
- * Zero Node.js dependencies — safe for Cloudflare Workers, Deno, Bun, and Node.js.
6
- *
7
- * For Node-only utilities (PackageGraph, IndependenceDetector),
8
- * use the `dag/local` subpath instead.
9
- *
10
- * @packageDocumentation
11
- */
12
- export { createExecutor, createExecutorFromTasks, ParallelExecutor } from './executor.js';
13
- export { realClock } from './interfaces.js';
14
- export { parsePlan, planTasksToGraphTasks } from './plan-parser.js';
15
- // Task Graph
16
- export { CycleDetector, TaskGraph } from './task-graph.js';
17
- //# sourceMappingURL=index.js.map
@@ -1,56 +0,0 @@
1
- /**
2
- * Interfaces for dependency injection and testability.
3
- *
4
- * These interfaces allow mocking of external dependencies (filesystem, time)
5
- * for deterministic testing.
6
- */
7
- /**
8
- * Filesystem abstraction for package discovery.
9
- * Allows mocking filesystem access in tests.
10
- */
11
- export interface IFileSystem {
12
- existsSync(path: string): boolean;
13
- readFileSync(path: string, encoding: 'utf-8'): string;
14
- }
15
- /**
16
- * Clock abstraction for time-dependent operations.
17
- * Allows deterministic testing of duration calculations.
18
- */
19
- export interface IClock {
20
- now(): number;
21
- }
22
- /**
23
- * Default clock using Date.now()
24
- */
25
- export declare const realClock: IClock;
26
- /**
27
- * Package graph interface for dependency analysis.
28
- * Allows mocking package structure in tests.
29
- */
30
- export interface IPackageGraph {
31
- findPackageRoot(filePath: string): string | null;
32
- getPackageName(packageRoot: string): string | null;
33
- hasCrossPackageDependency(pkgA: string, pkgB: string): boolean;
34
- areInSamePackage(filePathA: string, filePathB: string): boolean;
35
- }
36
- /**
37
- * Validation result for graph analysis.
38
- */
39
- export interface ValidationResult {
40
- valid: boolean;
41
- errors: string[];
42
- warnings: string[];
43
- }
44
- /**
45
- * Graph statistics for analysis.
46
- */
47
- export interface GraphStats {
48
- nodeCount: number;
49
- edgeCount: number;
50
- maxDepth: number;
51
- maxWidth: number;
52
- waveCount: number;
53
- hasCycles: boolean;
54
- isolatedNodes: string[];
55
- }
56
- //# sourceMappingURL=interfaces.d.ts.map
@@ -1,13 +0,0 @@
1
- /**
2
- * Interfaces for dependency injection and testability.
3
- *
4
- * These interfaces allow mocking of external dependencies (filesystem, time)
5
- * for deterministic testing.
6
- */
7
- /**
8
- * Default clock using Date.now()
9
- */
10
- export const realClock = {
11
- now: () => Date.now(),
12
- };
13
- //# sourceMappingURL=interfaces.js.map
@@ -1,107 +0,0 @@
1
- import type { IPackageGraph } from '#dag/interfaces';
2
- /**
3
- * Represents a task with its file access information.
4
- */
5
- export interface TaskFiles {
6
- id: string;
7
- files: string[];
8
- readOnly: boolean;
9
- }
10
- /**
11
- * Result of parallelization analysis.
12
- */
13
- export interface ParallelizeResult {
14
- canParallelize: boolean;
15
- reason: string;
16
- /** Files that would conflict if parallelized */
17
- conflictingFiles?: string[];
18
- }
19
- /**
20
- * A false dependency that can be removed.
21
- */
22
- export interface FalseDependency {
23
- from: string;
24
- to: string;
25
- reason: string;
26
- }
27
- /**
28
- * Analysis result for a pair of tasks.
29
- */
30
- export interface TaskPairAnalysis {
31
- taskA: string;
32
- taskB: string;
33
- canParallelize: boolean;
34
- reason: string;
35
- packagesA: string[];
36
- packagesB: string[];
37
- overlappingFiles: string[];
38
- hasCrossPackageDependency: boolean;
39
- }
40
- /**
41
- * IndependenceDetector analyzes tasks to find false dependencies.
42
- *
43
- * Uses file and package analysis to determine if tasks can run in parallel,
44
- * even when the plan declares a dependency between them.
45
- *
46
- * Accepts IPackageGraph interface for testability - package structure can be mocked.
47
- */
48
- export declare class IndependenceDetector {
49
- private readonly packageGraph;
50
- /**
51
- * Create a new IndependenceDetector.
52
- * @param rootOrPackageGraph - Either a root path (creates real PackageGraph) or an IPackageGraph for testing
53
- */
54
- constructor(rootOrPackageGraph: string | IPackageGraph);
55
- /**
56
- * Determine if two tasks can run in parallel based on their file access.
57
- *
58
- * Algorithm:
59
- * 1. Get package for each file (walk up to package.json)
60
- * 2. IF different packages AND no cross-package deps → PARALLEL
61
- * 3. IF same package but no file overlap → PARALLEL
62
- * 4. IF file overlap but both read-only → PARALLEL
63
- * 5. ELSE → SERIAL
64
- */
65
- canParallelize(taskA: TaskFiles, taskB: TaskFiles): ParallelizeResult;
66
- private analyzePackageLocation;
67
- private analyzeFilesOutsidePackages;
68
- private analyzeDifferentPackages;
69
- private analyzeSamePackage;
70
- /**
71
- * Analyze a pair of tasks in detail.
72
- * Useful for debugging why tasks can or cannot be parallelized.
73
- */
74
- analyzeTaskPair(taskA: TaskFiles, taskB: TaskFiles): TaskPairAnalysis;
75
- /**
76
- * Find all false dependencies in a task graph.
77
- *
78
- * @param tasks - List of tasks with their file information
79
- * @param edges - List of declared dependencies (from → to)
80
- * @returns List of edges that can be safely removed
81
- */
82
- findFalseDependencies(tasks: TaskFiles[], edges: Array<{
83
- from: string;
84
- to: string;
85
- }>): FalseDependency[];
86
- /**
87
- * Analyze all task pairs and return detailed analysis.
88
- * Useful for understanding the parallelization potential of a task set.
89
- */
90
- analyzeAllPairs(tasks: TaskFiles[]): {
91
- totalPairs: number;
92
- parallelizablePairs: number;
93
- analyses: TaskPairAnalysis[];
94
- };
95
- private getPackagesForFiles;
96
- private hasOverlap;
97
- private hasCrossPackageDep;
98
- private anyDependsOn;
99
- private getOverlappingFiles;
100
- }
101
- /**
102
- * Create a mock package graph for testing.
103
- * @param packages - Map of file paths to package roots
104
- * @param dependencies - Map of package roots to their dependencies
105
- */
106
- export declare function createMockPackageGraph(packages: Map<string, string | null>, dependencies?: Map<string, string[]>): IPackageGraph;
107
- //# sourceMappingURL=independence.d.ts.map