reactive-resume
reactive-resume
A one-of-a-kind resume builder that keeps your privacy in mind. Completely secure, customizable, portable, open-source and free forever. Try it out today!
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:blazar-source/dsh-r7-office
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
R7-Office (Р7-Офис) document processing plugin and Model Context Protocol (MCP) server for DeepSeek Harness.
Lets an AI agent inspect, read, create, format, edit and convert DOCX, XLSX,
PPTX and PDF documents — through standard OOXML manipulation plus the R7
converter you already have installed — without emulating a mouse or keyboard.
⚠️ Unofficial community project
This is an independent, community-maintained project. It is not affiliated with, endorsed by, sponsored by, or supported by АО «Р7» (R7-Office) or DeepSeek, and it is not an official R7-Office or DeepSeek product.
R7-Office and Р7-Офис are trademarks of their respective owners and are used here only to describe what this software interoperates with.
This repository contains no R7-Office code, binaries or other assets. It detects an R7-Office installation already present on the user's machine and drives it locally. You must install and license R7-Office yourself.
Русская документация: README.ru.md
x2t engine).r7_validate checks package integrity before and
after a change.DeepSeek Harness ──► dsh-r7-office plugin ──┐
├──► DOCX / XLSX / PPTX / PDF
Any MCP client ────► MCP server (stdio) ────┤
│
R7-Office Desktop ◄── desktop bridge ◄──────┘
Details in docs/architecture.md; design decisions in docs/decisions/.
| Node.js | >= 20.0.0 to run the plugin and MCP server. >= 22.0.0 to run the full test suite (the bridge and CDP clients use the global WebSocket, which only exists from Node 22). |
| Runtime dependencies | none — the plugin has zero runtime dependencies |
| R7-Office Desktop | optional. Needed for r7_convert (→ PDF/HTML), inspect fidelity on exotic documents, and the whole desktop bridge. Without it the pure-OOXML tools still work. |
| Platform | Windows, Linux and macOS. R7 auto-detection covers the standard install locations of all three; the live desktop bridge is verified on Windows only (see limitations). |
These steps assume an empty directory and a machine with Node.js 20+.
# 1. Get the code
git clone https://github.com/blazar-source/dsh-r7-office.git
cd dsh-r7-office
# 2. Install the optional dev dependencies (test-only: the MCP client SDK)
npm install
# 3. Verify the checkout — no R7-Office required for this step
npm test
npm test is the portable suite and needs nothing but Node: unit tests,
OOXML round-trip regression tests, file end-to-end workflows, security-policy
tests and an external MCP client smoke suite. Tests whose subject is the
installed product — R7's own templates, the x2t converter, the desktop editor
— skip themselves with a stated reason instead of failing, so a machine
that has never seen R7-Office gets a green run and a visible skip count.
$ npm test
# tests 469
# pass 390
# fail 0
# skipped 79
The R7-dependent tests are only meaningful where R7-Office is installed, so they get their own command, which refuses to run without it rather than skipping everything and reporting success:
# Requires an installed R7-Office. Runs the whole suite with nothing skipped,
# then drives the live desktop editor over CDP and saves a document for real.
npm run test:r7
# Just the suite, or just the live editor, if you want them separately:
npm run test:r7 -- --suite
npm run test:r7 -- --live
To see what the portable suite does on a machine without R7 even though you
have one installed, set R7_OFFICE_DISABLED=1 — detection then reports no
installation, which is exactly the condition CI runs under.
Then verify the integration you actually intend to use:
# R7-Office file pipeline (author → edit → validate → PDF). Skips if R7 is absent.
npm run test:live
# DeepSeek Harness plugin activation. Boots a fresh Harness and asserts the
# 28 r7_* tools reached the tool registry.
npm run test:harness -- --profile web
Install the package directory as a bundle:
# in the DeepSeek Harness UI: plugin_manager → install_bundle
# target: /absolute/path/to/dsh-r7-office
or from the CLI equivalent for your profile:
dsh plugin --profile <profile> add /absolute/path/to/dsh-r7-office
Confirm it activated — a fresh Harness boot prints:
[r7-office] зарегистрировано инструментов: 27 (r7_inspect, r7_read, ...); desktop bridge port=7888, developerMode=false
Note. Add the row either through
install_bundleor by hand in the profile'scordis.patch.yml— never both. Two entries with the samer7-officeid make the row fail to activate.
The plugin also registers a short usage section into the agent system prompt,
so the agent knows the tools and the intended inspect → read → edit → validate → convert order.
The MCP server speaks line-delimited JSON-RPC 2.0 on stdio.
{
"mcpServers": {
"r7-office": {
"command": "node",
"args": ["/absolute/path/to/dsh-r7-office/src/mcp/cli.js"]
}
}
}
Put that in your client's configuration file (for example
claude_desktop_config.json or .cursor/mcp.json). Any stdio MCP client
works; interoperability is verified in npm test against the official
@modelcontextprotocol/client SDK.
You can also run it by hand:
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node src/mcp/cli.js
| Tool | Purpose |
|---|---|
r7_inspect |
Document outline: headings, paragraphs, tables, sheets, slides, metadata |
r7_read |
Structured text, Markdown view, or spreadsheet cell ranges |
r7_create |
New DOCX / XLSX / PPTX. Refuses to replace an existing file unless overwrite: true; every sheets[] entry and name is honoured |
r7_edit |
Replace, restyle or delete one paragraph by index |
r7_replace |
Find and replace text, preserving run formatting |
r7_insert |
Insert paragraphs, headings, bullet items or page breaks |
r7_table |
Create, inspect or update tables and cells, including merge, borders, shading and column widths |
r7_docx_formatting |
Read the normalized formatting of every paragraph, run and table cell: style, font, size, colour, alignment, indents, spacing, line spacing, lists |
r7_docx_sections |
Read and set page size, orientation, margins, columns, page breaks and section breaks |
r7_docx_header_footer |
List, read, create or retitle headers and footers; page-number fields survive |
r7_docx_image |
Insert a PNG/JPEG/GIF at a size, keeping the aspect ratio |
r7_docx_hyperlink |
List, insert, retitle or remove hyperlinks and their relationships |
r7_sheet_read |
Read values, formulas or the normalized formatting of a sheet or range (e.g. A1:D10) |
r7_sheet_write |
Write cells or a 2-D matrix, addressed by sheet name or index; dates are stored as real date serials |
r7_sheet_format |
Format a cell or range: font, background, borders, alignment, wrap, number format (integer, decimal, currency, percent, date, datetime, custom), merge, column width and row height |
r7_sheet_add |
Add a worksheet to an existing workbook; other sheets are untouched |
r7_sheet_formula |
Insert or update a formula |
r7_slide_read |
Read a slide as a normalized structure: every object's id, type, geometry, text, font, fill, stroke, alignment and paragraphs |
r7_slide_create |
Create a deck, or append a slide built on one of the deck's own layouts, without altering the slides already there |
r7_slide_format |
Restyle or reposition one existing object in place: font, geometry, fill, border, alignment, lists, spacing, text |
r7_slide_edit |
Duplicate, move, reorder or delete slides |
r7_slide_object |
Add or remove an object: shape, text box or PNG/JPEG image |
r7_convert |
Convert via the R7 x2t engine (PDF, HTML, TXT, DOCX, XLSX, PPTX). PDF conversion uses the font list R7 generates, repairs a malformed ToUnicode count, and refuses to return a PDF with no extractable text instead of silently emitting a blank one. XLSX exports every worksheet by default (allSheets) |
r7_validate |
Check package integrity and XML health |
r7_pdf_inspect |
Report whether a PDF really contains text or was produced without fonts: per-font embedded flag and ToUnicode/Cyrillic map counts, text glyphs, empty fill operators, and a text / outlined / mixed verdict. repair: true fixes a malformed ToUnicode count in place |
r7_desktop_status |
Desktop bridge connection and effective security mode |
r7_desktop_selection |
Read or replace the selection in the open editor |
r7_desktop_exec |
Run a safe editor command, or raw DocScript in developer mode |
A deck is built on the layouts it already has. Adding a slide registers the
slide part, its relationship part, its [Content_Types].xml override, its
<p:sldId> entry and the presentation relationship; the layout, the master,
the theme, the notes and every slide that already existed keep their original
bytes. A placeholder written onto a slide stays a placeholder, so it keeps
inheriting its geometry and typography from the master.
Reading resolves that inheritance for you: r7_slide_read reports a title
slide's 60 pt layout title rather than the presentation's 18 pt default, and
reports the position a placeholder inherits from the layout or the master
instead of null.
import { PptxEngine } from 'dsh-r7-office/r7'
const pptx = new PptxEngine()
// 1. Read: geometry, text, font, fill, stroke, alignment, paragraphs.
const before = await pptx.readSlide('Deck.pptx', 1)
const title = before.slide.objects.find(o => o.placeholder?.type === 'title')
const body = before.slide.objects.find(o => o.placeholder?.type === 'body')
console.log(title.x, title.width, title.font.family, title.font.size)
// 2. Add a slide on one of the deck's own layouts.
const added = await pptx.addSlide('Deck.pptx', {
layoutType: 'obj',
title: 'Ключевые выводы',
paragraphs: [{ text: 'Выручка +18%', bullet: true }]
})
// 3. Restyle one object. Everything not named keeps its original bytes.
await pptx.formatObject('Deck.pptx', {
slideIndex: added.slideIndex,
objectId: title.id,
font: { family: 'Georgia', size: 32, bold: true, color: '#1F6FEB' },
alignment: 'center'
})
// 4. Add an object: fill, border, text, font, geometry — all in one call.
await pptx.addShape('Deck.pptx', {
slideIndex: added.slideIndex,
shape: 'rounded-rectangle', // rectangle, ellipse, line, arrow, star, …
x: '2cm', y: '10cm', width: '9.4cm', height: '8.2cm',
fill: '#1F6FEB', fillTransparency: 0.1,
line: '#0B3D91', lineWidth: 2, // lineWidth is in points
text: 'KPI 98%',
font: { family: 'Arial', size: 24, bold: true, color: '#FFFFFF' },
alignment: 'center', verticalAnchor: 'middle'
})
// 5. Insert and replace a picture.
const image = await pptx.addImage('Deck.pptx', {
slideIndex: added.slideIndex, imagePath: 'chart.png', x: '4cm', y: '4cm', width: '24cm'
})
await pptx.formatObject('Deck.pptx', {
slideIndex: added.slideIndex, objectId: image.objectId, imagePath: 'chart-v2.png'
})
// 6. Structure, and a PDF.
await pptx.duplicateSlide('Deck.pptx', 1)
await pptx.moveSlide('Deck.pptx', 2, 0)
await pptx.deleteSlide('Deck.pptx', 4)
console.log((await pptx.validate('Deck.pptx')).valid)
await pptx.toPdf('Deck.pptx', 'Deck.pdf')
Run the full acceptance deck:
node examples/pptx-acceptance.js # writes into os.tmpdir()/r7-acceptance
node examples/pptx-acceptance.js ./out # or wherever you like
Measurements. A bare number is EMU (the unit r7_slide_read returns), so a
value can be read, adjusted and written back unchanged. "2cm", "1in",
"30px" and "24pt" also work. lineWidth is the exception: a number below
100 is read as points, because "border: 1.5" means 1.5 pt to everyone who is
not holding a DrawingML specification.
Colours. #RRGGBB, #AARRGGBB and transparency as a separate 0..1 option.
transparency on a font and fillTransparency on a fill are deliberately
distinct, so a half-transparent caption colour cannot make the shape under it
see-through.
Shapes. rectangle, rounded-rectangle, ellipse, circle, line,
arrow (and arrow-left/up/down/left-right), triangle, diamond,
pentagon, hexagon, octagon, star, chevron, plus, cloud, heart,
cylinder, cube, donut, pie, parallelogram, trapezoid — or any
DrawingML preset name. pptx.shapeCatalog() lists them all.
"Take
Report.docx, update section 3, keep the formatting, add a summary table and save a PDF."
r7_inspect → r7_read → r7_replace (keeps formatting) → r7_table
→ r7_validate → r7_convert
Run it yourself:
node examples/report-scenario.js
Library use:
import { DocxEngine, R7Adapter } from 'dsh-r7-office/r7'
const docx = new DocxEngine()
const adapter = new R7Adapter()
await docx.replaceText('Report.docx', 'draft text', 'approved text', {
outputPath: 'Report_v2.docx' // the original is never overwritten by default
})
await docx.table('Report_v2.docx', {
action: 'create',
rows: [['Objective', 'Timeline', 'Owner'], ['Deploy R7', 'Q2', 'IT']]
})
console.log((await docx.validate('Report_v2.docx')).valid)
await adapter.convert('Report_v2.docx', 'Report_v2.pdf')
r7_desktop_exec can execute code inside the user's open editor. Raw
DocScript is therefore disabled by default; only a fixed allowlist of safe
argument-driven commands runs in production. Enable raw execution only
deliberately:
- id: r7-office
name: 'dsh-r7-office'
config:
developerMode: true # or export DSH_R7_DEVELOPER_MODE=1
r7_desktop_status always reports the effective mode. The desktop bridge binds
to 127.0.0.1 only.
See SECURITY.md for the full threat model and how to report a vulnerability.
type: "chart", type: "graphicFrame") and every part
behind them stays byte-identical through any edit, but the engine cannot
create one. A hand-written SmartArt frame is just a dgm:relIds reference,
and R7's own renderer dereferences the diagram parts behind it.scheme:accent1),
because no literal hex exists until the theme is resolved. Writing accepts
literals only.Editors-2026.3.1). Other platforms should work; they are untested.r7_convert needs a local R7 installation for its
x2t converter. Everything else works without it.tblStyle); changing a hyperlink's target
(retitle, or remove and insert instead); a convenience wrapper for per-section
different headers (both can be read and preserved, and r7_docx_header_footer
accepts first/even — for first also call r7_docx_sections with
titlePg). Search is not revision-aware: r7_replace scans raw <w:t>, so
text inside a tracked insertion is editable and paragraph indices count
paragraphs inside deleted content — <w:delText> is never matched.Subtitle (italic, centred, grey) may render with a faint
line across it after r7_convert. The document contains no strikethrough,
underline or paragraph border — w:strike, w:u and w:pBdr are all absent,
and the same style applied to R7's own template renders cleanly through the
same converter — so the line is introduced during PDF conversion and cannot
be corrected from the document. It is cosmetic: the text itself is correct and
extracts normally. Quantified at roughly 5 % more ink in that text band.validate() while
drawing the wrong glyphs or a solid block. scripts/visual-acceptance.py
renders the output with two independent engines and compares against a
LibreOffice render of the source; run it when changing anything in the
conversion path.r7_sheet_format; conditional formatting, data
validation, charts, pivot tables and defined names are preserved but not
editable.dgm:relIds reference), and editing their content is out of scope.npm test # the portable suite; needs only Node, R7 tests skip
npm run test:unit
npm run test:integration
npm run test:e2e
npm run test:r7 # requires R7-Office: full suite + the live desktop editor
npm run test:live # just the live desktop bridge (needs R7-Office)
npm run test:harness # boots a fresh DeepSeek Harness
npm run inspect:r7 # CDP probe of a running R7 Desktop
See docs/development.md and docs/roadmap.md.
MIT — see LICENSE.
R7-Office is proprietary software owned by АО «Р7». This project redistributes none of it.
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: mcp。