slyplan-mcp 1.7.2 → 1.7.4

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 (2) hide show
  1. package/dist/cli.js +16 -169
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -10,175 +10,23 @@ import { createClient } from '@supabase/supabase-js';
10
10
  const SUPABASE_URL = 'https://omfzpkwtuzucwwxmyuqt.supabase.co';
11
11
  const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im9tZnpwa3d0dXp1Y3d3eG15dXF0Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzA5MjMwNDIsImV4cCI6MjA4NjQ5OTA0Mn0.KXGoUez7M45RtFM9qR7mjzGX6UhlaRE-gggAJxSkIHY';
12
12
  const SLYPLAN_ORIGIN = 'https://slyplan.com';
13
- // Smart transcript-aware hook: checks if set_project + add_to_work_mode have been called.
14
- // Optimized: uses string search instead of parsing every JSON line.
13
+ // Simple reminder hook: always fires, Claude decides relevance via CLAUDE.md instructions.
15
14
  const PRE_HOOK_FILE_CONTENT = `#!/usr/bin/env node
16
- const fs = require('fs');
17
- const path = require('path');
18
- const os = require('os');
19
-
20
- let input = '';
21
- process.stdin.setEncoding('utf8');
22
- process.stdin.on('data', (chunk) => { input += chunk; });
23
- process.stdin.on('end', () => {
24
- try {
25
- const data = JSON.parse(input);
26
-
27
- if (!data.transcript_path) {
28
- process.stdout.write(JSON.stringify({
29
- hookSpecificOutput: {
30
- hookEventName: "PreToolCall",
31
- additionalContext: "BLOCKED: Call list_projects + set_project before doing any work. This is not optional."
32
- }
33
- }));
34
- process.exit(0);
35
- }
36
-
37
- const transcriptPath = data.transcript_path.replace(/^~/, process.env.HOME || process.env.USERPROFILE || '');
38
- if (!fs.existsSync(transcriptPath)) { process.exit(0); }
39
-
40
- // Fast: read file as string and use indexOf instead of parsing every JSON line
41
- const content = fs.readFileSync(transcriptPath, 'utf8');
42
-
43
- if (!content.includes('set_project')) {
44
- process.stdout.write(JSON.stringify({
45
- hookSpecificOutput: {
46
- hookEventName: "PreToolCall",
47
- additionalContext: "BLOCKED: Call list_projects + set_project before doing any work. This is not optional."
48
- }
49
- }));
50
- process.exit(0);
51
- }
52
-
53
- // For work mode, we need to check the LAST occurrence wins (add vs remove)
54
- const lastAdd = content.lastIndexOf('add_to_work_mode');
55
- const lastRemove = content.lastIndexOf('remove_from_work_mode');
56
- if (lastAdd < 0 || (lastRemove > lastAdd)) {
57
- process.stdout.write(JSON.stringify({
58
- hookSpecificOutput: {
59
- hookEventName: "PreToolCall",
60
- additionalContext: "BLOCKED: No node in work mode. Call search + add_to_work_mode before doing any work. This is not optional."
61
- }
62
- }));
63
- process.exit(0);
64
- }
65
-
66
- // Check for SlyPlan update (non-blocking, just informational)
67
- const cacheFile = path.join(os.homedir(), '.claude', 'cache', 'slyplan-update-check.json');
68
- try {
69
- if (fs.existsSync(cacheFile)) {
70
- const cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
71
- if (cache.update_available) {
72
- process.stdout.write(JSON.stringify({
73
- hookSpecificOutput: {
74
- hookEventName: "PreToolCall",
75
- additionalContext: "SlyPlan update available: " + cache.installed + " -> " + cache.latest + ". Run /sly:update to update."
76
- }
77
- }));
78
- process.exit(0);
79
- }
80
- }
81
- } catch {}
82
-
83
- process.exit(0);
84
- } catch (e) {
85
- process.exit(0);
15
+ process.stdout.write(JSON.stringify({
16
+ hookSpecificOutput: {
17
+ hookEventName: "PreToolCall",
18
+ additionalContext: "BLOCKED: You MUST call list_projects + set_project + add_to_work_mode before doing any work. Ignore if already done this session."
86
19
  }
87
- });
20
+ }));
88
21
  `;
