agent-work-loop 0.6.31 → 0.6.33

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 (46) hide show
  1. package/dist/{brief-ZZSQ6RQS.js → brief-IE2AC5XA.js} +5 -5
  2. package/dist/{changelog-JWLVVHZL.js → changelog-7XV2TAVB.js} +5 -5
  3. package/dist/{chunk-22SUY5RE.js → chunk-3ADAPFWK.js} +6 -6
  4. package/dist/{chunk-Z3QCPOOA.js → chunk-C2EWSFNH.js} +2 -2
  5. package/dist/{chunk-Q7V3WVKT.js → chunk-EW5CLZ7C.js} +4 -4
  6. package/dist/{chunk-3UPF7LZT.js → chunk-HNBBLKNT.js} +5 -5
  7. package/dist/{chunk-RNZCRXE3.js → chunk-I2F7DUOQ.js} +5 -5
  8. package/dist/{chunk-RRQYSRRT.js → chunk-IQNGZFEK.js} +5 -5
  9. package/dist/{chunk-7NOHUUXV.js → chunk-L3G3B7FT.js} +73 -12
  10. package/dist/{chunk-TTZY2GLK.js → chunk-LX57XSW3.js} +1 -1
  11. package/dist/{chunk-YP4VCWPV.js → chunk-NV5FE6II.js} +3 -3
  12. package/dist/{chunk-5APWNDRG.js → chunk-OA346OKL.js} +2 -2
  13. package/dist/{chunk-SV4D72NX.js → chunk-Q34HYTEX.js} +2 -2
  14. package/dist/{chunk-JPFGMDQ4.js → chunk-RBLDM2LU.js} +62 -42
  15. package/dist/{chunk-DIRYW77S.js → chunk-RQZBANFI.js} +5 -5
  16. package/dist/{chunk-45X7T64Y.js → chunk-SUF5ISJM.js} +63 -20
  17. package/dist/{chunk-77EZYCLF.js → chunk-TWL3QIQN.js} +2 -2
  18. package/dist/{chunk-2DAP3QBU.js → chunk-XFYYCBQD.js} +221 -126
  19. package/dist/cli.js +41 -42
  20. package/dist/{commit-3UZE7XJM.js → commit-QPFG6Y6H.js} +6 -6
  21. package/dist/{config-DAD4LIWR.js → config-7OAT6KH3.js} +3 -3
  22. package/dist/{doctor-AW65MZKN.js → doctor-E56OQZZH.js} +8 -8
  23. package/dist/{evolve-K4WKRA6U.js → evolve-QJACOUJV.js} +7 -7
  24. package/dist/{feedback-3C33YHKF.js → feedback-3K6AJBG5.js} +5 -5
  25. package/dist/{gotchas-IGEQILOO.js → gotchas-LZYMD22W.js} +7 -7
  26. package/dist/{hold-recheck-THSJKF5G.js → hold-recheck-GCQRCB5X.js} +16 -16
  27. package/dist/{init-MRJEU7IR.js → init-7BDRW6AP.js} +12 -2
  28. package/dist/lane-V3EFI7SW.js +41 -0
  29. package/dist/{loop-summary-MPEKQ2EC.js → loop-summary-QNH423MW.js} +6 -6
  30. package/dist/{metrics-64WBBQQX.js → metrics-HCUMZSAU.js} +4 -4
  31. package/dist/{record-GAWMF7KL.js → record-A35XVG5F.js} +5 -5
  32. package/dist/{remove-ELP4MFVE.js → remove-SSTHJZ5G.js} +15 -15
  33. package/dist/{review-A5Q7NSOD.js → review-44SX5ERY.js} +13 -13
  34. package/dist/{rules-BEQT7YVN.js → rules-GSOMM5VP.js} +8 -8
  35. package/dist/{state-RDKIOU25.js → state-46G4FKH3.js} +4 -4
  36. package/dist/status-RHIO7OI6.js +40 -0
  37. package/dist/{update-7RQQJ2TH.js → update-AKGNAL2F.js} +2 -2
  38. package/dist/{verify-UUJ6KD37.js → verify-R3ISFRBC.js} +10 -10
  39. package/dist/version-check-2DSSLKUD.js +14 -0
  40. package/dist/work-ETVZJUFX.js +60 -0
  41. package/engine/version.json +1 -1
  42. package/package.json +1 -1
  43. package/dist/lane-ZQVD7EDE.js +0 -41
  44. package/dist/status-FP73XOZS.js +0 -40
  45. package/dist/version-check-H2T3WW3I.js +0 -14
  46. package/dist/work-HWJSUWBR.js +0 -50
@@ -1,6 +1,12 @@
1
1
  import {
2
2
  caps,
3
3
  engineDir,
4
+ flowActiveNode,
5
+ flowClose,
6
+ flowConnector,
7
+ flowOpen,
8
+ flowSelectLine,
9
+ flowStepLine,
4
10
  globalRoot,
5
11
  installedEngineVersion,
6
12
  makeColors,
@@ -12,7 +18,7 @@ import {
12
18
  sectionBox,
13
19
  signal,
14
20
  stringWidth
15
- } from "./chunk-45X7T64Y.js";
21
+ } from "./chunk-SUF5ISJM.js";
16
22
 
17
23
  // src/commands/init.ts
18
24
  import fs from "fs";
@@ -107,14 +113,21 @@ function moveCursorUp(n) {
107
113
  }
