@gethmy/mcp 2.4.1 → 2.4.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.
package/dist/cli.js CHANGED
@@ -28074,7 +28074,8 @@ var BOILERPLATE_PATTERNS = [
28074
28074
  /^placeholder/i,
28075
28075
  /^\.\.\.$/,
28076
28076
  /^untitled/i,
28077
- /^(note|memo|draft)\s*\d*$/i
28077
+ /^(note|memo|draft)\s*\d*$/i,
28078
+ /^task transition:/i
28078
28079
  ];
28079
28080
  function isBoilerplate(title, content) {
28080
28081
  const t = title.trim();
@@ -28122,21 +28123,26 @@ function scoreEntity(entity, relationCount, archiveBelow, deleteBelow, staleDraf
28122
28123
  reasons.push("no relations");
28123
28124
  let content = 0;
28124
28125
  const contentLen = entity.content?.length || 0;
28125
- if (contentLen >= 80)
28126
- content += 8;
28127
- const titleOk = entity.title.trim().length >= 4 && !/^(untitled|draft|note)\b/i.test(entity.title.trim());
28128
- if (titleOk)
28129
- content += 4;
28130
- if (!isBoilerplate(entity.title, entity.content))
28131
- content += 3;
28132
- if (contentLen < 80)
28133
- reasons.push(`thin content (${contentLen} chars)`);
28134
- if (isBoilerplate(entity.title, entity.content))
28126
+ const boilerplate = isBoilerplate(entity.title, entity.content);
28127
+ if (boilerplate) {
28135
28128
  reasons.push("boilerplate title/content");
28129
+ } else {
28130
+ if (contentLen >= 80)
28131
+ content += 8;
28132
+ const titleOk = entity.title.trim().length >= 4 && !/^(untitled|draft|note)\b/i.test(entity.title.trim());
28133
+ if (titleOk)
28134
+ content += 4;
28135
+ content += 3;
28136
+ if (contentLen < 80)
28137
+ reasons.push(`thin content (${contentLen} chars)`);
28138
+ }
28136
28139
  let tierAgeFit = 15;
28137
28140
  if (entity.memory_tier === "draft" && ageDays > 60 && !entity.promoted_from_id) {
28138
28141
  tierAgeFit = 0;
28139
28142
  reasons.push("stuck draft >60d never promoted");
28143
+ } else if (entity.memory_tier === "draft" && (entity.access_count || 0) === 0 && ageDays > 2) {
28144
+ tierAgeFit = 5;
28145
+ reasons.push("draft >2d with zero access");
28140
28146
  }
28141
28147
  if (entity.promoted_from_id) {
28142
28148
  tierAgeFit = Math.min(15, tierAgeFit + 5);
package/dist/index.js CHANGED
@@ -25834,7 +25834,8 @@ var BOILERPLATE_PATTERNS = [
25834
25834
  /^placeholder/i,
25835
25835
  /^\.\.\.$/,
25836
25836
  /^untitled/i,
25837
- /^(note|memo|draft)\s*\d*$/i
25837
+ /^(note|memo|draft)\s*\d*$/i,
25838
+ /^task transition:/i
25838
25839
  ];
25839
25840
  function isBoilerplate(title, content) {
25840
25841
  const t = title.trim();
@@ -25882,21 +25883,26 @@ function scoreEntity(entity, relationCount, archiveBelow, deleteBelow, staleDraf
25882
25883
  reasons.push("no relations");
25883
25884
  let content = 0;
25884
25885
  const contentLen = entity.content?.length || 0;
25885
- if (contentLen >= 80)
25886
- content += 8;
25887
- const titleOk = entity.title.trim().length >= 4 && !/^(untitled|draft|note)\b/i.test(entity.title.trim());
25888
- if (titleOk)
25889
- content += 4;
25890
- if (!isBoilerplate(entity.title, entity.content))
25891
- content += 3;
25892
- if (contentLen < 80)
25893
- reasons.push(`thin content (${contentLen} chars)`);
25894
- if (isBoilerplate(entity.title, entity.content))
25886
+ const boilerplate = isBoilerplate(entity.title, entity.content);
25887
+ if (boilerplate) {
25895
25888
  reasons.push("boilerplate title/content");
25889
+ } else {
25890
+ if (contentLen >= 80)
25891
+ content += 8;
25892
+ const titleOk = entity.title.trim().length >= 4 && !/^(untitled|draft|note)\b/i.test(entity.title.trim());
25893
+ if (titleOk)
25894
+ content += 4;
25895
+ content += 3;
25896
+ if (contentLen < 80)
25897
+ reasons.push(`thin content (${contentLen} chars)`);
25898
+ }
25896
25899
  let tierAgeFit = 15;
25897
25900
  if (entity.memory_tier === "draft" && ageDays > 60 && !entity.promoted_from_id) {
25898
25901
  tierAgeFit = 0;
25899
25902
  reasons.push("stuck draft >60d never promoted");
25903
+ } else if (entity.memory_tier === "draft" && (entity.access_count || 0) === 0 && ageDays > 2) {
25904
+ tierAgeFit = 5;
25905
+ reasons.push("draft >2d with zero access");
25900
25906
  }
25901
25907
  if (entity.promoted_from_id) {
25902
25908
  tierAgeFit = Math.min(15, tierAgeFit + 5);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gethmy/mcp",
3
- "version": "2.4.1",
3
+ "version": "2.4.2",
4
4
  "description": "MCP server for Harmony Kanban board - enables AI coding agents to manage your boards",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -122,6 +122,9 @@ const BOILERPLATE_PATTERNS = [
122
122
  /^\.\.\.$/,
123
123
  /^untitled/i,
124
124
  /^(note|memo|draft)\s*\d*$/i,
125
+ // Auto-captured task-transition snapshots from a retired active-learning rule.
126
+ // No user intent, no access pattern — treat as boilerplate so scoring archives them.
127
+ /^task transition:/i,
125
128
  ];
126
129
 
127
130
  function isBoilerplate(title: string, content: string): boolean {
@@ -177,18 +180,22 @@ function scoreEntity(
177
180
  if (!hasTags) reasons.push("no tags");
178
181
  if (!hasRelations) reasons.push("no relations");
179
182
 
180
- // Content quality (15)
183
+ // Content quality (15) — boilerplate hard-zeroes the whole band. Auto-captured
184
+ // noise should never inherit the length/title bonuses it structurally earns.
181
185
  let content = 0;
182
186
  const contentLen = entity.content?.length || 0;
183
- if (contentLen >= 80) content += 8;
184
- const titleOk =
185
- entity.title.trim().length >= 4 &&
186
- !/^(untitled|draft|note)\b/i.test(entity.title.trim());
187
- if (titleOk) content += 4;
188
- if (!isBoilerplate(entity.title, entity.content)) content += 3;
189
- if (contentLen < 80) reasons.push(`thin content (${contentLen} chars)`);
190
- if (isBoilerplate(entity.title, entity.content))
187
+ const boilerplate = isBoilerplate(entity.title, entity.content);
188
+ if (boilerplate) {
191
189
  reasons.push("boilerplate title/content");
190
+ } else {
191
+ if (contentLen >= 80) content += 8;
192
+ const titleOk =
193
+ entity.title.trim().length >= 4 &&
194
+ !/^(untitled|draft|note)\b/i.test(entity.title.trim());
195
+ if (titleOk) content += 4;
196
+ content += 3;
197
+ if (contentLen < 80) reasons.push(`thin content (${contentLen} chars)`);
198
+ }
192
199
 
193
200
  // Tier-age fit (15)
194
201
  let tierAgeFit = 15;
@@ -199,6 +206,15 @@ function scoreEntity(
199
206
  ) {
200
207
  tierAgeFit = 0;
201
208
  reasons.push("stuck draft >60d never promoted");
209
+ } else if (
210
+ entity.memory_tier === "draft" &&
211
+ (entity.access_count || 0) === 0 &&
212
+ ageDays > 2
213
+ ) {
214
+ // Young drafts get a 2-day grace window. After that, zero access means
215
+ // zero signal — strip the tier-age bonus so useless auto-captures fall to archive.
216
+ tierAgeFit = 5;
217
+ reasons.push("draft >2d with zero access");
202
218
  }
203
219
  if (entity.promoted_from_id) {
204
220
  tierAgeFit = Math.min(15, tierAgeFit + 5);