@gethmy/mcp 2.4.3 → 2.4.6
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 +34 -8
- package/dist/index.js +34 -8
- package/dist/lib/api-client.js +21 -0
- package/dist/remote.js +1739 -463
- package/package.json +1 -1
- package/src/__tests__/memory-audit.test.ts +142 -0
- package/src/api-client.ts +42 -1
- package/src/memory-audit.ts +38 -10
- package/src/remote.ts +163 -24
package/dist/cli.js
CHANGED
|
@@ -27052,16 +27052,28 @@ async function requestWithBearer(apiUrl, bearerToken, method, path, body) {
|
|
|
27052
27052
|
return result;
|
|
27053
27053
|
}
|
|
27054
27054
|
|
|
27055
|
+
class HarmonyUnauthorizedError extends Error {
|
|
27056
|
+
constructor(message = "Invalid or expired credentials") {
|
|
27057
|
+
super(message);
|
|
27058
|
+
this.name = "HarmonyUnauthorizedError";
|
|
27059
|
+
}
|
|
27060
|
+
}
|
|
27061
|
+
|
|
27055
27062
|
class HarmonyApiClient {
|
|
27056
27063
|
apiKey;
|
|
27057
27064
|
apiUrl;
|
|
27065
|
+
onUnauthorized;
|
|
27058
27066
|
constructor(options) {
|
|
27059
27067
|
this.apiKey = options?.apiKey ?? getApiKey();
|
|
27060
27068
|
this.apiUrl = options?.apiUrl ?? getApiUrl();
|
|
27069
|
+
this.onUnauthorized = options?.onUnauthorized;
|
|
27061
27070
|
}
|
|
27062
27071
|
getApiUrl() {
|
|
27063
27072
|
return this.apiUrl;
|
|
27064
27073
|
}
|
|
27074
|
+
setApiKey(apiKey) {
|
|
27075
|
+
this.apiKey = apiKey;
|
|
27076
|
+
}
|
|
27065
27077
|
async request(method, path, body, options) {
|
|
27066
27078
|
await requestSemaphore.acquire();
|
|
27067
27079
|
try {
|
|
@@ -27108,6 +27120,10 @@ class HarmonyApiClient {
|
|
|
27108
27120
|
}
|
|
27109
27121
|
if (!response.ok) {
|
|
27110
27122
|
const errorMsg = data?.error || (looksLikeJson ? null : `API error: ${response.status} (non-JSON response)`) || `API error: ${response.status}`;
|
|
27123
|
+
if (response.status === 401) {
|
|
27124
|
+
this.onUnauthorized?.();
|
|
27125
|
+
throw new HarmonyUnauthorizedError(errorMsg);
|
|
27126
|
+
}
|
|
27111
27127
|
if (!isRetryableError(null, response.status)) {
|
|
27112
27128
|
throw new Error(errorMsg);
|
|
27113
27129
|
}
|
|
@@ -27157,6 +27173,10 @@ class HarmonyApiClient {
|
|
|
27157
27173
|
} catch {
|
|
27158
27174
|
errorMsg = text || `API error: ${response.status}`;
|
|
27159
27175
|
}
|
|
27176
|
+
if (response.status === 401) {
|
|
27177
|
+
this.onUnauthorized?.();
|
|
27178
|
+
throw new HarmonyUnauthorizedError(errorMsg);
|
|
27179
|
+
}
|
|
27160
27180
|
if (!isRetryableError(null, response.status)) {
|
|
27161
27181
|
throw new Error(errorMsg);
|
|
27162
27182
|
}
|
|
@@ -28088,23 +28108,25 @@ var BATCH_SIZE = 100;
|
|
|
28088
28108
|
var CONCURRENCY_LIMIT = 5;
|
|
28089
28109
|
var BOILERPLATE_PATTERNS = [
|
|
28090
28110
|
/^todo:?$/i,
|
|
28091
|
-
/^placeholder
|
|
28111
|
+
/^placeholder(\s+\d+|:)?$/i,
|
|
28092
28112
|
/^\.\.\.$/,
|
|
28093
|
-
/^untitled
|
|
28094
|
-
/^(note|memo|draft)\s
|
|
28113
|
+
/^untitled(\s+\d+|:)?$/i,
|
|
28114
|
+
/^(note|memo|draft)\s+\d+$/i,
|
|
28095
28115
|
/^task transition:/i
|
|
28096
28116
|
];
|
|
28097
|
-
function
|
|
28117
|
+
function isBoilerplateTitle(title) {
|
|
28098
28118
|
const t = title.trim();
|
|
28099
|
-
const c = content.trim();
|
|
28100
|
-
if (c.length === 0)
|
|
28101
|
-
return true;
|
|
28102
28119
|
for (const pat of BOILERPLATE_PATTERNS) {
|
|
28103
28120
|
if (pat.test(t))
|
|
28104
28121
|
return true;
|
|
28105
28122
|
}
|
|
28106
28123
|
return false;
|
|
28107
28124
|
}
|
|
28125
|
+
function isBoilerplate(title, content) {
|
|
28126
|
+
if (content.trim().length === 0)
|
|
28127
|
+
return true;
|
|
28128
|
+
return isBoilerplateTitle(title);
|
|
28129
|
+
}
|
|
28108
28130
|
function scoreEntity(entity, relationCount, archiveBelow, deleteBelow, staleDraftAgeDays) {
|
|
28109
28131
|
const now = Date.now();
|
|
28110
28132
|
const ageDays = (now - Date.parse(entity.created_at)) / MS_PER_DAY;
|
|
@@ -28186,8 +28208,12 @@ function scoreEntity(entity, relationCount, archiveBelow, deleteBelow, staleDraf
|
|
|
28186
28208
|
legacy = true;
|
|
28187
28209
|
legacyReasons.push("no graph presence");
|
|
28188
28210
|
}
|
|
28211
|
+
const boilerplateTitle = isBoilerplateTitle(entity.title);
|
|
28189
28212
|
let bucket;
|
|
28190
|
-
if (
|
|
28213
|
+
if (boilerplateTitle && deleteBelow > 0) {
|
|
28214
|
+
bucket = "delete";
|
|
28215
|
+
reasons.push("boilerplate title override");
|
|
28216
|
+
} else if (score < deleteBelow)
|
|
28191
28217
|
bucket = "delete";
|
|
28192
28218
|
else if (score < archiveBelow)
|
|
28193
28219
|
bucket = "archive";
|
package/dist/index.js
CHANGED
|
@@ -24812,16 +24812,28 @@ async function requestWithBearer(apiUrl, bearerToken, method, path, body) {
|
|
|
24812
24812
|
return result;
|
|
24813
24813
|
}
|
|
24814
24814
|
|
|
24815
|
+
class HarmonyUnauthorizedError extends Error {
|
|
24816
|
+
constructor(message = "Invalid or expired credentials") {
|
|
24817
|
+
super(message);
|
|
24818
|
+
this.name = "HarmonyUnauthorizedError";
|
|
24819
|
+
}
|
|
24820
|
+
}
|
|
24821
|
+
|
|
24815
24822
|
class HarmonyApiClient {
|
|
24816
24823
|
apiKey;
|
|
24817
24824
|
apiUrl;
|
|
24825
|
+
onUnauthorized;
|
|
24818
24826
|
constructor(options) {
|
|
24819
24827
|
this.apiKey = options?.apiKey ?? getApiKey();
|
|
24820
24828
|
this.apiUrl = options?.apiUrl ?? getApiUrl();
|
|
24829
|
+
this.onUnauthorized = options?.onUnauthorized;
|
|
24821
24830
|
}
|
|
24822
24831
|
getApiUrl() {
|
|
24823
24832
|
return this.apiUrl;
|
|
24824
24833
|
}
|
|
24834
|
+
setApiKey(apiKey) {
|
|
24835
|
+
this.apiKey = apiKey;
|
|
24836
|
+
}
|
|
24825
24837
|
async request(method, path, body, options) {
|
|
24826
24838
|
await requestSemaphore.acquire();
|
|
24827
24839
|
try {
|
|
@@ -24868,6 +24880,10 @@ class HarmonyApiClient {
|
|
|
24868
24880
|
}
|
|
24869
24881
|
if (!response.ok) {
|
|
24870
24882
|
const errorMsg = data?.error || (looksLikeJson ? null : `API error: ${response.status} (non-JSON response)`) || `API error: ${response.status}`;
|
|
24883
|
+
if (response.status === 401) {
|
|
24884
|
+
this.onUnauthorized?.();
|
|
24885
|
+
throw new HarmonyUnauthorizedError(errorMsg);
|
|
24886
|
+
}
|
|
24871
24887
|
if (!isRetryableError(null, response.status)) {
|
|
24872
24888
|
throw new Error(errorMsg);
|
|
24873
24889
|
}
|
|
@@ -24917,6 +24933,10 @@ class HarmonyApiClient {
|
|
|
24917
24933
|
} catch {
|
|
24918
24934
|
errorMsg = text || `API error: ${response.status}`;
|
|
24919
24935
|
}
|
|
24936
|
+
if (response.status === 401) {
|
|
24937
|
+
this.onUnauthorized?.();
|
|
24938
|
+
throw new HarmonyUnauthorizedError(errorMsg);
|
|
24939
|
+
}
|
|
24920
24940
|
if (!isRetryableError(null, response.status)) {
|
|
24921
24941
|
throw new Error(errorMsg);
|
|
24922
24942
|
}
|
|
@@ -25848,23 +25868,25 @@ var BATCH_SIZE = 100;
|
|
|
25848
25868
|
var CONCURRENCY_LIMIT = 5;
|
|
25849
25869
|
var BOILERPLATE_PATTERNS = [
|
|
25850
25870
|
/^todo:?$/i,
|
|
25851
|
-
/^placeholder
|
|
25871
|
+
/^placeholder(\s+\d+|:)?$/i,
|
|
25852
25872
|
/^\.\.\.$/,
|
|
25853
|
-
/^untitled
|
|
25854
|
-
/^(note|memo|draft)\s
|
|
25873
|
+
/^untitled(\s+\d+|:)?$/i,
|
|
25874
|
+
/^(note|memo|draft)\s+\d+$/i,
|
|
25855
25875
|
/^task transition:/i
|
|
25856
25876
|
];
|
|
25857
|
-
function
|
|
25877
|
+
function isBoilerplateTitle(title) {
|
|
25858
25878
|
const t = title.trim();
|
|
25859
|
-
const c = content.trim();
|
|
25860
|
-
if (c.length === 0)
|
|
25861
|
-
return true;
|
|
25862
25879
|
for (const pat of BOILERPLATE_PATTERNS) {
|
|
25863
25880
|
if (pat.test(t))
|
|
25864
25881
|
return true;
|
|
25865
25882
|
}
|
|
25866
25883
|
return false;
|
|
25867
25884
|
}
|
|
25885
|
+
function isBoilerplate(title, content) {
|
|
25886
|
+
if (content.trim().length === 0)
|
|
25887
|
+
return true;
|
|
25888
|
+
return isBoilerplateTitle(title);
|
|
25889
|
+
}
|
|
25868
25890
|
function scoreEntity(entity, relationCount, archiveBelow, deleteBelow, staleDraftAgeDays) {
|
|
25869
25891
|
const now = Date.now();
|
|
25870
25892
|
const ageDays = (now - Date.parse(entity.created_at)) / MS_PER_DAY;
|
|
@@ -25946,8 +25968,12 @@ function scoreEntity(entity, relationCount, archiveBelow, deleteBelow, staleDraf
|
|
|
25946
25968
|
legacy = true;
|
|
25947
25969
|
legacyReasons.push("no graph presence");
|
|
25948
25970
|
}
|
|
25971
|
+
const boilerplateTitle = isBoilerplateTitle(entity.title);
|
|
25949
25972
|
let bucket;
|
|
25950
|
-
if (
|
|
25973
|
+
if (boilerplateTitle && deleteBelow > 0) {
|
|
25974
|
+
bucket = "delete";
|
|
25975
|
+
reasons.push("boilerplate title override");
|
|
25976
|
+
} else if (score < deleteBelow)
|
|
25951
25977
|
bucket = "delete";
|
|
25952
25978
|
else if (score < archiveBelow)
|
|
25953
25979
|
bucket = "archive";
|
package/dist/lib/api-client.js
CHANGED
|
@@ -1570,16 +1570,28 @@ async function requestWithBearer(apiUrl, bearerToken, method, path, body) {
|
|
|
1570
1570
|
return result;
|
|
1571
1571
|
}
|
|
1572
1572
|
|
|
1573
|
+
class HarmonyUnauthorizedError extends Error {
|
|
1574
|
+
constructor(message = "Invalid or expired credentials") {
|
|
1575
|
+
super(message);
|
|
1576
|
+
this.name = "HarmonyUnauthorizedError";
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1573
1580
|
class HarmonyApiClient {
|
|
1574
1581
|
apiKey;
|
|
1575
1582
|
apiUrl;
|
|
1583
|
+
onUnauthorized;
|
|
1576
1584
|
constructor(options) {
|
|
1577
1585
|
this.apiKey = options?.apiKey ?? getApiKey();
|
|
1578
1586
|
this.apiUrl = options?.apiUrl ?? getApiUrl();
|
|
1587
|
+
this.onUnauthorized = options?.onUnauthorized;
|
|
1579
1588
|
}
|
|
1580
1589
|
getApiUrl() {
|
|
1581
1590
|
return this.apiUrl;
|
|
1582
1591
|
}
|
|
1592
|
+
setApiKey(apiKey) {
|
|
1593
|
+
this.apiKey = apiKey;
|
|
1594
|
+
}
|
|
1583
1595
|
async request(method, path, body, options) {
|
|
1584
1596
|
await requestSemaphore.acquire();
|
|
1585
1597
|
try {
|
|
@@ -1626,6 +1638,10 @@ class HarmonyApiClient {
|
|
|
1626
1638
|
}
|
|
1627
1639
|
if (!response.ok) {
|
|
1628
1640
|
const errorMsg = data?.error || (looksLikeJson ? null : `API error: ${response.status} (non-JSON response)`) || `API error: ${response.status}`;
|
|
1641
|
+
if (response.status === 401) {
|
|
1642
|
+
this.onUnauthorized?.();
|
|
1643
|
+
throw new HarmonyUnauthorizedError(errorMsg);
|
|
1644
|
+
}
|
|
1629
1645
|
if (!isRetryableError(null, response.status)) {
|
|
1630
1646
|
throw new Error(errorMsg);
|
|
1631
1647
|
}
|
|
@@ -1675,6 +1691,10 @@ class HarmonyApiClient {
|
|
|
1675
1691
|
} catch {
|
|
1676
1692
|
errorMsg = text || `API error: ${response.status}`;
|
|
1677
1693
|
}
|
|
1694
|
+
if (response.status === 401) {
|
|
1695
|
+
this.onUnauthorized?.();
|
|
1696
|
+
throw new HarmonyUnauthorizedError(errorMsg);
|
|
1697
|
+
}
|
|
1678
1698
|
if (!isRetryableError(null, response.status)) {
|
|
1679
1699
|
throw new Error(errorMsg);
|
|
1680
1700
|
}
|
|
@@ -2136,5 +2156,6 @@ export {
|
|
|
2136
2156
|
resetClient,
|
|
2137
2157
|
requestWithBearer,
|
|
2138
2158
|
getClient,
|
|
2159
|
+
HarmonyUnauthorizedError,
|
|
2139
2160
|
HarmonyApiClient
|
|
2140
2161
|
};
|