@pyxmate/memory 1.1.2 → 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.
Files changed (2) hide show
  1. package/dist/cli/pyx-mem.mjs +260 -126
  2. package/package.json +1 -1
@@ -352,7 +352,7 @@ async function promptMasked(label) {
352
352
  `);
353
353
  return value;
354
354
  }
355
- return new Promise((resolve3, reject) => {
355
+ return new Promise((resolve4, reject) => {
356
356
  const previousEncoding = stdin.readableEncoding;
357
357
  stdin.setEncoding("utf8");
358
358
  stdin.setRawMode(true);
@@ -370,7 +370,7 @@ async function promptMasked(label) {
370
370
  if (ch === "\n" || ch === "\r") {
371
371
  cleanup();
372
372
  stdout.write("\n");
373
- resolve3(buf.trim());
373
+ resolve4(buf.trim());
374
374
  return;
375
375
  }
376
376
  if (ch === "") {
@@ -564,6 +564,8 @@ function createReadCredentials(providerFactory) {
564
564
  }
565
565
 
566
566
  // src/mcp/proxy-server.ts
567
+ import { readFile, stat } from "fs/promises";
568
+ import { basename, isAbsolute, resolve } from "path";
567
569
  import { Client as McpClient } from "@modelcontextprotocol/sdk/client/index.js";
568
570
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
569
571
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -574,108 +576,6 @@ import {
574
576
  ListPromptsRequestSchema,
575
577
  ListToolsRequestSchema
576
578
  } from "@modelcontextprotocol/sdk/types.js";
577
- var REMOTE_MCP_PATH = "/mcp";
578
- function createProxyServer(client, version) {
579
- const caps = client.getServerCapabilities();
580
- const server = new Server(client.getServerVersion() ?? { name: "pyx-memory", version }, {
581
- capabilities: {
582
- // Advertise the PRESENCE of tools/prompts, but NOT their `listChanged`
583
- // sub-capability: this proxy does not relay the remote's list_changed
584
- // notifications, so claiming listChanged would be a capability the host
585
- // could rely on but we never honor (Codex: keep the proxy transparent).
586
- ...caps?.tools ? { tools: {} } : {},
587
- ...caps?.prompts ? { prompts: {} } : {}
588
- },
589
- instructions: client.getInstructions()
590
- });
591
- if (caps?.tools) {
592
- server.setRequestHandler(
593
- ListToolsRequestSchema,
594
- (req) => client.listTools(req.params)
595
- );
596
- server.setRequestHandler(
597
- CallToolRequestSchema,
598
- (req) => client.callTool(req.params)
599
- );
600
- }
601
- if (caps?.prompts) {
602
- server.setRequestHandler(
603
- ListPromptsRequestSchema,
604
- (req) => client.listPrompts(req.params)
605
- );
606
- server.setRequestHandler(
607
- GetPromptRequestSchema,
608
- (req) => client.getPrompt(req.params)
609
- );
610
- }
611
- return server;
612
- }
613
- async function runMcpProxyServer(opts) {
614
- const version = opts.version ?? (true ? "1.1.2" : "0.0.0-dev");
615
- const read = await opts.readCredentials();
616
- if (!read.ok) {
617
- const text = read.result.content.map((c) => c.type === "text" ? c.text : "").join(" ").trim();
618
- throw new Error(text || "pyx-memory credentials are unavailable. Run: pyx-mem login");
619
- }
620
- const { endpoint, apiKey } = read.credentials;
621
- const url = new URL(`${endpoint.replace(/\/+$/, "")}${REMOTE_MCP_PATH}`);
622
- const client = new McpClient({ name: "pyx-mem-proxy", version }, { capabilities: {} });
623
- const clientTransport = new StreamableHTTPClientTransport(url, {
624
- requestInit: { headers: { Authorization: `Bearer ${apiKey}` } }
625
- });
626
- try {
627
- await client.connect(clientTransport);
628
- } catch (err) {
629
- const msg = err instanceof Error ? err.message : String(err);
630
- throw new Error(
631
- `Could not reach the pyx-memory remote MCP at ${url.href}: ${msg}. Verify the endpoint and key with \`pyx-mem doctor\`, or run the bundled server with \`pyx-mem mcp\`.`
632
- );
633
- }
634
- try {
635
- const server = createProxyServer(client, version);
636
- const transport = new StdioServerTransport();
637
- const closed = new Promise((resolve3) => {
638
- transport.onclose = () => resolve3();
639
- });
640
- await server.connect(transport);
641
- await closed;
642
- } finally {
643
- await client.close().catch(() => {
644
- });
645
- }
646
- }
647
-
648
- // src/mcp/server.ts
649
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
650
- import { StdioServerTransport as StdioServerTransport2 } from "@modelcontextprotocol/sdk/server/stdio.js";
651
-
652
- // src/mcp/prompts/index.ts
653
- import { z } from "zod";
654
- var structureGraphPrompt = {
655
- name: "structure_graph",
656
- description: STRUCTURE_GRAPH_PROMPT_DESC,
657
- register(server) {
658
- server.registerPrompt(
659
- "structure_graph",
660
- {
661
- title: "Structure content into a knowledge graph",
662
- description: STRUCTURE_GRAPH_PROMPT_DESC,
663
- argsSchema: {
664
- content: z.string().min(1).describe("The memory content to extract graph fields from.")
665
- }
666
- },
667
- ({ content }) => ({
668
- messages: [
669
- { role: "user", content: { type: "text", text: buildGraphStructuringPrompt(content) } }
670
- ]
671
- })
672
- );
673
- }
674
- };
675
- var ALL_PROMPTS = [structureGraphPrompt];
676
-
677
- // src/mcp/tools/corrections.ts
678
- import { z as z3 } from "zod";
679
579
 
