@echomem/mcp 1.4.23 → 1.4.25
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/hud/server.js +1 -1
- package/dist/hud/web.js +1 -1
- package/dist/index.js +111 -15
- package/dist/package-metadata.js +5 -2
- package/dist/setup-page/client-extraction.js +1 -1
- package/dist/setup-preview.js +1 -1
- package/dist/setup.js +8 -5
- package/dist/v1-contract.js +81 -5
- package/package.json +1 -1
package/dist/hud/server.js
CHANGED
|
@@ -13,7 +13,7 @@ import { assembleCodex, assembleClaude } from "../migrate.js";
|
|
|
13
13
|
import { readBillingAlert } from "../billing-alert.js";
|
|
14
14
|
import { readSessionWorkingDirectory, } from "./session-launcher.js";
|
|
15
15
|
const API_BASE = (process.env.ECHO_API_BASE_URL || "https://echo-mem-chrome.vercel.app").replace(/\/$/, "");
|
|
16
|
-
const PRICING_URL = (process.env.ECHO_PRICING_URL || "https://echoknows.com/
|
|
16
|
+
const PRICING_URL = (process.env.ECHO_PRICING_URL || "https://echoknows.com/account").replace(/\/$/, "");
|
|
17
17
|
export async function createHudServer(opts = {}) {
|
|
18
18
|
const mode = opts.mode || "auto";
|
|
19
19
|
const port = opts.port ?? 17377;
|
package/dist/hud/web.js
CHANGED
|
@@ -1729,7 +1729,7 @@ export const HUD_HTML = String.raw `<!doctype html>
|
|
|
1729
1729
|
state: "ok",
|
|
1730
1730
|
plan: "pro",
|
|
1731
1731
|
paid: true,
|
|
1732
|
-
pricingUrl: "https://
|
|
1732
|
+
pricingUrl: "https://echoknows.com/account?source=hud_preview",
|
|
1733
1733
|
memoryProcessingQuota: { used: previewProcessingUsed, limit: 200000, remaining: 200000 - previewProcessingUsed, resetAt: new Date(Date.now() + 31 * 60 * 60 * 1000).toISOString() },
|
|
1734
1734
|
memorySearchQuota: { used: previewSearchUsed, limit: 500, remaining: 500 - previewSearchUsed, resetAt: new Date(Date.now() + 31 * 60 * 60 * 1000).toISOString() },
|
|
1735
1735
|
historicalConversationQuota: { used: 191, limit: 500, remaining: 309 },
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
4
4
|
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
5
|
import axios from "axios";
|
|
6
6
|
import { ZodError } from "zod";
|
|
7
|
-
import { canonicalToolNames, completeGroupPublicationSchema, createGroupInviteSchema, createGroupSchema, deleteMemorySchema, getByContextSchema, groupContextSchema, joinGroupSchema, keywordsSchema, listFriendsSchema, listToolSpecs, othersSchema, publishBatchToGroupSchema, publishToGroupSchema, prepareGroupPublicationSchema, publicMemorySchema, resolveCanonicalToolName, saveConversationSchema, searchMemoriesSchema, searchUsersSchema, sendFriendRequestSchema, timeRangeSchema, } from "./v1-contract.js";
|
|
7
|
+
import { canonicalToolNames, completeGroupPublicationSchema, createGroupInviteSchema, createGroupSchema, deleteMemorySchema, flagPublicationAttentionSchema, getByContextSchema, groupContextSchema, joinGroupSchema, keywordsSchema, listFriendsSchema, listToolSpecs, othersSchema, publishBatchToGroupSchema, publishToGroupSchema, prepareGroupPublicationSchema, publicMemorySchema, resolveCanonicalToolName, saveConversationSchema, searchMemoriesSchema, searchUsersSchema, sendFriendRequestSchema, timeRangeSchema, updateGroupProfileSchema, } from "./v1-contract.js";
|
|
8
8
|
import { KeyStore } from "./keystore.js";
|
|
9
9
|
import { EventLogger, hashText } from "./events.js";
|
|
10
10
|
import { buildReportText } from "./report.js";
|
|
@@ -16,7 +16,11 @@ import { MCP_PACKAGE_VERSION, MCP_SERVER_INSTRUCTIONS } from "./package-metadata
|
|
|
16
16
|
import { clearBillingAlert, writeBillingAlert } from "./billing-alert.js";
|
|
17
17
|
import { checkLatestUpdateStatus, formatUpdateNotice, formatUpdateStatusText, startBackgroundUpdateCheck, } from "./update-check.js";
|
|
18
18
|
const ECHO_API_BASE_URL = process.env.ECHO_API_BASE_URL || "https://echo-mem-chrome.vercel.app";
|
|
19
|
-
const ECHO_PRICING_URL = process.env.ECHO_PRICING_URL || "https://echoknows.com/
|
|
19
|
+
const ECHO_PRICING_URL = process.env.ECHO_PRICING_URL || "https://echoknows.com/account";
|
|
20
|
+
const ECHO_MEMORY_WEB_URL = (process.env.ECHO_MEMORY_WEB_URL || "https://echoknows.com/company/memories").replace(/\/$/, "");
|
|
21
|
+
function memoryWebUrl(memoryId) {
|
|
22
|
+
return `${ECHO_MEMORY_WEB_URL}?memoryId=${encodeURIComponent(memoryId)}`;
|
|
23
|
+
}
|
|
20
24
|
/** Thrown when no API token is present yet — the model gets a "run login" nudge, not a hard error. */
|
|
21
25
|
class NoTokenError extends Error {
|
|
22
26
|
}
|
|
@@ -495,6 +499,14 @@ function inputAnalyticsForTool(canonicalName, args) {
|
|
|
495
499
|
memory_id_hash: memoryId ? hashText(memoryId) : undefined,
|
|
496
500
|
};
|
|
497
501
|
}
|
|
502
|
+
case canonicalToolNames.flagPublicationAttention: {
|
|
503
|
+
const memoryIds = Array.isArray(a.memoryIds) ? a.memoryIds.filter((id) => typeof id === "string") : [];
|
|
504
|
+
return {
|
|
505
|
+
memory_count: memoryIds.length,
|
|
506
|
+
has_label: !!readString(a, "label"),
|
|
507
|
+
confirmed: a.confirmed === true,
|
|
508
|
+
};
|
|
509
|
+
}
|
|
498
510
|
case canonicalToolNames.publishBatchToGroup: {
|
|
499
511
|
const memoryIds = Array.isArray(a.memoryIds) ? a.memoryIds.filter((id) => typeof id === "string") : [];
|
|
500
512
|
return {
|
|
@@ -983,6 +995,16 @@ class EchoMemApiClient {
|
|
|
983
995
|
const response = await this.axios.post("/api/extension/social/groups/current/publications/prepare", parsed, { headers: enc.enabled && enc.key ? { "X-Encryption-Key": enc.key } : undefined });
|
|
984
996
|
return response.data;
|
|
985
997
|
}
|
|
998
|
+
async flagMemoriesForPublicationAttention(args) {
|
|
999
|
+
const parsed = flagPublicationAttentionSchema.parse(args ?? {});
|
|
1000
|
+
const response = await this.axios.post("/api/extension/memories/publication-attention", parsed);
|
|
1001
|
+
return response.data;
|
|
1002
|
+
}
|
|
1003
|
+
async updateGroupProfile(args) {
|
|
1004
|
+
const parsed = updateGroupProfileSchema.parse(args ?? {});
|
|
1005
|
+
const response = await this.axios.patch("/api/extension/social/groups/current/profile", parsed);
|
|
1006
|
+
return response.data;
|
|
1007
|
+
}
|
|
986
1008
|
async completeGroupPublication(args) {
|
|
987
1009
|
const parsed = completeGroupPublicationSchema.parse(args ?? {});
|
|
988
1010
|
const enc = await this.encState();
|
|
@@ -993,7 +1015,9 @@ class EchoMemApiClient {
|
|
|
993
1015
|
const parsed = publishToGroupSchema.parse(args ?? {});
|
|
994
1016
|
const enc = await this.encState();
|
|
995
1017
|
try {
|
|
996
|
-
const response = await this.axios.post(`/api/extension/social/groups/current/memories/${encodeURIComponent(parsed.memoryId)}/publish`, {
|
|
1018
|
+
const response = await this.axios.post(`/api/extension/social/groups/current/memories/${encodeURIComponent(parsed.memoryId)}/publish`, {
|
|
1019
|
+
acknowledgedFlaggedMemoryIds: parsed.acknowledgedFlaggedMemoryIds,
|
|
1020
|
+
}, {
|
|
997
1021
|
headers: enc.enabled && enc.key ? { "X-Encryption-Key": enc.key } : undefined,
|
|
998
1022
|
});
|
|
999
1023
|
return response.data;
|
|
@@ -1009,6 +1033,8 @@ class EchoMemApiClient {
|
|
|
1009
1033
|
const response = await this.axios.post("/api/extension/social/groups/current/memories/publish-batch", {
|
|
1010
1034
|
memoryIds: parsed.memoryIds,
|
|
1011
1035
|
contextId: parsed.contextId,
|
|
1036
|
+
selectionReason: parsed.selectionReason,
|
|
1037
|
+
acknowledgedFlaggedMemoryIds: parsed.acknowledgedFlaggedMemoryIds,
|
|
1012
1038
|
}, {
|
|
1013
1039
|
headers: enc.enabled && enc.key ? { "X-Encryption-Key": enc.key } : undefined,
|
|
1014
1040
|
});
|
|
@@ -1205,6 +1231,10 @@ class EchoMemMCPServer {
|
|
|
1205
1231
|
return await this.handleJoinGroup(request.params.arguments);
|
|
1206
1232
|
case canonicalToolNames.prepareGroupPublication:
|
|
1207
1233
|
return await this.handlePrepareGroupPublication(request.params.arguments);
|
|
1234
|
+
case canonicalToolNames.flagPublicationAttention:
|
|
1235
|
+
return await this.handleFlagPublicationAttention(request.params.arguments);
|
|
1236
|
+
case canonicalToolNames.updateGroupProfile:
|
|
1237
|
+
return await this.handleUpdateGroupProfile(request.params.arguments);
|
|
1208
1238
|
case canonicalToolNames.completeGroupPublication:
|
|
1209
1239
|
return await this.handleCompleteGroupPublication(request.params.arguments);
|
|
1210
1240
|
case canonicalToolNames.publishToGroup:
|
|
@@ -1627,6 +1657,7 @@ Details: ${m.details || "N/A"}`)
|
|
|
1627
1657
|
? m.similarity_score
|
|
1628
1658
|
: undefined;
|
|
1629
1659
|
return `[${idx + 1}] Memory ID: ${m.id || "unknown"}
|
|
1660
|
+
Open memory: ${memoryWebUrl(String(m.id || "unknown"))}
|
|
1630
1661
|
User ID: ${m.user_id || "unknown"}
|
|
1631
1662
|
User Name: ${m.username || m.user_name || m.name || "Anonymous"}
|
|
1632
1663
|
Time: ${m.time} | Location: ${m.location}
|
|
@@ -1752,6 +1783,7 @@ Details: ${m.details || "N/A"}`;
|
|
|
1752
1783
|
}
|
|
1753
1784
|
const text = [
|
|
1754
1785
|
`Memory ID: ${memory.id || parsed.memoryId}`,
|
|
1786
|
+
`Open memory: ${memoryWebUrl(String(memory.id || parsed.memoryId))}`,
|
|
1755
1787
|
`Owner User ID: ${memory.owner_user_id || memory.user_id || "Unknown"}`,
|
|
1756
1788
|
memory.time ? `Time: ${memory.time}` : "",
|
|
1757
1789
|
memory.location ? `Location: ${memory.location}` : "",
|
|
@@ -1776,6 +1808,9 @@ Details: ${m.details || "N/A"}`;
|
|
|
1776
1808
|
const participants = Array.isArray(payload?.participants)
|
|
1777
1809
|
? payload.participants.filter(isRecord)
|
|
1778
1810
|
: [];
|
|
1811
|
+
const currentParticipant = isRecord(payload?.currentParticipant)
|
|
1812
|
+
? payload.currentParticipant
|
|
1813
|
+
: null;
|
|
1779
1814
|
const coverage = isRecord(payload?.coverage) ? payload.coverage : {};
|
|
1780
1815
|
if (!group) {
|
|
1781
1816
|
return {
|
|
@@ -1803,6 +1838,10 @@ Details: ${m.details || "N/A"}`;
|
|
|
1803
1838
|
participantText,
|
|
1804
1839
|
"",
|
|
1805
1840
|
"Declared titles and responsibilities are directory facts. Use search_others_memories for current work evidence, and label suggested contribution areas as inference that should be confirmed with the team.",
|
|
1841
|
+
currentParticipant
|
|
1842
|
+
&& (!readString(currentParticipant, "title") || !readString(currentParticipant, "responsibilitySummary"))
|
|
1843
|
+
? "Your group profile is incomplete. Use prepare_group_publication to review your memory evidence, propose the missing fields, and save them only after confirmation with update_group_profile."
|
|
1844
|
+
: "",
|
|
1806
1845
|
].filter(Boolean).join("\n");
|
|
1807
1846
|
return { content: [{ type: "text", text }] };
|
|
1808
1847
|
}
|
|
@@ -1854,8 +1893,8 @@ Details: ${m.details || "N/A"}`;
|
|
|
1854
1893
|
content: [{
|
|
1855
1894
|
type: "text",
|
|
1856
1895
|
text: payload?.alreadyMember
|
|
1857
|
-
? `You are already a member of ${payload?.group?.name ?? "this group"}. No memories were published.`
|
|
1858
|
-
: `Joined ${payload?.group?.name ?? "the company group"}. No memories were published.
|
|
1896
|
+
? `You are already a member of ${payload?.group?.name ?? "this group"}. No memories were published. Use prepare_group_publication to review memories and propose any missing title or responsibility fields.`
|
|
1897
|
+
: `Joined ${payload?.group?.name ?? "the company group"}. No memories were published. Next use prepare_group_publication to review candidates, infer a proposed title and responsibility summary, and ask the user to confirm that profile together with the publication preview.`,
|
|
1859
1898
|
}],
|
|
1860
1899
|
};
|
|
1861
1900
|
}
|
|
@@ -1863,15 +1902,29 @@ Details: ${m.details || "N/A"}`;
|
|
|
1863
1902
|
const parsed = prepareGroupPublicationSchema.parse(args ?? {});
|
|
1864
1903
|
const payload = await this.client.prepareGroupPublication(parsed);
|
|
1865
1904
|
const candidates = Array.isArray(payload?.candidates) ? payload.candidates : [];
|
|
1866
|
-
const
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1905
|
+
const participantProfile = isRecord(payload?.participantProfile)
|
|
1906
|
+
? payload.participantProfile
|
|
1907
|
+
: {};
|
|
1908
|
+
const formatted = candidates.map((candidate, index) => {
|
|
1909
|
+
const attention = isRecord(candidate.publicationAttention)
|
|
1910
|
+
? candidate.publicationAttention
|
|
1911
|
+
: null;
|
|
1912
|
+
return [
|
|
1913
|
+
`[${index + 1}] Memory ID: ${readString(candidate, "memoryId") ?? "unknown"}`,
|
|
1914
|
+
`Open memory: ${memoryWebUrl(readString(candidate, "memoryId") ?? "unknown")}`,
|
|
1915
|
+
`Created: ${readString(candidate, "createdAt") ?? "unknown"}`,
|
|
1916
|
+
`Category: ${readString(candidate, "category") ?? "unknown"}`,
|
|
1917
|
+
`Description: ${readString(candidate, "description") ?? ""}`,
|
|
1918
|
+
readString(candidate, "details") ? `Details: ${readString(candidate, "details")}` : "",
|
|
1919
|
+
`Already published: ${candidate.alreadyPublished === true ? "yes" : "no"}`,
|
|
1920
|
+
`Exact content duplicate: ${candidate.exactContentDuplicate === true ? "yes" : "no"}`,
|
|
1921
|
+
attention ? `PUBLICATION ATTENTION: ${readString(attention, "label") ?? "flagged"}` : "",
|
|
1922
|
+
].filter(Boolean).join("\n");
|
|
1923
|
+
}).join("\n\n");
|
|
1924
|
+
const flaggedIds = candidates
|
|
1925
|
+
.filter((candidate) => isRecord(candidate.publicationAttention))
|
|
1926
|
+
.map((candidate) => readString(candidate, "memoryId"))
|
|
1927
|
+
.filter(Boolean);
|
|
1875
1928
|
return {
|
|
1876
1929
|
content: [{
|
|
1877
1930
|
type: "text",
|
|
@@ -1879,10 +1932,53 @@ Details: ${m.details || "N/A"}`;
|
|
|
1879
1932
|
`Prepared publication scan ${payload?.scanId} for ${payload?.group?.name ?? "your group"}.`,
|
|
1880
1933
|
`Window: ${payload?.windowStart ?? "context start"} → ${payload?.windowEnd}`,
|
|
1881
1934
|
`Candidates: ${candidates.length}. Nothing has been published.`,
|
|
1935
|
+
`Current title: ${readString(participantProfile, "title") ?? "Not declared"}`,
|
|
1936
|
+
`Current declared responsibility: ${readString(participantProfile, "responsibilitySummary") ?? "Not provided"}`,
|
|
1882
1937
|
"",
|
|
1883
1938
|
formatted,
|
|
1884
1939
|
"",
|
|
1885
|
-
|
|
1940
|
+
flaggedIds.length
|
|
1941
|
+
? `Extra attention required: ${flaggedIds.length} candidate(s) are flagged (${flaggedIds.join(", ")}). Show them in a separate warning and require a separate explicit acknowledgement before including their exact IDs in acknowledgedFlaggedMemoryIds.`
|
|
1942
|
+
: "",
|
|
1943
|
+
"Select exact memory IDs matching the user's instruction. From memory evidence, draft a concise title and responsibility summary. Show the profile proposal and memory preview together, then ask for explicit confirmation. After confirmation, call update_group_profile and complete_group_publication.",
|
|
1944
|
+
].join("\n"),
|
|
1945
|
+
}],
|
|
1946
|
+
};
|
|
1947
|
+
}
|
|
1948
|
+
async handleFlagPublicationAttention(args) {
|
|
1949
|
+
const parsed = flagPublicationAttentionSchema.parse(args ?? {});
|
|
1950
|
+
const payload = await this.client.flagMemoriesForPublicationAttention(parsed);
|
|
1951
|
+
const alreadyPublished = typeof payload?.alreadyPublishedGroupCount === "number"
|
|
1952
|
+
? payload.alreadyPublishedGroupCount
|
|
1953
|
+
: 0;
|
|
1954
|
+
return {
|
|
1955
|
+
content: [{
|
|
1956
|
+
type: "text",
|
|
1957
|
+
text: [
|
|
1958
|
+
`Flagged ${payload?.flaggedCount ?? parsed.memoryIds.length} memories for publication attention.`,
|
|
1959
|
+
`Label: ${parsed.label}`,
|
|
1960
|
+
`Memory IDs: ${parsed.memoryIds.join(", ")}`,
|
|
1961
|
+
"No memory was published, decrypted, or made globally public.",
|
|
1962
|
+
alreadyPublished > 0
|
|
1963
|
+
? `Attention: ${alreadyPublished} flagged memories already have group snapshots. This flag does not retract those existing snapshots.`
|
|
1964
|
+
: "",
|
|
1965
|
+
].filter(Boolean).join("\n"),
|
|
1966
|
+
}],
|
|
1967
|
+
};
|
|
1968
|
+
}
|
|
1969
|
+
async handleUpdateGroupProfile(args) {
|
|
1970
|
+
const parsed = updateGroupProfileSchema.parse(args ?? {});
|
|
1971
|
+
const payload = await this.client.updateGroupProfile(parsed);
|
|
1972
|
+
const participant = isRecord(payload?.participant) ? payload.participant : {};
|
|
1973
|
+
return {
|
|
1974
|
+
content: [{
|
|
1975
|
+
type: "text",
|
|
1976
|
+
text: [
|
|
1977
|
+
"Confirmed company-group profile updated.",
|
|
1978
|
+
`Display name: ${readString(participant, "displayName") ?? parsed.displayName ?? "unchanged"}`,
|
|
1979
|
+
`Title: ${readString(participant, "title") ?? parsed.title}`,
|
|
1980
|
+
`Declared responsibility: ${readString(participant, "responsibilitySummary") ?? parsed.responsibilitySummary}`,
|
|
1981
|
+
"These fields are now declared directory facts visible to group members.",
|
|
1886
1982
|
].join("\n"),
|
|
1887
1983
|
}],
|
|
1888
1984
|
};
|
package/dist/package-metadata.js
CHANGED
|
@@ -28,8 +28,11 @@ export const MCP_SERVER_INSTRUCTIONS = [
|
|
|
28
28
|
`If the user or local config expects a newer EchoMem MCP version than ${MCP_PACKAGE_VERSION}, update once with \`${MCP_UPDATE_ALL_COMMAND}\` and start a new MCP session.`,
|
|
29
29
|
"Use echomem_update_status to check whether npm has a newer bridge; it is cached and non-blocking during normal tool listing.",
|
|
30
30
|
"Do not auto-update on every MCP startup; this bridge is intentionally stable between explicit updates.",
|
|
31
|
-
"For company-group sharing, use get_group_context for orientation; create_memory_group/create_group_invite/join_memory_group for membership; and prepare_group_publication as a no-
|
|
32
|
-
"
|
|
31
|
+
"For company-group sharing, use get_group_context for orientation; create_memory_group/create_group_invite/join_memory_group for membership; and prepare_group_publication as a no-publication preview.",
|
|
32
|
+
"After joining or when profile fields are missing, use candidate memory evidence to propose a title and responsibility summary. Ask the user to confirm that proposal together with the publication preview, then call update_group_profile and complete_group_publication.",
|
|
33
|
+
"Each group-search result is one memory: preserve its Memory ID and direct echoknows.com link when citing it.",
|
|
34
|
+
"For sensitive-topic flags, search and preview exact owned memories before confirmed flag_memories_for_publication_attention. During publication, separate flagged candidates and require exact-ID acknowledgement.",
|
|
35
|
+
"Never save an inferred group profile or complete a group publication without explicit confirmation, and never store or log an echo_grp_ invite code.",
|
|
33
36
|
].join(" ");
|
|
34
37
|
export function withMcpVersion(description) {
|
|
35
38
|
return `${description}\n\nEchoMem MCP bridge: ${MCP_PACKAGE_LABEL}. If this version is stale, update once with \`${MCP_UPDATE_ALL_COMMAND}\` (or add \`--client cursor|windsurf|claude-desktop|claude-code|codex\` for a single client), then start a new MCP session. Do not run updates repeatedly or on every startup.`;
|
|
@@ -900,7 +900,7 @@ export const SETUP_PAGE_CLIENT_EXTRACTION = String.raw ` /* ---------- dash
|
|
|
900
900
|
var paidPlan = plan === "power" ? "power" : "pro";
|
|
901
901
|
return (billingStatus && billingStatus.pricingUrl)
|
|
902
902
|
? billingStatus.pricingUrl + (startTrial ? "&start=" + paidPlan + "&trial=" + (billingStatus.trialAvailable === false ? "0" : "1") : "")
|
|
903
|
-
: "https://echoknows.com/
|
|
903
|
+
: "https://echoknows.com/account?source=mcp_onboarding" + (startTrial ? "&start=" + paidPlan + "&trial=1" : "");
|
|
904
904
|
}
|
|
905
905
|
function setupPlanConfirmed() {
|
|
906
906
|
return setupPlanChoice === "free" || paidRecallPlan(billingStatus && billingStatus.plan);
|
package/dist/setup-preview.js
CHANGED
|
@@ -234,7 +234,7 @@ function extractionPreviewBootstrap(options) {
|
|
|
234
234
|
trialUsed: options.trialUsed,
|
|
235
235
|
subscriptionStatus: options.subscriptionStatus ?? null,
|
|
236
236
|
trialEndedAt: options.trialEndedAt ?? null,
|
|
237
|
-
pricingUrl: "https://echoknows.com/
|
|
237
|
+
pricingUrl: "https://echoknows.com/account?source=mcp_onboarding",
|
|
238
238
|
account: {
|
|
239
239
|
displayName: "Preview User",
|
|
240
240
|
email: "preview@example.com",
|
package/dist/setup.js
CHANGED
|
@@ -37,7 +37,7 @@ import { checkLatestUpdateStatus, compareSemver, readCachedUpdateStatus } from "
|
|
|
37
37
|
// The setup dashboard, account login, and encryption passphrase entry are all served by this
|
|
38
38
|
// localhost bridge. The hosted API only sends OTP email, verifies the code, and mints a device token.
|
|
39
39
|
const API_BASE_URL = (process.env.ECHO_API_BASE_URL || "https://echo-mem-chrome.vercel.app").replace(/\/$/, "");
|
|
40
|
-
const PRICING_URL = (process.env.ECHO_PRICING_URL || "https://echoknows.com/
|
|
40
|
+
const PRICING_URL = (process.env.ECHO_PRICING_URL || "https://echoknows.com/account").replace(/\/$/, "");
|
|
41
41
|
function hostedBillingEndpoint(pathname) {
|
|
42
42
|
const url = new URL(PRICING_URL);
|
|
43
43
|
url.pathname = pathname;
|
|
@@ -396,10 +396,13 @@ function echomemGuidanceBlock() {
|
|
|
396
396
|
"- Use `get_group_context` when the user asks who is in their company group, what teammates are responsible for, or what work is already covered. Treat declared participant fields as facts and published-memory conclusions as evidence or inference.",
|
|
397
397
|
"- A group publication is separate from a globally public memory: publishing to a group creates a group-scoped snapshot and must not change the encrypted original or its global `is_public` setting.",
|
|
398
398
|
"- If a user asks to create a group, call `create_memory_group`; if they ask for a code to share, call `create_group_invite` and return the secret invite code only to that user. Never save the invite code to memory or include it in logs, analytics, summaries, or unrelated output.",
|
|
399
|
-
"- If a user supplies an `echo_grp_...` code and explicitly asks to join, call `join_memory_group`. Joining never authorizes publishing by itself and must not move a user out of another group.",
|
|
400
|
-
"- For requests such as “prepare my recent work memories,” “upload work from this ticket,” or “publish work since my last sync,” call `prepare_group_publication` first. This is a no-
|
|
401
|
-
"- After preparing, select only exact candidate memory IDs that match the user's stated scope
|
|
402
|
-
"-
|
|
399
|
+
"- If a user supplies an `echo_grp_...` code and explicitly asks to join, call `join_memory_group`. Joining never authorizes publishing by itself and must not move a user out of another group. After joining, continue into the profile-and-publication preview instead of leaving title or responsibility blank.",
|
|
400
|
+
"- For requests such as “prepare my recent work memories,” “upload work from this ticket,” or “publish work since my last sync,” call `prepare_group_publication` first. This is a no-publication preview. For encrypted accounts, tell the user to run `echomem-mcp unlock` locally if the tool reports that the key is required.",
|
|
401
|
+
"- After preparing, select only exact candidate memory IDs that match the user's stated scope and exclude already-published or exact-content duplicates. Use the candidate evidence to draft a concise title and responsibility summary for the current member, but label both as proposals rather than facts.",
|
|
402
|
+
"- Each returned group-search result is one memory. When citing it in a bullet, preserve its Memory ID and include its `https://echoknows.com/company/memories?memoryId=...` link so the user can open the evidence directly.",
|
|
403
|
+
"- If the user asks to flag memories about a sensitive topic, search their own memories first, show the exact matches, and ask them to confirm. Only then call `flag_memories_for_publication_attention`; flagging does not publish, decrypt, change visibility, or retract an existing group snapshot.",
|
|
404
|
+
"- Present the proposed title/responsibility and the memory publication preview together and ask for explicit confirmation. Never save an inferred profile or publish memories before confirmation. Show flagged candidates in a separate warning.",
|
|
405
|
+
"- On confirmation, call `update_group_profile` with the confirmed title, responsibility summary, and `confirmed: true`, then call `complete_group_publication` with the exact `scanId`, selected memory IDs, and `confirmed: true`. If a flagged memory is selected, require separate explicit acknowledgement and pass its exact ID in `acknowledgedFlaggedMemoryIds`. If the user edits either proposal, use their wording. An explicit request to join and upload still requires this preview and confirmation.",
|
|
403
406
|
"- If the user asks to show, reopen, restart, or bring back the EchoMem HUD (the context-health overlay), run the shell command `echomem-hud app --client auto`.",
|
|
404
407
|
"- If the user wants the HUD to come back after a computer restart, run the shell command `echomem-hud autostart on --client auto`.",
|
|
405
408
|
AGENTS_MD_END,
|
package/dist/v1-contract.js
CHANGED
|
@@ -15,6 +15,8 @@ export const canonicalToolNames = {
|
|
|
15
15
|
createGroupInvite: "create_group_invite",
|
|
16
16
|
joinGroup: "join_memory_group",
|
|
17
17
|
prepareGroupPublication: "prepare_group_publication",
|
|
18
|
+
flagPublicationAttention: "flag_memories_for_publication_attention",
|
|
19
|
+
updateGroupProfile: "update_group_profile",
|
|
18
20
|
completeGroupPublication: "complete_group_publication",
|
|
19
21
|
publishToGroup: "publish_memory_to_group",
|
|
20
22
|
publishBatchToGroup: "publish_memories_to_group",
|
|
@@ -143,22 +145,38 @@ export const prepareGroupPublicationSchema = z.object({
|
|
|
143
145
|
limit: z.number().int().min(1).max(50).optional(),
|
|
144
146
|
instruction: z.string().max(500).optional(),
|
|
145
147
|
});
|
|
148
|
+
export const flagPublicationAttentionSchema = z.object({
|
|
149
|
+
...triggerMetadataSchema,
|
|
150
|
+
memoryIds: z.array(z.string().min(1)).min(1).max(50),
|
|
151
|
+
label: z.string().min(1).max(120),
|
|
152
|
+
confirmed: z.literal(true),
|
|
153
|
+
});
|
|
154
|
+
export const updateGroupProfileSchema = z.object({
|
|
155
|
+
...triggerMetadataSchema,
|
|
156
|
+
displayName: z.string().min(1).max(120).optional(),
|
|
157
|
+
title: z.string().min(1).max(160),
|
|
158
|
+
responsibilitySummary: z.string().min(1).max(1000),
|
|
159
|
+
confirmed: z.literal(true),
|
|
160
|
+
});
|
|
146
161
|
export const completeGroupPublicationSchema = z.object({
|
|
147
162
|
...triggerMetadataSchema,
|
|
148
163
|
scanId: z.string().min(1),
|
|
149
164
|
memoryIds: z.array(z.string().min(1)).max(50),
|
|
150
165
|
confirmed: z.literal(true),
|
|
151
166
|
selectionReason: z.string().max(500).optional(),
|
|
167
|
+
acknowledgedFlaggedMemoryIds: z.array(z.string().min(1)).max(50).optional(),
|
|
152
168
|
});
|
|
153
169
|
export const publishToGroupSchema = z.object({
|
|
154
170
|
...triggerMetadataSchema,
|
|
155
171
|
memoryId: z.string().min(1),
|
|
172
|
+
acknowledgedFlaggedMemoryIds: z.array(z.string().min(1)).max(1).optional(),
|
|
156
173
|
});
|
|
157
174
|
export const publishBatchToGroupSchema = z.object({
|
|
158
175
|
...triggerMetadataSchema,
|
|
159
176
|
memoryIds: z.array(z.string().min(1)).min(1).max(50),
|
|
160
177
|
contextId: z.string().min(1).optional(),
|
|
161
178
|
selectionReason: z.string().max(500).optional(),
|
|
179
|
+
acknowledgedFlaggedMemoryIds: z.array(z.string().min(1)).max(50).optional(),
|
|
162
180
|
});
|
|
163
181
|
export const deleteMemorySchema = z.object({
|
|
164
182
|
memoryId: z.string().min(1),
|
|
@@ -460,7 +478,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
460
478
|
},
|
|
461
479
|
{
|
|
462
480
|
name: canonicalToolNames.joinGroup,
|
|
463
|
-
description: "Join a company memory group using an invite code after the user explicitly asks to join. Joining never publishes memories
|
|
481
|
+
description: "Join a company memory group using an invite code after the user explicitly asks to join. Joining never publishes memories. Next call prepare_group_publication, infer a proposed title and responsibility summary from the user's own candidate memories, and ask the user to confirm the profile together with the publication preview.",
|
|
464
482
|
inputSchema: {
|
|
465
483
|
type: "object",
|
|
466
484
|
properties: {
|
|
@@ -474,7 +492,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
474
492
|
},
|
|
475
493
|
{
|
|
476
494
|
name: canonicalToolNames.prepareGroupPublication,
|
|
477
|
-
description: "Prepare a no-
|
|
495
|
+
description: "Prepare a no-publication preview of up to 50 owned memories for group publication. For encrypted accounts the local bridge must be unlocked. The host agent selects exact work-related memory ids, drafts a concise title and responsibility summary from memory evidence, and asks the user to confirm both the profile and publication selection together. Flagged memories are identified separately and require extra attention before publication. This tool never publishes.",
|
|
478
496
|
inputSchema: {
|
|
479
497
|
type: "object",
|
|
480
498
|
properties: {
|
|
@@ -488,9 +506,49 @@ export function listToolSpecs(opts = {}) {
|
|
|
488
506
|
},
|
|
489
507
|
},
|
|
490
508
|
},
|
|
509
|
+
{
|
|
510
|
+
name: canonicalToolNames.flagPublicationAttention,
|
|
511
|
+
description: "Mark exact owned memories for extra attention during future group publication. First search the user's own memories, show the matching memory IDs and summaries, and obtain explicit confirmation. This only records a safety flag; it does not publish, decrypt, change visibility, or retract an existing group snapshot.",
|
|
512
|
+
inputSchema: {
|
|
513
|
+
type: "object",
|
|
514
|
+
properties: {
|
|
515
|
+
memoryIds: {
|
|
516
|
+
type: "array",
|
|
517
|
+
minItems: 1,
|
|
518
|
+
maxItems: 50,
|
|
519
|
+
items: { type: "string" },
|
|
520
|
+
description: "Exact owned memory IDs the user reviewed and confirmed.",
|
|
521
|
+
},
|
|
522
|
+
label: {
|
|
523
|
+
type: "string",
|
|
524
|
+
description: "A short user-supplied attention label, such as investment or customer-confidential.",
|
|
525
|
+
},
|
|
526
|
+
confirmed: {
|
|
527
|
+
type: "boolean",
|
|
528
|
+
const: true,
|
|
529
|
+
description: "Set true only after the user confirms the exact memories.",
|
|
530
|
+
},
|
|
531
|
+
},
|
|
532
|
+
required: ["memoryIds", "label", "confirmed"],
|
|
533
|
+
},
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
name: canonicalToolNames.updateGroupProfile,
|
|
537
|
+
description: "Save the current member's declared group title and responsibility summary only after the user explicitly confirms the agent's proposal. These become directory facts visible to group members; never save an unconfirmed inference.",
|
|
538
|
+
inputSchema: {
|
|
539
|
+
type: "object",
|
|
540
|
+
properties: {
|
|
541
|
+
displayName: { type: "string" },
|
|
542
|
+
title: { type: "string" },
|
|
543
|
+
responsibilitySummary: { type: "string" },
|
|
544
|
+
confirmed: { type: "boolean", const: true },
|
|
545
|
+
},
|
|
546
|
+
required: ["title", "responsibilitySummary", "confirmed"],
|
|
547
|
+
},
|
|
548
|
+
},
|
|
491
549
|
{
|
|
492
550
|
name: canonicalToolNames.completeGroupPublication,
|
|
493
|
-
description: "Publish only the exact memory ids from a prepared scan after the user explicitly confirms the preview. confirmed must be true. Completing an empty selection safely advances the scan cursor without publishing.",
|
|
551
|
+
description: "Publish only the exact memory ids from a prepared scan after the user explicitly confirms the preview. confirmed must be true. Any flagged memories must be called out separately and their exact IDs supplied in acknowledgedFlaggedMemoryIds after extra user acknowledgement. Completing an empty selection safely advances the scan cursor without publishing.",
|
|
494
552
|
inputSchema: {
|
|
495
553
|
type: "object",
|
|
496
554
|
properties: {
|
|
@@ -498,13 +556,19 @@ export function listToolSpecs(opts = {}) {
|
|
|
498
556
|
memoryIds: { type: "array", maxItems: 50, items: { type: "string" } },
|
|
499
557
|
confirmed: { type: "boolean", const: true },
|
|
500
558
|
selectionReason: { type: "string" },
|
|
559
|
+
acknowledgedFlaggedMemoryIds: {
|
|
560
|
+
type: "array",
|
|
561
|
+
maxItems: 50,
|
|
562
|
+
items: { type: "string" },
|
|
563
|
+
description: "Exact flagged IDs the user separately acknowledged for this publication.",
|
|
564
|
+
},
|
|
501
565
|
},
|
|
502
566
|
required: ["scanId", "memoryIds", "confirmed"],
|
|
503
567
|
},
|
|
504
568
|
},
|
|
505
569
|
{
|
|
506
570
|
name: canonicalToolNames.publishToGroup,
|
|
507
|
-
description: "Publish one exact memory snapshot to your current company group without changing the memory's global is_public or encryption state. Call only after the user explicitly asks to publish or push that memory. The operation is idempotent.",
|
|
571
|
+
description: "Publish one exact memory snapshot to your current company group without changing the memory's global is_public or encryption state. Call only after the user explicitly asks to publish or push that memory. If it is flagged, call it out and pass its ID in acknowledgedFlaggedMemoryIds only after extra user acknowledgement. The operation is idempotent.",
|
|
508
572
|
inputSchema: {
|
|
509
573
|
type: "object",
|
|
510
574
|
properties: {
|
|
@@ -517,13 +581,19 @@ export function listToolSpecs(opts = {}) {
|
|
|
517
581
|
description: "Optional user message that explicitly requested publication.",
|
|
518
582
|
},
|
|
519
583
|
triggerMessageRole: { type: "string", default: "user" },
|
|
584
|
+
acknowledgedFlaggedMemoryIds: {
|
|
585
|
+
type: "array",
|
|
586
|
+
maxItems: 1,
|
|
587
|
+
items: { type: "string" },
|
|
588
|
+
description: "Include the memory ID only after separate acknowledgement if the memory is flagged.",
|
|
589
|
+
},
|
|
520
590
|
},
|
|
521
591
|
required: ["memoryId"],
|
|
522
592
|
},
|
|
523
593
|
},
|
|
524
594
|
{
|
|
525
595
|
name: canonicalToolNames.publishBatchToGroup,
|
|
526
|
-
description: "Publish up to 50 exact memory snapshots to your current company group without changing global is_public or the encrypted originals. For a session request, first call get_memories_by_context, select the exact ids that match the user's instruction, then pass those ids with the same contextId. Call only after explicit group-publication intent; report what was selected when the user delegates work-related filtering.",
|
|
596
|
+
description: "Publish up to 50 exact memory snapshots to your current company group without changing global is_public or the encrypted originals. For a session request, first call get_memories_by_context, select the exact ids that match the user's instruction, then pass those ids with the same contextId. Call only after explicit group-publication intent; report what was selected when the user delegates work-related filtering. Flagged memories must be called out separately and acknowledged by exact ID.",
|
|
527
597
|
inputSchema: {
|
|
528
598
|
type: "object",
|
|
529
599
|
properties: {
|
|
@@ -547,6 +617,12 @@ export function listToolSpecs(opts = {}) {
|
|
|
547
617
|
description: "Optional user message that explicitly requested publication.",
|
|
548
618
|
},
|
|
549
619
|
triggerMessageRole: { type: "string", default: "user" },
|
|
620
|
+
acknowledgedFlaggedMemoryIds: {
|
|
621
|
+
type: "array",
|
|
622
|
+
maxItems: 50,
|
|
623
|
+
items: { type: "string" },
|
|
624
|
+
description: "Exact flagged IDs the user separately acknowledged for this publication.",
|
|
625
|
+
},
|
|
550
626
|
},
|
|
551
627
|
required: ["memoryIds"],
|
|
552
628
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@echomem/mcp",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.25",
|
|
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",
|