laminark 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.
Files changed (55) hide show
  1. package/README.md +147 -0
  2. package/package.json +65 -0
  3. package/plugin/.claude-plugin/plugin.json +13 -0
  4. package/plugin/.mcp.json +12 -0
  5. package/plugin/CLAUDE.md +10 -0
  6. package/plugin/commands/recall.md +55 -0
  7. package/plugin/commands/remember.md +34 -0
  8. package/plugin/commands/resume.md +45 -0
  9. package/plugin/commands/stash.md +34 -0
  10. package/plugin/commands/status.md +33 -0
  11. package/plugin/dist/analysis/worker.d.ts +1 -0
  12. package/plugin/dist/analysis/worker.js +233 -0
  13. package/plugin/dist/analysis/worker.js.map +1 -0
  14. package/plugin/dist/config-t8LZeB-u.mjs +90 -0
  15. package/plugin/dist/config-t8LZeB-u.mjs.map +1 -0
  16. package/plugin/dist/hooks/handler.d.ts +286 -0
  17. package/plugin/dist/hooks/handler.d.ts.map +1 -0
  18. package/plugin/dist/hooks/handler.js +2413 -0
  19. package/plugin/dist/hooks/handler.js.map +1 -0
  20. package/plugin/dist/index.d.ts +447 -0
  21. package/plugin/dist/index.d.ts.map +1 -0
  22. package/plugin/dist/index.js +7334 -0
  23. package/plugin/dist/index.js.map +1 -0
  24. package/plugin/dist/observations-CorAAc1A.d.mts +192 -0
  25. package/plugin/dist/observations-CorAAc1A.d.mts.map +1 -0
  26. package/plugin/dist/tool-registry-e710BvXq.mjs +3574 -0
  27. package/plugin/dist/tool-registry-e710BvXq.mjs.map +1 -0
  28. package/plugin/hooks/hooks.json +78 -0
  29. package/plugin/laminark.db +0 -0
  30. package/plugin/package.json +17 -0
  31. package/plugin/scripts/README.md +65 -0
  32. package/plugin/scripts/bump-version.sh +42 -0
  33. package/plugin/scripts/dev-sync.sh +58 -0
  34. package/plugin/scripts/ensure-deps.sh +15 -0
  35. package/plugin/scripts/install.sh +139 -0
  36. package/plugin/scripts/local-install.sh +138 -0
  37. package/plugin/scripts/uninstall.sh +133 -0
  38. package/plugin/scripts/update.sh +39 -0
  39. package/plugin/scripts/verify-install.sh +87 -0
  40. package/plugin/skills/status/SKILL.md +6 -0
  41. package/plugin/ui/activity.js +197 -0
  42. package/plugin/ui/app.js +1612 -0
  43. package/plugin/ui/graph.js +2560 -0
  44. package/plugin/ui/help/activity-feed.png +0 -0
  45. package/plugin/ui/help/analysis-panel.png +0 -0
  46. package/plugin/ui/help/graph-toolbar.png +0 -0
  47. package/plugin/ui/help/graph-view.png +0 -0
  48. package/plugin/ui/help/settings.png +0 -0
  49. package/plugin/ui/help/timeline.png +0 -0
  50. package/plugin/ui/help.js +932 -0
  51. package/plugin/ui/index.html +756 -0
  52. package/plugin/ui/settings.js +1414 -0
  53. package/plugin/ui/styles.css +3856 -0
  54. package/plugin/ui/timeline.js +652 -0
  55. package/plugin/ui/tools.js +826 -0