108
114
  function renderInteractiveSelect(options, state, multi, c, presentation) {
109
115
  const color = makeColors(c.color);
110
- const lines = renderSelectOptions(options, state, multi, c).split("\n");
116
+ const lines = [];
117
+ if (presentation.body && presentation.body.length > 0) {
118
+ lines.push(...presentation.body, "");
119
+ }
120
+ lines.push(...renderSelectOptions(options, state, multi, c).split("\n"));
111
121
  if (presentation.hint) {
112
122
  lines.push("");
113
123
  lines.push(color.dim(presentation.hint));
114
124
  }
115
- const text = sectionBox(presentation.title ?? "\uC120\uD0DD", lines, c);
125
+ const text = flowActiveNode(presentation.title ?? "\uC120\uD0DD", lines, c);
116
126
  return { text, lineCount: text.split("\n").length };
117
127
  }
128
+ function clearFrame(n) {
129
+ return n > 0 ? `${moveCursorUp(n)}\x1B[0J` : "";
130
+ }
118
131
  async function runInteractiveSelect(options, defaultIndex, multi, c, defaultChecked = [], presentation = {}) {
119
132
  let state = initSelectState(defaultIndex, defaultChecked);
120
133
  process.stdin.setRawMode(true);
@@ -134,9 +147,45 @@ async function runInteractiveSelect(options, defaultIndex, multi, c, defaultChec
134
147
  process.stdin.setRawMode(false);
135
148
  process.stdin.pause();
136
149
  }
150
+ process.stdout.write(clearFrame(rendered.lineCount));
137
151
  return state.cancelled ? null : { index: state.index, checked: [...state.checked] };
138
152
  }
139
153
 
154
+ // src/core/flow.ts
155
+ function openFlow(title, c) {
156
+ process.stdout.write(`${flowOpen(title, c)}
157
+ `);
158
+ return { c };
159
+ }
160
+ function step(session, title) {
161
+ process.stdout.write(`${flowConnector(session.c)}
162
+ ${flowStepLine(title, session.c)}
163
+ `);
164
+ }
165
+ function selectStep(session, title) {
166
+ process.stdout.write(`${flowConnector(session.c)}
167
+ ${flowSelectLine(title, session.c)}
168
+ `);
169
+ }
170
+ async function activeSelect(session, options, defaultIndex, multi, defaultChecked = [], presentation = {}) {
171
+ process.stdout.write(`${flowConnector(session.c)}
172
+ `);
173
+ const result = await runInteractiveSelect(
174
+ options,
175
+ defaultIndex,
176
+ multi,
177
+ session.c,
178
+ defaultChecked,
179
+ presentation
180
+ );
181
+ process.stdout.write("\x1B[1A\x1B[0J");
182
+ return result;
183
+ }
184
+ function closeFlow(session) {
185
+ process.stdout.write(`${flowClose(session.c)}
186
+ `);
187
+ }
188
+
140
189
  // src/commands/init.ts
