slyplan-mcp 1.6.2 → 1.6.3

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.
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Sort Quick Tasks into the correct places in the project tree
2
+ description: Sort "Sort Later" tasks into the correct places in the project tree
3
3
  argument-hint: "[project-name]"
4
4
  allowed-tools:
5
5
  - mcp__slyplan__list_projects
@@ -11,9 +11,10 @@ allowed-tools:
11
11
  - mcp__slyplan__move_node
12
12
  - mcp__slyplan__add_node
13
13
  - mcp__slyplan__search
14
+ - mcp__supabase__execute_sql
14
15
  ---
15
16
 
16
- You are a task sorting agent for SlyPlan. Your job is to take all unsorted tasks from the "Quick Tasks" category and move them into the correct places in the project tree for "$ARGUMENTS". Follow each step in order.
17
+ You are a task sorting agent for SlyPlan. Your job is to take all unsorted tasks from the "Sort Later" list (stored in project metadata) and create them as proper nodes in the correct places in the project tree for "$ARGUMENTS". Follow each step in order.
17
18
 
18
19
  ## Step 1: Resolve Project
19
20
 
@@ -22,50 +23,47 @@ You are a task sorting agent for SlyPlan. Your job is to take all unsorted tasks
22
23
  3. If no reasonable match is found, output: **"No project found matching '$ARGUMENTS'"** and stop.
23
24
  4. Call `set_project` with the matched project's ID.
24
25
 
25
- ## Step 2: Find Quick Tasks
26
+ ## Step 2: Find Sort Later Tasks
26
27
 
27
- 1. Call `search` with query "Quick Tasks" to find the Quick Tasks category.
28
- 2. If no "Quick Tasks" category exists, output: **"No Quick Tasks category found nothing to sort."** and stop.
29
- 3. Call `get_node` on the Quick Tasks category to get its children.
30
- 4. If it has no children, output: **"Quick Tasks is empty nothing to sort."** and stop.
31
- 5. Note down all the tasks (children of Quick Tasks) — their IDs, titles, and descriptions.
28
+ 1. Call `get_node` on the project to read its metadata.
29
+ 2. Look for `metadata.sortLaterTasks` this is an array of tasks with `{ id, title, description, children: [{ id, title, description }] }`.
30
+ 3. If the array is empty or doesn't exist, output: **"No Sort Later tasks found — nothing to sort."** and stop.
31
+ 4. Note down all the taskstheir titles, descriptions, and children.
32
32
 
33
33
  ## Step 3: Understand the Tree
34
34
 
35
35
  1. Call `get_tree` **once** to get the complete project hierarchy.
36
36
  2. Analyze the existing structure: categories, phases, and plans.
37
- 3. For each Quick Task, determine the best placement:
37
+ 3. For each Sort Later task, determine the best placement:
38
38
  - Search for existing categories and phases that logically match the task.
39
39
  - Consider the task's title and description to understand its intent.
40
- 4. Plan ALL moves before executing any.
40
+ 4. Plan ALL placements before executing any.
41
41
 
42
- ## Step 4: Sort Each Task
42
+ ## Step 4: Create Nodes for Each Task
43
43
 
44
- For each Quick Task:
44
+ For each Sort Later task:
45
45
 
46
- 1. **If an existing category > phase fits:** Use `move_node` to move the task under that phase. The task stays as a `plan` node.
47
- 2. **If a category exists but no fitting phase:** Create a new `phase` with `add_node`, then `move_node` the task under it.
48
- 3. **If no relevant category exists:** Create a new `category` with `add_node`, then a `phase` under it, then `move_node` the task.
49
- 4. **If a task could itself be a category or phase:** Change its type using `update_node` and restructure accordingly.
50
- 5. **If a task makes absolutely no sense:** Ask the user what they want to do with it before sorting or deleting it.
46
+ 1. **If an existing category > phase fits:** Create the task as a `plan` node under that phase using `add_node`.
47
+ 2. **If a category exists but no fitting phase:** Create a new `phase` with `add_node`, then create the task under it.
48
+ 3. **If no relevant category exists:** Create a new `category` with `add_node`, then a `phase` under it, then the task.
49
+ 4. **If a task could itself be a category or phase:** Create it with that type and restructure accordingly.
50
+ 5. **If a task has children:** Create the parent first, then create each child as a `plan` node under it.
51
+ 6. **If a task makes absolutely no sense:** Ask the user what they want to do with it before creating or discarding it.
51
52
 
52
53
  Use your intelligence to group things logically. Related tasks should be near each other.
53
54
 
54
- ## Step 5: Cleanup
55
+ ## Step 5: Clear Sort Later List
55
56
 
