@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 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
- console.log(` ${name}${roSuffix}`);
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: cleanBody + "\n" + buildAttributionFooter("created")
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, cleanBody + "\n" + buildAttributionFooter("created"));
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: cleanBody + "\n" + buildAttributionFooter("updated")
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 cachedBody = stripAttributionFooter(toStorageFormat(opts.body));
45419
- pageCache.set(pageId, newVersion, cachedBody + "\n" + buildAttributionFooter("updated"));
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:11px;color:#999;margin-top:2em;"><em>This page was ${action} with <a href="${GITHUB_URL}">Epimethian</a>.</em></p>` + ATTRIBUTION_END;
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="attachment">${escapeXml(filename)}</ac:parameter>`,
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);