@siegesailor/terminal-sigma 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/LICENSE.md ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2026 Jin Yu Zhang
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
19
+ OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # Terminal-Sigma
2
+
3
+ [![NPM version](https://img.shields.io/npm/v/%40siegesailor/terminal-sigma?logo=npm)](https://www.npmjs.com/package/@siegesailor/terminal-sigma)
4
+ [![push: Verify](https://github.com/SiegeSailor/Terminal-Sigma/actions/workflows/push-verify.yml/badge.svg)](https://github.com/SiegeSailor/Terminal-Sigma/actions/workflows/push-verify.yml)
5
+ [![main: Release](https://github.com/SiegeSailor/Terminal-Sigma/actions/workflows/main-release.yml/badge.svg)](https://github.com/SiegeSailor/Terminal-Sigma/actions/workflows/main-release.yml)
6
+
7
+ Terminal-Sigma is a terminal-based application that gives game-style feedback on your self-development journey. Though it is a CLI, it is meant to stay open: it updates in real time and is operated through its terminal UI rather than through commands. It features 5 main components:
8
+
9
+ | Component | What It Does |
10
+ | --------------------- | ------------------------------------------------------------------------------------------------------ |
11
+ | Character Progression | An animated character that levels up with your experience and unlocks new gear as it does |
12
+ | Diet Tracker | Logs meals with optional calories, e.g. `Oatmeal 350`, against a daily goal of 3 meals |
13
+ | Everyday Quotes | An inspiring quote that refreshes every 30 minutes, on restart, or on demand |
14
+ | Tomato Timer | A Pomodoro timer: 25 minutes of focus, then a 5-minute break, against a daily goal of 4 focus sessions |
15
+ | Workout Tracker | Logs workouts in minutes, e.g. `Run 30`, against a daily goal of 30 minutes |
16
+
17
+ Underneath, your journey is written to the local file `~/.terminal-sigma/progress.json`. There is no plan to support logging at this point, and we chose JSON as a readable format, so that you can port it easily.
18
+
19
+ ## Installation
20
+
21
+ The package is available on NPM. Install it globally to get the command:
22
+
23
+ ```shell
24
+ npm install --global @siegesailor/terminal-sigma
25
+ ```
26
+
27
+ ### Prerequisites
28
+
29
+ Required software for this module:
30
+
31
+ - [Node.js](https://nodejs.org/): `>= 22`
32
+
33
+ ## Usage
34
+
35
+ Start the dashboard and leave it open in a terminal tab:
36
+
37
+ ```shell
38
+ siegesailor-terminal-sigma --name "Ken"
39
+ ```
40
+
41
+ Every option has a default:
42
+
43
+ | Option | Default | Description |
44
+ | --------------- | ------------ | ---------------------------------- |
45
+ | `--break <min>` | `5` | Minutes of each Tomato Timer break |
46
+ | `--focus <min>` | `25` | Minutes of each Tomato Timer focus |
47
+ | `--name <name>` | `Rook Sigma` | The name of your character |
48
+
49
+ ### Keys
50
+
51
+ The navigation menu at the bottom drives everything:
52
+
53
+ | Key | Action |
54
+ | ------------------------- | ------------------------------------------------------------------------- |
55
+ | `1` to `4` | Select a menu item |
56
+ | Arrows or `h` `j` `k` `l` | Move through the menu |
57
+ | Enter | Start or pause the timer, open the meal or workout entry, or draw a quote |
58
+ | Esc | Cancel a meal or workout entry |
59
+ | `q` or Ctrl+C | Quit |
60
+
61
+ A meal or workout entry is a name followed by a number: the calories of a meal, which are optional, or the minutes of a workout, which are required. When a focus or break ends, the terminal rings its bell.
62
+
63
+ ### Environment Variables
64
+
65
+ Both are optional:
66
+
67
+ | Variable | Effect |
68
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
69
+ | `API_NINJAS_KEY` | Fetch quotes from [API Ninjas](https://api-ninjas.com/api/quotes) instead of the bundled list, falling back to it on any error |
70
+ | `TERMINAL_SIGMA_HOME` | The folder that holds `progress.json`, instead of `~/.terminal-sigma`, e.g. a synced folder |
71
+
72
+ ## Progress File
73
+
74
+ `progress.json` holds only what you logged. Your experience, level, and daily progress are worked out from it every time, so editing the file by hand can never put them out of sync:
75
+
76
+ ```json
77
+ {
78
+ "focus": [{ "at": "2026-10-03T09:00:00.000Z", "minutes": 25 }],
79
+ "meals": [
80
+ { "at": "2026-10-03T08:00:00.000Z", "food": "Oatmeal", "calories": 350 }
81
+ ],
82
+ "workouts": [
83
+ { "at": "2026-10-03T07:00:00.000Z", "activity": "Run", "minutes": 30 }
84
+ ]
85
+ }
86
+ ```
87
+
88
+ Every 100 XP is a level, and every level from level 2 to level 9 upgrades 1 piece of your character's gear. Experience is earned as follows:
89
+
90
+ | Entry | Experience |
91
+ | -------------- | --------------- |
92
+ | Finished focus | 1 XP per minute |
93
+ | Meal | 5 XP |
94
+ | Workout | 1 XP per minute |
95
+
96
+ > [!important]
97
+ > If `progress.json` is not valid, Terminal-Sigma refuses to start rather than overwrite it. Fix or move the file, then start again.
98
+
99
+ ## Contributing
100
+
101
+ See [`CONTRIBUTING.md`](./.github/CONTRIBUTING.md) to work on Terminal-Sigma, and [`SECURITY.md`](./.github/SECURITY.md) to report a vulnerability.
102
+
103
+ ## License
104
+
105
+ [MIT](./LICENSE.md)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import Pastel from "pastel";
3
+ const app = new Pastel({
4
+ importMeta: import.meta,
5
+ name: "siegesailor-terminal-sigma",
6
+ });
7
+ await app.run();
8
+ //# sourceMappingURL=command-line-interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-line-interface.js","sourceRoot":"","sources":["../source/command-line-interface.tsx"],"names":[],"mappings":";AACA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC,IAAI;IACvB,IAAI,EAAE,4BAA4B;CAClC,CAAC,CAAC;AAEH,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC"}
@@ -0,0 +1,274 @@
1
+ import { homedir } from "node:os";
2
+ import process from "node:process";
3
+ import zod from "zod";
4
+ import React from "react";
5
+ import { TextInput } from "@inkjs/ui";
6
+ import { Box, Text, useApp, useInput, useWindowSize } from "ink";
7
+ import Character from "../components/character.js";
8
+ import MenuGrid from "../components/menu-grid.js";
9
+ import StatusPanel from "../components/status-panel.js";
10
+ import { dailyGoals, experienceOf, experiencePerLevel, experiencePerMeal, levelOf, loadProgress, parseEntry, progressFile, saveProgress, todayOf, } from "../progress.js";
11
+ import { fetchQuote, quoteRefreshMinutes, randomBundledQuote, } from "../quotes.js";
12
+ import { advanceTimer, formatClock, idleTimer, remainingOf, toggleTimer, } from "../timer.js";
13
+ const clamp = (value, minimum, maximum) => Math.min(Math.max(value, minimum), maximum);
14
+ const percentOf = (value, goal) => Math.min(Math.round((value / goal) * 100), 100);
15
+ const goalSignal = (value, goal) => {
16
+ if (value >= goal) {
17
+ return { signal: "Done", badgeColor: "green" };
18
+ }
19
+ return value > 0
20
+ ? { signal: "Going", badgeColor: "yellow" }
21
+ : { signal: "Start", badgeColor: "blue" };
22
+ };
23
+ export const options = zod.object({
24
+ name: zod.string().describe("Your name").default("Rook Sigma"),
25
+ focus: zod.number().int().positive().describe("Focus minutes").default(25),
26
+ break: zod.number().int().positive().describe("Break minutes").default(5),
27
+ });
28
+ export default function Index({ options }) {
29
+ const { exit } = useApp();
30
+ const { columns } = useWindowSize();
31
+ const file = React.useMemo(() => progressFile(), []);
32
+ const [progress, setProgress] = React.useState(() => loadProgress(file));
33
+ const [now, setNow] = React.useState(Date.now);
34
+ const durations = React.useMemo(() => ({ focus: options.focus, break: options.break }), [options.focus, options.break]);
35
+ const [timer, setTimer] = React.useState(() => idleTimer(durations));
36
+ const [quote, setQuote] = React.useState(randomBundledQuote);
37
+ const [entry, setEntry] = React.useState();
38
+ const [message, setMessage] = React.useState(`Progress is saved to ${file.replace(homedir(), "~")}.`);
39
+ const record = React.useCallback((update, text) => {
40
+ const next = update(progress);
41
+ try {
42
+ saveProgress(file, next);
43
+ }
44
+ catch (error) {
45
+ setMessage(`Not saved: ${String(error)}`);
46
+ return;
47
+ }
48
+ const before = levelOf(experienceOf(progress));
49
+ const after = levelOf(experienceOf(next));
50
+ setProgress(next);
51
+ setMessage(after > before ? `${text} Level up! LV ${after}.` : text);
52
+ }, [file, progress]);
53
+ React.useEffect(() => {
54
+ const interval = setInterval(() => {
55
+ setNow(Date.now());
56
+ }, 1000);
57
+ return () => {
58
+ clearInterval(interval);
59
+ };
60
+ }, []);
61
+ React.useEffect(() => {
62
+ const { timer: next, finished } = advanceTimer(timer, now, durations);
63
+ if (!finished) {
64
+ return;
65
+ }
66
+ setTimer(next);
67
+ process.stdout.write("\u0007");
68
+ if (finished === "break") {
69
+ setMessage("Break over. Select Tomato Timer and press Enter to focus.");
70
+ return;
71
+ }
72
+ record((current) => ({
73
+ ...current,
74
+ focus: [
75
+ ...current.focus,
76
+ { at: new Date(now).toISOString(), minutes: durations.focus },
77
+ ],
78
+ }), `Focus complete, +${durations.focus} XP. ${durations.break}-minute break started.`);
79
+ }, [now, timer, durations, record]);
80
+ React.useEffect(() => {
81
+ let isMounted = true;
82
+ const refresh = async () => {
83
+ const next = await fetchQuote();
84
+ if (isMounted) {
85
+ setQuote(next);
86
+ }
87
+ };
88
+ void refresh();
89
+ const interval = setInterval(() => {
90
+ void refresh();
91
+ }, quoteRefreshMinutes * 60_000);
92
+ return () => {
93
+ isMounted = false;
94
+ clearInterval(interval);
95
+ };
96
+ }, []);
97
+ useInput((input, key) => {
98
+ if (entry) {
99
+ if (key.escape) {
100
+ setEntry(undefined);
101
+ setMessage("Nothing logged.");
102
+ }
103
+ return;
104
+ }
105
+ if (input === "q") {
106
+ exit();
107
+ }
108
+ });
109
+ const submitEntry = (text) => {
110
+ const parsed = parseEntry(text);
111
+ const at = new Date().toISOString();
112
+ setEntry(undefined);
113
+ if (!parsed) {
114
+ setMessage("Nothing logged.");
115
+ return;
116
+ }
117
+ if (entry === "meal") {
118
+ record((current) => ({
119
+ ...current,
120
+ meals: [
121
+ ...current.meals,
122
+ { at, food: parsed.label, calories: parsed.amount },
123
+ ],
124
+ }), `Logged ${parsed.label}, +${experiencePerMeal} XP.`);
125
+ return;
126
+ }
127
+ if (!parsed.amount) {
128
+ setMessage("Add the minutes to log a workout, e.g. Run 30.");
129
+ return;
130
+ }
131
+ const minutes = parsed.amount;
132
+ record((current) => ({
133
+ ...current,
134
+ workouts: [
135
+ ...current.workouts,
136
+ { at, activity: parsed.label, minutes },
137
+ ],
138
+ }), `Logged ${parsed.label} for ${minutes} minutes, +${minutes} XP.`);
139
+ };
140
+ const selectMenu = (index) => {
141
+ switch (index) {
142
+ case 0: {
143
+ const next = toggleTimer(timer, Date.now());
144
+ setTimer(next);
145
+ setMessage(next.endsAt === undefined
146
+ ? "Timer paused."
147
+ : `${next.phase === "focus" ? "Focus" : "Break"} running.`);
148
+ break;
149
+ }
150
+ case 1: {
151
+ setEntry("meal");
152
+ break;
153
+ }
154
+ case 2: {
155
+ setEntry("workout");
156
+ break;
157
+ }
158
+ default: {
159
+ void fetchQuote().then(setQuote);
160
+ setMessage("New quote drawn.");
161
+ }
162
+ }
163
+ };
164
+ const experience = experienceOf(progress);
165
+ const level = levelOf(experience);
166
+ const levelExperience = experience % experiencePerLevel;
167
+ const today = todayOf(progress, now);
168
+ const isIdle = timer.endsAt === undefined &&
169
+ timer.phase === "focus" &&
170
+ timer.remaining === durations.focus * 60_000;
171
+ const clock = formatClock(remainingOf(timer, now));
172
+ const phaseLabel = timer.phase.toUpperCase();
173
+ let timerSignal = `${phaseLabel} ${clock}`;
174
+ let timerStatus = `${phaseLabel} ${clock} left`;
175
+ if (isIdle) {
176
+ timerSignal = "Ready";
177
+ timerStatus = "";
178
+ }
179
+ else if (timer.endsAt === undefined) {
180
+ timerSignal = "Paused";
181
+ timerStatus = `${phaseLabel} paused at ${clock}`;
182
+ }
183
+ const realtime = [
184
+ new Date(now).toTimeString().slice(0, 8),
185
+ timerStatus,
186
+ message,
187
+ ]
188
+ .filter(Boolean)
189
+ .join(" | ");
190
+ const metrics = [
191
+ {
192
+ label: "Character Progression",
193
+ value: percentOf(levelExperience, experiencePerLevel),
194
+ detail: `${experiencePerLevel - levelExperience} XP to level ${level + 1}.`,
195
+ signal: `LV ${level}`,
196
+ badgeColor: "blue",
197
+ numberColor: "cyanBright",
198
+ },
199
+ {
200
+ label: "Tomato Timer",
201
+ value: percentOf(today.focusSessions, dailyGoals.focusSessions),
202
+ detail: `${today.focusSessions} of ${dailyGoals.focusSessions} focus sessions today.`,
203
+ ...goalSignal(today.focusSessions, dailyGoals.focusSessions),
204
+ numberColor: "greenBright",
205
+ },
206
+ {
207
+ label: "Diet Tracker",
208
+ value: percentOf(today.meals, dailyGoals.meals),
209
+ detail: `${today.meals} of ${dailyGoals.meals} meals, ${today.calories} kcal today.`,
210
+ ...goalSignal(today.meals, dailyGoals.meals),
211
+ numberColor: "yellowBright",
212
+ },
213
+ {
214
+ label: "Workout Tracker",
215
+ value: percentOf(today.workoutMinutes, dailyGoals.workoutMinutes),
216
+ detail: `${today.workoutMinutes} of ${dailyGoals.workoutMinutes} workout minutes today.`,
217
+ ...goalSignal(today.workoutMinutes, dailyGoals.workoutMinutes),
218
+ numberColor: "magentaBright",
219
+ },
220
+ ];
221
+ const menuItems = [
222
+ {
223
+ label: "Tomato Timer",
224
+ signal: timerSignal,
225
+ description: `Enter starts or pauses a ${durations.focus}-minute focus. Each finished focus earns ${durations.focus} XP, then a ${durations.break}-minute break begins.`,
226
+ color: "greenBright",
227
+ },
228
+ {
229
+ label: "Diet Tracker",
230
+ signal: `${today.meals} meals`,
231
+ description: `Enter logs a meal as food and optional calories, e.g. Oatmeal 350. Each meal earns ${experiencePerMeal} XP.`,
232
+ color: "yellowBright",
233
+ },
234
+ {
235
+ label: "Workout Tracker",
236
+ signal: `${today.workoutMinutes} min`,
237
+ description: "Enter logs a workout as activity and minutes, e.g. Run 30. Each minute earns 1 XP.",
238
+ color: "magentaBright",
239
+ },
240
+ {
241
+ label: "Everyday Quotes",
242
+ signal: "New",
243
+ description: `Enter draws a new quote. It also refreshes every ${quoteRefreshMinutes} minutes, from API Ninjas when API_NINJAS_KEY is set.`,
244
+ color: "cyanBright",
245
+ },
246
+ ];
247
+ const terminalWidth = columns || 100;
248
+ const panelWidth = Math.min(clamp(terminalWidth - 4, 68, 112), terminalWidth);
249
+ const contentWidth = Math.max(panelWidth - 4, 40);
250
+ const shouldStackTopRow = contentWidth < 88;
251
+ const characterWidth = shouldStackTopRow ? contentWidth : 32;
252
+ const statusWidth = shouldStackTopRow
253
+ ? contentWidth
254
+ : Math.max(contentWidth - characterWidth - 3, 32);
255
+ const menuColumns = contentWidth < 56 ? 1 : 2;
256
+ return (React.createElement(Box, { flexDirection: "column", width: panelWidth },
257
+ React.createElement(Box, { borderStyle: "round", borderColor: "gray", flexDirection: "column", paddingX: 1, paddingY: 1, width: panelWidth },
258
+ React.createElement(Text, { color: "cyanBright" }, "TERMINAL SIGMA"),
259
+ React.createElement(Text, { color: "gray", wrap: "truncate-end" }, realtime),
260
+ React.createElement(Box, { flexDirection: shouldStackTopRow ? "column" : "row", justifyContent: "space-between", marginTop: 1 },
261
+ React.createElement(StatusPanel, { metrics: metrics, quote: quote, width: statusWidth }),
262
+ React.createElement(Box, { marginLeft: shouldStackTopRow ? 0 : 3, marginTop: shouldStackTopRow ? 1 : 0 },
263
+ React.createElement(Character, { level: level, name: options.name, width: characterWidth }))),
264
+ React.createElement(Box, { marginTop: 1 },
265
+ React.createElement(Text, { color: "gray" }, "-".repeat(contentWidth))),
266
+ React.createElement(Box, { marginTop: 1 },
267
+ React.createElement(MenuGrid, { columns: menuColumns, isActive: !entry, items: menuItems, title: "NAVIGATION MENU", width: contentWidth, onSelect: selectMenu })),
268
+ entry ? (React.createElement(Box, { marginTop: 1 },
269
+ React.createElement(Text, { color: "cyanBright" }, entry === "meal" ? "Meal > " : "Workout > "),
270
+ React.createElement(TextInput, { placeholder: entry === "meal"
271
+ ? "Oatmeal 350, Enter to log, Esc to cancel"
272
+ : "Run 30, Enter to log, Esc to cancel", onSubmit: submitEntry }))) : null)));
273
+ }
274
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../source/commands/index.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,296 @@
1
+ import { Badge } from "@inkjs/ui";
2
+ import React from "react";
3
+ import { Box, Text } from "ink";
4
+ const beltShape = String.raw ` /_\ `;
5
+ const visorCrest = String.raw ` /^\ `;
6
+ const hoodCrest = String.raw ` /~\ `;
7
+ const backslash = String.raw `\ `.trimEnd();
8
+ const walkStride = `/ ${backslash}`;
9
+ const armorOptions = {
10
+ "scout-weave": {
11
+ label: "Scout Weave",
12
+ color: "greenBright",
13
+ chest: "|=^=|",
14
+ belt: beltShape,
15
+ },
16
+ "carbon-shell": {
17
+ label: "Carbon Shell",
18
+ color: "yellowBright",
19
+ chest: "|###|",
20
+ belt: beltShape,
21
+ },
22
+ "bulwark-plate": {
23
+ label: "Bulwark Plate",
24
+ color: "cyanBright",
25
+ chest: "|*#*|",
26
+ belt: beltShape,
27
+ },
28
+ };
29
+ const weaponOptions = {
30
+ "arc-blade": {
31
+ label: "Arc Blade",
32
+ color: "magentaBright",
33
+ top: " /",
34
+ middle: "==>",
35
+ bottom: ` ${backslash}`,
36
+ },
37
+ "pulse-rifle": {
38
+ label: "Pulse Rifle",
39
+ color: "redBright",
40
+ top: " _",
41
+ middle: "-|>",
42
+ bottom: " /",
43
+ },
44
+ "signal-staff": {
45
+ label: "Signal Staff",
46
+ color: "blueBright",
47
+ top: " *",
48
+ middle: " |",
49
+ bottom: " |",
50
+ },
51
+ };
52
+ const helmetOptions = {
53
+ "signal-visor": {
54
+ label: "Signal Visor",
55
+ color: "cyanBright",
56
+ crest: visorCrest,
57
+ frameLeft: "[",
58
+ frameRight: "]",
59
+ },
60
+ "horned-guard": {
61
+ label: "Horned Guard",
62
+ color: "yellowBright",
63
+ crest: `/^^${backslash}`,
64
+ frameLeft: "{",
65
+ frameRight: "}",
66
+ },
67
+ "hood-shell": {
68
+ label: "Hood Shell",
69
+ color: "magentaBright",
70
+ crest: hoodCrest,
71
+ frameLeft: "<",
72
+ frameRight: ">",
73
+ },
74
+ };
75
+ const backpackOptions = {
76
+ "field-pack": {
77
+ label: "Field Pack",
78
+ color: "greenBright",
79
+ top: "[]",
80
+ middle: "[]",
81
+ bottom: "[]",
82
+ },
83
+ "cargo-rig": {
84
+ label: "Cargo Rig",
85
+ color: "yellowBright",
86
+ top: "{}",
87
+ middle: "{}",
88
+ bottom: "{}",
89
+ },
90
+ "reactor-pack": {
91
+ label: "Reactor Pack",
92
+ color: "cyanBright",
93
+ top: "()",
94
+ middle: "()",
95
+ bottom: "()",
96
+ },
97
+ };
98
+ const animationFrames = [
99
+ {
100
+ mode: "walk",
101
+ leftArm: "/",
102
+ rightArm: "-",
103
+ legs: walkStride,
104
+ expression: "o_o",
105
+ callout: "Stride calibrated.",
106
+ },
107
+ {
108
+ mode: "walk",
109
+ leftArm: "<",
110
+ rightArm: backslash,
111
+ legs: "| /",
112
+ expression: "o_o",
113
+ callout: "Route locked.",
114
+ },
115
+ {
116
+ mode: "talk",
117
+ leftArm: "/",
118
+ rightArm: "^",
119
+ legs: walkStride,
120
+ expression: "o-o",
121
+ callout: "Telemetry sounds clean.",
122
+ },
123
+ {
124
+ mode: "talk",
125
+ leftArm: "/",
126
+ rightArm: "~",
127
+ legs: walkStride,
128
+ expression: "o_o",
129
+ callout: "Backlog pressure nominal.",
130
+ },
131
+ {
132
+ mode: "guard",
133
+ leftArm: "/",
134
+ rightArm: backslash,
135
+ legs: walkStride,
136
+ expression: "o_o",
137
+ callout: "Holding formation.",
138
+ },
139
+ ];
140
+ // Weakest first. One slot upgrades per level from level 2, then every 4 levels per slot.
141
+ const weaponTiers = [
142
+ "signal-staff",
143
+ "pulse-rifle",
144
+ "arc-blade",
145
+ ];
146
+ const armorTiers = [
147
+ "scout-weave",
148
+ "carbon-shell",
149
+ "bulwark-plate",
150
+ ];
151
+ const helmetTiers = [
152
+ "hood-shell",
153
+ "signal-visor",
154
+ "horned-guard",
155
+ ];
156
+ const backpackTiers = [
157
+ "field-pack",
158
+ "cargo-rig",
159
+ "reactor-pack",
160
+ ];
161
+ const tierOf = (tiers, level, slot) => {
162
+ const tier = Math.floor((level - 2 - slot) / 4) + 1;
163
+ const option = tiers[Math.min(Math.max(tier, 0), tiers.length - 1)];
164
+ if (option === undefined) {
165
+ throw new Error("Character gear tiers are required.");
166
+ }
167
+ return option;
168
+ };
169
+ export const loadoutOf = (level) => ({
170
+ weapon: tierOf(weaponTiers, level, 0),
171
+ armor: tierOf(armorTiers, level, 1),
172
+ helmet: tierOf(helmetTiers, level, 2),
173
+ backpack: tierOf(backpackTiers, level, 3),
174
+ });
175
+ const modeBadgeColor = {
176
+ walk: "blue",
177
+ talk: "green",
178
+ guard: "yellow",
179
+ };
180
+ const modeLabel = {
181
+ walk: "WALK",
182
+ talk: "TALK",
183
+ guard: "GUARD",
184
+ };
185
+ const calloutColor = {
186
+ walk: "cyanBright",
187
+ talk: "magentaBright",
188
+ guard: "yellowBright",
189
+ };
190
+ function SpriteRow({ indent, segments }) {
191
+ return (React.createElement(Box, { marginLeft: indent }, segments.map((segment) => (React.createElement(Text, { key: segment.key, color: segment.color }, segment.text)))));
192
+ }
193
+ function LoadoutRow({ label, value, color }) {
194
+ return (React.createElement(Box, { justifyContent: "space-between" },
195
+ React.createElement(Text, { color: "gray" }, label),
196
+ React.createElement(Text, { color: color }, value)));
197
+ }
198
+ export default function Character({ width, name, level }) {
199
+ const [frameIndex, setFrameIndex] = React.useState(0);
200
+ React.useEffect(() => {
201
+ const interval = setInterval(() => {
202
+ setFrameIndex((current) => (current + 1) % animationFrames.length);
203
+ }, 240);
204
+ return () => {
205
+ clearInterval(interval);
206
+ };
207
+ }, []);
208
+ const fallbackFrame = animationFrames[0];
209
+ if (!fallbackFrame) {
210
+ throw new Error("Character animation frames are required.");
211
+ }
212
+ const frame = animationFrames[frameIndex] ?? fallbackFrame;
213
+ const { armor, weapon, helmet, backpack } = loadoutOf(level);
214
+ const armorView = armorOptions[armor];
215
+ const weaponView = weaponOptions[weapon];
216
+ const helmetView = helmetOptions[helmet];
217
+ const backpackView = backpackOptions[backpack];
218
+ const face = `${helmetView.frameLeft}${frame.expression}${helmetView.frameRight}`;
219
+ const spriteWidth = 13;
220
+ const contentWidth = Math.max(width - 4, spriteWidth);
221
+ const indent = Math.max(Math.floor((contentWidth - spriteWidth) / 2), 0);
222
+ return (React.createElement(Box, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1, paddingY: 1, width: width },
223
+ React.createElement(Box, { justifyContent: "space-between" },
224
+ React.createElement(Text, { color: "whiteBright" }, `${name} LV ${level}`),
225
+ React.createElement(Badge, { color: modeBadgeColor[frame.mode] }, modeLabel[frame.mode])),
226
+ React.createElement(Text, { color: "gray" }, "Gear unlocks as you level"),
227
+ React.createElement(Box, { marginTop: 1 },
228
+ React.createElement(Text, { color: calloutColor[frame.mode] }, `"${frame.callout}"`)),
229
+ React.createElement(Box, { flexDirection: "column", marginTop: 1 },
230
+ React.createElement(SpriteRow, { indent: indent, segments: [
231
+ { key: "indent", text: " " },
232
+ {
233
+ key: "crest",
234
+ text: helmetView.crest,
235
+ color: helmetView.color,
236
+ },
237
+ ] }),
238
+ React.createElement(SpriteRow, { indent: indent, segments: [
239
+ {
240
+ key: "pack-top",
241
+ text: backpackView.top,
242
+ color: backpackView.color,
243
+ },
244
+ { key: "face-gap", text: " " },
245
+ { key: "face", text: face, color: helmetView.color },
246
+ {
247
+ key: "weapon-top",
248
+ text: weaponView.top,
249
+ color: weaponView.color,
250
+ },
251
+ ] }),
252
+ React.createElement(SpriteRow, { indent: indent, segments: [
253
+ {
254
+ key: "pack-middle",
255
+ text: backpackView.middle,
256
+ color: backpackView.color,
257
+ },
258
+ { key: "left-arm", text: frame.leftArm, color: armorView.color },
259
+ { key: "chest", text: armorView.chest, color: armorView.color },
260
+ {
261
+ key: "right-arm",
262
+ text: frame.rightArm,
263
+ color: armorView.color,
264
+ },
265
+ {
266
+ key: "weapon-middle",
267
+ text: weaponView.middle,
268
+ color: weaponView.color,
269
+ },
270
+ ] }),
271
+ React.createElement(SpriteRow, { indent: indent, segments: [
272
+ {
273
+ key: "pack-bottom",
274
+ text: backpackView.bottom,
275
+ color: backpackView.color,
276
+ },
277
+ { key: "belt-gap-left", text: " " },
278
+ { key: "belt", text: armorView.belt, color: armorView.color },
279
+ { key: "belt-gap-right", text: " " },
280
+ {
281
+ key: "weapon-bottom",
282
+ text: weaponView.bottom,
283
+ color: weaponView.color,
284
+ },
285
+ ] }),
286
+ React.createElement(SpriteRow, { indent: indent, segments: [
287
+ { key: "leg-indent", text: " " },
288
+ { key: "legs", text: frame.legs },
289
+ ] })),
290
+ React.createElement(Box, { flexDirection: "column", marginTop: 1 },
291
+ React.createElement(LoadoutRow, { label: "Armor", value: armorView.label, color: armorView.color }),
292
+ React.createElement(LoadoutRow, { label: "Weapon", value: weaponView.label, color: weaponView.color }),
293
+ React.createElement(LoadoutRow, { label: "Helmet", value: helmetView.label, color: helmetView.color }),
294
+ React.createElement(LoadoutRow, { label: "Backpack", value: backpackView.label, color: backpackView.color }))));
295
+ }
296
+ //# sourceMappingURL=character.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"character.js","sourceRoot":"","sources":["../../source/components/character.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import React from "react";
2
+ import { Box, Text, useInput } from "ink";
3
+ const clamp = (value, minimum, maximum) => Math.min(Math.max(value, minimum), maximum);
4
+ const formatMenuCell = (item, index, isSelected, cellWidth) => {
5
+ const prefix = isSelected ? ">" : " ";
6
+ const label = `${prefix} [${index + 1}] ${item.label}`;
7
+ const signal = item.signal.toUpperCase();
8
+ const gapWidth = Math.max(cellWidth - label.length - signal.length, 1);
9
+ return `${label}${" ".repeat(gapWidth)}${signal}`;
10
+ };
11
+ export default function MenuGrid({ title, width, items: menuItems, onSelect, columns = 2, isActive = true, }) {
12
+ const [selectedIndex, setSelectedIndex] = React.useState(0);
13
+ const safeColumns = Math.max(columns, 1);
14
+ const gapWidth = safeColumns > 1 ? 3 : 0;
15
+ const cellWidth = Math.max(Math.floor((width - gapWidth * (safeColumns - 1)) / safeColumns), 20);
16
+ useInput((input, key) => {
17
+ if (key.leftArrow || input === "h") {
18
+ setSelectedIndex((current) => Math.max(current - 1, 0));
19
+ return;
20
+ }
21
+ if (key.rightArrow || input === "l") {
22
+ setSelectedIndex((current) => Math.min(current + 1, menuItems.length - 1));
23
+ return;
24
+ }
25
+ if (key.upArrow || input === "k") {
26
+ setSelectedIndex((current) => Math.max(current - safeColumns, 0));
27
+ return;
28
+ }
29
+ if (key.downArrow || input === "j") {
30
+ setSelectedIndex((current) => Math.min(current + safeColumns, menuItems.length - 1));
31
+ return;
32
+ }
33
+ if (key.return) {
34
+ onSelect(selectedIndex);
35
+ return;
36
+ }
37
+ const numericChoice = Number.parseInt(input, 10);
38
+ if (Number.isNaN(numericChoice)) {
39
+ return;
40
+ }
41
+ const nextIndex = clamp(numericChoice - 1, 0, menuItems.length - 1);
42
+ setSelectedIndex(nextIndex);
43
+ }, { isActive });
44
+ const activeItem = menuItems[selectedIndex] ?? menuItems[0];
45
+ const rowCount = Math.ceil(menuItems.length / safeColumns);
46
+ const rows = Array.from({ length: rowCount }, (_, rowIndex) => menuItems.slice(rowIndex * safeColumns, rowIndex * safeColumns + safeColumns));
47
+ return (React.createElement(Box, { flexDirection: "column", width: width },
48
+ React.createElement(Box, { justifyContent: "space-between" },
49
+ React.createElement(Text, { color: "greenBright" }, title),
50
+ React.createElement(Text, { color: "gray" }, "Arrows / hjkl / Enter / q")),
51
+ React.createElement(Box, { flexDirection: "column", marginTop: 1 }, rows.map((row, rowIndex) => (React.createElement(Box, { key: row.map((item) => item.label).join("-") }, row.map((item, columnIndex) => {
52
+ const index = rowIndex * safeColumns + columnIndex;
53
+ const isSelected = index === selectedIndex;
54
+ const marginRight = columnIndex < row.length - 1 ? gapWidth : 0;
55
+ return (React.createElement(Box, { key: item.label, marginRight: marginRight, width: cellWidth },
56
+ React.createElement(Text, { backgroundColor: isSelected ? "cyan" : undefined, color: isSelected ? "black" : item.color }, formatMenuCell(item, index, isSelected, cellWidth))));
57
+ }))))),
58
+ activeItem ? (React.createElement(Box, { marginTop: 1 },
59
+ React.createElement(Text, { color: activeItem.color }, activeItem.description))) : null));
60
+ }
61
+ //# sourceMappingURL=menu-grid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menu-grid.js","sourceRoot":"","sources":["../../source/components/menu-grid.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { Badge, ProgressBar } from "@inkjs/ui";
2
+ import React from "react";
3
+ import { Box, Text } from "ink";
4
+ export default function StatusPanel({ width, quote, metrics, }) {
5
+ const progressWidth = Math.max(width - 2, 18);
6
+ return (React.createElement(Box, { flexDirection: "column", width: width },
7
+ React.createElement(Text, { color: "yellowBright" }, "STATUS BOARD"),
8
+ React.createElement(Text, { color: "gray" }, `"${quote.quote}" - ${quote.author}`),
9
+ metrics.map((metric) => (React.createElement(Box, { key: metric.label, flexDirection: "column", marginTop: 1 },
10
+ React.createElement(Box, { justifyContent: "space-between" },
11
+ React.createElement(Text, { color: "whiteBright" }, metric.label),
12
+ React.createElement(Text, { color: metric.numberColor }, `${metric.value}%`)),
13
+ React.createElement(Box, { width: progressWidth },
14
+ React.createElement(ProgressBar, { value: metric.value })),
15
+ React.createElement(Box, { justifyContent: "space-between" },
16
+ React.createElement(Text, { color: "gray" }, metric.detail),
17
+ React.createElement(Badge, { color: metric.badgeColor }, metric.signal)))))));
18
+ }
19
+ //# sourceMappingURL=status-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-panel.js","sourceRoot":"","sources":["../../source/components/status-panel.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAqBhC,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EACnC,KAAK,EACL,KAAK,EACL,OAAO,GACW;IAClB,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;IAE9C,OAAO,CACN,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,KAAK,EAAE,KAAK;QACvC,oBAAC,IAAI,IAAC,KAAK,EAAC,cAAc,mBAAoB;QAC9C,oBAAC,IAAI,IAAC,KAAK,EAAC,MAAM,IAAE,IAAI,KAAK,CAAC,KAAK,OAAO,KAAK,CAAC,MAAM,EAAE,CAAQ;QAE/D,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CACxB,oBAAC,GAAG,IAAC,GAAG,EAAE,MAAM,CAAC,KAAK,EAAE,aAAa,EAAC,QAAQ,EAAC,SAAS,EAAE,CAAC;YAC1D,oBAAC,GAAG,IAAC,cAAc,EAAC,eAAe;gBAClC,oBAAC,IAAI,IAAC,KAAK,EAAC,aAAa,IAAE,MAAM,CAAC,KAAK,CAAQ;gBAC/C,oBAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,WAAW,IAAG,GAAG,MAAM,CAAC,KAAK,GAAG,CAAQ,CACvD;YACN,oBAAC,GAAG,IAAC,KAAK,EAAE,aAAa;gBACxB,oBAAC,WAAW,IAAC,KAAK,EAAE,MAAM,CAAC,KAAK,GAAI,CAC/B;YACN,oBAAC,GAAG,IAAC,cAAc,EAAC,eAAe;gBAClC,oBAAC,IAAI,IAAC,KAAK,EAAC,MAAM,IAAE,MAAM,CAAC,MAAM,CAAQ;gBACzC,oBAAC,KAAK,IAAC,KAAK,EAAE,MAAM,CAAC,UAAU,IAAG,MAAM,CAAC,MAAM,CAAS,CACnD,CACD,CACN,CAAC,CACG,CACN,CAAC;AACH,CAAC"}
@@ -0,0 +1,82 @@
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import path from "node:path";
4
+ import process from "node:process";
5
+ import zod from "zod";
6
+ const timestamp = zod.iso.datetime({ offset: true });
7
+ const progressSchema = zod.object({
8
+ focus: zod
9
+ .array(zod.object({ at: timestamp, minutes: zod.number().positive() }))
10
+ .default([]),
11
+ meals: zod
12
+ .array(zod.object({
13
+ at: timestamp,
14
+ food: zod.string().min(1),
15
+ calories: zod.number().nonnegative().optional(),
16
+ }))
17
+ .default([]),
18
+ workouts: zod
19
+ .array(zod.object({
20
+ at: timestamp,
21
+ activity: zod.string().min(1),
22
+ minutes: zod.number().positive(),
23
+ }))
24
+ .default([]),
25
+ });
26
+ export const experiencePerLevel = 100;
27
+ export const experiencePerMeal = 5;
28
+ export const dailyGoals = { focusSessions: 4, meals: 3, workoutMinutes: 30 };
29
+ export const progressFile = () => path.join(process.env.TERMINAL_SIGMA_HOME ?? path.join(homedir(), ".terminal-sigma"), "progress.json");
30
+ export function loadProgress(file) {
31
+ if (!existsSync(file)) {
32
+ return progressSchema.parse({});
33
+ }
34
+ try {
35
+ return progressSchema.parse(JSON.parse(readFileSync(file, "utf8")));
36
+ }
37
+ catch (error) {
38
+ throw new Error(`${file} is unreadable, so Terminal-Sigma will not touch it. Fix or move it, then restart.\n${String(error)}`, { cause: error });
39
+ }
40
+ }
41
+ export function saveProgress(file, progress) {
42
+ mkdirSync(path.dirname(file), { recursive: true });
43
+ // Validate, write, then rename: never save what loadProgress would reject, and
44
+ // a crash mid-write never truncates the journey.
45
+ const valid = progressSchema.parse(progress);
46
+ const temporary = `${file}.tmp`;
47
+ writeFileSync(temporary, `${JSON.stringify(valid, null, "\t")}\n`);
48
+ renameSync(temporary, file);
49
+ }
50
+ // Experience is derived from the entries, so hand-editing the file never desyncs it.
51
+ export function experienceOf(progress) {
52
+ const sum = (values) => values.reduce((total, value) => total + value, 0);
53
+ return (sum(progress.focus.map((entry) => entry.minutes)) +
54
+ progress.meals.length * experiencePerMeal +
55
+ sum(progress.workouts.map((entry) => entry.minutes)));
56
+ }
57
+ export const levelOf = (experience) => Math.floor(experience / experiencePerLevel) + 1;
58
+ export function todayOf(progress, now) {
59
+ const today = new Date(now).toDateString();
60
+ const isToday = ({ at }) => new Date(at).toDateString() === today;
61
+ const meals = progress.meals.filter((meal) => isToday(meal));
62
+ return {
63
+ focusSessions: progress.focus.filter((focus) => isToday(focus)).length,
64
+ meals: meals.length,
65
+ calories: meals.reduce((total, meal) => total + (meal.calories ?? 0), 0),
66
+ workoutMinutes: progress.workouts
67
+ .filter((workout) => isToday(workout))
68
+ .reduce((total, workout) => total + workout.minutes, 0),
69
+ };
70
+ }
71
+ // "Oatmeal 350" -> { label: "Oatmeal", amount: 350 }; "Salad" -> { label: "Salad" }
72
+ export function parseEntry(text) {
73
+ const match = /^(?<label>.+?)(?:\s+(?<amount>\d+))?$/v.exec(text.trim());
74
+ if (!match?.groups?.label) {
75
+ return undefined;
76
+ }
77
+ const { label, amount } = match.groups;
78
+ return amount === undefined
79
+ ? { label }
80
+ : { label, amount: Number.parseInt(amount, 10) };
81
+ }
82
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../source/progress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ import process from "node:process";
2
+ import zod from "zod";
3
+ export const bundledQuotes = [
4
+ { quote: "A healthy mind in a healthy body.", author: "Juvenal" },
5
+ {
6
+ quote: "Do what you can, with what you have, where you are.",
7
+ author: "Theodore Roosevelt",
8
+ },
9
+ {
10
+ quote: "Energy and persistence conquer all things.",
11
+ author: "Benjamin Franklin",
12
+ },
13
+ { quote: "Fall seven times, stand up eight.", author: "Japanese Proverb" },
14
+ {
15
+ quote: "First say to yourself what you would be; and then do what you have to do.",
16
+ author: "Epictetus",
17
+ },
18
+ {
19
+ quote: "Habit is a cable; we weave a thread of it each day, and at last we cannot break it.",
20
+ author: "Horace Mann",
21
+ },
22
+ {
23
+ quote: "He who has a why to live can bear almost any how.",
24
+ author: "Friedrich Nietzsche",
25
+ },
26
+ {
27
+ quote: "It does not matter how slowly you go as long as you do not stop.",
28
+ author: "Confucius",
29
+ },
30
+ {
31
+ quote: "It is not that we have a short time to live, but that we waste a lot of it.",
32
+ author: "Seneca",
33
+ },
34
+ {
35
+ quote: "Knowing is not enough; we must apply.",
36
+ author: "Johann Wolfgang von Goethe",
37
+ },
38
+ { quote: "Lost time is never found again.", author: "Benjamin Franklin" },
39
+ {
40
+ quote: "No man is free who is not master of himself.",
41
+ author: "Epictetus",
42
+ },
43
+ {
44
+ quote: "Patience is bitter, but its fruit is sweet.",
45
+ author: "Jean-Jacques Rousseau",
46
+ },
47
+ {
48
+ quote: "The journey of a thousand miles begins with one step.",
49
+ author: "Lao Tzu",
50
+ },
51
+ {
52
+ quote: "Waste no more time arguing about what a good man should be. Be one.",
53
+ author: "Marcus Aurelius",
54
+ },
55
+ {
56
+ quote: "We suffer more often in imagination than in reality.",
57
+ author: "Seneca",
58
+ },
59
+ { quote: "Well begun is half done.", author: "Aristotle" },
60
+ { quote: "Well done is better than well said.", author: "Benjamin Franklin" },
61
+ ];
62
+ export const quoteRefreshMinutes = 30;
63
+ export const randomBundledQuote = () => bundledQuotes[Math.floor(Math.random() * bundledQuotes.length)] ?? {
64
+ quote: "Well begun is half done.",
65
+ author: "Aristotle",
66
+ };
67
+ const apiResponse = zod
68
+ .array(zod.object({ quote: zod.string().min(1), author: zod.string() }))
69
+ .min(1);
70
+ // API Ninjas only when the user brings a key; any failure falls back to the bundled list.
71
+ export async function fetchQuote(apiKey = process.env.API_NINJAS_KEY) {
72
+ if (!apiKey) {
73
+ return randomBundledQuote();
74
+ }
75
+ try {
76
+ const response = await fetch("https://api.api-ninjas.com/v2/quotes", {
77
+ headers: { "X-Api-Key": apiKey },
78
+ signal: AbortSignal.timeout(5000),
79
+ });
80
+ const [first] = apiResponse.parse(await response.json());
81
+ return first ?? randomBundledQuote();
82
+ }
83
+ catch {
84
+ return randomBundledQuote();
85
+ }
86
+ }
87
+ //# sourceMappingURL=quotes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quotes.js","sourceRoot":"","sources":["../source/quotes.ts"],"names":[],"mappings":"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"}
package/build/timer.js ADDED
@@ -0,0 +1,33 @@
1
+ const minute = 60_000;
2
+ export const idleTimer = (durations) => ({
3
+ phase: "focus",
4
+ remaining: durations.focus * minute,
5
+ });
6
+ export const remainingOf = (timer, now) => Math.max((timer.endsAt ?? now + timer.remaining) - now, 0);
7
+ export const toggleTimer = (timer, now) => timer.endsAt === undefined
8
+ ? {
9
+ phase: timer.phase,
10
+ remaining: timer.remaining,
11
+ endsAt: now + timer.remaining,
12
+ }
13
+ : { phase: timer.phase, remaining: remainingOf(timer, now) };
14
+ // A finished focus starts the break right away; a finished break waits for the user.
15
+ export function advanceTimer(timer, now, durations) {
16
+ if (timer.endsAt === undefined || now < timer.endsAt) {
17
+ return { timer };
18
+ }
19
+ if (timer.phase === "focus") {
20
+ const remaining = durations.break * minute;
21
+ return {
22
+ timer: { phase: "break", remaining, endsAt: now + remaining },
23
+ finished: "focus",
24
+ };
25
+ }
26
+ return { timer: idleTimer(durations), finished: "break" };
27
+ }
28
+ export function formatClock(milliseconds) {
29
+ const seconds = Math.ceil(milliseconds / 1000);
30
+ const pad = (value) => String(value).padStart(2, "0");
31
+ return `${pad(Math.floor(seconds / 60))}:${pad(seconds % 60)}`;
32
+ }
33
+ //# sourceMappingURL=timer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timer.js","sourceRoot":"","sources":["../source/timer.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,GAAG,MAAM,CAAC;AAEtB,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,SAAoB,EAAS,EAAE,CAAC,CAAC;IAC1D,KAAK,EAAE,OAAO;IACd,SAAS,EAAE,SAAS,CAAC,KAAK,GAAG,MAAM;CACnC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAY,EAAE,GAAW,EAAE,EAAE,CACxD,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;AAE5D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAY,EAAE,GAAW,EAAS,EAAE,CAC/D,KAAK,CAAC,MAAM,KAAK,SAAS;IACzB,CAAC,CAAC;QACA,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,MAAM,EAAE,GAAG,GAAG,KAAK,CAAC,SAAS;KAC7B;IACF,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;AAE/D,qFAAqF;AACrF,MAAM,UAAU,YAAY,CAC3B,KAAY,EACZ,GAAW,EACX,SAAoB;IAEpB,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACtD,OAAO,EAAE,KAAK,EAAE,CAAC;IAClB,CAAC;IAED,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,GAAG,MAAM,CAAC;QAC3C,OAAO;YACN,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,SAAS,EAAE;YAC7D,QAAQ,EAAE,OAAO;SACjB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,YAAoB;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAE9D,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC;AAChE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "author": {
3
+ "name": "SiegeSailor",
4
+ "email": "siegesailor@gmail.com",
5
+ "url": "https://jinyu-zhang.com/"
6
+ },
7
+ "name": "@siegesailor/terminal-sigma",
8
+ "keywords": [
9
+ "command-line-tool",
10
+ "ink",
11
+ "pastel",
12
+ "pomodoro",
13
+ "self-development",
14
+ "terminal-dashboard",
15
+ "typescript"
16
+ ],
17
+ "description": "A long-running terminal dashboard that turns self-development into a game: a Tomato Timer, diet and workout trackers, everyday quotes, and a character that levels up with you.",
18
+ "homepage": "https://github.com/SiegeSailor/Terminal-Sigma",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/SiegeSailor/Terminal-Sigma.git"
22
+ },
23
+ "bugs": {
24
+ "url": "https://github.com/SiegeSailor/Terminal-Sigma/issues"
25
+ },
26
+ "version": "1.0.0",
27
+ "bin": {
28
+ "siegesailor-terminal-sigma": "build/command-line-interface.js"
29
+ },
30
+ "main": "build/command-line-interface.js",
31
+ "files": [
32
+ "build/",
33
+ "!build/tests/"
34
+ ],
35
+ "license": "MIT",
36
+ "private": false,
37
+ "type": "module",
38
+ "engines": {
39
+ "node": ">= 22"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public",
43
+ "provenance": true
44
+ },
45
+ "scripts": {
46
+ "prepare": "husky",
47
+ "build": "node --input-type=module --eval \"import {rmSync} from 'node:fs'; rmSync('build', {recursive: true, force: true}); rmSync('build-cache', {force: true});\" && tsc && tsc-alias && node --input-type=module --eval \"import {chmodSync} from 'node:fs'; chmodSync('build/command-line-interface.js', 0o755);\"",
48
+ "prepack": "npm run build",
49
+ "start": "npm run build && node build/command-line-interface.js",
50
+ "test": "prettier --check --ignore-unknown . && xo && ava"
51
+ },
52
+ "dependencies": {
53
+ "@inkjs/ui": "2.0.0",
54
+ "ink": "7.0.0",
55
+ "meow": "14.1.0",
56
+ "pastel": "4.0.1",
57
+ "react": "19.2.5",
58
+ "zod": "4.3.6"
59
+ },
60
+ "devDependencies": {
61
+ "@ava/typescript": "6.0.0",
62
+ "@commitlint/cli": "20.5.0",
63
+ "@commitlint/config-conventional": "20.5.0",
64
+ "@semantic-release/git": "11.0.1",
65
+ "@types/react": "19.2.14",
66
+ "ava": "7.0.0",
67
+ "conventional-changelog-conventionalcommits": "9.3.1",
68
+ "husky": "9.1.7",
69
+ "ink-testing-library": "4.0.0",
70
+ "lint-staged": "16.4.0",
71
+ "prettier": "3.8.2",
72
+ "semantic-release": "25.0.9",
73
+ "ts-node": "10.9.2",
74
+ "tsc-alias": "1.8.16",
75
+ "typescript": "6.0.2",
76
+ "xo": "2.0.2"
77
+ },
78
+ "lint-staged": {
79
+ "*": [
80
+ "prettier --write --ignore-unknown"
81
+ ],
82
+ "*.{js,mts,ts,tsx}": [
83
+ "xo"
84
+ ]
85
+ }
86
+ }