@de-otio/epimethian-mcp 4.2.0 → 4.2.2
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/dist/cli/index.js +70 -13
- package/dist/cli/index.js.map +2 -2
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -30591,6 +30591,26 @@ async function runProfiles() {
|
|
|
30591
30591
|
await setReadOnlyFlag(name, false);
|
|
30592
30592
|
return;
|
|
30593
30593
|
}
|
|
30594
|
+
const disableAttrIdx = args.indexOf("--disable-attribution");
|
|
30595
|
+
if (disableAttrIdx > -1) {
|
|
30596
|
+
const name = args[disableAttrIdx + 1];
|
|
30597
|
+
if (!name || !PROFILE_NAME_RE.test(name)) {
|
|
30598
|
+
console.error("Error: --disable-attribution requires a valid profile name.");
|
|
30599
|
+
process.exit(1);
|
|
30600
|
+
}
|
|
30601
|
+
await setAttributionFlag(name, false);
|
|
30602
|
+
return;
|
|
30603
|
+
}
|
|
30604
|
+
const enableAttrIdx = args.indexOf("--enable-attribution");
|
|
30605
|
+
if (enableAttrIdx > -1) {
|
|
30606
|
+
const name = args[enableAttrIdx + 1];
|
|
30607
|
+
if (!name || !PROFILE_NAME_RE.test(name)) {
|
|
30608
|
+
console.error("Error: --enable-attribution requires a valid profile name.");
|
|
30609
|
+
process.exit(1);
|
|
30610
|
+
}
|
|
30611
|
+
await setAttributionFlag(name, true);
|
|
30612
|
+
return;
|
|
30613
|
+
}
|
|
30594
30614
|
const verbose = args.includes("--verbose");
|
|
30595
30615
|
const profiles = await readProfileRegistry();
|
|
30596
30616
|
if (profiles.length === 0) {
|
|
@@ -30599,19 +30619,20 @@ async function runProfiles() {
|
|
|
30599
30619
|
}
|
|
30600
30620
|
if (verbose) {
|
|
30601
30621
|
console.log(
|
|
30602
|
-
` ${"Profile".padEnd(20)} ${"URL".padEnd(40)} ${"Read-Only".padEnd(12)} Email`
|
|
30622
|
+
` ${"Profile".padEnd(20)} ${"URL".padEnd(40)} ${"Read-Only".padEnd(12)} ${"Attribution".padEnd(14)} Email`
|
|
30603
30623
|
);
|
|
30604
30624
|
console.log(
|
|
30605
|
-
` ${"\u2500".repeat(20)} ${"\u2500".repeat(40)} ${"\u2500".repeat(12)} ${"\u2500".repeat(30)}`
|
|
30625
|
+
` ${"\u2500".repeat(20)} ${"\u2500".repeat(40)} ${"\u2500".repeat(12)} ${"\u2500".repeat(14)} ${"\u2500".repeat(30)}`
|
|
30606
30626
|
);
|
|
30607
30627
|
for (const name of profiles) {
|
|
30608
30628
|
try {
|
|
30609
30629
|
const creds = await readFromKeychain(name);
|
|
30610
30630
|
const settings = await getProfileSettings(name);
|
|
30611
30631
|
const roLabel = settings?.readOnly ? "YES" : "no";
|
|
30632
|
+
const attrLabel = settings?.attribution === false ? "disabled" : "enabled";
|
|
30612
30633
|
if (creds) {
|
|
30613
30634
|
console.log(
|
|
30614
|
-
` ${name.padEnd(20)} ${creds.url.padEnd(40)} ${roLabel.padEnd(12)} ${creds.email}`
|
|
30635
|
+
` ${name.padEnd(20)} ${creds.url.padEnd(40)} ${roLabel.padEnd(12)} ${attrLabel.padEnd(14)} ${creds.email}`
|
|
30615
30636
|
);
|
|
30616
30637
|
} else {
|
|
30617
30638
|
console.log(
|
|
@@ -30629,7 +30650,8 @@ async function runProfiles() {
|
|
|
30629
30650
|
for (const name of profiles) {
|
|
30630
30651
|
const settings = await getProfileSettings(name);
|
|
30631
30652
|
const roSuffix = settings?.readOnly ? " (read-only)" : "";
|
|
30632
|
-
|
|
30653
|
+
const attrSuffix = settings?.attribution === false ? " (no attribution)" : "";
|
|
30654
|
+
console.log(` ${name}${roSuffix}${attrSuffix}`);
|
|
30633
30655
|
}
|
|
30634
30656
|
console.log("\nUse --verbose to show URLs and emails.");
|
|
30635
30657
|
}
|
|
@@ -30645,6 +30667,17 @@ async function setReadOnlyFlag(name, readOnly) {
|
|
|
30645
30667
|
console.log(`Profile "${name}" is now ${label}.`);
|
|
30646
30668
|
console.log("Note: Restart any running MCP servers for this change to take effect.");
|
|
30647
30669
|
}
|
|
30670
|
+
async function setAttributionFlag(name, attribution) {
|
|
30671
|
+
const profiles = await readProfileRegistry();
|
|
30672
|
+
if (!profiles.includes(name)) {
|
|
30673
|
+
console.error(`Error: Profile "${name}" does not exist.`);
|
|
30674
|
+
process.exit(1);
|
|
30675
|
+
}
|
|
30676
|
+
await setProfileSettings(name, { attribution });
|
|
30677
|
+
const label = attribution ? "enabled" : "disabled";
|
|
30678
|
+
console.log(`Attribution footer for profile "${name}" is now ${label}.`);
|
|
30679
|
+
console.log("Note: Restart any running MCP servers for this change to take effect.");
|
|
30680
|
+
}
|
|
30648
30681
|
async function removeProfile(name, force) {
|
|
30649
30682
|
if (!force || import_node_process3.stdin.isTTY) {
|
|
30650
30683
|
if (!import_node_process3.stdin.isTTY) {
|
|
@@ -45120,12 +45153,14 @@ async function getConfig() {
|
|
|
45120
45153
|
const { url, email: email2, apiToken, profile } = await resolveCredentials();
|
|
45121
45154
|
const registrySettings = profile ? await getProfileSettings(profile) : void 0;
|
|
45122
45155
|
const readOnly = registrySettings?.readOnly === true || process.env.CONFLUENCE_READ_ONLY === "true";
|
|
45156
|
+
const attribution = registrySettings?.attribution !== false && process.env.CONFLUENCE_ATTRIBUTION !== "false";
|
|
45123
45157
|
const authHeader = "Basic " + Buffer.from(`${email2}:${apiToken}`).toString("base64");
|
|
45124
45158
|
_config = Object.freeze({
|
|
45125
45159
|
url,
|
|
45126
45160
|
email: email2,
|
|
45127
45161
|
profile,
|
|
45128
45162
|
readOnly,
|
|
45163
|
+
attribution,
|
|
45129
45164
|
apiV2: `${url}/wiki/api/v2`,
|
|
45130
45165
|
apiV1: `${url}/wiki/rest/api`,
|
|
45131
45166
|
authHeader,
|
|
@@ -45167,8 +45202,9 @@ Expected user: ${email2}
|
|
|
45167
45202
|
}
|
|
45168
45203
|
const profileLabel = profile ? `profile: ${profile}` : "env-var mode";
|
|
45169
45204
|
const readOnlyLabel = config2.readOnly ? ", READ-ONLY" : "";
|
|
45205
|
+
const attributionLabel = config2.attribution ? "" : ", NO-ATTRIBUTION";
|
|
45170
45206
|
console.error(
|
|
45171
|
-
`epimethian-mcp: connected to ${url} as ${email2} (${profileLabel}${readOnlyLabel})`
|
|
45207
|
+
`epimethian-mcp: connected to ${url} as ${email2} (${profileLabel}${readOnlyLabel}${attributionLabel})`
|
|
45172
45208
|
);
|
|
45173
45209
|
}
|
|
45174
45210
|
var PageSchema = external_exports.object({
|
|
@@ -45367,21 +45403,23 @@ async function getPage(pageId, includeBody) {
|
|
|
45367
45403
|
return page;
|
|
45368
45404
|
}
|
|
45369
45405
|
async function createPage(spaceId, title, body, parentId) {
|
|
45406
|
+
const cfg = await getConfig();
|
|
45370
45407
|
const cleanBody = stripAttributionFooter(toStorageFormat(body));
|
|
45408
|
+
const pageBody = cfg.attribution ? cleanBody + "\n" + buildAttributionFooter("created") : cleanBody;
|
|
45371
45409
|
const payload = {
|
|
45372
45410
|
title,
|
|
45373
45411
|
spaceId,
|
|
45374
45412
|
status: "current",
|
|
45375
45413
|
body: {
|
|
45376
45414
|
representation: "storage",
|
|
45377
|
-
value:
|
|
45415
|
+
value: pageBody
|
|
45378
45416
|
},
|
|
45379
45417
|
version: { message: "Created by Epimethian" }
|
|
45380
45418
|
};
|
|
45381
45419
|
if (parentId) payload.parentId = parentId;
|
|
45382
45420
|
const raw = await v2Post("/pages", payload);
|
|
45383
45421
|
const page = PageSchema.parse(raw);
|
|
45384
|
-
pageCache.set(page.id, page.version?.number ?? 1,
|
|
45422
|
+
pageCache.set(page.id, page.version?.number ?? 1, pageBody);
|
|
45385
45423
|
try {
|
|
45386
45424
|
await addLabels(page.id, [ATTRIBUTION_LABEL]);
|
|
45387
45425
|
} catch {
|
|
@@ -45389,6 +45427,7 @@ async function createPage(spaceId, title, body, parentId) {
|
|
|
45389
45427
|
return page;
|
|
45390
45428
|
}
|
|
45391
45429
|
async function updatePage(pageId, opts) {
|
|
45430
|
+
const cfg = await getConfig();
|
|
45392
45431
|
const newVersion = opts.version + 1;
|
|
45393
45432
|
const versionMessage = opts.versionMessage ? `${opts.versionMessage} (via Epimethian)` : "Updated by Epimethian";
|
|
45394
45433
|
const payload = {
|
|
@@ -45399,9 +45438,10 @@ async function updatePage(pageId, opts) {
|
|
|
45399
45438
|
};
|
|
45400
45439
|
if (opts.body) {
|
|
45401
45440
|
const cleanBody = stripAttributionFooter(toStorageFormat(opts.body));
|
|
45441
|
+
const pageBody = cfg.attribution ? cleanBody + "\n" + buildAttributionFooter("updated") : cleanBody;
|
|
45402
45442
|
payload.body = {
|
|
45403
45443
|
representation: "storage",
|
|
45404
|
-
value:
|
|
45444
|
+
value: pageBody
|
|
45405
45445
|
};
|
|
45406
45446
|
}
|
|
45407
45447
|
let raw;
|
|
@@ -45415,8 +45455,9 @@ async function updatePage(pageId, opts) {
|
|
|
45415
45455
|
}
|
|
45416
45456
|
const page = PageSchema.parse(raw);
|
|
45417
45457
|
if (opts.body) {
|
|
45418
|
-
const
|
|
45419
|
-
|
|
45458
|
+
const cleanBody = stripAttributionFooter(toStorageFormat(opts.body));
|
|
45459
|
+
const pageBody = cfg.attribution ? cleanBody + "\n" + buildAttributionFooter("updated") : cleanBody;
|
|
45460
|
+
pageCache.set(pageId, newVersion, pageBody);
|
|
45420
45461
|
}
|
|
45421
45462
|
try {
|
|
45422
45463
|
await addLabels(page.id, [ATTRIBUTION_LABEL]);
|
|
@@ -45541,12 +45582,18 @@ var ATTRIBUTION_LABEL = "epimethian-managed";
|
|
|
45541
45582
|
var ATTRIBUTION_START = "<!-- epimethian-attribution-start -->";
|
|
45542
45583
|
var ATTRIBUTION_END = "<!-- epimethian-attribution-end -->";
|
|
45543
45584
|
function buildAttributionFooter(action) {
|
|
45544
|
-
return ATTRIBUTION_START + `<p style="font-size:
|
|
45585
|
+
return ATTRIBUTION_START + `<p style="font-size:9px;color:#999;margin-top:2em;"><em>This page was ${action} with <a href="${GITHUB_URL}">Epimethian</a>.</em></p>` + ATTRIBUTION_END;
|
|
45545
45586
|
}
|
|
45546
45587
|
function stripAttributionFooter(body) {
|
|
45547
45588
|
return body.replace(
|
|
45548
45589
|
/<!--\s*epimethian-attribution-start\s*-->[\s\S]*?<!--\s*epimethian-attribution-end\s*-->/g,
|
|
45549
45590
|
""
|
|
45591
|
+
).replace(
|
|
45592
|
+
// Also strip bare (unmarked) attribution paragraphs — these appear
|
|
45593
|
+
// when an agent copies page content from get_page and passes it
|
|
45594
|
+
// back to update_page without removing the footer.
|
|
45595
|
+
/<p[^>]*>[\s\S]*?<a\s[^>]*href="https:\/\/github\.com\/de-otio\/epimethian-mcp"[^>]*>Epimethian<\/a>[\s\S]*?<\/p>/gi,
|
|
45596
|
+
""
|
|
45550
45597
|
).trimEnd();
|
|
45551
45598
|
}
|
|
45552
45599
|
async function getLabels(pageId) {
|
|
@@ -47066,10 +47113,20 @@ ${truncated}`);
|
|
|
47066
47113
|
} finally {
|
|
47067
47114
|
await (0, import_promises2.rm)(tmpDir, { recursive: true, force: true });
|
|
47068
47115
|
}
|
|
47116
|
+
const macroId = crypto.randomUUID();
|
|
47117
|
+
const localId = crypto.randomUUID();
|
|
47118
|
+
const baseUrl = `${config2.url}/wiki`;
|
|
47069
47119
|
const macro = [
|
|
47070
|
-
`<ac:structured-macro ac:name="drawio" ac:schema-version="1">`,
|
|
47120
|
+
`<ac:structured-macro ac:name="drawio" ac:schema-version="1" data-layout="default" ac:local-id="${localId}" ac:macro-id="${macroId}">`,
|
|
47121
|
+
` <ac:parameter ac:name="diagramDisplayName">${escapeXml(filename)}</ac:parameter>`,
|
|
47071
47122
|
` <ac:parameter ac:name="diagramName">${escapeXml(filename)}</ac:parameter>`,
|
|
47072
|
-
` <ac:parameter ac:name="
|
|
47123
|
+
` <ac:parameter ac:name="revision">1</ac:parameter>`,
|
|
47124
|
+
` <ac:parameter ac:name="pageId">${escapeXml(page_id)}</ac:parameter>`,
|
|
47125
|
+
` <ac:parameter ac:name="baseUrl">${escapeXml(baseUrl)}</ac:parameter>`,
|
|
47126
|
+
` <ac:parameter ac:name="zoom">1</ac:parameter>`,
|
|
47127
|
+
` <ac:parameter ac:name="lbox">1</ac:parameter>`,
|
|
47128
|
+
` <ac:parameter ac:name="simple">0</ac:parameter>`,
|
|
47129
|
+
` <ac:parameter ac:name="contentVer">1</ac:parameter>`,
|
|
47073
47130
|
`</ac:structured-macro>`
|
|
47074
47131
|
].join("\n");
|
|
47075
47132
|
const current = await getPage(page_id, true);
|