@tea-agent/loop-agent 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +10 -2
- package/CHANGELOG.md +67 -25
- package/README.md +82 -11
- package/dist/application/dag/args.js +1 -12
- package/dist/application/dag/generate-task-dag.js +23 -2
- package/dist/application/dag/run-dag.js +1 -27
- package/dist/application/dag/validate-dag.js +2 -2
- package/dist/application/loop/run-action.js +0 -4
- package/dist/cli/command-definitions.js +44 -16
- package/dist/cli/program.js +40 -23
- package/dist/cli/update/notifier.js +117 -0
- package/dist/cli/update/npm-client.js +151 -0
- package/dist/cli/update/policy.js +58 -0
- package/dist/cli/update/state.js +68 -0
- package/dist/cli.js +33 -0
- package/dist/commands/cursor-prompt.js +42 -82
- package/dist/commands/dag-approve.js +36 -0
- package/dist/commands/delegate.js +75 -77
- package/dist/commands/doctor.js +0 -18
- package/dist/commands/init.js +476 -91
- package/dist/commands/instructions.js +7 -10
- package/dist/commands/loop.js +4 -20
- package/dist/commands/plan.js +50 -0
- package/dist/executors/config-core.js +0 -51
- package/dist/executors/dag-pi-executor.js +1 -1
- package/dist/executors/dag.js +0 -1
- package/dist/executors/index.js +0 -2
- package/dist/executors/model-routing.js +9 -9
- package/dist/executors/shell-executor.js +1 -1
- package/dist/governance/checks.js +6 -3
- package/dist/governance/exec-plans.js +545 -0
- package/dist/governance/manifest-types.js +24 -2
- package/dist/infrastructure/harness/loop-action-store.js +0 -3
- package/dist/records/harvest.js +2 -23
- package/dist/records/one-shot-runs.js +1 -1
- package/dist/shared/artifacts-core.js +24 -5
- package/dist/shared/output-truncation.js +37 -0
- package/dist/shared/package-metadata.js +353 -0
- package/dist/{executors/cursor-executor.js → sidecars/cursor-prompt/executor.js} +2 -42
- package/dist/sidecars/cursor-prompt/index.js +3 -0
- package/dist/sidecars/cursor-prompt/stream.js +121 -0
- package/dist/task/config-types.js +28 -12
- package/dist/task/delegate.js +9 -21
- package/dist/task/runtime.js +1 -2
- package/dist/worker/cli.js +29 -2
- package/dist/worker/delivery/final-verification.js +47 -11
- package/dist/worker/delivery/package.js +63 -10
- package/dist/worker/feature/run.js +60 -8
- package/dist/worker/loop-agent/loop-agent-client.js +329 -126
- package/dist/worker/observability/read-model.js +27 -1
- package/dist/worker/observe/static/app.js +326 -45
- package/dist/worker/observe/static/index.html +1 -1
- package/dist/worker/observe/static/styles.css +5 -4
- package/dist/worker/preflight.js +49 -1
- package/dist/worker/run-task/run-task.js +22 -12
- package/dist/worker/runner/run-ready.js +76 -12
- package/dist/worker/task-spec/schema.js +0 -1
- package/dist/workflows/dag/convergence/controller.js +1 -1
- package/dist/workflows/dag/executor-registry.js +0 -2
- package/dist/workflows/dag/init-hybrid.js +402 -25
- package/dist/workflows/dag/node-execution.js +61 -7
- package/dist/workflows/dag/runner.js +45 -17
- package/dist/workflows/dag/scheduler.js +7 -2
- package/dist/workflows/dag/sdd-embedded.js +128 -0
- package/dist/workflows/dag/skill-instructions.js +5 -4
- package/dist/workflows/dag/skill-snapshot.js +527 -0
- package/dist/workflows/dag/types.js +42 -9
- package/dist/workflows/dag/validate.js +5 -8
- package/dist/workflows/loop/actions/dag-action.js +0 -2
- package/dist/workflows/loop/actions/shared.js +1 -1
- package/dist/workflows/loop/actions.js +14 -31
- package/dist/workflows/loop/benchmark.js +1 -1
- package/dist/workflows/loop/index.js +1 -1
- package/dist/workflows/loop/policy/auto-policy.js +22 -14
- package/dist/workflows/loop/policy/path-patterns.js +13 -0
- package/docs/README.md +36 -33
- package/docs/agent-dag-recovery-playbook.md +1 -1
- package/docs/agent-dag-runner.md +2 -2
- package/docs/architecture/README.md +26 -0
- package/docs/architecture/dag-execution.md +134 -0
- package/docs/architecture/evolution.md +52 -0
- package/docs/architecture/facts-and-state.md +58 -0
- package/docs/architecture/runtime-boundaries.md +45 -17
- package/docs/architecture/system-overview.md +93 -0
- package/docs/architecture/worker-and-feature.md +81 -0
- package/docs/cursor-prompt-sidecar.md +36 -0
- package/docs/decisions/README.md +13 -1
- package/docs/design/README.md +42 -21
- package/docs/development-principles.md +2 -2
- package/docs/exec-plans/active/README.md +2 -2
- package/docs/exec-plans/completed/README.md +12 -0
- package/docs/feature-workflow.md +50 -4
- package/docs/harness-methodology-debugging.md +1 -1
- package/docs/harness-methodology-tdd.md +3 -3
- package/docs/init-surface.manifest.json +60 -25
- package/docs/loop-agent-harness.md +28 -4
- package/docs/progress/README.md +32 -1
- package/docs/reports/README.md +84 -18
- package/docs/skills/README.md +2 -1
- package/docs/skills/vetted-skill-registry.md +2 -1
- package/docs/templates/agent-dag-report.schema.json +6 -6
- package/docs/templates/agent-dag.base.json +0 -5
- package/docs/templates/agent-dag.final-verification.json +0 -5
- package/docs/templates/agent-dag.schema.json +1 -2
- package/docs/templates/agent-dag.supervised-implementation.json +1 -6
- package/docs/templates/frontend-design-contract.md +33 -0
- package/docs/templates/frontend-task-constraints.md +25 -0
- package/docs/templates/frontend-task-requirement.md +61 -0
- package/docs/templates/harness.schema.json +10 -12
- package/docs/templates/hybrid-dag.json +1 -6
- package/docs/templates/interactive-ui-round2-experiment.md +1 -1
- package/docs/templates/product-line/task.yaml +0 -1
- package/docs/templates/project-start-checklist.md +2 -2
- package/docs/templates/worker-dogfood-evidence.md +28 -0
- package/docs/templates/worker-dogfood-setup.md +20 -0
- package/docs/verification-matrix.md +10 -0
- package/examples/decision-gate-agent-dag.json +87 -33
- package/examples/example-dag.json +0 -5
- package/examples/hybrid-loop-agent-dag.json +0 -5
- package/harness.json +7 -15
- package/package.json +22 -46
- package/scripts/check-product-line-docs.sh +10 -7
- package/skills/agent-worker/SKILL.md +37 -0
- package/skills/agent-worker/references/agent-worker-operator.md +43 -0
- package/skills/frontend-design-review/SKILL.md +59 -0
- package/skills/frontend-design-review/references/review-checklist.md +37 -0
- package/skills/frontend-implementation/SKILL.md +51 -0
- package/skills/frontend-implementation/references/code-standards.md +34 -0
- package/skills/frontend-implementation/references/design-spec.md +46 -0
- package/skills/frontend-implementation/references/node-contracts.md +32 -0
- package/skills/frontend-review/SKILL.md +53 -0
- package/skills/frontend-review/references/review-findings.md +42 -0
- package/skills/frontend-verification/SKILL.md +40 -0
- package/skills/frontend-verification/references/verification-checklist.md +56 -0
- package/skills/grill-me/SKILL.md +10 -0
- package/skills/grill-with-docs/SKILL.md +88 -0
- package/skills/grill-with-docs/adr-format.md +47 -0
- package/skills/grill-with-docs/context-format.md +60 -0
- package/skills/loop-agent/SKILL.md +11 -9
- package/skills/loop-agent/references/command-reference.md +13 -15
- package/skills/loop-agent/references/docs-converge.md +126 -0
- package/skills/loop-agent/references/harness-policy.md +7 -7
- package/skills/loop-agent/references/hybrid-dag.md +15 -18
- package/skills/loop-agent/references/long-running-loop.md +4 -6
- package/skills/loop-agent/references/multi-worktree.md +6 -6
- package/skills/loop-agent/references/orchestrator-and-interventions.md +3 -3
- package/skills/loop-agent/references/pi-subagent-assisted-mode.md +14 -11
- package/skills/loop-agent/references/task-workflow.md +1 -1
- package/skills/using-git-worktrees/SKILL.md +215 -0
- package/dist/commands/cursor-worker.js +0 -43
- package/dist/cursor-worker-entry.js +0 -8
- package/dist/executors/cursor-artifacts.js +0 -33
- package/dist/executors/cursor-execution-log.js +0 -81
- package/dist/executors/cursor-executor-artifacts.js +0 -134
- package/dist/executors/cursor-run.js +0 -115
- package/dist/executors/cursor-tool.js +0 -94
- package/dist/executors/cursor-worker-client.js +0 -223
- package/dist/executors/cursor-worker-protocol.js +0 -18
- package/dist/executors/cursor-worker-server.js +0 -54
- package/dist/executors/cursor-worker.js +0 -3
- package/dist/executors/cursor.js +0 -6
- package/dist/executors/dag-cursor-executor.js +0 -87
- package/dist/workflows/loop/actions/cursor-fix.js +0 -191
- package/dist/workflows/loop/policy/cursor-fix-policy.js +0 -31
- package/docs/cursor-executor-usage.md +0 -25
- package/docs/dynamic-workflow-dag-engine-roadmap.md +0 -1749
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { realpath } from "node:fs/promises";
|
|
3
|
+
import { controllerIdentityExpectationFailure, resolveControllerIdentity, } from "../loop-agent/loop-agent-client.js";
|
|
3
4
|
import { buildGlobalSnapshot } from "../observability/read-model.js";
|
|
4
5
|
import { createSnapshotStore } from "../observability/snapshot-store.js";
|
|
5
6
|
import { preflightTargetRepo } from "../preflight.js";
|
|
@@ -29,6 +30,37 @@ export async function runFeature(options) {
|
|
|
29
30
|
let gitTransaction;
|
|
30
31
|
const gitTasks = [];
|
|
31
32
|
const expectedArtifacts = expectedArtifactPaths(repoRoot, batchRunId);
|
|
33
|
+
let controllerIdentity;
|
|
34
|
+
try {
|
|
35
|
+
controllerIdentity = resolveControllerIdentity(options.client, options.controllerIdentity);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
return failedResult({
|
|
39
|
+
featureId,
|
|
40
|
+
mode: options.dryRun ? "dry-run" : "executed",
|
|
41
|
+
steps: [{ id: "preflight", status: "failed", durationMs: 0, message: errorMessage(error) }],
|
|
42
|
+
limitApplied,
|
|
43
|
+
code: "controller-identity-client-mismatch",
|
|
44
|
+
message: errorMessage(error),
|
|
45
|
+
evidence: [],
|
|
46
|
+
expectedArtifacts,
|
|
47
|
+
controllerIdentity: options.controllerIdentity,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const identityFailure = controllerIdentityExpectationFailure(controllerIdentity, options.controllerExpectation);
|
|
51
|
+
if (identityFailure) {
|
|
52
|
+
return failedResult({
|
|
53
|
+
featureId,
|
|
54
|
+
mode: options.dryRun ? "dry-run" : "executed",
|
|
55
|
+
steps: [{ id: "preflight", status: "failed", durationMs: 0, message: identityFailure.message }],
|
|
56
|
+
limitApplied,
|
|
57
|
+
code: identityFailure.code,
|
|
58
|
+
message: identityFailure.message,
|
|
59
|
+
evidence: [],
|
|
60
|
+
expectedArtifacts,
|
|
61
|
+
controllerIdentity,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
32
64
|
progress.step("feature validate");
|
|
33
65
|
const validation = await timedStep(steps, "validate", async () => dependencies.validateFeature(featureDir));
|
|
34
66
|
if (!validation.value?.ok) {
|
|
@@ -44,6 +76,7 @@ export async function runFeature(options) {
|
|
|
44
76
|
evidence: errors.flatMap((error) => error.path ? [error.path] : []),
|
|
45
77
|
nextCommand: `agent-worker task validate-feature ${JSON.stringify(featureDir)}`,
|
|
46
78
|
expectedArtifacts,
|
|
79
|
+
controllerIdentity,
|
|
47
80
|
});
|
|
48
81
|
}
|
|
49
82
|
featureId = validation.value.featureId;
|
|
@@ -56,11 +89,14 @@ export async function runFeature(options) {
|
|
|
56
89
|
client: options.client,
|
|
57
90
|
runCheckRepo: options.runCheckRepo,
|
|
58
91
|
...(options.checkRepoCommand ? { checkRepoCommand: options.checkRepoCommand } : {}),
|
|
92
|
+
...(options.controllerExpectation ? { expectation: options.controllerExpectation } : {}),
|
|
59
93
|
}));
|
|
60
94
|
if (!preflight.value?.ok) {
|
|
61
95
|
markLastStepFailed(steps, preflight.value && !preflight.value.ok ? preflight.value.message : preflight.error ?? "target repo preflight failed");
|
|
62
|
-
return preflightFailure({ featureId, repoRoot, steps, limitApplied, preflight: preflight.value, fallbackMessage: preflight.error, expectedArtifacts
|
|
96
|
+
return preflightFailure({ featureId, repoRoot, steps, limitApplied, preflight: preflight.value, fallbackMessage: preflight.error, expectedArtifacts,
|
|
97
|
+
controllerIdentity: preflight.value?.controllerIdentity ?? controllerIdentity });
|
|
63
98
|
}
|
|
99
|
+
controllerIdentity = preflight.value.controllerIdentity ?? controllerIdentity;
|
|
64
100
|
steps.at(-1).artifacts = preflight.value.commands.map((command) => command.result.artifacts.resultPath);
|
|
65
101
|
}
|
|
66
102
|
if (checkpointMode) {
|
|
@@ -68,7 +104,8 @@ export async function runFeature(options) {
|
|
|
68
104
|
const canonicalFeature = await realpath(featureDir).catch(() => featureDir);
|
|
69
105
|
const featureRelative = path.relative(canonicalRepo, canonicalFeature);
|
|
70
106
|
if (featureRelative.startsWith("..") || path.isAbsolute(featureRelative)) {
|
|
71
|
-
return failedResult({ featureId, mode: options.dryRun ? "dry-run" : "executed", steps, limitApplied, code: "git-feature-repo-mismatch", message: "Feature Packet must be inside the Git target repo for checkpoint mode", evidence: [featureDir, repoRoot], expectedArtifacts
|
|
107
|
+
return failedResult({ featureId, mode: options.dryRun ? "dry-run" : "executed", steps, limitApplied, code: "git-feature-repo-mismatch", message: "Feature Packet must be inside the Git target repo for checkpoint mode", evidence: [featureDir, repoRoot], expectedArtifacts,
|
|
108
|
+
controllerIdentity });
|
|
72
109
|
}
|
|
73
110
|
if (options.dryRun) {
|
|
74
111
|
steps.push(planned("git-preflight", `create or reuse agent/${featureId.toLowerCase()} and checkpoint each task`));
|
|
@@ -76,14 +113,16 @@ export async function runFeature(options) {
|
|
|
76
113
|
else {
|
|
77
114
|
const gitStep = await timedStep(steps, "git-preflight", async () => dependencies.startGit({ repoRoot, featureId, now }));
|
|
78
115
|
if (!gitStep.value)
|
|
79
|
-
return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "git-preflight-failed", message: gitStep.error ?? "Git transaction preflight failed", evidence: [], expectedArtifacts
|
|
116
|
+
return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "git-preflight-failed", message: gitStep.error ?? "Git transaction preflight failed", evidence: [], expectedArtifacts,
|
|
117
|
+
controllerIdentity });
|
|
80
118
|
gitTransaction = gitStep.value;
|
|
81
119
|
steps.at(-1).artifacts = [gitTransaction.recordPath];
|
|
82
120
|
}
|
|
83
121
|
}
|
|
84
122
|
const beforeStep = await timedStep(steps, "review-before", async () => dependencies.review({ featureDir, repoRoot }));
|
|
85
123
|
if (!beforeStep.value) {
|
|
86
|
-
return failedResult({ featureId, mode: options.dryRun ? "dry-run" : "executed", steps, limitApplied, code: "feature-review-failed", message: beforeStep.error ?? "Feature review failed", evidence: [], expectedArtifacts
|
|
124
|
+
return failedResult({ featureId, mode: options.dryRun ? "dry-run" : "executed", steps, limitApplied, code: "feature-review-failed", message: beforeStep.error ?? "Feature review failed", evidence: [], expectedArtifacts,
|
|
125
|
+
controllerIdentity });
|
|
87
126
|
}
|
|
88
127
|
before = beforeStep.value;
|
|
89
128
|
const readyTasks = before.tasks.filter((task) => task.status === "Ready").map((task) => task.taskId);
|
|
@@ -108,6 +147,7 @@ export async function runFeature(options) {
|
|
|
108
147
|
batch: null,
|
|
109
148
|
gitTasks,
|
|
110
149
|
limitApplied,
|
|
150
|
+
controllerIdentity,
|
|
111
151
|
};
|
|
112
152
|
}
|
|
113
153
|
if (readyTasks.length > 0 && limitApplied > 0) {
|
|
@@ -122,6 +162,8 @@ export async function runFeature(options) {
|
|
|
122
162
|
progress,
|
|
123
163
|
skipTaskPreflight: true,
|
|
124
164
|
...(options.piModel ? { piModel: options.piModel } : {}),
|
|
165
|
+
...(controllerIdentity ? { controllerIdentity } : {}),
|
|
166
|
+
...(options.controllerExpectation ? { controllerExpectation: options.controllerExpectation } : {}),
|
|
125
167
|
...(gitTransaction ? { onTaskFinalized: async (task) => {
|
|
126
168
|
const gitResult = await dependencies.finalizeGit(gitTransaction, { ...task, keepFailedDiff: options.keepFailedDiff, now });
|
|
127
169
|
gitTasks.push(gitResult);
|
|
@@ -132,7 +174,8 @@ export async function runFeature(options) {
|
|
|
132
174
|
batch = runStep.value;
|
|
133
175
|
if (!batch) {
|
|
134
176
|
const kept = runStep.error?.startsWith("git-keep-failed-diff:") ?? false;
|
|
135
|
-
const failed = failedResult({ featureId, mode: "executed", steps, limitApplied, code: kept ? "git-failed-diff-kept" : "run-ready-failed", message: kept ? "Failed task diff was kept by explicit request; automatic execution stopped" : runStep.error ?? "run-ready failed", evidence: kept ? [runStep.error.slice("git-keep-failed-diff:".length)] : [], before, readyTasks, expectedArtifacts
|
|
177
|
+
const failed = failedResult({ featureId, mode: "executed", steps, limitApplied, code: kept ? "git-failed-diff-kept" : "run-ready-failed", message: kept ? "Failed task diff was kept by explicit request; automatic execution stopped" : runStep.error ?? "run-ready failed", evidence: kept ? [runStep.error.slice("git-keep-failed-diff:".length)] : [], before, readyTasks, expectedArtifacts,
|
|
178
|
+
controllerIdentity });
|
|
136
179
|
return kept ? { ...failed, status: "needs-action", gitTasks, artifacts: { ...failed.artifacts, gitTransaction: gitTransaction?.recordPath ?? null } } : failed;
|
|
137
180
|
}
|
|
138
181
|
steps.at(-1).artifacts = [batch.batchRunPath];
|
|
@@ -147,7 +190,8 @@ export async function runFeature(options) {
|
|
|
147
190
|
progress.step("refresh morning report");
|
|
148
191
|
const report = await timedStep(steps, "morning-report", async () => dependencies.writeReport({ repoRoot, ...(batch ? { batchRunId: batch.batchRunId } : {}), outputPath: morningReportPath }));
|
|
149
192
|
if (!report.value)
|
|
150
|
-
return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "morning-report-failed", message: report.error ?? "morning report failed", evidence: [], before, readyTasks, batch, expectedArtifacts
|
|
193
|
+
return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "morning-report-failed", message: report.error ?? "morning report failed", evidence: [], before, readyTasks, batch, expectedArtifacts,
|
|
194
|
+
controllerIdentity });
|
|
151
195
|
steps.at(-1).artifacts = [report.value];
|
|
152
196
|
const snapshotPath = path.join(getTaskPoolRoot(repoRoot), "observability", "snapshot.json");
|
|
153
197
|
progress.step("refresh Observe snapshot");
|
|
@@ -157,12 +201,14 @@ export async function runFeature(options) {
|
|
|
157
201
|
return snapshotPath;
|
|
158
202
|
});
|
|
159
203
|
if (!snapshot.value)
|
|
160
|
-
return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "observe-snapshot-failed", message: snapshot.error ?? "Observe snapshot failed", evidence: [report.value], before, readyTasks, batch, artifacts: { morningReport: report.value }, expectedArtifacts
|
|
204
|
+
return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "observe-snapshot-failed", message: snapshot.error ?? "Observe snapshot failed", evidence: [report.value], before, readyTasks, batch, artifacts: { morningReport: report.value }, expectedArtifacts,
|
|
205
|
+
controllerIdentity });
|
|
161
206
|
steps.at(-1).artifacts = [snapshot.value];
|
|
162
207
|
progress.step("derive final Feature review");
|
|
163
208
|
const after = await timedStep(steps, "review-after", async () => dependencies.review({ featureDir, repoRoot }));
|
|
164
209
|
if (!after.value)
|
|
165
|
-
return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "feature-review-failed", message: after.error ?? "final Feature review failed", evidence: [report.value, snapshot.value], before, readyTasks, batch, artifacts: { morningReport: report.value, observeSnapshot: snapshot.value }, expectedArtifacts
|
|
210
|
+
return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "feature-review-failed", message: after.error ?? "final Feature review failed", evidence: [report.value, snapshot.value], before, readyTasks, batch, artifacts: { morningReport: report.value, observeSnapshot: snapshot.value }, expectedArtifacts,
|
|
211
|
+
controllerIdentity });
|
|
166
212
|
const taskFailures = batch?.tasks.filter((task) => task.status === "failed") ?? [];
|
|
167
213
|
const runInfrastructureFailed = batch?.status === "failed";
|
|
168
214
|
const executionError = runInfrastructureFailed
|
|
@@ -190,6 +236,7 @@ export async function runFeature(options) {
|
|
|
190
236
|
gitTasks,
|
|
191
237
|
...(executionError ? { error: executionError } : {}),
|
|
192
238
|
limitApplied,
|
|
239
|
+
controllerIdentity,
|
|
193
240
|
};
|
|
194
241
|
}
|
|
195
242
|
export function renderFeatureRun(result) {
|
|
@@ -271,6 +318,7 @@ function failedResult(input) {
|
|
|
271
318
|
batch: input.batch ?? null,
|
|
272
319
|
error: { code: input.code, message: input.message, evidence: input.evidence, ...(input.nextCommand ? { nextCommand: input.nextCommand } : {}) },
|
|
273
320
|
limitApplied: input.limitApplied,
|
|
321
|
+
controllerIdentity: input.controllerIdentity,
|
|
274
322
|
};
|
|
275
323
|
}
|
|
276
324
|
function expectedArtifactPaths(repoRoot, batchRunId) {
|
|
@@ -309,5 +357,9 @@ function preflightFailure(input) {
|
|
|
309
357
|
evidence: failed?.commands.flatMap((command) => [command.result.artifacts.resultPath]) ?? [],
|
|
310
358
|
nextCommand: `cd ${JSON.stringify(input.repoRoot)} && loop-agent doctor`,
|
|
311
359
|
expectedArtifacts: input.expectedArtifacts,
|
|
360
|
+
controllerIdentity: failed?.controllerIdentity ?? input.controllerIdentity,
|
|
312
361
|
});
|
|
313
362
|
}
|
|
363
|
+
function errorMessage(error) {
|
|
364
|
+
return error instanceof Error ? error.message : String(error);
|
|
365
|
+
}
|