@litmers/cursorflow-orchestrator 0.1.39 → 0.2.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 (214) hide show
  1. package/CHANGELOG.md +0 -2
  2. package/README.md +20 -16
  3. package/commands/cursorflow-init.md +0 -4
  4. package/dist/cli/logs.js +108 -9
  5. package/dist/cli/logs.js.map +1 -1
  6. package/dist/cli/models.js +20 -3
  7. package/dist/cli/models.js.map +1 -1
  8. package/dist/cli/monitor.d.ts +7 -10
  9. package/dist/cli/monitor.js +1088 -1240
  10. package/dist/cli/monitor.js.map +1 -1
  11. package/dist/cli/prepare.js +0 -1
  12. package/dist/cli/prepare.js.map +1 -1
  13. package/dist/cli/resume.js +23 -5
  14. package/dist/cli/resume.js.map +1 -1
  15. package/dist/cli/run.js +28 -9
  16. package/dist/cli/run.js.map +1 -1
  17. package/dist/cli/signal.d.ts +6 -1
  18. package/dist/cli/signal.js +94 -12
  19. package/dist/cli/signal.js.map +1 -1
  20. package/dist/cli/tasks.js +3 -46
  21. package/dist/cli/tasks.js.map +1 -1
  22. package/dist/core/agent-supervisor.d.ts +23 -0
  23. package/dist/core/agent-supervisor.js +42 -0
  24. package/dist/core/agent-supervisor.js.map +1 -0
  25. package/dist/core/auto-recovery.d.ts +2 -1
  26. package/dist/core/auto-recovery.js +6 -1
  27. package/dist/core/auto-recovery.js.map +1 -1
  28. package/dist/core/failure-policy.d.ts +0 -1
  29. package/dist/core/failure-policy.js +0 -1
  30. package/dist/core/failure-policy.js.map +1 -1
  31. package/dist/core/git-lifecycle-manager.d.ts +284 -0
  32. package/dist/core/git-lifecycle-manager.js +778 -0
  33. package/dist/core/git-lifecycle-manager.js.map +1 -0
  34. package/dist/core/git-pipeline-coordinator.d.ts +21 -0
  35. package/dist/core/git-pipeline-coordinator.js +205 -0
  36. package/dist/core/git-pipeline-coordinator.js.map +1 -0
  37. package/dist/core/intervention.d.ts +176 -0
  38. package/dist/core/intervention.js +424 -0
  39. package/dist/core/intervention.js.map +1 -0
  40. package/dist/core/lane-state-machine.d.ts +423 -0
  41. package/dist/core/lane-state-machine.js +890 -0
  42. package/dist/core/lane-state-machine.js.map +1 -0
  43. package/dist/core/orchestrator.d.ts +4 -1
  44. package/dist/core/orchestrator.js +38 -63
  45. package/dist/core/orchestrator.js.map +1 -1
  46. package/dist/core/runner/agent.d.ts +7 -1
  47. package/dist/core/runner/agent.js +45 -30
  48. package/dist/core/runner/agent.js.map +1 -1
  49. package/dist/core/runner/pipeline.js +283 -109
  50. package/dist/core/runner/pipeline.js.map +1 -1
  51. package/dist/core/runner/task.d.ts +4 -5
  52. package/dist/core/runner/task.js +6 -77
  53. package/dist/core/runner/task.js.map +1 -1
  54. package/dist/core/runner.js +11 -2
  55. package/dist/core/runner.js.map +1 -1
  56. package/dist/core/stall-detection.d.ts +27 -4
  57. package/dist/core/stall-detection.js +116 -28
  58. package/dist/core/stall-detection.js.map +1 -1
  59. package/dist/hooks/contexts/index.d.ts +104 -0
  60. package/dist/hooks/contexts/index.js +134 -0
  61. package/dist/hooks/contexts/index.js.map +1 -0
  62. package/dist/hooks/data-accessor.d.ts +86 -0
  63. package/dist/hooks/data-accessor.js +410 -0
  64. package/dist/hooks/data-accessor.js.map +1 -0
  65. package/dist/hooks/flow-controller.d.ts +136 -0
  66. package/dist/hooks/flow-controller.js +351 -0
  67. package/dist/hooks/flow-controller.js.map +1 -0
  68. package/dist/hooks/index.d.ts +68 -0
  69. package/dist/hooks/index.js +105 -0
  70. package/dist/hooks/index.js.map +1 -0
  71. package/dist/hooks/manager.d.ts +129 -0
  72. package/dist/hooks/manager.js +389 -0
  73. package/dist/hooks/manager.js.map +1 -0
  74. package/dist/hooks/types.d.ts +463 -0
  75. package/dist/hooks/types.js +45 -0
  76. package/dist/hooks/types.js.map +1 -0
  77. package/dist/services/logging/buffer.d.ts +2 -2
  78. package/dist/services/logging/buffer.js +95 -42
  79. package/dist/services/logging/buffer.js.map +1 -1
  80. package/dist/services/logging/console.js +8 -5
  81. package/dist/services/logging/console.js.map +1 -1
  82. package/dist/services/logging/formatter.d.ts +9 -3
  83. package/dist/services/logging/formatter.js +64 -17
  84. package/dist/services/logging/formatter.js.map +1 -1
  85. package/dist/services/logging/index.d.ts +0 -1
  86. package/dist/services/logging/index.js +0 -1
  87. package/dist/services/logging/index.js.map +1 -1
  88. package/dist/services/logging/paths.d.ts +8 -0
  89. package/dist/services/logging/paths.js +48 -0
  90. package/dist/services/logging/paths.js.map +1 -0
  91. package/dist/services/logging/raw-log.d.ts +6 -0
  92. package/dist/services/logging/raw-log.js +37 -0
  93. package/dist/services/logging/raw-log.js.map +1 -0
  94. package/dist/services/process/index.js +1 -1
  95. package/dist/services/process/index.js.map +1 -1
  96. package/dist/types/agent.d.ts +15 -0
  97. package/dist/types/config.d.ts +24 -1
  98. package/dist/types/event-categories.d.ts +601 -0
  99. package/dist/types/event-categories.js +233 -0
  100. package/dist/types/event-categories.js.map +1 -0
  101. package/dist/types/events.d.ts +0 -20
  102. package/dist/types/flow.d.ts +10 -6
  103. package/dist/types/index.d.ts +1 -1
  104. package/dist/types/index.js +17 -3
  105. package/dist/types/index.js.map +1 -1
  106. package/dist/types/lane.d.ts +1 -1
  107. package/dist/types/logging.d.ts +1 -1
  108. package/dist/types/task.d.ts +13 -2
  109. package/dist/ui/log-viewer.d.ts +3 -0
  110. package/dist/ui/log-viewer.js +3 -0
  111. package/dist/ui/log-viewer.js.map +1 -1
  112. package/dist/utils/config.js +15 -1
  113. package/dist/utils/config.js.map +1 -1
  114. package/dist/utils/cursor-agent.d.ts +11 -1
  115. package/dist/utils/cursor-agent.js +63 -16
  116. package/dist/utils/cursor-agent.js.map +1 -1
  117. package/dist/utils/enhanced-logger.d.ts +5 -1
  118. package/dist/utils/enhanced-logger.js +99 -20
  119. package/dist/utils/enhanced-logger.js.map +1 -1
  120. package/dist/utils/event-registry.d.ts +222 -0
  121. package/dist/utils/event-registry.js +463 -0
  122. package/dist/utils/event-registry.js.map +1 -0
  123. package/dist/utils/events.d.ts +1 -13
  124. package/dist/utils/events.js.map +1 -1
  125. package/dist/utils/flow.d.ts +10 -0
  126. package/dist/utils/flow.js +75 -0
  127. package/dist/utils/flow.js.map +1 -1
  128. package/dist/utils/git.d.ts +12 -1
  129. package/dist/utils/git.js +54 -1
  130. package/dist/utils/git.js.map +1 -1
  131. package/dist/utils/log-constants.d.ts +1 -0
  132. package/dist/utils/log-constants.js +2 -1
  133. package/dist/utils/log-constants.js.map +1 -1
  134. package/dist/utils/log-formatter.d.ts +3 -2
  135. package/dist/utils/log-formatter.js +11 -11
  136. package/dist/utils/log-formatter.js.map +1 -1
  137. package/dist/utils/logger.d.ts +11 -0
  138. package/dist/utils/logger.js +82 -3
  139. package/dist/utils/logger.js.map +1 -1
  140. package/dist/utils/repro-thinking-logs.js +0 -13
  141. package/dist/utils/repro-thinking-logs.js.map +1 -1
  142. package/dist/utils/run-service.js +1 -1
  143. package/dist/utils/run-service.js.map +1 -1
  144. package/examples/README.md +0 -2
  145. package/examples/demo-project/README.md +1 -2
  146. package/package.json +18 -28
  147. package/scripts/setup-security.sh +0 -1
  148. package/scripts/test-log-parser.ts +171 -0
  149. package/scripts/verify-change.sh +272 -0
  150. package/src/cli/logs.ts +121 -10
  151. package/src/cli/models.ts +20 -3
  152. package/src/cli/monitor.ts +1257 -1342
  153. package/src/cli/prepare.ts +0 -1
  154. package/src/cli/resume.ts +29 -5
  155. package/src/cli/run.ts +29 -11
  156. package/src/cli/signal.ts +115 -17
  157. package/src/cli/tasks.ts +2 -59
  158. package/src/core/agent-supervisor.ts +64 -0
  159. package/src/core/auto-recovery.ts +7 -1
  160. package/src/core/failure-policy.ts +0 -1
  161. package/src/core/git-lifecycle-manager.ts +1011 -0
  162. package/src/core/git-pipeline-coordinator.ts +221 -0
  163. package/src/core/intervention.ts +481 -0
  164. package/src/core/lane-state-machine.ts +1097 -0
  165. package/src/core/orchestrator.ts +45 -62
  166. package/src/core/runner/agent.ts +66 -33
  167. package/src/core/runner/pipeline.ts +318 -122
  168. package/src/core/runner/task.ts +12 -93
  169. package/src/core/runner.ts +12 -2
  170. package/src/core/stall-detection.ts +145 -28
  171. package/src/hooks/contexts/index.ts +256 -0
  172. package/src/hooks/data-accessor.ts +488 -0
  173. package/src/hooks/flow-controller.ts +425 -0
  174. package/src/hooks/index.ts +154 -0
  175. package/src/hooks/manager.ts +434 -0
  176. package/src/hooks/types.ts +544 -0
  177. package/src/services/logging/buffer.ts +104 -43
  178. package/src/services/logging/console.ts +9 -5
  179. package/src/services/logging/formatter.ts +74 -17
  180. package/src/services/logging/index.ts +0 -2
  181. package/src/services/logging/paths.ts +14 -0
  182. package/src/services/logging/raw-log.ts +43 -0
  183. package/src/services/process/index.ts +1 -1
  184. package/src/types/agent.ts +15 -0
  185. package/src/types/config.ts +25 -1
  186. package/src/types/event-categories.ts +663 -0
  187. package/src/types/events.ts +0 -25
  188. package/src/types/flow.ts +10 -6
  189. package/src/types/index.ts +50 -4
  190. package/src/types/lane.ts +1 -2
  191. package/src/types/logging.ts +2 -1
  192. package/src/types/task.ts +13 -2
  193. package/src/ui/log-viewer.ts +3 -0
  194. package/src/utils/config.ts +17 -1
  195. package/src/utils/cursor-agent.ts +68 -16
  196. package/src/utils/enhanced-logger.ts +106 -20
  197. package/src/utils/event-registry.ts +595 -0
  198. package/src/utils/events.ts +0 -16
  199. package/src/utils/flow.ts +84 -0
  200. package/src/utils/git.ts +59 -1
  201. package/src/utils/log-constants.ts +2 -1
  202. package/src/utils/log-formatter.ts +11 -12
  203. package/src/utils/logger.ts +49 -3
  204. package/src/utils/repro-thinking-logs.ts +0 -15
  205. package/src/utils/run-service.ts +1 -1
  206. package/dist/services/logging/file-writer.d.ts +0 -71
  207. package/dist/services/logging/file-writer.js +0 -516
  208. package/dist/services/logging/file-writer.js.map +0 -1
  209. package/dist/types/review.d.ts +0 -17
  210. package/dist/types/review.js +0 -6
  211. package/dist/types/review.js.map +0 -1
  212. package/scripts/ai-security-check.js +0 -233
  213. package/src/services/logging/file-writer.ts +0 -526
  214. package/src/types/review.ts +0 -20