@@ -0,0 +1,78 @@
1
+ {
2
+ "description": "Laminark: persistent adaptive memory for Claude Code",
3
+ "hooks": {
4
+ "SessionStart": [
5
+ {
6
+ "matcher": "",
7
+ "hooks": [
8
+ {
9
+ "type": "command",
10
+ "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/ensure-deps.sh node ${CLAUDE_PLUGIN_ROOT}/dist/hooks/handler.js",
11
+ "statusMessage": "Loading Laminark memory context...",
12
+ "timeout": 10
13
+ }
14
+ ]
15
+ }
16
+ ],
17
+ "PreToolUse": [
18
+ {
19
+ "matcher": "",
20
+ "hooks": [
21
+ {
22
+ "type": "command",
23
+ "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/ensure-deps.sh node ${CLAUDE_PLUGIN_ROOT}/dist/hooks/handler.js",
24
+ "timeout": 2
25
+ }
26
+ ]
27
+ }
28
+ ],
29
+ "PostToolUse": [
30
+ {
31
+ "hooks": [
32
+ {
33
+ "type": "command",
34
+ "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/ensure-deps.sh node ${CLAUDE_PLUGIN_ROOT}/dist/hooks/handler.js",
35
+ "async": true,
36
+ "timeout": 30
37
+ }
38
+ ]
39
+ }
40
+ ],
41
+ "PostToolUseFailure": [
42
+ {
43
+ "hooks": [
44
+ {
45
+ "type": "command",
46
+ "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/ensure-deps.sh node ${CLAUDE_PLUGIN_ROOT}/dist/hooks/handler.js",
47
+ "async": true,
48
+ "timeout": 30
49
+ }
50
+ ]
51
+ }
52
+ ],
53
+ "Stop": [
54
+ {
55
+ "hooks": [
56
+ {
57
+ "type": "command",
58
+ "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/ensure-deps.sh node ${CLAUDE_PLUGIN_ROOT}/dist/hooks/handler.js",
59
+ "async": true,
60
+ "timeout": 15
61
+ }
62
+ ]
63
+ }
64
+ ],
65
+ "SessionEnd": [
66
+ {
67
+ "hooks": [
68
+ {
69
+ "type": "command",
70
+ "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/ensure-deps.sh node ${CLAUDE_PLUGIN_ROOT}/dist/hooks/handler.js",
71
+ "async": true,
72
+ "timeout": 15
73
+ }
74
+ ]
75
+ }
76
+ ]
77
+ }
78
+ }
File without changes
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "laminark-plugin",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "description": "Laminark plugin runtime dependencies",
6
+ "type": "module",
7
+ "dependencies": {
8
+ "@anthropic-ai/claude-agent-sdk": "^0.2.42",
9
+ "@hono/node-server": "^1.19.9",
10
+ "@huggingface/transformers": "^3.8.1",
11
+ "@modelcontextprotocol/sdk": "^1.26.0",
12
+ "better-sqlite3": "^12.6.2",
13
+ "hono": "^4.11.9",
14
+ "sqlite-vec": "^0.1.7-alpha.2",
15
+ "zod": "^4.3.6"
16
+ }
17
+ }
@@ -0,0 +1,65 @@
1
+ # Scripts
2
+
3
+ ## Installation Scripts
4
+
5
+ | Script | Purpose |
6
+ |--------|---------|
7
+ | `install.sh` | Full install: npm global + MCP server + hooks |
8
+ | `local-install.sh` | Dev install: npm link + MCP server + hooks (points at repo) |
9
+ | `update.sh` | Update: `npm update -g laminark` |
10
+ | `uninstall.sh` | Remove MCP server, hooks, and npm package |
11
+ | `verify-install.sh` | Check installation status |
12
+
13
+ ## How It Works
14
+
15
+ Laminark installs via three steps:
16
+
17
+ 1. **npm package** — `npm install -g laminark` puts `laminark-server` and `laminark-hook` on PATH
18
+ 2. **MCP server** — `claude mcp add-json` registers the MCP server in `~/.claude/settings.json`
19
+ 3. **Hooks** — Hook entries are merged into `~/.claude/settings.json` to capture session events
20
+
21
+ ## Version Bumping
22
+
23
+ Laminark uses `MILESTONE.PHASE.SEQUENTIAL` versioning aligned with GSD (Get Shit Done) workflow.
24
+
25
+ ### Format: `M.P.S`
26
+ - **M** = Milestone generation (1, 2, 3...)
27
+ - **P** = Absolute phase number (1, 2, 3... 21+)
28
+ - **S** = Sequential release within phase (0, 1, 2...)
29
+
30
+ ### Automatic Bumping (CI/CD)
31
+
32
+ The GitHub Actions workflow automatically bumps the **patch** version (S) on every push to master:
33
+ ```bash
34
+ 2.21.0 → 2.21.1
35
+ ```
36
+
37
+ This is for incremental fixes and updates within the same phase.
38
+
39
+ ### Manual Bumping
40
+
41
+ When starting a **new phase** or **milestone**, manually run:
42
+
43
+ ```bash
44
+ # New phase (phase 21 → 22)
45
+ ./scripts/bump-version.sh phase
46
+ # 2.21.0 → 2.22.0
47
+
48
+ # New milestone (generation 2 → 3)
49
+ ./scripts/bump-version.sh milestone
50
+ # 2.21.0 → 3.22.0
51
+ ```
52
+
53
+ Then commit and push:
54
+ ```bash
55
+ git add package.json
56
+ git commit -m "chore: bump to vX.Y.0 for phase Z"
57
+ git push
58
+ ```
59
+
60
+ ### Version History
61
+
62
+ - **v1.8.0** - Phase 8 (Milestone v1.0 complete)
63
+ - **v2.16.0** - Phase 16 (Milestone v2.0 complete)
64
+ - **v2.18.0** - Phase 18 (Milestone v2.1 complete)
65
+ - **v2.21.0** - Phase 21 (Milestone v2.2 complete)
@@ -0,0 +1,42 @@
1
+ #!/bin/bash
2
+ # Bump version using MILESTONE.PHASE.SEQUENTIAL format
3
+ # Usage: ./scripts/bump-version.sh [patch|phase|milestone]
4
+ #
5
+ # Examples:
6
+ # ./scripts/bump-version.sh patch # 2.21.0 -> 2.21.1 (default)
7
+ # ./scripts/bump-version.sh phase # 2.21.0 -> 2.22.0 (new phase)
8
+ # ./scripts/bump-version.sh milestone # 2.21.0 -> 3.22.0 (new milestone)
9
+
10
+ set -euo pipefail
11
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
12
+ ROOT="$SCRIPT_DIR/.."
13
+
14
+ BUMP_TYPE="${1:-patch}"
15
+
16
+ CURRENT=$(node -e "console.log(require('$ROOT/package.json').version)")
17
+
18
+ # Parse current version
19
+ IFS='.' read -r MILESTONE PHASE SEQUENTIAL <<< "$CURRENT"
20
+
21
+ # Determine next version based on bump type
22
+ case "$BUMP_TYPE" in
23
+ patch)
24
+ NEXT="$MILESTONE.$PHASE.$((SEQUENTIAL + 1))"
25
+ ;;
26
+ phase)
27
+ NEXT="$MILESTONE.$((PHASE + 1)).0"
28
+ ;;
29
+ milestone)
30
+ NEXT="$((MILESTONE + 1)).$((PHASE + 1)).0"
31
+ ;;
32
+ *)
33
+ echo "Error: Invalid bump type '$BUMP_TYPE'. Use: patch, phase, or milestone" >&2
34
+ exit 1
35
+ ;;
36
+ esac
37
+
38
+ # Update version in all files
39
+ sed -i "s/\"version\": \"$CURRENT\"/\"version\": \"$NEXT\"/" \
40
+ "$ROOT/package.json"
41
+
42
+ echo "$NEXT"
@@ -0,0 +1,58 @@
1
+ #!/bin/bash
2
+ # Sync dev plugin build to the cached Claude Code plugin installation.
3
+ # Run after `npm run build` to hot-update the running plugin without restarting.
4
+ #
5
+ # Usage: ./plugin/scripts/dev-sync.sh
6
+ #
7
+ # Note: Static files (UI, hooks) take effect immediately on next page load.
8
+ # Compiled server code (dist/) requires a Claude Code session restart
9
+ # to pick up API changes.
10
+
11
+ set -e
12
+
13
+ CLAUDE_HOME="${CLAUDE_HOME:-$HOME/.claude}"
14
+ CACHE_BASE="$CLAUDE_HOME/plugins/cache/laminark/laminark"
15
+
16
+ # Resolve the repo root (script lives in plugin/scripts/)
17
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
18
+ REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
19
+ PLUGIN_SRC="$REPO_ROOT/plugin"
20
+
21
+ # Verify source exists
22
+ if [ ! -d "$PLUGIN_SRC/dist" ]; then
23
+ echo "Error: plugin/dist/ not found. Run 'npm run build' first."
24
+ exit 1
25
+ fi
26
+
27
+ # Find cached installation(s)
28
+ if [ ! -d "$CACHE_BASE" ]; then
29
+ echo "Error: No cached Laminark plugin found at $CACHE_BASE"
30
+ echo "Install Laminark first: claude plugin add laminark"
31
+ exit 1
32
+ fi
33
+
34
+ # Sync to every cached version (usually just one)
35
+ SYNCED=0
36
+ for CACHE_DIR in "$CACHE_BASE"/*/; do
37
+ [ -d "$CACHE_DIR" ] || continue
38
+ VERSION=$(basename "$CACHE_DIR")
39
+
40
+ rsync -a --delete \
41
+ --exclude '*.db' \
42
+ --exclude '*.db-wal' \
43
+ --exclude '*.db-shm' \
44
+ --exclude 'node_modules' \
45
+ "$PLUGIN_SRC/" "$CACHE_DIR"
46
+
47
+ echo "Synced to $VERSION"
48
+ SYNCED=$((SYNCED + 1))
49
+ done
50
+
51
+ if [ "$SYNCED" -eq 0 ]; then
52
+ echo "Error: No version directories found in $CACHE_BASE"
53
+ exit 1
54
+ fi
55
+
56
+ echo ""
57
+ echo "Done. $SYNCED cached installation(s) updated."
58
+ echo "UI changes are live. API changes need a session restart."
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+ # Auto-install production dependencies if missing (first run after plugin install)
3
+ PLUGIN_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
4
+ if [ ! -d "$PLUGIN_ROOT/node_modules/better-sqlite3/build" ]; then
5
+ # Use local tmp dir to avoid EXDEV errors on btrfs subvolumes / cross-device setups
6
+ NPM_TMP="$PLUGIN_ROOT/.npm-tmp"
7
+ mkdir -p "$NPM_TMP"
8
+ # Install deps without running install scripts (sharp build fails without node-addon-api)
9
+ # then selectively rebuild better-sqlite3 which needs its native addon
10
+ TMPDIR="$NPM_TMP" npm install --prefix "$PLUGIN_ROOT" --omit=dev --ignore-scripts --silent --cache "$NPM_TMP/cache" 2>/dev/null
11
+ npm rebuild --prefix "$PLUGIN_ROOT" better-sqlite3 --silent 2>/dev/null
12
+ rm -rf "$NPM_TMP"
13
+ fi
14
+ cd "$PLUGIN_ROOT"
15
+ exec "$@"
@@ -0,0 +1,139 @@
1
+ #!/bin/bash
2
+ # Install Laminark via npm + MCP server registration
3
+ # Fully standalone — no git clone required.
4
+ #
5
+ # Usage: curl -fsSL https://raw.githubusercontent.com/NoobyNull/Laminark/master/plugin/scripts/install.sh | bash
6
+ # or: ./plugin/scripts/install.sh
7
+
8
+ set -e
9
+
10
+ echo "Laminark Installer"
11
+ echo "=================="
12
+ echo ""
13
+
14
+ # Check prerequisites
15
+ if ! command -v node &> /dev/null; then
16
+ echo "Error: node not found"
17
+ echo "Please install Node.js >= 22: https://nodejs.org"
18
+ exit 1
19
+ fi
20
+
21
+ NODE_MAJOR=$(node -e "console.log(process.versions.node.split('.')[0])")
22
+ if [ "$NODE_MAJOR" -lt 22 ]; then
23
+ echo "Error: Node.js >= 22 required (found v$(node -v))"
24
+ exit 1
25
+ fi
26
+
27
+ if ! command -v npm &> /dev/null; then
28
+ echo "Error: npm not found"
29
+ exit 1
30
+ fi
31
+
32
+ if ! command -v claude &> /dev/null; then
33
+ echo "Error: claude CLI not found"
34
+ echo "Please install Claude Code first: https://claude.com/claude-code"
35
+ exit 1
36
+ fi
37
+
38
+ # Check if already installed
39
+ CURRENT_VERSION=$(npm list -g laminark --depth=0 2>/dev/null | grep laminark@ | sed 's/.*@//' || echo "")
40
+ if [ -n "$CURRENT_VERSION" ]; then
41
+ echo "Currently installed: v$CURRENT_VERSION"
42
+ echo "Reinstalling..."
43
+ fi
44
+
45
+ # Step 1: Install via npm
46
+ echo ""
47
+ echo "Installing laminark globally via npm..."
48
+ npm install -g laminark
49
+ echo "✓ npm package installed"
50
+
51
+ # Step 2: Register MCP server
52
+ echo ""
53
+ echo "Registering MCP server with Claude Code..."
54
+ claude mcp add-json laminark '{"command":"laminark-server"}' -s user
55
+ echo "✓ MCP server registered"
56
+
57
+ # Step 3: Configure hooks in ~/.claude/settings.json
58
+ echo ""
59
+ echo "Configuring hooks..."
60
+ SETTINGS_FILE="${CLAUDE_HOME:-$HOME/.claude}/settings.json"
61
+
62
+ node -e '
63
+ const fs = require("fs");
64
+ const path = require("path");
65
+ const settingsPath = process.argv[1];
66
+
67
+ // Ensure directory exists
68
+ fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
69
+
70
+ let settings = {};
71
+ if (fs.existsSync(settingsPath)) {
72
+ settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
73
+ }
74
+
75
+ if (!settings.hooks) settings.hooks = {};
76
+
77
+ const hookEvents = {
78
+ SessionStart: { type: "command", command: "laminark-hook", statusMessage: "Loading Laminark memory context...", timeout: 10 },
79
+ PreToolUse: { type: "command", command: "laminark-hook", timeout: 2 },
80
+ PostToolUse: { type: "command", command: "laminark-hook", async: true, timeout: 30 },
81
+ PostToolUseFailure: { type: "command", command: "laminark-hook", async: true, timeout: 30 },
82
+ Stop: { type: "command", command: "laminark-hook", async: true, timeout: 15 },
83
+ SessionEnd: { type: "command", command: "laminark-hook", async: true, timeout: 15 }
84
+ };
85
+
86
+ for (const [event, hookConfig] of Object.entries(hookEvents)) {
87
+ if (!settings.hooks[event]) settings.hooks[event] = [];
88
+
89
+ // Remove any existing laminark hooks, then re-add (ensures up-to-date config)
90
+ settings.hooks[event] = settings.hooks[event].filter(entry =>
91
+ !(entry.hooks && entry.hooks.some(h => h.command && h.command.includes("laminark")))
92
+ );
93
+
94
+ settings.hooks[event].push({
95
+ hooks: [hookConfig]
96
+ });
97
+ }
98
+
99
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
100
+ ' "$SETTINGS_FILE"
101
+
102
+ echo "✓ Hooks configured"
103
+
104
+ # Done
105
+ NEW_VERSION=$(npm list -g laminark --depth=0 2>/dev/null | grep laminark@ | sed 's/.*@//' || echo "unknown")
106
+ echo ""
107
+ echo "✓ Laminark v$NEW_VERSION installed successfully!"
108
+ echo ""
109
+ echo "Next steps:"
110
+ echo " 1. Start a new Claude Code session"
111
+ echo " 2. Verify with: /mcp (should show laminark tools)"
112
+
113
+ # Step 4: Recommend GSD (Get Shit Done) workflow plugin
114
+ echo ""
115
+ GSD_INSTALLED=false
116
+ if [ -d "${CLAUDE_HOME:-$HOME/.claude}/commands/gsd" ] || [ -d "${CLAUDE_HOME:-$HOME/.claude}/plugins/gsd" ]; then
117
+ GSD_INSTALLED=true
118
+ fi
119
+
120
+ if [ "$GSD_INSTALLED" = false ]; then
121
+ echo "Recommended: Install GSD (Get Shit Done) by @gsd-framework"
122
+ echo " GSD is an independent workflow plugin for Claude Code that pairs"
123
+ echo " well with Laminark — it handles project planning, phased execution,"
124
+ echo " and atomic commits while Laminark provides persistent memory."
125
+ echo " (GSD does not endorse or recommend Laminark — this is our suggestion.)"
126
+ echo ""
127
+ echo " Install: claude plugin add gsd"
128
+ echo " More info: https://github.com/gsd-framework/gsd"
129
+ echo ""
130
+ if [ -t 0 ]; then
131
+ read -rp "Install GSD now? [y/N] " INSTALL_GSD
132
+ if [[ "$INSTALL_GSD" =~ ^[Yy]$ ]]; then
133
+ echo ""
134
+ claude plugin add gsd 2>/dev/null && echo "✓ GSD installed" || echo " GSD install skipped (install manually with: claude plugin add gsd)"
135
+ fi
136
+ fi
137
+ fi
138
+
139
+ exit 0
@@ -0,0 +1,138 @@
1
+ #!/bin/bash
2
+ # Local development installation for Laminark
3
+ # Uses npm link + MCP server registration + hooks pointing at repo dist/
4
+ #
5
+ # Usage: ./plugin/scripts/local-install.sh [path-to-laminark]
6
+ # Default path: current directory (.)
7
+
8
+ set -e
9
+
10
+ # Parse path argument (default to current directory)
11
+ PLUGIN_PATH="${1:-.}"
12
+
13
+ # Resolve to absolute path
14
+ if [[ "$PLUGIN_PATH" != /* ]]; then
15
+ PLUGIN_PATH="$(cd "$PLUGIN_PATH" && pwd)"
16
+ fi
17
+
18
+ echo "Laminark Local Installer"
19
+ echo "========================"
20
+ echo ""
21
+ echo "Installing from: $PLUGIN_PATH"
22
+
23
+ # Validate prerequisites
24
+ if [ ! -d "$PLUGIN_PATH/plugin/dist" ]; then
25
+ echo "Error: plugin/dist/ directory not found in $PLUGIN_PATH"
26
+ echo "Please run 'npm install && npm run build' first"
27
+ exit 1
28
+ fi
29
+
30
+ if ! command -v claude &> /dev/null; then
31
+ echo "Error: claude CLI not found"
32
+ echo "Please install Claude Code first: https://claude.com/claude-code"
33
+ exit 1
34
+ fi
35
+
36
+ # Get version from package.json
37
+ if [ -f "$PLUGIN_PATH/package.json" ]; then
38
+ NEW_VERSION=$(grep '"version"' "$PLUGIN_PATH/package.json" | head -1 | sed -E 's/.*"version": "([^"]+)".*/\1/')
39
+ echo "Version: v$NEW_VERSION"
40
+ fi
41
+
42
+ # Step 1: npm link from repo root
43
+ echo ""
44
+ echo "Linking package globally..."
45
+ cd "$PLUGIN_PATH"
46
+ npm link
47
+ echo "✓ npm link complete"
48
+
49
+ # Step 2: Register MCP server
50
+ echo ""
51
+ echo "Registering MCP server with Claude Code..."
52
+ claude mcp add-json laminark '{"command":"laminark-server"}' -s user
53
+ echo "✓ MCP server registered"
54
+
55
+ # Step 3: Configure hooks using repo's dist/hooks/handler.js
56
+ echo ""
57
+ echo "Configuring hooks (dev mode - pointing at repo)..."
58
+ SETTINGS_FILE="${CLAUDE_HOME:-$HOME/.claude}/settings.json"
59
+ HANDLER_PATH="$PLUGIN_PATH/plugin/dist/hooks/handler.js"
60
+
61
+ node -e '
62
+ const fs = require("fs");
63
+ const settingsPath = process.argv[1];
64
+ const handlerPath = process.argv[2];
65
+ const hookCmd = `node "${handlerPath}"`;
66
+
67
+ let settings = {};
68
+ if (fs.existsSync(settingsPath)) {
69
+ settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
70
+ }
71
+
72
+ if (!settings.hooks) settings.hooks = {};
73
+
74
+ const hookEvents = {
75
+ SessionStart: { type: "command", command: hookCmd, statusMessage: "Loading Laminark memory context...", timeout: 10 },
76
+ PreToolUse: { type: "command", command: hookCmd, timeout: 2 },
77
+ PostToolUse: { type: "command", command: hookCmd, async: true, timeout: 30 },
78
+ PostToolUseFailure: { type: "command", command: hookCmd, async: true, timeout: 30 },
79
+ Stop: { type: "command", command: hookCmd, async: true, timeout: 15 },
80
+ SessionEnd: { type: "command", command: hookCmd, async: true, timeout: 15 }
81
+ };
82
+
83
+ for (const [event, hookConfig] of Object.entries(hookEvents)) {
84
+ if (!settings.hooks[event]) settings.hooks[event] = [];
85
+
86
+ // Remove any existing laminark hooks for this event
87
+ settings.hooks[event] = settings.hooks[event].filter(entry =>
88
+ !(entry.hooks && entry.hooks.some(h => h.command && h.command.includes("laminark")))
89
+ );
90
+
91
+ // Add the dev hook
92
+ settings.hooks[event].push({
93
+ hooks: [hookConfig]
94
+ });
95
+ }
96
+
97
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
98
+ ' "$SETTINGS_FILE" "$HANDLER_PATH"
99
+
100
+ echo "✓ Hooks configured (dev: $HANDLER_PATH)"
101
+
102
+ # Done
103
+ echo ""
104
+ echo "✓ Laminark v$NEW_VERSION installed locally!"
105
+ echo ""
106
+ echo "Next steps:"
107
+ echo " 1. Start a new Claude Code session"
108
+ echo " 2. Verify with: /mcp (should show laminark tools)"
109
+ echo ""
110
+ echo "To switch to production install: npm install -g laminark && ./plugin/scripts/install.sh"
111
+
112
+ # Step 4: Recommend GSD (Get Shit Done) workflow plugin
113
+ echo ""
114
+ GSD_INSTALLED=false
115
+ if [ -d "${CLAUDE_HOME:-$HOME/.claude}/commands/gsd" ] || [ -d "${CLAUDE_HOME:-$HOME/.claude}/plugins/gsd" ]; then
116
+ GSD_INSTALLED=true
117
+ fi
118
+
119
+ if [ "$GSD_INSTALLED" = false ]; then
120
+ echo "Recommended: Install GSD (Get Shit Done) by @gsd-framework"
121
+ echo " GSD is an independent workflow plugin for Claude Code that pairs"
122
+ echo " well with Laminark — it handles project planning, phased execution,"
123
+ echo " and atomic commits while Laminark provides persistent memory."
124
+ echo " (GSD does not endorse or recommend Laminark — this is our suggestion.)"
125
+ echo ""
126
+ echo " Install: claude plugin add gsd"
127
+ echo " More info: https://github.com/gsd-framework/gsd"
128
+ echo ""
129
+ if [ -t 0 ]; then
130
+ read -rp "Install GSD now? [y/N] " INSTALL_GSD
131
+ if [[ "$INSTALL_GSD" =~ ^[Yy]$ ]]; then
132
+ echo ""
133
+ claude plugin add gsd 2>/dev/null && echo "✓ GSD installed" || echo " GSD install skipped (install manually with: claude plugin add gsd)"
134
+ fi
135
+ fi
136
+ fi
137
+
138
+ exit 0
@@ -0,0 +1,133 @@
1
+ #!/bin/bash
2
+ # Uninstall Laminark: remove MCP server, hooks, and npm package
3
+
4
+ set -e
5
+
6
+ echo "Laminark Uninstaller"
7
+ echo "===================="
8
+ echo ""
9
+
10
+ # Check if claude CLI is available
11
+ if ! command -v claude &> /dev/null; then
12
+ echo "Warning: claude CLI not found, skipping MCP/hook cleanup"
13
+ SKIP_CLAUDE=true
14
+ fi
15
+
16
+ # Check what's installed
17
+ NPM_VERSION=$(npm list -g laminark --depth=0 2>/dev/null | grep laminark@ | sed 's/.*@//' || echo "")
18
+ if [ -n "$NPM_VERSION" ]; then
19
+ echo "npm package: v$NPM_VERSION"
20
+ fi
21
+
22
+ # Check MCP registration
23
+ if [ "$SKIP_CLAUDE" != "true" ]; then
24
+ if claude mcp list 2>/dev/null | grep -q "laminark"; then
25
+ echo "MCP server: registered"
26
+ MCP_REGISTERED=true
27
+ fi
28
+ fi
29
+
30
+ echo ""
31
+
32
+ # Ask for confirmation
33
+ read -p "Are you sure you want to uninstall Laminark? (y/N): " -n 1 -r
34
+ echo ""
35
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
36
+ echo "Uninstall cancelled."
37
+ exit 0
38
+ fi
39
+
40
+ # Step 1: Remove MCP server
41
+ if [ "$MCP_REGISTERED" = "true" ]; then
42
+ echo ""
43
+ echo "Removing MCP server..."
44
+ claude mcp remove laminark -s user 2>/dev/null || true
45
+ echo "✓ MCP server removed"
46
+ fi
47
+
48
+ # Step 2: Remove hooks from settings.json
49
+ echo ""
50
+ echo "Removing hooks from settings..."
51
+ SETTINGS_FILE="${CLAUDE_HOME:-$HOME/.claude}/settings.json"
52
+
53
+ if [ -f "$SETTINGS_FILE" ]; then
54
+ node -e '
55
+ const fs = require("fs");
56
+ const settingsPath = process.argv[1];
57
+
58
+ const settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
59
+
60
+ if (settings.hooks) {
61
+ for (const [event, entries] of Object.entries(settings.hooks)) {
62
+ settings.hooks[event] = entries.filter(entry =>
63
+ !(entry.hooks && entry.hooks.some(h => h.command && h.command.includes("laminark")))
64
+ );
65
+ // Remove empty arrays
66
+ if (settings.hooks[event].length === 0) {
67
+ delete settings.hooks[event];
68
+ }
69
+ }
70
+ // Remove empty hooks object
71
+ if (Object.keys(settings.hooks).length === 0) {
72
+ delete settings.hooks;
73
+ }
74
+ }
75
+
76
+ // Remove laminark from enabledPlugins if present
77
+ if (settings.enabledPlugins) {
78
+ for (const key of Object.keys(settings.enabledPlugins)) {
79
+ if (key.includes("laminark")) {
80
+ delete settings.enabledPlugins[key];
81
+ }
82
+ }
83
+ }
84
+
85
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
86
+ ' "$SETTINGS_FILE"
87
+ echo "✓ Hooks removed"
88
+ fi
89
+
90
+ # Step 3: Uninstall npm package
91
+ if [ -n "$NPM_VERSION" ]; then
92
+ echo ""
93
+ echo "Uninstalling npm package..."
94
+ npm uninstall -g laminark
95
+ echo "✓ npm package removed"
96
+ fi
97
+
98
+ # Step 4: Optional data cleanup
99
+ echo ""
100
+ echo "Data cleanup options:"
101
+ echo " 1. Keep all data (can reinstall later without losing memories)"
102
+ echo " 2. Remove everything (all memories and data)"
103
+ echo ""
104
+ read -p "Choose option (1-2, default=1): " -n 1 -r CLEANUP_OPTION
105
+ echo ""
106
+
107
+ case $CLEANUP_OPTION in
108
+ 2)
109
+ DATA_DIR="$HOME/.laminark"
110
+ if [ -d "$DATA_DIR" ]; then
111
+ echo ""
112
+ echo "WARNING: This will delete all your memories and observations!"
113
+ read -p "Delete $DATA_DIR? (y/N): " -n 1 -r
114
+ echo ""
115
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
116
+ rm -rf "$DATA_DIR"
117
+ echo "✓ Data directory removed: $DATA_DIR"
118
+ else
119
+ echo " Kept data directory: $DATA_DIR"
120
+ fi
121
+ fi
122
+ ;;
123
+ *)
124
+ echo "Keeping all data."
125
+ ;;
126
+ esac
127
+
128
+ echo ""
129
+ echo "✓ Uninstall complete!"
130
+ echo ""
131
+ echo "To reinstall: npm install -g laminark && ./plugin/scripts/install.sh"
132
+
133
+ exit 0