laminark 2.21.7 → 2.21.9

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 (52) hide show
  1. package/README.md +36 -71
  2. package/package.json +9 -7
  3. package/plugin/.claude-plugin/plugin.json +1 -1
  4. package/plugin/CLAUDE.md +10 -0
  5. package/plugin/commands/recall.md +55 -0
  6. package/plugin/commands/remember.md +34 -0
  7. package/plugin/commands/resume.md +45 -0
  8. package/plugin/commands/stash.md +34 -0
  9. package/plugin/commands/status.md +33 -0
  10. package/plugin/dist/hooks/handler.d.ts +3 -1
  11. package/plugin/dist/hooks/handler.d.ts.map +1 -1
  12. package/plugin/dist/hooks/handler.js +312 -23
  13. package/plugin/dist/hooks/handler.js.map +1 -1
  14. package/plugin/dist/index.d.ts +3 -1
  15. package/plugin/dist/index.d.ts.map +1 -1
  16. package/plugin/dist/index.js +2111 -525
  17. package/plugin/dist/index.js.map +1 -1
  18. package/plugin/dist/{observations-Ch0nc47i.d.mts → observations-CorAAc1A.d.mts} +23 -1
  19. package/plugin/dist/observations-CorAAc1A.d.mts.map +1 -0
  20. package/plugin/dist/{tool-registry-CZ3mJ4iR.mjs → tool-registry-D8un_AcG.mjs} +932 -13
  21. package/plugin/dist/tool-registry-D8un_AcG.mjs.map +1 -0
  22. package/plugin/hooks/hooks.json +6 -6
  23. package/plugin/laminark.db +0 -0
  24. package/plugin/package.json +17 -0
  25. package/plugin/scripts/README.md +19 -1
  26. package/plugin/scripts/bump-version.sh +24 -19
  27. package/plugin/scripts/dev-sync.sh +58 -0
  28. package/plugin/scripts/ensure-deps.sh +5 -2
  29. package/plugin/scripts/install.sh +115 -39
  30. package/plugin/scripts/local-install.sh +93 -58
  31. package/plugin/scripts/uninstall.sh +76 -38
  32. package/plugin/scripts/update.sh +20 -69
  33. package/plugin/scripts/verify-install.sh +69 -25
  34. package/plugin/ui/activity.js +12 -0
  35. package/plugin/ui/app.js +24 -54
  36. package/plugin/ui/graph.js +413 -186
  37. package/plugin/ui/help/activity-feed.png +0 -0
  38. package/plugin/ui/help/analysis-panel.png +0 -0
  39. package/plugin/ui/help/graph-toolbar.png +0 -0
  40. package/plugin/ui/help/graph-view.png +0 -0
  41. package/plugin/ui/help/settings.png +0 -0
  42. package/plugin/ui/help/timeline.png +0 -0
  43. package/plugin/ui/help.js +876 -172
  44. package/plugin/ui/index.html +506 -242
  45. package/plugin/ui/settings.js +781 -17
  46. package/plugin/ui/styles.css +990 -44
  47. package/plugin/ui/timeline.js +2 -2
  48. package/plugin/ui/tools.js +826 -0
  49. package/.claude-plugin/marketplace.json +0 -15
  50. package/plugin/dist/observations-Ch0nc47i.d.mts.map +0 -1
  51. package/plugin/dist/tool-registry-CZ3mJ4iR.mjs.map +0 -1
  52. package/plugin/scripts/setup-tmpdir.sh +0 -65
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
+ }
@@ -1,5 +1,23 @@
1
1
  # Scripts
2
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
+
3
21
  ## Version Bumping
4
22
 
5
23
  Laminark uses `MILESTONE.PHASE.SEQUENTIAL` versioning aligned with GSD (Get Shit Done) workflow.
@@ -34,7 +52,7 @@ When starting a **new phase** or **milestone**, manually run:
34
52
 
35
53
  Then commit and push:
36
54
  ```bash
37
- git add package.json .claude-plugin/plugin.json .claude-plugin/marketplace.json
55
+ git add package.json
38
56
  git commit -m "chore: bump to vX.Y.0 for phase Z"
39
57
  git push
40
58
  ```
@@ -1,44 +1,49 @@
1
1
  #!/bin/bash
