@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,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
|