@nmakarov/cli-toolkit 0.18.0 → 0.23.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 (69) hide show
  1. package/README.md +9 -0
  2. package/dist/args.cjs +1 -4
  3. package/dist/args.cjs.map +1 -1
  4. package/dist/args.js +1 -1
  5. package/dist/args.js.map +1 -1
  6. package/dist/cli-runner.cjs +1493 -516
  7. package/dist/cli-runner.cjs.map +1 -1
  8. package/dist/cli-runner.js +1509 -531
  9. package/dist/cli-runner.js.map +1 -1
  10. package/dist/db.cjs +85 -157
  11. package/dist/db.cjs.map +1 -1
  12. package/dist/db.js +84 -150
  13. package/dist/db.js.map +1 -1
  14. package/dist/errors.cjs +2 -2
  15. package/dist/errors.cjs.map +1 -1
  16. package/dist/errors.js +2 -1
  17. package/dist/errors.js.map +1 -1
  18. package/dist/filedatabase.cjs +19 -19
  19. package/dist/filedatabase.cjs.map +1 -1
  20. package/dist/filedatabase.js +19 -16
  21. package/dist/filedatabase.js.map +1 -1
  22. package/dist/http-client.cjs +9 -11
  23. package/dist/http-client.cjs.map +1 -1
  24. package/dist/http-client.js +10 -9
  25. package/dist/http-client.js.map +1 -1
  26. package/dist/http-client2.cjs +34 -33
  27. package/dist/http-client2.cjs.map +1 -1
  28. package/dist/http-client2.js +34 -30
  29. package/dist/http-client2.js.map +1 -1
  30. package/dist/index.cjs +2063 -658
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.js +2063 -663
  33. package/dist/index.js.map +1 -1
  34. package/dist/init.cjs +97 -69
  35. package/dist/init.cjs.map +1 -1
  36. package/dist/init.js +112 -83
  37. package/dist/init.js.map +1 -1
  38. package/dist/logger.cjs +5 -5
  39. package/dist/logger.cjs.map +1 -1
  40. package/dist/logger.js +5 -4
  41. package/dist/logger.js.map +1 -1
  42. package/dist/mock-server.cjs +21 -33
  43. package/dist/mock-server.cjs.map +1 -1
  44. package/dist/mock-server.js +21 -28
  45. package/dist/mock-server.js.map +1 -1
  46. package/dist/params.cjs +22 -10
  47. package/dist/params.cjs.map +1 -1
  48. package/dist/params.js +22 -7
  49. package/dist/params.js.map +1 -1
  50. package/dist/s3.cjs +286 -0
  51. package/dist/s3.cjs.map +1 -0
  52. package/dist/s3.js +273 -0
  53. package/dist/s3.js.map +1 -0
  54. package/dist/screen.cjs +34 -39
  55. package/dist/screen.cjs.map +1 -1
  56. package/dist/screen.js +48 -46
  57. package/dist/screen.js.map +1 -1
  58. package/dist/tasks.cjs +1640 -416
  59. package/dist/tasks.cjs.map +1 -1
  60. package/dist/tasks.js +1614 -412
  61. package/dist/tasks.js.map +1 -1
  62. package/dist/utils.cjs +7 -8
  63. package/dist/utils.cjs.map +1 -1
  64. package/dist/utils.js +6 -6
  65. package/dist/utils.js.map +1 -1
  66. package/package.json +36 -44
  67. package/scripts/ssm/parse-cli.js +35 -0
  68. package/scripts/ssm/ssm-admin.js +151 -0
  69. package/scripts/ssm/ssm-pull.js +147 -0
package/dist/init.js CHANGED
@@ -14,7 +14,7 @@ var __export = (target, all) => {
14
14
  __defProp(target, name, { get: all[name], enumerable: true });
15
15
  };
16
16
 
17
- // src/screen/components.ts
17
+ // src/screen/components.js
18
18
  import { createElement as h } from "react";
19
19
  import { Box, Text } from "ink";
20
20
  function getScreenWidth(maxWidth = null) {
@@ -89,13 +89,12 @@ function ScreenFooter({ lines, textStyle }) {
89
89
  );
90
90
  }