89
- // Smart transcript-aware hook: counts file changes SINCE last SlyPlan sync.
90
- // Optimized: reads only the tail of the transcript to find recent activity.
22
+ // Simple reminder hook: always fires, Claude decides relevance via CLAUDE.md instructions.
91
23
  const POST_HOOK_FILE_CONTENT = `#!/usr/bin/env node
92
- const fs = require('fs');
93
-
94
- const BATCH_THRESHOLD = 3;
95
- const TAIL_BYTES = 32768; // Read last 32KB enough for recent tool calls
96
-
97
- let input = '';
98
- process.stdin.setEncoding('utf8');
99
- process.stdin.on('data', (chunk) => { input += chunk; });
100
- process.stdin.on('end', () => {
101
- try {
102
- const data = JSON.parse(input);
103
-
104
- if (!data.transcript_path) { process.exit(0); }
105
-
106
- const transcriptPath = data.transcript_path.replace(/^~/, process.env.HOME || process.env.USERPROFILE || '');
107
- if (!fs.existsSync(transcriptPath)) { process.exit(0); }
108
-
109
- // Read only the tail of the file for performance
110
- const stat = fs.statSync(transcriptPath);
111
- const fd = fs.openSync(transcriptPath, 'r');
112
- const readStart = Math.max(0, stat.size - TAIL_BYTES);
113
- const buf = Buffer.alloc(Math.min(stat.size, TAIL_BYTES));
114
- fs.readSync(fd, buf, 0, buf.length, readStart);
115
- fs.closeSync(fd);
116
- const tail = buf.toString('utf8');
117
-
118
- // If we're reading a partial file, skip the first (possibly incomplete) line
119
- const lines = tail.split('\\n').filter(Boolean);
120
- if (readStart > 0 && lines.length > 0) lines.shift();
121
-
122
- let lastSyncIdx = -1;
123
- let fileChanges = 0;
124
- let hasCommit = false;
125
-
126
- for (let i = 0; i < lines.length; i++) {
127
- // Fast string checks before expensive JSON.parse
128
- const line = lines[i];
129
- if (!line.includes('tool_use')) continue;
130
-
131
- try {
132
- const entry = JSON.parse(line);
133
- if (entry.type !== 'assistant' || !entry.message || !Array.isArray(entry.message.content)) continue;
134
- for (const block of entry.message.content) {
135
- if (block.type !== 'tool_use') continue;
136
- const name = block.name || '';
137
-
138
- if (name.includes('update_node') || name.includes('add_node') || name.includes('add_to_work_mode')) {
139
- lastSyncIdx = i;
140
- fileChanges = 0;
141
- hasCommit = false;
142
- }
143
-
144
- if ((name === 'Write' || name === 'Edit' || name === 'NotebookEdit') && i > lastSyncIdx) {
145
- fileChanges++;
146
- }
147
-
148
- if (name === 'Bash' && line.includes('git commit') && i > lastSyncIdx) {
149
- hasCommit = true;
150
- }
151
- }
152
- } catch {}
153
- }
154
-
155
- if (fileChanges === 0 && !hasCommit) { process.exit(0); }
156
-
157
- if (hasCommit) {
158
- process.stdout.write(JSON.stringify({
159
- hookSpecificOutput: {
160
- hookEventName: "PostToolUse",
161
- additionalContext: "SYNC NOW: Git commit detected. Call update_node with current progress."
162
- }
163
- }));
164
- process.exit(0);
165
- }
166
-
167
- if (fileChanges >= BATCH_THRESHOLD) {
168
- process.stdout.write(JSON.stringify({
169
- hookSpecificOutput: {
170
- hookEventName: "PostToolUse",
171
- additionalContext: "SYNC NOW: " + fileChanges + " file change(s) since last sync. Call update_node with current progress."
172
- }
173
- }));
174
- process.exit(0);
175
- }
176
-
177
- process.exit(0);
178
- } catch (e) {
179
- process.exit(0);
24
+ process.stdout.write(JSON.stringify({
25
+ hookSpecificOutput: {
26
+ hookEventName: "PostToolUse",
27
+ additionalContext: "SYNC NOW: Call update_node with current progress. Ignore if recently synced or no meaningful changes since last sync."
180
28
  }
181
- });
29
+ }));
182
30
  `;
183
31
  // SessionStart hook: checks npm for new slyplan-mcp version in background
184
32
  const SESSION_START_HOOK_CONTENT = `#!/usr/bin/env node
@@ -499,11 +347,10 @@ function mergeMcpJson(existing, auth) {
499
347
  else if (auth.refreshToken) {
500
348
  env.SLYPLAN_REFRESH_TOKEN = auth.refreshToken;
501
349
  }
502
- result.mcpServers.slyplan = {
503
- command: 'npx',
504
- args: ['-y', 'slyplan-mcp@latest'],
505
- env,
506
- };
350
+ const isWindows = process.platform === 'win32';
351
+ result.mcpServers.slyplan = isWindows
352
+ ? { command: 'cmd', args: ['/c', 'npx', '-y', 'slyplan-mcp@latest'], env }
353
+ : { command: 'npx', args: ['-y', 'slyplan-mcp@latest'], env };
507
354
  return result;
508
355
  }
509
356
  // Hooks go in .claude/settings.json
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slyplan-mcp",
3
- "version": "1.7.2",
3
+ "version": "1.7.4",
4
4
  "description": "MCP server for Slyplan — visual project management via Claude",
5
5
  "type": "module",
6
6
  "bin": {