@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.cjs CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -30,7 +29,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
29
  ));
31
30
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
31
 
33
- // src/screen/components.ts
32
+ // src/screen/components.js
34
33
  function getScreenWidth(maxWidth = null) {
35
34
  const terminalWidth = process.stdout.columns || 80;
36
35
  const availableWidth = Math.max(20, terminalWidth - 4);
@@ -104,14 +103,13 @@ function ScreenFooter({ lines, textStyle }) {
104
103
  }
105
104
  var import_react, import_ink;
106
105
  var init_components = __esm({
107
- "src/screen/components.ts"() {
108
- "use strict";
106
+ "src/screen/components.js"() {
109
107
  import_react = require("react");
110
108
  import_ink = require("ink");
111
109
  }
112
110
  });
113
111
 
114
- // src/screen/list-components.ts
112
+ // src/screen/list-components.js
115
113
  function MultiColumnListComponent({ items, ctx, selectedIndexRef }) {
116
114
  const [, forceUpdate] = (0, import_react2.useState)({});
117
115
  const termWidth = (process.stdout.columns || 80) - 8;
@@ -263,11 +261,13 @@ function MultiColumnListWithPreviewComponent({
263
261
  ...previewRows
264
262
  );
265
263
  }
266
- function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sortable = false, maxHeight, sortHighlightStyle, selectionMarker = " " }) {
264
+ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sortable = false, maxHeight, sortHighlightStyle, selectionMarker = " ", onSelectionChange }) {
267
265
  const [, forceUpdate] = (0, import_react2.useState)({});
268
266
  const [sortOrder, setSortOrder] = (0, import_react2.useState)("none");
269
267
  const [scrollOffset, setScrollOffset] = (0, import_react2.useState)(0);
270
268
  const scrollStateRef = (0, import_react2.useRef)({ scrollOffset: 0, maxHeight: 0, totalItems: 0 });
269
+ const itemsRef = (0, import_react2.useRef)(items);
270
+ itemsRef.current = items;
271
271
  const defaultGetTitle = (item) => {
272
272
  return getTitle ? getTitle(item) : typeof item.value === "string" ? item.value : item.value?.title || item.name;
273
273
  };
@@ -281,18 +281,24 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
281
281
  return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;
282
282
  }
283
283
  }) : items;
284
+ const displayItemsRef = (0, import_react2.useRef)(displayItems);
285
+ displayItemsRef.current = displayItems;
284
286
  const effectiveMaxHeight = maxHeight || displayItems.length;
285
- const canScroll = displayItems.length > effectiveMaxHeight;
287
+ const _canScroll = displayItems.length > effectiveMaxHeight;
286
288
  const maxScrollOffset = Math.max(0, displayItems.length - effectiveMaxHeight);
287
289
  const clampedScrollOffset = Math.min(Math.max(0, scrollOffset), maxScrollOffset);
288
290
  const visibleItems = displayItems.slice(clampedScrollOffset, clampedScrollOffset + effectiveMaxHeight);
289
291
  const canScrollUp = clampedScrollOffset > 0;
290
292
  const canScrollDown = clampedScrollOffset < maxScrollOffset;
291
293
  scrollStateRef.current = { scrollOffset, maxHeight: effectiveMaxHeight, totalItems: displayItems.length };
