feat: add disk storage for already-greeted nicks #2

Merged
alex merged 1 commit from pi/issue1-1783972974060 into master 2026-07-14 01:58:51 +00:00
Contributor

Closes #1.

Summary

Adds a simple disk-backed store that keeps track of nicks the bot has already greeted, so the same person is not re-greeted — even after a restart.

Changes

  • src/storage.ts (new) — GreetedNicksStore class backed by a JSON file. Loads nicks into an in-memory Set on startup, and persists each newly greeted nick to disk. Uses Deno's built-in file I/O (Deno.readTextFile / Deno.writeTextFile) — no external dependencies.
  • src/storage_test.ts (new) — 8 unit tests covering: empty start, load from disk, persist on add, no-op for existing nicks, preservation of old nicks, non-string entry filtering, and error handling for malformed/non-array JSON.
  • src/config.ts — added optional IRC_STORE_PATH config (defaults to greeted-nicks.json) via the existing resolve() helper.
  • src/main.ts — loads the store on startup, skips already-greeted nicks in the join handler, and persists after a successful greeting.
  • deno.json — added --allow-write to dev, start, test, and compile tasks.
  • .env.example, .gitignore, README.md — documented the new option and behavior.

Design notes

  • Crash safety: the nick is persisted after the greeting is sent, so a crash between greeting and persisting at worst causes a duplicate greeting — never a skipped one.
  • Missing file is OK: if the store file doesn't exist yet, the store starts empty (not an error). Malformed JSON or a non-array file is an error.
  • Std Deno libs: the built-in Deno.readTextFile/Deno.writeTextFile APIs are the simplest fit for "simple disk storage." No @std/* package was needed.
Closes #1. ## Summary Adds a simple disk-backed store that keeps track of nicks the bot has already greeted, so the same person is not re-greeted — even after a restart. ## Changes - **`src/storage.ts`** (new) — `GreetedNicksStore` class backed by a JSON file. Loads nicks into an in-memory `Set` on startup, and persists each newly greeted nick to disk. Uses Deno's built-in file I/O (`Deno.readTextFile` / `Deno.writeTextFile`) — no external dependencies. - **`src/storage_test.ts`** (new) — 8 unit tests covering: empty start, load from disk, persist on add, no-op for existing nicks, preservation of old nicks, non-string entry filtering, and error handling for malformed/non-array JSON. - **`src/config.ts`** — added optional `IRC_STORE_PATH` config (defaults to `greeted-nicks.json`) via the existing `resolve()` helper. - **`src/main.ts`** — loads the store on startup, skips already-greeted nicks in the `join` handler, and persists after a successful greeting. - **`deno.json`** — added `--allow-write` to `dev`, `start`, `test`, and `compile` tasks. - **`.env.example`**, **`.gitignore`**, **`README.md`** — documented the new option and behavior. ## Design notes - **Crash safety**: the nick is persisted *after* the greeting is sent, so a crash between greeting and persisting at worst causes a duplicate greeting — never a skipped one. - **Missing file is OK**: if the store file doesn't exist yet, the store starts empty (not an error). Malformed JSON or a non-array file *is* an error. - **Std Deno libs**: the built-in `Deno.readTextFile`/`Deno.writeTextFile` APIs are the simplest fit for "simple disk storage." No `@std/*` package was needed.
feat: add disk storage for already-greeted nicks
Some checks failed
CI / check (pull_request) Failing after 4s
44be66b224
Co-authored-by: alex <alex@forge.l3x.in>
Owner

/pi rebase the pr, push change

/pi rebase the pr, push change
forgejo-actions force-pushed pi/issue1-1783972974060 from 44be66b224
Some checks failed
CI / check (pull_request) Failing after 4s
to bac701a02a 2026-07-13 20:15:51 +00:00
Compare
Author
Contributor

Now let me look at what master changed (potential conflict areas) vs what the PR changes, so I can be prepared:Let me examine the full content of conflicting files in both branches:Let me see master's version of main.ts and check the file tree:Now I have a clear picture. Master diverged from the PR's base by simplifying the README (removing the {gift}/horse-gift concept and project-structure section) and adding bot: true to the Client constructor. Let me look at the PR's exact changes to the overlapping files:I now have a full understanding of the divergence. Master added bot: true to the Client constructor and simplified the README (removed the {gift}/horse-gift concept, example-greeting block, and project-structure section). The PR adds storage logic/docs. The conflicts will be in README.md and src/main.ts. Let me check out the PR branch and start the rebase:Two conflicts as expected. Let me check the state of both files:Now let me check the auto-merged src/main.ts:The src/main.ts auto-merge is correct — it has both bot: true (from master) and the storage logic (from the PR). Now I'll resolve the README.md conflict, keeping master's simplifications (no {gift}, no example-greeting block, no project-structure section) while adding the storage documentation from the PR:Now let me verify there are no conflict markers and run deno fmt to ensure proper formatting (Deno aligns markdown tables):Deno isn't on the PATH. Let me locate it:Deno isn't installed. Let me install it so I can verify the rebased code type-checks and tests pass:deno fmt applied trailing comma in main.ts and wrapped the README intro. Let me verify the results:Both files look correct. Let me run formatting check on all PR-touched files, then type-check and run the test suite to verify the rebase produces working code:Type-check and lint pass. Now let me run the test suite:All 8 tests pass, and lint/check/fmt are clean. Now let me stage the resolved files and continue the rebase:Rebase succeeded. Let me verify the result — confirm the branch is now based on master and review the final diff:The branch now sits directly on top of master. Let me do a final review of the resolved conflicts to confirm correctness:The diff is exactly right — it cleanly combines master's bot: true and simplified README with the PR's storage feature, without re-introducing the removed {gift}/horse-gift content. Now let me force-push the rebased branch:The rebased branch has been force-pushed. Let me verify the final state of the PR:Done. The PR has been rebased onto the latest master and force-pushed.

What happened: master had diverged from the PR's original base with two commits that touched the same files as this PR (README.md and src/main.ts), so a straight rebase produced two conflicts. I resolved them as follows:

  • src/main.ts — auto-merged cleanly, combining master's new bot: true option on the Client constructor with the PR's storage logic and restructured join handler.
  • README.md — kept master's simplifications (the "fixed message" wording, {nick}-only greeting, and the removed example-greeting block and project-structure section) and layered the PR's storage documentation on top: the greeted-nicks sentence in the intro, the new IRC_STORE_PATH config-table row, and the "filesystem access" note in Usage. The stale {gift}/horse-gift content was not re-introduced.

Verification before pushing:

  • deno fmt --check — clean (applied a trailing comma to bot: true, and wrapped the README intro to match repo style)
  • deno lint — clean
  • deno check src/main.ts — passes
  • deno test — all 8 tests pass

The branch now contains a single commit (bac701a) sitting directly on top of master (5ddf130), with no merge commits.


View action run | Model: zai/glm-5.2 (thinking: max) | Time: 3m 57s | Tokens: 450.1K | Pi SDK v0.80.6 | Action v2.25.1-develop (develop @ 9c24480)

Now let me look at what master changed (potential conflict areas) vs what the PR changes, so I can be prepared:Let me examine the full content of conflicting files in both branches:Let me see master's version of main.ts and check the file tree:Now I have a clear picture. Master diverged from the PR's base by simplifying the README (removing the `{gift}`/horse-gift concept and project-structure section) and adding `bot: true` to the `Client` constructor. Let me look at the PR's exact changes to the overlapping files:I now have a full understanding of the divergence. Master added `bot: true` to the `Client` constructor and simplified the README (removed the `{gift}`/horse-gift concept, example-greeting block, and project-structure section). The PR adds storage logic/docs. The conflicts will be in `README.md` and `src/main.ts`. Let me check out the PR branch and start the rebase:Two conflicts as expected. Let me check the state of both files:Now let me check the auto-merged `src/main.ts`:The `src/main.ts` auto-merge is correct — it has both `bot: true` (from master) and the storage logic (from the PR). Now I'll resolve the `README.md` conflict, keeping master's simplifications (no `{gift}`, no example-greeting block, no project-structure section) while adding the storage documentation from the PR:Now let me verify there are no conflict markers and run `deno fmt` to ensure proper formatting (Deno aligns markdown tables):Deno isn't on the PATH. Let me locate it:Deno isn't installed. Let me install it so I can verify the rebased code type-checks and tests pass:`deno fmt` applied trailing comma in `main.ts` and wrapped the README intro. Let me verify the results:Both files look correct. Let me run formatting check on all PR-touched files, then type-check and run the test suite to verify the rebase produces working code:Type-check and lint pass. Now let me run the test suite:All 8 tests pass, and lint/check/fmt are clean. Now let me stage the resolved files and continue the rebase:Rebase succeeded. Let me verify the result — confirm the branch is now based on master and review the final diff:The branch now sits directly on top of master. Let me do a final review of the resolved conflicts to confirm correctness:The diff is exactly right — it cleanly combines master's `bot: true` and simplified README with the PR's storage feature, without re-introducing the removed `{gift}`/horse-gift content. Now let me force-push the rebased branch:The rebased branch has been force-pushed. Let me verify the final state of the PR:Done. The PR has been rebased onto the latest `master` and force-pushed. **What happened:** `master` had diverged from the PR's original base with two commits that touched the same files as this PR (`README.md` and `src/main.ts`), so a straight rebase produced two conflicts. I resolved them as follows: - **`src/main.ts`** — auto-merged cleanly, combining master's new `bot: true` option on the `Client` constructor with the PR's storage logic and restructured `join` handler. - **`README.md`** — kept master's simplifications (the "fixed message" wording, `{nick}`-only greeting, and the *removed* example-greeting block and project-structure section) and layered the PR's storage documentation on top: the greeted-nicks sentence in the intro, the new `IRC_STORE_PATH` config-table row, and the "filesystem access" note in Usage. The stale `{gift}`/horse-gift content was **not** re-introduced. **Verification before pushing:** - `deno fmt --check` — clean (applied a trailing comma to `bot: true,` and wrapped the README intro to match repo style) - `deno lint` — clean - `deno check src/main.ts` — passes - `deno test` — all 8 tests pass The branch now contains a single commit (`bac701a`) sitting directly on top of `master` (`5ddf130`), with no merge commits. --- [View action run](https://forge.l3x.in/alex/irc-horsegift-greeter/actions/runs/8) | Model: zai/glm-5.2 (thinking: max) | Time: 3m 57s | Tokens: 450.1K | Pi SDK v0.80.6 | Action v2.25.1-develop (develop @ 9c24480)
alex merged commit 1a6174762c into master 2026-07-14 01:58:51 +00:00
alex deleted branch pi/issue1-1783972974060 2026-07-14 01:58:51 +00:00
Sign in to join this conversation.
No reviewers
No labels
dependencies
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
alex/irc-greeter-bot!2
No description provided.