@imenam/mcp-documentor 1.0.35 → 1.0.36

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.
@@ -81,6 +81,7 @@ export declare const FreshnessReportSchema: z.ZodObject<{
81
81
  modified: z.ZodArray<z.ZodString>;
82
82
  missing: z.ZodArray<z.ZodString>;
83
83
  unchanged: z.ZodArray<z.ZodString>;
84
+ anchors_lost: z.ZodDefault<z.ZodArray<z.ZodString>>;
84
85
  total: z.ZodNumber;
85
86
  }, z.core.$strip>;
86
87
  export type FreshnessReport = z.infer<typeof FreshnessReportSchema>;
@@ -39,6 +39,7 @@ export const FreshnessReportSchema = z.object({
39
39
  modified: z.array(z.string()),
40
40
  missing: z.array(z.string()),
41
41
  unchanged: z.array(z.string()),
42
+ anchors_lost: z.array(z.string()).default([]),
42
43
  total: z.number(),
43
44
  });
44
45
  export const CreateDocArgsSchema = z.object({
@@ -8,11 +8,12 @@ export function computeFileHash(absolutePath) {
8
8
  }
9
9
  export function computeFreshness(trackedFiles) {
10
10
  if (!trackedFiles || trackedFiles.length === 0) {
11
- return { status: "no_tracking", modified: [], missing: [], unchanged: [], total: 0 };
11
+ return { status: "no_tracking", modified: [], missing: [], unchanged: [], anchors_lost: [], total: 0 };
12
12
  }
13
13
  const modified = [];
14
14
  const missing = [];
15
15
  const unchanged = [];
16
+ const anchors_lost = [];
16
17
  for (const tracked of trackedFiles) {
17
18
  const absolutePath = path.resolve(process.cwd(), tracked.path);
18
19
  if (!fs.existsSync(absolutePath)) {
@@ -21,15 +22,26 @@ export function computeFreshness(trackedFiles) {
21
22
  }
22
23
  if (tracked.sections && tracked.sections.length > 0) {
23
24
  let sectionStale = false;
25
+ let anchorLost = false;
24
26
  for (const section of tracked.sections) {
25
27
  const result = findAndHashSection(absolutePath, section);
26
- if (!result.found || result.currentHash !== section.sectionHash) {
28
+ if (!result.found) {
29
+ sectionStale = true;
30
+ anchorLost = true;
31
+ break;
32
+ }
33
+ else if (result.currentHash !== section.sectionHash) {
27
34
  sectionStale = true;
28
35
  break;
29
36
  }
30
37
  }
31
38
  if (sectionStale) {
32
- modified.push(tracked.path);
39
+ if (anchorLost) {
40
+ anchors_lost.push(tracked.path);
41
+ }
42
+ else {
43
+ modified.push(tracked.path);
44
+ }
33
45
  }
34
46
  else {
35
47
  unchanged.push(tracked.path);
@@ -56,12 +68,13 @@ export function computeFreshness(trackedFiles) {
56
68
  }
57
69
  }
58
70
  }
59
- const isStale = modified.length > 0 || missing.length > 0;
71
+ const isStale = modified.length > 0 || missing.length > 0 || anchors_lost.length > 0;
60
72
  return {
61
73
  status: isStale ? "stale" : "up_to_date",
62
74
  modified,
63
75
  missing,
64
76
  unchanged,
77
+ anchors_lost,
65
78
  total: trackedFiles.length,
66
79
  };
67
80
  }
@@ -72,13 +85,19 @@ export function formatFreshnessReport(title, report) {
72
85
  let text = report.status === "stale"
73
86
  ? `STALE: "${title}" — tracked files have changed since the documentation was last updated.\n`
74
87
  : `UP TO DATE: "${title}" — no tracked files have been modified.\n`;
75
- text += `\nSummary: ${report.modified.length} modified, ${report.missing.length} missing, ${report.unchanged.length} unchanged out of ${report.total} tracked file(s).`;
88
+ const anchorLostCount = report.anchors_lost?.length ?? 0;
89
+ text += `\nSummary: ${report.modified.length} modified, ${report.missing.length} missing, ${anchorLostCount} with lost anchors, ${report.unchanged.length} unchanged out of ${report.total} tracked file(s).`;
76
90
  if (report.modified.length > 0) {
77
- text += `\n\nModified files:\n${report.modified.map((f) => ` - ${f}`).join("\n")}`;
91
+ text += `\n\nModified files (call refresh_file_snapshot to acknowledge):\n${report.modified.map((f) => ` - ${f}`).join("\n")}`;
78
92
  }
79
93
  if (report.missing.length > 0) {
80
94
  text += `\n\nMissing files:\n${report.missing.map((f) => ` - ${f}`).join("\n")}`;
81
95
  }
96
+ if (anchorLostCount > 0) {
97
+ text += `\n\n⚠ Files with lost anchors — refresh_file_snapshot cannot fix this:\n${report.anchors_lost.map((f) => ` - ${f}`).join("\n")}`;
98
+ text += `\n → The tracked section(s) could not be located in the current file content (anchors were likely modified by a recent commit).`;
99
+ text += `\n → Required action: call update_doc with the new line numbers to re-establish section tracking.`;
100
+ }
82
101
  return text;
83
102
  }
84
103
  export async function checkFreshness(storageEngine, args) {
@@ -113,6 +132,7 @@ export async function checkFreshness(storageEngine, args) {
113
132
  const details = [
114
133
  ...report.modified.map((f) => ` • modified: ${f}`),
115
134
  ...report.missing.map((f) => ` • missing: ${f}`),
135
+ ...(report.anchors_lost ?? []).map((f) => ` • ⚠ anchors lost (needs update_doc): ${f}`),
116
136
  ].join("\n");
117
137
  stale.push(` - **${doc.title}** [${doc.id}]\n${details}`);
118
138
  }
@@ -153,6 +173,7 @@ export async function checkFreshness(storageEngine, args) {
153
173
  const details = [
154
174
  ...report.modified.map((f) => ` • modified: ${f}`),
155
175
  ...report.missing.map((f) => ` • missing: ${f}`),
176
+ ...(report.anchors_lost ?? []).map((f) => ` • ⚠ anchors lost (needs update_doc): ${f}`),
156
177
  ].join("\n");
157
178
  stale.push(` - **${doc.title}** [${doc.id}]\n${details}`);
158
179
  }
@@ -16,6 +16,7 @@ export async function refreshFileSnapshot(storageEngine, historyStore, args) {
16
16
  const refreshed = [];
17
17
  const missing = [];
18
18
  const skipped = [];
19
+ const anchorsLost = [];
19
20
  for (const tracked of doc.tracked_files) {
20
21
  if (validated.file_paths && !validated.file_paths.includes(tracked.path)) {
21
22
  skipped.push(tracked.path);
@@ -27,24 +28,38 @@ export async function refreshFileSnapshot(storageEngine, historyStore, args) {
27
28
  }
28
29
  tracked.lastModifiedAt = fs.statSync(tracked.path).mtime.toISOString();
29
30
  if (tracked.sections && tracked.sections.length > 0) {
31
+ let hasLostAnchors = false;
30
32
  const refreshedSections = tracked.sections.map((section) => {
31
33
  const result = relocateAndRefreshSection(tracked.path, section);
34
+ if (!result.found)
35
+ hasLostAnchors = true;
32
36
  return result.found ? result.refreshed : section;
33
37
  });
34
38
  tracked.sections = refreshedSections;
39
+ if (hasLostAnchors) {
40
+ anchorsLost.push(tracked.path);
41
+ }
42
+ else {
43
+ refreshed.push(tracked.path);
44
+ }
35
45
  }
36
46
  else {
37
47
  tracked.contentHash = computeFileHash(tracked.path);
48
+ refreshed.push(tracked.path);
38
49
  }
39
- refreshed.push(tracked.path);
40
50
  }
41
51
  await storageEngine.saveDoc(doc, resolvedProject);
42
52
  historyStore.record(resolvedProject, doc, "snapshot");
43
- let section = `**${doc.title}** [${docPath}]: refreshed ${refreshed.length}, missing ${missing.length}, skipped ${skipped.length}`;
53
+ let section = `**${doc.title}** [${docPath}]: refreshed ${refreshed.length}, anchors lost ${anchorsLost.length}, missing ${missing.length}, skipped ${skipped.length}`;
44
54
  if (refreshed.length > 0)
45
55
  section += `\n${refreshed.map((f) => ` ✓ ${f}`).join("\n")}`;
46
56
  if (missing.length > 0)
47
- section += `\n${missing.map((f) => ` ✗ ${f}`).join("\n")}`;
57
+ section += `\n${missing.map((f) => ` ✗ missing: ${f}`).join("\n")}`;
58
+ if (anchorsLost.length > 0) {
59
+ section += `\n${anchorsLost.map((f) => ` ⚠ anchors lost: ${f}`).join("\n")}`;
60
+ section += `\n → refresh_file_snapshot cannot fix this. The tracked section(s) could not be located in the current file content.`;
61
+ section += `\n → Required action: call update_doc with the new line numbers to re-establish section tracking.`;
62
+ }
48
63
  docSections.push(section);
49
64
  }
50
65
  return { content: [{ type: "text", text: docSections.join("\n\n") }] };
@@ -1 +1 @@
1
- export declare const APP_VERSION = "1.0.35";
1
+ export declare const APP_VERSION = "1.0.36";
@@ -1,2 +1,2 @@
1
1
  // Auto-generated version file - do not edit manually
2
- export const APP_VERSION = '1.0.35';
2
+ export const APP_VERSION = '1.0.36';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imenam/mcp-documentor",
3
- "version": "1.0.35",
3
+ "version": "1.0.36",
4
4
  "main": "dist/src/index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",