91
91
  var init_components = __esm({
92
- "src/screen/components.ts"() {
93
- "use strict";
92
+ "src/screen/components.js"() {
94
93
  }
95
94
  });
96
95
 
97
- // src/screen/list-components.ts
98
- import React2, { useState, useEffect, useRef, createElement } from "react";
96
+ // src/screen/list-components.js
97
+ import React, { useState, useEffect, useRef, createElement } from "react";
99
98
  import { Box as Box2, Text as Text2 } from "ink";
100
99
  function MultiColumnListComponent({ items, ctx, selectedIndexRef }) {
101
100
  const [, forceUpdate] = useState({});
@@ -231,11 +230,11 @@ function MultiColumnListWithPreviewComponent({
231
230
  const previewRows = [];
232
231
  if (typeof previewContent === "string") {
233
232
  previewRows.push(h2(ScreenRow, { key: "preview-string", children: h2(Text2, { bold: true }, previewContent) }));
234
- } else if (typeof previewContent === "object" && !React2.isValidElement(previewContent) && previewContent !== null) {
233
+ } else if (typeof previewContent === "object" && !React.isValidElement(previewContent) && previewContent !== null) {
235
234
  Object.entries(previewContent).forEach(([key, value], idx) => {
236
235
  previewRows.push(h2(ScreenRow, { key: `preview-${key}-${idx}`, children: h2(Text2, {}, `${key}: ${value}`) }));
237
236
  });
238
- } else if (React2.isValidElement(previewContent)) {
237
+ } else if (React.isValidElement(previewContent)) {
239
238
  previewRows.push(h2(ScreenRow, { key: "preview-element", children: previewContent }));
240
239
  }
241
240
  return h2(
@@ -248,11 +247,13 @@ function MultiColumnListWithPreviewComponent({
248
247
  ...previewRows
249
248
  );
250
249
  }
251
- function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sortable = false, maxHeight, sortHighlightStyle, selectionMarker = " " }) {
250
+ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sortable = false, maxHeight, sortHighlightStyle, selectionMarker = " ", onSelectionChange }) {
252
251
  const [, forceUpdate] = useState({});
253
252
  const [sortOrder, setSortOrder] = useState("none");
254
253
  const [scrollOffset, setScrollOffset] = useState(0);
255
254
  const scrollStateRef = useRef({ scrollOffset: 0, maxHeight: 0, totalItems: 0 });
255
+ const itemsRef = useRef(items);
256
+ itemsRef.current = items;
256
257
  const defaultGetTitle = (item) => {
257
258
  return getTitle ? getTitle(item) : typeof item.value === "string" ? item.value : item.value?.title || item.name;
258
259
  };
@@ -266,18 +267,24 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
266
267
  return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;
267
268
  }
268
269
  }) : items;
270
+ const displayItemsRef = useRef(displayItems);
271
+ displayItemsRef.current = displayItems;
269
272
  const effectiveMaxHeight = maxHeight || displayItems.length;
270
- const canScroll = displayItems.length > effectiveMaxHeight;
273
+ const _canScroll = displayItems.length > effectiveMaxHeight;
271
274
  const maxScrollOffset = Math.max(0, displayItems.length - effectiveMaxHeight);
272
275
  const clampedScrollOffset = Math.min(Math.max(0, scrollOffset), maxScrollOffset);
273
276
  const visibleItems = displayItems.slice(clampedScrollOffset, clampedScrollOffset + effectiveMaxHeight);
274
277
  const canScrollUp = clampedScrollOffset > 0;
275
278
  const canScrollDown = clampedScrollOffset < maxScrollOffset;
276
279
  scrollStateRef.current = { scrollOffset, maxHeight: effectiveMaxHeight, totalItems: displayItems.length };
