@attentionform/astra-mcp-server 0.0.0-stage → 0.2.0

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.
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @attentionform/astra-mcp-server lib barrel — OUR MCP server logic (single source of truth).
3
+ *
4
+ * Named re-exports ONLY (no `export *`): the public surface stays explicit
5
+ * and reviewable — every name below is listed deliberately.
6
+ */
7
+ export { MCP_SESSION_MAX_DOCS, MCP_SESSION_MAX_BYTES, MCP_SESSION_IDLE_MS, SessionMutex, McpSessionStore, collectTrackedExtrasForGit, ensureGitRepo, getMcpAllowedRoots, canonicalizeForMcp, validateDocPath, validateSaveTarget, validateOpenBufferLabel, SESSION_REDO_MAX_DEPTH_CLAMP, SESSION_REDO_MAX_BYTES_CLAMP, createMcpSessionStore, } from './session-store';
8
+ export type { McpSessionStoreOptions, DocHandle, McpSessionStats, } from './session-store';
9
+ export { MCP_RESEARCH_FLAG, isResearchEnabled, LEAN6_TOOL_NAMES, getLean6ToolNames, GIT_HISTORY_TOOL_NAMES, getGitHistoryToolNames, mcpError, sanitizeCommitMessage, sanitizeCommitAuthor, COMMIT_MESSAGE_MAX, COMMIT_AUTHOR_MAX, COMMIT_AUTHOR_DEFAULT, MCP_ECMA_ESSENTIALS, MCP_WORKFLOW, LEAN6_DESCRIPTIONS, GIT_HISTORY_DESCRIPTIONS, OpenDocumentSchema, InspectDocumentSchema, SearchContentSchema, ExecuteBatchSchema, SaveDocumentSchema, CloseDocumentSchema, GetDocumentHistorySchema, RevertDocumentSchema, RedoDocumentSchema, extractStylePalette, handleOpenDocument, handleInspectDocument, handleSearchContent, handleExecuteBatch, executeSaveDocument, handleSaveDocument, handleCloseDocument, handleGetDocumentHistory, handleRevertDocument, handleRedoDocument, LEAN6_HANDLERS, GIT_HISTORY_HANDLERS, } from './mcp-tool-adapter';
10
+ export type { Lean6ToolName, GitHistoryToolName, HistoryEntry, McpErrorCode, McpErrorShape, OpenDocumentInput, InspectDocumentInput, SearchContentInput, ExecuteBatchInput, SaveDocumentInput, CloseDocumentInput, GetDocumentHistoryInput, RevertDocumentInput, RedoDocumentInput, StylePalette, } from './mcp-tool-adapter';
@@ -0,0 +1,71 @@
1
+ import { type BaselineVerdict, type ValidationBaseline, type ValidationResult } from '@attentionform/astra-engine';
2
+ import type { DocHandle } from '../session-store';
3
+ /** Set by the `--strict-validation` flag. */
4
+ export declare function setStrictValidationDefault(value: boolean): void;
5
+ /** True when a save refuses every validator error, whether or not the file had it before. */
6
+ export declare function strictValidationDefault(): boolean;
7
+ /** Set by the `--open-validation-timeout` flag. */
8
+ export declare function setOpenValidationTimeoutMs(value: number): void;
9
+ /** How long open_document waits for the validator, in milliseconds. 0 skips the check. */
10
+ export declare function openValidationTimeoutMs(): number;
11
+ export declare function sha256Hex(bytes: Buffer): string;
12
+ /** Validates a package with the full error list, so the result can be compared. */
13
+ export declare function validateForBaseline(bytes: Buffer): Promise<ValidationResult>;
14
+ /** Stores the baseline of a package the session now holds as its saved state. */
15
+ export declare function adoptBaseline(handle: DocHandle, result: ValidationResult): void;
16
+ /**
17
+ * The baseline of a session. When the open did not produce one (timed out or skipped), the file on
18
+ * disk is validated, but only when it is still the file that was opened. Otherwise null, and the
19
+ * save is judged as not comparable.
20
+ */
21
+ export declare function resolveBaseline(handle: DocHandle): Promise<ValidationBaseline | null>;
22
+ /**
23
+ * Verdict for a package that revert_document or redo_document restores. Such a state was saved before,
24
+ * so it is allowed to carry the errors the file had when it was opened, as well as the errors of the
25
+ * saved state of the session. Anything beyond both is refused.
26
+ */
27
+ export declare function judgeRestoredPackage(handle: DocHandle, result: ValidationResult): Promise<BaselineVerdict>;
28
+ /** The first `limit` descriptions of a result, cut to a readable length. */
29
+ export declare function firstMessages(result: ValidationResult, limit?: number): string[];
30
+ /** The error a save or normalize raises when the edit adds validator errors. */
31
+ export declare function introducedError(toolName: string, verdict: Extract<BaselineVerdict, {
32
+ kind: 'introduced';
33
+ }>): Error;
34
+ /** The `validation` field of an answer for a result that was judged. */
35
+ export declare function validationField(result: ValidationResult, verdict: BaselineVerdict): {
36
+ ok: false;
37
+ tolerated: true;
38
+ preExistingErrors: number;
39
+ introducedErrors: 0;
40
+ messages: string[];
41
+ } | {
42
+ ok: true;
43
+ tolerated?: undefined;
44
+ preExistingErrors?: undefined;
45
+ introducedErrors?: undefined;
46
+ messages?: undefined;
47
+ };
48
+ /** Adds the note about existing errors to a commit message; the message is cut, the note never. */
49
+ export declare function withToleratedNote(message: string, preExisting: number): string;
50
+ export type OpenValidationField = {
51
+ status: 'valid';
52
+ } | {
53
+ status: 'invalid';
54
+ preExistingErrors: number;
55
+ baselineComparable: boolean;
56
+ messages: string[];
57
+ degraded: true;
58
+ note: string;
59
+ } | {
60
+ status: 'timed-out';
61
+ degraded: 'unknown';
62
+ note: string;
63
+ } | {
64
+ status: 'skipped';
65
+ note?: string;
66
+ };
67
+ /**
68
+ * Validates the file that was just opened and stores its baseline on the handle. The open itself is
69
+ * never refused for these reasons, and nothing is reported as valid unless the validator said so.
70
+ */
71
+ export declare function validateAtOpen(handle: DocHandle, timeoutMs: number): Promise<OpenValidationField>;
@@ -0,0 +1,12 @@
1
+ import type { Lean6ToolName, GitHistoryToolName, ParityToolName } from './tool-names';
2
+ export declare const MCP_ECMA_ESSENTIALS: string;
3
+ export declare const MCP_WORKFLOW: string;
4
+ export declare const MCP_ENVELOPE_NOTE = "";
5
+ export declare const LEAN6_DESCRIPTIONS: Record<Lean6ToolName, string>;
6
+ export declare const GIT_HISTORY_DESCRIPTIONS: Record<GitHistoryToolName, string>;
7
+ /**
8
+ * export_audit_trail description (handler-only: NOT a registered MCP tool, so
9
+ * the 12-tool pin is unaffected). Carries the HOLD retention note verbatim.
10
+ */
11
+ export declare const EXPORT_AUDIT_TRAIL_DESCRIPTION: string;
12
+ export declare const PARITY_DESCRIPTIONS: Record<ParityToolName, string>;
@@ -0,0 +1,220 @@
1
+ import type { DocHandle } from '../session-store';
2
+ /** Cap on discarded node ids listed in the revert echo. */
3
+ export declare const DISCARDED_NODE_IDS_MAX = 20;
4
+ /** Cap on affected node ids per history entry / audit-trail row. */
5
+ export declare const AUDIT_NODE_IDS_MAX = 100;
6
+ /** Cap on affected files listed by preview_revert / audit rows. */
7
+ export declare const AUDIT_FILES_MAX = 100;
8
+ /**
9
+ * Value-summary bounds (advisory, additive, bounded):
10
+ * - CHANGED_VALUES_MAX caps the changedValues entries per save/preview
11
+ * envelope (old→new {nodeId, before, after} in document order).
12
+ * - CHANGED_VALUE_TEXT_MAX caps each before/after string (chars); longer
13
+ * values are sliced and the envelope truncated flag is set (honest).
14
+ * History entries keep as-is (no value summaries there).
15
+ */
16
+ export declare const CHANGED_VALUES_MAX = 20;
17
+ export declare const CHANGED_VALUE_TEXT_MAX = 200;
18
+ /** Advisory old→new value summary for one node (bounded strings). */
19
+ export interface ChangedValue {
20
+ nodeId: string;
21
+ before: string;
22
+ after: string;
23
+ }
24
+ /**
25
+ * Diffs two id->text snapshots into bounded old→new summaries.
26
+ * before/after are id->text maps; primaryOrder is walked first (document
27
+ * order of the side the caller wants listed first), secondaryOrder covers
28
+ * ids absent from the primary side (deletions/restorations). Added nodes
29
+ * use before:'', removed nodes use after:''. Count + per-string caps apply;
30
+ * truncated is true when either cap was hit (honest, never silent).
31
+ */
32
+ export declare function diffChangedValues(before: Map<string, string>, after: Map<string, string>, primaryOrder: string[], secondaryOrder: string[]): {
33
+ values: ChangedValue[];
34
+ truncated: boolean;
35
+ };
36
+ /**
37
+ * Across-parse value diff for save/preview envelopes (advisory, additive,
38
+ * bounded). Same-parse ids are stable, but a FRESH parse mints positional
39
+ * ids (t_001…) while in-session inserts keep minted ids (_bk_new_…), so an
40
+ * id-keyed diff across a save/preview boundary reports phantom
41
+ * added+removed pairs for unchanged nodes. Strategy: shared ids diff by id
42
+ * (walked in live document order); remaining orphans zip positionally when
43
+ * both sides hold the same orphan count (silent when the paired texts are
44
+ * equal — the clean-resave case); otherwise orphans degrade honestly to
45
+ * added (before:'') / removed (after:'') entries. nodeId always prefers the
46
+ * live side (parsed-commit/baseline ids are ephemeral). liveIsAfter selects
47
+ * direction: save passes (live, baseline, true) = baseline→live; preview
48
+ * passes (live, target, false) = live→target. Count + per-string caps apply;
49
+ * truncated is true when either cap was hit (honest, never silent).
50
+ * positional is true when either side held orphan ids (no shared id across
51
+ * the boundary — usually a reparse id mismatch, common under duplicate
52
+ * native ids): paired entries were zipped by position, so consumers must
53
+ * treat before/after pairing as positional, not identity.
54
+ */
55
+ export declare function diffChangedValuesAcrossParse(live: {
56
+ order: string[];
57
+ texts: Map<string, string>;
58
+ }, other: {
59
+ order: string[];
60
+ texts: Map<string, string>;
61
+ }, liveIsAfter: boolean): {
62
+ values: ChangedValue[];
63
+ truncated: boolean;
64
+ positional: boolean;
65
+ };
66
+ /**
67
+ * Parses a target commit's document.xml into id->text via a synthetic docx
68
+ * (live package parts + target document.xml, same DocxParser path as live,
69
+ * so para/table ids and w:t concatenation match exactly). Best-effort:
70
+ * returns null when the synthetic package cannot be parsed — callers emit
71
+ * empty changedValues + reason and MUST NOT fail the preview on this probe.
72
+ */
73
+ export declare function parseTargetIdTextsForPreview(liveSnap: Map<string, Buffer>, targetXml: string): Promise<{
74
+ order: string[];
75
+ texts: Map<string, string>;
76
+ } | null>;
77
+ /**
78
+ * HOLD retention note (honest, no WORM claims): the .astra/ sidecar is
79
+ * deletable local state living beside the .docx — anyone with file access
80
+ * can wipe it. Full server-side retention is OUT of scope: history lives
81
+ * beside the document and dies with it; the audit handlers below only
82
+ * report what is currently on disk.
83
+ */
84
+ export declare const AUDIT_RETENTION_NOTE: string;
85
+ /** One created node per applied op, for the execute_batch result envelope. */
86
+ export interface BatchOpCreatedIds {
87
+ index: number;
88
+ action: string;
89
+ createdNodeIds: string[];
90
+ }
91
+ /** Echo of unsaved edits discarded by a revert (counts + ids only, never text). */
92
+ export interface DiscardedUnsavedSummary {
93
+ wasDirty: boolean;
94
+ /** Added + modified + deleted-vs-saved node count (0 when clean). */
95
+ discardedNodeCount: number;
96
+ /** Affected node ids in live-document order (bounded, [] when clean). */
97
+ discardedNodeIds: string[];
98
+ /** True when the id bound above was hit. */
99
+ truncated: boolean;
100
+ }
101
+ /** Node ids + live texts in document order (single AST walk). */
102
+ export declare function collectAstIdTexts(ast: {
103
+ sections: Array<{
104
+ nodes: Array<{
105
+ id: string;
106
+ metadata: {
107
+ text?: unknown;
108
+ };
109
+ }>;
110
+ }>;
111
+ }): {
112
+ order: string[];
113
+ texts: Map<string, string>;
114
+ };
115
+ /**
116
+ * Best-effort parse of saved .docx bytes into id->text (for the dirty diff).
117
+ * Returns null when the bytes cannot be parsed — callers fall back to a
118
+ * live-only summary and MUST NOT fail the revert on this probe.
119
+ */
120
+ export declare function parseSavedIdTextsOrdered(savedBytes: Buffer | null): Promise<{
121
+ order: string[];
122
+ texts: Map<string, string>;
123
+ } | null>;
124
+ export declare function parseSavedIdTexts(savedBytes: Buffer | null): Promise<Map<string, string> | null>;
125
+ /**
126
+ * Summarizes the unsaved edits a revert is about to discard: nodes added or
127
+ * text-modified vs the last saved bytes count as discarded, plus nodes
128
+ * deleted-vs-saved (their deletion is the discarded edit; they contribute
129
+ * ids + count). Counts + ids only, never text. Everything bounded; clean
130
+ * sessions yield the zero summary (never null, so callers can always echo it).
131
+ */
132
+ export declare function summarizeDiscardedUnsaved(live: {
133
+ order: string[];
134
+ texts: Map<string, string>;
135
+ }, saved: Map<string, string> | null, fallbackOpCount: number): DiscardedUnsavedSummary;
136
+ /**
137
+ * Diffs two id->text snapshots (pre vs post restore): added, removed, or
138
+ * text-changed ids, returned in post-restore document order, bounded.
139
+ * Used for revert/redo affected-node-ids (honest restore footprint).
140
+ */
141
+ export declare function diffIdTexts(before: Map<string, string>, afterOrder: string[], after: Map<string, string>): string[];
142
+ /**
143
+ * Attributes post-batch created ids to per-op results. Client-supplied `id`
144
+ * claims are exact when the id is present in the post-batch id set (the
145
+ * engine uses op.id verbatim as the node id — verified by probe); ids
146
+ * absent from that set are never echoed (footnote honors no id and creates
147
+ * zero AST nodes, so its id stays unclaimed). Remaining ids go to
148
+ * creator-candidate ops: a single unclaimed creator takes all of them
149
+ * (exact for the common single-insert batch and for multi-node creators
150
+ * like insertTOC/coverPage alone in a batch); multiple unclaimed creators
151
+ * split best-effort in batch order with leftovers on the last creator.
152
+ * Non-creators always report [].
153
+ */
154
+ export declare function attributeCreatedIds(actions: string[], ops: Array<Record<string, unknown>>, createdOrdered: string[]): BatchOpCreatedIds[];
155
+ /** sha256 hex over committed document.xml bytes (audit-trail package hash). */
156
+ export declare function hashDocumentXml(xml: string): string;
157
+ /**
158
+ * R-1: counts pending tracked revisions (w:ins + w:del) in a live parser DOM.
159
+ * Best-effort, never throws. Mirrors OperationEngine.countPendingRevisions
160
+ * for the save path (which does not go through executeBatch).
161
+ */
162
+ export declare function countPendingRevisionsInParser(parser: {
163
+ getDocumentDom?: () => unknown;
164
+ getDom?: () => unknown;
165
+ }): number;
166
+ /**
167
+ * T-5 revert commit subject: `Revert [N steps] to <oid> by <author>[: reason]`.
168
+ * N = how far back from the pre-revert head the target sat (1 for the common
169
+ * single-step revert); oid is the 7-char short form; reason is appended only
170
+ * when non-blank. Capped to COMMIT_MESSAGE_MAX like every other subject.
171
+ */
172
+ export declare function formatRevertCommitMessage(stepsBack: number, targetOid: string, author: string, reason: string): string;
173
+ /** 40-hex-char git object id (full oid; history tools never accept prefixes). */
174
+ export declare const COMMIT_OID_RE: RegExp;
175
+ /**
176
+ * Rebuilds the handle AST in place after a package-level restore
177
+ * (revert/redo): the parser DOMs were rewound underneath, so the live AST
178
+ * object (shared with handle.engine) is refreshed field-by-field, mirroring
179
+ * the engine rollback path so external references stay valid.
180
+ */
181
+ export declare function refreshHandleAstInPlace(handle: DocHandle): Promise<void>;
182
+ /**
183
+ * Phase C-1c: maps a validator failure to an xpath-specific remedy instead
184
+ * of the generic copy-paste. Matches on the validator xPath (falls back to
185
+ * the description text): drawing docPr/@id, table tbl children, and
186
+ * relationships each name their own fix.
187
+ */
188
+ export declare function remedyForValidationError(xPath: unknown, description: unknown): string;
189
+ /**
190
+ * Table node ids in live document order (session ids such as t_001.. or
191
+ * minted insert ids). Best-effort, never throws. Used to resolve a validator
192
+ * table ordinal to the concrete node id the agent should fix.
193
+ */
194
+ export declare function collectTableNodeIdsInOrder(ast: unknown): string[];
195
+ /**
196
+ * Builds the location fragment for a save-blocked envelope. Always names a
197
+ * location: the validator xPath verbatim plus the resolved table ordinal and
198
+ * session node id when the failure is table-related; the bare xPath for other
199
+ * parts; an explicit no-xPath fallback (with the live table inventory) when
200
+ * the validator gave no path. Never throws.
201
+ * Ordinals are body-top-level only: a nested-table fault resolves to the
202
+ * outer containing table (safe direction, never a wrong sibling).
203
+ */
204
+ export declare function formatValidationLocation(xPath: unknown, tableIds?: readonly string[]): string;
205
+ /**
206
+ * Shapes a rejected restore candidate (revert/redo) into the same
207
+ * xpath-specific E_VALIDATION throw the validating save uses, so callers get
208
+ * a fix-and-retry hint instead of a bare schema dump.
209
+ */
210
+ export declare function invalidRestoreError(toolName: string, errors: unknown, verb: string, tableIds?: readonly string[]): Error;
211
+ /** Best-effort restore double-fault visibility: file + op context on stderr. */
212
+ export declare function logRestoreFailure(op: string, filePath: string, step: string, err: unknown): void;
213
+ /**
214
+ * Honest remedy: only claim "left unchanged" when every restore step was
215
+ * verified. When any step failed, point at inspect/history verification.
216
+ */
217
+ export declare function honestRestoreRemedy(op: string, memoryOk: boolean, diskOk: boolean, okRemedy: string, detail: string): string;
218
+ export declare function pathDirname(p: string): string;
219
+ /** True when the sidecar git repo exists for `docPath` (read-only probe). */
220
+ export declare function sidecarRepoExists(docPath: string): boolean;
@@ -0,0 +1,45 @@
1
+ import { type EngineErrorCode } from '@attentionform/astra-engine';
2
+ export type McpErrorCode = EngineErrorCode;
3
+ export interface McpErrorShape {
4
+ ok: false;
5
+ code: McpErrorCode;
6
+ message: string;
7
+ remedy: string;
8
+ }
9
+ export declare function mcpError(code: McpErrorCode, message: string, remedy: string): McpErrorShape;
10
+ /**
11
+ * Q0b: core envelope mapper (exported for the E-code contract test, same as
12
+ * the visual/export/compose/new-document mappers). Every engine code survives
13
+ * verbatim via the shared getEngineErrorCode table (.code first, then
14
+ * [E_*]/E_* in the message — this catches message-only engine failures like
15
+ * the [E_LIMIT] zip ceilings and [E_SECURITY] adm-zip blocks that carry no
16
+ * .code prop). Uncoded failures keep the call-site fallback. Remedy passes
17
+ * through verbatim when the error carries its own, else the fallback.
18
+ */
19
+ export declare function mcpErrorFrom(err: unknown, fallbackCode: McpErrorCode, fallbackRemedy: string): McpErrorShape;
20
+ /**
21
+ * P2-2: strip `at ...` stack frames + absolute host paths from the
22
+ * client-facing message. Full stack stays stderr-only (engine already logs
23
+ * `🚨 Critical error...` to stderr; handlers log the raw value below).
24
+ * Minimal, no schema widening: first line + redacted paths only.
25
+ */
26
+ export declare function sanitizeMcpClientMessage(raw: unknown): string;
27
+ export declare function rewritePhantomMcpToolNames(text: string): string;
28
+ /**
29
+ * Commit-message hygiene for git-backed tools: single-line, capped.
30
+ * Newlines become spaces (multi-line input stays one commit subject);
31
+ * over-long input is truncated. Blank input falls back.
32
+ */
33
+ export declare const COMMIT_MESSAGE_MAX = 500;
34
+ export declare const COMMIT_AUTHOR_MAX = 100;
35
+ export declare const COMMIT_AUTHOR_DEFAULT = "ASTra Agent";
36
+ export declare function sanitizeCommitMessage(raw: unknown, fallback: string): string;
37
+ export declare function sanitizeCommitAuthor(raw: unknown): string;
38
+ /**
39
+ * Cross-surface parity: an unknown/expired session is E_SESSION on EVERY MCP
40
+ * tool (session tools preserve the store's E_SESSION verbatim; the history /
41
+ * audit family maps the same failure through this helper). Message + remedy
42
+ * stay byte-identical to the session-store shape for the same reason.
43
+ */
44
+ export declare function unknownSessionError(sessionId: string): McpErrorShape;
45
+ export declare function invalidInput(message: string): McpErrorShape;
@@ -0,0 +1,34 @@
1
+ import type { McpSessionStore } from '../../session-store';
2
+ import type { McpErrorShape } from '../errors';
3
+ export interface AuditTrailRow {
4
+ oid: string;
5
+ message: string;
6
+ author: string;
7
+ /** Ms-precision epoch millis (audit-bridge meta when tracked, else git seconds). */
8
+ timestampMs: number;
9
+ opCount?: number;
10
+ affectedNodeIds?: string[];
11
+ resultingHeadOid: string;
12
+ /** sha256 hex over the committed document.xml at this revision (reproducible). */
13
+ packageHash: string;
14
+ }
15
+ /**
16
+ * export_audit_trail handler (handler-only, NOT a registered MCP tool — the
17
+ * 12-tool pin is unaffected). Returns the full saved history plus a sha256
18
+ * over each revision's committed document.xml, recomputed via the read-only
19
+ * checkoutCommit path so verifiers can reproduce every hash independently.
20
+ * Read-only: never mutates revision state, disk bytes, or the redo stack.
21
+ * The HOLD retention note rides along because .astra/ is deletable local
22
+ * state and full server-side retention is OUT of scope.
23
+ */
24
+ export declare function handleExportAuditTrail(store: McpSessionStore, input: unknown): Promise<{
25
+ ok: true;
26
+ sessionId: string;
27
+ documentPath: string;
28
+ totalCommits: number;
29
+ currentCommit: string | null;
30
+ returnedCount: number;
31
+ truncated: boolean;
32
+ trail: AuditTrailRow[];
33
+ retentionNote: string;
34
+ } | McpErrorShape>;
@@ -0,0 +1,93 @@
1
+ import type { McpSessionStore } from '../../session-store';
2
+ import type { McpErrorShape } from '../errors';
3
+ import type { ChangedValue, DiscardedUnsavedSummary } from '../diff';
4
+ export interface HistoryEntry {
5
+ oid: string;
6
+ message: string;
7
+ author: string;
8
+ timestamp: Date;
9
+ /** Ms-precision epoch millis (audit-bridge meta when tracked, else git seconds). */
10
+ timestampMs: number;
11
+ /** Operations folded into this commit (0 for pre-tracking commits and heals-only saves). */
12
+ opCount?: number;
13
+ /** Node ids touched by this commit, bounded ([] for pre-tracking commits). */
14
+ affectedNodeIds?: string[];
15
+ /** Head oid resulting from this commit (== oid; append-only, refs never move). */
16
+ resultingHeadOid: string;
17
+ }
18
+ export declare function handleGetDocumentHistory(store: McpSessionStore, input: unknown): Promise<{
19
+ ok: true;
20
+ sessionId: string;
21
+ documentPath: string;
22
+ currentCommit: string | null;
23
+ totalCommits: number;
24
+ history: HistoryEntry[];
25
+ /** R-6 sidecar-removal warning (string when a regenerated chain replaced recorded history, else null). Additive, never a failure. */
26
+ warning: string | null;
27
+ } | McpErrorShape>;
28
+ export declare function handleRevertDocument(store: McpSessionStore, input: unknown): Promise<{
29
+ ok: true;
30
+ sessionId: string;
31
+ path: string;
32
+ revertedToCommit: string;
33
+ revision: number;
34
+ dirty: false;
35
+ /** Bounded echo of the unsaved edits discarded by this revert (zero summary when clean). */
36
+ discardedUnsaved: DiscardedUnsavedSummary;
37
+ commitOid: string;
38
+ commitMessage: string;
39
+ } | (McpErrorShape & {
40
+ dirtyReason?: string;
41
+ })>;
42
+ export declare function handleRedoDocument(store: McpSessionStore, input: unknown): Promise<{
43
+ ok: true;
44
+ sessionId: string;
45
+ path: string;
46
+ revision: number;
47
+ dirty: false;
48
+ commitOid: string;
49
+ commitMessage: string;
50
+ /** Advisory old→new value summaries (pre-redo live -> restored redo text; bounded). */
51
+ changedValues: ChangedValue[];
52
+ /** True when the count or per-string cap truncated changedValues. */
53
+ changedValuesTruncated: boolean;
54
+ /** Present when the value diff was not computable (empty changedValues). */
55
+ changedValuesReason?: string;
56
+ } | (McpErrorShape & {
57
+ atLatestState?: true;
58
+ })>;
59
+ /**
60
+ * Read-only WOULD-restore preview for revert_document. Resolves the same
61
+ * target (steps XOR commitOid, same E_ codes), reads the target package via
62
+ * the ref-safe checkoutCommit, and diffs package bytes — but performs zero
63
+ * writes: no revision bump, no markSaved, no redo-stack touch, no disk write.
64
+ * Dirty sessions are reported (dirty + dirtyHandling), never discarded here.
65
+ */
66
+ export declare function handlePreviewRevert(store: McpSessionStore, input: unknown): Promise<{
67
+ ok: true;
68
+ sessionId: string;
69
+ targetOid: string;
70
+ targetMessage: string;
71
+ targetAuthor: string;
72
+ stepsBack: number;
73
+ affectedFiles: string[];
74
+ /** Advisory old→new value summaries (live current -> target restore text; bounded). */
75
+ changedValues: ChangedValue[];
76
+ /** True when the count or per-string cap truncated changedValues. */
77
+ changedValuesTruncated: boolean;
78
+ /** True when either side held orphan ids (no shared id across the boundary): paired entries are positional, not identity. */
79
+ changedValuesPositional: boolean;
80
+ /** Present when the target range is not computable (empty changedValues). */
81
+ changedValuesReason?: string;
82
+ dirty: boolean;
83
+ dirtyHandling: string;
84
+ currentHeadOid: string;
85
+ totalCommits: number;
86
+ } | McpErrorShape>;
87
+ /** Git-history dispatch table (registered alongside lean-6 in index.ts). */
88
+ export declare const GIT_HISTORY_HANDLERS: {
89
+ readonly get_document_history: typeof handleGetDocumentHistory;
90
+ readonly preview_revert: typeof handlePreviewRevert;
91
+ readonly revert_document: typeof handleRevertDocument;
92
+ readonly redo_document: typeof handleRedoDocument;
93
+ };
@@ -0,0 +1,71 @@
1
+ import { DocxParser, type StyleGuideSummary } from '@attentionform/astra-engine';
2
+ import type { McpSessionStore } from '../../session-store';
3
+ import type { McpErrorShape } from '../errors';
4
+ import { type OpenValidationField } from '../baseline-gate';
5
+ export interface StylePalette {
6
+ availableStyles: string[];
7
+ brandColors: string[];
8
+ primaryFont: string;
9
+ headingStyles?: string[];
10
+ }
11
+ export declare function extractStylePalette(parser: DocxParser): StylePalette;
12
+ export declare function handleOpenDocument(store: McpSessionStore, input: unknown): Promise<{
13
+ ok: true;
14
+ sessionId: string;
15
+ revision: number;
16
+ summary: unknown;
17
+ evicted: string[];
18
+ pendingNormalizations: string[];
19
+ validation: OpenValidationField;
20
+ } | McpErrorShape>;
21
+ /**
22
+ * Phase C-2: docs rendering under ~2000 tokens return the full TOON
23
+ * (pre-C behavior, zero friction). Larger docs default to the first
24
+ * ~50-node window. Behavior-change note: large-doc default changed from
25
+ * full dump to first window — the navigation remedy teaches paging.
26
+ */
27
+ export declare const INSPECT_FULL_TOON_TOKEN_THRESHOLD = 2000;
28
+ export interface InspectWindowEnvelope {
29
+ totalNodes: number;
30
+ returnedNodes: number;
31
+ offset: number;
32
+ limit: number;
33
+ hasMore: boolean;
34
+ nextOffset: number | null;
35
+ truncated: boolean;
36
+ }
37
+ /**
38
+ * Best-effort dry-run preview of pending allowlist normalizations for an
39
+ * inspect envelope (clone-based, never mutates, never fails the inspect).
40
+ */
41
+ export declare function readPendingNormalizations(handle: {
42
+ parser?: {
43
+ getPendingNormalizations?: () => string[];
44
+ };
45
+ }): string[];
46
+ export declare function handleInspectDocument(store: McpSessionStore, input: unknown): Promise<{
47
+ ok: true;
48
+ sessionId: string;
49
+ revision: number;
50
+ /** Phase C-1b: true when in-memory state holds unsaved execute_batch edits. */
51
+ dirty: boolean;
52
+ fidelity: string;
53
+ palette: StylePalette;
54
+ /** E2 (F-4): docProps/core.xml core properties (Dates as ISO strings; {} when absent). */
55
+ metadata: Record<string, unknown>;
56
+ /** Would-be allowlist normalizations a save would apply (dry-run preview, [] when canonical). */
57
+ pendingNormalizations: string[];
58
+ toonText: string;
59
+ rowCount: number;
60
+ totalNodes: number;
61
+ returnedNodes: number;
62
+ offset: number;
63
+ limit: number;
64
+ hasMore: boolean;
65
+ nextOffset: number | null;
66
+ truncated: boolean;
67
+ /** Present when windowed: teaches search -> aroundNode zoom -> offset paging. */
68
+ remedy?: string;
69
+ /** Compact summary of the session style guide (absent when none attached). */
70
+ styleGuide?: StyleGuideSummary;
71
+ } | McpErrorShape>;