@echomem/echo-memory-cloud-openclaw-plugin 0.1.0 → 0.1.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/clawdbot.plugin.json +1 -1
- package/index.js +254 -216
- package/lib/api-client.js +125 -44
- package/lib/local-server.js +537 -381
- package/lib/local-ui/src/App.jsx +133 -25
- package/lib/local-ui/src/canvas/Viewport.jsx +10 -8
- package/lib/local-ui/src/cards/Card.css +13 -0
- package/lib/local-ui/src/cards/Card.jsx +10 -1
- package/lib/local-ui/src/styles/global.css +8 -0
- package/lib/local-ui/src/sync/api.js +16 -14
- package/lib/sync.js +507 -215
- package/moltbot.plugin.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/clawdbot.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "echo-memory-cloud-openclaw-plugin",
|
|
3
3
|
"name": "Echo Memory Cloud OpenClaw Plugin",
|
|
4
4
|
"description": "Sync OpenClaw local markdown memory files to Echo cloud",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.2",
|
|
6
6
|
"kind": "lifecycle",
|
|
7
7
|
"main": "./index.js",
|
|
8
8
|
"configSchema": {
|
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { buildConfig, getEnvFileStatus } from "./lib/config.js";
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { buildConfig, getEnvFileStatus } from "./lib/config.js";
|
|
4
4
|
import { createApiClient } from "./lib/api-client.js";
|
|
5
5
|
import { formatSearchResultsText } from "./lib/echo-memory-search.js";
|
|
6
6
|
import {
|
|
@@ -46,13 +46,22 @@ export default {
|
|
|
46
46
|
register(api) {
|
|
47
47
|
const cfg = buildConfig(api.pluginConfig);
|
|
48
48
|
const client = createApiClient(cfg);
|
|
49
|
+
const workspaceDir = path.resolve(path.dirname(cfg.memoryDir), "..");
|
|
50
|
+
const openclawHome = path.resolve(workspaceDir, "..");
|
|
51
|
+
const fallbackStateDir = path.join(openclawHome, "state", "plugins", "echo-memory-cloud-openclaw-plugin");
|
|
49
52
|
const syncRunner = createSyncRunner({
|
|
50
53
|
api,
|
|
51
54
|
cfg,
|
|
52
55
|
client,
|
|
56
|
+
fallbackStateDir,
|
|
53
57
|
});
|
|
54
|
-
const workspaceDir = path.resolve(path.dirname(cfg.memoryDir), "..");
|
|
55
58
|
let startupBrowserOpenAttempted = false;
|
|
59
|
+
let backgroundStarted = false;
|
|
60
|
+
let serviceStartObserved = false;
|
|
61
|
+
|
|
62
|
+
if (!workspaceDir || workspaceDir === "." || workspaceDir === path.sep) {
|
|
63
|
+
api.logger?.warn?.("[echo-memory] workspace resolution looks unusual; compatibility fallback may be limited");
|
|
64
|
+
}
|
|
56
65
|
|
|
57
66
|
async function ensureLocalUi({ openInBrowser = false, trigger = "manual" } = {}) {
|
|
58
67
|
const url = await startLocalServer(workspaceDir, {
|
|
@@ -77,223 +86,252 @@ export default {
|
|
|
77
86
|
return { url, openedInBrowser, openReason };
|
|
78
87
|
}
|
|
79
88
|
|
|
80
|
-
api.registerTool
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
89
|
+
if (typeof api.registerTool === "function") {
|
|
90
|
+
api.registerTool(createEchoMemorySearchTool(client));
|
|
91
|
+
api.registerTool(createEchoMemoryOnboardTool(cfg, resolveCommandLabel("slack")));
|
|
92
|
+
api.registerTool(createEchoMemoryGraphTool(client, cfg));
|
|
93
|
+
api.registerTool(createEchoMemoryLocalUiTool({
|
|
94
|
+
getLocalUiUrl: ensureLocalUi,
|
|
95
|
+
commandLabel: resolveCommandLabel("slack"),
|
|
96
|
+
}));
|
|
97
|
+
api.registerTool(createEchoMemoryStatusTool(client, syncRunner));
|
|
98
|
+
api.registerTool(createEchoMemorySyncTool(client, syncRunner));
|
|
99
|
+
}
|
|
100
|
+
if (typeof api.on === "function") {
|
|
101
|
+
api.on("before_prompt_build", (_event, _ctx) => {
|
|
102
|
+
return {
|
|
103
|
+
appendSystemContext: [
|
|
104
|
+
"EchoMem cloud retrieval is available through the `echo_memory_search` tool.",
|
|
105
|
+
"Echo Memory setup and usage guidance is available through the `echo_memory_onboard` tool.",
|
|
106
|
+
"Echo memory graph links are available through the `echo_memory_graph_link` tool.",
|
|
107
|
+
"Echo memory local workspace UI links are available through the `echo_memory_local_ui` tool.",
|
|
108
|
+
"Echo sync inspection is available through the `echo_memory_status` tool.",
|
|
109
|
+
"Echo markdown-to-cloud sync is available through the `echo_memory_sync` tool.",
|
|
110
|
+
"Use it when the conversation asks about prior facts, plans, decisions, dates, preferences, people, or when memory context would improve accuracy.",
|
|
111
|
+
"Prefer it before answering memory-dependent questions instead of guessing.",
|
|
112
|
+
"Use `echo_memory_onboard` when the user asks how to install, set up, configure, authenticate, or use the plugin, or asks about signup, API keys, commands, graph access, or troubleshooting.",
|
|
113
|
+
"Treat any question about becoming a new EchoMemory user, signing up, creating an account, receiving OTP, referral code, API key creation, or configuring the plugin as an onboarding question for `echo_memory_onboard`.",
|
|
114
|
+
"Do not answer Echo Memory signup, account setup, or plugin setup from generic prior knowledge. Call `echo_memory_onboard` so the OpenClaw-specific signup URL, OTP step, referral code, API key flow, command names, and config details stay exact.",
|
|
115
|
+
"There is only one onboarding path. Do not try to choose between signup/setup onboarding variants; call `echo_memory_onboard` and return the full authoritative guide.",
|
|
116
|
+
"Use `echo_memory_graph_link` when the user explicitly asks for the memory graph, cloud graph, graph view, public memories page, or an iditor.com page.",
|
|
117
|
+
"Use `echo_memory_local_ui` when the user asks to open, view, browse, launch, or get the URL for local memories, markdown files, the workspace viewer, the local UI, or the localhost view.",
|
|
118
|
+
"Treat `/echo-memory view` as the local localhost markdown viewer command.",
|
|
119
|
+
"Do not confuse the localhost local workspace UI with the cloud memory graph. The local UI shows local markdown files directly, while graph links open iditor.com pages.",
|
|
120
|
+
"If the user says 'view my memories' or similar without saying graph/iditor/public, prefer the local workspace UI.",
|
|
121
|
+
"If the user asks to open the local workspace UI, request `openInBrowser: true` and include the returned localhost URL directly in the reply.",
|
|
122
|
+
"Use `visibility: private` for the user's personal memory graph login page and `visibility: public` for the shared public memories page at iditor.com/memories.",
|
|
123
|
+
"Private graph access from OpenClaw intentionally requires a fresh login at iditor.com/login?next=/memory-graph instead of an auto-login bridge link.",
|
|
124
|
+
"When providing a graph link, include the returned URL directly in the Slack reply.",
|
|
125
|
+
"Use `echo_memory_status` when the user asks about sync health, import progress, last sync, recent imports, or whether Echo memory is working.",
|
|
126
|
+
"Use `echo_memory_sync` when the user explicitly asks to sync, refresh, import, upload, or push local markdown memories into Echo cloud.",
|
|
127
|
+
"If the user reports permission, privacy, authorization, or tool-access restrictions while using Echo Memory in OpenClaw, tell them to set `tools.profile` to `full` in `~/.openclaw/openclaw.json` and restart the gateway.",
|
|
128
|
+
].join("\n"),
|
|
129
|
+
};
|
|
130
|
+
});
|
|
131
|
+
}
|
|
119
132
|
|
|
120
133
|
const envStatus = getEnvFileStatus();
|
|
121
|
-
if (!envStatus.found) {
|
|
122
|
-
api.logger?.warn?.(
|
|
123
|
-
`[echo-memory] No .env file found in ${envStatus.searchPaths.join(", ")}. Using plugin config or process env.`,
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
api.registerService({
|
|
128
|
-
id: "echo-memory-cloud-openclaw-sync",
|
|
129
|
-
start: async (ctx) => {
|
|
130
|
-
await syncRunner.initialize(ctx.stateDir);
|
|
134
|
+
if (!envStatus.found) {
|
|
135
|
+
api.logger?.warn?.(
|
|
136
|
+
`[echo-memory] No .env file found in ${envStatus.searchPaths.join(", ")}. Using plugin config or process env.`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
131
139
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
140
|
+
async function startBackgroundFeatures({ stateDir = null, trigger = "service" } = {}) {
|
|
141
|
+
if (backgroundStarted) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
backgroundStarted = true;
|
|
145
|
+
await syncRunner.initialize(stateDir || fallbackStateDir);
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const shouldOpenBrowser = cfg.localUiAutoOpenOnGatewayStart && !startupBrowserOpenAttempted;
|
|
149
|
+
const { url, openedInBrowser, openReason } = await ensureLocalUi({
|
|
150
|
+
openInBrowser: shouldOpenBrowser,
|
|
151
|
+
trigger: trigger === "service" ? "gateway-start" : trigger,
|
|
152
|
+
});
|
|
153
|
+
api.logger?.info?.(`[echo-memory] Local workspace viewer: ${url}`);
|
|
154
|
+
if (shouldOpenBrowser) {
|
|
155
|
+
startupBrowserOpenAttempted = true;
|
|
156
|
+
if (openedInBrowser) {
|
|
157
|
+
api.logger?.info?.("[echo-memory] Opened local workspace viewer in the default browser");
|
|
158
|
+
} else {
|
|
159
|
+
api.logger?.info?.(`[echo-memory] Skipped browser auto-open (${openReason})`);
|
|
146
160
|
}
|
|
147
|
-
} catch (error) {
|
|
148
|
-
api.logger?.warn?.(`[echo-memory] local server failed: ${String(error?.message ?? error)}`);
|
|
149
161
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
162
|
+
} catch (error) {
|
|
163
|
+
api.logger?.warn?.(`[echo-memory] local server failed: ${String(error?.message ?? error)}`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (!cfg.autoSync) {
|
|
167
|
+
api.logger?.info?.("[echo-memory] autoSync disabled");
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
await syncRunner.runSync(trigger === "service" ? "startup" : trigger).catch((error) => {
|
|
172
|
+
api.logger?.warn?.(`[echo-memory] startup sync failed: ${String(error?.message ?? error)}`);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
syncRunner.startInterval();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (typeof api.registerService === "function") {
|
|
179
|
+
api.registerService({
|
|
180
|
+
id: "echo-memory-cloud-openclaw-sync",
|
|
181
|
+
start: async (ctx) => {
|
|
182
|
+
serviceStartObserved = true;
|
|
183
|
+
await startBackgroundFeatures({ stateDir: ctx?.stateDir || null, trigger: "service" });
|
|
184
|
+
},
|
|
185
|
+
stop: async () => {
|
|
186
|
+
syncRunner.stopInterval();
|
|
187
|
+
stopLocalServer();
|
|
188
|
+
backgroundStarted = false;
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Compatibility fallback for older hosts that discover the plugin but do not
|
|
194
|
+
// reliably auto-start registered background services.
|
|
195
|
+
queueMicrotask(() => {
|
|
196
|
+
if (serviceStartObserved) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
startBackgroundFeatures({ stateDir: fallbackStateDir, trigger: "compat-startup" }).catch((error) => {
|
|
200
|
+
api.logger?.warn?.(`[echo-memory] compatibility startup failed: ${String(error?.message ?? error)}`);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
if (typeof api.registerCommand === "function") {
|
|
205
|
+
api.registerCommand({
|
|
206
|
+
name: "echo-memory",
|
|
207
|
+
description: "Sync and search OpenClaw markdown memories through Echo cloud.",
|
|
208
|
+
acceptsArgs: true,
|
|
209
|
+
handler: async (ctx) => {
|
|
210
|
+
const { action, actionArgs } = parseCommandArgs(ctx.args);
|
|
211
|
+
const commandLabel = resolveCommandLabel(ctx.channel);
|
|
212
|
+
|
|
213
|
+
if (action === "view") {
|
|
214
|
+
const { url, openedInBrowser } = await ensureLocalUi({
|
|
215
|
+
openInBrowser: true,
|
|
216
|
+
trigger: "command",
|
|
217
|
+
});
|
|
218
|
+
return {
|
|
219
|
+
text: [
|
|
220
|
+
`Open your workspace: ${url}`,
|
|
221
|
+
openedInBrowser
|
|
222
|
+
? "The default browser was opened on this machine."
|
|
223
|
+
: "Open the URL manually if the browser did not launch automatically.",
|
|
224
|
+
"",
|
|
225
|
+
"This local UI reads your markdown files directly on localhost. All files stay local until you choose to sync.",
|
|
226
|
+
`For EchoMemory account signup or plugin onboarding, run ${commandLabel} onboard.`,
|
|
227
|
+
].join("\n"),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (action === "help") {
|
|
232
|
+
return {
|
|
233
|
+
text: [
|
|
234
|
+
"Echo Memory commands:",
|
|
235
|
+
"",
|
|
236
|
+
`${commandLabel} onboard`,
|
|
237
|
+
`${commandLabel} view`,
|
|
238
|
+
`${commandLabel} status`,
|
|
239
|
+
`${commandLabel} search <query>`,
|
|
240
|
+
`${commandLabel} graph`,
|
|
241
|
+
`${commandLabel} graph public`,
|
|
242
|
+
`${commandLabel} sync`,
|
|
243
|
+
`${commandLabel} whoami`,
|
|
244
|
+
`${commandLabel} help`,
|
|
245
|
+
].join("\n"),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (action === "whoami") {
|
|
250
|
+
const whoami = await client.whoami();
|
|
251
|
+
return {
|
|
252
|
+
text: [
|
|
253
|
+
"Echo identity:",
|
|
254
|
+
`- user_id: ${whoami.user_id}`,
|
|
255
|
+
`- token_type: ${whoami.token_type}`,
|
|
256
|
+
`- scopes: ${Array.isArray(whoami.scopes) ? whoami.scopes.join(", ") : "(none)"}`,
|
|
257
|
+
].join("\n"),
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (action === "onboard") {
|
|
262
|
+
const guide = buildOnboardingText({
|
|
263
|
+
commandLabel,
|
|
264
|
+
cfg,
|
|
265
|
+
});
|
|
266
|
+
return { text: guide.text };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (action === "sync") {
|
|
270
|
+
const result = await syncRunner.runSync("manual");
|
|
271
|
+
return { text: formatStatusText(result) };
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (action === "search") {
|
|
275
|
+
if (!actionArgs) {
|
|
276
|
+
return {
|
|
277
|
+
text: [
|
|
278
|
+
"Missing search query.",
|
|
279
|
+
`Usage: ${commandLabel} search <query>`,
|
|
280
|
+
].join("\n"),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const payload = await client.searchMemories({
|
|
285
|
+
query: actionArgs,
|
|
286
|
+
similarityThreshold: 0.3,
|
|
287
|
+
});
|
|
288
|
+
return {
|
|
289
|
+
text: formatSearchResultsText(actionArgs, payload),
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (action === "graph") {
|
|
294
|
+
const graphMode = String(actionArgs || "").trim().toLowerCase();
|
|
295
|
+
|
|
296
|
+
if (!graphMode || graphMode === "private") {
|
|
297
|
+
const url = buildPrivateGraphLoginUrl(cfg);
|
|
298
|
+
return {
|
|
299
|
+
text: [
|
|
300
|
+
"Log in again to open your private memory graph:",
|
|
301
|
+
url,
|
|
302
|
+
"This intentionally requires a fresh web login for security.",
|
|
303
|
+
].filter(Boolean).join("\n"),
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (graphMode === "public") {
|
|
308
|
+
return {
|
|
309
|
+
text: [
|
|
310
|
+
"Open the public memory page:",
|
|
311
|
+
`${cfg.webBaseUrl}/memories`,
|
|
312
|
+
].join("\n"),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
text: [
|
|
318
|
+
"Unknown graph mode.",
|
|
319
|
+
`Usage: ${commandLabel} graph`,
|
|
320
|
+
`Usage: ${commandLabel} graph public`,
|
|
321
|
+
].join("\n"),
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const [localState, remoteStatus] = await Promise.all([
|
|
326
|
+
readLastSyncState(syncRunner.getStatePath()),
|
|
327
|
+
client.getImportStatus().catch(() => null),
|
|
328
|
+
]);
|
|
175
329
|
|
|
176
|
-
if (action === "view") {
|
|
177
|
-
const { url, openedInBrowser } = await ensureLocalUi({
|
|
178
|
-
openInBrowser: true,
|
|
179
|
-
trigger: "command",
|
|
180
|
-
});
|
|
181
330
|
return {
|
|
182
|
-
text:
|
|
183
|
-
`Open your workspace: ${url}`,
|
|
184
|
-
openedInBrowser
|
|
185
|
-
? "The default browser was opened on this machine."
|
|
186
|
-
: "Open the URL manually if the browser did not launch automatically.",
|
|
187
|
-
"",
|
|
188
|
-
"This local UI reads your markdown files directly on localhost. All files stay local until you choose to sync.",
|
|
189
|
-
`For EchoMemory account signup or plugin onboarding, run ${commandLabel} onboard.`,
|
|
190
|
-
].join("\n"),
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (action === "help") {
|
|
195
|
-
return {
|
|
196
|
-
text: [
|
|
197
|
-
"Echo Memory commands:",
|
|
198
|
-
"",
|
|
199
|
-
`${commandLabel} onboard`,
|
|
200
|
-
`${commandLabel} view`,
|
|
201
|
-
`${commandLabel} status`,
|
|
202
|
-
`${commandLabel} search <query>`,
|
|
203
|
-
`${commandLabel} graph`,
|
|
204
|
-
`${commandLabel} graph public`,
|
|
205
|
-
`${commandLabel} sync`,
|
|
206
|
-
`${commandLabel} whoami`,
|
|
207
|
-
`${commandLabel} help`,
|
|
208
|
-
].join("\n"),
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (action === "whoami") {
|
|
213
|
-
const whoami = await client.whoami();
|
|
214
|
-
return {
|
|
215
|
-
text: [
|
|
216
|
-
"Echo identity:",
|
|
217
|
-
`- user_id: ${whoami.user_id}`,
|
|
218
|
-
`- token_type: ${whoami.token_type}`,
|
|
219
|
-
`- scopes: ${Array.isArray(whoami.scopes) ? whoami.scopes.join(", ") : "(none)"}`,
|
|
220
|
-
].join("\n"),
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (action === "onboard") {
|
|
225
|
-
const guide = buildOnboardingText({
|
|
226
|
-
commandLabel,
|
|
227
|
-
cfg,
|
|
228
|
-
});
|
|
229
|
-
return { text: guide.text };
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (action === "sync") {
|
|
233
|
-
const result = await syncRunner.runSync("manual");
|
|
234
|
-
return { text: formatStatusText(result) };
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (action === "search") {
|
|
238
|
-
if (!actionArgs) {
|
|
239
|
-
return {
|
|
240
|
-
text: [
|
|
241
|
-
"Missing search query.",
|
|
242
|
-
`Usage: ${commandLabel} search <query>`,
|
|
243
|
-
].join("\n"),
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const payload = await client.searchMemories({
|
|
248
|
-
query: actionArgs,
|
|
249
|
-
similarityThreshold: 0.3,
|
|
250
|
-
});
|
|
251
|
-
return {
|
|
252
|
-
text: formatSearchResultsText(actionArgs, payload),
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (action === "graph") {
|
|
257
|
-
const graphMode = String(actionArgs || "").trim().toLowerCase();
|
|
258
|
-
|
|
259
|
-
if (!graphMode || graphMode === "private") {
|
|
260
|
-
const url = buildPrivateGraphLoginUrl(cfg);
|
|
261
|
-
return {
|
|
262
|
-
text: [
|
|
263
|
-
"Log in again to open your private memory graph:",
|
|
264
|
-
url,
|
|
265
|
-
"This intentionally requires a fresh web login for security.",
|
|
266
|
-
].filter(Boolean).join("\n"),
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (graphMode === "public") {
|
|
271
|
-
return {
|
|
272
|
-
text: [
|
|
273
|
-
"Open the public memory page:",
|
|
274
|
-
`${cfg.webBaseUrl}/memories`,
|
|
275
|
-
].join("\n"),
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
return {
|
|
280
|
-
text: [
|
|
281
|
-
"Unknown graph mode.",
|
|
282
|
-
`Usage: ${commandLabel} graph`,
|
|
283
|
-
`Usage: ${commandLabel} graph public`,
|
|
284
|
-
].join("\n"),
|
|
331
|
+
text: formatStatusText(localState, remoteStatus),
|
|
285
332
|
};
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
]);
|
|
292
|
-
|
|
293
|
-
return {
|
|
294
|
-
text: formatStatusText(localState, remoteStatus),
|
|
295
|
-
};
|
|
296
|
-
},
|
|
297
|
-
});
|
|
298
|
-
},
|
|
299
|
-
};
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
};
|