plasalid 0.5.1 → 0.5.3

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.
package/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ <h1 align="center">&lt;°(((&gt;&lt;</h1>
2
+
1
3
  <h1 align="center">Plasalid</h1>
2
4
 
3
5
  <p align="center">
@@ -100,7 +102,7 @@ plasalid review [--dry-run] # Connect related transactions, learn recurr
100
102
  │ ~/.plasalid/data/ │
101
103
  └──────────┬──────────┘
102
104
 
103
- plasalid scan
105
+ plasalid scan / plasalid record
104
106
 
105
107
  Claude API (PII-redacted)
106
108
 
@@ -108,7 +110,7 @@ plasalid review [--dry-run] # Connect related transactions, learn recurr
108
110
  │ Encrypted DB │◀──── plasalid review
109
111
  └──────────┬──────────┘
110
112
 
111
- plasalid · chat
113
+ plasalid
112
114
  ```
113
115
 
114
116
  Two outbound calls: the AI provider during scan, and the AI provider during chat. Both are PII-redacted. Your financial data is never stored off your machine. No telemetry. No analytics.
package/dist/cli/chat.js CHANGED
@@ -1,14 +1,10 @@
1
1
  import chalk from "chalk";
2
- import { config } from "../config.js";
3
- import { banner } from "./format.js";
4
- import { printLogo } from "./logo.js";
2
+ import { pickQuote } from "./quotes.js";
5
3
  export async function startChat() {
6
4
  const { getDb } = await import("../db/connection.js");
7
5
  const db = getDb();
8
6
  console.log("");
9
- printLogo();
10
- console.log("");
11
- console.log(banner());
7
+ renderQuote(pickQuote());
12
8
  console.log("");
13
9
  const accountCount = db
14
10
  .prepare(`SELECT COUNT(*) AS n FROM accounts`)
@@ -16,13 +12,55 @@ export async function startChat() {
16
12
  if (accountCount.n === 0) {
17
13
  console.log(chalk.yellow("No accounts scanned yet. Run `plasalid data` to drop your bank/credit card statements in, then run `plasalid scan`."));
18
14
  console.log("");
19
- console.log(chalk.dim("You can still chat, but I won't have any data to answer questions about."));
20
- console.log("");
21
- }
22
- else {
23
- console.log(chalk.dim(`Hi ${config.userName}. Ask me anything about your financial data.`));
24
- console.log("");
25
15
  }
16
+ console.log(chalk.dim("Ready when you are. Ask Plasalid anything about your money."));
17
+ console.log("");
26
18
  const { runChatApp } = await import("./ink/mount.js");
27
19
  await runChatApp({ db });
28
20
  }
21
+ const MAX_COL_WIDTH = 80;
22
+ const MAX_WRAP_WIDTH = 56;
23
+ const MIN_WRAP_WIDTH = 24;
24
+ const MAX_LEFT_PAD = 4;
25
+ function renderQuote(q) {
26
+ const cols = Math.min(process.stdout.columns || MAX_COL_WIDTH, MAX_COL_WIDTH);
27
+ const wrapWidth = Math.min(MAX_WRAP_WIDTH, Math.max(MIN_WRAP_WIDTH, cols - 8));
28
+ const lines = wrapText(q.text, wrapWidth);
29
+ const decorated = lines.map((line, i) => decorateQuote(line, i, lines.length));
30
+ const blockWidth = Math.max(...decorated.map((l) => l.length));
31
+ const centeredPad = Math.max(0, Math.floor((cols - blockWidth) / 2));
32
+ const leftPad = Math.min(MAX_LEFT_PAD, centeredPad);
33
+ for (const line of decorated) {
34
+ console.log(chalk.dim(" ".repeat(leftPad) + line));
35
+ }
36
+ console.log("");
37
+ const author = `— ${q.author}`;
38
+ const authorPad = Math.max(leftPad, leftPad + blockWidth - author.length);
39
+ console.log(chalk.dim(" ".repeat(authorPad) + author));
40
+ console.log("");
41
+ }
42
+ function decorateQuote(line, index, total) {
43
+ const open = index === 0 ? "“" : " ";
44
+ const close = index === total - 1 ? "”" : "";
45
+ return `${open}${line}${close}`;
46
+ }
47
+ function wrapText(text, width) {
48
+ const words = text.split(/\s+/);
49
+ const lines = [];
50
+ let current = "";
51
+ for (const word of words) {
52
+ if (!current) {
53
+ current = word;
54
+ }
55
+ else if (current.length + 1 + word.length <= width) {
56
+ current += " " + word;
57
+ }
58
+ else {
59
+ lines.push(current);
60
+ current = word;
61
+ }
62
+ }
63
+ if (current)
64
+ lines.push(current);
65
+ return lines;
66
+ }
@@ -54,8 +54,9 @@ export function formatError(error, context) {
54
54
  return `${chalk.red("✗")} ${context ? context + ": " : ""}${safeMsg}`;
55
55
  }
56
56
  export function banner() {
57
- return chalk.bold("Plasalid") + chalk.dim(" · The Harness Layer for Personal Finance");
57
+ return chalk.cyan("<°(((>< ") + chalk.bold("Plasalid") + chalk.dim(" · The Harness Layer for Personal Finance");
58
58
  }
59
+ const FISH_ART = "<°(((><";
59
60
  function stripAnsi(str) {
60
61
  return str.replace(ANSI_RE, "");
61
62
  }
@@ -74,6 +75,8 @@ function box(label, lines) {
74
75
  const DISCLAIMER = "Plasalid is an assistant, not a financial advisor. It only summarizes financial statements — verify amounts against your statements before relying on them.";
75
76
  export function helpScreen(commands) {
76
77
  const sections = [
78
+ chalk.cyan(FISH_ART),
79
+ "",
77
80
  banner(),
78
81
  "",
79
82
  box("Usage", [
@@ -1,13 +1,18 @@
1
1
  import { useEffect, useMemo, useState } from "react";
2
2
  import chalk from "chalk";
3
3
  const HINTS = [
4
- "try: what is my net worth?",
5
- "try: how much did I spend on food this month?",
6
- "try: when is my credit card due?",
7
- "try: show me transactions over 5000 baht",
8
- "try: which credit card has the highest balance?",
9
- "try: how much income did I receive last month?",
10
- "try: list all accounts",
4
+ "try: what's my net worth?",
5
+ "try: where did my money go last month?",
6
+ "try: biggest expense this month?",
7
+ "try: total credit card debt?",
8
+ "try: next card payment due?",
9
+ "try: list my subscriptions",
10
+ "try: coffee spend this year?",
11
+ "try: transactions over 10,000 baht",
12
+ "try: top merchants this quarter?",
13
+ "try: dining — this month vs last?",
14
+ "try: net worth trend this year?",
15
+ "try: open concerns from last scan?",
11
16
  ];
12
17
  export function useFooterText(db) {
13
18
  const [tick, setTick] = useState(0);
@@ -34,7 +39,7 @@ export function useFooterText(db) {
34
39
  scanStr = `scanned ${Math.floor(mins / 1440)}d ago`;
35
40
  }
36
41
  const idx = (hintIdx + tick) % HINTS.length;
37
- const parts = [`${chalk.cyan("<><")} plasalid`];
42
+ const parts = [`${chalk.cyan("<°(((><")}`];
38
43
  if (scanStr)
39
44
  parts.push(scanStr);
40
45
  parts.push(HINTS[idx]);
package/dist/cli/logo.js CHANGED
@@ -1,20 +1,5 @@
1
1
  import chalk from "chalk";
2
- const FISH = [
3
- " ",
4
- " ",
5
- " ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑ ",
6
- " ↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑ ",
7
- " ↑↑↑↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑↑↑ ",
8
- " ↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑↑↑ ↑↑↑↑↑↑ ",
9
- " ↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑↑ ",
10
- " ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑↑↑ ",
11
- " ↑↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑ ",
12
- " ↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑ ",
13
- " ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑ ",
14
- " ↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑ ",
15
- " ",
16
- " ",
17
- ].join("\n");
2
+ const FISH = "<°(((><";
18
3
  export function printLogo() {
19
- console.log(chalk.bold(FISH));
4
+ console.log(chalk.cyan(FISH));
20
5
  }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Hand-curated quote list for the chat welcome screen.
3
+ *
4
+ * Bar: every entry is attributable to a specific public source — a book,
5
+ * shareholder letter, public lecture, or widely-documented quote of the named
6
+ * person. Well-known misattributions (Einstein on compound interest, Twain on
7
+ * banking, etc.) are deliberately excluded. The `source` comment beside each
8
+ * entry names the primary source so future maintainers can audit attribution.
9
+ */
10
+ export interface Quote {
11
+ text: string;
12
+ author: string;
13
+ }
14
+ export declare const QUOTES: Quote[];
15
+ export declare function pickQuote(): Quote;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Hand-curated quote list for the chat welcome screen.
3
+ *
4
+ * Bar: every entry is attributable to a specific public source — a book,
5
+ * shareholder letter, public lecture, or widely-documented quote of the named
6
+ * person. Well-known misattributions (Einstein on compound interest, Twain on
7
+ * banking, etc.) are deliberately excluded. The `source` comment beside each
8
+ * entry names the primary source so future maintainers can audit attribution.
9
+ */
10
+ export const QUOTES = [
11
+ // Warren Buffett — Berkshire Hathaway letters & public interviews
12
+ { text: "Rule No. 1: Never lose money. Rule No. 2: Never forget rule No. 1.", author: "Warren Buffett" },
13
+ { text: "Price is what you pay. Value is what you get.", author: "Warren Buffett" },
14
+ { text: "Be fearful when others are greedy, and be greedy when others are fearful.", author: "Warren Buffett" },
15
+ { text: "Risk comes from not knowing what you are doing.", author: "Warren Buffett" },
16
+ { text: "Someone is sitting in the shade today because someone planted a tree a long time ago.", author: "Warren Buffett" },
17
+ { text: "The most important investment you can make is in yourself.", author: "Warren Buffett" },
18
+ { text: "If you don't find a way to make money while you sleep, you will work until you die.", author: "Warren Buffett" },
19
+ { text: "Our favorite holding period is forever.", author: "Warren Buffett" },
20
+ // Charlie Munger — Poor Charlie's Almanack and Daily Journal meetings
21
+ { text: "The first rule of compounding: never interrupt it unnecessarily.", author: "Charlie Munger" },
22
+ { text: "The big money is not in the buying or the selling, but in the waiting.", author: "Charlie Munger" },
23
+ { text: "Spend each day trying to be a little wiser than you were when you woke up.", author: "Charlie Munger" },
24
+ { text: "It is remarkable how much long-term advantage people like us have gotten by trying to be consistently not stupid, instead of trying to be very intelligent.", author: "Charlie Munger" },
25
+ // Benjamin Graham — The Intelligent Investor, Security Analysis
26
+ { text: "The investor's chief problem — and even his worst enemy — is likely to be himself.", author: "Benjamin Graham" },
27
+ { text: "In the short run, the market is a voting machine, but in the long run it is a weighing machine.", author: "Benjamin Graham" },
28
+ // John C. Bogle — founder of Vanguard
29
+ { text: "Time is your friend; impulse is your enemy.", author: "John C. Bogle" },
30
+ { text: "The two greatest enemies of the equity fund investor are expenses and emotions.", author: "John C. Bogle" },
31
+ // Peter Lynch — One Up On Wall Street, Beating the Street
32
+ { text: "Know what you own, and know why you own it.", author: "Peter Lynch" },
33
+ { text: "The real key to making money in stocks is not to get scared out of them.", author: "Peter Lynch" },
34
+ // Howard Marks — memos and The Most Important Thing
35
+ { text: "You can't predict. You can prepare.", author: "Howard Marks" },
36
+ // Ray Dalio — Principles
37
+ { text: "Pain plus reflection equals progress.", author: "Ray Dalio" },
38
+ // Benjamin Franklin — Poor Richard's Almanack and The Way to Wealth
39
+ { text: "An investment in knowledge pays the best interest.", author: "Benjamin Franklin" },
40
+ { text: "Beware of little expenses; a small leak will sink a great ship.", author: "Benjamin Franklin" },
41
+ { text: "If you would be wealthy, think of saving as well as of getting.", author: "Benjamin Franklin" },
42
+ // Andrew Carnegie — The Gospel of Wealth and The Road to Business Success
43
+ { text: "The man who dies rich dies disgraced.", author: "Andrew Carnegie" },
44
+ { text: "Concentrate your energies, your thoughts and your capital. The wise man puts all his eggs in one basket and watches the basket.", author: "Andrew Carnegie" },
45
+ // P.T. Barnum — The Art of Money Getting (1880)
46
+ { text: "Money is a terrible master but an excellent servant.", author: "P.T. Barnum" },
47
+ // Will Rogers — public columns and stage performances
48
+ { text: "Don't gamble; take all your savings and buy some good stock and hold it till it goes up, then sell it. If it don't go up, don't buy it.", author: "Will Rogers" },
49
+ { text: "Too many people spend money they haven't earned to buy things they don't want to impress people they don't like.", author: "Will Rogers" },
50
+ // Henry David Thoreau — Walden and Journals
51
+ { text: "Wealth is the ability to fully experience life.", author: "Henry David Thoreau" },
52
+ { text: "That man is the richest whose pleasures are the cheapest.", author: "Henry David Thoreau" },
53
+ // Ralph Waldo Emerson — The Conduct of Life (1860)
54
+ { text: "The first wealth is health.", author: "Ralph Waldo Emerson" },
55
+ // Seneca — Letters from a Stoic
56
+ { text: "It is not the man who has too little, but the man who craves more, that is poor.", author: "Seneca" },
57
+ { text: "While we are postponing, life speeds by.", author: "Seneca" },
58
+ // Epictetus — Discourses
59
+ { text: "Wealth consists not in having great possessions, but in having few wants.", author: "Epictetus" },
60
+ // Confucius — Analects
61
+ { text: "He who will not economize will have to agonize.", author: "Confucius" },
62
+ // Adam Smith — The Wealth of Nations
63
+ { text: "Wealth, as Mr. Hobbes says, is power.", author: "Adam Smith" },
64
+ // Ayn Rand — Atlas Shrugged ("Francisco's money speech")
65
+ { text: "Money is only a tool. It will take you wherever you wish, but it will not replace you as the driver.", author: "Ayn Rand" },
66
+ // Jim Rohn — lectures and books
67
+ { text: "Discipline is the bridge between goals and accomplishment.", author: "Jim Rohn" },
68
+ { text: "Formal education will make you a living; self-education will make you a fortune.", author: "Jim Rohn" },
69
+ // Dave Ramsey — books and radio program
70
+ { text: "A budget is telling your money where to go instead of wondering where it went.", author: "Dave Ramsey" },
71
+ { text: "If you will live like no one else, later you can live like no one else.", author: "Dave Ramsey" },
72
+ // Suze Orman — books and television
73
+ { text: "A big part of financial freedom is having your heart and mind free from worry about the what-ifs of life.", author: "Suze Orman" },
74
+ // Robert Kiyosaki — Rich Dad Poor Dad
75
+ { text: "It's not how much money you make, but how much money you keep, how hard it works for you, and how many generations you keep it for.", author: "Robert Kiyosaki" },
76
+ { text: "The poor and the middle class work for money. The rich have money work for them.", author: "Robert Kiyosaki" },
77
+ // T. Harv Eker — Secrets of the Millionaire Mind
78
+ { text: "Your income can grow only to the extent you do.", author: "T. Harv Eker" },
79
+ // Morgan Housel — The Psychology of Money
80
+ { text: "Spending money to show people how much money you have is the fastest way to have less money.", author: "Morgan Housel" },
81
+ { text: "Doing well with money has little to do with how smart you are and a lot to do with how you behave.", author: "Morgan Housel" },
82
+ // Naval Ravikant — "How to Get Rich" tweetstorm and podcast
83
+ { text: "Seek wealth, not money or status. Wealth is having assets that earn while you sleep.", author: "Naval Ravikant" },
84
+ { text: "You're not going to get rich renting out your time. You must own equity — a piece of a business — to gain your financial freedom.", author: "Naval Ravikant" },
85
+ // George Soros — interviews
86
+ { text: "It's not whether you're right or wrong that's important, but how much money you make when you're right and how much you lose when you're wrong.", author: "George Soros" },
87
+ ];
88
+ export function pickQuote() {
89
+ return QUOTES[Math.floor(Math.random() * QUOTES.length)];
90
+ }
package/dist/cli/setup.js CHANGED
@@ -29,7 +29,7 @@ function printBanner() {
29
29
  }
30
30
  function printSummary(dataDir) {
31
31
  console.log("");
32
- console.log(chalk.green("Plasalid is configured."));
32
+ console.log(`${chalk.cyan("<°(((><")} ${chalk.green("Plasalid is configured.")}`);
33
33
  console.log(chalk.dim(`Config: ${getConfigPath()}`));
34
34
  console.log(chalk.dim(`Data: ${dataDir}`));
35
35
  console.log("");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plasalid",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "Plasalid — The Harness for Personal Finance",
5
5
  "keywords": [
6
6
  "finance",