@de-otio/epimethian-mcp 6.6.0 → 6.6.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
@@ -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.2"}`;
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.2"}`;
35506
35506
  const effectiveClient = cfg.attribution ? opts.clientLabel : void 0;
35507
35507
  let versionMessage;
35508
35508
  if (opts.versionMessage && effectiveClient)
@@ -47896,17 +47896,30 @@ Token tail: ...${last8} Expires: ${isoExpires} Audit ID: ${err.auditId}
47896
47896
  The token is single-use, bound to this exact diff and page version,
47897
47897
  and invalidated by any competing write to this page. If validation
47898
47898
  fails, mint a new one by re-calling without \`confirm_token\`.`;
47899
+ const tokenInText = process.env.EPIMETHIAN_TOKEN_IN_TEXT === "true";
47900
+ const finalText = tokenInText ? text2 + `
47901
+
47902
+ [FALLBACK] Full token (EPIMETHIAN_TOKEN_IN_TEXT=true): ${err.token}` : text2;
47899
47903
  const structuredContent = {
47904
+ kind: "confirmation_required",
47900
47905
  confirm_token: err.token,
47901
47906
  audit_id: err.auditId,
47902
47907
  expires_at: isoExpires,
47903
- page_id: params.pageId
47908
+ page_id: params.pageId,
47909
+ human_summary: err.humanSummary
47904
47910
  };
47905
47911
  if (params.deletionSummary) {
47906
- structuredContent.deletion_summary = params.deletionSummary;
47912
+ structuredContent.deletion_summary = {
47913
+ tocs: params.deletionSummary.tocs,
47914
+ links: params.deletionSummary.links,
47915
+ structured_macros: params.deletionSummary.structuredMacros,
47916
+ code_macros: params.deletionSummary.codeMacros,
47917
+ plain_elements: params.deletionSummary.plainElements,
47918
+ other: params.deletionSummary.other
47919
+ };
47907
47920
  }
47908
47921
  return {
47909
- content: [{ type: "text", text: text2 }],
47922
+ content: [{ type: "text", text: finalText }],
47910
47923
  isError: true,
47911
47924
  structuredContent
47912
47925
  };
@@ -48986,7 +48999,7 @@ var init_client_configs = __esm({
48986
48999
  null,
48987
49000
  2
48988
49001
  ),
48989
- warning: "VS Code extension \u2264 2.1.123 does not honour elicitation requests; if write tools fail with NO_USER_RESPONSE, set `EPIMETHIAN_BYPASS_ELICITATION=true`."
49002
+ warning: "VS Code extension \u2264 2.1.123 does not honour elicitation requests; if write tools fail with NO_USER_RESPONSE, set `EPIMETHIAN_BYPASS_ELICITATION=true`.\n\nv6.6.2 declares an `outputSchema` on every write tool, so a spec-compliant client should now surface the soft-confirm `structuredContent` to the agent. If your version of Claude Code drops content blocks when structuredContent is present (issue #15412), set `EPIMETHIAN_TOKEN_IN_TEXT=true` as a fallback \u2014 this restores the human-readable explanation by also putting the full token in the text block."
48990
49003
  },
