issue-flow 0.11.1 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/dist/{analyze-XV3K25K3.js → analyze-OEET7KGE.js} +15 -10
  2. package/dist/{analyze-XV3K25K3.js.map → analyze-OEET7KGE.js.map} +1 -1
  3. package/dist/{apply-WUJHDD7A.js → apply-ZIA3C52S.js} +6 -4
  4. package/dist/{apply-WUJHDD7A.js.map → apply-ZIA3C52S.js.map} +1 -1
  5. package/dist/{chunk-6N7LZZ5U.js → chunk-3QHK4YQA.js} +204 -107
  6. package/dist/chunk-3QHK4YQA.js.map +1 -0
  7. package/dist/chunk-42PJFMAR.js +605 -0
  8. package/dist/chunk-42PJFMAR.js.map +1 -0
  9. package/dist/{chunk-EWDJENFW.js → chunk-4JSOYE4G.js} +77 -12
  10. package/dist/chunk-4JSOYE4G.js.map +1 -0
  11. package/dist/chunk-56KS3TFQ.js +703 -0
  12. package/dist/chunk-56KS3TFQ.js.map +1 -0
  13. package/dist/{chunk-AAY6KM7N.js → chunk-73ATPIYX.js} +160 -154
  14. package/dist/chunk-73ATPIYX.js.map +1 -0
  15. package/dist/{chunk-KQ4JQN7T.js → chunk-A4SLHOW7.js} +68 -12
  16. package/dist/chunk-A4SLHOW7.js.map +1 -0
  17. package/dist/chunk-BAUPQXPE.js +173 -0
  18. package/dist/chunk-BAUPQXPE.js.map +1 -0
  19. package/dist/{chunk-HC2MT7BX.js → chunk-BYZDPR7N.js} +14 -581
  20. package/dist/chunk-BYZDPR7N.js.map +1 -0
  21. package/dist/chunk-CD5ULRVC.js +615 -0
  22. package/dist/chunk-CD5ULRVC.js.map +1 -0
  23. package/dist/chunk-DIDUVL6O.js +1365 -0
  24. package/dist/chunk-DIDUVL6O.js.map +1 -0
  25. package/dist/{chunk-47VIN33V.js → chunk-EZATO3DW.js} +7 -5
  26. package/dist/{chunk-47VIN33V.js.map → chunk-EZATO3DW.js.map} +1 -1
  27. package/dist/{chunk-BXCPXRBR.js → chunk-FADTCQGM.js} +46 -11
  28. package/dist/chunk-FADTCQGM.js.map +1 -0
  29. package/dist/{chunk-GANSDJV7.js → chunk-FJP3UQGD.js} +15 -13
  30. package/dist/chunk-FJP3UQGD.js.map +1 -0
  31. package/dist/chunk-KMMASOA6.js +134 -0
  32. package/dist/chunk-KMMASOA6.js.map +1 -0
  33. package/dist/{chunk-HQYXVIH6.js → chunk-LAFNLLQP.js} +3 -3
  34. package/dist/chunk-LWRSMTTZ.js +18 -0
  35. package/dist/chunk-LWRSMTTZ.js.map +1 -0
  36. package/dist/{chunk-IVHZEYAX.js → chunk-M5UCXTIT.js} +13 -11
  37. package/dist/{chunk-IVHZEYAX.js.map → chunk-M5UCXTIT.js.map} +1 -1
  38. package/dist/chunk-M66SJHQQ.js +206 -0
  39. package/dist/chunk-M66SJHQQ.js.map +1 -0
  40. package/dist/{chunk-OBLVLIUS.js → chunk-MJULIKQU.js} +42 -6
  41. package/dist/chunk-MJULIKQU.js.map +1 -0
  42. package/dist/{chunk-RKTEV6EG.js → chunk-NS6R37II.js} +4 -4
  43. package/dist/{run-DBF2VWUN.js → chunk-NTMMF5UD.js} +515 -544
  44. package/dist/chunk-NTMMF5UD.js.map +1 -0
  45. package/dist/{chunk-EY6WMHV2.js → chunk-QCPGHBSZ.js} +14 -12
  46. package/dist/{chunk-EY6WMHV2.js.map → chunk-QCPGHBSZ.js.map} +1 -1
  47. package/dist/{chunk-LVKQ2AKT.js → chunk-TSOLWK7Y.js} +8 -6
  48. package/dist/chunk-TSOLWK7Y.js.map +1 -0
  49. package/dist/{chunk-34WNTK3K.js → chunk-XQUSIEKA.js} +11 -9
  50. package/dist/{chunk-34WNTK3K.js.map → chunk-XQUSIEKA.js.map} +1 -1
  51. package/dist/chunk-Y5ZDJ4PJ.js +76 -0
  52. package/dist/chunk-Y5ZDJ4PJ.js.map +1 -0
  53. package/dist/cli.js +156 -26
  54. package/dist/cli.js.map +1 -1
  55. package/dist/{config-4THHOXNN.js → config-PRJGWW7J.js} +15 -3
  56. package/dist/execute-XBNVL753.js +18 -0
  57. package/dist/{generate-TBVTLMOP.js → generate-EGB4KV2B.js} +16 -10
  58. package/dist/{generate-TBVTLMOP.js.map → generate-EGB4KV2B.js.map} +1 -1
  59. package/dist/init-AJHCXJBP.js +10 -0
  60. package/dist/operations-BYT626KQ.js +365 -0
  61. package/dist/operations-BYT626KQ.js.map +1 -0
  62. package/dist/plan-QOZ3RIO6.js +21 -0
  63. package/dist/{policy-XQW5NUIE.js → policy-6S4GFC76.js} +6 -4
  64. package/dist/{policy-XQW5NUIE.js.map → policy-6S4GFC76.js.map} +1 -1
  65. package/dist/pr-EBBHD2ZX.js +26 -0
  66. package/dist/pr-review-VVMW5PO4.js +20 -0
  67. package/dist/prd-JQSZF7PR.js +21 -0
  68. package/dist/resume-PPCNQVVV.js +221 -0
  69. package/dist/resume-PPCNQVVV.js.map +1 -0
  70. package/dist/review-3F6MARWH.js +19 -0
  71. package/dist/run-RXE5GDQO.js +36 -0
  72. package/dist/run-RXE5GDQO.js.map +1 -0
  73. package/dist/state-manager-2EDVDBAR.js +34 -0
  74. package/dist/state-manager-2EDVDBAR.js.map +1 -0
  75. package/dist/{web-ANQQTTRD.js → web-EF5WIIGG.js} +13 -8
  76. package/dist/{web-ANQQTTRD.js.map → web-EF5WIIGG.js.map} +1 -1
  77. package/package.json +1 -1
  78. package/prompts/pr.md +11 -4
  79. package/web/public/app.js +12 -0
  80. package/dist/chunk-3BOHTH4V.js +0 -58
  81. package/dist/chunk-3BOHTH4V.js.map +0 -1
  82. package/dist/chunk-6N7LZZ5U.js.map +0 -1
  83. package/dist/chunk-AAY6KM7N.js.map +0 -1
  84. package/dist/chunk-BXCPXRBR.js.map +0 -1
  85. package/dist/chunk-EWDJENFW.js.map +0 -1
  86. package/dist/chunk-GANSDJV7.js.map +0 -1
  87. package/dist/chunk-HC2MT7BX.js.map +0 -1
  88. package/dist/chunk-HDV3YDTG.js +0 -52
  89. package/dist/chunk-HDV3YDTG.js.map +0 -1
  90. package/dist/chunk-KQ4JQN7T.js.map +0 -1
  91. package/dist/chunk-LVKQ2AKT.js.map +0 -1
  92. package/dist/chunk-OBLVLIUS.js.map +0 -1
  93. package/dist/chunk-VQ5VN7DF.js +0 -1018
  94. package/dist/chunk-VQ5VN7DF.js.map +0 -1
  95. package/dist/execute-5OEKLM5X.js +0 -15
  96. package/dist/init-PRMOTQ7N.js +0 -9
  97. package/dist/plan-Y2BYZD24.js +0 -17
  98. package/dist/pr-H6GLOSXF.js +0 -21
  99. package/dist/pr-review-CK5FR6WX.js +0 -17
  100. package/dist/prd-4PWLCGH5.js +0 -17
  101. package/dist/review-QGVAHEZF.js +0 -15
  102. package/dist/run-DBF2VWUN.js.map +0 -1
  103. /package/dist/{chunk-HQYXVIH6.js.map → chunk-LAFNLLQP.js.map} +0 -0
  104. /package/dist/{chunk-RKTEV6EG.js.map → chunk-NS6R37II.js.map} +0 -0
  105. /package/dist/{config-4THHOXNN.js.map → config-PRJGWW7J.js.map} +0 -0
  106. /package/dist/{execute-5OEKLM5X.js.map → execute-XBNVL753.js.map} +0 -0
  107. /package/dist/{init-PRMOTQ7N.js.map → init-AJHCXJBP.js.map} +0 -0
  108. /package/dist/{plan-Y2BYZD24.js.map → plan-QOZ3RIO6.js.map} +0 -0
  109. /package/dist/{pr-H6GLOSXF.js.map → pr-EBBHD2ZX.js.map} +0 -0
  110. /package/dist/{pr-review-CK5FR6WX.js.map → pr-review-VVMW5PO4.js.map} +0 -0
  111. /package/dist/{prd-4PWLCGH5.js.map → prd-JQSZF7PR.js.map} +0 -0
  112. /package/dist/{review-QGVAHEZF.js.map → review-3F6MARWH.js.map} +0 -0
@@ -1,62 +1,77 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  publishGitState
4
- } from "./chunk-LVKQ2AKT.js";
4
+ } from "./chunk-TSOLWK7Y.js";
5
5
  import {
6
- isTransientFailure,
7
- retryDelaySeconds,
8
6
  sleep
9
- } from "./chunk-HDV3YDTG.js";
7
+ } from "./chunk-LWRSMTTZ.js";
10
8
  import {
11
9
  EXECUTE_PHASE,
12
10
  elapsedSecondsSince,
13
11
  getPhaseUsageTotals,
14
12
  publishIterationMetrics,
15
13
  publishStoryMetrics,
14
+ readClaudeStream,
16
15
  resolvePolicyPlaceholders
17
- } from "./chunk-OBLVLIUS.js";
16
+ } from "./chunk-MJULIKQU.js";
18
17
  import {
19
18
  applyPlaceholders,
20
19
  loadPrompt
21
- } from "./chunk-HQYXVIH6.js";
20
+ } from "./chunk-LAFNLLQP.js";
21
+ import {
22
+ createWatchdog,
23
+ describeStall,
24
+ getShutdownSignal,
25
+ registerChild
26
+ } from "./chunk-M66SJHQQ.js";
22
27
  import {
23
28
  createConfig,
24
29
  resolvePaths,
25
30
  validateDependencies
26
- } from "./chunk-VQ5VN7DF.js";
31
+ } from "./chunk-42PJFMAR.js";
32
+ import {
33
+ classify,
34
+ committedStoryIds,
35
+ fixedBackoffPolicy,
36
+ getBaseBranch,
37
+ isWorkingTreeClean,
38
+ withRetry
39
+ } from "./chunk-DIDUVL6O.js";
27
40
  import {
28
- allStoriesPass,
29
- applyStoryMetrics,
30
- clearLastError,
31
- divideUsage,
32
41
  formatDuration,
33
- formatTokens,
34
42
  getIcons,
43
+ getInactivityTimeout,
35
44
  getOutputCallback,
36
45
  getSessionPublisher,
37
46
  getStoryStageCallback,
38
47
  getStoryUpdateCallback,
39
48
  getTermWidth,
40
- hasPendingCorrection,
41
- initializeState,
42
49
  isVerbose,
43
- isoNow,
44
- loadTaskPlan,
45
- markIssueCompleted,
46
- markIssueInProgress,
47
- parseUsage,
48
50
  printError,
49
51
  printInfo,
50
52
  printRetry,
51
53
  printSuccess,
52
54
  printWarning,
55
+ useColor,
56
+ useUnicode
57
+ } from "./chunk-BYZDPR7N.js";
58
+ import {
59
+ allStoriesPass,
60
+ applyStoryMetrics,
61
+ clearLastError,
62
+ divideUsage,
63
+ formatTokens,
64
+ hasPendingCorrection,
65
+ initializeState,
66
+ isoNow,
67
+ loadTaskPlan,
68
+ markIssueCompleted,
69
+ markIssueInProgress,
53
70
  saveTaskPlan,
54
71
  selectActiveStory,
55
72
  setLastError,
56
- trimErrorMessage,
57
- useColor,
58
- useUnicode
59
- } from "./chunk-HC2MT7BX.js";
73
+ trimErrorMessage
74
+ } from "./chunk-CD5ULRVC.js";
60
75
 
61
76
  // src/core/engine.ts
62
77
  import { existsSync } from "fs";
