@q1k-oss/btree-workflows 0.0.1

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.
Files changed (203) hide show
  1. package/.claude/settings.local.json +31 -0
  2. package/CLAUDE.md +181 -0
  3. package/LICENSE +21 -0
  4. package/README.md +920 -0
  5. package/behaviour-tree-workflows-landing/index.html +16 -0
  6. package/behaviour-tree-workflows-landing/package-lock.json +2074 -0
  7. package/behaviour-tree-workflows-landing/package.json +31 -0
  8. package/behaviour-tree-workflows-landing/public/favicon.svg +17 -0
  9. package/behaviour-tree-workflows-landing/src/App.css +103 -0
  10. package/behaviour-tree-workflows-landing/src/App.tsx +176 -0
  11. package/behaviour-tree-workflows-landing/src/components/BlackboardInspector.css +89 -0
  12. package/behaviour-tree-workflows-landing/src/components/BlackboardInspector.tsx +64 -0
  13. package/behaviour-tree-workflows-landing/src/components/ExampleSelector.css +64 -0
  14. package/behaviour-tree-workflows-landing/src/components/ExampleSelector.tsx +34 -0
  15. package/behaviour-tree-workflows-landing/src/components/ExecutionLog.css +107 -0
  16. package/behaviour-tree-workflows-landing/src/components/ExecutionLog.tsx +85 -0
  17. package/behaviour-tree-workflows-landing/src/components/Header.css +50 -0
  18. package/behaviour-tree-workflows-landing/src/components/Header.tsx +26 -0
  19. package/behaviour-tree-workflows-landing/src/components/StatusBadge.css +45 -0
  20. package/behaviour-tree-workflows-landing/src/components/StatusBadge.tsx +15 -0
  21. package/behaviour-tree-workflows-landing/src/components/Toolbar.css +74 -0
  22. package/behaviour-tree-workflows-landing/src/components/Toolbar.tsx +53 -0
  23. package/behaviour-tree-workflows-landing/src/components/TreeVisualizer.css +67 -0
  24. package/behaviour-tree-workflows-landing/src/components/TreeVisualizer.tsx +192 -0
  25. package/behaviour-tree-workflows-landing/src/components/YamlEditor.css +18 -0
  26. package/behaviour-tree-workflows-landing/src/components/YamlEditor.tsx +96 -0
  27. package/behaviour-tree-workflows-landing/src/lib/count-nodes.ts +11 -0
  28. package/behaviour-tree-workflows-landing/src/lib/execution-engine.ts +96 -0
  29. package/behaviour-tree-workflows-landing/src/lib/tree-layout.ts +136 -0
  30. package/behaviour-tree-workflows-landing/src/lib/yaml-examples.ts +549 -0
  31. package/behaviour-tree-workflows-landing/src/main.tsx +9 -0
  32. package/behaviour-tree-workflows-landing/src/stubs/activepieces.ts +18 -0
  33. package/behaviour-tree-workflows-landing/src/stubs/fs.ts +24 -0
  34. package/behaviour-tree-workflows-landing/src/stubs/path.ts +16 -0
  35. package/behaviour-tree-workflows-landing/src/stubs/temporal-activity.ts +6 -0
  36. package/behaviour-tree-workflows-landing/src/stubs/temporal-workflow.ts +22 -0
  37. package/behaviour-tree-workflows-landing/tsconfig.json +25 -0
  38. package/behaviour-tree-workflows-landing/vite.config.ts +40 -0
  39. package/demo-google-sheets.ts +181 -0
  40. package/demo-runtime-variables.ts +174 -0
  41. package/demo-template.ts +208 -0
  42. package/docs/ARCHITECTURE_SUMMARY.md +613 -0
  43. package/docs/NODE_REFERENCE.md +504 -0
  44. package/docs/README.md +53 -0
  45. package/docs/custom-nodes-architecture.md +826 -0
  46. package/docs/observability.md +175 -0
  47. package/docs/yaml-specification.md +990 -0
  48. package/examples/temporal/README.md +117 -0
  49. package/examples/temporal/activities.ts +373 -0
  50. package/examples/temporal/client.ts +115 -0
  51. package/examples/temporal/python-worker/activities.py +339 -0
  52. package/examples/temporal/python-worker/requirements.txt +12 -0
  53. package/examples/temporal/python-worker/worker.py +106 -0
  54. package/examples/temporal/worker.ts +66 -0
  55. package/examples/temporal/workflows.ts +6 -0
  56. package/examples/temporal/yaml-workflow-loader.ts +105 -0
  57. package/examples/yaml-test.ts +97 -0
  58. package/examples/yaml-workflows/01-simple-sequence.yaml +25 -0
  59. package/examples/yaml-workflows/02-parallel-timeout.yaml +45 -0
  60. package/examples/yaml-workflows/03-ecommerce-checkout.yaml +94 -0
  61. package/examples/yaml-workflows/04-ai-agent-workflow.yaml +346 -0
  62. package/examples/yaml-workflows/05-order-processing.yaml +146 -0
  63. package/examples/yaml-workflows/06-activity-test.yaml +71 -0
  64. package/examples/yaml-workflows/07-activity-simple-test.yaml +43 -0
  65. package/examples/yaml-workflows/08-file-processing.yaml +141 -0
  66. package/examples/yaml-workflows/09-http-request.yaml +137 -0
  67. package/examples/yaml-workflows/README.md +211 -0
  68. package/package.json +38 -0
  69. package/src/actions/code-execution.schema.ts +27 -0
  70. package/src/actions/code-execution.ts +218 -0
  71. package/src/actions/generate-file.test.ts +516 -0
  72. package/src/actions/generate-file.ts +166 -0
  73. package/src/actions/http-request.test.ts +784 -0
  74. package/src/actions/http-request.ts +228 -0
  75. package/src/actions/index.ts +20 -0
  76. package/src/actions/parse-file.test.ts +448 -0
  77. package/src/actions/parse-file.ts +139 -0
  78. package/src/actions/python-script.test.ts +439 -0
  79. package/src/actions/python-script.ts +154 -0
  80. package/src/base-node.test.ts +511 -0
  81. package/src/base-node.ts +605 -0
  82. package/src/behavior-tree.test.ts +431 -0
  83. package/src/behavior-tree.ts +283 -0
  84. package/src/blackboard.test.ts +222 -0
  85. package/src/blackboard.ts +192 -0
  86. package/src/composites/conditional.schema.ts +19 -0
  87. package/src/composites/conditional.test.ts +309 -0
  88. package/src/composites/conditional.ts +129 -0
  89. package/src/composites/for-each.schema.ts +23 -0
  90. package/src/composites/for-each.test.ts +254 -0
  91. package/src/composites/for-each.ts +132 -0
  92. package/src/composites/index.ts +15 -0
  93. package/src/composites/memory-sequence.schema.ts +19 -0
  94. package/src/composites/memory-sequence.test.ts +223 -0
  95. package/src/composites/memory-sequence.ts +98 -0
  96. package/src/composites/parallel.schema.ts +28 -0
  97. package/src/composites/parallel.test.ts +502 -0
  98. package/src/composites/parallel.ts +157 -0
  99. package/src/composites/reactive-sequence.schema.ts +19 -0
  100. package/src/composites/reactive-sequence.test.ts +170 -0
  101. package/src/composites/reactive-sequence.ts +85 -0
  102. package/src/composites/recovery.schema.ts +19 -0
  103. package/src/composites/recovery.test.ts +366 -0
  104. package/src/composites/recovery.ts +90 -0
  105. package/src/composites/selector.schema.ts +19 -0
  106. package/src/composites/selector.test.ts +387 -0
  107. package/src/composites/selector.ts +85 -0
  108. package/src/composites/sequence.schema.ts +19 -0
  109. package/src/composites/sequence.test.ts +337 -0
  110. package/src/composites/sequence.ts +72 -0
  111. package/src/composites/sub-tree.schema.ts +21 -0
  112. package/src/composites/sub-tree.test.ts +893 -0
  113. package/src/composites/sub-tree.ts +177 -0
  114. package/src/composites/while.schema.ts +24 -0
  115. package/src/composites/while.test.ts +381 -0
  116. package/src/composites/while.ts +149 -0
  117. package/src/data-store/index.ts +10 -0
  118. package/src/data-store/memory-store.ts +161 -0
  119. package/src/data-store/types.ts +94 -0
  120. package/src/debug/breakpoint.test.ts +47 -0
  121. package/src/debug/breakpoint.ts +30 -0
  122. package/src/debug/index.ts +17 -0
  123. package/src/debug/resume-point.test.ts +49 -0
  124. package/src/debug/resume-point.ts +29 -0
  125. package/src/decorators/delay.schema.ts +21 -0
  126. package/src/decorators/delay.test.ts +261 -0
  127. package/src/decorators/delay.ts +140 -0
  128. package/src/decorators/force-result.schema.ts +32 -0
  129. package/src/decorators/force-result.test.ts +133 -0
  130. package/src/decorators/force-result.ts +63 -0
  131. package/src/decorators/index.ts +13 -0
  132. package/src/decorators/invert.schema.ts +19 -0
  133. package/src/decorators/invert.test.ts +135 -0
  134. package/src/decorators/invert.ts +42 -0
  135. package/src/decorators/keep-running.schema.ts +20 -0
  136. package/src/decorators/keep-running.test.ts +105 -0
  137. package/src/decorators/keep-running.ts +49 -0
  138. package/src/decorators/precondition.schema.ts +19 -0
  139. package/src/decorators/precondition.test.ts +351 -0
  140. package/src/decorators/precondition.ts +139 -0
  141. package/src/decorators/repeat.schema.ts +21 -0
  142. package/src/decorators/repeat.test.ts +187 -0
  143. package/src/decorators/repeat.ts +94 -0
  144. package/src/decorators/run-once.schema.ts +19 -0
  145. package/src/decorators/run-once.test.ts +140 -0
  146. package/src/decorators/run-once.ts +61 -0
  147. package/src/decorators/soft-assert.schema.ts +19 -0
  148. package/src/decorators/soft-assert.test.ts +107 -0
  149. package/src/decorators/soft-assert.ts +68 -0
  150. package/src/decorators/timeout.schema.ts +21 -0
  151. package/src/decorators/timeout.test.ts +274 -0
  152. package/src/decorators/timeout.ts +159 -0
  153. package/src/errors.test.ts +63 -0
  154. package/src/errors.ts +34 -0
  155. package/src/events.test.ts +347 -0
  156. package/src/events.ts +183 -0
  157. package/src/index.ts +80 -0
  158. package/src/integrations/index.ts +30 -0
  159. package/src/integrations/integration-action.test.ts +571 -0
  160. package/src/integrations/integration-action.ts +233 -0
  161. package/src/integrations/piece-executor.ts +320 -0
  162. package/src/observability/execution-tracker.ts +320 -0
  163. package/src/observability/index.ts +23 -0
  164. package/src/observability/sinks.ts +138 -0
  165. package/src/observability/types.ts +130 -0
  166. package/src/registry-utils.ts +147 -0
  167. package/src/registry.test.ts +466 -0
  168. package/src/registry.ts +334 -0
  169. package/src/schemas/base.schema.ts +104 -0
  170. package/src/schemas/index.ts +223 -0
  171. package/src/schemas/integration.test.ts +238 -0
  172. package/src/schemas/tree-definition.schema.ts +170 -0
  173. package/src/schemas/validation.test.ts +146 -0
  174. package/src/schemas/validation.ts +122 -0
  175. package/src/scripting/index.ts +22 -0
  176. package/src/templates/template-loader.test.ts +281 -0
  177. package/src/templates/template-loader.ts +152 -0
  178. package/src/temporal-integration.test.ts +213 -0
  179. package/src/test-nodes.ts +259 -0
  180. package/src/types.ts +503 -0
  181. package/src/utilities/index.ts +17 -0
  182. package/src/utilities/log-message.test.ts +275 -0
  183. package/src/utilities/log-message.ts +134 -0
  184. package/src/utilities/regex-extract.test.ts +138 -0
  185. package/src/utilities/regex-extract.ts +108 -0
  186. package/src/utilities/variable-resolver.test.ts +416 -0
  187. package/src/utilities/variable-resolver.ts +318 -0
  188. package/src/utils/error-handler.test.ts +117 -0
  189. package/src/utils/error-handler.ts +48 -0
  190. package/src/utils/signal-check.test.ts +234 -0
  191. package/src/utils/signal-check.ts +140 -0
  192. package/src/yaml/errors.ts +143 -0
  193. package/src/yaml/index.ts +30 -0
  194. package/src/yaml/loader.ts +39 -0
  195. package/src/yaml/parser.ts +286 -0
  196. package/src/yaml/validation/semantic-validator.ts +196 -0
  197. package/templates/google-sheets/insert-row.yaml +76 -0
  198. package/templates/notification-sender.yaml +33 -0
  199. package/templates/order-validation.yaml +44 -0
  200. package/tsconfig.json +24 -0
  201. package/vitest.config.ts +25 -0
  202. package/workflows/order-processor.yaml +59 -0
  203. package/workflows/process-order-workflow.yaml +142 -0
