@theronap/cortex-mcp 0.9.110 → 0.9.112
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/lib/server.mjs +41 -6
- package/package.json +1 -1
package/lib/server.mjs
CHANGED
|
@@ -859,7 +859,35 @@ export async function runServer(version) {
|
|
|
859
859
|
const body = await res.text()
|
|
860
860
|
return toolError(body)
|
|
861
861
|
}
|
|
862
|
-
|
|
862
|
+
const body = await res.json()
|
|
863
|
+
// WHERE THE SESSION'S OWN WORK LANDED, in words rather than buried in the JSON dump.
|
|
864
|
+
//
|
|
865
|
+
// Three outcomes that look identical in raw JSON and mean completely different things:
|
|
866
|
+
// null the attach THREW — a real failure, and best-effort swallowed it
|
|
867
|
+
// attached: [] the session authored no page in this brain — the ~85% normal case
|
|
868
|
+
// attached: [...] filed under N pages
|
|
869
|
+
//
|
|
870
|
+
// Reporting only a count would make the first indistinguishable from the second, which is how
|
|
871
|
+
// a broken write hides inside a normal-looking result. `undefined` means the server has not
|
|
872
|
+
// shipped this field yet, so nothing is said rather than something wrong.
|
|
873
|
+
const lines = []
|
|
874
|
+
const sa = body?.sessionAttachments
|
|
875
|
+
if (sa === null) {
|
|
876
|
+
lines.push('⚠ Session-page attachment FAILED for this record — it was written, but not filed under the pages this session wrote. Re-run the reconciler.')
|
|
877
|
+
} else if (sa && Array.isArray(sa.attached)) {
|
|
878
|
+
if (sa.attached.length > 0) {
|
|
879
|
+
lines.push(`Filed under ${sa.attached.length} page(s) this session wrote.`)
|
|
880
|
+
} else {
|
|
881
|
+
lines.push('No pages filed: this session authored none in this brain (the normal case).')
|
|
882
|
+
}
|
|
883
|
+
if (sa.droppedCrossBrain > 0) {
|
|
884
|
+
lines.push(`${sa.droppedCrossBrain} page(s) this session wrote live in another brain and were skipped — a record belongs to one brain.`)
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
const text = lines.length
|
|
888
|
+
? `${lines.join('\n')}\n\n${JSON.stringify(body, null, 2)}`
|
|
889
|
+
: JSON.stringify(body, null, 2)
|
|
890
|
+
return { content: [{ type: 'text', text }] }
|
|
863
891
|
},
|
|
864
892
|
)
|
|
865
893
|
|
|
@@ -1181,7 +1209,10 @@ export async function runServer(version) {
|
|
|
1181
1209
|
// drift again.
|
|
1182
1210
|
const secs = (t.sections ?? []).map((s) => renderSection(s, day)).join('\n\n')
|
|
1183
1211
|
const head = `[${t.tier}${day(t.updated_at) ? ` · authored ${day(t.updated_at)}` : ''}${t.validity && t.validity !== 'current' ? ` · ${t.validity}` : ''}]`
|
|
1184
|
-
|
|
1212
|
+
// ADR-0030 step 3b (2026-08-24): the summary header is NO LONGER RENDERED. It duplicated the
|
|
1213
|
+
// `In short` section byte-for-byte on 6 of 6 pages sampled, so every read paid for the same
|
|
1214
|
+
// text twice. The column stays vestigial; this just stops serving it.
|
|
1215
|
+
return [head, secs].filter(Boolean).join('\n')
|
|
1185
1216
|
})
|
|
1186
1217
|
const brainTag = matches.length > 1 ? ` · brain: ${m.brain}` : ''
|
|
1187
1218
|
return `# ${m.title ?? key} (authored page${brainTag})\n\n${blocks.join('\n\n---\n\n')}`
|
|
@@ -1336,7 +1367,11 @@ export async function runServer(version) {
|
|
|
1336
1367
|
? `\nversion: ${t.version}`
|
|
1337
1368
|
: `\nversion: none (this variant predates content-hash tracking — base_version writes will always fail here; ask an admin about the ADR-0018 backfill)`
|
|
1338
1369
|
const head = `[${t.tier}${day(t.updated_at) ? ` · authored ${day(t.updated_at)}` : ''}${t.validity && t.validity !== 'current' ? ` · ${t.validity}` : ''}${versionLine}]`
|
|
1339
|
-
|
|
1370
|
+
// ADR-0030 step 3b (2026-08-24): the summary header is NO LONGER RENDERED here either.
|
|
1371
|
+
// ⚠ There were TWO of these — project_status and read_page — and the first patch fixed only
|
|
1372
|
+
// project_status, leaving the primary surface untouched. Same granularity miss this repo
|
|
1373
|
+
// keeps recording: a fix applied to the occurrence you happened to find first.
|
|
1374
|
+
return [head, secs].filter(Boolean).join('\n')
|
|
1340
1375
|
})
|
|
1341
1376
|
// REPAIR TOOL (2026-07-31). This footer used to say "re-author just those sections with
|
|
1342
1377
|
// `author`" — which `author` cannot do: computeDroppedSections rejects a partial-section
|
|
@@ -1345,7 +1380,7 @@ export async function runServer(version) {
|
|
|
1345
1380
|
// retype silently deleted a sentence, a [[link]] (a graph edge), a command list and the
|
|
1346
1381
|
// word "today" from sections it was never meant to touch. This footer renders on EVERY
|
|
1347
1382
|
// page read in the system, so it was the single widest surface pointing the wrong way.
|
|
1348
|
-
let footer = `— Follow any [[links]] above with read_page to go deeper.\n— If you hold fresher FIRST-HAND truth than this page — something you established THIS session (ran the command, made the change, hold the artifact) that a section here gets concretely wrong — fix just that passage with \`edit_page\`: quote the wrong text as old_string and pass this page's \`version\` as base_version (any node you are permitted to edit; concise; a material contradiction, not merely extra detail). If the save comes back stale the page changed under you — the conflict hands back what changed, so re-anchor from that instead of re-reading. Reading a stale page you can fix IS the trigger to fix it. Editing is pre-authorized — do NOT ask the user before updating (edits are versioned + reversible via page_history/rollback_page); update, then briefly report it.
|
|
1383
|
+
let footer = `— Follow any [[links]] above with read_page to go deeper.\n— If you hold fresher FIRST-HAND truth than this page — something you established THIS session (ran the command, made the change, hold the artifact) that a section here gets concretely wrong — fix just that passage with \`edit_page\`: quote the wrong text as old_string and pass this page's \`version\` as base_version (any node you are permitted to edit; concise; a material contradiction, not merely extra detail). If the save comes back stale the page changed under you — the conflict hands back what changed, so re-anchor from that instead of re-reading. Reading a stale page you can fix IS the trigger to fix it. Editing is pre-authorized — do NOT ask the user before updating (edits are versioned + reversible via page_history/rollback_page); update, then briefly report it. Use \`author\` only to CREATE a page or rewrite one wholesale: it re-emits every section, so untouched sections get retyped on the way through and drift.\n— Citing code? Use a SYMBOL and file (\`formConnections\` in \`web/app/api/ingest/route.ts\`), never a line number — line numbers drift with every commit above them. And cite only what you opened THIS session; re-emitting a reference you read on another page is how a stale claim gains a second source and starts looking corroborated.`
|
|
1349
1384
|
// ADDRESSING (2026-08-04). The server accepts `ref` on every page/node route and its ambiguity
|
|
1350
1385
|
// 409s hand refs back — but read_page never PRINTED one, so the only way to obtain a ref was to
|
|
1351
1386
|
// trigger the error first. That made ID addressing reachable in principle and unusable in
|
|
@@ -1654,7 +1689,7 @@ export async function runServer(version) {
|
|
|
1654
1689
|
'set_summary',
|
|
1655
1690
|
{
|
|
1656
1691
|
title: 'Rewrite a wiki page summary without touching its sections',
|
|
1657
|
-
description: '
|
|
1692
|
+
description: 'DEPRECATED — retired by ADR-0030 (decided 2026-08-24: no part of a page summarises the page). Do not call it. It still works so seats on older clients do not break, and it will be removed in a later release. ⚠ This description previously claimed page retrieval matches on title + summary ALONE and that a stale summary decides whether a page is found — that was true only of the digest branch deleted by ADR-0030 step 2, and on 2026-08-24 a session read it, believed it, and asserted the opposite of the truth to its operator. `grep` searches SECTION BODIES and always has. Put the content in a section.',
|
|
1658
1693
|
inputSchema: {
|
|
1659
1694
|
name: z.string().describe('the exact page name, as read_page shows it'),
|
|
1660
1695
|
summary: z.string().describe('the new summary: one sentence saying what this is and where it stands. May contain [[links]]. Max 2,000 chars — detail belongs in a section.'),
|
|
@@ -3147,7 +3182,7 @@ export async function runServer(version) {
|
|
|
3147
3182
|
inputSchema: {
|
|
3148
3183
|
kind: z.enum(['project', 'person', 'org', 'user']).describe('the node type'),
|
|
3149
3184
|
name: z.string().describe('the canonical node name — an EXACT existing name from the namespace to update it, or a new name to create the node (project/person/org). e.g. "Agnoclast" or "Theron Peterson"'),
|
|
3150
|
-
summary: z.string().describe('
|
|
3185
|
+
summary: z.string().optional().describe('DEPRECATED and no longer required (ADR-0030, decided 2026-08-24: no part of a page summarises the page). Omit it. Accepted only so older callers keep working; the column is vestigial and nothing reads it. Put what the page is in its FIRST SECTION — grep indexes section bodies, and never indexed this.'),
|
|
3151
3186
|
sections: z.array(z.object({
|
|
3152
3187
|
heading: z.string().describe('e.g. Overview, Current state, Decisions, Open threads, People'),
|
|
3153
3188
|
body: z.string().describe('dense markdown WITH inline [[links]] where the prose references another node'),
|
package/package.json
CHANGED