lastlight-workflow-engine 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,233 @@
1
+ /**
2
+ * The workflow engine's injected ports — the concrete couplings the app layer
3
+ * supplies so the engine stays domain-agnostic (no imports of `../engine`,
4
+ * `../state`, `../notify`, `../admin`, `../config`, GitHub, or better-sqlite3).
5
+ *
6
+ * The app's existing concrete types already satisfy these structurally, so
7
+ * introducing each port is a type-only change: the default adapters (built in
8
+ * `src/workflows/runner.ts`) are thin delegations to the real functions.
9
+ */
10
+ import type { ExecutorConfig, ExecutionResult, GitSandboxAccess, CommandSpec } from "../core/types.js";
11
+ import type { PhaseDefinition } from "../core/schema.js";
12
+ import type { DagNode } from "../core/dag.js";
13
+ import type { TemplateContext } from "../core/templates.js";
14
+ import type { ParsedVerdict } from "../core/verdict.js";
15
+ /** Lifecycle state of a single checklist step. */
16
+ export type StepStatus = "pending" | "running" | "done" | "blocked" | "awaiting" | "failed" | "skipped";
17
+ /** One row in the task list. `key` is stable; `label` is what humans see. */
18
+ export interface ProgressStep {
19
+ key: string;
20
+ label: string;
21
+ status: StepStatus;
22
+ /** Optional one-line context shown after the label (e.g. a link or status). */
23
+ detail?: string;
24
+ }
25
+ export interface PhaseResult {
26
+ phase: string;
27
+ success: boolean;
28
+ output: string;
29
+ error?: string;
30
+ }
31
+ export interface WorkflowResult {
32
+ success: boolean;
33
+ phases: PhaseResult[];
34
+ prNumber?: number;
35
+ paused?: boolean;
36
+ }
37
+ /** The delta a single `execute(node, outputs)` returns to the scheduler. */
38
+ export interface PhaseOutcome {
39
+ results: PhaseResult[];
40
+ status: "succeeded" | "failed" | "skipped";
41
+ /** Approval / reply gate hit — scheduler returns `{ success: true, paused: true }`. */
42
+ paused?: boolean;
43
+ /**
44
+ * Dedup running-skip — another instance is mid-flight on this exact phase.
45
+ * Scheduler stops the whole run immediately with `success: false` and does
46
+ * NOT cascade skips (it isn't a phase failure).
47
+ */
48
+ aborted?: boolean;
49
+ /** Output map additions to merge into the scheduler's accumulated outputs. */
50
+ outputVars?: Record<string, unknown>;
51
+ }
52
+ export interface AgentRunOpts {
53
+ taskId?: string;
54
+ githubAccess?: GitSandboxAccess;
55
+ onSessionId?: (sessionId: string) => void;
56
+ timeoutSeconds?: number;
57
+ sandboxEnv?: Record<string, string>;
58
+ writeSession?: boolean;
59
+ }
60
+ /**
61
+ * Replaces the direct `executeAgent` / `executeCommand` imports in the phase
62
+ * executor. Signatures mirror `src/engine/agent-executor.ts`.
63
+ */
64
+ export interface AgentPort {
65
+ runAgent(prompt: string, config: ExecutorConfig, opts: AgentRunOpts): Promise<ExecutionResult>;
66
+ runCommand(spec: CommandSpec, config: ExecutorConfig, opts: AgentRunOpts): Promise<ExecutionResult>;
67
+ }
68
+ export interface PhaseHistoryEntry {
69
+ phase: string;
70
+ timestamp: string;
71
+ success: boolean;
72
+ summary?: string;
73
+ }
74
+ /** A non-agent phase marker folded into an atomic lifecycle op. */
75
+ export interface PhaseMarker {
76
+ phase: string;
77
+ summary?: string;
78
+ }
79
+ /** The subset of a workflow run the engine reads. */
80
+ export interface WorkflowRunView {
81
+ status: "running" | "paused" | "succeeded" | "failed" | "cancelled";
82
+ scratch?: Record<string, unknown>;
83
+ }
84
+ /** The approval row the engine asks the store to create when pausing. */
85
+ export interface NewApproval {
86
+ id: string;
87
+ workflowRunId: string;
88
+ gate: string;
89
+ summary: string;
90
+ kind: "approve" | "reply";
91
+ artifact?: string;
92
+ requestedBy?: string;
93
+ createdAt: string;
94
+ }
95
+ /** The row the engine records when a phase starts. */
96
+ export interface NewExecution {
97
+ id: string;
98
+ triggerType: "webhook" | "cron" | "chat" | "api";
99
+ triggerId: string;
100
+ skill: string;
101
+ repo?: string;
102
+ issueNumber?: number;
103
+ startedAt: string;
104
+ workflowRunId?: string;
105
+ }
106
+ /** The fields the engine records when a phase finishes. */
107
+ export interface ExecutionFinish {
108
+ success: boolean;
109
+ error?: string;
110
+ turns?: number;
111
+ durationMs?: number;
112
+ sessionId?: string;
113
+ costUsd?: number;
114
+ inputTokens?: number;
115
+ cacheCreationInputTokens?: number;
116
+ cacheReadInputTokens?: number;
117
+ outputTokens?: number;
118
+ apiDurationMs?: number;
119
+ stopReason?: string;
120
+ extensionStatus?: string;
121
+ skillsStatus?: string;
122
+ }
123
+ export interface FinishOpts {
124
+ error?: string;
125
+ terminalMarker?: PhaseMarker;
126
+ }
127
+ export interface RunStore {
128
+ getRun(id: string): WorkflowRunView | null;
129
+ appendPhase(id: string, phase: string, entry: PhaseHistoryEntry): void;
130
+ finishRun(id: string, status: "succeeded" | "failed" | "cancelled", opts?: FinishOpts): void;
131
+ mergeScratch(id: string, patch: Record<string, unknown>): void;
132
+ pauseForApproval(runId: string, approval: NewApproval, marker: PhaseMarker, scratchPatch?: Record<string, unknown>): void;
133
+ }
134
+ export interface ExecutionLedger {
135
+ shouldRunPhase(dedupKey: string, triggerId: string, workflowRunId?: string): "run" | "running" | "done";
136
+ markStaleAsFailed(dedupKey: string, triggerId: string, workflowRunId?: string): number;
137
+ markLatestAsFailed(dedupKey: string, triggerId: string, reason: string, workflowRunId?: string): number;
138
+ recordStart(row: NewExecution): void;
139
+ recordFinish(id: string, result: ExecutionFinish): void;
140
+ recordSessionId(id: string, sessionId: string): void;
141
+ recordOutputText(id: string, text: string): void;
142
+ recordSkippedPhase(dedupKey: string, triggerId: string, workflowRunId?: string, repo?: string): void;
143
+ getPhaseOutput(dedupKey: string, triggerId: string, workflowRunId?: string): string | null;
144
+ getExecutionOutput(id: string): string | null;
145
+ }
146
+ export interface WorkflowStateStore {
147
+ runs: RunStore;
148
+ executions: ExecutionLedger;
149
+ }
150
+ export interface AssetLoader {
151
+ loadPromptTemplate(relativePath: string): string;
152
+ resolveSkillPaths(names: readonly string[]): string[];
153
+ }
154
+ export interface LivenessPort {
155
+ isPhaseContainerAlive(taskId: string): Promise<boolean>;
156
+ }
157
+ export interface EngineSpan {
158
+ addEvent(name: string, attrs?: Record<string, unknown>): void;
159
+ setAttributes(attrs: Record<string, unknown>): void;
160
+ }
161
+ export interface ObservabilityPort {
162
+ withSpan<T>(name: string, attrs: Record<string, unknown>, fn: (span?: EngineSpan) => Promise<T> | T): Promise<T>;
163
+ recordExecutionMetrics(surface: string, attrs: Record<string, unknown>): void;
164
+ recordError(surface: string, error: unknown, attrs: Record<string, unknown>): void;
165
+ }
166
+ export interface ReportStepOpts {
167
+ label?: string;
168
+ insertBefore?: string;
169
+ insert?: boolean;
170
+ alsoNote?: boolean;
171
+ }
172
+ /** Progress / notification surface — the reporting collaborator. */
173
+ export interface PhaseReporter {
174
+ onStart(phase: string): Promise<void>;
175
+ onEnd(phase: string, result: PhaseResult): Promise<void>;
176
+ /** Transition a checklist step (and optionally render a YAML message detail). */
177
+ step(key: string, status: StepStatus, template?: string, extraCtx?: Partial<TemplateContext>, opts?: ReportStepOpts): Promise<void>;
178
+ /** Render a YAML message template and post it as a standalone note. */
179
+ message(template: string | undefined, extraCtx?: Partial<TemplateContext>): Promise<void>;
180
+ /**
181
+ * Render a YAML message template and post it as an *interactive approval
182
+ * prompt* (Approve/Reject buttons on rich surfaces, plain text elsewhere).
183
+ */
184
+ approvalNote(template: string | undefined, extraCtx: Partial<TemplateContext>, meta: {
185
+ workflowRunId: string;
186
+ }): Promise<void>;
187
+ /** Post a pre-rendered standalone message. */
188
+ postNote(text: string): Promise<void>;
189
+ /** Persist a phase-history entry on the workflow run. */
190
+ persistPhase(phase: string, summary?: string): void;
191
+ /** Mark the workflow run failed. */
192
+ failWorkflow(errorMsg?: string): void;
193
+ /** Set (or clear) the trailing footer of the single status surface. */
194
+ footer(markdown: string): Promise<void>;
195
+ /** Post the run's completion message (terminal-ping surfaces only). */
196
+ noteTerminal(markdown: string): Promise<void>;
197
+ }
198
+ /** Model / variant / prompt / gate resolution — the resolution collaborator. */
199
+ export interface PhaseResolver {
200
+ modelFor(taskType: string): string | undefined;
201
+ variantFor(taskType: string): string | undefined;
202
+ renderPrompt(promptPath: string, extraCtx?: Partial<TemplateContext>): string;
203
+ gateEnabled(gateName: string | undefined): boolean;
204
+ }
205
+ /**
206
+ * Reads the reviewer's authoritative verdict from its on-disk artifact
207
+ * (`reviewer-verdict.md`, in the server-mode build-asset store or the committed
208
+ * host checkout) when the stdout `VERDICT:` marker is missing. App-coupled
209
+ * (filesystem + build-asset store), so it's injected. Absent ⇒ the reviewer
210
+ * loop's file-fallback recovery simply no-ops (the "no recoverable verdict"
211
+ * path), which is safe.
212
+ */
213
+ export interface VerdictArtifactReader {
214
+ read(input: {
215
+ config: ExecutorConfig;
216
+ repo: string;
217
+ issueDir: string;
218
+ taskId: string;
219
+ }): ParsedVerdict | undefined;
220
+ }
221
+ export interface PhaseTypeHandler {
222
+ execute(phase: PhaseDefinition, node: DagNode, outputs: Readonly<Record<string, unknown>>): Promise<PhaseOutcome>;
223
+ }
224
+ export interface EnginePorts {
225
+ agent: AgentPort;
226
+ assets: AssetLoader;
227
+ liveness: LivenessPort;
228
+ observability: ObservabilityPort;
229
+ /** Reviewer verdict-artifact fallback reader (see {@link VerdictArtifactReader}). */
230
+ verdictReader?: VerdictArtifactReader;
231
+ /** App-registered handlers for non-generic phase types (e.g. post-review). */
232
+ handlers?: Map<string, PhaseTypeHandler>;
233
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The workflow engine's injected ports — the concrete couplings the app layer
3
+ * supplies so the engine stays domain-agnostic (no imports of `../engine`,
4
+ * `../state`, `../notify`, `../admin`, `../config`, GitHub, or better-sqlite3).
5
+ *
6
+ * The app's existing concrete types already satisfy these structurally, so
7
+ * introducing each port is a type-only change: the default adapters (built in
8
+ * `src/workflows/runner.ts`) are thin delegations to the real functions.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=ports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.js","sourceRoot":"","sources":["../../src/ports/ports.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * In-memory fakes for the workflow engine's injected ports — no docker, git,
3
+ * sqlite, or filesystem. They let a consumer (the app's unit tests, an external
4
+ * eval harness, or another codebase embedding the engine) drive a real workflow
5
+ * run with scripted agent outcomes.
6
+ *
7
+ * Engine-pure: imports only the port interfaces + core types.
8
+ */
9
+ import type { AgentPort, AgentRunOpts, AssetLoader, ExecutionLedger, LivenessPort, ObservabilityPort, PhaseReporter, PhaseResult, RunStore, StepStatus, WorkflowStateStore } from "../ports/ports.js";
10
+ import type { CommandSpec, ExecutionResult, ExecutorConfig } from "../core/types.js";
11
+ export interface RecordedAgentCall {
12
+ kind: "agent" | "command";
13
+ prompt?: string;
14
+ spec?: CommandSpec;
15
+ config: ExecutorConfig;
16
+ opts: AgentRunOpts;
17
+ }
18
+ /**
19
+ * Records every `{prompt|spec, config, opts}` and returns scripted
20
+ * `ExecutionResult`s (a queue, or a single default). Mirrors the app's
21
+ * `FakeSandbox` shape.
22
+ */
23
+ export declare class FakeAgentPort implements AgentPort {
24
+ readonly calls: RecordedAgentCall[];
25
+ private queue;
26
+ private fallback;
27
+ constructor(fallback?: ExecutionResult);
28
+ /** Script the next N results (consumed FIFO). */
29
+ script(...results: ExecutionResult[]): this;
30
+ private next;
31
+ runAgent(prompt: string, config: ExecutorConfig, opts: AgentRunOpts): Promise<ExecutionResult>;
32
+ runCommand(spec: CommandSpec, config: ExecutorConfig, opts: AgentRunOpts): Promise<ExecutionResult>;
33
+ }
34
+ /**
35
+ * Map-backed {@link WorkflowStateStore} — the resume/dedup ledger + run store,
36
+ * with no better-sqlite3. Reproduces the production resume caveat: a phase whose
37
+ * ledger row is already `success=1` returns `"done"` from
38
+ * {@link ExecutionLedger.shouldRunPhase}, so the engine skips it (and it
39
+ * contributes nothing to the in-memory `outputs` map).
40
+ */
41
+ export declare class InMemoryStateStore implements WorkflowStateStore {
42
+ private runsById;
43
+ private ledger;
44
+ private byExecId;
45
+ constructor(runId?: string);
46
+ private ensureRun;
47
+ readonly runs: RunStore;
48
+ readonly executions: ExecutionLedger;
49
+ }
50
+ export interface RecordedStep {
51
+ key: string;
52
+ status: StepStatus;
53
+ template?: string;
54
+ }
55
+ /** A {@link PhaseReporter} that records everything and posts nowhere. */
56
+ export declare class RecordingReporter implements PhaseReporter {
57
+ readonly steps: RecordedStep[];
58
+ readonly notes: string[];
59
+ readonly persisted: {
60
+ phase: string;
61
+ summary?: string;
62
+ }[];
63
+ readonly failures: string[];
64
+ readonly ends: PhaseResult[];
65
+ onStart(): Promise<void>;
66
+ onEnd(_phase: string, result: PhaseResult): Promise<void>;
67
+ step(key: string, status: StepStatus, template?: string): Promise<void>;
68
+ message(template: string | undefined): Promise<void>;
69
+ approvalNote(template: string | undefined): Promise<void>;
70
+ postNote(text: string): Promise<void>;
71
+ persistPhase(phase: string, summary?: string): void;
72
+ failWorkflow(errorMsg?: string): void;
73
+ footer(markdown: string): Promise<void>;
74
+ noteTerminal(markdown: string): Promise<void>;
75
+ }
76
+ /** Returns a deterministic stub template per path + no skill paths. */
77
+ export declare class StubAssetLoader implements AssetLoader {
78
+ private readonly templates;
79
+ constructor(templates?: Record<string, string>);
80
+ loadPromptTemplate(relativePath: string): string;
81
+ resolveSkillPaths(names: readonly string[]): string[];
82
+ }
83
+ /** Liveness port that never sees a live container (the test default). */
84
+ export declare const noopLiveness: LivenessPort;
85
+ /** Observability port that runs the span body directly and drops metrics. */
86
+ export declare const noopObservability: ObservabilityPort;
Binary file
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fakes.js","sourceRoot":"","sources":["../../src/test-support/fakes.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "lastlight-workflow-engine",
3
+ "version": "0.1.0",
4
+ "description": "Port-driven workflow engine extracted from Last Light — DAG scheduler, phase executor, DSL/schema, template + loop constructs.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./test-support": {
14
+ "types": "./dist/test-support/fakes.d.ts",
15
+ "import": "./dist/test-support/fakes.js"
16
+ },
17
+ "./package.json": "./package.json"
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "license": "MIT",
23
+ "engines": {
24
+ "node": ">=22.12"
25
+ },
26
+ "dependencies": {
27
+ "zod": "^4.3.6"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^22.0.0",
31
+ "dependency-cruiser": "^18.1.0",
32
+ "typescript": "^5.7.0"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc -p tsconfig.json",
36
+ "typecheck": "tsc -p tsconfig.json --noEmit && pnpm run lint:boundaries",
37
+ "lint:boundaries": "depcruise --config .dependency-cruiser.cjs src"
38
+ }
39
+ }