@daliovic/cc-statusline 1.2.0 → 1.3.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/README.md CHANGED
@@ -96,6 +96,15 @@ Supported calculation methods:
96
96
  | 12 | UOIF France |
97
97
  | 13 | Diyanet Turkey |
98
98
  | 14 | Spiritual Administration of Muslims of Russia |
99
+ | 15 | Moonsighting Committee Worldwide |
100
+ | 16 | Dubai (experimental) |
101
+ | 17 | JAKIM, Malaysia |
102
+ | 18 | Tunisia |
103
+ | 19 | Algeria |
104
+ | 20 | KEMENAG, Indonesia |
105
+ | 21 | Morocco |
106
+ | 22 | Comunidade Islamica de Lisboa |
107
+ | 23 | Ministry of Awqaf, Jordan |
99
108
 
100
109
  ### Environment Variables
101
110
 
package/dist/config.js CHANGED
@@ -18,6 +18,15 @@ export const PRAYER_METHODS = {
18
18
  12: "Union Organization Islamic de France",
19
19
  13: "Diyanet İşleri Başkanlığı, Turkey",
20
20
  14: "Spiritual Administration of Muslims of Russia",
21
+ 15: "Moonsighting Committee Worldwide",
22
+ 16: "Dubai (experimental)",
23
+ 17: "JAKIM, Malaysia",
24
+ 18: "Tunisia",
25
+ 19: "Algeria",
26
+ 20: "KEMENAG, Indonesia",
27
+ 21: "Morocco",
28
+ 22: "Comunidade Islamica de Lisboa",
29
+ 23: "Ministry of Awqaf, Jordan",
21
30
  };
