recallx 1.0.8 → 1.2.0

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/README.md CHANGED
@@ -43,7 +43,7 @@ Use the public repo when you want the full source-run surface:
43
43
 
44
44
  - local API under `/api/v1`
45
45
  - source-run renderer workflow through `npm run dev`
46
- - stdio MCP bridge through `npm run mcp`
46
+ - stdio MCP bridge through `npm run dev:mcp` during source development
47
47
  - runtime workspace create/open switching without restarting the service
48
48
 
49
49
  ```bash
@@ -56,6 +56,13 @@ npm run dev
56
56
  MCP from source:
57
57
 
58
58
  ```bash
59
+ npm run dev:mcp
60
+ ```
61
+
62
+ If you want to run the built MCP entrypoint instead, build the server first:
63
+
64
+ ```bash
65
+ npm run build:server
59
66
  npm run mcp
60
67
  ```
61
68
 
@@ -88,6 +95,18 @@ When you are preparing a release, bump from the highest known version instead of
88
95
  npm run version:bump -- patch
89
96
  ```
90
97
 
98
+ Workspace lifecycle and backup commands from the same source checkout:
99
+
100
+ ```bash
101
+ recallx workspace current
102
+ recallx workspace backups
103
+ recallx workspace backup --label "before-upgrade"
104
+ recallx workspace export --format markdown
105
+ recallx workspace restore --backup <id> --root /path/to/restore
106
+ ```
107
+
108
+ The renderer Workspace page exposes the same backup, export, restore, and single-writer safety warnings over the local API.
109
+
91
110
  If you want an installable runtime instead of source-run workflows, use one of the npm distribution paths below.
92
111
 
93
112
  ## 2. npm Full Runtime (`recallx`)
@@ -118,6 +137,15 @@ The full npm package includes:
118
137
 
119
138
  `recallx mcp install` writes a stable launcher to `~/.recallx/bin/recallx-mcp`, which is the recommended command path for Codex and other editor MCP configs.
120
139
 
140
+ Workspace backup and recovery commands are available in the packaged CLI too:
141
+
142
+ ```bash
143
+ recallx workspace backups
144
+ recallx workspace backup --label "before-upgrade"
145
+ recallx workspace export --format json
146
+ recallx workspace restore --backup <id> --root /path/to/restore
147
+ ```
148
+
121
149
  If the API is running in bearer mode, set `RECALLX_API_TOKEN` in the MCP client environment. The launcher does not write tokens to disk.
122
150
 
123
151
  Start the packaged runtime with:
@@ -204,16 +232,38 @@ Use the returned endpoint list and request examples to search nodes and activiti
204
232
  Reuse the existing local service instead of starting a new one.
205
233
  ```
206
234
 
235
+ Recommended instruction for MCP-connected coding agents:
236
+
237
+ ```text
238
+ Use my RecallX MCP server as an active local memory layer during this task, not just for final write-back.
239
+ Treat the current workspace as the default scope and do not switch workspaces unless I explicitly ask.
240
+ Before making assumptions or starting meaningful work, read context first: confirm the current workspace, use recallx_search_workspace when the target is still unclear, search for an existing project node when the task is clearly project-shaped, and build a compact recallx_context_bundle once the relevant node or project is known.
241
+ Prefer compact context over repeated broad browsing.
242
+ Once a project is known, append routine work logs to that project instead of writing untargeted workspace captures.
243
+ At the end of meaningful work, write back a concise summary of what changed, what was verified, and any follow-up.
244
+ ```
245
+
246
+ MCP result rendering note:
247
+
248
+ - RecallX MCP keeps `structuredContent` as the authoritative machine-readable payload.
249
+ - The mirrored text content may be a compact deterministic summary rather than a pretty-printed JSON dump.
250
+ - For the current rendering policy and compatibility guidance, see `docs/mcp.md`.
251
+
207
252
  ## MCP Bridge
208
253
 
209
254
  RecallX also ships a stdio MCP adapter for agent clients that prefer tool discovery over raw HTTP calls.
210
255
 
256
+ MCP tool results keep `structuredContent` as the authoritative machine-readable payload, while `content.text` is rendered as a compact deterministic summary instead of a pretty-printed JSON mirror when the payload shape is known.
257
+
211
258
  ```bash