2
- # Bump version using MILESTONE.PHASE.SEQUENTIAL format
3
- # Usage: ./scripts/bump-version.sh [patch|phase|milestone]
2
+ # Bump version using standard semver (patch | minor | major)
3
+ # Usage: ./plugin/scripts/bump-version.sh [patch|minor|major]
4
4
  #
5
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)
6
+ # ./plugin/scripts/bump-version.sh patch # 0.1.0 -> 0.1.1 (default)
7
+ # ./plugin/scripts/bump-version.sh minor # 0.1.0 -> 0.2.0
8
+ # ./plugin/scripts/bump-version.sh major # 0.1.0 -> 1.0.0
9
9
 
10
10
  set -euo pipefail
11
11
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
12
- ROOT="$SCRIPT_DIR/.."
12
+ ROOT="$SCRIPT_DIR/../.."
13
13
 
14
14
  BUMP_TYPE="${1:-patch}"
15
15
 
16
16
  CURRENT=$(node -e "console.log(require('$ROOT/package.json').version)")
17
17
 
18
- # Parse current version
19
- IFS='.' read -r MILESTONE PHASE SEQUENTIAL <<< "$CURRENT"
18
+ IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT"
20
19
 
21
- # Determine next version based on bump type
22
20
  case "$BUMP_TYPE" in
23
21
  patch)
24
- NEXT="$MILESTONE.$PHASE.$((SEQUENTIAL + 1))"
22
+ NEXT="$MAJOR.$MINOR.$((PATCH + 1))"
25
23
  ;;
26
- phase)
27
- NEXT="$MILESTONE.$((PHASE + 1)).0"
24
+ minor)
25
+ NEXT="$MAJOR.$((MINOR + 1)).0"
28
26
  ;;
29
- milestone)
30
- NEXT="$((MILESTONE + 1)).$((PHASE + 1)).0"
27
+ major)
28
+ NEXT="$((MAJOR + 1)).0.0"
31
29
  ;;
32
30
  *)
33
- echo "Error: Invalid bump type '$BUMP_TYPE'. Use: patch, phase, or milestone" >&2
31
+ echo "Error: Invalid bump type '$BUMP_TYPE'. Use: patch, minor, or major" >&2
34
32
  exit 1
35
33
  ;;
36
34
  esac
37
35
 
38
- # Update version in all files
39
- sed -i "s/\"version\": \"$CURRENT\"/\"version\": \"$NEXT\"/" \
36
+ # Update version in all files that track it
37
+ for file in \
40
38
  "$ROOT/package.json" \
41
- "$ROOT/.claude-plugin/plugin.json" \
39
+ "$ROOT/package-lock.json" \
40
+ "$ROOT/plugin/package.json" \
41
+ "$ROOT/plugin/.claude-plugin/plugin.json" \
42
42
  "$ROOT/.claude-plugin/marketplace.json"
43
+ do
44
+ if [ -f "$file" ]; then
45
+ sed -i "s/\"version\": \"$CURRENT\"/\"version\": \"$NEXT\"/" "$file"
46
+ fi
47
+ done
43
48
 
44
- echo "$NEXT"
49
+ echo "Bumped $CURRENT -> $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."
@@ -1,11 +1,14 @@
1
1
  #!/bin/bash
2
2
  # Auto-install production dependencies if missing (first run after plugin install)
3
3
  PLUGIN_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
4
- if [ ! -d "$PLUGIN_ROOT/node_modules/better-sqlite3" ]; then
4
+ if [ ! -d "$PLUGIN_ROOT/node_modules/better-sqlite3/build" ]; then
5
5
  # Use local tmp dir to avoid EXDEV errors on btrfs subvolumes / cross-device setups
6
6
  NPM_TMP="$PLUGIN_ROOT/.npm-tmp"
7
7
  mkdir -p "$NPM_TMP"
8
- TMPDIR="$NPM_TMP" npm install --prefix "$PLUGIN_ROOT" --production --silent --cache "$NPM_TMP/cache" 2>/dev/null
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
9
12
  rm -rf "$NPM_TMP"
10
13
  fi
11
14
  cd "$PLUGIN_ROOT"
@@ -1,18 +1,34 @@
1
1
  #!/bin/bash
