groundswell 0.0.1 → 0.0.2

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 (242) hide show
  1. package/.claude/commands/subtask-planning/prp-base-create.md +120 -0
  2. package/.claude/commands/subtask-planning/prp-base-execute.md +65 -0
  3. package/.claude/commands/task-breakdown.md +94 -0
  4. package/.claude/system_prompts/task-breakdown.md +1 -0
  5. package/CHANGELOG.md +188 -0
  6. package/PRD.md +543 -0
  7. package/README.md +99 -5
  8. package/examples/README.md +15 -1
  9. package/examples/examples/11-reparenting-workflows.ts +269 -0
  10. package/examples/index.ts +4 -0
  11. package/package-lock.json +2398 -0
  12. package/package.json +3 -1
  13. package/plan/001_d3bb02af4886/TEST_RESULTS.md +259 -0
  14. package/plan/001_d3bb02af4886/bug_fix_tasks.json +484 -0
  15. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S1/PRP.md +488 -0
  16. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S2/PRP.md +581 -0
  17. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S3/PRP.md +687 -0
  18. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S1/PRP.md +492 -0
  19. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/PRP.md +932 -0
  20. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/concurrent_error_testing_patterns.md +1109 -0
  21. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/vitest_concurrent_testing.md +802 -0
  22. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/workflow_engine_test_references.md +603 -0
  23. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S1/PRP.md +564 -0
  24. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S3/PRP.md +518 -0
  25. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S4/PRP.md +1252 -0
  26. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/PRP.md +364 -0
  27. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/CODEBASE_INVENTORY.md +114 -0
  28. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/DECORATOR_DOCUMENTATION_PATTERNS.md +205 -0
  29. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/PRD_LOCATION_ANALYSIS.md +199 -0
  30. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/ULTRATHINK_PRP_PLAN.md +134 -0
  31. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/PRP.md +495 -0
  32. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/research/console_error_inventory.md +435 -0
  33. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S2/PRP.md +506 -0
  34. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S3/PRP.md +612 -0
  35. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/PRP.md +558 -0
  36. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/research/external_research.md +788 -0
  37. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S2/PRP.md +460 -0
  38. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S3/PRP.md +454 -0
  39. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/PRP.md +520 -0
  40. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/RECOMMENDATION.md +417 -0
  41. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/external_workflow_engines_research.md +760 -0
  42. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/security_implications_analysis.md +245 -0
  43. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S2/PRP.md +792 -0
  44. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/PRP.md +535 -0
  45. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/TEST_EXECUTION_REPORT.md +190 -0
  46. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/PRP.md +654 -0
  47. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/TEST_FIX_REPORT.md +227 -0
  48. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/KEY_FINDINGS.md +345 -0
  49. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/QUICK_REFERENCE.md +193 -0
  50. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/test_maintenance_research.md +1323 -0
  51. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/BREAKING_CHANGES_AUDIT.md +1011 -0
  52. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/PRP.md +927 -0
  53. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S2/PRP.md +505 -0
  54. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/architecture/logger_child_signature_analysis.md +401 -0
  55. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/child_implementation_research.md +142 -0
  56. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/test_patterns_research.md +112 -0
  57. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/vitest_patterns_research.md +159 -0
  58. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/PRP.md +549 -0
  59. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/VERIFICATION_REPORT.md +368 -0
  60. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/edge_case_analysis.md +172 -0
  61. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/usage_inventory.md +175 -0
  62. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S2/PRP.md +696 -0
  63. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S4/PRP.md +860 -0
  64. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/PRP.md +1066 -0
  65. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01-testing-aggregated-errors.md +1103 -0
  66. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01_typescript_error_aggregation_patterns.md +789 -0
  67. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02-error-merge-strategy-testing-guide.md +1098 -0
  68. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02_aggregate_error_patterns.md +1037 -0
  69. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03-promise-allsettled-testing-patterns.md +916 -0
  70. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03_error_merging_strategies.md +1045 -0
  71. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/04_github_stackoverflow_examples.md +890 -0
  72. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/05_comprehensive_summary.md +822 -0
  73. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/INDEX.md +668 -0
  74. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/QUICK_REFERENCE.md +706 -0
  75. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/README.md +265 -0
  76. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/RESEARCH_REPORT.md +655 -0
  77. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S4/research/vitest_testing_patterns.md +1103 -0
  78. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T3S2/PRP.md +426 -0
  79. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/PRP.md +506 -0
  80. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/QUICK_REFERENCE.md +114 -0
  81. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/RESEARCH_SUMMARY.md +316 -0
  82. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/vitest_observer_error_logging_best_practices.md +754 -0
  83. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S3/PRP.md +612 -0
  84. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/PRP.md +719 -0
  85. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/README.md +215 -0
  86. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/analysis.md +765 -0
  87. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S3/PRP.md +718 -0
  88. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/DECISION.md +149 -0
  89. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/PRP.md +470 -0
  90. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/ULTRATHINK_PLAN.md +332 -0
  91. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/codebase_workflow_name_analysis.md +167 -0
  92. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/external_best_practices.md +265 -0
  93. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/validation_patterns.md +273 -0
  94. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S1/workflow_engine_ancestry_api_research.md +760 -0
  95. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S3-PRP.md +434 -0
  96. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S1/PRP.md +717 -0
  97. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/PRP.md +472 -0
  98. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/VALIDATION_REPORT.md +125 -0
  99. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/research/ULTRATHINK_PRP_PLAN.md +301 -0
  100. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/error-logging-best-practices.md +1170 -0
  101. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/research_typescript_partial_and_overloads.md +940 -0
  102. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-quick-reference.md +151 -0
  103. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-research.md +650 -0
  104. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/prd_snapshot.md +259 -0
  105. package/plan/001_d3bb02af4886/bugfix/P1M1T1S1/PRP.md +457 -0
  106. package/plan/001_d3bb02af4886/bugfix/RESEARCH_SUMMARY.md +346 -0
  107. package/plan/001_d3bb02af4886/bugfix/architecture/codebase_structure.md +311 -0
  108. package/plan/001_d3bb02af4886/bugfix/architecture/concurrent_execution_best_practices.md +1565 -0
  109. package/plan/001_d3bb02af4886/bugfix/architecture/error_handling_patterns.md +288 -0
  110. package/plan/001_d3bb02af4886/bugfix/architecture/promise_all_analysis.md +741 -0
  111. package/plan/001_d3bb02af4886/docs/PRP/P1M1T1S4-functional-workflow-error-state-capture-test.md +652 -0
  112. package/plan/001_d3bb02af4886/docs/PRP/PRP.md +527 -0
  113. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S1-PRP.md +415 -0
  114. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S2-PRP.md +378 -0
  115. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S4-PRP.md +713 -0
  116. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M2T1S4-PRP.md +370 -0
  117. package/plan/001_d3bb02af4886/docs/PRP_P1M3T1S3.md +499 -0
  118. package/plan/001_d3bb02af4886/docs/TEST_RESULTS.md +230 -0
  119. package/plan/001_d3bb02af4886/docs/bugfix/ANALYSIS_PRD_VS_IMPLEMENTATION.md +1134 -0
  120. package/plan/001_d3bb02af4886/docs/bugfix/GAP_ANALYSIS_SUMMARY.md +179 -0
  121. package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/PRP.md +629 -0
  122. package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/validation-report.md +214 -0
  123. package/plan/001_d3bb02af4886/docs/bugfix/PRP_P1M4T2S3.md +629 -0
  124. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_PRP.md +529 -0
  125. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_QUICK_REFERENCE.md +142 -0
  126. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_README.md +304 -0
  127. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_TEST_RESULTS.md +558 -0
  128. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_VALIDATION_SUMMARY.md +256 -0
  129. package/plan/001_d3bb02af4886/docs/bugfix/system_context.md +346 -0
  130. package/plan/001_d3bb02af4886/docs/bugfix-architecture/bug_analysis.md +415 -0
  131. package/plan/001_d3bb02af4886/docs/bugfix-architecture/implementation_patterns.md +489 -0
  132. package/plan/001_d3bb02af4886/docs/bugfix-architecture/system_context.md +218 -0
  133. package/plan/001_d3bb02af4886/docs/bugfix_INITIATION_SUMMARY.md +380 -0
  134. package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_PATTERNS.md +1923 -0
  135. package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_QUICK_REF.md +319 -0
  136. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/codebase-context.md +115 -0
  137. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/cycle-detection-algorithms.md +134 -0
  138. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/test-patterns.md +153 -0
  139. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/workflow-class.md +132 -0
  140. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_BEST_PRACTICES.md +716 -0
  141. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_QUICK_REF.md +186 -0
  142. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/GROUNDSWELL_DECORATOR_EXAMPLES.md +604 -0
  143. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/INDEX.md +213 -0
  144. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/codebase_structure.md +30 -0
  145. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/existing_test_pattern.md +56 -0
  146. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/getRootObservers_implementation.md +53 -0
  147. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/test_conventions.md +49 -0
  148. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/PRP.md +958 -0
  149. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/QUICK_REFERENCE.md +339 -0
  150. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/README.md +305 -0
  151. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/SUMMARY.md +433 -0
  152. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/bidirectional-tree-consistency-testing.md +1574 -0
  153. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/test-pattern-examples.md +1014 -0
  154. package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_QUICK_REF.md +376 -0
  155. package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_RESEARCH.md +1507 -0
  156. package/plan/001_d3bb02af4886/docs/research/bugfix_typescript_patterns.md +949 -0
  157. package/plan/001_d3bb02af4886/docs/research/error-testing-research.md +619 -0
  158. package/plan/001_d3bb02af4886/docs/research/error_handling_patterns.md +723 -0
  159. package/plan/{research → 001_d3bb02af4886/docs/research/general}/introspection-security-guide.md +56 -0
  160. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/PRP_TEMPLATE.md +460 -0
  161. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/QUICK_REFERENCE.md +324 -0
  162. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/README.md +175 -0
  163. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/RESEARCH_REPORT.md +499 -0
  164. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/SUMMARY.md +163 -0
  165. package/plan/bugfix/BUG_FIX_SUMMARY.md +961 -0
  166. package/src/__tests__/adversarial/attachChild-performance.test.ts +216 -0
  167. package/src/__tests__/adversarial/circular-reference.test.ts +101 -0
  168. package/src/__tests__/adversarial/complex-circular-reference.test.ts +139 -0
  169. package/src/__tests__/adversarial/concurrent-task-failures.test.ts +571 -0
  170. package/src/__tests__/adversarial/deep-analysis.test.ts +729 -0
  171. package/src/__tests__/adversarial/deep-hierarchy-stress.test.ts +213 -0
  172. package/src/__tests__/adversarial/e2e-prd-validation.test.ts +448 -0
  173. package/src/__tests__/adversarial/edge-case.test.ts +703 -0
  174. package/src/__tests__/adversarial/error-merge-strategy.test.ts +760 -0
  175. package/src/__tests__/adversarial/incremental-performance.test.ts +140 -0
  176. package/src/__tests__/adversarial/node-map-update-benchmarks.test.ts +457 -0
  177. package/src/__tests__/adversarial/observer-propagation.test.ts +487 -0
  178. package/src/__tests__/adversarial/parent-validation.test.ts +143 -0
  179. package/src/__tests__/adversarial/prd-12-2-compliance.test.ts +611 -0
  180. package/src/__tests__/adversarial/prd-compliance.test.ts +731 -0
  181. package/src/__tests__/compatibility/backward-compatibility.test.ts +1572 -0
  182. package/src/__tests__/helpers/index.ts +18 -0
  183. package/src/__tests__/helpers/tree-verification.ts +257 -0
  184. package/src/__tests__/integration/bidirectional-consistency.test.ts +847 -0
  185. package/src/__tests__/integration/observer-logging.test.ts +643 -0
  186. package/src/__tests__/integration/tree-mirroring.test.ts +37 -0
  187. package/src/__tests__/integration/workflow-reparenting.test.ts +303 -0
  188. package/src/__tests__/unit/context.test.ts +79 -0
  189. package/src/__tests__/unit/logger.test.ts +293 -0
  190. package/src/__tests__/unit/observable.test.ts +321 -0
  191. package/src/__tests__/unit/tree-debugger-incremental.test.ts +170 -0
  192. package/src/__tests__/unit/utils/workflow-error-utils.test.ts +209 -0
  193. package/src/__tests__/unit/workflow-detachChild.test.ts +100 -0
  194. package/src/__tests__/unit/workflow-emitEvent-childDetached.test.ts +153 -0
  195. package/src/__tests__/unit/workflow-isDescendantOf.test.ts +180 -0
  196. package/src/__tests__/unit/workflow.test.ts +277 -1
  197. package/src/core/agent.ts +21 -1
  198. package/src/core/logger.ts +27 -2
  199. package/src/core/workflow-context.ts +6 -4
  200. package/src/core/workflow.ts +252 -14
  201. package/src/debugger/tree-debugger.ts +52 -7
  202. package/src/decorators/task.ts +65 -2
  203. package/src/index.ts +4 -2
  204. package/src/types/decorators.ts +8 -1
  205. package/src/types/events.ts +1 -0
  206. package/src/utils/index.ts +1 -0
  207. package/src/utils/observable.ts +32 -3
  208. package/src/utils/workflow-error-utils.ts +56 -0
  209. package/tsconfig.json +1 -1
  210. package/llms_full.txt +0 -5890
  211. package/tasks.json +0 -0
  212. /package/plan/{backlog.json → 001_d3bb02af4886/backlog.json} +0 -0
  213. /package/plan/{P1P2/PRP.md → 001_d3bb02af4886/docs/PRP/P1P2-PRP.md} +0 -0
  214. /package/plan/{P3P4/PRP.md → 001_d3bb02af4886/docs/PRP/P3P4-PRP.md} +0 -0
  215. /package/plan/{P4P5/PRP.md → 001_d3bb02af4886/docs/PRP/P4P5-PRP.md} +0 -0
  216. /package/plan/{architecture → 001_d3bb02af4886/docs/architecture}/external_deps.md +0 -0
  217. /package/plan/{architecture → 001_d3bb02af4886/docs/architecture}/system_context.md +0 -0
  218. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_BEST_PRACTICES.md +0 -0
  219. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_CODE_PATTERNS.md +0 -0
  220. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_INTEGRATION_GUIDE.md +0 -0
  221. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_RESEARCH_INDEX.md +0 -0
  222. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/REFLECTION_INDEX.md +0 -0
  223. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/REFLECTION_RESEARCH_REPORT.md +0 -0
  224. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/RESEARCH_SUMMARY.md +0 -0
  225. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/anthropic-sdk.md +0 -0
  226. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/async-local-storage.md +0 -0
  227. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-code-patterns.md +0 -0
  228. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-decision-matrix.md +0 -0
  229. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-implementation-guide.md +0 -0
  230. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-integration-guide.md +0 -0
  231. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-patterns.md +0 -0
  232. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-quick-reference.md +0 -0
  233. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/zod-schema.md +0 -0
  234. /package/plan/{P3P4/research → 001_d3bb02af4886/docs/research/P3P4}/caching-lru.md +0 -0
  235. /package/plan/{P3P4/research → 001_d3bb02af4886/docs/research/P3P4}/introspection-tools.md +0 -0
  236. /package/plan/{P3P4/research → 001_d3bb02af4886/docs/research/P3P4}/reflection-patterns.md +0 -0
  237. /package/plan/{P4P5/research → 001_d3bb02af4886/docs/research/P4P5}/RESEARCH_SUMMARY.md +0 -0
  238. /package/plan/{research → 001_d3bb02af4886/docs/research/general}/INTROSPECTION_RESEARCH_SUMMARY.md +0 -0
  239. /package/plan/{research → 001_d3bb02af4886/docs/research/general}/README-INTROSPECTION.md +0 -0
  240. /package/plan/{research → 001_d3bb02af4886/docs/research/general}/agent-introspection-patterns.md +0 -0
  241. /package/plan/{research → 001_d3bb02af4886/docs/research/general}/introspection-tool-examples.md +0 -0
  242. /package/{PRPs/PRDs/001-hierarchical-workflow-engine.md → plan/001_d3bb02af4886/prd_snapshot.md} +0 -0