141
190
  function exists(p) {
142
191
  try {
@@ -670,8 +719,8 @@ function applyInit(projectRoot, inputs, now) {
670
719
  };
671
720
  }
672
721
  var WIDTH = 64;
673
- function stepBox(step, title, lines, c) {
674
- return sectionBox(`${step}${c.unicode ? " \xB7 " : " - "}${title}`, lines, c, WIDTH - 4);
722
+ function stepBox(step2, title, lines, c) {
723
+ return sectionBox(`${step2}${c.unicode ? " \xB7 " : " - "}${title}`, lines, c, WIDTH - 4);
675
724
  }
676
725
  var VERIFY_LABELS = {
677
726
  typecheck: "\uD0C0\uC785\uCCB4\uD06C",
@@ -709,7 +758,7 @@ function renderNonTtyNotice() {
709
758
  ""
710
759
  ].join("\n");
711
760
  }
712
- function renderResult(result, inputs, c) {
761
+ function resultSetupLines(result, c) {
713
762
  const color = makeColors(c.color);
714
763
  const t = makeTokens(c);
715
764
  const line = (name, value, note = "") => ` ${padEndDisplay(name, 20)}${t.emphasis(value)}${note ? ` ${color.dim(note)}` : ""}`;
@@ -729,6 +778,10 @@ function renderResult(result, inputs, c) {
729
778
  `\uADDC\uCE59 ${result.ruleCount}\uAC1C \xB7 \uAD50\uD6C8 ${result.lessonCount}\uAC1C \xB7 \uB4F1\uB85D\uB41C \uD504\uB85C\uC81D\uD2B8 ${result.projectCount}\uAC1C \xB7 1\uC138\uB300`
730
779
  )
731
780
  );
781
+ return setupLines;
782
+ }
783
+ function resultNextLines(inputs, c) {
784
+ const color = makeColors(c.color);
732
785
  const nextLines = [];
733
786
  if (inputs.skills.claude) {
734
787
  nextLines.push("Claude Code \uB97C \uC5F4\uACE0 \uC774\uB807\uAC8C \uB9D0\uD558\uC138\uC694.");
@@ -741,13 +794,26 @@ function renderResult(result, inputs, c) {
741
794
  } else {
742
795
  nextLines.push("\uB098\uC911\uC5D0 \uC2A4\uD0AC\uC744 \uC124\uCE58\uD558\uB824\uBA74 awl init \uC744 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.");
743
796
  }
797
+ return nextLines;
798
+ }
799
+ function renderResult(result, inputs, c) {
744
800
  return [
745
801
  "",
746
- sectionBox("\uC124\uC815 \uC644\uB8CC", setupLines, c, WIDTH - 4),
802
+ sectionBox("\uC124\uC815 \uC644\uB8CC", resultSetupLines(result, c), c, WIDTH - 4),
747
803
  "",
748
- sectionBox("\uB2E4\uC74C \uB2E8\uACC4", nextLines, c, WIDTH - 4)
804
+ sectionBox("\uB2E4\uC74C \uB2E8\uACC4", resultNextLines(inputs, c), c, WIDTH - 4)
749
805
  ].join("\n");
750
806
  }
807
+ function commitResultFlow(session, result, inputs, c) {
808
+ for (const line of resultSetupLines(result, c)) {
809
+ step(session, line);
810
+ }
811
+ step(session, "\uB2E4\uC74C \uB2E8\uACC4");
812
+ for (const line of resultNextLines(inputs, c)) {
813
+ process.stdout.write(`${flowConnector(c)} ${line}
814
+ `);
815
+ }
816
+ }
751
817
  var LANG_OPTIONS = ["TypeScript", "JavaScript", "Python", "\uC9C1\uC811 \uC785\uB825"];
752
818
  var LANG_VALUES = ["typescript", "javascript", "python", ""];
753
819
  function langDefaultIndices(projectRoot) {
@@ -760,10 +826,19 @@ function langDefaultIndices(projectRoot) {
760
826
  }
761
827
  function buildScreens(projectRoot, hasGlobal, c) {
762
828
  const project = path.basename(projectRoot);
763
- const defLangIndices = langDefaultIndices(projectRoot);
764
829
  const verify = detectVerify(projectRoot);
765
830
  const agents = detectAgents(projectRoot);
766
- const welcome = hasGlobal ? null : [
831
+ const welcome = hasGlobal ? null : welcomeLines(project, projectRoot).join("\n");
832
+ return {
833
+ welcome,
834
+ lang: stepBox("1/3", "\uC8FC \uC5B8\uC5B4", langScreenLines(projectRoot), c),
835
+ verify: stepBox("2/3", "\uAC80\uC99D \uBA85\uB839\uC5B4", verifyStepLines(verify), c),
836
+ character: stepBox("3/3", "\uADDC\uCE59\uACFC \uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uC131\uACA9", characterScreenLines(), c),
837
+ skills: stepBox("\uC2A4\uD0AC", "\uC2A4\uD0AC \uC124\uCE58", skillsScreenLines(agents), c)
838
+ };
839
+ }
840
+ function welcomeLines(project, projectRoot) {
841
+ return [
767
842
  "",
768
843
  " ~/.awl \uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uCC98\uC74C \uC624\uC168\uAD70\uC694.",
769
844
  "",
@@ -776,46 +851,38 @@ function buildScreens(projectRoot, hasGlobal, c) {
776
851
  " \uB2E4\uB978 \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C\uB3C4 awl init \uC744 \uC2E4\uD589\uD558\uBA74 \uADF8\uB54C \uB4F1\uB85D\uB429\uB2C8\uB2E4.",
777
852
  " \uADDC\uCE59\uACFC \uAD50\uD6C8\uC740 \uD504\uB85C\uC81D\uD2B8\uAC00 \uC544\uB2C8\uB77C \uB2F9\uC2E0\uC5D0\uAC8C \uC313\uC774\uACE0,",
778
853
  " \uB4F1\uB85D\uB41C \uBAA8\uB4E0 \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C \uD568\uAED8 \uC4F0\uC785\uB2C8\uB2E4."
779
- ].join("\n");
854
+ ];
855
+ }
856
+ function langScreenLines(projectRoot) {
857
+ const defLangIndices = langDefaultIndices(projectRoot);
780
858
  const detectedLangLabels = defLangIndices.map((i) => LANG_OPTIONS[i] ?? "TypeScript").join(", ");
781
- const langLines = [
859
+ return [
782
860
  `\uC790\uB3D9 \uAC10\uC9C0: ${detectedLangLabels || "TypeScript"}`,
783
861
  "",
784
862
  "\uC5EC\uB7EC \uAC1C\uB97C \uC4F0\uB294 \uD504\uB85C\uC81D\uD2B8\uBA74(\uC608: TypeScript \uD504\uB860\uD2B8 + Python \uBC31\uC5D4\uB4DC) \uC804\uBD80 \uACE0\uB974\uC138\uC694.",
785
863
  "\u2191\u2193 \uB610\uB294 j/k \uB85C \uC774\uB3D9, Space \uB85C \uC120\uD0DD, Enter \uB85C \uD655\uC815\uD558\uC138\uC694.",
786
864
  "\uD0A4 \uC785\uB825\uC744 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD130\uBBF8\uB110\uC5D0\uC11C\uB294 \uBC88\uD638\uB97C \uC27C\uD45C\uB85C \uC785\uB825\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4."
787
865
  ];
788
- return {
789
- welcome,
790
- lang: stepBox("1/3", "\uC8FC \uC5B8\uC5B4", langLines, c),
791
- verify: stepBox("2/3", "\uAC80\uC99D \uBA85\uB839\uC5B4", verifyStepLines(verify), c),
792
- character: stepBox(
793
- "3/3",
794
- "\uADDC\uCE59\uACFC \uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uC131\uACA9",
795
- [
796
- "\uAC19\uC740 \uC2E4\uD328\uAC00 \uC313\uC774\uBA74 \uADDC\uCE59\uC774 \uB418\uACE0, \uB2E4\uC74C \uD504\uB85C\uC81D\uD2B8\uC5D0\uB3C4 \uC804\uD30C\uB429\uB2C8\uB2E4.",
797
- "\uD504\uB85C\uC81D\uD2B8\uC758 \uC131\uACA9\uC740 \uADF8 \uADDC\uCE59\uC744 \uC5EC\uAE30\uC5D0\uB3C4 \uC801\uC6A9\uD560\uC9C0 \uD310\uB2E8\uD558\uB294 \uADFC\uAC70\uC785\uB2C8\uB2E4.",
798
- "",
799
- "\uC774 \uD504\uB85C\uC81D\uD2B8\uB294 \uC5B4\uB5A4 \uACF3\uC785\uB2C8\uAE4C?",
800
- '(\uC608\uC2DC: "React + TailwindCSS \uC6F9 \uD504\uB860\uD2B8\uC5D4\uB4DC", "Python Fast API \uBD84\uC11D \uC11C\uBC84",',
801
- ' "TypeScript \uB77C\uC774\uBE0C\uB7EC\uB9AC \uD328\uD0A4\uC9C0")'
802
- ],
803
- c
804
- ),
805
- skills: stepBox(
806
- "\uC2A4\uD0AC",
807
- "\uC2A4\uD0AC \uC124\uCE58",
808
- [
809
- "awl \uC740 \uD310\uB2E8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uD30C\uC77C\uACFC \uC0C1\uD0DC\uB9CC \uAD00\uB9AC\uD569\uB2C8\uB2E4.",
810
- "\uD310\uB2E8\uC740 \uC774\uBBF8 \uC4F0\uACE0 \uACC4\uC2E0 \uC5D0\uC774\uC804\uD2B8\uAC00 \uD569\uB2C8\uB2E4.",
811
- "",
812
- "\uBC14\uB85C \uC544\uB798\uC5D0\uC11C \uC124\uCE58\uD560 \uC5D0\uC774\uC804\uD2B8\uB97C \uACE0\uB985\uB2C8\uB2E4.",
813
- "\uCCAB \uBC88\uC9F8 \u201C\uBAA8\uB450 \uC124\uCE58\u201D\uB97C \uACE0\uB974\uAC70\uB098, Space \uB85C \uD544\uC694\uD55C \uD56D\uBAA9\uB9CC \uACE0\uB97C \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
814
- `\uAC10\uC9C0\uB428: Claude Code ${agents.claude ? "\uC788\uC74C" : "\uC5C6\uC74C"} \xB7 Codex ${agents.codex ? "\uC788\uC74C" : "\uC5C6\uC74C"}`
815
- ],
816
- c
817
- )
818
- };
866
+ }
867
+ function characterScreenLines() {
868
+ return [
869
+ "\uAC19\uC740 \uC2E4\uD328\uAC00 \uC313\uC774\uBA74 \uADDC\uCE59\uC774 \uB418\uACE0, \uB2E4\uC74C \uD504\uB85C\uC81D\uD2B8\uC5D0\uB3C4 \uC804\uD30C\uB429\uB2C8\uB2E4.",
870
+ "\uD504\uB85C\uC81D\uD2B8\uC758 \uC131\uACA9\uC740 \uADF8 \uADDC\uCE59\uC744 \uC5EC\uAE30\uC5D0\uB3C4 \uC801\uC6A9\uD560\uC9C0 \uD310\uB2E8\uD558\uB294 \uADFC\uAC70\uC785\uB2C8\uB2E4.",
871
+ "",
872
+ "\uC774 \uD504\uB85C\uC81D\uD2B8\uB294 \uC5B4\uB5A4 \uACF3\uC785\uB2C8\uAE4C?",
873
+ '(\uC608\uC2DC: "React + TailwindCSS \uC6F9 \uD504\uB860\uD2B8\uC5D4\uB4DC", "Python Fast API \uBD84\uC11D \uC11C\uBC84",',
874
+ ' "TypeScript \uB77C\uC774\uBE0C\uB7EC\uB9AC \uD328\uD0A4\uC9C0")'
875
+ ];
876
+ }
877
+ function skillsScreenLines(agents) {
878
+ return [
879
+ "awl \uC740 \uD310\uB2E8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uD30C\uC77C\uACFC \uC0C1\uD0DC\uB9CC \uAD00\uB9AC\uD569\uB2C8\uB2E4.",
880
+ "\uD310\uB2E8\uC740 \uC774\uBBF8 \uC4F0\uACE0 \uACC4\uC2E0 \uC5D0\uC774\uC804\uD2B8\uAC00 \uD569\uB2C8\uB2E4.",
881
+ "",
882
+ "\uBC14\uB85C \uC544\uB798\uC5D0\uC11C \uC124\uCE58\uD560 \uC5D0\uC774\uC804\uD2B8\uB97C \uACE0\uB985\uB2C8\uB2E4.",
883
+ "\uCCAB \uBC88\uC9F8 \u201C\uBAA8\uB450 \uC124\uCE58\u201D\uB97C \uACE0\uB974\uAC70\uB098, Space \uB85C \uD544\uC694\uD55C \uD56D\uBAA9\uB9CC \uACE0\uB97C \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
884
+ `\uAC10\uC9C0\uB428: Claude Code ${agents.claude ? "\uC788\uC74C" : "\uC5C6\uC74C"} \xB7 Codex ${agents.codex ? "\uC788\uC74C" : "\uC5C6\uC74C"}`
885
+ ];
819
886
  }
820
887
  function ask(rl, q) {
821
888
  return new Promise((resolve) => rl.question(q, (a) => resolve(a)));
@@ -903,7 +970,6 @@ function applyVerifyCwd(verify, cwd) {
903
970
  return verify;
904
971
  }
905
972
  async function interactiveInputs(projectRoot, hasGlobal, c) {
906
- const screens = buildScreens(projectRoot, hasGlobal, c);
907
973
  const project = path.basename(projectRoot);
908
974
  const useRawMode = rawModeCapable();
909
975
  const session = { rl: null };
@@ -913,29 +979,48 @@ async function interactiveInputs(projectRoot, hasGlobal, c) {
913
979
  }
914
980
  return session.rl;
915
981
  };
982
+ const flow = openFlow("awl init", c);
916
983
  try {
917
- if (screens.welcome) {
918
- process.stdout.write(`${screens.welcome}
984
+ if (!hasGlobal) {
985
+ process.stdout.write(`${flowConnector(c)}
919
986
  `);
920
- }
921
- process.stdout.write(`
922
- ${screens.lang}
923
-
987
+ for (const line of welcomeLines(project, projectRoot)) {
988
+ process.stdout.write(`${flowConnector(c)}${line}
924
989
  `);
990
+ }
991
+ }
925
992
  const defaultLangChecked = langDefaultIndices(projectRoot);
926
- const rawLanguage = useRawMode ? await runInteractiveSelect(LANG_OPTIONS, 0, true, c, defaultLangChecked, {
927
- title: "\uC8FC \uC5B8\uC5B4",
928
- hint: "\u2191\u2193 \uB610\uB294 j/k \uC774\uB3D9 \xB7 Space \uC120\uD0DD \xB7 Enter \uD655\uC815 \xB7 Esc \uAE30\uBCF8\uAC12 \uC720\uC9C0"
929
- }) : null;
930
- const langChecked = rawLanguage?.checked ?? (useRawMode ? defaultLangChecked : await selectMulti(prompt(), LANG_OPTIONS, defaultLangChecked, c, false, "\uC8FC \uC5B8\uC5B4"));
993
+ const langBody = langScreenLines(projectRoot);
994
+ let langChecked;
995
+ if (useRawMode) {
996
+ const r = await activeSelect(flow, LANG_OPTIONS, 0, true, defaultLangChecked, {
997
+ title: "\uC8FC \uC5B8\uC5B4",
998
+ body: langBody,
999
+ hint: "\u2191\u2193 \uB610\uB294 j/k \uC774\uB3D9 \xB7 Space \uC120\uD0DD \xB7 Enter \uD655\uC815 \xB7 Esc \uAE30\uBCF8\uAC12 \uC720\uC9C0"
1000
+ });
1001
+ langChecked = r?.checked ?? defaultLangChecked;
1002
+ } else {
1003
+ process.stdout.write(`${flowConnector(c)}
1004
+ ${flowActiveNode("\uC8FC \uC5B8\uC5B4", langBody, c)}
1005
+ `);
1006
+ langChecked = await selectMulti(
1007
+ prompt(),
1008
+ LANG_OPTIONS,
1009
+ defaultLangChecked,
1010
+ c,
1011
+ false,
1012
+ "\uC8FC \uC5B8\uC5B4"
1013
+ );
1014
+ }
931
1015
  const manualLangIdx = LANG_OPTIONS.length - 1;
932
1016
  const mainLanguage = langChecked.filter((i) => i !== manualLangIdx).map((i) => LANG_VALUES[i]).filter((v) => typeof v === "string" && v !== "");
933
1017
  if (langChecked.includes(manualLangIdx)) {
934
- const typed = (await ask(prompt(), " \uC8FC \uC5B8\uC5B4\uB97C \uC785\uB825\uD558\uC138\uC694: ")).trim();
1018
+ const typed = (await ask(prompt(), `${flowConnector(c)} \uC8FC \uC5B8\uC5B4\uB97C \uC785\uB825\uD558\uC138\uC694: `)).trim();
935
1019
  if (typed) {
936
1020
  mainLanguage.push(typed);
937
1021
  }
938
1022
  }
1023
+ selectStep(flow, `\uC8FC \uC5B8\uC5B4: ${mainLanguage.length > 0 ? mainLanguage.join(", ") : "(\uC5C6\uC74C)"}`);
939
1024
  const rootVerify = detectVerify(projectRoot);
940
1025
  const located = await promptVerifyLocation(
941
1026
  prompt(),
@@ -944,35 +1029,26 @@ ${screens.lang}
944
1029
  makeColors(c.color)
945
1030
  );
946
1031
  const verify = located.verify;
947
- if (located.cwd) {
948
- process.stdout.write(`
949
- ${stepBox("2/3", "\uAC80\uC99D \uBA85\uB839\uC5B4", verifyStepLines(verify), c)}
950
-
951
- `);
952
- } else {
953
- process.stdout.write(`
954
- ${screens.verify}
955
-
956
- `);
957
- }
1032
+ process.stdout.write(
1033
+ `${flowConnector(c)}
1034
+ ${flowActiveNode("\uAC80\uC99D \uBA85\uB839\uC5B4", verifyStepLines(verify), c)}
1035
+ `
1036
+ );
958
1037
  for (const k of Object.keys(VERIFY_LABELS)) {
959
1038
  const cur = verify[k];
960
1039
  const shown = cur ? cur.cmd : "(\uC5C6\uC74C)";
961
- const answer = (await ask(prompt(), ` ${VERIFY_LABELS[k]} [${shown}]: `)).trim();
1040
+ const answer = (await ask(prompt(), `${flowConnector(c)} ${VERIFY_LABELS[k]} [${shown}]: `)).trim();
962
1041
  if (answer !== "") {
963
1042
  verify[k] = answer.toLowerCase() === "\uC5C6\uC74C" || answer === "-" ? null : splitEnv(answer);
964
1043
  }
965
1044
  }
966
1045
  applyVerifyCwd(verify, located.cwd);
967
- process.stdout.write(`
968
- ${screens.character}
969
-
970
- `);
971
- const character = (await ask(prompt(), " > ")).trim();
972
- process.stdout.write(`
973
- ${screens.skills}
974
-
975
- `);
1046
+ process.stdout.write(
1047
+ `${flowConnector(c)}
1048
+ ${flowActiveNode("\uADDC\uCE59\uACFC \uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uC131\uACA9", characterScreenLines(), c)}
1049
+ `
1050
+ );
1051
+ const character = (await ask(prompt(), `${flowConnector(c)} > `)).trim();
976
1052
  const agents = detectAgents(projectRoot);
977
1053
  const skillOptions = [
978
1054
  "\uBAA8\uB450 \uC124\uCE58 (Claude Code + Codex)",
@@ -984,26 +1060,39 @@ ${screens.skills}
984
1060
  session.rl.close();
985
1061
  session.rl = null;
986
1062
  }
987
- const rawSkills = useRawMode ? await runInteractiveSelect(skillOptions, 0, true, c, defaultChecked, {
988
- title: "\uC124\uCE58\uD560 \uC5D0\uC774\uC804\uD2B8 \uC2A4\uD0AC",
989
- hint: "\u2191\u2193 \uB610\uB294 j/k \uC774\uB3D9 \xB7 Space \uC120\uD0DD \xB7 Enter \uD655\uC815 \xB7 Esc \uAE30\uBCF8\uAC12 \uC720\uC9C0",
990
- selectAllIndex: 0
991
- }) : null;
992
- const checked = rawSkills?.checked ?? (useRawMode ? defaultChecked : await selectMulti(
993
- prompt(),
994
- skillOptions,
995
- defaultChecked,
996
- c,
997
- false,
998
- "\uC124\uCE58\uD560 \uC5D0\uC774\uC804\uD2B8 \uC2A4\uD0AC",
999
- 0
1000
- ));
1063
+ let checked;
1064
+ if (useRawMode) {
1065
+ const r = await activeSelect(flow, skillOptions, 0, true, defaultChecked, {
1066
+ title: "\uC124\uCE58\uD560 \uC5D0\uC774\uC804\uD2B8 \uC2A4\uD0AC",
1067
+ body: skillsScreenLines(agents),
1068
+ hint: "\u2191\u2193 \uB610\uB294 j/k \uC774\uB3D9 \xB7 Space \uC120\uD0DD \xB7 Enter \uD655\uC815 \xB7 Esc \uAE30\uBCF8\uAC12 \uC720\uC9C0",
1069
+ selectAllIndex: 0
1070
+ });
1071
+ checked = r?.checked ?? defaultChecked;
1072
+ } else {
1073
+ process.stdout.write(
1074
+ `${flowConnector(c)}
1075
+ ${flowActiveNode("\uC124\uCE58\uD560 \uC5D0\uC774\uC804\uD2B8 \uC2A4\uD0AC", skillsScreenLines(agents), c)}
1076
+ `
1077
+ );
1078
+ checked = await selectMulti(
1079
+ prompt(),
1080
+ skillOptions,
1081
+ defaultChecked,
1082
+ c,
1083
+ false,
1084
+ "\uC124\uCE58\uD560 \uC5D0\uC774\uC804\uD2B8 \uC2A4\uD0AC",
1085
+ 0
1086
+ );
1087
+ }
1001
1088
  const installAll = checked.includes(0);
1002
1089
  const skills = {
1003
1090
  claude: installAll || checked.includes(1),
1004
1091
  codex: installAll || checked.includes(2)
1005
1092
  };
1006
- return { project, mainLanguage, character, verify, skills };
1093
+ const skillsSummary = installAll ? "\uBAA8\uB450 \uC124\uCE58 (Claude Code + Codex)" : [skills.claude && "Claude Code", skills.codex && "Codex"].filter(Boolean).join(", ") || "(\uC5C6\uC74C)";
1094
+ selectStep(flow, `\uC124\uCE58: ${skillsSummary}`);
1095
+ return { inputs: { project, mainLanguage, character, verify, skills }, session: flow };
1007
1096
  } finally {
1008
1097
  session.rl?.close();
1009
1098
  }
@@ -1013,35 +1102,30 @@ async function handleExistingConfig(rl, projectRoot, c, now) {
1013
1102
  const config = raw;
1014
1103
  scaffoldGlobal();
1015
1104
  const installedVer = installedEngineVersion();
1016
- process.stdout.write("\n .awl/config.json \uC774 \uC774\uBBF8 \uC788\uC2B5\uB2C8\uB2E4. \uD300\uC6D0\uC774 \uC124\uC815\uD574\uB450\uC5C8\uAD70\uC694.\n\n");
1017
- process.stdout.write(` \uD504\uB85C\uC81D\uD2B8 ${config?.project ?? "(\uC5C6\uC74C)"}
1018
- `);
1019
- process.stdout.write(` \uC8FC \uC5B8\uC5B4 ${config?.mainLanguage?.join(", ") || "(\uC5C6\uC74C)"}
1020
- `);
1021
- process.stdout.write(` \uC131\uACA9 ${config?.character || "(\uC5C6\uC74C)"}
1022
- `);
1023
1105
  const engineNote = installedVer && config?.engineVersion ? installedVer === config.engineVersion ? `(\uC124\uCE58\uB428: ${installedVer} \uC77C\uCE58)` : `(\uC124\uCE58\uB428: ${installedVer} \uBD88\uC77C\uCE58 -> '\uADF8\uB300\uB85C \uC4F4\uB2E4'\uB97C \uACE0\uB974\uBA74 \uB3D9\uAE30\uD654\uB429\uB2C8\uB2E4)` : "";
1024
- process.stdout.write(` \uC5D4\uC9C4 ${config?.engineVersion ?? "(\uC5C6\uC74C)"} ${engineNote}
1025
-
1106
+ const summaryLines = [
1107
+ ".awl/config.json \uC774 \uC774\uBBF8 \uC788\uC2B5\uB2C8\uB2E4. \uD300\uC6D0\uC774 \uC124\uC815\uD574\uB450\uC5C8\uAD70\uC694.",
1108
+ "",
1109
+ `\uD504\uB85C\uC81D\uD2B8 ${config?.project ?? "(\uC5C6\uC74C)"}`,
1110
+ `\uC8FC \uC5B8\uC5B4 ${config?.mainLanguage?.join(", ") || "(\uC5C6\uC74C)"}`,
1111
+ `\uC131\uACA9 ${config?.character || "(\uC5C6\uC74C)"}`,
1112
+ `\uC5D4\uC9C4 ${config?.engineVersion ?? "(\uC5C6\uC74C)"} ${engineNote}`,
1113
+ ...config?.verify ? ["", ...verifyLines(config.verify).map((l) => `\uAC80\uC99D ${l.trim()}`)] : [],
1114
+ "",
1115
+ "\uC774 \uC124\uC815\uC744 \uADF8\uB300\uB85C \uC4F0\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?"
1116
+ ];
1117
+ const flow = openFlow("\uAE30\uC874 \uC124\uC815", c);
1118
+ process.stdout.write(`${flowConnector(c)}
1119
+ ${flowActiveNode("\uAE30\uC874 \uC124\uC815", summaryLines, c)}
1026
1120
  `);
1027
- if (config?.verify) {
1028
- for (const line of verifyLines(config.verify)) {
1029
- process.stdout.write(` \uAC80\uC99D ${line.trim()}
1121
+ const options = ["\uADF8\uB300\uB85C \uC4F4\uB2E4", "\uAC80\uC99D \uBA85\uB839\uC5B4\uB9CC \uACE0\uCE5C\uB2E4", "\uCC98\uC74C\uBD80\uD130 \uB2E4\uC2DC"];
1122
+ for (let i = 0; i < options.length; i++) {
1123
+ process.stdout.write(`${flowConnector(c)} ${i + 1}. ${options[i]}
1030
1124
  `);
1031
- }
1032
- process.stdout.write("\n");
1033
1125
  }
1034
- process.stdout.write(" \uC774 \uC124\uC815\uC744 \uADF8\uB300\uB85C \uC4F0\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?\n\n");
1035
- const options = ["\uADF8\uB300\uB85C \uC4F4\uB2E4", "\uAC80\uC99D \uBA85\uB839\uC5B4\uB9CC \uACE0\uCE5C\uB2E4", "\uCC98\uC74C\uBD80\uD130 \uB2E4\uC2DC"];
1036
- process.stdout.write(
1037
- `${sectionBox(
1038
- "\uAE30\uC874 \uC124\uC815",
1039
- options.map((option, i) => `${i + 1}. ${option}`),
1040
- c
1041
- )}
1042
- `
1043
- );
1044
1126
  const choice = await promptNumber(rl, 0, options.length);
1127
+ selectStep(flow, `\uC120\uD0DD: ${options[choice]}`);
1128
+ closeFlow(flow);
1045
1129
  process.stdout.write(
1046
1130
  `
1047
1131
  ${makeColors(c.color).dim("\uADDC\uCE59\uACFC \uAD50\uD6C8\uC740 \uACF5\uC720\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC800 \uC124\uC815\uB9CC \uD300\uC6D0\uACFC \uAC19\uACE0, \uC313\uC774\uB294 \uAC83\uC740 \uB2F9\uC2E0 \uAC83\uC785\uB2C8\uB2E4.")}
@@ -1082,11 +1166,10 @@ async function handleExistingConfig(rl, projectRoot, c, now) {
1082
1166
  return;
1083
1167
  }
1084
1168
  rl.close();
1085
- const inputs = await interactiveInputs(projectRoot, isGlobalInstalled(), c);
1169
+ const { inputs, session } = await interactiveInputs(projectRoot, isGlobalInstalled(), c);
1086
1170
  const result = applyInit(projectRoot, inputs, now);
1087
- process.stdout.write(`
1088
- ${renderResult(result, inputs, c)}
1089
- `);
1171
+ commitResultFlow(session, result, inputs, c);
1172
+ closeFlow(session);
1090
1173
  }
1091
1174
  function resolveProjectChoice(idx, candidates) {
1092
1175
  if (idx >= 0 && idx < candidates.length) {
@@ -1157,13 +1240,14 @@ async function pickProjectRoot(cwd, c) {
1157
1240
  }
1158
1241
  return session.rl;
1159
1242
  };
1243
+ const flow = openFlow("\uD504\uB85C\uC81D\uD2B8 \uC120\uD0DD", c);
1160
1244
  const select = async (options, title) => {
1161
1245
  if (raw) {
1162
1246
  if (session.rl) {
1163
1247
  session.rl.close();
1164
1248
  session.rl = null;
1165
1249
  }
1166
- const r = await runInteractiveSelect(options, 0, false, c, [], {
1250
+ const r = await activeSelect(flow, options, 0, false, [], {
1167
1251
  title,
1168
1252
  hint: "\u2191\u2193 \uB610\uB294 j/k \uC774\uB3D9 \xB7 Enter \uC120\uD0DD \xB7 Esc \uAE30\uBCF8\uAC12 \uC720\uC9C0"
1169
1253
  });
@@ -1178,6 +1262,7 @@ async function pickProjectRoot(cwd, c) {
1178
1262
  "\uC5B4\uB290 \uD504\uB85C\uC81D\uD2B8\uC5D0 awl \uC744 \uBD99\uC77C\uAE4C\uC694?"
1179
1263
  );
1180
1264
  if (idx === 0) {
1265
+ selectStep(flow, `\uD504\uB85C\uC81D\uD2B8: ${cwd}`);
1181
1266
  return cwd;
1182
1267
  }
1183
1268
  if (idx !== 1) {
@@ -1189,12 +1274,13 @@ async function pickProjectRoot(cwd, c) {
1189
1274
  const title = candidates.length > 0 ? "\uD504\uB85C\uC81D\uD2B8\uB97C \uACE0\uB974\uC138\uC694 (\uCD5C\uADFC \uC218\uC815\uC21C, \uCD5C\uB300 20)\n" : "\uD558\uC704\uC5D0 git \uD504\uB85C\uC81D\uD2B8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uC9C1\uC811 \uC785\uB825\uD558\uAC70\uB098 \uCDE8\uC18C\n";
1190
1275
  const choice = resolveProjectChoice(await select(labels, title), candidates);
1191
1276
  if (choice.kind === "path") {
1277
+ selectStep(flow, `\uD504\uB85C\uC81D\uD2B8: ${choice.path}`);
1192
1278
  return choice.path;
1193
1279
  }
1194
1280
  if (choice.kind === "cancel") {
1195
1281
  return null;
1196
1282
  }
1197
- const typed = (await ask(prompt(), " \uD504\uB85C\uC81D\uD2B8 \uACBD\uB85C\uB97C \uC785\uB825\uD558\uC138\uC694: ")).trim();
1283
+ const typed = (await ask(prompt(), `${flowConnector(c)} \uD504\uB85C\uC81D\uD2B8 \uACBD\uB85C\uB97C \uC785\uB825\uD558\uC138\uC694: `)).trim();
1198
1284
  if (!typed) {
1199
1285
  return null;
1200
1286
  }
@@ -1205,11 +1291,13 @@ async function pickProjectRoot(cwd, c) {
1205
1291
  `);
1206
1292
  return null;
1207
1293
  }
1294
+ selectStep(flow, `\uD504\uB85C\uC81D\uD2B8: ${resolved}`);
1208
1295
  return resolved;
1209
1296
  } finally {
1210
1297
  if (session.rl) {
1211
1298
  session.rl.close();
1212
1299
  }
1300
+ closeFlow(flow);
1213
1301
  }
1214
1302
  }
1215
1303
  async function runInit(opts) {
@@ -1268,14 +1356,16 @@ async function runInit(opts) {
1268
1356
  }
1269
1357
  return;
1270
1358
  }
1271
- const inputs = await interactiveInputs(chosenRoot, isGlobalInstalled(), c);
1359
+ const { inputs, session } = await interactiveInputs(chosenRoot, isGlobalInstalled(), c);
1272
1360
  const result = applyInit(chosenRoot, inputs, now);
1273
- process.stdout.write(`
1274
- ${renderResult(result, inputs, c)}
1275
- `);
1361
+ commitResultFlow(session, result, inputs, c);
1362
+ closeFlow(session);
1276
1363
  }
1277
1364
 
1278
1365
  export {
1366
+ openFlow,
1367
+ step,
1368
+ closeFlow,
1279
1369
  scanGitProjects,
1280
1370
  detectLanguage,
1281
1371
  detectLanguages,
@@ -1303,9 +1393,14 @@ export {
1303
1393
  verifyStepLines,
1304
1394
  renderNonTtyNotice,
1305
1395
  renderResult,
1396
+ commitResultFlow,
1306
1397
  LANG_OPTIONS,
1307
1398
  LANG_VALUES,
1308
1399
  buildScreens,
1400
+ welcomeLines,
1401
+ langScreenLines,
1402
+ characterScreenLines,
1403
+ skillsScreenLines,
1309
1404
  ask,
1310
1405
  promptNumber,
1311
1406
  selectSingle,