@matelink/cli 2026.4.15 → 2026.4.17

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/bin/matecli.mjs +190 -2
  2. package/package.json +1 -1
package/bin/matecli.mjs CHANGED
@@ -14,7 +14,7 @@ import fs from "node:fs";
14
14
  import os from "node:os";
15
15
  import path from "node:path";
16
16
  import process from "node:process";
17
- import { fileURLToPath } from "node:url";
17
+ import { fileURLToPath, pathToFileURL } from "node:url";
18
18
 
19
19
  const NUMERIC_CODE_LENGTH = 4;
20
20
  const GROUP_SIZE = 4;
@@ -51,6 +51,7 @@ const DEFAULT_GATEWAY_SCOPES = [
51
51
  "operator.approvals",
52
52
  "operator.pairing",
53
53
  ].join(",");
54
+ const SESSION_CONTEXT_MIN_TOKENS = 1024;
54
55
  const CLI_ENTRY = fileURLToPath(import.meta.url);
55
56
  const CLI_LANGUAGE = detectCliLanguage();
56
57
  const CLI_I18N = {
@@ -446,6 +447,18 @@ function resolveOpenClawConfigPath() {
446
447
  return path.join(resolveOpenClawHome(), "openclaw.json");
447
448
  }
448
449
 
450
+ function resolveOpenClawDistPath(fileName) {
451
+ return path.join(
452
+ resolveOpenClawHome(),
453
+ "extensions",
454
+ "memory-tdai",
455
+ "node_modules",
456
+ "openclaw",
457
+ "dist",
458
+ fileName,
459
+ );
460
+ }
461
+
449
462
  function resolveTestNextIMStatePath() {
450
463
  return path.join(resolveOpenClawHome(), "testnextim.state.json");
451
464
  }
@@ -546,6 +559,21 @@ function resolveConfiguredWorkspaceRoot() {
546
559
  return path.resolve(resolved);
547
560
  }
548
561
 
562
+ let sessionStoreHelpersPromise = null;
563
+
564
+ async function loadSessionStoreHelpers() {
565
+ if (!sessionStoreHelpersPromise) {
566
+ sessionStoreHelpersPromise = Promise.all([
567
+ import(pathToFileURL(resolveOpenClawDistPath("session-utils-PHKOUUva.js")).href),
568
+ import(pathToFileURL(resolveOpenClawDistPath("store-DACjypj4.js")).href),
569
+ ]).then(([sessionUtilsMod, storeMod]) => ({
570
+ loadSessionEntry: sessionUtilsMod.s,
571
+ updateSessionStoreEntry: storeMod.f,
572
+ }));
573
+ }
574
+ return sessionStoreHelpersPromise;
575
+ }
576
+
549
577
  function normalizeWorkspaceRelativePath(rawName) {
550
578
  const value = String(rawName ?? "").trim();
551
579
  if (!value) {
@@ -663,11 +691,104 @@ function listWorkspaceFiles(workspaceRoot) {
663
691
  return files;
664
692
  }
665
693
 
694
+ const FIXED_MEMORY_FILES = new Set([
695
+ "AGENTS.md",
696
+ "HEARTBEAT.md",
697
+ "IDENTITY.md",
698
+ "MEMORY.md",
699
+ "SOUL.md",
700
+ "TOOLS.md",
701
+ "USER.md",
702
+ ]);
703
+
704
+ function normalizeFixedMemoryFileName(rawName) {
705
+ const normalized = String(rawName ?? "").trim().toUpperCase();
706
+ for (const fileName of FIXED_MEMORY_FILES) {
707
+ if (fileName.toUpperCase() === normalized) {
708
+ return fileName;
709
+ }
710
+ }
711
+ throw new Error(`unsupported memory file: ${String(rawName ?? "").trim()}`);
712
+ }
713
+
714
+ function listFixedMemoryFiles(workspaceRoot) {
715
+ return Array.from(FIXED_MEMORY_FILES)
716
+ .sort((a, b) => a.localeCompare(b))
717
+ .map((name) => {
718
+ const { relativePath, absolutePath } = resolveWorkspaceFilePath(workspaceRoot, name);
719
+ if (!fs.existsSync(absolutePath)) {
720
+ return buildWorkspaceFileMeta({
721
+ workspaceRoot,
722
+ relativePath,
723
+ absolutePath,
724
+ missing: true,
725
+ });
726
+ }
727
+ return buildWorkspaceFileMeta({
728
+ workspaceRoot,
729
+ relativePath,
730
+ absolutePath,
731
+ });
732
+ });
733
+ }
734
+
666
735
  async function callWorkspaceRpcLocal({
667
736
  method,
668
737
  params,
669
738
  }) {
670
739
  const workspaceRoot = resolveConfiguredWorkspaceRoot();
740
+ if (method === "memory.files.list") {
741
+ return {
742
+ ok: true,
743
+ workspace: workspaceRoot,
744
+ files: listFixedMemoryFiles(workspaceRoot),
745
+ };
746
+ }
747
+
748
+ if (method === "memory.files.get") {
749
+ const fixedName = normalizeFixedMemoryFileName(params?.name);
750
+ const { relativePath, absolutePath } = resolveWorkspaceFilePath(workspaceRoot, fixedName);
751
+ if (!fs.existsSync(absolutePath)) {
752
+ return {
753
+ ok: true,
754
+ workspace: workspaceRoot,
755
+ file: buildWorkspaceFileMeta({
756
+ workspaceRoot,
757
+ relativePath,
758
+ absolutePath,
759
+ missing: true,
760
+ }),
761
+ };
762
+ }
763
+ return {
764
+ ok: true,
765
+ workspace: workspaceRoot,
766
+ file: buildWorkspaceFileMeta({
767
+ workspaceRoot,
768
+ relativePath,
769
+ absolutePath,
770
+ includeContent: true,
771
+ }),
772
+ };
773
+ }
774
+
775
+ if (method === "memory.files.set") {
776
+ const fixedName = normalizeFixedMemoryFileName(params?.name);
777
+ const { relativePath, absolutePath } = resolveWorkspaceFilePath(workspaceRoot, fixedName);
778
+ fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
779
+ fs.writeFileSync(absolutePath, String(params?.content ?? ""), "utf8");
780
+ return {
781
+ ok: true,
782
+ workspace: workspaceRoot,
783
+ file: buildWorkspaceFileMeta({
784
+ workspaceRoot,
785
+ relativePath,
786
+ absolutePath,
787
+ includeContent: true,
788
+ }),
789
+ };
790
+ }
791
+
671
792
  if (method === "agents.files.list") {
672
793
  return {
673
794
  ok: true,
@@ -721,6 +842,62 @@ async function callWorkspaceRpcLocal({
721
842
  return null;
722
843
  }
723
844
 
845
+ async function callSessionContextRpcLocal({
846
+ method,
847
+ params,
848
+ }) {
849
+ const sessionKey = String(params?.sessionKey ?? params?.key ?? "").trim();
850
+ if (!sessionKey) {
851
+ throw new Error("session key is required");
852
+ }
853
+
854
+ const { loadSessionEntry, updateSessionStoreEntry } = await loadSessionStoreHelpers();
855
+ const loaded = loadSessionEntry(sessionKey);
856
+ const resolvedSessionKey = String(loaded?.canonicalKey ?? sessionKey).trim() || sessionKey;
857
+
858
+ if (method === "session.context.get") {
859
+ return {
860
+ ok: true,
861
+ sessionKey: resolvedSessionKey,
862
+ contextTokens: Number.isFinite(loaded?.entry?.contextTokens)
863
+ ? Math.max(0, Math.floor(loaded.entry.contextTokens))
864
+ : null,
865
+ storePath: loaded?.storePath ?? "",
866
+ };
867
+ }
868
+
869
+ if (method === "session.context.set") {
870
+ if (!loaded?.entry || !String(loaded?.storePath ?? "").trim()) {
871
+ throw new Error(`session not found: ${sessionKey}`);
872
+ }
873
+ const contextTokens = Math.max(
874
+ SESSION_CONTEXT_MIN_TOKENS,
875
+ Math.floor(Number(params?.contextTokens ?? 0) || 0),
876
+ );
877
+ const updated = await updateSessionStoreEntry({
878
+ storePath: loaded.storePath,
879
+ sessionKey: resolvedSessionKey,
880
+ update: async (existing) => ({
881
+ contextTokens,
882
+ updatedAt: Math.max(existing?.updatedAt ?? 0, Date.now()),
883
+ }),
884
+ });
885
+ if (!updated) {
886
+ throw new Error(`session not found: ${sessionKey}`);
887
+ }
888
+ return {
889
+ ok: true,
890
+ sessionKey: resolvedSessionKey,
891
+ contextTokens: Number.isFinite(updated?.contextTokens)
892
+ ? Math.max(0, Math.floor(updated.contextTokens))
893
+ : contextTokens,
894
+ storePath: loaded.storePath,
895
+ };
896
+ }
897
+
898
+ return null;
899
+ }
900
+
724
901
  function commandToString(command, args) {
725
902
  return [command, ...args]
726
903
  .map((part) => {
@@ -2944,13 +3121,24 @@ async function callGatewayRpcLocal({
2944
3121
  return {
2945
3122
  ok: true,
2946
3123
  methods: ["sessions.list", "sessions.abort", "sessions.delete", "sessions.usage", "sessions.patch",
2947
- "usage.cost", "agents.files.list", "agents.files.get", "agents.files.set",
3124
+ "usage.cost", "session.context.get", "session.context.set",
3125
+ "memory.files.list", "memory.files.get", "memory.files.set", "agents.files.list", "agents.files.get", "agents.files.set",
2948
3126
  "skills.status", "models.list", "chat.history", "chat.abort",
2949
3127
  "config.get", "config.patch"],
2950
3128
  };
2951
3129
  }
2952
3130
 
2953
3131
  if (
3132
+ method === "session.context.get" ||
3133
+ method === "session.context.set"
3134
+ ) {
3135
+ return callSessionContextRpcLocal({ method, params });
3136
+ }
3137
+
3138
+ if (
3139
+ method === "memory.files.list" ||
3140
+ method === "memory.files.get" ||
3141
+ method === "memory.files.set" ||
2954
3142
  method === "agents.files.list" ||
2955
3143
  method === "agents.files.get" ||
2956
3144
  method === "agents.files.set"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matelink/cli",
3
- "version": "2026.4.15",
3
+ "version": "2026.4.17",
4
4
  "private": false,
5
5
  "description": "Relay-first CLI for pairing and bridging OpenClaw gateway traffic",
6
6
  "type": "module",