259
+ npm run dev:mcp
212
260
  npm run mcp
213
261
  node dist/server/app/mcp/index.js --api http://127.0.0.1:8787/api/v1
214
262
  recallx-mcp --api http://127.0.0.1:8787/api/v1
215
263
  ```
216
264
 
265
+ Use `npm run dev:mcp` during source development. `npm run mcp` runs the built entrypoint, so it expects `npm run build:server` to have already created `dist/server/app/mcp/index.js`.
266
+
217
267
  For launcher paths, environment variables, and editor-specific setup, see `docs/mcp.md`.
218
268
 
219
269
  ## Docs
@@ -224,6 +274,7 @@ For launcher paths, environment variables, and editor-specific setup, see `docs/
224
274
  - `docs/api.md` for the local HTTP and CLI contract
225
275
  - `docs/mcp.md` for MCP bridge setup
226
276
  - `docs/workflows.md` for common usage flows
277
+ - `docs/sync-backup.md` for backup, restore, and single-writer multi-device guidance
227
278
  - `docs/schema.md` for storage and data model details
228
279
 
229
280
  ## License
@@ -6,7 +6,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
6
6
  import { getApiBase, getAuthToken, requestJson } from "./http.js";
7
7
  import { RECALLX_VERSION } from "../../shared/version.js";
8
8
  import { applyCliUpdate, getCliUpdatePlan } from "./update.js";
9
- import { renderActivitySearchResults, renderBundleMarkdown, renderGovernanceIssues, renderJson, renderNode, renderRelated, renderSearchResults, renderTelemetryErrors, renderTelemetrySummary, renderText, renderUpdateResult, renderWorkspaceSearchResults, renderWorkspaces, } from "./format.js";
9
+ import { renderActivitySearchResults, renderBundleMarkdown, renderGovernanceIssues, renderJson, renderNode, renderRelated, renderSearchResults, renderTelemetryErrors, renderTelemetrySummary, renderText, renderUpdateResult, renderWorkspaceBackups, renderWorkspaceSearchResults, renderWorkspaces, } from "./format.js";
10
10
  const DEFAULT_SOURCE = {
11
11
  actorType: "human",
12
12
  actorLabel: "recallx-cli",
@@ -465,6 +465,27 @@ async function runWorkspace(apiBase, token, format, args, positionals) {
465
465
  action,
466
466
  rootPath: args.root || args.path || positionals[1],
467
467
  });
468
+ case "backups": {
469
+ const data = await requestJson(apiBase, "/workspaces/backups", { token });
470
+ outputData(data, format, "workspace-backups");
471
+ return;
472
+ }
473
+ case "backup":
474
+ return runPostCommand(apiBase, token, format, "/workspaces/backups", "workspace-backup", {
475
+ label: args.label || args.name || positionals[1],
476
+ });
477
+ case "export":
478
+ return runPostCommand(apiBase, token, format, "/workspaces/export", "workspace-export", {
479
+ format: args.format || args.kind || "json",
480
+ });
481
+ case "restore":
482
+ validateRequired(args.backup || args.id || positionals[1], "workspace restore requires --backup");
483
+ validateRequired(args.root || args.path || positionals[2], "workspace restore requires --root");
484
+ return runPostCommand(apiBase, token, format, "/workspaces/restore", "workspace-restore", {
485
+ backupId: args.backup || args.id || positionals[1],
486
+ targetRootPath: args.root || args.path || positionals[2],
487
+ workspaceName: args.name || args.title,
488
+ });
468
489
  }
469
490
  throw new Error(`Unknown workspace action: ${action}`);
470
491
  }
