coding-friend-cli 1.38.3 → 1.38.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.
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-NREZK463.js";
15
15
 
16
16
  // src/commands/clean.ts
17
- import { existsSync, readdirSync, rmSync, statSync } from "fs";
17
+ import { existsSync, readFileSync, readdirSync, rmSync, statSync } from "fs";
18
18
  import { join, relative } from "path";
19
19
  import { confirm, input, select } from "@inquirer/prompts";
20
20
  import chalk from "chalk";
@@ -55,6 +55,32 @@ function matchesRange(entryPath, name, range, cutoff, now) {
55
55
  return cutoff !== null && date.getTime() < cutoff.getTime();
56
56
  }
57
57
  }
58
+ var STATUS_RE = /^status:\s*([^\s#]+)/m;
59
+ function readPlanStatus(entryPath, isDirectory) {
60
+ let file;
61
+ if (isDirectory) {
62
+ file = join(entryPath, "README.md");
63
+ } else if (entryPath.endsWith(".md")) {
64
+ file = entryPath;
65
+ } else {
66
+ return null;
67
+ }
68
+ if (!existsSync(file)) return null;
69
+ try {
70
+ const content = readFileSync(file, "utf8");
71
+ if (!content.startsWith("---")) return null;
72
+ const end = content.indexOf("\n---", 3);
73
+ if (end === -1) return null;
74
+ const frontmatter = content.slice(3, end);
75
+ const m = STATUS_RE.exec(frontmatter);
76
+ return m ? m[1].trim().toLowerCase() : null;
77
+ } catch {
78
+ return null;
79
+ }
80
+ }
81
+ function isDonePlan(entryPath, isDirectory) {
82
+ return readPlanStatus(entryPath, isDirectory) === "done";
83
+ }
58
84
  function countFiles(dir) {
59
85
  if (!existsSync(dir)) return 0;
60
86
  let count = 0;
@@ -68,12 +94,13 @@ function countFiles(dir) {
68
94
  }
69
95
  return count;
70
96
  }
71
- function deleteMatchingEntries(dir, range, cutoff, now) {
97
+ function deleteMatchingEntries(dir, range, cutoff, now, extraFilter) {
72
98
  if (!existsSync(dir)) return { deleted: 0, failed: 0 };
73
99
  let deleted = 0;
74
100
  let failed = 0;
75
101
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
76
102
  const entryPath = join(dir, entry.name);
103
+ if (extraFilter && !extraFilter(entryPath, entry.isDirectory())) continue;
77
104
  if (matchesRange(entryPath, entry.name, range, cutoff, now)) {
78
105
  const filesBefore = entry.isDirectory() ? countFiles(entryPath) : 1;
79
106
  try {
@@ -147,7 +174,15 @@ async function cleanCommand() {
147
174
  console.log(`${chalk.yellow("\u2192")} ${chalk.bold(entry.key)} (${relPath})`);
148
175
  const { range, cutoff } = await promptDateRange();
149
176
  const isMemory = entry.key === "memory";
150
- const message = isMemory ? `Delete matching contents of ${relPath}/? (includes SQLite databases \u2014 stop memory daemon first if running)` : `Delete matching contents of ${relPath}/?`;
177
+ const isPlans = entry.key === "plans";
178
+ let message;
179
+ if (isMemory) {
180
+ message = `Delete matching contents of ${relPath}/? (includes SQLite databases \u2014 stop memory daemon first if running)`;
181
+ } else if (isPlans) {
182
+ message = `Delete matching plans in ${relPath}/? (only plans with frontmatter status: done are removed \u2014 in-progress/failed plans are kept)`;
183
+ } else {
184
+ message = `Delete matching contents of ${relPath}/?`;
185
+ }
151
186
  const ok = await confirm({ message, default: false });
152
187
  if (ok) {
153
188
  const now = /* @__PURE__ */ new Date();
@@ -155,7 +190,8 @@ async function cleanCommand() {
155
190
  entry.path,
156
191
  range,
157
192
  cutoff,
158
- now
193
+ now,
194
+ isPlans ? isDonePlan : void 0
159
195
  );
160
196
  summary.push({ key: entry.key, deleted });
161
197
  const failNote = failed > 0 ? `, ${failed} failed` : "";
@@ -181,7 +217,9 @@ async function cleanCommand() {
181
217
  export {
182
218
  cleanCommand,
183
219
  getEffectiveDate,
220
+ isDonePlan,
184
221
  matchesRange,
185
222
  olderThanDays,
186
- parseDateFromName
223
+ parseDateFromName,
224
+ readPlanStatus
187
225
  };
package/dist/index.js CHANGED
@@ -132,7 +132,7 @@ program.command("status").description("Show comprehensive Coding Friend status")
132
132
  await statusCommand();
133
133
  });
134
134
  program.command("clean").description("Clean files generated by Coding Friend in docs/").action(async () => {
135
- const { cleanCommand } = await import("./clean-BJSNDUPN.js");
135
+ const { cleanCommand } = await import("./clean-MSRZSOSO.js");
136
136
  await cleanCommand();
137
137
  });
138
138
  var session = program.command("session").description("[beta] Save and load Claude Code sessions across machines");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coding-friend-cli",
3
- "version": "1.38.3",
3
+ "version": "1.38.4",
4
4
  "description": "CLI for coding-friend — host learning docs, setup MCP server, initialize projects",
5
5
  "type": "module",
6
6
  "bin": {