@duckmind/dm-windows-x64 0.61.4 → 0.61.9
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/dm.exe +0 -0
- package/extensions/.dm-extensions.json +211 -67
- package/extensions/dm-subagents/agents/claude-code-writer.md +15 -0
- package/extensions/dm-subagents/agents/claude-code.md +15 -0
- package/extensions/dm-subagents/agents/codex-exec-writer.md +15 -0
- package/extensions/dm-subagents/agents/codex-exec.md +15 -0
- package/extensions/dm-subagents/agents/cursor-agent-writer.md +14 -0
- package/extensions/dm-subagents/agents/cursor-agent.md +14 -0
- package/extensions/dm-subagents/agents/delegate.md +3 -2
- package/extensions/dm-subagents/agents/oracle.md +10 -5
- package/extensions/dm-subagents/agents/researcher.md +2 -2
- package/extensions/dm-subagents/agents/reviewer.md +17 -7
- package/extensions/dm-subagents/agents/scout.md +5 -5
- package/extensions/dm-subagents/agents/worker.md +6 -2
- package/extensions/dm-subagents/async-retention-discovery-worker.mjs +167 -0
- package/extensions/dm-subagents/index.js +4 -0
- package/extensions/dm-subagents/inspector-runner.mjs +10 -0
- package/extensions/dm-subagents/install.mjs +3 -2
- package/extensions/dm-subagents/package.json +2 -2
- package/extensions/dm-subagents/prompts/council.md +60 -0
- package/extensions/dm-subagents/prompts/parallel-review.md +5 -1
- package/extensions/dm-subagents/prompts/review-loop.md +13 -7
- package/extensions/dm-subagents/skills/council-mode/SKILL.md +59 -0
- package/extensions/dm-subagents/skills/council-mode/references/pass-contracts.md +150 -0
- package/extensions/dm-subagents/skills/dm-subagents/SKILL.md +96 -911
- package/extensions/dm-subagents/skills/dm-subagents/references/constraints-and-recipes.md +70 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/execution-controls.md +539 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/management-authoring-rpc.md +161 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/multi-lane-orchestration.md +51 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/prompting-and-roles.md +295 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/review-and-validation.md +73 -0
- package/extensions/dm-subagents/src/agents/agent-management.js +716 -484
- package/extensions/dm-subagents/src/agents/agent-refinements.js +563 -0
- package/extensions/dm-subagents/src/agents/agent-serializer.js +70 -5
- package/extensions/dm-subagents/src/agents/agents.js +1447 -299
- package/extensions/dm-subagents/src/agents/builtin-names.js +15 -0
- package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -7
- package/extensions/dm-subagents/src/agents/frontmatter.js +64 -14
- package/extensions/dm-subagents/src/agents/identity.js +1 -1
- package/extensions/dm-subagents/src/agents/proactive-skills.js +14 -11
- package/extensions/dm-subagents/src/agents/runtime-agent-events.js +49 -0
- package/extensions/dm-subagents/src/agents/runtime-agent-registry.js +412 -0
- package/extensions/dm-subagents/src/agents/skills.js +52 -35
- package/extensions/dm-subagents/src/api/agents.js +6 -0
- package/extensions/dm-subagents/src/api/background-work.js +151 -0
- package/extensions/dm-subagents/src/api/capability-ceiling.js +12 -0
- package/extensions/dm-subagents/src/api/control-channel.js +3 -0
- package/extensions/dm-subagents/src/api/delegation.js +5 -0
- package/extensions/dm-subagents/src/api/dm-args.js +3 -0
- package/extensions/dm-subagents/src/api/external-job-provider.js +137 -0
- package/extensions/dm-subagents/src/api/external-runs.js +233 -0
- package/extensions/dm-subagents/src/api/intercom-bridge.js +3 -0
- package/extensions/dm-subagents/src/api/preflight.js +322 -0
- package/extensions/dm-subagents/src/api/project-panes.js +11 -0
- package/extensions/dm-subagents/src/api/shared-types.js +4 -0
- package/extensions/dm-subagents/src/extension/config.js +175 -0
- package/extensions/dm-subagents/src/extension/control-notices.js +4 -43
- package/extensions/dm-subagents/src/extension/doctor.js +71 -17
- package/extensions/dm-subagents/src/extension/fanout-child.js +49 -32
- package/extensions/dm-subagents/src/extension/index.js +711 -265
- package/extensions/dm-subagents/src/extension/public-execution.js +114 -0
- package/extensions/dm-subagents/src/extension/rpc.js +427 -22
- package/extensions/dm-subagents/src/extension/schemas.js +158 -65
- package/extensions/dm-subagents/src/extension/steering-notices.js +23 -0
- package/extensions/dm-subagents/src/extension/subagent-guide.js +31 -0
- package/extensions/dm-subagents/src/extension/tool-description.js +92 -74
- package/extensions/dm-subagents/src/extension/tool-result.js +7 -0
- package/extensions/dm-subagents/src/inspectors/herdr/actions.js +218 -0
- package/extensions/dm-subagents/src/inspectors/herdr/client.js +123 -0
- package/extensions/dm-subagents/src/inspectors/herdr/focus.js +47 -0
- package/extensions/dm-subagents/src/inspectors/herdr/inspector-runner.js +160 -0
- package/extensions/dm-subagents/src/inspectors/herdr/project-panes.js +618 -0
- package/extensions/dm-subagents/src/inspectors/herdr/session-roots-codec.js +21 -0
- package/extensions/dm-subagents/src/inspectors/herdr/shell-command.js +15 -0
- package/extensions/dm-subagents/src/integrations/herdr-status.js +377 -0
- package/extensions/dm-subagents/src/intercom/intercom-bridge.js +17 -13
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +371 -79
- package/extensions/dm-subagents/src/intercom/result-intercom.js +47 -7
- package/extensions/dm-subagents/src/missions/actions.js +394 -0
- package/extensions/dm-subagents/src/missions/goal-driver.js +149 -0
- package/extensions/dm-subagents/src/missions/lifecycle.js +331 -0
- package/extensions/dm-subagents/src/missions/store.js +548 -0
- package/extensions/dm-subagents/src/missions/types.js +9 -0
- package/extensions/dm-subagents/src/missions/workflow-state.js +245 -0
- package/extensions/dm-subagents/src/policy/authority.js +37 -0
- package/extensions/dm-subagents/src/profiles/profiles.js +36 -18
- package/extensions/dm-subagents/src/runs/background/active-async-capacity.js +427 -0
- package/extensions/dm-subagents/src/runs/background/active-run-index.js +122 -0
- package/extensions/dm-subagents/src/runs/background/async-execution.js +925 -137
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +515 -148
- package/extensions/dm-subagents/src/runs/background/async-resume.js +378 -51
- package/extensions/dm-subagents/src/runs/background/async-retention.js +828 -0
- package/extensions/dm-subagents/src/runs/background/async-status-snapshot.js +31 -0
- package/extensions/dm-subagents/src/runs/background/async-status.js +259 -22
- package/extensions/dm-subagents/src/runs/background/auto-drain.js +46 -0
- package/extensions/dm-subagents/src/runs/background/chain-append.js +50 -15
- package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +67 -12
- package/extensions/dm-subagents/src/runs/background/completion-batcher.js +5 -1
- package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +3 -11
- package/extensions/dm-subagents/src/runs/background/completion-replay.js +245 -0
- package/extensions/dm-subagents/src/runs/background/control-channel.js +423 -36
- package/extensions/dm-subagents/src/runs/background/fleet-view.js +132 -59
- package/extensions/dm-subagents/src/runs/background/index-segment.js +38 -0
- package/extensions/dm-subagents/src/runs/background/inspect-rpc.js +373 -0
- package/extensions/dm-subagents/src/runs/background/notify.js +357 -57
- package/extensions/dm-subagents/src/runs/background/owned-process-tree.js +86 -0
- package/extensions/dm-subagents/src/runs/background/process-terminal.js +269 -0
- package/extensions/dm-subagents/src/runs/background/result-delivery-ownership.js +34 -0
- package/extensions/dm-subagents/src/runs/background/result-files.js +469 -0
- package/extensions/dm-subagents/src/runs/background/result-watcher.js +540 -75
- package/extensions/dm-subagents/src/runs/background/resume-guidance.js +44 -0
- package/extensions/dm-subagents/src/runs/background/retained-children.js +119 -0
- package/extensions/dm-subagents/src/runs/background/run-id-query.js +5 -0
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +93 -9
- package/extensions/dm-subagents/src/runs/background/run-status.js +303 -32
- package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +784 -376
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +75 -34
- package/extensions/dm-subagents/src/runs/background/steering.js +221 -0
- package/extensions/dm-subagents/src/runs/background/subagent-runner.js +3106 -844
- package/extensions/dm-subagents/src/runs/background/subagent-wait.js +529 -0
- package/extensions/dm-subagents/src/runs/background/terminal-run-index.js +106 -0
- package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -1
- package/extensions/dm-subagents/src/runs/background/wait-completions.js +155 -0
- package/extensions/dm-subagents/src/runs/background/wait-config.js +46 -0
- package/extensions/dm-subagents/src/runs/background/wait-subscriptions.js +278 -0
- package/extensions/dm-subagents/src/runs/background/wait-tool.js +47 -0
- package/extensions/dm-subagents/src/runs/foreground/async-dismiss-action.js +81 -0
- package/extensions/dm-subagents/src/runs/foreground/async-steering-action.js +245 -0
- package/extensions/dm-subagents/src/runs/foreground/async-stop-action.js +74 -0
- package/extensions/dm-subagents/src/runs/foreground/execution.js +1401 -342
- package/extensions/dm-subagents/src/runs/foreground/foreground-control.js +133 -0
- package/extensions/dm-subagents/src/runs/foreground/foreground-history.js +148 -0
- package/extensions/dm-subagents/src/runs/foreground/prompt-audit.js +139 -0
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +4278 -1441
- package/extensions/dm-subagents/src/runs/foreground/workflow-detach-reconcile.js +278 -0
- package/extensions/dm-subagents/src/runs/foreground/workflow-foreground-steering.js +155 -0
- package/extensions/dm-subagents/src/runs/shared/abort-recovery.js +97 -0
- package/extensions/dm-subagents/src/runs/shared/acceptance.js +597 -148
- package/extensions/dm-subagents/src/runs/shared/agent-contract.js +35 -0
- package/extensions/dm-subagents/src/runs/shared/async-status-projection.js +472 -0
- package/extensions/dm-subagents/src/runs/shared/background-process-options.js +6 -0
- package/extensions/dm-subagents/src/runs/shared/capability-ceiling.js +175 -0
- package/extensions/dm-subagents/src/runs/shared/child-identity.js +32 -0
- package/extensions/dm-subagents/src/runs/shared/child-launch-plan.js +65 -0
- package/extensions/dm-subagents/src/runs/shared/child-protocol.js +447 -0
- package/extensions/dm-subagents/src/runs/shared/claude-code-adapter.js +120 -0
- package/extensions/dm-subagents/src/runs/shared/codex-exec-adapter.js +129 -0
- package/extensions/dm-subagents/src/runs/shared/completion-evidence.js +40 -0
- package/extensions/dm-subagents/src/runs/shared/completion-guard.js +140 -83
- package/extensions/dm-subagents/src/runs/shared/context-mode.js +38 -0
- package/extensions/dm-subagents/src/runs/shared/cursor-agent-adapter.js +101 -0
- package/extensions/dm-subagents/src/runs/shared/dm-args.js +445 -72
- package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +27 -16
- package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +19 -6
- package/extensions/dm-subagents/src/runs/shared/extension-bindings.js +81 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-contract.js +134 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-preflight.js +98 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-runner.js +419 -0
- package/extensions/dm-subagents/src/runs/shared/external-job-bridge.js +404 -0
- package/extensions/dm-subagents/src/runs/shared/external-job-runner.js +334 -0
- package/extensions/dm-subagents/src/runs/shared/fast-mode-extension.js +8 -0
- package/extensions/dm-subagents/src/runs/shared/host-step-status.js +228 -0
- package/extensions/dm-subagents/src/runs/shared/lane-metadata.js +104 -0
- package/extensions/dm-subagents/src/runs/shared/launch-cwd.js +17 -0
- package/extensions/dm-subagents/src/runs/shared/llm-intent-arbiter.js +190 -0
- package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +48 -3
- package/extensions/dm-subagents/src/runs/shared/mcp-config-sources.js +387 -0
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +212 -137
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-grant.js +131 -0
- package/extensions/dm-subagents/src/runs/shared/model-exclusions.js +207 -0
- package/extensions/dm-subagents/src/runs/shared/model-fallback.js +225 -55
- package/extensions/dm-subagents/src/runs/shared/model-scope.js +85 -28
- package/extensions/dm-subagents/src/runs/shared/mutation-evidence.js +182 -0
- package/extensions/dm-subagents/src/runs/shared/nested-events.js +264 -102
- package/extensions/dm-subagents/src/runs/shared/nested-render.js +15 -5
- package/extensions/dm-subagents/src/runs/shared/orca-progress-tabs.js +505 -0
- package/extensions/dm-subagents/src/runs/shared/parallel-handoff.js +653 -0
- package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +29 -12
- package/extensions/dm-subagents/src/runs/shared/permissions.js +108 -0
- package/extensions/dm-subagents/src/runs/shared/process-signal.js +13 -0
- package/extensions/dm-subagents/src/runs/shared/run-fanout-budget.js +257 -0
- package/extensions/dm-subagents/src/runs/shared/run-history.js +133 -13
- package/extensions/dm-subagents/src/runs/shared/runtime-acknowledged-extensions.js +62 -0
- package/extensions/dm-subagents/src/runs/shared/session-lease.js +225 -0
- package/extensions/dm-subagents/src/runs/shared/single-output.js +129 -27
- package/extensions/dm-subagents/src/runs/shared/spawn-budget.js +95 -0
- package/extensions/dm-subagents/src/runs/shared/structured-output.js +129 -10
- package/extensions/dm-subagents/src/runs/shared/subagent-control.js +66 -11
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +548 -70
- package/extensions/dm-subagents/src/runs/shared/subagent-startup-retry.js +50 -0
- package/extensions/dm-subagents/src/runs/shared/task-intent.js +130 -0
- package/extensions/dm-subagents/src/runs/shared/tool-availability.js +59 -0
- package/extensions/dm-subagents/src/runs/shared/tool-budget.js +7 -5
- package/extensions/dm-subagents/src/runs/shared/tool-timeout.js +64 -0
- package/extensions/dm-subagents/src/runs/shared/usage-budget.js +74 -0
- package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +22 -0
- package/extensions/dm-subagents/src/runs/shared/worktree-cleanup-plan.js +721 -0
- package/extensions/dm-subagents/src/runs/shared/worktree.js +168 -19
- package/extensions/dm-subagents/src/shared/accessible-dir.js +35 -0
- package/extensions/dm-subagents/src/shared/agent-stream-options.js +3 -0
- package/extensions/dm-subagents/src/shared/artifacts.js +170 -11
- package/extensions/dm-subagents/src/shared/atomic-json.js +36 -38
- package/extensions/dm-subagents/src/shared/capacity-resilient-json.js +77 -0
- package/extensions/dm-subagents/src/shared/child-session-name.js +15 -0
- package/extensions/dm-subagents/src/shared/child-transcript.js +57 -2
- package/extensions/dm-subagents/src/shared/completion-owner.js +7 -0
- package/extensions/dm-subagents/src/shared/display-text.js +142 -0
- package/extensions/dm-subagents/src/shared/extension-context.js +17 -0
- package/extensions/dm-subagents/src/shared/file-coalescer.js +9 -0
- package/extensions/dm-subagents/src/shared/file-system-retry.js +56 -0
- package/extensions/dm-subagents/src/shared/fork-context.js +96 -33
- package/extensions/dm-subagents/src/shared/formatters.js +21 -7
- package/extensions/dm-subagents/src/shared/launch-contract.js +94 -0
- package/extensions/dm-subagents/src/shared/model-info.js +10 -5
- package/extensions/dm-subagents/src/shared/node-executable.js +19 -0
- package/extensions/dm-subagents/src/shared/prompt-resources.js +10 -0
- package/extensions/dm-subagents/src/shared/pruned-fork.js +427 -0
- package/extensions/dm-subagents/src/shared/session-file-trust.js +19 -0
- package/extensions/dm-subagents/src/shared/session-tokens.js +14 -3
- package/extensions/dm-subagents/src/shared/settings.js +39 -47
- package/extensions/dm-subagents/src/shared/shortcuts.js +16 -0
- package/extensions/dm-subagents/src/shared/status-format.js +9 -2
- package/extensions/dm-subagents/src/shared/thinking-ceiling.js +41 -0
- package/extensions/dm-subagents/src/shared/types.js +47 -7
- package/extensions/dm-subagents/src/shared/utf8.js +12 -0
- package/extensions/dm-subagents/src/shared/utils.js +151 -131
- package/extensions/dm-subagents/src/shared/watch-strategy.js +3 -0
- package/extensions/dm-subagents/src/shared/workflow-child-permit.js +84 -0
- package/extensions/dm-subagents/src/slash/delegation-adapters.js +274 -0
- package/extensions/dm-subagents/src/slash/delegation-json.js +113 -0
- package/extensions/dm-subagents/src/slash/delegation-request.js +152 -0
- package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +294 -243
- package/extensions/dm-subagents/src/slash/prompt-workflows.js +35 -73
- package/extensions/dm-subagents/src/slash/selector.js +101 -0
- package/extensions/dm-subagents/src/slash/slash-bridge.js +17 -1
- package/extensions/dm-subagents/src/slash/slash-commands.js +722 -732
- package/extensions/dm-subagents/src/slash/slash-live-state.js +37 -19
- package/extensions/dm-subagents/src/slash/subagents-admin.js +410 -0
- package/extensions/dm-subagents/src/tui/fleet-status.js +824 -0
- package/extensions/dm-subagents/src/tui/fleet-transcript.js +479 -0
- package/extensions/dm-subagents/src/tui/fleet.js +1326 -0
- package/extensions/dm-subagents/src/tui/render-helpers.js +22 -0
- package/extensions/dm-subagents/src/tui/render.js +1511 -261
- package/extensions/dm-subagents/src/watchdog/change-signature.js +220 -0
- package/extensions/dm-subagents/src/watchdog/child-status.js +151 -0
- package/extensions/dm-subagents/src/watchdog/emission-guard.js +90 -0
- package/extensions/dm-subagents/src/watchdog/lsp-diagnostics.js +484 -0
- package/extensions/dm-subagents/src/watchdog/model-selection.js +154 -0
- package/extensions/dm-subagents/src/watchdog/permission-arbiter.js +138 -0
- package/extensions/dm-subagents/src/watchdog/register-child.js +112 -0
- package/extensions/dm-subagents/src/watchdog/register-main.js +419 -0
- package/extensions/dm-subagents/src/watchdog/render.js +54 -0
- package/extensions/dm-subagents/src/watchdog/review.js +251 -0
- package/extensions/dm-subagents/src/watchdog/runtime.js +803 -0
- package/extensions/dm-subagents/src/watchdog/scope.js +56 -0
- package/extensions/dm-subagents/src/watchdog/settings.js +515 -0
- package/extensions/dm-subagents/src/watchdog/tool-actions.js +151 -0
- package/extensions/dm-subagents/src/watchdog/turn-delta.js +169 -0
- package/extensions/dm-subagents/src/watchdog/types.js +29 -0
- package/extensions/dm-subagents/src/watchdog/warning-format.js +58 -0
- package/extensions/dm-subagents/src/workflows/chat-progress.js +116 -0
- package/extensions/dm-subagents/src/workflows/host-command.js +227 -0
- package/extensions/dm-subagents/src/workflows/scripted-workflow.js +2011 -0
- package/extensions/dm-subagents/src/workflows/workflow-child-summary.js +116 -0
- package/extensions/dm-subagents/src/workflows/workflow-preflight.js +243 -0
- package/extensions/dm-subagents/src/workflows/workflow-receipt.js +387 -0
- package/extensions/dm-subagents/src/workflows/workflow-settlement.js +189 -0
- package/package.json +4 -3
- package/extensions/dm-fff/package.json +0 -21
- package/extensions/dm-fff/src/index.js +0 -691
- package/extensions/dm-fff/src/query.js +0 -60
- package/extensions/dm-subagents/agents/context-builder.md +0 -46
- package/extensions/dm-subagents/agents/planner.md +0 -55
- package/extensions/dm-subagents/prompts/parallel-context-build.md +0 -55
- package/extensions/dm-subagents/prompts/parallel-handoff-plan.md +0 -61
- package/extensions/dm-subagents/src/runs/background/wait.js +0 -206
- package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +0 -1013
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +0 -981
- package/extensions/dm-subagents/src/runs/shared/turn-budget.js +0 -50
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
const KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
2
|
+
const TERMINAL_STATES = new Set(["completed", "failed", "paused", "stopped", "rejected", "detached"]);
|
|
3
|
+
const MAX_REQUIRED_ID_BYTES = 4096;
|
|
4
|
+
function bounded(value, maxBytes) {
|
|
5
|
+
if (typeof value !== "string" || !value.trim() || Buffer.byteLength(value, "utf8") > maxBytes)
|
|
6
|
+
return;
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
function requiredId(value, label) {
|
|
10
|
+
const id = bounded(value, MAX_REQUIRED_ID_BYTES);
|
|
11
|
+
if (!id)
|
|
12
|
+
throw new Error(`${label} must be a non-empty identifier of at most ${MAX_REQUIRED_ID_BYTES} UTF-8 bytes.`);
|
|
13
|
+
return id;
|
|
14
|
+
}
|
|
15
|
+
export function workflowChildSummary(input) {
|
|
16
|
+
const rows = new Map;
|
|
17
|
+
for (const entry of input.trace ?? []) {
|
|
18
|
+
if (entry.operation !== "run" || !KEY_PATTERN.test(entry.key))
|
|
19
|
+
continue;
|
|
20
|
+
const previous = rows.get(entry.key);
|
|
21
|
+
const state = entry.state === "completed" ? "completed" : entry.state === "failed" ? "failed" : entry.state === "stopped" ? "stopped" : entry.state === "detached" ? "detached" : previous?.state ?? "running";
|
|
22
|
+
rows.set(entry.key, {
|
|
23
|
+
childId: entry.key,
|
|
24
|
+
state,
|
|
25
|
+
...bounded(entry.runId, 256) ? { runId: bounded(entry.runId, 256) } : {},
|
|
26
|
+
...previous?.agent ? { agent: previous.agent } : {},
|
|
27
|
+
...previous?.sessionName ? { sessionName: previous.sessionName } : {},
|
|
28
|
+
...previous?.model ? { model: previous.model } : {},
|
|
29
|
+
...previous?.thinking ? { thinking: previous.thinking } : {}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
for (const step of input.steps ?? []) {
|
|
33
|
+
const key = step.workflowKey;
|
|
34
|
+
if (!key || !KEY_PATTERN.test(key))
|
|
35
|
+
continue;
|
|
36
|
+
const state = step.status === "complete" || step.status === "completed" ? "completed" : step.status === "failed" ? "failed" : step.status === "paused" ? "paused" : step.status === "stopped" ? "stopped" : step.status === "rejected" ? "rejected" : step.status === "pending" ? "pending" : "running";
|
|
37
|
+
const launchResolved = step.async !== undefined || step.sessionFile !== undefined || step.runId !== undefined || step.model !== undefined;
|
|
38
|
+
rows.set(key, {
|
|
39
|
+
childId: key,
|
|
40
|
+
state,
|
|
41
|
+
...bounded(step.runId, 256) ? { runId: bounded(step.runId, 256) } : {},
|
|
42
|
+
...launchResolved && bounded(step.agent, 256) ? { agent: bounded(step.agent, 256) } : {},
|
|
43
|
+
...bounded(step.sessionName, 256) ? { sessionName: bounded(step.sessionName, 256) } : {},
|
|
44
|
+
...bounded(step.model, 256) ? { model: bounded(step.model, 256) } : {},
|
|
45
|
+
...bounded(step.thinking, 32) ? { thinking: bounded(step.thinking, 32) } : {}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
for (const child of input.children ?? []) {
|
|
49
|
+
if (!KEY_PATTERN.test(child.key))
|
|
50
|
+
continue;
|
|
51
|
+
const result = Array.isArray(child.results) ? child.results.find((value) => value && typeof value === "object") : undefined;
|
|
52
|
+
const state = child.detached ? "detached" : child.stopped ? "stopped" : child.interrupted ? "paused" : child.ok ? "completed" : result?.acceptance && typeof result.acceptance === "object" && result.acceptance.status === "rejected" ? "rejected" : "failed";
|
|
53
|
+
rows.set(child.key, {
|
|
54
|
+
childId: child.key,
|
|
55
|
+
state,
|
|
56
|
+
...bounded(child.runId, 256) ? { runId: bounded(child.runId, 256) } : {},
|
|
57
|
+
...bounded(child.agent, 256) ? { agent: bounded(child.agent, 256) } : {},
|
|
58
|
+
...bounded(result?.sessionName, 256) ? { sessionName: bounded(result?.sessionName, 256) } : {},
|
|
59
|
+
...bounded(result?.model, 256) ? { model: bounded(result?.model, 256) } : {},
|
|
60
|
+
...bounded(result?.thinking, 32) ? { thinking: bounded(result?.thinking, 32) } : {}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (input.inventoryComplete) {
|
|
64
|
+
for (const [key, row] of rows) {
|
|
65
|
+
if (!TERMINAL_STATES.has(row.state))
|
|
66
|
+
rows.set(key, { ...row, state: input.workflowState === "stopped" ? "stopped" : "failed" });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
version: 1,
|
|
71
|
+
parentToolCallId: requiredId(input.parentToolCallId, "parentToolCallId"),
|
|
72
|
+
workflowRunId: requiredId(input.workflowRunId, "workflowRunId"),
|
|
73
|
+
inventoryComplete: input.inventoryComplete,
|
|
74
|
+
workflowState: input.workflowState,
|
|
75
|
+
children: [...rows.values()]
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export function parseWorkflowChildSummary(value) {
|
|
79
|
+
if (value === undefined)
|
|
80
|
+
return;
|
|
81
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
82
|
+
throw new Error("workflowChildren must be an object.");
|
|
83
|
+
const input = value;
|
|
84
|
+
const allowed = new Set(["version", "parentToolCallId", "workflowRunId", "inventoryComplete", "workflowState", "children"]);
|
|
85
|
+
if (Object.keys(input).some((key) => !allowed.has(key)))
|
|
86
|
+
throw new Error("workflowChildren has unsupported fields.");
|
|
87
|
+
if (input.version !== 1 || typeof input.inventoryComplete !== "boolean" || !Array.isArray(input.children))
|
|
88
|
+
throw new Error("workflowChildren is invalid.");
|
|
89
|
+
const workflowState = input.workflowState;
|
|
90
|
+
if (workflowState !== "queued" && workflowState !== "running" && workflowState !== "completed" && workflowState !== "failed" && workflowState !== "paused" && workflowState !== "stopped")
|
|
91
|
+
throw new Error("workflowChildren.workflowState is invalid.");
|
|
92
|
+
const children = input.children.map((row) => {
|
|
93
|
+
if (!row || typeof row !== "object" || Array.isArray(row))
|
|
94
|
+
throw new Error("workflowChildren child row is invalid.");
|
|
95
|
+
const child = row;
|
|
96
|
+
if (Object.keys(child).some((key) => !["childId", "runId", "agent", "sessionName", "model", "thinking", "state"].includes(key)))
|
|
97
|
+
throw new Error("workflowChildren child row has unsupported fields.");
|
|
98
|
+
if (typeof child.childId !== "string" || !KEY_PATTERN.test(child.childId))
|
|
99
|
+
throw new Error("workflowChildren childId is invalid.");
|
|
100
|
+
const state = child.state;
|
|
101
|
+
if (state !== "pending" && state !== "running" && state !== "completed" && state !== "failed" && state !== "paused" && state !== "stopped" && state !== "rejected" && state !== "detached")
|
|
102
|
+
throw new Error("workflowChildren child state is invalid.");
|
|
103
|
+
for (const [field, maxBytes] of [["runId", 256], ["agent", 256], ["sessionName", 256], ["model", 256], ["thinking", 32]]) {
|
|
104
|
+
if (child[field] !== undefined && bounded(child[field], maxBytes) === undefined)
|
|
105
|
+
throw new Error(`workflowChildren child ${field} is invalid.`);
|
|
106
|
+
}
|
|
107
|
+
return { childId: child.childId, state, ...child.runId ? { runId: child.runId } : {}, ...child.agent ? { agent: child.agent } : {}, ...child.sessionName ? { sessionName: child.sessionName } : {}, ...child.model ? { model: child.model } : {}, ...child.thinking ? { thinking: child.thinking } : {} };
|
|
108
|
+
});
|
|
109
|
+
if (new Set(children.map((child) => child.childId)).size !== children.length)
|
|
110
|
+
throw new Error("workflowChildren has duplicate childId values.");
|
|
111
|
+
if (typeof input.parentToolCallId !== "string")
|
|
112
|
+
throw new Error("workflowChildren.parentToolCallId is invalid.");
|
|
113
|
+
if (typeof input.workflowRunId !== "string")
|
|
114
|
+
throw new Error("workflowChildren.workflowRunId is invalid.");
|
|
115
|
+
return { version: 1, parentToolCallId: requiredId(input.parentToolCallId, "parentToolCallId"), workflowRunId: requiredId(input.workflowRunId, "workflowRunId"), inventoryComplete: input.inventoryComplete, workflowState, children };
|
|
116
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
export const WORKFLOW_PREFLIGHT_VERSION = 1;
|
|
2
|
+
export const WORKFLOW_PREFLIGHT_MAX_LANES = 64;
|
|
3
|
+
export const WORKFLOW_PREFLIGHT_MAX_STRING_LENGTH = 256;
|
|
4
|
+
export const WORKFLOW_PREFLIGHT_MAX_CLAIMS = 16;
|
|
5
|
+
export const WORKFLOW_PREFLIGHT_MAX_DEPTH = 3;
|
|
6
|
+
export const WORKFLOW_PREFLIGHT_MAX_BYTES = 16 * 1024;
|
|
7
|
+
export const WORKFLOW_PREFLIGHT_MAX_WARNINGS = 16;
|
|
8
|
+
const WORKFLOW_KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
9
|
+
const PREFLIGHT_FIELDS = new Set(["version", "coverage", "lanes"]);
|
|
10
|
+
const LANE_FIELDS = new Set(["key", "mode", "decision", "claims", "expectedOutput", "independence"]);
|
|
11
|
+
const PREFLIGHT_MODES = new Set(["mutation", "review", "scout", "gate"]);
|
|
12
|
+
function isPlainObject(value) {
|
|
13
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
14
|
+
return false;
|
|
15
|
+
const prototype = Object.getPrototypeOf(value);
|
|
16
|
+
return prototype === Object.prototype || prototype === null;
|
|
17
|
+
}
|
|
18
|
+
function assertPlainObject(value, path) {
|
|
19
|
+
if (!isPlainObject(value))
|
|
20
|
+
throw new Error(`${path} must be a plain JSON object.`);
|
|
21
|
+
if (Object.getOwnPropertySymbols(value).length > 0)
|
|
22
|
+
throw new Error(`${path} must not contain symbol keys.`);
|
|
23
|
+
for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
|
|
24
|
+
if (!descriptor.enumerable || !("value" in descriptor))
|
|
25
|
+
throw new Error(`${path}.${key} must be an enumerable data property.`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function assertKnownFields(value, allowed, path) {
|
|
29
|
+
for (const key of Object.keys(value)) {
|
|
30
|
+
if (!allowed.has(key))
|
|
31
|
+
throw new Error(`${path} contains unsupported field '${key}'.`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function normalizeDisplayString(value, path) {
|
|
35
|
+
if (typeof value !== "string")
|
|
36
|
+
throw new Error(`${path} must be a string.`);
|
|
37
|
+
const normalized = value.replace(/[\u0000-\u001f\u007f]/g, " ").replace(/\s+/g, " ").trim();
|
|
38
|
+
if (!normalized)
|
|
39
|
+
throw new Error(`${path} must be a non-empty string.`);
|
|
40
|
+
if (normalized.length > WORKFLOW_PREFLIGHT_MAX_STRING_LENGTH) {
|
|
41
|
+
throw new Error(`${path} exceeds the maximum length of ${WORKFLOW_PREFLIGHT_MAX_STRING_LENGTH}.`);
|
|
42
|
+
}
|
|
43
|
+
return normalized;
|
|
44
|
+
}
|
|
45
|
+
function normalizeLane(value, index) {
|
|
46
|
+
const path = `preflight.lanes[${index}]`;
|
|
47
|
+
assertPlainObject(value, path);
|
|
48
|
+
assertKnownFields(value, LANE_FIELDS, path);
|
|
49
|
+
const key = normalizeDisplayString(value.key, `${path}.key`);
|
|
50
|
+
if (!WORKFLOW_KEY_PATTERN.test(key))
|
|
51
|
+
throw new Error(`${path}.key must be 1-128 characters using letters, numbers, '.', '_' or '-', and start with a letter or number.`);
|
|
52
|
+
let mode;
|
|
53
|
+
if (value.mode !== undefined) {
|
|
54
|
+
if (typeof value.mode !== "string" || !PREFLIGHT_MODES.has(value.mode)) {
|
|
55
|
+
throw new Error(`${path}.mode must be one of: mutation, review, scout, gate.`);
|
|
56
|
+
}
|
|
57
|
+
mode = value.mode;
|
|
58
|
+
}
|
|
59
|
+
let claims;
|
|
60
|
+
if (value.claims !== undefined) {
|
|
61
|
+
if (!Array.isArray(value.claims))
|
|
62
|
+
throw new Error(`${path}.claims must be an array of strings.`);
|
|
63
|
+
if (value.claims.length > WORKFLOW_PREFLIGHT_MAX_CLAIMS)
|
|
64
|
+
throw new Error(`${path}.claims supports at most ${WORKFLOW_PREFLIGHT_MAX_CLAIMS} entries.`);
|
|
65
|
+
claims = value.claims.map((claim, claimIndex) => normalizeDisplayString(claim, `${path}.claims[${claimIndex}]`));
|
|
66
|
+
for (let claimIndex = 0;claimIndex < value.claims.length; claimIndex += 1) {
|
|
67
|
+
if (!Object.prototype.hasOwnProperty.call(value.claims, claimIndex))
|
|
68
|
+
throw new Error(`${path}.claims must not contain sparse arrays.`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
key,
|
|
73
|
+
...mode ? { mode } : {},
|
|
74
|
+
...value.decision !== undefined ? { decision: normalizeDisplayString(value.decision, `${path}.decision`) } : {},
|
|
75
|
+
...claims ? { claims } : {},
|
|
76
|
+
...value.expectedOutput !== undefined ? { expectedOutput: normalizeDisplayString(value.expectedOutput, `${path}.expectedOutput`) } : {},
|
|
77
|
+
...value.independence !== undefined ? { independence: normalizeDisplayString(value.independence, `${path}.independence`) } : {}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function normalizeWorkflowPreflight(input) {
|
|
81
|
+
if (input === undefined)
|
|
82
|
+
return;
|
|
83
|
+
assertPlainObject(input, "preflight");
|
|
84
|
+
assertKnownFields(input, PREFLIGHT_FIELDS, "preflight");
|
|
85
|
+
if (input.version !== WORKFLOW_PREFLIGHT_VERSION)
|
|
86
|
+
throw new Error(`preflight.version must be ${WORKFLOW_PREFLIGHT_VERSION}.`);
|
|
87
|
+
const coverage = input.coverage === undefined ? "partial" : input.coverage;
|
|
88
|
+
if (coverage !== "complete" && coverage !== "partial")
|
|
89
|
+
throw new Error("preflight.coverage must be 'complete' or 'partial'.");
|
|
90
|
+
if (!Array.isArray(input.lanes))
|
|
91
|
+
throw new Error("preflight.lanes must be an array.");
|
|
92
|
+
if (input.lanes.length > WORKFLOW_PREFLIGHT_MAX_LANES)
|
|
93
|
+
throw new Error(`preflight.lanes supports at most ${WORKFLOW_PREFLIGHT_MAX_LANES} lanes.`);
|
|
94
|
+
for (let index = 0;index < input.lanes.length; index += 1) {
|
|
95
|
+
if (!Object.prototype.hasOwnProperty.call(input.lanes, index))
|
|
96
|
+
throw new Error("preflight.lanes must not contain sparse arrays.");
|
|
97
|
+
}
|
|
98
|
+
const lanes = input.lanes.map(normalizeLane);
|
|
99
|
+
const seenKeys = new Set;
|
|
100
|
+
for (const lane of lanes) {
|
|
101
|
+
if (seenKeys.has(lane.key))
|
|
102
|
+
throw new Error(`preflight.lanes contains duplicate key '${lane.key}'.`);
|
|
103
|
+
seenKeys.add(lane.key);
|
|
104
|
+
}
|
|
105
|
+
const normalized = { version: WORKFLOW_PREFLIGHT_VERSION, coverage, lanes };
|
|
106
|
+
const depth = 1 + (lanes.length > 0 ? 1 : 0) + (lanes.some((lane) => lane.claims !== undefined) ? 1 : 0);
|
|
107
|
+
if (depth > WORKFLOW_PREFLIGHT_MAX_DEPTH)
|
|
108
|
+
throw new Error(`preflight exceeds the maximum nesting depth of ${WORKFLOW_PREFLIGHT_MAX_DEPTH}.`);
|
|
109
|
+
const bytes = Buffer.byteLength(JSON.stringify(normalized), "utf8");
|
|
110
|
+
if (bytes > WORKFLOW_PREFLIGHT_MAX_BYTES)
|
|
111
|
+
throw new Error(`preflight canonical JSON is ${bytes} bytes; maximum is ${WORKFLOW_PREFLIGHT_MAX_BYTES}.`);
|
|
112
|
+
return normalized;
|
|
113
|
+
}
|
|
114
|
+
export function validateWorkflowPreflight(input) {
|
|
115
|
+
try {
|
|
116
|
+
const preflight = normalizeWorkflowPreflight(input);
|
|
117
|
+
return { ok: true, ...preflight ? { preflight } : {} };
|
|
118
|
+
} catch (error) {
|
|
119
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function warningLimit(messages) {
|
|
123
|
+
if (messages.length <= WORKFLOW_PREFLIGHT_MAX_WARNINGS)
|
|
124
|
+
return messages;
|
|
125
|
+
const omitted = messages.length - WORKFLOW_PREFLIGHT_MAX_WARNINGS + 1;
|
|
126
|
+
return [...messages.slice(0, WORKFLOW_PREFLIGHT_MAX_WARNINGS - 1), `Preflight advisory: ${omitted} additional mismatch warning(s) omitted.`];
|
|
127
|
+
}
|
|
128
|
+
function declaredKeys(preflight) {
|
|
129
|
+
return new Set(preflight.lanes.map((lane) => lane.key));
|
|
130
|
+
}
|
|
131
|
+
function declaredLaneCoversWorkflowKey(entry, laneKey) {
|
|
132
|
+
return entry.key === laneKey || entry.key.startsWith(`${laneKey}.`);
|
|
133
|
+
}
|
|
134
|
+
function keyCoveredByDeclaredLane(entry, declared) {
|
|
135
|
+
for (const laneKey of declared)
|
|
136
|
+
if (declaredLaneCoversWorkflowKey(entry, laneKey))
|
|
137
|
+
return true;
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
function launchedEntries(trace) {
|
|
141
|
+
const entries = [];
|
|
142
|
+
const seen = new Set;
|
|
143
|
+
for (const entry of trace) {
|
|
144
|
+
if (entry.operation !== "run" || entry.phase === "auto-resume" || seen.has(entry.key))
|
|
145
|
+
continue;
|
|
146
|
+
seen.add(entry.key);
|
|
147
|
+
entries.push(entry);
|
|
148
|
+
}
|
|
149
|
+
return entries;
|
|
150
|
+
}
|
|
151
|
+
function undeclaredWarning(key) {
|
|
152
|
+
return `Preflight advisory: workflow key '${key}' launched without a declared lane.`;
|
|
153
|
+
}
|
|
154
|
+
function unlaunchedWarning(key) {
|
|
155
|
+
return `Preflight advisory: declared lane '${key}' was not launched.`;
|
|
156
|
+
}
|
|
157
|
+
export function workflowPreflightWarnings(preflight, trace, options = {}) {
|
|
158
|
+
if (!preflight)
|
|
159
|
+
return [];
|
|
160
|
+
const declared = declaredKeys(preflight);
|
|
161
|
+
const launched = launchedEntries(trace);
|
|
162
|
+
const messages = launched.filter((entry) => !keyCoveredByDeclaredLane(entry, declared)).map((entry) => undeclaredWarning(entry.key));
|
|
163
|
+
if (options.settled === true) {
|
|
164
|
+
for (const lane of preflight.lanes)
|
|
165
|
+
if (!launched.some((entry) => declaredLaneCoversWorkflowKey(entry, lane.key)))
|
|
166
|
+
messages.push(unlaunchedWarning(lane.key));
|
|
167
|
+
}
|
|
168
|
+
return warningLimit(messages);
|
|
169
|
+
}
|
|
170
|
+
export function annotateWorkflowPreflightTrace(trace, preflight) {
|
|
171
|
+
if (!preflight)
|
|
172
|
+
return [...trace];
|
|
173
|
+
const declared = declaredKeys(preflight);
|
|
174
|
+
const warned = new Set;
|
|
175
|
+
return trace.map((entry) => {
|
|
176
|
+
if (entry.operation !== "run" || entry.phase === "auto-resume" || keyCoveredByDeclaredLane(entry, declared) || warned.has(entry.key))
|
|
177
|
+
return entry;
|
|
178
|
+
warned.add(entry.key);
|
|
179
|
+
return { ...entry, warning: entry.warning ?? undeclaredWarning(entry.key) };
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
function laneCell(value) {
|
|
183
|
+
return value ?? "—";
|
|
184
|
+
}
|
|
185
|
+
const WORKFLOW_PREFLIGHT_PLAN_LABEL_LENGTH = 96;
|
|
186
|
+
function planLaneLabel(lane) {
|
|
187
|
+
const value = lane.decision?.trim() || lane.key;
|
|
188
|
+
if (value.length <= WORKFLOW_PREFLIGHT_PLAN_LABEL_LENGTH)
|
|
189
|
+
return value;
|
|
190
|
+
return `${value.slice(0, WORKFLOW_PREFLIGHT_PLAN_LABEL_LENGTH - 1).trimEnd()}…`;
|
|
191
|
+
}
|
|
192
|
+
export function formatWorkflowPreflight(preflight, options = {}) {
|
|
193
|
+
if (!preflight)
|
|
194
|
+
return "";
|
|
195
|
+
const indent = options.indent ?? "";
|
|
196
|
+
const count = preflight.lanes.length;
|
|
197
|
+
const lines = [
|
|
198
|
+
`${indent}Preflight: v${preflight.version} · ${preflight.coverage} · ${count} lane${count === 1 ? "" : "s"}`,
|
|
199
|
+
`${indent} key | mode | decision | claims | expected output | independence`
|
|
200
|
+
];
|
|
201
|
+
for (const lane of preflight.lanes) {
|
|
202
|
+
lines.push(`${indent} ${[
|
|
203
|
+
lane.key,
|
|
204
|
+
laneCell(lane.mode),
|
|
205
|
+
laneCell(lane.decision),
|
|
206
|
+
lane.claims?.join(", ") ?? "—",
|
|
207
|
+
laneCell(lane.expectedOutput),
|
|
208
|
+
laneCell(lane.independence)
|
|
209
|
+
].join(" | ")}`);
|
|
210
|
+
}
|
|
211
|
+
return lines.join(`
|
|
212
|
+
`);
|
|
213
|
+
}
|
|
214
|
+
export function formatWorkflowPreflightSummary(preflight) {
|
|
215
|
+
if (!preflight)
|
|
216
|
+
return "";
|
|
217
|
+
const keys = preflight.lanes.slice(0, 4).map((lane) => lane.key).join(", ");
|
|
218
|
+
const remainder = preflight.lanes.length > 4 ? `, +${preflight.lanes.length - 4}` : "";
|
|
219
|
+
return `preflight · ${preflight.coverage} · ${preflight.lanes.length} lane${preflight.lanes.length === 1 ? "" : "s"}${keys ? `: ${keys}${remainder}` : ""}`;
|
|
220
|
+
}
|
|
221
|
+
export function formatWorkflowPreflightPlanSummary(preflight, options = {}) {
|
|
222
|
+
if (!preflight)
|
|
223
|
+
return "";
|
|
224
|
+
const indent = options.indent ?? "";
|
|
225
|
+
const count = preflight.lanes.length;
|
|
226
|
+
const labels = count === 1 ? planLaneLabel(preflight.lanes[0]) : preflight.lanes.slice(0, 4).map((lane) => lane.key).join(", ") + (count > 4 ? `, +${count - 4}` : "");
|
|
227
|
+
return `${indent}Plan: ${count} lane${count === 1 ? "" : "s"}${labels ? ` · ${labels}` : ""}`;
|
|
228
|
+
}
|
|
229
|
+
export function formatWorkflowPreflightWarningSummary(warnings, options = {}) {
|
|
230
|
+
if (!warnings?.length)
|
|
231
|
+
return "";
|
|
232
|
+
const indent = options.indent ?? "";
|
|
233
|
+
const hint = options.hint ?? "details available for debug";
|
|
234
|
+
const count = warnings.length;
|
|
235
|
+
return `${indent}Plan note: ${count} preflight mismatch${count === 1 ? "" : "es"} · ${hint}.`;
|
|
236
|
+
}
|
|
237
|
+
export function formatWorkflowPreflightWarnings(warnings, options = {}) {
|
|
238
|
+
if (!warnings?.length)
|
|
239
|
+
return "";
|
|
240
|
+
const indent = options.indent ?? "";
|
|
241
|
+
return [`${indent}Preflight warnings:`, ...warnings.map((warning) => `${indent} - ${warning.replace(/\s+/g, " ").trim()}`)].join(`
|
|
242
|
+
`);
|
|
243
|
+
}
|