@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
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { JsonValue } from "../state/json.js";
|
|
2
|
+
|
|
3
|
+
export type ParsedResourceManagerArgs =
|
|
4
|
+
| { kind: "list" }
|
|
5
|
+
| { kind: "get"; resourceManager: string; key: string }
|
|
6
|
+
| { kind: "apply"; resourceManager: string; key: string; spec: JsonValue }
|
|
7
|
+
| { kind: "reconcile"; resourceManager: string; key: string }
|
|
8
|
+
| { kind: "delete"; resourceManager: string; key: string };
|
|
9
|
+
|
|
10
|
+
const RESOURCE_MANAGER_USAGE =
|
|
11
|
+
"Usage: /resource-manager [list|get <resource-manager> <key>|apply <resource-manager> <key> <json>|reconcile <resource-manager> <key>|delete <resource-manager> <key>]";
|
|
12
|
+
|
|
13
|
+
export function parseResourceManagerArgs(args: string): ParsedResourceManagerArgs {
|
|
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 resource manager spec JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
kind: "apply",
|
|
29
|
+
resourceManager: 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
|
+
resourceManager: operation[2] as string,
|
|
40
|
+
key: operation[3] as string,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
throw new Error(RESOURCE_MANAGER_USAGE);
|
|
45
|
+
}
|
|
@@ -20,7 +20,7 @@ type QueuedSessionDelivery = {
|
|
|
20
20
|
const SESSION_ENTRY_CONFIRMATION_MS = 10_000;
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* Delivers at most one
|
|
23
|
+
* Delivers at most one server-owned message into a Pi session at a time.
|
|
24
24
|
*
|
|
25
25
|
* Pi's public sendMessage API does not return the saved session entry ID. Keep
|
|
26
26
|
* the claimed delivery in memory until that entry becomes observable. Polling
|
|
@@ -54,7 +54,7 @@ export class SessionDeliveryCoordinator {
|
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
// Remember the
|
|
57
|
+
// Remember the server claim before the final idle check. If Pi starts a
|
|
58
58
|
// turn while the claim request is in flight, a later poll can use this
|
|
59
59
|
// exact still-live claim instead of making a conflicting second claim.
|
|
60
60
|
this.claimed = delivery;
|
|
@@ -10,7 +10,7 @@ import { buildWidgetView } from "./widget.js";
|
|
|
10
10
|
const WIDGET_KEY = "pi-workflows";
|
|
11
11
|
const WIDGET_SCROLL_STEP = 3;
|
|
12
12
|
|
|
13
|
-
/** Client-backed projection of the
|
|
13
|
+
/** Client-backed projection of the server-owned run into the origin Pi session. */
|
|
14
14
|
export class SessionWorkflowView {
|
|
15
15
|
private session: WorkflowSessionView | null = null;
|
|
16
16
|
private scroll: number | null = null;
|
|
@@ -25,7 +25,7 @@ type PendingTurn = {
|
|
|
25
25
|
end: { stopReason: WorkflowTurnStopReason; responseSessionEntryId: string | null } | null;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
/** Adds every
|
|
28
|
+
/** Adds every server-owned workflow message to one Pi session through one public API path. */
|
|
29
29
|
export class WorkflowMessageCoordinator {
|
|
30
30
|
private readonly queued = new Set<string>();
|
|
31
31
|
private readonly closedTurnMessages = new Set<string>();
|
|
@@ -296,7 +296,7 @@ export class WorkflowMessageCoordinator {
|
|
|
296
296
|
},
|
|
297
297
|
});
|
|
298
298
|
if (response.outcome !== "accepted" && response.outcome !== "adopted") {
|
|
299
|
-
throw new Error(response.error ?? "Workflow
|
|
299
|
+
throw new Error(response.error ?? "Workflow server rejected the Pi branch report");
|
|
300
300
|
}
|
|
301
301
|
for (const entry of entries) {
|
|
302
302
|
const message = messageById(view, entry.workflowMessageId);
|
|
@@ -364,7 +364,7 @@ async function reportTurn(
|
|
|
364
364
|
payload: report as unknown as JsonValue,
|
|
365
365
|
});
|
|
366
366
|
if (response.outcome !== "accepted" && response.outcome !== "adopted") {
|
|
367
|
-
throw new Error(response.error ?? "Workflow
|
|
367
|
+
throw new Error(response.error ?? "Workflow server rejected the model-turn report");
|
|
368
368
|
}
|
|
369
369
|
const receipt = response.receipt;
|
|
370
370
|
if (
|
|
@@ -372,12 +372,12 @@ async function reportTurn(
|
|
|
372
372
|
receipt.schema !== WORKFLOW_TURN_REPORT_RECEIPT_SCHEMA ||
|
|
373
373
|
!["active", "settled", "absent"].includes(String(receipt.ownership))
|
|
374
374
|
) {
|
|
375
|
-
throw new Error("Workflow
|
|
375
|
+
throw new Error("Workflow server returned an invalid model-turn receipt");
|
|
376
376
|
}
|
|
377
377
|
const ownership = receipt.ownership as WorkflowTurnReportReceipt["ownership"];
|
|
378
378
|
if (ownership === "absent") {
|
|
379
379
|
if (receipt.turn !== null) {
|
|
380
|
-
throw new Error("Workflow
|
|
380
|
+
throw new Error("Workflow server returned an invalid model-turn receipt");
|
|
381
381
|
}
|
|
382
382
|
} else if (
|
|
383
383
|
!isRecord(receipt.turn) ||
|
|
@@ -388,7 +388,7 @@ async function reportTurn(
|
|
|
388
388
|
receipt.turn.targetSessionId !== report.targetSessionId ||
|
|
389
389
|
receipt.turn.state !== (ownership === "active" ? "started" : "ended")
|
|
390
390
|
) {
|
|
391
|
-
throw new Error("Workflow
|
|
391
|
+
throw new Error("Workflow server returned an invalid model-turn receipt");
|
|
392
392
|
}
|
|
393
393
|
return receipt as unknown as WorkflowTurnReportReceipt;
|
|
394
394
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
ManagedResourceCondition,
|
|
3
|
+
ManagedResourceConditionInput,
|
|
4
|
+
ManagedResourceConditionStatus,
|
|
5
|
+
ManagedResourceStatus,
|
|
6
|
+
ResourceManagerStatusPatch,
|
|
7
7
|
} from "./types.js";
|
|
8
8
|
|
|
9
9
|
export function conditionTrue(
|
|
10
10
|
type: string,
|
|
11
11
|
reason: string,
|
|
12
12
|
message?: string,
|
|
13
|
-
):
|
|
13
|
+
): ManagedResourceConditionInput {
|
|
14
14
|
return condition(type, true, reason, message);
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -18,7 +18,7 @@ export function conditionFalse(
|
|
|
18
18
|
type: string,
|
|
19
19
|
reason: string,
|
|
20
20
|
message?: string,
|
|
21
|
-
):
|
|
21
|
+
): ManagedResourceConditionInput {
|
|
22
22
|
return condition(type, false, reason, message);
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -26,23 +26,23 @@ export function conditionUnknown(
|
|
|
26
26
|
type: string,
|
|
27
27
|
reason: string,
|
|
28
28
|
message?: string,
|
|
29
|
-
):
|
|
29
|
+
): ManagedResourceConditionInput {
|
|
30
30
|
return condition(type, "unknown", reason, message);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export function applyStatusPatch<TStatus>(
|
|
34
|
-
current:
|
|
35
|
-
patch:
|
|
34
|
+
current: ManagedResourceStatus<TStatus>,
|
|
35
|
+
patch: ResourceManagerStatusPatch<TStatus> | undefined,
|
|
36
36
|
generation: number,
|
|
37
37
|
now: string,
|
|
38
|
-
):
|
|
38
|
+
): ManagedResourceStatus<TStatus> {
|
|
39
39
|
return {
|
|
40
40
|
observedGeneration: generation,
|
|
41
41
|
conditions: mergeConditions(current.conditions, patch?.conditions ?? [], generation, now),
|
|
42
|
-
|
|
43
|
-
patch !== undefined && Object.hasOwn(patch, "
|
|
44
|
-
? (patch.
|
|
45
|
-
: current.
|
|
42
|
+
resourceManagerStatus:
|
|
43
|
+
patch !== undefined && Object.hasOwn(patch, "resourceManagerStatus")
|
|
44
|
+
? (patch.resourceManagerStatus as TStatus)
|
|
45
|
+
: current.resourceManagerStatus,
|
|
46
46
|
...(patch?.workflowRun === null
|
|
47
47
|
? {}
|
|
48
48
|
: patch?.workflowRun !== undefined
|
|
@@ -54,11 +54,11 @@ export function applyStatusPatch<TStatus>(
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
export function mergeConditions(
|
|
57
|
-
current:
|
|
58
|
-
updates:
|
|
57
|
+
current: ManagedResourceCondition[],
|
|
58
|
+
updates: ManagedResourceConditionInput[],
|
|
59
59
|
generation: number,
|
|
60
60
|
now: string,
|
|
61
|
-
):
|
|
61
|
+
): ManagedResourceCondition[] {
|
|
62
62
|
const byType = new Map(current.map((item) => [item.type, item]));
|
|
63
63
|
const seen = new Set<string>();
|
|
64
64
|
for (const update of updates) {
|
|
@@ -68,7 +68,7 @@ export function mergeConditions(
|
|
|
68
68
|
}
|
|
69
69
|
seen.add(update.type);
|
|
70
70
|
const previous = byType.get(update.type);
|
|
71
|
-
const next:
|
|
71
|
+
const next: ManagedResourceCondition = {
|
|
72
72
|
...update,
|
|
73
73
|
observedGeneration: generation,
|
|
74
74
|
lastTransitionTime:
|
|
@@ -83,11 +83,11 @@ export function mergeConditions(
|
|
|
83
83
|
|
|
84
84
|
function condition(
|
|
85
85
|
type: string,
|
|
86
|
-
status:
|
|
86
|
+
status: ManagedResourceConditionStatus,
|
|
87
87
|
reason: string,
|
|
88
88
|
message: string | undefined,
|
|
89
|
-
):
|
|
90
|
-
const value:
|
|
89
|
+
): ManagedResourceConditionInput {
|
|
90
|
+
const value: ManagedResourceConditionInput = {
|
|
91
91
|
type,
|
|
92
92
|
status,
|
|
93
93
|
reason,
|
|
@@ -97,7 +97,7 @@ function condition(
|
|
|
97
97
|
return value;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
function validateCondition(value:
|
|
100
|
+
function validateCondition(value: ManagedResourceConditionInput): void {
|
|
101
101
|
if (value.type.trim().length === 0) {
|
|
102
102
|
throw new Error("Condition type must not be empty");
|
|
103
103
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnyResourceManagerDefinition,
|
|
3
|
+
ResourceManagerDefinition,
|
|
4
|
+
ManagedResource,
|
|
5
|
+
} from "./types.js";
|
|
6
|
+
|
|
7
|
+
const RESOURCE_MANAGER_DEFINITION_BRAND = Symbol.for("pi-workflows.resource-manager-definition");
|
|
8
|
+
const RESOURCE_MANAGER_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
9
|
+
|
|
10
|
+
export function defineResourceManager<TSpec, TStatus>(
|
|
11
|
+
definition: ResourceManagerDefinition<TSpec, TStatus>,
|
|
12
|
+
): ResourceManagerDefinition<TSpec, TStatus> {
|
|
13
|
+
assertValidResourceManagerDefinition(definition);
|
|
14
|
+
if (isResourceManagerDefinition(definition)) {
|
|
15
|
+
return definition;
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(definition, RESOURCE_MANAGER_DEFINITION_BRAND, {
|
|
18
|
+
value: true,
|
|
19
|
+
enumerable: false,
|
|
20
|
+
configurable: false,
|
|
21
|
+
writable: false,
|
|
22
|
+
});
|
|
23
|
+
return definition;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function isResourceManagerDefinition(value: unknown): value is AnyResourceManagerDefinition {
|
|
27
|
+
return (
|
|
28
|
+
value !== null &&
|
|
29
|
+
typeof value === "object" &&
|
|
30
|
+
(value as Record<PropertyKey, unknown>)[RESOURCE_MANAGER_DEFINITION_BRAND] === true
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function assertValidResourceManagerDefinition<TSpec, TStatus>(
|
|
35
|
+
definition: ResourceManagerDefinition<TSpec, TStatus>,
|
|
36
|
+
): void {
|
|
37
|
+
if (definition === null || typeof definition !== "object") {
|
|
38
|
+
throw new Error("Invalid resource manager definition: expected an object");
|
|
39
|
+
}
|
|
40
|
+
if (!RESOURCE_MANAGER_NAME_PATTERN.test(definition.name)) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Invalid resource manager definition: name ${JSON.stringify(definition.name)} must match ${RESOURCE_MANAGER_NAME_PATTERN.source}`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
if (typeof definition.initialStatus !== "function") {
|
|
46
|
+
throw new Error("Invalid resource manager definition: initialStatus must be a function");
|
|
47
|
+
}
|
|
48
|
+
if (typeof definition.reconcile !== "function") {
|
|
49
|
+
throw new Error("Invalid resource manager definition: reconcile must be a function");
|
|
50
|
+
}
|
|
51
|
+
if (
|
|
52
|
+
definition.timeoutMs !== undefined &&
|
|
53
|
+
(!Number.isSafeInteger(definition.timeoutMs) || definition.timeoutMs <= 0)
|
|
54
|
+
) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
"Invalid resource manager definition: timeoutMs must be a positive safe integer",
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function asAnyResourceManagerDefinition<TSpec, TStatus>(
|
|
62
|
+
definition: ResourceManagerDefinition<TSpec, TStatus>,
|
|
63
|
+
): AnyResourceManagerDefinition {
|
|
64
|
+
return definition as unknown as ResourceManagerDefinition<unknown, unknown>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function asTypedResource<TSpec, TStatus>(
|
|
68
|
+
resource: ManagedResource,
|
|
69
|
+
): ManagedResource<TSpec, TStatus> {
|
|
70
|
+
return resource as ManagedResource<TSpec, TStatus>;
|
|
71
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsonFingerprint } from "./json.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ResourceManagerStore } from "./store.js";
|
|
3
3
|
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
ResourceManagerEffects,
|
|
5
|
+
ResourceManagerQueueClaim,
|
|
6
|
+
ManagedResource,
|
|
7
7
|
EffectApplication,
|
|
8
8
|
EffectDefinition,
|
|
9
9
|
EffectObservation,
|
|
@@ -11,13 +11,13 @@ import type {
|
|
|
11
11
|
JsonObject,
|
|
12
12
|
} from "./types.js";
|
|
13
13
|
|
|
14
|
-
export class
|
|
14
|
+
export class ResourceManagerEffectService implements ResourceManagerEffects {
|
|
15
15
|
private used = false;
|
|
16
16
|
|
|
17
17
|
constructor(
|
|
18
|
-
private readonly store:
|
|
19
|
-
private readonly resource:
|
|
20
|
-
private readonly claim:
|
|
18
|
+
private readonly store: ResourceManagerStore,
|
|
19
|
+
private readonly resource: ManagedResource,
|
|
20
|
+
private readonly claim: ResourceManagerQueueClaim,
|
|
21
21
|
private readonly signal: AbortSignal,
|
|
22
22
|
) {}
|
|
23
23
|
|
|
@@ -115,7 +115,7 @@ export class ControllerEffectService implements ControllerEffects {
|
|
|
115
115
|
|
|
116
116
|
private recordEvent(type: string, effectKey: string, extra: JsonObject = {}): void {
|
|
117
117
|
this.store.recordEvent({
|
|
118
|
-
|
|
118
|
+
resourceManager: this.resource.metadata.resourceManager,
|
|
119
119
|
key: this.resource.metadata.key,
|
|
120
120
|
claim: this.claim,
|
|
121
121
|
type,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export class ManagedResourceConflictError extends Error {
|
|
2
|
+
constructor(resourceManager: string, key: string) {
|
|
3
|
+
super(`Managed resource ${resourceManager}/${key} changed during reconciliation`);
|
|
4
|
+
this.name = "ManagedResourceConflictError";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class ManagedResourceNotFoundError extends Error {
|
|
9
|
+
constructor(resourceManager: string, key: string) {
|
|
10
|
+
super(`Managed resource not found: ${resourceManager}/${key}`);
|
|
11
|
+
this.name = "ManagedResourceNotFoundError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class EffectRequestConflictError extends Error {
|
|
16
|
+
constructor(key: string) {
|
|
17
|
+
super(`Effect key ${JSON.stringify(key)} was reused with a different request`);
|
|
18
|
+
this.name = "EffectRequestConflictError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class WorkflowRequestConflictError extends Error {
|
|
23
|
+
constructor(key: string) {
|
|
24
|
+
super(`Workflow request key ${JSON.stringify(key)} was reused with different input`);
|
|
25
|
+
this.name = "WorkflowRequestConflictError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export {
|
|
2
|
+
assertValidResourceManagerDefinition,
|
|
3
|
+
defineResourceManager,
|
|
4
|
+
isResourceManagerDefinition,
|
|
5
|
+
} from "./definition.js";
|
|
6
|
+
export {
|
|
7
|
+
applyStatusPatch,
|
|
8
|
+
conditionFalse,
|
|
9
|
+
conditionTrue,
|
|
10
|
+
conditionUnknown,
|
|
11
|
+
mergeConditions,
|
|
12
|
+
} from "./conditions.js";
|
|
13
|
+
export {
|
|
14
|
+
EffectRequestConflictError,
|
|
15
|
+
ManagedResourceConflictError,
|
|
16
|
+
ManagedResourceNotFoundError,
|
|
17
|
+
WorkflowRequestConflictError,
|
|
18
|
+
} from "./errors.js";
|
|
19
|
+
export { ResourceManagerEffectService } from "./effects.js";
|
|
20
|
+
export { canonicalJson, jsonFingerprint } from "./json.js";
|
|
21
|
+
export { ResourceManagerRuntime, type ResourceManagerRuntimeOptions } from "./runtime.js";
|
|
22
|
+
export { createResultHelpers, requeue, requeueAfter, settled } from "./results.js";
|
|
23
|
+
export {
|
|
24
|
+
SqliteResourceManagerStore,
|
|
25
|
+
type RunEventRecord,
|
|
26
|
+
type WorkflowRunClaimOptions,
|
|
27
|
+
type WorkflowRunPreparationResult,
|
|
28
|
+
type WorkflowRunQueueRecord,
|
|
29
|
+
type WorkflowRunReservationOptions,
|
|
30
|
+
} from "./sqlite.js";
|
|
31
|
+
export {
|
|
32
|
+
type ResourceManagerStore,
|
|
33
|
+
type EffectReservation,
|
|
34
|
+
type QueueItem,
|
|
35
|
+
type QueueRequeueOptions,
|
|
36
|
+
type WorkflowRecordUpdate,
|
|
37
|
+
type WorkflowReservation,
|
|
38
|
+
} from "./store.js";
|
|
39
|
+
export {
|
|
40
|
+
resourceManagerFileStem,
|
|
41
|
+
resourceManagerSearchDirs,
|
|
42
|
+
discoverResourceManagers,
|
|
43
|
+
loadResourceManagerFile,
|
|
44
|
+
loadDiscoveredResourceManagers,
|
|
45
|
+
type DiscoveredResourceManager,
|
|
46
|
+
} from "./loader.js";
|
|
47
|
+
export {
|
|
48
|
+
ResourceManagerWorkflowCoordinator,
|
|
49
|
+
type ResourceManagerWorkflowControlRequest,
|
|
50
|
+
type ResourceManagerWorkflowScheduler,
|
|
51
|
+
type WorkflowSchedulerRequest,
|
|
52
|
+
type WorkflowSchedulerResult,
|
|
53
|
+
} from "./workflows.js";
|
|
54
|
+
export type {
|
|
55
|
+
AnyResourceManagerDefinition,
|
|
56
|
+
ChildWorkflowRecord,
|
|
57
|
+
ChildWorkflowReference,
|
|
58
|
+
ChildWorkflowRequest,
|
|
59
|
+
ChildWorkflowState,
|
|
60
|
+
ManagedResourceCondition,
|
|
61
|
+
ManagedResourceConditionInput,
|
|
62
|
+
ManagedResourceConditionStatus,
|
|
63
|
+
ResourceManagerDefinition,
|
|
64
|
+
ResourceManagerEffects,
|
|
65
|
+
ResourceManagerFollowUpResult,
|
|
66
|
+
ResourceManagerQueueFollowUpRequest,
|
|
67
|
+
ResourceManagerRemoveFollowUpRequest,
|
|
68
|
+
ResourceManagerSettingsChangeRequest,
|
|
69
|
+
ResourceManagerSettingsChangeResult,
|
|
70
|
+
ResourceManagerEvent,
|
|
71
|
+
ResourceManagerQueueClaim,
|
|
72
|
+
ManagedResource,
|
|
73
|
+
ManagedResourceRef,
|
|
74
|
+
ManagedResourceStatus,
|
|
75
|
+
ResourceManagerStatusPatch,
|
|
76
|
+
ResourceManagerWorkflows,
|
|
77
|
+
EffectApplication,
|
|
78
|
+
EffectDefinition,
|
|
79
|
+
EffectObservation,
|
|
80
|
+
EffectRecord,
|
|
81
|
+
EffectState,
|
|
82
|
+
JsonObject,
|
|
83
|
+
JsonPrimitive,
|
|
84
|
+
JsonValue,
|
|
85
|
+
MaybePromise,
|
|
86
|
+
ReconcileContext,
|
|
87
|
+
ReconcileResult,
|
|
88
|
+
} from "./types.js";
|
|
@@ -0,0 +1,111 @@
|
|
|
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 { isResourceManagerDefinition } from "./definition.js";
|
|
7
|
+
import type { AnyResourceManagerDefinition } from "./types.js";
|
|
8
|
+
|
|
9
|
+
const RESOURCE_MANAGER_FILE_SUFFIXES = [
|
|
10
|
+
".resource-manager.ts",
|
|
11
|
+
".resource-manager.js",
|
|
12
|
+
".resource-manager.mts",
|
|
13
|
+
".resource-manager.mjs",
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
export type DiscoveredResourceManager = {
|
|
17
|
+
name: string;
|
|
18
|
+
path: string;
|
|
19
|
+
source: "project" | "global";
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function resourceManagerSearchDirs(options: {
|
|
23
|
+
cwd: string;
|
|
24
|
+
homeDir?: string;
|
|
25
|
+
}): { dir: string; source: DiscoveredResourceManager["source"] }[] {
|
|
26
|
+
const homeDir = options.homeDir ?? os.homedir();
|
|
27
|
+
return [
|
|
28
|
+
{ dir: path.join(options.cwd, ".pi", "resource-managers"), source: "project" },
|
|
29
|
+
{ dir: path.join(homeDir, ".pi", "agent", "resource-managers"), source: "global" },
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function resourceManagerFileStem(filePath: string): string {
|
|
34
|
+
const base = path.basename(filePath);
|
|
35
|
+
const suffix = RESOURCE_MANAGER_FILE_SUFFIXES.find((candidate) => base.endsWith(candidate));
|
|
36
|
+
return suffix === undefined ? base : base.slice(0, -suffix.length);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const RESOURCE_MANAGER_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 loadResourceManagerFile(
|
|
46
|
+
filePath: string,
|
|
47
|
+
): Promise<AnyResourceManagerDefinition> {
|
|
48
|
+
const absolutePath = path.resolve(filePath);
|
|
49
|
+
const jiti = createJiti(pathToFileURL(absolutePath).href, {
|
|
50
|
+
interopDefault: true,
|
|
51
|
+
moduleCache: false,
|
|
52
|
+
alias: {
|
|
53
|
+
"@osolmaz/pi-workflows/resource-managers": RESOURCE_MANAGER_ENTRY,
|
|
54
|
+
"@osolmaz/pi-workflows": WORKFLOW_ENTRY,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
const loaded = (await jiti.import(absolutePath, { default: true })) as unknown;
|
|
58
|
+
if (!isResourceManagerDefinition(loaded)) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`ResourceManager module must default-export defineResourceManager(...): ${absolutePath}`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
return loaded;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function discoverResourceManagers(options: {
|
|
67
|
+
cwd: string;
|
|
68
|
+
homeDir?: string;
|
|
69
|
+
}): Promise<DiscoveredResourceManager[]> {
|
|
70
|
+
const discovered: DiscoveredResourceManager[] = [];
|
|
71
|
+
const seen = new Set<string>();
|
|
72
|
+
for (const { dir, source } of resourceManagerSearchDirs(options)) {
|
|
73
|
+
for (const filePath of await listResourceManagerFiles(dir)) {
|
|
74
|
+
const name = resourceManagerFileStem(filePath);
|
|
75
|
+
if (seen.has(name)) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
seen.add(name);
|
|
79
|
+
discovered.push({ name, path: filePath, source });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return discovered;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function loadDiscoveredResourceManagers(options: {
|
|
86
|
+
cwd: string;
|
|
87
|
+
homeDir?: string;
|
|
88
|
+
}): Promise<AnyResourceManagerDefinition[]> {
|
|
89
|
+
return await Promise.all(
|
|
90
|
+
(await discoverResourceManagers(options)).map(
|
|
91
|
+
async (entry) => await loadResourceManagerFile(entry.path),
|
|
92
|
+
),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function listResourceManagerFiles(dir: string): Promise<string[]> {
|
|
97
|
+
let entries: import("node:fs").Dirent[];
|
|
98
|
+
try {
|
|
99
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
100
|
+
} catch {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
return entries
|
|
104
|
+
.filter(
|
|
105
|
+
(entry) =>
|
|
106
|
+
entry.isFile() &&
|
|
107
|
+
RESOURCE_MANAGER_FILE_SUFFIXES.some((suffix) => entry.name.endsWith(suffix)),
|
|
108
|
+
)
|
|
109
|
+
.map((entry) => path.join(dir, entry.name))
|
|
110
|
+
.sort();
|
|
111
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ResourceManagerStatusPatch, ReconcileContext, ReconcileResult } from "./types.js";
|
|
2
2
|
|
|
3
3
|
export function createResultHelpers<TStatus>(): Pick<
|
|
4
4
|
ReconcileContext<TStatus>,
|
|
@@ -27,20 +27,20 @@ export function createResultHelpers<TStatus>(): Pick<
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export function settled<TStatus>(
|
|
30
|
-
status?:
|
|
30
|
+
status?: ResourceManagerStatusPatch<TStatus>,
|
|
31
31
|
): ReconcileResult<TStatus> {
|
|
32
32
|
return createResultHelpers<TStatus>().settled(status);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export function requeue<TStatus>(
|
|
36
|
-
status?:
|
|
36
|
+
status?: ResourceManagerStatusPatch<TStatus>,
|
|
37
37
|
): ReconcileResult<TStatus> {
|
|
38
38
|
return createResultHelpers<TStatus>().requeue(status);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export function requeueAfter<TStatus>(
|
|
42
42
|
afterMs: number,
|
|
43
|
-
status?:
|
|
43
|
+
status?: ResourceManagerStatusPatch<TStatus>,
|
|
44
44
|
): ReconcileResult<TStatus> {
|
|
45
45
|
return createResultHelpers<TStatus>().requeueAfter(afterMs, status);
|
|
46
46
|
}
|