@zoulabo/line-hive 0.1.21 → 0.1.23

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.
Files changed (45) hide show
  1. package/README.md +51 -7
  2. package/dist/cli/config-writer.js +1 -1
  3. package/dist/cli/config-writer.js.map +1 -1
  4. package/dist/config.js +4 -1
  5. package/dist/config.js.map +1 -1
  6. package/dist/constants.js +2 -0
  7. package/dist/constants.js.map +1 -1
  8. package/dist/i18n.js +3 -1
  9. package/dist/i18n.js.map +1 -1
  10. package/dist/index.js +29 -3
  11. package/dist/index.js.map +1 -1
  12. package/dist/line/messages.js +141 -2
  13. package/dist/line/messages.js.map +1 -1
  14. package/dist/line/webhook.js +163 -28
  15. package/dist/line/webhook.js.map +1 -1
  16. package/dist/server.js +40 -15
  17. package/dist/server.js.map +1 -1
  18. package/dist/store/messageStore.js +16 -36
  19. package/dist/store/messageStore.js.map +1 -1
  20. package/dist/tools/ask.js +85 -55
  21. package/dist/tools/ask.js.map +1 -1
  22. package/dist/tools/createDocx.js +459 -0
  23. package/dist/tools/createDocx.js.map +1 -0
  24. package/dist/tools/createPptx.js +554 -0
  25. package/dist/tools/createPptx.js.map +1 -0
  26. package/dist/tools/createXlsx.js +360 -0
  27. package/dist/tools/createXlsx.js.map +1 -0
  28. package/dist/tools/gitReview-template.js +208 -0
  29. package/dist/tools/gitReview-template.js.map +1 -0
  30. package/dist/tools/gitReview.js +232 -0
  31. package/dist/tools/gitReview.js.map +1 -0
  32. package/dist/tools/readFile.js +6 -25
  33. package/dist/tools/readFile.js.map +1 -1
  34. package/dist/tools/renderMarkdown.js +159 -31
  35. package/dist/tools/renderMarkdown.js.map +1 -1
  36. package/dist/tools/sendMessage.js +9 -3
  37. package/dist/tools/sendMessage.js.map +1 -1
  38. package/dist/tools/setStatus.js +4 -2
  39. package/dist/tools/setStatus.js.map +1 -1
  40. package/dist/tunnel.js +1 -17
  41. package/dist/tunnel.js.map +1 -1
  42. package/dist/util/toolHelpers.js +232 -38
  43. package/dist/util/toolHelpers.js.map +1 -1
  44. package/package.json +7 -1
  45. package/templates/line-notification.instructions.md +114 -14