294
+ const onSelectionChangeRef = (0, import_react2.useRef)(onSelectionChange);
295
+ onSelectionChangeRef.current = onSelectionChange;
292
296
  (0, import_react2.useEffect)(() => {
293
297
  ctx.setAction("moveUp", () => {
294
298
  const newIndex = Math.max(0, selectedIndexRef.current - 1);
295
299
  selectedIndexRef.current = newIndex;
300
+ const list = displayItemsRef.current;
301
+ onSelectionChangeRef.current?.(newIndex, list[newIndex]);
296
302
  const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;
297
303
  const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);
298
304
  const currentClampedScrollOffset = Math.min(Math.max(0, currentScrollOffset), currentMaxScrollOffset);
@@ -302,18 +308,11 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
302
308
  forceUpdate({});
303
309
  });
304
310
  ctx.setAction("moveDown", () => {
305
- const currentItems = sortable && sortOrder !== "none" ? [...items].sort((a, b) => {
306
- const titleA = titleGetter(a).toLowerCase();
307
- const titleB = titleGetter(b).toLowerCase();
308
- if (sortOrder === "asc") {
309
- return titleA < titleB ? -1 : titleA > titleB ? 1 : 0;
310
- } else {
311
- return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;
312
- }
313
- }) : items;
314
- const maxIndex = currentItems.length - 1;
311
+ const currentItems = displayItemsRef.current;
312
+ const maxIndex = Math.max(0, currentItems.length - 1);
315
313
  const newIndex = Math.min(maxIndex, selectedIndexRef.current + 1);
316
314
  selectedIndexRef.current = newIndex;
315
+ onSelectionChangeRef.current?.(newIndex, currentItems[newIndex]);
317
316
  const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;
318
317
  const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);
319
318
  const currentClampedScrollOffset = Math.min(Math.max(0, currentScrollOffset), currentMaxScrollOffset);
@@ -323,8 +322,7 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
323
322
  forceUpdate({});
324
323
  });