680
580
  // src/mcp/http-client.ts
681
581
  var DEFAULT_TIMEOUT_MS = 15e3;
@@ -781,6 +681,202 @@ function extractEnvelopeError(parsed) {
781
681
  return null;
782
682
  }
783
683
 
684
+ // src/mcp/tools/shared.ts
685
+ var LOCAL_UPLOAD_META_KEY = "pyx.dev/local-upload";
686
+
687
+ // src/mcp/proxy-server.ts
688
+ var REMOTE_MCP_PATH = "/mcp";
689
+ function extractLocalUpload(meta) {
690
+ if (meta === null || typeof meta !== "object") return void 0;
691
+ const descriptor = meta[LOCAL_UPLOAD_META_KEY];
692
+ if (descriptor === null || typeof descriptor !== "object") return void 0;
693
+ const obj = descriptor;
694
+ if (typeof obj.pathArg !== "string" || typeof obj.endpoint !== "string" || typeof obj.fileField !== "string") {
695
+ return void 0;
696
+ }
697
+ if (!obj.endpoint.startsWith("/") || obj.endpoint.startsWith("//")) {
698
+ return void 0;
699
+ }
700
+ return obj;
701
+ }
702
+ async function readCappedLocalFile(rawPath, descriptor) {
703
+ if (typeof rawPath !== "string" || rawPath.length === 0) {
704
+ return {
705
+ ok: false,
706
+ result: mcpText(`\`${descriptor.pathArg}\` must be a non-empty local file path.`, true)
707
+ };
708
+ }
709
+ const abs = isAbsolute(rawPath) ? rawPath : resolve(rawPath);
710
+ try {
711
+ if (typeof descriptor.maxBytes === "number") {
712
+ const info = await stat(abs);
713
+ if (info.size > descriptor.maxBytes) {
714
+ return {
715
+ ok: false,
716
+ result: mcpText(`File too large: ${info.size} bytes > ${descriptor.maxBytes} cap.`, true)
717
+ };
718
+ }
719
+ }
720
+ return { ok: true, bytes: await readFile(abs), name: basename(abs) };
721
+ } catch (err) {
722
+ return {
723
+ ok: false,
724
+ result: mcpText(
725
+ `Failed to read ${abs}: ${err instanceof Error ? err.message : String(err)}.`,
726
+ true
727
+ )
728
+ };
729
+ }
730
+ }
731
+ function createLocalFileUploader(credentials, fetchImpl = fetch) {
732
+ return async (descriptor, args) => {
733
+ const file = await readCappedLocalFile(args[descriptor.pathArg], descriptor);
734
+ if (!file.ok) return file.result;
735
+ const http = createHttpClient(credentials, fetchImpl);
736
+ const res = await http.requestMultipart({
737
+ path: descriptor.endpoint,
738
+ formData: () => {
739
+ const form = new FormData();
740
+ form.set(descriptor.fileField, new File([new Uint8Array(file.bytes)], file.name));
741
+ for (const key of descriptor.optionalArgs ?? []) {
742
+ const value = args[key];
743
+ if (typeof value === "string" && value.length > 0) form.set(key, value);
744
+ }
745
+ return form;
746
+ }
747
+ });
748
+ return res.ok ? mcpJson(res.data) : res.result;
749
+ };
750
+ }
751
+ function createProxyServer(client, version, uploadLocalFile) {
752
+ const caps = client.getServerCapabilities();
753
+ const server = new Server(client.getServerVersion() ?? { name: "pyx-memory", version }, {
754
+ capabilities: {
755
+ // Advertise the PRESENCE of tools/prompts, but NOT their `listChanged`
756
+ // sub-capability: this proxy does not relay the remote's list_changed
757
+ // notifications, so claiming listChanged would be a capability the host
758
+ // could rely on but we never honor (Codex: keep the proxy transparent).
759
+ ...caps?.tools ? { tools: {} } : {},
760
+ ...caps?.prompts ? { prompts: {} } : {}
761
+ },
762
+ instructions: client.getInstructions()
763
+ });
764
+ const localUploads = /* @__PURE__ */ new Map();
765
+ let listedOnce = false;
766
+ const refreshFromList = (result) => {
767
+ const tools = result.tools;
768
+ if (Array.isArray(tools)) {
769
+ listedOnce = true;
770
+ for (const tool of tools) {
771
+ const descriptor = uploadLocalFile ? extractLocalUpload(tool._meta) : void 0;
772
+ if (descriptor) localUploads.set(tool.name, descriptor);
773
+ else localUploads.delete(tool.name);
774
+ }
775
+ }
776
+ return result;
777
+ };
778
+ if (caps?.tools) {
779
+ server.setRequestHandler(
780
+ ListToolsRequestSchema,
781
+ async (req) => refreshFromList(await client.listTools(req.params))
782
+ );
783
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
784
+ if (uploadLocalFile && !listedOnce) {
785
+ try {
786
+ refreshFromList(await client.listTools());
787
+ } catch {
788
+ }
789
+ }
790
+ const descriptor = uploadLocalFile ? localUploads.get(req.params.name) : void 0;
791
+ if (uploadLocalFile && descriptor) {
792
+ const result = await uploadLocalFile(
793
+ descriptor,
794
+ req.params.arguments ?? {}
795
+ );
796
+ return result;
797
+ }
798
+ return client.callTool(req.params);
799
+ });
800
+ }
801
+ if (caps?.prompts) {
802
+ server.setRequestHandler(
803
+ ListPromptsRequestSchema,
804
+ (req) => client.listPrompts(req.params)
805
+ );
806
+ server.setRequestHandler(
807
+ GetPromptRequestSchema,
808
+ (req) => client.getPrompt(req.params)
809
+ );
810
+ }
811
+ return server;
812
+ }
813
+ async function runMcpProxyServer(opts) {
814
+ const version = opts.version ?? (true ? "1.2.0" : "0.0.0-dev");
815
+ const read = await opts.readCredentials();
816
+ if (!read.ok) {
817
+ const text = read.result.content.map((c) => c.type === "text" ? c.text : "").join(" ").trim();
818
+ throw new Error(text || "pyx-memory credentials are unavailable. Run: pyx-mem login");
819
+ }
820
+ const { endpoint, apiKey } = read.credentials;
821
+ const url = new URL(`${endpoint.replace(/\/+$/, "")}${REMOTE_MCP_PATH}`);
822
+ const client = new McpClient({ name: "pyx-mem-proxy", version }, { capabilities: {} });
823
+ const clientTransport = new StreamableHTTPClientTransport(url, {
824
+ requestInit: { headers: { Authorization: `Bearer ${apiKey}` } }
825
+ });
826
+ try {
827
+ await client.connect(clientTransport);
828
+ } catch (err) {
829
+ const msg = err instanceof Error ? err.message : String(err);
830
+ throw new Error(
831
+ `Could not reach the pyx-memory remote MCP at ${url.href}: ${msg}. Verify the endpoint and key with \`pyx-mem doctor\`, or run the legacy bundled server with \`pyx-mem mcp --bundled\`.`
832
+ );
833
+ }
834
+ try {
835
+ const server = createProxyServer(client, version, createLocalFileUploader(read.credentials));
836
+ const transport = new StdioServerTransport();
837
+ const closed = new Promise((resolve4) => {
838
+ transport.onclose = () => resolve4();
839
+ });
840
+ await server.connect(transport);
841
+ await closed;
842
+ } finally {
843
+ await client.close().catch(() => {
844
+ });
845
+ }
846
+ }
847
+
848
+ // src/mcp/server.ts
849
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
850
+ import { StdioServerTransport as StdioServerTransport2 } from "@modelcontextprotocol/sdk/server/stdio.js";
851
+
852
+ // src/mcp/prompts/index.ts
853
+ import { z } from "zod";
854
+ var structureGraphPrompt = {
855
+ name: "structure_graph",
856
+ description: STRUCTURE_GRAPH_PROMPT_DESC,
857
+ register(server) {
858
+ server.registerPrompt(
859
+ "structure_graph",
860
+ {
861
+ title: "Structure content into a knowledge graph",
862
+ description: STRUCTURE_GRAPH_PROMPT_DESC,
863
+ argsSchema: {
864
+ content: z.string().min(1).describe("The memory content to extract graph fields from.")
865
+ }
866
+ },
867
+ ({ content }) => ({
868
+ messages: [
869
+ { role: "user", content: { type: "text", text: buildGraphStructuringPrompt(content) } }
870
+ ]
871
+ })
872
+ );
873
+ }
874
+ };
875
+ var ALL_PROMPTS = [structureGraphPrompt];
876
+
877
+ // src/mcp/tools/corrections.ts
878
+ import { z as z3 } from "zod";
879
+
784
880
  // src/mcp/tools/scopes.ts
