openalmanac 0.2.36 → 0.2.38

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/dist/setup.js CHANGED
@@ -580,8 +580,7 @@ function installSkill(skillName) {
580
580
  }
581
581
  /* ── Reddit-specific tool groups ───────────────────────────────── */
582
582
  const REDDIT_EXTRA_TOOLS = [
583
- "Bash(node *)",
584
- "Bash(curl *)",
583
+ "Bash(node */ingest.js *)",
585
584
  ];
586
585
  /* ── Reddit setup banner ───────────────────────────────────────── */
587
586
  function printRedditBanner() {
@@ -623,6 +622,8 @@ function printRedditResult(agent, loginResult, mcpChanged, toolCount) {
623
622
  w(row(` ${BLUE}1.${RST} Type ${WHITE_BOLD}claude${RST} to start Claude Code`));
624
623
  w(row(` ${BLUE}2.${RST} Run ${BLUE}/reddit-wiki r/<subreddit>${RST}`));
625
624
  w(empty);
625
+ w(row(` ${DIM}Ask "how does reddit wiki work?" to learn more${RST}`));
626
+ w(empty);
626
627
  w(` ${BLUE_DIM}\u2570${"─".repeat(innerW)}\u256f${RST}`);
627
628
  w("");
628
629
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openalmanac",
3
- "version": "0.2.36",
3
+ "version": "0.2.38",
4
4
  "description": "OpenAlmanac — pull, edit, and push articles to the open knowledge base",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: reddit-wiki
3
3
  description: Turn any subreddit into a published wiki on Almanac
4
- allowed-tools: Bash(node *), Bash(curl *), mcp__almanac__search_articles, mcp__almanac__search_communities, mcp__almanac__list_articles, mcp__almanac__read, mcp__almanac__download, mcp__almanac__new, mcp__almanac__publish, mcp__almanac__search_web, mcp__almanac__read_webpage, mcp__almanac__search_images, mcp__almanac__view_images, mcp__almanac__register_sources, mcp__almanac__login, mcp__almanac__create_community, Read(~/.openalmanac/**), Write(~/.openalmanac/**), Edit(~/.openalmanac/**)
4
+ allowed-tools: Bash(node ${CLAUDE_SKILL_DIR}/scripts/ingest.js *), mcp__almanac__search_articles, mcp__almanac__search_communities, mcp__almanac__list_articles, mcp__almanac__read, mcp__almanac__download, mcp__almanac__new, mcp__almanac__publish, mcp__almanac__search_web, mcp__almanac__read_webpage, mcp__almanac__search_images, mcp__almanac__view_images, mcp__almanac__register_sources, mcp__almanac__login, mcp__almanac__create_community, Read(~/.openalmanac/**), Write(~/.openalmanac/**), Edit(~/.openalmanac/**)
5
5
  argument-hint: r/<subreddit>
6
6
  ---
7
7
 
@@ -28,6 +28,18 @@ Two phases:
28
28
  - **API calls / community slugs**: Bare name — `subreddit=lockpicking`
29
29
  - **Accept both** as input: `r/lockpicking` or `lockpicking`
30
30
 
31
+ ## If no subreddit is given (or user asks "how does this work")
32
+
33
+ If the user runs `/reddit-wiki` without arguments or asks how it works, explain briefly:
34
+
35
+ - **What it does:** Takes any subreddit and builds a wiki on Almanac — real articles with citations, images, and links between them. Two phases: a foundation of 15-20 core articles, then a deep pass through the corpus finding niche topics.
36
+ - **What Almanac is:** An open knowledge base anyone can read and write to. Think Wikipedia's depth meets Reddit's community energy.
37
+ - **How it works:** Downloads the subreddit's history, scores posts by quality, then uses AI agents to research and write articles citing the community's own discussions.
38
+ - **Data storage:** Everything is stored locally at `~/.openalmanac/corpus/<subreddit>/`. The user can delete it anytime after the wiki is published.
39
+ - **Any subreddit:** They can pick any subreddit they're interested in. Some smaller or newer subreddits may not have data available — if that happens, you'll suggest alternatives or nearby subreddits that do have data.
40
+
41
+ Then ask them which subreddit they want to build a wiki for.
42
+
31
43
  ## Step 1: Scout
32
44
 
33
45
  Extract the subreddit name from the argument (strip `r/` prefix if present). Use the bare name for all API calls and file paths. Use `r/<name>` when talking to the user.
@@ -79,8 +91,17 @@ node ${CLAUDE_SKILL_DIR}/scripts/ingest.js <subreddit> download --since <year>
79
91
 
80
92
  This saves raw JSONL to `~/.openalmanac/corpus/<subreddit>/raw/`. The raw data is kept so you can re-filter later with different quality thresholds without re-downloading.
81
93
 
94
+ Tell the user:
95
+
96
+ ```
97
+ Downloading now. Go grab a coffee ☕ — I'll have everything
98
+ ready when you get back.
99
+ ```
100
+
82
101
  While it downloads, share interesting context about the community. Use your knowledge and do a quick `search_web` if helpful. Share REAL information — facts, history, notable members, what makes this community unique. Not questions, not small talk.
83
102
 
103
+ Also tell them where the data is being stored: `~/.openalmanac/corpus/<subreddit>/`
104
+
84
105
  When the download finishes, run the filter step:
85
106
 
86
107
  ```bash
@@ -113,7 +134,15 @@ This writes markdown entries to `~/.openalmanac/corpus/<subreddit>/entries/`. Ea
113
134
 
114
135
  Report the results:
115
136
  - How many entries were created
116
- - Where they're stored
137
+ - Where they're stored (`~/.openalmanac/corpus/<subreddit>/entries/`)
138
+
139
+ ### If the subreddit has no data on Arctic Shift
140
+
141
+ If the `count` command returns 0 posts, the subreddit may not be indexed. In this case:
142
+ - Tell the user this subreddit doesn't have historical data available
143
+ - Suggest nearby or related subreddits by searching Arctic Shift for similar names
144
+ - Ask if they'd like to try one of those instead
145
+ - Do NOT just fail silently — help them find something that works
117
146
 
118
147
  ## Step 3: Phase 1 — Foundation
119
148
 
@@ -54,6 +54,10 @@ function parseArgs() {
54
54
  }
55
55
 
56
56
  const subreddit = args[0].replace(/^r\//, "");
57
+ if (!/^[a-zA-Z0-9_]+$/.test(subreddit)) {
58
+ console.error(`Invalid subreddit name: ${subreddit}`);
59
+ process.exit(1);
60
+ }
57
61
  const command = args[1]; // download, filter, or count
58
62
 
59
63
  const opts = {
@@ -142,7 +146,9 @@ async function* paginateSearch(subreddit, type, since, limit = 100) {
142
146
 
143
147
  const lastCreated = items[items.length - 1].created_utc;
144
148
  if (!lastCreated) break;
145
- after = new Date(lastCreated * 1000).toISOString();
149
+ const newAfter = new Date(lastCreated * 1000).toISOString();
150
+ if (newAfter === after) break; // no progress — would loop forever on duplicate timestamps
151
+ after = newAfter;
146
152
  }
147
153
  }
148
154
 
@@ -436,7 +442,7 @@ async function runDownload(opts) {
436
442
  postCount += batch.length;
437
443
  printProgress("Posts", postCount, estPosts);
438
444
  }
439
- postsStream.end();
445
+ await new Promise(resolve => postsStream.end(resolve));
440
446
  console.error("");
441
447
 
442
448
  // Download comments → raw/comments.jsonl
@@ -453,7 +459,7 @@ async function runDownload(opts) {
453
459
  commentCount += batch.length;
454
460
  printProgress("Comments", commentCount, estComments);
455
461
  }
456
- commentsStream.end();
462
+ await new Promise(resolve => commentsStream.end(resolve));
457
463
  console.error("");
458
464
  }
459
465