@echomem/mcp 1.4.14 → 1.4.16
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/billing-alert.js +39 -0
- package/dist/hud/diagnostics.js +135 -0
- package/dist/hud/server.js +110 -0
- package/dist/hud/web.js +250 -0
- package/dist/index.js +154 -32
- package/dist/setup-page/client-core.js +2 -0
- package/dist/setup-page/client-extraction.js +101 -4
- package/dist/setup-page/client-lifecycle.js +71 -5
- package/dist/setup-page/document.js +1 -1
- package/dist/setup-page/styles-extraction.js +211 -0
- package/dist/setup.js +112 -40
- package/dist/v1-contract.js +8 -7
- package/package.json +1 -1
|
@@ -59,7 +59,73 @@ export const SETUP_PAGE_STYLES_EXTRACTION = String.raw ` /* ---- dashboard (p
|
|
|
59
59
|
}
|
|
60
60
|
.primary { background: var(--echo-ink-primary); color: #fff; }
|
|
61
61
|
.secondary { background: #fff; color: var(--echo-ink-primary); }
|
|
62
|
+
.textButton {
|
|
63
|
+
min-height: 36px;
|
|
64
|
+
border-color: transparent;
|
|
65
|
+
background: transparent;
|
|
66
|
+
color: var(--echo-ink-faint);
|
|
67
|
+
padding: 0 8px;
|
|
68
|
+
font-size: 13px;
|
|
69
|
+
font-weight: 700;
|
|
70
|
+
}
|
|
71
|
+
.textButton:hover { color: var(--echo-ink-primary); background: transparent; }
|
|
62
72
|
button:disabled { cursor: not-allowed; opacity: 0.55; }
|
|
73
|
+
.consentStage {
|
|
74
|
+
display: grid;
|
|
75
|
+
place-items: center;
|
|
76
|
+
min-height: min(620px, calc(100vh - 180px));
|
|
77
|
+
}
|
|
78
|
+
.localConsent {
|
|
79
|
+
width: min(680px, 100%);
|
|
80
|
+
border: 2px solid var(--echo-ink-primary);
|
|
81
|
+
border-radius: 8px;
|
|
82
|
+
background: var(--echo-paper-white);
|
|
83
|
+
padding: clamp(22px, 4vw, 34px);
|
|
84
|
+
box-shadow: 0 18px 38px -28px rgba(26,58,143,0.45);
|
|
85
|
+
}
|
|
86
|
+
.consentEyebrow {
|
|
87
|
+
margin: 0 0 10px;
|
|
88
|
+
font-family: var(--echo-font-mono);
|
|
89
|
+
font-size: 11px;
|
|
90
|
+
font-weight: 800;
|
|
91
|
+
letter-spacing: 0.08em;
|
|
92
|
+
text-transform: uppercase;
|
|
93
|
+
color: var(--echo-ink-primary);
|
|
94
|
+
}
|
|
95
|
+
.localConsent h2 {
|
|
96
|
+
max-width: 620px;
|
|
97
|
+
margin: 0;
|
|
98
|
+
font-size: clamp(30px, 3.4vw, 42px);
|
|
99
|
+
line-height: 1.04;
|
|
100
|
+
color: var(--echo-ink-primary);
|
|
101
|
+
}
|
|
102
|
+
.localConsent > p:not(.consentEyebrow):not(.consentFine) {
|
|
103
|
+
max-width: 590px;
|
|
104
|
+
margin: 14px 0 0;
|
|
105
|
+
font-size: 16px;
|
|
106
|
+
line-height: 1.55;
|
|
107
|
+
color: var(--echo-ink-mute);
|
|
108
|
+
}
|
|
109
|
+
.consentActions {
|
|
110
|
+
display: flex;
|
|
111
|
+
flex-wrap: wrap;
|
|
112
|
+
gap: 10px;
|
|
113
|
+
align-items: center;
|
|
114
|
+
margin-top: 22px;
|
|
115
|
+
}
|
|
116
|
+
.consentActions button {
|
|
117
|
+
min-height: 48px;
|
|
118
|
+
padding: 0 18px;
|
|
119
|
+
}
|
|
120
|
+
.consentFine {
|
|
121
|
+
min-height: 18px;
|
|
122
|
+
margin: 10px 0 0;
|
|
123
|
+
font-family: var(--echo-font-mono);
|
|
124
|
+
font-size: 11px;
|
|
125
|
+
line-height: 1.45;
|
|
126
|
+
color: var(--echo-ink-faint);
|
|
127
|
+
}
|
|
128
|
+
.consentFine:empty { display: none; }
|
|
63
129
|
.track { height: 12px; overflow: hidden; border-radius: 999px; background: #e8e8e1; margin: 16px 0 10px; }
|
|
64
130
|
.fill { height: 100%; width: 0%; background: var(--echo-ink-primary); transition: width 180ms ease; }
|
|
65
131
|
/* indeterminate "we're working on it" bar for the prep phase (before job counts move) */
|
|
@@ -93,6 +159,7 @@ export const SETUP_PAGE_STYLES_EXTRACTION = String.raw ` /* ---- dashboard (p
|
|
|
93
159
|
.explainCopy h2 { font-size: 38px; }
|
|
94
160
|
.explainCta .promiseActions { width: 100%; }
|
|
95
161
|
.explainCta .primary, .explainCta .secondary { width: 100%; }
|
|
162
|
+
.consentActions .primary { width: 100%; }
|
|
96
163
|
.cityHero { min-height: auto; }
|
|
97
164
|
.cityShell {
|
|
98
165
|
width: 100vw;
|
|
@@ -615,6 +682,150 @@ export const SETUP_PAGE_STYLES_EXTRACTION = String.raw ` /* ---- dashboard (p
|
|
|
615
682
|
.exCountdown strong { color: var(--echo-ink-primary); font-weight: 700; }
|
|
616
683
|
.exOverdue { margin: 0; max-width: 620px; border: 1px solid rgba(196, 148, 42, 0.45); background: rgba(233, 185, 73, 0.12); border-radius: 8px; padding: 12px 14px; font-size: 13px; line-height: 1.5; color: var(--echo-ink-text); }
|
|
617
684
|
.exOverdue strong { display: block; margin-bottom: 4px; color: var(--echo-ink-primary); }
|
|
685
|
+
.is-hidden { display: none !important; }
|
|
686
|
+
.recallGateBlock { width: min(680px, 100%); margin: 2px auto 0; }
|
|
687
|
+
.recallGate {
|
|
688
|
+
width: 100%;
|
|
689
|
+
position: relative;
|
|
690
|
+
overflow: hidden;
|
|
691
|
+
border: 1px solid rgba(33,64,154,0.42);
|
|
692
|
+
border-radius: 12px;
|
|
693
|
+
background:
|
|
694
|
+
linear-gradient(180deg, rgba(239,244,255,0.98) 0%, rgba(255,255,255,0.99) 46%),
|
|
695
|
+
var(--echo-paper-white);
|
|
696
|
+
padding: clamp(24px, 4vw, 36px);
|
|
697
|
+
box-shadow: 0 28px 60px -42px rgba(33,64,154,0.48);
|
|
698
|
+
text-align: left;
|
|
699
|
+
}
|
|
700
|
+
.recallGate::before {
|
|
701
|
+
content: "";
|
|
702
|
+
position: absolute;
|
|
703
|
+
inset: 0 0 auto 0;
|
|
704
|
+
height: 8px;
|
|
705
|
+
background: linear-gradient(90deg, #18317d, #4b6bd4, var(--echo-ink-primary));
|
|
706
|
+
}
|
|
707
|
+
.recallEyebrow {
|
|
708
|
+
display: inline-flex;
|
|
709
|
+
align-items: center;
|
|
710
|
+
gap: 8px;
|
|
711
|
+
margin: 0 0 14px;
|
|
712
|
+
border: 1px solid rgba(33,64,154,0.18);
|
|
713
|
+
border-radius: 999px;
|
|
714
|
+
background: #eef3ff;
|
|
715
|
+
padding: 7px 11px;
|
|
716
|
+
font-family: var(--echo-font-mono);
|
|
717
|
+
font-size: 11px;
|
|
718
|
+
font-weight: 900;
|
|
719
|
+
letter-spacing: 0.06em;
|
|
720
|
+
text-transform: uppercase;
|
|
721
|
+
color: #18317d;
|
|
722
|
+
}
|
|
723
|
+
.recallEyebrow i {
|
|
724
|
+
width: 8px;
|
|
725
|
+
height: 8px;
|
|
726
|
+
border-radius: 999px;
|
|
727
|
+
background: var(--echo-ink-primary);
|
|
728
|
+
box-shadow: 0 0 0 4px rgba(33,64,154,0.1);
|
|
729
|
+
}
|
|
730
|
+
.recallGate h3 {
|
|
731
|
+
margin: 0;
|
|
732
|
+
max-width: 520px;
|
|
733
|
+
font-family: var(--echo-font-brand);
|
|
734
|
+
font-size: clamp(34px, 4.6vw, 48px);
|
|
735
|
+
line-height: 1.02;
|
|
736
|
+
font-weight: 900;
|
|
737
|
+
color: var(--echo-ink-text);
|
|
738
|
+
letter-spacing: 0;
|
|
739
|
+
}
|
|
740
|
+
.recallGate p {
|
|
741
|
+
max-width: 560px;
|
|
742
|
+
margin: 14px 0 0;
|
|
743
|
+
font-size: 16px;
|
|
744
|
+
line-height: 1.55;
|
|
745
|
+
color: var(--echo-ink-mute);
|
|
746
|
+
}
|
|
747
|
+
.recallTrial {
|
|
748
|
+
margin-top: 18px;
|
|
749
|
+
display: inline-grid;
|
|
750
|
+
grid-template-columns: auto 1fr;
|
|
751
|
+
gap: 10px;
|
|
752
|
+
align-items: center;
|
|
753
|
+
border: 1px solid rgba(33,64,154,0.18);
|
|
754
|
+
border-radius: 10px;
|
|
755
|
+
background: #f3f6ff;
|
|
756
|
+
padding: 10px 12px;
|
|
757
|
+
color: #18317d;
|
|
758
|
+
}
|
|
759
|
+
.recallTrial strong {
|
|
760
|
+
font-size: 28px;
|
|
761
|
+
line-height: 1;
|
|
762
|
+
color: #18317d;
|
|
763
|
+
}
|
|
764
|
+
.recallTrial span {
|
|
765
|
+
font-size: 13px;
|
|
766
|
+
line-height: 1.25;
|
|
767
|
+
font-weight: 800;
|
|
768
|
+
}
|
|
769
|
+
.recallUsedNote {
|
|
770
|
+
margin-top: 18px;
|
|
771
|
+
border-left: 4px solid var(--echo-ink-primary);
|
|
772
|
+
background: #f3f6ff;
|
|
773
|
+
padding: 11px 13px;
|
|
774
|
+
color: #18317d;
|
|
775
|
+
font-size: 13px;
|
|
776
|
+
line-height: 1.45;
|
|
777
|
+
font-weight: 700;
|
|
778
|
+
}
|
|
779
|
+
.recallGateActions {
|
|
780
|
+
display: flex;
|
|
781
|
+
flex-wrap: wrap;
|
|
782
|
+
gap: 14px;
|
|
783
|
+
align-items: center;
|
|
784
|
+
margin-top: 24px;
|
|
785
|
+
}
|
|
786
|
+
.recallGateActions button {
|
|
787
|
+
min-height: 50px;
|
|
788
|
+
}
|
|
789
|
+
.recallGateActions .primary {
|
|
790
|
+
min-width: 0;
|
|
791
|
+
border-color: #18317d;
|
|
792
|
+
background: var(--echo-ink-primary);
|
|
793
|
+
color: #fff;
|
|
794
|
+
box-shadow: 0 18px 34px -26px rgba(33,64,154,0.85);
|
|
795
|
+
}
|
|
796
|
+
.recallGateActions .primary:hover {
|
|
797
|
+
background: #18317d;
|
|
798
|
+
}
|
|
799
|
+
.recallGate .recallFine {
|
|
800
|
+
margin-top: 10px;
|
|
801
|
+
font-family: var(--echo-font-mono);
|
|
802
|
+
font-size: 11px;
|
|
803
|
+
color: var(--echo-ink-faint);
|
|
804
|
+
}
|
|
805
|
+
@media (max-width: 720px) {
|
|
806
|
+
.recallGateActions .primary { width: 100%; }
|
|
807
|
+
}
|
|
808
|
+
.recallGate code,
|
|
809
|
+
.recallSkipNote code {
|
|
810
|
+
font-family: var(--echo-font-mono);
|
|
811
|
+
font-size: 0.92em;
|
|
812
|
+
background: var(--echo-paper-soft);
|
|
813
|
+
border: 1px solid var(--echo-line-soft);
|
|
814
|
+
border-radius: 5px;
|
|
815
|
+
padding: 1px 5px;
|
|
816
|
+
color: var(--echo-ink-primary);
|
|
817
|
+
}
|
|
818
|
+
.recallTryWrap { width: 100%; }
|
|
819
|
+
.recallSkipNote {
|
|
820
|
+
margin: 0 0 12px;
|
|
821
|
+
border: 1px solid var(--echo-line-soft);
|
|
822
|
+
border-radius: 8px;
|
|
823
|
+
background: rgba(246,244,238,0.86);
|
|
824
|
+
padding: 10px 12px;
|
|
825
|
+
font-size: 13px;
|
|
826
|
+
line-height: 1.45;
|
|
827
|
+
color: var(--echo-ink-mute);
|
|
828
|
+
}
|
|
618
829
|
.tryCard { margin-top: 2px; max-width: 760px; border: 2px solid var(--echo-ink-primary); border-radius: 8px; background: var(--echo-paper-white); padding: clamp(18px, 3vw, 26px); box-shadow: 0 18px 38px -28px rgba(26,58,143,0.45); }
|
|
619
830
|
.tryCard .tryK { margin: 0 0 10px; font-family: var(--echo-font-mono); font-size: 12px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--echo-ink-primary); }
|
|
620
831
|
.tryCard .tryTitle {
|
package/dist/setup.js
CHANGED
|
@@ -38,6 +38,7 @@ import { checkLatestUpdateStatus, compareSemver, readCachedUpdateStatus } from "
|
|
|
38
38
|
// device unless the user explicitly starts migration. Override the hosted auth origin with ECHO_WEB_URL.
|
|
39
39
|
const WEB_URL = (process.env.ECHO_WEB_URL || "https://yeahecho.com").replace(/\/$/, "");
|
|
40
40
|
const API_BASE_URL = (process.env.ECHO_API_BASE_URL || "https://echo-mem-chrome.vercel.app").replace(/\/$/, "");
|
|
41
|
+
const PRICING_URL = (process.env.ECHO_PRICING_URL || "https://echoknows.com/pricing").replace(/\/$/, "");
|
|
41
42
|
function home(...p) {
|
|
42
43
|
return path.join(os.homedir(), ...p);
|
|
43
44
|
}
|
|
@@ -1250,6 +1251,33 @@ export function startCallbackServer(opts = {}) {
|
|
|
1250
1251
|
json(res, 200, payload);
|
|
1251
1252
|
return;
|
|
1252
1253
|
}
|
|
1254
|
+
if (route === "/billing-status" && req.method === "GET") {
|
|
1255
|
+
if (!checkNonce(url.searchParams.get("nonce") || undefined))
|
|
1256
|
+
return void text(res, 403, "bad nonce");
|
|
1257
|
+
const token = new KeyStore().getToken();
|
|
1258
|
+
const pricingUrl = `${PRICING_URL}?source=mcp_onboarding`;
|
|
1259
|
+
if (!token) {
|
|
1260
|
+
json(res, 200, { plan: "free", paid: false, trialAvailable: true, trialUsed: false, pricingUrl });
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
try {
|
|
1264
|
+
const response = await authedAxios(token).get("/api/extension/account/bootstrap", { timeout: 6000 });
|
|
1265
|
+
const plan = (asString(response.data?.plan) || "free").toLowerCase();
|
|
1266
|
+
const trialUsed = response.data?.billing?.trialUsed === true;
|
|
1267
|
+
const trialAvailable = response.data?.billing?.trialAvailable !== false;
|
|
1268
|
+
json(res, 200, {
|
|
1269
|
+
plan,
|
|
1270
|
+
paid: ["pro", "power", "team", "enterprise"].includes(plan),
|
|
1271
|
+
trialAvailable,
|
|
1272
|
+
trialUsed,
|
|
1273
|
+
pricingUrl,
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1276
|
+
catch {
|
|
1277
|
+
json(res, 200, { plan: "unknown", paid: false, trialAvailable: true, trialUsed: false, pricingUrl });
|
|
1278
|
+
}
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1253
1281
|
if (route === "/report" && req.method === "GET") {
|
|
1254
1282
|
// Local forensic "Context Doctor" report — computed locally, served BEFORE auth (scan-first).
|
|
1255
1283
|
res.setHeader("Cache-Control", "no-store");
|
|
@@ -1353,6 +1381,22 @@ export function startCallbackServer(opts = {}) {
|
|
|
1353
1381
|
json(res, 200, progress);
|
|
1354
1382
|
return;
|
|
1355
1383
|
}
|
|
1384
|
+
if (route === "/report-consent" && req.method === "POST") {
|
|
1385
|
+
let body;
|
|
1386
|
+
try {
|
|
1387
|
+
body = await readJsonBody(req);
|
|
1388
|
+
}
|
|
1389
|
+
catch {
|
|
1390
|
+
text(res, 400, "bad json");
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
if (!checkNonce(asString(body.nonce)))
|
|
1394
|
+
return void text(res, 403, "bad nonce");
|
|
1395
|
+
const allowed = body.allowed === true;
|
|
1396
|
+
opts.onReportConsent?.(allowed);
|
|
1397
|
+
json(res, 200, { ok: true, allowed });
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1356
1400
|
if (route === "/logout" && req.method === "POST") {
|
|
1357
1401
|
let body;
|
|
1358
1402
|
try {
|
|
@@ -1780,6 +1824,8 @@ async function cmdLogin(flags) {
|
|
|
1780
1824
|
const nonce = devNonce || randomUUID();
|
|
1781
1825
|
let stats = null;
|
|
1782
1826
|
let forensicReport = null;
|
|
1827
|
+
let forensicConsent = "pending";
|
|
1828
|
+
let forensicScanStarted = false;
|
|
1783
1829
|
const forensicStartedAt = Date.now();
|
|
1784
1830
|
let forensicStageStartedAt = forensicStartedAt;
|
|
1785
1831
|
let forensicStage = "starting";
|
|
@@ -1799,6 +1845,28 @@ async function cmdLogin(flags) {
|
|
|
1799
1845
|
getStats: () => stats,
|
|
1800
1846
|
getReport: () => forensicReport,
|
|
1801
1847
|
getReportProgress: () => forensicProgress,
|
|
1848
|
+
onReportConsent: (allowed) => {
|
|
1849
|
+
if (!allowed) {
|
|
1850
|
+
forensicConsent = "declined";
|
|
1851
|
+
forensicProgress = {
|
|
1852
|
+
status: "failed",
|
|
1853
|
+
scanned: 0,
|
|
1854
|
+
total: 0,
|
|
1855
|
+
stage: "failed",
|
|
1856
|
+
label: "Local scan skipped",
|
|
1857
|
+
elapsedMs: Date.now() - forensicStartedAt,
|
|
1858
|
+
stageElapsedMs: Date.now() - forensicStageStartedAt,
|
|
1859
|
+
updatedAt: Date.now(),
|
|
1860
|
+
error: {
|
|
1861
|
+
code: "REPORT_SCAN_DECLINED",
|
|
1862
|
+
message: "Local file analysis was skipped. EchoMem can still connect, save conversations, and import memories.",
|
|
1863
|
+
},
|
|
1864
|
+
};
|
|
1865
|
+
return;
|
|
1866
|
+
}
|
|
1867
|
+
forensicConsent = "allowed";
|
|
1868
|
+
startForensicScan();
|
|
1869
|
+
},
|
|
1802
1870
|
});
|
|
1803
1871
|
const callbackUrl = `http://127.0.0.1:${srv.port}/callback`;
|
|
1804
1872
|
const localSetupUrl = `http://127.0.0.1:${srv.port}/setup?nonce=${nonce}`;
|
|
@@ -1812,46 +1880,50 @@ async function cmdLogin(flags) {
|
|
|
1812
1880
|
openBrowser(localSetupUrl);
|
|
1813
1881
|
console.log(`If it didn't open, visit:\n ${localSetupUrl}\n`);
|
|
1814
1882
|
console.log("Waiting for browser approval for up to 15 minutes…");
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1883
|
+
const startForensicScan = () => {
|
|
1884
|
+
if (forensicScanStarted || forensicConsent !== "allowed")
|
|
1885
|
+
return;
|
|
1886
|
+
forensicScanStarted = true;
|
|
1887
|
+
// Build the local forensic "Context Doctor" report off-thread only after explicit consent.
|
|
1888
|
+
buildForensicReportOffThread((progress) => {
|
|
1889
|
+
const now = Date.now();
|
|
1890
|
+
const nextStage = progress.stage || forensicStage;
|
|
1891
|
+
if (nextStage !== forensicStage) {
|
|
1892
|
+
forensicStage = nextStage;
|
|
1893
|
+
forensicStageStartedAt = now;
|
|
1894
|
+
console.log(`Local scan: ${forensicStageLabel(forensicStage)}…`);
|
|
1895
|
+
}
|
|
1896
|
+
forensicProgress = {
|
|
1897
|
+
status: "running",
|
|
1898
|
+
scanned: progress.done,
|
|
1899
|
+
total: progress.total,
|
|
1900
|
+
stage: forensicStage,
|
|
1901
|
+
label: forensicStageLabel(forensicStage),
|
|
1902
|
+
detail: progress.detail,
|
|
1903
|
+
elapsedMs: now - forensicStartedAt,
|
|
1904
|
+
stageElapsedMs: now - forensicStageStartedAt,
|
|
1905
|
+
updatedAt: now,
|
|
1906
|
+
};
|
|
1907
|
+
})
|
|
1908
|
+
.then((r) => {
|
|
1909
|
+
forensicReport = r;
|
|
1910
|
+
})
|
|
1911
|
+
.catch((e) => {
|
|
1912
|
+
const now = Date.now();
|
|
1913
|
+
forensicProgress = {
|
|
1914
|
+
status: "failed",
|
|
1915
|
+
scanned: forensicProgress.scanned,
|
|
1916
|
+
total: forensicProgress.total,
|
|
1917
|
+
stage: "failed",
|
|
1918
|
+
label: "Local scan failed",
|
|
1919
|
+
elapsedMs: now - forensicStartedAt,
|
|
1920
|
+
stageElapsedMs: now - forensicStageStartedAt,
|
|
1921
|
+
updatedAt: now,
|
|
1922
|
+
error: safeForensicError(e),
|
|
1923
|
+
};
|
|
1924
|
+
console.error(`Could not build the local report: ${e instanceof Error ? e.message : String(e)}`);
|
|
1925
|
+
});
|
|
1926
|
+
};
|
|
1855
1927
|
let token;
|
|
1856
1928
|
let key;
|
|
1857
1929
|
try {
|
package/dist/v1-contract.js
CHANGED
|
@@ -108,6 +108,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
108
108
|
const currentTime = new Date().toISOString();
|
|
109
109
|
const map = opts.map?.trim();
|
|
110
110
|
const updateNotice = opts.updateNotice?.trim();
|
|
111
|
+
const paidRecallNote = "Requires Echo Pro or Power; saving conversations and memory extraction remain included.";
|
|
111
112
|
const updateSection = updateNotice ? `\n\nUPDATE NOTICE: ${updateNotice}` : "";
|
|
112
113
|
const mapSection = map
|
|
113
114
|
? `\n\nThis user's EchoMem currently covers these topics (a relevance guide — recall when the task relates to one of them):\n${map}\n`
|
|
@@ -115,7 +116,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
115
116
|
return [
|
|
116
117
|
{
|
|
117
118
|
name: canonicalToolNames.search,
|
|
118
|
-
description: withMcpVersion(`Recall the user's prior decisions, preferences, and project context from EchoMem — their long-term memory across ALL their AI tools, not just this session. Use it instead of re-deriving or re-asking what the user already settled
|
|
119
|
+
description: withMcpVersion(`Recall the user's prior decisions, preferences, and project context from EchoMem — their long-term memory across ALL their AI tools, not just this session. Use it instead of re-deriving or re-asking what the user already settled. ${paidRecallNote}${mapSection}\nReturns the ranked memories; set includeAnswer=true only if you need the legacy synthesized answer. Current time: ${currentTime}.${updateSection}`),
|
|
119
120
|
inputSchema: {
|
|
120
121
|
type: "object",
|
|
121
122
|
properties: {
|
|
@@ -138,7 +139,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
138
139
|
},
|
|
139
140
|
{
|
|
140
141
|
name: "search_memories_by_description_semantic",
|
|
141
|
-
description:
|
|
142
|
+
description: `Legacy alias for search_memories. ${paidRecallNote}`,
|
|
142
143
|
inputSchema: {
|
|
143
144
|
type: "object",
|
|
144
145
|
properties: {
|
|
@@ -161,7 +162,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
161
162
|
},
|
|
162
163
|
{
|
|
163
164
|
name: canonicalToolNames.save,
|
|
164
|
-
description: "Save this conversation into EchoMem as long-term memory (durable memories are extracted automatically). passthrough=true stores the text verbatim as a session capsule
|
|
165
|
+
description: "Save this conversation into EchoMem as long-term memory (durable memories are extracted automatically). Saving is included. passthrough=true stores the text verbatim as a session capsule; reloading/searching saved memories requires Echo Pro or Power.",
|
|
165
166
|
inputSchema: {
|
|
166
167
|
type: "object",
|
|
167
168
|
properties: {
|
|
@@ -194,7 +195,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
194
195
|
},
|
|
195
196
|
{
|
|
196
197
|
name: canonicalToolNames.timeRange,
|
|
197
|
-
description: `Retrieve memories within a specific date range. Current time: ${currentTime}.`,
|
|
198
|
+
description: `Retrieve memories within a specific date range. ${paidRecallNote} Current time: ${currentTime}.`,
|
|
198
199
|
inputSchema: {
|
|
199
200
|
type: "object",
|
|
200
201
|
properties: {
|
|
@@ -212,7 +213,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
212
213
|
},
|
|
213
214
|
{
|
|
214
215
|
name: canonicalToolNames.keywords,
|
|
215
|
-
description:
|
|
216
|
+
description: `Search memories based on keywords in keys field. ${paidRecallNote}`,
|
|
216
217
|
inputSchema: {
|
|
217
218
|
type: "object",
|
|
218
219
|
properties: {
|
|
@@ -369,7 +370,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
369
370
|
},
|
|
370
371
|
{
|
|
371
372
|
name: canonicalToolNames.getByContext,
|
|
372
|
-
description: withMcpVersion(`Deterministically re-fetch the exact batch of memories saved under one contextId — no semantic search, no ranking, just that session's saved capsule. save_conversation returns a contextId; pass it here to pull back precisely those memories, e.g. to warm up a fresh session with what a prior session saved, or to verify the saved facts are still present. Current time: ${currentTime}.`),
|
|
373
|
+
description: withMcpVersion(`Deterministically re-fetch the exact batch of memories saved under one contextId — no semantic search, no ranking, just that session's saved capsule. ${paidRecallNote} save_conversation returns a contextId; pass it here to pull back precisely those memories, e.g. to warm up a fresh session with what a prior session saved, or to verify the saved facts are still present. Current time: ${currentTime}.`),
|
|
373
374
|
inputSchema: {
|
|
374
375
|
type: "object",
|
|
375
376
|
properties: {
|
|
@@ -386,7 +387,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
386
387
|
},
|
|
387
388
|
{
|
|
388
389
|
name: canonicalToolNames.checkpointByContext,
|
|
389
|
-
description: withMcpVersion(`Rebuild a clean-context checkpoint / decision log from one EchoMem contextId. Use this when the user or EchoMem HUD gives you a contextId for a renewed coding session and you need the session handoff, not a raw memory dump. It deterministically fetches that context and formats it as orientation state: decisions, carryover, constraints, and checkpoints. Current time: ${currentTime}.`),
|
|
390
|
+
description: withMcpVersion(`Rebuild a clean-context checkpoint / decision log from one EchoMem contextId. ${paidRecallNote} Use this when the user or EchoMem HUD gives you a contextId for a renewed coding session and you need the session handoff, not a raw memory dump. It deterministically fetches that context and formats it as orientation state: decisions, carryover, constraints, and checkpoints. Current time: ${currentTime}.`),
|
|
390
391
|
inputSchema: {
|
|
391
392
|
type: "object",
|
|
392
393
|
properties: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@echomem/mcp",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.16",
|
|
4
4
|
"description": "EchoMem MCP bridge: cloud-first memory tools, local context HUD, and the Agent Doctor workspace forensics report (cost ledger + 3D repo city)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|