785
881
  import { z as z2 } from "zod";
786
882
  var scopeShape = {
@@ -923,11 +1019,12 @@ var getMemoryTool = {
923
1019
  };
924
1020
 
925
1021
  // src/mcp/tools/ingest.ts
926
- import { readFile, stat } from "fs/promises";
927
- import { basename, extname, isAbsolute, resolve } from "path";
1022
+ import { readFile as readFile2, stat as stat2 } from "fs/promises";
1023
+ import { basename as basename2, extname, isAbsolute as isAbsolute2, resolve as resolve2 } from "path";
928
1024
  import { z as z6 } from "zod";
929
1025
  var IMAGE_EXT = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".webp", ".gif", ".bmp", ".tiff", ".svg"]);
930
1026
  var MAX_BYTES = 50 * 1024 * 1024;
1027
+ var INGEST_ENDPOINT = "/api/memory/ingest/file";
931
1028
  var inputShape3 = {
932
1029
  path: z6.string().min(1).describe(
933
1030
  "Local file path readable by the pyx-mem process. Uploaded as multipart `file`. Images require `description`; documents auto-extract text."
@@ -946,6 +1043,17 @@ var ingestMemoryFileTool = {
946
1043
  inputSchema: inputShape3,
947
1044
  annotations: { readOnlyHint: false, idempotentHint: false, openWorldHint: true }
948
1045
  },
1046
+ // `path` is a host-local file. On the remote `/mcp` route the server cannot
1047
+ // read it, so this descriptor lets the local proxy bridge the upload (read
1048
+ // bytes here, multipart-POST to the declared endpoint). The bundled handler
1049
+ // below ignores it. Field names map 1:1 to the multipart form built below.
1050
+ localUpload: {
1051
+ pathArg: "path",
1052
+ endpoint: INGEST_ENDPOINT,
1053
+ fileField: "file",
1054
+ optionalArgs: ["description", "namespaceId"],
1055
+ maxBytes: MAX_BYTES
1056
+ },
949
1057
  handler: (deps) => async (raw) => {
950
1058
  const args = raw;
951
1059
  const ext = extname(args.path).toLowerCase();
@@ -956,14 +1064,14 @@ var ingestMemoryFileTool = {
956
1064
  true
957
1065
  );
958
1066
  }
959
- const abs = isAbsolute(args.path) ? args.path : resolve(args.path);
1067
+ const abs = isAbsolute2(args.path) ? args.path : resolve2(args.path);
960
1068
  let bytes;
961
1069
  try {
962
- const info = await stat(abs);
1070
+ const info = await stat2(abs);
963
1071
  if (info.size > MAX_BYTES) {
964
1072
  return mcpText(`File too large: ${info.size} bytes > 50MB cap.`, true);
965
1073
  }
966
- bytes = await readFile(abs);
1074
+ bytes = await readFile2(abs);
967
1075
  } catch (err) {
968
1076
  return mcpText(
969
1077
  `Failed to read ${abs}: ${err instanceof Error ? err.message : String(err)}.`,
@@ -974,11 +1082,11 @@ var ingestMemoryFileTool = {
974
1082
  if (!creds.ok) return creds.result;
975
1083
  const http = createHttpClient(creds.credentials, deps.fetchImpl);
976
1084
  const res = await http.requestMultipart({
977
- path: "/api/memory/ingest/file",
1085
+ path: INGEST_ENDPOINT,
978
1086
  scope: args,
979
1087
  formData: () => {
980
1088
  const form = new FormData();
981
- const file = new File([new Uint8Array(bytes)], basename(abs));
1089
+ const file = new File([new Uint8Array(bytes)], basename2(abs));
982
1090
  form.set("file", file);
983
1091
  if (args.description) form.set("description", args.description);
984
1092
  if (args.namespaceId) form.set("namespaceId", args.namespaceId);
@@ -1459,7 +1567,7 @@ var ALL_TOOL_NAMES = ALL_TOOLS.map((t) => t.name);
1459
1567
  // src/mcp/server.ts
1460
1568
  async function runMcpServer(opts) {
1461
1569
  const fetchImpl = opts.fetchImpl ?? fetch;
1462
- const version = opts.version ?? (true ? "1.1.2" : "0.0.0-dev");
1570
+ const version = opts.version ?? (true ? "1.2.0" : "0.0.0-dev");
1463
1571
  const server = new McpServer(
1464
1572
  { name: "pyx-memory", version },
1465
1573
  { instructions: PYX_MEMORY_INSTRUCTIONS, capabilities: { tools: {}, prompts: {} } }
@@ -1479,8 +1587,8 @@ async function runMcpServer(opts) {
1479
1587
  prompt.register(server);
1480
1588
  }
1481
1589
  const transport = new StdioServerTransport2();
1482
- const closed = new Promise((resolve3) => {
1483
- transport.onclose = () => resolve3();
1590
+ const closed = new Promise((resolve4) => {
1591
+ transport.onclose = () => resolve4();
1484
1592
  });
1485
1593
  await server.connect(transport);
1486
1594
  await closed;
@@ -1489,12 +1597,12 @@ async function runMcpServer(opts) {
1489
1597
  // src/cli/commands/mcp.ts
1490
1598
  async function mcpCommand(opts = {}) {
1491
1599
  const readCredentials = createReadCredentials(() => getDefaultKeychain());
1492
- const onStdinEnd = new Promise((resolve3) => {
1493
- process.stdin.once("end", resolve3);
1494
- process.stdin.once("close", resolve3);
1600
+ const onStdinEnd = new Promise((resolve4) => {
1601
+ process.stdin.once("end", resolve4);
1602
+ process.stdin.once("close", resolve4);
1495
1603
  });
1496
1604
  try {
1497
- const run = opts.remote ? runMcpProxyServer({ readCredentials }) : runMcpServer({ readCredentials });
1605
+ const run = opts.bundled ? runMcpServer({ readCredentials }) : runMcpProxyServer({ readCredentials });
1498
1606
  await Promise.race([run, onStdinEnd]);
1499
1607
  return EXIT.OK;
1500
1608
  } catch (err) {
@@ -1503,6 +1611,14 @@ async function mcpCommand(opts = {}) {
1503
1611
  return EXIT.USAGE;
1504
1612
  }
1505
1613
  }
1614
+ function resolveMcpMode(flags) {
1615
+ const remote = flags.remote === true;
1616
+ const bundled = flags.bundled === true;
1617
+ if (remote && bundled) {
1618
+ return { ok: false, error: "`--remote` and `--bundled` are mutually exclusive." };
1619
+ }
1620
+ return { ok: true, bundled, implicit: !remote && !bundled };
1621
+ }
1506
1622
 
1507
1623
  // src/cli/commands/mcp-install.ts
1508
1624
  import { spawnSync as nodeSpawnSync } from "child_process";
@@ -1959,7 +2075,7 @@ function writeJsonAndReport(filePath, agentLabel, entry, opts = {}) {
1959
2075
 
1960
2076
  // src/cli/commands/scaffold.ts
1961
2077
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, statSync, writeFileSync as writeFileSync2 } from "fs";
1962
- import { basename as basename2, join as join2, resolve as resolve2 } from "path";
2078
+ import { basename as basename3, join as join2, resolve as resolve3 } from "path";
1963
2079
  var SERVER_IMAGE = "ghcr.io/pyx-corp/pyx-memory-v1:latest";
1964
2080
  var DOCKER_COMPOSE = `services:
1965
2081
  pyx-memory:
@@ -2082,8 +2198,8 @@ function resolveTarget(args) {
2082
2198
  process.stderr.write("Error: --name requires a non-empty directory name.\n");
2083
2199
  return null;
2084
2200
  }
2085
- const targetDir = trimmedName ? resolve2(cwd, trimmedName) : cwd;
2086
- const appName = trimmedName || basename2(resolve2(cwd));
2201
+ const targetDir = trimmedName ? resolve3(cwd, trimmedName) : cwd;
2202
+ const appName = trimmedName || basename3(resolve3(cwd));
2087
2203
  return { targetDir, appName };
2088
2204
  }
2089
2205
  function buildFiles(targetDir, appName) {
@@ -2109,7 +2225,7 @@ function scaffoldCommand(args = {}) {
2109
2225
  const created = [];
2110
2226
  const skipped = [];
2111
2227
  for (const file of buildFiles(target.targetDir, target.appName)) {
2112
- const relativePath = basename2(file.path);
2228
+ const relativePath = basename3(file.path);
2113
2229
  if (existsSync2(file.path)) {
2114
2230
  skipped.push(relativePath);
2115
2231
  continue;
@@ -2189,9 +2305,11 @@ Commands:
2189
2305
  logout Delete stored pyx-memory credentials.
2190
2306
  doctor [--json] Diagnose keychain, credentials, backend, MCP startup.
2191
2307
  scaffold [--name <dir>] Generate Docker, env, SDK, and memory design-guide starter files.
2192
- mcp [--remote] Start stdio MCP server. --remote proxies to the hosted
2193
- server so tools + instructions stay server-owned
2194
- (zero-touch updates; key stays in the keychain).
2308
+ mcp [--bundled] Start the stdio MCP server. Default connects to the
2309
+ hosted server so tools + instructions stay
2310
+ server-owned (zero-touch updates; key stays in the
2311
+ keychain). --bundled runs the legacy in-package server
2312
+ (offline / version-pinned / host-local file ingest).
2195
2313
  mcp install <target> [--scope user|local|project] [--remote]
2196
2314
  Install pyx-memory MCP config for your AI agent.
2197
2315
  --remote installs the hosted thin-proxy (zero-touch
@@ -2276,7 +2394,23 @@ function runMcpInstall(target, scope, remote) {
2276
2394
  return handler({ scope, remote });
2277
2395
  }
2278
2396
  function runMcpCommand(parsed) {
2279
- if (parsed.subcommand === void 0) return mcpCommand({ remote: parsed.flags.remote === true });
2397
+ if (parsed.subcommand === void 0) {
2398
+ const resolved = resolveMcpMode({
2399
+ remote: parsed.flags.remote === true,
2400
+ bundled: parsed.flags.bundled === true
2401
+ });
2402
+ if (!resolved.ok) {
2403
+ process.stderr.write(`Error: ${resolved.error}
2404
+ `);
2405
+ return EXIT.USAGE;
2406
+ }
2407
+ if (resolved.implicit) {
2408
+ process.stderr.write(
2409
+ "pyx-memory: `pyx-mem mcp` now connects to the hosted server (zero-touch \u2014 tools and instructions stay server-owned). Pass `--bundled` for the legacy in-package server.\n"
2410
+ );
2411
+ }
2412
+ return mcpCommand({ bundled: resolved.bundled });
2413
+ }
2280
2414
  if (parsed.subcommand === "install") {
2281
2415
  const target = parsed.positional[0];
2282
2416
  const scope = typeof parsed.flags.scope === "string" ? parsed.flags.scope : void 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyxmate/memory",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "description": "SDK for pyx-memory — Memory as a Service for AI agents",
6
6
  "license": "MIT",