@@ -0,0 +1,321 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { Observable, ObservableLogger } from '../../utils/observable';
3
+
4
+ describe('Observable', () => {
5
+ describe('with logger injection', () => {
6
+ let mockLogger: ObservableLogger;
7
+
8
+ beforeEach(() => {
9
+ mockLogger = {
10
+ error: vi.fn(),
11
+ };
12
+ });
13
+
14
+ it('should log subscriber next() errors via logger', () => {
15
+ const observable = new Observable<number>(mockLogger);
16
+ const testError = new Error('Next error');
17
+
18
+ const throwingSubscriber = {
19
+ next: () => {
20
+ throw testError;
21
+ },
22
+ };
23
+
24
+ observable.subscribe(throwingSubscriber);
25
+ observable.next(42);
26
+
27
+ expect(mockLogger.error).toHaveBeenCalledWith('Observable subscriber error', {
28
+ error: testError,
29
+ });
30
+ });
31
+
32
+ it('should log subscriber error() errors via logger', () => {
33
+ const observable = new Observable<number>(mockLogger);
34
+ const testError = new Error('Error handler failed');
35
+ const handlerError = new Error('Handler threw');
36
+
37
+ const throwingSubscriber = {
38
+ error: () => {
39
+ throw handlerError;
40
+ },
41
+ };
42
+
43
+ observable.subscribe(throwingSubscriber);
44
+ observable.error(testError);
45
+
46
+ expect(mockLogger.error).toHaveBeenCalledWith('Observable error handler failed', {
47
+ error: handlerError,
48
+ });
49
+ });
50
+
51
+ it('should log subscriber complete() errors via logger', () => {
52
+ const observable = new Observable<number>(mockLogger);
53
+ const completeError = new Error('Complete handler failed');
54
+
55
+ const throwingSubscriber = {
56
+ complete: () => {
57
+ throw completeError;
58
+ },
59
+ };
60
+
61
+ observable.subscribe(throwingSubscriber);
62
+ observable.complete();
63
+
64
+ expect(mockLogger.error).toHaveBeenCalledWith('Observable complete handler failed', {
65
+ error: completeError,
66
+ });
67
+ });
68
+
69
+ it('should continue notifying other subscribers after one throws', () => {
70
+ const observable = new Observable<number>(mockLogger);
71
+ const testError = new Error('First subscriber error');
72
+
73
+ const results: number[] = [];
74
+
75
+ const throwingSubscriber = {
76
+ next: () => {
77
+ throw testError;
78
+ },
79
+ };
80
+
81
+ const workingSubscriber = {
82
+ next: (value: number) => {
83
+ results.push(value);
84
+ },
85
+ };
86
+
87
+ observable.subscribe(throwingSubscriber);
88
+ observable.subscribe(workingSubscriber);
89
+ observable.next(42);
90
+
91
+ expect(results).toEqual([42]);
92
+ expect(mockLogger.error).toHaveBeenCalled();
93
+ });
94
+
95
+ it('should handle multiple throwing subscribers', () => {
96
+ const observable = new Observable<number>(mockLogger);
97
+ const error1 = new Error('Error 1');
98
+ const error2 = new Error('Error 2');
99
+
100
+ const throwingSubscriber1 = {
101
+ next: () => {
102
+ throw error1;
103
+ },
104
+ };
105
+
106
+ const throwingSubscriber2 = {
107
+ next: () => {
108
+ throw error2;
109
+ },
110
+ };
111
+
112
+ observable.subscribe(throwingSubscriber1);
113
+ observable.subscribe(throwingSubscriber2);
114
+ observable.next(42);
115
+
116
+ expect(mockLogger.error).toHaveBeenCalledTimes(2);
117
+ expect(mockLogger.error).toHaveBeenNthCalledWith(1, 'Observable subscriber error', {
118
+ error: error1,
119
+ });
120
+ expect(mockLogger.error).toHaveBeenNthCalledWith(2, 'Observable subscriber error', {
121
+ error: error2,
122
+ });
123
+ });
124
+ });
125
+
126
+ describe('without logger (fallback)', () => {
127
+ it('should fall back to console.error when no logger provided', () => {
128
+ const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
129
+ const observable = new Observable<number>();
130
+ const testError = new Error('Next error');
131
+
132
+ const throwingSubscriber = {
133
+ next: () => {
134
+ throw testError;
135
+ },
136
+ };
137
+
138
+ observable.subscribe(throwingSubscriber);
139
+ observable.next(42);
140
+
141
+ expect(consoleErrorSpy).toHaveBeenCalledWith('Observable subscriber error', testError);
142
+ consoleErrorSpy.mockRestore();
143
+ });
144
+
145
+ it('should fall back to console.error for error() method', () => {
146
+ const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
147
+ const observable = new Observable<number>();
148
+ const handlerError = new Error('Handler threw');
149
+
150
+ const throwingSubscriber = {
151
+ error: () => {
152
+ throw handlerError;
153
+ },
154
+ };
155
+
156
+ observable.subscribe(throwingSubscriber);
157
+ observable.error(new Error('Original error'));
158
+
159
+ expect(consoleErrorSpy).toHaveBeenCalledWith('Observable error handler failed', handlerError);
160
+ consoleErrorSpy.mockRestore();
161
+ });
162
+
163
+ it('should fall back to console.error for complete() method', () => {
164
+ const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
165
+ const observable = new Observable<number>();
166
+ const completeError = new Error('Complete threw');
167
+
168
+ const throwingSubscriber = {
169
+ complete: () => {
170
+ throw completeError;
171
+ },
172
+ };
173
+
174
+ observable.subscribe(throwingSubscriber);
175
+ observable.complete();
176
+
177
+ expect(consoleErrorSpy).toHaveBeenCalledWith('Observable complete handler failed', completeError);
178
+ consoleErrorSpy.mockRestore();
179
+ });
180
+ });
181
+
182
+ describe('backward compatibility', () => {
183
+ it('should work without any constructor arguments', () => {
184
+ const observable = new Observable<number>();
185
+ const results: number[] = [];
186
+
187
+ const subscriber = {
188
+ next: (value: number) => {
189
+ results.push(value);
190
+ },
191
+ };
192
+
193
+ observable.subscribe(subscriber);
194
+ observable.next(1);
195
+ observable.next(2);
196
+ observable.next(3);
197
+
198
+ expect(results).toEqual([1, 2, 3]);
199
+ });
200
+
201
+ it('should support subscribe/unsubscribe cycle', () => {
202
+ const observable = new Observable<number>();
203
+ const results: number[] = [];
204
+
205
+ const subscriber = {
206
+ next: (value: number) => {
207
+ results.push(value);
208
+ },
209
+ };
210
+
211
+ const subscription = observable.subscribe(subscriber);
212
+ observable.next(1);
213
+ subscription.unsubscribe();
214
+ observable.next(2);
215
+
216
+ expect(results).toEqual([1]);
217
+ });
218
+
219
+ it('should report subscriber count correctly', () => {
220
+ const observable = new Observable<number>();
221
+
222
+ const subscriber1 = { next: () => {} };
223
+ const subscriber2 = { next: () => {} };
224
+
225
+ expect(observable.subscriberCount).toBe(0);
226
+
227
+ const sub1 = observable.subscribe(subscriber1);
228
+ expect(observable.subscriberCount).toBe(1);
229
+
230
+ const sub2 = observable.subscribe(subscriber2);
231
+ expect(observable.subscriberCount).toBe(2);
232
+
233
+ sub1.unsubscribe();
234
+ expect(observable.subscriberCount).toBe(1);
235
+
236
+ sub2.unsubscribe();
237
+ expect(observable.subscriberCount).toBe(0);
238
+ });
239
+
240
+ it('should clear subscribers on complete', () => {
241
+ const observable = new Observable<number>();
242
+ const subscriber = { next: () => {}, complete: () => {} };
243
+
244
+ observable.subscribe(subscriber);
245
+ expect(observable.subscriberCount).toBe(1);
246
+
247
+ observable.complete();
248
+ expect(observable.subscriberCount).toBe(0);
249
+ });
250
+ });
251
+
252
+ describe('error isolation', () => {
253
+ let mockLogger: ObservableLogger;
254
+
255
+ beforeEach(() => {
256
+ mockLogger = {
257
+ error: vi.fn(),
258
+ };
259
+ });
260
+
261
+ it('should not propagate errors outside try-catch', () => {
262
+ const observable = new Observable<number>(mockLogger);
263
+ const testError = new Error('Subscriber error');
264
+
265
+ const throwingSubscriber = {
266
+ next: () => {
267
+ throw testError;
268
+ },
269
+ };
270
+
271
+ observable.subscribe(throwingSubscriber);
272
+
273
+ // This should not throw
274
+ expect(() => {
275
+ observable.next(42);
276
+ }).not.toThrow();
277
+
278
+ expect(mockLogger.error).toHaveBeenCalled();
279
+ });
280
+
281
+ it('should handle undefined optional callbacks', () => {
282
+ const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
283
+ const observable = new Observable<number>();
284
+
285
+ const subscriberWithMissingCallbacks = {
286
+ // next is undefined
287
+ // error is undefined
288
+ // complete is undefined
289
+ };
290
+
291
+ observable.subscribe(subscriberWithMissingCallbacks);
292
+
293
+ // Should not throw when callbacks are undefined
294
+ expect(() => {
295
+ observable.next(42);
296
+ observable.error(new Error('test'));
297
+ observable.complete();
298
+ }).not.toThrow();
299
+
300
+ consoleErrorSpy.mockRestore();
301
+ });
302
+ });
303
+
304
+ describe('ObservableLogger interface', () => {
305
+ it('should match WorkflowLogger.error() signature', () => {
306
+ const mockLogger: ObservableLogger = {
307
+ error: vi.fn(),
308
+ };
309
+
310
+ const observable = new Observable<number>(mockLogger);
311
+
312
+ // Test the signature matches: error(message: string, data?: unknown): void
313
+ mockLogger.error('test message');
314
+ mockLogger.error('test message', { key: 'value' });
315
+ mockLogger.error('test message', { error: new Error('test') });
316
+ mockLogger.error('test message', undefined);
317
+
318
+ expect(mockLogger.error).toHaveBeenCalledTimes(4);
319
+ });
320
+ });
321
+ });
@@ -0,0 +1,170 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { Workflow, WorkflowTreeDebugger } from '../../index.js';
3
+
4
+ class IncrementalTestWorkflow extends Workflow {
5
+ async run(): Promise<void> {
6
+ this.setStatus('completed');
7
+ }
8
+ }
9
+
10
+ describe('Incremental Node Map Updates', () => {
11
+ it('childDetached removes entire subtree (node + descendants)', () => {
12
+ const root = new IncrementalTestWorkflow('Root');
13
+ const child1 = new IncrementalTestWorkflow('Child1', root);
14
+ const grandchild = new IncrementalTestWorkflow('Grandchild', child1);
15
+ const child2 = new IncrementalTestWorkflow('Child2', root);
16
+
17
+ const debugger_ = new WorkflowTreeDebugger(root);
18
+
19
+ // Verify all nodes are initially in the map
20
+ expect(debugger_.getNode(root.id)).toBe(root.getNode());
21
+ expect(debugger_.getNode(child1.id)).toBe(child1.getNode());
22
+ expect(debugger_.getNode(grandchild.id)).toBe(grandchild.getNode());
23
+ expect(debugger_.getNode(child2.id)).toBe(child2.getNode());
24
+ expect(debugger_.getStats().totalNodes).toBe(4);
25
+
26
+ // Detach child1 (should remove child1 + grandchild)
27
+ root.detachChild(child1);
28
+
29
+ // Verify child1 and grandchild are removed
30
+ expect(debugger_.getNode(child1.id)).toBeUndefined();
31
+ expect(debugger_.getNode(grandchild.id)).toBeUndefined();
32
+
33
+ // Verify root and child2 are still present
34
+ expect(debugger_.getNode(root.id)).toBe(root.getNode());
35
+ expect(debugger_.getNode(child2.id)).toBe(child2.getNode());
36
+
37
+ // Verify total node count decreased by 2
38
+ expect(debugger_.getStats().totalNodes).toBe(2);
39
+ });
40
+
41
+ it('childDetached on already-removed node is no-op', () => {
42
+ const root = new IncrementalTestWorkflow('Root');
43
+ const child1 = new IncrementalTestWorkflow('Child1', root);
44
+ const grandchild = new IncrementalTestWorkflow('Grandchild', child1);
45
+
46
+ const debugger_ = new WorkflowTreeDebugger(root);
47
+ expect(debugger_.getStats().totalNodes).toBe(3);
48
+
49
+ // Detach child1
50
+ root.detachChild(child1);
51
+ expect(debugger_.getStats().totalNodes).toBe(1);
52
+ expect(debugger_.getNode(child1.id)).toBeUndefined();
53
+ expect(debugger_.getNode(grandchild.id)).toBeUndefined();
54
+
55
+ // Simulate the edge case where nodeMap still has orphaned nodes
56
+ // by directly removing a node that was never properly attached
57
+ // This tests the removeSubtreeNodes() no-op behavior
58
+ const orphanId = 'nonexistent-node';
59
+ expect(debugger_.getNode(orphanId)).toBeUndefined();
60
+
61
+ // Calling removeSubtreeNodes on a non-existent node should be safe
62
+ // We can't call detachChild twice because it throws, but we can
63
+ // verify the nodeMap state is consistent
64
+ expect(debugger_.getStats().totalNodes).toBe(1);
65
+ });
66
+
67
+ it('childAttached adds subtree (verify existing behavior)', () => {
68
+ const root = new IncrementalTestWorkflow('Root');
69
+
70
+ const debugger_ = new WorkflowTreeDebugger(root);
71
+ expect(debugger_.getStats().totalNodes).toBe(1);
72
+
73
+ // Attach a child with its own subtree
74
+ const child1 = new IncrementalTestWorkflow('Child1', root);
75
+ const grandchild = new IncrementalTestWorkflow('Grandchild', child1);
76
+
77
+ // Verify all nodes are in the map
78
+ expect(debugger_.getNode(root.id)).toBe(root.getNode());
79
+ expect(debugger_.getNode(child1.id)).toBe(child1.getNode());
80
+ expect(debugger_.getNode(grandchild.id)).toBe(grandchild.getNode());
81
+ expect(debugger_.getStats().totalNodes).toBe(3);
82
+ });
83
+
84
+ it('onTreeChanged does not rebuild map', () => {
85
+ const root = new IncrementalTestWorkflow('Root');
86
+ const child1 = new IncrementalTestWorkflow('Child1', root);
87
+ const grandchild = new IncrementalTestWorkflow('Grandchild', child1);
88
+ const child2 = new IncrementalTestWorkflow('Child2', root);
89
+
90
+ const debugger_ = new WorkflowTreeDebugger(root);
91
+
92
+ // Get reference to the nodeMap (we'll check it's the same object)
93
+ const nodeMapBefore = debugger_.getStats();
94
+
95
+ // Detach child1
96
+ root.detachChild(child1);
97
+
98
+ // Verify map was updated incrementally (nodes removed)
99
+ expect(debugger_.getStats().totalNodes).toBe(2);
100
+ expect(debugger_.getNode(child1.id)).toBeUndefined();
101
+ expect(debugger_.getNode(grandchild.id)).toBeUndefined();
102
+
103
+ // Verify remaining nodes are still accessible
104
+ expect(debugger_.getNode(root.id)).toBe(root.getNode());
105
+ expect(debugger_.getNode(child2.id)).toBe(child2.getNode());
106
+ });
107
+
108
+ it('multiple rapid attach/detach operations work correctly', () => {
109
+ const root = new IncrementalTestWorkflow('Root');
110
+ const child1 = new IncrementalTestWorkflow('Child1', root);
111
+ const child2 = new IncrementalTestWorkflow('Child2', root);
112
+ const grandchild1 = new IncrementalTestWorkflow('Grandchild1', child1);
113
+ const grandchild2 = new IncrementalTestWorkflow('Grandchild2', child1);
114
+
115
+ const debugger_ = new WorkflowTreeDebugger(root);
116
+ expect(debugger_.getStats().totalNodes).toBe(5);
117
+
118
+ // Detach child1 (removes child1 + 2 grandchildren)
119
+ root.detachChild(child1);
120
+ expect(debugger_.getStats().totalNodes).toBe(2);
121
+
122
+ // Attach a new child
123
+ const child3 = new IncrementalTestWorkflow('Child3', root);
124
+ expect(debugger_.getStats().totalNodes).toBe(3);
125
+ expect(debugger_.getNode(child3.id)).toBe(child3.getNode());
126
+
127
+ // Detach child2
128
+ root.detachChild(child2);
129
+ expect(debugger_.getStats().totalNodes).toBe(2);
130
+
131
+ // Verify final state
132
+ expect(debugger_.getNode(root.id)).toBe(root.getNode());
133
+ expect(debugger_.getNode(child3.id)).toBe(child3.getNode());
134
+ expect(debugger_.getNode(child1.id)).toBeUndefined();
135
+ expect(debugger_.getNode(child2.id)).toBeUndefined();
136
+ expect(debugger_.getNode(grandchild1.id)).toBeUndefined();
137
+ expect(debugger_.getNode(grandchild2.id)).toBeUndefined();
138
+ });
139
+
140
+ it('detaching node with many descendants removes all', () => {
141
+ const root = new IncrementalTestWorkflow('Root');
142
+
143
+ // Build a deep subtree
144
+ const child1 = new IncrementalTestWorkflow('Child1', root);
145
+ let current = child1;
146
+ const descendants: IncrementalTestWorkflow[] = [];
147
+ for (let i = 0; i < 10; i++) {
148
+ const descendant = new IncrementalTestWorkflow(`Descendant${i}`, current);
149
+ descendants.push(descendant);
150
+ current = descendant;
151
+ }
152
+
153
+ const debugger_ = new WorkflowTreeDebugger(root);
154
+ // Total: 1 root + 1 child1 + 10 descendants = 12 nodes
155
+ expect(debugger_.getStats().totalNodes).toBe(12);
156
+
157
+ // Detach child1 (should remove child1 + all 10 descendants)
158
+ root.detachChild(child1);
159
+
160
+ // Verify all were removed
161
+ expect(debugger_.getStats().totalNodes).toBe(1);
162
+ expect(debugger_.getNode(child1.id)).toBeUndefined();
163
+ for (const descendant of descendants) {
164
+ expect(debugger_.getNode(descendant.id)).toBeUndefined();
165
+ }
166
+
167
+ // Verify root is still there
168
+ expect(debugger_.getNode(root.id)).toBe(root.getNode());
169
+ });
170
+ });
@@ -0,0 +1,209 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { mergeWorkflowErrors } from '../../../utils/workflow-error-utils.js';
3
+ import type { WorkflowError } from '../../../types/error.js';
4
+
5
+ describe('mergeWorkflowErrors', () => {
6
+ // Helper function to create a mock WorkflowError
7
+ function createMockWorkflowError(overrides?: Partial<WorkflowError>): WorkflowError {
8
+ return {
9
+ message: 'Test error',
10
+ original: new Error('Original error'),
11
+ workflowId: 'wf-test-123',
12
+ stack: 'Error: Test error\n at test.ts:10:15',
13
+ state: { key: 'value' },
14
+ logs: [
15
+ {
16
+ id: 'log-1',
17
+ workflowId: 'wf-test-123',
18
+ timestamp: Date.now(),
19
+ level: 'error',
20
+ message: 'Test log message',
21
+ },
22
+ ],
23
+ ...overrides,
24
+ };
25
+ }
26
+
27
+ it('should return a single error when merging one error', () => {
28
+ const error = createMockWorkflowError({ workflowId: 'wf-1' });
29
+ const result = mergeWorkflowErrors([error], 'testTask', 'parent-wf', 1);
30
+
31
+ expect(result.message).toBe("1 of 1 concurrent child workflows failed in task 'testTask'");
32
+ expect(result.workflowId).toBe('parent-wf');
33
+ expect(result.logs).toEqual(error.logs);
34
+ expect(result.stack).toBe(error.stack);
35
+ expect(result.state).toEqual(error.state);
36
+ });
37
+
38
+ it('should aggregate multiple errors with unique workflow IDs', () => {
39
+ const error1 = createMockWorkflowError({
40
+ message: 'Error 1',
41
+ workflowId: 'wf-1',
42
+ stack: 'stack 1',
43
+ state: { key1: 'value1' },
44
+ logs: [{ id: 'log-1', workflowId: 'wf-1', timestamp: 1000, level: 'error', message: 'Log 1' }],
45
+ });
46
+ const error2 = createMockWorkflowError({
47
+ message: 'Error 2',
48
+ workflowId: 'wf-2',
49
+ stack: 'stack 2',
50
+ state: { key2: 'value2' },
51
+ logs: [{ id: 'log-2', workflowId: 'wf-2', timestamp: 2000, level: 'error', message: 'Log 2' }],
52
+ });
53
+ const error3 = createMockWorkflowError({
54
+ message: 'Error 3',
55
+ workflowId: 'wf-3',
56
+ stack: 'stack 3',
57
+ state: { key3: 'value3' },
58
+ logs: [{ id: 'log-3', workflowId: 'wf-3', timestamp: 3000, level: 'error', message: 'Log 3' }],
59
+ });
60
+
61
+ const result = mergeWorkflowErrors([error1, error2, error3], 'concurrentTask', 'parent-wf', 5);
62
+
63
+ expect(result.message).toBe("3 of 5 concurrent child workflows failed in task 'concurrentTask'");
64
+ expect(result.workflowId).toBe('parent-wf');
65
+ expect(result.stack).toBe('stack 1'); // First error's stack
66
+ expect(result.state).toEqual({ key1: 'value1' }); // First error's state
67
+ expect(result.logs).toHaveLength(3); // All logs aggregated
68
+ });
69
+
70
+ it('should deduplicate workflow IDs when errors have duplicate IDs', () => {
71
+ const error1 = createMockWorkflowError({ workflowId: 'wf-dup' });
72
+ const error2 = createMockWorkflowError({ workflowId: 'wf-dup' });
73
+ const error3 = createMockWorkflowError({ workflowId: 'wf-unique' });
74
+
75
+ const result = mergeWorkflowErrors([error1, error2, error3], 'testTask', 'parent-wf', 4);
76
+
77
+ // Access the metadata from original field
78
+ const metadata = result.original as {
79
+ name: string;
80
+ message: string;
81
+ errors: WorkflowError[];
82
+ totalChildren: number;
83
+ failedChildren: number;
84
+ failedWorkflowIds: string[];
85
+ };
86
+
87
+ expect(metadata.failedWorkflowIds).toEqual(['wf-dup', 'wf-unique']);
88
+ expect(metadata.failedWorkflowIds).toHaveLength(2); // Deduplicated
89
+ });
90
+
91
+ it('should flatten logs arrays from all errors using flatMap', () => {
92
+ const error1 = createMockWorkflowError({
93
+ workflowId: 'wf-1',
94
+ logs: [
95
+ { id: 'log-1', workflowId: 'wf-1', timestamp: 1000, level: 'info', message: 'Log 1.1' },
96
+ { id: 'log-2', workflowId: 'wf-1', timestamp: 2000, level: 'info', message: 'Log 1.2' },
97
+ ],
98
+ });
99
+ const error2 = createMockWorkflowError({
100
+ workflowId: 'wf-2',
101
+ logs: [
102
+ { id: 'log-3', workflowId: 'wf-2', timestamp: 3000, level: 'error', message: 'Log 2.1' },
103
+ { id: 'log-4', workflowId: 'wf-2', timestamp: 4000, level: 'error', message: 'Log 2.2' },
104
+ ],
105
+ });
106
+
107
+ const result = mergeWorkflowErrors([error1, error2], 'testTask', 'parent-wf', 2);
108
+
109
+ expect(result.logs).toHaveLength(4);
110
+ expect(result.logs[0].message).toBe('Log 1.1');
111
+ expect(result.logs[1].message).toBe('Log 1.2');
112
+ expect(result.logs[2].message).toBe('Log 2.1');
113
+ expect(result.logs[3].message).toBe('Log 2.2');
114
+ });
115
+
116
+ it('should use first error stack trace', () => {
117
+ const error1 = createMockWorkflowError({ stack: 'First stack trace' });
118
+ const error2 = createMockWorkflowError({ stack: 'Second stack trace' });
119
+ const error3 = createMockWorkflowError({ stack: 'Third stack trace' });
120
+
121
+ const result = mergeWorkflowErrors([error1, error2, error3], 'testTask', 'parent-wf', 3);
122
+
123
+ expect(result.stack).toBe('First stack trace');
124
+ });
125
+
126
+ it('should use first error state', () => {
127
+ const error1 = createMockWorkflowError({ state: { first: 'state1' } });
128
+ const error2 = createMockWorkflowError({ state: { second: 'state2' } });
129
+
130
+ const result = mergeWorkflowErrors([error1, error2], 'testTask', 'parent-wf', 2);
131
+
132
+ expect(result.state).toEqual({ first: 'state1' });
133
+ });
134
+
135
+ it('should use empty object when first error has no state', () => {
136
+ const error1 = createMockWorkflowError({ state: undefined as any });
137
+ const error2 = createMockWorkflowError({ state: { hasState: 'yes' } });
138
+
139
+ const result = mergeWorkflowErrors([error1, error2], 'testTask', 'parent-wf', 2);
140
+
141
+ expect(result.state).toEqual({});
142
+ });
143
+
144
+ it('should handle undefined stack trace gracefully', () => {
145
+ const error1 = createMockWorkflowError({ stack: undefined });
146
+ const error2 = createMockWorkflowError({ stack: 'Has stack' });
147
+
148
+ const result = mergeWorkflowErrors([error1, error2], 'testTask', 'parent-wf', 2);
149
+
150
+ expect(result.stack).toBeUndefined();
151
+ });
152
+
153
+ it('should include metadata in original field', () => {
154
+ const error1 = createMockWorkflowError({ workflowId: 'wf-1' });
155
+ const error2 = createMockWorkflowError({ workflowId: 'wf-2' });
156
+ const error3 = createMockWorkflowError({ workflowId: 'wf-3' });
157
+
158
+ const result = mergeWorkflowErrors([error1, error2, error3], 'concurrentTask', 'parent-wf', 5);
159
+
160
+ const metadata = result.original as {
161
+ name: string;
162
+ message: string;
163
+ errors: WorkflowError[];
164
+ totalChildren: number;
165
+ failedChildren: number;
166
+ failedWorkflowIds: string[];
167
+ };
168
+
169
+ expect(metadata.name).toBe('WorkflowAggregateError');
170
+ expect(metadata.message).toBe("3 of 5 concurrent child workflows failed in task 'concurrentTask'");
171
+ expect(metadata.errors).toEqual([error1, error2, error3]);
172
+ expect(metadata.totalChildren).toBe(5);
173
+ expect(metadata.failedChildren).toBe(3);
174
+ expect(metadata.failedWorkflowIds).toEqual(['wf-1', 'wf-2', 'wf-3']);
175
+ });
176
+
177
+ it('should handle empty logs array', () => {
178
+ const error1 = createMockWorkflowError({ logs: [] });
179
+ const error2 = createMockWorkflowError({ logs: [] });
180
+
181
+ const result = mergeWorkflowErrors([error1, error2], 'testTask', 'parent-wf', 2);
182
+
183
+ expect(result.logs).toEqual([]);
184
+ });
185
+
186
+ it('should include task name in message', () => {
187
+ const error = createMockWorkflowError();
188
+ const result = mergeWorkflowErrors([error], 'myCustomTask', 'parent-wf', 1);
189
+
190
+ expect(result.message).toContain("task 'myCustomTask'");
191
+ });
192
+
193
+ it('should include correct counts in message', () => {
194
+ const errors = Array.from({ length: 3 }, (_, i) =>
195
+ createMockWorkflowError({ workflowId: `wf-${i}` })
196
+ );
197
+
198
+ const result = mergeWorkflowErrors(errors, 'testTask', 'parent-wf', 10);
199
+
200
+ expect(result.message).toBe("3 of 10 concurrent child workflows failed in task 'testTask'");
201
+ });
202
+
203
+ it('should preserve parent workflow ID', () => {
204
+ const error = createMockWorkflowError({ workflowId: 'child-123' });
205
+ const result = mergeWorkflowErrors([error], 'testTask', 'parent-abc', 1);
206
+
207
+ expect(result.workflowId).toBe('parent-abc');
208
+ });
209
+ });