22
31
  export const DEFAULT_CONFIG = {
23
32
  show: {
@@ -32,6 +41,9 @@ export const DEFAULT_CONFIG = {
32
41
  contextWarning: 75,
33
42
  cacheTtlMs: 300000,
34
43
  },
44
+ wizard: {
45
+ autosave: true,
46
+ },
35
47
  colors: {
36
48
  model: 36, // cyan
37
49
  context: 248, // gray
@@ -57,6 +69,7 @@ export function loadConfig() {
57
69
  return {
58
70
  show: { ...DEFAULT_CONFIG.show, ...loaded.show },
59
71
  thresholds: { ...DEFAULT_CONFIG.thresholds, ...loaded.thresholds },
72
+ wizard: { ...DEFAULT_CONFIG.wizard, ...loaded.wizard },
60
73
  colors: { ...DEFAULT_CONFIG.colors, ...loaded.colors },
61
74
  prayer: { ...DEFAULT_CONFIG.prayer, ...loaded.prayer },
62
75
  };
package/dist/prayer.js CHANGED
@@ -24,11 +24,33 @@ function formatTimeLeft(diffMs) {
24
24
  }
25
25
  async function getLocationFromIP() {
26
26
  try {
27
- const res = await fetch("http://ip-api.com/json/?fields=lat,lon");
27
+ const res = await fetch("http://ip-api.com/json/?fields=lat,lon,city,country");
28
28
  if (!res.ok)
29
29
  return null;
30
30
  const data = await res.json();
31
- return { latitude: data.lat, longitude: data.lon };
31
+ return { latitude: data.lat, longitude: data.lon, city: data.city, country: data.country };
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ export async function geocodeCity(city, country) {
38
+ try {
39
+ const query = encodeURIComponent(`${city}, ${country}`);
40
+ const res = await fetch(`https://nominatim.openstreetmap.org/search?q=${query}&format=json&limit=1`, {
41
+ headers: { "User-Agent": "cc-statusline/1.0" },
42
+ });
43
+ if (!res.ok)
44
+ return null;
45
+ const data = await res.json();
46
+ if (!data.length)
47
+ return null;
48
+ return {
49
+ latitude: parseFloat(data[0].lat),
50
+ longitude: parseFloat(data[0].lon),
51
+ city,
52
+ country,
53
+ };
32
54
  }
33
55
  catch {
34
56
  return null;
package/dist/wizard.js CHANGED
@@ -4,6 +4,14 @@ import { DEFAULT_CONFIG, loadConfig, saveConfig, CONFIG_PATH, PRAYER_METHODS } f
4
4
  function colorize(code, text) {
5
5
  return `\x1b[38;5;${code}m${text}\x1b[0m`;
6
6
  }
7
+ // Handle Ctrl+C cancellation
8
+ function isCancelled(error) {
9
+ if (!(error instanceof Error))
10
+ return false;
11
+ return error.name === "ExitPromptError" ||
12
+ error.name === "AbortError" ||
13
+ error.message.includes("force closed");
14
+ }
7
15
  function showPreview(config) {
8
16
  const c = config.colors;
9
17
  const parts = [];
@@ -31,211 +39,321 @@ function showPreview(config) {
31
39
  }
32
40
  console.log("\n Preview: " + parts.join(" \x1b[2m\u{2502}\x1b[0m ") + "\n");
33
41
  }
34
- async function visibilityMenu(config) {
35
- const choices = [
36
- { name: "Model indicator", value: "model", checked: config.show.model },
37
- { name: "Context usage", value: "context", checked: config.show.context },
38
- { name: "5-hour usage limit", value: "usage5hr", checked: config.show.usage5hr },
39
- { name: "7-day usage limit", value: "usage7day", checked: config.show.usage7day },
40
- { name: "Budget delta arrows", value: "delta", checked: config.show.delta },
41
- { name: "Prayer times", value: "prayer", checked: config.show.prayer },
42
- ];
43
- const selected = await checkbox({
44
- message: "Toggle items to show (space to toggle, enter to confirm)",
45
- choices,
46
- });
47
- config.show.model = selected.includes("model");
48
- config.show.context = selected.includes("context");
49
- config.show.usage5hr = selected.includes("usage5hr");
50
- config.show.usage7day = selected.includes("usage7day");
51
- config.show.delta = selected.includes("delta");
52
- config.show.prayer = selected.includes("prayer");
42
+ function autoSave(config) {
43
+ if (config.wizard.autosave) {
44
+ saveConfig(config);
45
+ console.log(" \x1b[2m(autosaved)\x1b[0m");
46
+ }
53
47
  }
54
- async function colorsMenu(config) {
55
- const colorOptions = [
56
- { name: `Model (current: ${colorize(config.colors.model, String(config.colors.model))})`, value: "model" },
57
- { name: `Context (current: ${colorize(config.colors.context, String(config.colors.context))})`, value: "context" },
58
- { name: `Context warning (current: ${colorize(config.colors.contextWarning, String(config.colors.contextWarning))})`, value: "contextWarning" },
59
- { name: `Usage (current: ${colorize(config.colors.usage, String(config.colors.usage))})`, value: "usage" },
60
- { name: `Delta under budget (current: ${colorize(config.colors.deltaUnder, String(config.colors.deltaUnder))})`, value: "deltaUnder" },
61
- { name: `Delta over budget (current: ${colorize(config.colors.deltaOver, String(config.colors.deltaOver))})`, value: "deltaOver" },
62
- { name: `Prayer (current: ${colorize(config.colors.prayer, String(config.colors.prayer))})`, value: "prayer" },
63
- { name: "Back", value: "back" },
64
- ];
65
- while (true) {
66
- const choice = await select({
67
- message: "Select color to change (ANSI 256 codes: 0-255)",
68
- choices: colorOptions,
69
- });
70
- if (choice === "back")
71
- break;
72
- const current = config.colors[choice];
73
- const newValue = await input({
74
- message: `Enter ANSI color code (0-255, current: ${colorize(current, String(current))})`,
75
- default: String(current),
76
- validate: (val) => {
77
- const num = parseInt(val, 10);
78
- if (isNaN(num) || num < 0 || num > 255)
79
- return "Enter a number 0-255";
80
- return true;
81
- },
48
+ async function visibilityMenu(config) {
49
+ try {
50
+ const choices = [
51
+ { name: "Model indicator", value: "model", checked: config.show.model },
52
+ { name: "Context usage", value: "context", checked: config.show.context },
53
+ { name: "5-hour usage limit", value: "usage5hr", checked: config.show.usage5hr },
54
+ { name: "7-day usage limit", value: "usage7day", checked: config.show.usage7day },
55
+ { name: "Budget delta arrows", value: "delta", checked: config.show.delta },
56
+ { name: "Prayer times", value: "prayer", checked: config.show.prayer },
57
+ ];
58
+ const selected = await checkbox({
59
+ message: "Toggle items (space=toggle, enter=confirm, ctrl+c=back)",
60
+ choices,
82
61
  });
83
- config.colors[choice] = parseInt(newValue, 10);
84
- // Update the menu option to show new color
85
- const idx = colorOptions.findIndex(o => o.value === choice);
86
- if (idx >= 0) {
87
- const label = choice.replace(/([A-Z])/g, " $1").toLowerCase();
88
- colorOptions[idx].name = `${label.charAt(0).toUpperCase() + label.slice(1)} (current: ${colorize(config.colors[choice], newValue)})`;
89
- }
62
+ config.show.model = selected.includes("model");
63
+ config.show.context = selected.includes("context");
64
+ config.show.usage5hr = selected.includes("usage5hr");
65
+ config.show.usage7day = selected.includes("usage7day");
66
+ config.show.delta = selected.includes("delta");
67
+ config.show.prayer = selected.includes("prayer");
68
+ autoSave(config);
69
+ return false;
70
+ }
71
+ catch (e) {
72
+ if (isCancelled(e))
73
+ return true;
74
+ throw e;
90
75
  }
91
76
  }
92
- async function prayerMenu(config) {
93
- const methodChoices = Object.entries(PRAYER_METHODS).map(([code, name]) => ({
94
- name: `${name}${Number(code) === config.prayer.method ? " (current)" : ""}`,
95
- value: code,
96
- }));
97
- methodChoices.push({ name: "Back", value: "back" });
98
- while (true) {
99
- const choice = await select({
100
- message: "Prayer settings",
101
- choices: [
102
- { name: `Calculation method: ${PRAYER_METHODS[config.prayer.method]}`, value: "method" },
103
- { name: config.prayer.location
104
- ? `Location: ${config.prayer.location.latitude}, ${config.prayer.location.longitude}`
105
- : "Location: Auto-detect (IP)", value: "location" },
106
- { name: "Back", value: "back" },
107
- ],
108
- });
109
- if (choice === "back")
110
- break;
111
- if (choice === "method") {
112
- const method = await select({
113
- message: "Select calculation method",
114
- choices: methodChoices,
77
+ async function colorsMenu(config) {
78
+ try {
79
+ const colorOptions = [
80
+ { name: `Model (current: ${colorize(config.colors.model, String(config.colors.model))})`, value: "model" },
81
+ { name: `Context (current: ${colorize(config.colors.context, String(config.colors.context))})`, value: "context" },
82
+ { name: `Context warning (current: ${colorize(config.colors.contextWarning, String(config.colors.contextWarning))})`, value: "contextWarning" },
83
+ { name: `Usage (current: ${colorize(config.colors.usage, String(config.colors.usage))})`, value: "usage" },
84
+ { name: `Delta under budget (current: ${colorize(config.colors.deltaUnder, String(config.colors.deltaUnder))})`, value: "deltaUnder" },
85
+ { name: `Delta over budget (current: ${colorize(config.colors.deltaOver, String(config.colors.deltaOver))})`, value: "deltaOver" },
86
+ { name: `Prayer (current: ${colorize(config.colors.prayer, String(config.colors.prayer))})`, value: "prayer" },
87
+ { name: "\x1b[2m← Back\x1b[0m", value: "back" },
88
+ ];
89
+ while (true) {
90
+ const choice = await select({
91
+ message: "Select color to change (0-255)",
92
+ choices: colorOptions,
115
93
  });
116
- if (method !== "back") {
117
- config.prayer.method = Number(method);
94
+ if (choice === "back")
95
+ return false;
96
+ const current = config.colors[choice];
97
+ const newValue = await input({
98
+ message: `Enter ANSI color code (0-255, current: ${colorize(current, String(current))})`,
99
+ default: String(current),
100
+ validate: (val) => {
101
+ const num = parseInt(val, 10);
102
+ if (isNaN(num) || num < 0 || num > 255)
103
+ return "Enter a number 0-255";
104
+ return true;
105
+ },
106
+ });
107
+ config.colors[choice] = parseInt(newValue, 10);
108
+ autoSave(config);
109
+ // Update the menu option to show new color
110
+ const idx = colorOptions.findIndex(o => o.value === choice);
111
+ if (idx >= 0) {
112
+ const label = choice.replace(/([A-Z])/g, " $1").toLowerCase();
113
+ colorOptions[idx].name = `${label.charAt(0).toUpperCase() + label.slice(1)} (current: ${colorize(config.colors[choice], newValue)})`;
118
114
  }
119
115
  }
120
- else if (choice === "location") {
121
- const locChoice = await select({
122
- message: "Location setting",
116
+ }
117
+ catch (e) {
118
+ if (isCancelled(e))
119
+ return true;
120
+ throw e;
121
+ }
122
+ }
123
+ async function prayerMenu(config) {
124
+ try {
125
+ const methodChoices = Object.entries(PRAYER_METHODS).map(([code, name]) => ({
126
+ name: `${name}${Number(code) === config.prayer.method ? " (current)" : ""}`,
127
+ value: code,
128
+ }));
129
+ methodChoices.push({ name: "\x1b[2m← Back\x1b[0m", value: "back" });
130
+ while (true) {
131
+ const locationDisplay = config.prayer.location
132
+ ? config.prayer.location.city
133
+ ? `${config.prayer.location.city}, ${config.prayer.location.country}`
134
+ : `${config.prayer.location.latitude.toFixed(2)}, ${config.prayer.location.longitude.toFixed(2)}`
135
+ : "Auto-detect (IP)";
136
+ const choice = await select({
137
+ message: "Prayer settings",
123
138
  choices: [
124
- { name: "Auto-detect from IP (recommended)", value: "auto" },
125
- { name: "Enter manually", value: "manual" },
139
+ { name: `Calculation method: ${PRAYER_METHODS[config.prayer.method]}`, value: "method" },
140
+ { name: `Location: ${locationDisplay}`, value: "location" },
141
+ { name: "\x1b[2m← Back\x1b[0m", value: "back" },
126
142
  ],
127
143
  });
128
- if (locChoice === "auto") {
129
- config.prayer.location = null;
130
- }
131
- else {
132
- const lat = await input({
133
- message: "Latitude",
134
- default: config.prayer.location?.latitude?.toString() || "",
135
- validate: (val) => {
136
- const num = parseFloat(val);
137
- if (isNaN(num) || num < -90 || num > 90)
138
- return "Enter -90 to 90";
139
- return true;
140
- },
144
+ if (choice === "back")
145
+ return false;
146
+ if (choice === "method") {
147
+ const method = await select({
148
+ message: "Select calculation method",
149
+ choices: methodChoices,
141
150
  });
142
- const lng = await input({
143
- message: "Longitude",
144
- default: config.prayer.location?.longitude?.toString() || "",
145
- validate: (val) => {
146
- const num = parseFloat(val);
147
- if (isNaN(num) || num < -180 || num > 180)
148
- return "Enter -180 to 180";
149
- return true;
150
- },
151
+ if (method !== "back") {
152
+ config.prayer.method = Number(method);
153
+ autoSave(config);
154
+ }
155
+ }
156
+ else if (choice === "location") {
157
+ const locChoice = await select({
158
+ message: "Location setting",
159
+ choices: [
160
+ { name: "Auto-detect from IP (recommended)", value: "auto" },
161
+ { name: "Enter city and country", value: "city" },
162
+ { name: "Enter coordinates manually", value: "coords" },
163
+ ],
151
164
  });
152
- config.prayer.location = {
153
- latitude: parseFloat(lat),
154
- longitude: parseFloat(lng),
155
- };
165
+ if (locChoice === "auto") {
166
+ config.prayer.location = null;
167
+ autoSave(config);
168
+ }
169
+ else if (locChoice === "city") {
170
+ const city = await input({
171
+ message: "City name",
172
+ default: config.prayer.location?.city || "",
173
+ validate: (val) => val.trim() ? true : "Enter a city name",
174
+ });
175
+ const country = await input({
176
+ message: "Country",
177
+ default: config.prayer.location?.country || "",
178
+ validate: (val) => val.trim() ? true : "Enter a country",
179
+ });
180
+ console.log(" Looking up coordinates...");
181
+ const { geocodeCity } = await import("./prayer.js");
182
+ const location = await geocodeCity(city.trim(), country.trim());
183
+ if (location) {
184
+ config.prayer.location = location;
185
+ console.log(` Found: ${location.latitude.toFixed(4)}, ${location.longitude.toFixed(4)}\n`);
186
+ autoSave(config);
187
+ }
188
+ else {
189
+ console.log(" Could not find location. Please try again or enter coordinates manually.\n");
190
+ }
191
+ }
192
+ else {
193
+ const lat = await input({
194
+ message: "Latitude",
195
+ default: config.prayer.location?.latitude?.toString() || "",
196
+ validate: (val) => {
197
+ const num = parseFloat(val);
198
+ if (isNaN(num) || num < -90 || num > 90)
199
+ return "Enter -90 to 90";
200
+ return true;
201
+ },
202
+ });
203
+ const lng = await input({
204
+ message: "Longitude",
205
+ default: config.prayer.location?.longitude?.toString() || "",
206
+ validate: (val) => {
207
+ const num = parseFloat(val);
208
+ if (isNaN(num) || num < -180 || num > 180)
209
+ return "Enter -180 to 180";
210
+ return true;
211
+ },
212
+ });
213
+ config.prayer.location = {
214
+ latitude: parseFloat(lat),
215
+ longitude: parseFloat(lng),
216
+ };
217
+ autoSave(config);
218
+ }
156
219
  }
157
220
  }
158
221
  }
222
+ catch (e) {
223
+ if (isCancelled(e))
224
+ return true;
225
+ throw e;
226
+ }
159
227
  }
160
228
  async function thresholdsMenu(config) {
161
- const contextWarning = await input({
162
- message: "Context warning threshold % (turns orange)",
163
- default: String(config.thresholds.contextWarning),
164
- validate: (val) => {
165
- const num = parseInt(val, 10);
166
- if (isNaN(num) || num < 1 || num > 100)
167
- return "Enter 1-100";
229
+ try {
230
+ const contextWarning = await input({
231
+ message: "Context warning threshold % (turns orange)",
232
+ default: String(config.thresholds.contextWarning),
233
+ validate: (val) => {
234
+ const num = parseInt(val, 10);
235
+ if (isNaN(num) || num < 1 || num > 100)
236
+ return "Enter 1-100";
237
+ return true;
238
+ },
239
+ });
240
+ config.thresholds.contextWarning = parseInt(contextWarning, 10);
241
+ const cacheTtl = await input({
242
+ message: "API cache TTL (milliseconds)",
243
+ default: String(config.thresholds.cacheTtlMs),
244
+ validate: (val) => {
245
+ const num = parseInt(val, 10);
246
+ if (isNaN(num) || num < 0)
247
+ return "Enter a positive number";
248
+ return true;
249
+ },
250
+ });
251
+ config.thresholds.cacheTtlMs = parseInt(cacheTtl, 10);
252
+ autoSave(config);
253
+ return false;
254
+ }
255
+ catch (e) {
256
+ if (isCancelled(e))
168
257
  return true;
169
- },
170
- });
171
- config.thresholds.contextWarning = parseInt(contextWarning, 10);
172
- const cacheTtl = await input({
173
- message: "API cache TTL (milliseconds)",
174
- default: String(config.thresholds.cacheTtlMs),
175
- validate: (val) => {
176
- const num = parseInt(val, 10);
177
- if (isNaN(num) || num < 0)
178
- return "Enter a positive number";
258
+ throw e;
259
+ }
260
+ }
261
+ async function settingsMenu(config) {
262
+ try {
263
+ const autosave = await confirm({
264
+ message: "Enable autosave? (saves after each change)",
265
+ default: config.wizard.autosave,
266
+ });
267
+ config.wizard.autosave = autosave;
268
+ saveConfig(config); // Always save settings changes
269
+ console.log(` Autosave ${autosave ? "enabled" : "disabled"}\n`);
270
+ return false;
271
+ }
272
+ catch (e) {
273
+ if (isCancelled(e))
179
274
  return true;
180
- },
181
- });
182
- config.thresholds.cacheTtlMs = parseInt(cacheTtl, 10);
275
+ throw e;
276
+ }
183
277
  }
184
278
  export async function runWizard() {
185
- console.log("\n\x1b[1mcc-statusline Configuration\x1b[0m\n");
279
+ console.log("\n\x1b[1mcc-statusline Configuration\x1b[0m");
280
+ console.log("\x1b[2mCtrl+C to go back/exit\x1b[0m\n");
186
281
  const config = loadConfig();
187
282
  showPreview(config);
188
- while (true) {
189
- const choice = await select({
190
- message: "What would you like to configure?",
191
- choices: [
192
- { name: "Visibility (show/hide items)", value: "visibility" },
193
- { name: "Colors", value: "colors" },
194
- { name: "Thresholds", value: "thresholds" },
195
- { name: "Prayer settings", value: "prayer" },
196
- { name: "Reset to defaults", value: "reset" },
197
- { name: "Save & Exit", value: "save" },
198
- { name: "Exit without saving", value: "exit" },
199
- ],
200
- });
201
- switch (choice) {
202
- case "visibility":
203
- await visibilityMenu(config);
204
- showPreview(config);
205
- break;
206
- case "colors":
207
- await colorsMenu(config);
208
- showPreview(config);
209
- break;
210
- case "thresholds":
211
- await thresholdsMenu(config);
212
- break;
213
- case "prayer":
214
- await prayerMenu(config);
215
- break;
216
- case "reset":
217
- const confirmReset = await confirm({
218
- message: "Reset all settings to defaults?",
219
- default: false,
220
- });
221
- if (confirmReset) {
222
- Object.assign(config, JSON.parse(JSON.stringify(DEFAULT_CONFIG)));
223
- console.log(" Reset to defaults.\n");
283
+ try {
284
+ while (true) {
285
+ const autosaveLabel = config.wizard.autosave ? "\x1b[32m●\x1b[0m" : "\x1b[2m○\x1b[0m";
286
+ const choice = await select({
287
+ message: "What would you like to configure?",
288
+ choices: [
289
+ { name: "Visibility (show/hide items)", value: "visibility" },
290
+ { name: "Colors", value: "colors" },
291
+ { name: "Thresholds", value: "thresholds" },
292
+ { name: "Prayer settings", value: "prayer" },
293
+ { name: `Settings ${autosaveLabel} autosave`, value: "settings" },
294
+ { name: "Reset to defaults", value: "reset" },
295
+ ...(config.wizard.autosave ? [] : [{ name: "Save & Exit", value: "save" }]),
296
+ { name: config.wizard.autosave ? "Exit" : "Exit without saving", value: "exit" },
297
+ ],
298
+ });
299
+ switch (choice) {
300
+ case "visibility":
301
+ await visibilityMenu(config);
224
302
  showPreview(config);
225
- }
226
- break;
227
- case "save":
228
- saveConfig(config);
229
- console.log(`\n Saved to ${CONFIG_PATH}\n`);
230
- return;
231
- case "exit":
232
- const confirmExit = await confirm({
233
- message: "Exit without saving changes?",
234
- default: false,
235
- });
236
- if (confirmExit)
303
+ break;
304
+ case "colors":
305
+ await colorsMenu(config);
306
+ showPreview(config);
307
+ break;
308
+ case "thresholds":
309
+ await thresholdsMenu(config);
310
+ break;
311
+ case "prayer":
312
+ await prayerMenu(config);
313
+ break;
314
+ case "settings":
315
+ await settingsMenu(config);
316
+ break;
317
+ case "reset":
318
+ const confirmReset = await confirm({
319
+ message: "Reset all settings to defaults?",
320
+ default: false,
321
+ });
322
+ if (confirmReset) {
323
+ Object.assign(config, JSON.parse(JSON.stringify(DEFAULT_CONFIG)));
324
+ console.log(" Reset to defaults.\n");
325
+ autoSave(config);
326
+ showPreview(config);
327
+ }
328
+ break;
329
+ case "save":
330
+ saveConfig(config);
331
+ console.log(`\n Saved to ${CONFIG_PATH}\n`);
237
332
  return;
238
- break;
333
+ case "exit":
334
+ if (config.wizard.autosave) {
335
+ return;
336
+ }
337
+ const confirmExit = await confirm({
338
+ message: "Exit without saving changes?",
339
+ default: false,
340
+ });
341
+ if (confirmExit)
342
+ return;
343
+ break;
344
+ }
345
+ }
346
+ }
347
+ catch (e) {
348
+ if (isCancelled(e)) {
349
+ if (config.wizard.autosave) {
350
+ console.log("\n \x1b[2mExited (changes autosaved)\x1b[0m\n");
351
+ }
352
+ else {
353
+ console.log("\n \x1b[2mExited without saving\x1b[0m\n");
354
+ }
355
+ return;
239
356
  }
357
+ throw e;
240
358
  }
241
359
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daliovic/cc-statusline",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Minimal Claude Code statusline with usage limits and budget tracking",
5
5
  "type": "module",
6
6
  "main": "dist/statusline.js",