@osolmaz/pi-workflows 0.16.2 → 0.16.3
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 +41 -41
- package/dist/builtins/monitor.workflow.d.ts +1 -1
- package/dist/builtins/monitor.workflow.js +8 -8
- package/dist/builtins/pi-agent-group.js +3 -3
- package/dist/builtins/pi-agent-group.js.map +1 -1
- package/dist/channels/adapter-entry.js +14 -14
- package/dist/channels/adapter-entry.js.map +1 -1
- package/dist/client/client.d.ts +6 -6
- package/dist/client/client.js +27 -27
- package/dist/client/client.js.map +1 -1
- package/dist/client/protocol.d.ts +4 -1
- package/dist/client/protocol.js +17 -11
- package/dist/client/protocol.js.map +1 -1
- package/dist/client/resolver.d.ts +4 -4
- package/dist/client/view.d.ts +1 -1
- package/dist/extension/index.d.ts +1 -1
- package/dist/extension/index.js +32 -32
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/recorder.d.ts +1 -1
- package/dist/extension/recorder.js +1 -1
- package/dist/extension/recorder.js.map +1 -1
- package/dist/extension/remote-recorder-store.d.ts +1 -1
- package/dist/extension/remote-recorder-store.js +2 -2
- package/dist/extension/remote-recorder-store.js.map +1 -1
- package/dist/extension/{controller-command.d.ts → resource-manager-command.d.ts} +6 -6
- package/dist/extension/{controller-command.js → resource-manager-command.js} +7 -7
- package/dist/extension/resource-manager-command.js.map +1 -0
- package/dist/extension/session-delivery.d.ts +1 -1
- package/dist/extension/session-delivery.js +2 -2
- package/dist/extension/session-delivery.js.map +1 -1
- package/dist/extension/session-view.d.ts +1 -1
- package/dist/extension/session-view.js +1 -1
- package/dist/extension/session-view.js.map +1 -1
- package/dist/extension/workflow-message-coordinator.d.ts +1 -1
- package/dist/extension/workflow-message-coordinator.js +6 -6
- package/dist/extension/workflow-message-coordinator.js.map +1 -1
- package/dist/resource-managers/conditions.d.ts +6 -0
- package/dist/{controllers → resource-managers}/conditions.js +3 -3
- package/dist/resource-managers/conditions.js.map +1 -0
- package/dist/resource-managers/definition.d.ts +6 -0
- package/dist/resource-managers/definition.js +45 -0
- package/dist/resource-managers/definition.js.map +1 -0
- package/dist/resource-managers/effects.d.ts +15 -0
- package/dist/{controllers → resource-managers}/effects.js +2 -2
- package/dist/resource-managers/effects.js.map +1 -0
- package/dist/resource-managers/errors.d.ts +12 -0
- package/dist/resource-managers/errors.js +25 -0
- package/dist/resource-managers/errors.js.map +1 -0
- package/dist/resource-managers/index.d.ts +12 -0
- package/dist/resource-managers/index.js +12 -0
- package/dist/resource-managers/index.js.map +1 -0
- package/dist/resource-managers/json.js.map +1 -0
- package/dist/resource-managers/loader.d.ts +23 -0
- package/dist/resource-managers/loader.js +75 -0
- package/dist/resource-managers/loader.js.map +1 -0
- package/dist/resource-managers/results.d.ts +5 -0
- package/dist/resource-managers/results.js.map +1 -0
- package/dist/resource-managers/runtime.d.ts +59 -0
- package/dist/{controllers/manager.js → resource-managers/runtime.js} +57 -57
- package/dist/resource-managers/runtime.js.map +1 -0
- package/dist/{controllers → resource-managers}/sqlite.d.ts +44 -44
- package/dist/{controllers → resource-managers}/sqlite.js +139 -130
- package/dist/resource-managers/sqlite.js.map +1 -0
- package/dist/{controllers → resource-managers}/store.d.ts +33 -33
- package/dist/{controllers → resource-managers}/store.js.map +1 -1
- package/dist/{controllers → resource-managers}/types.d.ts +41 -41
- package/dist/{controllers → resource-managers}/types.js.map +1 -1
- package/dist/resource-managers/workflows.d.ts +34 -0
- package/dist/{controllers → resource-managers}/workflows.js +15 -15
- package/dist/resource-managers/workflows.js.map +1 -0
- package/dist/server/channel-effects.js.map +1 -0
- package/dist/{host → server}/channel-supervisor.d.ts +6 -6
- package/dist/{host → server}/channel-supervisor.js +3 -3
- package/dist/server/channel-supervisor.js.map +1 -0
- package/dist/{host/child-worker-supervisor.d.ts → server/child-runner-supervisor.d.ts} +15 -13
- package/dist/{host/child-worker-supervisor.js → server/child-runner-supervisor.js} +6 -5
- package/dist/server/child-runner-supervisor.js.map +1 -0
- package/dist/{host → server}/processes.d.ts +3 -3
- package/dist/{host → server}/processes.js +3 -3
- package/dist/server/processes.js.map +1 -0
- package/dist/{host → server}/resolver-entry.d.ts +6 -6
- package/dist/{host → server}/resolver-entry.js +14 -14
- package/dist/server/resolver-entry.js.map +1 -0
- package/dist/server/resource-runner-entry.d.ts +2 -0
- package/dist/{host/controller-worker-entry.js → server/resource-runner-entry.js} +33 -33
- package/dist/server/resource-runner-entry.js.map +1 -0
- package/dist/server/resource-runner-protocol.d.ts +36 -0
- package/dist/server/resource-runner-protocol.js +49 -0
- package/dist/server/resource-runner-protocol.js.map +1 -0
- package/dist/server/resource-runner-supervisor.d.ts +21 -0
- package/dist/{host/worker-supervisor.js → server/resource-runner-supervisor.js} +17 -17
- package/dist/server/resource-runner-supervisor.js.map +1 -0
- package/dist/{host → server}/rpc-bridge.d.ts +3 -3
- package/dist/{host → server}/rpc-bridge.js +3 -3
- package/dist/server/rpc-bridge.js.map +1 -0
- package/dist/{host → server}/rpc-executor.d.ts +1 -1
- package/dist/{host → server}/rpc-executor.js +3 -3
- package/dist/server/rpc-executor.js.map +1 -0
- package/dist/{host/host-entry.js → server/server-entry.js} +6 -6
- package/dist/server/server-entry.js.map +1 -0
- package/dist/{host/runner.d.ts → server/server.d.ts} +39 -38
- package/dist/{host/runner.js → server/server.js} +408 -374
- package/dist/server/server.js.map +1 -0
- package/dist/{host → server}/state.d.ts +25 -25
- package/dist/{host → server}/state.js +49 -49
- package/dist/server/state.js.map +1 -0
- package/dist/{host → server}/view.d.ts +7 -7
- package/dist/{host → server}/view.js +13 -13
- package/dist/server/view.js.map +1 -0
- package/dist/server/workflow-runner-content.d.ts +6 -0
- package/dist/server/workflow-runner-content.js +96 -0
- package/dist/server/workflow-runner-content.js.map +1 -0
- package/dist/{host/worker-entry.d.ts → server/workflow-runner-entry.d.ts} +3 -3
- package/dist/{host/worker-entry.js → server/workflow-runner-entry.js} +68 -35
- package/dist/server/workflow-runner-entry.js.map +1 -0
- package/dist/server/workflow-runner-protocol.d.ts +69 -0
- package/dist/server/workflow-runner-protocol.js +176 -0
- package/dist/server/workflow-runner-protocol.js.map +1 -0
- package/dist/{host/worker-store.d.ts → server/workflow-runner-store.d.ts} +11 -11
- package/dist/{host/worker-store.js → server/workflow-runner-store.js} +8 -8
- package/dist/server/workflow-runner-store.js.map +1 -0
- package/dist/server/workflow-runner-supervisor.d.ts +22 -0
- package/dist/server/workflow-runner-supervisor.js +56 -0
- package/dist/server/workflow-runner-supervisor.js.map +1 -0
- package/dist/state/prune.d.ts +1 -1
- package/dist/state/prune.js +17 -10
- package/dist/state/prune.js.map +1 -1
- package/dist/state/schema.js +2 -2
- package/dist/state/workflow-messages.d.ts +1 -1
- package/dist/state/workflow-messages.js +1 -1
- package/dist/state/workflow-messages.js.map +1 -1
- package/dist/viewer/backup.js +1 -1
- package/dist/viewer/backup.js.map +1 -1
- package/dist/viewer/cli.d.ts +2 -2
- package/dist/viewer/cli.js +46 -32
- package/dist/viewer/cli.js.map +1 -1
- package/dist/viewer/tui.d.ts +1 -1
- package/dist/viewer/tui.js +1 -1
- package/dist/viewer/tui.js.map +1 -1
- package/dist/workflows/command-batch.js +2 -2
- package/dist/workflows/engine.js +14 -15
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/store.d.ts +12 -11
- package/dist/workflows/store.js +24 -18
- package/dist/workflows/store.js.map +1 -1
- package/dist/workflows/types.d.ts +2 -2
- package/docs/2026-08-20-durable-workflow-launch-plan.md +12 -12
- package/docs/2026-08-25-workflow-follow-ups.md +7 -7
- package/docs/2026-08-25-workflow-settings.md +3 -3
- package/docs/2026-08-30-out-of-process-workflow-host-plan.md +3 -3
- package/docs/2026-09-01-restore-session-delivery-controls-plan.md +5 -5
- package/docs/2026-09-01-unified-workflow-client-plan.md +6 -6
- package/docs/2026-09-02-installed-live-e2e-plan.md +3 -3
- package/docs/2026-09-02-unify-workflow-messages-plan.md +8 -8
- package/docs/2026-09-04-workflow-run-state-plan.md +6 -6
- package/docs/DEFERRED_TURNS.md +7 -7
- package/docs/DESIGN_PHILOSOPHY.md +1 -1
- package/docs/HUMAN_DECISIONS.md +11 -11
- package/docs/HUMAN_DECISION_PRESENTATIONS.md +4 -4
- package/docs/MONITOR.md +1 -1
- package/docs/RESOURCE_MANAGERS.md +221 -0
- package/docs/SQLITE_STATE.md +35 -33
- package/docs/WORKFLOW_COMPOSITION.md +1 -1
- package/docs/{WORKFLOW_HOST.md → WORKFLOW_SERVER.md} +125 -119
- package/docs/WORKFLOW_STEP_MESSAGES.md +18 -18
- package/docs/WORKFLOW_UPDATES.md +16 -16
- package/docs/development.md +15 -14
- package/docs/live-replay-protocol.md +20 -20
- package/docs/plans/2026-08-04-controller-runtime-plan.md +25 -25
- package/docs/plans/2026-08-05-always-on-workflows-plan.md +8 -8
- package/docs/plans/2026-08-10-agent-managed-monitor-workflows-plan.md +2 -2
- package/docs/plans/2026-08-13-session-addressed-workflow-notifications-plan.md +1 -1
- package/docs/plans/2026-08-16-workflow-updates-plan.md +5 -5
- package/docs/plans/2026-08-19-human-decision-gates-plan.md +1 -1
- package/docs/plans/2026-08-20-bounded-command-batches-plan.md +1 -1
- package/docs/plans/2026-08-21-deferred-turn-intents-plan.md +3 -3
- package/docs/plans/2026-08-21-sanity-check-plan.md +2 -2
- package/docs/plans/2026-08-23-assistant-agent-completion-plan.md +5 -5
- package/docs/plans/2026-08-23-sqlite-state-plan.md +25 -25
- package/docs/plans/2026-08-25-live-workflow-settings-plan.md +4 -4
- package/docs/plans/2026-08-27-workflow-terminal-restart-plan.md +3 -3
- package/docs/plans/2026-09-04-workflow-runner-resume-state-plan.md +318 -0
- package/docs/plans/piw-viewer-experience-implementation-plan.md +1 -1
- package/docs/tui-viewer.md +9 -9
- package/docs/workflows.md +72 -66
- package/examples/{controllers/pull-request.controller.ts → resource-managers/pull-request.resource-manager.ts} +12 -12
- package/herdr-plugin.toml +1 -1
- package/package.json +5 -5
- package/protocol/client.v1.schema.json +7 -7
- package/protocol/fixtures/client-v1.json +1 -1
- package/src/builtins/monitor.workflow.ts +9 -9
- package/src/builtins/pi-agent-group.ts +3 -3
- package/src/channels/adapter-entry.ts +14 -14
- package/src/client/client.ts +33 -32
- package/src/client/protocol.ts +16 -11
- package/src/client/resolver.ts +4 -4
- package/src/client/view.ts +1 -1
- package/src/extension/index.ts +44 -34
- package/src/extension/recorder.ts +1 -1
- package/src/extension/remote-recorder-store.ts +2 -2
- package/src/extension/resource-manager-command.ts +45 -0
- package/src/extension/session-delivery.ts +2 -2
- package/src/extension/session-view.ts +1 -1
- package/src/extension/workflow-message-coordinator.ts +6 -6
- package/src/{controllers → resource-managers}/conditions.ts +23 -23
- package/src/resource-managers/definition.ts +71 -0
- package/src/{controllers → resource-managers}/effects.ts +9 -9
- package/src/resource-managers/errors.ts +27 -0
- package/src/resource-managers/index.ts +88 -0
- package/src/resource-managers/loader.ts +111 -0
- package/src/{controllers → resource-managers}/results.ts +4 -4
- package/src/{controllers/manager.ts → resource-managers/runtime.ts} +95 -92
- package/src/{controllers → resource-managers}/sqlite.ts +198 -186
- package/src/{controllers → resource-managers}/store.ts +46 -38
- package/src/{controllers → resource-managers}/types.ts +50 -41
- package/src/{controllers → resource-managers}/workflows.ts +43 -41
- package/src/{host → server}/channel-supervisor.ts +8 -8
- package/src/{host/child-worker-supervisor.ts → server/child-runner-supervisor.ts} +22 -18
- package/src/{host → server}/processes.ts +3 -3
- package/src/{host → server}/resolver-entry.ts +28 -25
- package/src/{host/controller-worker-entry.ts → server/resource-runner-entry.ts} +67 -65
- package/src/server/resource-runner-protocol.ts +103 -0
- package/src/server/resource-runner-supervisor.ts +76 -0
- package/src/{host → server}/rpc-bridge.ts +3 -3
- package/src/{host → server}/rpc-executor.ts +4 -4
- package/src/{host/host-entry.ts → server/server-entry.ts} +5 -5
- package/src/{host/runner.ts → server/server.ts} +526 -461
- package/src/{host → server}/state.ts +78 -67
- package/src/{host → server}/view.ts +15 -15
- package/src/server/workflow-runner-content.ts +119 -0
- package/src/{host/worker-entry.ts → server/workflow-runner-entry.ts} +98 -57
- package/src/server/workflow-runner-protocol.ts +241 -0
- package/src/{host/worker-store.ts → server/workflow-runner-store.ts} +18 -20
- package/src/server/workflow-runner-supervisor.ts +79 -0
- package/src/state/prune.ts +27 -9
- package/src/state/schema.ts +2 -2
- package/src/state/workflow-messages.ts +1 -1
- package/src/viewer/backup.ts +1 -1
- package/src/viewer/cli.ts +50 -36
- package/src/viewer/tui.ts +1 -1
- package/src/workflows/command-batch.ts +2 -2
- package/src/workflows/engine.ts +14 -15
- package/src/workflows/store.ts +31 -28
- package/src/workflows/types.ts +2 -2
- package/dist/controllers/conditions.d.ts +0 -6
- package/dist/controllers/conditions.js.map +0 -1
- package/dist/controllers/definition.d.ts +0 -6
- package/dist/controllers/definition.js +0 -45
- package/dist/controllers/definition.js.map +0 -1
- package/dist/controllers/effects.d.ts +0 -15
- package/dist/controllers/effects.js.map +0 -1
- package/dist/controllers/errors.d.ts +0 -12
- package/dist/controllers/errors.js +0 -25
- package/dist/controllers/errors.js.map +0 -1
- package/dist/controllers/index.d.ts +0 -12
- package/dist/controllers/index.js +0 -12
- package/dist/controllers/index.js.map +0 -1
- package/dist/controllers/json.js.map +0 -1
- package/dist/controllers/loader.d.ts +0 -23
- package/dist/controllers/loader.js +0 -74
- package/dist/controllers/loader.js.map +0 -1
- package/dist/controllers/manager.d.ts +0 -59
- package/dist/controllers/manager.js.map +0 -1
- package/dist/controllers/results.d.ts +0 -5
- package/dist/controllers/results.js.map +0 -1
- package/dist/controllers/sqlite.js.map +0 -1
- package/dist/controllers/workflows.d.ts +0 -34
- package/dist/controllers/workflows.js.map +0 -1
- package/dist/extension/controller-command.js.map +0 -1
- package/dist/host/channel-effects.js.map +0 -1
- package/dist/host/channel-supervisor.js.map +0 -1
- package/dist/host/child-worker-supervisor.js.map +0 -1
- package/dist/host/controller-worker-entry.d.ts +0 -2
- package/dist/host/controller-worker-entry.js.map +0 -1
- package/dist/host/controller-worker-protocol.d.ts +0 -36
- package/dist/host/controller-worker-protocol.js +0 -49
- package/dist/host/controller-worker-protocol.js.map +0 -1
- package/dist/host/controller-worker-supervisor.d.ts +0 -21
- package/dist/host/controller-worker-supervisor.js +0 -54
- package/dist/host/controller-worker-supervisor.js.map +0 -1
- package/dist/host/host-entry.js.map +0 -1
- package/dist/host/processes.js.map +0 -1
- package/dist/host/resolver-entry.js.map +0 -1
- package/dist/host/rpc-bridge.js.map +0 -1
- package/dist/host/rpc-executor.js.map +0 -1
- package/dist/host/runner.js.map +0 -1
- package/dist/host/state.js.map +0 -1
- package/dist/host/view.js.map +0 -1
- package/dist/host/worker-entry.js.map +0 -1
- package/dist/host/worker-protocol.d.ts +0 -46
- package/dist/host/worker-protocol.js +0 -122
- package/dist/host/worker-protocol.js.map +0 -1
- package/dist/host/worker-store.js.map +0 -1
- package/dist/host/worker-supervisor.d.ts +0 -22
- package/dist/host/worker-supervisor.js.map +0 -1
- package/docs/CONTROLLERS.md +0 -217
- package/src/controllers/definition.ts +0 -65
- package/src/controllers/errors.ts +0 -27
- package/src/controllers/index.ts +0 -88
- package/src/controllers/loader.ts +0 -104
- package/src/extension/controller-command.ts +0 -45
- package/src/host/controller-worker-protocol.ts +0 -104
- package/src/host/controller-worker-supervisor.ts +0 -79
- package/src/host/worker-protocol.ts +0 -176
- package/src/host/worker-supervisor.ts +0 -74
- /package/dist/{controllers → resource-managers}/json.d.ts +0 -0
- /package/dist/{controllers → resource-managers}/json.js +0 -0
- /package/dist/{controllers → resource-managers}/results.js +0 -0
- /package/dist/{controllers → resource-managers}/store.js +0 -0
- /package/dist/{controllers → resource-managers}/types.js +0 -0
- /package/dist/{host → server}/channel-effects.d.ts +0 -0
- /package/dist/{host → server}/channel-effects.js +0 -0
- /package/dist/{host/host-entry.d.ts → server/server-entry.d.ts} +0 -0
- /package/src/{controllers → resource-managers}/json.ts +0 -0
- /package/src/{host → server}/channel-effects.ts +0 -0
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import os from "node:os";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
|
-
import { createJiti } from "jiti";
|
|
6
|
-
import { isControllerDefinition } from "./definition.js";
|
|
7
|
-
import type { AnyControllerDefinition } from "./types.js";
|
|
8
|
-
|
|
9
|
-
const CONTROLLER_FILE_SUFFIXES = [
|
|
10
|
-
".controller.ts",
|
|
11
|
-
".controller.js",
|
|
12
|
-
".controller.mts",
|
|
13
|
-
".controller.mjs",
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
export type DiscoveredController = {
|
|
17
|
-
name: string;
|
|
18
|
-
path: string;
|
|
19
|
-
source: "project" | "global";
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export function controllerSearchDirs(options: {
|
|
23
|
-
cwd: string;
|
|
24
|
-
homeDir?: string;
|
|
25
|
-
}): { dir: string; source: DiscoveredController["source"] }[] {
|
|
26
|
-
const homeDir = options.homeDir ?? os.homedir();
|
|
27
|
-
return [
|
|
28
|
-
{ dir: path.join(options.cwd, ".pi", "controllers"), source: "project" },
|
|
29
|
-
{ dir: path.join(homeDir, ".pi", "agent", "controllers"), source: "global" },
|
|
30
|
-
];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function controllerFileStem(filePath: string): string {
|
|
34
|
-
const base = path.basename(filePath);
|
|
35
|
-
const suffix = CONTROLLER_FILE_SUFFIXES.find((candidate) => base.endsWith(candidate));
|
|
36
|
-
return suffix === undefined ? base : base.slice(0, -suffix.length);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const CONTROLLER_ENTRY = path.join(path.dirname(fileURLToPath(import.meta.url)), "index");
|
|
40
|
-
const WORKFLOW_ENTRY = path.join(
|
|
41
|
-
path.dirname(fileURLToPath(import.meta.url)),
|
|
42
|
-
"../workflows/index",
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
export async function loadControllerFile(filePath: string): Promise<AnyControllerDefinition> {
|
|
46
|
-
const absolutePath = path.resolve(filePath);
|
|
47
|
-
const jiti = createJiti(pathToFileURL(absolutePath).href, {
|
|
48
|
-
interopDefault: true,
|
|
49
|
-
moduleCache: false,
|
|
50
|
-
alias: {
|
|
51
|
-
"@osolmaz/pi-workflows/controllers": CONTROLLER_ENTRY,
|
|
52
|
-
"@osolmaz/pi-workflows": WORKFLOW_ENTRY,
|
|
53
|
-
},
|
|
54
|
-
});
|
|
55
|
-
const loaded = (await jiti.import(absolutePath, { default: true })) as unknown;
|
|
56
|
-
if (!isControllerDefinition(loaded)) {
|
|
57
|
-
throw new Error(`Controller module must default-export defineController(...): ${absolutePath}`);
|
|
58
|
-
}
|
|
59
|
-
return loaded;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export async function discoverControllers(options: {
|
|
63
|
-
cwd: string;
|
|
64
|
-
homeDir?: string;
|
|
65
|
-
}): Promise<DiscoveredController[]> {
|
|
66
|
-
const discovered: DiscoveredController[] = [];
|
|
67
|
-
const seen = new Set<string>();
|
|
68
|
-
for (const { dir, source } of controllerSearchDirs(options)) {
|
|
69
|
-
for (const filePath of await listControllerFiles(dir)) {
|
|
70
|
-
const name = controllerFileStem(filePath);
|
|
71
|
-
if (seen.has(name)) {
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
seen.add(name);
|
|
75
|
-
discovered.push({ name, path: filePath, source });
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return discovered;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export async function loadDiscoveredControllers(options: {
|
|
82
|
-
cwd: string;
|
|
83
|
-
homeDir?: string;
|
|
84
|
-
}): Promise<AnyControllerDefinition[]> {
|
|
85
|
-
return await Promise.all(
|
|
86
|
-
(await discoverControllers(options)).map(async (entry) => await loadControllerFile(entry.path)),
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async function listControllerFiles(dir: string): Promise<string[]> {
|
|
91
|
-
let entries: import("node:fs").Dirent[];
|
|
92
|
-
try {
|
|
93
|
-
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
94
|
-
} catch {
|
|
95
|
-
return [];
|
|
96
|
-
}
|
|
97
|
-
return entries
|
|
98
|
-
.filter(
|
|
99
|
-
(entry) =>
|
|
100
|
-
entry.isFile() && CONTROLLER_FILE_SUFFIXES.some((suffix) => entry.name.endsWith(suffix)),
|
|
101
|
-
)
|
|
102
|
-
.map((entry) => path.join(dir, entry.name))
|
|
103
|
-
.sort();
|
|
104
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { JsonValue } from "../state/json.js";
|
|
2
|
-
|
|
3
|
-
export type ParsedControllerArgs =
|
|
4
|
-
| { kind: "list" }
|
|
5
|
-
| { kind: "get"; controller: string; key: string }
|
|
6
|
-
| { kind: "apply"; controller: string; key: string; spec: JsonValue }
|
|
7
|
-
| { kind: "reconcile"; controller: string; key: string }
|
|
8
|
-
| { kind: "delete"; controller: string; key: string };
|
|
9
|
-
|
|
10
|
-
const CONTROLLER_USAGE =
|
|
11
|
-
"Usage: /controller [list|get <controller> <key>|apply <controller> <key> <json>|reconcile <controller> <key>|delete <controller> <key>]";
|
|
12
|
-
|
|
13
|
-
export function parseControllerArgs(args: string): ParsedControllerArgs {
|
|
14
|
-
const trimmed = args.trim();
|
|
15
|
-
if (trimmed.length === 0 || trimmed === "list") return { kind: "list" };
|
|
16
|
-
|
|
17
|
-
const apply = trimmed.match(/^apply\s+(\S+)\s+(\S+)\s+([\s\S]+)$/u);
|
|
18
|
-
if (apply !== null) {
|
|
19
|
-
let spec: JsonValue;
|
|
20
|
-
try {
|
|
21
|
-
spec = JSON.parse(apply[3] as string) as JsonValue;
|
|
22
|
-
} catch (error) {
|
|
23
|
-
throw new Error(
|
|
24
|
-
`Invalid controller spec JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
return {
|
|
28
|
-
kind: "apply",
|
|
29
|
-
controller: apply[1] as string,
|
|
30
|
-
key: apply[2] as string,
|
|
31
|
-
spec,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const operation = trimmed.match(/^(get|reconcile|delete)\s+(\S+)\s+(\S+)$/u);
|
|
36
|
-
if (operation !== null) {
|
|
37
|
-
return {
|
|
38
|
-
kind: operation[1] as "get" | "reconcile" | "delete",
|
|
39
|
-
controller: operation[2] as string,
|
|
40
|
-
key: operation[3] as string,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
throw new Error(CONTROLLER_USAGE);
|
|
45
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import type { ControllerResource } from "../controllers/types.js";
|
|
2
|
-
import { canonicalJson, parseJson, type JsonValue } from "../state/json.js";
|
|
3
|
-
|
|
4
|
-
export const CONTROLLER_WORKER_LAUNCH_SCHEMA = "pi-workflows.controller-worker-launch.v1" as const;
|
|
5
|
-
export const CONTROLLER_WORKER_MESSAGE_SCHEMA =
|
|
6
|
-
"pi-workflows.controller-worker-message.v1" as const;
|
|
7
|
-
export const CONTROLLER_WORKER_RESPONSE_SCHEMA =
|
|
8
|
-
"pi-workflows.controller-worker-response.v1" as const;
|
|
9
|
-
|
|
10
|
-
export type ControllerWorkerLaunchEnvelope = {
|
|
11
|
-
schema: typeof CONTROLLER_WORKER_LAUNCH_SCHEMA;
|
|
12
|
-
workerEpoch: string;
|
|
13
|
-
hostEpoch: number;
|
|
14
|
-
generation: number;
|
|
15
|
-
projectPath: string;
|
|
16
|
-
definitionPath: string;
|
|
17
|
-
controllerName: string;
|
|
18
|
-
resource: ControllerResource;
|
|
19
|
-
timeoutMs: number;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type ControllerWorkerOperation =
|
|
23
|
-
| "worker.ready"
|
|
24
|
-
| "effect.reserve"
|
|
25
|
-
| "effect.settle"
|
|
26
|
-
| "workflow.ensure"
|
|
27
|
-
| "workflow.changeSettings"
|
|
28
|
-
| "workflow.queueFollowUp"
|
|
29
|
-
| "workflow.removeFollowUp"
|
|
30
|
-
| "worker.finished"
|
|
31
|
-
| "worker.failed";
|
|
32
|
-
|
|
33
|
-
export type ControllerWorkerMessage = {
|
|
34
|
-
schema: typeof CONTROLLER_WORKER_MESSAGE_SCHEMA;
|
|
35
|
-
launchSchema: typeof CONTROLLER_WORKER_LAUNCH_SCHEMA;
|
|
36
|
-
messageId: string;
|
|
37
|
-
workerEpoch: string;
|
|
38
|
-
generation: number;
|
|
39
|
-
operation: ControllerWorkerOperation;
|
|
40
|
-
payload: JsonValue;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export type ControllerWorkerResponse = {
|
|
44
|
-
schema: typeof CONTROLLER_WORKER_RESPONSE_SCHEMA;
|
|
45
|
-
messageId: string;
|
|
46
|
-
outcome: "accepted" | "rejected" | "claimLost";
|
|
47
|
-
result?: JsonValue;
|
|
48
|
-
error?: string;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export function encodeControllerWorkerLine(
|
|
52
|
-
value: ControllerWorkerMessage | ControllerWorkerResponse,
|
|
53
|
-
): Buffer {
|
|
54
|
-
return Buffer.from(`${canonicalJson(value)}\n`, "utf8");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function parseControllerWorkerMessage(frame: Buffer): ControllerWorkerMessage {
|
|
58
|
-
const value = parseJson(frame.toString("utf8"));
|
|
59
|
-
if (!isRecord(value) || value.schema !== CONTROLLER_WORKER_MESSAGE_SCHEMA) {
|
|
60
|
-
throw new Error("Invalid controller worker message schema");
|
|
61
|
-
}
|
|
62
|
-
if (
|
|
63
|
-
value.launchSchema !== CONTROLLER_WORKER_LAUNCH_SCHEMA ||
|
|
64
|
-
typeof value.messageId !== "string" ||
|
|
65
|
-
typeof value.workerEpoch !== "string" ||
|
|
66
|
-
!Number.isSafeInteger(value.generation) ||
|
|
67
|
-
typeof value.operation !== "string" ||
|
|
68
|
-
!OPERATIONS.has(value.operation as ControllerWorkerOperation) ||
|
|
69
|
-
!Object.hasOwn(value, "payload")
|
|
70
|
-
) {
|
|
71
|
-
throw new Error("Invalid controller worker message");
|
|
72
|
-
}
|
|
73
|
-
return value as ControllerWorkerMessage;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function parseControllerWorkerResponse(frame: Buffer): ControllerWorkerResponse {
|
|
77
|
-
const value = parseJson(frame.toString("utf8"));
|
|
78
|
-
if (!isRecord(value) || value.schema !== CONTROLLER_WORKER_RESPONSE_SCHEMA) {
|
|
79
|
-
throw new Error("Invalid controller worker response schema");
|
|
80
|
-
}
|
|
81
|
-
if (
|
|
82
|
-
typeof value.messageId !== "string" ||
|
|
83
|
-
!["accepted", "rejected", "claimLost"].includes(String(value.outcome))
|
|
84
|
-
) {
|
|
85
|
-
throw new Error("Invalid controller worker response");
|
|
86
|
-
}
|
|
87
|
-
return value as ControllerWorkerResponse;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const OPERATIONS = new Set<ControllerWorkerOperation>([
|
|
91
|
-
"worker.ready",
|
|
92
|
-
"effect.reserve",
|
|
93
|
-
"effect.settle",
|
|
94
|
-
"workflow.ensure",
|
|
95
|
-
"workflow.changeSettings",
|
|
96
|
-
"workflow.queueFollowUp",
|
|
97
|
-
"workflow.removeFollowUp",
|
|
98
|
-
"worker.finished",
|
|
99
|
-
"worker.failed",
|
|
100
|
-
]);
|
|
101
|
-
|
|
102
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
103
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
104
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { canonicalJson, type JsonValue } from "../state/json.js";
|
|
5
|
-
import { ChildWorkerSupervisor, type SupervisedWorkerResult } from "./child-worker-supervisor.js";
|
|
6
|
-
import {
|
|
7
|
-
encodeControllerWorkerLine,
|
|
8
|
-
parseControllerWorkerMessage,
|
|
9
|
-
type ControllerWorkerLaunchEnvelope,
|
|
10
|
-
type ControllerWorkerMessage,
|
|
11
|
-
type ControllerWorkerResponse,
|
|
12
|
-
} from "./controller-worker-protocol.js";
|
|
13
|
-
import { HostProcessRegistry, type ProcessIdentity } from "./processes.js";
|
|
14
|
-
import type { WorkerOutcome } from "./state.js";
|
|
15
|
-
|
|
16
|
-
export class ControllerWorkerSupervisor {
|
|
17
|
-
private readonly supervisor: ChildWorkerSupervisor<
|
|
18
|
-
ControllerWorkerMessage,
|
|
19
|
-
ControllerWorkerResponse
|
|
20
|
-
>;
|
|
21
|
-
|
|
22
|
-
constructor(
|
|
23
|
-
readonly envelope: ControllerWorkerLaunchEnvelope,
|
|
24
|
-
private readonly options: {
|
|
25
|
-
registry: HostProcessRegistry;
|
|
26
|
-
onMessage: (message: ControllerWorkerMessage) => Promise<ControllerWorkerResponse>;
|
|
27
|
-
env?: Record<string, string>;
|
|
28
|
-
startupTimeoutMs?: number;
|
|
29
|
-
workerEntryPath?: string;
|
|
30
|
-
onSpawn?: (identity: ProcessIdentity) => void;
|
|
31
|
-
onDiagnostic?: (message: string) => void;
|
|
32
|
-
},
|
|
33
|
-
) {
|
|
34
|
-
this.supervisor = new ChildWorkerSupervisor({
|
|
35
|
-
label: "Controller worker",
|
|
36
|
-
registry: options.registry,
|
|
37
|
-
onMessage: options.onMessage,
|
|
38
|
-
parseMessage: parseControllerWorkerMessage,
|
|
39
|
-
encodeResponse: encodeControllerWorkerLine,
|
|
40
|
-
isReady: (message) => message.operation === "worker.ready",
|
|
41
|
-
isTerminal: (message) =>
|
|
42
|
-
message.operation === "worker.finished" || message.operation === "worker.failed",
|
|
43
|
-
...(options.startupTimeoutMs === undefined
|
|
44
|
-
? {}
|
|
45
|
-
: { startupTimeoutMs: options.startupTimeoutMs }),
|
|
46
|
-
...(options.onSpawn === undefined ? {} : { onSpawn: options.onSpawn }),
|
|
47
|
-
...(options.onDiagnostic === undefined ? {} : { onDiagnostic: options.onDiagnostic }),
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async start(): Promise<void> {
|
|
52
|
-
const builtEntry = fileURLToPath(new URL("./controller-worker-entry.js", import.meta.url));
|
|
53
|
-
const sourceEntry = fileURLToPath(new URL("./controller-worker-entry.ts", import.meta.url));
|
|
54
|
-
const workerEntry = this.options.workerEntryPath ?? builtEntry;
|
|
55
|
-
const args =
|
|
56
|
-
this.options.workerEntryPath === undefined && !fs.existsSync(builtEntry)
|
|
57
|
-
? ["--import", createRequire(import.meta.url).resolve("tsx"), sourceEntry]
|
|
58
|
-
: [workerEntry];
|
|
59
|
-
await this.supervisor.start({
|
|
60
|
-
args,
|
|
61
|
-
cwd: this.envelope.projectPath,
|
|
62
|
-
env: {
|
|
63
|
-
...process.env,
|
|
64
|
-
...this.options.env,
|
|
65
|
-
PI_WORKFLOWS_CONTROLLER_WORKER_LAUNCH: Buffer.from(
|
|
66
|
-
canonicalJson(this.envelope as unknown as JsonValue),
|
|
67
|
-
).toString("base64url"),
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async wait(): Promise<SupervisedWorkerResult> {
|
|
73
|
-
return await this.supervisor.wait();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async stop(outcome: WorkerOutcome = "cancelled"): Promise<void> {
|
|
77
|
-
await this.supervisor.stop(outcome);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import { MAX_PROTOCOL_MESSAGE_BYTES } from "../client/protocol.js";
|
|
2
|
-
import { canonicalJson, parseJson, type JsonValue } from "../state/json.js";
|
|
3
|
-
|
|
4
|
-
export const WORKER_MESSAGE_SCHEMA = "pi-workflows.worker-message.v1" as const;
|
|
5
|
-
export const WORKER_RESPONSE_SCHEMA = "pi-workflows.worker-response.v1" as const;
|
|
6
|
-
|
|
7
|
-
export type WorkerRunCommand =
|
|
8
|
-
| { kind: "start"; input: JsonValue }
|
|
9
|
-
| { kind: "resume"; resumeInteractionAttemptId?: string }
|
|
10
|
-
| {
|
|
11
|
-
kind: "continue";
|
|
12
|
-
parentRunId: string;
|
|
13
|
-
input: JsonValue;
|
|
14
|
-
humanDecision?: JsonValue;
|
|
15
|
-
}
|
|
16
|
-
| { kind: "restart"; input: JsonValue };
|
|
17
|
-
|
|
18
|
-
export const WORKER_MESSAGE_KINDS = [
|
|
19
|
-
"worker.ready",
|
|
20
|
-
"node.started",
|
|
21
|
-
"node.update",
|
|
22
|
-
"node.finished",
|
|
23
|
-
"node.failed",
|
|
24
|
-
"run.parked",
|
|
25
|
-
"run.finished",
|
|
26
|
-
"interaction.requested",
|
|
27
|
-
"interaction.accepted",
|
|
28
|
-
"interaction.rejected",
|
|
29
|
-
"notification.requested",
|
|
30
|
-
"presentation.requested",
|
|
31
|
-
"effect.reserve",
|
|
32
|
-
"effect.settle",
|
|
33
|
-
"worker.progress",
|
|
34
|
-
"worker.exiting",
|
|
35
|
-
] as const;
|
|
36
|
-
|
|
37
|
-
export type WorkerMessageKind = (typeof WORKER_MESSAGE_KINDS)[number];
|
|
38
|
-
export type WorkerStoreOperation =
|
|
39
|
-
| "store.initializeRun"
|
|
40
|
-
| "store.prepareRunResume"
|
|
41
|
-
| "store.readRun"
|
|
42
|
-
| "store.writeSnapshot"
|
|
43
|
-
| "store.publishUpdate"
|
|
44
|
-
| "store.findSettingsScope"
|
|
45
|
-
| "store.ensureSettingsScope"
|
|
46
|
-
| "store.getSettingsScopeAtChange"
|
|
47
|
-
| "store.createHumanDecisionRequest"
|
|
48
|
-
| "store.readResolvedHumanDecision"
|
|
49
|
-
| "store.reserveEffect"
|
|
50
|
-
| "store.settleEffect"
|
|
51
|
-
| "process.register"
|
|
52
|
-
| "process.unregister"
|
|
53
|
-
| "interaction.request"
|
|
54
|
-
| "interaction.accept"
|
|
55
|
-
| "interaction.reject"
|
|
56
|
-
| "notification.request"
|
|
57
|
-
| "presentation.request";
|
|
58
|
-
|
|
59
|
-
export type WorkerMessage = {
|
|
60
|
-
schema: typeof WORKER_MESSAGE_SCHEMA;
|
|
61
|
-
launchSchema: "pi-workflows.worker-launch.v1";
|
|
62
|
-
messageId: string;
|
|
63
|
-
kind: WorkerMessageKind;
|
|
64
|
-
operation: WorkerStoreOperation | "worker.ready" | "worker.exiting";
|
|
65
|
-
runId: string;
|
|
66
|
-
generation: number;
|
|
67
|
-
workerEpoch: string;
|
|
68
|
-
expectedRevision: number;
|
|
69
|
-
attemptId?: string;
|
|
70
|
-
payload: JsonValue;
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export type WorkerResponse = {
|
|
74
|
-
schema: typeof WORKER_RESPONSE_SCHEMA;
|
|
75
|
-
messageId: string;
|
|
76
|
-
outcome: "accepted" | "adopted" | "rejected" | "claimLost";
|
|
77
|
-
revision?: number;
|
|
78
|
-
result?: JsonValue;
|
|
79
|
-
error?: string;
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
export function workerKindForOperation(
|
|
83
|
-
operation: WorkerStoreOperation,
|
|
84
|
-
payload: Record<string, unknown>,
|
|
85
|
-
): WorkerMessageKind {
|
|
86
|
-
if (operation === "store.publishUpdate") return "node.update";
|
|
87
|
-
if (operation === "store.reserveEffect") return "effect.reserve";
|
|
88
|
-
if (operation === "store.settleEffect") return "effect.settle";
|
|
89
|
-
if (operation === "store.createHumanDecisionRequest" || operation === "interaction.request") {
|
|
90
|
-
return "interaction.requested";
|
|
91
|
-
}
|
|
92
|
-
if (operation === "interaction.accept") return "interaction.accepted";
|
|
93
|
-
if (operation === "interaction.reject") return "interaction.rejected";
|
|
94
|
-
if (operation === "notification.request") return "notification.requested";
|
|
95
|
-
if (operation === "presentation.request") return "presentation.requested";
|
|
96
|
-
if (operation === "store.writeSnapshot") {
|
|
97
|
-
const event = payload.event;
|
|
98
|
-
const eventType = isRecord(event) && typeof event.type === "string" ? event.type : "";
|
|
99
|
-
if (eventType === "node_started") return "node.started";
|
|
100
|
-
if (eventType === "node_finished") return "node.finished";
|
|
101
|
-
if (eventType === "node_failed" || eventType === "node_timed_out") return "node.failed";
|
|
102
|
-
if (eventType === "run_waiting" || eventType.includes("park")) return "run.parked";
|
|
103
|
-
if (eventType.startsWith("run_") && eventType !== "run_started") return "run.finished";
|
|
104
|
-
}
|
|
105
|
-
return "worker.progress";
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export function encodeWorkerLine(message: WorkerMessage | WorkerResponse): Buffer {
|
|
109
|
-
const encoded = Buffer.from(`${canonicalJson(message)}\n`, "utf8");
|
|
110
|
-
if (encoded.byteLength > MAX_PROTOCOL_MESSAGE_BYTES) {
|
|
111
|
-
throw new Error("Worker protocol message exceeds 1 MiB");
|
|
112
|
-
}
|
|
113
|
-
return encoded;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function parseWorkerMessage(line: Buffer | string): WorkerMessage {
|
|
117
|
-
const value = parseWorkerValue(line);
|
|
118
|
-
if (
|
|
119
|
-
value.schema !== WORKER_MESSAGE_SCHEMA ||
|
|
120
|
-
value.launchSchema !== "pi-workflows.worker-launch.v1"
|
|
121
|
-
) {
|
|
122
|
-
throw new Error("Invalid worker message schema");
|
|
123
|
-
}
|
|
124
|
-
requireText(value.messageId, "messageId");
|
|
125
|
-
requireText(value.runId, "runId");
|
|
126
|
-
requireText(value.workerEpoch, "workerEpoch");
|
|
127
|
-
if (!WORKER_MESSAGE_KINDS.includes(value.kind as WorkerMessageKind)) {
|
|
128
|
-
throw new Error("Invalid worker message kind");
|
|
129
|
-
}
|
|
130
|
-
if (!Number.isSafeInteger(value.generation) || (value.generation as number) <= 0) {
|
|
131
|
-
throw new Error("Worker generation must be positive");
|
|
132
|
-
}
|
|
133
|
-
if (!Number.isSafeInteger(value.expectedRevision) || (value.expectedRevision as number) < 0) {
|
|
134
|
-
throw new Error("Worker expectedRevision must be non-negative");
|
|
135
|
-
}
|
|
136
|
-
requireText(value.operation, "operation");
|
|
137
|
-
if (value.attemptId !== undefined) requireText(value.attemptId, "attemptId");
|
|
138
|
-
if (!Object.hasOwn(value, "payload")) throw new Error("Worker payload is required");
|
|
139
|
-
return value as WorkerMessage;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export function parseWorkerResponse(line: Buffer | string): WorkerResponse {
|
|
143
|
-
const value = parseWorkerValue(line);
|
|
144
|
-
if (value.schema !== WORKER_RESPONSE_SCHEMA) throw new Error("Invalid worker response schema");
|
|
145
|
-
requireText(value.messageId, "messageId");
|
|
146
|
-
if (!["accepted", "adopted", "rejected", "claimLost"].includes(value.outcome as string)) {
|
|
147
|
-
throw new Error("Invalid worker response outcome");
|
|
148
|
-
}
|
|
149
|
-
if (value.error !== undefined && typeof value.error !== "string") {
|
|
150
|
-
throw new Error("Worker response error must be text");
|
|
151
|
-
}
|
|
152
|
-
return value as WorkerResponse;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function parseWorkerValue(line: Buffer | string): Record<string, unknown> {
|
|
156
|
-
const buffer = Buffer.isBuffer(line) ? line : Buffer.from(line, "utf8");
|
|
157
|
-
if (buffer.byteLength + 1 > MAX_PROTOCOL_MESSAGE_BYTES) {
|
|
158
|
-
throw new Error("Worker protocol message exceeds 1 MiB");
|
|
159
|
-
}
|
|
160
|
-
const text = buffer.toString("utf8");
|
|
161
|
-
const value = parseJson(text);
|
|
162
|
-
if (!isRecord(value) || canonicalJson(value) !== text) {
|
|
163
|
-
throw new Error("Worker protocol message must be a canonical JSON object");
|
|
164
|
-
}
|
|
165
|
-
return value;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function requireText(value: unknown, field: string): asserts value is string {
|
|
169
|
-
if (typeof value !== "string" || value.length === 0 || value.length > 256) {
|
|
170
|
-
throw new Error(`Worker ${field} must be nonempty bounded text`);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
175
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
176
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { canonicalJson } from "../state/json.js";
|
|
5
|
-
import { ChildWorkerSupervisor, type SupervisedWorkerResult } from "./child-worker-supervisor.js";
|
|
6
|
-
import { HostProcessRegistry, type ProcessIdentity } from "./processes.js";
|
|
7
|
-
import type { WorkerLaunchEnvelope, WorkerOutcome } from "./state.js";
|
|
8
|
-
import {
|
|
9
|
-
encodeWorkerLine,
|
|
10
|
-
parseWorkerMessage,
|
|
11
|
-
type WorkerMessage,
|
|
12
|
-
type WorkerResponse,
|
|
13
|
-
} from "./worker-protocol.js";
|
|
14
|
-
|
|
15
|
-
export type WorkflowWorkerResult = SupervisedWorkerResult;
|
|
16
|
-
|
|
17
|
-
export class WorkflowWorkerSupervisor {
|
|
18
|
-
private readonly supervisor: ChildWorkerSupervisor<WorkerMessage, WorkerResponse>;
|
|
19
|
-
|
|
20
|
-
constructor(
|
|
21
|
-
readonly envelope: WorkerLaunchEnvelope,
|
|
22
|
-
private readonly options: {
|
|
23
|
-
registry: HostProcessRegistry;
|
|
24
|
-
onMessage: (message: WorkerMessage) => Promise<WorkerResponse>;
|
|
25
|
-
env?: Record<string, string>;
|
|
26
|
-
startupTimeoutMs?: number;
|
|
27
|
-
workerEntryPath?: string;
|
|
28
|
-
onSpawn?: (identity: ProcessIdentity) => void;
|
|
29
|
-
onDiagnostic?: (message: string) => void;
|
|
30
|
-
},
|
|
31
|
-
) {
|
|
32
|
-
this.supervisor = new ChildWorkerSupervisor({
|
|
33
|
-
label: "Workflow worker",
|
|
34
|
-
registry: options.registry,
|
|
35
|
-
onMessage: options.onMessage,
|
|
36
|
-
parseMessage: parseWorkerMessage,
|
|
37
|
-
encodeResponse: encodeWorkerLine,
|
|
38
|
-
isReady: (message) => message.kind === "worker.ready",
|
|
39
|
-
isTerminal: (message) => message.kind === "worker.exiting",
|
|
40
|
-
...(options.startupTimeoutMs === undefined
|
|
41
|
-
? {}
|
|
42
|
-
: { startupTimeoutMs: options.startupTimeoutMs }),
|
|
43
|
-
...(options.onSpawn === undefined ? {} : { onSpawn: options.onSpawn }),
|
|
44
|
-
...(options.onDiagnostic === undefined ? {} : { onDiagnostic: options.onDiagnostic }),
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async start(): Promise<void> {
|
|
49
|
-
const builtEntry = fileURLToPath(new URL("./worker-entry.js", import.meta.url));
|
|
50
|
-
const sourceEntry = fileURLToPath(new URL("./worker-entry.ts", import.meta.url));
|
|
51
|
-
const workerEntry = this.options.workerEntryPath ?? builtEntry;
|
|
52
|
-
const args =
|
|
53
|
-
this.options.workerEntryPath === undefined && !fs.existsSync(builtEntry)
|
|
54
|
-
? ["--import", createRequire(import.meta.url).resolve("tsx"), sourceEntry]
|
|
55
|
-
: [workerEntry];
|
|
56
|
-
await this.supervisor.start({
|
|
57
|
-
args,
|
|
58
|
-
cwd: this.envelope.projectPath,
|
|
59
|
-
env: {
|
|
60
|
-
...process.env,
|
|
61
|
-
...this.options.env,
|
|
62
|
-
PI_WORKFLOWS_WORKER_LAUNCH: Buffer.from(canonicalJson(this.envelope)).toString("base64url"),
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async wait(): Promise<WorkflowWorkerResult> {
|
|
68
|
-
return await this.supervisor.wait();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async stop(outcome: WorkerOutcome = "cancelled"): Promise<void> {
|
|
72
|
-
await this.supervisor.stop(outcome);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|