@phren/cli 0.0.6 → 0.0.7

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.
@@ -294,7 +294,7 @@ export function getSessionArtifacts(phrenPath, sessionId, project) {
294
294
  const shortId = sessionId.slice(0, 8);
295
295
  try {
296
296
  const projectDirs = getProjectDirs(phrenPath);
297
- const targetProjects = project ? [project] : projectDirs;
297
+ const targetProjects = project ? [project] : projectDirs.map((d) => path.basename(d));
298
298
  for (const proj of targetProjects) {
299
299
  // Findings with matching sessionId
300
300
  const findingsResult = readFindings(phrenPath, proj);
@@ -364,15 +364,16 @@ export function computeSessionDiff(phrenPath, project, lastSessionEnd) {
364
364
  superseded++;
365
365
  }
366
366
  }
367
- // Count completed tasks since last session
368
- const tasksPath = path.join(projectDir, "TASKS.md");
367
+ // Count tasks completed since last session by checking Done items with recent activity dates
369
368
  let tasksCompleted = 0;
370
- if (fs.existsSync(tasksPath)) {
371
- const taskContent = fs.readFileSync(tasksPath, "utf8");
372
- const doneMatch = taskContent.match(/## Done[\s\S]*/);
373
- if (doneMatch) {
374
- const doneLines = doneMatch[0].split("\n").filter(l => l.startsWith("- "));
375
- tasksCompleted = doneLines.length;
369
+ const tasksResult = readTasks(phrenPath, project);
370
+ if (tasksResult.ok) {
371
+ for (const item of tasksResult.data.items.Done) {
372
+ // lastActivity is updated on completion; fall back to createdAt
373
+ const itemDate = item.lastActivity?.slice(0, 10) ?? item.createdAt?.slice(0, 10);
374
+ if (itemDate && itemDate >= cutoff) {
375
+ tasksCompleted++;
376
+ }
376
377
  }
377
378
  }
378
379
  return { newFindings, superseded, tasksCompleted };
@@ -443,12 +444,12 @@ export function register(server, ctx) {
443
444
  try {
444
445
  const tasks = readTasks(phrenPath, activeProject);
445
446
  if (tasks.ok) {
446
- const queueItems = tasks.data.items.Queue
447
+ const activeItems = tasks.data.items.Active
447
448
  .filter((entry) => isMemoryScopeVisible(normalizeMemoryScope(entry.scope), activeScope))
448
449
  .slice(0, 5)
449
450
  .map((entry) => `- [ ] ${entry.line}`);
450
- if (queueItems.length > 0) {
451
- parts.push(`## Active task (${activeProject})\n${queueItems.join("\n")}`);
451
+ if (activeItems.length > 0) {
452
+ parts.push(`## Active task (${activeProject})\n${activeItems.join("\n")}`);
452
453
  }
453
454
  }
454
455
  }
@@ -120,9 +120,12 @@ export function register(server, ctx) {
120
120
  }
121
121
  fs.mkdirSync(destDir, { recursive: true });
122
122
  const existing = findLocalSkill(phrenPath, scope, safeName);
123
- const dest = existing
123
+ const dest = path.resolve(existing
124
124
  ? existing.path
125
- : path.join(destDir, `${safeName}.md`);
125
+ : path.join(destDir, `${safeName}.md`));
126
+ if (!dest.startsWith(phrenPath + path.sep) && dest !== phrenPath) {
127
+ return mcpResponse({ ok: false, error: "Skill path escapes phren store." });
128
+ }
126
129
  const existed = Boolean(existing) || fs.existsSync(dest);
127
130
  fs.writeFileSync(dest, content);
128
131
  updateFileInIndex(dest);
@@ -159,9 +159,12 @@ export function register(server, ctx) {
159
159
  data: { project, includedSections: view.includedSections, totalItems: view.totalItems, summary: true },
160
160
  });
161
161
  }
162
+ const sectionCounts = view.includedSections
163
+ .map((s) => `${s}: ${view.doc.items[s].length}/${doc.items[s].length}`)
164
+ .join(", ");
162
165
  const paginationNote = view.truncated
163
- ? `\n\n_Showing ${offset ?? 0}–${(offset ?? 0) + view.totalItems} of ${view.totalUnpaged} items. Use offset/limit to page._`
164
- : (offset ? `\n\n_Page offset: ${offset}. ${view.totalItems} items returned._` : "");
166
+ ? `\n\n_${sectionCounts} (offset ${offset ?? 0}). Use offset/limit to page._`
167
+ : (offset ? `\n\n_Page offset: ${offset}. ${sectionCounts}._` : "");
165
168
  return mcpResponse({
166
169
  ok: true,
167
170
  message: `## ${project}\n${taskMarkdown(view.doc)}${paginationNote}`,
@@ -231,7 +234,7 @@ export function register(server, ctx) {
231
234
  const { added, errors } = result.data;
232
235
  if (added.length > 0)
233
236
  refreshTaskIndex(updateFileInIndex, phrenPath, project);
234
- return mcpResponse({ ok: added.length > 0, message: `Added ${added.length} of ${items.length} tasks to ${project}`, data: { project, added, errors } });
237
+ return mcpResponse({ ok: added.length > 0, ...(added.length === 0 ? { error: `No tasks added: ${errors.join("; ")}` } : {}), message: `Added ${added.length} of ${items.length} tasks to ${project}`, data: { project, added, errors } });
235
238
  });
236
239
  });
237
240
  server.registerTool("complete_task", {
@@ -303,7 +306,7 @@ export function register(server, ctx) {
303
306
  }
304
307
  if (completed.length > 0)
305
308
  refreshTaskIndex(updateFileInIndex, phrenPath, project);
306
- return mcpResponse({ ok: completed.length > 0, message: `Completed ${completed.length}/${items.length} items`, data: { project, completed, errors } });
309
+ return mcpResponse({ ok: completed.length > 0, ...(completed.length === 0 ? { error: `No tasks completed: ${errors.join("; ")}` } : {}), message: `Completed ${completed.length}/${items.length} items`, data: { project, completed, errors } });
307
310
  });
308
311
  });
309
312
  server.registerTool("remove_task", {