append_hwp_paragraph
Append a new paragraph to the end of an HWPX document, cloning the last paragraph's structure and inserting specified text.
Instructions
Append a new paragraph to the end of an .hwpx document body. Clones the last paragraph's structure (paraPr/charPr/style refs) and replaces text. Args: file_path, text, output_path (optional).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| file_path | Yes | ||
| text | Yes | ||
| output_path | No |
Implementation Reference
- src/tools/edit.ts:51-63 (handler)MCP tool handler that validates file path (must be .hwpx), determines output path, calls appendHwpxParagraph core function, and returns a Korean/English status message.
export async function appendHwpParagraph(args: AppendParaArgs): Promise<string> { const err = preflight(args.file_path); if (err) return err; const out = args.output_path && args.output_path.length > 0 ? args.output_path : defaultOutput(args.file_path, "appended"); try { const r = await appendHwpxParagraph(args.file_path, out, args.text); return `문단 추가 (paragraph appended): ${r.inserted}건\n저장 (saved): ${out}`; } catch (e) { return `문단 추가 오류 (append error): ${(e as Error).message}`; } } - src/tools/edit.ts:45-49 (schema)TypeScript interface defining the input arguments for appendHwpParagraph: file_path (required), text (required), output_path (optional).
export interface AppendParaArgs { file_path: string; text: string; output_path?: string; } - src/server.ts:217-230 (registration)Tool registration in the TOOLS array with name 'append_hwp_paragraph', description, and inputSchema (JSON Schema with file_path and text required).
{ name: "append_hwp_paragraph", description: "Append a new paragraph to the end of an .hwpx document body. Clones the last paragraph's structure (paraPr/charPr/style refs) and replaces text. Args: file_path, text, output_path (optional).", inputSchema: { type: "object", properties: { file_path: { type: "string" }, text: { type: "string" }, output_path: { type: "string" }, }, required: ["file_path", "text"], }, }, - src/server.ts:526-527 (registration)Maps the tool name 'append_hwp_paragraph' to the appendHwpParagraph handler function in the HANDLERS record.
append_hwp_paragraph: appendHwpParagraph, delete_hwp_paragraph: deleteHwpParagraph, - src/core/hwpx-mutate.ts:188-212 (helper)Core mutation logic: loads the .hwpx ZIP, finds the last paragraph via regex, clones its attributes (with a fresh id), creates a new paragraph with the given text, inserts it before the closing </hs:sec>, and writes the modified ZIP.
export async function appendHwpxParagraph( inputPath: string, outputPath: string, text: string ): Promise<{ inserted: number }> { const { zip, sectionName, xml } = await loadSection(inputPath); const matches = [...xml.matchAll(PARA_REGEX)]; if (matches.length === 0) throw new Error("No <hp:p> paragraph found in section to clone"); const last = matches[matches.length - 1][0]; // Extract <hp:p> attributes (paraPrIDRef, styleIDRef, etc.) — keep them, // but build a minimal body to avoid cloning embedded secPr/linesegarray/etc. const openTagMatch = last.match(/^<hp:p ([^>]*)>/); if (!openTagMatch) throw new Error("Could not parse <hp:p> opening tag"); const attrs = openTagMatch[1].replace(/\s*id="\d+"\s*/, ` id="${freshId()}" `); // Find a charPrIDRef from any <hp:run ...> inside the cloned para; default 0. const charPrMatch = last.match(/<hp:run [^>]*charPrIDRef="(\d+)"/); const charPrId = charPrMatch ? charPrMatch[1] : "0"; const newPara = `<hp:p ${attrs}>` + `<hp:run charPrIDRef="${charPrId}"><hp:t>${xmlEscape(text)}</hp:t></hp:run>` + `</hp:p>`; const newXml = xml.replace(/<\/hs:sec>\s*$/, newPara + "</hs:sec>"); await writeSection(zip, sectionName, newXml, outputPath); return { inserted: 1 }; }