@noetaris/harness 0.6.0 → 0.8.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/README.md +78 -6
- package/dist/index.d.ts +66 -2
- package/dist/index.js +209 -152
- package/dist/index.js.map +1 -1
- package/package.json +13 -9
package/dist/index.js
CHANGED
|
@@ -510,7 +510,27 @@ function safeInvoke(hookName, call, sink) {
|
|
|
510
510
|
reportObserverError(error, { hookName }, sink);
|
|
511
511
|
}
|
|
512
512
|
}
|
|
513
|
+
async function runWrapped(wrap, fn, onObserverError) {
|
|
514
|
+
let p;
|
|
515
|
+
const inner = () => {
|
|
516
|
+
if (p === void 0) {
|
|
517
|
+
p = new Promise((resolve) => resolve(fn()));
|
|
518
|
+
p.catch(() => {
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
return p;
|
|
522
|
+
};
|
|
523
|
+
try {
|
|
524
|
+
await wrap(inner);
|
|
525
|
+
} catch (e) {
|
|
526
|
+
const started = p;
|
|
527
|
+
const passedThrough = started !== void 0 && await started.then(() => false, (err) => err === e);
|
|
528
|
+
if (!passedThrough) reportObserverError(e, { hookName: "wrap" }, onObserverError);
|
|
529
|
+
}
|
|
530
|
+
return inner();
|
|
531
|
+
}
|
|
513
532
|
function composeObservers(observers, onObserverError) {
|
|
533
|
+
const wrappers = observers.filter((o) => o.wrap !== void 0);
|
|
514
534
|
return {
|
|
515
535
|
onRunStart: (ctx) => {
|
|
516
536
|
for (const o of observers) safeInvoke("onRunStart", () => o.onRunStart?.(ctx), onObserverError);
|
|
@@ -535,6 +555,11 @@ function composeObservers(observers, onObserverError) {
|
|
|
535
555
|
},
|
|
536
556
|
onStepSettled: (ctx, event) => {
|
|
537
557
|
for (const o of observers) safeInvoke("onStepSettled", () => o.onStepSettled?.(ctx, event), onObserverError);
|
|
558
|
+
},
|
|
559
|
+
// First observer outermost; each layer isolated on its own by runWrapped.
|
|
560
|
+
wrap: (ctx, scope, fn) => {
|
|
561
|
+
const layer = (i) => i === wrappers.length ? fn() : runWrapped((inner) => wrappers[i].wrap(ctx, scope, inner), () => layer(i + 1), onObserverError);
|
|
562
|
+
return layer(0);
|
|
538
563
|
}
|
|
539
564
|
};
|
|
540
565
|
}
|
|
@@ -588,6 +613,21 @@ function extractRunListeners(resources) {
|
|
|
588
613
|
return raw;
|
|
589
614
|
}
|
|
590
615
|
|
|
616
|
+
// src/agent/ctx-within.ts
|
|
617
|
+
function createWithinFn(observer, currentStep, onObserverError) {
|
|
618
|
+
return (type, payload, fn) => {
|
|
619
|
+
const wrap = observer?.wrap;
|
|
620
|
+
const stepCtx = currentStep();
|
|
621
|
+
if (wrap === void 0 || stepCtx === null) return fn();
|
|
622
|
+
return runWrapped((inner) => wrap(stepCtx, { kind: "event", type, payload }, inner), fn, onObserverError);
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
function runStepScope(observer, stepCtx, fn, onObserverError) {
|
|
626
|
+
const wrap = observer?.wrap;
|
|
627
|
+
if (wrap === void 0) return fn();
|
|
628
|
+
return runWrapped((inner) => wrap(stepCtx, { kind: "step" }, inner), fn, onObserverError);
|
|
629
|
+
}
|
|
630
|
+
|
|
591
631
|
// src/loop/loop-executor.ts
|
|
592
632
|
var NOOP_OBSERVER = {};
|
|
593
633
|
function isForkCursor(cursor) {
|
|
@@ -654,6 +694,15 @@ function fireSettled(obs, stepCtx, stepStart, fields, onObserverError) {
|
|
|
654
694
|
const event = { ...fields, durationMs: Date.now() - stepStart };
|
|
655
695
|
safeInvoke("onStepSettled", () => hook(stepCtx, event), onObserverError);
|
|
656
696
|
}
|
|
697
|
+
function stepContextOf(runCtx, stepName) {
|
|
698
|
+
return {
|
|
699
|
+
agentId: runCtx.agentId,
|
|
700
|
+
sessionId: runCtx.sessionId,
|
|
701
|
+
runId: runCtx.runId,
|
|
702
|
+
stepName,
|
|
703
|
+
...runCtx.branchPath !== void 0 ? { branchPath: runCtx.branchPath } : {}
|
|
704
|
+
};
|
|
705
|
+
}
|
|
657
706
|
function asError(e) {
|
|
658
707
|
return e instanceof Error ? e : new Error(String(e));
|
|
659
708
|
}
|
|
@@ -675,165 +724,178 @@ async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callb
|
|
|
675
724
|
...callbacks?.branchPath !== void 0 && callbacks.branchPath.length > 0 ? { branchPath: callbacks.branchPath } : {}
|
|
676
725
|
};
|
|
677
726
|
safeInvoke("onRunStart", () => obs?.onRunStart?.(runCtx), onObserverError);
|
|
727
|
+
let runEnded = false;
|
|
728
|
+
const endRun = (signal, failure) => {
|
|
729
|
+
runEnded = true;
|
|
730
|
+
const event = { signal, durationMs: Date.now() - runStart, ...failure !== void 0 ? { error: failure.error } : {} };
|
|
731
|
+
safeInvoke("onRunEnd", () => obs?.onRunEnd?.(runCtx, event), onObserverError);
|
|
732
|
+
};
|
|
678
733
|
const callCountRef = { current: 0 };
|
|
679
734
|
const stepCtxRef = { current: null };
|
|
680
735
|
ctx["interrupt"] = createInterruptFn(state, callCountRef, callbacks?.branchPath);
|
|
681
736
|
ctx["emit"] = createEmitFn(callbacks?.listeners ?? {}, obs, stepCtxRef, onObserverError);
|
|
737
|
+
ctx["within"] = createWithinFn(obs, () => stepCtxRef.current, onObserverError);
|
|
738
|
+
const telemetryObserver = obs !== void 0 ? composeObservers([obs], onObserverError) : NOOP_OBSERVER;
|
|
682
739
|
let cursor = startCursor ?? graph.entryStep;
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
if (isForkCursor(cursor)) {
|
|
689
|
-
const forkCursor = cursor;
|
|
690
|
-
const forkNode = graph.steps.find((s) => s.name === forkCursor.fork);
|
|
691
|
-
if (!isForkDef(forkNode)) {
|
|
692
|
-
throw new NoNextStepError(forkCursor.fork);
|
|
693
|
-
}
|
|
694
|
-
onBeforeStep?.(forkNode.name, { ...state });
|
|
695
|
-
const outcome = await handleFork(
|
|
696
|
-
forkNode,
|
|
697
|
-
forkCursor.branches,
|
|
698
|
-
state,
|
|
699
|
-
ctx,
|
|
700
|
-
schema,
|
|
701
|
-
shouldStop,
|
|
702
|
-
callbacks,
|
|
703
|
-
obs,
|
|
704
|
-
runCtx,
|
|
705
|
-
runStart,
|
|
706
|
-
implicitNextMap,
|
|
707
|
-
graph
|
|
708
|
-
);
|
|
709
|
-
if (outcome.done) {
|
|
710
|
-
return outcome.result;
|
|
711
|
-
}
|
|
712
|
-
cursor = outcome.nextCursor;
|
|
713
|
-
continue;
|
|
714
|
-
}
|
|
715
|
-
onBeforeStep?.(cursor, { ...state });
|
|
716
|
-
const node = graph.steps.find((s) => s.name === cursor);
|
|
717
|
-
if (isForkDef(node)) {
|
|
718
|
-
const outcome = await handleFork(
|
|
719
|
-
node,
|
|
720
|
-
void 0,
|
|
721
|
-
state,
|
|
722
|
-
ctx,
|
|
723
|
-
schema,
|
|
724
|
-
shouldStop,
|
|
725
|
-
callbacks,
|
|
726
|
-
obs,
|
|
727
|
-
runCtx,
|
|
728
|
-
runStart,
|
|
729
|
-
implicitNextMap,
|
|
730
|
-
graph
|
|
731
|
-
);
|
|
732
|
-
if (outcome.done) {
|
|
733
|
-
return outcome.result;
|
|
734
|
-
}
|
|
735
|
-
cursor = outcome.nextCursor;
|
|
736
|
-
continue;
|
|
737
|
-
}
|
|
738
|
-
const step = node;
|
|
739
|
-
callCountRef.current = 0;
|
|
740
|
-
const stepCtx = {
|
|
741
|
-
agentId: ctx.agentId,
|
|
742
|
-
sessionId: ctx.sessionId,
|
|
743
|
-
stepName: cursor,
|
|
744
|
-
...callbacks?.branchPath !== void 0 && callbacks.branchPath.length > 0 ? { branchPath: callbacks.branchPath } : {}
|
|
745
|
-
};
|
|
746
|
-
stepCtxRef.current = stepCtx;
|
|
747
|
-
const stepStart = Date.now();
|
|
748
|
-
safeInvoke("onStepStart", () => obs?.onStepStart?.(stepCtx), onObserverError);
|
|
749
|
-
if (callbacks?.telemetrySlots !== void 0) {
|
|
750
|
-
const telemetry = { observer: obs ?? NOOP_OBSERVER, stepContext: stepCtx };
|
|
751
|
-
for (const { key, slot } of callbacks.telemetrySlots) {
|
|
752
|
-
;
|
|
753
|
-
ctx[key] = slot.withTelemetry(telemetry);
|
|
740
|
+
try {
|
|
741
|
+
while (true) {
|
|
742
|
+
if (shouldStop?.()) {
|
|
743
|
+
endRun("$stopped");
|
|
744
|
+
return { state, signal: null, cursor, paused: true };
|
|
754
745
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
const
|
|
746
|
+
if (isForkCursor(cursor)) {
|
|
747
|
+
const forkCursor = cursor;
|
|
748
|
+
const forkNode = graph.steps.find((s) => s.name === forkCursor.fork);
|
|
749
|
+
if (!isForkDef(forkNode)) {
|
|
750
|
+
throw new NoNextStepError(forkCursor.fork);
|
|
751
|
+
}
|
|
752
|
+
onBeforeStep?.(forkNode.name, { ...state });
|
|
753
|
+
const outcome = await handleFork(
|
|
754
|
+
forkNode,
|
|
755
|
+
forkCursor.branches,
|
|
763
756
|
state,
|
|
764
|
-
ctx
|
|
757
|
+
ctx,
|
|
758
|
+
schema,
|
|
759
|
+
shouldStop,
|
|
760
|
+
callbacks,
|
|
761
|
+
obs,
|
|
762
|
+
runCtx,
|
|
763
|
+
endRun,
|
|
764
|
+
implicitNextMap,
|
|
765
|
+
graph
|
|
765
766
|
);
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
if (hadResponses) {
|
|
769
|
-
state.$interrupt = null;
|
|
770
|
-
state.$interruptResponses = {};
|
|
767
|
+
if (outcome.done) {
|
|
768
|
+
return outcome.result;
|
|
771
769
|
}
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
770
|
+
cursor = outcome.nextCursor;
|
|
771
|
+
continue;
|
|
772
|
+
}
|
|
773
|
+
onBeforeStep?.(cursor, { ...state });
|
|
774
|
+
const node = graph.steps.find((s) => s.name === cursor);
|
|
775
|
+
if (isForkDef(node)) {
|
|
776
|
+
const outcome = await handleFork(
|
|
777
|
+
node,
|
|
778
|
+
void 0,
|
|
779
|
+
state,
|
|
780
|
+
ctx,
|
|
781
|
+
schema,
|
|
782
|
+
shouldStop,
|
|
783
|
+
callbacks,
|
|
784
|
+
obs,
|
|
785
|
+
runCtx,
|
|
786
|
+
endRun,
|
|
787
|
+
implicitNextMap,
|
|
788
|
+
graph
|
|
789
|
+
);
|
|
790
|
+
if (outcome.done) {
|
|
791
|
+
return outcome.result;
|
|
780
792
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
safeInvoke("onStepError", () => obs?.onStepError?.(stepCtx, { error: state.$error, durationMs: Date.now() - stepStart }), onObserverError);
|
|
793
|
+
cursor = outcome.nextCursor;
|
|
794
|
+
continue;
|
|
784
795
|
}
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
return { state, signal: "$error", cursor, paused: true };
|
|
796
|
+
const step = node;
|
|
797
|
+
callCountRef.current = 0;
|
|
798
|
+
const stepCtx = stepContextOf(runCtx, cursor);
|
|
799
|
+
stepCtxRef.current = stepCtx;
|
|
800
|
+
const stepStart = Date.now();
|
|
801
|
+
safeInvoke("onStepStart", () => obs?.onStepStart?.(stepCtx), onObserverError);
|
|
802
|
+
if (callbacks?.telemetrySlots !== void 0) {
|
|
803
|
+
const telemetry = {
|
|
804
|
+
observer: telemetryObserver,
|
|
805
|
+
stepContext: stepCtx,
|
|
806
|
+
within: createWithinFn(obs, () => stepCtx, onObserverError)
|
|
807
|
+
};
|
|
808
|
+
for (const { key, slot } of callbacks.telemetrySlots) {
|
|
809
|
+
;
|
|
810
|
+
ctx[key] = slot.withTelemetry(telemetry);
|
|
811
|
+
}
|
|
802
812
|
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
813
|
+
let runSucceeded = false;
|
|
814
|
+
let applied;
|
|
815
|
+
const settle = (fields) => fireSettled(obs, stepCtx, stepStart, { ...fields, ...applied !== void 0 ? { update: applied } : {} }, onObserverError);
|
|
816
|
+
if (step.run !== void 0) {
|
|
817
|
+
const hadResponses = Object.keys(state.$interruptResponses).length > 0;
|
|
818
|
+
try {
|
|
819
|
+
const run = step.run;
|
|
820
|
+
const update = await runStepScope(obs, stepCtx, () => run(
|
|
821
|
+
state,
|
|
822
|
+
ctx
|
|
823
|
+
), onObserverError);
|
|
824
|
+
applyUpdate(state, update, schema, callbacks?.touchedKeys);
|
|
825
|
+
applied = update;
|
|
826
|
+
if (hadResponses) {
|
|
827
|
+
state.$interrupt = null;
|
|
828
|
+
state.$interruptResponses = {};
|
|
829
|
+
}
|
|
830
|
+
runSucceeded = true;
|
|
831
|
+
} catch (e) {
|
|
832
|
+
if (isInterruptPause(e)) {
|
|
833
|
+
onInterrupt?.(e.prompt, e.interruptId);
|
|
834
|
+
safeInvoke("onInterrupt", () => obs?.onInterrupt?.(stepCtx, { prompt: e.prompt, interruptId: e.interruptId }), onObserverError);
|
|
835
|
+
settle({ outcome: "interrupt", interrupt: { interruptId: e.interruptId, prompt: e.prompt }, next: { kind: "pause" } });
|
|
836
|
+
endRun("$interrupt");
|
|
837
|
+
return { state, signal: "$interrupt", cursor, paused: true };
|
|
838
|
+
}
|
|
839
|
+
state.$error = e instanceof Error ? e : new Error(String(e));
|
|
840
|
+
onError?.(state.$error, cursor);
|
|
841
|
+
safeInvoke("onStepError", () => obs?.onStepError?.(stepCtx, { error: state.$error, durationMs: Date.now() - stepStart }), onObserverError);
|
|
842
|
+
}
|
|
809
843
|
}
|
|
810
|
-
if (
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
safeInvoke("
|
|
814
|
-
return { state, signal, cursor: null, paused: false };
|
|
844
|
+
if (runSucceeded) {
|
|
845
|
+
state.$error = null;
|
|
846
|
+
onAfterStep?.(cursor, state);
|
|
847
|
+
safeInvoke("onStepEnd", () => obs?.onStepEnd?.(stepCtx, { durationMs: Date.now() - stepStart }), onObserverError);
|
|
815
848
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
849
|
+
const callRoute = step.route !== void 0 && (runSucceeded || step.run === void 0 || step.errorAware);
|
|
850
|
+
if (callRoute) {
|
|
851
|
+
const routeFn = step.route;
|
|
852
|
+
let signal;
|
|
853
|
+
try {
|
|
854
|
+
signal = routeFn(state);
|
|
855
|
+
} catch (e) {
|
|
856
|
+
state.$error = e instanceof Error ? e : new Error(String(e));
|
|
857
|
+
settle({ outcome: "error", error: state.$error, next: { kind: "pause" } });
|
|
858
|
+
endRun("$error", { error: state.$error });
|
|
859
|
+
return { state, signal: "$error", cursor, paused: true };
|
|
860
|
+
}
|
|
861
|
+
const routed = runSucceeded || step.run === void 0 ? { outcome: "ok", signal } : { outcome: "error", signal, error: state.$error };
|
|
862
|
+
const transition = step.transitions.find((t) => t.signal === signal);
|
|
863
|
+
if (transition === void 0) {
|
|
864
|
+
const unknownSignal = new UnknownSignalError(cursor, signal);
|
|
865
|
+
settle({ outcome: "error", signal, error: unknownSignal, next: { kind: "throw" } });
|
|
866
|
+
throw unknownSignal;
|
|
867
|
+
}
|
|
868
|
+
if (transition.target.kind === "end") {
|
|
869
|
+
settle({ ...routed, next: { kind: "end" } });
|
|
870
|
+
onComplete?.(state, signal);
|
|
871
|
+
endRun(signal);
|
|
872
|
+
return { state, signal, cursor: null, paused: false };
|
|
873
|
+
}
|
|
874
|
+
settle({ ...routed, next: { kind: "step", name: transition.target.name } });
|
|
875
|
+
cursor = transition.target.name;
|
|
876
|
+
} else if (step.run !== void 0 && !runSucceeded) {
|
|
877
|
+
if (graph.onError !== void 0) {
|
|
878
|
+
settle({ outcome: "error", error: state.$error, next: { kind: "step", name: graph.onError } });
|
|
879
|
+
cursor = graph.onError;
|
|
880
|
+
} else {
|
|
881
|
+
settle({ outcome: "error", error: state.$error, next: { kind: "pause" } });
|
|
882
|
+
endRun("$error", { error: state.$error });
|
|
883
|
+
return { state, signal: "$error", cursor, paused: true };
|
|
884
|
+
}
|
|
822
885
|
} else {
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
settle({ outcome: "error", error: noNext, next: { kind: "throw" } });
|
|
832
|
-
throw noNext;
|
|
886
|
+
const next = step.next ?? implicitNextMap.get(cursor) ?? null;
|
|
887
|
+
if (next === null) {
|
|
888
|
+
const noNext = new NoNextStepError(cursor);
|
|
889
|
+
settle({ outcome: "error", error: noNext, next: { kind: "throw" } });
|
|
890
|
+
throw noNext;
|
|
891
|
+
}
|
|
892
|
+
settle({ outcome: "ok", next: { kind: "step", name: next } });
|
|
893
|
+
cursor = next;
|
|
833
894
|
}
|
|
834
|
-
settle({ outcome: "ok", next: { kind: "step", name: next } });
|
|
835
|
-
cursor = next;
|
|
836
895
|
}
|
|
896
|
+
} catch (e) {
|
|
897
|
+
if (!runEnded) endRun("$error", { error: e });
|
|
898
|
+
throw e;
|
|
837
899
|
}
|
|
838
900
|
}
|
|
839
901
|
async function runBranch(branch, prior, outerState, outerCtx, schema, shouldStop, branchSignal, branchCallbacks) {
|
|
@@ -941,13 +1003,8 @@ async function dispatchFork(forkNode, priorBranches, outerState, outerCtx, schem
|
|
|
941
1003
|
branches: outcomes.map((o) => ({ name: o.name, status: "done", touchedKeys: [...o.touchedKeys] }))
|
|
942
1004
|
};
|
|
943
1005
|
}
|
|
944
|
-
async function handleFork(forkNode, priorBranches, state, ctx, schema, shouldStop, callbacks, obs, runCtx,
|
|
945
|
-
const stepCtx =
|
|
946
|
-
agentId: ctx.agentId,
|
|
947
|
-
sessionId: ctx.sessionId,
|
|
948
|
-
stepName: forkNode.name,
|
|
949
|
-
...callbacks?.branchPath !== void 0 && callbacks.branchPath.length > 0 ? { branchPath: callbacks.branchPath } : {}
|
|
950
|
-
};
|
|
1006
|
+
async function handleFork(forkNode, priorBranches, state, ctx, schema, shouldStop, callbacks, obs, runCtx, endRun, implicitNextMap, graph) {
|
|
1007
|
+
const stepCtx = stepContextOf(runCtx, forkNode.name);
|
|
951
1008
|
const stepStart = Date.now();
|
|
952
1009
|
const onObserverError = callbacks?.onObserverError;
|
|
953
1010
|
safeInvoke("onStepStart", () => obs?.onStepStart?.(stepCtx), onObserverError);
|
|
@@ -964,11 +1021,11 @@ async function handleFork(forkNode, priorBranches, state, ctx, schema, shouldSto
|
|
|
964
1021
|
};
|
|
965
1022
|
if (dispatch.interrupted === true) {
|
|
966
1023
|
fireSettled(obs, stepCtx, stepStart, { outcome: "interrupt", next: { kind: "pause" }, fork }, onObserverError);
|
|
967
|
-
|
|
1024
|
+
endRun("$interrupt");
|
|
968
1025
|
return { done: true, result: { state, signal: "$interrupt", cursor: dispatch.forkCursor, paused: true } };
|
|
969
1026
|
}
|
|
970
1027
|
fireSettled(obs, stepCtx, stepStart, { outcome: "stopped", next: { kind: "pause" }, fork }, onObserverError);
|
|
971
|
-
|
|
1028
|
+
endRun("$stopped");
|
|
972
1029
|
return { done: true, result: { state, signal: null, cursor: dispatch.forkCursor, paused: true } };
|
|
973
1030
|
}
|
|
974
1031
|
if (dispatch.kind === "failed") {
|
|
@@ -980,7 +1037,7 @@ async function handleFork(forkNode, priorBranches, state, ctx, schema, shouldSto
|
|
|
980
1037
|
return { done: false, nextCursor: graph.onError };
|
|
981
1038
|
}
|
|
982
1039
|
fireSettled(obs, stepCtx, stepStart, { outcome: "error", error: state.$error, next: { kind: "pause" } }, onObserverError);
|
|
983
|
-
|
|
1040
|
+
endRun("$error", { error: state.$error });
|
|
984
1041
|
return { done: true, result: { state, signal: "$error", cursor: forkNode.name, paused: true } };
|
|
985
1042
|
}
|
|
986
1043
|
state.$error = null;
|