2
- # Bootstrap installer for Laminark plugin.
3
- # Works around EXDEV (cross-device rename) errors on btrfs subvolumes,
4
- # separate /tmp partitions, and other cross-device setups.
2
+ # Install Laminark via npm + MCP server registration
3
+ # Fully standalone no git clone required.
5
4
  #
6
- # Usage: curl -fsSL <raw-url> | bash
7
- # or: ./scripts/install.sh
5
+ # Usage: curl -fsSL https://raw.githubusercontent.com/NoobyNull/Laminark/master/plugin/scripts/install.sh | bash
6
+ # or: ./plugin/scripts/install.sh
8
7
 
9
8
  set -e
10
9
 
11
- echo "Laminark Marketplace Installer"
12
- echo "==============================="
10
+ echo "Laminark Installer"
11
+ echo "=================="
13
12
  echo ""
14
13
 
15
- # Check if claude CLI is available
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
+
16
32
  if ! command -v claude &> /dev/null; then
17
33
  echo "Error: claude CLI not found"
18
34
  echo "Please install Claude Code first: https://claude.com/claude-code"
@@ -20,44 +36,104 @@ if ! command -v claude &> /dev/null; then
20
36
  fi
21
37
 
22
38
  # Check if already installed
23
- if claude plugin list 2>/dev/null | grep -q "laminark"; then
24
- CURRENT_VERSION=$(claude plugin list 2>/dev/null | grep "laminark" | awk '{print $2}' || echo "unknown")
39
+ CURRENT_VERSION=$(npm list -g laminark --depth=0 2>/dev/null | grep laminark@ | sed 's/.*@//' || echo "")
40
+ if [ -n "$CURRENT_VERSION" ]; then
25
41
  echo "Currently installed: v$CURRENT_VERSION"
26
- echo ""
27
- read -p "Update/reinstall? (Y/n): " -n 1 -r
28
- echo ""
29
- if [[ $REPLY =~ ^[Nn]$ ]]; then
30
- echo "Installation cancelled."
31
- exit 0
32
- fi
33
- echo "Removing existing installation..."
34
- claude plugin remove laminark 2>/dev/null || true
42
+ echo "Reinstalling..."
35
43
  fi
36
44
 
37
- # Set up TMPDIR to avoid EXDEV errors
38
- CLAUDE_DIR="${CLAUDE_HOME:-$HOME/.claude}"
39
- SAFE_TMP="$CLAUDE_DIR/tmp"
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"
40
56
 
57
+ # Step 3: Configure hooks in ~/.claude/settings.json
41
58
  echo ""
42
- echo "Installing Laminark from marketplace..."
43
- mkdir -p "$SAFE_TMP"
44
- TMPDIR="$SAFE_TMP" claude plugin install laminark
45
- STATUS=$?
46
- rm -rf "$SAFE_TMP"
47
-
48
- if [ $STATUS -eq 0 ]; then
49
- NEW_VERSION=$(claude plugin list 2>/dev/null | grep "laminark" | awk '{print $2}' || echo "unknown")
50
- echo ""
51
- echo "✓ Laminark installed successfully! (v$NEW_VERSION)"
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.)"
52
126
  echo ""
53
- echo "Next steps:"
54
- echo " 1. Enable the plugin: claude plugin enable laminark"
55
- echo " 2. Start a new Claude Code session"
56
- echo " 3. Verify with: /mcp (should show laminark tools)"
57
- else
127
+ echo " Install: claude plugin add gsd"
128
+ echo " More info: https://github.com/gsd-framework/gsd"
58
129
  echo ""
59
- echo "✗ Installation failed with exit code $STATUS"
60
- exit $STATUS
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
61
137
  fi
62
138
 
63
139
  exit 0
@@ -1,9 +1,8 @@
1
1
  #!/bin/bash
2
- # Local installation wrapper for Laminark plugin.
3
- # Works around EXDEV (cross-device rename) errors on btrfs subvolumes,
4
- # separate /tmp partitions, and other cross-device setups.
2
+ # Local development installation for Laminark
3
+ # Uses npm link + MCP server registration + hooks pointing at repo dist/
5
4
  #
6
- # Usage: ./scripts/local-install.sh [path-to-laminark]
5
+ # Usage: ./plugin/scripts/local-install.sh [path-to-laminark]
7
6
  # Default path: current directory (.)