280
+ const onSelectionChangeRef = useRef(onSelectionChange);
281
+ onSelectionChangeRef.current = onSelectionChange;
277
282
  useEffect(() => {
278
283
  ctx.setAction("moveUp", () => {
279
284
  const newIndex = Math.max(0, selectedIndexRef.current - 1);
280
285
  selectedIndexRef.current = newIndex;
286
+ const list = displayItemsRef.current;
287
+ onSelectionChangeRef.current?.(newIndex, list[newIndex]);
281
288
  const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;
282
289
  const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);
283
290
  const currentClampedScrollOffset = Math.min(Math.max(0, currentScrollOffset), currentMaxScrollOffset);
@@ -287,18 +294,11 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
287
294
  forceUpdate({});
288
295
  });
289
296
  ctx.setAction("moveDown", () => {
290
- const currentItems = sortable && sortOrder !== "none" ? [...items].sort((a, b) => {
291
- const titleA = titleGetter(a).toLowerCase();
292
- const titleB = titleGetter(b).toLowerCase();
293
- if (sortOrder === "asc") {
294
- return titleA < titleB ? -1 : titleA > titleB ? 1 : 0;
295
- } else {
296
- return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;
297
- }
298
- }) : items;
299
- const maxIndex = currentItems.length - 1;
297
+ const currentItems = displayItemsRef.current;
298
+ const maxIndex = Math.max(0, currentItems.length - 1);
300
299
  const newIndex = Math.min(maxIndex, selectedIndexRef.current + 1);
301
300
  selectedIndexRef.current = newIndex;
301
+ onSelectionChangeRef.current?.(newIndex, currentItems[newIndex]);
302
302
  const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;
303
303
  const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);
304
304
  const currentClampedScrollOffset = Math.min(Math.max(0, currentScrollOffset), currentMaxScrollOffset);
@@ -308,8 +308,7 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
308
308
  forceUpdate({});
309
309
  });
