@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 +233 -29
- package/dist/cli/index.js.map +3 -3
- package/package.json +1 -1
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.
|
|
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.
|
|
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 =
|
|
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:
|
|
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.
|
|
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
|
-
|
|
60932
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
63945
|
+
checkForUpdates("6.6.2").catch(() => {
|
|
63742
63946
|
});
|
|
63743
63947
|
}
|
|
63744
63948
|
|