meridian-dev 1.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/BOOTSTRAP_PROMPT.md +110 -0
- package/README.md +344 -0
- package/backup/hooks/session-end.sh +44 -0
- package/backup/hooks/session-start.sh +37 -0
- package/backup/setup.sh +156 -0
- package/bin/meridian.js +100 -0
- package/doctor.sh +173 -0
- package/install.sh +62 -0
- package/journal-summary.sh +577 -0
- package/package.json +42 -0
- package/setup.sh +407 -0
- package/specializations/claude-code/CLAUDE.md-global-fragment.md +52 -0
- package/specializations/claude-code/CLAUDE.md-repo-fragment.md +16 -0
- package/specializations/claude-code/README.md +96 -0
- package/specializations/claude-code/commands/doctor.md +31 -0
- package/specializations/claude-code/commands/init-memory.md +127 -0
- package/specializations/claude-code/commands/init-team.md +335 -0
- package/specializations/claude-code/commands/journal.md +66 -0
- package/specializations/claude-code/hooks/check-global-state.sh +68 -0
- package/specializations/claude-code/settings.json +10 -0
- package/specializations/cursor/README.md +112 -0
- package/specializations/cursor/global-rule.mdc +53 -0
- package/specializations/cursor/repo-rule.mdc +25 -0
- package/specializations/generic/README.md +47 -0
- package/templates/global.md +73 -0
- package/templates/memory-file.md +18 -0
- package/templates/personal-state.md +14 -0
- package/templates/product-state.md +39 -0
- package/templates/repo-state.md +18 -0
- package/templates/session-protocol-fragment.md +46 -0
- package/templates/strategy-state.md +37 -0
- package/templates/team-state.md +29 -0
- package/uninstall.sh +85 -0
package/bin/meridian.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execSync, spawnSync } = require('child_process');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
|
|
7
|
+
const ROOT = path.join(__dirname, '..');
|
|
8
|
+
const COMMANDS = {
|
|
9
|
+
init: {
|
|
10
|
+
desc: 'Install Meridian for your AI tool (Claude Code, Cursor, or generic)',
|
|
11
|
+
run: (args) => {
|
|
12
|
+
const hasToolFlag = args.some((a) => a === '--tool' || a.startsWith('--tool='));
|
|
13
|
+
const toolArgs = hasToolFlag ? args : ['--tool', 'claude-code', ...args];
|
|
14
|
+
spawn('bash', [path.join(ROOT, 'setup.sh'), ...toolArgs]);
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
'init-cursor': {
|
|
18
|
+
desc: 'Install Meridian for Cursor',
|
|
19
|
+
run: (args) => {
|
|
20
|
+
spawn('bash', [path.join(ROOT, 'setup.sh'), '--tool', 'cursor', ...args]);
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
update: {
|
|
24
|
+
desc: 'Update Meridian to latest version (re-runs setup in update mode)',
|
|
25
|
+
run: (args) => {
|
|
26
|
+
const tool = args.includes('--tool') ? args : ['--tool', 'claude-code', ...args];
|
|
27
|
+
spawn('bash', [path.join(ROOT, 'setup.sh'), '--update', ...tool]);
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
digest: {
|
|
31
|
+
desc: 'Generate a journal digest (weekly summary of AI sessions)',
|
|
32
|
+
run: (args) => {
|
|
33
|
+
spawn('bash', [path.join(ROOT, 'journal-summary.sh'), ...args]);
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
doctor: {
|
|
37
|
+
desc: 'Check your Meridian installation for issues',
|
|
38
|
+
run: (args) => {
|
|
39
|
+
spawn('bash', [path.join(ROOT, 'doctor.sh'), ...args]);
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
help: {
|
|
43
|
+
desc: 'Show this help message',
|
|
44
|
+
run: () => showHelp(),
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
function showHelp() {
|
|
49
|
+
console.log('');
|
|
50
|
+
console.log('Meridian — Team decision trail for AI-assisted development');
|
|
51
|
+
console.log('');
|
|
52
|
+
console.log('Usage: meridian <command> [options]');
|
|
53
|
+
console.log('');
|
|
54
|
+
console.log('Commands:');
|
|
55
|
+
for (const [name, cmd] of Object.entries(COMMANDS)) {
|
|
56
|
+
console.log(` ${name.padEnd(16)} ${cmd.desc}`);
|
|
57
|
+
}
|
|
58
|
+
console.log('');
|
|
59
|
+
console.log('Getting started:');
|
|
60
|
+
console.log(' npx meridian-dev init Install for Claude Code');
|
|
61
|
+
console.log(' npx meridian-dev init-cursor Install for Cursor');
|
|
62
|
+
console.log('');
|
|
63
|
+
console.log('In a Claude Code session:');
|
|
64
|
+
console.log(' /init-memory Set up memory for current repo');
|
|
65
|
+
console.log(' /init-team Set up team context (journals, digests, Notion)');
|
|
66
|
+
console.log(' /journal View your session journal digest');
|
|
67
|
+
console.log(' /doctor Check installation health');
|
|
68
|
+
console.log('');
|
|
69
|
+
console.log('Ongoing:');
|
|
70
|
+
console.log(' npx meridian-dev digest This week\'s digest');
|
|
71
|
+
console.log(' npx meridian-dev digest --last-week Last week\'s digest');
|
|
72
|
+
console.log(' npx meridian-dev digest --team <path> Team digest from shared journals');
|
|
73
|
+
console.log('');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function spawn(cmd, args) {
|
|
77
|
+
const result = spawnSync(cmd, args, {
|
|
78
|
+
stdio: 'inherit',
|
|
79
|
+
env: { ...process.env },
|
|
80
|
+
});
|
|
81
|
+
if (result.error) {
|
|
82
|
+
console.error(`Error: ${result.error.message}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
process.exit(result.status || 0);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// --- Main ---
|
|
89
|
+
|
|
90
|
+
const args = process.argv.slice(2);
|
|
91
|
+
const command = args[0] || 'help';
|
|
92
|
+
const commandArgs = args.slice(1);
|
|
93
|
+
|
|
94
|
+
if (COMMANDS[command]) {
|
|
95
|
+
COMMANDS[command].run(commandArgs);
|
|
96
|
+
} else {
|
|
97
|
+
console.error(`Unknown command: ${command}`);
|
|
98
|
+
console.error('Run "meridian help" for available commands.');
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
package/doctor.sh
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Skip Tissue — Doctor
|
|
3
|
+
# Validates that the memory system is correctly installed and functioning.
|
|
4
|
+
# Usage: bash doctor.sh [--verbose]
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
VERBOSE=false
|
|
9
|
+
[[ "${1:-}" == "--verbose" ]] && VERBOSE=true
|
|
10
|
+
|
|
11
|
+
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; RESET='\033[0m'
|
|
12
|
+
|
|
13
|
+
ok() { echo -e "${GREEN}✓${RESET} $1"; }
|
|
14
|
+
warn() { echo -e "${YELLOW}⚠${RESET} $1"; }
|
|
15
|
+
err() { echo -e "${RED}✗${RESET} $1"; }
|
|
16
|
+
info() { echo " $1"; }
|
|
17
|
+
|
|
18
|
+
ISSUES=0
|
|
19
|
+
|
|
20
|
+
check_hook_registered() {
|
|
21
|
+
echo ""
|
|
22
|
+
echo "Hook registration"
|
|
23
|
+
local SETTINGS="$HOME/.claude/settings.json"
|
|
24
|
+
if [ ! -f "$SETTINGS" ]; then
|
|
25
|
+
err "settings.json not found — hook is not registered"
|
|
26
|
+
info "Run: bash setup.sh --tool claude-code"
|
|
27
|
+
ISSUES=$((ISSUES + 1))
|
|
28
|
+
return
|
|
29
|
+
fi
|
|
30
|
+
if grep -q "check-global-state" "$SETTINGS" 2>/dev/null; then
|
|
31
|
+
ok "SessionStart hook registered in settings.json"
|
|
32
|
+
else
|
|
33
|
+
err "Hook not registered in settings.json"
|
|
34
|
+
info "Re-run setup.sh to merge the hook"
|
|
35
|
+
ISSUES=$((ISSUES + 1))
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
if [ -f "$HOME/.claude/hooks/check-global-state.sh" ]; then
|
|
39
|
+
ok "check-global-state.sh exists"
|
|
40
|
+
else
|
|
41
|
+
err "check-global-state.sh not found at ~/.claude/hooks/"
|
|
42
|
+
ISSUES=$((ISSUES + 1))
|
|
43
|
+
fi
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
check_global_state() {
|
|
47
|
+
echo ""
|
|
48
|
+
echo "Global state file"
|
|
49
|
+
local GLOBAL="$HOME/.claude/global-state.md"
|
|
50
|
+
if [ ! -f "$GLOBAL" ]; then
|
|
51
|
+
err "global-state.md not found at $GLOBAL"
|
|
52
|
+
info "Run: bash setup.sh --tool claude-code"
|
|
53
|
+
ISSUES=$((ISSUES + 1))
|
|
54
|
+
return
|
|
55
|
+
fi
|
|
56
|
+
ok "global-state.md exists"
|
|
57
|
+
|
|
58
|
+
# Check if it was updated recently
|
|
59
|
+
local LAST_UPDATED
|
|
60
|
+
LAST_UPDATED=$(grep -m1 '^Last updated:' "$GLOBAL" 2>/dev/null | sed 's/^Last updated: *//' || echo "")
|
|
61
|
+
if [ -n "$LAST_UPDATED" ]; then
|
|
62
|
+
if [[ "$LAST_UPDATED" < "$(date -d '7 days ago' +%Y-%m-%d 2>/dev/null || date -v-7d +%Y-%m-%d 2>/dev/null || echo '0000-00-00')" ]]; then
|
|
63
|
+
warn "global-state.md last updated $LAST_UPDATED (>7 days ago)"
|
|
64
|
+
else
|
|
65
|
+
ok "global-state.md updated $LAST_UPDATED"
|
|
66
|
+
fi
|
|
67
|
+
else
|
|
68
|
+
warn "global-state.md has no 'Last updated:' line"
|
|
69
|
+
fi
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
check_backup() {
|
|
73
|
+
echo ""
|
|
74
|
+
echo "Backup status"
|
|
75
|
+
local LAST_PUSH="$HOME/.claude/.backup-last-push"
|
|
76
|
+
local LAST_ERROR="$HOME/.claude/.backup-last-error"
|
|
77
|
+
|
|
78
|
+
if [ ! -f "$HOME/.claude-backup/.git/config" ] 2>/dev/null && [ ! -f "$LAST_PUSH" ]; then
|
|
79
|
+
info "Backup not configured (optional — run backup/setup.sh <repo-url> to enable)"
|
|
80
|
+
return
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
if [ -f "$LAST_ERROR" ]; then
|
|
84
|
+
warn "Backup: last push FAILED"
|
|
85
|
+
info "$(cat "$LAST_ERROR")"
|
|
86
|
+
ISSUES=$((ISSUES + 1))
|
|
87
|
+
elif [ -f "$LAST_PUSH" ]; then
|
|
88
|
+
local PUSH_TIME
|
|
89
|
+
PUSH_TIME=$(cat "$LAST_PUSH")
|
|
90
|
+
ok "Backup: last push $PUSH_TIME"
|
|
91
|
+
else
|
|
92
|
+
warn "Backup configured but no push record found"
|
|
93
|
+
fi
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
scan_repos() {
|
|
97
|
+
echo ""
|
|
98
|
+
echo "Repo state files"
|
|
99
|
+
local SCAN_ROOTS="${AI_MEMORY_SCAN_ROOTS:-$HOME/repos $HOME/code $HOME/dev $HOME/projects}"
|
|
100
|
+
local FOUND=0
|
|
101
|
+
|
|
102
|
+
for root in $SCAN_ROOTS; do
|
|
103
|
+
[ -d "$root" ] || continue
|
|
104
|
+
while IFS= read -r state_file; do
|
|
105
|
+
FOUND=$((FOUND + 1))
|
|
106
|
+
local rel="${state_file#$HOME/}"
|
|
107
|
+
local repo_name="${rel%/.claude/team-state.md}"
|
|
108
|
+
repo_name="${repo_name%/.claude/state.md}"
|
|
109
|
+
local LAST_UPDATED
|
|
110
|
+
LAST_UPDATED=$(grep -m1 '^Last updated:' "$state_file" 2>/dev/null | sed 's/^Last updated: *//' || echo "unknown")
|
|
111
|
+
ok "$repo_name (updated $LAST_UPDATED)"
|
|
112
|
+
done < <(find "$root" \( -path '*/.claude/state.md' -o -path '*/.claude/team-state.md' \) 2>/dev/null | sort)
|
|
113
|
+
done
|
|
114
|
+
|
|
115
|
+
if [ "$FOUND" -eq 0 ]; then
|
|
116
|
+
info "No repos with state.md found in: $SCAN_ROOTS"
|
|
117
|
+
info "Run /init-memory in a repo to initialize it"
|
|
118
|
+
fi
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
check_memory_files() {
|
|
122
|
+
echo ""
|
|
123
|
+
echo "Memory files"
|
|
124
|
+
local MEMORY_DIR="$HOME/.claude/memory"
|
|
125
|
+
if [ ! -d "$MEMORY_DIR" ]; then
|
|
126
|
+
warn "Memory directory not found: $MEMORY_DIR"
|
|
127
|
+
return
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
local COUNT=0
|
|
131
|
+
while IFS= read -r f; do
|
|
132
|
+
COUNT=$((COUNT + 1))
|
|
133
|
+
local SIZE
|
|
134
|
+
SIZE=$(wc -c < "$f" 2>/dev/null || echo 0)
|
|
135
|
+
local SIZE_KB=$((SIZE / 1024))
|
|
136
|
+
local FNAME
|
|
137
|
+
FNAME=$(basename "$f")
|
|
138
|
+
if [ "$SIZE" -gt 8192 ]; then
|
|
139
|
+
warn "$FNAME (${SIZE_KB}KB) — exceeds recommended 8KB; consider summarizing"
|
|
140
|
+
else
|
|
141
|
+
[ "$VERBOSE" = true ] && ok "$FNAME (${SIZE_KB}KB)"
|
|
142
|
+
fi
|
|
143
|
+
done < <(find "$MEMORY_DIR" -name '*.md' -not -path '*/journal/*' 2>/dev/null | sort)
|
|
144
|
+
|
|
145
|
+
local JOURNAL_DIR="$MEMORY_DIR/journal"
|
|
146
|
+
if [ -d "$JOURNAL_DIR" ]; then
|
|
147
|
+
local JOURNAL_COUNT
|
|
148
|
+
JOURNAL_COUNT=$(find "$JOURNAL_DIR" -name '*.md' 2>/dev/null | wc -l)
|
|
149
|
+
ok "Journal: $JOURNAL_COUNT entries"
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
[ "$COUNT" -gt 0 ] && ok "$COUNT memory file(s) found" || info "No memory files yet"
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
# Run checks
|
|
156
|
+
echo ""
|
|
157
|
+
echo "Skip Tissue — Doctor"
|
|
158
|
+
echo "══════════════════════"
|
|
159
|
+
|
|
160
|
+
check_hook_registered
|
|
161
|
+
check_global_state
|
|
162
|
+
check_backup
|
|
163
|
+
check_memory_files
|
|
164
|
+
scan_repos
|
|
165
|
+
|
|
166
|
+
echo ""
|
|
167
|
+
echo "══════════════════════"
|
|
168
|
+
if [ "$ISSUES" -eq 0 ]; then
|
|
169
|
+
echo -e "${GREEN}All checks passed${RESET}"
|
|
170
|
+
else
|
|
171
|
+
echo -e "${YELLOW}$ISSUES issue(s) found${RESET}"
|
|
172
|
+
exit 1
|
|
173
|
+
fi
|
package/install.sh
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Skip Tissue — Installer
|
|
3
|
+
# Usage:
|
|
4
|
+
# curl -fsSL https://raw.githubusercontent.com/leizerowicz/skip-tissue/main/install.sh | bash
|
|
5
|
+
# ST_VERSION=v1.0.0 bash install.sh # Install specific version
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
REPO="leizerowicz/skip-tissue"
|
|
10
|
+
VERSION="${ST_VERSION:-main}"
|
|
11
|
+
TMP_DIR="$(mktemp -d)"
|
|
12
|
+
|
|
13
|
+
cleanup() { rm -rf "$TMP_DIR"; }
|
|
14
|
+
trap cleanup EXIT
|
|
15
|
+
|
|
16
|
+
echo ""
|
|
17
|
+
echo "Skip Tissue — Installing${VERSION:+ (${VERSION})}..."
|
|
18
|
+
echo ""
|
|
19
|
+
|
|
20
|
+
# Download
|
|
21
|
+
if [ "$VERSION" = "main" ]; then
|
|
22
|
+
DOWNLOAD_URL="https://github.com/$REPO/archive/refs/heads/main.tar.gz"
|
|
23
|
+
ARCHIVE_NAME="skip-tissue-main"
|
|
24
|
+
else
|
|
25
|
+
DOWNLOAD_URL="https://github.com/$REPO/archive/refs/tags/${VERSION}.tar.gz"
|
|
26
|
+
ARCHIVE_NAME="skip-tissue-${VERSION#v}"
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
ARCHIVE="$TMP_DIR/kit.tar.gz"
|
|
30
|
+
if ! curl -fsSL "$DOWNLOAD_URL" -o "$ARCHIVE"; then
|
|
31
|
+
echo ""
|
|
32
|
+
echo "Error: download failed."
|
|
33
|
+
if [ "$VERSION" != "main" ]; then
|
|
34
|
+
echo "Check that version '$VERSION' exists: https://github.com/$REPO/releases"
|
|
35
|
+
fi
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
tar -xz -C "$TMP_DIR" -f "$ARCHIVE"
|
|
39
|
+
KIT_DIR="$TMP_DIR/$ARCHIVE_NAME"
|
|
40
|
+
|
|
41
|
+
# Verify the kit downloaded correctly
|
|
42
|
+
if [ ! -f "$KIT_DIR/setup.sh" ]; then
|
|
43
|
+
echo "Error: download failed or unexpected archive structure"
|
|
44
|
+
exit 1
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# Run setup
|
|
48
|
+
bash "$KIT_DIR/setup.sh" --tool claude-code
|
|
49
|
+
|
|
50
|
+
# Keep the kit locally so doctor.sh and future updates are available
|
|
51
|
+
KIT_DEST="$HOME/.claude/skip-tissue"
|
|
52
|
+
rm -rf "$KIT_DEST"
|
|
53
|
+
cp -r "$KIT_DIR" "$KIT_DEST"
|
|
54
|
+
|
|
55
|
+
echo ""
|
|
56
|
+
echo "Installation complete."
|
|
57
|
+
[ "$VERSION" != "main" ] && echo "Version: $VERSION"
|
|
58
|
+
echo "Kit installed to: $KIT_DEST"
|
|
59
|
+
echo ""
|
|
60
|
+
echo "Next: run /init-memory in any Claude Code session to initialize a repo."
|
|
61
|
+
echo "To set up backup: tell Claude 'Set up backup using <your-private-repo-url>'"
|
|
62
|
+
echo ""
|