@hasna/workflows 0.1.3 → 0.2.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/README.md +152 -98
- package/dist/agent-tools.js +152 -959
- package/dist/cli/index.js +4130 -2329
- package/dist/handlers.js +3287 -55
- package/dist/index.js +1534 -370
- package/dist/mcp/index.js +1741 -1660
- package/dist/sdk.js +1620 -0
- package/dist/serve/admin.js +4248 -0
- package/dist/serve/index.js +3416 -1350
- package/dist/service.js +1302 -286
- package/hasna.contract.json +17 -17
- package/package.json +16 -13
- package/types/agent-tools.d.ts +3 -17
- package/types/client-error.d.ts +4 -0
- package/types/client-tools.d.ts +4 -0
- package/types/client.d.ts +60 -0
- package/types/daemon.d.ts +18 -9
- package/types/db/postgres-store.d.ts +54 -0
- package/types/graph.d.ts +7 -0
- package/types/handlers.d.ts +2 -1
- package/types/identity.d.ts +7 -0
- package/types/lanes/types.d.ts +12 -3
- package/types/openapi.d.ts +7 -0
- package/types/paths.d.ts +10 -1
- package/types/sdk/generated-api.d.ts +159 -0
- package/types/sdk.d.ts +6 -0
- package/types/serve/admin.d.ts +2 -0
- package/types/service.d.ts +75 -4
- package/types/session.d.ts +31 -8
- package/types/setup.d.ts +71 -0
- package/types/store.d.ts +35 -0
- package/types/tool-definitions.d.ts +18 -0
- package/types/types.d.ts +8 -0
- package/types/version.d.ts +1 -0
- package/types/wal.d.ts +9 -1
package/hasna.contract.json
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"name": "workflows",
|
|
4
4
|
"class": "service",
|
|
5
5
|
"contractVersion": "v1",
|
|
6
|
-
"kitVersion": "
|
|
7
|
-
"description": "
|
|
6
|
+
"kitVersion": "1.3.3",
|
|
7
|
+
"description": "Hosted workflow CLI, MCP and HTTP SDK, with a PostgreSQL execution server and a preserved session journal.",
|
|
8
8
|
"bins": [
|
|
9
9
|
"workflows",
|
|
10
10
|
"workflows-mcp",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"kind": "api",
|
|
20
20
|
"status": "supported",
|
|
21
21
|
"bin": "workflows-serve",
|
|
22
|
-
"authMode": "
|
|
22
|
+
"authMode": "api-key",
|
|
23
23
|
"health": {
|
|
24
24
|
"method": "GET",
|
|
25
25
|
"path": "/health",
|
|
@@ -35,41 +35,41 @@
|
|
|
35
35
|
"path": "/version",
|
|
36
36
|
"public": true
|
|
37
37
|
},
|
|
38
|
-
"openApiPath": "/openapi.json"
|
|
38
|
+
"openApiPath": "/v1/openapi.json"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
"name": "typescript-sdk",
|
|
42
42
|
"kind": "sdk",
|
|
43
43
|
"status": "supported",
|
|
44
|
-
"authMode": "
|
|
44
|
+
"authMode": "api-key",
|
|
45
45
|
"exportSubpath": "./sdk",
|
|
46
|
-
"clientClassName": "
|
|
47
|
-
"generatedFrom": "/openapi.json"
|
|
46
|
+
"clientClassName": "WorkflowsClient",
|
|
47
|
+
"generatedFrom": "/v1/openapi.json"
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"name": "mcp",
|
|
51
51
|
"kind": "mcp",
|
|
52
52
|
"status": "supported",
|
|
53
53
|
"mcpBin": "workflows-mcp",
|
|
54
|
-
"authMode": "
|
|
54
|
+
"authMode": "api-key"
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
57
|
"name": "cli",
|
|
58
58
|
"kind": "cli",
|
|
59
59
|
"status": "supported",
|
|
60
60
|
"bin": "workflows",
|
|
61
|
-
"authMode": "
|
|
61
|
+
"authMode": "api-key"
|
|
62
62
|
}
|
|
63
63
|
],
|
|
64
64
|
"metadata": {
|
|
65
65
|
"serve": {
|
|
66
66
|
"healthEndpoints": [
|
|
67
|
-
"/health",
|
|
68
|
-
"/ready",
|
|
69
|
-
"/version"
|
|
67
|
+
"/v1/health",
|
|
68
|
+
"/v1/ready",
|
|
69
|
+
"/v1/version"
|
|
70
70
|
],
|
|
71
|
-
"openapi": "/openapi.json",
|
|
72
|
-
"auth": "
|
|
71
|
+
"openapi": "/v1/openapi.json",
|
|
72
|
+
"auth": "api-key"
|
|
73
73
|
},
|
|
74
74
|
"release": {
|
|
75
75
|
"artifactScan": {
|
|
@@ -78,10 +78,10 @@
|
|
|
78
78
|
}
|
|
79
79
|
},
|
|
80
80
|
"storage": {
|
|
81
|
-
"backend": "
|
|
81
|
+
"backend": "postgresql",
|
|
82
82
|
"engines": [
|
|
83
|
-
"
|
|
84
|
-
"
|
|
83
|
+
"postgresql",
|
|
84
|
+
"sqlite"
|
|
85
85
|
],
|
|
86
86
|
"envPrefix": "HASNA_WORKFLOWS_",
|
|
87
87
|
"aliasEnvPrefix": "WORKFLOWS_",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/workflows",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Universal graph workflow app — graph language (start/step/decision/while/end), three-table store, session WAL, daemon with claims/leases, four lane adapters (claude/codex/cursor/grok), and a full CLI on four surfaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"import": "./dist/index.js"
|
|
17
17
|
},
|
|
18
18
|
"./sdk": {
|
|
19
|
-
"types": "./types/
|
|
20
|
-
"import": "./dist/
|
|
19
|
+
"types": "./types/sdk.d.ts",
|
|
20
|
+
"import": "./dist/sdk.js"
|
|
21
21
|
},
|
|
22
22
|
"./cli": {
|
|
23
23
|
"types": "./types/cli/index.d.ts",
|
|
@@ -32,14 +32,17 @@
|
|
|
32
32
|
"hasna.contract.json"
|
|
33
33
|
],
|
|
34
34
|
"scripts": {
|
|
35
|
-
"build": "bun run build:runtime && bun run build:types",
|
|
36
|
-
"
|
|
37
|
-
"
|
|
35
|
+
"build": "bun run check:sdk && bun run build:runtime && bun run build:types",
|
|
36
|
+
"generate:sdk": "bun scripts/generate-sdk.ts --write",
|
|
37
|
+
"check:sdk": "bun scripts/generate-sdk.ts",
|
|
38
|
+
"test:artifacts": "bun scripts/artifact-acceptance.ts",
|
|
39
|
+
"build:runtime": "bun build src/cli/index.ts --outdir dist/cli --target bun && bun build src/mcp/index.ts --outdir dist/mcp --target bun && bun build src/serve/index.ts src/serve/admin.ts --outdir dist/serve --target bun --packages external && bun build src/index.ts src/service.ts src/handlers.ts src/agent-tools.ts src/types.ts --root src --outdir dist --target bun --packages external && bun build src/sdk.ts --outdir dist --target node",
|
|
40
|
+
"build:types": "tsc -p tsconfig.build.json --emitDeclarationOnly --outDir types",
|
|
38
41
|
"artifact-scan": "bun scripts/contracts-cli.mjs artifact-scan dist",
|
|
39
42
|
"contract:check": "bun scripts/contracts-cli.mjs repo-conformance .",
|
|
40
43
|
"typecheck": "tsc --noEmit",
|
|
41
44
|
"test": "bun test",
|
|
42
|
-
"test:pg": "WORKFLOWS_TEST_DATABASE_URL=\"${WORKFLOWS_TEST_DATABASE_URL:?point it at a
|
|
45
|
+
"test:pg": "WORKFLOWS_TEST_DATABASE_URL=\"${WORKFLOWS_TEST_DATABASE_URL:?point it at a fresh test Postgres database}\" WORKFLOWS_REQUIRE_POSTGRES=1 bun test src/db/postgres-store.test.ts src/db/postgres-http.test.ts src/db/postgres-fencing.test.ts",
|
|
43
46
|
"prepack": "bun run build && bun run artifact-scan",
|
|
44
47
|
"prepublishOnly": "bun run test && bun run build"
|
|
45
48
|
},
|
|
@@ -58,7 +61,8 @@
|
|
|
58
61
|
},
|
|
59
62
|
"repository": {
|
|
60
63
|
"type": "git",
|
|
61
|
-
"url": "
|
|
64
|
+
"url": "https://github.com/hasna/apps.git",
|
|
65
|
+
"directory": "apps/workflows"
|
|
62
66
|
},
|
|
63
67
|
"homepage": "https://github.com/hasna/apps/tree/main/apps/workflows",
|
|
64
68
|
"bugs": {
|
|
@@ -72,15 +76,14 @@
|
|
|
72
76
|
"dependencies": {
|
|
73
77
|
"@anthropic-ai/claude-agent-sdk": "0.3.234",
|
|
74
78
|
"@cursor/sdk": "^1.0.28",
|
|
75
|
-
"@hasna/paths": "0.1.0",
|
|
76
79
|
"@openai/codex-sdk": "0.147.0",
|
|
77
|
-
"commander": "^13.1.0"
|
|
80
|
+
"commander": "^13.1.0",
|
|
81
|
+
"@hasna/contracts": "1.3.3",
|
|
82
|
+
"pg": "^8.16.3"
|
|
78
83
|
},
|
|
79
84
|
"devDependencies": {
|
|
80
|
-
"@
|
|
81
|
-
"@types/bun": "latest",
|
|
85
|
+
"@types/bun": "1.3.14",
|
|
82
86
|
"@types/pg": "^8.15.6",
|
|
83
|
-
"pg": "^8.16.3",
|
|
84
87
|
"typescript": "^5.7.3"
|
|
85
88
|
}
|
|
86
89
|
}
|
package/types/agent-tools.d.ts
CHANGED
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
import type { WorkflowsService } from "./service.js";
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
inputSchema: {
|
|
6
|
-
type: "object";
|
|
7
|
-
properties: Record<string, unknown>;
|
|
8
|
-
required?: string[];
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
export interface ToolCallResult {
|
|
12
|
-
content: {
|
|
13
|
-
type: "text";
|
|
14
|
-
text: string;
|
|
15
|
-
}[];
|
|
16
|
-
isError: boolean;
|
|
17
|
-
}
|
|
18
|
-
export declare function workflowsTools(_service: WorkflowsService): McpTool[];
|
|
2
|
+
export { workflowsTools } from "./tool-definitions.js";
|
|
3
|
+
export type { McpTool, ToolCallResult } from "./tool-definitions.js";
|
|
4
|
+
import type { ToolCallResult } from "./tool-definitions.js";
|
|
19
5
|
export declare function callWorkflowTool(service: WorkflowsService, name: string, args: Record<string, unknown>): Promise<ToolCallResult>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { WorkflowsClient } from "./client.js";
|
|
2
|
+
import { type ToolCallResult } from "./tool-definitions.js";
|
|
3
|
+
/** MCP delegates data operations to the same hosted client as the CLI and SDK. */
|
|
4
|
+
export declare function callClientTool(client: () => WorkflowsClient, name: string, args: Record<string, unknown>): Promise<ToolCallResult>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Hosted client shared by CLI, MCP and SDK. Never opens an application store. */
|
|
2
|
+
import { type ClientTransportResolution } from "@hasna/contracts/client";
|
|
3
|
+
import type { WorkflowGraph } from "./graph.js";
|
|
4
|
+
import type { RunRow, RunNodeRow, RunStatus } from "./store.js";
|
|
5
|
+
import type { HealthReport, ReadinessReport } from "./types.js";
|
|
6
|
+
import { WorkflowsApi } from "./sdk/generated-api.js";
|
|
7
|
+
export interface WorkflowsClientOptions {
|
|
8
|
+
apiUrl?: string;
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
env?: Record<string, string | undefined>;
|
|
11
|
+
fetchImpl?: typeof fetch;
|
|
12
|
+
timeoutMs?: number;
|
|
13
|
+
agent?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface RunSummary {
|
|
16
|
+
runId: string;
|
|
17
|
+
status: string;
|
|
18
|
+
error: string | null;
|
|
19
|
+
result: unknown;
|
|
20
|
+
reused: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare class WorkflowsClient extends WorkflowsApi {
|
|
23
|
+
readonly name = "workflows";
|
|
24
|
+
readonly resolution: ClientTransportResolution;
|
|
25
|
+
private readonly http;
|
|
26
|
+
constructor(options?: WorkflowsClientOptions);
|
|
27
|
+
request<T>(method: string, path: string, body?: unknown): Promise<T>;
|
|
28
|
+
protected apiRequest<T>(method: string, path: string, opts: {
|
|
29
|
+
body?: unknown;
|
|
30
|
+
query?: Record<string, unknown>;
|
|
31
|
+
}): Promise<T>;
|
|
32
|
+
health(): Promise<HealthReport>;
|
|
33
|
+
ready(): Promise<ReadinessReport>;
|
|
34
|
+
version(): Promise<{
|
|
35
|
+
service: string;
|
|
36
|
+
version: string;
|
|
37
|
+
}>;
|
|
38
|
+
validate(graph: unknown): Promise<{
|
|
39
|
+
ok: boolean;
|
|
40
|
+
issues: {
|
|
41
|
+
path: string;
|
|
42
|
+
message: string;
|
|
43
|
+
}[];
|
|
44
|
+
}>;
|
|
45
|
+
triggerRun(graph: WorkflowGraph, context?: unknown, opts?: {
|
|
46
|
+
maxCycles?: number;
|
|
47
|
+
idempotencyKey?: string;
|
|
48
|
+
}): Promise<RunSummary>;
|
|
49
|
+
listRuns(options?: {
|
|
50
|
+
status?: RunStatus;
|
|
51
|
+
limit?: number;
|
|
52
|
+
}): Promise<RunRow[]>;
|
|
53
|
+
getRun(id: string): Promise<RunRow>;
|
|
54
|
+
listNodes(id: string): Promise<RunNodeRow[]>;
|
|
55
|
+
events(id: string): Promise<unknown[]>;
|
|
56
|
+
cancelRun(id: string): Promise<RunRow>;
|
|
57
|
+
resumeRun(id: string): Promise<RunSummary>;
|
|
58
|
+
lanes(): Promise<unknown[]>;
|
|
59
|
+
}
|
|
60
|
+
export declare function createWorkflowsClient(options?: WorkflowsClientOptions): WorkflowsClient;
|
package/types/daemon.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type WorkflowGraph } from "./graph.js";
|
|
2
|
-
import type { RunRow, WorkflowsStore } from "./store.js";
|
|
2
|
+
import type { RunRow, WorkflowsStore, EngineStore } from "./store.js";
|
|
3
3
|
import { SessionWAL } from "./wal.js";
|
|
4
4
|
import { type LaneJob, type LaneResult } from "./lanes/types.js";
|
|
5
5
|
export type { LaneJob, LaneKind, LaneResult } from "./lanes/types.js";
|
|
@@ -50,8 +50,8 @@ export type StepOutcome = {
|
|
|
50
50
|
kind: "blocked";
|
|
51
51
|
};
|
|
52
52
|
/** Execute a shell command with a bounded timeout (the built-in step executor). */
|
|
53
|
-
export declare function runCommand(job: LaneJob): LaneResult
|
|
54
|
-
export declare class WorkflowsDaemon {
|
|
53
|
+
export declare function runCommand(job: LaneJob): Promise<LaneResult>;
|
|
54
|
+
export declare class WorkflowsDaemon<S extends EngineStore = WorkflowsStore> {
|
|
55
55
|
private readonly store;
|
|
56
56
|
private readonly wal;
|
|
57
57
|
readonly worker: string;
|
|
@@ -66,7 +66,7 @@ export declare class WorkflowsDaemon {
|
|
|
66
66
|
private readonly fencingCounter;
|
|
67
67
|
private graphCache;
|
|
68
68
|
private isolatedRunId;
|
|
69
|
-
constructor(store:
|
|
69
|
+
constructor(store: S, wal: SessionWAL, options?: DaemonOptions);
|
|
70
70
|
/** Foreground single-run mode: reap() touches only this run from now on. */
|
|
71
71
|
isolateRun(runId: string): void;
|
|
72
72
|
/**
|
|
@@ -82,25 +82,29 @@ export declare class WorkflowsDaemon {
|
|
|
82
82
|
/** Acquire (or refresh) the lease on a run. Returns null while another
|
|
83
83
|
* worker's lease is live. */
|
|
84
84
|
claim(runId: string): Lease | null;
|
|
85
|
+
private claimLocked;
|
|
85
86
|
/** Extend a lease. Only the fencing-holding worker may. */
|
|
86
87
|
heartbeat(runId: string, fencing: number): boolean;
|
|
88
|
+
private heartbeatLocked;
|
|
87
89
|
/** Release a lease. Only the fencing-holding worker may. */
|
|
88
90
|
release(runId: string, fencing: number): boolean;
|
|
91
|
+
private releaseLocked;
|
|
89
92
|
/** One bounded cycle: expire leases -> repair torn runs -> dispatch pending
|
|
90
93
|
* runs -> advance every claimed run one step. */
|
|
91
94
|
reap(): Promise<ReapReport>;
|
|
92
95
|
/** Validate + persist a new run. Returns the pending run row. */
|
|
93
|
-
startRun(graph: WorkflowGraph, context: unknown):
|
|
96
|
+
startRun(graph: WorkflowGraph, context: unknown): ReturnType<S["createRun"]>;
|
|
94
97
|
/** Execute ONE step of the graph for a claimed run. */
|
|
95
98
|
advanceRun(runId: string): Promise<StepOutcome>;
|
|
96
99
|
private loadGraph;
|
|
97
100
|
/** The condition scope: user context + steps + loop counter (i). */
|
|
98
101
|
private conditionScope;
|
|
99
102
|
private persistContext;
|
|
103
|
+
private discardStep;
|
|
100
104
|
private executeStep;
|
|
101
|
-
/**
|
|
102
|
-
*
|
|
103
|
-
private
|
|
105
|
+
/** Prepare continuation before commitStep so output, cursor and loop counts
|
|
106
|
+
* share one transaction. Cancellation retains all of them or rejects all. */
|
|
107
|
+
private advanceAfterStep;
|
|
104
108
|
private executeWhile;
|
|
105
109
|
private recordStepResult;
|
|
106
110
|
private completeRun;
|
|
@@ -114,6 +118,11 @@ export interface RunToCompletionOptions {
|
|
|
114
118
|
/** Pre-set the daemon's isolation; the foreground driver always isolates
|
|
115
119
|
* to its own run anyway (see isolateRun in runGraphToCompletion). */
|
|
116
120
|
isolatedRunId?: string;
|
|
121
|
+
/** Observe the durable run identity immediately after creation (the CLI -j
|
|
122
|
+
* failure surface needs the runId even when the run later throws). */
|
|
123
|
+
onRunCreated?: (run: RunRow) => void;
|
|
124
|
+
/** Internal continuation of an existing durable run. */
|
|
125
|
+
existingRunId?: string;
|
|
117
126
|
}
|
|
118
127
|
/** Drive a run to a terminal state with bounded cycles. Returns the final row. */
|
|
119
|
-
export declare function runGraphToCompletion(store:
|
|
128
|
+
export declare function runGraphToCompletion(store: EngineStore, wal: SessionWAL, graph: WorkflowGraph, context: unknown, options?: RunToCompletionOptions): Promise<RunRow>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { WorkflowsStore, RunRow, RunNodeRow, MemoRow, CreateRunInput, CreateRunNodeInput, StepCommit, DispatchResult } from "../store.js";
|
|
2
|
+
export type AsyncWorkflowsStore = {
|
|
3
|
+
[K in keyof WorkflowsStore]: WorkflowsStore[K] extends (...args: infer A) => infer R ? (...args: A) => Promise<R> : WorkflowsStore[K];
|
|
4
|
+
};
|
|
5
|
+
/** Safe diagnostic: driver errors may carry connection details and are never rendered. */
|
|
6
|
+
export declare class WorkflowStorageError extends Error {
|
|
7
|
+
constructor();
|
|
8
|
+
}
|
|
9
|
+
export declare class PostgresWorkflowsStore implements AsyncWorkflowsStore {
|
|
10
|
+
private readonly pool;
|
|
11
|
+
private readonly prefix;
|
|
12
|
+
readonly dataDir: string;
|
|
13
|
+
private execution?;
|
|
14
|
+
constructor(options: {
|
|
15
|
+
databaseUrl: string;
|
|
16
|
+
dataDir: string;
|
|
17
|
+
schema?: string;
|
|
18
|
+
});
|
|
19
|
+
private rows;
|
|
20
|
+
close(): Promise<void>;
|
|
21
|
+
/** Session advisory lock is shared by every executor, including separate journals.
|
|
22
|
+
* All owner writes use its exact connection; a lost connection never falls back. */
|
|
23
|
+
acquireExecution(runId: string): Promise<boolean>;
|
|
24
|
+
releaseExecution(): Promise<void>;
|
|
25
|
+
private transaction;
|
|
26
|
+
listTables(): Promise<string[]>;
|
|
27
|
+
checkSchema(): Promise<boolean>;
|
|
28
|
+
/** Creation-only bootstrap. Operators admit this explicitly; reads never migrate. */
|
|
29
|
+
initialize(): Promise<void>;
|
|
30
|
+
createRun(input: CreateRunInput): Promise<RunRow>;
|
|
31
|
+
getRun(id: string): Promise<RunRow | undefined>;
|
|
32
|
+
getRunByIdempotencyKey(key: string): Promise<RunRow | undefined>;
|
|
33
|
+
listRuns(options?: Parameters<WorkflowsStore["listRuns"]>[0]): Promise<RunRow[]>;
|
|
34
|
+
setRunStatus(id: string, status: RunRow["status"], patch?: NonNullable<Parameters<WorkflowsStore["setRunStatus"]>[2]>): Promise<void>;
|
|
35
|
+
compareRunStatus(id: string, expected: RunRow["status"][], status: RunRow["status"], patch?: Parameters<WorkflowsStore["setRunStatus"]>[2]): Promise<boolean>;
|
|
36
|
+
setRunContext(id: string, context: unknown): Promise<void>;
|
|
37
|
+
setRunningContext(id: string, context: unknown): Promise<boolean>;
|
|
38
|
+
blockRunResume(id: string): Promise<void>;
|
|
39
|
+
dispatchIfRunning<T>(id: string, action: () => T): Promise<DispatchResult<T>>;
|
|
40
|
+
finishDispatch(id: string, unconfirmed: boolean): Promise<void>;
|
|
41
|
+
commitStep(input: StepCommit): Promise<boolean>;
|
|
42
|
+
bumpAttempts(id: string): Promise<void>;
|
|
43
|
+
createRunNode(input: CreateRunNodeInput): Promise<RunNodeRow>;
|
|
44
|
+
getRunNode(id: string): Promise<RunNodeRow | undefined>;
|
|
45
|
+
listRunNodes(runId: string): Promise<RunNodeRow[]>;
|
|
46
|
+
getLatestRunNode(runId: string, nodeId: string): Promise<RunNodeRow | undefined>;
|
|
47
|
+
setRunNodeStatus(id: string, status: RunNodeRow["status"], patch?: NonNullable<Parameters<WorkflowsStore["setRunNodeStatus"]>[2]>): Promise<void>;
|
|
48
|
+
bumpAttemptsNode(id: string): Promise<void>;
|
|
49
|
+
memoPut(key: string, graphName: string, nodeId: string, inputHash: string, outputJson: string): Promise<void>;
|
|
50
|
+
memoGet(key: string): Promise<MemoRow | undefined>;
|
|
51
|
+
memoHit(key: string): Promise<void>;
|
|
52
|
+
memoList(): Promise<MemoRow[]>;
|
|
53
|
+
memoClear(): Promise<void>;
|
|
54
|
+
}
|
package/types/graph.d.ts
CHANGED
|
@@ -53,6 +53,13 @@ export interface WorkflowGraph {
|
|
|
53
53
|
name: string;
|
|
54
54
|
version: string;
|
|
55
55
|
nodes: GraphNode[];
|
|
56
|
+
/**
|
|
57
|
+
* Optional files/globs (relative to the data dir, or absolute) whose
|
|
58
|
+
* fingerprint (mtime + sha256) joins every memoized node's input.
|
|
59
|
+
* A memoized command that reads external state MUST declare it here, or
|
|
60
|
+
* it can serve a stale cached value that contradicts a live run.
|
|
61
|
+
*/
|
|
62
|
+
memoWatch?: string[];
|
|
56
63
|
}
|
|
57
64
|
export interface GraphIssue {
|
|
58
65
|
/** Dotted path to the offending member, e.g. "nodes.build" or "nodes.w.body". */
|
package/types/handlers.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type WorkflowsService } from "./service.js";
|
|
2
2
|
export declare function jsonResponse(body: unknown, status?: number): Response;
|
|
3
|
+
export declare function openApiDoc(service: WorkflowsService): Record<string, unknown>;
|
|
3
4
|
export declare function createRequestHandler(service: WorkflowsService): (req: Request) => Response | Promise<Response>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type IdentityEnvironment = Record<string, string | undefined>;
|
|
2
|
+
export interface WorkflowAgent {
|
|
3
|
+
name: string;
|
|
4
|
+
source: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function workflowAgent(env?: IdentityEnvironment, explicit?: string): WorkflowAgent;
|
|
7
|
+
export declare function workflowMcpAgent(env: IdentityEnvironment, harness: string, explicit?: unknown, meta?: unknown): WorkflowAgent;
|
package/types/lanes/types.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export interface LaneResult {
|
|
|
19
19
|
output: string;
|
|
20
20
|
durationMs: number;
|
|
21
21
|
error?: string;
|
|
22
|
+
/** False when retry could overlap a timed-out execution or a policy refusal. */
|
|
23
|
+
retryable?: boolean;
|
|
22
24
|
}
|
|
23
25
|
/**
|
|
24
26
|
* A lane maturity probe: is the substrate actually wired on THIS machine
|
|
@@ -52,8 +54,15 @@ export declare class LaneAdapterShapeError extends Error {
|
|
|
52
54
|
export declare const DEFAULT_LANE_TIMEOUT_MS = 120000;
|
|
53
55
|
/** Is a binary present on PATH (read-only existence check; never runs it)? */
|
|
54
56
|
export declare function binaryOnPath(binary: string): boolean;
|
|
55
|
-
/**
|
|
56
|
-
export declare function
|
|
57
|
+
/** Preserve native subscription configuration while excluding API billing and server secrets. */
|
|
58
|
+
export declare function subscriptionEnvironment(overrides?: Record<string, string>): Record<string, string>;
|
|
59
|
+
/** SDKs that merge process.env need explicit undefined entries for excluded fields. */
|
|
60
|
+
export declare function subscriptionSdkEnvironment(overrides?: Record<string, string>): Record<string, string | undefined>;
|
|
61
|
+
export declare class LaneTimeoutError extends Error {
|
|
62
|
+
constructor(what: string, timeoutMs: number);
|
|
63
|
+
}
|
|
64
|
+
/** A timeout requests cancellation. Callers mark it non-retryable. */
|
|
65
|
+
export declare function withTimeout<T>(promise: Promise<T>, timeoutMs: number, what: string, cancel?: () => void): Promise<T>;
|
|
57
66
|
/** Spawn a CLI binary with a bounded timeout; maps ENOENT to a missing-substrate error. */
|
|
58
67
|
export declare function spawnCli(cmd: string[], opts: {
|
|
59
68
|
cwd?: string;
|
|
@@ -61,4 +70,4 @@ export declare function spawnCli(cmd: string[], opts: {
|
|
|
61
70
|
timeoutMs?: number;
|
|
62
71
|
binaryName: string;
|
|
63
72
|
packageHint: string;
|
|
64
|
-
}): LaneResult
|
|
73
|
+
}): Promise<LaneResult>;
|
package/types/paths.d.ts
CHANGED
|
@@ -15,6 +15,15 @@
|
|
|
15
15
|
* data-kind override `HASNA_DATA_HOME`. An existing local store never becomes
|
|
16
16
|
* invisible on upgrade.
|
|
17
17
|
*/
|
|
18
|
+
export type PathKind = "config" | "data" | "state" | "cache";
|
|
19
|
+
export interface PathsResolverOptions {
|
|
20
|
+
app: string;
|
|
21
|
+
internal?: boolean;
|
|
22
|
+
platform?: string;
|
|
23
|
+
home?: string;
|
|
24
|
+
env?: Record<string, string | undefined>;
|
|
25
|
+
}
|
|
26
|
+
export declare function dataDir(options: PathsResolverOptions): string;
|
|
18
27
|
/** The workflows app slug used by the @hasna/paths resolver. */
|
|
19
28
|
export declare const APP: "workflows";
|
|
20
29
|
/** The store database file name, the marker that a store lives at a data home. */
|
|
@@ -33,7 +42,7 @@ export declare function getLegacyDataDir(env?: NodeJS.ProcessEnv): string;
|
|
|
33
42
|
* pre-existing `$HOME`-first resolution so the resolver follows the same home
|
|
34
43
|
* the legacy path does.
|
|
35
44
|
*/
|
|
36
|
-
export declare function getResolverDataDir(env?: NodeJS.ProcessEnv): string;
|
|
45
|
+
export declare function getResolverDataDir(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): string;
|
|
37
46
|
/**
|
|
38
47
|
* Whether the resolver (XDG) data home should be adopted as the effective
|
|
39
48
|
* workflows data home. The resolver home is adopted only when the operator
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
export interface ApiError {
|
|
2
|
+
"error": string;
|
|
3
|
+
"message"?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface HealthReport {
|
|
6
|
+
"ok": boolean;
|
|
7
|
+
"status": "ok";
|
|
8
|
+
"backend": "postgresql" | "sqlite";
|
|
9
|
+
"service": string;
|
|
10
|
+
"version": string;
|
|
11
|
+
"pid": number;
|
|
12
|
+
"uptimeMs": number;
|
|
13
|
+
}
|
|
14
|
+
export interface ReadinessReport {
|
|
15
|
+
"ok": boolean;
|
|
16
|
+
"service": string;
|
|
17
|
+
"version": string;
|
|
18
|
+
"checks": Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
export interface GraphValidation {
|
|
21
|
+
"ok": boolean;
|
|
22
|
+
"issues": Array<{
|
|
23
|
+
"path": string;
|
|
24
|
+
"message": string;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
export interface StartNode {
|
|
28
|
+
"id": string;
|
|
29
|
+
"type": "start";
|
|
30
|
+
"next"?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface StepNode {
|
|
33
|
+
"id": string;
|
|
34
|
+
"type": "step";
|
|
35
|
+
"next"?: string;
|
|
36
|
+
"lane"?: "claude" | "codex" | "cursor" | "grok";
|
|
37
|
+
"prompt"?: string;
|
|
38
|
+
"command"?: string;
|
|
39
|
+
"maxRetries"?: number;
|
|
40
|
+
"memo"?: boolean;
|
|
41
|
+
"timeoutMs"?: number;
|
|
42
|
+
}
|
|
43
|
+
export interface DecisionNode {
|
|
44
|
+
"id": string;
|
|
45
|
+
"type": "decision";
|
|
46
|
+
"condition": string;
|
|
47
|
+
"then"?: string;
|
|
48
|
+
"else"?: string;
|
|
49
|
+
}
|
|
50
|
+
export interface WhileNode {
|
|
51
|
+
"id": string;
|
|
52
|
+
"type": "while";
|
|
53
|
+
"condition": string;
|
|
54
|
+
"body": Array<string>;
|
|
55
|
+
"maxIterations": number;
|
|
56
|
+
"next"?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface EndNode {
|
|
59
|
+
"id": string;
|
|
60
|
+
"type": "end";
|
|
61
|
+
}
|
|
62
|
+
export type GraphNode = StartNode | StepNode | DecisionNode | WhileNode | EndNode;
|
|
63
|
+
export interface WorkflowGraph {
|
|
64
|
+
"name": string;
|
|
65
|
+
"version": string;
|
|
66
|
+
"nodes": Array<GraphNode>;
|
|
67
|
+
"memoWatch"?: Array<string>;
|
|
68
|
+
}
|
|
69
|
+
export interface RunSummary {
|
|
70
|
+
"runId": string;
|
|
71
|
+
"status": "pending" | "running" | "completed" | "failed" | "interrupted" | "cancelled";
|
|
72
|
+
"error": string | null;
|
|
73
|
+
"result": unknown;
|
|
74
|
+
"reused": boolean;
|
|
75
|
+
}
|
|
76
|
+
export interface RunRow {
|
|
77
|
+
"id": string;
|
|
78
|
+
"graphName": string;
|
|
79
|
+
"graphVersion": string;
|
|
80
|
+
"status": "pending" | "running" | "completed" | "failed" | "interrupted" | "cancelled";
|
|
81
|
+
"attempts": number;
|
|
82
|
+
"contextJson": string;
|
|
83
|
+
"resultJson": string | null;
|
|
84
|
+
"error": string | null;
|
|
85
|
+
"startedAt": string | null;
|
|
86
|
+
"finishedAt": string | null;
|
|
87
|
+
"createdAt": string;
|
|
88
|
+
"updatedAt": string;
|
|
89
|
+
}
|
|
90
|
+
export interface RunNodeRow {
|
|
91
|
+
"id": string;
|
|
92
|
+
"runId": string;
|
|
93
|
+
"nodeId": string;
|
|
94
|
+
"status": "pending" | "running" | "completed" | "failed" | "skipped";
|
|
95
|
+
"attempts": number;
|
|
96
|
+
"lane": string | null;
|
|
97
|
+
"exitCode": number | null;
|
|
98
|
+
"outputJson": string | null;
|
|
99
|
+
"error": string | null;
|
|
100
|
+
"startedAt": string | null;
|
|
101
|
+
"finishedAt": string | null;
|
|
102
|
+
}
|
|
103
|
+
export declare abstract class WorkflowsApi {
|
|
104
|
+
protected abstract apiRequest<T>(method: string, path: string, opts: {
|
|
105
|
+
body?: unknown;
|
|
106
|
+
query?: Record<string, unknown>;
|
|
107
|
+
}): Promise<T>;
|
|
108
|
+
/** Bounded-trigger executor status */
|
|
109
|
+
inspectDaemon(): Promise<Record<string, unknown>>;
|
|
110
|
+
/** Service health */
|
|
111
|
+
getHealth(): Promise<HealthReport>;
|
|
112
|
+
/** Inspect lane substrates; this does not prove sign-in or model capacity */
|
|
113
|
+
listLanes(): Promise<Array<Record<string, unknown>>>;
|
|
114
|
+
/** Inspect one lane substrate */
|
|
115
|
+
probeLane(lane: "claude" | "codex" | "cursor" | "grok"): Promise<Record<string, unknown>>;
|
|
116
|
+
/** This executor, not a fleet census */
|
|
117
|
+
listServerMachines(): Promise<Array<Record<string, unknown>>>;
|
|
118
|
+
/** This executor's health and claims */
|
|
119
|
+
inspectServerMachine(): Promise<Record<string, unknown>>;
|
|
120
|
+
/** Recent memo results */
|
|
121
|
+
listMemoRecords(): Promise<Array<Record<string, unknown>>>;
|
|
122
|
+
/** Authentication and actual schema readiness */
|
|
123
|
+
getReadiness(): Promise<ReadinessReport>;
|
|
124
|
+
/** List recent runs */
|
|
125
|
+
listRunRecords(query?: {
|
|
126
|
+
"status"?: "pending" | "running" | "completed" | "failed" | "interrupted" | "cancelled";
|
|
127
|
+
"limit"?: number;
|
|
128
|
+
}): Promise<Array<RunRow>>;
|
|
129
|
+
/** Read a durable run */
|
|
130
|
+
getRunRecord(id: string): Promise<RunRow>;
|
|
131
|
+
/** Cancel a pending, running or interrupted run and fence late results */
|
|
132
|
+
cancelWorkflow(id: string): Promise<RunRow>;
|
|
133
|
+
/** Preserved execution journal events */
|
|
134
|
+
getRunEvents(id: string): Promise<Array<Record<string, unknown>>>;
|
|
135
|
+
/** Ordered node execution history */
|
|
136
|
+
getRunNodes(id: string): Promise<Array<RunNodeRow>>;
|
|
137
|
+
/** Continue a failed, cancelled or interrupted run using its pinned graph; active or unconfirmed execution refuses resume */
|
|
138
|
+
resumeWorkflow(id: string): Promise<RunSummary>;
|
|
139
|
+
/** Recent journal event metadata */
|
|
140
|
+
listSessionEvents(): Promise<Array<Record<string, unknown>>>;
|
|
141
|
+
/** Read journal and claim state without repair */
|
|
142
|
+
inspectSession(): Promise<Record<string, unknown>>;
|
|
143
|
+
/** Execute a bounded workflow; identical keyed retries reuse the original run */
|
|
144
|
+
triggerWorkflow(body: {
|
|
145
|
+
"graph": WorkflowGraph;
|
|
146
|
+
"context"?: Record<string, unknown>;
|
|
147
|
+
"idempotencyKey"?: string;
|
|
148
|
+
"maxCycles"?: number;
|
|
149
|
+
}): Promise<RunSummary>;
|
|
150
|
+
/** Validate a workflow graph */
|
|
151
|
+
validateWorkflow(body: {
|
|
152
|
+
"graph": WorkflowGraph;
|
|
153
|
+
}): Promise<GraphValidation>;
|
|
154
|
+
/** Package version */
|
|
155
|
+
getVersion(): Promise<{
|
|
156
|
+
"service": string;
|
|
157
|
+
"version": string;
|
|
158
|
+
}>;
|
|
159
|
+
}
|
package/types/sdk.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** The SDK is a hosted HTTP client; server implementation is exported at the package root. */
|
|
2
|
+
export { WorkflowsClient, createWorkflowsClient } from "./client.js";
|
|
3
|
+
export type { WorkflowsClientOptions, RunSummary } from "./client.js";
|
|
4
|
+
export type { WorkflowGraph, GraphNode, GraphValidation } from "./graph.js";
|
|
5
|
+
export type { RunRow, RunNodeRow, RunStatus } from "./store.js";
|
|
6
|
+
export type { HealthReport, ReadinessReport } from "./types.js";
|