crisis-to-calm 1.0.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.
- package/calm.exe +0 -0
- package/calm.zip +0 -0
- package/dist/bundle.cjs +881 -0
- package/index.js +444 -0
- package/launcher.cjs +4 -0
- package/package.json +23 -0
- package/stats.json +7 -0
package/calm.exe
ADDED
|
Binary file
|
package/calm.zip
ADDED
|
Binary file
|
package/dist/bundle.cjs
ADDED
|
@@ -0,0 +1,881 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
|
|
25
|
+
// index.js
|
|
26
|
+
var import_os = __toESM(require("os"), 1);
|
|
27
|
+
|
|
28
|
+
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
29
|
+
var ANSI_BACKGROUND_OFFSET = 10;
|
|
30
|
+
var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
|
|
31
|
+
var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
|
|
32
|
+
var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
|
|
33
|
+
var styles = {
|
|
34
|
+
modifier: {
|
|
35
|
+
reset: [0, 0],
|
|
36
|
+
// 21 isn't widely supported and 22 does the same thing
|
|
37
|
+
bold: [1, 22],
|
|
38
|
+
dim: [2, 22],
|
|
39
|
+
italic: [3, 23],
|
|
40
|
+
underline: [4, 24],
|
|
41
|
+
overline: [53, 55],
|
|
42
|
+
inverse: [7, 27],
|
|
43
|
+
hidden: [8, 28],
|
|
44
|
+
strikethrough: [9, 29]
|
|
45
|
+
},
|
|
46
|
+
color: {
|
|
47
|
+
black: [30, 39],
|
|
48
|
+
red: [31, 39],
|
|
49
|
+
green: [32, 39],
|
|
50
|
+
yellow: [33, 39],
|
|
51
|
+
blue: [34, 39],
|
|
52
|
+
magenta: [35, 39],
|
|
53
|
+
cyan: [36, 39],
|
|
54
|
+
white: [37, 39],
|
|
55
|
+
// Bright color
|
|
56
|
+
blackBright: [90, 39],
|
|
57
|
+
gray: [90, 39],
|
|
58
|
+
// Alias of `blackBright`
|
|
59
|
+
grey: [90, 39],
|
|
60
|
+
// Alias of `blackBright`
|
|
61
|
+
redBright: [91, 39],
|
|
62
|
+
greenBright: [92, 39],
|
|
63
|
+
yellowBright: [93, 39],
|
|
64
|
+
blueBright: [94, 39],
|
|
65
|
+
magentaBright: [95, 39],
|
|
66
|
+
cyanBright: [96, 39],
|
|
67
|
+
whiteBright: [97, 39]
|
|
68
|
+
},
|
|
69
|
+
bgColor: {
|
|
70
|
+
bgBlack: [40, 49],
|
|
71
|
+
bgRed: [41, 49],
|
|
72
|
+
bgGreen: [42, 49],
|
|
73
|
+
bgYellow: [43, 49],
|
|
74
|
+
bgBlue: [44, 49],
|
|
75
|
+
bgMagenta: [45, 49],
|
|
76
|
+
bgCyan: [46, 49],
|
|
77
|
+
bgWhite: [47, 49],
|
|
78
|
+
// Bright color
|
|
79
|
+
bgBlackBright: [100, 49],
|
|
80
|
+
bgGray: [100, 49],
|
|
81
|
+
// Alias of `bgBlackBright`
|
|
82
|
+
bgGrey: [100, 49],
|
|
83
|
+
// Alias of `bgBlackBright`
|
|
84
|
+
bgRedBright: [101, 49],
|
|
85
|
+
bgGreenBright: [102, 49],
|
|
86
|
+
bgYellowBright: [103, 49],
|
|
87
|
+
bgBlueBright: [104, 49],
|
|
88
|
+
bgMagentaBright: [105, 49],
|
|
89
|
+
bgCyanBright: [106, 49],
|
|
90
|
+
bgWhiteBright: [107, 49]
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
var modifierNames = Object.keys(styles.modifier);
|
|
94
|
+
var foregroundColorNames = Object.keys(styles.color);
|
|
95
|
+
var backgroundColorNames = Object.keys(styles.bgColor);
|
|
96
|
+
var colorNames = [...foregroundColorNames, ...backgroundColorNames];
|
|
97
|
+
function assembleStyles() {
|
|
98
|
+
const codes = /* @__PURE__ */ new Map();
|
|
99
|
+
for (const [groupName, group] of Object.entries(styles)) {
|
|
100
|
+
for (const [styleName, style] of Object.entries(group)) {
|
|
101
|
+
styles[styleName] = {
|
|
102
|
+
open: `\x1B[${style[0]}m`,
|
|
103
|
+
close: `\x1B[${style[1]}m`
|
|
104
|
+
};
|
|
105
|
+
group[styleName] = styles[styleName];
|
|
106
|
+
codes.set(style[0], style[1]);
|
|
107
|
+
}
|
|
108
|
+
Object.defineProperty(styles, groupName, {
|
|
109
|
+
value: group,
|
|
110
|
+
enumerable: false
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
Object.defineProperty(styles, "codes", {
|
|
114
|
+
value: codes,
|
|
115
|
+
enumerable: false
|
|
116
|
+
});
|
|
117
|
+
styles.color.close = "\x1B[39m";
|
|
118
|
+
styles.bgColor.close = "\x1B[49m";
|
|
119
|
+
styles.color.ansi = wrapAnsi16();
|
|
120
|
+
styles.color.ansi256 = wrapAnsi256();
|
|
121
|
+
styles.color.ansi16m = wrapAnsi16m();
|
|
122
|
+
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
123
|
+
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
124
|
+
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
125
|
+
Object.defineProperties(styles, {
|
|
126
|
+
rgbToAnsi256: {
|
|
127
|
+
value(red, green, blue) {
|
|
128
|
+
if (red === green && green === blue) {
|
|
129
|
+
if (red < 8) {
|
|
130
|
+
return 16;
|
|
131
|
+
}
|
|
132
|
+
if (red > 248) {
|
|
133
|
+
return 231;
|
|
134
|
+
}
|
|
135
|
+
return Math.round((red - 8) / 247 * 24) + 232;
|
|
136
|
+
}
|
|
137
|
+
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
|
|
138
|
+
},
|
|
139
|
+
enumerable: false
|
|
140
|
+
},
|
|
141
|
+
hexToRgb: {
|
|
142
|
+
value(hex) {
|
|
143
|
+
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
144
|
+
if (!matches) {
|
|
145
|
+
return [0, 0, 0];
|
|
146
|
+
}
|
|
147
|
+
let [colorString] = matches;
|
|
148
|
+
if (colorString.length === 3) {
|
|
149
|
+
colorString = [...colorString].map((character) => character + character).join("");
|
|
150
|
+
}
|
|
151
|
+
const integer = Number.parseInt(colorString, 16);
|
|
152
|
+
return [
|
|
153
|
+
/* eslint-disable no-bitwise */
|
|
154
|
+
integer >> 16 & 255,
|
|
155
|
+
integer >> 8 & 255,
|
|
156
|
+
integer & 255
|
|
157
|
+
/* eslint-enable no-bitwise */
|
|
158
|
+
];
|
|
159
|
+
},
|
|
160
|
+
enumerable: false
|
|
161
|
+
},
|
|
162
|
+
hexToAnsi256: {
|
|
163
|
+
value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
|
|
164
|
+
enumerable: false
|
|
165
|
+
},
|
|
166
|
+
ansi256ToAnsi: {
|
|
167
|
+
value(code) {
|
|
168
|
+
if (code < 8) {
|
|
169
|
+
return 30 + code;
|
|
170
|
+
}
|
|
171
|
+
if (code < 16) {
|
|
172
|
+
return 90 + (code - 8);
|
|
173
|
+
}
|
|
174
|
+
let red;
|
|
175
|
+
let green;
|
|
176
|
+
let blue;
|
|
177
|
+
if (code >= 232) {
|
|
178
|
+
red = ((code - 232) * 10 + 8) / 255;
|
|
179
|
+
green = red;
|
|
180
|
+
blue = red;
|
|
181
|
+
} else {
|
|
182
|
+
code -= 16;
|
|
183
|
+
const remainder = code % 36;
|
|
184
|
+
red = Math.floor(code / 36) / 5;
|
|
185
|
+
green = Math.floor(remainder / 6) / 5;
|
|
186
|
+
blue = remainder % 6 / 5;
|
|
187
|
+
}
|
|
188
|
+
const value = Math.max(red, green, blue) * 2;
|
|
189
|
+
if (value === 0) {
|
|
190
|
+
return 30;
|
|
191
|
+
}
|
|
192
|
+
let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
|
|
193
|
+
if (value === 2) {
|
|
194
|
+
result += 60;
|
|
195
|
+
}
|
|
196
|
+
return result;
|
|
197
|
+
},
|
|
198
|
+
enumerable: false
|
|
199
|
+
},
|
|
200
|
+
rgbToAnsi: {
|
|
201
|
+
value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
|
|
202
|
+
enumerable: false
|
|
203
|
+
},
|
|
204
|
+
hexToAnsi: {
|
|
205
|
+
value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
|
|
206
|
+
enumerable: false
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
return styles;
|
|
210
|
+
}
|
|
211
|
+
var ansiStyles = assembleStyles();
|
|
212
|
+
var ansi_styles_default = ansiStyles;
|
|
213
|
+
|
|
214
|
+
// node_modules/chalk/source/vendor/supports-color/index.js
|
|
215
|
+
var import_node_process = __toESM(require("node:process"), 1);
|
|
216
|
+
var import_node_os = __toESM(require("node:os"), 1);
|
|
217
|
+
var import_node_tty = __toESM(require("node:tty"), 1);
|
|
218
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : import_node_process.default.argv) {
|
|
219
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
220
|
+
const position = argv.indexOf(prefix + flag);
|
|
221
|
+
const terminatorPosition = argv.indexOf("--");
|
|
222
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
223
|
+
}
|
|
224
|
+
var { env } = import_node_process.default;
|
|
225
|
+
var flagForceColor;
|
|
226
|
+
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
227
|
+
flagForceColor = 0;
|
|
228
|
+
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
229
|
+
flagForceColor = 1;
|
|
230
|
+
}
|
|
231
|
+
function envForceColor() {
|
|
232
|
+
if ("FORCE_COLOR" in env) {
|
|
233
|
+
if (env.FORCE_COLOR === "true") {
|
|
234
|
+
return 1;
|
|
235
|
+
}
|
|
236
|
+
if (env.FORCE_COLOR === "false") {
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function translateLevel(level) {
|
|
243
|
+
if (level === 0) {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
level,
|
|
248
|
+
hasBasic: true,
|
|
249
|
+
has256: level >= 2,
|
|
250
|
+
has16m: level >= 3
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
254
|
+
const noFlagForceColor = envForceColor();
|
|
255
|
+
if (noFlagForceColor !== void 0) {
|
|
256
|
+
flagForceColor = noFlagForceColor;
|
|
257
|
+
}
|
|
258
|
+
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
259
|
+
if (forceColor === 0) {
|
|
260
|
+
return 0;
|
|
261
|
+
}
|
|
262
|
+
if (sniffFlags) {
|
|
263
|
+
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
264
|
+
return 3;
|
|
265
|
+
}
|
|
266
|
+
if (hasFlag("color=256")) {
|
|
267
|
+
return 2;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
if ("TF_BUILD" in env && "AGENT_NAME" in env) {
|
|
271
|
+
return 1;
|
|
272
|
+
}
|
|
273
|
+
if (haveStream && !streamIsTTY && forceColor === void 0) {
|
|
274
|
+
return 0;
|
|
275
|
+
}
|
|
276
|
+
const min = forceColor || 0;
|
|
277
|
+
if (env.TERM === "dumb") {
|
|
278
|
+
return min;
|
|
279
|
+
}
|
|
280
|
+
if (import_node_process.default.platform === "win32") {
|
|
281
|
+
const osRelease = import_node_os.default.release().split(".");
|
|
282
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
283
|
+
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
284
|
+
}
|
|
285
|
+
return 1;
|
|
286
|
+
}
|
|
287
|
+
if ("CI" in env) {
|
|
288
|
+
if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
|
|
289
|
+
return 3;
|
|
290
|
+
}
|
|
291
|
+
if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
|
|
292
|
+
return 1;
|
|
293
|
+
}
|
|
294
|
+
return min;
|
|
295
|
+
}
|
|
296
|
+
if ("TEAMCITY_VERSION" in env) {
|
|
297
|
+
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
298
|
+
}
|
|
299
|
+
if (env.COLORTERM === "truecolor") {
|
|
300
|
+
return 3;
|
|
301
|
+
}
|
|
302
|
+
if (env.TERM === "xterm-kitty") {
|
|
303
|
+
return 3;
|
|
304
|
+
}
|
|
305
|
+
if (env.TERM === "xterm-ghostty") {
|
|
306
|
+
return 3;
|
|
307
|
+
}
|
|
308
|
+
if (env.TERM === "wezterm") {
|
|
309
|
+
return 3;
|
|
310
|
+
}
|
|
311
|
+
if ("TERM_PROGRAM" in env) {
|
|
312
|
+
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
313
|
+
switch (env.TERM_PROGRAM) {
|
|
314
|
+
case "iTerm.app": {
|
|
315
|
+
return version >= 3 ? 3 : 2;
|
|
316
|
+
}
|
|
317
|
+
case "Apple_Terminal": {
|
|
318
|
+
return 2;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (/-256(color)?$/i.test(env.TERM)) {
|
|
323
|
+
return 2;
|
|
324
|
+
}
|
|
325
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
326
|
+
return 1;
|
|
327
|
+
}
|
|
328
|
+
if ("COLORTERM" in env) {
|
|
329
|
+
return 1;
|
|
330
|
+
}
|
|
331
|
+
return min;
|
|
332
|
+
}
|
|
333
|
+
function createSupportsColor(stream, options = {}) {
|
|
334
|
+
const level = _supportsColor(stream, {
|
|
335
|
+
streamIsTTY: stream && stream.isTTY,
|
|
336
|
+
...options
|
|
337
|
+
});
|
|
338
|
+
return translateLevel(level);
|
|
339
|
+
}
|
|
340
|
+
var supportsColor = {
|
|
341
|
+
stdout: createSupportsColor({ isTTY: import_node_tty.default.isatty(1) }),
|
|
342
|
+
stderr: createSupportsColor({ isTTY: import_node_tty.default.isatty(2) })
|
|
343
|
+
};
|
|
344
|
+
var supports_color_default = supportsColor;
|
|
345
|
+
|
|
346
|
+
// node_modules/chalk/source/utilities.js
|
|
347
|
+
function stringReplaceAll(string, substring, replacer) {
|
|
348
|
+
let index = string.indexOf(substring);
|
|
349
|
+
if (index === -1) {
|
|
350
|
+
return string;
|
|
351
|
+
}
|
|
352
|
+
const substringLength = substring.length;
|
|
353
|
+
let endIndex = 0;
|
|
354
|
+
let returnValue = "";
|
|
355
|
+
do {
|
|
356
|
+
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
357
|
+
endIndex = index + substringLength;
|
|
358
|
+
index = string.indexOf(substring, endIndex);
|
|
359
|
+
} while (index !== -1);
|
|
360
|
+
returnValue += string.slice(endIndex);
|
|
361
|
+
return returnValue;
|
|
362
|
+
}
|
|
363
|
+
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
364
|
+
let endIndex = 0;
|
|
365
|
+
let returnValue = "";
|
|
366
|
+
do {
|
|
367
|
+
const gotCR = string[index - 1] === "\r";
|
|
368
|
+
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
|
|
369
|
+
endIndex = index + 1;
|
|
370
|
+
index = string.indexOf("\n", endIndex);
|
|
371
|
+
} while (index !== -1);
|
|
372
|
+
returnValue += string.slice(endIndex);
|
|
373
|
+
return returnValue;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// node_modules/chalk/source/index.js
|
|
377
|
+
var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
|
|
378
|
+
var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
|
|
379
|
+
var STYLER = /* @__PURE__ */ Symbol("STYLER");
|
|
380
|
+
var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
|
|
381
|
+
var levelMapping = [
|
|
382
|
+
"ansi",
|
|
383
|
+
"ansi",
|
|
384
|
+
"ansi256",
|
|
385
|
+
"ansi16m"
|
|
386
|
+
];
|
|
387
|
+
var styles2 = /* @__PURE__ */ Object.create(null);
|
|
388
|
+
var applyOptions = (object, options = {}) => {
|
|
389
|
+
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
|
|
390
|
+
throw new Error("The `level` option should be an integer from 0 to 3");
|
|
391
|
+
}
|
|
392
|
+
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
393
|
+
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
394
|
+
};
|
|
395
|
+
var chalkFactory = (options) => {
|
|
396
|
+
const chalk2 = (...strings) => strings.join(" ");
|
|
397
|
+
applyOptions(chalk2, options);
|
|
398
|
+
Object.setPrototypeOf(chalk2, createChalk.prototype);
|
|
399
|
+
return chalk2;
|
|
400
|
+
};
|
|
401
|
+
function createChalk(options) {
|
|
402
|
+
return chalkFactory(options);
|
|
403
|
+
}
|
|
404
|
+
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
|
405
|
+
for (const [styleName, style] of Object.entries(ansi_styles_default)) {
|
|
406
|
+
styles2[styleName] = {
|
|
407
|
+
get() {
|
|
408
|
+
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
|
|
409
|
+
Object.defineProperty(this, styleName, { value: builder });
|
|
410
|
+
return builder;
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
styles2.visible = {
|
|
415
|
+
get() {
|
|
416
|
+
const builder = createBuilder(this, this[STYLER], true);
|
|
417
|
+
Object.defineProperty(this, "visible", { value: builder });
|
|
418
|
+
return builder;
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
var getModelAnsi = (model, level, type, ...arguments_) => {
|
|
422
|
+
if (model === "rgb") {
|
|
423
|
+
if (level === "ansi16m") {
|
|
424
|
+
return ansi_styles_default[type].ansi16m(...arguments_);
|
|
425
|
+
}
|
|
426
|
+
if (level === "ansi256") {
|
|
427
|
+
return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
|
|
428
|
+
}
|
|
429
|
+
return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
|
|
430
|
+
}
|
|
431
|
+
if (model === "hex") {
|
|
432
|
+
return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
|
|
433
|
+
}
|
|
434
|
+
return ansi_styles_default[type][model](...arguments_);
|
|
435
|
+
};
|
|
436
|
+
var usedModels = ["rgb", "hex", "ansi256"];
|
|
437
|
+
for (const model of usedModels) {
|
|
438
|
+
styles2[model] = {
|
|
439
|
+
get() {
|
|
440
|
+
const { level } = this;
|
|
441
|
+
return function(...arguments_) {
|
|
442
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
|
|
443
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
448
|
+
styles2[bgModel] = {
|
|
449
|
+
get() {
|
|
450
|
+
const { level } = this;
|
|
451
|
+
return function(...arguments_) {
|
|
452
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
|
|
453
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
var proto = Object.defineProperties(() => {
|
|
459
|
+
}, {
|
|
460
|
+
...styles2,
|
|
461
|
+
level: {
|
|
462
|
+
enumerable: true,
|
|
463
|
+
get() {
|
|
464
|
+
return this[GENERATOR].level;
|
|
465
|
+
},
|
|
466
|
+
set(level) {
|
|
467
|
+
this[GENERATOR].level = level;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
var createStyler = (open, close, parent) => {
|
|
472
|
+
let openAll;
|
|
473
|
+
let closeAll;
|
|
474
|
+
if (parent === void 0) {
|
|
475
|
+
openAll = open;
|
|
476
|
+
closeAll = close;
|
|
477
|
+
} else {
|
|
478
|
+
openAll = parent.openAll + open;
|
|
479
|
+
closeAll = close + parent.closeAll;
|
|
480
|
+
}
|
|
481
|
+
return {
|
|
482
|
+
open,
|
|
483
|
+
close,
|
|
484
|
+
openAll,
|
|
485
|
+
closeAll,
|
|
486
|
+
parent
|
|
487
|
+
};
|
|
488
|
+
};
|
|
489
|
+
var createBuilder = (self, _styler, _isEmpty) => {
|
|
490
|
+
const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
|
|
491
|
+
Object.setPrototypeOf(builder, proto);
|
|
492
|
+
builder[GENERATOR] = self;
|
|
493
|
+
builder[STYLER] = _styler;
|
|
494
|
+
builder[IS_EMPTY] = _isEmpty;
|
|
495
|
+
return builder;
|
|
496
|
+
};
|
|
497
|
+
var applyStyle = (self, string) => {
|
|
498
|
+
if (self.level <= 0 || !string) {
|
|
499
|
+
return self[IS_EMPTY] ? "" : string;
|
|
500
|
+
}
|
|
501
|
+
let styler = self[STYLER];
|
|
502
|
+
if (styler === void 0) {
|
|
503
|
+
return string;
|
|
504
|
+
}
|
|
505
|
+
const { openAll, closeAll } = styler;
|
|
506
|
+
if (string.includes("\x1B")) {
|
|
507
|
+
while (styler !== void 0) {
|
|
508
|
+
string = stringReplaceAll(string, styler.close, styler.open);
|
|
509
|
+
styler = styler.parent;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
const lfIndex = string.indexOf("\n");
|
|
513
|
+
if (lfIndex !== -1) {
|
|
514
|
+
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
|
515
|
+
}
|
|
516
|
+
return openAll + string + closeAll;
|
|
517
|
+
};
|
|
518
|
+
Object.defineProperties(createChalk.prototype, styles2);
|
|
519
|
+
var chalk = createChalk();
|
|
520
|
+
var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
521
|
+
var source_default = chalk;
|
|
522
|
+
|
|
523
|
+
// index.js
|
|
524
|
+
var import_fs = __toESM(require("fs"), 1);
|
|
525
|
+
var import_path = __toESM(require("path"), 1);
|
|
526
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
527
|
+
var __dirname = import_path.default.resolve();
|
|
528
|
+
var statsFilePath = import_path.default.join(import_os.default.homedir(), ".crisis-to-calm-stats.json");
|
|
529
|
+
var themes = {
|
|
530
|
+
"--forest": { baseHex: "#00FF00", symbol: "\u2663 ", bg: source_default.hex("#004400") },
|
|
531
|
+
"--ocean": { baseHex: "#00D4FF", symbol: "~ ", bg: source_default.hex("#003344") },
|
|
532
|
+
"--mountain": { baseHex: "#FF4500", symbol: "\u25B2 ", bg: source_default.hex("#441100") },
|
|
533
|
+
"--space": { baseHex: "#AAAAAA", symbol: "* ", bg: source_default.hex("#333333") },
|
|
534
|
+
"--happy": { baseHex: "#FFD700", symbol: "\xDC ", bg: source_default.hex("#443300") },
|
|
535
|
+
"--surprised": { baseHex: "#FF00FF", symbol: "\xF6 ", bg: source_default.hex("#440044") },
|
|
536
|
+
"--rainbow": { isRainbow: true, baseHex: "#FFFFFF", symbol: "\u2022 ", bg: source_default.white.dim },
|
|
537
|
+
"default": { baseHex: "#FFFFFF", symbol: "\xF8 ", bg: source_default.gray.dim }
|
|
538
|
+
};
|
|
539
|
+
var message = [
|
|
540
|
+
"Take a second to just be here.",
|
|
541
|
+
"Let go of all your worries and stress.",
|
|
542
|
+
"The code will still be there when you're done.",
|
|
543
|
+
"Just take a moment for yourself.",
|
|
544
|
+
"You deserve a moment of peace and calm.",
|
|
545
|
+
"Breathe in, breathe out, and let go of all your thoughts.",
|
|
546
|
+
"You are not alone in this, and you are strong.",
|
|
547
|
+
"Take a moment to breathe, and let go of all your worries.",
|
|
548
|
+
"You are capable of handling whatever comes your way.",
|
|
549
|
+
"You are more than your productivity",
|
|
550
|
+
"Your brain is a muscle, and it needs rest too.",
|
|
551
|
+
"Remember, you are not defined by your to-do list.",
|
|
552
|
+
"You are more than just a collection of tasks and deadlines.",
|
|
553
|
+
"You are doing a great job.",
|
|
554
|
+
"It's ok to git checkout of work for a moment.",
|
|
555
|
+
"Sometimes a system needs a RESTART. So do you."
|
|
556
|
+
];
|
|
557
|
+
function updateStats(cyclesCompleted) {
|
|
558
|
+
let stats = { totalBreaths: 0, streak: 0, lastDate: null, rank: "Baby Breather", icon: "\u{1F37C}" };
|
|
559
|
+
try {
|
|
560
|
+
if (import_fs.default.existsSync(statsFilePath)) {
|
|
561
|
+
const fileData = import_fs.default.readFileSync(statsFilePath, "utf8");
|
|
562
|
+
if (fileData.trim()) stats = JSON.parse(fileData);
|
|
563
|
+
}
|
|
564
|
+
const oldRank = stats.rank;
|
|
565
|
+
const today = (/* @__PURE__ */ new Date()).toLocaleDateString();
|
|
566
|
+
const breathsEarned = cyclesCompleted * 4;
|
|
567
|
+
if (breathsEarned > 0) {
|
|
568
|
+
if (!stats.lastDate) {
|
|
569
|
+
stats.streak = 1;
|
|
570
|
+
} else if (stats.lastDate !== today) {
|
|
571
|
+
const yesterday = /* @__PURE__ */ new Date();
|
|
572
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
573
|
+
stats.streak = stats.lastDate === yesterday.toLocaleDateString() ? stats.streak + 1 : 1;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
stats.totalBreaths += breathsEarned;
|
|
577
|
+
stats.lastDate = today;
|
|
578
|
+
const levelData = getLevel(stats.totalBreaths);
|
|
579
|
+
stats.rank = levelData.rank;
|
|
580
|
+
stats.icon = levelData.icon;
|
|
581
|
+
const levelUp = oldRank !== stats.rank;
|
|
582
|
+
const levels = [
|
|
583
|
+
{ name: "Baby Breather", goal: 0 },
|
|
584
|
+
{ name: "Novice Breather", goal: 50 },
|
|
585
|
+
{ name: "Calm Novice", goal: 100 },
|
|
586
|
+
{ name: "Calm Apprentice", goal: 250 },
|
|
587
|
+
{ name: "Steady Hand", goal: 500 },
|
|
588
|
+
{ name: "Breath Royalty", goal: 1e3 },
|
|
589
|
+
{ name: "Breath Master", goal: 2500 },
|
|
590
|
+
{ name: "Calm Sage", goal: 5e3 },
|
|
591
|
+
{ name: "Zen Legend", goal: 1e4 }
|
|
592
|
+
];
|
|
593
|
+
const currentIdx = levels.findIndex((l) => l.name === stats.rank);
|
|
594
|
+
const nextLevelObj = levels[currentIdx + 1] || null;
|
|
595
|
+
import_fs.default.writeFileSync(statsFilePath, JSON.stringify(stats, null, 2));
|
|
596
|
+
return {
|
|
597
|
+
...stats,
|
|
598
|
+
levelUp,
|
|
599
|
+
nextLevelName: nextLevelObj ? nextLevelObj.name : "Max Level",
|
|
600
|
+
nextLevelGoal: nextLevelObj ? nextLevelObj.goal : stats.totalBreaths
|
|
601
|
+
};
|
|
602
|
+
} catch (error) {
|
|
603
|
+
return { ...stats, levelUp: false, nextLevelName: "Error", nextLevelGoal: 100 };
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
async function resetStats() {
|
|
607
|
+
console.log(source_default.red.bold("\n\u26A0\uFE0F WARNING: This will delete all your stats, rank, and streaks."));
|
|
608
|
+
process.stdout.write(source_default.white("Are you sure? (y/n): "));
|
|
609
|
+
process.stdin.setRawMode(true);
|
|
610
|
+
process.stdin.resume();
|
|
611
|
+
process.stdin.setEncoding("utf8");
|
|
612
|
+
const key = await new Promise((resolve) => {
|
|
613
|
+
process.stdin.once("data", (data) => {
|
|
614
|
+
resolve(data.toString().toLowerCase());
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
process.stdin.setRawMode(false);
|
|
618
|
+
process.stdin.pause();
|
|
619
|
+
if (key === "y") {
|
|
620
|
+
if (import_fs.default.existsSync(statsFilePath)) {
|
|
621
|
+
import_fs.default.unlinkSync(statsFilePath);
|
|
622
|
+
}
|
|
623
|
+
console.log(source_default.green("\n\n\u2705 Stats have been reset. Start fresh whenever you're ready."));
|
|
624
|
+
} else {
|
|
625
|
+
console.log(source_default.yellow("\n\nReset cancelled. Your progress is safe."));
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
function getLevel(totalBreaths) {
|
|
629
|
+
if (totalBreaths >= 1e4) return { rank: "Zen Legend", icon: "\u{1F409}" };
|
|
630
|
+
else if (totalBreaths >= 5e3) return { rank: "Calm Sage", icon: "\u{1F9D8}\u200D\u2642\uFE0F" };
|
|
631
|
+
else if (totalBreaths >= 2500) return { rank: "Breath Master", icon: "\u{1F32A}\uFE0F" };
|
|
632
|
+
else if (totalBreaths >= 1e3) return { rank: "Breath Royalty", icon: "\u{1F451}" };
|
|
633
|
+
else if (totalBreaths >= 500) return { rank: "Steady Hand", icon: "\u{1F30A}" };
|
|
634
|
+
else if (totalBreaths >= 250) return { rank: "Calm Apprentice", icon: "\u{1F343}" };
|
|
635
|
+
else if (totalBreaths >= 100) return { rank: "Calm Novice", icon: "\u{1F33F}" };
|
|
636
|
+
else if (totalBreaths >= 50) return { rank: "Novice Breather", icon: "\u{1F331}" };
|
|
637
|
+
else return { rank: "Baby Breather", icon: "\u{1F37C}" };
|
|
638
|
+
}
|
|
639
|
+
function getRainbowColor(step) {
|
|
640
|
+
const r = Math.floor(127.5 * (Math.sin(step * 0.5) + 1));
|
|
641
|
+
const g = Math.floor(127.5 * (Math.sin(step * 0.5 + 2) + 1));
|
|
642
|
+
const b = Math.floor(127.5 * (Math.sin(step * 0.5 + 4) + 1));
|
|
643
|
+
return source_default.rgb(r, g, b);
|
|
644
|
+
}
|
|
645
|
+
function hexToRgb(hex) {
|
|
646
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
647
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
648
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
649
|
+
return { r, g, b };
|
|
650
|
+
}
|
|
651
|
+
function drawBox(size, currentTheme, step = 0) {
|
|
652
|
+
const theme = currentTheme || themes["default"];
|
|
653
|
+
let activeColor, ghostColor;
|
|
654
|
+
if (theme.isRainbow) {
|
|
655
|
+
activeColor = getRainbowColor(step);
|
|
656
|
+
ghostColor = activeColor.dim;
|
|
657
|
+
} else {
|
|
658
|
+
const intensity = 1 - (size - 1) * 0.06;
|
|
659
|
+
const rgb = hexToRgb(theme.baseHex || "#FFFFFF");
|
|
660
|
+
activeColor = source_default.rgb(
|
|
661
|
+
Math.floor(rgb.r * intensity),
|
|
662
|
+
Math.floor(rgb.g * intensity),
|
|
663
|
+
Math.floor(rgb.b * intensity)
|
|
664
|
+
);
|
|
665
|
+
ghostColor = theme.bg || source_default.gray.dim;
|
|
666
|
+
}
|
|
667
|
+
const maxSize = 10;
|
|
668
|
+
const sideMargin = 10;
|
|
669
|
+
let display = "\n".repeat(2);
|
|
670
|
+
const offset = Math.floor((maxSize - size) / 2);
|
|
671
|
+
for (let row = 0; row < maxSize; row++) {
|
|
672
|
+
display += " ".repeat(sideMargin);
|
|
673
|
+
for (let col = 0; col < maxSize; col++) {
|
|
674
|
+
const isInsideRow = row >= offset && row < offset + size;
|
|
675
|
+
const isInsideCol = col >= offset && col < offset + size;
|
|
676
|
+
if (isInsideRow && isInsideCol) {
|
|
677
|
+
display += activeColor(theme.symbol);
|
|
678
|
+
} else {
|
|
679
|
+
display += ghostColor(". ");
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
display += "\n";
|
|
683
|
+
}
|
|
684
|
+
display += "\n";
|
|
685
|
+
console.log(display);
|
|
686
|
+
}
|
|
687
|
+
async function askWellness() {
|
|
688
|
+
console.log(source_default.bold.cyan("Before you go, how are you feeling now?"));
|
|
689
|
+
console.log(source_default.white("1. Better / Good"));
|
|
690
|
+
console.log(source_default.white("2. Still stressed / Bad"));
|
|
691
|
+
process.stdout.write(source_default.gray("\nPress 1 or 2: "));
|
|
692
|
+
process.stdin.setRawMode(true);
|
|
693
|
+
process.stdin.resume();
|
|
694
|
+
process.stdin.setEncoding("utf8");
|
|
695
|
+
const key = await new Promise((resolve) => {
|
|
696
|
+
process.stdin.once("data", (data) => {
|
|
697
|
+
resolve(data.toString());
|
|
698
|
+
});
|
|
699
|
+
});
|
|
700
|
+
process.stdin.setRawMode(false);
|
|
701
|
+
process.stdin.pause();
|
|
702
|
+
console.log("\n");
|
|
703
|
+
if (key === "2") {
|
|
704
|
+
console.log(source_default.yellow("I'm sorry you're still feeling this way. \u2764\uFE0F"));
|
|
705
|
+
console.log(source_default.white("Perhaps try another session with ") + source_default.cyan("--deep") + source_default.white(" mode or a longer breath count?"));
|
|
706
|
+
console.log(source_default.white("\nIf you need immediate support, remember these resources:"));
|
|
707
|
+
console.log(source_default.bold.magenta("- Crisis Text Line: Text HOME to 741741"));
|
|
708
|
+
console.log(source_default.bold.magenta("- National Suicide Prevention Lifeline: 988"));
|
|
709
|
+
console.log(source_default.bold("\nYou don't have to carry it all alone."));
|
|
710
|
+
} else {
|
|
711
|
+
console.log(source_default.green("I'm so glad to hear that! \u2728"));
|
|
712
|
+
console.log(source_default.white("Take that calm energy with you into the rest of your day."));
|
|
713
|
+
}
|
|
714
|
+
console.log(source_default.bold.cyan("\nGoodbye for now!\n"));
|
|
715
|
+
}
|
|
716
|
+
function displayStats(finalStats) {
|
|
717
|
+
if (finalStats.levelUp) {
|
|
718
|
+
console.log("\n" + "\u2B50".repeat(20));
|
|
719
|
+
console.log(source_default.bold.yellow(`LEVEL UP: You are now a ${finalStats.rank.toUpperCase()} \u{1F973}!`));
|
|
720
|
+
console.log(source_default.cyan(`Your journey into mindfulness is growing...`));
|
|
721
|
+
console.log("\u2B50".repeat(20) + "\n");
|
|
722
|
+
process.stdout.write("\x07");
|
|
723
|
+
setTimeout(() => process.stdout.write("\x07"), 200);
|
|
724
|
+
setTimeout(() => process.stdout.write("\x07"), 400);
|
|
725
|
+
}
|
|
726
|
+
console.log(source_default.bold.cyan("\n--- PROGRESS SAVED ---"));
|
|
727
|
+
console.log(source_default.cyan("\nYour stats:"));
|
|
728
|
+
console.log(source_default.cyan(`\u{1F31F} Rank: ${finalStats.rank} ${finalStats.icon}`));
|
|
729
|
+
console.log(source_default.cyan(`\u{1F9D8} Total breaths taken: ${finalStats.totalBreaths}`));
|
|
730
|
+
console.log(source_default.cyan(`\u{1F525} Current Streak: ${finalStats.streak} days`));
|
|
731
|
+
console.log(source_default.cyan("----------------------\n"));
|
|
732
|
+
if (finalStats.nextLevelName && finalStats.nextLevelGoal) {
|
|
733
|
+
const progressPercent = Math.min(finalStats.totalBreaths / finalStats.nextLevelGoal * 100, 100);
|
|
734
|
+
const bar = "\u25A0".repeat(Math.round(progressPercent / 10)) + ".".repeat(10 - Math.round(progressPercent / 10));
|
|
735
|
+
console.log(source_default.magenta(`
|
|
736
|
+
Next Level: ${finalStats.nextLevelName} (${finalStats.nextLevelGoal} breaths)`));
|
|
737
|
+
console.log(source_default.gray(`[${bar}] ${progressPercent.toFixed(1)}%`));
|
|
738
|
+
console.log(source_default.magenta("------------------------\n"));
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
function displayHelp() {
|
|
742
|
+
console.log(source_default.bold.green("\n\u{1F33F} CRISIS TO CALM - Manual"));
|
|
743
|
+
console.log(source_default.cyan("A mindful breathing tool for your terminal.\n"));
|
|
744
|
+
console.log(source_default.yellow("Usage:"));
|
|
745
|
+
console.log(" calm [themes] [options]\n");
|
|
746
|
+
console.log(source_default.yellow("Themes:"));
|
|
747
|
+
console.log(` ${source_default.cyan("--forest")} Calming Forest theme.`);
|
|
748
|
+
console.log(` ${source_default.cyan("--ocean")} Soothing Ocean theme.`);
|
|
749
|
+
console.log(` ${source_default.cyan("--mountain")} Peaceful Mountain theme.`);
|
|
750
|
+
console.log(` ${source_default.cyan("--space")} Cosmic Space theme.`);
|
|
751
|
+
console.log(` ${source_default.cyan("--happy")} Uplifting Happy theme.`);
|
|
752
|
+
console.log(` ${source_default.cyan("--surprised")} Distracting Surprised theme.`);
|
|
753
|
+
console.log(` ${source_default.cyan("--rainbow")} Fun Rainbow effect theme.`);
|
|
754
|
+
console.log(` ${source_default.cyan("--random")} Picks a random theme.`);
|
|
755
|
+
console.log(source_default.yellow("Options:"));
|
|
756
|
+
console.log(` ${source_default.cyan("--[number]")} Set breath length in seconds (e.g., --6, --10). Default is 4.`);
|
|
757
|
+
console.log(` ${source_default.cyan("--deep")} Enter Deep Focus mode (hides cursor, system beeps).`);
|
|
758
|
+
console.log(` ${source_default.cyan("--stats")} View your rank, streak, and total breaths.`);
|
|
759
|
+
console.log(` ${source_default.cyan("--reset")} Clear all progress and start fresh.`);
|
|
760
|
+
console.log(` ${source_default.cyan("--help")} Show this help menu.
|
|
761
|
+
`);
|
|
762
|
+
console.log(` ${source_default.cyan("--h")} Show this help menu.
|
|
763
|
+
`);
|
|
764
|
+
console.log(source_default.magenta("Example:"));
|
|
765
|
+
console.log(" calm --ocean --6 --deep\n");
|
|
766
|
+
}
|
|
767
|
+
async function startBreathing() {
|
|
768
|
+
const args = process.argv;
|
|
769
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
770
|
+
displayHelp();
|
|
771
|
+
process.exit();
|
|
772
|
+
}
|
|
773
|
+
if (args.includes("--reset")) {
|
|
774
|
+
await resetStats();
|
|
775
|
+
process.exit();
|
|
776
|
+
}
|
|
777
|
+
if (args.includes("--stats")) {
|
|
778
|
+
displayStats(updateStats(0));
|
|
779
|
+
process.exit();
|
|
780
|
+
}
|
|
781
|
+
const timeArg = args.find((arg) => /^--\d+$/.test(arg));
|
|
782
|
+
const customSeconds = timeArg ? parseInt(timeArg.replace("--", "")) : 4;
|
|
783
|
+
const frameSpeed = customSeconds * 1e3 / 10;
|
|
784
|
+
const isRandom = args.includes("--random");
|
|
785
|
+
const isDeep = args.includes("--deep");
|
|
786
|
+
const functionalFlags = ["--deep", "--random", "--stats", "--reset", "--help", "-h"];
|
|
787
|
+
let theme;
|
|
788
|
+
if (isRandom) {
|
|
789
|
+
const themeKeys = Object.keys(themes).filter((k) => k !== "default");
|
|
790
|
+
const randomKey = themeKeys[Math.floor(Math.random() * themeKeys.length)];
|
|
791
|
+
theme = themes[randomKey];
|
|
792
|
+
console.log(source_default.gray(`Random theme selected: ${randomKey}`));
|
|
793
|
+
} else {
|
|
794
|
+
const themeArg = args.find(
|
|
795
|
+
(arg) => arg.startsWith("--") && !/^--\d+$/.test(arg) && // Ignore things like --6 or --10
|
|
796
|
+
!functionalFlags.includes(arg)
|
|
797
|
+
);
|
|
798
|
+
theme = themes[themeArg] ? themes[themeArg] : themes["default"];
|
|
799
|
+
}
|
|
800
|
+
console.clear();
|
|
801
|
+
console.log(source_default.cyan("Ready? Let's take a moment for yourself.\n"));
|
|
802
|
+
await sleep(2e3);
|
|
803
|
+
if (isDeep) {
|
|
804
|
+
process.stdout.write("\x1B[?25l");
|
|
805
|
+
if (typeof process.stdin.setRawMode === "function") {
|
|
806
|
+
process.stdin.setRawMode(true);
|
|
807
|
+
process.stdin.resume();
|
|
808
|
+
process.stdin.setEncoding("utf8");
|
|
809
|
+
process.stdin.on("data", (key) => {
|
|
810
|
+
if (key === "") {
|
|
811
|
+
process.stdout.write("\x1B[?25h");
|
|
812
|
+
process.stdin.setRawMode(false);
|
|
813
|
+
console.log(source_default.red("\n\nEmergency stop. Returning to normal."));
|
|
814
|
+
process.exit();
|
|
815
|
+
}
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
console.log(source_default.bold.magenta("ENTERING DEEP FOCUS MODE..."));
|
|
819
|
+
await sleep(2e3);
|
|
820
|
+
}
|
|
821
|
+
for (let i = 0; i < 4; i++) {
|
|
822
|
+
let randomMessage = message[Math.floor(Math.random() * message.length)];
|
|
823
|
+
console.clear();
|
|
824
|
+
console.log(source_default.hex(theme.baseHex)(`Step 1: Inhale... (${customSeconds}s)`));
|
|
825
|
+
for (let size = 1; size <= 10; size++) {
|
|
826
|
+
console.clear();
|
|
827
|
+
console.log(source_default.hex(theme.baseHex)(`Step 1: Inhale... (${customSeconds}s)`));
|
|
828
|
+
drawBox(size, theme, size);
|
|
829
|
+
console.log(source_default.hex(theme.baseHex).italic(randomMessage));
|
|
830
|
+
await sleep(frameSpeed);
|
|
831
|
+
}
|
|
832
|
+
for (let sec = customSeconds; sec > 0; sec--) {
|
|
833
|
+
console.clear();
|
|
834
|
+
console.log(source_default.hex(theme.baseHex)(`Step 2: Hold... (${sec}s)`));
|
|
835
|
+
drawBox(10, theme, 10);
|
|
836
|
+
console.log(source_default.hex(theme.baseHex).italic(randomMessage));
|
|
837
|
+
await sleep(1e3);
|
|
838
|
+
}
|
|
839
|
+
console.clear();
|
|
840
|
+
console.log(source_default.hex(theme.baseHex)(`Step 3: Exhale... (${customSeconds}s)`));
|
|
841
|
+
for (let size = 10; size >= 1; size--) {
|
|
842
|
+
console.clear();
|
|
843
|
+
console.log(source_default.hex(theme.baseHex)(`Step 3: Exhale... (${customSeconds}s)`));
|
|
844
|
+
drawBox(size, theme, size);
|
|
845
|
+
console.log(source_default.hex(theme.baseHex).italic(randomMessage));
|
|
846
|
+
await sleep(frameSpeed);
|
|
847
|
+
}
|
|
848
|
+
for (let sec = customSeconds; sec > 0; sec--) {
|
|
849
|
+
console.clear();
|
|
850
|
+
console.log(source_default.hex(theme.baseHex)(`Step 4: Hold... (${sec}s)`));
|
|
851
|
+
drawBox(1, theme, 1);
|
|
852
|
+
console.log(source_default.hex(theme.baseHex).italic(randomMessage));
|
|
853
|
+
await sleep(1e3);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
console.clear();
|
|
857
|
+
if (isDeep) {
|
|
858
|
+
process.stdout.write("\x07");
|
|
859
|
+
process.stdout.write("\x1B[?25h");
|
|
860
|
+
if (typeof process.stdin.setRawMode === "function") {
|
|
861
|
+
process.stdin.setRawMode(false);
|
|
862
|
+
process.stdin.pause();
|
|
863
|
+
}
|
|
864
|
+
console.log(source_default.magenta("\nDeep Focus complete. Now you can take on the world."));
|
|
865
|
+
} else {
|
|
866
|
+
console.log(source_default.magenta("\nGreat job. You are ready to go back now."));
|
|
867
|
+
}
|
|
868
|
+
const finalStats = updateStats(4);
|
|
869
|
+
displayStats(finalStats);
|
|
870
|
+
await askWellness();
|
|
871
|
+
process.exit();
|
|
872
|
+
}
|
|
873
|
+
startBreathing();
|
|
874
|
+
process.on("SIGINT", () => {
|
|
875
|
+
process.stdout.write("\x1B[?25h");
|
|
876
|
+
if (typeof process.stdin.setRawMode === "function") {
|
|
877
|
+
process.stdin.setRawMode(false);
|
|
878
|
+
}
|
|
879
|
+
console.log(source_default.red("\n\n[EXIT] Emergency stop. Terminal restored."));
|
|
880
|
+
process.exit();
|
|
881
|
+
});
|
package/index.js
ADDED
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
|
|
9
|
+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
10
|
+
const __dirname = path.resolve();
|
|
11
|
+
const statsFilePath = path.join(os.homedir(), '.crisis-to-calm-stats.json');
|
|
12
|
+
|
|
13
|
+
const themes = {
|
|
14
|
+
'--forest': { baseHex: '#00FF00', symbol: '♣ ', bg: chalk.hex('#004400') },
|
|
15
|
+
'--ocean': { baseHex: '#00D4FF', symbol: '~ ', bg: chalk.hex('#003344') },
|
|
16
|
+
'--mountain': { baseHex: '#FF4500', symbol: '▲ ', bg: chalk.hex('#441100') },
|
|
17
|
+
'--space': { baseHex: '#AAAAAA', symbol: '* ', bg: chalk.hex('#333333') },
|
|
18
|
+
'--happy': { baseHex: '#FFD700', symbol: 'Ü ', bg: chalk.hex('#443300') },
|
|
19
|
+
'--surprised': { baseHex: '#FF00FF', symbol: 'ö ', bg: chalk.hex('#440044') },
|
|
20
|
+
'--rainbow': { isRainbow: true, baseHex: '#FFFFFF', symbol: '• ', bg: chalk.white.dim },
|
|
21
|
+
'default': { baseHex: '#FFFFFF', symbol: 'ø ', bg: chalk.gray.dim }
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const message = [
|
|
25
|
+
"Take a second to just be here.",
|
|
26
|
+
"Let go of all your worries and stress.",
|
|
27
|
+
"The code will still be there when you're done.",
|
|
28
|
+
"Just take a moment for yourself.",
|
|
29
|
+
"You deserve a moment of peace and calm.",
|
|
30
|
+
"Breathe in, breathe out, and let go of all your thoughts.",
|
|
31
|
+
"You are not alone in this, and you are strong.",
|
|
32
|
+
"Take a moment to breathe, and let go of all your worries.",
|
|
33
|
+
"You are capable of handling whatever comes your way.",
|
|
34
|
+
"You are more than your productivity",
|
|
35
|
+
"Your brain is a muscle, and it needs rest too.",
|
|
36
|
+
"Remember, you are not defined by your to-do list.",
|
|
37
|
+
"You are more than just a collection of tasks and deadlines.",
|
|
38
|
+
"You are doing a great job.",
|
|
39
|
+
"It's ok to git checkout of work for a moment.",
|
|
40
|
+
"Sometimes a system needs a RESTART. So do you."
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
function updateStats(cyclesCompleted) {
|
|
44
|
+
let stats = { totalBreaths: 0, streak: 0, lastDate: null, rank: "Baby Breather", icon: "🍼" };
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
if (fs.existsSync(statsFilePath)) {
|
|
48
|
+
const fileData = fs.readFileSync(statsFilePath, 'utf8');
|
|
49
|
+
if (fileData.trim()) stats = JSON.parse(fileData);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const oldRank = stats.rank;
|
|
53
|
+
const today = new Date().toLocaleDateString();
|
|
54
|
+
const breathsEarned = cyclesCompleted * 4;
|
|
55
|
+
|
|
56
|
+
// Update totals and streak
|
|
57
|
+
if (breathsEarned > 0) {
|
|
58
|
+
if (!stats.lastDate) {
|
|
59
|
+
stats.streak = 1;
|
|
60
|
+
} else if (stats.lastDate !== today) {
|
|
61
|
+
const yesterday = new Date();
|
|
62
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
63
|
+
stats.streak = (stats.lastDate === yesterday.toLocaleDateString()) ? stats.streak + 1 : 1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
stats.totalBreaths += breathsEarned;
|
|
68
|
+
stats.lastDate = today;
|
|
69
|
+
|
|
70
|
+
// Level Logic
|
|
71
|
+
const levelData = getLevel(stats.totalBreaths);
|
|
72
|
+
stats.rank = levelData.rank;
|
|
73
|
+
stats.icon = levelData.icon;
|
|
74
|
+
const levelUp = oldRank !== stats.rank;
|
|
75
|
+
|
|
76
|
+
// Progress Bar Calculation
|
|
77
|
+
const levels = [
|
|
78
|
+
{ name: "Baby Breather", goal: 0 },
|
|
79
|
+
{ name: "Novice Breather", goal: 50 },
|
|
80
|
+
{ name: "Calm Novice", goal: 100 },
|
|
81
|
+
{ name: "Calm Apprentice", goal: 250 },
|
|
82
|
+
{ name: "Steady Hand", goal: 500 },
|
|
83
|
+
{ name: "Breath Royalty", goal: 1000 },
|
|
84
|
+
{ name: "Breath Master", goal: 2500 },
|
|
85
|
+
{ name: "Calm Sage", goal: 5000 },
|
|
86
|
+
{ name: "Zen Legend", goal: 10000 }
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
const currentIdx = levels.findIndex(l => l.name === stats.rank);
|
|
90
|
+
const nextLevelObj = levels[currentIdx + 1] || null;
|
|
91
|
+
|
|
92
|
+
fs.writeFileSync(statsFilePath, JSON.stringify(stats, null, 2));
|
|
93
|
+
|
|
94
|
+
// RETURN EVERYTHING
|
|
95
|
+
return {
|
|
96
|
+
...stats,
|
|
97
|
+
levelUp,
|
|
98
|
+
nextLevelName: nextLevelObj ? nextLevelObj.name : "Max Level",
|
|
99
|
+
nextLevelGoal: nextLevelObj ? nextLevelObj.goal : stats.totalBreaths
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
} catch (error) {
|
|
103
|
+
return { ...stats, levelUp: false, nextLevelName: "Error", nextLevelGoal: 100 };
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
async function resetStats() {
|
|
108
|
+
console.log(chalk.red.bold("\n⚠️ WARNING: This will delete all your stats, rank, and streaks."));
|
|
109
|
+
process.stdout.write(chalk.white("Are you sure? (y/n): "));
|
|
110
|
+
|
|
111
|
+
// Prepare the terminal to listen for one character
|
|
112
|
+
process.stdin.setRawMode(true);
|
|
113
|
+
process.stdin.resume();
|
|
114
|
+
process.stdin.setEncoding('utf8');
|
|
115
|
+
|
|
116
|
+
// Wait for the keypress
|
|
117
|
+
const key = await new Promise(resolve => {
|
|
118
|
+
process.stdin.once('data', (data) => {
|
|
119
|
+
resolve(data.toString().toLowerCase());
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Immediately return terminal to normal mode
|
|
124
|
+
process.stdin.setRawMode(false);
|
|
125
|
+
process.stdin.pause();
|
|
126
|
+
|
|
127
|
+
if (key === 'y') {
|
|
128
|
+
if (fs.existsSync(statsFilePath)) {
|
|
129
|
+
fs.unlinkSync(statsFilePath);
|
|
130
|
+
}
|
|
131
|
+
console.log(chalk.green("\n\n✅ Stats have been reset. Start fresh whenever you're ready."));
|
|
132
|
+
} else {
|
|
133
|
+
console.log(chalk.yellow("\n\nReset cancelled. Your progress is safe."));
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
function getLevel(totalBreaths) {
|
|
138
|
+
if (totalBreaths >= 10000) return { rank: "Zen Legend", icon: "🐉" };
|
|
139
|
+
else if (totalBreaths >= 5000) return { rank: "Calm Sage", icon: "🧘♂️" };
|
|
140
|
+
else if (totalBreaths >= 2500) return { rank: "Breath Master", icon: "🌪️" };
|
|
141
|
+
else if (totalBreaths >= 1000) return { rank: "Breath Royalty", icon: "👑" };
|
|
142
|
+
else if (totalBreaths >= 500) return { rank: "Steady Hand", icon: "🌊" };
|
|
143
|
+
else if (totalBreaths >= 250) return { rank: "Calm Apprentice", icon: "🍃" };
|
|
144
|
+
else if (totalBreaths >= 100) return { rank: "Calm Novice", icon: "🌿" };
|
|
145
|
+
else if (totalBreaths >= 50) return { rank: "Novice Breather", icon: "🌱" };
|
|
146
|
+
else return { rank: "Baby Breather", icon: "🍼" }
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
function getRainbowColor(step) {
|
|
150
|
+
// Creates a shifting effect by changing R, G, and B based on the step
|
|
151
|
+
const r = Math.floor(127.5 * (Math.sin(step * 0.5) + 1));
|
|
152
|
+
const g = Math.floor(127.5 * (Math.sin(step * 0.5 + 2) + 1));
|
|
153
|
+
const b = Math.floor(127.5 * (Math.sin(step * 0.5 + 4) + 1));
|
|
154
|
+
|
|
155
|
+
// Return a Chalk color object with the calculated RGB values
|
|
156
|
+
return chalk.rgb(r, g, b);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
function hexToRgb(hex) {
|
|
160
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
161
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
162
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
163
|
+
return { r, g, b };
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
function drawBox(size, currentTheme, step = 0) {
|
|
167
|
+
// Use default if theme is missing
|
|
168
|
+
const theme = currentTheme || themes['default'];
|
|
169
|
+
|
|
170
|
+
//Handle Rainbow colors
|
|
171
|
+
let activeColor, ghostColor;
|
|
172
|
+
if (theme.isRainbow) {
|
|
173
|
+
activeColor = getRainbowColor(step);
|
|
174
|
+
ghostColor = activeColor.dim; // Use the rainbow color but dimmed
|
|
175
|
+
} else {
|
|
176
|
+
const intensity = 1.0 - ((size - 1) * 0.06);
|
|
177
|
+
const rgb = hexToRgb(theme.baseHex || '#FFFFFF');
|
|
178
|
+
|
|
179
|
+
activeColor = chalk.rgb(
|
|
180
|
+
Math.floor(rgb.r * intensity),
|
|
181
|
+
Math.floor(rgb.g * intensity),
|
|
182
|
+
Math.floor(rgb.b * intensity)
|
|
183
|
+
);
|
|
184
|
+
ghostColor = theme.bg || chalk.gray.dim; // Use the background color if provided, otherwise default to gray
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const maxSize = 10;
|
|
188
|
+
const sideMargin = 10;
|
|
189
|
+
let display = "\n".repeat(2);
|
|
190
|
+
|
|
191
|
+
const offset = Math.floor((maxSize - size) / 2);
|
|
192
|
+
|
|
193
|
+
for (let row = 0; row < maxSize; row++) {
|
|
194
|
+
display += " ".repeat(sideMargin);
|
|
195
|
+
|
|
196
|
+
for (let col = 0; col < maxSize; col++) {
|
|
197
|
+
const isInsideRow = row >= offset && row < offset + size;
|
|
198
|
+
const isInsideCol = col >= offset && col < offset + size;
|
|
199
|
+
|
|
200
|
+
if (isInsideRow && isInsideCol) {
|
|
201
|
+
display += activeColor(theme.symbol);
|
|
202
|
+
} else {
|
|
203
|
+
// Calculated ghostColor
|
|
204
|
+
display += ghostColor(". ");
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
display += "\n";
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
display += "\n";
|
|
211
|
+
console.log(display);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
async function askWellness() {
|
|
215
|
+
console.log(chalk.bold.cyan("Before you go, how are you feeling now?"));
|
|
216
|
+
console.log(chalk.white("1. Better / Good"));
|
|
217
|
+
console.log(chalk.white("2. Still stressed / Bad"));
|
|
218
|
+
process.stdout.write(chalk.gray("\nPress 1 or 2: "));
|
|
219
|
+
|
|
220
|
+
process.stdin.setRawMode(true);
|
|
221
|
+
process.stdin.resume();
|
|
222
|
+
process.stdin.setEncoding('utf8');
|
|
223
|
+
|
|
224
|
+
const key = await new Promise(resolve => {
|
|
225
|
+
process.stdin.once('data', (data) => {
|
|
226
|
+
resolve(data.toString());
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
process.stdin.setRawMode(false);
|
|
231
|
+
process.stdin.pause();
|
|
232
|
+
|
|
233
|
+
console.log("\n"); // Move to a new line after the keypress
|
|
234
|
+
|
|
235
|
+
if (key === '2') {
|
|
236
|
+
console.log(chalk.yellow("I'm sorry you're still feeling this way. ❤️"));
|
|
237
|
+
console.log(chalk.white("Perhaps try another session with ") + chalk.cyan("--deep") + chalk.white(" mode or a longer breath count?"));
|
|
238
|
+
console.log(chalk.white("\nIf you need immediate support, remember these resources:"));
|
|
239
|
+
console.log(chalk.bold.magenta("- Crisis Text Line: Text HOME to 741741"));
|
|
240
|
+
console.log(chalk.bold.magenta("- National Suicide Prevention Lifeline: 988"));
|
|
241
|
+
console.log(chalk.bold("\nYou don't have to carry it all alone."));
|
|
242
|
+
} else {
|
|
243
|
+
console.log(chalk.green("I'm so glad to hear that! ✨"));
|
|
244
|
+
console.log(chalk.white("Take that calm energy with you into the rest of your day."));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
console.log(chalk.bold.cyan("\nGoodbye for now!\n"));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function displayStats(finalStats) {
|
|
251
|
+
if (finalStats.levelUp) {
|
|
252
|
+
console.log("\n" + "⭐".repeat(20));
|
|
253
|
+
console.log(chalk.bold.yellow(`LEVEL UP: You are now a ${finalStats.rank.toUpperCase()} 🥳!`));
|
|
254
|
+
console.log(chalk.cyan(`Your journey into mindfulness is growing...`));
|
|
255
|
+
console.log("⭐".repeat(20) + "\n");
|
|
256
|
+
|
|
257
|
+
process.stdout.write('\x07');
|
|
258
|
+
setTimeout(() => process.stdout.write('\x07'), 200);
|
|
259
|
+
setTimeout(() => process.stdout.write('\x07'), 400);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
console.log(chalk.bold.cyan("\n--- PROGRESS SAVED ---"));
|
|
263
|
+
console.log(chalk.cyan("\nYour stats:"));
|
|
264
|
+
console.log(chalk.cyan(`🌟 Rank: ${finalStats.rank} ${finalStats.icon}`));
|
|
265
|
+
console.log(chalk.cyan(`🧘 Total breaths taken: ${finalStats.totalBreaths}`));
|
|
266
|
+
console.log(chalk.cyan(`🔥 Current Streak: ${finalStats.streak} days`));
|
|
267
|
+
console.log(chalk.cyan("----------------------\n"));
|
|
268
|
+
|
|
269
|
+
if (finalStats.nextLevelName && finalStats.nextLevelGoal) {
|
|
270
|
+
const progressPercent = Math.min((finalStats.totalBreaths / finalStats.nextLevelGoal) * 100, 100);
|
|
271
|
+
const bar = "■".repeat(Math.round(progressPercent / 10)) + ".".repeat(10 - Math.round(progressPercent / 10));
|
|
272
|
+
console.log(chalk.magenta(`\nNext Level: ${finalStats.nextLevelName} (${finalStats.nextLevelGoal} breaths)`));
|
|
273
|
+
console.log(chalk.gray(`[${bar}] ${progressPercent.toFixed(1)}%`));
|
|
274
|
+
console.log(chalk.magenta("------------------------\n"));
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
function displayHelp() {
|
|
279
|
+
console.log(chalk.bold.green("\n🌿 CRISIS TO CALM - Manual"));
|
|
280
|
+
console.log(chalk.cyan("A mindful breathing tool for your terminal.\n"));
|
|
281
|
+
|
|
282
|
+
console.log(chalk.yellow("Usage:"));
|
|
283
|
+
console.log(" calm [themes] [options]\n");
|
|
284
|
+
|
|
285
|
+
console.log(chalk.yellow("Themes:"));
|
|
286
|
+
console.log(` ${chalk.cyan("--forest")} Calming Forest theme.`);
|
|
287
|
+
console.log(` ${chalk.cyan("--ocean")} Soothing Ocean theme.`);
|
|
288
|
+
console.log(` ${chalk.cyan("--mountain")} Peaceful Mountain theme.`);
|
|
289
|
+
console.log(` ${chalk.cyan("--space")} Cosmic Space theme.`);
|
|
290
|
+
console.log(` ${chalk.cyan("--happy")} Uplifting Happy theme.`);
|
|
291
|
+
console.log(` ${chalk.cyan("--surprised")} Distracting Surprised theme.`);
|
|
292
|
+
console.log(` ${chalk.cyan("--rainbow")} Fun Rainbow effect theme.`);
|
|
293
|
+
console.log(` ${chalk.cyan("--random")} Picks a random theme.`);
|
|
294
|
+
|
|
295
|
+
console.log(chalk.yellow("Options:"));
|
|
296
|
+
console.log(` ${chalk.cyan("--[number]")} Set breath length in seconds (e.g., --6, --10). Default is 4.`);
|
|
297
|
+
console.log(` ${chalk.cyan("--deep")} Enter Deep Focus mode (hides cursor, system beeps).`);
|
|
298
|
+
console.log(` ${chalk.cyan("--stats")} View your rank, streak, and total breaths.`);
|
|
299
|
+
console.log(` ${chalk.cyan("--reset")} Clear all progress and start fresh.`);
|
|
300
|
+
console.log(` ${chalk.cyan("--help")} Show this help menu.\n`);
|
|
301
|
+
console.log(` ${chalk.cyan("--h")} Show this help menu.\n`);
|
|
302
|
+
|
|
303
|
+
console.log(chalk.magenta("Example:"));
|
|
304
|
+
console.log(" calm --ocean --6 --deep\n");
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async function startBreathing() {
|
|
308
|
+
const args = process.argv; // Get all command-line arguments
|
|
309
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
310
|
+
displayHelp();
|
|
311
|
+
process.exit();
|
|
312
|
+
}
|
|
313
|
+
if (args.includes('--reset')) {
|
|
314
|
+
await resetStats();
|
|
315
|
+
process.exit();
|
|
316
|
+
}
|
|
317
|
+
if (args.includes('--stats')) {
|
|
318
|
+
displayStats(updateStats(0)); // Display stats without updating
|
|
319
|
+
process.exit();
|
|
320
|
+
}
|
|
321
|
+
const timeArg = args.find(arg => /^--\d+$/.test(arg));
|
|
322
|
+
const customSeconds = timeArg ? parseInt(timeArg.replace('--', '')) : 4;
|
|
323
|
+
const frameSpeed = (customSeconds * 1000) / 10;
|
|
324
|
+
const isRandom = args.includes('--random'); // Check for random flag
|
|
325
|
+
const isDeep = args.includes('--deep'); // Check for deep flag
|
|
326
|
+
const functionalFlags = ['--deep', '--random', '--stats', '--reset', '--help', '-h'];
|
|
327
|
+
let theme;
|
|
328
|
+
if (isRandom) {
|
|
329
|
+
const themeKeys = Object.keys(themes).filter(k => k !== 'default');
|
|
330
|
+
const randomKey = themeKeys[Math.floor(Math.random() * themeKeys.length)];
|
|
331
|
+
theme = themes[randomKey];
|
|
332
|
+
console.log(chalk.gray(`Random theme selected: ${randomKey}`));
|
|
333
|
+
} else {
|
|
334
|
+
// 2. Find an argument that starts with '--', isn't a number, and isn't a functional flag
|
|
335
|
+
const themeArg = args.find(arg =>
|
|
336
|
+
arg.startsWith('--') &&
|
|
337
|
+
!/^--\d+$/.test(arg) && // Ignore things like --6 or --10
|
|
338
|
+
!functionalFlags.includes(arg)
|
|
339
|
+
);
|
|
340
|
+
theme = themes[themeArg] ? themes[themeArg] : themes['default'];
|
|
341
|
+
}
|
|
342
|
+
console.clear();
|
|
343
|
+
console.log(chalk.cyan("Ready? Let's take a moment for yourself.\n"));
|
|
344
|
+
await sleep(2000);
|
|
345
|
+
|
|
346
|
+
if (isDeep) {
|
|
347
|
+
process.stdout.write('\x1B[?25l'); // Hide cursor
|
|
348
|
+
|
|
349
|
+
if (typeof process.stdin.setRawMode === 'function') {
|
|
350
|
+
process.stdin.setRawMode(true);
|
|
351
|
+
process.stdin.resume();
|
|
352
|
+
process.stdin.setEncoding('utf8');
|
|
353
|
+
|
|
354
|
+
// Listen for the "Panic Exit" keys manually
|
|
355
|
+
process.stdin.on('data', (key) => {
|
|
356
|
+
if (key === '\u0003') { // This is the code for Ctrl + C
|
|
357
|
+
// Run cleanup and exit
|
|
358
|
+
process.stdout.write('\x1B[?25h');
|
|
359
|
+
process.stdin.setRawMode(false);
|
|
360
|
+
console.log(chalk.red("\n\nEmergency stop. Returning to normal."));
|
|
361
|
+
process.exit();
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
console.log(chalk.bold.magenta("ENTERING DEEP FOCUS MODE..."));
|
|
366
|
+
await sleep(2000);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
for (let i = 0; i < 4; i++) { // Repeat the breathing cycle 4 times
|
|
370
|
+
let randomMessage = message[Math.floor(Math.random() * message.length)];
|
|
371
|
+
console.clear();
|
|
372
|
+
console.log(chalk.hex(theme.baseHex)(`Step 1: Inhale... (${customSeconds}s)`));
|
|
373
|
+
for (let size = 1; size <= 10; size++) {
|
|
374
|
+
console.clear();
|
|
375
|
+
console.log(chalk.hex(theme.baseHex)(`Step 1: Inhale... (${customSeconds}s)`));
|
|
376
|
+
drawBox(size, theme, size);
|
|
377
|
+
console.log(chalk.hex(theme.baseHex).italic(randomMessage));
|
|
378
|
+
await sleep(frameSpeed); // Wait between each frame
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
for (let sec = customSeconds; sec > 0; sec--) { // Repeat the hold step 4 times
|
|
382
|
+
console.clear();
|
|
383
|
+
console.log(chalk.hex(theme.baseHex)(`Step 2: Hold... (${sec}s)`));
|
|
384
|
+
drawBox(10, theme, 10);
|
|
385
|
+
console.log(chalk.hex(theme.baseHex).italic(randomMessage));
|
|
386
|
+
await sleep(1000);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
console.clear();
|
|
390
|
+
console.log(chalk.hex(theme.baseHex)(`Step 3: Exhale... (${customSeconds}s)`));
|
|
391
|
+
for (let size = 10; size >= 1; size--) {
|
|
392
|
+
console.clear();
|
|
393
|
+
console.log(chalk.hex(theme.baseHex)(`Step 3: Exhale... (${customSeconds}s)`));
|
|
394
|
+
drawBox(size, theme, size);
|
|
395
|
+
console.log(chalk.hex(theme.baseHex).italic(randomMessage));
|
|
396
|
+
await sleep(frameSpeed); // Wait between each frame
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
for (let sec = customSeconds; sec > 0; sec--) { // Repeat the hold step 4 times
|
|
400
|
+
console.clear();
|
|
401
|
+
console.log(chalk.hex(theme.baseHex)(`Step 4: Hold... (${sec}s)`));
|
|
402
|
+
drawBox(1, theme, 1);
|
|
403
|
+
console.log(chalk.hex(theme.baseHex).italic(randomMessage));
|
|
404
|
+
await sleep(1000); // Wait one second between each hold step
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
console.clear();
|
|
409
|
+
|
|
410
|
+
if (isDeep) {
|
|
411
|
+
process.stdout.write('\x07'); // System Beep
|
|
412
|
+
process.stdout.write('\x1B[?25h'); // Show cursor
|
|
413
|
+
if (typeof process.stdin.setRawMode === 'function') {
|
|
414
|
+
process.stdin.setRawMode(false);
|
|
415
|
+
process.stdin.pause();
|
|
416
|
+
}
|
|
417
|
+
console.log(chalk.magenta("\nDeep Focus complete. Now you can take on the world."));
|
|
418
|
+
} else {
|
|
419
|
+
console.log(chalk.magenta("\nGreat job. You are ready to go back now."));
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const finalStats = updateStats(4); // Save progress
|
|
423
|
+
|
|
424
|
+
displayStats(finalStats);
|
|
425
|
+
|
|
426
|
+
await askWellness();
|
|
427
|
+
|
|
428
|
+
process.exit();
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
startBreathing();
|
|
432
|
+
|
|
433
|
+
process.on('SIGINT', () => {
|
|
434
|
+
// Force the cursor to show back up
|
|
435
|
+
process.stdout.write('\x1B[?25h');
|
|
436
|
+
|
|
437
|
+
// Unlock the keyboard
|
|
438
|
+
if (typeof process.stdin.setRawMode === 'function') {
|
|
439
|
+
process.stdin.setRawMode(false);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
console.log(chalk.red("\n\n[EXIT] Emergency stop. Terminal restored."));
|
|
443
|
+
process.exit();
|
|
444
|
+
});
|
package/launcher.cjs
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "crisis-to-calm",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"calm": "./index.js"
|
|
9
|
+
},
|
|
10
|
+
"pkg": {
|
|
11
|
+
"assets": [],
|
|
12
|
+
"targets": ["node18-win-x64"]
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [],
|
|
18
|
+
"author": "",
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"chalk": "^5.6.2"
|
|
22
|
+
}
|
|
23
|
+
}
|