@imenam/mcp-documentor 1.0.90 → 1.0.92
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/README.md +3 -3
- package/dist/src/gui-worker.js +52 -68
- package/dist/src/index.js +8 -1
- package/dist/src/tools/get-doc-metadata.js +2 -0
- package/dist/src/tools/git-diff-doc.js +10 -5
- package/gui/dist/assets/{arc-VljQAUvA.js → arc-BbedxJ3W.js} +1 -1
- package/gui/dist/assets/{architectureDiagram-3BPJPVTR-lbkjtvmN.js → architectureDiagram-3BPJPVTR-DF3IYwLZ.js} +1 -1
- package/gui/dist/assets/{blockDiagram-GPEHLZMM-G4A-rV4c.js → blockDiagram-GPEHLZMM-CgILcS8Q.js} +1 -1
- package/gui/dist/assets/{c4Diagram-AAUBKEIU-Dq3aMw8v.js → c4Diagram-AAUBKEIU-ByGBdJcU.js} +1 -1
- package/gui/dist/assets/channel-CIJsZK_a.js +1 -0
- package/gui/dist/assets/{chunk-2J33WTMH-VSzyIJHo.js → chunk-2J33WTMH-DIk0ZeJ6.js} +1 -1
- package/gui/dist/assets/{chunk-4BX2VUAB-DER41q8w.js → chunk-4BX2VUAB-fF78mC-G.js} +1 -1
- package/gui/dist/assets/{chunk-55IACEB6-BlOGGRk4.js → chunk-55IACEB6-BzoqbAWn.js} +1 -1
- package/gui/dist/assets/{chunk-727SXJPM-Dv3Ay2KV.js → chunk-727SXJPM-B0BlALdx.js} +1 -1
- package/gui/dist/assets/{chunk-AQP2D5EJ-BycHHbwh.js → chunk-AQP2D5EJ-DlKhB6LK.js} +1 -1
- package/gui/dist/assets/{chunk-FMBD7UC4-DBoCiqpY.js → chunk-FMBD7UC4-DBTqXHP1.js} +1 -1
- package/gui/dist/assets/{chunk-ND2GUHAM-DGKypjhb.js → chunk-ND2GUHAM-BmMICe1L.js} +1 -1
- package/gui/dist/assets/{chunk-QZHKN3VN-B8Gn_mBo.js → chunk-QZHKN3VN-DyEBqCzf.js} +1 -1
- package/gui/dist/assets/classDiagram-4FO5ZUOK-LzEGnqT7.js +1 -0
- package/gui/dist/assets/classDiagram-v2-Q7XG4LA2-LzEGnqT7.js +1 -0
- package/gui/dist/assets/{cose-bilkent-S5V4N54A-DyamTuYj.js → cose-bilkent-S5V4N54A-DMkNiOVz.js} +1 -1
- package/gui/dist/assets/{dagre-BM42HDAG-BKC5D2WN.js → dagre-BM42HDAG-CEGX5APR.js} +1 -1
- package/gui/dist/assets/{diagram-2AECGRRQ-BV2lBpwH.js → diagram-2AECGRRQ-DHo40rfh.js} +1 -1
- package/gui/dist/assets/{diagram-5GNKFQAL-DGwbAj4W.js → diagram-5GNKFQAL-CPbyX-Jj.js} +1 -1
- package/gui/dist/assets/{diagram-KO2AKTUF-CZAde8Sg.js → diagram-KO2AKTUF-B-LnaXtr.js} +1 -1
- package/gui/dist/assets/{diagram-LMA3HP47-fQfo0z7i.js → diagram-LMA3HP47-gjnm6GxN.js} +1 -1
- package/gui/dist/assets/{diagram-OG6HWLK6-BlD3VAFM.js → diagram-OG6HWLK6-B_qc7WBs.js} +1 -1
- package/gui/dist/assets/{erDiagram-TEJ5UH35-DPUEmQfe.js → erDiagram-TEJ5UH35-B7jlXuub.js} +1 -1
- package/gui/dist/assets/{flowDiagram-I6XJVG4X-p2HfkBjW.js → flowDiagram-I6XJVG4X-BjWyZsCs.js} +1 -1
- package/gui/dist/assets/{ganttDiagram-6RSMTGT7-CWfFoy4g.js → ganttDiagram-6RSMTGT7-CGdvXL_7.js} +1 -1
- package/gui/dist/assets/{gitGraphDiagram-PVQCEYII-DkTKzmes.js → gitGraphDiagram-PVQCEYII-TxUcHrcr.js} +1 -1
- package/gui/dist/assets/{index-BJ4WCWig.css → index-ARDnpfWR.css} +1 -1
- package/gui/dist/assets/{index-C8LVeAsA.js → index-CrG0yj-K.js} +93 -96
- package/gui/dist/assets/{infoDiagram-5YYISTIA-CXHTqZoU.js → infoDiagram-5YYISTIA-BElIHd-R.js} +1 -1
- package/gui/dist/assets/{ishikawaDiagram-YF4QCWOH-DZ61Cc8a.js → ishikawaDiagram-YF4QCWOH-De4Ds8bG.js} +1 -1
- package/gui/dist/assets/{journeyDiagram-JHISSGLW-qYtEmFuB.js → journeyDiagram-JHISSGLW-Cjpgxilg.js} +1 -1
- package/gui/dist/assets/{kanban-definition-UN3LZRKU-Bs-W313s.js → kanban-definition-UN3LZRKU-D8Y_Af2d.js} +1 -1
- package/gui/dist/assets/{linear-CU6J91M5.js → linear-BB2LhUqA.js} +1 -1
- package/gui/dist/assets/{mindmap-definition-RKZ34NQL-CvBqAH4c.js → mindmap-definition-RKZ34NQL-Cq_fBarD.js} +1 -1
- package/gui/dist/assets/{pieDiagram-4H26LBE5-BD2UcQce.js → pieDiagram-4H26LBE5-LGkTEx-6.js} +1 -1
- package/gui/dist/assets/{quadrantDiagram-W4KKPZXB-DEuynlP9.js → quadrantDiagram-W4KKPZXB-mgy_9RRW.js} +1 -1
- package/gui/dist/assets/{requirementDiagram-4Y6WPE33-DPxfzOF3.js → requirementDiagram-4Y6WPE33-B_d8OEc3.js} +1 -1
- package/gui/dist/assets/{sankeyDiagram-5OEKKPKP-C70_cePR.js → sankeyDiagram-5OEKKPKP-BgBLM80u.js} +1 -1
- package/gui/dist/assets/{sequenceDiagram-3UESZ5HK-FDb_1B1W.js → sequenceDiagram-3UESZ5HK-B9GkqtWb.js} +1 -1
- package/gui/dist/assets/{stateDiagram-AJRCARHV-BH1bq2it.js → stateDiagram-AJRCARHV-UoRM2vqX.js} +1 -1
- package/gui/dist/assets/stateDiagram-v2-BHNVJYJU-B7m-qaHs.js +1 -0
- package/gui/dist/assets/{timeline-definition-PNZ67QCA-DNUx0JIp.js → timeline-definition-PNZ67QCA-Dyx58rRr.js} +1 -1
- package/gui/dist/assets/{vennDiagram-CIIHVFJN-DEAfzbjb.js → vennDiagram-CIIHVFJN-IypthVr7.js} +1 -1
- package/gui/dist/assets/{wardley-L42UT6IY-_REPWPb-.js → wardley-L42UT6IY-DkLzWKUw.js} +1 -1
- package/gui/dist/assets/{wardleyDiagram-YWT4CUSO-CZFLXFE3.js → wardleyDiagram-YWT4CUSO-98VafNiZ.js} +1 -1
- package/gui/dist/assets/{xychartDiagram-2RQKCTM6-P2Nhif6M.js → xychartDiagram-2RQKCTM6-dZj2dDaC.js} +1 -1
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/gui/dist/assets/channel-DFvG2cZZ.js +0 -1
- package/gui/dist/assets/classDiagram-4FO5ZUOK-B8xEoAMI.js +0 -1
- package/gui/dist/assets/classDiagram-v2-Q7XG4LA2-B8xEoAMI.js +0 -1
- package/gui/dist/assets/stateDiagram-v2-BHNVJYJU-BfpDu1Qi.js +0 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Connect it to Cursor, Claude Desktop, or any MCP-compatible agent to let your AI
|
|
|
12
12
|
- **Track a branch, not a checkout** — point a project at a GitHub branch from its settings in the GUI and freshness is measured against *published* code: switching branches or editing without committing no longer makes docs look stale, and a server with no copy of the codebase (an MCP gateway) can still verify them
|
|
13
13
|
- **Semantic search** — find relevant docs by meaning (requires an OpenAI API key)
|
|
14
14
|
- **Multi-project support** — organize docs into separate projects; every MCP tool names the project it targets, and the GUI's project selector is a per-browser view preference
|
|
15
|
-
- **GUI** — built-in web interface, either behind the proxy (`PROXY_URL`) or served directly on a local port (`APP_PORT`); with neither, the GUI worker is not started. Navigation runs from an icon rail on the left: the current project's badge (click to switch projects or create one), then Documentation, Search (`Ctrl/⌘ + K`, current or all projects), Outdated, Recent, Export bundles and Logs, with Sync and Settings at the bottom. Each destination fills the panel next to the rail; the panel's hide button, or a second click on the active icon, folds it away. Drag the panel's right edge to resize it (double-click resets the width); the browser remembers the width. The details panel on the right of a document (`Ctrl/⌘ + \`) is open by default from 1280 px wide; showing or hiding it by hand is remembered across reloads until the window crosses that width. Badges show the outdated docs, pending commits and the day's failed GitHub calls
|
|
15
|
+
- **GUI** — built-in web interface, either behind the proxy (`PROXY_URL`) or served directly on a local port (`APP_PORT`); with neither, the GUI worker is not started. Navigation runs from an icon rail on the left: the current project's badge (click to switch projects or create one), then Documentation, Search (`Ctrl/⌘ + K`, current or all projects), Outdated, Recent, Export bundles and Logs, with Sync and Settings at the bottom. Each destination fills the panel next to the rail; the panel's hide button, or a second click on the active icon, folds it away. Drag the panel's right edge to resize it (double-click resets the width); the browser remembers the width. The details panel on the right of a document (`Ctrl/⌘ + \`) is open by default from 1280 px wide; showing or hiding it by hand is remembered across reloads until the window crosses that width. Badges show the outdated docs, pending commits and the day's failed GitHub calls. Each open tab polls `GET /api/changes` every 3 seconds and every request is answered immediately: no connection stays open, so many tabs can share the proxy's origin, and changes made by the agent show up within 3 seconds. After a GUI worker restart, or when it has fallen more than 200 changes behind, the tab reloads the server state (`GET /api/initial-state`) and the list of the project it shows
|
|
16
16
|
- **Proxy-aware** — integrates with the [proxy-setup](https://github.com/Imena/proxy-setup) for GUI exposure
|
|
17
17
|
- **Links & structure** — `check_links`, `get_doc_tree`, `move_doc`, and `git_diff_doc` for maintenance workflows
|
|
18
18
|
- **Image support** — upload images to a project's assets via `upload_image` (local file path) or directly from the GUI editor; images are stored per-project and rendered inline in the viewer and in PDF exports
|
|
@@ -127,7 +127,7 @@ that work on a whole project (`list_docs`, `get_doc_tree`, `check_freshness` wit
|
|
|
127
127
|
| `search_docs` | Semantic search over docs (natural language; requires OpenAI) |
|
|
128
128
|
| `check_freshness` | Staleness for one doc (`project` required) or a full project scan |
|
|
129
129
|
| `refresh_file_snapshot` | Mark tracked files as up-to-date without editing the doc (`project` required) |
|
|
130
|
-
| `git_diff_doc` | Diff of changed tracked files between their snapshot content and the current one (`project` required) |
|
|
130
|
+
| `git_diff_doc` | Diff of changed tracked files between their snapshot content and the current one (`project` required). Files whose tracked sections can no longer be located (anchors lost) are included and diffed whole, with a warning |
|
|
131
131
|
| `check_links` | Validate `related_docs`, `doc://` links, and `#heading` anchors (`project` required) |
|
|
132
132
|
| `list_projects` | List all documentation projects |
|
|
133
133
|
| `upload_image` | Upload an image from a local file path to a project's assets (`project` required); returns the markdown link to insert |
|
|
@@ -320,7 +320,7 @@ Everything else is content-addressed: a commit's tree is cached by its sha for t
|
|
|
320
320
|
|
|
321
321
|
By default, data lives under **`.docs-data`** next to the resolved package root (the folder that contains `package.json` for the running install). Set **`MCP_DATA_DIR`** to use another directory. Contents include projects, SQLite/embeddings, and logs under `.docs-data/logs`. This tree is **not** part of the npm package; it is created at runtime.
|
|
322
322
|
|
|
323
|
-
There is no server-side "active project": every MCP tool call names its project, and the GUI's selector only changes what that browser displays (kept in the URL and in `localStorage`). A legacy `currentProject` left in `config.json` is dropped on first read. GitHub sync settings live in environment variables, not on disk.
|
|
323
|
+
There is no server-side "active project": every MCP tool call names its project, and the GUI's selector only changes what that browser displays (kept in the URL and in `localStorage`). The open and closed folders of each project's navigation tree are also kept in `localStorage`, so a reload restores them. A legacy `currentProject` left in `config.json` is dropped on first read. GitHub sync settings live in environment variables, not on disk.
|
|
324
324
|
|
|
325
325
|
## License
|
|
326
326
|
|
package/dist/src/gui-worker.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { serve } from "@hono/node-server";
|
|
2
2
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
3
3
|
import { Hono } from "hono";
|
|
4
|
-
import { streamSSE } from "hono/streaming";
|
|
5
4
|
import { GUI_LISTEN_HOST, ProxyClient, honoGuiGuard } from "@imenam/mcp-gui-interface";
|
|
6
5
|
import { IPCMessageSchema } from "../shared/schemas/doc.schema.js";
|
|
7
6
|
import { isReadOnly } from "../shared/read-only.js";
|
|
@@ -9,6 +8,7 @@ import path from "path";
|
|
|
9
8
|
import fs from "fs";
|
|
10
9
|
import { execFile, spawn } from "child_process";
|
|
11
10
|
import { Readable } from "stream";
|
|
11
|
+
import { randomUUID } from "crypto";
|
|
12
12
|
import { promisify } from "util";
|
|
13
13
|
const execFileAsync = promisify(execFile);
|
|
14
14
|
import { fileURLToPath } from "url";
|
|
@@ -129,7 +129,6 @@ let guiPublicUrl = '';
|
|
|
129
129
|
const app = new Hono();
|
|
130
130
|
app.use("*", honoGuiGuard());
|
|
131
131
|
let proxyClient = null;
|
|
132
|
-
const sseControllers = new Set();
|
|
133
132
|
const pendingRequests = new Map();
|
|
134
133
|
function safeSend(message) {
|
|
135
134
|
if (process.send && process.connected) {
|
|
@@ -171,6 +170,27 @@ function ipcRequest(type, data, timeout = 5000) {
|
|
|
171
170
|
}
|
|
172
171
|
});
|
|
173
172
|
}
|
|
173
|
+
/** Message types the master pushes to every GUI, journaled for `/api/changes`. */
|
|
174
|
+
const BROADCAST_TYPES = [
|
|
175
|
+
"INITIAL_STATE",
|
|
176
|
+
"CONFIG_UPDATED",
|
|
177
|
+
"BUNDLES_UPDATED",
|
|
178
|
+
"PROJECTS_CHANGED",
|
|
179
|
+
"DOCS_CHANGED",
|
|
180
|
+
"CODE_SOURCES_CHANGED",
|
|
181
|
+
];
|
|
182
|
+
/** Number of pushed messages kept for clients catching up. */
|
|
183
|
+
const CHANGE_JOURNAL_SIZE = 200;
|
|
184
|
+
/** Identifies this worker run: a client holding another epoch has missed everything since. */
|
|
185
|
+
const workerEpoch = randomUUID();
|
|
186
|
+
let changeSeq = 0;
|
|
187
|
+
const changeJournal = [];
|
|
188
|
+
function recordChange(message) {
|
|
189
|
+
changeSeq += 1;
|
|
190
|
+
changeJournal.push({ seq: changeSeq, message });
|
|
191
|
+
if (changeJournal.length > CHANGE_JOURNAL_SIZE)
|
|
192
|
+
changeJournal.shift();
|
|
193
|
+
}
|
|
174
194
|
function setupIpcErrorHandlers() {
|
|
175
195
|
process.on("error", (err) => {
|
|
176
196
|
if (err.code === "ERR_IPC_CHANNEL_CLOSED")
|
|
@@ -179,7 +199,7 @@ function setupIpcErrorHandlers() {
|
|
|
179
199
|
});
|
|
180
200
|
process.on("disconnect", () => {
|
|
181
201
|
logger.warn("IPC disconnected from MCP master (parent closed the channel or process exited). " +
|
|
182
|
-
"GUI worker will exit
|
|
202
|
+
"GUI worker will exit.");
|
|
183
203
|
process.exit(0);
|
|
184
204
|
});
|
|
185
205
|
process.on("message", (msg) => {
|
|
@@ -199,24 +219,8 @@ function setupIpcErrorHandlers() {
|
|
|
199
219
|
});
|
|
200
220
|
return;
|
|
201
221
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
"CONFIG_UPDATED",
|
|
205
|
-
"BUNDLES_UPDATED",
|
|
206
|
-
"PROJECTS_CHANGED",
|
|
207
|
-
"DOCS_CHANGED",
|
|
208
|
-
"CODE_SOURCES_CHANGED",
|
|
209
|
-
];
|
|
210
|
-
if (msg && BROADCAST_TYPES.includes(msg.type)) {
|
|
211
|
-
for (const controller of sseControllers) {
|
|
212
|
-
try {
|
|
213
|
-
controller.writeSSE({ data: JSON.stringify(msg), event: "message" });
|
|
214
|
-
}
|
|
215
|
-
catch {
|
|
216
|
-
sseControllers.delete(controller);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
222
|
+
if (msg && BROADCAST_TYPES.includes(msg.type))
|
|
223
|
+
recordChange(msg);
|
|
220
224
|
});
|
|
221
225
|
}
|
|
222
226
|
// --- HTTP Routes ---
|
|
@@ -251,54 +255,34 @@ app.get("/proxy/health", (c) => {
|
|
|
251
255
|
timestamp: new Date().toISOString(),
|
|
252
256
|
});
|
|
253
257
|
});
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
}
|
|
275
|
-
catch (err) {
|
|
276
|
-
logger.warn(`SSE /api/events: initial writeSSE failed (id=${clientId}): ${err?.message ?? err}`);
|
|
277
|
-
sseControllers.delete(stream);
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
while (true) {
|
|
281
|
-
await stream.sleep(30000);
|
|
282
|
-
try {
|
|
283
|
-
await stream.writeSSE({ data: "ping", event: "ping" });
|
|
284
|
-
}
|
|
285
|
-
catch (err) {
|
|
286
|
-
logger.warn(`SSE /api/events: keepalive ping failed (id=${clientId}): ${err?.message ?? err}`);
|
|
287
|
-
sseControllers.delete(stream);
|
|
288
|
-
break;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
258
|
+
// Answers immediately with the pushed messages after `since`, or `reset: true` when the
|
|
259
|
+
// client must reload the whole state: no cursor, another worker run, or messages dropped.
|
|
260
|
+
app.get("/api/changes", (c) => {
|
|
261
|
+
const since = c.req.query("since");
|
|
262
|
+
const epoch = c.req.query("epoch");
|
|
263
|
+
if (since !== undefined && !/^\d+$/.test(since)) {
|
|
264
|
+
return c.json({ error: `since must be a non-negative integer, got "${since}"` }, 400);
|
|
265
|
+
}
|
|
266
|
+
const reset = { epoch: workerEpoch, seq: changeSeq, reset: true };
|
|
267
|
+
if (since === undefined || epoch !== workerEpoch)
|
|
268
|
+
return c.json(reset);
|
|
269
|
+
const from = Number(since);
|
|
270
|
+
const oldestKept = changeJournal.length > 0 ? changeJournal[0].seq : changeSeq + 1;
|
|
271
|
+
if (from > changeSeq || from < oldestKept - 1)
|
|
272
|
+
return c.json(reset);
|
|
273
|
+
return c.json({
|
|
274
|
+
epoch: workerEpoch,
|
|
275
|
+
seq: changeSeq,
|
|
276
|
+
reset: false,
|
|
277
|
+
events: changeJournal.filter((entry) => entry.seq > from).map((entry) => entry.message),
|
|
291
278
|
});
|
|
292
279
|
});
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
logger.warn(`Client diagnostics: invalid JSON body (${e?.message ?? e})`);
|
|
300
|
-
}
|
|
301
|
-
return c.json({ ok: true });
|
|
280
|
+
// Server-side state a client loads on start and after each reset.
|
|
281
|
+
app.get("/api/initial-state", async (c) => {
|
|
282
|
+
const result = await ipcRequest("GET_INITIAL_STATE");
|
|
283
|
+
if (result.error)
|
|
284
|
+
return c.json({ error: result.error }, 500);
|
|
285
|
+
return c.json(result.data);
|
|
302
286
|
});
|
|
303
287
|
app.get("/api/configurations", async (c) => {
|
|
304
288
|
const configRes = await ipcRequest("GET_CONFIG");
|
|
@@ -700,7 +684,7 @@ app.get("/api/export-zip/:id", async (c) => {
|
|
|
700
684
|
docId = ref;
|
|
701
685
|
}
|
|
702
686
|
else {
|
|
703
|
-
zip.file(`${ref}.md`, `# [Unqualified doc reference: ${ref} — no project given]
|
|
687
|
+
zip.file(`${ref}.md`, `# [Unqualified doc reference: ${ref} — no project given]
|
|
704
688
|
`);
|
|
705
689
|
continue;
|
|
706
690
|
}
|
package/dist/src/index.js
CHANGED
|
@@ -120,7 +120,6 @@ let guiLauncher;
|
|
|
120
120
|
let guiStatus = "disabled";
|
|
121
121
|
let guiUrl = null;
|
|
122
122
|
let guiStartWaiter = null;
|
|
123
|
-
const sseControllers = new Set();
|
|
124
123
|
function broadcastToGUI(message) {
|
|
125
124
|
const child = guiLauncher.getProcess();
|
|
126
125
|
if (child?.connected) {
|
|
@@ -359,6 +358,14 @@ async function handleGetInitialState(msg) {
|
|
|
359
358
|
}
|
|
360
359
|
catch (err) {
|
|
361
360
|
logger.error(`Failed to get initial state: ${err.message}`);
|
|
361
|
+
if (msg.correlationId) {
|
|
362
|
+
broadcastToGUI({
|
|
363
|
+
type: "INITIAL_STATE",
|
|
364
|
+
correlationId: msg.correlationId,
|
|
365
|
+
error: err.message,
|
|
366
|
+
timestamp: new Date().toISOString(),
|
|
367
|
+
});
|
|
368
|
+
}
|
|
362
369
|
}
|
|
363
370
|
}
|
|
364
371
|
async function handleGetConfig(msg) {
|
|
@@ -18,6 +18,8 @@ export async function getDocMetadata(storageEngine, args) {
|
|
|
18
18
|
return "✗ modified";
|
|
19
19
|
if (report.missing.includes(filePath))
|
|
20
20
|
return "✗ missing";
|
|
21
|
+
if (report.anchors_lost.includes(filePath))
|
|
22
|
+
return "⚠ anchors lost (re-declare the sections via update_doc)";
|
|
21
23
|
return "✓ up to date";
|
|
22
24
|
};
|
|
23
25
|
let text = `**Path:** ${doc.id}\n`;
|
|
@@ -163,15 +163,16 @@ export async function gitDiffDoc(storageEngine, args) {
|
|
|
163
163
|
docSections.push(`## ${doc.title}\n\n[INFO] No tracked files.`);
|
|
164
164
|
continue;
|
|
165
165
|
}
|
|
166
|
+
const freshness = await computeFreshness(doc.tracked_files, project);
|
|
167
|
+
const anchorsLost = new Set(freshness.anchors_lost);
|
|
166
168
|
let filesToDiff;
|
|
167
169
|
if (wanted) {
|
|
168
170
|
filesToDiff = doc.tracked_files.filter((tf) => wanted.has(tf.path));
|
|
169
171
|
}
|
|
170
172
|
else {
|
|
171
|
-
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
const changedPaths = new Set([...freshness.modified, ...freshness.missing, ...freshness.broken]);
|
|
173
|
+
// Broken entries (no snapshot) and files whose sections can no longer be located can't be
|
|
174
|
+
// hash-compared, but the whole-file diff is the best signal the agent has to re-assess them.
|
|
175
|
+
const changedPaths = new Set([...freshness.modified, ...freshness.missing, ...freshness.broken, ...anchorsLost]);
|
|
175
176
|
filesToDiff = doc.tracked_files.filter((tf) => changedPaths.has(tf.path));
|
|
176
177
|
}
|
|
177
178
|
if (filesToDiff.length === 0) {
|
|
@@ -194,7 +195,11 @@ export async function gitDiffDoc(storageEngine, args) {
|
|
|
194
195
|
const diffs = await mapWithConcurrency(fresh, FILE_CONCURRENCY, (tf) => diffTrackedFile(tf, project, source));
|
|
195
196
|
const fileSections = fresh.map((tf, i) => {
|
|
196
197
|
const base = tf.sourceRevision ? `\nSnapshot commit: ${short(tf.sourceRevision)}` : "";
|
|
197
|
-
|
|
198
|
+
const anchorsNote = anchorsLost.has(tf.path)
|
|
199
|
+
? ` [WARN] Anchors lost: the tracked section(s) can no longer be located, so the whole file is diffed.\n` +
|
|
200
|
+
` → Re-declare the sections in tracked_files via update_doc.\n\n`
|
|
201
|
+
: "";
|
|
202
|
+
return `### ${tf.path}\nSnapshot date: ${tf.lastModifiedAt}${base}\n\n${anchorsNote}${diffs[i]}`;
|
|
198
203
|
});
|
|
199
204
|
docSections.push(`## ${doc.title} [${docPath}]\n\nCode source: ${source.label}\n\n${fileSections.join("\n\n---\n\n")}`);
|
|
200
205
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a0 as ln,a1 as an,a2 as y,a3 as tn,a4 as H,a5 as q,a6 as _,a7 as un,a8 as rn,a9 as L,aa as o,ab as B,ac as sn,ad as on,ae as fn}from"./index-
|
|
1
|
+
import{a0 as ln,a1 as an,a2 as y,a3 as tn,a4 as H,a5 as q,a6 as _,a7 as un,a8 as rn,a9 as L,aa as o,ab as B,ac as sn,ad as on,ae as fn}from"./index-CrG0yj-K.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,C,a){var O=I-l,i=D-h,n=C-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function W(l,h,I,D,v,A,C){var a=l-I,O=h-D,i=(C?A:-A)/L(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,F=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*L(fn(0,T*T*R-P*P)),j=(P*g-m*S)/R,z=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=j-F,e=z-t,r=w-F,G=p-t;return x*x+e*e>r*r+G*G&&(j=w,z=p),{cx:j,cy:z,x01:-n,y01:-d,x11:j*(v/T-1),y11:z*(v/T-1)}}function hn(){var l=cn,h=yn,I=B(0),D=null,v=gn,A=dn,C=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-an,c=A.apply(this,arguments)-an,F=un(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(F>tn-y)a.moveTo(s*H(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*H(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=F,S=F,j=C.apply(this,arguments)/2,z=j>y&&(D?+D.apply(this,arguments):L(u*u+s*s)),w=_(un(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if(z>y){var G=sn(z/u*q(j)),M=sn(z/s*q(j));(P-=G*2)>y?(G*=t?1:-1,R+=G,T-=G):(P=0,R=T=(f+c)/2),(S-=M*2)>y?(M*=t?1:-1,m+=M,g-=M):(S=0,m=g=(f+c)/2)}var J=s*H(m),K=s*q(m),N=u*H(T),Q=u*q(T);if(w>y){var U=s*H(g),V=s*q(g),X=u*H(R),Y=u*q(R),E;if(F<rn)if(E=pn(J,K,X,Y,U,V,N,Q)){var Z=J-E[0],$=K-E[1],b=U-E[0],k=V-E[1],nn=1/q(on((Z*b+$*k)/(L(Z*Z+$*$)*L(b*b+k*k)))/2),en=L(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=W(X,Y,J,K,s,x,t),r=W(U,V,N,Q,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(J,K),a.arc(0,0,s,m,g,!t)):a.moveTo(J,K),!(u>y)||!(P>y)?a.lineTo(N,Q):p>y?(e=W(N,Q,U,V,u,-p,t),r=W(J,K,X,Y,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-rn/2;return[H(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:B(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:B(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:B(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:B(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:B(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:B(+n),i):A},i.padAngle=function(n){return arguments.length?(C=typeof n=="function"?n:B(+n),i):C},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
|