@@ -315,32 +330,65 @@ function printRunSummary(info) {
315
330
 
316
331
  // src/core/executor.ts
317
332
  import { execa } from "execa";
318
- async function executeClaude(prompt) {
319
- const result = await execa(
333
+ async function executeClaude(prompt, options = {}) {
334
+ const subprocess = execa(
320
335
  "claude",
321
- ["--dangerously-skip-permissions", "--print", "--output-format", "json"],
336
+ ["--dangerously-skip-permissions", "--print", "--output-format", "stream-json", "--verbose"],
322
337
  {
323
338
  input: prompt,
324
339
  reject: false,
325
340
  timeout: 0,
326
- // No timeout — let the engine handle iteration limits
341
+ // No timeout — the engine bounds this by iterations
327
342
  stripFinalNewline: false
328
343
  }
329
344
  );
345
+ const unregisterChild = registerChild({
346
+ kill: (signal) => subprocess.kill(signal),
347
+ done: subprocess.then(
348
+ () => void 0,
349
+ () => void 0
350
+ )
351
+ });
352
+ const watchdog = createWatchdog({
353
+ ...options.inactivityTimeoutMs === void 0 ? {} : { inactivityTimeoutMs: options.inactivityTimeoutMs },
354
+ child: {
355
+ kill: (signal) => subprocess.kill(signal),
356
+ done: subprocess.then(
357
+ () => void 0,
358
+ () => void 0
359
+ )
360
+ }
361
+ });
362
+ let streamed = {
363
+ result: "",
364
+ isError: false,
365
+ usage: null,
366
+ events: 0,
367
+ raw: ""
368
+ };
369
+ if (subprocess.stdout) {
370
+ streamed = await readClaudeStream(subprocess.stdout, { onLine: () => watchdog.beat() });
371
+ }
372
+ const result = await subprocess;
373
+ watchdog.stop();
374
+ unregisterChild();
330
375
  const stdout = result.stdout?.toString() ?? "";
331
376
  const stderr = result.stderr?.toString() ?? "";
332
377
  const exitCode = result.exitCode ?? 1;
333
- let output = stdout + (stderr ? `
378
+ const printed = streamed.raw === "" ? stdout : streamed.raw;
379
+ let output = printed + (stderr ? `
334
380
  ${stderr}` : "");
335
381
  let cost = null;
336
- if (exitCode === 0) {
337
- try {
338
- const parsed = JSON.parse(stdout);
339
- const text = parsed?.result;
340
- output = typeof text === "string" ? text : stdout;
341
- cost = parseUsage(parsed);
342
- } catch {
343
- }
382
+ if (watchdog.stalled) {
383
+ return {
384
+ exitCode: exitCode === 0 ? 1 : exitCode,
385
+ output: describeStall(watchdog.silentMs),
386
+ cost: null
387
+ };
388
+ }
389
+ if (exitCode === 0 && streamed.result !== "") {
390
+ output = streamed.result;
391
+ cost = streamed.usage;
344
392
  }
345
393
  const onOutput = getOutputCallback();
346
394
  if (onOutput) {
@@ -367,6 +415,14 @@ function emitLog(message) {
367
415
  console.log(message);
368
416
  }
369
417
  }
418
+ function executeRetryPolicy(config) {
419
+ return fixedBackoffPolicy(
420
+ config.retryLimit + 1,
421
+ config.backoffBaseSeconds,
422
+ config.backoffMaxSeconds,
423
+ { retryForever: config.retryForever }
424
+ );
425
+ }
370
426
  function newlyCompletedStoryIds(before, after) {
371
427
  const wasPassing = new Map(before.map((story) => [story.id, story.passes]));
372
428
  return after.filter((story) => story.passes && wasPassing.get(story.id) === false).map((story) => story.id);
@@ -379,6 +435,30 @@ function commitPlaceholders(scope, convention) {
379
435
  __FIX_COMMIT_MESSAGE__: `fix${suffix}: address review findings`
380
436
  };
381
437
  }
438
+ function inactivityOptions() {
439
+ const configured = getInactivityTimeout();
440
+ return configured === void 0 ? {} : { inactivityTimeoutMs: configured };
441
+ }
442
+ async function adoptCommittedStories(tasksPath) {
443
+ try {
444
+ const plan = await loadTaskPlan(tasksPath);
445
+ const pending = plan.userStories.filter((story) => !story.passes);
446
+ if (pending.length === 0) return [];
447
+ if (!await isWorkingTreeClean()) return [];
448
+ const committed = await committedStoryIds(await getBaseBranch());
449
+ const adopted = pending.filter((story) => committed.has(story.id)).map((story) => story.id);
450
+ if (adopted.length === 0) return [];
451
+ await saveTaskPlan(tasksPath, {
452
+ ...plan,
453
+ userStories: plan.userStories.map(
454
+ (story) => adopted.includes(story.id) ? { ...story, passes: true } : story
455
+ )
456
+ });
457
+ return adopted;
458
+ } catch {
459
+ return [];
460
+ }
461
+ }
382
462
  async function ensureProgressFile(progressFile) {
383
463
  if (!existsSync(progressFile)) {
384
464
  const content = `# Issue Flow Progress Log
@@ -471,101 +551,118 @@ async function runEngine(config, paths) {
471
551
  printStartupHeader(config, plan);
472
552
  const startTime = Date.now();
473
553
  let i = 0;
474
- let retryCount = 0;
475
554
  let totalRetryCount = 0;
476
555
  while (true) {
477
556
  if (config.maxIterations !== void 0 && i >= config.maxIterations) {
478
557
  break;
479
558
  }
480
559
  i++;
481
- plan = await loadTaskPlan(paths.prdFile);
482
- const storiesBeforeIteration = plan.userStories;
483
- const activeStoryId = selectActiveStory(plan.userStories)?.id;
484
- getSessionPublisher().publish({
485
- type: "iteration:start",
486
- at: isoNow(),
487
- iteration: i,
488
- storyId: activeStoryId
489
- });
490
- getStoryStageCallback()?.(activeStoryId);
491
- if (isVerbose()) {
492
- printIterationHeader(i, config.maxIterations, plan.userStories, activeStoryId);
560
+ const adopted = await adoptCommittedStories(paths.prdFile);
561
+ if (adopted.length > 0) {
562
+ printInfo(
563
+ `Adopting ${adopted.join(", ")}: already committed on this branch with a clean tree.`
564
+ );
565
+ plan = await loadTaskPlan(paths.prdFile);
566
+ if (plan.userStories.every((story) => story.passes) && plan.lastReviewFindings === null) {
567
+ break;
568
+ }
493
569
  }
494
- const prompt = applyPlaceholders(promptTemplate, {
495
- __PRD_FILE__: paths.prdFile,
496
- __PROGRESS_FILE__: paths.progressFile,
497
- ...policy,
498
- // The convention comes off the projection above rather than from a second
499
- // discovery: one resolution per run is the whole point of the cache.
500
- ...commitPlaceholders(config.commitScope, policy.__COMMIT_CONVENTION__)
501
- });
502
- const iterationStartedAt = isoNow();
503
- plan = markIssueInProgress(plan, iterationStartedAt);
504
- await saveTaskPlan(paths.prdFile, plan);
505
- const iterationStartedAtMs = Date.now();
506
- const result = await executeClaude(prompt);
507
- const iterationSeconds = elapsedSecondsSince(iterationStartedAtMs);
508
- if (result.exitCode !== 0) {
509
- publishIterationMetrics(i, result.cost, iterationSeconds);
510
- const errorMessage = trimErrorMessage(result.output);
511
- if (isTransientFailure(result.exitCode, result.output)) {
512
- retryCount++;
513
- totalRetryCount++;
570
+ const attempted = await withRetry(
571
+ async () => {
514
572
  plan = await loadTaskPlan(paths.prdFile);
515
- plan = setLastError(plan, "transient_claude_failure", errorMessage);
516
- await saveTaskPlan(paths.prdFile, plan);
517
- if (!config.retryForever && retryCount > config.retryLimit) {
518
- const elapsed3 = Math.floor((Date.now() - startTime) / 1e3);
519
- plan = await loadTaskPlan(paths.prdFile);
520
- printSummaryBox(
521
- "failed",
522
- i,
523
- totalRetryCount,
524
- elapsed3,
525
- plan,
526
- `Exceeded retry limit (${config.retryLimit}) on transient errors`,
527
- getPhaseUsageTotals(EXECUTE_PHASE)
528
- );
529
- return result.exitCode;
530
- }
531
- const delaySeconds = retryDelaySeconds(
532
- retryCount,
533
- config.backoffBaseSeconds,
534
- config.backoffMaxSeconds
535
- );
573
+ const storiesBefore = plan.userStories;
574
+ const activeStoryId = selectActiveStory(plan.userStories)?.id;
536
575
  getSessionPublisher().publish({
537
- type: "retry",
576
+ type: "iteration:start",
538
577
  at: isoNow(),
539
- attempt: retryCount,
540
- delaySeconds,
541
- reason: "transient_claude_failure"
578
+ iteration: i,
579
+ storyId: activeStoryId
542
580
  });
581
+ getStoryStageCallback()?.(activeStoryId);
543
582
  if (isVerbose()) {
544
- emitLog("");
583
+ printIterationHeader(i, config.maxIterations, plan.userStories, activeStoryId);
584
+ }
585
+ const prompt = applyPlaceholders(promptTemplate, {
586
+ __PRD_FILE__: paths.prdFile,
587
+ __PROGRESS_FILE__: paths.progressFile,
588
+ ...policy,
589
+ // The convention comes off the projection above rather than from a second
590
+ // discovery: one resolution per run is the whole point of the cache.
591
+ ...commitPlaceholders(config.commitScope, policy.__COMMIT_CONVENTION__)
592
+ });
593
+ const startedAt = isoNow();
594
+ plan = markIssueInProgress(plan, startedAt);
595
+ await saveTaskPlan(paths.prdFile, plan);
596
+ const startedAtMs = Date.now();
597
+ const result2 = await executeClaude(prompt, inactivityOptions());
598
+ const seconds = elapsedSecondsSince(startedAtMs);
599
+ if (result2.exitCode !== 0) {
600
+ publishIterationMetrics(i, result2.cost, seconds);
601
+ }
602
+ return { result: result2, startedAt, seconds, storiesBefore };
603
+ },
604
+ {
605
+ policy: executeRetryPolicy(config),
606
+ // A `Ctrl+C` during a fifteen-minute backoff must stop in that instant,
607
+ // not fifteen minutes later. `abortableDelay` resolves `false` on the
608
+ // abort, which `withRetry` reports as `aborted` rather than a failure.
609
+ signal: getShutdownSignal(),
610
+ // The exit code and the output are all the evidence the CLI leaves
611
+ // behind, which is exactly what `isTransientFailure()` used to be given
612
+ // here — `classify()` is the same verdict plus the kind.
613
+ evaluate: ({ result: result2 }) => result2.exitCode === 0 ? null : classify({ source: "agent", exitCode: result2.exitCode, stdout: result2.output }),
614
+ onAttempt: async ({ value, attempt, failure, willRetry, delayMs }) => {
615
+ if (failure === null) return;
616
+ const errorMessage = trimErrorMessage(value.result.output);
617
+ if (!failure.retryable) {
618
+ plan = await loadTaskPlan(paths.prdFile);
619
+ plan = setLastError(plan, "fatal_claude_failure", errorMessage);
620
+ await saveTaskPlan(paths.prdFile, plan);
621
+ return;
622
+ }
623
+ totalRetryCount++;
624
+ plan = await loadTaskPlan(paths.prdFile);
625
+ plan = setLastError(plan, "transient_claude_failure", errorMessage);
626
+ await saveTaskPlan(paths.prdFile, plan);
627
+ if (!willRetry) return;
628
+ const delaySeconds = delayMs / 1e3;
629
+ getSessionPublisher().publish({
630
+ type: "retry",
631
+ at: isoNow(),
632
+ attempt,
633
+ delaySeconds,
634
+ reason: "transient_claude_failure",
635
+ kind: failure.kind
636
+ });
637
+ if (isVerbose()) {
638
+ emitLog("");
639
+ }
640
+ printRetry(
641
+ `Transient Claude failure on iteration ${i} (attempt ${attempt}). Retrying in ${delaySeconds}s.`
642
+ );
545
643
  }
546
- printRetry(
547
- `Transient Claude failure on iteration ${i} (attempt ${retryCount}). Retrying in ${delaySeconds}s.`
548
- );
549
- i--;
550
- await sleep(delaySeconds);
551
- continue;
552
644
  }
553
- plan = await loadTaskPlan(paths.prdFile);
554
- plan = setLastError(plan, "fatal_claude_failure", errorMessage);
555
- await saveTaskPlan(paths.prdFile, plan);
645
+ );
646
+ const {
647
+ result,
648
+ seconds: iterationSeconds,
649
+ storiesBefore: storiesBeforeIteration
650
+ } = attempted.value;
651
+ const iterationStartedAt = attempted.value.startedAt;
652
+ if (result.exitCode !== 0) {
556
653
  const elapsed2 = Math.floor((Date.now() - startTime) / 1e3);
654
+ plan = await loadTaskPlan(paths.prdFile);
557
655
  printSummaryBox(
558
656
  "failed",
559
657
  i,
560
658
  totalRetryCount,
561
659
  elapsed2,
562
660
  plan,
563
- `Claude CLI failed with exit code ${result.exitCode}`,
661
+ attempted.exhausted ? `Exceeded retry limit (${config.retryLimit}) on transient errors` : `Claude CLI failed with exit code ${result.exitCode}`,
564
662
  getPhaseUsageTotals(EXECUTE_PHASE)
565
663
  );
566
664
  return result.exitCode;
567
665
  }
568
- retryCount = 0;
569
666
  plan = await loadTaskPlan(paths.prdFile);
570
667
  plan = clearLastError(plan, iterationStartedAt);
571
668
  await saveTaskPlan(paths.prdFile, plan);
@@ -680,4 +777,4 @@ export {
680
777
  printRunSummary,
681
778
  runExecute
682
779
  };
683
- //# sourceMappingURL=chunk-6N7LZZ5U.js.map
780
+ //# sourceMappingURL=chunk-3QHK4YQA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/engine.ts","../src/ui/progress.ts","../src/ui/summary.ts","../src/core/executor.ts","../src/commands/execute.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { cp, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { resolvePolicyPlaceholders } from '../policy/placeholders.js';\nimport { classify } from '../resilience/errors.js';\nimport type { RetryPolicy } from '../resilience/policy.js';\nimport { fixedBackoffPolicy, withRetry } from '../resilience/retry.js';\nimport type { ClaudeResult, EngineConfig, ResolvedPaths, TaskPlan, UserStory } from '../types.js';\nimport { printError, printInfo, printRetry, printSuccess, printWarning } from '../ui/logger.js';\nimport { printIterationHeader } from '../ui/progress.js';\nimport { printStartupHeader, printSummaryBox } from '../ui/summary.js';\nimport { committedStoryIds, getBaseBranch, isWorkingTreeClean } from '../utils/git.js';\nimport { sleep } from '../utils/retry.js';\nimport { executeClaude } from './executor.js';\nimport { divideUsage } from './metrics.js';\nimport { applyPlaceholders, loadPrompt } from './prompt-resolver.js';\nimport { publishGitState } from './session-git.js';\nimport {\n EXECUTE_PHASE,\n elapsedSecondsSince,\n getPhaseUsageTotals,\n publishIterationMetrics,\n publishStoryMetrics,\n} from './session-metrics.js';\nimport { getSessionPublisher } from './session-publisher.js';\nimport { getShutdownSignal } from './shutdown.js';\nimport {\n allStoriesPass,\n applyStoryMetrics,\n clearLastError,\n hasPendingCorrection,\n initializeState,\n isoNow,\n loadTaskPlan,\n markIssueCompleted,\n markIssueInProgress,\n saveTaskPlan,\n selectActiveStory,\n setLastError,\n trimErrorMessage,\n} from './state-manager.js';\nimport {\n getInactivityTimeout,\n getOutputCallback,\n getStoryStageCallback,\n getStoryUpdateCallback,\n isVerbose,\n} from './verbose.js';\n\n/**\n * Emit a message through the output callback if available, otherwise console.log.\n * Used for bare console.log calls in engine functions so they route through listr2.\n */\nfunction emitLog(message: string): void {\n const cb = getOutputCallback();\n if (cb) {\n // Skip empty lines in listr2 context — they don't render meaningfully\n if (message) {\n cb(message);\n }\n } else {\n console.log(message);\n }\n}\n\n/** What one pass of the execute loop produces, retry or not. */\ninterface ExecuteAttempt {\n result: ClaudeResult;\n /** When the attempt started, for `clearLastError`. */\n startedAt: string;\n /** How long the attempt took, for the metrics split across stories. */\n seconds: number;\n /** The stories as they were before the agent ran, for attribution. */\n storiesBefore: UserStory[];\n}\n\n/**\n * The execute loop's retry budget, unchanged in effect from the hand-rolled\n * loop it replaces: `retryLimit` counts *retries*, so the attempt budget is one\n * more than it, and `retryForever` lifts the count while `backoffMaxSeconds`\n * still caps the wait.\n */\nfunction executeRetryPolicy(config: EngineConfig): RetryPolicy {\n return fixedBackoffPolicy(\n config.retryLimit + 1,\n config.backoffBaseSeconds,\n config.backoffMaxSeconds,\n { retryForever: config.retryForever },\n );\n}\n\n/**\n * Ids of the stories that flipped from `passes: false` to `passes: true`\n * between the two readings of the plan taken around one execute iteration.\n *\n * Stories already passing before the iteration, and stories that only exist in\n * the newer plan, are never attributed: nothing says this iteration paid for\n * them.\n */\nfunction newlyCompletedStoryIds(before: UserStory[], after: UserStory[]): string[] {\n const wasPassing = new Map(before.map((story) => [story.id, story.passes]));\n return after\n .filter((story) => story.passes && wasPassing.get(story.id) === false)\n .map((story) => story.id);\n}\n\n/**\n * Commit message formats handed to the execute prompt.\n *\n * Without a scope they are byte-for-byte what the prompt has always spelled\n * out, so a single-issue run produces the same history it always did. With one\n * — the only case being several issues sharing a branch — the issue becomes a\n * conventional-commit scope, which is what makes `git log` on the shared branch\n * readable per issue.\n *\n * `convention` is the repository's own commit convention, when it declares one.\n * The hard-coded `feat` is wrong for most stories under Conventional Commits: a\n * bug fix committed as `feat:` corrupts a changelog and a semver bump computed\n * from the history. So a repository that declared a convention gets a `<type>`\n * placeholder and the instruction to choose; one that declared none keeps the\n * exact string it always had.\n */\nexport function commitPlaceholders(\n scope?: string,\n convention?: string | null,\n): Record<string, string> {\n const suffix = scope === undefined || scope === '' ? '' : `(${scope})`;\n const declared = convention !== undefined && convention !== null && convention !== '';\n\n return {\n __COMMIT_MESSAGE__: declared\n ? `<type>${suffix}: [Story ID] - [Story Title]`\n : `feat${suffix}: [Story ID] - [Story Title]`,\n __FIX_COMMIT_MESSAGE__: `fix${suffix}: address review findings`,\n };\n}\n\n/**\n * The watchdog budget of one iteration, from the process-wide setting.\n *\n * Absent means the default; `0` turns the watchdog off. Reading it here rather\n * than threading it through the engine's config keeps it a single value per\n * process, which is what it is.\n */\nfunction inactivityOptions(): { inactivityTimeoutMs?: number } {\n const configured = getInactivityTimeout();\n return configured === undefined ? {} : { inactivityTimeoutMs: configured };\n}\n\n/**\n * Mark as passing every pending story whose commit is already on the branch.\n *\n * Two conditions, and both are required:\n *\n * - the story's id appears in a commit subject of this branch, which is what\n * the execute prompt writes (`<type>(scope): US-001 - Title`);\n * - the working tree is **clean**, so nothing is half-applied. A dirty tree\n * means work in flight, and adopting a story on that basis would call\n * finished something that is not.\n *\n * Returns the ids it adopted. Never throws: a git that cannot answer, or a plan\n * that cannot be written, leaves the loop doing exactly what it did before.\n */\nasync function adoptCommittedStories(tasksPath: string): Promise<string[]> {\n try {\n const plan = await loadTaskPlan(tasksPath);\n const pending = plan.userStories.filter((story) => !story.passes);\n if (pending.length === 0) return [];\n\n if (!(await isWorkingTreeClean())) return [];\n\n const committed = await committedStoryIds(await getBaseBranch());\n const adopted = pending.filter((story) => committed.has(story.id)).map((story) => story.id);\n if (adopted.length === 0) return [];\n\n await saveTaskPlan(tasksPath, {\n ...plan,\n userStories: plan.userStories.map((story) =>\n adopted.includes(story.id) ? { ...story, passes: true } : story,\n ),\n });\n return adopted;\n } catch {\n return [];\n }\n}\n\n/**\n * Initialize the progress file if it doesn't exist.\n */\nasync function ensureProgressFile(progressFile: string): Promise<void> {\n if (!existsSync(progressFile)) {\n const content = `# Issue Flow Progress Log\\nStarted: ${new Date().toString()}\\n---\\n`;\n await writeFile(progressFile, content, 'utf-8');\n }\n}\n\n/**\n * Archive previous run artifacts if the branch has changed.\n */\nasync function archiveIfBranchChanged(plan: TaskPlan, paths: ResolvedPaths): Promise<void> {\n const { lastBranchFile, archiveDir, prdFile, progressFile } = paths;\n\n if (!existsSync(lastBranchFile)) {\n return;\n }\n\n const currentBranch = plan.branchName ?? '';\n let lastBranch = '';\n\n try {\n lastBranch = (await readFile(lastBranchFile, 'utf-8')).trim();\n } catch {\n return;\n }\n\n if (currentBranch && lastBranch && currentBranch !== lastBranch) {\n const dateStr = new Date().toISOString().split('T')[0];\n const folderName = lastBranch.replace(/^issue\\//, '').replace(/[<>:\"|?*\\\\]/g, '_');\n const archiveFolder = join(archiveDir, `${dateStr}-${folderName}`);\n\n printInfo(`Archiving previous run: ${lastBranch}`);\n await mkdir(archiveFolder, { recursive: true });\n\n if (existsSync(prdFile)) {\n await cp(prdFile, join(archiveFolder, 'tasks.json'));\n }\n if (existsSync(progressFile)) {\n await cp(progressFile, join(archiveFolder, 'progress.txt'));\n }\n\n printInfo(` Archived to: ${archiveFolder}`);\n\n // Reset progress file for new run\n await writeFile(\n progressFile,\n `# Issue Flow Progress Log\\nStarted: ${new Date().toString()}\\n---\\n`,\n 'utf-8',\n );\n }\n}\n\n/**\n * Write the current branch to the last-branch tracking file.\n */\nasync function trackBranch(plan: TaskPlan, lastBranchFile: string): Promise<void> {\n const branch = plan.branchName ?? '';\n if (branch) {\n await writeFile(lastBranchFile, `${branch}\\n`, 'utf-8');\n }\n}\n\n/**\n * Run the issue-flow engine loop.\n *\n * This replicates the full execution flow:\n * 1. Load and initialize task plan state\n * 2. Check for early exit (already complete)\n * 3. Archive previous run if branch changed\n * 4. Resolve prompt\n * 5. Main loop: iterate, execute Claude, handle results\n * 6. Print summary\n */\nexport async function runEngine(config: EngineConfig, paths: ResolvedPaths): Promise<number> {\n // Load task plan\n if (!existsSync(paths.prdFile)) {\n printError(`PRD file not found at ${paths.prdFile}`);\n if (config.issueNumber) {\n emitLog(`Have you run the resolve-issue skill for issue #${config.issueNumber} first?`);\n }\n return 1;\n }\n\n let plan = await loadTaskPlan(paths.prdFile);\n plan = initializeState(plan);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Check if already completed. A pending correction (a failed review whose\n // findings haven't been addressed yet) always overrides this, even though\n // every userStories[].passes is already true — otherwise a correction\n // cycle's re-run of execute would exit here without ever looking at what\n // the review found.\n if (plan.issueStatus === 'completed' && allStoriesPass(plan) && !hasPendingCorrection(plan)) {\n emitLog(`Issue already marked complete in ${paths.prdFile}`);\n return 0;\n }\n\n // Warn if marked complete but stories still pending\n if (plan.issueStatus === 'completed' && !allStoriesPass(plan)) {\n printWarning(\n 'Issue marked completed but some stories are still pending. Resetting to in_progress.',\n );\n plan = markIssueInProgress(plan);\n plan = setLastError(\n plan,\n 'invalid_completion_state',\n 'tasks.json claimed the issue was completed before every story had passes=true.',\n );\n await saveTaskPlan(paths.prdFile, plan);\n }\n\n // Check if all stories already pass\n if (allStoriesPass(plan) && !hasPendingCorrection(plan)) {\n emitLog('All user stories already pass. Marking issue as completed.');\n plan = markIssueCompleted(plan);\n await saveTaskPlan(paths.prdFile, plan);\n return 0;\n }\n\n // Archive previous run if branch changed\n await archiveIfBranchChanged(plan, paths);\n\n // Track current branch\n await trackBranch(plan, paths.lastBranchFile);\n\n // Initialize progress file\n await ensureProgressFile(paths.progressFile);\n\n // Load prompt template. The root is handed over rather than rediscovered:\n // it was resolved once by `resolvePaths()`, and a second `git rev-parse` here\n // would be a subprocess per run for an answer already in hand.\n const promptTemplate = await loadPrompt('execute', { projectRoot: paths.projectRoot });\n\n // The repository's own conventions, resolved once for the whole loop: they\n // cannot change mid-run, and every iteration renders the same projection.\n const policy = await resolvePolicyPlaceholders({ root: paths.projectRoot });\n\n // Print startup header\n printStartupHeader(config, plan);\n\n const startTime = Date.now();\n let i = 0;\n let totalRetryCount = 0;\n\n // Main loop\n while (true) {\n // Check iteration limit\n if (config.maxIterations !== undefined && i >= config.maxIterations) {\n break;\n }\n\n i++;\n\n // Safety net for the crash between a story's commit and the agent writing\n // `passes: true` (scenario I). The commit is the durable fact; the plan is\n // written after it, so a process that died in between leaves work that is\n // done and a plan that says it is not — and the next iteration redoes it on\n // top of a commit that already exists.\n //\n // This never *replaces* the agent's `passes`, which stays the primary\n // source: it only closes the window the agent cannot close itself.\n const adopted = await adoptCommittedStories(paths.prdFile);\n if (adopted.length > 0) {\n printInfo(\n `Adopting ${adopted.join(', ')}: already committed on this branch with a clean tree.`,\n );\n plan = await loadTaskPlan(paths.prdFile);\n if (plan.userStories.every((story) => story.passes) && plan.lastReviewFindings === null) {\n // Everything the loop was going to do is already done.\n break;\n }\n }\n\n // One iteration is one attempt of the Claude CLI, retried in place by the\n // project's single retry executor (`resilience/retry.ts`). A retry costs no\n // iteration budget, exactly as the `i--` it replaces cost none. Everything a\n // retried attempt has to redo — re-reading the plan, republishing\n // `iteration:start`, re-rendering the prompt — lives inside `attempt`,\n // because the loop this used to be written as re-ran all of it too.\n const attempted = await withRetry<ExecuteAttempt>(\n async () => {\n // Re-read plan to get latest state\n plan = await loadTaskPlan(paths.prdFile);\n // Baseline for story attribution: whatever was still pending before the\n // agent ran is what this iteration can claim credit for.\n const storiesBefore = plan.userStories;\n\n // Highest-priority story with passes: false — the same rule\n // prompts/execute.md gives the agent. Computed once, here, and shared by\n // the published event and the verbose terminal header, so every surface\n // agrees on who is active instead of each deriving its own heuristic.\n const activeStoryId = selectActiveStory(plan.userStories)?.id;\n getSessionPublisher().publish({\n type: 'iteration:start',\n at: isoNow(),\n iteration: i,\n storyId: activeStoryId,\n });\n getStoryStageCallback()?.(activeStoryId);\n\n if (isVerbose()) {\n printIterationHeader(i, config.maxIterations, plan.userStories, activeStoryId);\n }\n\n // Apply placeholders to prompt\n const prompt = applyPlaceholders(promptTemplate, {\n __PRD_FILE__: paths.prdFile,\n __PROGRESS_FILE__: paths.progressFile,\n ...policy,\n // The convention comes off the projection above rather than from a second\n // discovery: one resolution per run is the whole point of the cache.\n ...commitPlaceholders(config.commitScope, policy.__COMMIT_CONVENTION__),\n });\n\n const startedAt = isoNow();\n plan = markIssueInProgress(plan, startedAt);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Execute Claude\n const startedAtMs = Date.now();\n const result = await executeClaude(prompt, inactivityOptions());\n const seconds = elapsedSecondsSince(startedAtMs);\n\n if (result.exitCode !== 0) {\n // A failed iteration still burned tokens: report them on the execute\n // phase, with no attribution to any story.\n publishIterationMetrics(i, result.cost, seconds);\n }\n\n return { result, startedAt, seconds, storiesBefore };\n },\n {\n policy: executeRetryPolicy(config),\n // A `Ctrl+C` during a fifteen-minute backoff must stop in that instant,\n // not fifteen minutes later. `abortableDelay` resolves `false` on the\n // abort, which `withRetry` reports as `aborted` rather than a failure.\n signal: getShutdownSignal(),\n // The exit code and the output are all the evidence the CLI leaves\n // behind, which is exactly what `isTransientFailure()` used to be given\n // here — `classify()` is the same verdict plus the kind.\n evaluate: ({ result }) =>\n result.exitCode === 0\n ? null\n : classify({ source: 'agent', exitCode: result.exitCode, stdout: result.output }),\n onAttempt: async ({ value, attempt, failure, willRetry, delayMs }) => {\n if (failure === null) return;\n\n const errorMessage = trimErrorMessage(value.result.output);\n\n if (!failure.retryable) {\n plan = await loadTaskPlan(paths.prdFile);\n plan = setLastError(plan, 'fatal_claude_failure', errorMessage);\n await saveTaskPlan(paths.prdFile, plan);\n return;\n }\n\n // Recorded even on the attempt that spends the last of the budget:\n // the run ends on a transient failure, and the plan has to say so.\n totalRetryCount++;\n plan = await loadTaskPlan(paths.prdFile);\n plan = setLastError(plan, 'transient_claude_failure', errorMessage);\n await saveTaskPlan(paths.prdFile, plan);\n if (!willRetry) return;\n\n const delaySeconds = delayMs / 1000;\n getSessionPublisher().publish({\n type: 'retry',\n at: isoNow(),\n attempt,\n delaySeconds,\n reason: 'transient_claude_failure',\n kind: failure.kind,\n });\n\n if (isVerbose()) {\n emitLog('');\n }\n printRetry(\n `Transient Claude failure on iteration ${i} (attempt ${attempt}). Retrying in ${delaySeconds}s.`,\n );\n },\n },\n );\n\n const {\n result,\n seconds: iterationSeconds,\n storiesBefore: storiesBeforeIteration,\n } = attempted.value;\n const iterationStartedAt = attempted.value.startedAt;\n\n if (result.exitCode !== 0) {\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n plan = await loadTaskPlan(paths.prdFile);\n printSummaryBox(\n 'failed',\n i,\n totalRetryCount,\n elapsed,\n plan,\n attempted.exhausted\n ? `Exceeded retry limit (${config.retryLimit}) on transient errors`\n : `Claude CLI failed with exit code ${result.exitCode}`,\n getPhaseUsageTotals(EXECUTE_PHASE),\n );\n return result.exitCode;\n }\n\n plan = await loadTaskPlan(paths.prdFile);\n plan = clearLastError(plan, iterationStartedAt);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Notify story progress listeners (e.g., listr2 subtasks)\n const storyUpdateCb = getStoryUpdateCallback();\n if (storyUpdateCb) {\n storyUpdateCb(plan.userStories);\n }\n getSessionPublisher().publish({\n type: 'stories:update',\n at: isoNow(),\n stories: plan.userStories,\n });\n\n // Story attribution — an approximation by construction: the CLI reports a\n // single usage for the whole iteration, so the stories that flipped to\n // passing in it split tokens, cost and duration evenly. With none, nothing\n // is attributed and the whole cost stays on the execute phase. Published\n // after stories:update, which rebuilds the stories array.\n const completedStoryIds = newlyCompletedStoryIds(storiesBeforeIteration, plan.userStories);\n if (completedStoryIds.length > 0) {\n const storyShare = divideUsage(result.cost, completedStoryIds.length);\n const storySeconds = Math.round(iterationSeconds / completedStoryIds.length);\n for (const storyId of completedStoryIds) {\n publishStoryMetrics(storyId, storyShare, storySeconds);\n }\n\n // The same shares also land on tasks.json, so the numbers outlive the\n // session and are readable with web monitoring off. Persisting them is\n // observational: a write failure must never change the iteration's\n // outcome, so the plan in memory only advances when the write succeeded.\n const planWithMetrics = applyStoryMetrics(plan, completedStoryIds, storyShare, storySeconds);\n try {\n await saveTaskPlan(paths.prdFile, planWithMetrics);\n plan = planWithMetrics;\n } catch {\n // Metrics are a nice-to-have; the iteration succeeded regardless.\n }\n }\n\n getSessionPublisher().publish({ type: 'iteration:end', at: isoNow(), iteration: i });\n publishIterationMetrics(i, result.cost, iterationSeconds);\n // Low-frequency commit/PR enrichment: iteration end is one of the only\n // two sanctioned points (the other is phase boundaries in run.ts).\n await publishGitState(getSessionPublisher());\n\n // Check for completion signal\n if (result.output.includes('<promise>COMPLETE</promise>')) {\n plan = await loadTaskPlan(paths.prdFile);\n if (allStoriesPass(plan) && !hasPendingCorrection(plan)) {\n plan = markIssueCompleted(plan);\n await saveTaskPlan(paths.prdFile, plan);\n\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n printSummaryBox(\n 'success',\n i,\n totalRetryCount,\n elapsed,\n plan,\n undefined,\n getPhaseUsageTotals(EXECUTE_PHASE),\n );\n return 0;\n }\n\n plan = setLastError(\n plan,\n 'invalid_completion_signal',\n hasPendingCorrection(plan)\n ? 'Claude returned <promise>COMPLETE</promise> while lastReviewFindings was still set.'\n : 'Claude returned <promise>COMPLETE</promise> before every story had passes=true.',\n );\n await saveTaskPlan(paths.prdFile, plan);\n\n emitLog('');\n printWarning(\n hasPendingCorrection(plan)\n ? 'Claude returned a completion signal, but lastReviewFindings is still set. Ignoring completion and continuing.'\n : 'Claude returned a completion signal, but tasks.json still has pending stories. Ignoring completion and continuing.',\n );\n }\n\n if (isVerbose()) {\n printSuccess(`Iteration ${i} complete. Continuing...`);\n }\n await sleep(2);\n }\n\n // Reached max iterations\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n plan = await loadTaskPlan(paths.prdFile);\n printSummaryBox(\n 'incomplete',\n config.maxIterations ?? i,\n totalRetryCount,\n elapsed,\n plan,\n 'Reached max iterations without completing all tasks.',\n getPhaseUsageTotals(EXECUTE_PHASE),\n );\n return 1;\n}\n","import chalk from 'chalk';\nimport { getOutputCallback } from '../core/verbose.js';\nimport type { UserStory } from '../types.js';\nimport { getIcons, useColor, useUnicode } from './logger.js';\n\n/**\n * Print a visual progress bar showing passed/total stories.\n */\nexport function printProgressBar(passed: number, total: number): string {\n const barWidth = 20;\n let pct = 0;\n let filled = 0;\n\n if (total > 0) {\n pct = Math.floor((passed * 100) / total);\n filled = Math.floor((passed * barWidth) / total);\n }\n\n const empty = barWidth - filled;\n const fillChar = useUnicode() ? '\\u2588' : '#';\n const emptyChar = useUnicode() ? '\\u2591' : '-';\n\n const bar = fillChar.repeat(filled) + emptyChar.repeat(empty);\n const text = `${passed}/${total} (${pct}%)`;\n\n if (useColor()) {\n return `${chalk.green(bar)} ${text}`;\n }\n return `${bar} ${text}`;\n}\n\n/**\n * Print the iteration header showing story statuses and progress bar.\n *\n * When a global output callback is set (e.g., inside a listr2 task),\n * output is routed through it instead of console.log.\n *\n * `activeStoryId`, when provided, identifies the story the engine is\n * actually about to work on this iteration (the same id published on\n * `iteration:start` \\u2014 see `core/state-manager.ts`'s `selectActiveStory`),\n * so the header agrees with the session snapshot instead of guessing.\n * Omitted, it falls back to the previous heuristic (\"first non-passing story\n * in array order\"), which existing callers that cannot supply the real id\n * keep relying on.\n */\nexport function printIterationHeader(\n iteration: number,\n maxIter: number | undefined,\n stories: UserStory[],\n activeStoryId?: string,\n): void {\n const icons = getIcons();\n const colored = useColor();\n const cb = getOutputCallback();\n\n const iterLabel = maxIter ? `Iteration ${iteration} of ${maxIter}` : `Iteration ${iteration}`;\n\n const total = stories.length;\n const passed = stories.filter((s) => s.passes).length;\n\n const lines: string[] = [];\n\n if (colored) {\n lines.push(chalk.blue(`\\u2501\\u2501\\u2501 ${icons.start} ${iterLabel} \\u2501\\u2501\\u2501`));\n } else {\n lines.push(`--- ${icons.start} ${iterLabel} ---`);\n }\n\n // Display each story status\n let foundFirstPending = false;\n for (const story of stories) {\n let icon: string;\n let colorFn: (s: string) => string;\n const isActive =\n activeStoryId !== undefined\n ? story.id === activeStoryId\n : !story.passes && !foundFirstPending;\n\n if (story.passes) {\n icon = icons.success;\n colorFn = colored ? chalk.green : (s: string) => s;\n } else if (isActive) {\n icon = icons.pending;\n colorFn = colored ? chalk.yellow : (s: string) => s;\n foundFirstPending = true;\n } else {\n // Not yet reached\n icon = icons.notReached;\n colorFn = colored ? chalk.gray : (s: string) => s;\n }\n\n lines.push(colorFn(` ${icon} ${story.id}: ${story.title}`));\n }\n\n lines.push(` ${printProgressBar(passed, total)}`);\n\n if (cb) {\n // Send as single output to listr2 task context\n cb(lines.join('\\n'));\n } else {\n console.log('');\n for (const line of lines) {\n console.log(line);\n }\n console.log('');\n }\n}\n","import chalk from 'chalk';\nimport { type ClaudeUsage, formatTokens } from '../core/metrics.js';\nimport type { EngineConfig, PrReviewRecommendation, TaskPlan } from '../types.js';\nimport {\n formatDuration,\n getIcons,\n getTermWidth,\n printSuccess,\n printWarning,\n useColor,\n useUnicode,\n} from './logger.js';\n\n/**\n * Truncate or pad a string to fit within a given width.\n */\nfunction fitLine(text: string, width: number): string {\n if (text.length > width) {\n return text.substring(0, width);\n }\n return text.padEnd(width);\n}\n\n/**\n * Print a box with border characters around content lines.\n * Lines equal to \"---\" render as separator rows.\n */\nexport function printBox(lines: string[]): void {\n const colored = useColor();\n const unicode = useUnicode();\n const termWidth = getTermWidth();\n\n // Find max content width\n let maxContentWidth = 0;\n for (const line of lines) {\n if (line !== '---' && line.length > maxContentWidth) {\n maxContentWidth = line.length;\n }\n }\n\n // Cap to terminal width (border + padding = 4 chars)\n const available = termWidth - 4;\n if (maxContentWidth > available) {\n maxContentWidth = available;\n }\n if (maxContentWidth < 20) {\n maxContentWidth = 20;\n }\n\n // Box drawing characters\n const tl = unicode ? '\\u256D' : '+';\n const tr = unicode ? '\\u256E' : '+';\n const bl = unicode ? '\\u2570' : '+';\n const br = unicode ? '\\u256F' : '+';\n const h = unicode ? '\\u2500' : '-';\n const v = unicode ? '\\u2502' : '|';\n const sepL = unicode ? '\\u251C' : '+';\n const sepR = unicode ? '\\u2524' : '+';\n\n const hrule = h.repeat(maxContentWidth + 2);\n\n const blue = colored ? chalk.blue : (s: string) => s;\n const _reset = (s: string) => s;\n\n // Top border\n console.log(blue(`${tl}${hrule}${tr}`));\n\n // Content lines\n for (const line of lines) {\n if (line === '---') {\n console.log(blue(`${sepL}${hrule}${sepR}`));\n } else {\n const fitted = fitLine(line, maxContentWidth);\n console.log(`${blue(v)} ${fitted} ${blue(v)}`);\n }\n }\n\n // Bottom border\n console.log(blue(`${bl}${hrule}${br}`));\n}\n\n/**\n * Print the startup header box showing engine configuration.\n */\nexport function printStartupHeader(config: EngineConfig, plan: TaskPlan): void {\n const icons = getIcons();\n\n const storiesTotal = plan.userStories.length;\n const storiesPassing = plan.userStories.filter((s) => s.passes).length;\n const branchName = plan.branchName ?? 'N/A';\n\n const issueLabel = config.issueNumber ? `Issue #${config.issueNumber}` : 'Standalone mode';\n\n const maxIterLabel =\n config.maxIterations !== undefined ? String(config.maxIterations) : 'unlimited';\n\n const retryLabel = config.retryForever\n ? 'unlimited retries'\n : `${config.retryLimit} consecutive retries`;\n\n printBox([\n `${icons.start} Issue Flow`,\n '---',\n `Issue: ${issueLabel}`,\n `Branch: ${branchName}`,\n `Stories: ${storiesPassing}/${storiesTotal} passing`,\n `Iterations: ${maxIterLabel}`,\n `Retries: ${retryLabel}`,\n ]);\n}\n\n// Re-export formatDuration from logger to maintain backwards compatibility\nexport { formatDuration } from './logger.js';\n\n/**\n * Print the final summary box.\n */\nexport function printSummaryBox(\n status: 'success' | 'incomplete' | 'failed',\n iterations: number,\n totalRetries: number,\n elapsedSeconds: number,\n plan: TaskPlan,\n extraInfo?: string,\n /**\n * Tokens and cost spent by this run, already resolved by the caller (the\n * process-owned counters in `core/session-metrics.ts`, never the session\n * snapshot — that one is empty whenever web monitoring is off). Omitted or\n * empty means \"the CLI reported nothing\", and the line is skipped entirely.\n */\n usage?: ClaudeUsage | null,\n): void {\n const icons = getIcons();\n\n const storiesTotal = plan.userStories.length;\n const storiesPassing = plan.userStories.filter((s) => s.passes).length;\n const duration = formatDuration(elapsedSeconds);\n\n let statusIcon: string;\n let statusLabel: string;\n\n switch (status) {\n case 'success':\n statusIcon = icons.success;\n statusLabel = 'Completed';\n break;\n case 'incomplete':\n statusIcon = icons.warn;\n statusLabel = 'Incomplete';\n break;\n case 'failed':\n statusIcon = icons.fail;\n statusLabel = 'Failed';\n break;\n }\n\n const boxLines = [\n `${icons.end} Issue Flow Summary`,\n '---',\n `Status: ${statusIcon} ${statusLabel}`,\n `Stories: ${storiesPassing}/${storiesTotal} passing`,\n `Iterations: ${iterations}`,\n `Duration: ${duration}`,\n ];\n\n const tokens = formatTokens(usage);\n if (tokens !== '') {\n boxLines.push(`Tokens: ${tokens}`);\n }\n\n boxLines.push(`Retries: ${totalRetries}`);\n\n if (extraInfo) {\n boxLines.push('---');\n boxLines.push(extraInfo);\n }\n\n console.log('');\n printBox(boxLines);\n}\n\n/**\n * What the optional `pr-review` phase produced, as far as the summary cares.\n * `null` in `recommendation` means the verdict could not be recovered from\n * disk — the exit code still told us whether changes were requested.\n */\nexport interface RunSummaryPrReview {\n requestedChanges: boolean;\n recommendation: PrReviewRecommendation | null;\n reportPath: string | null;\n}\n\n/**\n * Everything the final `run` summary prints, already resolved by the caller.\n */\nexport interface RunSummaryInfo {\n issueNumber: string;\n /** 'unknown' when the branch could not be detected. */\n branchName: string;\n /** Pipelines run with --no-branch open no Pull Request. */\n noBranch: boolean;\n storyCount: number;\n elapsedSeconds: number;\n /** 'unknown' when no Pull Request could be resolved. */\n prUrl: string;\n /** Only set when the pr-review phase actually ran. */\n prReview?: RunSummaryPrReview | null;\n /**\n * Tokens and cost of the whole pipeline, from the process-owned counters in\n * `core/session-metrics.ts`. Absent or empty omits the line.\n */\n usage?: ClaudeUsage | null;\n}\n\n/**\n * Detail lines of the final `run` summary (everything below the headline).\n *\n * Kept separate from the printing so the shape is testable without capturing\n * stdout. Without `prReview` the lines are exactly the ones the pipeline has\n * always printed.\n */\nexport function buildRunSummaryLines(info: RunSummaryInfo): string[] {\n const lines = [\n ` Branch: ${info.branchName}${info.noBranch ? ' (current)' : ''}`,\n ` Stories: ${info.storyCount}`,\n ` Duration: ${formatDuration(info.elapsedSeconds)}`,\n ];\n\n // Skipped altogether when the CLI reported nothing — better no line than\n // \"0 in / 0 out\" or \"~$NaN\".\n const tokens = formatTokens(info.usage);\n if (tokens !== '') {\n lines.push(` Tokens: ${tokens}`);\n }\n\n if (!info.noBranch) {\n lines.push(` PR: ${info.prUrl}`);\n }\n\n const review = info.prReview;\n if (review) {\n // The exit code is the source of truth for the verdict, so a report whose\n // recommendation could not be read still reports REQUEST_CHANGES.\n const verdict =\n review.recommendation ?? (review.requestedChanges ? 'REQUEST_CHANGES' : 'unknown');\n lines.push(` Review: ${verdict}`);\n if (review.reportPath !== null) {\n lines.push(` Report: ${review.reportPath}`);\n }\n }\n\n return lines;\n}\n\n/** One issue of a multi-issue queue, as the consolidated summary reports it. */\nexport interface QueueIssueSummary {\n id: string;\n title: string;\n storyCount: number;\n elapsedSeconds: number;\n /** Tokens and cost of this issue alone — never of the whole queue. */\n usage?: ClaudeUsage | null;\n}\n\n/** Everything the consolidated summary of a queue prints. */\nexport interface QueueSummaryInfo {\n /** Identifier of the queue, i.e. of its primary issue. */\n queueId: string;\n /** Branch every issue shared, `null` when the queue ran with --no-branch. */\n branchName: string | null;\n issues: QueueIssueSummary[];\n /** Issues discovered but left out of the run. */\n excluded: { id: string; title: string }[];\n elapsedSeconds: number;\n /** The single consolidated Pull Request, `null` when none was opened. */\n prUrl: string | null;\n /** Tokens and cost of the whole queue. */\n usage?: ClaudeUsage | null;\n /** Verdict of the pr-review phase, when the queue ran it. */\n prReview?: RunSummaryPrReview | null;\n}\n\n/**\n * Detail lines of a queue's final summary.\n *\n * Per-issue lines carry their own duration and cost, which is the visible half\n * of the per-issue metric scoping: what one issue spent is never folded into\n * another's line.\n */\nexport function buildQueueSummaryLines(info: QueueSummaryInfo): string[] {\n const lines: string[] = [];\n\n lines.push(` Branch: ${info.branchName ?? 'current'}`);\n lines.push(` Issues: ${info.issues.length}`);\n\n for (const issue of info.issues) {\n const tokens = formatTokens(issue.usage);\n const title = issue.title === '' ? '' : ` ${issue.title}`;\n lines.push(\n ` #${issue.id}${title} — ${issue.storyCount} stories, ${formatDuration(issue.elapsedSeconds)}` +\n (tokens === '' ? '' : `, ${tokens}`),\n );\n }\n\n lines.push(` Duration: ${formatDuration(info.elapsedSeconds)}`);\n\n const tokens = formatTokens(info.usage);\n if (tokens !== '') {\n lines.push(` Tokens: ${tokens}`);\n }\n if (info.prUrl !== null) {\n lines.push(` PR: ${info.prUrl}`);\n }\n if (info.excluded.length > 0) {\n lines.push(` Skipped: ${info.excluded.map((entry) => `#${entry.id}`).join(', ')}`);\n }\n\n const review = info.prReview;\n if (review) {\n lines.push(\n ` Review: ${review.recommendation ?? (review.requestedChanges ? 'REQUEST_CHANGES' : 'unknown')}`,\n );\n if (review.reportPath !== null) {\n lines.push(` Report: ${review.reportPath}`);\n }\n }\n\n return lines;\n}\n\n/** Print the consolidated summary of a multi-issue queue. */\nexport function printQueueSummary(info: QueueSummaryInfo): void {\n console.log('');\n if (info.prReview?.requestedChanges === true) {\n printWarning(`Queue finished for issue #${info.queueId}, but the PR review requested changes.`);\n } else {\n printSuccess(`Queue complete for issue #${info.queueId} (${info.issues.length} issues)!`);\n }\n for (const line of buildQueueSummaryLines(info)) {\n console.log(line);\n }\n}\n\n/**\n * Print the final summary of a `run` (the flat listing, not the box used by\n * the execute engine).\n */\nexport function printRunSummary(info: RunSummaryInfo): void {\n console.log('');\n if (info.prReview?.requestedChanges) {\n printWarning(\n `Pipeline finished for issue #${info.issueNumber}, but the PR review requested changes.`,\n );\n } else {\n printSuccess(`Pipeline complete for issue #${info.issueNumber}!`);\n }\n for (const line of buildRunSummaryLines(info)) {\n console.log(line);\n }\n}\n","import { execa } from 'execa';\nimport type { ClaudeResult } from '../types.js';\nimport type { ClaudeUsage } from './metrics.js';\nimport { registerChild } from './shutdown.js';\nimport { readClaudeStream } from './stream.js';\nimport { getOutputCallback } from './verbose.js';\nimport { createWatchdog, describeStall } from './watchdog.js';\n\nexport interface ExecuteClaudeOptions {\n /**\n * Silence tolerated before the agent is considered stuck. `0` disables the\n * watchdog, which is the behaviour every release before it had.\n */\n inactivityTimeoutMs?: number;\n}\n\n/**\n * Execute Claude CLI with a prompt piped to stdin.\n *\n * Runs: `claude --dangerously-skip-permissions --print --output-format\n * stream-json --verbose`, with the prompt on stdin.\n *\n * **The stream is what makes the loop observable.** This phase runs with\n * `timeout: 0` on purpose — its budget is iterations, not seconds — so before\n * the stream there was no signal whatsoever between \"started\" and \"finished\",\n * and an agent that hung hung forever. Every line is now a heartbeat for the\n * watchdog, which is the only instrument that can tell a long task from a stuck\n * one.\n *\n * What callers see is unchanged: `exitCode`, the assistant's text as `output`,\n * and the usage of the invocation. Whenever the stream yields nothing usable\n * (or the CLI failed), the behaviour falls back exactly to the previous\n * combined stdout+stderr text with no metrics.\n */\nexport async function executeClaude(\n prompt: string,\n options: ExecuteClaudeOptions = {},\n): Promise<ClaudeResult> {\n const subprocess = execa(\n 'claude',\n ['--dangerously-skip-permissions', '--print', '--output-format', 'stream-json', '--verbose'],\n {\n input: prompt,\n reject: false,\n timeout: 0, // No timeout — the engine bounds this by iterations\n stripFinalNewline: false,\n },\n );\n\n const unregisterChild = registerChild({\n kill: (signal) => subprocess.kill(signal),\n done: subprocess.then(\n () => undefined,\n () => undefined,\n ),\n });\n\n const watchdog = createWatchdog({\n ...(options.inactivityTimeoutMs === undefined\n ? {}\n : { inactivityTimeoutMs: options.inactivityTimeoutMs }),\n child: {\n kill: (signal) => subprocess.kill(signal),\n done: subprocess.then(\n () => undefined,\n () => undefined,\n ),\n },\n });\n\n let streamed: Awaited<ReturnType<typeof readClaudeStream>> = {\n result: '',\n isError: false,\n usage: null,\n events: 0,\n raw: '',\n };\n if (subprocess.stdout) {\n streamed = await readClaudeStream(subprocess.stdout, { onLine: () => watchdog.beat() });\n }\n\n const result = await subprocess;\n watchdog.stop();\n unregisterChild();\n\n // Combine stdout and stderr to match Bash's 2>&1 behavior\n const stdout = result.stdout?.toString() ?? '';\n const stderr = result.stderr?.toString() ?? '';\n const exitCode = result.exitCode ?? 1;\n\n // The stream is consumed by the time the process finishes, so what it printed\n // lives in `streamed.raw` rather than in `result.stdout`. Falling back to\n // `stdout` keeps a CLI build that ignores `--output-format` — and every\n // failure that printed nothing on the stream — behaving as it always did.\n const printed = streamed.raw === '' ? stdout : streamed.raw;\n let output = printed + (stderr ? `\\n${stderr}` : '');\n let cost: ClaudeUsage | null = null;\n\n if (watchdog.stalled) {\n // The wording is the contract: `classify()` reads it as a last resort, and\n // `stalled` has to survive the trip through a plain string for the phase to\n // keep its retries.\n return {\n exitCode: exitCode === 0 ? 1 : exitCode,\n output: describeStall(watchdog.silentMs),\n cost: null,\n };\n }\n\n // Only unwrap on success: a failing CLI may print diagnostics on stderr that\n // trimErrorMessage()/isTransientFailure() need to see verbatim.\n if (exitCode === 0 && streamed.result !== '') {\n output = streamed.result;\n cost = streamed.usage;\n }\n\n // Forward output through the global callback (listr2 renderer) when active\n const onOutput = getOutputCallback();\n if (onOutput) {\n const trimmed = output.trim();\n if (trimmed) {\n onOutput(trimmed);\n }\n }\n\n return {\n exitCode,\n output,\n cost,\n };\n}\n","import { createConfig, resolvePaths, validateDependencies } from '../config.js';\nimport { runEngine } from '../core/engine.js';\nimport { allStoriesPass, loadTaskPlan, saveTaskPlan } from '../core/state-manager.js';\nimport { printError } from '../ui/logger.js';\n\nexport interface ExecuteOptions {\n issue?: string;\n maxIterations?: number;\n retryLimit?: number;\n retryForever?: boolean;\n /**\n * Conventional-commit scope for the stories of this issue (`issue-71`).\n * Only the multi-issue queue sets it — see `EngineConfig.commitScope`.\n */\n commitScope?: string;\n}\n\nexport async function runExecute(\n positionalMaxIter: number | undefined,\n options: ExecuteOptions,\n): Promise<number> {\n const errors = await validateDependencies();\n if (errors.length > 0) {\n printError('The following required tools are not installed:');\n for (const err of errors) {\n console.log(err);\n }\n return 1;\n }\n\n const maxIterations = options.maxIterations ?? positionalMaxIter;\n\n const config = createConfig({\n issueNumber: options.issue,\n maxIterations,\n retryLimit: options.retryLimit,\n retryForever: options.retryForever,\n commitScope: options.commitScope,\n });\n\n const paths = await resolvePaths(config);\n const exitCode = await runEngine(config, paths);\n\n // Update pipeline state if all stories pass\n if (exitCode === 0 && config.issueNumber) {\n try {\n const plan = await loadTaskPlan(paths.prdFile);\n if (allStoriesPass(plan)) {\n plan.pipeline.executionCompleted = true;\n await saveTaskPlan(paths.prdFile, plan);\n }\n } catch {\n // Non-critical — engine already handled state\n }\n }\n\n return exitCode;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,IAAI,OAAO,UAAU,iBAAiB;AAC/C,SAAS,YAAY;;;ACFrB,OAAO,WAAW;AAQX,SAAS,iBAAiB,QAAgB,OAAuB;AACtE,QAAM,WAAW;AACjB,MAAI,MAAM;AACV,MAAI,SAAS;AAEb,MAAI,QAAQ,GAAG;AACb,UAAM,KAAK,MAAO,SAAS,MAAO,KAAK;AACvC,aAAS,KAAK,MAAO,SAAS,WAAY,KAAK;AAAA,EACjD;AAEA,QAAM,QAAQ,WAAW;AACzB,QAAM,WAAW,WAAW,IAAI,WAAW;AAC3C,QAAM,YAAY,WAAW,IAAI,WAAW;AAE5C,QAAM,MAAM,SAAS,OAAO,MAAM,IAAI,UAAU,OAAO,KAAK;AAC5D,QAAM,OAAO,GAAG,MAAM,IAAI,KAAK,KAAK,GAAG;AAEvC,MAAI,SAAS,GAAG;AACd,WAAO,GAAG,MAAM,MAAM,GAAG,CAAC,IAAI,IAAI;AAAA,EACpC;AACA,SAAO,GAAG,GAAG,IAAI,IAAI;AACvB;AAgBO,SAAS,qBACd,WACA,SACA,SACA,eACM;AACN,QAAM,QAAQ,SAAS;AACvB,QAAM,UAAU,SAAS;AACzB,QAAM,KAAK,kBAAkB;AAE7B,QAAM,YAAY,UAAU,aAAa,SAAS,OAAO,OAAO,KAAK,aAAa,SAAS;AAE3F,QAAM,QAAQ,QAAQ;AACtB,QAAM,SAAS,QAAQ,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE;AAE/C,QAAM,QAAkB,CAAC;AAEzB,MAAI,SAAS;AACX,UAAM,KAAK,MAAM,KAAK,sBAAsB,MAAM,KAAK,IAAI,SAAS,qBAAqB,CAAC;AAAA,EAC5F,OAAO;AACL,UAAM,KAAK,OAAO,MAAM,KAAK,IAAI,SAAS,MAAM;AAAA,EAClD;AAGA,MAAI,oBAAoB;AACxB,aAAW,SAAS,SAAS;AAC3B,QAAI;AACJ,QAAI;AACJ,UAAM,WACJ,kBAAkB,SACd,MAAM,OAAO,gBACb,CAAC,MAAM,UAAU,CAAC;AAExB,QAAI,MAAM,QAAQ;AAChB,aAAO,MAAM;AACb,gBAAU,UAAU,MAAM,QAAQ,CAAC,MAAc;AAAA,IACnD,WAAW,UAAU;AACnB,aAAO,MAAM;AACb,gBAAU,UAAU,MAAM,SAAS,CAAC,MAAc;AAClD,0BAAoB;AAAA,IACtB,OAAO;AAEL,aAAO,MAAM;AACb,gBAAU,UAAU,MAAM,OAAO,CAAC,MAAc;AAAA,IAClD;AAEA,UAAM,KAAK,QAAQ,KAAK,IAAI,IAAI,MAAM,EAAE,KAAK,MAAM,KAAK,EAAE,CAAC;AAAA,EAC7D;AAEA,QAAM,KAAK,KAAK,iBAAiB,QAAQ,KAAK,CAAC,EAAE;AAEjD,MAAI,IAAI;AAEN,OAAG,MAAM,KAAK,IAAI,CAAC;AAAA,EACrB,OAAO;AACL,YAAQ,IAAI,EAAE;AACd,eAAW,QAAQ,OAAO;AACxB,cAAQ,IAAI,IAAI;AAAA,IAClB;AACA,YAAQ,IAAI,EAAE;AAAA,EAChB;AACF;;;AC1GA,OAAOA,YAAW;AAgBlB,SAAS,QAAQ,MAAc,OAAuB;AACpD,MAAI,KAAK,SAAS,OAAO;AACvB,WAAO,KAAK,UAAU,GAAG,KAAK;AAAA,EAChC;AACA,SAAO,KAAK,OAAO,KAAK;AAC1B;AAMO,SAAS,SAAS,OAAuB;AAC9C,QAAM,UAAU,SAAS;AACzB,QAAM,UAAU,WAAW;AAC3B,QAAM,YAAY,aAAa;AAG/B,MAAI,kBAAkB;AACtB,aAAW,QAAQ,OAAO;AACxB,QAAI,SAAS,SAAS,KAAK,SAAS,iBAAiB;AACnD,wBAAkB,KAAK;AAAA,IACzB;AAAA,EACF;AAGA,QAAM,YAAY,YAAY;AAC9B,MAAI,kBAAkB,WAAW;AAC/B,sBAAkB;AAAA,EACpB;AACA,MAAI,kBAAkB,IAAI;AACxB,sBAAkB;AAAA,EACpB;AAGA,QAAM,KAAK,UAAU,WAAW;AAChC,QAAM,KAAK,UAAU,WAAW;AAChC,QAAM,KAAK,UAAU,WAAW;AAChC,QAAM,KAAK,UAAU,WAAW;AAChC,QAAM,IAAI,UAAU,WAAW;AAC/B,QAAM,IAAI,UAAU,WAAW;AAC/B,QAAM,OAAO,UAAU,WAAW;AAClC,QAAM,OAAO,UAAU,WAAW;AAElC,QAAM,QAAQ,EAAE,OAAO,kBAAkB,CAAC;AAE1C,QAAM,OAAO,UAAUC,OAAM,OAAO,CAAC,MAAc;AACnD,QAAM,SAAS,CAAC,MAAc;AAG9B,UAAQ,IAAI,KAAK,GAAG,EAAE,GAAG,KAAK,GAAG,EAAE,EAAE,CAAC;AAGtC,aAAW,QAAQ,OAAO;AACxB,QAAI,SAAS,OAAO;AAClB,cAAQ,IAAI,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,EAAE,CAAC;AAAA,IAC5C,OAAO;AACL,YAAM,SAAS,QAAQ,MAAM,eAAe;AAC5C,cAAQ,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,EAAE;AAAA,IAC/C;AAAA,EACF;AAGA,UAAQ,IAAI,KAAK,GAAG,EAAE,GAAG,KAAK,GAAG,EAAE,EAAE,CAAC;AACxC;AAKO,SAAS,mBAAmB,QAAsB,MAAsB;AAC7E,QAAM,QAAQ,SAAS;AAEvB,QAAM,eAAe,KAAK,YAAY;AACtC,QAAM,iBAAiB,KAAK,YAAY,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE;AAChE,QAAM,aAAa,KAAK,cAAc;AAEtC,QAAM,aAAa,OAAO,cAAc,UAAU,OAAO,WAAW,KAAK;AAEzE,QAAM,eACJ,OAAO,kBAAkB,SAAY,OAAO,OAAO,aAAa,IAAI;AAEtE,QAAM,aAAa,OAAO,eACtB,sBACA,GAAG,OAAO,UAAU;AAExB,WAAS;AAAA,IACP,GAAG,MAAM,KAAK;AAAA,IACd;AAAA,IACA,gBAAgB,UAAU;AAAA,IAC1B,gBAAgB,UAAU;AAAA,IAC1B,gBAAgB,cAAc,IAAI,YAAY;AAAA,IAC9C,gBAAgB,YAAY;AAAA,IAC5B,gBAAgB,UAAU;AAAA,EAC5B,CAAC;AACH;AAQO,SAAS,gBACd,QACA,YACA,cACA,gBACA,MACA,WAOA,OACM;AACN,QAAM,QAAQ,SAAS;AAEvB,QAAM,eAAe,KAAK,YAAY;AACtC,QAAM,iBAAiB,KAAK,YAAY,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE;AAChE,QAAM,WAAW,eAAe,cAAc;AAE9C,MAAI;AACJ,MAAI;AAEJ,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,mBAAa,MAAM;AACnB,oBAAc;AACd;AAAA,IACF,KAAK;AACH,mBAAa,MAAM;AACnB,oBAAc;AACd;AAAA,IACF,KAAK;AACH,mBAAa,MAAM;AACnB,oBAAc;AACd;AAAA,EACJ;AAEA,QAAM,WAAW;AAAA,IACf,GAAG,MAAM,GAAG;AAAA,IACZ;AAAA,IACA,gBAAgB,UAAU,IAAI,WAAW;AAAA,IACzC,gBAAgB,cAAc,IAAI,YAAY;AAAA,IAC9C,gBAAgB,UAAU;AAAA,IAC1B,gBAAgB,QAAQ;AAAA,EAC1B;AAEA,QAAM,SAAS,aAAa,KAAK;AACjC,MAAI,WAAW,IAAI;AACjB,aAAS,KAAK,gBAAgB,MAAM,EAAE;AAAA,EACxC;AAEA,WAAS,KAAK,gBAAgB,YAAY,EAAE;AAE5C,MAAI,WAAW;AACb,aAAS,KAAK,KAAK;AACnB,aAAS,KAAK,SAAS;AAAA,EACzB;AAEA,UAAQ,IAAI,EAAE;AACd,WAAS,QAAQ;AACnB;AA0CO,SAAS,qBAAqB,MAAgC;AACnE,QAAM,QAAQ;AAAA,IACZ,eAAe,KAAK,UAAU,GAAG,KAAK,WAAW,eAAe,EAAE;AAAA,IAClE,eAAe,KAAK,UAAU;AAAA,IAC9B,eAAe,eAAe,KAAK,cAAc,CAAC;AAAA,EACpD;AAIA,QAAM,SAAS,aAAa,KAAK,KAAK;AACtC,MAAI,WAAW,IAAI;AACjB,UAAM,KAAK,eAAe,MAAM,EAAE;AAAA,EACpC;AAEA,MAAI,CAAC,KAAK,UAAU;AAClB,UAAM,KAAK,eAAe,KAAK,KAAK,EAAE;AAAA,EACxC;AAEA,QAAM,SAAS,KAAK;AACpB,MAAI,QAAQ;AAGV,UAAM,UACJ,OAAO,mBAAmB,OAAO,mBAAmB,oBAAoB;AAC1E,UAAM,KAAK,eAAe,OAAO,EAAE;AACnC,QAAI,OAAO,eAAe,MAAM;AAC9B,YAAM,KAAK,eAAe,OAAO,UAAU,EAAE;AAAA,IAC/C;AAAA,EACF;AAEA,SAAO;AACT;AAqCO,SAAS,uBAAuB,MAAkC;AACvE,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,eAAe,KAAK,cAAc,SAAS,EAAE;AACxD,QAAM,KAAK,eAAe,KAAK,OAAO,MAAM,EAAE;AAE9C,aAAW,SAAS,KAAK,QAAQ;AAC/B,UAAMC,UAAS,aAAa,MAAM,KAAK;AACvC,UAAM,QAAQ,MAAM,UAAU,KAAK,KAAK,IAAI,MAAM,KAAK;AACvD,UAAM;AAAA,MACJ,QAAQ,MAAM,EAAE,GAAG,KAAK,WAAM,MAAM,UAAU,aAAa,eAAe,MAAM,cAAc,CAAC,MAC5FA,YAAW,KAAK,KAAK,KAAKA,OAAM;AAAA,IACrC;AAAA,EACF;AAEA,QAAM,KAAK,eAAe,eAAe,KAAK,cAAc,CAAC,EAAE;AAE/D,QAAM,SAAS,aAAa,KAAK,KAAK;AACtC,MAAI,WAAW,IAAI;AACjB,UAAM,KAAK,eAAe,MAAM,EAAE;AAAA,EACpC;AACA,MAAI,KAAK,UAAU,MAAM;AACvB,UAAM,KAAK,eAAe,KAAK,KAAK,EAAE;AAAA,EACxC;AACA,MAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,UAAM,KAAK,eAAe,KAAK,SAAS,IAAI,CAAC,UAAU,IAAI,MAAM,EAAE,EAAE,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,EACrF;AAEA,QAAM,SAAS,KAAK;AACpB,MAAI,QAAQ;AACV,UAAM;AAAA,MACJ,eAAe,OAAO,mBAAmB,OAAO,mBAAmB,oBAAoB,UAAU;AAAA,IACnG;AACA,QAAI,OAAO,eAAe,MAAM;AAC9B,YAAM,KAAK,eAAe,OAAO,UAAU,EAAE;AAAA,IAC/C;AAAA,EACF;AAEA,SAAO;AACT;AAGO,SAAS,kBAAkB,MAA8B;AAC9D,UAAQ,IAAI,EAAE;AACd,MAAI,KAAK,UAAU,qBAAqB,MAAM;AAC5C,iBAAa,6BAA6B,KAAK,OAAO,wCAAwC;AAAA,EAChG,OAAO;AACL,iBAAa,6BAA6B,KAAK,OAAO,KAAK,KAAK,OAAO,MAAM,WAAW;AAAA,EAC1F;AACA,aAAW,QAAQ,uBAAuB,IAAI,GAAG;AAC/C,YAAQ,IAAI,IAAI;AAAA,EAClB;AACF;AAMO,SAAS,gBAAgB,MAA4B;AAC1D,UAAQ,IAAI,EAAE;AACd,MAAI,KAAK,UAAU,kBAAkB;AACnC;AAAA,MACE,gCAAgC,KAAK,WAAW;AAAA,IAClD;AAAA,EACF,OAAO;AACL,iBAAa,gCAAgC,KAAK,WAAW,GAAG;AAAA,EAClE;AACA,aAAW,QAAQ,qBAAqB,IAAI,GAAG;AAC7C,YAAQ,IAAI,IAAI;AAAA,EAClB;AACF;;;ACvWA,SAAS,aAAa;AAkCtB,eAAsB,cACpB,QACA,UAAgC,CAAC,GACV;AACvB,QAAM,aAAa;AAAA,IACjB;AAAA,IACA,CAAC,kCAAkC,WAAW,mBAAmB,eAAe,WAAW;AAAA,IAC3F;AAAA,MACE,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA;AAAA,MACT,mBAAmB;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,kBAAkB,cAAc;AAAA,IACpC,MAAM,CAAC,WAAW,WAAW,KAAK,MAAM;AAAA,IACxC,MAAM,WAAW;AAAA,MACf,MAAM;AAAA,MACN,MAAM;AAAA,IACR;AAAA,EACF,CAAC;AAED,QAAM,WAAW,eAAe;AAAA,IAC9B,GAAI,QAAQ,wBAAwB,SAChC,CAAC,IACD,EAAE,qBAAqB,QAAQ,oBAAoB;AAAA,IACvD,OAAO;AAAA,MACL,MAAM,CAAC,WAAW,WAAW,KAAK,MAAM;AAAA,MACxC,MAAM,WAAW;AAAA,QACf,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAI,WAAyD;AAAA,IAC3D,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AACA,MAAI,WAAW,QAAQ;AACrB,eAAW,MAAM,iBAAiB,WAAW,QAAQ,EAAE,QAAQ,MAAM,SAAS,KAAK,EAAE,CAAC;AAAA,EACxF;AAEA,QAAM,SAAS,MAAM;AACrB,WAAS,KAAK;AACd,kBAAgB;AAGhB,QAAM,SAAS,OAAO,QAAQ,SAAS,KAAK;AAC5C,QAAM,SAAS,OAAO,QAAQ,SAAS,KAAK;AAC5C,QAAM,WAAW,OAAO,YAAY;AAMpC,QAAM,UAAU,SAAS,QAAQ,KAAK,SAAS,SAAS;AACxD,MAAI,SAAS,WAAW,SAAS;AAAA,EAAK,MAAM,KAAK;AACjD,MAAI,OAA2B;AAE/B,MAAI,SAAS,SAAS;AAIpB,WAAO;AAAA,MACL,UAAU,aAAa,IAAI,IAAI;AAAA,MAC/B,QAAQ,cAAc,SAAS,QAAQ;AAAA,MACvC,MAAM;AAAA,IACR;AAAA,EACF;AAIA,MAAI,aAAa,KAAK,SAAS,WAAW,IAAI;AAC5C,aAAS,SAAS;AAClB,WAAO,SAAS;AAAA,EAClB;AAGA,QAAM,WAAW,kBAAkB;AACnC,MAAI,UAAU;AACZ,UAAM,UAAU,OAAO,KAAK;AAC5B,QAAI,SAAS;AACX,eAAS,OAAO;AAAA,IAClB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AH7EA,SAAS,QAAQ,SAAuB;AACtC,QAAM,KAAK,kBAAkB;AAC7B,MAAI,IAAI;AAEN,QAAI,SAAS;AACX,SAAG,OAAO;AAAA,IACZ;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,OAAO;AAAA,EACrB;AACF;AAmBA,SAAS,mBAAmB,QAAmC;AAC7D,SAAO;AAAA,IACL,OAAO,aAAa;AAAA,IACpB,OAAO;AAAA,IACP,OAAO;AAAA,IACP,EAAE,cAAc,OAAO,aAAa;AAAA,EACtC;AACF;AAUA,SAAS,uBAAuB,QAAqB,OAA8B;AACjF,QAAM,aAAa,IAAI,IAAI,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,MAAM,MAAM,CAAC,CAAC;AAC1E,SAAO,MACJ,OAAO,CAAC,UAAU,MAAM,UAAU,WAAW,IAAI,MAAM,EAAE,MAAM,KAAK,EACpE,IAAI,CAAC,UAAU,MAAM,EAAE;AAC5B;AAkBO,SAAS,mBACd,OACA,YACwB;AACxB,QAAM,SAAS,UAAU,UAAa,UAAU,KAAK,KAAK,IAAI,KAAK;AACnE,QAAM,WAAW,eAAe,UAAa,eAAe,QAAQ,eAAe;AAEnF,SAAO;AAAA,IACL,oBAAoB,WAChB,SAAS,MAAM,iCACf,OAAO,MAAM;AAAA,IACjB,wBAAwB,MAAM,MAAM;AAAA,EACtC;AACF;AASA,SAAS,oBAAsD;AAC7D,QAAM,aAAa,qBAAqB;AACxC,SAAO,eAAe,SAAY,CAAC,IAAI,EAAE,qBAAqB,WAAW;AAC3E;AAgBA,eAAe,sBAAsB,WAAsC;AACzE,MAAI;AACF,UAAM,OAAO,MAAM,aAAa,SAAS;AACzC,UAAM,UAAU,KAAK,YAAY,OAAO,CAAC,UAAU,CAAC,MAAM,MAAM;AAChE,QAAI,QAAQ,WAAW,EAAG,QAAO,CAAC;AAElC,QAAI,CAAE,MAAM,mBAAmB,EAAI,QAAO,CAAC;AAE3C,UAAM,YAAY,MAAM,kBAAkB,MAAM,cAAc,CAAC;AAC/D,UAAM,UAAU,QAAQ,OAAO,CAAC,UAAU,UAAU,IAAI,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,UAAU,MAAM,EAAE;AAC1F,QAAI,QAAQ,WAAW,EAAG,QAAO,CAAC;AAElC,UAAM,aAAa,WAAW;AAAA,MAC5B,GAAG;AAAA,MACH,aAAa,KAAK,YAAY;AAAA,QAAI,CAAC,UACjC,QAAQ,SAAS,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,QAAQ,KAAK,IAAI;AAAA,MAC5D;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAKA,eAAe,mBAAmB,cAAqC;AACrE,MAAI,CAAC,WAAW,YAAY,GAAG;AAC7B,UAAM,UAAU;AAAA,YAAuC,oBAAI,KAAK,GAAE,SAAS,CAAC;AAAA;AAAA;AAC5E,UAAM,UAAU,cAAc,SAAS,OAAO;AAAA,EAChD;AACF;AAKA,eAAe,uBAAuB,MAAgB,OAAqC;AACzF,QAAM,EAAE,gBAAgB,YAAY,SAAS,aAAa,IAAI;AAE9D,MAAI,CAAC,WAAW,cAAc,GAAG;AAC/B;AAAA,EACF;AAEA,QAAM,gBAAgB,KAAK,cAAc;AACzC,MAAI,aAAa;AAEjB,MAAI;AACF,kBAAc,MAAM,SAAS,gBAAgB,OAAO,GAAG,KAAK;AAAA,EAC9D,QAAQ;AACN;AAAA,EACF;AAEA,MAAI,iBAAiB,cAAc,kBAAkB,YAAY;AAC/D,UAAM,WAAU,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AACrD,UAAM,aAAa,WAAW,QAAQ,YAAY,EAAE,EAAE,QAAQ,gBAAgB,GAAG;AACjF,UAAM,gBAAgB,KAAK,YAAY,GAAG,OAAO,IAAI,UAAU,EAAE;AAEjE,cAAU,2BAA2B,UAAU,EAAE;AACjD,UAAM,MAAM,eAAe,EAAE,WAAW,KAAK,CAAC;AAE9C,QAAI,WAAW,OAAO,GAAG;AACvB,YAAM,GAAG,SAAS,KAAK,eAAe,YAAY,CAAC;AAAA,IACrD;AACA,QAAI,WAAW,YAAY,GAAG;AAC5B,YAAM,GAAG,cAAc,KAAK,eAAe,cAAc,CAAC;AAAA,IAC5D;AAEA,cAAU,mBAAmB,aAAa,EAAE;AAG5C,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,YAAuC,oBAAI,KAAK,GAAE,SAAS,CAAC;AAAA;AAAA;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AACF;AAKA,eAAe,YAAY,MAAgB,gBAAuC;AAChF,QAAM,SAAS,KAAK,cAAc;AAClC,MAAI,QAAQ;AACV,UAAM,UAAU,gBAAgB,GAAG,MAAM;AAAA,GAAM,OAAO;AAAA,EACxD;AACF;AAaA,eAAsB,UAAU,QAAsB,OAAuC;AAE3F,MAAI,CAAC,WAAW,MAAM,OAAO,GAAG;AAC9B,eAAW,yBAAyB,MAAM,OAAO,EAAE;AACnD,QAAI,OAAO,aAAa;AACtB,cAAQ,mDAAmD,OAAO,WAAW,SAAS;AAAA,IACxF;AACA,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,MAAM,aAAa,MAAM,OAAO;AAC3C,SAAO,gBAAgB,IAAI;AAC3B,QAAM,aAAa,MAAM,SAAS,IAAI;AAOtC,MAAI,KAAK,gBAAgB,eAAe,eAAe,IAAI,KAAK,CAAC,qBAAqB,IAAI,GAAG;AAC3F,YAAQ,oCAAoC,MAAM,OAAO,EAAE;AAC3D,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,gBAAgB,eAAe,CAAC,eAAe,IAAI,GAAG;AAC7D;AAAA,MACE;AAAA,IACF;AACA,WAAO,oBAAoB,IAAI;AAC/B,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,aAAa,MAAM,SAAS,IAAI;AAAA,EACxC;AAGA,MAAI,eAAe,IAAI,KAAK,CAAC,qBAAqB,IAAI,GAAG;AACvD,YAAQ,4DAA4D;AACpE,WAAO,mBAAmB,IAAI;AAC9B,UAAM,aAAa,MAAM,SAAS,IAAI;AACtC,WAAO;AAAA,EACT;AAGA,QAAM,uBAAuB,MAAM,KAAK;AAGxC,QAAM,YAAY,MAAM,MAAM,cAAc;AAG5C,QAAM,mBAAmB,MAAM,YAAY;AAK3C,QAAM,iBAAiB,MAAM,WAAW,WAAW,EAAE,aAAa,MAAM,YAAY,CAAC;AAIrF,QAAM,SAAS,MAAM,0BAA0B,EAAE,MAAM,MAAM,YAAY,CAAC;AAG1E,qBAAmB,QAAQ,IAAI;AAE/B,QAAM,YAAY,KAAK,IAAI;AAC3B,MAAI,IAAI;AACR,MAAI,kBAAkB;AAGtB,SAAO,MAAM;AAEX,QAAI,OAAO,kBAAkB,UAAa,KAAK,OAAO,eAAe;AACnE;AAAA,IACF;AAEA;AAUA,UAAM,UAAU,MAAM,sBAAsB,MAAM,OAAO;AACzD,QAAI,QAAQ,SAAS,GAAG;AACtB;AAAA,QACE,YAAY,QAAQ,KAAK,IAAI,CAAC;AAAA,MAChC;AACA,aAAO,MAAM,aAAa,MAAM,OAAO;AACvC,UAAI,KAAK,YAAY,MAAM,CAAC,UAAU,MAAM,MAAM,KAAK,KAAK,uBAAuB,MAAM;AAEvF;AAAA,MACF;AAAA,IACF;AAQA,UAAM,YAAY,MAAM;AAAA,MACtB,YAAY;AAEV,eAAO,MAAM,aAAa,MAAM,OAAO;AAGvC,cAAM,gBAAgB,KAAK;AAM3B,cAAM,gBAAgB,kBAAkB,KAAK,WAAW,GAAG;AAC3D,4BAAoB,EAAE,QAAQ;AAAA,UAC5B,MAAM;AAAA,UACN,IAAI,OAAO;AAAA,UACX,WAAW;AAAA,UACX,SAAS;AAAA,QACX,CAAC;AACD,8BAAsB,IAAI,aAAa;AAEvC,YAAI,UAAU,GAAG;AACf,+BAAqB,GAAG,OAAO,eAAe,KAAK,aAAa,aAAa;AAAA,QAC/E;AAGA,cAAM,SAAS,kBAAkB,gBAAgB;AAAA,UAC/C,cAAc,MAAM;AAAA,UACpB,mBAAmB,MAAM;AAAA,UACzB,GAAG;AAAA;AAAA;AAAA,UAGH,GAAG,mBAAmB,OAAO,aAAa,OAAO,qBAAqB;AAAA,QACxE,CAAC;AAED,cAAM,YAAY,OAAO;AACzB,eAAO,oBAAoB,MAAM,SAAS;AAC1C,cAAM,aAAa,MAAM,SAAS,IAAI;AAGtC,cAAM,cAAc,KAAK,IAAI;AAC7B,cAAMC,UAAS,MAAM,cAAc,QAAQ,kBAAkB,CAAC;AAC9D,cAAM,UAAU,oBAAoB,WAAW;AAE/C,YAAIA,QAAO,aAAa,GAAG;AAGzB,kCAAwB,GAAGA,QAAO,MAAM,OAAO;AAAA,QACjD;AAEA,eAAO,EAAE,QAAAA,SAAQ,WAAW,SAAS,cAAc;AAAA,MACrD;AAAA,MACA;AAAA,QACE,QAAQ,mBAAmB,MAAM;AAAA;AAAA;AAAA;AAAA,QAIjC,QAAQ,kBAAkB;AAAA;AAAA;AAAA;AAAA,QAI1B,UAAU,CAAC,EAAE,QAAAA,QAAO,MAClBA,QAAO,aAAa,IAChB,OACA,SAAS,EAAE,QAAQ,SAAS,UAAUA,QAAO,UAAU,QAAQA,QAAO,OAAO,CAAC;AAAA,QACpF,WAAW,OAAO,EAAE,OAAO,SAAS,SAAS,WAAW,QAAQ,MAAM;AACpE,cAAI,YAAY,KAAM;AAEtB,gBAAM,eAAe,iBAAiB,MAAM,OAAO,MAAM;AAEzD,cAAI,CAAC,QAAQ,WAAW;AACtB,mBAAO,MAAM,aAAa,MAAM,OAAO;AACvC,mBAAO,aAAa,MAAM,wBAAwB,YAAY;AAC9D,kBAAM,aAAa,MAAM,SAAS,IAAI;AACtC;AAAA,UACF;AAIA;AACA,iBAAO,MAAM,aAAa,MAAM,OAAO;AACvC,iBAAO,aAAa,MAAM,4BAA4B,YAAY;AAClE,gBAAM,aAAa,MAAM,SAAS,IAAI;AACtC,cAAI,CAAC,UAAW;AAEhB,gBAAM,eAAe,UAAU;AAC/B,8BAAoB,EAAE,QAAQ;AAAA,YAC5B,MAAM;AAAA,YACN,IAAI,OAAO;AAAA,YACX;AAAA,YACA;AAAA,YACA,QAAQ;AAAA,YACR,MAAM,QAAQ;AAAA,UAChB,CAAC;AAED,cAAI,UAAU,GAAG;AACf,oBAAQ,EAAE;AAAA,UACZ;AACA;AAAA,YACE,yCAAyC,CAAC,aAAa,OAAO,kBAAkB,YAAY;AAAA,UAC9F;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM;AAAA,MACJ;AAAA,MACA,SAAS;AAAA,MACT,eAAe;AAAA,IACjB,IAAI,UAAU;AACd,UAAM,qBAAqB,UAAU,MAAM;AAE3C,QAAI,OAAO,aAAa,GAAG;AACzB,YAAMC,WAAU,KAAK,OAAO,KAAK,IAAI,IAAI,aAAa,GAAI;AAC1D,aAAO,MAAM,aAAa,MAAM,OAAO;AACvC;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACAA;AAAA,QACA;AAAA,QACA,UAAU,YACN,yBAAyB,OAAO,UAAU,0BAC1C,oCAAoC,OAAO,QAAQ;AAAA,QACvD,oBAAoB,aAAa;AAAA,MACnC;AACA,aAAO,OAAO;AAAA,IAChB;AAEA,WAAO,MAAM,aAAa,MAAM,OAAO;AACvC,WAAO,eAAe,MAAM,kBAAkB;AAC9C,UAAM,aAAa,MAAM,SAAS,IAAI;AAGtC,UAAM,gBAAgB,uBAAuB;AAC7C,QAAI,eAAe;AACjB,oBAAc,KAAK,WAAW;AAAA,IAChC;AACA,wBAAoB,EAAE,QAAQ;AAAA,MAC5B,MAAM;AAAA,MACN,IAAI,OAAO;AAAA,MACX,SAAS,KAAK;AAAA,IAChB,CAAC;AAOD,UAAM,oBAAoB,uBAAuB,wBAAwB,KAAK,WAAW;AACzF,QAAI,kBAAkB,SAAS,GAAG;AAChC,YAAM,aAAa,YAAY,OAAO,MAAM,kBAAkB,MAAM;AACpE,YAAM,eAAe,KAAK,MAAM,mBAAmB,kBAAkB,MAAM;AAC3E,iBAAW,WAAW,mBAAmB;AACvC,4BAAoB,SAAS,YAAY,YAAY;AAAA,MACvD;AAMA,YAAM,kBAAkB,kBAAkB,MAAM,mBAAmB,YAAY,YAAY;AAC3F,UAAI;AACF,cAAM,aAAa,MAAM,SAAS,eAAe;AACjD,eAAO;AAAA,MACT,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,wBAAoB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,IAAI,OAAO,GAAG,WAAW,EAAE,CAAC;AACnF,4BAAwB,GAAG,OAAO,MAAM,gBAAgB;AAGxD,UAAM,gBAAgB,oBAAoB,CAAC;AAG3C,QAAI,OAAO,OAAO,SAAS,6BAA6B,GAAG;AACzD,aAAO,MAAM,aAAa,MAAM,OAAO;AACvC,UAAI,eAAe,IAAI,KAAK,CAAC,qBAAqB,IAAI,GAAG;AACvD,eAAO,mBAAmB,IAAI;AAC9B,cAAM,aAAa,MAAM,SAAS,IAAI;AAEtC,cAAMA,WAAU,KAAK,OAAO,KAAK,IAAI,IAAI,aAAa,GAAI;AAC1D;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACAA;AAAA,UACA;AAAA,UACA;AAAA,UACA,oBAAoB,aAAa;AAAA,QACnC;AACA,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,qBAAqB,IAAI,IACrB,wFACA;AAAA,MACN;AACA,YAAM,aAAa,MAAM,SAAS,IAAI;AAEtC,cAAQ,EAAE;AACV;AAAA,QACE,qBAAqB,IAAI,IACrB,kHACA;AAAA,MACN;AAAA,IACF;AAEA,QAAI,UAAU,GAAG;AACf,mBAAa,aAAa,CAAC,0BAA0B;AAAA,IACvD;AACA,UAAM,MAAM,CAAC;AAAA,EACf;AAGA,QAAM,UAAU,KAAK,OAAO,KAAK,IAAI,IAAI,aAAa,GAAI;AAC1D,SAAO,MAAM,aAAa,MAAM,OAAO;AACvC;AAAA,IACE;AAAA,IACA,OAAO,iBAAiB;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB,aAAa;AAAA,EACnC;AACA,SAAO;AACT;;;AIxkBA,eAAsB,WACpB,mBACA,SACiB;AACjB,QAAM,SAAS,MAAM,qBAAqB;AAC1C,MAAI,OAAO,SAAS,GAAG;AACrB,eAAW,iDAAiD;AAC5D,eAAW,OAAO,QAAQ;AACxB,cAAQ,IAAI,GAAG;AAAA,IACjB;AACA,WAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,QAAQ,iBAAiB;AAE/C,QAAM,SAAS,aAAa;AAAA,IAC1B,aAAa,QAAQ;AAAA,IACrB;AAAA,IACA,YAAY,QAAQ;AAAA,IACpB,cAAc,QAAQ;AAAA,IACtB,aAAa,QAAQ;AAAA,EACvB,CAAC;AAED,QAAM,QAAQ,MAAM,aAAa,MAAM;AACvC,QAAM,WAAW,MAAM,UAAU,QAAQ,KAAK;AAG9C,MAAI,aAAa,KAAK,OAAO,aAAa;AACxC,QAAI;AACF,YAAM,OAAO,MAAM,aAAa,MAAM,OAAO;AAC7C,UAAI,eAAe,IAAI,GAAG;AACxB,aAAK,SAAS,qBAAqB;AACnC,cAAM,aAAa,MAAM,SAAS,IAAI;AAAA,MACxC;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AACT;","names":["chalk","chalk","tokens","result","elapsed"]}