akm-cli 0.9.0-beta.30 → 0.9.0-beta.31

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/CHANGELOG.md CHANGED
@@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.9.0-beta.31] — 2026-06-20
10
+
11
+ ### Changed
12
+
13
+ - **#632 — recombine now filters junk tags structurally.** Frontmatter tags that
14
+ are pure numbers, dates (`20260529`), short hex hashes (`002c624c`), version
15
+ strings (`0.8.0`, `v2`), single chars, or common English stopwords (`is`, `the`,
16
+ `for`, `when`, …) carry no topical signal and never form a recombine cluster.
17
+ Unlike `excludeTags` (a fixed project list), this catches the OPEN-ENDED junk —
18
+ every new date or commit hash — with no config upkeep. Exposed as `isJunkTag`.
19
+ On the live stash this turns the recombine cluster set from generic 66–171-member
20
+ buckets into tight topical clusters (`auth`, `architecture`, `patterns`, …).
21
+
9
22
  ## [0.9.0-beta.30] — 2026-06-20
10
23
 
11
24
  ### Changed / Fixed
@@ -67,6 +67,69 @@ const DEFAULT_CONFIRM_THRESHOLD = 2;
67
67
  */
68
68
  const DEFAULT_RECOMBINE_OVERLAP = 0.7;
69
69
  // ── Clustering by relatedness (NOT similarity) ────────────────────────────────
70
+ /**
71
+ * #632 — English stopwords that occasionally leak into frontmatter tags
72
+ * (`is`, `the`, `for`, …). They carry no topical signal, so a cluster keyed on
73
+ * one is meaningless. Lowercased; matched case-insensitively.
74
+ */
75
+ const JUNK_STOPWORD_TAGS = new Set([
76
+ "a",
77
+ "an",
78
+ "and",
79
+ "the",
80
+ "to",
81
+ "of",
82
+ "in",
83
+ "on",
84
+ "for",
85
+ "is",
86
+ "are",
87
+ "be",
88
+ "no",
89
+ "not",
90
+ "or",
91
+ "if",
92
+ "it",
93
+ "as",
94
+ "at",
95
+ "by",
96
+ "we",
97
+ "us",
98
+ "do",
99
+ "so",
100
+ "when",
101
+ "then",
102
+ "than",
103
+ "with",
104
+ "from",
105
+ "this",
106
+ "that",
107
+ "uses",
108
+ "use",
109
+ "via",
110
+ ]);
111
+ /**
112
+ * #632 — a tag carries no clustering signal (and must be skipped) when it is
113
+ * purely a number / date / hash / version string, a single char, or a common
114
+ * stopword. Unlike `excludeTags` (a fixed project list), this catches the
115
+ * OPEN-ENDED junk — every new date or commit hash — without config upkeep.
116
+ */
117
+ export function isJunkTag(tag) {
118
+ const t = tag.trim().toLowerCase();
119
+ if (t.length <= 1)
120
+ return true;
121
+ if (JUNK_STOPWORD_TAGS.has(t))
122
+ return true;
123
+ if (/^\d+$/.test(t))
124
+ return true; // pure numbers + dates: 2026, 05, 23, 20260529
125
+ if (/^v?\d+(?:\.\d+)+$/.test(t))
126
+ return true; // versions: 0.8.0, v1.2
127
+ if (/^v\d+$/.test(t))
128
+ return true; // v0, v2
129
+ if (/^[0-9a-f]{4,}$/.test(t) && /\d/.test(t))
130
+ return true; // short hex hashes: 002c624c, 192d
131
+ return false;
132
+ }
70
133
  /**
71
134
  * Build relatedness clusters from the memory pool. Clustering is driven purely
72
135
  * by shared tags / graph entities — it MUST NOT use embedding similarity, so
@@ -114,6 +177,8 @@ export function buildRelatednessClusters(entries, opts) {
114
177
  for (const tag of entry.entry.tags ?? []) {
115
178
  if (excludeTags.has(tag))
116
179
  continue;
180
+ if (isJunkTag(tag))
181
+ continue; // #632 — skip numeric/date/hash/version/stopword junk
117
182
  add(`tag:${tag}`, entry);
118
183
  }
119
184
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-cli",
3
- "version": "0.9.0-beta.30",
3
+ "version": "0.9.0-beta.31",
4
4
  "type": "module",
5
5
  "description": "akm (Agent Knowledge Management) — A package manager for AI agent skills, commands, tools, and knowledge. Works with Claude Code, OpenCode, Cursor, and any AI coding assistant.",
6
6
  "keywords": [