310
310
  ctx.setAction("scrollUp", () => {
311
- const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;
312
- const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);
311
+ const { scrollOffset: currentScrollOffset } = scrollStateRef.current;
313
312
  const newScrollOffset = Math.max(0, currentScrollOffset - 1);
314
313
  setScrollOffset(newScrollOffset);
315
314
  forceUpdate({});
@@ -324,9 +323,9 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
324
323
  if (sortable) {
325
324
  ctx.setAction("toggleSort", () => {
326
325
  const nextSort = sortOrder === "none" ? "asc" : sortOrder === "asc" ? "desc" : "none";
327
- const currentSelectedItem = displayItems[selectedIndexRef.current];
326
+ const currentSelectedItem = displayItemsRef.current[selectedIndexRef.current];
328
327
  setSortOrder(nextSort);
329
- const newSortedItems = nextSort !== "none" ? [...items].sort((a, b) => {
328
+ const newSortedItems = nextSort !== "none" ? [...itemsRef.current].sort((a, b) => {
330
329
  const titleA = titleGetter(a).toLowerCase();
331
330
  const titleB = titleGetter(b).toLowerCase();
332
331
  if (nextSort === "asc") {
@@ -334,7 +333,7 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
334
333
  } else {
335
334
  return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;
336
335
  }
337
- }) : items;
336
+ }) : itemsRef.current;
338
337
  const newIndex = newSortedItems.findIndex((item) => item === currentSelectedItem);
339
338
  if (newIndex !== -1) {
340
339
  selectedIndexRef.current = newIndex;
@@ -472,14 +471,13 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
472
471
  }
473
472
  var h2;
474
473
  var init_list_components = __esm({
475
- "src/screen/list-components.ts"() {
476
- "use strict";
474
+ "src/screen/list-components.js"() {
477
475
  init_components();
478
476
  h2 = createElement;
479
477
  }
480
478
  });
481
479
 
482
- // src/screen/screens.ts
480
+ // src/screen/screens.js
483
481
  import { useState as useState2, createElement as h3 } from "react";
484
482
  import { render, useInput, Text as Text3 } from "ink";
485
483
  function groupKeyBindings(bindings) {
@@ -557,7 +555,7 @@ async function showScreen(config2) {
557
555
  let renderResult = null;
558
556
  let initialized = false;
559
557
  const Screen = () => {
560
- const [updateCounter, setUpdateCounter] = useState2(0);
558
+ const [, setUpdateCounter] = useState2(0);
561
559
  if (!initialized) {
562
560
  const defaultBindings = [
563
561
  { key: "escape", caption: "go back", action: "back", protected: true, order: 1 },
@@ -676,7 +674,7 @@ async function showScreen(config2) {
676
674
  }
677
675
  }
678
676
  if (matchedBinding && actions[matchedBinding.action]) {
679
- const actionResult = actions[matchedBinding.action]({
677
+ actions[matchedBinding.action]({
680
678
  input,
681
679
  key,
682
680
  binding: matchedBinding
@@ -806,8 +804,7 @@ async function showMultiColumnListWithPreviewScreen(config2) {
806
804
  }
807
805
  var showMenuScreen, showWordGridScreen;
808
806
  var init_screens = __esm({
809
- "src/screen/screens.ts"() {
810
- "use strict";
807
+ "src/screen/screens.js"() {
811
808
  init_components();
812
809
  init_list_components();
813
810
  showMenuScreen = showListScreen;
@@ -815,9 +812,9 @@ var init_screens = __esm({
815
812
  }
816
813
  });
817
814
 
818
- // src/screen/ui-elements.ts
815
+ // src/screen/ui-elements.js
819
816
  import { createElement as h4 } from "react";
820
- import { Box as Box4, Text as Text4 } from "ink";
817
+ import { Box as Box3, Text as Text4 } from "ink";
821
818
  function ListItem({
822
819
  children,
823
820
  isSelected = false,
@@ -827,7 +824,7 @@ function ListItem({
827
824
  dimColor = false
828
825
  }) {
829
826
  return h4(
830
- Box4,
827
+ Box3,
831
828
  {},
832
829
  h4(Text4, {
833
830
  color: isSelected ? backgroundColor || "green" : color,
@@ -842,10 +839,10 @@ function TextBlock({
842
839
  color = "white",
843
840
  dimmed = false,
844
841
  bold = false,
845
- maxWidth
842
+ maxWidth: _maxWidth
846
843
  }) {
847
844
  return h4(
848
- Box4,
845
+ Box3,
849
846
  {},
850
847
  h4(Text4, {
851
848
  color,
@@ -856,7 +853,7 @@ function TextBlock({
856
853
  }
857
854
  function Divider({ character = "\u2500", width = 80 }) {
858
855
  return h4(
859
- Box4,
856
+ Box3,
860
857
  { marginY: 1 },
861
858
  h4(Text4, { dimColor: true }, character.repeat(width))
862
859
  );
@@ -871,7 +868,7 @@ function GridCell({
871
868
  align = "left"
872
869
  }) {
873
870
  return h4(
874
- Box4,
871
+ Box3,
875
872
  { width },
876
873
  h4(Text4, {
877
874
  color,
@@ -882,25 +879,24 @@ function GridCell({
882
879
  }, children)
883
880
  );
884
881
  }
885
- function InputField({ prompt, value, onChange, onSubmit }) {
882
+ function InputField({ prompt, value, onChange: _onChange, onSubmit: _onSubmit }) {
886
883
  return h4(
887
- Box4,
884
+ Box3,
888
885
  { flexDirection: "column" },
889
886
  h4(Text4, {}, prompt),
890
887
  h4(
891
- Box4,
888
+ Box3,
892
889
  { marginTop: 1 },
893
890
  h4(Text4, { color: "cyan" }, " > ", value, "_")
894
891
  )
895
892
  );
896
893
  }
897
894
  var init_ui_elements = __esm({
898
- "src/screen/ui-elements.ts"() {
899
- "use strict";
895
+ "src/screen/ui-elements.js"() {
900
896
  }
901
897
  });
902
898
 
903
- // src/screen/utils.ts
899
+ // src/screen/utils.js
904
900
  function buildBreadcrumb(parts) {
905
901
  if (parts.length === 0) return "";
906
902
  if (parts.length === 1) return parts[0];
@@ -914,12 +910,11 @@ function buildDetailBreadcrumb(path, suffix = "") {
914
910
  return suffix ? `${breadcrumb} ${suffix}` : breadcrumb;
915
911
  }
916
912
  var init_utils = __esm({
917
- "src/screen/utils.ts"() {
918
- "use strict";
913
+ "src/screen/utils.js"() {
919
914
  }
920
915
  });
921
916
 
922
- // src/screen/footer-builder.ts
917
+ // src/screen/footer-builder.js
923
918
  function buildFooter(config2 = {}) {
924
919
  const {
925
920
  navigation = null,
@@ -970,8 +965,7 @@ function organizeFooterMessages(messages) {
970
965
  }
971
966
  var FooterPresets;
972
967
  var init_footer_builder = __esm({
973
- "src/screen/footer-builder.ts"() {
974
- "use strict";
968
+ "src/screen/footer-builder.js"() {
975
969
  FooterPresets = {
976
970
  /**
977
971
  * Menu screen footer
@@ -1030,10 +1024,10 @@ var init_footer_builder = __esm({
1030
1024
  }
1031
1025
  });
1032
1026
 
1033
- // src/screen/index.ts
1027
+ // src/screen/index.js
1034
1028
  var screen_exports = {};
1035
1029
  __export(screen_exports, {
1036
- Box: () => Box5,
1030
+ Box: () => Box4,
1037
1031
  Divider: () => Divider,
1038
1032
  FooterPresets: () => FooterPresets,
1039
1033
  GridCell: () => GridCell,
@@ -1042,7 +1036,7 @@ __export(screen_exports, {
1042
1036
  ListItem: () => ListItem,
1043
1037
  MultiColumnListComponent: () => MultiColumnListComponent,
1044
1038
  MultiColumnListWithPreviewComponent: () => MultiColumnListWithPreviewComponent,
1045
- React: () => React5,
1039
+ React: () => React2,
1046
1040
  ScreenBody: () => ScreenBody,
1047
1041
  ScreenContainer: () => ScreenContainer,
1048
1042
  ScreenDivider: () => ScreenDivider,
@@ -1056,6 +1050,7 @@ __export(screen_exports, {
1056
1050
  buildFooter: () => buildFooter,
1057
1051
  h: () => createElement2,
1058
1052
  load: () => load,
1053
+ memo: () => memo,
1059
1054
  organizeFooterMessages: () => organizeFooterMessages,
1060
1055
  showListScreen: () => showListScreen,
1061
1056
  showMenuScreen: () => showMenuScreen,
@@ -1064,14 +1059,15 @@ __export(screen_exports, {
1064
1059
  showScreen: () => showScreen,
1065
1060
  showWordGridScreen: () => showWordGridScreen,
1066
1061
  useCallback: () => useCallback,
1067
- useEffect: () => useEffect3,
1062
+ useEffect: () => useEffect2,
1068
1063
  useInput: () => useInput2,
1064
+ useLayoutEffect: () => useLayoutEffect,
1069
1065
  useMemo: () => useMemo,
1070
- useRef: () => useRef3,
1066
+ useRef: () => useRef2,
1071
1067
  useState: () => useState3
1072
1068
  });
1073
- import React5, { useState as useState3, useEffect as useEffect3, useRef as useRef3, useMemo, useCallback, createElement as createElement2 } from "react";
1074
- import { Box as Box5, Text as Text5, useInput as useInput2 } from "ink";
1069
+ import React2, { useState as useState3, useEffect as useEffect2, useLayoutEffect, useRef as useRef2, useMemo, useCallback, memo, createElement as createElement2 } from "react";
1070
+ import { Box as Box4, Text as Text5, useInput as useInput2 } from "ink";
1075
1071
  async function load() {
1076
1072
  if (loadPromise) return loadPromise;
1077
1073
  loadPromise = Promise.all([
@@ -1083,8 +1079,7 @@ async function load() {
1083
1079
  }
1084
1080
  var loadPromise;
1085
1081
  var init_screen = __esm({
1086
- "src/screen/index.ts"() {
1087
- "use strict";
1082
+ "src/screen/index.js"() {
1088
1083
  init_screens();
1089
1084
  init_list_components();
1090
1085
  init_components();
@@ -1099,7 +1094,7 @@ var init_screen = __esm({
1099
1094
  }
1100
1095
  });
1101
1096
 
1102
- // src/args/index.ts
1097
+ // src/args/index.js
1103
1098
  import { readFileSync, existsSync } from "fs";
1104
1099
  import { resolve, dirname, basename, extname, join, isAbsolute } from "path";
1105
1100
  import { config } from "dotenv";
@@ -1582,10 +1577,10 @@ var Args = class _Args {
1582
1577
  }
1583
1578
  };
1584
1579
 
1585
- // src/params/index.ts
1580
+ // src/params/index.js
1586
1581
  import Joi from "joi";
1587
1582
 
1588
- // src/errors.ts
1583
+ // src/errors.js
1589
1584
  var FrameworkError = class extends Error {
1590
1585
  constructor(message) {
1591
1586
  super(message);
@@ -1605,7 +1600,7 @@ var InitError = class extends FrameworkError {
1605
1600
  }
1606
1601
  };
1607
1602
 
1608
- // src/params/custom-types.ts
1603
+ // src/params/custom-types.js
1609
1604
  var joiEdateType = (value, helpers) => {
1610
1605
  if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/.test(value)) {
1611
1606
  const testDate = new Date(value);
@@ -1698,7 +1693,7 @@ function calculateTimeOffset(amount, unit, sign) {
1698
1693
  }
1699
1694
  return sign === "+" ? amount * multiplier : -amount * multiplier;
1700
1695
  }
1701
- var joiStringArrayType = (type) => (value, helpers) => {
1696
+ var joiStringArrayType = (type) => (value, _helpers) => {
1702
1697
  if (value === void 0 || typeof value === "function") {
1703
1698
  return [];
1704
1699
  }
@@ -1724,7 +1719,7 @@ var joiStringArrayType = (type) => (value, helpers) => {
1724
1719
  return arr;
1725
1720
  };
1726
1721
 
1727
- // src/params/index.ts
1722
+ // src/params/index.js
1728
1723
  var Params = class _Params {
1729
1724
  context;
1730
1725
  // Partial context during initialization
@@ -1916,7 +1911,7 @@ var Params = class _Params {
1916
1911
  throw new ParamError(`default value "${defValObj.value}" type mismatch`);
1917
1912
  }
1918
1913
  type = type.default(defValObj.value);
1919
- } else if (str.match(/required/)) {
1914
+ } else if (str.match(/\s*required\s*/)) {
1920
1915
  type = type.required();
1921
1916
  } else {
1922
1917
  type = type.optional();
@@ -1984,7 +1979,7 @@ var Params = class _Params {
1984
1979
  definition = val;
1985
1980
  val = val.value;
1986
1981
  }
1987
- const def = this.assignDefinition(key, definition);
1982
+ this.assignDefinition(key, definition);
1988
1983
  if (!this.runAllRegisteredSetters(key, val)) {
1989
1984
  this.params[key] = val;
1990
1985
  }
@@ -1992,6 +1987,8 @@ var Params = class _Params {
1992
1987
  /**
1993
1988
  * Get all parameters from definitions (main script).
1994
1989
  * Same as getAllForModule("script", defs). Processes left-to-right for cross-parameter references.
1990
+ * Libraries should use {@link getAllForModule} with an explicit module name (or {@link runWithModule}
1991
+ * around {@link get}) so --showUsedParams groups usage correctly.
1995
1992
  */
1996
1993
  getAll(defs) {
1997
1994
  return this.getAllForModule("script", defs);
@@ -2028,6 +2025,19 @@ var Params = class _Params {
2028
2025
  this._currentModule = prev;
2029
2026
  }
2030
2027
  }
2028
+ /**
2029
+ * Run a callback with {@link _currentModule} set so single {@link get} calls are tracked
2030
+ * under the same module (for --showUsedParams / getFiguredByModule).
2031
+ */
2032
+ runWithModule(moduleName, fn) {
2033
+ const prev = this._currentModule;
2034
+ this._currentModule = moduleName;
2035
+ try {
2036
+ return fn();
2037
+ } finally {
2038
+ this._currentModule = prev;
2039
+ }
2040
+ }
2031
2041
  /**
2032
2042
  * Infer module name from call stack: first caller outside params/index gives path like .../src/<moduleName>/...
2033
2043
  */
@@ -2088,11 +2098,11 @@ var Params = class _Params {
2088
2098
  }
2089
2099
  };
2090
2100
 
2091
- // src/logger/index.ts
2101
+ // src/logger/index.js
2092
2102
  import chalk from "chalk";
2093
2103
  import util from "util";
2094
2104
 
2095
- // src/logger/transports.ts
2105
+ // src/logger/transports.js
2096
2106
  var ConsoleTransport = class {
2097
2107
  write(payload) {
2098
2108
  console.info(payload);
@@ -2112,7 +2122,7 @@ var ParentProcessTransport = class {
2112
2122
  }
2113
2123
  };
2114
2124
 
2115
- // src/logger/index.ts
2125
+ // src/logger/index.js
2116
2126
  var ALL_LEVELS = [
2117
2127
  "silly",
2118
2128
  "debug",
@@ -2185,6 +2195,7 @@ var Logger = class _Logger {
2185
2195
  }
2186
2196
  /**
2187
2197
  * Initialize logger from context and CLI parameters. Whatever is in options goes (after discovered params).
2198
+ * Params are tracked under the `logger` module for --showUsedParams.
2188
2199
  */
2189
2200
  static init(context, options) {
2190
2201
  const paramDefs = {
@@ -2198,7 +2209,7 @@ var Logger = class _Logger {
2198
2209
  progressWithTimes: "boolean default false",
2199
2210
  progressThrottleMs: "number"
2200
2211
  };
2201
- const discovered = context.params.getAllForModule(paramDefs);
2212
+ const discovered = context.params.getAllForModule("logger", paramDefs);
2202
2213
  const config2 = { ...discovered, ...options };
2203
2214
  const logger = new _Logger(context, config2);
2204
2215
  context.logger = logger;
@@ -2394,9 +2405,9 @@ var Logger = class _Logger {
2394
2405
  }
2395
2406
  };
2396
2407
 
2397
- // src/init/index.ts
2408
+ // src/init/index.js
2398
2409
  import { EventEmitter } from "events";
2399
- function extractComponentOptions(opts, componentName) {
2410
+ function extractComponentOptions(opts, _componentName) {
2400
2411
  const reservedKeys = ["overrides", "defaults", "modules"];
2401
2412
  const componentOptions = {};
2402
2413
  for (const [key, value] of Object.entries(opts)) {
@@ -2463,6 +2474,19 @@ function printAllParameters(context) {
2463
2474
  async function init(flow, opts = {}) {
2464
2475
  let stop = false;
2465
2476
  let context = null;
2477
+ let cleanupRan = false;
2478
+ const runRegisteredCleanups = async (ctx) => {
2479
+ if (cleanupRan) return;
2480
+ cleanupRan = true;
2481
+ const fns = [...ctx.cleanupFunctions].reverse();
2482
+ for (const fn of fns) {
2483
+ try {
2484
+ await fn(ctx);
2485
+ } catch (error) {
2486
+ ctx.logger.warn("[cleanup] error in cleanup function:", error);
2487
+ }
2488
+ }
2489
+ };
2466
2490
  try {
2467
2491
  try {
2468
2492
  const screenModule = await Promise.resolve().then(() => (init_screen(), screen_exports));
@@ -2485,13 +2509,24 @@ async function init(flow, opts = {}) {
2485
2509
  printAllParameters(context);
2486
2510
  process.exit(0);
2487
2511
  }
2512
+ let sigintCount = 0;
2488
2513
  process.on("SIGINT", async () => {
2489
- if (stop) {
2490
- context.logger.warn("[process] killed");
2491
- process.exit(2);
2514
+ if (!context) return;
2515
+ sigintCount += 1;
2516
+ if (sigintCount === 1) {
2517
+ stop = true;
2518
+ context.logger.info(`>> emitting stop with allowance ${stopAllowance}`);
2519
+ context.emitter.emit("stop", stopAllowance);
2520
+ return;
2492
2521
  }
2522
+ context.logger.warn("[process] second SIGINT: running cleanup then exit");
2523
+ await runRegisteredCleanups(context);
2524
+ process.exit(2);
2525
+ });
2526
+ process.on("SIGTERM", () => {
2527
+ if (!context || stop) return;
2493
2528
  stop = true;
2494
- context.logger.info(`>> emitting stop with allowance ${stopAllowance}`);
2529
+ context.logger.info(`>> SIGTERM: emitting stop with allowance ${stopAllowance}`);
2495
2530
  context.emitter.emit("stop", stopAllowance);
2496
2531
  });
2497
2532
  await flow(context);
@@ -2516,13 +2551,7 @@ async function init(flow, opts = {}) {
2516
2551
  }
2517
2552
  } finally {
2518
2553
  if (context) {
2519
- for (const fn of context.cleanupFunctions.reverse()) {
2520
- try {
2521
- await fn(context);
2522
- } catch (error) {
2523
- context.logger.warn("[cleanup] error in cleanup function:", error);
2524
- }
2525
- }
2554
+ await runRegisteredCleanups(context);
2526
2555
  }
2527
2556
  }
2528
2557
  }