56
- 1. After sorting all tasks, check if the "Quick Tasks" category is now empty.
57
- 2. If empty, delete it using `delete_node`.
58
- 3. If some tasks remain (because you asked the user and they haven't decided), leave the category.
57
+ After all tasks are created as nodes, clear the Sort Later list from project metadata:
59
58
 
60
- ## CRITICAL SAFETY RULE
61
-
62
- **Before calling `delete_node` on ANY node, you MUST first `move_node` ALL of its children to their new parent.**
63
-
64
- The database uses `ON DELETE CASCADE` on `parent_id`. Deleting a parent node **permanently destroys ALL descendants**. There is no undo.
59
+ Use `execute_sql` to clear the sortLaterTasks from the project metadata:
60
+ ```sql
61
+ UPDATE nodes SET metadata = metadata - 'sortLaterTasks' WHERE id = '<project-id>';
62
+ ```
65
63
 
66
64
  ## Behavioral Rules
67
65
 
68
- - Do NOT rewrite existing node titles or descriptions unless the task clearly needs it.
66
+ - Do NOT modify existing nodes only create new ones for the Sort Later tasks.
69
67
  - Ask the user about ambiguous tasks rather than guessing wrong.
70
68
  - Fetch `get_tree` only ONCE (Step 3). Work from the snapshot.
71
69
  - Plan all changes before executing MCP calls.
@@ -81,7 +79,7 @@ Sort complete for "[Project Name]"
81
79
  Sorted: X tasks
82
80
  Created: Y new categories/phases
83
81
  Skipped: Z tasks (asked user)
84
- Quick Tasks category: [deleted | X tasks remaining]
82
+ Sort Later list: [cleared | X tasks remaining]
85
83
  ```
86
84
 
87
85
  Then list where each task was placed:
package/dist/cli.js CHANGED
@@ -49,7 +49,9 @@ process.stdin.on('end', () => {
49
49
  if (block.type !== 'tool_use') continue;
50
50
  const name = block.name || '';
51
51
  if (name.includes('set_project')) hasSetProject = true;
52
+ // Track add/remove — last action wins
52
53
  if (name.includes('add_to_work_mode')) hasWorkModeNode = true;
54
+ if (name.includes('remove_from_work_mode')) hasWorkModeNode = false;
53
55
  }
54
56
  }
55
57
  } catch {}
@@ -72,7 +74,7 @@ process.stdin.on('end', () => {
72
74
  suppressOutput: true,
73
75
  hookSpecificOutput: {
74
76
  hookEventName: "PreToolCall",
75
- additionalContext: "SYNC NOW: You have a project set but no node in work mode. Call search + add_to_work_mode before continuing."
77
+ additionalContext: "BLOCKED: No node in work mode. Call search + add_to_work_mode before doing any work. This is not optional."
76
78
  }
77
79
  });
78
80
  process.stdout.write(output);
package/dist/supabase.js CHANGED
@@ -38,13 +38,34 @@ export async function authenticate() {
38
38
  const email = process.env.SLYPLAN_EMAIL;
39
39
  const password = process.env.SLYPLAN_PASSWORD;
40
40
  // 1. Preferred: permanent API key (never expires)
41
+ // Calls edge function to exchange API key → Supabase session tokens
41
42
  if (apiKey) {
42
- const { data, error } = await supabase.rpc('authenticate_api_key', { api_key: apiKey });
43
- if (error || !data) {
44
- console.error(`API key authentication failed: ${error?.message || 'Invalid key'}`);
43
+ try {
44
+ const res = await fetch(`${SUPABASE_URL}/functions/v1/exchange-api-key`, {
45
+ method: 'POST',
46
+ headers: { 'Content-Type': 'application/json' },
47
+ body: JSON.stringify({ api_key: apiKey }),
48
+ });
49
+ if (!res.ok) {
50
+ const err = await res.json().catch(() => ({ error: res.statusText }));
51
+ console.error(`API key authentication failed: ${err.error || res.statusText}`);
52
+ process.exit(1);
53
+ }
54
+ const tokens = await res.json();
55
+ const { error: sessionError } = await supabase.auth.setSession({
56
+ access_token: tokens.access_token,
57
+ refresh_token: tokens.refresh_token,
58
+ });
59
+ if (sessionError) {
60
+ console.error(`Failed to set session from API key: ${sessionError.message}`);
61
+ process.exit(1);
62
+ }
63
+ userId = tokens.user_id;
64
+ }
65
+ catch (err) {
66
+ console.error(`API key authentication failed: ${err.message}`);
45
67
  process.exit(1);
46
68
  }
47
- userId = data;
48
69
  return;
49
70
  }
50
71
  // 2. Refresh token (browser-based flow)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slyplan-mcp",
3
- "version": "1.6.2",
3
+ "version": "1.6.3",
4
4
  "description": "MCP server for Slyplan — visual project management via Claude",
5
5
  "type": "module",
6
6
  "bin": {