create-ai-memory 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +340 -0
- package/bin/create-ai-memory.js +41 -0
- package/create-ai-memory.plugin.zsh +5 -0
- package/hooks/claude/session-start.sh +16 -0
- package/hooks/claude/session-summary.sh +54 -0
- package/hooks/claude/settings.snippet.json +19 -0
- package/hooks/git/commit-msg +178 -0
- package/hooks/git/pre-push +19 -0
- package/install.sh +124 -0
- package/package.json +44 -0
- package/shell/adapters.zsh +75 -0
- package/shell/ai-mem.zsh +483 -0
- package/vault-template/_Global_Profile.md +33 -0
- package/vault-template/_Standards.md +29 -0
- package/vault-template/_projects/_project_template.md +26 -0
- package/vault-template/_session_logs/_session_template.md +12 -0
package/install.sh
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ai-memory installer. Interactive when run in a terminal (banner + prompts),
|
|
3
|
+
# and non-interactive when piped (npx, CI): it takes defaults or environment
|
|
4
|
+
# overrides and never blocks. Idempotent; it never clobbers existing vault notes
|
|
5
|
+
# and never double-appends to ~/.zshrc.
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
9
|
+
|
|
10
|
+
# Interactive only when both stdin and stdout are a terminal.
|
|
11
|
+
INTERACTIVE=0
|
|
12
|
+
[ -t 0 ] && [ -t 1 ] && INTERACTIVE=1
|
|
13
|
+
|
|
14
|
+
# ask <var> <prompt> <default>: read a value interactively, else take the default
|
|
15
|
+
# (or an existing environment value of the same name).
|
|
16
|
+
ask() {
|
|
17
|
+
local __var="$1" __prompt="$2" __default="$3" __cur __reply
|
|
18
|
+
__cur="${!__var:-}"
|
|
19
|
+
[ -n "$__cur" ] && __default="$__cur"
|
|
20
|
+
if [ "$INTERACTIVE" -eq 1 ]; then
|
|
21
|
+
read -r -p " $__prompt [$__default] " __reply || true
|
|
22
|
+
printf -v "$__var" '%s' "${__reply:-$__default}"
|
|
23
|
+
else
|
|
24
|
+
printf -v "$__var" '%s' "$__default"
|
|
25
|
+
fi
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
confirm() { # confirm <prompt> -> 0 for yes; defaults to yes, and yes when piped
|
|
29
|
+
[ "$INTERACTIVE" -eq 0 ] && return 0
|
|
30
|
+
local __reply
|
|
31
|
+
read -r -p " $1 [Y/n] " __reply || true
|
|
32
|
+
case "${__reply:-Y}" in [Nn]*) return 1 ;; *) return 0 ;; esac
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# Color only when it lands in a real terminal that wants it.
|
|
36
|
+
supports_color() {
|
|
37
|
+
[ "$INTERACTIVE" -eq 1 ] || return 1
|
|
38
|
+
[ -z "${NO_COLOR:-}" ] || return 1
|
|
39
|
+
[ "${TERM:-}" != "dumb" ] || return 1
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# ANSI Shadow "AI MEMORY" with a teal->violet vertical gradient (24-bit color),
|
|
43
|
+
# degrading to plain block art when color is unavailable.
|
|
44
|
+
banner() {
|
|
45
|
+
local art=(
|
|
46
|
+
' █████╗ ██╗ ███╗ ███╗███████╗███╗ ███╗ ██████╗ ██████╗ ██╗ ██╗'
|
|
47
|
+
'██╔══██╗██║ ████╗ ████║██╔════╝████╗ ████║██╔═══██╗██╔══██╗╚██╗ ██╔╝'
|
|
48
|
+
'███████║██║ ██╔████╔██║█████╗ ██╔████╔██║██║ ██║██████╔╝ ╚████╔╝ '
|
|
49
|
+
'██╔══██║██║ ██║╚██╔╝██║██╔══╝ ██║╚██╔╝██║██║ ██║██╔══██╗ ╚██╔╝ '
|
|
50
|
+
'██║ ██║██║ ██║ ╚═╝ ██║███████╗██║ ╚═╝ ██║╚██████╔╝██║ ██║ ██║ '
|
|
51
|
+
'╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ '
|
|
52
|
+
)
|
|
53
|
+
local grad=( '45;212;191' '56;189;248' '59;130;246' '99;102;241' '139;92;246' '168;85;247' )
|
|
54
|
+
echo
|
|
55
|
+
if supports_color; then
|
|
56
|
+
local i
|
|
57
|
+
for i in "${!art[@]}"; do
|
|
58
|
+
printf '\033[1;38;2;%sm%s\033[0m\n' "${grad[$i]}" "${art[$i]}"
|
|
59
|
+
done
|
|
60
|
+
printf '\033[2m persistent, agent-agnostic session memory · one vault, any CLI\033[0m\n\n'
|
|
61
|
+
else
|
|
62
|
+
printf '%s\n' "${art[@]}"
|
|
63
|
+
printf ' persistent, agent-agnostic session memory - one vault, any CLI\n\n'
|
|
64
|
+
fi
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
banner
|
|
68
|
+
|
|
69
|
+
# --- gather settings ---------------------------------------------------------
|
|
70
|
+
AI_MEM_ROOT="${AI_MEM_ROOT:-$HOME/.ai-memory/_Ai_Memory}"
|
|
71
|
+
ask AI_MEM_ROOT "Where should your memory vault live?" "$AI_MEM_ROOT"
|
|
72
|
+
AI_MEM_AGENTS="${AI_MEM_AGENTS:-claude codex gemini cursor}"
|
|
73
|
+
ask AI_MEM_AGENTS "Which agents should get <agent>-start launchers?" "$AI_MEM_AGENTS"
|
|
74
|
+
|
|
75
|
+
# --- scaffold the vault ------------------------------------------------------
|
|
76
|
+
echo
|
|
77
|
+
echo " scaffolding vault at: $AI_MEM_ROOT"
|
|
78
|
+
mkdir -p "$AI_MEM_ROOT/_projects" "$AI_MEM_ROOT/_session_logs"
|
|
79
|
+
|
|
80
|
+
copy_if_absent() { # never overwrite the user's real notes on a re-run
|
|
81
|
+
local src="$1" dst="$2"
|
|
82
|
+
if [ -e "$dst" ]; then echo " keep ${dst##*/}"; else cp "$src" "$dst"; echo " create ${dst##*/}"; fi
|
|
83
|
+
}
|
|
84
|
+
copy_if_absent "$HERE/vault-template/_Global_Profile.md" "$AI_MEM_ROOT/_Global_Profile.md"
|
|
85
|
+
copy_if_absent "$HERE/vault-template/_Standards.md" "$AI_MEM_ROOT/_Standards.md"
|
|
86
|
+
copy_if_absent "$HERE/vault-template/_projects/_project_template.md" "$AI_MEM_ROOT/_projects/_project_template.md"
|
|
87
|
+
copy_if_absent "$HERE/vault-template/_session_logs/_session_template.md" "$AI_MEM_ROOT/_session_logs/_session_template.md"
|
|
88
|
+
|
|
89
|
+
# --- assemble the ~/.zshrc lines ---------------------------------------------
|
|
90
|
+
LINES="export AI_MEM_ROOT=\"$AI_MEM_ROOT\""
|
|
91
|
+
if [ "$AI_MEM_AGENTS" != "claude codex gemini cursor" ]; then
|
|
92
|
+
LINES="$LINES
|
|
93
|
+
export AI_MEM_AGENTS=\"$AI_MEM_AGENTS\""
|
|
94
|
+
fi
|
|
95
|
+
LINES="$LINES
|
|
96
|
+
source \"$HERE/shell/ai-mem.zsh\""
|
|
97
|
+
|
|
98
|
+
RC="$HOME/.zshrc"
|
|
99
|
+
SOURCE_LINE="source \"$HERE/shell/ai-mem.zsh\""
|
|
100
|
+
|
|
101
|
+
echo
|
|
102
|
+
if [ -f "$RC" ] && grep -qF "$SOURCE_LINE" "$RC"; then
|
|
103
|
+
echo " ~/.zshrc already sources ai-memory; leaving it untouched."
|
|
104
|
+
elif confirm "Append the setup lines to ~/.zshrc now?"; then
|
|
105
|
+
{ printf '\n# ai-memory (https://github.com/rambaarde/create-ai-memory)\n'; printf '%s\n' "$LINES"; } >> "$RC"
|
|
106
|
+
echo " added to $RC"
|
|
107
|
+
echo
|
|
108
|
+
echo " Reload your shell: exec zsh"
|
|
109
|
+
else
|
|
110
|
+
cat <<EOF
|
|
111
|
+
|
|
112
|
+
Add these lines to your ~/.zshrc yourself:
|
|
113
|
+
|
|
114
|
+
$(printf '%s\n' "$LINES" | sed 's/^/ /')
|
|
115
|
+
EOF
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
cat <<EOF
|
|
119
|
+
|
|
120
|
+
Done. From inside any git repo, run: claude-start
|
|
121
|
+
(or codex-start / gemini-start / cursor-start)
|
|
122
|
+
|
|
123
|
+
Optional integrations: see $HERE/hooks/ and the README.
|
|
124
|
+
EOF
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-ai-memory",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Persistent, agent-agnostic session memory for AI coding CLIs (Claude Code, Codex, Gemini, Cursor, opencode). One Markdown vault, any agent.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"create-ai-memory": "bin/create-ai-memory.js"
|
|
7
|
+
},
|
|
8
|
+
"type": "commonjs",
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=18"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/",
|
|
14
|
+
"shell/",
|
|
15
|
+
"hooks/",
|
|
16
|
+
"vault-template/",
|
|
17
|
+
"install.sh",
|
|
18
|
+
"create-ai-memory.plugin.zsh",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"keywords": [
|
|
22
|
+
"ai",
|
|
23
|
+
"memory",
|
|
24
|
+
"claude",
|
|
25
|
+
"codex",
|
|
26
|
+
"gemini",
|
|
27
|
+
"cursor",
|
|
28
|
+
"opencode",
|
|
29
|
+
"cli",
|
|
30
|
+
"agent",
|
|
31
|
+
"obsidian",
|
|
32
|
+
"zsh"
|
|
33
|
+
],
|
|
34
|
+
"homepage": "https://github.com/rambaarde/create-ai-memory#readme",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/rambaarde/create-ai-memory.git"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/rambaarde/create-ai-memory/issues"
|
|
41
|
+
},
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"author": "Ram Christopher Baarde"
|
|
44
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Agent launch adapters for ai-mem.
|
|
2
|
+
#
|
|
3
|
+
# One function per agent: _ai_adapter_<name>. It receives:
|
|
4
|
+
# $1 memory_prompt — assembled vault context + session-mode block
|
|
5
|
+
# $2 mode_block — just the session-mode instructions (may be empty)
|
|
6
|
+
# $3… extra CLI args — anything passed to <name>-start (e.g. files to open)
|
|
7
|
+
#
|
|
8
|
+
# Add a new agent (opencode, aider, …) by defining _ai_adapter_<name> here and
|
|
9
|
+
# listing <name> in AI_MEM_AGENTS (see ai-mem.zsh). No core edits needed.
|
|
10
|
+
|
|
11
|
+
# Codex: --add-dir grants read access to the vault; prompt is positional.
|
|
12
|
+
_ai_adapter_codex() {
|
|
13
|
+
local memory_prompt="$1"
|
|
14
|
+
codex --add-dir "$AI_MEM_ROOT" "$memory_prompt"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# Claude Code: --add-dir is variadic, so the prompt must come FIRST or it gets
|
|
18
|
+
# swallowed as a bogus directory and Claude starts with no initial prompt.
|
|
19
|
+
_ai_adapter_claude() {
|
|
20
|
+
local memory_prompt="$1" mode_block="$2"
|
|
21
|
+
if [[ -n "$mode_block" ]]; then
|
|
22
|
+
claude "$memory_prompt" --add-dir "$AI_MEM_ROOT" --append-system-prompt "$mode_block"
|
|
23
|
+
else
|
|
24
|
+
claude "$memory_prompt" --add-dir "$AI_MEM_ROOT"
|
|
25
|
+
fi
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# Gemini CLI: --include-directories for vault access, -i for the initial prompt.
|
|
29
|
+
_ai_adapter_gemini() {
|
|
30
|
+
local memory_prompt="$1"
|
|
31
|
+
gemini --include-directories "$AI_MEM_ROOT" -i "$memory_prompt"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Cursor has no CLI prompt path, so persist the session's skill choices as a
|
|
35
|
+
# managed always-apply rule that this adapter rewrites each launch (and clears
|
|
36
|
+
# when nothing is selected).
|
|
37
|
+
_ai_adapter_cursor() {
|
|
38
|
+
local memory_prompt="$1" mode_block="$2"
|
|
39
|
+
shift 2
|
|
40
|
+
local cursor_rule="$HOME/.cursor/rules/_ai-session.mdc"
|
|
41
|
+
if [[ -n "$mode_block" ]]; then
|
|
42
|
+
mkdir -p "$HOME/.cursor/rules"
|
|
43
|
+
{
|
|
44
|
+
print -r -- "---"
|
|
45
|
+
print -r -- "description: Active AI session skills (managed by cursor-start; rewritten each launch, cleared when none chosen)."
|
|
46
|
+
print -r -- "globs:"
|
|
47
|
+
print -r -- "alwaysApply: true"
|
|
48
|
+
print -r -- "---"
|
|
49
|
+
print -r --
|
|
50
|
+
print -r -- "$mode_block"
|
|
51
|
+
} > "$cursor_rule"
|
|
52
|
+
else
|
|
53
|
+
rm -f "$cursor_rule"
|
|
54
|
+
fi
|
|
55
|
+
if command -v cursor >/dev/null 2>&1; then
|
|
56
|
+
cursor "$@"
|
|
57
|
+
else
|
|
58
|
+
open -a Cursor
|
|
59
|
+
fi
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# opencode (sst/opencode): the TUI seeds its first message from --prompt. It has
|
|
63
|
+
# no --add-dir, so vault access rides on the inlined profile/standards in the
|
|
64
|
+
# prompt plus the absolute note paths the agent can read on demand.
|
|
65
|
+
_ai_adapter_opencode() {
|
|
66
|
+
local memory_prompt="$1"
|
|
67
|
+
opencode --prompt "$memory_prompt"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# --- Example: add another agent by defining its adapter and listing it in
|
|
71
|
+
# AI_MEM_AGENTS. aider takes the initial instruction via --message:
|
|
72
|
+
# _ai_adapter_aider() {
|
|
73
|
+
# local memory_prompt="$1"
|
|
74
|
+
# aider --message "$memory_prompt"
|
|
75
|
+
# }
|