325
324
  ctx.setAction("scrollUp", () => {
326
- const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;
327
- const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);
325
+ const { scrollOffset: currentScrollOffset } = scrollStateRef.current;
328
326
  const newScrollOffset = Math.max(0, currentScrollOffset - 1);
329
327
  setScrollOffset(newScrollOffset);
330
328
  forceUpdate({});
@@ -339,9 +337,9 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
339
337
  if (sortable) {
340
338
  ctx.setAction("toggleSort", () => {
341
339
  const nextSort = sortOrder === "none" ? "asc" : sortOrder === "asc" ? "desc" : "none";
342
- const currentSelectedItem = displayItems[selectedIndexRef.current];
340
+ const currentSelectedItem = displayItemsRef.current[selectedIndexRef.current];
343
341
  setSortOrder(nextSort);
344
- const newSortedItems = nextSort !== "none" ? [...items].sort((a, b) => {
342
+ const newSortedItems = nextSort !== "none" ? [...itemsRef.current].sort((a, b) => {
345
343
  const titleA = titleGetter(a).toLowerCase();
346
344
  const titleB = titleGetter(b).toLowerCase();
347
345
  if (nextSort === "asc") {
@@ -349,7 +347,7 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
349
347
  } else {
350
348
  return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;
351
349
  }
352
- }) : items;
350
+ }) : itemsRef.current;
353
351
  const newIndex = newSortedItems.findIndex((item) => item === currentSelectedItem);
354
352
  if (newIndex !== -1) {
355
353
  selectedIndexRef.current = newIndex;
@@ -487,8 +485,7 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
487
485
  }
488
486
  var import_react2, import_ink2, h2;
489
487
  var init_list_components = __esm({
490
- "src/screen/list-components.ts"() {
491
- "use strict";
488
+ "src/screen/list-components.js"() {
492
489
  import_react2 = __toESM(require("react"), 1);
493
490
  import_ink2 = require("ink");
494
491
  init_components();
@@ -496,7 +493,7 @@ var init_list_components = __esm({
496
493
  }
497
494
  });
498
495
 
499
- // src/screen/screens.ts
496
+ // src/screen/screens.js
500
497
  function groupKeyBindings(bindings) {
501
498
  const groups = {};
502
499
  const enabledBindings = bindings.filter((b) => b.enabled !== false);
@@ -572,7 +569,7 @@ async function showScreen(config2) {
572
569
  let renderResult = null;
573
570
  let initialized = false;
574
571
  const Screen = () => {
575
- const [updateCounter, setUpdateCounter] = (0, import_react3.useState)(0);
572
+ const [, setUpdateCounter] = (0, import_react3.useState)(0);
576
573
  if (!initialized) {
577
574
  const defaultBindings = [
578
575
  { key: "escape", caption: "go back", action: "back", protected: true, order: 1 },
@@ -691,7 +688,7 @@ async function showScreen(config2) {
691
688
  }
692
689
  }
693
690
  if (matchedBinding && actions[matchedBinding.action]) {
694
- const actionResult = actions[matchedBinding.action]({
691
+ actions[matchedBinding.action]({
695
692
  input,
696
693
  key,
697
694
  binding: matchedBinding
@@ -821,8 +818,7 @@ async function showMultiColumnListWithPreviewScreen(config2) {
821
818
  }
822
819
  var import_react3, import_ink3, showMenuScreen, showWordGridScreen;
823
820
  var init_screens = __esm({
824
- "src/screen/screens.ts"() {
825
- "use strict";
821
+ "src/screen/screens.js"() {
826
822
  import_react3 = require("react");
827
823
  import_ink3 = require("ink");
828
824
  init_components();
@@ -832,7 +828,7 @@ var init_screens = __esm({
832
828
  }
833
829
  });
834
830
 
835
- // src/screen/ui-elements.ts
831
+ // src/screen/ui-elements.js
836
832
  function ListItem({
837
833
  children,
838
834
  isSelected = false,
@@ -857,7 +853,7 @@ function TextBlock({
857
853
  color = "white",
858
854
  dimmed = false,
859
855
  bold = false,
860
- maxWidth
856
+ maxWidth: _maxWidth
861
857
  }) {
862
858
  return (0, import_react4.createElement)(
863
859
  import_ink4.Box,
@@ -897,7 +893,7 @@ function GridCell({
897
893
  }, children)
898
894
  );
899
895
  }
900
- function InputField({ prompt, value, onChange, onSubmit }) {
896
+ function InputField({ prompt, value, onChange: _onChange, onSubmit: _onSubmit }) {
901
897
  return (0, import_react4.createElement)(
902
898
  import_ink4.Box,
903
899
  { flexDirection: "column" },
@@ -911,14 +907,13 @@ function InputField({ prompt, value, onChange, onSubmit }) {
911
907
  }
912
908
  var import_react4, import_ink4;
913
909
  var init_ui_elements = __esm({
914
- "src/screen/ui-elements.ts"() {
915
- "use strict";
910
+ "src/screen/ui-elements.js"() {
916
911
  import_react4 = require("react");
917
912
  import_ink4 = require("ink");
918
913
  }
919
914
  });
920
915
 
921
- // src/screen/utils.ts
916
+ // src/screen/utils.js
922
917
  function buildBreadcrumb(parts) {
923
918
  if (parts.length === 0) return "";
924
919
  if (parts.length === 1) return parts[0];
@@ -932,12 +927,11 @@ function buildDetailBreadcrumb(path, suffix = "") {
932
927
  return suffix ? `${breadcrumb} ${suffix}` : breadcrumb;
933
928
  }
934
929
  var init_utils = __esm({
935
- "src/screen/utils.ts"() {
936
- "use strict";
930
+ "src/screen/utils.js"() {
937
931
  }
938
932
  });
939
933
 
940
- // src/screen/footer-builder.ts
934
+ // src/screen/footer-builder.js
941
935
  function buildFooter(config2 = {}) {
942
936
  const {
943
937
  navigation = null,
@@ -988,8 +982,7 @@ function organizeFooterMessages(messages) {
988
982
  }
989
983
  var FooterPresets;
990
984
  var init_footer_builder = __esm({
991
- "src/screen/footer-builder.ts"() {
992
- "use strict";
985
+ "src/screen/footer-builder.js"() {
993
986
  FooterPresets = {
994
987
  /**
995
988
  * Menu screen footer
@@ -1048,7 +1041,7 @@ var init_footer_builder = __esm({
1048
1041
  }
1049
1042
  });
1050
1043
 
1051
- // src/screen/index.ts
1044
+ // src/screen/index.js
1052
1045
  var screen_exports = {};
1053
1046
  __export(screen_exports, {
1054
1047
  Box: () => import_ink5.Box,
@@ -1074,6 +1067,7 @@ __export(screen_exports, {
1074
1067
  buildFooter: () => buildFooter,
1075
1068
  h: () => import_react5.createElement,
1076
1069
  load: () => load,
1070
+ memo: () => import_react5.memo,
1077
1071
  organizeFooterMessages: () => organizeFooterMessages,
1078
1072
  showListScreen: () => showListScreen,
1079
1073
  showMenuScreen: () => showMenuScreen,
@@ -1084,6 +1078,7 @@ __export(screen_exports, {
1084
1078
  useCallback: () => import_react5.useCallback,
1085
1079
  useEffect: () => import_react5.useEffect,
1086
1080
  useInput: () => import_ink5.useInput,
1081
+ useLayoutEffect: () => import_react5.useLayoutEffect,
1087
1082
  useMemo: () => import_react5.useMemo,
1088
1083
  useRef: () => import_react5.useRef,
1089
1084
  useState: () => import_react5.useState
@@ -1099,8 +1094,7 @@ async function load() {
1099
1094
  }
1100
1095
  var import_react5, import_ink5, loadPromise;
1101
1096
  var init_screen = __esm({
1102
- "src/screen/index.ts"() {
1103
- "use strict";
1097
+ "src/screen/index.js"() {
1104
1098
  import_react5 = __toESM(require("react"), 1);
1105
1099
  import_ink5 = require("ink");
1106
1100
  init_screens();
@@ -1117,7 +1111,7 @@ var init_screen = __esm({
1117
1111
  }
1118
1112
  });
1119
1113
 
1120
- // src/init.ts
1114
+ // src/init/index.js
1121
1115
  var init_exports = {};
1122
1116
  __export(init_exports, {
1123
1117
  init: () => init,
@@ -1125,7 +1119,7 @@ __export(init_exports, {
1125
1119
  });
1126
1120
  module.exports = __toCommonJS(init_exports);
1127
1121
 
1128
- // src/args/index.ts
1122
+ // src/args/index.js
1129
1123
  var import_fs = require("fs");
1130
1124
  var import_path = require("path");
1131
1125
  var import_dotenv = require("dotenv");
@@ -1608,10 +1602,10 @@ var Args = class _Args {
1608
1602
  }
1609
1603
  };
1610
1604
 
1611
- // src/params/index.ts
1605
+ // src/params/index.js
1612
1606
  var import_joi = __toESM(require("joi"), 1);
1613
1607
 
1614
- // src/errors.ts
1608
+ // src/errors.js
1615
1609
  var FrameworkError = class extends Error {
1616
1610
  constructor(message) {
1617
1611
  super(message);
@@ -1631,7 +1625,7 @@ var InitError = class extends FrameworkError {
1631
1625
  }
1632
1626
  };
1633
1627
 
1634
- // src/params/custom-types.ts
1628
+ // src/params/custom-types.js
1635
1629
  var joiEdateType = (value, helpers) => {
1636
1630
  if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/.test(value)) {
1637
1631
  const testDate = new Date(value);
@@ -1724,7 +1718,7 @@ function calculateTimeOffset(amount, unit, sign) {
1724
1718
  }
1725
1719
  return sign === "+" ? amount * multiplier : -amount * multiplier;
1726
1720
  }
1727
- var joiStringArrayType = (type) => (value, helpers) => {
1721
+ var joiStringArrayType = (type) => (value, _helpers) => {
1728
1722
  if (value === void 0 || typeof value === "function") {
1729
1723
  return [];
1730
1724
  }
@@ -1750,7 +1744,7 @@ var joiStringArrayType = (type) => (value, helpers) => {
1750
1744
  return arr;
1751
1745
  };
1752
1746
 
1753
- // src/params/index.ts
1747
+ // src/params/index.js
1754
1748
  var Params = class _Params {
1755
1749
  context;
1756
1750
  // Partial context during initialization
@@ -1942,7 +1936,7 @@ var Params = class _Params {
1942
1936
  throw new ParamError(`default value "${defValObj.value}" type mismatch`);
1943
1937
  }
1944
1938
  type = type.default(defValObj.value);
1945
- } else if (str.match(/required/)) {
1939
+ } else if (str.match(/\s*required\s*/)) {
1946
1940
  type = type.required();
1947
1941
  } else {
1948
1942
  type = type.optional();
@@ -2010,7 +2004,7 @@ var Params = class _Params {
2010
2004
  definition = val;
2011
2005
  val = val.value;
2012
2006
  }
2013
- const def = this.assignDefinition(key, definition);
2007
+ this.assignDefinition(key, definition);
2014
2008
  if (!this.runAllRegisteredSetters(key, val)) {
2015
2009
  this.params[key] = val;
2016
2010
  }
@@ -2018,6 +2012,8 @@ var Params = class _Params {
2018
2012
  /**
2019
2013
  * Get all parameters from definitions (main script).
2020
2014
  * Same as getAllForModule("script", defs). Processes left-to-right for cross-parameter references.
2015
+ * Libraries should use {@link getAllForModule} with an explicit module name (or {@link runWithModule}
2016
+ * around {@link get}) so --showUsedParams groups usage correctly.
2021
2017
  */
2022
2018
  getAll(defs) {
2023
2019
  return this.getAllForModule("script", defs);
@@ -2054,6 +2050,19 @@ var Params = class _Params {
2054
2050
  this._currentModule = prev;
2055
2051
  }
2056
2052
  }
2053
+ /**
2054
+ * Run a callback with {@link _currentModule} set so single {@link get} calls are tracked
2055
+ * under the same module (for --showUsedParams / getFiguredByModule).
2056
+ */
2057
+ runWithModule(moduleName, fn) {
2058
+ const prev = this._currentModule;
2059
+ this._currentModule = moduleName;
2060
+ try {
2061
+ return fn();
2062
+ } finally {
2063
+ this._currentModule = prev;
2064
+ }
2065
+ }
2057
2066
  /**
2058
2067
  * Infer module name from call stack: first caller outside params/index gives path like .../src/<moduleName>/...
2059
2068
  */
@@ -2114,11 +2123,11 @@ var Params = class _Params {
2114
2123
  }
2115
2124
  };
2116
2125
 
2117
- // src/logger/index.ts
2126
+ // src/logger/index.js
2118
2127
  var import_chalk = __toESM(require("chalk"), 1);
2119
2128
  var import_util = __toESM(require("util"), 1);
2120
2129
 
2121
- // src/logger/transports.ts
2130
+ // src/logger/transports.js
2122
2131
  var ConsoleTransport = class {
2123
2132
  write(payload) {
2124
2133
  console.info(payload);
@@ -2138,7 +2147,7 @@ var ParentProcessTransport = class {
2138
2147
  }
2139
2148
  };
2140
2149
 
2141
- // src/logger/index.ts
2150
+ // src/logger/index.js
2142
2151
  var ALL_LEVELS = [
2143
2152
  "silly",
2144
2153
  "debug",
@@ -2211,6 +2220,7 @@ var Logger = class _Logger {
2211
2220
  }
2212
2221
  /**
2213
2222
  * Initialize logger from context and CLI parameters. Whatever is in options goes (after discovered params).
2223
+ * Params are tracked under the `logger` module for --showUsedParams.
2214
2224
  */
2215
2225
  static init(context, options) {
2216
2226
  const paramDefs = {
@@ -2224,7 +2234,7 @@ var Logger = class _Logger {
2224
2234
  progressWithTimes: "boolean default false",
2225
2235
  progressThrottleMs: "number"
2226
2236
  };
2227
- const discovered = context.params.getAllForModule(paramDefs);
2237
+ const discovered = context.params.getAllForModule("logger", paramDefs);
2228
2238
  const config2 = { ...discovered, ...options };
2229
2239
  const logger = new _Logger(context, config2);
2230
2240
  context.logger = logger;
@@ -2420,9 +2430,9 @@ var Logger = class _Logger {
2420
2430
  }
2421
2431
  };
2422
2432
 
2423
- // src/init/index.ts
2433
+ // src/init/index.js
2424
2434
  var import_events = require("events");
2425
- function extractComponentOptions(opts, componentName) {
2435
+ function extractComponentOptions(opts, _componentName) {
2426
2436
  const reservedKeys = ["overrides", "defaults", "modules"];
2427
2437
  const componentOptions = {};
2428
2438
  for (const [key, value] of Object.entries(opts)) {
@@ -2489,6 +2499,19 @@ function printAllParameters(context) {
2489
2499
  async function init(flow, opts = {}) {
2490
2500
  let stop = false;
2491
2501
  let context = null;
2502
+ let cleanupRan = false;
2503
+ const runRegisteredCleanups = async (ctx) => {
2504
+ if (cleanupRan) return;
2505
+ cleanupRan = true;
2506
+ const fns = [...ctx.cleanupFunctions].reverse();
2507
+ for (const fn of fns) {
2508
+ try {
2509
+ await fn(ctx);
2510
+ } catch (error) {
2511
+ ctx.logger.warn("[cleanup] error in cleanup function:", error);
2512
+ }
2513
+ }
2514
+ };
2492
2515
  try {
2493
2516
  try {
2494
2517
  const screenModule = await Promise.resolve().then(() => (init_screen(), screen_exports));
@@ -2511,13 +2534,24 @@ async function init(flow, opts = {}) {
2511
2534
  printAllParameters(context);
2512
2535
  process.exit(0);
2513
2536
  }
2537
+ let sigintCount = 0;
2514
2538
  process.on("SIGINT", async () => {
2515
- if (stop) {
2516
- context.logger.warn("[process] killed");
2517
- process.exit(2);
2539
+ if (!context) return;
2540
+ sigintCount += 1;
2541
+ if (sigintCount === 1) {
2542
+ stop = true;
2543
+ context.logger.info(`>> emitting stop with allowance ${stopAllowance}`);
2544
+ context.emitter.emit("stop", stopAllowance);
2545
+ return;
2518
2546
  }
2547
+ context.logger.warn("[process] second SIGINT: running cleanup then exit");
2548
+ await runRegisteredCleanups(context);
2549
+ process.exit(2);
2550
+ });
2551
+ process.on("SIGTERM", () => {
2552
+ if (!context || stop) return;
2519
2553
  stop = true;
2520
- context.logger.info(`>> emitting stop with allowance ${stopAllowance}`);
2554
+ context.logger.info(`>> SIGTERM: emitting stop with allowance ${stopAllowance}`);
2521
2555
  context.emitter.emit("stop", stopAllowance);
2522
2556
  });
2523
2557
  await flow(context);
@@ -2542,13 +2576,7 @@ async function init(flow, opts = {}) {
2542
2576
  }
2543
2577
  } finally {
2544
2578
  if (context) {
2545
- for (const fn of context.cleanupFunctions.reverse()) {
2546
- try {
2547
- await fn(context);
2548
- } catch (error) {
2549
- context.logger.warn("[cleanup] error in cleanup function:", error);
2550
- }
2551
- }
2579
+ await runRegisteredCleanups(context);
2552
2580
  }
2553
2581
  }
2554
2582
  }