neuronix-node 0.2.0 → 0.6.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,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handlePayroll = handlePayroll;
4
+ async function handlePayroll(task) {
5
+ const start = Date.now();
6
+ const input = task.input_payload;
7
+ const period = input.pay_period || "Bi-Weekly";
8
+ const fedRate = input.federal_tax_rate || 0.22;
9
+ const stateRate = input.state_tax_rate || 0.05;
10
+ const ficaRate = input.fica_rate || 0.062;
11
+ const medicareRate = input.medicare_rate || 0.0145;
12
+ const periodsPerYear = period === "Weekly" ? 52 : period === "Bi-Weekly" ? 26 : period === "Semi-Monthly" ? 24 : 12;
13
+ const employees = input.employees || [
14
+ { name: "John Smith", type: "salary", rate: 85000, deductions: [{ name: "Health Insurance", amount: 250 }, { name: "401k (6%)", amount: 196.15 }] },
15
+ { name: "Jane Doe", type: "salary", rate: 72000, deductions: [{ name: "Health Insurance", amount: 250 }, { name: "401k (4%)", amount: 110.77 }] },
16
+ { name: "Bob Wilson", type: "hourly", rate: 28.50, hours: 80, deductions: [{ name: "Health Insurance", amount: 180 }] },
17
+ { name: "Alice Chen", type: "salary", rate: 95000, deductions: [{ name: "Health Insurance", amount: 250 }, { name: "401k (8%)", amount: 292.31 }, { name: "HSA", amount: 100 }] },
18
+ { name: "Mike Torres", type: "hourly", rate: 22.00, hours: 84, deductions: [{ name: "Health Insurance", amount: 180 }] },
19
+ ];
20
+ let totalGross = 0, totalFed = 0, totalState = 0, totalFica = 0, totalMedicare = 0, totalDeductions = 0, totalNet = 0, totalEmployerFica = 0, totalEmployerMedicare = 0;
21
+ const payStubs = employees.map(emp => {
22
+ const gross = emp.type === "salary" ? round(emp.rate / periodsPerYear) : round((emp.rate) * (emp.hours || 80));
23
+ const overtimeHours = emp.type === "hourly" && (emp.hours || 0) > 80 ? (emp.hours || 0) - 80 : 0;
24
+ const overtimePay = emp.type === "hourly" ? round(overtimeHours * emp.rate * 0.5) : 0;
25
+ const totalGrossPay = round(gross + overtimePay);
26
+ const fedTax = round(totalGrossPay * fedRate);
27
+ const stateTax = round(totalGrossPay * stateRate);
28
+ const ficaTax = round(totalGrossPay * ficaRate);
29
+ const medicareTax = round(totalGrossPay * medicareRate);
30
+ const totalTax = round(fedTax + stateTax + ficaTax + medicareTax);
31
+ const deductionTotal = round((emp.deductions || []).reduce((s, d) => s + d.amount, 0));
32
+ const netPay = round(totalGrossPay - totalTax - deductionTotal);
33
+ const employerFica = ficaTax;
34
+ const employerMedicare = medicareTax;
35
+ totalGross += totalGrossPay;
36
+ totalFed += fedTax;
37
+ totalState += stateTax;
38
+ totalFica += ficaTax;
39
+ totalMedicare += medicareTax;
40
+ totalDeductions += deductionTotal;
41
+ totalNet += netPay;
42
+ totalEmployerFica += employerFica;
43
+ totalEmployerMedicare += employerMedicare;
44
+ return {
45
+ name: emp.name, type: emp.type, hours: emp.hours, rate: emp.rate,
46
+ gross: totalGrossPay, overtime_pay: overtimePay,
47
+ federal_tax: fedTax, state_tax: stateTax, fica: ficaTax, medicare: medicareTax,
48
+ total_tax: totalTax, deductions: emp.deductions || [], deduction_total: deductionTotal,
49
+ net_pay: netPay, employer_fica: employerFica, employer_medicare: employerMedicare,
50
+ };
51
+ });
52
+ totalGross = round(totalGross);
53
+ totalNet = round(totalNet);
54
+ totalDeductions = round(totalDeductions);
55
+ const totalTaxes = round(totalFed + totalState + totalFica + totalMedicare);
56
+ const totalEmployerCost = round(totalGross + totalEmployerFica + totalEmployerMedicare);
57
+ const csv = [
58
+ "PAYROLL REGISTER",
59
+ `Pay Period: ${period}`,
60
+ `Date: ${new Date().toISOString().split("T")[0]}`,
61
+ `Employees: ${employees.length}`,
62
+ "",
63
+ "EMPLOYEE DETAIL",
64
+ "Name,Type,Rate,Hours,Gross Pay,Federal Tax,State Tax,FICA,Medicare,Deductions,Net Pay",
65
+ ...payStubs.map(p => `${esc(p.name)},${p.type},${p.type === "salary" ? fmt(p.rate) + "/yr" : fmt(p.rate) + "/hr"},${p.hours || "N/A"},${fmt(p.gross)},${fmt(p.federal_tax)},${fmt(p.state_tax)},${fmt(p.fica)},${fmt(p.medicare)},${fmt(p.deduction_total)},${fmt(p.net_pay)}`),
66
+ "",
67
+ `TOTALS,,,,${fmt(totalGross)},${fmt(totalFed)},${fmt(round(totalState))},${fmt(round(totalFica))},${fmt(round(totalMedicare))},${fmt(totalDeductions)},${fmt(totalNet)}`,
68
+ "",
69
+ "DEDUCTION DETAIL",
70
+ "Employee,Deduction,Amount",
71
+ ...payStubs.flatMap(p => p.deductions.map(d => `${esc(p.name)},${esc(d.name)},${fmt(d.amount)}`)),
72
+ "",
73
+ "TAX SUMMARY",
74
+ `Federal Income Tax,${fmt(round(totalFed))}`,
75
+ `State Income Tax,${fmt(round(totalState))}`,
76
+ `Employee FICA (Social Security),${fmt(round(totalFica))}`,
77
+ `Employee Medicare,${fmt(round(totalMedicare))}`,
78
+ `Total Employee Taxes,${fmt(totalTaxes)}`,
79
+ "",
80
+ "EMPLOYER OBLIGATIONS",
81
+ `Employer FICA Match,${fmt(round(totalEmployerFica))}`,
82
+ `Employer Medicare Match,${fmt(round(totalEmployerMedicare))}`,
83
+ `Total Employer Taxes,${fmt(round(totalEmployerFica + totalEmployerMedicare))}`,
84
+ "",
85
+ "GRAND TOTALS",
86
+ `Total Gross Pay,${fmt(totalGross)}`,
87
+ `Total Deductions,${fmt(totalDeductions)}`,
88
+ `Total Taxes (Employee),${fmt(totalTaxes)}`,
89
+ `Total Net Pay,${fmt(totalNet)}`,
90
+ `Total Employer Cost,${fmt(totalEmployerCost)}`,
91
+ ];
92
+ return {
93
+ text: `Payroll: ${employees.length} employees | Gross: ${fmt(totalGross)} | Net: ${fmt(totalNet)} | Employer Cost: ${fmt(totalEmployerCost)}`,
94
+ output_csv: csv.join("\n"),
95
+ summary: { employee_count: employees.length, total_gross: totalGross, total_net: totalNet, total_taxes: totalTaxes, total_deductions: totalDeductions, employer_cost: totalEmployerCost },
96
+ duration_ms: Date.now() - start,
97
+ };
98
+ }
99
+ function round(n) { return Math.round(n * 100) / 100; }
100
+ function fmt(n) { return "$" + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }
101
+ function esc(v) { return v.includes(",") ? `"${v}"` : v; }
@@ -0,0 +1,2 @@
1
+ import type { TaskInput, TaskOutput } from "./index.js";
2
+ export declare function handleSalesTax(task: TaskInput): Promise<TaskOutput>;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleSalesTax = handleSalesTax;
4
+ async function handleSalesTax(task) {
5
+ const start = Date.now();
6
+ const input = task.input_payload;
7
+ const period = input.period || "Current Period";
8
+ const transactions = input.transactions || [
9
+ { date: "2026-03-01", description: "Product Sale - Widget A", amount: 1200, tax_rate: 0.0725, state: "CA", taxable: true },
10
+ { date: "2026-03-03", description: "Consulting Service", amount: 5000, tax_rate: 0, state: "CA", taxable: false },
11
+ { date: "2026-03-05", description: "Product Sale - Widget B", amount: 850, tax_rate: 0.0725, state: "CA", taxable: true },
12
+ { date: "2026-03-08", description: "Product Sale - Online (TX)", amount: 2300, tax_rate: 0.0625, state: "TX", taxable: true },
13
+ { date: "2026-03-12", description: "SaaS Subscription", amount: 499, tax_rate: 0, taxable: false },
14
+ { date: "2026-03-15", description: "Product Sale - Widget C", amount: 3400, tax_rate: 0.0725, state: "CA", taxable: true },
15
+ { date: "2026-03-20", description: "Product Sale - Online (NY)", amount: 1800, tax_rate: 0.08, state: "NY", taxable: true },
16
+ ];
17
+ let totalSales = 0, totalTaxable = 0, totalExempt = 0, totalTaxCollected = 0;
18
+ const byState = {};
19
+ for (const txn of transactions) {
20
+ totalSales += txn.amount;
21
+ if (txn.taxable !== false && txn.tax_rate > 0) {
22
+ const tax = round(txn.amount * txn.tax_rate);
23
+ totalTaxable += txn.amount;
24
+ totalTaxCollected += tax;
25
+ const st = txn.state || "Unknown";
26
+ if (!byState[st])
27
+ byState[st] = { sales: 0, taxable: 0, tax: 0, rate: txn.tax_rate, count: 0 };
28
+ byState[st].sales += txn.amount;
29
+ byState[st].taxable += txn.amount;
30
+ byState[st].tax += tax;
31
+ byState[st].count += 1;
32
+ }
33
+ else {
34
+ totalExempt += txn.amount;
35
+ }
36
+ }
37
+ totalSales = round(totalSales);
38
+ totalTaxable = round(totalTaxable);
39
+ totalExempt = round(totalExempt);
40
+ totalTaxCollected = round(totalTaxCollected);
41
+ const stateSummary = Object.entries(byState).sort((a, b) => b[1].tax - a[1].tax).map(([st, d]) => ({
42
+ state: st, sales: round(d.sales), taxable: round(d.taxable), tax_collected: round(d.tax), rate: d.rate, transactions: d.count,
43
+ }));
44
+ const csv = [
45
+ "SALES TAX REPORT",
46
+ `Period: ${period}`,
47
+ `Generated: ${new Date().toISOString().split("T")[0]}`,
48
+ "",
49
+ "SUMMARY",
50
+ `Total Sales,${fmt(totalSales)}`,
51
+ `Taxable Sales,${fmt(totalTaxable)}`,
52
+ `Exempt Sales,${fmt(totalExempt)}`,
53
+ `Total Tax Collected,${fmt(totalTaxCollected)}`,
54
+ `Effective Tax Rate,${totalTaxable > 0 ? round((totalTaxCollected / totalTaxable) * 100) : 0}%`,
55
+ "",
56
+ "BY STATE/JURISDICTION",
57
+ "State,Taxable Sales,Tax Rate,Tax Collected,Transactions",
58
+ ...stateSummary.map(s => `${s.state},${fmt(s.taxable)},${(s.rate * 100).toFixed(2)}%,${fmt(s.tax_collected)},${s.transactions}`),
59
+ "",
60
+ "TRANSACTION DETAIL",
61
+ "Date,Description,Amount,Taxable,Tax Rate,Tax Amount,State",
62
+ ...transactions.map(t => {
63
+ const tax = (t.taxable !== false && t.tax_rate > 0) ? round(t.amount * t.tax_rate) : 0;
64
+ return `${t.date},${esc(t.description)},${fmt(t.amount)},${t.taxable !== false && t.tax_rate > 0 ? "Yes" : "No"},${(t.tax_rate * 100).toFixed(2)}%,${fmt(tax)},${t.state || ""}`;
65
+ }),
66
+ "",
67
+ "TAX LIABILITY",
68
+ `Total Tax Owed,${fmt(totalTaxCollected)}`,
69
+ `Filing Deadline,${getNextQuarterEnd()}`,
70
+ ];
71
+ return {
72
+ text: `Sales Tax: ${fmt(totalTaxCollected)} collected on ${fmt(totalTaxable)} taxable sales (${stateSummary.length} jurisdictions)`,
73
+ output_csv: csv.join("\n"),
74
+ summary: { total_sales: totalSales, total_taxable: totalTaxable, total_exempt: totalExempt, total_tax: totalTaxCollected, jurisdictions: stateSummary.length },
75
+ by_state: stateSummary,
76
+ duration_ms: Date.now() - start,
77
+ };
78
+ }
79
+ function getNextQuarterEnd() {
80
+ const now = new Date();
81
+ const m = now.getMonth();
82
+ const q = m < 3 ? 0 : m < 6 ? 1 : m < 9 ? 2 : 3;
83
+ const deadlines = ["04-30", "07-31", "10-31", "01-31"];
84
+ const year = q === 3 ? now.getFullYear() + 1 : now.getFullYear();
85
+ return `${year}-${deadlines[q]}`;
86
+ }
87
+ function round(n) { return Math.round(n * 100) / 100; }
88
+ function fmt(n) { return "$" + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }
89
+ function esc(v) { return v.includes(",") ? `"${v}"` : v; }
@@ -0,0 +1,2 @@
1
+ import type { TaskInput, TaskOutput } from "./index.js";
2
+ export declare function handleVarianceAnalysis(task: TaskInput): Promise<TaskOutput>;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleVarianceAnalysis = handleVarianceAnalysis;
4
+ async function handleVarianceAnalysis(task) {
5
+ const start = Date.now();
6
+ const input = task.input_payload;
7
+ const period = input.period || "Current Period";
8
+ const threshold = input.threshold_pct || 10;
9
+ const lines = input.lines || [
10
+ { item: "Product Revenue", budget: 120000, actual: 115000, category: "Revenue" },
11
+ { item: "Service Revenue", budget: 80000, actual: 92000, category: "Revenue" },
12
+ { item: "Cost of Goods Sold", budget: 48000, actual: 52000, category: "COGS" },
13
+ { item: "Salaries", budget: 70000, actual: 72800, category: "OpEx" },
14
+ { item: "Marketing", budget: 15000, actual: 22000, category: "OpEx" },
15
+ { item: "Rent", budget: 8500, actual: 8500, category: "OpEx" },
16
+ { item: "Technology", budget: 10000, actual: 14200, category: "OpEx" },
17
+ { item: "Travel", budget: 5000, actual: 8900, category: "OpEx" },
18
+ { item: "Office Supplies", budget: 2000, actual: 1650, category: "OpEx" },
19
+ { item: "Insurance", budget: 3200, actual: 3200, category: "OpEx" },
20
+ ];
21
+ const analyzed = lines.map(l => {
22
+ const variance = round(l.actual - l.budget);
23
+ const variancePct = l.budget !== 0 ? round((variance / Math.abs(l.budget)) * 100) : 0;
24
+ const favorable = l.category === "Revenue" ? variance >= 0 : variance <= 0;
25
+ const significant = Math.abs(variancePct) >= threshold;
26
+ return { ...l, variance, variance_pct: variancePct, favorable, significant };
27
+ });
28
+ const significant = analyzed.filter(l => l.significant);
29
+ const favorableItems = analyzed.filter(l => l.favorable && l.variance !== 0);
30
+ const unfavorableItems = analyzed.filter(l => !l.favorable && l.variance !== 0);
31
+ const totalBudget = round(lines.reduce((s, l) => s + l.budget, 0));
32
+ const totalActual = round(lines.reduce((s, l) => s + l.actual, 0));
33
+ const totalVariance = round(totalActual - totalBudget);
34
+ const csv = [
35
+ "VARIANCE ANALYSIS REPORT",
36
+ `Period: ${period}`,
37
+ `Generated: ${new Date().toISOString().split("T")[0]}`,
38
+ `Significance Threshold: ${threshold}%`,
39
+ "",
40
+ "DETAILED ANALYSIS",
41
+ "Item,Category,Budget,Actual,Variance ($),Variance (%),Favorable?,Significant?",
42
+ ...analyzed.map(l => `${esc(l.item)},${l.category || ""},${fmt(l.budget)},${fmt(l.actual)},${l.variance >= 0 ? "+" : ""}${fmt(l.variance)},${l.variance_pct >= 0 ? "+" : ""}${l.variance_pct}%,${l.favorable ? "Yes" : "No"},${l.significant ? "YES" : "No"}`),
43
+ "",
44
+ "SIGNIFICANT VARIANCES (>${threshold}%)",
45
+ "Item,Variance ($),Variance (%),Impact",
46
+ ...significant.sort((a, b) => Math.abs(b.variance_pct) - Math.abs(a.variance_pct)).map(l => `${esc(l.item)},${l.variance >= 0 ? "+" : ""}${fmt(l.variance)},${l.variance_pct >= 0 ? "+" : ""}${l.variance_pct}%,${l.favorable ? "Favorable" : "Unfavorable"}`),
47
+ "",
48
+ "FAVORABLE VARIANCES",
49
+ "Item,Amount Saved/Gained",
50
+ ...favorableItems.map(l => `${esc(l.item)},${fmt(Math.abs(l.variance))}`),
51
+ "",
52
+ "UNFAVORABLE VARIANCES",
53
+ "Item,Amount Over/Under",
54
+ ...unfavorableItems.map(l => `${esc(l.item)},${fmt(Math.abs(l.variance))}`),
55
+ "",
56
+ "SUMMARY",
57
+ `Total Budget,${fmt(totalBudget)}`,
58
+ `Total Actual,${fmt(totalActual)}`,
59
+ `Net Variance,${totalVariance >= 0 ? "+" : ""}${fmt(totalVariance)}`,
60
+ `Significant Variances,${significant.length} of ${analyzed.length} items`,
61
+ `Favorable Items,${favorableItems.length}`,
62
+ `Unfavorable Items,${unfavorableItems.length}`,
63
+ ];
64
+ return {
65
+ text: `Variance Analysis: ${significant.length} significant variances (>${threshold}%) | Net: ${totalVariance >= 0 ? "+" : ""}${fmt(totalVariance)}`,
66
+ output_csv: csv.join("\n"),
67
+ summary: { total_budget: totalBudget, total_actual: totalActual, total_variance: totalVariance, significant_count: significant.length, favorable_count: favorableItems.length, unfavorable_count: unfavorableItems.length },
68
+ duration_ms: Date.now() - start,
69
+ };
70
+ }
71
+ function round(n) { return Math.round(n * 100) / 100; }
72
+ function fmt(n) { return "$" + Math.abs(n).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }
73
+ function esc(v) { return v.includes(",") ? `"${v}"` : v; }
@@ -0,0 +1,2 @@
1
+ import type { TaskInput, TaskOutput } from "./index.js";
2
+ export declare function handleW21099(task: TaskInput): Promise<TaskOutput>;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleW21099 = handleW21099;
4
+ async function handleW21099(task) {
5
+ const start = Date.now();
6
+ const input = task.input_payload;
7
+ const taxYear = input.tax_year || "2025";
8
+ const company = input.company_name || "Company Name";
9
+ const employees = input.employees || [
10
+ { name: "John Smith", ssn_last4: "1234", wages: 85000, federal_tax_withheld: 14280, state_tax_withheld: 4250, social_security_wages: 85000, social_security_tax: 5270, medicare_wages: 85000, medicare_tax: 1232.50, state: "CA" },
11
+ { name: "Jane Doe", ssn_last4: "5678", wages: 72000, federal_tax_withheld: 11520, state_tax_withheld: 3600, social_security_wages: 72000, social_security_tax: 4464, medicare_wages: 72000, medicare_tax: 1044, state: "CA" },
12
+ { name: "Alice Chen", ssn_last4: "9012", wages: 95000, federal_tax_withheld: 17100, state_tax_withheld: 4750, social_security_wages: 95000, social_security_tax: 5890, medicare_wages: 95000, medicare_tax: 1377.50, state: "CA" },
13
+ ];
14
+ const contractors = input.contractors || [
15
+ { name: "Bob's Web Design", tin_last4: "4321", total_paid: 15000, type: "NEC" },
16
+ { name: "Marketing Maven LLC", tin_last4: "8765", total_paid: 28000, type: "NEC" },
17
+ { name: "Office Cleaning Pro", tin_last4: "2468", total_paid: 9600, type: "NEC" },
18
+ ];
19
+ const totalWages = round(employees.reduce((s, e) => s + e.wages, 0));
20
+ const totalFedWithheld = round(employees.reduce((s, e) => s + e.federal_tax_withheld, 0));
21
+ const totalStateWithheld = round(employees.reduce((s, e) => s + e.state_tax_withheld, 0));
22
+ const totalSSWithheld = round(employees.reduce((s, e) => s + e.social_security_tax, 0));
23
+ const totalMedicareWithheld = round(employees.reduce((s, e) => s + e.medicare_tax, 0));
24
+ const totalContractorPaid = round(contractors.reduce((s, c) => s + c.total_paid, 0));
25
+ const contractors1099 = contractors.filter(c => c.total_paid >= 600);
26
+ const csv = [
27
+ `W-2 AND 1099 COMPILATION — TAX YEAR ${taxYear}`,
28
+ `Company: ${company}`,
29
+ `Generated: ${new Date().toISOString().split("T")[0]}`,
30
+ `Filing Deadline: ${parseInt(taxYear) + 1}-01-31`,
31
+ "",
32
+ "W-2 EMPLOYEE SUMMARY",
33
+ "Employee,SSN (last 4),Gross Wages,Federal Tax,State Tax,SS Tax,Medicare Tax,State",
34
+ ...employees.map(e => `${esc(e.name)},***-**-${e.ssn_last4},${fmt(e.wages)},${fmt(e.federal_tax_withheld)},${fmt(e.state_tax_withheld)},${fmt(e.social_security_tax)},${fmt(e.medicare_tax)},${e.state || ""}`),
35
+ "",
36
+ "W-2 TOTALS",
37
+ `Total Wages,${fmt(totalWages)}`,
38
+ `Total Federal Tax Withheld,${fmt(totalFedWithheld)}`,
39
+ `Total State Tax Withheld,${fmt(totalStateWithheld)}`,
40
+ `Total Social Security Tax,${fmt(totalSSWithheld)}`,
41
+ `Total Medicare Tax,${fmt(totalMedicareWithheld)}`,
42
+ `Total W-2s to Issue,${employees.length}`,
43
+ "",
44
+ "1099-NEC CONTRACTOR SUMMARY",
45
+ "Contractor,TIN (last 4),Total Paid,Form Required?,Type",
46
+ ...contractors.map(c => `${esc(c.name)},***-**-${c.tin_last4},${fmt(c.total_paid)},${c.total_paid >= 600 ? "YES" : "No (under $600)"},${c.type || "NEC"}`),
47
+ "",
48
+ "1099 TOTALS",
49
+ `Total Paid to Contractors,${fmt(totalContractorPaid)}`,
50
+ `1099s Required (>=$600),${contractors1099.length}`,
51
+ `Contractors Under $600 Threshold,${contractors.length - contractors1099.length}`,
52
+ "",
53
+ "FILING CHECKLIST",
54
+ `Task,Status`,
55
+ `Verify all employee SSNs,Pending`,
56
+ `Verify all contractor TINs,Pending`,
57
+ `Review wage and tax totals,Pending`,
58
+ `Print/e-file W-2s,Pending`,
59
+ `Print/e-file 1099s,Pending`,
60
+ `Mail copies to employees by ${parseInt(taxYear) + 1}-01-31,Pending`,
61
+ `Mail copies to contractors by ${parseInt(taxYear) + 1}-01-31,Pending`,
62
+ `File W-3 transmittal with SSA,Pending`,
63
+ `File 1096 transmittal with IRS,Pending`,
64
+ "",
65
+ "EMPLOYER TAX OBLIGATIONS",
66
+ `Employer SS Match (6.2%),${fmt(totalSSWithheld)}`,
67
+ `Employer Medicare Match (1.45%),${fmt(totalMedicareWithheld)}`,
68
+ `Total Employer Tax,${fmt(round(totalSSWithheld + totalMedicareWithheld))}`,
69
+ ];
70
+ return {
71
+ text: `W-2/1099 Compilation: ${employees.length} W-2s + ${contractors1099.length} 1099s | Total Wages: ${fmt(totalWages)} | Contractor Payments: ${fmt(totalContractorPaid)}`,
72
+ output_csv: csv.join("\n"),
73
+ summary: {
74
+ tax_year: taxYear,
75
+ w2_count: employees.length,
76
+ total_wages: totalWages,
77
+ total_fed_withheld: totalFedWithheld,
78
+ contractor_count: contractors1099.length,
79
+ total_contractor_paid: totalContractorPaid,
80
+ filing_deadline: `${parseInt(taxYear) + 1}-01-31`,
81
+ },
82
+ duration_ms: Date.now() - start,
83
+ };
84
+ }
85
+ function round(n) { return Math.round(n * 100) / 100; }
86
+ function fmt(n) { return "$" + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }
87
+ function esc(v) { return v.includes(",") ? `"${v}"` : v; }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * File parser registry.
3
- * Detects file type and extracts structured data.
3
+ * Detects file type, extracts structured data, and determines the best handler.
4
4
  */
