@clude/sdk 3.0.3 → 3.0.4
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 +1 -1
- package/dist/cli/index.js +547 -58
- package/dist/mcp/server.js +1 -1
- package/dist/sdk/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -471,7 +471,7 @@ Memories form a graph with typed bonds:
|
|
|
471
471
|
This package also includes the full Clude bot — an autonomous AI agent on X ([@Cludebot](https://x.com/Cludebot)).
|
|
472
472
|
|
|
473
473
|
```bash
|
|
474
|
-
git clone https://github.com/sebbsssss/
|
|
474
|
+
git clone https://github.com/sebbsssss/clude.git
|
|
475
475
|
cd cludebot
|
|
476
476
|
npm install
|
|
477
477
|
cp .env.example .env # fill in API keys
|
package/dist/cli/index.js
CHANGED
|
@@ -2143,7 +2143,7 @@ async function runInit() {
|
|
|
2143
2143
|
}
|
|
2144
2144
|
}
|
|
2145
2145
|
console.log(`
|
|
2146
|
-
${c.dim}Docs: https://github.com/sebbsssss/
|
|
2146
|
+
${c.dim}Docs: https://github.com/sebbsssss/clude${c.reset}`);
|
|
2147
2147
|
console.log(` ${c.dim}Website: https://clude.io${c.reset}`);
|
|
2148
2148
|
printDivider();
|
|
2149
2149
|
console.log("");
|
|
@@ -2797,6 +2797,232 @@ var init_status = __esm({
|
|
|
2797
2797
|
}
|
|
2798
2798
|
});
|
|
2799
2799
|
|
|
2800
|
+
// packages/brain/src/memorypack/types.ts
|
|
2801
|
+
var MEMORYPACK_VERSION;
|
|
2802
|
+
var init_types = __esm({
|
|
2803
|
+
"packages/brain/src/memorypack/types.ts"() {
|
|
2804
|
+
"use strict";
|
|
2805
|
+
MEMORYPACK_VERSION = "0.1";
|
|
2806
|
+
}
|
|
2807
|
+
});
|
|
2808
|
+
|
|
2809
|
+
// packages/brain/src/memorypack/sign.ts
|
|
2810
|
+
function hashRecordLine(line) {
|
|
2811
|
+
const clean = line.replace(/\n$/, "");
|
|
2812
|
+
const hex = (0, import_crypto.createHash)("sha256").update(clean, "utf-8").digest("hex");
|
|
2813
|
+
return `sha256:${hex}`;
|
|
2814
|
+
}
|
|
2815
|
+
function signHash(hash, secretKey) {
|
|
2816
|
+
const messageBytes = Buffer.from(hash, "utf-8");
|
|
2817
|
+
const sig = import_tweetnacl.default.sign.detached(messageBytes, secretKey);
|
|
2818
|
+
return `base58:${bs58.encode(sig)}`;
|
|
2819
|
+
}
|
|
2820
|
+
function verifyHash(hash, signature, publicKey) {
|
|
2821
|
+
try {
|
|
2822
|
+
const messageBytes = Buffer.from(hash, "utf-8");
|
|
2823
|
+
const sigRaw = signature.startsWith("base58:") ? signature.slice("base58:".length) : signature;
|
|
2824
|
+
const sigBytes = bs58.decode(sigRaw);
|
|
2825
|
+
const pkBytes = bs58.decode(publicKey);
|
|
2826
|
+
return import_tweetnacl.default.sign.detached.verify(messageBytes, sigBytes, pkBytes);
|
|
2827
|
+
} catch {
|
|
2828
|
+
return false;
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
var import_crypto, import_tweetnacl, bs58Module, bs58;
|
|
2832
|
+
var init_sign = __esm({
|
|
2833
|
+
"packages/brain/src/memorypack/sign.ts"() {
|
|
2834
|
+
"use strict";
|
|
2835
|
+
import_crypto = require("crypto");
|
|
2836
|
+
import_tweetnacl = __toESM(require("tweetnacl"));
|
|
2837
|
+
bs58Module = __toESM(require("bs58"));
|
|
2838
|
+
bs58 = bs58Module.default || bs58Module;
|
|
2839
|
+
}
|
|
2840
|
+
});
|
|
2841
|
+
|
|
2842
|
+
// packages/brain/src/memorypack/writer.ts
|
|
2843
|
+
function serializeRecord(record) {
|
|
2844
|
+
const KNOWN_ORDER = [
|
|
2845
|
+
"id",
|
|
2846
|
+
"created_at",
|
|
2847
|
+
"kind",
|
|
2848
|
+
"content",
|
|
2849
|
+
"tags",
|
|
2850
|
+
"importance",
|
|
2851
|
+
"source",
|
|
2852
|
+
"summary",
|
|
2853
|
+
"embedding",
|
|
2854
|
+
"embedding_model",
|
|
2855
|
+
"metadata",
|
|
2856
|
+
"access_count",
|
|
2857
|
+
"last_accessed_at",
|
|
2858
|
+
"parent_ids",
|
|
2859
|
+
"compacted_from",
|
|
2860
|
+
"blob_ref"
|
|
2861
|
+
];
|
|
2862
|
+
const out = {};
|
|
2863
|
+
for (const k of KNOWN_ORDER) {
|
|
2864
|
+
if (record[k] !== void 0) out[k] = record[k];
|
|
2865
|
+
}
|
|
2866
|
+
const recAsUnknown = record;
|
|
2867
|
+
const unknownKeys = Object.keys(recAsUnknown).filter(
|
|
2868
|
+
(k) => !KNOWN_ORDER.includes(k)
|
|
2869
|
+
);
|
|
2870
|
+
for (const k of unknownKeys.sort()) {
|
|
2871
|
+
out[k] = recAsUnknown[k];
|
|
2872
|
+
}
|
|
2873
|
+
return JSON.stringify(out);
|
|
2874
|
+
}
|
|
2875
|
+
function writeMemoryPack(dir, records, opts, anchors) {
|
|
2876
|
+
(0, import_fs2.mkdirSync)(dir, { recursive: true });
|
|
2877
|
+
const manifest = {
|
|
2878
|
+
memorypack_version: MEMORYPACK_VERSION,
|
|
2879
|
+
producer: opts.producer,
|
|
2880
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2881
|
+
record_count: records.length,
|
|
2882
|
+
record_schema: opts.record_schema,
|
|
2883
|
+
signature_algorithm: opts.secretKey ? "ed25519" : void 0,
|
|
2884
|
+
anchor_chain: opts.anchor_chain
|
|
2885
|
+
};
|
|
2886
|
+
(0, import_fs2.writeFileSync)((0, import_path3.join)(dir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
2887
|
+
const recordLines = [];
|
|
2888
|
+
const sigs = [];
|
|
2889
|
+
for (const record of records) {
|
|
2890
|
+
const line = serializeRecord(record);
|
|
2891
|
+
recordLines.push(line);
|
|
2892
|
+
if (opts.secretKey && opts.producer.public_key) {
|
|
2893
|
+
const hash = hashRecordLine(line);
|
|
2894
|
+
const signature = signHash(hash, opts.secretKey);
|
|
2895
|
+
sigs.push({
|
|
2896
|
+
record_hash: hash,
|
|
2897
|
+
signature,
|
|
2898
|
+
algorithm: "ed25519",
|
|
2899
|
+
public_key: opts.producer.public_key
|
|
2900
|
+
});
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
(0, import_fs2.writeFileSync)((0, import_path3.join)(dir, "records.jsonl"), recordLines.join("\n") + "\n");
|
|
2904
|
+
if (sigs.length > 0) {
|
|
2905
|
+
(0, import_fs2.writeFileSync)(
|
|
2906
|
+
(0, import_path3.join)(dir, "signatures.jsonl"),
|
|
2907
|
+
sigs.map((s) => JSON.stringify(s)).join("\n") + "\n"
|
|
2908
|
+
);
|
|
2909
|
+
}
|
|
2910
|
+
if (anchors && anchors.length > 0) {
|
|
2911
|
+
(0, import_fs2.writeFileSync)(
|
|
2912
|
+
(0, import_path3.join)(dir, "anchors.jsonl"),
|
|
2913
|
+
anchors.map((a) => JSON.stringify(a)).join("\n") + "\n"
|
|
2914
|
+
);
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
var import_fs2, import_path3;
|
|
2918
|
+
var init_writer = __esm({
|
|
2919
|
+
"packages/brain/src/memorypack/writer.ts"() {
|
|
2920
|
+
"use strict";
|
|
2921
|
+
import_fs2 = require("fs");
|
|
2922
|
+
import_path3 = require("path");
|
|
2923
|
+
init_types();
|
|
2924
|
+
init_sign();
|
|
2925
|
+
}
|
|
2926
|
+
});
|
|
2927
|
+
|
|
2928
|
+
// packages/brain/src/memorypack/reader.ts
|
|
2929
|
+
function readMemoryPack(dir, opts = {}) {
|
|
2930
|
+
const warnings = [];
|
|
2931
|
+
const manifestPath = (0, import_path4.join)(dir, "manifest.json");
|
|
2932
|
+
if (!(0, import_fs3.existsSync)(manifestPath)) {
|
|
2933
|
+
throw new Error(`MemoryPack: manifest.json not found in ${dir}`);
|
|
2934
|
+
}
|
|
2935
|
+
const manifest = JSON.parse((0, import_fs3.readFileSync)(manifestPath, "utf-8"));
|
|
2936
|
+
if (!manifest.memorypack_version) {
|
|
2937
|
+
throw new Error("MemoryPack: manifest missing memorypack_version");
|
|
2938
|
+
}
|
|
2939
|
+
if (!manifest.memorypack_version.startsWith("0.")) {
|
|
2940
|
+
throw new Error(
|
|
2941
|
+
`MemoryPack: unsupported memorypack_version ${manifest.memorypack_version} (reader supports 0.x)`
|
|
2942
|
+
);
|
|
2943
|
+
}
|
|
2944
|
+
const recordsPath = (0, import_path4.join)(dir, "records.jsonl");
|
|
2945
|
+
if (!(0, import_fs3.existsSync)(recordsPath)) {
|
|
2946
|
+
throw new Error(`MemoryPack: records.jsonl not found in ${dir}`);
|
|
2947
|
+
}
|
|
2948
|
+
const recordLines = (0, import_fs3.readFileSync)(recordsPath, "utf-8").split("\n").filter((l) => l.length > 0);
|
|
2949
|
+
const records = [];
|
|
2950
|
+
const lineByHash = /* @__PURE__ */ new Map();
|
|
2951
|
+
for (const line of recordLines) {
|
|
2952
|
+
const rec = JSON.parse(line);
|
|
2953
|
+
records.push(rec);
|
|
2954
|
+
lineByHash.set(hashRecordLine(line), line);
|
|
2955
|
+
}
|
|
2956
|
+
if (records.length !== manifest.record_count) {
|
|
2957
|
+
warnings.push(`record_count mismatch: manifest ${manifest.record_count} vs jsonl ${records.length}`);
|
|
2958
|
+
}
|
|
2959
|
+
const verifiedRecords = /* @__PURE__ */ new Set();
|
|
2960
|
+
const sigsPath = (0, import_path4.join)(dir, "signatures.jsonl");
|
|
2961
|
+
const signaturesFilePresent = (0, import_fs3.existsSync)(sigsPath);
|
|
2962
|
+
if (signaturesFilePresent) {
|
|
2963
|
+
const sigLines = (0, import_fs3.readFileSync)(sigsPath, "utf-8").split("\n").filter((l) => l.length > 0);
|
|
2964
|
+
const pubkey = opts.publicKey ?? manifest.producer.public_key;
|
|
2965
|
+
if (!pubkey) {
|
|
2966
|
+
throw new Error("MemoryPack: signatures.jsonl present but no public_key in manifest");
|
|
2967
|
+
}
|
|
2968
|
+
const validSigHashes = /* @__PURE__ */ new Set();
|
|
2969
|
+
for (const line of sigLines) {
|
|
2970
|
+
const sig = JSON.parse(line);
|
|
2971
|
+
const ok = verifyHash(sig.record_hash, sig.signature, pubkey);
|
|
2972
|
+
if (!ok) {
|
|
2973
|
+
throw new Error(`MemoryPack: signature verification failed for ${sig.record_hash}`);
|
|
2974
|
+
}
|
|
2975
|
+
validSigHashes.add(sig.record_hash);
|
|
2976
|
+
}
|
|
2977
|
+
for (const recordHash of lineByHash.keys()) {
|
|
2978
|
+
if (!validSigHashes.has(recordHash)) {
|
|
2979
|
+
throw new Error(
|
|
2980
|
+
`MemoryPack: signature verification failed \u2014 record ${recordHash} has no matching signature`
|
|
2981
|
+
);
|
|
2982
|
+
}
|
|
2983
|
+
verifiedRecords.add(recordHash);
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
const unsignedRecords = /* @__PURE__ */ new Set();
|
|
2987
|
+
if (!signaturesFilePresent) {
|
|
2988
|
+
for (const hash of lineByHash.keys()) unsignedRecords.add(hash);
|
|
2989
|
+
}
|
|
2990
|
+
if (opts.strictSignatures && unsignedRecords.size > 0) {
|
|
2991
|
+
throw new Error(
|
|
2992
|
+
`MemoryPack: strictSignatures=true but ${unsignedRecords.size} records are unsigned`
|
|
2993
|
+
);
|
|
2994
|
+
}
|
|
2995
|
+
const anchors = [];
|
|
2996
|
+
const anchorsPath = (0, import_path4.join)(dir, "anchors.jsonl");
|
|
2997
|
+
if ((0, import_fs3.existsSync)(anchorsPath)) {
|
|
2998
|
+
const anchorLines = (0, import_fs3.readFileSync)(anchorsPath, "utf-8").split("\n").filter((l) => l.length > 0);
|
|
2999
|
+
for (const line of anchorLines) {
|
|
3000
|
+
anchors.push(JSON.parse(line));
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
return { manifest, records, verifiedRecords, unsignedRecords, anchors, warnings };
|
|
3004
|
+
}
|
|
3005
|
+
var import_fs3, import_path4;
|
|
3006
|
+
var init_reader = __esm({
|
|
3007
|
+
"packages/brain/src/memorypack/reader.ts"() {
|
|
3008
|
+
"use strict";
|
|
3009
|
+
import_fs3 = require("fs");
|
|
3010
|
+
import_path4 = require("path");
|
|
3011
|
+
init_sign();
|
|
3012
|
+
}
|
|
3013
|
+
});
|
|
3014
|
+
|
|
3015
|
+
// packages/brain/src/memorypack/index.ts
|
|
3016
|
+
var init_memorypack = __esm({
|
|
3017
|
+
"packages/brain/src/memorypack/index.ts"() {
|
|
3018
|
+
"use strict";
|
|
3019
|
+
init_types();
|
|
3020
|
+
init_writer();
|
|
3021
|
+
init_reader();
|
|
3022
|
+
init_sign();
|
|
3023
|
+
}
|
|
3024
|
+
});
|
|
3025
|
+
|
|
2800
3026
|
// packages/brain/src/mcp/local-store.ts
|
|
2801
3027
|
var local_store_exports = {};
|
|
2802
3028
|
__export(local_store_exports, {
|
|
@@ -2809,22 +3035,22 @@ __export(local_store_exports, {
|
|
|
2809
3035
|
localUpdate: () => localUpdate
|
|
2810
3036
|
});
|
|
2811
3037
|
function ensureDir() {
|
|
2812
|
-
if (!(0,
|
|
2813
|
-
(0,
|
|
3038
|
+
if (!(0, import_fs4.existsSync)(CLUDE_DIR2)) {
|
|
3039
|
+
(0, import_fs4.mkdirSync)(CLUDE_DIR2, { recursive: true });
|
|
2814
3040
|
}
|
|
2815
3041
|
}
|
|
2816
3042
|
function loadStore() {
|
|
2817
3043
|
ensureDir();
|
|
2818
|
-
if (!(0,
|
|
3044
|
+
if (!(0, import_fs4.existsSync)(MEMORIES_FILE2)) {
|
|
2819
3045
|
return { version: 1, next_id: 1, memories: [] };
|
|
2820
3046
|
}
|
|
2821
3047
|
try {
|
|
2822
|
-
const raw = (0,
|
|
3048
|
+
const raw = (0, import_fs4.readFileSync)(MEMORIES_FILE2, "utf-8");
|
|
2823
3049
|
const data = JSON.parse(raw);
|
|
2824
3050
|
if (!data || !Array.isArray(data.memories)) {
|
|
2825
3051
|
console.error("[clude-local] Warning: memories.json has invalid structure, starting fresh. Backup saved.");
|
|
2826
3052
|
try {
|
|
2827
|
-
(0,
|
|
3053
|
+
(0, import_fs4.writeFileSync)(MEMORIES_FILE2 + ".bak", raw);
|
|
2828
3054
|
} catch {
|
|
2829
3055
|
}
|
|
2830
3056
|
return { version: 1, next_id: 1, memories: [] };
|
|
@@ -2833,8 +3059,8 @@ function loadStore() {
|
|
|
2833
3059
|
} catch (err) {
|
|
2834
3060
|
console.error("[clude-local] Warning: failed to parse memories.json:", err.message);
|
|
2835
3061
|
try {
|
|
2836
|
-
const raw = (0,
|
|
2837
|
-
(0,
|
|
3062
|
+
const raw = (0, import_fs4.readFileSync)(MEMORIES_FILE2, "utf-8");
|
|
3063
|
+
(0, import_fs4.writeFileSync)(MEMORIES_FILE2 + ".bak", raw);
|
|
2838
3064
|
console.error("[clude-local] Backup saved to memories.json.bak");
|
|
2839
3065
|
} catch {
|
|
2840
3066
|
}
|
|
@@ -2844,8 +3070,8 @@ function loadStore() {
|
|
|
2844
3070
|
function saveStore(store) {
|
|
2845
3071
|
ensureDir();
|
|
2846
3072
|
const tmpFile = MEMORIES_FILE2 + ".tmp";
|
|
2847
|
-
(0,
|
|
2848
|
-
(0,
|
|
3073
|
+
(0, import_fs4.writeFileSync)(tmpFile, JSON.stringify(store, null, 2));
|
|
3074
|
+
(0, import_fs4.renameSync)(tmpFile, MEMORIES_FILE2);
|
|
2849
3075
|
}
|
|
2850
3076
|
function scoreRelevance(query, memory) {
|
|
2851
3077
|
const queryTerms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 2);
|
|
@@ -3031,14 +3257,14 @@ function localList(opts) {
|
|
|
3031
3257
|
const start = (page - 1) * pageSize;
|
|
3032
3258
|
return { memories: memories.slice(start, start + pageSize), total };
|
|
3033
3259
|
}
|
|
3034
|
-
var
|
|
3260
|
+
var import_fs4, import_path5, CLUDE_DIR2, MEMORIES_FILE2;
|
|
3035
3261
|
var init_local_store = __esm({
|
|
3036
3262
|
"packages/brain/src/mcp/local-store.ts"() {
|
|
3037
3263
|
"use strict";
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
CLUDE_DIR2 = (0,
|
|
3041
|
-
MEMORIES_FILE2 = (0,
|
|
3264
|
+
import_fs4 = require("fs");
|
|
3265
|
+
import_path5 = require("path");
|
|
3266
|
+
CLUDE_DIR2 = (0, import_path5.join)(process.env.HOME || process.env.USERPROFILE || ".", ".clude");
|
|
3267
|
+
MEMORIES_FILE2 = (0, import_path5.join)(CLUDE_DIR2, "memories.json");
|
|
3042
3268
|
}
|
|
3043
3269
|
});
|
|
3044
3270
|
|
|
@@ -3679,11 +3905,12 @@ var init_text = __esm({
|
|
|
3679
3905
|
});
|
|
3680
3906
|
|
|
3681
3907
|
// packages/shared/src/utils/constants.ts
|
|
3682
|
-
var MEMO_PROGRAM_ID, BOT_X_HANDLE, MEMORY_MIN_DECAY, MEMORY_MAX_CONTENT_LENGTH, MEMORY_MAX_SUMMARY_LENGTH, DECAY_RATES, RECENCY_DECAY_BASE, RETRIEVAL_WEIGHT_RECENCY, RETRIEVAL_WEIGHT_RELEVANCE, RETRIEVAL_WEIGHT_IMPORTANCE, RETRIEVAL_WEIGHT_VECTOR, KNOWLEDGE_TYPE_BOOST, VECTOR_MATCH_THRESHOLD, BOND_TYPE_WEIGHTS, RETRIEVAL_WEIGHT_GRAPH, RETRIEVAL_WEIGHT_COOCCURRENCE, LINK_SIMILARITY_THRESHOLD, MAX_AUTO_LINKS, LINK_CO_RETRIEVAL_BOOST, INTERNAL_MEMORY_SOURCES, INTERNAL_IMPORTANCE_BOOST, REFLECTION_MIN_INTERVAL_MS, WHALE_SELL_COOLDOWN_MS, MEMO_MAX_LENGTH;
|
|
3908
|
+
var MEMO_PROGRAM_ID, SOLSCAN_TX_BASE_URL, BOT_X_HANDLE, MEMORY_MIN_DECAY, MEMORY_MAX_CONTENT_LENGTH, MEMORY_MAX_SUMMARY_LENGTH, DECAY_RATES, RECENCY_DECAY_BASE, RETRIEVAL_WEIGHT_RECENCY, RETRIEVAL_WEIGHT_RELEVANCE, RETRIEVAL_WEIGHT_IMPORTANCE, RETRIEVAL_WEIGHT_VECTOR, KNOWLEDGE_TYPE_BOOST, VECTOR_MATCH_THRESHOLD, BOND_TYPE_WEIGHTS, RETRIEVAL_WEIGHT_GRAPH, RETRIEVAL_WEIGHT_COOCCURRENCE, LINK_SIMILARITY_THRESHOLD, MAX_AUTO_LINKS, LINK_CO_RETRIEVAL_BOOST, INTERNAL_MEMORY_SOURCES, INTERNAL_IMPORTANCE_BOOST, REFLECTION_MIN_INTERVAL_MS, WHALE_SELL_COOLDOWN_MS, MEMO_MAX_LENGTH;
|
|
3683
3909
|
var init_constants = __esm({
|
|
3684
3910
|
"packages/shared/src/utils/constants.ts"() {
|
|
3685
3911
|
"use strict";
|
|
3686
3912
|
MEMO_PROGRAM_ID = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
|
|
3913
|
+
SOLSCAN_TX_BASE_URL = "https://solscan.io/tx";
|
|
3687
3914
|
BOT_X_HANDLE = process.env.BOT_X_HANDLE || "cludebot";
|
|
3688
3915
|
MEMORY_MIN_DECAY = 0.05;
|
|
3689
3916
|
MEMORY_MAX_CONTENT_LENGTH = 5e3;
|
|
@@ -3990,12 +4217,46 @@ var init_claude_client = __esm({
|
|
|
3990
4217
|
});
|
|
3991
4218
|
|
|
3992
4219
|
// packages/shared/src/core/solana-client.ts
|
|
4220
|
+
var solana_client_exports = {};
|
|
4221
|
+
__export(solana_client_exports, {
|
|
4222
|
+
_configureMemoryRegistry: () => _configureMemoryRegistry,
|
|
4223
|
+
_configureSolana: () => _configureSolana,
|
|
4224
|
+
getBotWallet: () => getBotWallet,
|
|
4225
|
+
getConnection: () => getConnection,
|
|
4226
|
+
initializeRegistry: () => initializeRegistry,
|
|
4227
|
+
isRegistryEnabled: () => isRegistryEnabled,
|
|
4228
|
+
parseMemoContentHash: () => parseMemoContentHash,
|
|
4229
|
+
registerMemoryOnChain: () => registerMemoryOnChain,
|
|
4230
|
+
solscanTxUrl: () => solscanTxUrl,
|
|
4231
|
+
verifyMemoTransaction: () => verifyMemoTransaction,
|
|
4232
|
+
verifyMemoryOnChain: () => verifyMemoryOnChain,
|
|
4233
|
+
verifySignature: () => verifySignature,
|
|
4234
|
+
writeMemo: () => writeMemo,
|
|
4235
|
+
writeMemoDevnet: () => writeMemoDevnet
|
|
4236
|
+
});
|
|
3993
4237
|
function getConnection() {
|
|
3994
4238
|
if (!connection) {
|
|
3995
4239
|
connection = new import_web3.Connection(config.solana.rpcUrl, "confirmed");
|
|
3996
4240
|
}
|
|
3997
4241
|
return connection;
|
|
3998
4242
|
}
|
|
4243
|
+
function _configureSolana(rpcUrl, privateKey) {
|
|
4244
|
+
connection = new import_web3.Connection(rpcUrl, "confirmed");
|
|
4245
|
+
if (privateKey) {
|
|
4246
|
+
try {
|
|
4247
|
+
const raw = privateKey.trim();
|
|
4248
|
+
let secretKey;
|
|
4249
|
+
if (raw.startsWith("[")) {
|
|
4250
|
+
secretKey = Uint8Array.from(JSON.parse(raw));
|
|
4251
|
+
} else {
|
|
4252
|
+
secretKey = bs582.decode(raw);
|
|
4253
|
+
}
|
|
4254
|
+
botWallet = import_web3.Keypair.fromSecretKey(secretKey);
|
|
4255
|
+
} catch (err) {
|
|
4256
|
+
log6.error({ err }, "SDK: Failed to load bot wallet");
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
3999
4260
|
function getBotWallet() {
|
|
4000
4261
|
if (!botWallet && config.solana.botWalletPrivateKey) {
|
|
4001
4262
|
try {
|
|
@@ -4004,7 +4265,7 @@ function getBotWallet() {
|
|
|
4004
4265
|
if (raw.startsWith("[")) {
|
|
4005
4266
|
secretKey = Uint8Array.from(JSON.parse(raw));
|
|
4006
4267
|
} else {
|
|
4007
|
-
secretKey =
|
|
4268
|
+
secretKey = bs582.decode(raw);
|
|
4008
4269
|
}
|
|
4009
4270
|
botWallet = import_web3.Keypair.fromSecretKey(secretKey);
|
|
4010
4271
|
log6.info({ publicKey: botWallet.publicKey.toBase58() }, "Bot wallet loaded");
|
|
@@ -4037,6 +4298,50 @@ async function writeMemo(memo) {
|
|
|
4037
4298
|
return null;
|
|
4038
4299
|
}
|
|
4039
4300
|
}
|
|
4301
|
+
function getDevnetConnection() {
|
|
4302
|
+
if (!devnetConnection) {
|
|
4303
|
+
devnetConnection = new import_web3.Connection("https://api.devnet.solana.com", "confirmed");
|
|
4304
|
+
}
|
|
4305
|
+
return devnetConnection;
|
|
4306
|
+
}
|
|
4307
|
+
async function writeMemoDevnet(memo) {
|
|
4308
|
+
const wallet = getBotWallet();
|
|
4309
|
+
if (!wallet) {
|
|
4310
|
+
log6.error("No bot wallet configured, cannot write devnet memo");
|
|
4311
|
+
return null;
|
|
4312
|
+
}
|
|
4313
|
+
const conn = getDevnetConnection();
|
|
4314
|
+
const truncatedMemo = memo.slice(0, MEMO_MAX_LENGTH);
|
|
4315
|
+
const instruction = new import_web3.TransactionInstruction({
|
|
4316
|
+
keys: [{ pubkey: wallet.publicKey, isSigner: true, isWritable: true }],
|
|
4317
|
+
programId: MEMO_PROGRAM_ID2,
|
|
4318
|
+
data: Buffer.from(truncatedMemo, "utf-8")
|
|
4319
|
+
});
|
|
4320
|
+
const transaction = new import_web3.Transaction().add(instruction);
|
|
4321
|
+
try {
|
|
4322
|
+
const signature = await (0, import_web3.sendAndConfirmTransaction)(conn, transaction, [wallet]);
|
|
4323
|
+
log6.info({ signature, memoLength: truncatedMemo.length }, "Memo written on devnet");
|
|
4324
|
+
return signature;
|
|
4325
|
+
} catch (err) {
|
|
4326
|
+
log6.error({ err }, "Failed to write devnet memo");
|
|
4327
|
+
return null;
|
|
4328
|
+
}
|
|
4329
|
+
}
|
|
4330
|
+
function verifySignature(message, signature, publicKey) {
|
|
4331
|
+
const messageBytes = new TextEncoder().encode(message);
|
|
4332
|
+
return import_tweetnacl2.default.sign.detached.verify(messageBytes, signature, publicKey);
|
|
4333
|
+
}
|
|
4334
|
+
function solscanTxUrl(signature) {
|
|
4335
|
+
return `${SOLSCAN_TX_BASE_URL}/${signature}`;
|
|
4336
|
+
}
|
|
4337
|
+
function _configureMemoryRegistry(programId) {
|
|
4338
|
+
try {
|
|
4339
|
+
registryProgramId = new import_web3.PublicKey(programId);
|
|
4340
|
+
log6.info({ programId: programId.slice(0, 12) + "..." }, "Memory registry program configured");
|
|
4341
|
+
} catch (err) {
|
|
4342
|
+
log6.error({ err }, "Invalid memory registry program ID");
|
|
4343
|
+
}
|
|
4344
|
+
}
|
|
4040
4345
|
function isRegistryEnabled() {
|
|
4041
4346
|
return registryProgramId !== null;
|
|
4042
4347
|
}
|
|
@@ -4048,10 +4353,42 @@ function deriveRegistryPDA(authority) {
|
|
|
4048
4353
|
);
|
|
4049
4354
|
}
|
|
4050
4355
|
function anchorDiscriminator(name) {
|
|
4051
|
-
const { createHash:
|
|
4052
|
-
const hash =
|
|
4356
|
+
const { createHash: createHash4 } = require("crypto");
|
|
4357
|
+
const hash = createHash4("sha256").update(`global:${name}`).digest();
|
|
4053
4358
|
return hash.subarray(0, 8);
|
|
4054
4359
|
}
|
|
4360
|
+
async function initializeRegistry() {
|
|
4361
|
+
if (registryInitialized) return;
|
|
4362
|
+
const wallet = getBotWallet();
|
|
4363
|
+
if (!wallet || !registryProgramId) return;
|
|
4364
|
+
const conn = getConnection();
|
|
4365
|
+
const [registryPDA] = deriveRegistryPDA(wallet.publicKey);
|
|
4366
|
+
const accountInfo = await conn.getAccountInfo(registryPDA);
|
|
4367
|
+
if (accountInfo) {
|
|
4368
|
+
registryInitialized = true;
|
|
4369
|
+
log6.info({ registry: registryPDA.toBase58() }, "Registry PDA already exists");
|
|
4370
|
+
return;
|
|
4371
|
+
}
|
|
4372
|
+
const discriminator = anchorDiscriminator("initialize");
|
|
4373
|
+
const instruction = new import_web3.TransactionInstruction({
|
|
4374
|
+
keys: [
|
|
4375
|
+
{ pubkey: registryPDA, isSigner: false, isWritable: true },
|
|
4376
|
+
{ pubkey: wallet.publicKey, isSigner: true, isWritable: true },
|
|
4377
|
+
{ pubkey: import_web3.SystemProgram.programId, isSigner: false, isWritable: false }
|
|
4378
|
+
],
|
|
4379
|
+
programId: registryProgramId,
|
|
4380
|
+
data: discriminator
|
|
4381
|
+
});
|
|
4382
|
+
const transaction = new import_web3.Transaction().add(instruction);
|
|
4383
|
+
try {
|
|
4384
|
+
const signature = await (0, import_web3.sendAndConfirmTransaction)(conn, transaction, [wallet]);
|
|
4385
|
+
registryInitialized = true;
|
|
4386
|
+
log6.info({ signature, registry: registryPDA.toBase58() }, "Registry PDA initialized on-chain");
|
|
4387
|
+
} catch (err) {
|
|
4388
|
+
log6.error({ err }, "Failed to initialize registry PDA");
|
|
4389
|
+
throw err;
|
|
4390
|
+
}
|
|
4391
|
+
}
|
|
4055
4392
|
function memoryTypeToU8(type) {
|
|
4056
4393
|
switch (type) {
|
|
4057
4394
|
case "episodic":
|
|
@@ -4103,21 +4440,82 @@ async function registerMemoryOnChain(contentHash, memoryType, importance, memory
|
|
|
4103
4440
|
return null;
|
|
4104
4441
|
}
|
|
4105
4442
|
}
|
|
4106
|
-
|
|
4443
|
+
async function verifyMemoryOnChain(contentHash, authority) {
|
|
4444
|
+
const wallet = getBotWallet();
|
|
4445
|
+
const authPubkey = authority || wallet?.publicKey;
|
|
4446
|
+
if (!authPubkey || !registryProgramId) return false;
|
|
4447
|
+
const conn = getConnection();
|
|
4448
|
+
const [registryPDA] = deriveRegistryPDA(authPubkey);
|
|
4449
|
+
try {
|
|
4450
|
+
const accountInfo = await conn.getAccountInfo(registryPDA);
|
|
4451
|
+
if (!accountInfo || !accountInfo.data) return false;
|
|
4452
|
+
const data = accountInfo.data;
|
|
4453
|
+
if (data.length < 53) return false;
|
|
4454
|
+
const vecLen = data.readUInt32LE(49);
|
|
4455
|
+
const ENTRY_SIZE = 56;
|
|
4456
|
+
const entriesStart = 53;
|
|
4457
|
+
for (let i = 0; i < vecLen; i++) {
|
|
4458
|
+
const offset = entriesStart + i * ENTRY_SIZE;
|
|
4459
|
+
if (offset + 32 > data.length) break;
|
|
4460
|
+
const hash = data.subarray(offset, offset + 32);
|
|
4461
|
+
if (contentHash.equals(hash)) return true;
|
|
4462
|
+
}
|
|
4463
|
+
return false;
|
|
4464
|
+
} catch (err) {
|
|
4465
|
+
log6.warn({ err }, "Failed to verify memory on-chain");
|
|
4466
|
+
return false;
|
|
4467
|
+
}
|
|
4468
|
+
}
|
|
4469
|
+
function parseMemoContentHash(memo) {
|
|
4470
|
+
if (!memo.startsWith("clude-memory |")) return null;
|
|
4471
|
+
const v2Match = memo.match(/^clude-memory \| v2 \| ([a-f0-9]{64})$/);
|
|
4472
|
+
if (v2Match) return v2Match[1];
|
|
4473
|
+
const v1Match = memo.match(/^clude-memory \| id: \d+ \| type: \w+ \| hash: ([a-f0-9]{16}) \|/);
|
|
4474
|
+
if (v1Match) return v1Match[1];
|
|
4475
|
+
return null;
|
|
4476
|
+
}
|
|
4477
|
+
async function verifyMemoTransaction(signature, contentHash) {
|
|
4478
|
+
const conn = getConnection();
|
|
4479
|
+
try {
|
|
4480
|
+
const tx = await conn.getTransaction(signature, { maxSupportedTransactionVersion: 0 });
|
|
4481
|
+
if (!tx?.meta || !tx.transaction.message) return false;
|
|
4482
|
+
const memoProgram = MEMO_PROGRAM_ID2.toBase58();
|
|
4483
|
+
const message = tx.transaction.message;
|
|
4484
|
+
const accountKeys = message.staticAccountKeys?.map((k) => k.toBase58()) ?? [];
|
|
4485
|
+
const compiledIxs = message.compiledInstructions;
|
|
4486
|
+
for (const ix of compiledIxs) {
|
|
4487
|
+
if (accountKeys[ix.programIdIndex] !== memoProgram) continue;
|
|
4488
|
+
const memoStr = Buffer.from(ix.data).toString("utf-8");
|
|
4489
|
+
const parsedHash = parseMemoContentHash(memoStr);
|
|
4490
|
+
if (!parsedHash) continue;
|
|
4491
|
+
const contentHashHex = contentHash.toString("hex");
|
|
4492
|
+
if (parsedHash.length === 64) {
|
|
4493
|
+
return parsedHash === contentHashHex;
|
|
4494
|
+
}
|
|
4495
|
+
return contentHashHex.startsWith(parsedHash);
|
|
4496
|
+
}
|
|
4497
|
+
return false;
|
|
4498
|
+
} catch (err) {
|
|
4499
|
+
log6.warn({ err, signature: signature.slice(0, 16) }, "Failed to verify memo transaction");
|
|
4500
|
+
return false;
|
|
4501
|
+
}
|
|
4502
|
+
}
|
|
4503
|
+
var import_web3, bs58Module2, import_tweetnacl2, bs582, log6, connection, botWallet, MEMO_PROGRAM_ID2, devnetConnection, registryProgramId, registryInitialized;
|
|
4107
4504
|
var init_solana_client = __esm({
|
|
4108
4505
|
"packages/shared/src/core/solana-client.ts"() {
|
|
4109
4506
|
"use strict";
|
|
4110
4507
|
import_web3 = require("@solana/web3.js");
|
|
4111
|
-
|
|
4508
|
+
bs58Module2 = __toESM(require("bs58"));
|
|
4112
4509
|
init_config();
|
|
4113
4510
|
init_logger();
|
|
4114
|
-
|
|
4511
|
+
import_tweetnacl2 = __toESM(require("tweetnacl"));
|
|
4115
4512
|
init_constants();
|
|
4116
|
-
|
|
4513
|
+
bs582 = bs58Module2.default || bs58Module2;
|
|
4117
4514
|
log6 = createChildLogger("solana-client");
|
|
4118
4515
|
botWallet = null;
|
|
4119
4516
|
MEMO_PROGRAM_ID2 = new import_web3.PublicKey(MEMO_PROGRAM_ID);
|
|
4120
4517
|
registryProgramId = null;
|
|
4518
|
+
registryInitialized = false;
|
|
4121
4519
|
}
|
|
4122
4520
|
});
|
|
4123
4521
|
|
|
@@ -4391,9 +4789,9 @@ function encryptContent(plaintext) {
|
|
|
4391
4789
|
if (!encryptionKey) {
|
|
4392
4790
|
throw new Error("Encryption not configured. Call configureEncryption() first.");
|
|
4393
4791
|
}
|
|
4394
|
-
const nonce =
|
|
4792
|
+
const nonce = import_tweetnacl3.default.randomBytes(NONCE_LENGTH);
|
|
4395
4793
|
const messageBytes = new TextEncoder().encode(plaintext);
|
|
4396
|
-
const ciphertext =
|
|
4794
|
+
const ciphertext = import_tweetnacl3.default.secretbox(messageBytes, nonce, encryptionKey);
|
|
4397
4795
|
const combined = new Uint8Array(NONCE_LENGTH + ciphertext.length);
|
|
4398
4796
|
combined.set(nonce, 0);
|
|
4399
4797
|
combined.set(ciphertext, NONCE_LENGTH);
|
|
@@ -4410,7 +4808,7 @@ function decryptContent(encrypted) {
|
|
|
4410
4808
|
}
|
|
4411
4809
|
const nonce = combined.subarray(0, NONCE_LENGTH);
|
|
4412
4810
|
const ciphertext = combined.subarray(NONCE_LENGTH);
|
|
4413
|
-
const plaintext =
|
|
4811
|
+
const plaintext = import_tweetnacl3.default.secretbox.open(ciphertext, nonce, encryptionKey);
|
|
4414
4812
|
if (!plaintext) {
|
|
4415
4813
|
return null;
|
|
4416
4814
|
}
|
|
@@ -4436,17 +4834,17 @@ function decryptMemoryBatch(memories) {
|
|
|
4436
4834
|
}
|
|
4437
4835
|
return memories;
|
|
4438
4836
|
}
|
|
4439
|
-
var
|
|
4837
|
+
var import_tweetnacl3, import_crypto2, import_util, log9, hkdfAsync, NONCE_LENGTH, encryptionKey, encryptionPubkey;
|
|
4440
4838
|
var init_encryption = __esm({
|
|
4441
4839
|
"packages/shared/src/core/encryption.ts"() {
|
|
4442
4840
|
"use strict";
|
|
4443
|
-
|
|
4444
|
-
|
|
4841
|
+
import_tweetnacl3 = __toESM(require("tweetnacl"));
|
|
4842
|
+
import_crypto2 = require("crypto");
|
|
4445
4843
|
import_util = require("util");
|
|
4446
4844
|
init_logger();
|
|
4447
4845
|
log9 = createChildLogger("encryption");
|
|
4448
|
-
hkdfAsync = (0, import_util.promisify)(
|
|
4449
|
-
NONCE_LENGTH =
|
|
4846
|
+
hkdfAsync = (0, import_util.promisify)(import_crypto2.hkdf);
|
|
4847
|
+
NONCE_LENGTH = import_tweetnacl3.default.secretbox.nonceLength;
|
|
4450
4848
|
encryptionKey = null;
|
|
4451
4849
|
encryptionPubkey = null;
|
|
4452
4850
|
}
|
|
@@ -4787,7 +5185,7 @@ function scopeToOwner(query) {
|
|
|
4787
5185
|
return query;
|
|
4788
5186
|
}
|
|
4789
5187
|
function generateHashId() {
|
|
4790
|
-
return `${HASH_ID_PREFIX}-${(0,
|
|
5188
|
+
return `${HASH_ID_PREFIX}-${(0, import_crypto3.randomBytes)(4).toString("hex")}`;
|
|
4791
5189
|
}
|
|
4792
5190
|
function isValidHashId(id) {
|
|
4793
5191
|
return /^clude-[a-f0-9]{8}$/.test(id);
|
|
@@ -4899,7 +5297,7 @@ async function storeMemory(opts) {
|
|
|
4899
5297
|
}
|
|
4900
5298
|
async function commitMemoryToChain(memoryId, opts) {
|
|
4901
5299
|
if (opts.source === "demo" || opts.source === "demo-maas" || opts.source === "locomo-benchmark" || opts.source === "longmemeval-benchmark") return;
|
|
4902
|
-
const contentHashBuf = (0,
|
|
5300
|
+
const contentHashBuf = (0, import_crypto3.createHash)("sha256").update(opts.content).digest();
|
|
4903
5301
|
let signature = null;
|
|
4904
5302
|
if (isRegistryEnabled()) {
|
|
4905
5303
|
const encrypted = isEncryptionEnabled();
|
|
@@ -4913,7 +5311,7 @@ async function commitMemoryToChain(memoryId, opts) {
|
|
|
4913
5311
|
}
|
|
4914
5312
|
if (!signature) {
|
|
4915
5313
|
const contentHashHex = contentHashBuf.toString("hex");
|
|
4916
|
-
const memo = `clude
|
|
5314
|
+
const memo = `clude:v1:sha256:${contentHashHex}`;
|
|
4917
5315
|
signature = await writeMemo(memo);
|
|
4918
5316
|
}
|
|
4919
5317
|
if (!signature) return;
|
|
@@ -5865,7 +6263,7 @@ function moodToValence(mood) {
|
|
|
5865
6263
|
return 0;
|
|
5866
6264
|
}
|
|
5867
6265
|
}
|
|
5868
|
-
var
|
|
6266
|
+
var import_crypto3, EMBED_CACHE_MAX, embeddingCache, _ownerWallet, SCOPE_BOT_OWN, HASH_ID_PREFIX, log11, DEDUP_TTL_MS, dedupCache, STOPWORDS;
|
|
5869
6267
|
var init_memory = __esm({
|
|
5870
6268
|
"packages/brain/src/memory/memory.ts"() {
|
|
5871
6269
|
"use strict";
|
|
@@ -5880,7 +6278,7 @@ var init_memory = __esm({
|
|
|
5880
6278
|
init_openrouter_client();
|
|
5881
6279
|
init_encryption();
|
|
5882
6280
|
init_event_bus();
|
|
5883
|
-
|
|
6281
|
+
import_crypto3 = require("crypto");
|
|
5884
6282
|
init_graph();
|
|
5885
6283
|
init_owner_context();
|
|
5886
6284
|
EMBED_CACHE_MAX = 200;
|
|
@@ -6179,7 +6577,8 @@ async function runExport() {
|
|
|
6179
6577
|
-h, --help Show this help
|
|
6180
6578
|
|
|
6181
6579
|
${c.bold}Formats:${c.reset}
|
|
6182
|
-
${c.cyan}json${c.reset}
|
|
6580
|
+
${c.cyan}json${c.reset} Legacy single-file JSON (default)
|
|
6581
|
+
${c.cyan}memorypack${c.reset} MemoryPack v0.1 spec directory (manifest + records.jsonl + sigs)
|
|
6183
6582
|
${c.cyan}md${c.reset} Clean Markdown
|
|
6184
6583
|
${c.cyan}chatgpt${c.reset} System prompt for ChatGPT Custom Instructions
|
|
6185
6584
|
${c.cyan}gemini${c.reset} System prompt for Gemini Gems
|
|
@@ -6199,7 +6598,7 @@ async function runExport() {
|
|
|
6199
6598
|
const output = getFlag(args, "--output") || getFlag(args, "-o");
|
|
6200
6599
|
const typesRaw = getFlag(args, "--types");
|
|
6201
6600
|
const types = typesRaw ? typesRaw.split(",").map((t) => t.trim()) : void 0;
|
|
6202
|
-
const validFormats = ["json", "md", "chatgpt", "gemini", "clipboard"];
|
|
6601
|
+
const validFormats = ["json", "md", "chatgpt", "gemini", "clipboard", "memorypack"];
|
|
6203
6602
|
if (!validFormats.includes(format)) {
|
|
6204
6603
|
printError(`Format must be one of: ${validFormats.join(", ")}`);
|
|
6205
6604
|
process.exit(1);
|
|
@@ -6346,6 +6745,63 @@ async function runExport() {
|
|
|
6346
6745
|
} else if (format === "md") {
|
|
6347
6746
|
content = formatMarkdown(memories);
|
|
6348
6747
|
defaultName = "clude-memories.md";
|
|
6748
|
+
} else if (format === "memorypack") {
|
|
6749
|
+
const outputDir = output || "clude-memorypack";
|
|
6750
|
+
const records = memories.map((m, i) => {
|
|
6751
|
+
const id = m.id ? String(m.id) : String(i + 1);
|
|
6752
|
+
const kind = m.type || m.memory_type || "episodic";
|
|
6753
|
+
const rec = {
|
|
6754
|
+
id,
|
|
6755
|
+
created_at: m.created_at || (/* @__PURE__ */ new Date()).toISOString(),
|
|
6756
|
+
kind,
|
|
6757
|
+
content: m.content || "",
|
|
6758
|
+
tags: m.tags || [],
|
|
6759
|
+
importance: typeof m.importance === "number" ? m.importance : 0.5,
|
|
6760
|
+
source: m.source || ""
|
|
6761
|
+
};
|
|
6762
|
+
if (m.summary) rec.summary = m.summary;
|
|
6763
|
+
if (m.access_count != null) rec.access_count = m.access_count;
|
|
6764
|
+
if (m.last_accessed_at) rec.last_accessed_at = m.last_accessed_at;
|
|
6765
|
+
return rec;
|
|
6766
|
+
});
|
|
6767
|
+
let secretKey;
|
|
6768
|
+
let publicKey;
|
|
6769
|
+
try {
|
|
6770
|
+
const { getBotWallet: getBotWallet2 } = (init_solana_client(), __toCommonJS(solana_client_exports));
|
|
6771
|
+
const wallet = getBotWallet2();
|
|
6772
|
+
if (wallet) {
|
|
6773
|
+
secretKey = wallet.secretKey;
|
|
6774
|
+
publicKey = wallet.publicKey.toBase58();
|
|
6775
|
+
}
|
|
6776
|
+
} catch {
|
|
6777
|
+
}
|
|
6778
|
+
writeMemoryPack(outputDir, records, {
|
|
6779
|
+
producer: {
|
|
6780
|
+
name: "clude",
|
|
6781
|
+
version: "3.0.3",
|
|
6782
|
+
agent_id: config3?.agent?.id,
|
|
6783
|
+
public_key: publicKey
|
|
6784
|
+
},
|
|
6785
|
+
record_schema: "clude-memory-v3",
|
|
6786
|
+
secretKey,
|
|
6787
|
+
anchor_chain: "solana-mainnet"
|
|
6788
|
+
});
|
|
6789
|
+
printSuccess(
|
|
6790
|
+
`MemoryPack written to ${outputDir}/ (${records.length} records${secretKey ? ", signed" : ", UNSIGNED"})`
|
|
6791
|
+
);
|
|
6792
|
+
if (!secretKey) {
|
|
6793
|
+
console.log(
|
|
6794
|
+
`
|
|
6795
|
+
${c.dim}No wallet configured \u2014 pack is unsigned. Set CLUDE_WALLET_SECRET to sign.${c.reset}`
|
|
6796
|
+
);
|
|
6797
|
+
}
|
|
6798
|
+
console.log(
|
|
6799
|
+
`
|
|
6800
|
+
${c.dim}Contents: manifest.json, records.jsonl${secretKey ? ", signatures.jsonl" : ""}${c.reset}`
|
|
6801
|
+
);
|
|
6802
|
+
printDivider();
|
|
6803
|
+
console.log("");
|
|
6804
|
+
return;
|
|
6349
6805
|
} else {
|
|
6350
6806
|
defaultName = "clude-memories.json";
|
|
6351
6807
|
const pack = {
|
|
@@ -6374,7 +6830,7 @@ async function runExport() {
|
|
|
6374
6830
|
content = JSON.stringify(pack, null, 2);
|
|
6375
6831
|
}
|
|
6376
6832
|
const filename = output || defaultName;
|
|
6377
|
-
(0,
|
|
6833
|
+
(0, import_fs5.writeFileSync)(filename, content, "utf-8");
|
|
6378
6834
|
printSuccess(`Written to ${filename} (${formatBytes(Buffer.byteLength(content))})`);
|
|
6379
6835
|
if (format === "chatgpt") {
|
|
6380
6836
|
console.log(`
|
|
@@ -6389,12 +6845,13 @@ async function runExport() {
|
|
|
6389
6845
|
printDivider();
|
|
6390
6846
|
console.log("");
|
|
6391
6847
|
}
|
|
6392
|
-
var
|
|
6848
|
+
var import_fs5;
|
|
6393
6849
|
var init_export = __esm({
|
|
6394
6850
|
"packages/brain/src/cli/export.ts"() {
|
|
6395
6851
|
"use strict";
|
|
6396
|
-
|
|
6852
|
+
import_fs5 = require("fs");
|
|
6397
6853
|
init_banner();
|
|
6854
|
+
init_memorypack();
|
|
6398
6855
|
}
|
|
6399
6856
|
});
|
|
6400
6857
|
|
|
@@ -6406,9 +6863,35 @@ __export(import_exports, {
|
|
|
6406
6863
|
function hasFlag2(args, flag) {
|
|
6407
6864
|
return args.includes(flag);
|
|
6408
6865
|
}
|
|
6866
|
+
function isMemoryPackDir(path8) {
|
|
6867
|
+
try {
|
|
6868
|
+
return (0, import_fs6.statSync)(path8).isDirectory() && (0, import_fs6.existsSync)((0, import_path6.join)(path8, "manifest.json"));
|
|
6869
|
+
} catch {
|
|
6870
|
+
return false;
|
|
6871
|
+
}
|
|
6872
|
+
}
|
|
6873
|
+
function parseMemoryPackDir(dir) {
|
|
6874
|
+
const result = readMemoryPack(dir);
|
|
6875
|
+
const signedCount = result.verifiedRecords.size;
|
|
6876
|
+
if (signedCount > 0) {
|
|
6877
|
+
const pubFp = result.manifest.producer.public_key?.slice(0, 8) ?? "?";
|
|
6878
|
+
printInfo(`Verified ${signedCount} record signature(s) against ${pubFp}...`);
|
|
6879
|
+
} else {
|
|
6880
|
+
printInfo("Pack is unsigned (no signatures.jsonl) \u2014 proceeding without verification");
|
|
6881
|
+
}
|
|
6882
|
+
for (const w of result.warnings) printInfo(`warning: ${w}`);
|
|
6883
|
+
return result.records.map((r) => ({
|
|
6884
|
+
content: r.content,
|
|
6885
|
+
summary: r.summary || r.content.slice(0, 200),
|
|
6886
|
+
type: ["episodic", "semantic", "procedural"].includes(r.kind) ? r.kind : "episodic",
|
|
6887
|
+
importance: r.importance,
|
|
6888
|
+
tags: [...r.tags || [], "imported", "memorypack"],
|
|
6889
|
+
source: r.source || "memorypack"
|
|
6890
|
+
}));
|
|
6891
|
+
}
|
|
6409
6892
|
function isZipFile(path8) {
|
|
6410
6893
|
try {
|
|
6411
|
-
const buf = (0,
|
|
6894
|
+
const buf = (0, import_fs6.readFileSync)(path8);
|
|
6412
6895
|
return buf[0] === 80 && buf[1] === 75;
|
|
6413
6896
|
} catch {
|
|
6414
6897
|
return false;
|
|
@@ -6536,9 +7019,9 @@ function extractFromChatGPTConversations(conversations) {
|
|
|
6536
7019
|
async function parseChatGPTZip(filePath) {
|
|
6537
7020
|
const { execSync: execSync2 } = require("child_process");
|
|
6538
7021
|
const { mkdtempSync, readdirSync: readdirSync2 } = require("fs");
|
|
6539
|
-
const { join:
|
|
7022
|
+
const { join: join11 } = require("path");
|
|
6540
7023
|
const os5 = require("os");
|
|
6541
|
-
const tmpDir = mkdtempSync(
|
|
7024
|
+
const tmpDir = mkdtempSync(join11(os5.tmpdir(), "clude-import-"));
|
|
6542
7025
|
try {
|
|
6543
7026
|
execSync2(`unzip -o -q "${filePath}" -d "${tmpDir}"`);
|
|
6544
7027
|
} catch {
|
|
@@ -6546,7 +7029,7 @@ async function parseChatGPTZip(filePath) {
|
|
|
6546
7029
|
process.exit(1);
|
|
6547
7030
|
}
|
|
6548
7031
|
const files = readdirSync2(tmpDir);
|
|
6549
|
-
const convFile = files.find((f) => f === "conversations.json") ?
|
|
7032
|
+
const convFile = files.find((f) => f === "conversations.json") ? join11(tmpDir, "conversations.json") : null;
|
|
6550
7033
|
if (!convFile) {
|
|
6551
7034
|
const { execSync: exec2 } = require("child_process");
|
|
6552
7035
|
try {
|
|
@@ -6555,18 +7038,18 @@ async function parseChatGPTZip(filePath) {
|
|
|
6555
7038
|
printError("No conversations.json found in ZIP.");
|
|
6556
7039
|
process.exit(1);
|
|
6557
7040
|
}
|
|
6558
|
-
const conversations2 = JSON.parse((0,
|
|
7041
|
+
const conversations2 = JSON.parse((0, import_fs6.readFileSync)(found.split("\n")[0], "utf-8"));
|
|
6559
7042
|
return extractFromChatGPTConversations(conversations2);
|
|
6560
7043
|
} catch {
|
|
6561
7044
|
printError("No conversations.json found in ZIP.");
|
|
6562
7045
|
process.exit(1);
|
|
6563
7046
|
}
|
|
6564
7047
|
}
|
|
6565
|
-
const conversations = JSON.parse((0,
|
|
7048
|
+
const conversations = JSON.parse((0, import_fs6.readFileSync)(convFile, "utf-8"));
|
|
6566
7049
|
return extractFromChatGPTConversations(conversations);
|
|
6567
7050
|
}
|
|
6568
7051
|
function parseMarkdown(filePath) {
|
|
6569
|
-
const content = (0,
|
|
7052
|
+
const content = (0, import_fs6.readFileSync)(filePath, "utf-8");
|
|
6570
7053
|
const memories = [];
|
|
6571
7054
|
const sections = content.split(/\n#{1,3}\s+|\n\n+/).filter((s) => s.trim().length > 20);
|
|
6572
7055
|
for (const section of sections) {
|
|
@@ -6600,7 +7083,7 @@ function parseMarkdown(filePath) {
|
|
|
6600
7083
|
return memories;
|
|
6601
7084
|
}
|
|
6602
7085
|
function parseMemoryPack(filePath) {
|
|
6603
|
-
const data = JSON.parse((0,
|
|
7086
|
+
const data = JSON.parse((0, import_fs6.readFileSync)(filePath, "utf-8"));
|
|
6604
7087
|
if (data.memories && Array.isArray(data.memories)) {
|
|
6605
7088
|
return data.memories.map((m) => ({
|
|
6606
7089
|
content: m.content || m.summary || "",
|
|
@@ -6684,9 +7167,10 @@ async function runImport() {
|
|
|
6684
7167
|
${c.bold}Usage:${c.reset} npx @clude/sdk import <file> [options]
|
|
6685
7168
|
|
|
6686
7169
|
${c.bold}Supported formats:${c.reset}
|
|
7170
|
+
${c.cyan}pack/${c.reset} MemoryPack v0.1 directory (manifest.json + records.jsonl)
|
|
6687
7171
|
${c.cyan}chatgpt-export.zip${c.reset} ChatGPT data export (ZIP with conversations.json)
|
|
6688
7172
|
${c.cyan}memories.md${c.reset} Markdown or text file (paragraphs \u2192 memories)
|
|
6689
|
-
${c.cyan}pack.json${c.reset} Clude MemoryPack JSON
|
|
7173
|
+
${c.cyan}pack.json${c.reset} Legacy Clude MemoryPack JSON
|
|
6690
7174
|
|
|
6691
7175
|
${c.bold}Options:${c.reset}
|
|
6692
7176
|
--dry-run Show what would be imported without storing
|
|
@@ -6702,7 +7186,7 @@ async function runImport() {
|
|
|
6702
7186
|
}
|
|
6703
7187
|
const filePath = args.find((a) => !a.startsWith("--"));
|
|
6704
7188
|
const dryRun = hasFlag2(args, "--dry-run");
|
|
6705
|
-
if (!(0,
|
|
7189
|
+
if (!(0, import_fs6.existsSync)(filePath)) {
|
|
6706
7190
|
printError(`File not found: ${filePath}`);
|
|
6707
7191
|
process.exit(1);
|
|
6708
7192
|
}
|
|
@@ -6730,11 +7214,14 @@ async function runImport() {
|
|
|
6730
7214
|
${c.bold}Import${c.reset}
|
|
6731
7215
|
`);
|
|
6732
7216
|
let memories;
|
|
6733
|
-
if (
|
|
7217
|
+
if (isMemoryPackDir(filePath)) {
|
|
7218
|
+
printInfo("Detected: MemoryPack v0.1 directory");
|
|
7219
|
+
memories = parseMemoryPackDir(filePath);
|
|
7220
|
+
} else if (isZipFile(filePath)) {
|
|
6734
7221
|
printInfo("Detected: ChatGPT data export (ZIP)");
|
|
6735
7222
|
memories = await parseChatGPTZip(filePath);
|
|
6736
7223
|
} else if (isJsonFile(filePath)) {
|
|
6737
|
-
printInfo("Detected: MemoryPack JSON");
|
|
7224
|
+
printInfo("Detected: Legacy MemoryPack JSON");
|
|
6738
7225
|
memories = parseMemoryPack(filePath);
|
|
6739
7226
|
} else if (isMarkdownOrText(filePath)) {
|
|
6740
7227
|
printInfo("Detected: Markdown/text file");
|
|
@@ -6778,12 +7265,14 @@ async function runImport() {
|
|
|
6778
7265
|
printDivider();
|
|
6779
7266
|
console.log("");
|
|
6780
7267
|
}
|
|
6781
|
-
var
|
|
7268
|
+
var import_fs6, import_path6;
|
|
6782
7269
|
var init_import = __esm({
|
|
6783
7270
|
"packages/brain/src/cli/import.ts"() {
|
|
6784
7271
|
"use strict";
|
|
6785
|
-
|
|
7272
|
+
import_fs6 = require("fs");
|
|
7273
|
+
import_path6 = require("path");
|
|
6786
7274
|
init_banner();
|
|
7275
|
+
init_memorypack();
|
|
6787
7276
|
}
|
|
6788
7277
|
});
|
|
6789
7278
|
|
|
@@ -6895,7 +7384,7 @@ async function runSync() {
|
|
|
6895
7384
|
const refresh = async () => {
|
|
6896
7385
|
try {
|
|
6897
7386
|
const content = await generatePrompt(format);
|
|
6898
|
-
(0,
|
|
7387
|
+
(0, import_fs7.writeFileSync)(output, content, "utf-8");
|
|
6899
7388
|
printSuccess(`Updated ${output} (${content.split(/\s+/).length} words) \u2014 ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}`);
|
|
6900
7389
|
} catch (err) {
|
|
6901
7390
|
printError(`Refresh failed: ${err.message}`);
|
|
@@ -6911,11 +7400,11 @@ async function runSync() {
|
|
|
6911
7400
|
`);
|
|
6912
7401
|
setInterval(refresh, interval * 1e3);
|
|
6913
7402
|
}
|
|
6914
|
-
var
|
|
7403
|
+
var import_fs7;
|
|
6915
7404
|
var init_sync = __esm({
|
|
6916
7405
|
"packages/brain/src/cli/sync.ts"() {
|
|
6917
7406
|
"use strict";
|
|
6918
|
-
|
|
7407
|
+
import_fs7 = require("fs");
|
|
6919
7408
|
init_banner();
|
|
6920
7409
|
}
|
|
6921
7410
|
});
|
package/dist/mcp/server.js
CHANGED
|
@@ -2717,7 +2717,7 @@ async function commitMemoryToChain(memoryId, opts) {
|
|
|
2717
2717
|
}
|
|
2718
2718
|
if (!signature) {
|
|
2719
2719
|
const contentHashHex = contentHashBuf.toString("hex");
|
|
2720
|
-
const memo = `clude
|
|
2720
|
+
const memo = `clude:v1:sha256:${contentHashHex}`;
|
|
2721
2721
|
signature = await writeMemo(memo);
|
|
2722
2722
|
}
|
|
2723
2723
|
if (!signature) return;
|
package/dist/sdk/index.js
CHANGED
|
@@ -2542,7 +2542,7 @@ async function commitMemoryToChain(memoryId, opts) {
|
|
|
2542
2542
|
}
|
|
2543
2543
|
if (!signature) {
|
|
2544
2544
|
const contentHashHex = contentHashBuf.toString("hex");
|
|
2545
|
-
const memo = `clude
|
|
2545
|
+
const memo = `clude:v1:sha256:${contentHashHex}`;
|
|
2546
2546
|
signature = await writeMemo(memo);
|
|
2547
2547
|
}
|
|
2548
2548
|
if (!signature) return;
|
package/package.json
CHANGED