@qzoft/check-list 1.0.9 → 1.0.10

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/dist/parser.d.ts CHANGED
@@ -10,6 +10,7 @@ export interface TaskSection {
10
10
  /** Represents all checkbox tasks found in a single markdown file. */
11
11
  export interface FileTaskGroup {
12
12
  file: string;
13
+ absolutePath?: string;
13
14
  sections: TaskSection[];
14
15
  }
15
16
  /**
package/dist/server.js CHANGED
@@ -44,55 +44,51 @@ registerAppResource(server, 'Task Checklist', uiResourceUri, { description: 'Int
44
44
  }],
45
45
  }));
46
46
  registerAppTool(server, 'list_tasks', {
47
- description: 'Discover and display checklists from markdown files in the project. When the user asks to see tasks in a specific file, pass its ABSOLUTE file path as the `file` parameter. IMPORTANT: Always use the full absolute path (e.g. "/Users/me/project/tasks.md" or "C:\\Users\\me\\project\\tasks.md"), never a relative or workspace-relative path. When no file is specified, all markdown files in the project directory are scanned.',
47
+ description: 'Discover and display checklists from markdown files. IMPORTANT: Always pass the `cwd` parameter with the absolute path of the current workspace folder so the tool knows where to look for files. When the user asks to see tasks in a specific file, also pass its ABSOLUTE file path as the `file` parameter.',
48
48
  inputSchema: {
49
- file: z.string().optional().describe('ABSOLUTE path to a specific markdown file (e.g. "/Users/me/project/tasks.md" or "C:\\Users\\me\\project\\tasks.md"). Always use the full absolute path from the file reference. Omit to scan all markdown files in the project directory.'),
49
+ cwd: z.string().describe('REQUIRED. The absolute path to the current workspace/project folder (e.g. "C:\\\\Users\\\\me\\\\projects\\\\my-app" or "/home/me/projects/my-app"). This tells the tool where to scan for markdown files.'),
50
+ file: z.string().optional().describe('Optional ABSOLUTE path to a specific markdown file. Omit to scan all markdown files in the workspace folder.'),
50
51
  },
51
52
  _meta: { ui: { resourceUri: uiResourceUri } },
52
- }, async ({ file }) => {
53
+ }, async ({ cwd, file }) => {
54
+ // Use the provided cwd, fall back to env/config projectDir
55
+ const effectiveDir = cwd ? path.resolve(cwd) : projectDir;
53
56
  let mdFiles;
54
57
  if (file) {
55
- // Build a list of candidate paths to try, in priority order
56
- const candidates = [];
57
- if (path.isAbsolute(file)) {
58
- candidates.push(path.resolve(file));
59
- }
60
- else {
61
- // 1. Relative to projectDir
62
- candidates.push(path.resolve(projectDir, file));
63
- // 2. Relative to cwd (if different from projectDir)
64
- const cwd = process.cwd();
65
- if (cwd !== projectDir) {
66
- candidates.push(path.resolve(cwd, file));
67
- }
68
- }
69
- // Find the first candidate that exists on disk
70
- let resolved = candidates.find(c => fs.existsSync(c));
71
- // If none found, search by filename/suffix in projectDir
72
- if (!resolved) {
58
+ // Single-file mode
59
+ const resolved = path.isAbsolute(file) ? path.resolve(file) : path.resolve(effectiveDir, file);
60
+ if (!fs.existsSync(resolved)) {
61
+ // Try to find by filename in the workspace
73
62
  const basename = path.basename(file);
74
- const suffix = file.replace(/\//g, path.sep);
75
63
  try {
76
- const allMd = await discoverMarkdownFiles(projectDir);
77
- resolved = allMd.find(f => f.endsWith(path.sep + suffix))
64
+ const allMd = await discoverMarkdownFiles(effectiveDir);
65
+ const match = allMd.find(f => f.endsWith(path.sep + file.replace(/\//g, path.sep)))
78
66
  || allMd.find(f => path.basename(f) === basename);
67
+ if (match) {
68
+ mdFiles = [match];
69
+ }
70
+ else {
71
+ return {
72
+ isError: true,
73
+ content: [{ type: 'text', text: `File not found: ${file}` }],
74
+ };
75
+ }
79
76
  }
80
77
  catch {
81
- // ignore discovery errors
78
+ return {
79
+ isError: true,
80
+ content: [{ type: 'text', text: `File not found: ${file}` }],
81
+ };
82
82
  }
83
83
  }
84
- if (!resolved) {
85
- return {
86
- isError: true,
87
- content: [{ type: 'text', text: `File not found: ${file}\nSearched in: ${candidates.join(', ')}` }],
88
- };
84
+ else {
85
+ mdFiles = [resolved];
89
86
  }
90
- mdFiles = [resolved];
91
87
  }
92
88
  else {
93
- // All-files mode: discover every markdown file in the project
89
+ // All-files mode: discover every markdown file in the workspace
94
90
  try {
95
- mdFiles = await discoverMarkdownFiles(projectDir);
91
+ mdFiles = await discoverMarkdownFiles(effectiveDir);
96
92
  }
97
93
  catch (err) {
98
94
  const message = err instanceof Error ? err.message : String(err);
@@ -101,7 +97,7 @@ registerAppTool(server, 'list_tasks', {
101
97
  content: [
102
98
  {
103
99
  type: 'text',
104
- text: `Error scanning project directory ${projectDir}: ${message}`,
100
+ text: `Error scanning directory ${effectiveDir}: ${message}`,
105
101
  },
106
102
  ],
107
103
  };
@@ -126,9 +122,8 @@ registerAppTool(server, 'list_tasks', {
126
122
  const hasTasks = sections.some((s) => s.tasks.length > 0);
127
123
  if (!hasTasks)
128
124
  continue;
129
- // Use relative path for cleaner display
130
- const relPath = path.relative(projectDir, filePath);
131
- fileGroups.push({ file: relPath, sections });
125
+ const relPath = path.relative(effectiveDir, filePath);
126
+ fileGroups.push({ file: relPath, absolutePath: filePath, sections });
132
127
  }
133
128
  return {
134
129
  content: [
@@ -141,9 +136,9 @@ registerAppTool(server, 'list_tasks', {
141
136
  };
142
137
  });
143
138
  registerAppTool(server, 'update_tasks', {
144
- description: 'Update checkbox states in a project markdown file (auto-saved on toggle)',
139
+ description: 'Update checkbox states in a markdown file (auto-saved on toggle)',
145
140
  inputSchema: {
146
- file: z.string().describe('ABSOLUTE path to the markdown file (e.g. "/Users/me/project/tasks.md"). Always use the full absolute path.'),
141
+ file: z.string().describe('ABSOLUTE path to the markdown file.'),
147
142
  updates: z.array(z.object({
148
143
  line: z.number().describe('0-indexed line number in the markdown file'),
149
144
  checked: z.boolean().describe('New checked state for the checkbox'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qzoft/check-list",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "description": "MCP App for interactive task management from markdown files",
5
5
  "type": "module",
6
6
  "main": "dist/server.js",
@@ -362,7 +362,7 @@
362
362
  checkboxEl.addEventListener('change', () => {
363
363
  const newChecked = checkboxEl.checked;
364
364
  labelEl.className = 'task-label' + (newChecked ? ' done' : '');
365
- autoSave(fg.file, task.line, newChecked, checkboxEl, labelEl);
365
+ autoSave(fg.absolutePath || fg.file, task.line, newChecked, checkboxEl, labelEl);
366
366
  });
367
367
 
368
368
  itemEl.appendChild(checkboxEl);