memoryai-claude 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MemoryAI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # MemoryAI for Claude Code
2
+
3
+ Your AI keeps forgetting you. MemoryAI gives Claude Code a real long-term
4
+ memory: one that follows you across every model.
5
+
6
+ ```text
7
+ You move models. You move IDEs. Your memory stays.
8
+ ```
9
+
10
+ ## Install (one command)
11
+
12
+ ```bash
13
+ npx memoryai-claude install
14
+ ```
15
+
16
+ That's it. After it finishes, restart Claude Code once and just work. Past
17
+ decisions, preferences, and recent project context come back at the start of
18
+ each prompt; important moments save automatically when each turn ends.
19
+
20
+ ## Get a key
21
+
22
+ Pick whichever is easier:
23
+
24
+ - Skip the prompt and a free key is created for you on install
25
+ - Or grab one upfront at https://memoryai.dev/connect and paste it
26
+
27
+ ## Health check
28
+
29
+ ```bash
30
+ npx memoryai-claude doctor
31
+ ```
32
+
33
+ Confirms the three hooks are wired and that each endpoint actually responds.
34
+
35
+ ## Status
36
+
37
+ ```bash
38
+ npx memoryai-claude status
39
+ ```
40
+
41
+ Tells you how many hooks are wired in user-scope and project-scope settings.
42
+
43
+ ## Uninstall
44
+
45
+ ```bash
46
+ npx memoryai-claude uninstall
47
+ ```
48
+
49
+ Removes the hooks from `settings.json`. Foreign hooks stay untouched. Memory
50
+ on the server is preserved unless you delete it from the dashboard.
51
+
52
+ ## What gets touched
53
+
54
+ - `~/.claude/settings.json` (or `./.claude/settings.json` with `--project`)
55
+ - `~/.claude/CLAUDE.md` (or `./CLAUDE.md` with `--project`) — a short note
56
+ is appended so the agent knows memory is wired.
57
+
58
+ The original file is backed up before each write.
59
+
60
+ ## Privacy
61
+
62
+ - API keys live in your local `settings.json`. They never leave your machine
63
+ except to talk to the endpoint you configured.
64
+ - No telemetry from this CLI itself.
65
+ - Add `MEMORYAI_NONINTERACTIVE=1` to skip prompts during scripted installs.
66
+
67
+ ## License
68
+
69
+ MIT.
package/dist/cli.js ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ "use strict";var a=require("node:fs"),m=require("node:path"),X=require("node:os");var F=require("node:readline/promises"),S=require("node:process");async function $(e,o){let t=(0,F.createInterface)({input:S.stdin,output:S.stdout});try{let n=o?` [${o}]`:"";return(await t.question(`${e}${n}: `)).trim()||o||""}finally{t.close()}}async function R(e,o=!0){return(await $(`${e} (${o?"Y/n":"y/N"})`,o?"y":"n")).toLowerCase().startsWith("y")}function k(){return process.env.MEMORYAI_NONINTERACTIVE==="1"||process.env.CI==="true"||!process.stdin.isTTY}var l=require("node:fs"),g=require("node:path"),x=require("node:os");function v(e){return e==="project"?(0,g.join)(process.cwd(),".claude","settings.json"):(0,g.join)((0,x.homedir)(),".claude","settings.json")}function N(e){return e==="project"?(0,g.join)(process.cwd(),"CLAUDE.md"):(0,g.join)((0,x.homedir)(),".claude","CLAUDE.md")}function w(e){if(!(0,l.existsSync)(e))return{};try{return JSON.parse((0,l.readFileSync)(e,"utf-8"))||{}}catch{throw new Error(`${e} is not valid JSON. Fix it manually before re-running.`)}}function I(e,o){(0,l.mkdirSync)((0,g.dirname)(e),{recursive:!0}),(0,l.writeFileSync)(e,JSON.stringify(o,null,2)+`
3
+ `,"utf-8")}function M(e){if(!(0,l.existsSync)(e))return null;let o=new Date().toISOString().replace(/[:.]/g,"-"),t=`${e}.bak-${o}`;return(0,l.copyFileSync)(e,t),t}var oe="/v1/hooks/claude/",te="memoryai/session-start-runner";function H(e,o,t){return{type:"http",url:e,timeout:t,headers:{Authorization:`Bearer ${o}`},allowedEnvVars:[]}}function K(e,o,t){return{type:"command",command:e,args:[o],timeout:t}}function D(e){if(!e)return!1;if(typeof e.url=="string"&&e.url.includes(oe))return!0;if(typeof e.command=="string"){let o=Array.isArray(e.args)?e.args.join(" "):"",t=`${e.command} ${o}`;if(t.includes(te)||t.includes("session-start-runner"))return!0}return!1}function J(e){return(e&&e.hooks||[]).some(D)}function A(e,o,t){return e.hooks=e.hooks||{},e.hooks[o]=e.hooks[o]||[],e.hooks[o].some(J)?!1:(e.hooks[o].push({hooks:[t]}),!0)}function L(e){if(!e.hooks)return 0;let o=0;for(let t of Object.keys(e.hooks)){let n=(e.hooks[t]||[]).length;e.hooks[t]=(e.hooks[t]||[]).filter(r=>!J(r)),o+=n-e.hooks[t].length,e.hooks[t].length===0&&delete e.hooks[t]}return Object.keys(e.hooks).length===0&&delete e.hooks,o}function O(e){let o={SessionStart:{present:!1},UserPromptSubmit:{present:!1},Stop:{present:!1}};for(let t of Object.keys(o)){let n=e?.hooks?.[t]||[];for(let r of n){let s=(r.hooks||[]).find(D);if(s){o[t]={present:!0,url:s.url,command:s.command?`${s.command} ${(s.args||[]).join(" ")}`.trim():void 0,timeout:s.timeout};break}}}return o}var p=require("node:fs"),P="<!-- memoryai:auto-note -->",Y=`
4
+ ${P}
5
+ ## MemoryAI
6
+
7
+ Memory works automatically here. Past decisions, preferences, and recent project
8
+ context are recalled before each prompt and saved when each turn ends. Nothing
9
+ to call by hand \u2014 just work normally.
10
+ `;function z(e){let o=(0,p.existsSync)(e)?(0,p.readFileSync)(e,"utf-8"):"";if(o.includes(P))return"skipped";let t=o?`${o.replace(/\s*$/,"")}
11
+ ${Y}`:Y;return(0,p.writeFileSync)(e,t,"utf-8"),o?"appended":"created"}function B(e){if(!(0,p.existsSync)(e))return!1;let o=(0,p.readFileSync)(e,"utf-8");if(!o.includes(P))return!1;let t=o.replace(new RegExp(`\\n*${P}[\\s\\S]*$`,"m"),"").replace(/\s*$/,`
12
+ `);return(0,p.writeFileSync)(e,t,"utf-8"),!0}async function G(e,o){let t=e.replace(/\/+$/,"");try{return(await fetch(`${t}/v1/stats`,{method:"GET",headers:{Authorization:`Bearer ${o}`}})).ok}catch{return!1}}async function V(e,o){let t=e.replace(/\/+$/,"");try{let n=await fetch(`${t}/v1/admin/provision`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:o||"claude-code",tos_accepted:!0})});if(!n.ok)return null;let r=await n.json();return r&&typeof r.api_key=="string"?{api_key:r.api_key,plan:r.plan}:null}catch{return null}}async function q(e,o){let t=e.replace(/\/+$/,""),n={},r=[{event:"SessionStart",path:"/v1/ide/guard/bootstrap",body:{task:"",limit:1}},{event:"UserPromptSubmit",path:"/v1/hooks/claude/user-prompt",body:{prompt:"health check from memoryai-claude doctor"}},{event:"Stop",path:"/v1/hooks/claude/stop",body:{last_assistant_message:""}}];for(let{event:s,path:c,body:f}of r)try{let u=await fetch(`${t}${c}`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify(f)});n[s]=u.ok}catch{n[s]=!1}return n}var Z="0.1.1",W="https://memoryai.dev",j=(0,m.join)((0,X.homedir)(),".memoryai"),E=(0,m.join)(j,"claude.json"),_=(0,m.join)(j,"session-start-runner.js");function ne(e){let o={command:e[0]||"help"};for(let t=1;t<e.length;t++){let n=e[t];n==="--user"?o.scope="user":n==="--project"?o.scope="project":n==="--endpoint"?o.endpoint=e[++t]:n==="--key"?o.key=e[++t]:(n==="--yes"||n==="-y")&&(o.yes=!0)}return o}function h(){console.log(`MemoryAI for Claude Code v${Z}`),console.log("One brain. Every AI you use. Forever."),console.log("")}function Q(){h(),console.log(`Usage:
13
+ memoryai-claude install [--user|--project] [--endpoint URL] [--key KEY] [--yes]
14
+ memoryai-claude doctor
15
+ memoryai-claude status
16
+ memoryai-claude logs
17
+ memoryai-claude uninstall [--user|--project]
18
+ memoryai-claude help
19
+
20
+ Memory works automatically once installed: relevant context comes back at the
21
+ start of each prompt, and important moments save when each turn ends. There is
22
+ nothing to call by hand.
23
+
24
+ Get a free key at https://memoryai.dev (or leave it blank during install and a
25
+ key will be created for you).
26
+ `)}async function ee(e){return e.scope?e.scope:k()?"user":(await $("Apply to (u)ser globally or this (p)roject?","u")).toLowerCase().startsWith("p")?"project":"user"}async function re(e){if(e.endpoint)return e.endpoint;let o=process.env.HM_ENDPOINT||process.env.MEMORYAI_ENDPOINT;return o||(k()?W:await $("Endpoint",W))}async function se(e,o){if(e.key)return e.key;let t=process.env.HM_API_KEY||process.env.MEMORYAI_API_KEY;if(t)return t;let n="";if(k()||(n=(await $("API key (leave blank to auto-create a free one")).trim()),!n){process.stdout.write(" ... creating a free key for you ...");let r=await V(o,"claude-code");if(r)return console.log(` ok (plan=${r.plan||"free"})`),r.api_key;throw console.log(" failed"),new Error("Could not create a key automatically. Get one from https://memoryai.dev/connect and rerun with --key.")}return n}function ie(e){try{let o=new URL(e);return`${o.origin}${o.pathname.replace("/v1/hooks/claude/","/v1/hooks/claude/")}`}catch{return e}}async function ae(e){h();let o=await ee(e),t=await re(e),n=await se(e,t);if(process.stdout.write(" ... verifying key ..."),await G(t,n))console.log(" ok");else if(console.log(" failed"),!e.yes&&!k()&&!await R("Server did not accept the key (or is offline). Continue anyway?",!1))throw new Error("Aborted by user.");let s=v(o),c=N(o),f=w(s),u=M(s);u&&console.log(` back ${u}`),(0,a.mkdirSync)(j,{recursive:!0}),(0,a.writeFileSync)(E,JSON.stringify({endpoint:t,apiKey:n},null,2)+`
27
+ `,"utf-8");try{require("node:fs").chmodSync(E,384)}catch{}let y=ce();if(!y)throw new Error("session-start-runner.js not found alongside the CLI. If running from source, run `npm run build` first.");(0,a.copyFileSync)(y,_),console.log(` setup ${_}`);let i=process.execPath,d=t.replace(/\/+$/,""),b={SessionStart:A(f,"SessionStart",K(i,_,12)),UserPromptSubmit:A(f,"UserPromptSubmit",H(`${d}/v1/hooks/claude/user-prompt`,n,10)),Stop:A(f,"Stop",H(`${d}/v1/hooks/claude/stop`,n,15))};for(let[T,U]of Object.entries(b))console.log(` ${U?"add ":"skip "} hook ${T}${U?"":" (already present)"}`);I(s,f),console.log(` write ${s}`);let C=z(c);console.log(C==="created"?` create ${c}`:C==="appended"?` append ${c}`:` skip ${c} (note already present)`),console.log(""),console.log("Installed. Restart Claude Code once, then just work."),console.log(" - Past context returns at the start of each prompt."),console.log(" - Important moments save when each turn ends."),console.log(" - Run `memoryai-claude doctor` any time to verify health.")}function ce(){let e=[(0,m.join)((0,m.dirname)(process.argv[1]||""),"session-start-runner.js"),(0,m.join)(__dirname,"session-start-runner.js")];for(let o of e)if(o&&(0,a.existsSync)(o))return o;return null}async function le(){h(),console.log("Diagnostics:");let e=v("user"),o=v("project"),t=!1;for(let[n,r]of[["user",e],["project",o]]){if(!(0,a.existsSync)(r)){console.log(` -- ${n}: ${r} (not present)`);continue}let s=w(r),c=O(s);if(Object.values(c).filter(i=>i.present).length===0){console.log(` -- ${n}: ${r} (no MemoryAI hooks)`);continue}t=!0,console.log(` ok ${n}: ${r}`);for(let[i,d]of Object.entries(c)){let b=d.url?` ${ie(d.url)}`:d.command?` command: ${d.command}`:"";console.log(` ${d.present?"present":"MISSING"} ${i}${b}`)}let u="",y="";if((0,a.existsSync)(E))try{let i=JSON.parse((0,a.readFileSync)(E,"utf-8"));i&&typeof i.endpoint=="string"&&(u=i.endpoint),i&&typeof i.apiKey=="string"&&(y=i.apiKey)}catch{}if(!u||!y){let i=ue(s);i?.url&&(u=new URL(i.url).origin,y=(i.headers?.Authorization||"").replace(/^Bearer\s+/i,""))}if(u&&y){process.stdout.write(" ... ping endpoints ...");let i=await q(u,y);console.log("");for(let[d,b]of Object.entries(i))console.log(` ${b?"ok":"FAIL"} ${d}`)}}t||(console.log(""),console.log("No MemoryAI hooks found in either user or project settings."),console.log("Run `memoryai-claude install` to wire them up."))}function ue(e){let o=e?.hooks||{};for(let t of Object.keys(o))for(let n of o[t]||[])for(let r of n.hooks||[])if(typeof r?.url=="string"&&r.url.includes("/v1/hooks/claude/"))return r;return null}async function de(){let e=(0,m.join)(j,"runner.log");if(!(0,a.existsSync)(e)){h(),console.log(`No SessionStart hook activity yet (${e} does not exist).`),console.log("This means Claude Code has not fired SessionStart since install."),console.log("Open a fresh terminal and run `claude` to trigger it.");return}let n=(0,a.readFileSync)(e,"utf-8").trim().split(/\r?\n/).slice(-20).join(`
28
+ `);h(),console.log(`SessionStart runner log (${e}):`),console.log(""),console.log(n)}async function pe(){h();for(let e of["user","project"]){let o=v(e);if(!(0,a.existsSync)(o)){console.log(` ${e}: not present`);continue}let t=w(o),n=O(t),r=Object.values(n).filter(s=>s.present).length;console.log(` ${e}: ${r}/3 hooks wired (${o})`)}}async function me(e){h();let o=await ee(e),t=v(o),n=N(o);if(!(0,a.existsSync)(t)){console.log(` Nothing to do \u2014 ${t} does not exist.`);return}if(!e.yes&&!k()&&!await R(`Remove MemoryAI hooks from ${t}?`,!0))return;let r=w(t),s=M(t);s&&console.log(` back ${s}`);let c=L(r);I(t,r),console.log(` removed ${c} hook${c===1?"":"s"} from ${t}`),B(n)&&console.log(` cleaned ${n}`),console.log(""),console.log("Uninstalled. Restart Claude Code once. Memory still lives on the server until you delete it.")}async function fe(){let e=ne(process.argv.slice(2));try{switch(e.command){case"install":await ae(e);break;case"doctor":await le();break;case"status":await pe();break;case"logs":await de();break;case"uninstall":await me(e);break;case"-v":case"--version":console.log(Z);break;case"help":case"--help":case"-h":case void 0:case"":Q();break;default:console.error(`Unknown command: ${e.command}`),Q(),process.exit(2)}}catch(o){console.error(""),console.error(`Error: ${o.message}`),process.exit(1)}}fe();
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ "use strict";var o=require("node:fs"),s=require("node:path"),p=require("node:os"),d=process.env.MEMORYAI_CLAUDE_CONFIG||(0,s.join)((0,p.homedir)(),".memoryai","claude.json"),f=(0,s.join)((0,p.homedir)(),".memoryai","runner.log");function n(t){try{(0,o.mkdirSync)((0,s.dirname)(f),{recursive:!0}),(0,o.appendFileSync)(f,`${new Date().toISOString()} ${t}
3
+ `,"utf-8")}catch{}}function l(){if(!(0,o.existsSync)(d))return n("config-missing"),null;try{let t=JSON.parse((0,o.readFileSync)(d,"utf-8"));return t&&typeof t.endpoint=="string"&&typeof t.apiKey=="string"?t:(n("config-malformed"),null)}catch(t){return n(`config-parse-error: ${t.message}`),null}}async function y(){return new Promise(t=>{let e="";if(process.stdin.isTTY){t({});return}process.stdin.setEncoding("utf-8"),process.stdin.on("data",r=>{e+=r}),process.stdin.on("end",()=>{try{t(e?JSON.parse(e):{})}catch{t({})}}),setTimeout(()=>t(e?S(e):{}),800)})}function S(t){try{return JSON.parse(t)}catch{return{}}}function h(t){let r={hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:t.slice(0,9500)}};process.stdout.write(JSON.stringify(r))}async function k(){let e=(await y())?.source||"unknown";n(`fired source=${e}`);let r=l();r||process.exit(0);try{let a=r.endpoint.replace(/\/+$/,""),u=new AbortController,g=setTimeout(()=>u.abort(),1e4),c=await fetch(`${a}/v1/ide/guard/bootstrap`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r.apiKey}`},body:JSON.stringify({task:"",limit:14}),signal:u.signal});clearTimeout(g),c.ok||(n(`bootstrap-http-${c.status}`),process.exit(0));let i=await c.json(),m=i&&typeof i.context_block=="string"?i.context_block.trim():"";m||(n("bootstrap-empty"),process.exit(0)),h(m),n(`bootstrap-ok memories=${i.memories_restored??"?"} tokens=${i.tokens_used??"?"}`)}catch(a){n(`exception: ${a.message}`)}process.exit(0)}k();
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "memoryai-claude",
3
+ "version": "0.1.1",
4
+ "description": "Your AI keeps forgetting you. MemoryAI gives Claude Code a real long-term memory — one that follows you across every model.",
5
+ "license": "MIT",
6
+ "homepage": "https://memoryai.dev",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/memoryai-dev/memoryai-claude"
10
+ },
11
+ "keywords": [
12
+ "claude-code",
13
+ "memory",
14
+ "context",
15
+ "llm",
16
+ "ai"
17
+ ],
18
+ "engines": {
19
+ "node": ">=18"
20
+ },
21
+ "bin": {
22
+ "memoryai-claude": "dist/cli.js"
23
+ },
24
+ "files": [
25
+ "dist/",
26
+ "README.md",
27
+ "LICENSE"
28
+ ],
29
+ "scripts": {
30
+ "vscode:prepublish": "npm run package",
31
+ "build:cli": "esbuild ./src/cli.ts --bundle --outfile=dist/cli.js --platform=node --target=node18 --format=cjs --banner:js=\"#!/usr/bin/env node\"",
32
+ "build:runner": "esbuild ./src/session-start-runner.ts --bundle --outfile=dist/session-start-runner.js --platform=node --target=node18 --format=cjs --banner:js=\"#!/usr/bin/env node\"",
33
+ "build": "npm run build:cli && npm run build:runner",
34
+ "package:cli": "npm run build:cli -- --minify",
35
+ "package:runner": "npm run build:runner -- --minify",
36
+ "package": "npm run package:cli && npm run package:runner",
37
+ "lint": "tsc --noEmit"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^22.0.0",
41
+ "esbuild": "^0.25.0",
42
+ "typescript": "^5.5.0"
43
+ }
44
+ }