@de-otio/epimethian-mcp 6.6.0 → 6.6.1

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
@@ -35481,7 +35481,7 @@ async function getPage(pageId, includeBody) {
35481
35481
  async function _rawCreatePage(spaceId, title, body, parentId, clientLabel) {
35482
35482
  const cfg = await getConfig();
35483
35483
  const pageBody = normalizeBodyForSubmit(body);
35484
- const epimethianTag = `Epimethian v${"6.6.0"}`;
35484
+ const epimethianTag = `Epimethian v${"6.6.1"}`;
35485
35485
  const versionMsg = cfg.attribution && clientLabel ? `Created by ${clientLabel} (via ${epimethianTag})` : `Created by ${epimethianTag}`;
35486
35486
  const payload = {
35487
35487
  title,
@@ -35502,7 +35502,7 @@ async function _rawCreatePage(spaceId, title, body, parentId, clientLabel) {
35502
35502
  async function _rawUpdatePage(pageId, opts) {
35503
35503
  const cfg = await getConfig();
35504
35504
  const newVersion = opts.version + 1;
35505
- const epimethianTag = `Epimethian v${"6.6.0"}`;
35505
+ const epimethianTag = `Epimethian v${"6.6.1"}`;
35506
35506
  const effectiveClient = cfg.attribution ? opts.clientLabel : void 0;
35507
35507
  let versionMessage;
35508
35508
  if (opts.versionMessage && effectiveClient)
@@ -49937,7 +49937,7 @@ __export(upgrade_exports, {
49937
49937
  runUpgrade: () => runUpgrade
49938
49938
  });
49939
49939
  async function runUpgrade() {
49940
- const currentVersion = "6.6.0";
49940
+ const currentVersion = "6.6.1";
49941
49941
  console.log(`epimethian-mcp upgrade: current version v${currentVersion}`);
49942
49942
  let pending = await getPendingUpdate();
49943
49943
  if (!pending) {
@@ -60928,8 +60928,37 @@ function renderDeletionSummary(s) {
60928
60928
  return `This update will remove ${list2}.`;
60929
60929
  }
60930
60930
  var bypassMisconfigWarningFired = false;
60931
- async function gateOperation(server, context) {
60932
- const supported = clientSupportsElicitation(server);
60931
+ var FAST_DECLINE_THRESHOLD_MS = 50;
60932
+ var FAST_DECLINE_THRESHOLD_OVERRIDE_ENV = "EPIMETHIAN_FAST_DECLINE_THRESHOLD_MS";
60933
+ var DISABLE_FAST_DECLINE_DETECTION_ENV = "EPIMETHIAN_DISABLE_FAST_DECLINE_DETECTION";
60934
+ var TREAT_ELICITATION_AS_UNSUPPORTED_ENV = "EPIMETHIAN_TREAT_ELICITATION_AS_UNSUPPORTED";
60935
+ var fakingElicitationFlags = /* @__PURE__ */ new WeakMap();
60936
+ function isClientFakingElicitation(server) {
60937
+ return fakingElicitationFlags.get(server) === true;
60938
+ }
60939
+ function _markClientAsFakingElicitation(server) {
60940
+ fakingElicitationFlags.set(server, true);
60941
+ }
60942
+ function readFastDeclineThresholdMs() {
60943
+ const raw = process.env[FAST_DECLINE_THRESHOLD_OVERRIDE_ENV];
60944
+ if (raw === void 0 || raw === "") return FAST_DECLINE_THRESHOLD_MS;
60945
+ const parsed = Number.parseInt(raw, 10);
60946
+ if (!Number.isFinite(parsed)) return FAST_DECLINE_THRESHOLD_MS;
60947
+ if (parsed < 10) return 10;
60948
+ if (parsed > 5e3) return 5e3;
60949
+ return parsed;
60950
+ }
60951
+ function effectiveSupportsElicitation(server) {
60952
+ if (process.env[TREAT_ELICITATION_AS_UNSUPPORTED_ENV] === "true") {
60953
+ return false;
60954
+ }
60955
+ if (isClientFakingElicitation(server)) {
60956
+ return false;
60957
+ }
60958
+ return clientSupportsElicitation(server);
60959
+ }
60960
+ async function evaluateUnsupportedBranch(server, context) {
60961
+ const supported = effectiveSupportsElicitation(server);
60933
60962
  if (process.env.EPIMETHIAN_BYPASS_ELICITATION === "true") {
60934
60963
  if (!supported && !bypassMisconfigWarningFired) {
60935
60964
  bypassMisconfigWarningFired = true;
@@ -60940,13 +60969,13 @@ async function gateOperation(server, context) {
60940
60969
  console.error(
60941
60970
  `epimethian-mcp: [UNGATED] tool=${context.tool} \u2014 bypassing elicitation gate; proceeding because EPIMETHIAN_BYPASS_ELICITATION=true.`
60942
60971
  );
60943
- return;
60972
+ return "handled";
60944
60973
  }
60945
60974
  if (!supported && process.env.EPIMETHIAN_ALLOW_UNGATED_WRITES === "true") {
60946
60975
  console.error(
60947
60976
  `epimethian-mcp: [UNGATED] tool=${context.tool} \u2014 client does not support elicitation; proceeding because EPIMETHIAN_ALLOW_UNGATED_WRITES=true.`
60948
60977
  );
60949
- return;
60978
+ return "handled";
60950
60979
  }
60951
60980
  if (!supported && process.env.EPIMETHIAN_DISABLE_SOFT_CONFIRM === "true") {
60952
60981
  throw new GatedOperationError(
@@ -60989,6 +61018,11 @@ async function gateOperation(server, context) {
60989
61018
  `This tool requires interactive confirmation but your MCP client does not expose elicitation. Use \`update_page_section\` instead, or switch to a client that supports MCP elicitation (Claude Code \u2265 2.x, Claude Desktop \u2265 0.10).`
60990
61019
  );
60991
61020
  }
61021
+ return "fall_through";
61022
+ }
61023
+ async function gateOperation(server, context) {
61024
+ const initial = await evaluateUnsupportedBranch(server, context);
61025
+ if (initial === "handled") return;
60992
61026
  const lines = [context.summary];
60993
61027
  if (context.details) {
60994
61028
  for (const [k, v] of Object.entries(context.details)) {
@@ -61007,6 +61041,7 @@ async function gateOperation(server, context) {
61007
61041
  }
61008
61042
  const message = lines.join("\n");
61009
61043
  let result;
61044
+ const startedAt = performance.now();
61010
61045
  try {
61011
61046
  result = await server.server.elicitInput({
61012
61047
  message,
@@ -61028,6 +61063,19 @@ async function gateOperation(server, context) {
61028
61063
  `Elicitation for ${context.tool} failed (${err instanceof Error ? err.message : String(err)}) \u2014 refusing the operation.`
61029
61064
  );
61030
61065
  }
61066
+ const elapsedMs = performance.now() - startedAt;
61067
+ const fastDeclineDisabled = process.env[DISABLE_FAST_DECLINE_DETECTION_ENV] === "true";
61068
+ if (!fastDeclineDisabled && result.action === "decline" && elapsedMs < readFastDeclineThresholdMs()) {
61069
+ _markClientAsFakingElicitation(server);
61070
+ const retry = await evaluateUnsupportedBranch(server, context);
61071
+ if (retry === "fall_through") {
61072
+ throw new GatedOperationError(
61073
+ NO_USER_RESPONSE,
61074
+ `${context.tool} could not be confirmed: fast-decline retry unexpectedly fell through to row 6.`
61075
+ );
61076
+ }
61077
+ return;
61078
+ }
61031
61079
  if (result.action === "accept" && result.content?.confirm === true) {
61032
61080
  return;
61033
61081
  }
@@ -61051,6 +61099,18 @@ async function gateOperation(server, context) {
61051
61099
 
61052
61100
  // src/server/index.ts
61053
61101
  init_confirmation_tokens();
61102
+
61103
+ // src/server/version-schema.ts
61104
+ init_zod();
61105
+ var versionField = external_exports.union([
61106
+ external_exports.preprocess(
61107
+ (v) => typeof v === "string" && /^\d+$/.test(v) ? Number(v) : v,
61108
+ external_exports.number().int().positive()
61109
+ ),
61110
+ external_exports.literal("current")
61111
+ ]);
61112
+
61113
+ // src/server/index.ts
61054
61114
  init_update_orchestrator();
61055
61115
  init_tokeniser();
61056
61116
 
@@ -61798,7 +61858,7 @@ ${truncated}${truncationNote(origLen)}`
61798
61858
  inputSchema: {
61799
61859
  page_id: external_exports.string().describe("The Confluence page ID"),
61800
61860
  title: external_exports.string().describe("Page title (use the title from get_page if unchanged)"),
61801
- version: external_exports.union([external_exports.number().int().positive(), external_exports.literal("current")]).describe(
61861
+ version: versionField.describe(
61802
61862
  `The page version number from your most recent get_page call. Pass the literal string "current" to skip the read and apply this update on top of whatever the latest version is right now. WARNING: "current" deliberately bypasses optimistic concurrency \u2014 it is NOT a conflict-resolution strategy. If a coworker (or another agent) writes between our read and submit, the API will still 409 and we propagate the conflict. Use a numeric version when you want the "don't overwrite my coworker's changes" guard. Use "current" only as a shortcut to skip the get_page round-trip when concurrent writes are not a concern (e.g. immediately after create_page).`
61803
61863
  ),
61804
61864
  body: external_exports.string().optional().describe("New body content \u2014 GFM markdown or Confluence storage format (XHTML). Markdown is auto-detected and converted via the token-aware write path. Do not mix the two: inlining <ac:.../> macros inside a markdown body is rejected. For a TOC use YAML frontmatter (toc: { maxLevel, minLevel }); for other macros use directive syntax (:info[...], :mention[...]{...})."),
@@ -62047,7 +62107,7 @@ ${truncated}${truncationNote(origLen)}`
62047
62107
  ).min(1).optional().describe(
62048
62108
  "Alternative to `body`: apply literal string substitutions inside the section's storage XML instead of replacing the whole section. Each entry's `find` is searched for and replaced with `replace`. Pairs are applied in input order; each subsequent `find` searches the partially-substituted body, so chained substitutions work as expected. If a `find` string is not found, the call fails with FIND_REPLACE_MATCH_FAILED \u2014 no silent no-op. Substitutions are ONLY applied to text outside macro boundaries (attribute values and CDATA bodies are protected). Exactly one of `body` or `find_replace` must be provided."
62049
62109
  ),
62050
- version: external_exports.union([external_exports.number().int().positive(), external_exports.literal("current")]).describe(
62110
+ version: versionField.describe(
62051
62111
  `The page version number from your most recent get_page call. Pass the literal string "current" to skip the read and apply this update on top of whatever the latest version is right now. WARNING: "current" deliberately bypasses optimistic concurrency \u2014 it is NOT a conflict-resolution strategy. If a coworker (or another agent) writes between our read and submit, the API will still 409. Use a numeric version when you want the "don't overwrite my coworker's changes" guard.`
62052
62112
  ),
62053
62113
  version_message: external_exports.string().optional().describe("Optional version comment"),
@@ -62223,7 +62283,7 @@ ${truncated}${truncationNote(origLen)}`
62223
62283
  ),
62224
62284
  inputSchema: {
62225
62285
  page_id: external_exports.string().describe("The Confluence page ID"),
62226
- version: external_exports.union([external_exports.number().int().positive(), external_exports.literal("current")]).describe(
62286
+ version: versionField.describe(
62227
62287
  'The page version number from your most recent get_page call. Pass the literal string "current" to skip the read and apply this update on top of whatever the latest version is right now. WARNING: "current" deliberately bypasses optimistic concurrency.'
62228
62288
  ),
62229
62289
  version_message: external_exports.string().optional().describe("Optional version comment for the single resulting revision"),
@@ -62381,7 +62441,7 @@ ${truncated}${truncationNote(origLen)}`
62381
62441
  ),
62382
62442
  inputSchema: {
62383
62443
  page_id: external_exports.string().describe("The Confluence page ID"),
62384
- version: external_exports.union([external_exports.number().int().positive(), external_exports.literal("current")]).describe(
62444
+ version: versionField.describe(
62385
62445
  'Page version from your most recent get_page call. Pass the literal string "current" to skip the read and apply on top of whatever the latest version is right now. WARNING: "current" bypasses optimistic concurrency \u2014 it does not protect against concurrent writes; the API can still 409 between our read and submit.'
62386
62446
  ),
62387
62447
  content: external_exports.string().describe("Content to insert before the existing body. GFM markdown or storage format (auto-detected)."),
@@ -62431,7 +62491,7 @@ ${truncated}${truncationNote(origLen)}`
62431
62491
  ),
62432
62492
  inputSchema: {
62433
62493
  page_id: external_exports.string().describe("The Confluence page ID"),
62434
- version: external_exports.union([external_exports.number().int().positive(), external_exports.literal("current")]).describe(
62494
+ version: versionField.describe(
62435
62495
  'Page version from your most recent get_page call. Pass the literal string "current" to skip the read and apply on top of whatever the latest version is right now. WARNING: "current" bypasses optimistic concurrency \u2014 it does not protect against concurrent writes; the API can still 409 between our read and submit.'
62436
62496
  ),
62437
62497
  content: external_exports.string().describe("Content to insert after the existing body. GFM markdown or storage format (auto-detected)."),
@@ -63620,7 +63680,7 @@ ${titleFenced}${echo2}`
63620
63680
  inputSchema: {}
63621
63681
  },
63622
63682
  async () => {
63623
- let text2 = `epimethian-mcp v${"6.6.0"}`;
63683
+ let text2 = `epimethian-mcp v${"6.6.1"}`;
63624
63684
  try {
63625
63685
  const pending = await getPendingUpdate();
63626
63686
  if (pending) {
@@ -63651,7 +63711,7 @@ ${label} update available: v${pending.current} \u2192 v${pending.latest}. Run \`
63651
63711
  const pending = await getPendingUpdate();
63652
63712
  if (!pending) {
63653
63713
  return toolResult(
63654
- `epimethian-mcp v${"6.6.0"} is already up to date.`
63714
+ `epimethian-mcp v${"6.6.1"} is already up to date.`
63655
63715
  );
63656
63716
  }
63657
63717
  const output = await performUpgrade(pending.latest);
@@ -63673,7 +63733,7 @@ async function startRecoveryServer(profile) {
63673
63733
  const server = new McpServer(
63674
63734
  {
63675
63735
  name: `confluence-${profile}-setup-needed`,
63676
- version: "6.6.0"
63736
+ version: "6.6.1"
63677
63737
  },
63678
63738
  {
63679
63739
  instructions: `The Confluence profile "${profile}" referenced by CONFLUENCE_PROFILE has no keychain entry, so no Confluence tools are available. Call the setup_profile tool for instructions to create it.`
@@ -63724,21 +63784,21 @@ async function main() {
63724
63784
  const serverName = config3.profile ? `confluence-${config3.profile}` : "confluence";
63725
63785
  const server = new McpServer({
63726
63786
  name: serverName,
63727
- version: "6.6.0"
63787
+ version: "6.6.1"
63728
63788
  });
63729
63789
  await registerTools(server, config3);
63730
63790
  const transport = new StdioServerTransport();
63731
63791
  await server.connect(transport);
63732
63792
  try {
63733
63793
  const pending = await getPendingUpdate();
63734
- if (pending && pending.current === "6.6.0") {
63794
+ if (pending && pending.current === "6.6.1") {
63735
63795
  console.error(
63736
63796
  `epimethian-mcp: update available: v${pending.current} \u2192 v${pending.latest} (${pending.type}). Run \`epimethian-mcp upgrade\` to install.`
63737
63797
  );
63738
63798
  }
63739
63799
  } catch {
63740
63800
  }
63741
- checkForUpdates("6.6.0").catch(() => {
63801
+ checkForUpdates("6.6.1").catch(() => {
63742
63802
  });
63743
63803
  }
63744
63804