8
7
 
9
8
  set -e
@@ -22,8 +21,8 @@ echo ""
22
21
  echo "Installing from: $PLUGIN_PATH"
23
22
 
24
23
  # Validate prerequisites
25
- if [ ! -d "$PLUGIN_PATH/dist" ]; then
26
- echo "Error: dist/ directory not found in $PLUGIN_PATH"
24
+ if [ ! -d "$PLUGIN_PATH/plugin/dist" ]; then
25
+ echo "Error: plugin/dist/ directory not found in $PLUGIN_PATH"
27
26
  echo "Please run 'npm install && npm run build' first"
28
27
  exit 1
29
28
  fi
@@ -37,67 +36,103 @@ fi
37
36
  # Get version from package.json
38
37
  if [ -f "$PLUGIN_PATH/package.json" ]; then
39
38
  NEW_VERSION=$(grep '"version"' "$PLUGIN_PATH/package.json" | head -1 | sed -E 's/.*"version": "([^"]+)".*/\1/')
40
- echo "Version to install: v$NEW_VERSION"
41
- else
42
- NEW_VERSION="unknown"
39
+ echo "Version: v$NEW_VERSION"
43
40
  fi
44
41
 
45
- # Check if already installed
46
- if claude plugin list 2>/dev/null | grep -q "laminark"; then
47
- CURRENT_VERSION=$(claude plugin list 2>/dev/null | grep "laminark" | awk '{print $2}' || echo "unknown")
48
- echo "Currently installed: v$CURRENT_VERSION"
49
- echo ""
50
-
51
- if [ "$CURRENT_VERSION" = "$NEW_VERSION" ]; then
52
- echo "Same version is already installed."
53
- read -p "Reinstall anyway? (y/N): " -n 1 -r
54
- echo ""
55
- if [[ ! $REPLY =~ ^[Yy]$ ]]; then
56
- echo "Installation cancelled."
57
- exit 0
58
- fi
59
- else
60
- echo "An existing version is installed."
61
- read -p "Update from v$CURRENT_VERSION to v$NEW_VERSION? (Y/n): " -n 1 -r
62
- echo ""
63
- if [[ $REPLY =~ ^[Nn]$ ]]; then
64
- echo "Installation cancelled."
65
- exit 0
66
- fi
67
- fi
68
-
69
- echo "Removing existing installation..."
70
- TMPDIR="$SAFE_TMP" claude plugin remove laminark 2>/dev/null || true
71
- fi
72
-
73
- # Set up safe temp directory on same filesystem as ~/.claude/
74
- CLAUDE_DIR="${CLAUDE_HOME:-$HOME/.claude}"
75
- SAFE_TMP="$CLAUDE_DIR/tmp"
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"
76
48
 
49
+ # Step 2: Register MCP server
77
50
  echo ""
78
- echo "Creating temporary directory: $SAFE_TMP"
79
- mkdir -p "$SAFE_TMP"
51
+ echo "Registering MCP server with Claude Code..."
52
+ claude mcp add-json laminark '{"command":"laminark-server"}' -s user
53
+ echo "✓ MCP server registered"
80
54
 
81
- # Run claude plugin add with TMPDIR override
82
- echo "Running: claude plugin add $PLUGIN_PATH"
83
- TMPDIR="$SAFE_TMP" claude plugin add "$PLUGIN_PATH"
84
- STATUS=$?
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"
85
111
 
86
- # Clean up
87
- rm -rf "$SAFE_TMP"
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
88
118
 
89
- if [ $STATUS -eq 0 ]; then
90
- echo ""
91
- echo " Laminark plugin installed successfully!"
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.)"
92
125
  echo ""
93
- echo "Next steps:"
94
- echo " 1. Enable the plugin: claude plugin enable laminark"
95
- echo " 2. Start a new Claude Code session"
96
- echo " 3. Verify with: /mcp (should show laminark tools)"
97
- else
126
+ echo " Install: claude plugin add gsd"
127
+ echo " More info: https://github.com/gsd-framework/gsd"
98
128
  echo ""
99
- echo "✗ Installation failed with exit code $STATUS"
100
- exit $STATUS
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
101
136
  fi
102
137
 
103
138
  exit 0