@@ -0,0 +1,360 @@
1
+ /**
2
+ * line_create_xlsx — Generate Excel workbooks from CSV data + JSON formatting.
3
+ *
4
+ * Uses exceljs (optional dependency). CSV for bulk data, JSON for formatting params.
5
+ * Supports multi-sheet, multi-table per sheet, column styles, formulas, merges.
6
+ */
7
+ import { toolResult, toolError, sanitizeFilename, sanitizeSheetName, writeAndTrackFile, parseCsv, autoCastCsvValue, clampTtlMs, } from "../util/toolHelpers.js";
8
+ import { sendWithTokenPool } from "../util/sendWithTokenPool.js";
9
+ import { resolveLocale } from "../i18n.js";
10
+ // ─── Constants ──────────────────────────────────────────────────────────────
11
+ const MAX_ROWS_WARNING = 50000;
12
+ const MAX_ROWS_REJECT = 100000;
13
+ const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
14
+ // ─── Style Presets ──────────────────────────────────────────────────────────
15
+ function getColumnNumFmt(style, locale) {
16
+ if (!style)
17
+ return undefined;
18
+ const map = {
19
+ currency: locale === "ja" ? "¥#,##0" : "$#,##0.00",
20
+ percent: "0.0%",
21
+ date: "YYYY-MM-DD",
22
+ datetime: "YYYY-MM-DD HH:mm",
23
+ number: "#,##0",
24
+ decimal: "#,##0.00",
25
+ text: "@",
26
+ };
27
+ return map[style];
28
+ }
29
+ function getHeaderPreset(style) {
30
+ const presets = {
31
+ dark: {
32
+ fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FF333333" } },
33
+ font: { bold: true, color: { argb: "FFFFFFFF" } },
34
+ border: { bottom: { style: "thin", color: { argb: "FF333333" } } },
35
+ },
36
+ light: {
37
+ fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FFF0F0F0" } },
38
+ font: { bold: true },
39
+ border: { bottom: { style: "thin", color: { argb: "FFDDDDDD" } } },
40
+ },
41
+ accent: {
42
+ fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FF06C755" } },
43
+ font: { bold: true, color: { argb: "FFFFFFFF" } },
44
+ border: { bottom: { style: "thin", color: { argb: "FF06C755" } } },
45
+ },
46
+ none: {
47
+ fill: { type: "pattern", pattern: "solid", fgColor: { argb: "00000000" } },
48
+ font: { bold: true },
49
+ },
50
+ };
51
+ return style ? presets[style] || null : null;
52
+ }
53
+ // ─── Cell Address Helpers ───────────────────────────────────────────────────
54
+ /**
55
+ * Parse Excel A1 notation to { col, row } (1-indexed).
56
+ * e.g. "A1" → { col: 1, row: 1 }, "E10" → { col: 5, row: 10 }
57
+ */
58
+ function parseA1(ref) {
59
+ const match = ref.match(/^([A-Z]+)(\d+)$/i);
60
+ if (!match)
61
+ return null;
62
+ const letters = match[1].toUpperCase();
63
+ let col = 0;
64
+ for (let i = 0; i < letters.length; i++) {
65
+ col = col * 26 + (letters.charCodeAt(i) - 64);
66
+ }
67
+ return { col, row: parseInt(match[2], 10) };
68
+ }
69
+ // ─── Stripe Row Color ───────────────────────────────────────────────────────
70
+ const STRIPE_FILL = {
71
+ type: "pattern",
72
+ pattern: "solid",
73
+ fgColor: { argb: "FFFAFAFA" },
74
+ };
75
+ // ─── Handler ────────────────────────────────────────────────────────────────
76
+ export async function handleCreateXlsx({ config, messageStore, statusStore, lineClient, logger, args }) {
77
+ // Check for exceljs
78
+ let ExcelJS = null;
79
+ try {
80
+ const mod = await import("exceljs");
81
+ // ESM dynamic import wraps CJS modules in { default: ... }
82
+ ExcelJS = mod.default ?? mod;
83
+ }
84
+ catch {
85
+ return toolError("exceljs_not_installed", {
86
+ hint: "Run: npm install exceljs",
87
+ });
88
+ }
89
+ // Parse args
90
+ const rawTitle = args.title || "";
91
+ const fileName = sanitizeFilename(rawTitle, ".xlsx");
92
+ const send = args.send !== false;
93
+ const agentName = args.agentName || undefined;
94
+ const text = args.text || undefined;
95
+ const ttlMs = clampTtlMs(args.ttl);
96
+ if (send && !agentName) {
97
+ return toolError("missing_agent_name", {
98
+ message: "agentName is required when send is true (default).",
99
+ });
100
+ }
101
+ // Resolve locale for currency format
102
+ const userLang = messageStore.getConfig?.("user_language") || null;
103
+ const locale = resolveLocale(userLang);
104
+ // Normalize input into sheets array
105
+ let sheets;
106
+ if (args.sheets && Array.isArray(args.sheets)) {
107
+ sheets = args.sheets;
108
+ }
109
+ else if (args.csv && typeof args.csv === "string") {
110
+ // Single-sheet shorthand
111
+ sheets = [{
112
+ name: args.sheetName || undefined,
113
+ csv: args.csv,
114
+ columns: args.columns,
115
+ options: args.options,
116
+ formulas: args.formulas,
117
+ merges: args.merges,
118
+ }];
119
+ }
120
+ else {
121
+ return toolError("missing_data", {
122
+ message: "Provide either 'csv' (single sheet) or 'sheets' (multi-sheet).",
123
+ });
124
+ }
125
+ if (sheets.length === 0) {
126
+ return toolError("empty_sheets", { message: "At least one sheet is required." });
127
+ }
128
+ // Create workbook
129
+ const workbook = new ExcelJS.Workbook();
130
+ const sheetNames = new Set();
131
+ let totalRows = 0;
132
+ let rowLimitWarning = null;
133
+ for (const sheetDef of sheets) {
134
+ const sheetName = sanitizeSheetName(sheetDef.name || "Sheet1", sheetNames);
135
+ const worksheet = workbook.addWorksheet(sheetName);
136
+ // Determine tables to render
137
+ let tables;
138
+ if (sheetDef.tables && Array.isArray(sheetDef.tables)) {
139
+ tables = sheetDef.tables;
140
+ }
141
+ else if (sheetDef.csv) {
142
+ tables = [{
143
+ csv: sheetDef.csv,
144
+ columns: sheetDef.columns,
145
+ headerStyle: sheetDef.options?.headerStyle,
146
+ }];
147
+ }
148
+ else {
149
+ continue; // Empty sheet
150
+ }
151
+ const tableGap = typeof sheetDef.tableGap === "number" ? sheetDef.tableGap : 2;
152
+ let nextRow = 1; // Track auto-placement cursor
153
+ let firstHeaderRow = 1; // Track first header position for freeze/filter
154
+ for (const tableDef of tables) {
155
+ if (!tableDef.csv)
156
+ continue;
157
+ const rows = parseCsv(tableDef.csv);
158
+ if (rows.length === 0)
159
+ continue;
160
+ const [headerCells, ...dataRows] = rows;
161
+ const nonEmptyData = dataRows.filter(r => r.some(c => c.trim() !== ""));
162
+ // Row limit check
163
+ if (nonEmptyData.length > MAX_ROWS_REJECT) {
164
+ return toolError("too_many_rows", {
165
+ message: `Sheet '${sheetName}' has ${nonEmptyData.length} rows (limit: ${MAX_ROWS_REJECT}).`,
166
+ });
167
+ }
168
+ if (nonEmptyData.length > MAX_ROWS_WARNING) {
169
+ rowLimitWarning = `Sheet '${sheetName}' has ${nonEmptyData.length} rows (limit: ${MAX_ROWS_WARNING})`;
170
+ }
171
+ totalRows += nonEmptyData.length;
172
+ // Determine start position
173
+ let startCol = 1;
174
+ let startRow = nextRow;
175
+ if (tableDef.startCell) {
176
+ const pos = parseA1(tableDef.startCell);
177
+ if (pos) {
178
+ startCol = pos.col;
179
+ startRow = pos.row;
180
+ }
181
+ }
182
+ // Write table title (merged bold row)
183
+ if (tableDef.title) {
184
+ const titleCell = worksheet.getCell(startRow, startCol);
185
+ titleCell.value = tableDef.title;
186
+ titleCell.font = { bold: true, size: 12 };
187
+ if (headerCells.length > 1) {
188
+ const endColLetter = columnLetter(startCol + headerCells.length - 1);
189
+ const startColLetter = columnLetter(startCol);
190
+ worksheet.mergeCells(`${startColLetter}${startRow}:${endColLetter}${startRow}`);
191
+ }
192
+ startRow++;
193
+ }
194
+ // Apply column widths
195
+ const colDefs = tableDef.columns || sheetDef.columns || [];
196
+ for (let ci = 0; ci < headerCells.length; ci++) {
197
+ const col = worksheet.getColumn(startCol + ci);
198
+ const def = colDefs[ci];
199
+ if (def?.width)
200
+ col.width = def.width;
201
+ const numFmt = getColumnNumFmt(def?.style, locale);
202
+ if (numFmt)
203
+ col.numFmt = numFmt;
204
+ }
205
+ // Write header row
206
+ const headerRowNum = startRow;
207
+ if (firstHeaderRow === 1)
208
+ firstHeaderRow = headerRowNum; // Track for freeze/filter
209
+ const headerPreset = getHeaderPreset(tableDef.headerStyle || sheetDef.options?.headerStyle);
210
+ for (let ci = 0; ci < headerCells.length; ci++) {
211
+ const cell = worksheet.getCell(headerRowNum, startCol + ci);
212
+ cell.value = headerCells[ci];
213
+ if (headerPreset) {
214
+ cell.fill = headerPreset.fill;
215
+ cell.font = headerPreset.font;
216
+ if (headerPreset.border) {
217
+ cell.border = { bottom: headerPreset.border.bottom };
218
+ }
219
+ }
220
+ else {
221
+ cell.font = { bold: true };
222
+ }
223
+ }
224
+ // Write data rows
225
+ for (let ri = 0; ri < nonEmptyData.length; ri++) {
226
+ const dataRow = nonEmptyData[ri];
227
+ const rowNum = headerRowNum + 1 + ri;
228
+ for (let ci = 0; ci < headerCells.length; ci++) {
229
+ const rawVal = ci < dataRow.length ? dataRow[ci] : "";
230
+ const cell = worksheet.getCell(rowNum, startCol + ci);
231
+ const val = autoCastCsvValue(rawVal);
232
+ if (typeof val === "string" && val.startsWith("=")) {
233
+ cell.value = { formula: val.slice(1) };
234
+ }
235
+ else {
236
+ cell.value = val;
237
+ }
238
+ }
239
+ // Stripe rows
240
+ if (sheetDef.options?.stripeRows && ri % 2 === 1) {
241
+ for (let ci = 0; ci < headerCells.length; ci++) {
242
+ worksheet.getCell(rowNum, startCol + ci).fill = STRIPE_FILL;
243
+ }
244
+ }
245
+ }
246
+ // Update auto-placement cursor
247
+ const endRow = headerRowNum + nonEmptyData.length;
248
+ if (!tableDef.startCell) {
249
+ nextRow = endRow + 1 + tableGap;
250
+ }
251
+ }
252
+ // Apply sheet-level options
253
+ if (sheetDef.options?.freezeHeader) {
254
+ worksheet.views = [{ state: "frozen", ySplit: firstHeaderRow, xSplit: 0 }];
255
+ }
256
+ if (sheetDef.options?.autoFilter && worksheet.rowCount > 0) {
257
+ const lastCol = worksheet.columnCount;
258
+ worksheet.autoFilter = {
259
+ from: { row: firstHeaderRow, column: 1 },
260
+ to: { row: worksheet.rowCount, column: lastCol },
261
+ };
262
+ }
263
+ // Apply formulas
264
+ if (sheetDef.formulas) {
265
+ for (const [cellRef, formula] of Object.entries(sheetDef.formulas)) {
266
+ const cell = worksheet.getCell(cellRef);
267
+ const formulaStr = formula.startsWith("=") ? formula.slice(1) : formula;
268
+ cell.value = { formula: formulaStr };
269
+ }
270
+ }
271
+ // Apply merges
272
+ if (sheetDef.merges) {
273
+ for (const range of sheetDef.merges) {
274
+ try {
275
+ worksheet.mergeCells(range);
276
+ }
277
+ catch {
278
+ // Invalid merge range — skip silently
279
+ }
280
+ }
281
+ }
282
+ }
283
+ // Generate buffer
284
+ const buffer = Buffer.from(await workbook.xlsx.writeBuffer());
285
+ if (buffer.length > MAX_FILE_SIZE) {
286
+ return toolError("file_too_large", {
287
+ message: `Generated file is ${(buffer.length / 1024 / 1024).toFixed(1)}MB (limit: 10MB).`,
288
+ });
289
+ }
290
+ // Write to disk and get URL
291
+ const writeResult = writeAndTrackFile(buffer, ".xlsx", config, messageStore, ttlMs, fileName);
292
+ if ("error" in writeResult) {
293
+ return toolError(writeResult.error);
294
+ }
295
+ // Auto-send if requested
296
+ let sent = false;
297
+ if (send && lineClient && agentName) {
298
+ const userId = messageStore.getDefaultUserId();
299
+ if (userId) {
300
+ try {
301
+ const messages = [];
302
+ if (text) {
303
+ messages.push({ type: "text", text });
304
+ }
305
+ messages.push({
306
+ type: "text",
307
+ text: `📎 ${fileName} (⏱ ${writeResult.expiresIn})\n${writeResult.url}`,
308
+ });
309
+ await sendWithTokenPool({
310
+ messageStore,
311
+ lineClient,
312
+ userId,
313
+ message: messages.length === 1 ? messages[0] : messages,
314
+ logger,
315
+ replyOnly: false,
316
+ });
317
+ sent = true;
318
+ }
319
+ catch (err) {
320
+ // Send failed but file is still generated — return URL
321
+ const errMsg = err instanceof Error ? err.message : String(err);
322
+ return toolResult({
323
+ success: true,
324
+ url: writeResult.url,
325
+ filePath: writeResult.filePath,
326
+ fileName: writeResult.fileName,
327
+ expiresIn: writeResult.expiresIn,
328
+ sheets: sheets.length,
329
+ totalRows,
330
+ sent: false,
331
+ sendError: errMsg,
332
+ rowLimitWarning,
333
+ });
334
+ }
335
+ }
336
+ }
337
+ return toolResult({
338
+ success: true,
339
+ url: writeResult.url,
340
+ filePath: writeResult.filePath,
341
+ fileName: writeResult.fileName,
342
+ expiresIn: writeResult.expiresIn,
343
+ sheets: sheets.length,
344
+ totalRows,
345
+ sent,
346
+ rowLimitWarning,
347
+ });
348
+ }
349
+ // ─── Utility ────────────────────────────────────────────────────────────────
350
+ /** Convert 1-indexed column number to Excel letter (1→A, 26→Z, 27→AA) */
351
+ function columnLetter(col) {
352
+ let s = "";
353
+ while (col > 0) {
354
+ const r = (col - 1) % 26;
355
+ s = String.fromCharCode(65 + r) + s;
356
+ col = Math.floor((col - 1) / 26);
357
+ }
358
+ return s;
359
+ }
360
+ //# sourceMappingURL=createXlsx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createXlsx.js","sourceRoot":"","sources":["../../src/tools/createXlsx.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,208 @@
1
+ /**
2
+ * gitReview-template — HTML template and CSS for git review reports.
3
+ *
4
+ * Extracted from the main gitReview handler to keep files under 600 lines.
5
+ * Contains minified CSS class names for compact output.
6
+ */
7
+ /** Escape HTML special characters */
8
+ export function escapeHtml(text) {
9
+ return text
10
+ .replace(/&/g, "&amp;")
11
+ .replace(/</g, "&lt;")
12
+ .replace(/>/g, "&gt;")
13
+ .replace(/"/g, "&quot;");
14
+ }
15
+ /** Minified CSS for git review HTML */
16
+ export const GIT_REVIEW_CSS = `*{box-sizing:border-box;margin:0;padding:0}
17
+ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;background:#f8f9fa;color:#1a1a1a;line-height:1.5;padding:12px;max-width:600px;margin:0 auto}
18
+ .su{background:linear-gradient(135deg,#1a1a2e,#16213e);color:#fff;padding:16px;border-radius:12px;margin-bottom:16px}
19
+ .su h1{font-size:18px;margin-bottom:4px}.su .me{font-size:13px;color:#b0bec5}
20
+ .su .ss{display:flex;gap:12px;margin-top:8px;font-size:14px;flex-wrap:wrap}
21
+ .su .ad{color:#69f0ae}.su .dl{color:#ff8a80}
22
+ .dc-box{background:#fff;border-radius:10px;margin-bottom:12px;padding:16px;border:1px solid #e65100}
23
+ .dc-box h2{font-size:15px;margin-bottom:12px;color:#e65100}
24
+ .fi{padding:10px 12px;border-radius:8px;margin-bottom:8px;font-size:13px}.fi:last-child{margin-bottom:0}
25
+ .fw{background:#fff3e0;border-left:3px solid #e65100}.fn{background:#e3f2fd;border-left:3px solid #1565c0}
26
+ .fl{font-weight:600;margin-bottom:2px}
27
+ .cm-box{background:#fff;border-radius:10px;margin-bottom:12px;padding:16px;border:1px solid #e0e0e0}
28
+ .cm-box h2{font-size:15px;margin-bottom:12px}
29
+ .cc{background:#f8f9fa;border-radius:8px;padding:12px;margin-bottom:8px;border-left:3px solid #4caf50}.cc:last-child{margin-bottom:0}
30
+ .cm{font-family:'SF Mono',Menlo,monospace;font-size:13px;font-weight:600;color:#1565c0}
31
+ .cf{font-size:12px;color:#666;margin-top:4px}.cr{font-size:12px;color:#888;margin-top:4px;font-style:italic}
32
+ .gr{background:#fff;border-radius:10px;margin-bottom:12px;overflow:hidden;border:1px solid #e0e0e0}
33
+ .gh{padding:14px 16px;cursor:pointer;display:flex;align-items:center;gap:8px}
34
+ .gh h2{font-size:15px;flex:1}
35
+ .bd{font-size:11px;padding:2px 8px;border-radius:10px;font-weight:600}
36
+ .bf{background:#e3f2fd;color:#1565c0}.bo{background:#f3e5f5;color:#7b1fa2}
37
+ .bx{background:#fff3e0;color:#e65100}.bn{background:#e8f5e9;color:#2e7d32}
38
+ .gb{padding:0 16px 14px;border-top:1px solid #f0f0f0;display:none}
39
+ .gd{font-size:13px;color:#666;margin:10px 0;padding:8px 12px;background:#f8f9fa;border-radius:6px;border-left:3px solid #90caf9}
40
+ .ul{list-style:none}
41
+ .ul li{font-size:13px;font-family:'SF Mono',Menlo,monospace;padding:3px 0;display:flex;align-items:center;gap:6px;flex-wrap:wrap}
42
+ .st{font-size:11px;font-weight:700;width:24px;text-align:center;border-radius:4px;padding:1px 4px}
43
+ .sm{background:#fff3e0;color:#e65100}.sa{background:#e8f5e9;color:#2e7d32}.sd{background:#ffebe9;color:#cf222e}
44
+ .ch{color:#888;font-size:11px;margin-left:auto}
45
+ .df{background:#fff;border-radius:10px;margin-bottom:8px;border:1px solid #e0e0e0;overflow:hidden}
46
+ .dh{padding:10px 14px;cursor:pointer;font-size:13px;font-family:'SF Mono',Menlo,monospace;display:flex;align-items:center;gap:6px;background:#fafafa}
47
+ .dh .ar{transition:transform .2s}.dh.open .ar{transform:rotate(90deg)}
48
+ .db{display:none;overflow-x:auto}.dh.open+.db{display:block}
49
+ .db pre{font-size:11px;line-height:1.5;padding:10px;margin:0;white-space:pre-wrap;word-break:break-all}
50
+ .da{background:#e6ffec;color:#1a7f37}.dd{background:#ffebe9;color:#cf222e}
51
+ .dk{color:#8250df;font-weight:600}.dc{color:#57606a}.ds{color:#888;margin-left:auto;font-size:12px}
52
+ .ac{background:linear-gradient(135deg,#1b5e20,#2e7d32);color:#fff;padding:16px;border-radius:12px;margin-bottom:16px}
53
+ .ac h2{font-size:15px;margin-bottom:8px}.ac p{font-size:13px;line-height:1.6}
54
+ .ac code{background:rgba(255,255,255,.15);padding:2px 6px;border-radius:4px;font-size:12px}
55
+ .ac .de{background:rgba(255,255,255,.1);padding:10px;border-radius:8px;margin-top:10px;font-size:13px}
56
+ .se{background:#fff;border-radius:10px;margin-bottom:12px;padding:16px;border:1px solid #e0e0e0}
57
+ .se h2{font-size:15px;margin-bottom:12px}
58
+ .ft{text-align:center;font-size:11px;color:#aaa;padding:16px 0}`;
59
+ /** Build summary section HTML */
60
+ export function buildSummaryHtml(summary) {
61
+ let html = `<div class="su"><h1>📋 Git Review</h1>
62
+ <div class="me">${escapeHtml(summary.branch)} · <code style="background:rgba(255,255,255,.1);padding:2px 6px;border-radius:4px;font-size:12px">${escapeHtml(summary.commit)}</code></div>
63
+ <div class="ss"><span>${summary.total} files</span><span class="ad">+${summary.additions}</span><span class="dl">−${summary.deletions}</span>`;
64
+ if (summary.staged > 0)
65
+ html += `<span style="color:#b0bec5">· ${summary.staged} staged</span>`;
66
+ if (summary.untracked > 0)
67
+ html += `<span style="color:#b0bec5">· ${summary.untracked} untracked</span>`;
68
+ html += "</div></div>";
69
+ return html;
70
+ }
71
+ /** Build file list HTML */
72
+ export function buildFileListHtml(files) {
73
+ const items = files.map(f => {
74
+ let badge, label;
75
+ switch (f.status) {
76
+ case "staged":
77
+ badge = "sm";
78
+ label = "M";
79
+ break;
80
+ case "added":
81
+ badge = "sa";
82
+ label = "A";
83
+ break;
84
+ case "deleted":
85
+ badge = "sd";
86
+ label = "D";
87
+ break;
88
+ case "untracked":
89
+ badge = "sa";
90
+ label = "?";
91
+ break;
92
+ default:
93
+ badge = "sm";
94
+ label = "M";
95
+ break;
96
+ }
97
+ let li = ` <li><span class="st ${badge}">${label}</span> ${escapeHtml(f.path)}`;
98
+ if (f.status !== "untracked" && (f.additions > 0 || f.deletions > 0)) {
99
+ li += ` <span class="ch">+${f.additions} −${f.deletions}</span>`;
100
+ }
101
+ li += "</li>";
102
+ return li;
103
+ }).join("\n");
104
+ return `<div class="se"><h2>📄 All Files</h2><ul class="ul">\n${items}\n</ul></div>`;
105
+ }
106
+ /** Syntax-color a single diff line */
107
+ function colorDiffLine(line) {
108
+ const esc = escapeHtml(line);
109
+ if (line.startsWith("+"))
110
+ return `<span class="da">${esc}</span>`;
111
+ if (line.startsWith("-"))
112
+ return `<span class="dd">${esc}</span>`;
113
+ if (line.startsWith("@@"))
114
+ return `<span class="dk">${esc}</span>`;
115
+ return `<span class="dc">${esc}</span>`;
116
+ }
117
+ /** Maximum diff lines before truncation */
118
+ const MAX_DIFF_LINES = 300;
119
+ const SHOW_DIFF_LINES = 200;
120
+ /** Build a single file diff accordion */
121
+ export function buildDiffHtml(filePath, diffText, prefix) {
122
+ const lines = diffText.split("\n");
123
+ // Skip the first 4 header lines (diff --git, index, ---, +++)
124
+ const body = lines.slice(4);
125
+ const totalLines = body.length;
126
+ const truncate = totalLines > MAX_DIFF_LINES;
127
+ const displayLines = truncate ? body.slice(0, SHOW_DIFF_LINES) : body;
128
+ const adds = body.filter(l => l.startsWith("+")).length;
129
+ const dels = body.filter(l => l.startsWith("-")).length;
130
+ const stats = `+${adds} −${dels}`;
131
+ let content = displayLines.map(colorDiffLine).join("\n");
132
+ if (truncate) {
133
+ content += `\n<span class="dk">… truncated (${totalLines} lines, showing ${SHOW_DIFF_LINES}) …</span>`;
134
+ }
135
+ const label = prefix ? `${prefix}${escapeHtml(filePath)}` : escapeHtml(filePath);
136
+ return `<div class="df">
137
+ <div class="dh" onclick="this.classList.toggle('open')">
138
+ <span class="ar">▶</span> ${label} <span class="ds">${stats}</span>
139
+ </div>
140
+ <div class="db"><pre>\n${content}\n</pre></div>
141
+ </div>`;
142
+ }
143
+ /** Build action footer HTML */
144
+ export function buildActionFooter() {
145
+ return `<div class="ac"><h2>💬 Reply to proceed</h2>
146
+ <div class="de"><strong>Default:</strong> Execute all A commits → push</div>
147
+ <p style="margin-top:10px"><code>ok, D1 ignore, D2 skip</code><br>
148
+ <code>merge A1+A3, skip A2</code><br><code>msg A1: new msg</code><br><code>cancel</code></p></div>`;
149
+ }
150
+ /** Build the complete HTML page with slots */
151
+ export function buildReviewPage(summary, files, diffs, slots) {
152
+ const parts = [];
153
+ // Head
154
+ parts.push(`<!DOCTYPE html><html lang="en"><head>
155
+ <meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
156
+ <title>Git Review</title>
157
+ <style>\n${GIT_REVIEW_CSS}\n</style>
158
+ </head><body>`);
159
+ // Summary
160
+ parts.push(buildSummaryHtml(summary));
161
+ // Slots (D, A, Groups)
162
+ parts.push(slots.decisions || "<!-- SLOT:DECISIONS -->");
163
+ parts.push(slots.commits || "<!-- SLOT:COMMITS -->");
164
+ parts.push(slots.groups || "<!-- SLOT:GROUPS -->");
165
+ // Files
166
+ parts.push(buildFileListHtml(files));
167
+ // Diffs
168
+ const unstaged = diffs.filter(d => !d.staged);
169
+ const staged = diffs.filter(d => d.staged);
170
+ if (unstaged.length > 0) {
171
+ parts.push('<div style="font-size:14px;font-weight:600;margin-bottom:8px;color:#666">📎 Diffs</div>');
172
+ for (const d of unstaged)
173
+ parts.push(buildDiffHtml(d.path, d.diff));
174
+ }
175
+ if (staged.length > 0) {
176
+ parts.push('<div style="font-size:14px;font-weight:600;margin:16px 0 8px;color:#666">📎 Staged</div>');
177
+ for (const d of staged)
178
+ parts.push(buildDiffHtml(d.path, d.diff, "[staged] "));
179
+ }
180
+ // Action footer
181
+ parts.push(buildActionFooter());
182
+ // Embedded JSON
183
+ const jsonData = {
184
+ branch: summary.branch,
185
+ commit: summary.commit,
186
+ totals: {
187
+ mod: summary.modified,
188
+ staged: summary.staged,
189
+ untracked: summary.untracked,
190
+ add: summary.additions,
191
+ del: summary.deletions,
192
+ },
193
+ files: files.map(f => ({
194
+ p: f.path,
195
+ s: f.status,
196
+ d: f.dir,
197
+ "+": f.additions,
198
+ "-": f.deletions,
199
+ })),
200
+ };
201
+ parts.push(`<script id="git-data" type="application/json">\n${JSON.stringify(jsonData, null, 2)}\n</script>`);
202
+ // Footer
203
+ const now = new Date();
204
+ const ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")} ${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}`;
205
+ parts.push(`<div class="ft">${ts}</div></body></html>`);
206
+ return parts.join("\n");
207
+ }
208
+ //# sourceMappingURL=gitReview-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitReview-template.js","sourceRoot":"","sources":["../../src/tools/gitReview-template.ts"],"names":[],"mappings":"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"}