@@ -0,0 +1,890 @@
1
+ "use strict";
2
+ /**
3
+ * Lane State Machine
4
+ *
5
+ * Lane의 생명주기를 세분화된 상태로 관리하는 상태 머신입니다.
6
+ *
7
+ * 핵심 원칙:
8
+ * 1. 명시적 상태 전이 (Explicit State Transitions)
9
+ * 2. 단일 상태 저장소 (Single Source of Truth)
10
+ * 3. 상태 전이 검증 (Transition Validation)
11
+ * 4. 복구/재시도 로직 중앙화 (Centralized Recovery)
12
+ *
13
+ * 상태 계층:
14
+ * - 주 상태 (Primary State): Lane의 기본 상태 (pending, running, completed 등)
15
+ * - 부 상태 (Sub State): 세부 작업 상태 (preparing_git, executing_task 등)
16
+ * - 복구 상태 (Recovery State): 복구 진행 상태 (idle, monitoring, recovering 등)
17
+ */
18
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ var desc = Object.getOwnPropertyDescriptor(m, k);
21
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
22
+ desc = { enumerable: true, get: function() { return m[k]; } };
23
+ }
24
+ Object.defineProperty(o, k2, desc);
25
+ }) : (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ o[k2] = m[k];
28
+ }));
29
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31
+ }) : function(o, v) {
32
+ o["default"] = v;
33
+ });
34
+ var __importStar = (this && this.__importStar) || (function () {
35
+ var ownKeys = function(o) {
36
+ ownKeys = Object.getOwnPropertyNames || function (o) {
37
+ var ar = [];
38
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
39
+ return ar;
40
+ };
41
+ return ownKeys(o);
42
+ };
43
+ return function (mod) {
44
+ if (mod && mod.__esModule) return mod;
45
+ var result = {};
46
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
47
+ __setModuleDefault(result, mod);
48
+ return result;
49
+ };
50
+ })();
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ exports.LaneStateMachine = exports.StateTransitionTrigger = exports.RecoveryState = exports.LaneSubState = exports.LanePrimaryState = void 0;
53
+ exports.getStateMachine = getStateMachine;
54
+ exports.resetStateMachine = resetStateMachine;
55
+ exports.primaryStateToLaneStatus = primaryStateToLaneStatus;
56
+ const fs = __importStar(require("fs"));
57
+ const events_1 = require("../utils/events");
58
+ const path_1 = require("../utils/path");
59
+ const logger = __importStar(require("../utils/logger"));
60
+ const event_categories_1 = require("../types/event-categories");
61
+ // ============================================================================
62
+ // State Definitions (상태 정의)
63
+ // ============================================================================
64
+ /**
65
+ * Lane 주 상태 (Primary State)
66
+ *
67
+ * 상태 전이 규칙:
68
+ * - PENDING → INITIALIZING → RUNNING → COMPLETED | FAILED
69
+ * - RUNNING ↔ WAITING (의존성 대기)
70
+ * - RUNNING ↔ PAUSED (사용자 요청)
71
+ * - RUNNING → RECOVERING → RUNNING | FAILED
72
+ * - * → ABORTED (강제 중단)
73
+ */
74
+ var LanePrimaryState;
75
+ (function (LanePrimaryState) {
76
+ /** 대기 중 - 아직 시작되지 않음 */
77
+ LanePrimaryState["PENDING"] = "pending";
78
+ /** 초기화 중 - 워크트리/브랜치 준비 */
79
+ LanePrimaryState["INITIALIZING"] = "initializing";
80
+ /** 실행 중 */
81
+ LanePrimaryState["RUNNING"] = "running";
82
+ /** 의존성 대기 중 */
83
+ LanePrimaryState["WAITING"] = "waiting";
84
+ /** 일시 중지 */
85
+ LanePrimaryState["PAUSED"] = "paused";
86
+ /** 복구 중 */
87
+ LanePrimaryState["RECOVERING"] = "recovering";
88
+ /** 완료 */
89
+ LanePrimaryState["COMPLETED"] = "completed";
90
+ /** 실패 */
91
+ LanePrimaryState["FAILED"] = "failed";
92
+ /** 강제 중단 */
93
+ LanePrimaryState["ABORTED"] = "aborted";
94
+ })(LanePrimaryState || (exports.LanePrimaryState = LanePrimaryState = {}));
95
+ /**
96
+ * Lane 부 상태 (Sub State) - RUNNING 상태의 세부 단계
97
+ */
98
+ var LaneSubState;
99
+ (function (LaneSubState) {
100
+ /** 없음 (비실행 상태) */
101
+ LaneSubState["NONE"] = "none";
102
+ // --- Git 관련 ---
103
+ /** Git 워크트리 준비 */
104
+ LaneSubState["PREPARING_GIT"] = "preparing_git";
105
+ /** 의존성 브랜치 머지 */
106
+ LaneSubState["MERGING_DEPENDENCIES"] = "merging_dependencies";
107
+ /** Task 브랜치 생성 */
108
+ LaneSubState["CREATING_TASK_BRANCH"] = "creating_task_branch";
109
+ /** 변경사항 커밋 */
110
+ LaneSubState["COMMITTING"] = "committing";
111
+ /** 푸시 */
112
+ LaneSubState["PUSHING"] = "pushing";
113
+ /** 머지 */
114
+ LaneSubState["MERGING"] = "merging";
115
+ // --- Task 관련 ---
116
+ /** Task 실행 준비 */
117
+ LaneSubState["PREPARING_TASK"] = "preparing_task";
118
+ /** AI 에이전트와 통신 중 */
119
+ LaneSubState["EXECUTING_AGENT"] = "executing_agent";
120
+ /** Task 실행 완료 처리 */
121
+ LaneSubState["FINALIZING_TASK"] = "finalizing_task";
122
+ // --- 대기 관련 ---
123
+ /** 의존성 완료 대기 */
124
+ LaneSubState["WAITING_DEPENDENCY"] = "waiting_dependency";
125
+ /** 사용자 입력 대기 */
126
+ LaneSubState["WAITING_USER_INPUT"] = "waiting_user_input";
127
+ /** Rate limit 대기 */
128
+ LaneSubState["WAITING_RATE_LIMIT"] = "waiting_rate_limit";
129
+ })(LaneSubState || (exports.LaneSubState = LaneSubState = {}));
130
+ /**
131
+ * 복구 상태 (Recovery State)
132
+ */
133
+ var RecoveryState;
134
+ (function (RecoveryState) {
135
+ /** 복구 필요 없음 */
136
+ RecoveryState["IDLE"] = "idle";
137
+ /** 모니터링 중 (Stall 감지) */
138
+ RecoveryState["MONITORING"] = "monitoring";
139
+ /** Continue 신호 발송됨 */
140
+ RecoveryState["CONTINUE_SENT"] = "continue_sent";
141
+ /** Stronger prompt 발송됨 */
142
+ RecoveryState["STRONGER_PROMPT_SENT"] = "stronger_prompt_sent";
143
+ /** 재시작 요청됨 */
144
+ RecoveryState["RESTART_REQUESTED"] = "restart_requested";
145
+ /** 진단 실행됨 */
146
+ RecoveryState["DIAGNOSED"] = "diagnosed";
147
+ /** 복구 포기 */
148
+ RecoveryState["EXHAUSTED"] = "exhausted";
149
+ })(RecoveryState || (exports.RecoveryState = RecoveryState = {}));
150
+ // ============================================================================
151
+ // State Transition Triggers (상태 전이 트리거)
152
+ // ============================================================================
153
+ /**
154
+ * 상태 전이를 발생시키는 트리거
155
+ */
156
+ var StateTransitionTrigger;
157
+ (function (StateTransitionTrigger) {
158
+ // --- Lifecycle Triggers ---
159
+ /** Lane 시작 */
160
+ StateTransitionTrigger["START"] = "start";
161
+ /** 초기화 완료 */
162
+ StateTransitionTrigger["INITIALIZED"] = "initialized";
163
+ /** Task 완료 */
164
+ StateTransitionTrigger["TASK_COMPLETED"] = "task_completed";
165
+ /** 모든 Task 완료 */
166
+ StateTransitionTrigger["ALL_TASKS_COMPLETED"] = "all_tasks_completed";
167
+ /** 실패 발생 */
168
+ StateTransitionTrigger["FAILURE"] = "failure";
169
+ /** 강제 중단 요청 */
170
+ StateTransitionTrigger["ABORT"] = "abort";
171
+ // --- Dependency Triggers ---
172
+ /** 의존성 대기 시작 */
173
+ StateTransitionTrigger["WAIT_DEPENDENCY"] = "wait_dependency";
174
+ /** 의존성 해결됨 */
175
+ StateTransitionTrigger["DEPENDENCY_RESOLVED"] = "dependency_resolved";
176
+ /** 의존성 타임아웃 */
177
+ StateTransitionTrigger["DEPENDENCY_TIMEOUT"] = "dependency_timeout";
178
+ /** 의존성 실패 */
179
+ StateTransitionTrigger["DEPENDENCY_FAILED"] = "dependency_failed";
180
+ // --- Pause/Resume Triggers ---
181
+ /** 일시 중지 요청 */
182
+ StateTransitionTrigger["PAUSE"] = "pause";
183
+ /** 재개 요청 */
184
+ StateTransitionTrigger["RESUME"] = "resume";
185
+ // --- Recovery Triggers ---
186
+ /** 복구 시작 */
187
+ StateTransitionTrigger["RECOVERY_START"] = "recovery_start";
188
+ /** 복구 성공 */
189
+ StateTransitionTrigger["RECOVERY_SUCCESS"] = "recovery_success";
190
+ /** 복구 실패 */
191
+ StateTransitionTrigger["RECOVERY_FAILED"] = "recovery_failed";
192
+ /** Stall 감지 */
193
+ StateTransitionTrigger["STALL_DETECTED"] = "stall_detected";
194
+ /** Continue 신호 발송 */
195
+ StateTransitionTrigger["CONTINUE_SIGNAL_SENT"] = "continue_signal_sent";
196
+ /** Stronger prompt 발송 */
197
+ StateTransitionTrigger["STRONGER_PROMPT_SENT"] = "stronger_prompt_sent";
198
+ /** 재시작 요청 */
199
+ StateTransitionTrigger["RESTART_REQUESTED"] = "restart_requested";
200
+ /** 진단 완료 */
201
+ StateTransitionTrigger["DIAGNOSIS_COMPLETE"] = "diagnosis_complete";
202
+ // --- Sub-state Triggers ---
203
+ /** Git 작업 시작 */
204
+ StateTransitionTrigger["GIT_START"] = "git_start";
205
+ /** Git 작업 완료 */
206
+ StateTransitionTrigger["GIT_COMPLETE"] = "git_complete";
207
+ /** Task 실행 시작 */
208
+ StateTransitionTrigger["TASK_START"] = "task_start";
209
+ /** Agent 통신 시작 */
210
+ StateTransitionTrigger["AGENT_START"] = "agent_start";
211
+ /** Agent 응답 수신 */
212
+ StateTransitionTrigger["AGENT_RESPONSE"] = "agent_response";
213
+ })(StateTransitionTrigger || (exports.StateTransitionTrigger = StateTransitionTrigger = {}));
214
+ /**
215
+ * 상태 전이 규칙 테이블
216
+ */
217
+ const TRANSITION_RULES = [
218
+ // --- 시작 및 초기화 ---
219
+ { from: LanePrimaryState.PENDING, to: LanePrimaryState.INITIALIZING, trigger: StateTransitionTrigger.START },
220
+ { from: LanePrimaryState.INITIALIZING, to: LanePrimaryState.RUNNING, trigger: StateTransitionTrigger.INITIALIZED },
221
+ { from: LanePrimaryState.INITIALIZING, to: LanePrimaryState.FAILED, trigger: StateTransitionTrigger.FAILURE },
222
+ // --- 실행 중 → 완료/실패 ---
223
+ { from: LanePrimaryState.RUNNING, to: LanePrimaryState.COMPLETED, trigger: StateTransitionTrigger.ALL_TASKS_COMPLETED },
224
+ { from: LanePrimaryState.RUNNING, to: LanePrimaryState.FAILED, trigger: StateTransitionTrigger.FAILURE },
225
+ // --- 의존성 대기 ---
226
+ { from: LanePrimaryState.RUNNING, to: LanePrimaryState.WAITING, trigger: StateTransitionTrigger.WAIT_DEPENDENCY },
227
+ { from: LanePrimaryState.WAITING, to: LanePrimaryState.RUNNING, trigger: StateTransitionTrigger.DEPENDENCY_RESOLVED },
228
+ { from: LanePrimaryState.WAITING, to: LanePrimaryState.FAILED, trigger: StateTransitionTrigger.DEPENDENCY_TIMEOUT },
229
+ { from: LanePrimaryState.WAITING, to: LanePrimaryState.FAILED, trigger: StateTransitionTrigger.DEPENDENCY_FAILED },
230
+ // --- 일시 중지/재개 ---
231
+ { from: LanePrimaryState.RUNNING, to: LanePrimaryState.PAUSED, trigger: StateTransitionTrigger.PAUSE },
232
+ { from: LanePrimaryState.WAITING, to: LanePrimaryState.PAUSED, trigger: StateTransitionTrigger.PAUSE },
233
+ { from: LanePrimaryState.PAUSED, to: LanePrimaryState.RUNNING, trigger: StateTransitionTrigger.RESUME },
234
+ // --- 복구 ---
235
+ { from: LanePrimaryState.RUNNING, to: LanePrimaryState.RECOVERING, trigger: StateTransitionTrigger.RECOVERY_START },
236
+ { from: LanePrimaryState.RECOVERING, to: LanePrimaryState.RUNNING, trigger: StateTransitionTrigger.RECOVERY_SUCCESS },
237
+ { from: LanePrimaryState.RECOVERING, to: LanePrimaryState.FAILED, trigger: StateTransitionTrigger.RECOVERY_FAILED },
238
+ // --- 강제 중단 (모든 상태에서 가능) ---
239
+ {
240
+ from: [
241
+ LanePrimaryState.PENDING,
242
+ LanePrimaryState.INITIALIZING,
243
+ LanePrimaryState.RUNNING,
244
+ LanePrimaryState.WAITING,
245
+ LanePrimaryState.PAUSED,
246
+ LanePrimaryState.RECOVERING,
247
+ ],
248
+ to: LanePrimaryState.ABORTED,
249
+ trigger: StateTransitionTrigger.ABORT
250
+ },
251
+ ];
252
+ // ============================================================================
253
+ // Lane State Machine
254
+ // ============================================================================
255
+ /**
256
+ * Lane 상태 머신
257
+ *
258
+ * 사용 예:
259
+ * ```typescript
260
+ * const sm = LaneStateMachine.getInstance();
261
+ *
262
+ * // Lane 등록
263
+ * sm.registerLane('lane-1', 'run-123', {
264
+ * totalTasks: 5,
265
+ * pipelineBranch: 'cursorflow/pipeline/lane-1'
266
+ * });
267
+ *
268
+ * // 상태 전이
269
+ * sm.transition('lane-1', StateTransitionTrigger.START);
270
+ * sm.transition('lane-1', StateTransitionTrigger.INITIALIZED);
271
+ *
272
+ * // 부 상태 업데이트
273
+ * sm.setSubState('lane-1', LaneSubState.EXECUTING_AGENT);
274
+ *
275
+ * // 상태 조회
276
+ * const ctx = sm.getContext('lane-1');
277
+ * console.log(ctx.primaryState, ctx.subState);
278
+ * ```
279
+ */
280
+ class LaneStateMachine {
281
+ static instance = null;
282
+ /** Lane별 상태 컨텍스트 */
283
+ contexts = new Map();
284
+ /** 상태 히스토리 (디버깅/감사용) */
285
+ history = new Map();
286
+ /** 상태 변경 콜백 */
287
+ onTransitionCallbacks = [];
288
+ /** 디버그 모드 */
289
+ verbose = false;
290
+ constructor() {
291
+ this.verbose = process.env['DEBUG_STATE'] === 'true';
292
+ }
293
+ /**
294
+ * 싱글톤 인스턴스 획득
295
+ */
296
+ static getInstance() {
297
+ if (!LaneStateMachine.instance) {
298
+ LaneStateMachine.instance = new LaneStateMachine();
299
+ }
300
+ return LaneStateMachine.instance;
301
+ }
302
+ /**
303
+ * 인스턴스 리셋 (테스트용)
304
+ */
305
+ static resetInstance() {
306
+ LaneStateMachine.instance = null;
307
+ }
308
+ // --------------------------------------------------------------------------
309
+ // Lane Registration
310
+ // --------------------------------------------------------------------------
311
+ /**
312
+ * Lane 등록
313
+ */
314
+ registerLane(laneName, runId, options = {}) {
315
+ const now = Date.now();
316
+ const context = {
317
+ laneName,
318
+ runId,
319
+ primaryState: LanePrimaryState.PENDING,
320
+ subState: LaneSubState.NONE,
321
+ recoveryState: RecoveryState.IDLE,
322
+ currentTaskIndex: 0,
323
+ totalTasks: options.totalTasks || 0,
324
+ completedTasks: [],
325
+ restartCount: 0,
326
+ startTime: now,
327
+ lastTransitionTime: now,
328
+ pipelineBranch: options.pipelineBranch,
329
+ worktreeDir: options.worktreeDir,
330
+ metadata: options.metadata,
331
+ };
332
+ this.contexts.set(laneName, context);
333
+ this.history.set(laneName, []);
334
+ this.log(`[${laneName}] Registered (runId: ${runId}, tasks: ${options.totalTasks || 0})`);
335
+ return context;
336
+ }
337
+ /**
338
+ * Lane 해제
339
+ */
340
+ unregisterLane(laneName) {
341
+ this.contexts.delete(laneName);
342
+ this.history.delete(laneName);
343
+ this.log(`[${laneName}] Unregistered`);
344
+ }
345
+ /**
346
+ * Lane 컨텍스트 조회
347
+ */
348
+ getContext(laneName) {
349
+ return this.contexts.get(laneName);
350
+ }
351
+ /**
352
+ * 모든 Lane 컨텍스트 조회
353
+ */
354
+ getAllContexts() {
355
+ return new Map(this.contexts);
356
+ }
357
+ // --------------------------------------------------------------------------
358
+ // State Transitions
359
+ // --------------------------------------------------------------------------
360
+ /**
361
+ * 상태 전이 실행
362
+ */
363
+ transition(laneName, trigger, options = {}) {
364
+ const context = this.contexts.get(laneName);
365
+ if (!context) {
366
+ return {
367
+ success: false,
368
+ fromState: LanePrimaryState.PENDING,
369
+ toState: LanePrimaryState.PENDING,
370
+ trigger,
371
+ error: `Lane not found: ${laneName}`,
372
+ };
373
+ }
374
+ const currentState = context.primaryState;
375
+ // 전이 규칙 찾기
376
+ const rule = this.findTransitionRule(currentState, trigger);
377
+ if (!rule && !options.force) {
378
+ const result = {
379
+ success: false,
380
+ fromState: currentState,
381
+ toState: currentState,
382
+ trigger,
383
+ error: `Invalid transition: ${currentState} + ${trigger}`,
384
+ };
385
+ this.emitTransitionFailed(laneName, context, trigger, result.error);
386
+ return result;
387
+ }
388
+ const targetState = rule?.to || currentState;
389
+ // Guard 체크
390
+ if (rule?.guard && !rule.guard(context)) {
391
+ const result = {
392
+ success: false,
393
+ fromState: currentState,
394
+ toState: currentState,
395
+ trigger,
396
+ error: 'Transition guard failed',
397
+ };
398
+ this.emitTransitionFailed(laneName, context, trigger, result.error);
399
+ return result;
400
+ }
401
+ // 상태 전이 실행
402
+ const previousState = context.primaryState;
403
+ context.primaryState = targetState;
404
+ context.lastTransitionTime = Date.now();
405
+ // 오류 정보 업데이트
406
+ if (options.error) {
407
+ context.lastError = options.error;
408
+ }
409
+ // 종료 상태 처리
410
+ if (this.isTerminalState(targetState)) {
411
+ context.endTime = Date.now();
412
+ }
413
+ // 부 상태 리셋 (필요한 경우)
414
+ if (this.shouldResetSubState(previousState, targetState)) {
415
+ context.subState = LaneSubState.NONE;
416
+ }
417
+ // 히스토리 기록
418
+ const historyEntry = {
419
+ timestamp: Date.now(),
420
+ fromState: previousState,
421
+ toState: targetState,
422
+ trigger,
423
+ };
424
+ this.history.get(laneName)?.push(historyEntry);
425
+ // 콜백 및 이벤트 발행
426
+ const result = {
427
+ success: true,
428
+ fromState: previousState,
429
+ toState: targetState,
430
+ trigger,
431
+ };
432
+ rule?.onTransition?.(context);
433
+ this.notifyTransition(laneName, result);
434
+ this.emitTransition(laneName, context, previousState, trigger);
435
+ this.log(`[${laneName}] ${previousState} → ${targetState} (trigger: ${trigger})`);
436
+ return result;
437
+ }
438
+ /**
439
+ * 전이 규칙 찾기
440
+ */
441
+ findTransitionRule(currentState, trigger) {
442
+ return TRANSITION_RULES.find(rule => {
443
+ const fromStates = Array.isArray(rule.from) ? rule.from : [rule.from];
444
+ return fromStates.includes(currentState) && rule.trigger === trigger;
445
+ });
446
+ }
447
+ /**
448
+ * 종료 상태인지 확인
449
+ */
450
+ isTerminalState(state) {
451
+ return [
452
+ LanePrimaryState.COMPLETED,
453
+ LanePrimaryState.FAILED,
454
+ LanePrimaryState.ABORTED,
455
+ ].includes(state);
456
+ }
457
+ /**
458
+ * 부 상태 리셋 필요 여부
459
+ */
460
+ shouldResetSubState(from, to) {
461
+ // RUNNING을 벗어날 때 부 상태 리셋
462
+ return from === LanePrimaryState.RUNNING && to !== LanePrimaryState.RUNNING;
463
+ }
464
+ // --------------------------------------------------------------------------
465
+ // Sub-State Management
466
+ // --------------------------------------------------------------------------
467
+ /**
468
+ * 부 상태 설정
469
+ */
470
+ setSubState(laneName, subState) {
471
+ const context = this.contexts.get(laneName);
472
+ if (!context)
473
+ return false;
474
+ const previousSubState = context.subState;
475
+ context.subState = subState;
476
+ this.log(`[${laneName}] SubState: ${previousSubState} → ${subState}`);
477
+ return true;
478
+ }
479
+ /**
480
+ * 부 상태 조회
481
+ */
482
+ getSubState(laneName) {
483
+ return this.contexts.get(laneName)?.subState || LaneSubState.NONE;
484
+ }
485
+ // --------------------------------------------------------------------------
486
+ // Recovery State Management
487
+ // --------------------------------------------------------------------------
488
+ /**
489
+ * 복구 상태 설정
490
+ */
491
+ setRecoveryState(laneName, recoveryState) {
492
+ const context = this.contexts.get(laneName);
493
+ if (!context)
494
+ return false;
495
+ const previousState = context.recoveryState;
496
+ context.recoveryState = recoveryState;
497
+ this.log(`[${laneName}] RecoveryState: ${previousState} → ${recoveryState}`);
498
+ return true;
499
+ }
500
+ /**
501
+ * 복구 상태 조회
502
+ */
503
+ getRecoveryState(laneName) {
504
+ return this.contexts.get(laneName)?.recoveryState || RecoveryState.IDLE;
505
+ }
506
+ /**
507
+ * 재시작 횟수 증가
508
+ */
509
+ incrementRestartCount(laneName) {
510
+ const context = this.contexts.get(laneName);
511
+ if (!context)
512
+ return 0;
513
+ context.restartCount++;
514
+ return context.restartCount;
515
+ }
516
+ // --------------------------------------------------------------------------
517
+ // Context Updates
518
+ // --------------------------------------------------------------------------
519
+ /**
520
+ * Task 진행 상황 업데이트
521
+ */
522
+ updateTaskProgress(laneName, taskIndex, taskName, taskBranch) {
523
+ const context = this.contexts.get(laneName);
524
+ if (!context)
525
+ return false;
526
+ context.currentTaskIndex = taskIndex;
527
+ if (taskName)
528
+ context.currentTaskName = taskName;
529
+ if (taskBranch)
530
+ context.taskBranch = taskBranch;
531
+ return true;
532
+ }
533
+ /**
534
+ * Task 완료 기록
535
+ */
536
+ recordTaskCompletion(laneName, taskName) {
537
+ const context = this.contexts.get(laneName);
538
+ if (!context)
539
+ return false;
540
+ if (!context.completedTasks.includes(taskName)) {
541
+ context.completedTasks.push(taskName);
542
+ }
543
+ return true;
544
+ }
545
+ /**
546
+ * 대기 중인 의존성 설정
547
+ */
548
+ setWaitingFor(laneName, dependencies) {
549
+ const context = this.contexts.get(laneName);
550
+ if (!context)
551
+ return false;
552
+ context.waitingFor = dependencies;
553
+ return true;
554
+ }
555
+ /**
556
+ * 오류 설정
557
+ */
558
+ setError(laneName, error) {
559
+ const context = this.contexts.get(laneName);
560
+ if (!context)
561
+ return false;
562
+ context.lastError = error;
563
+ return true;
564
+ }
565
+ /**
566
+ * 프로세스 ID 설정
567
+ */
568
+ setPid(laneName, pid) {
569
+ const context = this.contexts.get(laneName);
570
+ if (!context)
571
+ return false;
572
+ context.pid = pid;
573
+ return true;
574
+ }
575
+ /**
576
+ * 채팅 세션 ID 설정
577
+ */
578
+ setChatId(laneName, chatId) {
579
+ const context = this.contexts.get(laneName);
580
+ if (!context)
581
+ return false;
582
+ context.chatId = chatId;
583
+ return true;
584
+ }
585
+ /**
586
+ * 메타데이터 업데이트
587
+ */
588
+ updateMetadata(laneName, metadata) {
589
+ const context = this.contexts.get(laneName);
590
+ if (!context)
591
+ return false;
592
+ context.metadata = { ...context.metadata, ...metadata };
593
+ return true;
594
+ }
595
+ // --------------------------------------------------------------------------
596
+ // State Persistence
597
+ // --------------------------------------------------------------------------
598
+ /**
599
+ * 상태를 파일로 저장
600
+ */
601
+ persistState(laneName, stateDir) {
602
+ const context = this.contexts.get(laneName);
603
+ if (!context)
604
+ return false;
605
+ const statePath = (0, path_1.safeJoin)(stateDir, 'state.json');
606
+ // LaneState 형식으로 변환 (기존 호환성)
607
+ const laneState = this.contextToLaneState(context);
608
+ try {
609
+ const stateParent = require('path').dirname(statePath);
610
+ if (!fs.existsSync(stateParent)) {
611
+ fs.mkdirSync(stateParent, { recursive: true });
612
+ }
613
+ const tempPath = `${statePath}.tmp.${process.pid}`;
614
+ fs.writeFileSync(tempPath, JSON.stringify(laneState, null, 2), 'utf8');
615
+ fs.renameSync(tempPath, statePath);
616
+ events_1.events.emit(event_categories_1.StateEventType.PERSISTED, {
617
+ laneName,
618
+ filePath: statePath,
619
+ });
620
+ return true;
621
+ }
622
+ catch (error) {
623
+ logger.error(`[StateMachine] Failed to persist state for ${laneName}: ${error.message}`);
624
+ return false;
625
+ }
626
+ }
627
+ /**
628
+ * 파일에서 상태 복구
629
+ */
630
+ restoreState(laneName, runId, stateDir) {
631
+ const statePath = (0, path_1.safeJoin)(stateDir, 'state.json');
632
+ if (!fs.existsSync(statePath)) {
633
+ return null;
634
+ }
635
+ try {
636
+ const content = fs.readFileSync(statePath, 'utf8');
637
+ const laneState = JSON.parse(content);
638
+ // LaneState에서 컨텍스트로 변환
639
+ const context = this.laneStateToContext(laneName, runId, laneState);
640
+ this.contexts.set(laneName, context);
641
+ this.history.set(laneName, []);
642
+ events_1.events.emit(event_categories_1.StateEventType.RESTORED, {
643
+ laneName,
644
+ filePath: statePath,
645
+ state: laneState,
646
+ });
647
+ this.log(`[${laneName}] State restored from ${statePath}`);
648
+ return context;
649
+ }
650
+ catch (error) {
651
+ logger.error(`[StateMachine] Failed to restore state for ${laneName}: ${error.message}`);
652
+ events_1.events.emit(event_categories_1.StateEventType.CORRUPTED, {
653
+ laneName,
654
+ filePath: statePath,
655
+ issues: [error.message],
656
+ });
657
+ return null;
658
+ }
659
+ }
660
+ /**
661
+ * 컨텍스트를 기존 LaneState 형식으로 변환
662
+ */
663
+ contextToLaneState(context) {
664
+ return {
665
+ label: context.laneName,
666
+ status: context.primaryState,
667
+ currentTaskIndex: context.currentTaskIndex,
668
+ totalTasks: context.totalTasks,
669
+ worktreeDir: context.worktreeDir || null,
670
+ pipelineBranch: context.pipelineBranch || null,
671
+ startTime: context.startTime,
672
+ endTime: context.endTime || null,
673
+ error: context.lastError || null,
674
+ dependencyRequest: null,
675
+ updatedAt: Date.now(),
676
+ tasksFile: context.metadata?.tasksFile,
677
+ pid: context.pid,
678
+ completedTasks: context.completedTasks,
679
+ waitingFor: context.waitingFor,
680
+ chatId: context.chatId,
681
+ // 확장 필드
682
+ subState: context.subState,
683
+ recoveryState: context.recoveryState,
684
+ restartCount: context.restartCount,
685
+ currentTaskName: context.currentTaskName,
686
+ taskBranch: context.taskBranch,
687
+ };
688
+ }
689
+ /**
690
+ * 기존 LaneState에서 컨텍스트로 변환
691
+ */
692
+ laneStateToContext(laneName, runId, laneState) {
693
+ return {
694
+ laneName,
695
+ runId,
696
+ primaryState: laneState.status || LanePrimaryState.PENDING,
697
+ subState: laneState.subState || LaneSubState.NONE,
698
+ recoveryState: laneState.recoveryState || RecoveryState.IDLE,
699
+ currentTaskIndex: laneState.currentTaskIndex || 0,
700
+ totalTasks: laneState.totalTasks || 0,
701
+ completedTasks: laneState.completedTasks || [],
702
+ currentTaskName: laneState.currentTaskName,
703
+ waitingFor: laneState.waitingFor,
704
+ lastError: laneState.error,
705
+ restartCount: laneState.restartCount || 0,
706
+ startTime: laneState.startTime || Date.now(),
707
+ endTime: laneState.endTime,
708
+ lastTransitionTime: laneState.updatedAt || Date.now(),
709
+ worktreeDir: laneState.worktreeDir,
710
+ pipelineBranch: laneState.pipelineBranch,
711
+ taskBranch: laneState.taskBranch,
712
+ pid: laneState.pid,
713
+ chatId: laneState.chatId,
714
+ metadata: {
715
+ tasksFile: laneState.tasksFile,
716
+ },
717
+ };
718
+ }
719
+ // --------------------------------------------------------------------------
720
+ // Event Handling
721
+ // --------------------------------------------------------------------------
722
+ /**
723
+ * 상태 전이 콜백 등록
724
+ */
725
+ onTransition(callback) {
726
+ this.onTransitionCallbacks.push(callback);
727
+ return () => {
728
+ const index = this.onTransitionCallbacks.indexOf(callback);
729
+ if (index > -1) {
730
+ this.onTransitionCallbacks.splice(index, 1);
731
+ }
732
+ };
733
+ }
734
+ /**
735
+ * 전이 콜백 실행
736
+ */
737
+ notifyTransition(laneName, result) {
738
+ for (const callback of this.onTransitionCallbacks) {
739
+ try {
740
+ callback(laneName, result);
741
+ }
742
+ catch (error) {
743
+ logger.error(`[StateMachine] Callback error: ${error}`);
744
+ }
745
+ }
746
+ }
747
+ /**
748
+ * 전이 이벤트 발행
749
+ */
750
+ emitTransition(laneName, context, fromState, trigger) {
751
+ const payload = {
752
+ laneName,
753
+ fromState,
754
+ toState: context.primaryState,
755
+ trigger,
756
+ timestamp: Date.now(),
757
+ };
758
+ events_1.events.emit(event_categories_1.StateEventType.TRANSITION, payload);
759
+ }
760
+ /**
761
+ * 전이 실패 이벤트 발행
762
+ */
763
+ emitTransitionFailed(laneName, context, trigger, reason) {
764
+ const payload = {
765
+ laneName,
766
+ fromState: context.primaryState,
767
+ attemptedState: 'unknown',
768
+ trigger,
769
+ reason,
770
+ };
771
+ events_1.events.emit(event_categories_1.StateEventType.TRANSITION_FAILED, payload);
772
+ }
773
+ // --------------------------------------------------------------------------
774
+ // Query Methods
775
+ // --------------------------------------------------------------------------
776
+ /**
777
+ * 특정 상태의 Lane들 조회
778
+ */
779
+ getLanesInState(state) {
780
+ const result = [];
781
+ for (const [laneName, context] of this.contexts) {
782
+ if (context.primaryState === state) {
783
+ result.push(laneName);
784
+ }
785
+ }
786
+ return result;
787
+ }
788
+ /**
789
+ * 활성 상태 Lane들 조회 (종료되지 않은)
790
+ */
791
+ getActiveLanes() {
792
+ const result = [];
793
+ for (const [laneName, context] of this.contexts) {
794
+ if (!this.isTerminalState(context.primaryState)) {
795
+ result.push(laneName);
796
+ }
797
+ }
798
+ return result;
799
+ }
800
+ /**
801
+ * 전이 히스토리 조회
802
+ */
803
+ getHistory(laneName) {
804
+ return this.history.get(laneName) || [];
805
+ }
806
+ /**
807
+ * 전체 상태 요약 조회
808
+ */
809
+ getSummary() {
810
+ const summary = {};
811
+ for (const state of Object.values(LanePrimaryState)) {
812
+ summary[state] = 0;
813
+ }
814
+ for (const context of this.contexts.values()) {
815
+ summary[context.primaryState]++;
816
+ }
817
+ return summary;
818
+ }
819
+ // --------------------------------------------------------------------------
820
+ // Utility
821
+ // --------------------------------------------------------------------------
822
+ /**
823
+ * 로깅
824
+ */
825
+ log(message) {
826
+ if (this.verbose) {
827
+ logger.debug(`[StateMachine] ${message}`);
828
+ }
829
+ }
830
+ /**
831
+ * 디버그 모드 설정
832
+ */
833
+ setVerbose(verbose) {
834
+ this.verbose = verbose;
835
+ }
836
+ /**
837
+ * 디버그 덤프
838
+ */
839
+ dumpState(laneName) {
840
+ const context = this.contexts.get(laneName);
841
+ if (!context)
842
+ return `Lane not found: ${laneName}`;
843
+ return JSON.stringify({
844
+ ...context,
845
+ historyLength: this.history.get(laneName)?.length || 0,
846
+ }, null, 2);
847
+ }
848
+ }
849
+ exports.LaneStateMachine = LaneStateMachine;
850
+ // ============================================================================
851
+ // Convenience Functions
852
+ // ============================================================================
853
+ /**
854
+ * 싱글톤 인스턴스 획득
855
+ */
856
+ function getStateMachine() {
857
+ return LaneStateMachine.getInstance();
858
+ }
859
+ /**
860
+ * 인스턴스 리셋 (테스트용)
861
+ */
862
+ function resetStateMachine() {
863
+ LaneStateMachine.resetInstance();
864
+ }
865
+ /**
866
+ * LanePrimaryState를 기존 LaneStatus로 변환 (호환성)
867
+ */
868
+ function primaryStateToLaneStatus(state) {
869
+ switch (state) {
870
+ case LanePrimaryState.PENDING:
871
+ case LanePrimaryState.INITIALIZING:
872
+ return 'pending';
873
+ case LanePrimaryState.RUNNING:
874
+ return 'running';
875
+ case LanePrimaryState.WAITING:
876
+ return 'waiting';
877
+ case LanePrimaryState.PAUSED:
878
+ return 'paused';
879
+ case LanePrimaryState.RECOVERING:
880
+ return 'running'; // 복구 중은 running으로 표시
881
+ case LanePrimaryState.COMPLETED:
882
+ return 'completed';
883
+ case LanePrimaryState.FAILED:
884
+ case LanePrimaryState.ABORTED:
885
+ return 'failed';
886
+ default:
887
+ return 'unknown';
888
+ }
889
+ }
890
+ //# sourceMappingURL=lane-state-machine.js.map