@@ -0,0 +1,135 @@
1
+ import { beforeEach, describe, expect, it } from "vitest";
2
+ import { ScopedBlackboard } from "../blackboard.js";
3
+ import { ConfigurationError } from "../errors.js";
4
+ import { MockAction } from "../test-nodes.js";
5
+ import { type TemporalContext, NodeStatus } from "../types.js";
6
+ import { Invert } from "./invert.js";
7
+
8
+ describe("Invert", () => {
9
+ let context: TemporalContext;
10
+ let invert: Invert;
11
+
12
+ beforeEach(() => {
13
+ context = {
14
+ blackboard: new ScopedBlackboard(),
15
+ timestamp: Date.now(),
16
+ deltaTime: 0,
17
+ };
18
+ invert = new Invert({ id: "test-invert" });
19
+ });
20
+
21
+ it("should propagate ConfigurationError if no child is set", async () => {
22
+ try {
23
+ await invert.tick(context);
24
+ throw new Error("Expected tick to throw");
25
+ } catch (error) {
26
+ expect(error).toBeInstanceOf(ConfigurationError);
27
+ expect((error as ConfigurationError).message).toContain(
28
+ "Decorator must have a child",
29
+ );
30
+ }
31
+ });
32
+
33
+ it("should invert SUCCESS to FAILURE", async () => {
34
+ const child = new MockAction({
35
+ id: "child",
36
+ returnStatus: NodeStatus.SUCCESS,
37
+ });
38
+
39
+ invert.setChild(child);
40
+
41
+ const status = await invert.tick(context);
42
+ expect(status).toBe(NodeStatus.FAILURE);
43
+ expect(invert.status()).toBe(NodeStatus.FAILURE);
44
+ });
45
+
46
+ it("should invert FAILURE to SUCCESS", async () => {
47
+ const child = new MockAction({
48
+ id: "child",
49
+ returnStatus: NodeStatus.FAILURE,
50
+ });
51
+
52
+ invert.setChild(child);
53
+
54
+ const status = await invert.tick(context);
55
+ expect(status).toBe(NodeStatus.SUCCESS);
56
+ expect(invert.status()).toBe(NodeStatus.SUCCESS);
57
+ });
58
+
59
+ it("should pass through RUNNING status", async () => {
60
+ const child = new MockAction({
61
+ id: "child",
62
+ returnStatus: NodeStatus.RUNNING,
63
+ });
64
+
65
+ invert.setChild(child);
66
+
67
+ const status = await invert.tick(context);
68
+ expect(status).toBe(NodeStatus.RUNNING);
69
+ expect(invert.status()).toBe(NodeStatus.RUNNING);
70
+ });
71
+
72
+ it("should pass through other statuses unchanged", async () => {
73
+ const child = new MockAction({
74
+ id: "child",
75
+ returnStatus: NodeStatus.IDLE,
76
+ });
77
+
78
+ invert.setChild(child);
79
+
80
+ const status = await invert.tick(context);
81
+ expect(status).toBe(NodeStatus.IDLE);
82
+ });
83
+
84
+ it("should properly propagate halt to child", () => {
85
+ const child = new MockAction({
86
+ id: "child",
87
+ returnStatus: NodeStatus.RUNNING,
88
+ });
89
+
90
+ invert.setChild(child);
91
+
92
+ // Set child to RUNNING state
93
+ (child as unknown)._status = NodeStatus.RUNNING;
94
+
95
+ // Halt the invert decorator
96
+ invert.halt();
97
+
98
+ expect(child.status()).toBe(NodeStatus.IDLE);
99
+ });
100
+
101
+ it("should properly propagate reset to child", () => {
102
+ const child = new MockAction({
103
+ id: "child",
104
+ returnStatus: NodeStatus.SUCCESS,
105
+ });
106
+
107
+ invert.setChild(child);
108
+
109
+ // Set child to SUCCESS state
110
+ (child as unknown)._status = NodeStatus.SUCCESS;
111
+
112
+ // Reset the invert decorator
113
+ invert.reset();
114
+
115
+ expect(child.status()).toBe(NodeStatus.IDLE);
116
+ });
117
+
118
+ it("should work with async children", async () => {
119
+ const child = new MockAction({
120
+ id: "child",
121
+ returnStatus: NodeStatus.SUCCESS,
122
+ ticksBeforeComplete: 2, // Will return RUNNING first
123
+ });
124
+
125
+ invert.setChild(child);
126
+
127
+ // First tick - child returns RUNNING
128
+ let status = await invert.tick(context);
129
+ expect(status).toBe(NodeStatus.RUNNING);
130
+
131
+ // Second tick - child returns SUCCESS, inverted to FAILURE
132
+ status = await invert.tick(context);
133
+ expect(status).toBe(NodeStatus.FAILURE);
134
+ });
135
+ });
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Invert decorator node
3
+ * Inverts the result of its child (SUCCESS becomes FAILURE and vice versa)
4
+ */
5
+
6
+ import { DecoratorNode } from "../base-node.js";
7
+ import { ConfigurationError } from "../errors.js";
8
+ import { type TemporalContext, NodeStatus } from "../types.js";
9
+ import { checkSignal } from "../utils/signal-check.js";
10
+
11
+ export class Invert extends DecoratorNode {
12
+ async executeTick(context: TemporalContext): Promise<NodeStatus> {
13
+ checkSignal(context.signal);
14
+
15
+ if (!this.child) {
16
+ throw new ConfigurationError(`${this.name}: Decorator must have a child`);
17
+ }
18
+
19
+ this.log("Ticking child");
20
+ const childStatus = await this.child.tick(context);
21
+
22
+ switch (childStatus) {
23
+ case NodeStatus.SUCCESS:
24
+ this.log("Child succeeded - returning FAILURE");
25
+ this._status = NodeStatus.FAILURE;
26
+ return NodeStatus.FAILURE;
27
+
28
+ case NodeStatus.FAILURE:
29
+ this.log("Child failed - returning SUCCESS");
30
+ this._status = NodeStatus.SUCCESS;
31
+ return NodeStatus.SUCCESS;
32
+
33
+ case NodeStatus.RUNNING:
34
+ this.log("Child is running");
35
+ this._status = NodeStatus.RUNNING;
36
+ return NodeStatus.RUNNING;
37
+
38
+ default:
39
+ return childStatus;
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * KeepRunningUntilFailure decorator configuration schema
3
+ */
4
+
5
+ import { z } from "zod";
6
+ import { nodeConfigurationSchema } from "../schemas/base.schema.js";
7
+
8
+ /**
9
+ * Schema for KeepRunningUntilFailure decorator configuration
10
+ * Uses base schema only (no additional properties)
11
+ */
12
+ export const keepRunningUntilFailureConfigurationSchema =
13
+ nodeConfigurationSchema;
14
+
15
+ /**
16
+ * Validated KeepRunningUntilFailure configuration type
17
+ */
18
+ export type ValidatedKeepRunningUntilFailureConfiguration = z.infer<
19
+ typeof keepRunningUntilFailureConfigurationSchema
20
+ >;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Tests for KeepRunningUntilFailure decorator
3
+ */
4
+
5
+ import { beforeEach, describe, expect, it } from "vitest";
6
+ import { ScopedBlackboard } from "../blackboard.js";
7
+ import { ConfigurationError } from "../errors.js";
8
+ import { FailureNode, SuccessNode } from "../test-nodes.js";
9
+ import { type TemporalContext, NodeStatus } from "../types.js";
10
+ import { KeepRunningUntilFailure } from "./keep-running.js";
11
+
12
+ describe("KeepRunningUntilFailure", () => {
13
+ let blackboard: ScopedBlackboard;
14
+ let context: TemporalContext;
15
+
16
+ beforeEach(() => {
17
+ blackboard = new ScopedBlackboard("root");
18
+ context = {
19
+ blackboard,
20
+ timestamp: Date.now(),
21
+ deltaTime: 0,
22
+ };
23
+ });
24
+
25
+ it("should return RUNNING while child succeeds", async () => {
26
+ const keep = new KeepRunningUntilFailure({ id: "keep1" });
27
+ keep.setChild(new SuccessNode({ id: "child" }));
28
+
29
+ const result = await keep.tick(context);
30
+ expect(result).toBe(NodeStatus.RUNNING);
31
+ });
32
+
33
+ it("should return SUCCESS on child failure", async () => {
34
+ const keep = new KeepRunningUntilFailure({ id: "keep1" });
35
+ keep.setChild(new FailureNode({ id: "child" }));
36
+
37
+ const result = await keep.tick(context);
38
+ expect(result).toBe(NodeStatus.SUCCESS);
39
+ });
40
+
41
+ it("should reset child between ticks", async () => {
42
+ const keep = new KeepRunningUntilFailure({ id: "keep1" });
43
+
44
+ let tickCount = 0;
45
+ class CountingNode extends SuccessNode {
46
+ tick(context: TemporalContext) {
47
+ tickCount++;
48
+ return super.tick(context);
49
+ }
50
+ }
51
+
52
+ keep.setChild(new CountingNode({ id: "child" }));
53
+
54
+ await keep.tick(context);
55
+ await keep.tick(context);
56
+ await keep.tick(context);
57
+
58
+ expect(tickCount).toBe(3); // Ticked 3 times (reset between each)
59
+ });
60
+
61
+ it("should propagate RUNNING from child", async () => {
62
+ const keep = new KeepRunningUntilFailure({ id: "keep1" });
63
+
64
+ let tickCount = 0;
65
+ class RunningThenFail extends SuccessNode {
66
+ tick(_context: TemporalContext) {
67
+ const self = this;
68
+ return (async () => {
69
+ tickCount++;
70
+ if (tickCount < 3) {
71
+ self._status = NodeStatus.RUNNING;
72
+ return NodeStatus.RUNNING;
73
+ }
74
+ self._status = NodeStatus.FAILURE;
75
+ return NodeStatus.FAILURE;
76
+ })();
77
+ }
78
+ }
79
+
80
+ keep.setChild(new RunningThenFail({ id: "child" }));
81
+
82
+ let result = await keep.tick(context);
83
+ expect(result).toBe(NodeStatus.RUNNING);
84
+
85
+ result = await keep.tick(context);
86
+ expect(result).toBe(NodeStatus.RUNNING);
87
+
88
+ result = await keep.tick(context);
89
+ expect(result).toBe(NodeStatus.SUCCESS); // Child failed
90
+ });
91
+
92
+ it("should propagate ConfigurationError if no child", async () => {
93
+ const keep = new KeepRunningUntilFailure({ id: "keep1" });
94
+
95
+ try {
96
+ await keep.tick(context);
97
+ throw new Error("Expected tick to throw");
98
+ } catch (error) {
99
+ expect(error).toBeInstanceOf(ConfigurationError);
100
+ expect((error as ConfigurationError).message).toContain(
101
+ "KeepRunningUntilFailure requires a child",
102
+ );
103
+ }
104
+ });
105
+ });
@@ -0,0 +1,49 @@
1
+ /**
2
+ * KeepRunningUntilFailure decorator
3
+ * Opposite of Retry - keeps running while child succeeds
4
+ */
5
+
6
+ import { DecoratorNode } from "../base-node.js";
7
+ import { ConfigurationError } from "../errors.js";
8
+ import { type TemporalContext, NodeStatus } from "../types.js";
9
+ import { checkSignal } from "../utils/signal-check.js";
10
+
11
+ /**
12
+ * KeepRunningUntilFailure keeps executing its child while it succeeds.
13
+ * Returns SUCCESS when child fails (goal achieved).
14
+ * Returns RUNNING while child succeeds (keep going).
15
+ */
16
+ export class KeepRunningUntilFailure extends DecoratorNode {
17
+ async executeTick(context: TemporalContext): Promise<NodeStatus> {
18
+ checkSignal(context.signal);
19
+
20
+ if (!this.child) {
21
+ throw new ConfigurationError(
22
+ "KeepRunningUntilFailure requires a child",
23
+ );
24
+ }
25
+
26
+ const result = await this.child.tick(context);
27
+
28
+ switch (result) {
29
+ case NodeStatus.SUCCESS:
30
+ this.log("Child succeeded - resetting and continuing");
31
+ this.child.reset();
32
+ this._status = NodeStatus.RUNNING;
33
+ return NodeStatus.RUNNING;
34
+
35
+ case NodeStatus.FAILURE:
36
+ this.log("Child failed - goal achieved");
37
+ this._status = NodeStatus.SUCCESS;
38
+ return NodeStatus.SUCCESS;
39
+
40
+ case NodeStatus.RUNNING:
41
+ this.log("Child is running");
42
+ this._status = NodeStatus.RUNNING;
43
+ return NodeStatus.RUNNING;
44
+
45
+ default:
46
+ throw new Error(`Unexpected status from child: ${result}`);
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Precondition decorator configuration schema
3
+ */
4
+
5
+ import { z } from "zod";
6
+ import { nodeConfigurationSchema } from "../schemas/base.schema.js";
7
+
8
+ /**
9
+ * Schema for Precondition decorator configuration
10
+ * Uses base schema only - preconditions are set programmatically via API
11
+ */
12
+ export const preconditionConfigurationSchema = nodeConfigurationSchema;
13
+
14
+ /**
15
+ * Validated Precondition configuration type
16
+ */
17
+ export type ValidatedPreconditionConfiguration = z.infer<
18
+ typeof preconditionConfigurationSchema
19
+ >;