motd-tool 1.0.2

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.
@@ -0,0 +1,28 @@
1
+ class MotdTool < Formula
2
+ desc "Tiny CLI that prints a random message of the day in your terminal"
3
+ homepage "https://github.com/AlucPro/motd-tool"
4
+ url "https://registry.npmjs.org/motd-tool/-/motd-tool-1.0.2.tgz"
5
+ sha256 "08afc5723eb1086d95e6a0752c168b324d708bf3ef0761d4effbb39eac2c1bc4"
6
+ license "MIT"
7
+
8
+ depends_on "node"
9
+
10
+ def install
11
+ libexec.install Dir["*"]
12
+ (bin/"xmotd").write_env_script libexec/"bin/xmotd.js", PATH => "#{Formula["node"].opt_bin}:#{ENV["PATH"]}"
13
+ end
14
+
15
+ def caveats
16
+ <<~EOS
17
+ Run:
18
+ xmotd init
19
+
20
+ to enable automatic once-per-day terminal messages in your shell.
21
+ EOS
22
+ end
23
+
24
+ test do
25
+ output = shell_output("#{bin}/xmotd --help")
26
+ assert_match "xmotd - tiny message of the day CLI", output
27
+ end
28
+ end
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 π™Όπš’πš—πš
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,184 @@
1
+ # motd-tool
2
+
3
+ Tiny CLI that prints a random message of the day in your terminal.
4
+
5
+ `xmotd` is built for developers who live in the shell and want something lighter than a dashboard, but more personal than a static prompt.
6
+
7
+ ## Why people install it
8
+
9
+ - `xmotd` prints a random line from your own local message library
10
+ - `xmotd init` shows one message automatically on the first terminal session of each day
11
+ - `xmotd add`, `remove`, `list`, `import`, and `export` keep the message library simple
12
+ - It is local-first, fast, and dependency-light at runtime
13
+
14
+ ## Quick look
15
+
16
+ ```bash
17
+ $ xmotd
18
+ Stay hungry, stay foolish.
19
+ ```
20
+
21
+ ```bash
22
+ $ xmotd add "Code is poetry"
23
+ Added: Code is poetry
24
+ ```
25
+
26
+ ```bash
27
+ $ xmotd list
28
+ 1. Stay hungry, stay foolish.
29
+ 2. Code is poetry
30
+ ```
31
+
32
+ ```bash
33
+ $ xmotd remove 2
34
+ Removed #2: Code is poetry
35
+ ```
36
+
37
+ ## Install
38
+
39
+ Install from npm:
40
+
41
+ ```bash
42
+ npm install -g motd-tool
43
+ ```
44
+
45
+ Install from Homebrew:
46
+
47
+ ```bash
48
+ brew install AlucPro/tap/motd-tool
49
+ ```
50
+
51
+ For local development, this repository uses `pnpm` and TypeScript:
52
+
53
+ ```bash
54
+ pnpm install
55
+ pnpm check
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ Print a random message:
61
+
62
+ ```bash
63
+ xmotd
64
+ ```
65
+
66
+ Add a message:
67
+
68
+ ```bash
69
+ xmotd add "Ship small, ship often"
70
+ ```
71
+
72
+ Remove a message by index or exact text:
73
+
74
+ ```bash
75
+ xmotd remove 2
76
+ xmotd remove "Ship small, ship often"
77
+ ```
78
+
79
+ List all messages:
80
+
81
+ ```bash
82
+ xmotd list
83
+ ```
84
+
85
+ Import messages from `.txt` or `.json`:
86
+
87
+ ```bash
88
+ xmotd import ./messages.txt
89
+ xmotd import ./messages.json
90
+ ```
91
+
92
+ Export your current library:
93
+
94
+ ```bash
95
+ xmotd export ./backup.json
96
+ xmotd export ./backup.txt
97
+ ```
98
+
99
+ Enable once-per-day automatic output in your shell:
100
+
101
+ ```bash
102
+ xmotd init
103
+ ```
104
+
105
+ Preview the shell hook:
106
+
107
+ ```bash
108
+ xmotd hook
109
+ ```
110
+
111
+ See where files are stored:
112
+
113
+ ```bash
114
+ xmotd paths
115
+ ```
116
+
117
+ ## Default behavior
118
+
119
+ After installation, `xmotd` starts with one built-in message:
120
+
121
+ ```text
122
+ Stay hungry, stay foolish.
123
+ ```
124
+
125
+ Every manual `xmotd` run selects a random message from your local library.
126
+
127
+ The automatic shell hook uses a separate state file so the message only appears once per local calendar day.
128
+
129
+ ## Message storage
130
+
131
+ `xmotd` stores data in standard XDG-style locations:
132
+
133
+ - Config: `~/.config/motd-tool/messages.json`
134
+ - State: `~/.local/state/motd-tool/state.json`
135
+
136
+ You can override these with `XDG_CONFIG_HOME` and `XDG_STATE_HOME`.
137
+
138
+ ## Release workflow
139
+
140
+ Project maintainers can use:
141
+
142
+ ```bash
143
+ pnpm release:check
144
+ ```
145
+
146
+ `pnpm release:check` runs build and tests, then updates the Homebrew formula SHA based on the npm tarball.
147
+
148
+ Release flow:
149
+
150
+ 1. Update `package.json` version
151
+ 2. Commit the release changes
152
+ 3. Push `main`
153
+ 4. Create and push a matching tag such as `v1.0.1`
154
+
155
+ ```bash
156
+ git add .
157
+ git commit -m "release: v1.0.1"
158
+ git push origin main
159
+ git tag v1.0.1
160
+ git push origin v1.0.1
161
+ ```
162
+
163
+ When the tag lands on GitHub, the `Release` workflow will:
164
+
165
+ - build and test the project
166
+ - publish `motd-tool` to npm with `NPM_TOKEN`
167
+ - rebuild the Homebrew formula with the new npm tarball SHA
168
+ - push `Formula/motd-tool.rb` to `AlucPro/homebrew-tap` with `HOMEBREW_TAP_TOKEN`
169
+ - create a GitHub Release with the packaged tarball
170
+
171
+ GitHub Actions included in this repo:
172
+
173
+ - `CI`: install, build, test, and pack on pushes and pull requests
174
+ - `Release`: publish to npm, update the Homebrew tap, and attach the package tarball when a `v*` tag is pushed
175
+
176
+ ## Contributing
177
+
178
+ Issues and pull requests are welcome.
179
+
180
+ The easiest way to contribute is to improve the default message set, shell support, and installation experience.
181
+
182
+ ## License
183
+
184
+ MIT
package/bin/xmotd.js ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { run } = require("../dist/src/cli");
4
+
5
+ run(process.argv.slice(2)).catch((error) => {
6
+ const message = error && error.message ? error.message : String(error);
7
+ console.error(`xmotd: ${message}`);
8
+ process.exitCode = 1;
9
+ });
@@ -0,0 +1,2 @@
1
+ export declare function maybePrintAutoMessage(): boolean;
2
+ export declare function run(argv: string[]): Promise<void>;
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.maybePrintAutoMessage = maybePrintAutoMessage;
7
+ exports.run = run;
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const hook_1 = require("./hook");
10
+ const store_1 = require("./store");
11
+ function printHelp() {
12
+ console.log(`xmotd - tiny message of the day CLI
13
+
14
+ Usage:
15
+ xmotd
16
+ xmotd add "Your message"
17
+ xmotd remove <index|exact message>
18
+ xmotd list
19
+ xmotd import <file.json|file.txt>
20
+ xmotd export <file.json|file.txt>
21
+ xmotd init [zsh|bash|fish]
22
+ xmotd hook [zsh|bash|fish]
23
+ xmotd paths
24
+
25
+ Options:
26
+ --auto Print only on the first terminal session of the day
27
+ -h, --help
28
+ -v, --version`);
29
+ }
30
+ function printVersion() {
31
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
32
+ const pkg = require(node_path_1.default.join(__dirname, "..", "..", "package.json"));
33
+ console.log(pkg.version);
34
+ }
35
+ function todayIsoDate() {
36
+ const now = new Date();
37
+ const year = now.getFullYear();
38
+ const month = String(now.getMonth() + 1).padStart(2, "0");
39
+ const day = String(now.getDate()).padStart(2, "0");
40
+ return `${year}-${month}-${day}`;
41
+ }
42
+ function printRandomMessage() {
43
+ (0, store_1.ensureStore)();
44
+ console.log((0, store_1.pickRandomMessage)());
45
+ }
46
+ function maybePrintAutoMessage() {
47
+ (0, store_1.ensureStore)();
48
+ const today = todayIsoDate();
49
+ const state = (0, store_1.getState)();
50
+ if (state.lastShownOn === today) {
51
+ return false;
52
+ }
53
+ console.log((0, store_1.pickRandomMessage)());
54
+ (0, store_1.setLastShownOn)(today);
55
+ return true;
56
+ }
57
+ function printMessages() {
58
+ (0, store_1.getMessages)().forEach((message, index) => {
59
+ console.log(`${index + 1}. ${message}`);
60
+ });
61
+ }
62
+ function handleInit(shellName) {
63
+ const shell = shellName || node_path_1.default.basename(process.env.SHELL || "");
64
+ const result = (0, hook_1.installHook)(shell);
65
+ if (result.changed) {
66
+ console.log(`Installed xmotd shell hook in ${result.rcFile}`);
67
+ console.log("Open a new terminal to see the first message of each day.");
68
+ return;
69
+ }
70
+ console.log(`xmotd shell hook already exists in ${result.rcFile}`);
71
+ }
72
+ function handlePaths() {
73
+ const paths = (0, store_1.getPaths)();
74
+ console.log(`config: ${paths.configDir}`);
75
+ console.log(`messages: ${paths.messagesFile}`);
76
+ console.log(`state: ${paths.stateFile}`);
77
+ console.log(`shellrc: ${(0, hook_1.resolveRcFile)()}`);
78
+ }
79
+ async function run(argv) {
80
+ const [command, ...rest] = argv;
81
+ if (!command) {
82
+ printRandomMessage();
83
+ return;
84
+ }
85
+ if (command === "--auto") {
86
+ maybePrintAutoMessage();
87
+ return;
88
+ }
89
+ if (command === "-h" || command === "--help" || command === "help") {
90
+ printHelp();
91
+ return;
92
+ }
93
+ if (command === "-v" || command === "--version" || command === "version") {
94
+ printVersion();
95
+ return;
96
+ }
97
+ if (command === "add") {
98
+ const added = (0, store_1.addMessage)(rest.join(" ").trim());
99
+ console.log(`Added: ${added}`);
100
+ return;
101
+ }
102
+ if (command === "remove") {
103
+ const target = rest.join(" ").trim();
104
+ const result = (0, store_1.removeMessage)(target);
105
+ console.log(`Removed #${result.index + 1}: ${result.removed}`);
106
+ return;
107
+ }
108
+ if (command === "list") {
109
+ printMessages();
110
+ return;
111
+ }
112
+ if (command === "import") {
113
+ const filePath = rest[0];
114
+ if (!filePath) {
115
+ throw new Error("import requires a file path");
116
+ }
117
+ const result = (0, store_1.importMessages)(filePath);
118
+ console.log(`Imported ${result.imported} message(s). Total: ${result.total}`);
119
+ return;
120
+ }
121
+ if (command === "export") {
122
+ const filePath = rest[0];
123
+ if (!filePath) {
124
+ throw new Error("export requires a file path");
125
+ }
126
+ const result = (0, store_1.exportMessages)(filePath);
127
+ console.log(`Exported ${result.count} message(s) to ${result.filePath}`);
128
+ return;
129
+ }
130
+ if (command === "init") {
131
+ handleInit(rest[0]);
132
+ return;
133
+ }
134
+ if (command === "hook") {
135
+ console.log((0, hook_1.getHookScript)(rest[0]));
136
+ return;
137
+ }
138
+ if (command === "paths") {
139
+ handlePaths();
140
+ return;
141
+ }
142
+ throw new Error(`unknown command "${command}"`);
143
+ }
144
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function resolveRcFile(shellName?: string): string;
2
+ export declare function getHookScript(shellName?: string): string;
3
+ export declare function installHook(shellName?: string): {
4
+ rcFile: string;
5
+ changed: boolean;
6
+ };
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resolveRcFile = resolveRcFile;
7
+ exports.getHookScript = getHookScript;
8
+ exports.installHook = installHook;
9
+ const node_fs_1 = __importDefault(require("node:fs"));
10
+ const node_os_1 = __importDefault(require("node:os"));
11
+ const node_path_1 = __importDefault(require("node:path"));
12
+ const HOOK_BEGIN = "# >>> xmotd >>>";
13
+ const HOOK_END = "# <<< xmotd <<<";
14
+ function resolveRcFile(shellName) {
15
+ const home = node_os_1.default.homedir();
16
+ const shell = shellName || node_path_1.default.basename(process.env.SHELL || "");
17
+ if (shell === "bash") {
18
+ const bashProfile = node_path_1.default.join(home, ".bash_profile");
19
+ return node_fs_1.default.existsSync(bashProfile) ? bashProfile : node_path_1.default.join(home, ".bashrc");
20
+ }
21
+ if (shell === "fish") {
22
+ return node_path_1.default.join(home, ".config", "fish", "config.fish");
23
+ }
24
+ return node_path_1.default.join(home, ".zshrc");
25
+ }
26
+ function getHookScript(shellName) {
27
+ const shell = shellName || node_path_1.default.basename(process.env.SHELL || "");
28
+ if (shell === "fish") {
29
+ return [
30
+ HOOK_BEGIN,
31
+ "if status is-interactive",
32
+ " xmotd --auto 2>/dev/null; or true",
33
+ "end",
34
+ HOOK_END
35
+ ].join("\n");
36
+ }
37
+ return [
38
+ HOOK_BEGIN,
39
+ 'if [ -n "$PS1" ]; then',
40
+ " xmotd --auto 2>/dev/null || true",
41
+ "fi",
42
+ HOOK_END
43
+ ].join("\n");
44
+ }
45
+ function installHook(shellName) {
46
+ const rcFile = resolveRcFile(shellName);
47
+ const hook = getHookScript(shellName);
48
+ const existing = node_fs_1.default.existsSync(rcFile) ? node_fs_1.default.readFileSync(rcFile, "utf8") : "";
49
+ if (existing.includes(HOOK_BEGIN)) {
50
+ return { rcFile, changed: false };
51
+ }
52
+ node_fs_1.default.mkdirSync(node_path_1.default.dirname(rcFile), { recursive: true });
53
+ const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
54
+ node_fs_1.default.writeFileSync(rcFile, `${existing}${prefix}${hook}\n`, "utf8");
55
+ return { rcFile, changed: true };
56
+ }
57
+ //# sourceMappingURL=hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.js","sourceRoot":"","sources":["../../src/hook.ts"],"names":[],"mappings":";;;;;AAOA,sCAcC;AAED,sCAoBC;AAED,kCAcC;AA3DD,sDAAyB;AACzB,sDAAyB;AACzB,0DAA6B;AAE7B,MAAM,UAAU,GAAG,iBAAiB,CAAC;AACrC,MAAM,QAAQ,GAAG,iBAAiB,CAAC;AAEnC,SAAgB,aAAa,CAAC,SAAkB;IAC9C,MAAM,IAAI,GAAG,iBAAE,CAAC,OAAO,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,SAAS,IAAI,mBAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAElE,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;QACrB,MAAM,WAAW,GAAG,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QACrD,OAAO,iBAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC/E,CAAC;IAED,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;QACrB,OAAO,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACnC,CAAC;AAED,SAAgB,aAAa,CAAC,SAAkB;IAC9C,MAAM,KAAK,GAAG,SAAS,IAAI,mBAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAElE,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;QACrB,OAAO;YACL,UAAU;YACV,0BAA0B;YAC1B,qCAAqC;YACrC,KAAK;YACL,QAAQ;SACT,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IAED,OAAO;QACL,UAAU;QACV,wBAAwB;QACxB,oCAAoC;QACpC,IAAI;QACJ,QAAQ;KACT,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,SAAgB,WAAW,CAAC,SAAkB;IAC5C,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,iBAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,iBAAE,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE9E,IAAI,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACpC,CAAC;IAED,iBAAE,CAAC,SAAS,CAAC,mBAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,QAAQ,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAChE,iBAAE,CAAC,aAAa,CAAC,MAAM,EAAE,GAAG,QAAQ,GAAG,MAAM,GAAG,IAAI,IAAI,EAAE,MAAM,CAAC,CAAC;IAElE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACnC,CAAC"}
@@ -0,0 +1,31 @@
1
+ export type StorePaths = {
2
+ configDir: string;
3
+ stateDir: string;
4
+ messagesFile: string;
5
+ stateFile: string;
6
+ };
7
+ type DisplayState = {
8
+ lastShownOn: string | null;
9
+ };
10
+ export declare const APP_NAME = "motd-tool";
11
+ export declare const DEFAULT_MESSAGE = "Stay hungry, stay foolish.";
12
+ export declare function getPaths(): StorePaths;
13
+ export declare function ensureStore(): StorePaths;
14
+ export declare function getMessages(): string[];
15
+ export declare function addMessage(message: string): string;
16
+ export declare function removeMessage(input: string): {
17
+ removed: string;
18
+ index: number;
19
+ };
20
+ export declare function importMessages(filePath: string): {
21
+ imported: number;
22
+ total: number;
23
+ };
24
+ export declare function exportMessages(filePath: string): {
25
+ filePath: string;
26
+ count: number;
27
+ };
28
+ export declare function pickRandomMessage(): string;
29
+ export declare function getState(): DisplayState;
30
+ export declare function setLastShownOn(isoDate: string): void;
31
+ export {};
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DEFAULT_MESSAGE = exports.APP_NAME = void 0;
7
+ exports.getPaths = getPaths;
8
+ exports.ensureStore = ensureStore;
9
+ exports.getMessages = getMessages;
10
+ exports.addMessage = addMessage;
11
+ exports.removeMessage = removeMessage;
12
+ exports.importMessages = importMessages;
13
+ exports.exportMessages = exportMessages;
14
+ exports.pickRandomMessage = pickRandomMessage;
15
+ exports.getState = getState;
16
+ exports.setLastShownOn = setLastShownOn;
17
+ const node_fs_1 = __importDefault(require("node:fs"));
18
+ const node_os_1 = __importDefault(require("node:os"));
19
+ const node_path_1 = __importDefault(require("node:path"));
20
+ exports.APP_NAME = "motd-tool";
21
+ exports.DEFAULT_MESSAGE = "Stay hungry, stay foolish.";
22
+ function resolveConfigHome() {
23
+ return process.env.XDG_CONFIG_HOME || node_path_1.default.join(node_os_1.default.homedir(), ".config");
24
+ }
25
+ function resolveStateHome() {
26
+ return process.env.XDG_STATE_HOME || node_path_1.default.join(node_os_1.default.homedir(), ".local", "state");
27
+ }
28
+ function ensureDir(dirPath) {
29
+ node_fs_1.default.mkdirSync(dirPath, { recursive: true });
30
+ }
31
+ function writeJson(filePath, value) {
32
+ node_fs_1.default.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
33
+ }
34
+ function readJson(filePath, fallbackValue) {
35
+ try {
36
+ return JSON.parse(node_fs_1.default.readFileSync(filePath, "utf8"));
37
+ }
38
+ catch {
39
+ return fallbackValue;
40
+ }
41
+ }
42
+ function normalizeMessages(messages) {
43
+ const normalized = messages
44
+ .map((message) => String(message).trim())
45
+ .filter(Boolean);
46
+ return normalized.length > 0 ? normalized : [exports.DEFAULT_MESSAGE];
47
+ }
48
+ function getPaths() {
49
+ const configDir = node_path_1.default.join(resolveConfigHome(), exports.APP_NAME);
50
+ const stateDir = node_path_1.default.join(resolveStateHome(), exports.APP_NAME);
51
+ return {
52
+ configDir,
53
+ stateDir,
54
+ messagesFile: node_path_1.default.join(configDir, "messages.json"),
55
+ stateFile: node_path_1.default.join(stateDir, "state.json")
56
+ };
57
+ }
58
+ function ensureStore() {
59
+ const paths = getPaths();
60
+ ensureDir(paths.configDir);
61
+ ensureDir(paths.stateDir);
62
+ if (!node_fs_1.default.existsSync(paths.messagesFile)) {
63
+ writeJson(paths.messagesFile, { messages: [exports.DEFAULT_MESSAGE] });
64
+ }
65
+ if (!node_fs_1.default.existsSync(paths.stateFile)) {
66
+ writeJson(paths.stateFile, { lastShownOn: null });
67
+ }
68
+ return paths;
69
+ }
70
+ function getMessages() {
71
+ const { messagesFile } = ensureStore();
72
+ const data = readJson(messagesFile, { messages: [exports.DEFAULT_MESSAGE] });
73
+ return normalizeMessages(Array.isArray(data.messages) ? data.messages : [exports.DEFAULT_MESSAGE]);
74
+ }
75
+ function saveMessages(messages) {
76
+ const { messagesFile } = ensureStore();
77
+ writeJson(messagesFile, { messages });
78
+ }
79
+ function addMessage(message) {
80
+ const nextMessage = String(message).trim();
81
+ if (!nextMessage) {
82
+ throw new Error("message cannot be empty");
83
+ }
84
+ const messages = getMessages();
85
+ messages.push(nextMessage);
86
+ saveMessages(messages);
87
+ return nextMessage;
88
+ }
89
+ function removeMessage(input) {
90
+ const target = String(input).trim();
91
+ if (!target) {
92
+ throw new Error("remove requires an index or exact message");
93
+ }
94
+ const messages = getMessages();
95
+ let index = Number.NaN;
96
+ if (/^\d+$/.test(target)) {
97
+ index = Number(target) - 1;
98
+ }
99
+ else {
100
+ index = messages.findIndex((message) => message === target);
101
+ }
102
+ if (index < 0 || index >= messages.length) {
103
+ throw new Error(`message not found: ${target}`);
104
+ }
105
+ const [removed] = messages.splice(index, 1);
106
+ saveMessages(messages.length > 0 ? messages : [exports.DEFAULT_MESSAGE]);
107
+ return { removed, index };
108
+ }
109
+ function importMessages(filePath) {
110
+ const sourcePath = node_path_1.default.resolve(filePath);
111
+ const raw = node_fs_1.default.readFileSync(sourcePath, "utf8");
112
+ const imported = sourcePath.endsWith(".json")
113
+ ? parseJsonMessages(raw)
114
+ : raw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
115
+ if (imported.length === 0) {
116
+ throw new Error("no messages found in import file");
117
+ }
118
+ const current = getMessages();
119
+ const merged = Array.from(new Set([...current, ...imported]));
120
+ saveMessages(merged);
121
+ return { imported: merged.length - current.length, total: merged.length };
122
+ }
123
+ function exportMessages(filePath) {
124
+ const destinationPath = node_path_1.default.resolve(filePath);
125
+ const messages = getMessages();
126
+ const content = destinationPath.endsWith(".json")
127
+ ? `${JSON.stringify(messages, null, 2)}\n`
128
+ : `${messages.join("\n")}\n`;
129
+ ensureDir(node_path_1.default.dirname(destinationPath));
130
+ node_fs_1.default.writeFileSync(destinationPath, content, "utf8");
131
+ return { filePath: destinationPath, count: messages.length };
132
+ }
133
+ function parseJsonMessages(raw) {
134
+ const parsed = JSON.parse(raw);
135
+ if (!Array.isArray(parsed)) {
136
+ throw new Error("JSON import file must be an array of strings");
137
+ }
138
+ return parsed.map((message) => String(message).trim()).filter(Boolean);
139
+ }
140
+ function pickRandomMessage() {
141
+ const messages = getMessages();
142
+ const index = Math.floor(Math.random() * messages.length);
143
+ return messages[index];
144
+ }
145
+ function getState() {
146
+ const { stateFile } = ensureStore();
147
+ return readJson(stateFile, { lastShownOn: null });
148
+ }
149
+ function setLastShownOn(isoDate) {
150
+ const { stateFile } = ensureStore();
151
+ writeJson(stateFile, { lastShownOn: isoDate });
152
+ }
153
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const node_test_1 = __importDefault(require("node:test"));
40
+ const strict_1 = __importDefault(require("node:assert/strict"));
41
+ const node_fs_1 = __importDefault(require("node:fs"));
42
+ const node_os_1 = __importDefault(require("node:os"));
43
+ const node_path_1 = __importDefault(require("node:path"));
44
+ function createTempHomes() {
45
+ const root = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), "xmotd-"));
46
+ const config = node_path_1.default.join(root, "config");
47
+ const state = node_path_1.default.join(root, "state");
48
+ process.env.XDG_CONFIG_HOME = config;
49
+ process.env.XDG_STATE_HOME = state;
50
+ return { root, config, state };
51
+ }
52
+ (0, node_test_1.default)("store initializes with a default message", async () => {
53
+ createTempHomes();
54
+ const { getMessages } = await Promise.resolve().then(() => __importStar(require("../src/store")));
55
+ const messages = getMessages();
56
+ strict_1.default.equal(messages.length, 1);
57
+ strict_1.default.equal(messages[0], "Stay hungry, stay foolish.");
58
+ });
59
+ (0, node_test_1.default)("add appends messages to the local store", async () => {
60
+ createTempHomes();
61
+ const { addMessage, getMessages } = await Promise.resolve().then(() => __importStar(require("../src/store")));
62
+ addMessage("Code is poetry");
63
+ const messages = getMessages();
64
+ strict_1.default.deepEqual(messages, ["Stay hungry, stay foolish.", "Code is poetry"]);
65
+ });
66
+ (0, node_test_1.default)("remove accepts an index", async () => {
67
+ createTempHomes();
68
+ const { addMessage, getMessages, removeMessage } = await Promise.resolve().then(() => __importStar(require("../src/store")));
69
+ addMessage("Code is poetry");
70
+ const removed = removeMessage("2");
71
+ strict_1.default.equal(removed.removed, "Code is poetry");
72
+ strict_1.default.deepEqual(getMessages(), ["Stay hungry, stay foolish."]);
73
+ });
74
+ (0, node_test_1.default)("import/export handles text files", async () => {
75
+ const { root } = createTempHomes();
76
+ const { exportMessages, importMessages, getMessages } = await Promise.resolve().then(() => __importStar(require("../src/store")));
77
+ const importFile = node_path_1.default.join(root, "messages.txt");
78
+ const exportFile = node_path_1.default.join(root, "export.json");
79
+ node_fs_1.default.writeFileSync(importFile, "Code is poetry\nShip it\n", "utf8");
80
+ const imported = importMessages(importFile);
81
+ const exported = exportMessages(exportFile);
82
+ strict_1.default.equal(imported.imported, 2);
83
+ strict_1.default.equal(exported.count, getMessages().length);
84
+ strict_1.default.deepEqual(JSON.parse(node_fs_1.default.readFileSync(exportFile, "utf8")), getMessages());
85
+ });
86
+ (0, node_test_1.default)("auto mode only prints once per day", async () => {
87
+ createTempHomes();
88
+ const { maybePrintAutoMessage } = await Promise.resolve().then(() => __importStar(require("../src/cli")));
89
+ const logs = [];
90
+ const originalLog = console.log;
91
+ console.log = (value) => logs.push(String(value));
92
+ try {
93
+ strict_1.default.equal(maybePrintAutoMessage(), true);
94
+ strict_1.default.equal(maybePrintAutoMessage(), false);
95
+ }
96
+ finally {
97
+ console.log = originalLog;
98
+ }
99
+ strict_1.default.equal(logs.length, 1);
100
+ });
101
+ //# sourceMappingURL=cli.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.test.js","sourceRoot":"","sources":["../../test/cli.test.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "motd-tool",
3
+ "version": "1.0.2",
4
+ "description": "Tiny CLI that prints a random message of the day in your terminal.",
5
+ "license": "MIT",
6
+ "author": "AlucPro",
7
+ "homepage": "https://github.com/AlucPro/motd-tool",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/AlucPro/motd-tool.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/AlucPro/motd-tool/issues"
14
+ },
15
+ "keywords": [
16
+ "motd",
17
+ "cli",
18
+ "terminal",
19
+ "shell",
20
+ "inspiration"
21
+ ],
22
+ "type": "commonjs",
23
+ "bin": {
24
+ "xmotd": "./bin/xmotd.js"
25
+ },
26
+ "files": [
27
+ "bin",
28
+ "dist",
29
+ "scripts",
30
+ "Formula",
31
+ "README.md",
32
+ "LICENSE"
33
+ ],
34
+ "engines": {
35
+ "node": ">=18"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^24.0.0",
39
+ "typescript": "^5.8.2"
40
+ },
41
+ "scripts": {
42
+ "build": "tsc --project tsconfig.json",
43
+ "check": "pnpm build && pnpm test",
44
+ "dev": "pnpm build --watch",
45
+ "postinstall": "node ./scripts/postinstall.js",
46
+ "release:check": "pnpm check && node ./scripts/prepare-release.mjs",
47
+ "test": "pnpm build && node --test dist/test/*.test.js"
48
+ }
49
+ }
@@ -0,0 +1,15 @@
1
+ const os = require("os");
2
+ const path = require("path");
3
+
4
+ const shell = path.basename(process.env.SHELL || "");
5
+ const rcFile =
6
+ shell === "bash"
7
+ ? path.join(os.homedir(), ".bashrc")
8
+ : shell === "fish"
9
+ ? path.join(os.homedir(), ".config", "fish", "config.fish")
10
+ : path.join(os.homedir(), ".zshrc");
11
+
12
+ console.log("motd-tool installed.");
13
+ console.log('Run "xmotd" to print a random message.');
14
+ console.log(`Run "xmotd init ${shell || "zsh"}" to enable once-per-day terminal messages in ${rcFile}.`);
15
+ console.log('Run "xmotd --help" to see add/remove/import/export commands.');
@@ -0,0 +1,26 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import crypto from "node:crypto";
4
+
5
+ const root = process.cwd();
6
+ const packageJson = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
7
+ const formulaPath = path.join(root, "Formula", "motd-tool.rb");
8
+ const version = packageJson.version;
9
+ const tarballName = `motd-tool-${version}.tgz`;
10
+ const tarballPath = path.join(root, tarballName);
11
+
12
+ if (!fs.existsSync(tarballPath)) {
13
+ console.log(`Tarball not found: ${tarballName}`);
14
+ console.log("Run: pnpm pack");
15
+ process.exit(1);
16
+ }
17
+
18
+ const sha256 = crypto.createHash("sha256").update(fs.readFileSync(tarballPath)).digest("hex");
19
+ const formula = fs.readFileSync(formulaPath, "utf8")
20
+ .replace(/motd-tool-\d+\.\d+\.\d+\.tgz/, `motd-tool-${version}.tgz`)
21
+ .replace(/sha256 "[^"]+"/, `sha256 "${sha256}"`);
22
+
23
+ fs.writeFileSync(formulaPath, formula, "utf8");
24
+
25
+ console.log(`Updated Formula/motd-tool.rb for v${version}`);
26
+ console.log(`sha256: ${sha256}`);