48991
49004
  {
48992
49005
  id: "cursor",
@@ -49937,7 +49950,7 @@ __export(upgrade_exports, {
49937
49950
  runUpgrade: () => runUpgrade
49938
49951
  });
49939
49952
  async function runUpgrade() {
49940
- const currentVersion = "6.6.0";
49953
+ const currentVersion = "6.6.2";
49941
49954
  console.log(`epimethian-mcp upgrade: current version v${currentVersion}`);
49942
49955
  let pending = await getPendingUpdate();
49943
49956
  if (!pending) {
@@ -60928,8 +60941,37 @@ function renderDeletionSummary(s) {
60928
60941
  return `This update will remove ${list2}.`;
60929
60942
  }
60930
60943
  var bypassMisconfigWarningFired = false;
60931
- async function gateOperation(server, context) {
60932
- const supported = clientSupportsElicitation(server);
60944
+ var FAST_DECLINE_THRESHOLD_MS = 50;
60945
+ var FAST_DECLINE_THRESHOLD_OVERRIDE_ENV = "EPIMETHIAN_FAST_DECLINE_THRESHOLD_MS";
60946
+ var DISABLE_FAST_DECLINE_DETECTION_ENV = "EPIMETHIAN_DISABLE_FAST_DECLINE_DETECTION";
60947
+ var TREAT_ELICITATION_AS_UNSUPPORTED_ENV = "EPIMETHIAN_TREAT_ELICITATION_AS_UNSUPPORTED";
60948
+ var fakingElicitationFlags = /* @__PURE__ */ new WeakMap();
60949
+ function isClientFakingElicitation(server) {
60950
+ return fakingElicitationFlags.get(server) === true;
60951
+ }
60952
+ function _markClientAsFakingElicitation(server) {
60953
+ fakingElicitationFlags.set(server, true);
60954
+ }
60955
+ function readFastDeclineThresholdMs() {
60956
+ const raw = process.env[FAST_DECLINE_THRESHOLD_OVERRIDE_ENV];
60957
+ if (raw === void 0 || raw === "") return FAST_DECLINE_THRESHOLD_MS;
60958
+ const parsed = Number.parseInt(raw, 10);
60959
+ if (!Number.isFinite(parsed)) return FAST_DECLINE_THRESHOLD_MS;
60960
+ if (parsed < 10) return 10;
60961
+ if (parsed > 5e3) return 5e3;
60962
+ return parsed;
60963
+ }
60964
+ function effectiveSupportsElicitation(server) {
60965
+ if (process.env[TREAT_ELICITATION_AS_UNSUPPORTED_ENV] === "true") {
60966
+ return false;
60967
+ }
60968
+ if (isClientFakingElicitation(server)) {
60969
+ return false;
60970
+ }
60971
+ return clientSupportsElicitation(server);
60972
+ }
60973
+ async function evaluateUnsupportedBranch(server, context) {
60974
+ const supported = effectiveSupportsElicitation(server);
60933
60975
  if (process.env.EPIMETHIAN_BYPASS_ELICITATION === "true") {
60934
60976
  if (!supported && !bypassMisconfigWarningFired) {
60935
60977
  bypassMisconfigWarningFired = true;
@@ -60940,13 +60982,13 @@ async function gateOperation(server, context) {
60940
60982
  console.error(
60941
60983
  `epimethian-mcp: [UNGATED] tool=${context.tool} \u2014 bypassing elicitation gate; proceeding because EPIMETHIAN_BYPASS_ELICITATION=true.`
60942
60984
  );
60943
- return;
60985
+ return "handled";
60944
60986
  }
60945
60987
  if (!supported && process.env.EPIMETHIAN_ALLOW_UNGATED_WRITES === "true") {
60946
60988
  console.error(
60947
60989
  `epimethian-mcp: [UNGATED] tool=${context.tool} \u2014 client does not support elicitation; proceeding because EPIMETHIAN_ALLOW_UNGATED_WRITES=true.`
60948
60990
  );
60949
- return;
60991
+ return "handled";
60950
60992
  }
60951
60993
  if (!supported && process.env.EPIMETHIAN_DISABLE_SOFT_CONFIRM === "true") {
60952
60994
  throw new GatedOperationError(
@@ -60989,6 +61031,11 @@ async function gateOperation(server, context) {
60989
61031
  `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
61032
  );
60991
61033
  }
61034
+ return "fall_through";
61035
+ }
61036
+ async function gateOperation(server, context) {
61037
+ const initial = await evaluateUnsupportedBranch(server, context);
61038
+ if (initial === "handled") return;
60992
61039
  const lines = [context.summary];
60993
61040
  if (context.details) {
60994
61041
  for (const [k, v] of Object.entries(context.details)) {
@@ -61007,6 +61054,7 @@ async function gateOperation(server, context) {
61007
61054
  }
61008
61055
  const message = lines.join("\n");
61009
61056
  let result;
61057
+ const startedAt = performance.now();
61010
61058
  try {
61011
61059
  result = await server.server.elicitInput({
61012
61060
  message,
@@ -61028,6 +61076,19 @@ async function gateOperation(server, context) {
61028
61076
  `Elicitation for ${context.tool} failed (${err instanceof Error ? err.message : String(err)}) \u2014 refusing the operation.`
61029
61077
  );
61030
61078
  }
61079
+ const elapsedMs = performance.now() - startedAt;
61080
+ const fastDeclineDisabled = process.env[DISABLE_FAST_DECLINE_DETECTION_ENV] === "true";
61081
+ if (!fastDeclineDisabled && result.action === "decline" && elapsedMs < readFastDeclineThresholdMs()) {
61082
+ _markClientAsFakingElicitation(server);
61083
+ const retry = await evaluateUnsupportedBranch(server, context);
61084
+ if (retry === "fall_through") {
61085
+ throw new GatedOperationError(
61086
+ NO_USER_RESPONSE,
61087
+ `${context.tool} could not be confirmed: fast-decline retry unexpectedly fell through to row 6.`
61088
+ );
61089
+ }
61090
+ return;
61091
+ }
61031
61092
  if (result.action === "accept" && result.content?.confirm === true) {
61032
61093
  return;
61033
61094
  }
@@ -61051,6 +61112,59 @@ async function gateOperation(server, context) {
61051
61112
 
61052
61113
  // src/server/index.ts
61053
61114
  init_confirmation_tokens();
61115
+
61116
+ // src/server/version-schema.ts
61117
+ init_zod();
61118
+ var versionField = external_exports.union([
61119
+ external_exports.preprocess(
61120
+ (v) => typeof v === "string" && /^\d+$/.test(v) ? Number(v) : v,
61121
+ external_exports.number().int().positive()
61122
+ ),
61123
+ external_exports.literal("current")
61124
+ ]);
61125
+
61126
+ // src/server/output-schema.ts
61127
+ init_zod();
61128
+ var deletionSummarySchema = external_exports.object({
61129
+ tocs: external_exports.number().int().nonnegative(),
61130
+ links: external_exports.number().int().nonnegative(),
61131
+ structured_macros: external_exports.number().int().nonnegative(),
61132
+ code_macros: external_exports.number().int().nonnegative(),
61133
+ plain_elements: external_exports.number().int().nonnegative(),
61134
+ other: external_exports.number().int().nonnegative()
61135
+ });
61136
+ var confirmationRequiredArm = external_exports.object({
61137
+ kind: external_exports.literal("confirmation_required"),
61138
+ confirm_token: external_exports.string().min(1),
61139
+ audit_id: external_exports.string().min(1),
61140
+ expires_at: external_exports.string().min(1),
61141
+ page_id: external_exports.string().min(1),
61142
+ human_summary: external_exports.string(),
61143
+ deletion_summary: deletionSummarySchema.optional()
61144
+ });
61145
+ var writeSuccessArm = external_exports.object({
61146
+ kind: external_exports.literal("written"),
61147
+ page_id: external_exports.string().min(1),
61148
+ new_version: external_exports.number().int().positive(),
61149
+ body_bytes_before: external_exports.number().int().nonnegative().optional(),
61150
+ body_bytes_after: external_exports.number().int().nonnegative().optional(),
61151
+ title: external_exports.string().optional()
61152
+ });
61153
+ var deleteSuccessArm = external_exports.object({
61154
+ kind: external_exports.literal("deleted"),
61155
+ page_id: external_exports.string().min(1),
61156
+ last_version: external_exports.number().int().positive().optional()
61157
+ });
61158
+ var writeOutputSchema = external_exports.discriminatedUnion("kind", [
61159
+ writeSuccessArm,
61160
+ confirmationRequiredArm
61161
+ ]);
61162
+ var deleteOutputSchema = external_exports.discriminatedUnion("kind", [
61163
+ deleteSuccessArm,
61164
+ confirmationRequiredArm
61165
+ ]);
61166
+
61167
+ // src/server/index.ts
61054
61168
  init_update_orchestrator();
61055
61169
  init_tokeniser();
61056
61170
 
@@ -61798,7 +61912,7 @@ ${truncated}${truncationNote(origLen)}`
61798
61912
  inputSchema: {
61799
61913
  page_id: external_exports.string().describe("The Confluence page ID"),
61800
61914
  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(
61915
+ version: versionField.describe(
61802
61916
  `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
61917
  ),
61804
61918
  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[...]{...})."),
@@ -61816,6 +61930,11 @@ ${truncated}${truncationNote(origLen)}`
61816
61930
  source: sourceSchema,
61817
61931
  confirm_token: external_exports.string().optional().describe("Soft-confirmation token from a prior SOFT_CONFIRMATION_REQUIRED response. Single-use; bound to this exact diff and page version.")
61818
61932
  },
61933
+ // v6.6.2 §3.1 — declared so spec-compliant clients forward our
61934
+ // structuredContent payload to the agent (the soft-confirmation
61935
+ // round-trip relied on this from the start; v6.6.0/6.6.1 emitted
61936
+ // structuredContent without a schema so most clients dropped it).
61937
+ outputSchema: writeOutputSchema,
61819
61938
  annotations: { destructiveHint: false, idempotentHint: false }
61820
61939
  },
61821
61940
  async ({ page_id, title, version: version2, body, version_message, confirm_deletions, replace_body, confirm_shrinkage, confirm_structure_loss, allow_raw_html, confluence_base_url, source, confirm_token }) => {
@@ -61912,14 +62031,34 @@ ${truncated}${truncationNote(origLen)}`
61912
62031
  const badgeResult = await markPageUnverified(submitted.page.id, cfg);
61913
62032
  if (badgeResult.warning) warnings.push(badgeResult.warning);
61914
62033
  if (isTitleOnly) {
61915
- return toolResult(
62034
+ const titleOnlyResult = toolResult(
61916
62035
  appendWarnings(`Updated: ${submitted.page.title} (ID: ${submitted.page.id}, version: ${submitted.newVersion}, title only, body unchanged)`, warnings) + echo
61917
62036
  );
62037
+ return {
62038
+ ...titleOnlyResult,
62039
+ structuredContent: {
62040
+ kind: "written",
62041
+ page_id,
62042
+ new_version: submitted.newVersion,
62043
+ title: submitted.page.title
62044
+ }
62045
+ };
61918
62046
  }
61919
62047
  const removalNote = submitted.deletedTokens.length > 0 ? `; removed ${submitted.deletedTokens.length} preserved macro${submitted.deletedTokens.length === 1 ? "" : "s"}: ${submitted.deletedTokens.map((t) => t.fingerprint).join(", ")}` : "";
61920
- return toolResult(
62048
+ const bodyUpdateResult = toolResult(
61921
62049
  appendWarnings(`Updated: ${submitted.page.title} (ID: ${submitted.page.id}, version: ${submitted.newVersion}, body: ${submitted.oldLen}\u2192${submitted.newLen} chars${removalNote})`, warnings) + echo
61922
62050
  );
62051
+ return {
62052
+ ...bodyUpdateResult,
62053
+ structuredContent: {
62054
+ kind: "written",
62055
+ page_id,
62056
+ new_version: submitted.newVersion,
62057
+ body_bytes_before: submitted.oldLen,
62058
+ body_bytes_after: submitted.newLen,
62059
+ title: submitted.page.title
62060
+ }
62061
+ };
61923
62062
  } catch (err) {
61924
62063
  if (err instanceof SoftConfirmationRequiredError) {
61925
62064
  return formatSoftConfirmationResult(err, { pageId: page_id });
@@ -61945,6 +62084,10 @@ ${truncated}${truncationNote(origLen)}`
61945
62084
  source: sourceSchema,
61946
62085
  confirm_token: external_exports.string().optional().describe("Soft-confirmation token from a prior SOFT_CONFIRMATION_REQUIRED response. Single-use; bound to this exact page version.")
61947
62086
  },
62087
+ // v6.6.2 §3.1 — declared so spec-compliant clients forward our
62088
+ // structuredContent payload (especially the soft-confirm token)
62089
+ // to the agent.
62090
+ outputSchema: deleteOutputSchema,
61948
62091
  annotations: { destructiveHint: true, idempotentHint: true }
61949
62092
  },
61950
62093
  async ({ page_id, version: version2, source, confirm_token }) => {
@@ -62010,7 +62153,15 @@ ${truncated}${truncationNote(origLen)}`
62010
62153
  ...version2 !== void 0 ? { oldVersion: version2 } : {},
62011
62154
  source: effectiveSource
62012
62155
  });
62013
- return toolResult(`Deleted page ${page_id}` + echo);
62156
+ const deletedResult = toolResult(`Deleted page ${page_id}` + echo);
62157
+ return {
62158
+ ...deletedResult,
62159
+ structuredContent: {
62160
+ kind: "deleted",
62161
+ page_id,
62162
+ ...version2 !== void 0 ? { last_version: version2 } : {}
62163
+ }
62164
+ };
62014
62165
  } catch (err) {
62015
62166
  if (err instanceof SoftConfirmationRequiredError) {
62016
62167
  return formatSoftConfirmationResult(err, { pageId: page_id });
@@ -62047,13 +62198,16 @@ ${truncated}${truncationNote(origLen)}`
62047
62198
  ).min(1).optional().describe(
62048
62199
  "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
62200
  ),
62050
- version: external_exports.union([external_exports.number().int().positive(), external_exports.literal("current")]).describe(
62201
+ version: versionField.describe(
62051
62202
  `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
62203
  ),
62053
62204
  version_message: external_exports.string().optional().describe("Optional version comment"),
62054
62205
  confirm_deletions: external_exports.boolean().default(false).describe("Set to true to acknowledge that your markdown removes preserved macros, emoticons, or rich elements from this section. Required when any preserved element would be deleted."),
62055
62206
  confirm_token: external_exports.string().optional().describe("Soft-confirmation token from a prior SOFT_CONFIRMATION_REQUIRED response. Single-use; bound to this exact diff and page version.")
62056
62207
  },
62208
+ // v6.6.2 §3.1 — declared so spec-compliant clients forward our
62209
+ // structuredContent payload to the agent.
62210
+ outputSchema: writeOutputSchema,
62057
62211
  annotations: { destructiveHint: false, idempotentHint: false }
62058
62212
  },
62059
62213
  async ({ page_id, section, body, find_replace, version: version2, version_message, confirm_deletions, confirm_token }) => {
@@ -62127,12 +62281,23 @@ ${truncated}${truncationNote(origLen)}`
62127
62281
  const badgeResult2 = await markPageUnverified(submitted2.page.id, cfg);
62128
62282
  if (badgeResult2.warning) warnings2.push(badgeResult2.warning);
62129
62283
  const pairCount = find_replace.length;
62130
- return toolResult(
62284
+ const findReplaceResult = toolResult(
62131
62285
  appendWarnings(
62132
62286
  `Updated section "${section}" in: ${submitted2.page.title} (ID: ${submitted2.page.id}, version: ${submitted2.newVersion}; applied ${pairCount} find/replace substitution${pairCount === 1 ? "" : "s"})`,
62133
62287
  warnings2
62134
62288
  ) + echo
62135
62289
  );
62290
+ return {
62291
+ ...findReplaceResult,
62292
+ structuredContent: {
62293
+ kind: "written",
62294
+ page_id,
62295
+ new_version: submitted2.newVersion,
62296
+ body_bytes_before: submitted2.oldLen,
62297
+ body_bytes_after: submitted2.newLen,
62298
+ title: submitted2.page.title
62299
+ }
62300
+ };
62136
62301
  }
62137
62302
  if (confirm_deletions) {
62138
62303
  const deletionSummary = tryForecastDeletions(currentSectionBody, body, cfg.url);
@@ -62201,9 +62366,20 @@ ${truncated}${truncationNote(origLen)}`
62201
62366
  const badgeResult = await markPageUnverified(submitted.page.id, cfg);
62202
62367
  if (badgeResult.warning) warnings.push(badgeResult.warning);
62203
62368
  const removalNote = submitted.deletedTokens.length > 0 ? `; removed ${submitted.deletedTokens.length} preserved macro${submitted.deletedTokens.length === 1 ? "" : "s"}: ${submitted.deletedTokens.map((t) => t.fingerprint).join(", ")}` : "";
62204
- return toolResult(
62369
+ const sectionBodyResult = toolResult(
62205
62370
  appendWarnings(`Updated section "${section}" in: ${submitted.page.title} (ID: ${submitted.page.id}, version: ${submitted.newVersion}${removalNote})`, warnings) + echo
62206
62371
  );
62372
+ return {
62373
+ ...sectionBodyResult,
62374
+ structuredContent: {
62375
+ kind: "written",
62376
+ page_id,
62377
+ new_version: submitted.newVersion,
62378
+ body_bytes_before: submitted.oldLen,
62379
+ body_bytes_after: submitted.newLen,
62380
+ title: submitted.page.title
62381
+ }
62382
+ };
62207
62383
  } catch (err) {
62208
62384
  if (err instanceof SoftConfirmationRequiredError) {
62209
62385
  return formatSoftConfirmationResult(err, { pageId: page_id });
@@ -62223,7 +62399,7 @@ ${truncated}${truncationNote(origLen)}`
62223
62399
  ),
62224
62400
  inputSchema: {
62225
62401
  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(
62402
+ version: versionField.describe(
62227
62403
  '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
62404
  ),
62229
62405
  version_message: external_exports.string().optional().describe("Optional version comment for the single resulting revision"),
@@ -62381,7 +62557,7 @@ ${truncated}${truncationNote(origLen)}`
62381
62557
  ),
62382
62558
  inputSchema: {
62383
62559
  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(
62560
+ version: versionField.describe(
62385
62561
  '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
62562
  ),
62387
62563
  content: external_exports.string().describe("Content to insert before the existing body. GFM markdown or storage format (auto-detected)."),
@@ -62391,6 +62567,9 @@ ${truncated}${truncationNote(origLen)}`
62391
62567
  confluence_base_url: external_exports.string().url().optional().describe("Override the Confluence base URL used by the link rewriter."),
62392
62568
  confirm_token: external_exports.string().optional().describe("Soft-confirmation token from a prior SOFT_CONFIRMATION_REQUIRED response. Single-use; bound to this exact diff and page version.")
62393
62569
  },
62570
+ // v6.6.2 \u00a73.1 \u2014 declared so spec-compliant clients forward our
62571
+ // structuredContent payload to the agent.
62572
+ outputSchema: writeOutputSchema,
62394
62573
  annotations: { destructiveHint: false, idempotentHint: false }
62395
62574
  },
62396
62575
  async ({ page_id, version: version2, content, separator, version_message, allow_raw_html, confluence_base_url }) => {
@@ -62411,7 +62590,18 @@ ${truncated}${truncationNote(origLen)}`
62411
62590
  if (labelResult.warning) warnings.push(labelResult.warning);
62412
62591
  const badgeResult = await markPageUnverified(page.id, cfg);
62413
62592
  if (badgeResult.warning) warnings.push(badgeResult.warning);
62414
- return toolResult(appendWarnings(`Prepended to: ${page.title} (ID: ${page.id}, version: ${newVersion}, body: ${oldLen}\u2192${newLen} chars)`, warnings) + echo);
62593
+ const prependResult = toolResult(appendWarnings(`Prepended to: ${page.title} (ID: ${page.id}, version: ${newVersion}, body: ${oldLen}\u2192${newLen} chars)`, warnings) + echo);
62594
+ return {
62595
+ ...prependResult,
62596
+ structuredContent: {
62597
+ kind: "written",
62598
+ page_id,
62599
+ new_version: newVersion,
62600
+ body_bytes_before: oldLen,
62601
+ body_bytes_after: newLen,
62602
+ title: page.title
62603
+ }
62604
+ };
62415
62605
  } catch (err) {
62416
62606
  if (err instanceof SoftConfirmationRequiredError) {
62417
62607
  return formatSoftConfirmationResult(err, { pageId: page_id });
@@ -62431,7 +62621,7 @@ ${truncated}${truncationNote(origLen)}`
62431
62621
  ),
62432
62622
  inputSchema: {
62433
62623
  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(
62624
+ version: versionField.describe(
62435
62625
  '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
62626
  ),
62437
62627
  content: external_exports.string().describe("Content to insert after the existing body. GFM markdown or storage format (auto-detected)."),
@@ -62441,6 +62631,9 @@ ${truncated}${truncationNote(origLen)}`
62441
62631
  confluence_base_url: external_exports.string().url().optional().describe("Override the Confluence base URL used by the link rewriter."),
62442
62632
  confirm_token: external_exports.string().optional().describe("Soft-confirmation token from a prior SOFT_CONFIRMATION_REQUIRED response. Single-use; bound to this exact diff and page version.")
62443
62633
  },
62634
+ // v6.6.2 \u00a73.1 \u2014 declared so spec-compliant clients forward our
62635
+ // structuredContent payload to the agent.
62636
+ outputSchema: writeOutputSchema,
62444
62637
  annotations: { destructiveHint: false, idempotentHint: false }
62445
62638
  },
62446
62639
  async ({ page_id, version: version2, content, separator, version_message, allow_raw_html, confluence_base_url }) => {
@@ -62461,7 +62654,18 @@ ${truncated}${truncationNote(origLen)}`
62461
62654
  if (labelResult.warning) warnings.push(labelResult.warning);
62462
62655
  const badgeResult = await markPageUnverified(page.id, cfg);
62463
62656
  if (badgeResult.warning) warnings.push(badgeResult.warning);
62464
- return toolResult(appendWarnings(`Appended to: ${page.title} (ID: ${page.id}, version: ${newVersion}, body: ${oldLen}\u2192${newLen} chars)`, warnings) + echo);
62657
+ const appendResult = toolResult(appendWarnings(`Appended to: ${page.title} (ID: ${page.id}, version: ${newVersion}, body: ${oldLen}\u2192${newLen} chars)`, warnings) + echo);
62658
+ return {
62659
+ ...appendResult,
62660
+ structuredContent: {
62661
+ kind: "written",
62662
+ page_id,
62663
+ new_version: newVersion,
62664
+ body_bytes_before: oldLen,
62665
+ body_bytes_after: newLen,
62666
+ title: page.title
62667
+ }
62668
+ };
62465
62669
  } catch (err) {
62466
62670
  if (err instanceof SoftConfirmationRequiredError) {
62467
62671
  return formatSoftConfirmationResult(err, { pageId: page_id });
@@ -63620,7 +63824,7 @@ ${titleFenced}${echo2}`
63620
63824
  inputSchema: {}
63621
63825
  },
63622
63826
  async () => {
63623
- let text2 = `epimethian-mcp v${"6.6.0"}`;
63827
+ let text2 = `epimethian-mcp v${"6.6.2"}`;
63624
63828
  try {
63625
63829
  const pending = await getPendingUpdate();
63626
63830
  if (pending) {
@@ -63651,7 +63855,7 @@ ${label} update available: v${pending.current} \u2192 v${pending.latest}. Run \`
63651
63855
  const pending = await getPendingUpdate();
63652
63856
  if (!pending) {
63653
63857
  return toolResult(
63654
- `epimethian-mcp v${"6.6.0"} is already up to date.`
63858
+ `epimethian-mcp v${"6.6.2"} is already up to date.`
63655
63859
  );
63656
63860
  }
63657
63861
  const output = await performUpgrade(pending.latest);
@@ -63673,7 +63877,7 @@ async function startRecoveryServer(profile) {
63673
63877
  const server = new McpServer(
63674
63878
  {
63675
63879
  name: `confluence-${profile}-setup-needed`,
63676
- version: "6.6.0"
63880
+ version: "6.6.2"
63677
63881
  },
63678
63882
  {
63679
63883
  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 +63928,21 @@ async function main() {
63724
63928
  const serverName = config3.profile ? `confluence-${config3.profile}` : "confluence";
63725
63929
  const server = new McpServer({
63726
63930
  name: serverName,
63727
- version: "6.6.0"
63931
+ version: "6.6.2"
63728
63932
  });
63729
63933
  await registerTools(server, config3);
63730
63934
  const transport = new StdioServerTransport();
63731
63935
  await server.connect(transport);
63732
63936
  try {
63733
63937
  const pending = await getPendingUpdate();
63734
- if (pending && pending.current === "6.6.0") {
63938
+ if (pending && pending.current === "6.6.2") {
63735
63939
  console.error(
63736
63940
  `epimethian-mcp: update available: v${pending.current} \u2192 v${pending.latest} (${pending.type}). Run \`epimethian-mcp upgrade\` to install.`
63737
63941
  );
63738
63942
  }
63739
63943
  } catch {
63740
63944
  }
63741
- checkForUpdates("6.6.0").catch(() => {
63945
+ checkForUpdates("6.6.2").catch(() => {
63742
63946
  });
63743
63947
  }
63744
63948