Add docs, scripts, skills, commands, and taskmaster config to repo

Includes:
- docs/: architecture, block-schema, migration-plan, product-specification
- scripts/: bidi_table, decompose-decisions, extract-claims, seed-knowledge, etc.
- skill-legal-decision/: SKILL.md + references + block-schema
- skill-legal-assistant/: SKILL.md
- skill-legal-docx/: SKILL.md + references
- .claude/commands/: bidi-table skill
- .taskmaster/: task config + PRDs
- .gitignore: exclude legacy/, kiryat-yearim/, node_modules/, memory/

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-04 14:19:17 +00:00
parent bacb330a2a
commit d5ccf03e4c
41 changed files with 9356 additions and 2 deletions

View File

@@ -0,0 +1,261 @@
#!/usr/bin/env node
/**
* create-legal-doc.js — תבנית בסיסית למסמך משפטי בעברית
*
* שימוש: העתק לתיקיית העבודה, ערוך את CONTENT, הרץ עם node.
*
* הסקריפט כולל את כל הגדרות ה-RTL הנדרשות ב-5 רמות:
* 1. Document defaults (styles)
* 2. Section properties (bidi: true)
* 3. Per-paragraph (bidirectional + alignment)
* 4. Per-run (rightToLeft + font)
* 5. Numbering (alignment: START, not RIGHT!)
*
* שינוי פונט: החלף "David" ב-"FrankRuehl" או "Miriam"
* שינוי שוליים: שנה MARGIN_CM
*
* v3.0 — תיקון באג: AlignmentType.START במקום RIGHT במספור
*/
const fs = require('fs');
const { Document, Packer, Paragraph, TextRun, Header, Footer,
AlignmentType, HeadingLevel, PageNumber, LevelFormat,
Table, TableRow, TableCell, WidthType, BorderStyle,
LineRuleType } = require('docx');
// ═══════════════════════════════════════════════
// CONFIGURATION — שנה כאן
// ═══════════════════════════════════════════════
const FONT = "David";
const FONT_SIZE = 24; // half-points (24 = 12pt)
const HEADING1_SIZE = 32; // 16pt
const HEADING2_SIZE = 28; // 14pt
const MARGIN_CM = 2.5;
const MARGIN_DXA = Math.round(MARGIN_CM / 2.54 * 1440);
const OUTPUT_FILE = "legal-document.docx";
const HEADER_TEXT = ""; // שם המשרד — השאר ריק אם לא צריך
const FOOTER_CONFIDENTIAL = "";
// ═══════════════════════════════════════════════
// HELPERS — פונקציות עזר
// ═══════════════════════════════════════════════
// TextRun עם RTL
const rtlRun = (text, opts = {}) => new TextRun({
text,
...opts,
font: opts.font || FONT,
size: opts.size || FONT_SIZE,
rightToLeft: true, // ← חובה! תמיד אחרון — לא ניתן לדריסה
});
// Paragraph עם RTL
const rtlPara = (children, opts = {}) => new Paragraph({
bidirectional: true, // ← חובה!
alignment: opts.alignment || AlignmentType.BOTH, // ✅ BOTH, לא JUSTIFIED
spacing: opts.spacing,
children: Array.isArray(children) ? children : [children],
...(opts.heading ? { heading: opts.heading } : {}),
...(opts.numbering ? { numbering: opts.numbering } : {}),
});
// כותרת ראשית
const heading1 = (text) => rtlPara(
rtlRun(text, { bold: true, size: HEADING1_SIZE }),
{ heading: HeadingLevel.HEADING_1, alignment: AlignmentType.CENTER }
);
// כותרת משנה
const heading2 = (text) => rtlPara(
rtlRun(text, { bold: true, size: HEADING2_SIZE }),
{ heading: HeadingLevel.HEADING_2, alignment: AlignmentType.START } // ✅ START
);
// רווח
const spacer = (after = 200) => rtlPara(rtlRun(""), { spacing: { after } });
// ═══════════════════════════════════════════════
// CONTENT — ערוך כאן את תוכן המסמך
// ═══════════════════════════════════════════════
const CONTENT = [
// כותרת
heading1("הסכם שירותים משפטיים"),
// תאריך
rtlPara(rtlRun("נערך ונחתם בתל אביב ביום ___________"), { spacing: { after: 200 } }),
// צדדים
heading2("בין הצדדים"),
rtlPara([
rtlRun("מצד אחד: ", { bold: true }),
rtlRun('[שם], ח.פ./ת.ז. [מספר], מ[כתובת] (להלן: "'),
rtlRun("המזמין", { bold: true }),
rtlRun('")'),
], { spacing: { after: 120 } }),
rtlPara([
rtlRun("מצד שני: ", { bold: true }),
rtlRun('[שם], ח.פ./ת.ז. [מספר], מ[כתובת] (להלן: "'),
rtlRun("הספק", { bold: true }),
rtlRun('")'),
], { spacing: { after: 200 } }),
// הואילים
heading2("הואיל:"),
rtlPara(rtlRun("1. והואיל ו[תנאי ראשון];"), { spacing: { after: 120 } }),
rtlPara(rtlRun("2. והואיל ו[תנאי שני];"), { spacing: { after: 120 } }),
rtlPara(rtlRun("3. והואיל והצדדים מעוניינים להסדיר את תנאי ההתקשרות ביניהם;"),
{ spacing: { after: 200 } }),
// מעבר
rtlPara(rtlRun("לפיכך הוסכם, הותנה והוצהר בין הצדדים כדלקמן:", { bold: true }),
{ alignment: AlignmentType.CENTER, spacing: { before: 200, after: 200 } }),
// סעיפים
heading2("1. היקף השירותים"),
rtlPara(rtlRun("1.1 [תוכן הסעיף]"), { spacing: { after: 120 } }),
rtlPara(rtlRun("1.2 [תוכן הסעיף]"), { spacing: { after: 120 } }),
heading2("2. התמורה"),
rtlPara(rtlRun("2.1 [תוכן הסעיף]"), { spacing: { after: 120 } }),
// חתימות
rtlPara(rtlRun("ולראיה באו הצדדים על החתום:", { bold: true }),
{ alignment: AlignmentType.CENTER, spacing: { before: 600, after: 400 } }),
// טבלת חתימות
new Table({
visuallyRightToLeft: true, // ✅ קריטי!
width: { size: 9072, type: WidthType.DXA },
columnWidths: [4536, 4536],
rows: [
new TableRow({
children: [
new TableCell({
borders: {
top: { style: BorderStyle.NONE },
bottom: { style: BorderStyle.NONE },
left: { style: BorderStyle.NONE },
right: { style: BorderStyle.NONE }
},
children: [
rtlPara(rtlRun("________________________"), { alignment: AlignmentType.CENTER }),
rtlPara(rtlRun("המזמין"), { alignment: AlignmentType.CENTER })
]
}),
new TableCell({
borders: {
top: { style: BorderStyle.NONE },
bottom: { style: BorderStyle.NONE },
left: { style: BorderStyle.NONE },
right: { style: BorderStyle.NONE }
},
children: [
rtlPara(rtlRun("________________________"), { alignment: AlignmentType.CENTER }),
rtlPara(rtlRun("הספק"), { alignment: AlignmentType.CENTER })
]
})
]
})
]
})
];
// ═══════════════════════════════════════════════
// DOCUMENT GENERATION — לא לשנות (אלא אם יודע מה עושים)
// ═══════════════════════════════════════════════
const doc = new Document({
// רמה 1: Document defaults
styles: {
default: {
document: {
run: { font: FONT, size: FONT_SIZE, rightToLeft: true },
paragraph: { bidirectional: true, alignment: AlignmentType.BOTH }
}
},
paragraphStyles: [
{
id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal",
quickFormat: true,
run: { size: HEADING1_SIZE, bold: true, font: FONT, rightToLeft: true },
paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0,
bidirectional: true, alignment: AlignmentType.CENTER }
},
{
id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal",
quickFormat: true,
run: { size: HEADING2_SIZE, bold: true, font: FONT, rightToLeft: true },
paragraph: { spacing: { before: 200, after: 200 }, outlineLevel: 1,
bidirectional: true, alignment: AlignmentType.START } // ✅ START
},
]
},
// מספור סעיפים
numbering: {
config: [{
reference: "legal-clauses",
levels: [
{
level: 0,
format: LevelFormat.DECIMAL,
text: "%1.",
alignment: AlignmentType.START, // ✅ START — לא RIGHT!
suffix: "tab",
style: { paragraph: { indent: { left: 720, hanging: 360 } } }
},
{
level: 1,
format: LevelFormat.DECIMAL,
text: "%1.%2",
alignment: AlignmentType.START, // ✅ START — לא RIGHT!
suffix: "tab",
style: { paragraph: { indent: { left: 1440, hanging: 500 } } }
},
]
}]
},
sections: [{
// רמה 2: Section properties
properties: {
page: {
size: { width: 11906, height: 16838 }, // A4
margin: { top: MARGIN_DXA, right: MARGIN_DXA, bottom: MARGIN_DXA, left: MARGIN_DXA }
},
bidi: true, // ← חובה!
},
headers: HEADER_TEXT ? {
default: new Header({
children: [rtlPara(rtlRun(HEADER_TEXT, { bold: true, size: 20 }),
{ alignment: AlignmentType.CENTER })]
})
} : undefined,
footers: {
default: new Footer({
children: [new Paragraph({
bidirectional: true,
alignment: AlignmentType.CENTER,
children: [
rtlRun("עמוד ", { size: 18 }),
new TextRun({ children: [PageNumber.CURRENT], font: FONT, size: 18 }),
...(FOOTER_CONFIDENTIAL ? [rtlRun(` | ${FOOTER_CONFIDENTIAL}`, { size: 18 })] : []),
]
})]
})
},
children: CONTENT
}]
});
Packer.toBuffer(doc).then(buffer => {
fs.writeFileSync(OUTPUT_FILE, buffer);
console.log(`${OUTPUT_FILE} created successfully`);
console.log(` Font: ${FONT} ${FONT_SIZE/2}pt`);
console.log(` Margins: ${MARGIN_CM}cm (${MARGIN_DXA} DXA)`);
console.log(` Size: ${(buffer.length / 1024).toFixed(1)} KB`);
console.log(` RTL: bidi + bidirectional + rightToLeft ✓`);
console.log(` Alignment: START/END (not LEFT/RIGHT) ✓`);
});