@attentionform/astra-mcp-server 0.4.0 → 0.4.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/index.js CHANGED
@@ -6082,6 +6082,9 @@ var RSIDS_EMPTY_RE = /<w:rsids>\s*<\/w:rsids>/g;
6082
6082
  var RSIDS_SELF_CLOSING_RE = /<w:rsids\s*\/>/g;
6083
6083
  var AUTHOR_ATTR_RE = /\s+(w|w15):author="[^"]*"/g;
6084
6084
  var INITIALS_ATTR_RE = /\s+w:initials="[^"]*"/g;
6085
+ var PRESENCE_INFO_TAG_RE = /<w15:presenceInfo\b(?:[^>"']|"[^"]*"|'[^']*')*>/g;
6086
+ var PRESENCE_PROVIDER_NONE_RE = /\sw15:providerId=(["'])None\1/;
6087
+ var PRESENCE_USERID_RE = /(\sw15:userId=)(?:"[^"]*"|'[^']*')/;
6085
6088
  var EMAIL_RE = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
6086
6089
  var PHONE_RE = /(\+\d[\d\s\-().]{6,}\d|\(\d{3}\)\s*\d{3}[\s\-.]\d{4}|\b\d{3}[\s\-.]\d{3}[\s\-.]\d{4}\b)/g;
6087
6090
  var CLAUSE_ACRONYM_RE = /\b(dfars|far|cfr|nist)\b/gi;
@@ -6853,6 +6856,15 @@ function sanitizeDocumentXml(xml, opts, partName = "word XML part", hooks) {
6853
6856
  o.replacementAuthor.split(/[\s._-]+/).filter(Boolean).map((s) => s[0]).join("").slice(0, 4).toUpperCase() || "A"
6854
6857
  );
6855
6858
  out = out.replace(INITIALS_ATTR_RE, ` w:initials="${initials}"`);
6859
+ if (partName === "word/people.xml") {
6860
+ out = out.replace(PRESENCE_INFO_TAG_RE, (tag) => {
6861
+ if (!PRESENCE_PROVIDER_NONE_RE.test(tag)) return tag;
6862
+ return tag.replace(PRESENCE_USERID_RE, (_m, open) => {
6863
+ purgedAuthors += 1;
6864
+ return `${open}"${replacement === "" ? "Anonymous" : replacement}"`;
6865
+ });
6866
+ });
6867
+ }
6856
6868
  }
6857
6869
  let acceptedRevisions = 0;
6858
6870
  let unresolvedRevisions = [];
@@ -10480,9 +10492,10 @@ var DocxParser = class _DocxParser {
10480
10492
  /**
10481
10493
  * Restores the package to a previously captured snapshot: every entry is
10482
10494
  * restored (entries added after the snapshot are removed), then documentDom
10483
- * and stylesDom are reloaded and stable IDs re-assigned.
10495
+ * and stylesDom are reloaded and stable IDs re-assigned. The restored package is exactly the snapshot;
10496
+ * only a restore that mixes a pre-0.4.2 commit with live parts passes `registerCoreProperties`.
10484
10497
  */
10485
- restorePackageSnapshot(snapshot3) {
10498
+ restorePackageSnapshot(snapshot3, options) {
10486
10499
  for (const entry of [...this.zip.getEntries()]) {
10487
10500
  if (!snapshot3.has(entry.entryName)) {
10488
10501
  this.zip.deleteFile(entry);
@@ -10501,8 +10514,15 @@ var DocxParser = class _DocxParser {
10501
10514
  continue;
10502
10515
  }
10503
10516
  const buffer = Buffer.from(data);
10504
- if (this.zip.getEntry(entryName)) {
10505
- this.zip.updateFile(entryName, buffer);
10517
+ const liveEntry = this.zip.getEntry(entryName);
10518
+ if (liveEntry) {
10519
+ let unchanged = false;
10520
+ try {
10521
+ unchanged = !liveEntry.isDirectory && liveEntry.header.size === buffer.length && readPartData(liveEntry, entryName).equals(buffer);
10522
+ } catch {
10523
+ unchanged = false;
10524
+ }
10525
+ if (!unchanged) this.zip.updateFile(entryName, buffer);
10506
10526
  } else {
10507
10527
  this.zip.addFile(entryName, buffer);
10508
10528
  }
@@ -10527,7 +10547,7 @@ var DocxParser = class _DocxParser {
10527
10547
  } else {
10528
10548
  this.stylesDom = null;
10529
10549
  }
10530
- registerExistingCorePropertiesPart(this.getZipAdapter());
10550
+ if (options?.registerCoreProperties) registerExistingCorePropertiesPart(this.getZipAdapter());
10531
10551
  this.invalidateMediaCache();
10532
10552
  this.assignStableIds();
10533
10553
  this._bumpNodePagesRevision();
@@ -13818,7 +13838,55 @@ function getRepoDir(docPath) {
13818
13838
  if (root !== null) return import_path3.default.join(root, historyKey(import_path3.default.dirname(docPath)), import_path3.default.basename(docPath));
13819
13839
  return import_path3.default.join(import_path3.default.dirname(docPath), ".astra", import_path3.default.basename(docPath));
13820
13840
  }
13841
+ var SNAPSHOT_FORMAT_MARKER = ".astra-snapshot-format";
13842
+ var SNAPSHOT_FORMAT_VERSION = "2";
13843
+ function isCompleteSnapshotMarker(content) {
13844
+ if (content === void 0) return false;
13845
+ return Buffer.from(content).toString("utf8").trim() === SNAPSHOT_FORMAT_VERSION;
13846
+ }
13847
+ var ESCAPED_DIR = "__astra_escaped__";
13848
+ var ESCAPED_NAME_MAX = 255;
13849
+ function needsHistoryEscape(entryName) {
13850
+ const name2 = entryName.replace(/\\/g, "/");
13851
+ if (name2 === SNAPSHOT_FORMAT_MARKER || name2 === "document.xml") return true;
13852
+ if (name2 === ESCAPED_DIR || name2.startsWith(`${ESCAPED_DIR}/`)) return true;
13853
+ return name2.split("/").some((segment) => segment.toLowerCase().startsWith(".git"));
13854
+ }
13855
+ function isUnrecordableName(entryName) {
13856
+ const name2 = entryName.replace(/\\/g, "/");
13857
+ if (name2 === "" || name2.endsWith("/") || name2.startsWith("/") || /^[a-zA-Z]:/.test(name2)) return true;
13858
+ return name2.split("/").some((segment) => segment === "" || segment === "." || segment === "..");
13859
+ }
13821
13860
  function isTrackedPackageFile(entryName) {
13861
+ const name2 = entryName.replace(/\\/g, "/");
13862
+ if (name2 === "word/document.xml") return false;
13863
+ return !isUnrecordableName(name2);
13864
+ }
13865
+ function historyPathFor(entryName) {
13866
+ const name2 = entryName.replace(/\\/g, "/");
13867
+ if (!needsHistoryEscape(name2)) return name2;
13868
+ const encoded = Buffer.from(name2, "utf8").toString("base64url");
13869
+ if (encoded.length > ESCAPED_NAME_MAX) {
13870
+ throw Object.assign(
13871
+ new Error(`E_VALIDATION: the package entry name is too long to record in history (${name2.length} characters).`),
13872
+ {
13873
+ code: "E_VALIDATION",
13874
+ remedy: "Rename or remove that package part (for example with sanitize_document), then save again."
13875
+ }
13876
+ );
13877
+ }
13878
+ return `${ESCAPED_DIR}/${encoded}`;
13879
+ }
13880
+ function entryNameFor(repoPath) {
13881
+ const rel = repoPath.replace(/\\/g, "/");
13882
+ if (!rel.startsWith(`${ESCAPED_DIR}/`)) return rel;
13883
+ return Buffer.from(rel.slice(ESCAPED_DIR.length + 1), "base64url").toString("utf8");
13884
+ }
13885
+ function isRepoPartPath(repoPath) {
13886
+ const rel = repoPath.replace(/\\/g, "/");
13887
+ return rel !== "document.xml" && rel !== SNAPSHOT_FORMAT_MARKER && rel !== "" && !rel.startsWith(".git/");
13888
+ }
13889
+ function isLegacyTrackedPackageFile(entryName) {
13822
13890
  const name2 = entryName.replace(/\\/g, "/");
13823
13891
  if (name2 === "word/document.xml") return false;
13824
13892
  if (name2 === "word/styles.xml") return true;
@@ -13842,7 +13910,7 @@ function toRepoRelative(entryName) {
13842
13910
  }
13843
13911
  async function writeAndAdd(repoDir, relPath, content) {
13844
13912
  const safeRel = toRepoRelative(relPath);
13845
- if (safeRel.includes("..") || import_path3.default.isAbsolute(safeRel) || /^[a-zA-Z]:/.test(safeRel)) {
13913
+ if (isTraversalName(safeRel)) {
13846
13914
  throw new Error(`Security Violation: refusing to track package path '${relPath}'`);
13847
13915
  }
13848
13916
  const fullPath = import_path3.default.join(repoDir, safeRel);
@@ -13854,6 +13922,59 @@ async function writeAndAdd(repoDir, relPath, content) {
13854
13922
  await writeFileNoFollow(fullPath, content);
13855
13923
  await import_isomorphic_git.default.add({ fs: import_fs4.default, dir: repoDir, filepath: safeRel });
13856
13924
  }
13925
+ function isTraversalName(entryName) {
13926
+ const name2 = toRepoRelative(entryName);
13927
+ return name2.split("/").includes("..") || import_path3.default.isAbsolute(name2) || /^[a-zA-Z]:/.test(name2);
13928
+ }
13929
+ async function writeSnapshotParts(repoDir, extraFiles) {
13930
+ const written = /* @__PURE__ */ new Set();
13931
+ if (!extraFiles) return written;
13932
+ for (const [name2, content] of Object.entries(extraFiles)) {
13933
+ if (isTraversalName(name2)) {
13934
+ await writeAndAdd(repoDir, name2, content);
13935
+ continue;
13936
+ }
13937
+ if (!isTrackedPackageFile(name2)) continue;
13938
+ const repoPath = historyPathFor(name2);
13939
+ await writeAndAdd(repoDir, repoPath, content);
13940
+ written.add(repoPath);
13941
+ }
13942
+ return written;
13943
+ }
13944
+ async function indexedPartPaths(repoDir) {
13945
+ const tracked = await import_isomorphic_git.default.listFiles({ fs: import_fs4.default, dir: repoDir });
13946
+ return new Set(tracked.map((t) => toRepoRelative(t)).filter(isRepoPartPath));
13947
+ }
13948
+ async function snapshotIsProvenComplete(repoDir, extraFiles, written) {
13949
+ if (!extraFiles) return false;
13950
+ try {
13951
+ const indexed = await indexedPartPaths(repoDir);
13952
+ if (indexed.size !== written.size) return false;
13953
+ for (const p of written) if (!indexed.has(p)) return false;
13954
+ return true;
13955
+ } catch {
13956
+ return false;
13957
+ }
13958
+ }
13959
+ async function applySnapshotMarker(repoDir, complete) {
13960
+ if (complete) {
13961
+ await writeAndAdd(repoDir, SNAPSHOT_FORMAT_MARKER, `${SNAPSHOT_FORMAT_VERSION}
13962
+ `);
13963
+ return;
13964
+ }
13965
+ try {
13966
+ await import_promises2.default.unlink(import_path3.default.join(repoDir, SNAPSHOT_FORMAT_MARKER));
13967
+ } catch {
13968
+ }
13969
+ try {
13970
+ await import_isomorphic_git.default.remove({ fs: import_fs4.default, dir: repoDir, filepath: SNAPSHOT_FORMAT_MARKER });
13971
+ } catch {
13972
+ }
13973
+ const stillIndexed = (await import_isomorphic_git.default.listFiles({ fs: import_fs4.default, dir: repoDir })).some((t) => toRepoRelative(t) === SNAPSHOT_FORMAT_MARKER);
13974
+ if (stillIndexed) {
13975
+ throw new Error("History commit refused: could not clear the snapshot marker of an earlier commit.");
13976
+ }
13977
+ }
13857
13978
  async function chmod0700BestEffort(dir) {
13858
13979
  if (process.platform === "win32") return;
13859
13980
  try {
@@ -14229,11 +14350,8 @@ async function initAstraRepo(docPath, initialXml, extraFiles) {
14229
14350
  const repoDir = await ensureAstraGitRepo(docPath);
14230
14351
  await import_isomorphic_git.default.init({ fs: import_fs4.default, dir: repoDir });
14231
14352
  await writeAndAdd(repoDir, "document.xml", initialXml);
14232
- if (extraFiles) {
14233
- for (const [name2, content] of Object.entries(extraFiles)) {
14234
- await writeAndAdd(repoDir, name2, content);
14235
- }
14236
- }
14353
+ const writtenParts = await writeSnapshotParts(repoDir, extraFiles);
14354
+ await applySnapshotMarker(repoDir, await snapshotIsProvenComplete(repoDir, extraFiles, writtenParts));
14237
14355
  await import_isomorphic_git.default.commit({
14238
14356
  fs: import_fs4.default,
14239
14357
  dir: repoDir,
@@ -14289,41 +14407,35 @@ async function commitChange(docPath, xmlContent, message, extraFiles, deletedFil
14289
14407
  } catch (err) {
14290
14408
  if (err?.code === HISTORY_QUOTA_CODE) throw err;
14291
14409
  }
14292
- await writeAndAdd(repoDir, "document.xml", xmlContent);
14293
14410
  if (extraFiles) {
14294
- for (const [name2, content] of Object.entries(extraFiles)) {
14295
- await writeAndAdd(repoDir, name2, content);
14296
- }
14411
+ for (const name2 of Object.keys(extraFiles)) if (!isTraversalName(name2) && isTrackedPackageFile(name2)) historyPathFor(name2);
14297
14412
  }
14413
+ await writeAndAdd(repoDir, "document.xml", xmlContent);
14414
+ const writtenParts = await writeSnapshotParts(repoDir, extraFiles);
14298
14415
  try {
14299
14416
  const toDelete = /* @__PURE__ */ new Set();
14300
14417
  if (deletedFiles) {
14301
14418
  for (const name2 of deletedFiles) {
14302
- const rel = toRepoRelative(name2);
14303
- if (rel === "document.xml") continue;
14304
- toDelete.add(rel);
14419
+ if (!isTrackedPackageFile(name2) || isTraversalName(name2)) continue;
14420
+ toDelete.add(historyPathFor(name2));
14305
14421
  }
14306
14422
  }
14307
14423
  if (extraFiles) {
14308
- const newTracked = new Set(
14309
- Object.keys(extraFiles).map((k) => toRepoRelative(k))
14310
- );
14424
+ const newTracked = writtenParts;
14311
14425
  try {
14312
14426
  const tracked = await import_isomorphic_git.default.listFiles({ fs: import_fs4.default, dir: repoDir });
14313
14427
  for (const t of tracked) {
14314
14428
  const rel = toRepoRelative(t);
14315
- if (rel === "document.xml") continue;
14316
- if (isTrackedPackageFile(rel) && !newTracked.has(rel)) {
14429
+ if (isRepoPartPath(rel) && !newTracked.has(rel)) {
14317
14430
  toDelete.add(rel);
14318
14431
  }
14319
14432
  }
14320
14433
  } catch {
14321
14434
  }
14322
14435
  try {
14323
- const onDisk = await collectRepoFiles(repoDir);
14324
- for (const rel of onDisk.keys()) {
14325
- if (rel === "document.xml") continue;
14326
- if (isTrackedPackageFile(rel) && !newTracked.has(rel)) {
14436
+ const onDisk = await listRepoPaths(repoDir);
14437
+ for (const rel of onDisk) {
14438
+ if (isRepoPartPath(rel) && !newTracked.has(rel)) {
14327
14439
  toDelete.add(rel);
14328
14440
  }
14329
14441
  }
@@ -14331,7 +14443,7 @@ async function commitChange(docPath, xmlContent, message, extraFiles, deletedFil
14331
14443
  }
14332
14444
  }
14333
14445
  for (const rel of toDelete) {
14334
- if (rel.includes("..") || import_path3.default.isAbsolute(rel) || /^[a-zA-Z]:/.test(rel)) continue;
14446
+ if (isTraversalName(rel)) continue;
14335
14447
  const fullPath = import_path3.default.join(repoDir, rel);
14336
14448
  try {
14337
14449
  await import_promises2.default.unlink(fullPath);
@@ -14344,6 +14456,7 @@ async function commitChange(docPath, xmlContent, message, extraFiles, deletedFil
14344
14456
  }
14345
14457
  } catch {
14346
14458
  }
14459
+ await applySnapshotMarker(repoDir, await snapshotIsProvenComplete(repoDir, extraFiles, writtenParts));
14347
14460
  const sha = await import_isomorphic_git.default.commit({
14348
14461
  fs: import_fs4.default,
14349
14462
  dir: repoDir,
@@ -14395,8 +14508,8 @@ async function getHistory(docPath) {
14395
14508
  });
14396
14509
  return entries;
14397
14510
  }
14398
- async function collectRepoFiles(repoDir) {
14399
- const out = /* @__PURE__ */ new Map();
14511
+ async function listRepoPaths(repoDir) {
14512
+ const out = [];
14400
14513
  async function walk(dir, relBase) {
14401
14514
  let entries = [];
14402
14515
  try {
@@ -14406,21 +14519,18 @@ async function collectRepoFiles(repoDir) {
14406
14519
  }
14407
14520
  for (const entry of entries) {
14408
14521
  if (entry.name === ".git") continue;
14409
- const full = import_path3.default.join(dir, entry.name);
14410
14522
  const rel = relBase ? `${relBase}/${entry.name}` : entry.name;
14411
- if (entry.isDirectory()) {
14412
- await walk(full, rel);
14413
- } else if (entry.isFile()) {
14414
- try {
14415
- out.set(rel, await import_promises2.default.readFile(full));
14416
- } catch {
14417
- }
14418
- }
14523
+ if (entry.isDirectory()) await walk(import_path3.default.join(dir, entry.name), rel);
14524
+ else if (entry.isFile()) out.push(rel);
14419
14525
  }
14420
14526
  }
14421
14527
  await walk(repoDir, "");
14422
14528
  return out;
14423
14529
  }
14530
+ function trackedPredicateFor(target) {
14531
+ return target.complete ? isTrackedPackageFile : isLegacyTrackedPackageFile;
14532
+ }
14533
+ var INCOMPLETE_SNAPSHOT_WARNING = "This commit was recorded by an older ASTra version and predates complete snapshots: parts it never recorded (for example comment metadata, document properties, custom XML) keep their current content in the file, so the restore is not exact: those parts can be left without the content-type or relationship entries they had before. Restores to versions saved from now on are exact.";
14424
14534
  async function checkoutCommit(docPath, commitOid) {
14425
14535
  if (typeof commitOid !== "string" || commitOid.length === 0) {
14426
14536
  throw new Error(`Cannot checkout: commit ${commitOid} not found in history.`);
@@ -14484,8 +14594,18 @@ async function checkoutCommit(docPath, commitOid) {
14484
14594
  );
14485
14595
  }
14486
14596
  const xml = Buffer.from(docBlob.blob).toString("utf8");
14597
+ let complete = false;
14598
+ const markerOid = blobs.get(SNAPSHOT_FORMAT_MARKER);
14599
+ if (markerOid) {
14600
+ try {
14601
+ const marker = await import_isomorphic_git.default.readBlob({ fs: import_fs4.default, dir: repoDir, oid: markerOid });
14602
+ complete = isCompleteSnapshotMarker(marker.blob);
14603
+ } catch {
14604
+ complete = false;
14605
+ }
14606
+ }
14487
14607
  const trackedEntries = [...blobs.entries()].filter(
14488
- ([rel]) => rel !== "document.xml" && isTrackedPackageFile(rel)
14608
+ ([rel]) => isRepoPartPath(rel) && (complete || isLegacyTrackedPackageFile(entryNameFor(rel)))
14489
14609
  );
14490
14610
  const extraBlobs = await Promise.all(
14491
14611
  trackedEntries.map(async ([rel, blobOid]) => {
@@ -14498,11 +14618,11 @@ async function checkoutCommit(docPath, commitOid) {
14498
14618
  `Checkout failed: cannot read blob '${rel}' (${blobOid}) at commit ${commitOid}: ${cause}`
14499
14619
  );
14500
14620
  }
14501
- return [rel, Buffer.from(blobResult.blob)];
14621
+ return [entryNameFor(rel), Buffer.from(blobResult.blob)];
14502
14622
  })
14503
14623
  );
14504
14624
  const extra = new Map(extraBlobs);
14505
- return { xml, extra };
14625
+ return { xml, extra, complete };
14506
14626
  }
14507
14627
  async function commitStateIfDiffersFromHead(docPath, xmlContent, message, extraFiles = {}, author) {
14508
14628
  try {
@@ -43908,15 +44028,16 @@ async function handleRevertDocument(store, input) {
43908
44028
  });
43909
44029
  }
43910
44030
  const merged = new Map(preRevertSnap);
44031
+ const isTrackedForTarget = trackedPredicateFor(target);
43911
44032
  for (const key of [...merged.keys()]) {
43912
- if (key !== "word/document.xml" && isTrackedPackageFile(key)) merged.delete(key);
44033
+ if (key !== "word/document.xml" && isTrackedForTarget(key)) merged.delete(key);
43913
44034
  }
43914
44035
  for (const [k, v] of target.extra) merged.set(k, v);
43915
44036
  merged.set("word/document.xml", Buffer.from(target.xml, "utf8"));
43916
44037
  let writeAttempted = false;
43917
44038
  let commitPhase = false;
43918
44039
  try {
43919
- handle.parser.restorePackageSnapshot(merged);
44040
+ handle.parser.restorePackageSnapshot(merged, { registerCoreProperties: !target.complete });
43920
44041
  await refreshHandleAstInPlace(handle);
43921
44042
  const buf = handle.parser.rezip();
43922
44043
  const candidate = await validateForBaseline(buf);
@@ -43964,7 +44085,9 @@ async function handleRevertDocument(store, input) {
43964
44085
  dirty: false,
43965
44086
  discardedUnsaved,
43966
44087
  commitOid,
43967
- commitMessage
44088
+ commitMessage,
44089
+ snapshotComplete: target.complete,
44090
+ ...target.complete ? {} : { restoreWarning: INCOMPLETE_SNAPSHOT_WARNING }
43968
44091
  };
43969
44092
  } catch (stageErr) {
43970
44093
  const preserved = getEngineErrorCode(stageErr);
@@ -44266,7 +44389,8 @@ async function handlePreviewRevert(store, input) {
44266
44389
  const targetXmlBytes = Buffer.from(target.xml, "utf8");
44267
44390
  if (!liveXml || Buffer.compare(liveXml, targetXmlBytes) !== 0) affectedFiles.push("word/document.xml");
44268
44391
  const names = /* @__PURE__ */ new Set();
44269
- for (const k of liveSnap.keys()) if (k !== "word/document.xml" && isTrackedPackageFile(k)) names.add(k);
44392
+ const isTrackedForTarget = trackedPredicateFor(target);
44393
+ for (const k of liveSnap.keys()) if (k !== "word/document.xml" && isTrackedForTarget(k)) names.add(k);
44270
44394
  for (const k of target.extra.keys()) names.add(k);
44271
44395
  for (const name2 of [...names].sort()) {
44272
44396
  if (affectedFiles.length >= AUDIT_FILES_MAX) break;
@@ -44314,6 +44438,8 @@ async function handlePreviewRevert(store, input) {
44314
44438
  changedValuesTruncated,
44315
44439
  changedValuesPositional,
44316
44440
  ...changedValuesReason ? { changedValuesReason } : {},
44441
+ snapshotComplete: target.complete,
44442
+ ...target.complete ? {} : { restoreWarning: INCOMPLETE_SNAPSHOT_WARNING },
44317
44443
  dirty,
44318
44444
  dirtyHandling: dirty ? `Session holds ${unsavedOps} revision(s) of unsaved edits: a bare real revert would fail closed with E_CONFLICT; a real revert with discardUnsaved:true WOULD discard them (echoed back bounded). Net-zero edits still count as dirty (revisions pending, not a content diff). This preview discarded nothing.` : "Session is clean: a real revert would discard nothing.",
44319
44445
  currentHeadOid: full[0].oid,
@@ -45658,7 +45784,8 @@ var import_zod9 = require("zod");
45658
45784
  // package.json
45659
45785
  var package_default = {
45660
45786
  name: "@attentionform/astra-mcp-server",
45661
- version: "0.4.0",
45787
+ mcpName: "com.attentionform/astra-mcp-server",
45788
+ version: "0.4.2",
45662
45789
  description: "Official Model Context Protocol (MCP) server for ASTra document IDE",
45663
45790
  main: "dist/index.js",
45664
45791
  types: "dist/index.d.ts",
@@ -45699,8 +45826,8 @@ var package_default = {
45699
45826
  "adm-zip-gate": "node ../../scripts/check-adm-zip-imports.mjs"
45700
45827
  },
45701
45828
  dependencies: {
45702
- "@attentionform/astra-engine": "^0.4.0",
45703
- "@attentionform/ooxml-validator": "^0.4.0",
45829
+ "@attentionform/astra-engine": "^0.4.2",
45830
+ "@attentionform/ooxml-validator": "^0.4.2",
45704
45831
  "@modelcontextprotocol/sdk": "^1.32.2",
45705
45832
  "@xmldom/xmldom": "0.8.15",
45706
45833
  "adm-zip": "0.6.1",
@@ -36,6 +36,10 @@ export declare function handleRevertDocument(store: McpSessionStore, input: unkn
36
36
  discardedUnsaved: DiscardedUnsavedSummary;
37
37
  commitOid: string;
38
38
  commitMessage: string;
39
+ /** True when the target commit recorded every package part, so the restore is exact. */
40
+ snapshotComplete: boolean;
41
+ /** Present when the target commit predates complete snapshots: the restore is not exact. */
42
+ restoreWarning?: string;
39
43
  } | (McpErrorShape & {
40
44
  dirtyReason?: string;
41
45
  })>;
@@ -79,6 +83,10 @@ export declare function handlePreviewRevert(store: McpSessionStore, input: unkno
79
83
  changedValuesPositional: boolean;
80
84
  /** Present when the target range is not computable (empty changedValues). */
81
85
  changedValuesReason?: string;
86
+ /** True when the target commit recorded every package part, so a real revert is exact. */
87
+ snapshotComplete: boolean;
88
+ /** Present when the target commit predates complete snapshots: a real revert is not exact. */
89
+ restoreWarning?: string;
82
90
  dirty: boolean;
83
91
  dirtyHandling: string;
84
92
  currentHeadOid: string;
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@attentionform/astra-mcp-server",
3
- "version": "0.4.0",
3
+ "mcpName": "com.attentionform/astra-mcp-server",
4
+ "version": "0.4.2",
4
5
  "description": "Official Model Context Protocol (MCP) server for ASTra document IDE",
5
6
  "main": "dist/index.js",
6
7
  "types": "dist/index.d.ts",
@@ -41,8 +42,8 @@
41
42
  "adm-zip-gate": "node ../../scripts/check-adm-zip-imports.mjs"
42
43
  },
43
44
  "dependencies": {
44
- "@attentionform/astra-engine": "^0.4.0",
45
- "@attentionform/ooxml-validator": "^0.4.0",
45
+ "@attentionform/astra-engine": "^0.4.2",
46
+ "@attentionform/ooxml-validator": "^0.4.2",
46
47
  "@modelcontextprotocol/sdk": "^1.32.2",
47
48
  "@xmldom/xmldom": "0.8.15",
48
49
  "adm-zip": "0.6.1",