@@ -547,6 +568,9 @@ function outputData(data, format, command) {
547
568
  case "workspace-list":
548
569
  writeStdout(renderWorkspaces(payload));
549
570
  return;
571
+ case "workspace-backups":
572
+ writeStdout(renderWorkspaceBackups(payload));
573
+ return;
550
574
  case "append":
551
575
  case "create":
552
576
  case "link":
@@ -557,6 +581,9 @@ function outputData(data, format, command) {
557
581
  case "workspace-current":
558
582
  case "workspace-create":
559
583
  case "workspace-open":
584
+ case "workspace-backup":
585
+ case "workspace-export":
586
+ case "workspace-restore":
560
587
  writeStdout(renderText(payload));
561
588
  return;
562
589
  case "observability-summary":
@@ -696,6 +723,10 @@ Usage:
696
723
  recallx workspace list
697
724
  recallx workspace create --root /path/to/workspace [--name "Personal"]
698
725
  recallx workspace open --root /path/to/workspace
726
+ recallx workspace backups
727
+ recallx workspace backup [--label "before-upgrade"]
728
+ recallx workspace export [--format json|markdown]
729
+ recallx workspace restore --backup <id> --root /path/to/restore [--name "Recovered"]
699
730
  recallx observability summary [--since 24h]
700
731
  recallx observability errors [--since 24h] [--surface mcp] [--limit 50]
701
732
 
@@ -144,6 +144,20 @@ export function renderWorkspaces(data) {
144
144
  .join("\n\n")}\n`;
145
145
  }
146
146
 
147
+ export function renderWorkspaceBackups(data) {
148
+ const items = data?.items || [];
149
+ if (!items.length) {
150
+ return "No backups.\n";
151
+ }
152
+
153
+ return `${items
154
+ .map(
155
+ (item, index) =>
156
+ `${index + 1}. ${item.label || item.id}\n id: ${item.id}\n created: ${item.createdAt}\n path: ${item.backupPath}`,
157
+ )
158
+ .join("\n\n")}\n`;
159
+ }
160
+
147
161
  export function renderUpdateResult(data) {
148
162
  const lines = [
149
163
  `package: ${data?.packageName || ""}`,
@@ -206,8 +220,18 @@ export function renderTelemetrySummary(data) {
206
220
  `since: ${data?.since || ""}`,
207
221
  `logs: ${data?.logsPath || ""}`,
208
222
  `events: ${data?.totalEvents ?? 0}`,
223
+ `slow threshold: ${data?.slowRequestThresholdMs ?? ""}ms`,
209
224
  ];
210
225
 
226
+ const hot = Array.isArray(data?.hotOperations) ? data.hotOperations : [];
227
+ if (hot.length > 0) {
228
+ lines.push("");
229
+ lines.push("Hot operations:");
230
+ for (const item of hot.slice(0, 5)) {
231
+ lines.push(`- [${item.surface}] ${item.operation} p95=${item.p95DurationMs ?? ""}ms errors=${item.errorCount}/${item.count}`);
232
+ }
233
+ }
234
+
211
235
  const slow = Array.isArray(data?.slowOperations) ? data.slowOperations : [];
212
236
  if (slow.length > 0) {
213
237
  lines.push("");
package/app/mcp/index.js CHANGED
@@ -45,7 +45,7 @@ async function resolveObservabilityState() {
45
45
  workspaceRoot: typeof workspace.rootPath === "string" ? workspace.rootPath : process.cwd(),
46
46
  workspaceName: typeof workspace.workspaceName === "string" ? workspace.workspaceName : "RecallX MCP",
47
47
  retentionDays: typeof values["observability.retentionDays"] === "number" ? values["observability.retentionDays"] : 14,
48
- slowRequestMs: typeof values["observability.slowRequestMs"] === "number" ? values["observability.slowRequestMs"] : 250,
48
+ slowRequestMs: typeof values["observability.slowRequestMs"] === "number" ? values["observability.slowRequestMs"] : 50,
49
49
  capturePayloadShape: values["observability.capturePayloadShape"] !== false
50
50
  };
51
51
  }
@@ -55,7 +55,7 @@ async function resolveObservabilityState() {
55
55
  workspaceRoot: process.cwd(),
56
56
  workspaceName: "RecallX MCP",
57
57
  retentionDays: 14,
58
- slowRequestMs: 250,
58
+ slowRequestMs: 50,
59
59
  capturePayloadShape: true
60
60
  };
61
61
  }