5
5
  import { parseCSV, type CSVData } from "./csv.js";
6
6
  export interface ParsedFile {
@@ -10,8 +10,7 @@ export interface ParsedFile {
10
10
  suggestedActions: string[];
11
11
  }
12
12
  /**
13
- * Parse file content based on its type.
14
- * Returns structured data + suggested actions the bot can take.
13
+ * Parse file content and intelligently detect what kind of financial data it contains.
15
14
  */
16
15
  export declare function parseFile(fileName: string, fileType: string, content: string | Buffer): ParsedFile;
17
16
  export { parseCSV, type CSVData };
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  /**
3
3
  * File parser registry.
4
- * Detects file type and extracts structured data.
4
+ * Detects file type, extracts structured data, and determines the best handler.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.parseCSV = void 0;
@@ -9,8 +9,7 @@ exports.parseFile = parseFile;
9
9
  const csv_js_1 = require("./csv.js");
10
10
  Object.defineProperty(exports, "parseCSV", { enumerable: true, get: function () { return csv_js_1.parseCSV; } });
11
11
  /**
12
- * Parse file content based on its type.
13
- * Returns structured data + suggested actions the bot can take.
12
+ * Parse file content and intelligently detect what kind of financial data it contains.
14
13
  */
15
14
  function parseFile(fileName, fileType, content) {
16
15
  const lower = fileName.toLowerCase();
@@ -18,33 +17,16 @@ function parseFile(fileName, fileType, content) {
18
17
  if (fileType === "csv" || lower.endsWith(".csv")) {
19
18
  const text = typeof content === "string" ? content : content.toString("utf-8");
20
19
  const data = (0, csv_js_1.parseCSV)(text);
21
- const suggestedActions = [];
22
- // Detect what kind of CSV this is based on headers
23
- const headersLower = data.headers.map((h) => h.toLowerCase());
24
- if (headersLower.some((h) => /amount|cost|price|total|expense|debit|credit/.test(h))) {
25
- suggestedActions.push("expense_report", "chart");
26
- }
27
- if (headersLower.some((h) => /revenue|income|sales/.test(h)) && headersLower.some((h) => /expense|cost/.test(h))) {
28
- suggestedActions.push("pnl");
29
- }
30
- if (headersLower.some((h) => /invoice|bill|vendor|supplier/.test(h))) {
31
- suggestedActions.push("invoice");
32
- }
33
- if (headersLower.some((h) => /quantity|stock|inventory|sku/.test(h))) {
34
- suggestedActions.push("inventory_report");
35
- }
36
- if (data.summary.numericColumns.length > 0) {
37
- suggestedActions.push("chart", "summary");
38
- }
20
+ const suggestedActions = detectCSVType(data, lower);
39
21
  return { type: "csv", fileName, data, suggestedActions };
40
22
  }
41
- // Excel files (basic detection — full parsing requires xlsx library on the node)
23
+ // Excel files
42
24
  if (fileType === "excel" || lower.endsWith(".xlsx") || lower.endsWith(".xls")) {
43
25
  return {
44
26
  type: "excel",
45
27
  fileName,
46
28
  data: { message: "Excel file detected. Will be parsed by the processing node." },
47
- suggestedActions: ["chart", "expense_report", "summary"],
29
+ suggestedActions: detectFromFileName(lower),
48
30
  };
49
31
  }
50
32
  // PDF files
@@ -53,47 +35,174 @@ function parseFile(fileName, fileType, content) {
53
35
  type: "pdf",
54
36
  fileName,
55
37
  data: { message: "PDF file detected. Will be parsed by the processing node." },
56
- suggestedActions: detectPDFActions(lower),
38
+ suggestedActions: detectFromFileName(lower),
57
39
  };
58
40
  }
59
41
  // Text files
60
42
  if (fileType === "text" || lower.endsWith(".txt")) {
61
43
  const text = typeof content === "string" ? content : content.toString("utf-8");
62
- return {
63
- type: "text",
64
- fileName,
65
- data: { content: text, length: text.length },
66
- suggestedActions: ["summary"],
67
- };
44
+ return { type: "text", fileName, data: { content: text, length: text.length }, suggestedActions: ["summary"] };
68
45
  }
69
46
  // JSON files
70
47
  if (fileType === "json" || lower.endsWith(".json")) {
71
48
  const text = typeof content === "string" ? content : content.toString("utf-8");
72
49
  try {
73
50
  const parsed = JSON.parse(text);
74
- return {
75
- type: "json",
76
- fileName,
77
- data: { content: parsed, keys: Object.keys(parsed) },
78
- suggestedActions: ["summary", "chart"],
79
- };
51
+ return { type: "json", fileName, data: { content: parsed, keys: Object.keys(parsed) }, suggestedActions: ["summary", "chart"] };
80
52
  }
81
53
  catch {
82
54
  return { type: "json", fileName, data: { error: "Invalid JSON" }, suggestedActions: [] };
83
55
  }
84
56
  }
85
- // Unknown
86
- return {
87
- type: "unknown",
88
- fileName,
89
- data: { message: `Unrecognized file type: ${fileType}` },
90
- suggestedActions: [],
91
- };
57
+ return { type: "unknown", fileName, data: { message: `Unrecognized file type: ${fileType}` }, suggestedActions: [] };
92
58
  }
93
- function detectPDFActions(fileName) {
59
+ /**
60
+ * Intelligently detect the type of CSV data based on headers, column types, and file name.
61
+ * This is the core detection logic — order matters.
62
+ */
63
+ function detectCSVType(data, fileName) {
64
+ const headers = data.headers.map(h => h.toLowerCase());
65
+ const actions = [];
66
+ // ─── BANK STATEMENT detection ──────────────────────────
67
+ // Key signals: has debit/credit type column, reference numbers, deposit/withdrawal descriptions
68
+ const hasTypeCol = headers.some(h => /^type$/.test(h));
69
+ const hasRefCol = headers.some(h => /reference|ref|check|confirmation/.test(h));
70
+ const hasDebitCreditValues = data.rows.some(r => {
71
+ const typeIdx = headers.findIndex(h => /^type$/.test(h));
72
+ if (typeIdx >= 0) {
73
+ const val = (r[typeIdx] || "").toLowerCase();
74
+ return val === "debit" || val === "credit";
75
+ }
76
+ return false;
77
+ });
78
+ const hasDepositDescriptions = data.rows.some(r => {
79
+ const descIdx = headers.findIndex(h => /description/.test(h));
80
+ return descIdx >= 0 && /deposit|withdrawal|transfer|ach|wire|fee|interest/i.test(r[descIdx] || "");
81
+ });
82
+ if ((hasTypeCol && hasDebitCreditValues) || (hasRefCol && hasDepositDescriptions) || /bank|statement|reconcil/i.test(fileName)) {
83
+ actions.push("bank_reconciliation");
84
+ return actions;
85
+ }
86
+ // ─── INVOICE / AR detection ────────────────────────────
87
+ // Key signals: customer column, invoice number, due date, status (paid/unpaid/overdue)
88
+ const hasCustomerCol = headers.some(h => /customer|client|bill.?to/.test(h));
89
+ const hasInvoiceNumCol = headers.some(h => /invoice.?(?:number|no|num|#)|inv.?(?:no|num|#)/.test(h));
90
+ const hasDueDateCol = headers.some(h => /due.?date|payment.?due/.test(h));
91
+ const hasStatusCol = headers.some(h => /status/.test(h));
92
+ const hasStatusValues = data.rows.some(r => {
93
+ const statusIdx = headers.findIndex(h => /status/.test(h));
94
+ return statusIdx >= 0 && /paid|unpaid|overdue|outstanding|pending/i.test(r[statusIdx] || "");
95
+ });
96
+ if ((hasCustomerCol && hasInvoiceNumCol) || (hasInvoiceNumCol && hasDueDateCol) || (hasStatusValues && hasCustomerCol) || /invoice/i.test(fileName)) {
97
+ actions.push("ar_aging");
98
+ return actions;
99
+ }
100
+ // ─── AP / BILLS detection ──────────────────────────────
101
+ const hasVendorCol = headers.some(h => /vendor|supplier|payee/.test(h));
102
+ const hasBillNumCol = headers.some(h => /bill.?(?:number|no|num|#)/.test(h));
103
+ if ((hasVendorCol && hasBillNumCol) || (hasVendorCol && hasDueDateCol) || /bill|payable/i.test(fileName)) {
104
+ actions.push("ap_aging");
105
+ return actions;
106
+ }
107
+ // ─── PAYROLL detection ─────────────────────────────────
108
+ // Key signals: employee name, rate/salary, hours, department, type (salary/hourly)
109
+ const hasEmployeeCol = headers.some(h => /employee|name/.test(h));
110
+ const hasRateCol = headers.some(h => /rate|salary|wage|pay/.test(h));
111
+ const hasHoursCol = headers.some(h => /hours/.test(h));
112
+ const hasTypePayroll = data.rows.some(r => {
113
+ const typeIdx = headers.findIndex(h => /^type$/.test(h));
114
+ return typeIdx >= 0 && /salary|hourly/i.test(r[typeIdx] || "");
115
+ });
116
+ if ((hasEmployeeCol && hasRateCol) || (hasEmployeeCol && hasHoursCol) || hasTypePayroll || /payroll|employee|salary|wage/i.test(fileName)) {
117
+ actions.push("payroll");
118
+ return actions;
119
+ }
120
+ // ─── BUDGET VS ACTUALS detection ───────────────────────
121
+ const hasBudgetCol = headers.some(h => /budget/.test(h));
122
+ const hasActualCol = headers.some(h => /actual/.test(h));
123
+ if (hasBudgetCol && hasActualCol) {
124
+ actions.push("budget_vs_actuals");
125
+ return actions;
126
+ }
127
+ if (/budget/i.test(fileName) && (hasBudgetCol || hasActualCol)) {
128
+ actions.push("budget_vs_actuals");
129
+ return actions;
130
+ }
131
+ // ─── P&L detection ─────────────────────────────────────
132
+ const hasRevenueData = headers.some(h => /revenue|income|sales/.test(h)) || data.rows.some(r => /revenue|income|sales/i.test(r.join(" ")));
133
+ const hasExpenseData = headers.some(h => /expense|cost/.test(h)) || data.rows.some(r => /expense|cost of goods/i.test(r.join(" ")));
134
+ if (hasRevenueData && hasExpenseData) {
135
+ actions.push("pnl");
136
+ return actions;
137
+ }
138
+ if (/p&l|pnl|profit.?loss|income.?statement/i.test(fileName)) {
139
+ actions.push("pnl");
140
+ return actions;
141
+ }
142
+ // ─── SALES TAX detection ───────────────────────────────
143
+ const hasTaxRateCol = headers.some(h => /tax.?rate/.test(h));
144
+ const hasTaxableCol = headers.some(h => /taxable/.test(h));
145
+ const hasStateCol = headers.some(h => /^state$/.test(h));
146
+ if (hasTaxRateCol || (hasTaxableCol && hasStateCol) || /sales.?tax|tax.?report/i.test(fileName)) {
147
+ actions.push("sales_tax");
148
+ return actions;
149
+ }
150
+ // ─── DEPRECIATION / ASSET detection ────────────────────
151
+ const hasUsefulLifeCol = headers.some(h => /useful.?life|lifespan/.test(h));
152
+ const hasSalvageCol = headers.some(h => /salvage|residual/.test(h));
153
+ const hasAcquiredCol = headers.some(h => /acquired|purchase.?date/.test(h));
154
+ if (hasUsefulLifeCol || hasSalvageCol || /deprec|asset|equipment/i.test(fileName)) {
155
+ actions.push("depreciation");
156
+ return actions;
157
+ }
158
+ // ─── DEPARTMENT SPENDING detection ─────────────────────
159
+ const hasDepartmentCol = headers.some(h => /department|dept|team|division|cost.?center/.test(h));
160
+ const hasCategoryCol = headers.some(h => /category|type|class/.test(h));
161
+ const hasAmountCol = headers.some(h => /amount|cost|price|total/.test(h));
162
+ if (hasDepartmentCol && hasAmountCol) {
163
+ actions.push("department_spending");
164
+ return actions;
165
+ }
166
+ // ─── EXPENSE REPORT detection (catch-all for financial data) ──
167
+ if (hasAmountCol && hasCategoryCol) {
168
+ actions.push("expense_report");
169
+ return actions;
170
+ }
171
+ if (hasAmountCol && headers.some(h => /description|desc|memo/.test(h))) {
172
+ actions.push("expense_report");
173
+ return actions;
174
+ }
175
+ if (/expense|spending|receipt/i.test(fileName)) {
176
+ actions.push("expense_report");
177
+ return actions;
178
+ }
179
+ // ─── GENERIC fallback ─────────────────────────────────
180
+ if (data.summary.numericColumns.length > 0) {
181
+ actions.push("chart");
182
+ }
183
+ return actions;
184
+ }
185
+ /**
186
+ * Detect file type from file name alone (for PDFs, Excel, etc. where we can't read headers)
187
+ */
188
+ function detectFromFileName(fileName) {
94
189
  if (/invoice/i.test(fileName))
95
- return ["invoice", "expense_report"];
96
- if (/receipt/i.test(fileName))
190
+ return ["ar_aging"];
191
+ if (/bill|payable/i.test(fileName))
192
+ return ["ap_aging"];
193
+ if (/bank|statement|reconcil/i.test(fileName))
194
+ return ["bank_reconciliation"];
195
+ if (/payroll|employee|salary/i.test(fileName))
196
+ return ["payroll"];
197
+ if (/budget/i.test(fileName))
198
+ return ["budget_vs_actuals"];
199
+ if (/p&l|pnl|profit/i.test(fileName))
200
+ return ["pnl"];
201
+ if (/tax/i.test(fileName))
202
+ return ["sales_tax"];
203
+ if (/deprec|asset/i.test(fileName))
204
+ return ["depreciation"];
205
+ if (/expense|receipt|spending/i.test(fileName))
97
206
  return ["expense_report"];
98
207
  if (/report|statement/i.test(fileName))
99
208
  return ["summary", "chart"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neuronix-node",
3
- "version": "0.2.0",
3
+ "version": "0.6.0",
4
4
  "description": "Neuronix GPU Provider Node — earn by contributing compute to the Neuronix network",
5
5
  "main": "dist/index.js",
6
6
  "bin": {