@bastani/atomic 0.8.21 → 0.8.22
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/CHANGELOG.md +66 -9
- package/dist/builtin/intercom/broker/broker.ts +3 -3
- package/dist/builtin/intercom/config.ts +3 -3
- package/dist/builtin/intercom/index.ts +1 -1
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/ui/compose.ts +2 -2
- package/dist/builtin/mcp/host-html-template.ts +0 -3
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +20 -4
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +9 -9
- package/dist/builtin/subagents/agents/debugger.md +6 -6
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/prompts/parallel-handoff-plan.md +1 -1
- package/dist/builtin/subagents/skills/browser-use/SKILL.md +234 -0
- package/dist/builtin/subagents/skills/browser-use/references/cdp-python.md +76 -0
- package/dist/builtin/subagents/skills/browser-use/references/multi-session.md +92 -0
- package/dist/builtin/subagents/skills/subagent/SKILL.md +4 -4
- package/dist/builtin/subagents/src/agents/skills.ts +19 -1
- package/dist/builtin/subagents/src/extension/index.ts +24 -22
- package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +7 -1
- package/dist/builtin/subagents/src/runs/background/async-execution.ts +23 -7
- package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +98 -3
- package/dist/builtin/subagents/src/runs/background/async-status.ts +3 -1
- package/dist/builtin/subagents/src/runs/background/run-status.ts +1 -1
- package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +3 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +37 -12
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify.ts +15 -15
- package/dist/builtin/subagents/src/runs/foreground/execution.ts +26 -2
- package/dist/builtin/subagents/src/runs/shared/nested-render.ts +1 -1
- package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +7 -0
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +28 -1
- package/dist/builtin/subagents/src/shared/fast-mode.ts +80 -0
- package/dist/builtin/subagents/src/shared/formatters.ts +4 -2
- package/dist/builtin/subagents/src/shared/types.ts +4 -2
- package/dist/builtin/subagents/src/shared/utils.ts +3 -61
- package/dist/builtin/subagents/src/tui/render.ts +303 -157
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +113 -35
- package/dist/builtin/workflows/README.md +228 -41
- package/dist/builtin/workflows/builtin/deep-research-codebase.ts +535 -541
- package/dist/builtin/workflows/builtin/goal.ts +39 -25
- package/dist/builtin/workflows/builtin/open-claude-design.ts +66 -69
- package/dist/builtin/workflows/builtin/ralph.ts +21 -21
- package/dist/builtin/workflows/package.json +6 -5
- package/dist/builtin/workflows/skills/research-codebase/SKILL.md +1 -1
- package/dist/builtin/workflows/src/extension/background-ui-adapter.ts +2 -2
- package/dist/builtin/workflows/src/extension/discovery.ts +25 -146
- package/dist/builtin/workflows/src/extension/dispatcher.ts +72 -24
- package/dist/builtin/workflows/src/extension/hil-answer-notifications.ts +363 -0
- package/dist/builtin/workflows/src/extension/index.ts +690 -352
- package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +99 -62
- package/dist/builtin/workflows/src/extension/render-call.ts +2 -1
- package/dist/builtin/workflows/src/extension/render-result.ts +9 -3
- package/dist/builtin/workflows/src/extension/renderers.ts +5 -3
- package/dist/builtin/workflows/src/extension/runtime.ts +68 -33
- package/dist/builtin/workflows/src/extension/status-writer.ts +1 -1
- package/dist/builtin/workflows/src/extension/wiring.ts +34 -13
- package/dist/builtin/workflows/src/extension/workflow-module-loader.ts +142 -0
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +4 -4
- package/dist/builtin/workflows/src/index.ts +2 -0
- package/dist/builtin/workflows/src/intercom/result-intercom.ts +1 -1
- package/dist/builtin/workflows/src/runs/background/runner.ts +6 -4
- package/dist/builtin/workflows/src/runs/background/status.ts +45 -21
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +624 -52
- package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +80 -24
- package/dist/builtin/workflows/src/runs/shared/validate-inputs.ts +61 -24
- package/dist/builtin/workflows/src/runs/shared/workflow-runner.ts +32 -10
- package/dist/builtin/workflows/src/sdk-surface.ts +6 -0
- package/dist/builtin/workflows/src/shared/expanded-workflow-graph.ts +178 -0
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +92 -12
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +21 -3
- package/dist/builtin/workflows/src/shared/render-inputs-schema.ts +1 -2
- package/dist/builtin/workflows/src/shared/run-visibility.ts +9 -0
- package/dist/builtin/workflows/src/shared/schema-introspection.ts +121 -0
- package/dist/builtin/workflows/src/shared/serializable.ts +132 -0
- package/dist/builtin/workflows/src/shared/stage-ui-broker.ts +91 -9
- package/dist/builtin/workflows/src/shared/store-types.ts +31 -3
- package/dist/builtin/workflows/src/shared/store.ts +58 -14
- package/dist/builtin/workflows/src/shared/types.ts +105 -40
- package/dist/builtin/workflows/src/tui/chat-surface-message.ts +129 -13
- package/dist/builtin/workflows/src/tui/chat-surface.ts +6 -1
- package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +3 -2
- package/dist/builtin/workflows/src/tui/graph-canvas.ts +1 -1
- package/dist/builtin/workflows/src/tui/graph-view.ts +91 -65
- package/dist/builtin/workflows/src/tui/inline-form-card.ts +1 -1
- package/dist/builtin/workflows/src/tui/inline-form-overlay.ts +3 -2
- package/dist/builtin/workflows/src/tui/inputs-overlay.ts +3 -2
- package/dist/builtin/workflows/src/tui/inputs-picker.ts +8 -7
- package/dist/builtin/workflows/src/tui/keybindings-adapter.ts +2 -0
- package/dist/builtin/workflows/src/tui/node-card.ts +34 -8
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +4 -11
- package/dist/builtin/workflows/src/tui/prompt-card.ts +98 -50
- package/dist/builtin/workflows/src/tui/session-list.ts +7 -2
- package/dist/builtin/workflows/src/tui/session-picker.ts +2 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +226 -55
- package/dist/builtin/workflows/src/tui/status-helpers.ts +2 -0
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +37 -158
- package/dist/builtin/workflows/src/tui/toast.ts +2 -2
- package/dist/builtin/workflows/src/tui/widget.ts +53 -12
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +270 -19
- package/dist/builtin/workflows/src/tui/workflow-notice-card.ts +184 -0
- package/dist/builtin/workflows/src/workflows/define-workflow.ts +138 -43
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +45 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +27 -9
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +196 -17
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/atomic-guide-command.d.ts.map +1 -1
- package/dist/core/atomic-guide-command.js +2 -2
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/dist/core/codex-fast-mode.d.ts +36 -0
- package/dist/core/codex-fast-mode.d.ts.map +1 -0
- package/dist/core/codex-fast-mode.js +117 -0
- package/dist/core/codex-fast-mode.js.map +1 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +1 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/index.d.ts +4 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -0
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +7 -2
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +23 -8
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/reactive-widget.d.ts +58 -0
- package/dist/core/extensions/reactive-widget.d.ts.map +1 -0
- package/dist/core/extensions/reactive-widget.js +182 -0
- package/dist/core/extensions/reactive-widget.js.map +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +1 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +26 -12
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/messages.d.ts +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +8 -2
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry.d.ts +4 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +11 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/resource-loader.d.ts +9 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +49 -21
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +22 -13
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +7 -5
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +5 -3
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +16 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +64 -5
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +7 -4
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/ask-user-question.js +2 -2
- package/dist/core/tools/ask-user-question/ask-user-question.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +12 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/chat-input-actions.d.ts.map +1 -1
- package/dist/modes/interactive/chat-input-actions.js.map +1 -1
- package/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/dist/modes/interactive/components/diff.js +0 -1
- package/dist/modes/interactive/components/diff.js.map +1 -1
- package/dist/modes/interactive/components/fast-mode-selector.d.ts +27 -0
- package/dist/modes/interactive/components/fast-mode-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/fast-mode-selector.js +105 -0
- package/dist/modes/interactive/components/fast-mode-selector.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +7 -12
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +132 -30
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +53 -6
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +3 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/docs/compaction.md +1 -1
- package/docs/custom-provider.md +2 -2
- package/docs/development.md +2 -2
- package/docs/docs.json +2 -2
- package/docs/extensions.md +18 -13
- package/docs/providers.md +5 -1
- package/docs/quickstart.md +5 -3
- package/docs/rpc.md +5 -5
- package/docs/sdk.md +12 -12
- package/docs/settings.md +18 -0
- package/docs/themes.md +6 -6
- package/docs/tui.md +20 -18
- package/docs/usage.md +2 -0
- package/docs/workflows.md +403 -39
- package/examples/extensions/qna.ts +2 -2
- package/package.json +4 -4
- package/dist/builtin/subagents/skills/playwright-cli/SKILL.md +0 -392
- package/dist/builtin/subagents/skills/playwright-cli/references/element-attributes.md +0 -23
- package/dist/builtin/subagents/skills/playwright-cli/references/playwright-tests.md +0 -39
- package/dist/builtin/subagents/skills/playwright-cli/references/request-mocking.md +0 -87
- package/dist/builtin/subagents/skills/playwright-cli/references/running-code.md +0 -241
- package/dist/builtin/subagents/skills/playwright-cli/references/session-management.md +0 -225
- package/dist/builtin/subagents/skills/playwright-cli/references/spec-driven-testing.md +0 -305
- package/dist/builtin/subagents/skills/playwright-cli/references/storage-state.md +0 -275
- package/dist/builtin/subagents/skills/playwright-cli/references/test-generation.md +0 -134
- package/dist/builtin/subagents/skills/playwright-cli/references/tracing.md +0 -139
- package/dist/builtin/subagents/skills/playwright-cli/references/video-recording.md +0 -143
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { Store } from "./store.js";
|
|
10
|
-
import type { RunSnapshot, StageSnapshot, StageStatus } from "./store-types.js";
|
|
10
|
+
import type { RunSnapshot, StageSnapshot, StageStatus, WorkflowChildReplaySnapshot } from "./store-types.js";
|
|
11
|
+
import type { WorkflowInputValues, WorkflowOutputValues } from "./types.js";
|
|
12
|
+
import { workflowSerializableObjectSchema } from "./serializable.js";
|
|
13
|
+
import { Value } from "typebox/value";
|
|
11
14
|
import { isWorkflowFailureKind } from "./workflow-failures.js";
|
|
12
15
|
|
|
13
16
|
// ---------------------------------------------------------------------------
|
|
@@ -40,7 +43,7 @@ export interface SessionManager {
|
|
|
40
43
|
export interface InFlightRun {
|
|
41
44
|
readonly runId: string;
|
|
42
45
|
readonly name: string;
|
|
43
|
-
readonly inputs: Readonly<
|
|
46
|
+
readonly inputs: Readonly<WorkflowInputValues>;
|
|
44
47
|
readonly startTs: number;
|
|
45
48
|
/** Stage IDs that were started (in order) but may or may not have ended. */
|
|
46
49
|
readonly stageIds: readonly string[];
|
|
@@ -57,7 +60,7 @@ export interface InFlightRun {
|
|
|
57
60
|
* Pure function — does not mutate anything.
|
|
58
61
|
*/
|
|
59
62
|
export function scanInFlightRuns(entries: readonly SessionEntry[]): InFlightRun[] {
|
|
60
|
-
const started = new Map<string, { name: string; inputs:
|
|
63
|
+
const started = new Map<string, { name: string; inputs: WorkflowInputValues; startTs: number; stageIds: string[] }>();
|
|
61
64
|
const ended = new Set<string>();
|
|
62
65
|
|
|
63
66
|
for (const entry of entries) {
|
|
@@ -73,9 +76,7 @@ export function scanInFlightRuns(entries: readonly SessionEntry[]): InFlightRun[
|
|
|
73
76
|
) {
|
|
74
77
|
started.set(runId, {
|
|
75
78
|
name,
|
|
76
|
-
inputs: (inputs
|
|
77
|
-
? (inputs as Record<string, unknown>)
|
|
78
|
-
: {},
|
|
79
|
+
inputs: serializableObjectOrEmpty(inputs),
|
|
79
80
|
startTs: ts,
|
|
80
81
|
stageIds: [],
|
|
81
82
|
});
|
|
@@ -180,6 +181,9 @@ export function restoreOnSessionStart(
|
|
|
180
181
|
status: "running",
|
|
181
182
|
stages,
|
|
182
183
|
startedAt: run.startTs,
|
|
184
|
+
...(runMeta.parentRunId !== undefined ? { parentRunId: runMeta.parentRunId } : {}),
|
|
185
|
+
...(runMeta.parentStageId !== undefined ? { parentStageId: runMeta.parentStageId } : {}),
|
|
186
|
+
...(runMeta.rootRunId !== undefined ? { rootRunId: runMeta.rootRunId } : {}),
|
|
183
187
|
...(runMeta.resumedFromRunId !== undefined ? { resumedFromRunId: runMeta.resumedFromRunId } : {}),
|
|
184
188
|
...(runMeta.resumeFromStageId !== undefined ? { resumeFromStageId: runMeta.resumeFromStageId } : {}),
|
|
185
189
|
};
|
|
@@ -198,6 +202,9 @@ export function restoreOnSessionStart(
|
|
|
198
202
|
error: "Run did not complete — process was interrupted.",
|
|
199
203
|
failureKind: "unknown",
|
|
200
204
|
resumable: false,
|
|
205
|
+
...(runMeta.parentRunId !== undefined ? { parentRunId: runMeta.parentRunId } : {}),
|
|
206
|
+
...(runMeta.parentStageId !== undefined ? { parentStageId: runMeta.parentStageId } : {}),
|
|
207
|
+
...(runMeta.rootRunId !== undefined ? { rootRunId: runMeta.rootRunId } : {}),
|
|
201
208
|
...(runMeta.resumedFromRunId !== undefined ? { resumedFromRunId: runMeta.resumedFromRunId } : {}),
|
|
202
209
|
...(runMeta.resumeFromStageId !== undefined ? { resumeFromStageId: runMeta.resumeFromStageId } : {}),
|
|
203
210
|
};
|
|
@@ -262,7 +269,7 @@ function _buildStageSnapshots(
|
|
|
262
269
|
if (typeof failureKind === "string" && isWorkflowFailureKind(failureKind)) snap.failureKind = failureKind;
|
|
263
270
|
if (typeof failureMessage === "string") snap.failureMessage = failureMessage;
|
|
264
271
|
if (typeof skippedReason === "string") snap.skippedReason = skippedReason;
|
|
265
|
-
Object.assign(snap, replayMetadata(entry.payload));
|
|
272
|
+
Object.assign(snap, replayMetadata(entry.payload), workflowChildMetadata(entry.payload));
|
|
266
273
|
}
|
|
267
274
|
}
|
|
268
275
|
}
|
|
@@ -289,6 +296,66 @@ function replayMetadata(payload: Record<string, unknown>): Pick<StageSnapshot, "
|
|
|
289
296
|
};
|
|
290
297
|
}
|
|
291
298
|
|
|
299
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
300
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function serializableObject(value: unknown): WorkflowOutputValues | undefined {
|
|
304
|
+
return Value.Check(workflowSerializableObjectSchema, value)
|
|
305
|
+
? (value as WorkflowOutputValues)
|
|
306
|
+
: undefined;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function serializableObjectOrEmpty(value: unknown): WorkflowOutputValues {
|
|
310
|
+
return serializableObject(value) ?? {};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function isWorkflowChildReplayStatus(status: unknown): status is WorkflowChildReplaySnapshot["status"] {
|
|
314
|
+
return status === "completed";
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function workflowChildMetadata(payload: Record<string, unknown>): Pick<StageSnapshot, "workflowChild"> {
|
|
318
|
+
const workflowChild = payload["workflowChild"];
|
|
319
|
+
if (!isRecord(workflowChild)) return {};
|
|
320
|
+
const alias = workflowChild["alias"];
|
|
321
|
+
const workflow = workflowChild["workflow"];
|
|
322
|
+
const childRunId = workflowChild["runId"];
|
|
323
|
+
const status = workflowChild["status"];
|
|
324
|
+
const outputs = workflowChild["outputs"];
|
|
325
|
+
if (
|
|
326
|
+
typeof alias !== "string" ||
|
|
327
|
+
typeof workflow !== "string" ||
|
|
328
|
+
typeof childRunId !== "string" ||
|
|
329
|
+
!isWorkflowChildReplayStatus(status) ||
|
|
330
|
+
!isRecord(outputs)
|
|
331
|
+
) {
|
|
332
|
+
return {};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// `structuredClone` detaches the restored snapshot from the parsed JSONL
|
|
336
|
+
// payload with a guaranteed deep copy, independent of the TypeBox
|
|
337
|
+
// serializable check. Declared `outputs` are the child contract, so a
|
|
338
|
+
// non-serializable value bails the whole child snapshot.
|
|
339
|
+
let clonedOutputs: WorkflowOutputValues;
|
|
340
|
+
try {
|
|
341
|
+
const serializableOutputs = serializableObject(outputs);
|
|
342
|
+
if (serializableOutputs === undefined) return {};
|
|
343
|
+
clonedOutputs = structuredClone(serializableOutputs);
|
|
344
|
+
} catch {
|
|
345
|
+
return {};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return {
|
|
349
|
+
workflowChild: {
|
|
350
|
+
alias,
|
|
351
|
+
workflow,
|
|
352
|
+
runId: childRunId,
|
|
353
|
+
status,
|
|
354
|
+
outputs: clonedOutputs,
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
|
|
292
359
|
function restoreStageStatus(status: unknown): StageStatus {
|
|
293
360
|
switch (status) {
|
|
294
361
|
case "completed":
|
|
@@ -301,7 +368,7 @@ function restoreStageStatus(status: unknown): StageStatus {
|
|
|
301
368
|
}
|
|
302
369
|
|
|
303
370
|
function restoreTerminalRuns(entries: readonly SessionEntry[], store: Store): void {
|
|
304
|
-
const started = new Map<string, { readonly name: string; readonly inputs: Readonly<
|
|
371
|
+
const started = new Map<string, { readonly name: string; readonly inputs: Readonly<WorkflowInputValues>; readonly startTs: number }>();
|
|
305
372
|
const ended = new Map<string, Record<string, unknown>>();
|
|
306
373
|
|
|
307
374
|
for (const entry of entries) {
|
|
@@ -313,9 +380,7 @@ function restoreTerminalRuns(entries: readonly SessionEntry[], store: Store): vo
|
|
|
313
380
|
if (typeof runId === "string" && typeof name === "string" && typeof ts === "number") {
|
|
314
381
|
started.set(runId, {
|
|
315
382
|
name,
|
|
316
|
-
inputs: (inputs
|
|
317
|
-
? (inputs as Record<string, unknown>)
|
|
318
|
-
: {},
|
|
383
|
+
inputs: serializableObjectOrEmpty(inputs),
|
|
319
384
|
startTs: ts,
|
|
320
385
|
});
|
|
321
386
|
}
|
|
@@ -342,6 +407,9 @@ function restoreTerminalRuns(entries: readonly SessionEntry[], store: Store): vo
|
|
|
342
407
|
status: "running",
|
|
343
408
|
stages,
|
|
344
409
|
startedAt: start.startTs,
|
|
410
|
+
...(runMeta.parentRunId !== undefined ? { parentRunId: runMeta.parentRunId } : {}),
|
|
411
|
+
...(runMeta.parentStageId !== undefined ? { parentStageId: runMeta.parentStageId } : {}),
|
|
412
|
+
...(runMeta.rootRunId !== undefined ? { rootRunId: runMeta.rootRunId } : {}),
|
|
345
413
|
...(runMeta.resumedFromRunId !== undefined ? { resumedFromRunId: runMeta.resumedFromRunId } : {}),
|
|
346
414
|
...(runMeta.resumeFromStageId !== undefined ? { resumeFromStageId: runMeta.resumeFromStageId } : {}),
|
|
347
415
|
});
|
|
@@ -380,12 +448,24 @@ function restoreTerminalRunStatus(status: unknown): "completed" | "failed" | "ki
|
|
|
380
448
|
function findRunStartMetadata(
|
|
381
449
|
entries: readonly SessionEntry[],
|
|
382
450
|
runId: string,
|
|
383
|
-
): {
|
|
451
|
+
): {
|
|
452
|
+
readonly parentRunId?: string;
|
|
453
|
+
readonly parentStageId?: string;
|
|
454
|
+
readonly rootRunId?: string;
|
|
455
|
+
readonly resumedFromRunId?: string;
|
|
456
|
+
readonly resumeFromStageId?: string;
|
|
457
|
+
} {
|
|
384
458
|
for (const entry of entries) {
|
|
385
459
|
if (entry.type !== "workflow.run.start" || entry.payload["runId"] !== runId) continue;
|
|
460
|
+
const parentRunId = entry.payload["parentRunId"];
|
|
461
|
+
const parentStageId = entry.payload["parentStageId"];
|
|
462
|
+
const rootRunId = entry.payload["rootRunId"];
|
|
386
463
|
const resumedFromRunId = entry.payload["resumedFromRunId"];
|
|
387
464
|
const resumeFromStageId = entry.payload["resumeFromStageId"];
|
|
388
465
|
return {
|
|
466
|
+
...(typeof parentRunId === "string" ? { parentRunId } : {}),
|
|
467
|
+
...(typeof parentStageId === "string" ? { parentStageId } : {}),
|
|
468
|
+
...(typeof rootRunId === "string" ? { rootRunId } : {}),
|
|
389
469
|
...(typeof resumedFromRunId === "string" ? { resumedFromRunId } : {}),
|
|
390
470
|
...(typeof resumeFromStageId === "string" ? { resumeFromStageId } : {}),
|
|
391
471
|
};
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* through gracefully when the runtime doesn't support the method.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import type { WorkflowInputValues, WorkflowOutputValues } from "./types.js";
|
|
10
|
+
|
|
9
11
|
// ---------------------------------------------------------------------------
|
|
10
12
|
// Structural API type (subset of ExtensionAPI needed here)
|
|
11
13
|
// ---------------------------------------------------------------------------
|
|
@@ -30,7 +32,10 @@ export interface PersistenceAPI {
|
|
|
30
32
|
export interface RunStartPayload {
|
|
31
33
|
readonly runId: string;
|
|
32
34
|
readonly name: string;
|
|
33
|
-
readonly inputs: Readonly<
|
|
35
|
+
readonly inputs: Readonly<WorkflowInputValues>;
|
|
36
|
+
readonly parentRunId?: string;
|
|
37
|
+
readonly parentStageId?: string;
|
|
38
|
+
readonly rootRunId?: string;
|
|
34
39
|
readonly resumedFromRunId?: string;
|
|
35
40
|
readonly resumeFromStageId?: string;
|
|
36
41
|
readonly ts: number;
|
|
@@ -55,6 +60,14 @@ export interface StageProgressPayload {
|
|
|
55
60
|
readonly payload: unknown;
|
|
56
61
|
}
|
|
57
62
|
|
|
63
|
+
export interface WorkflowChildReplayPayload {
|
|
64
|
+
readonly alias: string;
|
|
65
|
+
readonly workflow: string;
|
|
66
|
+
readonly runId: string;
|
|
67
|
+
readonly status: "completed";
|
|
68
|
+
readonly outputs: WorkflowOutputValues;
|
|
69
|
+
}
|
|
70
|
+
|
|
58
71
|
export interface StageEndPayload {
|
|
59
72
|
readonly runId: string;
|
|
60
73
|
readonly stageId: string;
|
|
@@ -68,12 +81,13 @@ export interface StageEndPayload {
|
|
|
68
81
|
readonly replayKey?: string;
|
|
69
82
|
readonly replayedFromStageId?: string;
|
|
70
83
|
readonly replayed?: boolean;
|
|
84
|
+
readonly workflowChild?: WorkflowChildReplayPayload;
|
|
71
85
|
}
|
|
72
86
|
|
|
73
87
|
export interface RunEndPayload {
|
|
74
88
|
readonly runId: string;
|
|
75
89
|
readonly status: string;
|
|
76
|
-
readonly result?:
|
|
90
|
+
readonly result?: WorkflowOutputValues;
|
|
77
91
|
readonly error?: string;
|
|
78
92
|
readonly failureKind?: string;
|
|
79
93
|
readonly failureMessage?: string;
|
|
@@ -96,6 +110,9 @@ export function appendRunStart(api: PersistenceAPI, payload: RunStartPayload): v
|
|
|
96
110
|
runId: payload.runId,
|
|
97
111
|
name: payload.name,
|
|
98
112
|
inputs: payload.inputs,
|
|
113
|
+
...(payload.parentRunId !== undefined ? { parentRunId: payload.parentRunId } : {}),
|
|
114
|
+
...(payload.parentStageId !== undefined ? { parentStageId: payload.parentStageId } : {}),
|
|
115
|
+
...(payload.rootRunId !== undefined ? { rootRunId: payload.rootRunId } : {}),
|
|
99
116
|
...(payload.resumedFromRunId !== undefined ? { resumedFromRunId: payload.resumedFromRunId } : {}),
|
|
100
117
|
...(payload.resumeFromStageId !== undefined ? { resumeFromStageId: payload.resumeFromStageId } : {}),
|
|
101
118
|
ts: payload.ts,
|
|
@@ -153,6 +170,7 @@ export function appendStageEnd(
|
|
|
153
170
|
...(payload.replayKey !== undefined ? { replayKey: payload.replayKey } : {}),
|
|
154
171
|
...(payload.replayedFromStageId !== undefined ? { replayedFromStageId: payload.replayedFromStageId } : {}),
|
|
155
172
|
...(payload.replayed !== undefined ? { replayed: payload.replayed } : {}),
|
|
173
|
+
...(payload.workflowChild !== undefined ? { workflowChild: payload.workflowChild } : {}),
|
|
156
174
|
});
|
|
157
175
|
if (opts?.emitMessage === true && payload.summary && typeof api.appendCustomMessageEntry === "function") {
|
|
158
176
|
api.appendCustomMessageEntry(
|
|
@@ -168,7 +186,7 @@ export function appendRunEnd(api: PersistenceAPI, payload: RunEndPayload): void
|
|
|
168
186
|
api.appendEntry("workflow.run.end", {
|
|
169
187
|
runId: payload.runId,
|
|
170
188
|
status: payload.status,
|
|
171
|
-
...(payload.result !== undefined ? { result: payload.result
|
|
189
|
+
...(payload.result !== undefined ? { result: payload.result } : {}),
|
|
172
190
|
...(payload.error !== undefined ? { error: payload.error } : {}),
|
|
173
191
|
...(payload.failureKind !== undefined ? { failureKind: payload.failureKind } : {}),
|
|
174
192
|
...(payload.failureMessage !== undefined ? { failureMessage: payload.failureMessage } : {}),
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* and for non-TTY consumers (LLM tool results, logfiles, --help in
|
|
20
20
|
* redirected output).
|
|
21
21
|
*
|
|
22
|
-
* The layout in pretty mode mirrors
|
|
22
|
+
* The layout in pretty mode mirrors bastani-inc/atomic's `renderInputsText` so a
|
|
23
23
|
* dev moving between the atomic CLI and the pi extension feels at home:
|
|
24
24
|
*
|
|
25
25
|
* INPUTS FOR ralph
|
|
@@ -42,7 +42,6 @@
|
|
|
42
42
|
import type { GraphTheme } from "../tui/graph-theme.js";
|
|
43
43
|
import { paint } from "../tui/color-utils.js";
|
|
44
44
|
import { renderRoundedBox, chatWidth } from "../tui/chat-surface.js";
|
|
45
|
-
import { truncateToWidth } from "../tui/text-helpers.js";
|
|
46
45
|
import type { WorkflowInputEntry } from "../extension/render-result.js";
|
|
47
46
|
|
|
48
47
|
export interface RenderInputsSchemaOptions {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RunSnapshot } from "./store-types.js";
|
|
2
|
+
|
|
3
|
+
export function isTopLevelWorkflowRun(run: Pick<RunSnapshot, "parentRunId">): boolean {
|
|
4
|
+
return run.parentRunId === undefined;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function topLevelWorkflowRuns(runs: readonly RunSnapshot[]): RunSnapshot[] {
|
|
8
|
+
return runs.filter(isTopLevelWorkflowRun);
|
|
9
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* schema-introspection — single adapter between TypeBox input/output schemas
|
|
3
|
+
* and the legacy normalized field descriptor (`WorkflowInputEntry`) consumed by
|
|
4
|
+
* the inputs picker UI, validation, dispatch, and render paths.
|
|
5
|
+
*
|
|
6
|
+
* Authors declare inputs/outputs with TypeBox schemas (`Type.String`,
|
|
7
|
+
* `Type.Number`, `Type.Union([...literals])`, …). The many UI/render/dispatch
|
|
8
|
+
* surfaces still want a flat `{ type, choices?, default?, required?,
|
|
9
|
+
* description? }` view; rather than rewrite all of them, they derive that view
|
|
10
|
+
* from a TypeBox schema through this module.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
IsAny,
|
|
15
|
+
IsArray,
|
|
16
|
+
IsBoolean,
|
|
17
|
+
IsInteger,
|
|
18
|
+
IsLiteralString,
|
|
19
|
+
IsNumber,
|
|
20
|
+
IsObject,
|
|
21
|
+
IsOptional,
|
|
22
|
+
IsString,
|
|
23
|
+
IsUnion,
|
|
24
|
+
type TSchema,
|
|
25
|
+
} from "typebox";
|
|
26
|
+
import type { WorkflowInputEntry } from "../extension/render-result.js";
|
|
27
|
+
|
|
28
|
+
/** Field-kind label expected by the legacy descriptor consumers. */
|
|
29
|
+
export type SchemaFieldKind =
|
|
30
|
+
| "text"
|
|
31
|
+
| "number"
|
|
32
|
+
| "integer"
|
|
33
|
+
| "boolean"
|
|
34
|
+
| "select"
|
|
35
|
+
| "object"
|
|
36
|
+
| "array"
|
|
37
|
+
| "unknown";
|
|
38
|
+
|
|
39
|
+
interface SchemaMeta {
|
|
40
|
+
readonly default?: unknown;
|
|
41
|
+
readonly description?: string;
|
|
42
|
+
readonly anyOf?: readonly TSchema[];
|
|
43
|
+
readonly const?: unknown;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function meta(schema: TSchema): SchemaMeta {
|
|
47
|
+
return schema as unknown as SchemaMeta;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** True when every member of a union is a string literal. */
|
|
51
|
+
function isStringLiteralUnion(schema: TSchema): boolean {
|
|
52
|
+
if (!IsUnion(schema)) return false;
|
|
53
|
+
const members = meta(schema).anyOf ?? [];
|
|
54
|
+
return members.length > 0 && members.every((m) => IsLiteralString(m));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Map a TypeBox schema to the legacy field-kind label. */
|
|
58
|
+
export function schemaFieldKind(schema: TSchema): SchemaFieldKind {
|
|
59
|
+
if (isStringLiteralUnion(schema)) return "select";
|
|
60
|
+
if (IsLiteralString(schema)) return "text";
|
|
61
|
+
if (IsString(schema)) return "text";
|
|
62
|
+
if (IsInteger(schema)) return "integer";
|
|
63
|
+
if (IsNumber(schema)) return "number";
|
|
64
|
+
if (IsBoolean(schema)) return "boolean";
|
|
65
|
+
if (IsObject(schema)) return "object";
|
|
66
|
+
if (IsArray(schema)) return "array";
|
|
67
|
+
if (IsAny(schema)) return "unknown";
|
|
68
|
+
return "unknown";
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Declared default value (`schema.default`), or undefined when none. */
|
|
72
|
+
export function schemaDefault(schema: TSchema): unknown {
|
|
73
|
+
return meta(schema).default;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Declared description, or undefined. */
|
|
77
|
+
export function schemaDescription(schema: TSchema): string | undefined {
|
|
78
|
+
return meta(schema).description;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Allowed string values for a string-literal union, else undefined. */
|
|
82
|
+
export function schemaChoices(schema: TSchema): readonly string[] | undefined {
|
|
83
|
+
if (!isStringLiteralUnion(schema)) return undefined;
|
|
84
|
+
const members = meta(schema).anyOf ?? [];
|
|
85
|
+
return members.map((m) => String(meta(m).const));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* A field is "required" in the picker/validation sense — i.e. the caller MUST
|
|
90
|
+
* supply it — when it is neither wrapped in `Type.Optional(...)` nor carries a
|
|
91
|
+
* `default`. A defaulted input is a required KEY at the type level (it is always
|
|
92
|
+
* present after defaults are applied) but the user need not provide it, so it is
|
|
93
|
+
* reported as not-required here, matching the legacy descriptor semantics where
|
|
94
|
+
* `{ default }` implied `required: false`.
|
|
95
|
+
*/
|
|
96
|
+
export function schemaIsRequired(schema: TSchema): boolean {
|
|
97
|
+
return !IsOptional(schema) && schemaDefault(schema) === undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Derive the legacy normalized input descriptor for a single named field. */
|
|
101
|
+
export function deriveInputField(name: string, schema: TSchema): WorkflowInputEntry {
|
|
102
|
+
const choices = schemaChoices(schema);
|
|
103
|
+
const def = schemaDefault(schema);
|
|
104
|
+
const description = schemaDescription(schema);
|
|
105
|
+
const entry: WorkflowInputEntry = {
|
|
106
|
+
name,
|
|
107
|
+
type: schemaFieldKind(schema),
|
|
108
|
+
required: schemaIsRequired(schema),
|
|
109
|
+
};
|
|
110
|
+
if (description !== undefined) entry.description = description;
|
|
111
|
+
if (def !== undefined) entry.default = def;
|
|
112
|
+
if (choices !== undefined) entry.choices = choices;
|
|
113
|
+
return entry;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Derive descriptors for an entire declared input map (preserving order). */
|
|
117
|
+
export function deriveInputFields(
|
|
118
|
+
schema: Readonly<Record<string, TSchema>>,
|
|
119
|
+
): WorkflowInputEntry[] {
|
|
120
|
+
return Object.entries(schema).map(([name, s]) => deriveInputField(name, s));
|
|
121
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { Refine, Type, type TSchema } from "typebox";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A JSON-serializable object must be a *plain* object (or array, handled
|
|
5
|
+
* separately) — class instances such as `Date`, `Map`, or `RegExp` structurally
|
|
6
|
+
* look like empty records to the schema checker but are not JSON round-trippable,
|
|
7
|
+
* so they are rejected here.
|
|
8
|
+
*/
|
|
9
|
+
function isPlainObjectValue(value: unknown): boolean {
|
|
10
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return true;
|
|
11
|
+
const proto = Object.getPrototypeOf(value);
|
|
12
|
+
return proto === Object.prototype || proto === null;
|
|
13
|
+
}
|
|
14
|
+
import { Value } from "typebox/value";
|
|
15
|
+
import type {
|
|
16
|
+
WorkflowOutputValues,
|
|
17
|
+
WorkflowSerializableValue,
|
|
18
|
+
} from "./types.js";
|
|
19
|
+
|
|
20
|
+
export const WORKFLOW_SERIALIZABLE_DESCRIPTION =
|
|
21
|
+
"JSON-serializable (string, finite number, boolean, null, array, or object)";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Recursive TypeBox schema describing a JSON-serializable value: string, finite
|
|
25
|
+
* number, boolean, null, array of serializable values, or an object whose
|
|
26
|
+
* values are serializable. `Type.Number` already rejects NaN/Infinity in
|
|
27
|
+
* TypeBox's value checker, matching the previous `z.number().finite()`.
|
|
28
|
+
*/
|
|
29
|
+
export const workflowSerializableValueSchema: TSchema = Type.Cyclic(
|
|
30
|
+
{
|
|
31
|
+
Serializable: Type.Union([
|
|
32
|
+
Type.String(),
|
|
33
|
+
Type.Number(),
|
|
34
|
+
Type.Boolean(),
|
|
35
|
+
Type.Null(),
|
|
36
|
+
Type.Array(Type.Ref("Serializable")),
|
|
37
|
+
Refine(
|
|
38
|
+
Type.Record(Type.String(), Type.Ref("Serializable")),
|
|
39
|
+
isPlainObjectValue,
|
|
40
|
+
"must be a plain JSON object",
|
|
41
|
+
),
|
|
42
|
+
]),
|
|
43
|
+
},
|
|
44
|
+
"Serializable",
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
export const workflowSerializableObjectSchema: TSchema = Type.Record(
|
|
48
|
+
Type.String(),
|
|
49
|
+
workflowSerializableValueSchema,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
export function workflowSerializableTypeName(value: unknown): string {
|
|
53
|
+
if (value === null) return "null";
|
|
54
|
+
if (Array.isArray(value)) return "array";
|
|
55
|
+
if (typeof value === "number" && Number.isNaN(value)) return "NaN";
|
|
56
|
+
if (typeof value === "number" && !Number.isFinite(value)) return String(value);
|
|
57
|
+
return typeof value;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Convert a TypeBox `instancePath` ("/a/0/b") to the legacy "a[0].b" form. */
|
|
61
|
+
function formatInstancePath(instancePath: string): string {
|
|
62
|
+
if (!instancePath) return "";
|
|
63
|
+
const segments = instancePath.split("/").filter((s) => s.length > 0);
|
|
64
|
+
return segments
|
|
65
|
+
.map((segment) =>
|
|
66
|
+
/^\d+$/.test(segment)
|
|
67
|
+
? `[${segment}]`
|
|
68
|
+
: /^[A-Za-z_$][\w$]*$/.test(segment)
|
|
69
|
+
? `.${segment}`
|
|
70
|
+
: `[${JSON.stringify(segment)}]`,
|
|
71
|
+
)
|
|
72
|
+
.join("")
|
|
73
|
+
.replace(/^\./, "");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Resolve the value located at a TypeBox instance path within `root`. */
|
|
77
|
+
function valueAtInstancePath(root: unknown, instancePath: string): unknown {
|
|
78
|
+
if (!instancePath) return root;
|
|
79
|
+
let current: unknown = root;
|
|
80
|
+
for (const segment of instancePath.split("/").filter((s) => s.length > 0)) {
|
|
81
|
+
if (current === null || typeof current !== "object") return current;
|
|
82
|
+
current = (current as Record<string, unknown>)[segment];
|
|
83
|
+
}
|
|
84
|
+
return current;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function firstError(schema: TSchema, value: unknown): { instancePath: string } | undefined {
|
|
88
|
+
for (const error of Value.Errors(schema, value)) {
|
|
89
|
+
return { instancePath: error.instancePath };
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function workflowSerializableValidationError(
|
|
95
|
+
value: unknown,
|
|
96
|
+
label: string,
|
|
97
|
+
): string | undefined {
|
|
98
|
+
if (Value.Check(workflowSerializableValueSchema, value)) return undefined;
|
|
99
|
+
const issue = firstError(workflowSerializableValueSchema, value);
|
|
100
|
+
const issuePath = issue === undefined ? "" : formatInstancePath(issue.instancePath);
|
|
101
|
+
const location = issuePath.length > 0 ? ` at ${issuePath}` : "";
|
|
102
|
+
const offending = issue === undefined ? value : valueAtInstancePath(value, issue.instancePath);
|
|
103
|
+
return `${label}${location} must be ${WORKFLOW_SERIALIZABLE_DESCRIPTION}, got ${workflowSerializableTypeName(offending)}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function workflowSerializableObjectValidationError(
|
|
107
|
+
value: unknown,
|
|
108
|
+
label: string,
|
|
109
|
+
): string | undefined {
|
|
110
|
+
if (Value.Check(workflowSerializableObjectSchema, value)) return undefined;
|
|
111
|
+
const issue = firstError(workflowSerializableObjectSchema, value);
|
|
112
|
+
const issuePath = issue === undefined ? "" : formatInstancePath(issue.instancePath);
|
|
113
|
+
const location = issuePath.length > 0 ? ` at ${issuePath}` : "";
|
|
114
|
+
const offending = issue === undefined ? value : valueAtInstancePath(value, issue.instancePath);
|
|
115
|
+
return `${label}${location} must be a ${WORKFLOW_SERIALIZABLE_DESCRIPTION} object, got ${workflowSerializableTypeName(offending)}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function assertWorkflowSerializableValue(
|
|
119
|
+
value: unknown,
|
|
120
|
+
label: string,
|
|
121
|
+
): asserts value is WorkflowSerializableValue {
|
|
122
|
+
const error = workflowSerializableValidationError(value, label);
|
|
123
|
+
if (error !== undefined) throw new Error(`atomic-workflows: ${error}`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function assertWorkflowSerializableObject(
|
|
127
|
+
value: unknown,
|
|
128
|
+
label: string,
|
|
129
|
+
): asserts value is WorkflowOutputValues {
|
|
130
|
+
const error = workflowSerializableObjectValidationError(value, label);
|
|
131
|
+
if (error !== undefined) throw new Error(`atomic-workflows: ${error}`);
|
|
132
|
+
}
|