@morroc/open-ledger 0.14.1

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 (81) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +191 -0
  3. package/datasets/defaults/cn.json +1 -0
  4. package/datasets/defaults/jp.json +1 -0
  5. package/datasets/defaults/th.json +1 -0
  6. package/datasets/defaults/us.json +1 -0
  7. package/datasets/institutions/cn.json +47 -0
  8. package/datasets/institutions/jp.json +59 -0
  9. package/datasets/institutions/th.json +99 -0
  10. package/datasets/institutions/us.json +70 -0
  11. package/dist/accounts/accounts.js +99 -0
  12. package/dist/accounts/balances.js +109 -0
  13. package/dist/accounts/matching.js +72 -0
  14. package/dist/accounts/resolve.js +118 -0
  15. package/dist/cli/commands/accounts.js +477 -0
  16. package/dist/cli/commands/config.js +175 -0
  17. package/dist/cli/commands/datasets.js +56 -0
  18. package/dist/cli/commands/doctor.js +153 -0
  19. package/dist/cli/commands/files.js +72 -0
  20. package/dist/cli/commands/ingest-commit.js +279 -0
  21. package/dist/cli/commands/ingest.js +203 -0
  22. package/dist/cli/commands/merchants.js +140 -0
  23. package/dist/cli/commands/notes.js +71 -0
  24. package/dist/cli/commands/open.js +54 -0
  25. package/dist/cli/commands/questions.js +119 -0
  26. package/dist/cli/commands/report.js +50 -0
  27. package/dist/cli/commands/setup.js +61 -0
  28. package/dist/cli/commands/status.js +187 -0
  29. package/dist/cli/commands/transactions.js +420 -0
  30. package/dist/cli/commands/vault.js +65 -0
  31. package/dist/cli/currency.js +28 -0
  32. package/dist/cli/db.js +5 -0
  33. package/dist/cli/format.js +71 -0
  34. package/dist/cli/index.js +19 -0
  35. package/dist/cli/output.js +304 -0
  36. package/dist/cli/program.js +140 -0
  37. package/dist/config.js +104 -0
  38. package/dist/context.js +30 -0
  39. package/dist/datasets/defaults.js +29 -0
  40. package/dist/datasets/index.js +33 -0
  41. package/dist/datasets/institutions.js +31 -0
  42. package/dist/datasets/loader.js +57 -0
  43. package/dist/db/connection.js +39 -0
  44. package/dist/db/encryption.js +42 -0
  45. package/dist/db/migrations/0001_baseline.js +121 -0
  46. package/dist/db/migrations/index.js +3 -0
  47. package/dist/db/queries/accounts.js +108 -0
  48. package/dist/db/queries/balances.js +61 -0
  49. package/dist/db/queries/files.js +72 -0
  50. package/dist/db/queries/merchants.js +163 -0
  51. package/dist/db/queries/notes.js +28 -0
  52. package/dist/db/queries/questions.js +117 -0
  53. package/dist/db/queries/transactions-dedup.js +80 -0
  54. package/dist/db/queries/transactions.js +319 -0
  55. package/dist/db/queries/vault.js +48 -0
  56. package/dist/db/schema.js +105 -0
  57. package/dist/extract/extract.js +89 -0
  58. package/dist/extract/ocr.js +164 -0
  59. package/dist/extract/pdf.js +127 -0
  60. package/dist/extract/presets/index.js +18 -0
  61. package/dist/extract/presets/lighton-ocr.js +12 -0
  62. package/dist/extract/presets/typhoon-ocr.js +23 -0
  63. package/dist/extract/route.js +40 -0
  64. package/dist/extract/source.js +84 -0
  65. package/dist/ingest/commit.js +313 -0
  66. package/dist/ingest/dedup.js +35 -0
  67. package/dist/ingest/prepare.js +241 -0
  68. package/dist/ingest/vault.js +56 -0
  69. package/dist/lib/date.js +6 -0
  70. package/dist/lib/ids.js +25 -0
  71. package/dist/lib/json.js +12 -0
  72. package/dist/lib/masked.js +49 -0
  73. package/dist/lib/money.js +35 -0
  74. package/dist/lib/patch.js +29 -0
  75. package/dist/lib/result.js +15 -0
  76. package/dist/lib/validate.js +154 -0
  77. package/dist/privacy/redactor.js +140 -0
  78. package/dist/setup/hosts.js +32 -0
  79. package/dist/setup/install.js +60 -0
  80. package/package.json +60 -0
  81. package/skills/SKILL.md +18 -0
package/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this
152
+ License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright 2026 Phureewat Aphibansri
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,191 @@
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="assets/logo-dark.svg">
4
+ <img src="assets/logo.svg" alt="OpenLedger" width="108">
5
+ </picture>
6
+ </p>
7
+
8
+ <h1 align="center">OpenLedger</h1>
9
+
10
+ <p align="center">
11
+ <strong>The Harness Layer for Personal Finance</strong>
12
+ </p>
13
+
14
+ <p align="center">
15
+ A harness that turns scattered financial statements into a private, deterministic ledger for your AI.
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="https://www.npmjs.com/package/@morroc/open-ledger"><img src="https://img.shields.io/npm/v/@morroc/open-ledger.svg" alt="npm version" /></a>
20
+ <a href="https://www.npmjs.com/package/@morroc/open-ledger"><img src="https://img.shields.io/npm/dt/@morroc/open-ledger.svg" alt="npm total downloads" /></a>
21
+ </p>
22
+
23
+ <br />
24
+
25
+ You've tried many personal finance apps from the App Store. None of them fits what you need, because each is someone else's idea of your money and lifestyle. So you asked AI to build the one that would, and it failed you too. It hallucinated the numbers, mangled your data, and never quite understood what you wanted.
26
+
27
+ AI fails when it has nowhere reliable to keep the numbers. OpenLedger gives it that place, a deterministic harness that holds every number in your own records.
28
+
29
+ OpenLedger is a secure bookkeeping that serves as a harness for your AI. The data source is what you already receive which are monthly statements from your banks and credit cards. Your AI reads each statement and records what it finds as double-entry bookkeeping.
30
+
31
+ Everything stays on your machine, the database is fully encrypted, and what the harness returns to your AI has PII redacted by default before it sends to AI provider. No bank logins, no bank API keys, no cloud aggregator needed, just the bank documents you already have as the source of truth.
32
+
33
+ By using this harness, your AI can build the app you never found: a budget tracker that fits your lifestyle, a subscription auditor, a retirement planner, a personal money coach. Your finance app is yours to reimagine, and everything you build reads from the same ledger, so you can keep adding without starting over.
34
+
35
+ ## Use OpenLedger with your AI
36
+
37
+ The whole skill is one file: [`skills/SKILL.md`](./skills/SKILL.md). Every host gets the same bytes; `oled setup --print` prints them.
38
+
39
+ ### AI Chat Apps (ChatGPT, Claude, Gemini, Kimi)
40
+
41
+ 1. Install [Node.js](https://nodejs.org) (LTS), then paste into your terminal:
42
+
43
+ ```bash
44
+ npm install -g @morroc/open-ledger
45
+ ```
46
+
47
+ 2. Paste into your AI chat:
48
+
49
+ ```
50
+ Fetch https://raw.githubusercontent.com/phureewat29/open-ledger/main/skills/SKILL.md
51
+ and follow it. oled is installed; help me set up my ledger.
52
+ ```
53
+
54
+ If your chat app cannot fetch URLs, paste the skill itself: `oled setup --print | pbcopy` copies it; drop it into the first message or the app's custom instructions.
55
+
56
+ Your AI walks you through the rest.
57
+
58
+ ### Coding Agents (Claude Code, Codex, Cursor, Gemini CLI, OpenCode, PI)
59
+
60
+ ```bash
61
+ npm install -g @morroc/open-ledger
62
+ npx skills add phureewat29/open-ledger
63
+ ```
64
+
65
+ Or run `oled setup`, which writes the skill to `.agents/skills/`, the shared directory most agents read (use `--host claude` for Claude Code).
66
+
67
+ ### Your own agent stack
68
+
69
+ Every command speaks `--json` with typed exit codes, built to be scripted. `oled setup --dir <agent-home>` installs the skill anywhere. Two complete references ship in this repo: [`examples/corgi-claude`](./examples/corgi-claude) runs the statement-to-answers loop with `claude -p`, and [`examples/corgi-eval`](./examples/corgi-eval) runs evals against any model and scores how well the harness fits.
70
+
71
+ With the skill installed, give your agent a real task:
72
+
73
+ 1. Start with the statements you have waiting: *"Ingest my new statements."* It discovers new files, prepares and reads each one, commits the transactions it finds, and raises a question for anything it can't resolve on its own.
74
+ 2. Clear whatever it flagged: *"Show me anything you weren't sure about, and let's resolve it."* It walks you through open questions, such as an unrecognized merchant or an ambiguous account match, one at a time.
75
+ 3. With the ledger current, ask for the payoff: *"What's my net worth, and where did most of my spending go last month?"* It reads the answer straight from the ledger.
76
+
77
+ ## The Agent Workflow
78
+
79
+ Every row becomes a *transaction*: it debits one account and credits another by the same positive amount.
80
+
81
+ This is the loop the skill teaches an agent to run:
82
+
83
+ 1. **Discover**: `oled ingest list --json` to find new/pending files.
84
+ 2. **Prepare**: `oled ingest prepare <path>` registers the file and extracts it, unlocking encrypted PDFs via `oled vault`. A PDF carrying its own text layer, or a scan read by a configured OCR endpoint, comes back as a `document` text file. With no text layer and no OCR endpoint, it comes back as one image per page.
85
+ 3. **Read**: the agent reads what prepare returned, either the text document or the page images, and picks out every transaction row.
86
+ 4. **Commit**: the agent pipes the transactions it extracted (one debit account, one credit account, one positive amount per row; splits go as a compound `linked` group) into `oled ingest commit`. The harness posts them into the ledger and raises a question for anything it can't resolve confidently (unknown merchant, fuzzy account match, uncategorized fallback, cross-currency row).
87
+ 5. **Resolve**: the agent (or you) works through `oled questions` for whatever got raised, then closes the file out with `oled ingest done <id>`.
88
+
89
+ ## Commands
90
+
91
+ Run `oled --help` (or `oled <noun> --help`) for the full flag reference. Grouped overview:
92
+
93
+ ```
94
+ oled # Status: config, database, ledger counts, net worth (default)
95
+ oled doctor # Diagnose the harness environment
96
+ oled setup # Install the skill for an agent CLI (--host <id> | --dir <path>)
97
+ oled config # Configuration
98
+
99
+ oled ingest # Ingest pipeline: list / prepare / commit / done / fail
100
+ oled files # Browse ingested files (list / show / drop)
101
+ oled vault # Manage file-password patterns for encrypted statements
102
+
103
+ oled transactions # Transactions: list / show / add / update / delete / recategorize / dedupe / merge
104
+ oled accounts # Manage the chart of accounts
105
+ oled merchants # Manage merchants and their default accounts
106
+ oled questions # List, answer, and defer open questions
107
+
108
+ oled report # Income, expenses, and net
109
+ oled notes # Manage freeform notes
110
+ oled datasets # Reference datasets
111
+
112
+ oled open # Open the data folder in file explorer
113
+ ```
114
+
115
+ ## Security & Privacy
116
+
117
+ - All financial data stays on your machine, encrypted with AES-256 (libsql); default `~/.oled/db.sqlite`.
118
+ - The config file (`~/.oled/config.json`) carries `0600` permissions. It holds two secrets at most, the database encryption key and the OCR endpoint API key; `config show` surfaces a fingerprint of each and `status` one of the database key, never the plaintext.
119
+ - Encrypted-PDF passwords sit AES-GCM-encrypted in `db.sqlite` under a filename pattern; plaintext never touches disk.
120
+ - A decrypted statement stays in memory. Only what an agent has to read is written to `cache/`: the extracted text, or the page images.
121
+ - Read commands mask PII in free-text fields by default; `--no-redact` returns verbatim text.
122
+ - No telemetry, no analytics. OpenLedger makes no network calls of its own. The exception is opt-in and goes only to the OCR endpoint you configure: `ingest prepare` sends it the page images to read, and `doctor` asks it which models it serves.
123
+
124
+ ## Configuration
125
+
126
+ OpenLedger stores everything in `~/.oled/`:
127
+
128
+ ```
129
+ ~/.oled/
130
+ config.json # locale, currency, paths, database encryption key (0600 permissions)
131
+ context.md # persistent freeform context an agent can read (path shown as context_path in oled config show)
132
+ db.sqlite # encrypted SQLite database
133
+ data/ # drop your statements here, as PDFs or images (subfolders allowed)
134
+ cache/ # extracted text and page images handed to an agent
135
+ ```
136
+
137
+ ### Environment variables
138
+
139
+ See `.env.example` for the current list:
140
+
141
+ ```bash
142
+ # OpenLedger environment variables. Copy this file to `.env` and fill the values.
143
+
144
+ # Optional. Relocates the entire ~/.oled directory. Individual
145
+ # OLED_* overrides below still win for their own paths.
146
+ OLED_DIR=
147
+
148
+ # Optional. Passphrase used to encrypt the local SQLite database (AES-256).
149
+ # `oled config --generate-key` generates one if left blank.
150
+ OLED_DB_ENCRYPTION_KEY=
151
+
152
+ # Optional. Default: ~/.oled/db.sqlite
153
+ OLED_DB_PATH=
154
+
155
+ # Optional. Default: ~/.oled/data
156
+ OLED_DATA_DIR=
157
+
158
+ # Optional. Scratch space for the extracted text and page images handed to external
159
+ # agent CLIs. Default: ~/.oled/cache
160
+ OLED_CACHE_DIR=
161
+
162
+ # Optional. OpenAI-compatible OCR endpoint base URL, including its version
163
+ # segment, e.g. http://127.0.0.1:1234/v1. A non-local URL sends statement page
164
+ # images off this machine.
165
+ OLED_OCR_BASE_URL=
166
+
167
+ # Optional. Model id served at OLED_OCR_BASE_URL. The id picks the built-in
168
+ # prompt, sampling, and page-render profile; blank asks the endpoint for the
169
+ # default profile's own model.
170
+ OLED_OCR_MODEL=
171
+
172
+ # Optional. API key for the OCR endpoint, if it requires one. Set it here or in
173
+ # the shell: `oled config` has no flag for it.
174
+ OLED_OCR_API_KEY=
175
+ ```
176
+
177
+ ## Contributing
178
+
179
+ ```bash
180
+ git clone https://github.com/phureewat29/open-ledger
181
+ cd open-ledger
182
+ npm install
183
+ npm run build
184
+ npm link # makes 'oled' available globally
185
+ ```
186
+
187
+ `npm run integration` builds the CLI and runs a two-stage integration test against the built binary: a read-surface sweep (NDJSON validity, exit codes, zero ANSI) and a full write-path lifecycle in an isolated environment.
188
+
189
+ ## License
190
+
191
+ OpenLedger is licensed under the [Apache License 2.0](./LICENSE).
@@ -0,0 +1 @@
1
+ { "country": "CN", "locale": "zh-CN", "currency": "CNY" }
@@ -0,0 +1 @@
1
+ { "country": "JP", "locale": "ja-JP", "currency": "JPY" }
@@ -0,0 +1 @@
1
+ { "country": "TH", "locale": "th-TH", "currency": "THB" }
@@ -0,0 +1 @@
1
+ { "country": "US", "locale": "en-US", "currency": "USD" }
@@ -0,0 +1,47 @@
1
+ {
2
+ "country": "CN",
3
+ "institutions": [
4
+ { "code": "ICBC", "label": "Industrial and Commercial Bank of China (工商银行)", "kind": "bank", "notes": "Largest of the Big Four; state-owned." },
5
+ { "code": "CCB", "label": "China Construction Bank (建设银行)", "kind": "bank", "notes": "Big Four; state-owned." },
6
+ { "code": "ABC", "label": "Agricultural Bank of China (农业银行)", "kind": "bank", "notes": "Big Four; state-owned." },
7
+ { "code": "BOC", "label": "Bank of China (中国银行)", "kind": "bank", "notes": "Big Four; strongest overseas presence." },
8
+ { "code": "BOCOM", "label": "Bank of Communications (交通银行)", "kind": "bank", "notes": "Fifth large state bank." },
9
+ { "code": "PSBC", "label": "Postal Savings Bank of China (邮储银行)", "kind": "bank", "notes": "State-owned; rural reach." },
10
+ { "code": "CMB", "label": "China Merchants Bank (招商银行)", "kind": "bank", "notes": "Leading retail joint-stock bank." },
11
+ { "code": "CITIC-CN", "label": "China CITIC Bank (中信银行)", "kind": "bank" },
12
+ { "code": "SPDB", "label": "Shanghai Pudong Development Bank (浦发银行)", "kind": "bank" },
13
+ { "code": "CIB", "label": "Industrial Bank (兴业银行)", "kind": "bank" },
14
+ { "code": "CMBC", "label": "China Minsheng Bank (民生银行)", "kind": "bank", "notes": "Largest private bank." },
15
+ { "code": "PAB", "label": "Ping An Bank (平安银行)", "kind": "bank", "notes": "Ping An Group subsidiary." },
16
+ { "code": "CEB", "label": "China Everbright Bank (光大银行)", "kind": "bank" },
17
+ { "code": "HXB", "label": "Hua Xia Bank (华夏银行)", "kind": "bank" },
18
+ { "code": "CGB", "label": "China Guangfa Bank (广发银行)", "kind": "bank" },
19
+ { "code": "WEBANK", "label": "WeBank (微众银行)", "kind": "bank", "notes": "Digital-only; Tencent-backed." },
20
+ { "code": "MYBANK", "label": "MYbank (网商银行)", "kind": "bank", "notes": "Digital-only; Ant Group-backed." },
21
+ { "code": "ALIPAY", "label": "Alipay (支付宝)", "kind": "wallet", "notes": "Ant Group; dominant wallet alongside WeChat Pay." },
22
+ { "code": "WECHATPAY", "label": "WeChat Pay (微信支付)", "kind": "wallet", "notes": "Tencent." },
23
+ { "code": "JDPAY", "label": "JD Pay (京东支付)", "kind": "wallet", "notes": "JD.com." },
24
+ { "code": "UNIONPAY", "label": "UnionPay (银联)", "kind": "payment_rail", "notes": "National card network and QuickPass QR rail; appears on statements, not an account." },
25
+ { "code": "CITICSEC", "label": "CITIC Securities (中信证券)", "kind": "broker", "notes": "Largest broker." },
26
+ { "code": "HUATAI", "label": "Huatai Securities (华泰证券)", "kind": "broker" },
27
+ { "code": "GTJA", "label": "Guotai Junan Securities (国泰君安)", "kind": "broker", "notes": "Merged with Haitong (2025) as Guotai Haitong." },
28
+ { "code": "GFSEC", "label": "GF Securities (广发证券)", "kind": "broker" },
29
+ { "code": "GALAXY", "label": "China Galaxy Securities (银河证券)", "kind": "broker" },
30
+ { "code": "EASTMONEY", "label": "East Money Securities (东方财富)", "kind": "broker", "notes": "Leading online/retail broker." },
31
+ { "code": "FUTU", "label": "Futu (富途牛牛)", "kind": "broker", "notes": "HK-based app broker; serves mainland investors offshore." },
32
+ { "code": "TIGER", "label": "Tiger Brokers (老虎证券)", "kind": "broker", "notes": "Offshore app broker." },
33
+ { "code": "PINGAN", "label": "Ping An Insurance (中国平安)", "kind": "insurer", "notes": "Life + P&C; largest insurer." },
34
+ { "code": "CHINALIFE", "label": "China Life (中国人寿)", "kind": "insurer", "notes": "State-owned life leader." },
35
+ { "code": "CPIC", "label": "China Pacific Insurance (太平洋保险)", "kind": "insurer" },
36
+ { "code": "PICC", "label": "People's Insurance Company of China (人保)", "kind": "insurer", "notes": "P&C leader; state-owned." },
37
+ { "code": "TAIKANG", "label": "Taikang Insurance (泰康保险)", "kind": "insurer", "notes": "Life and pensions." },
38
+ { "code": "STA", "label": "State Taxation Administration (税务总局)", "kind": "gov", "notes": "Individual income tax (IIT) withholding and filings." },
39
+ { "code": "SIO", "label": "Social Insurance (社保)", "kind": "gov", "notes": "Pension/medical/unemployment contributions on payslips." },
40
+ { "code": "HPF", "label": "Housing Provident Fund (公积金)", "kind": "gov", "notes": "Mandatory housing savings; employer-matched." },
41
+ { "code": "CHINAMOBILE", "label": "China Mobile (中国移动)", "kind": "telco" },
42
+ { "code": "CHINAUNICOM", "label": "China Unicom (中国联通)", "kind": "telco" },
43
+ { "code": "CHINATELECOM", "label": "China Telecom (中国电信)", "kind": "telco" },
44
+ { "code": "STATEGRID", "label": "State Grid (国家电网)", "kind": "utility", "notes": "Electricity for most provinces." },
45
+ { "code": "CSG", "label": "China Southern Power Grid (南方电网)", "kind": "utility", "notes": "Electricity for the five southern provinces." }
46
+ ]
47
+ }
@@ -0,0 +1,59 @@
1
+ {
2
+ "country": "JP",
3
+ "institutions": [
4
+ { "code": "MUFG", "label": "MUFG Bank (三菱UFJ銀行)", "kind": "bank", "notes": "Largest megabank." },
5
+ { "code": "SMBC", "label": "Sumitomo Mitsui Banking Corporation (三井住友銀行)", "kind": "bank", "notes": "Megabank." },
6
+ { "code": "MIZUHO", "label": "Mizuho Bank (みずほ銀行)", "kind": "bank", "notes": "Megabank." },
7
+ { "code": "RESONA", "label": "Resona Bank (りそな銀行)", "kind": "bank" },
8
+ { "code": "YUCHO", "label": "Japan Post Bank (ゆうちょ銀行)", "kind": "bank", "notes": "Largest deposit base; postal network." },
9
+ { "code": "RAKUTEN-BANK", "label": "Rakuten Bank (楽天銀行)", "kind": "bank", "notes": "Online-only; largest digital bank." },
10
+ { "code": "SBI-SHINSEI", "label": "SBI Shinsei Bank (SBI新生銀行)", "kind": "bank", "notes": "Former Shinsei; SBI-owned since 2021." },
11
+ { "code": "SONYBANK", "label": "Sony Bank (ソニー銀行)", "kind": "bank", "notes": "Online-only; FX-friendly." },
12
+ { "code": "PAYPAY-BANK", "label": "PayPay Bank (PayPay銀行)", "kind": "bank", "notes": "Former Japan Net Bank; SoftBank/Z group." },
13
+ { "code": "JIBUN", "label": "au Jibun Bank (auじぶん銀行)", "kind": "bank", "notes": "KDDI + MUFG online bank." },
14
+ { "code": "SEVENBANK", "label": "Seven Bank (セブン銀行)", "kind": "bank", "notes": "ATM network in 7-Eleven stores." },
15
+ { "code": "JCB", "label": "JCB", "kind": "card_issuer", "notes": "Japan's domestic card network and issuer." },
16
+ { "code": "RAKUTEN-CARD", "label": "Rakuten Card (楽天カード)", "kind": "card_issuer", "notes": "Largest issuer by cards in force." },
17
+ { "code": "SAISON", "label": "Credit Saison (クレディセゾン)", "kind": "card_issuer" },
18
+ { "code": "SMCC", "label": "Sumitomo Mitsui Card (三井住友カード)", "kind": "card_issuer", "notes": "SMBC group; Visa-centric." },
19
+ { "code": "ORICO", "label": "Orient Corporation (オリコ)", "kind": "card_issuer", "notes": "Cards and shopping credit." },
20
+ { "code": "AEON-JP", "label": "AEON Financial Service (イオンカード)", "kind": "card_issuer", "notes": "Retail-linked; distinct from AEON Thailand." },
21
+ { "code": "VIEWCARD", "label": "View Card (ビューカード)", "kind": "card_issuer", "notes": "JR East; Suica auto-charge." },
22
+ { "code": "PAYPAY", "label": "PayPay", "kind": "wallet", "notes": "Dominant QR wallet; SoftBank/Z group." },
23
+ { "code": "RAKUTEN-PAY", "label": "Rakuten Pay (楽天ペイ)", "kind": "wallet" },
24
+ { "code": "DBARAI", "label": "d Barai (d払い)", "kind": "wallet", "notes": "NTT Docomo; can settle via phone bill." },
25
+ { "code": "AUPAY", "label": "au PAY", "kind": "wallet", "notes": "KDDI." },
26
+ { "code": "MERPAY", "label": "Merpay (メルペイ)", "kind": "wallet", "notes": "Mercari's wallet." },
27
+ { "code": "SUICA", "label": "Suica", "kind": "wallet", "notes": "JR East transit IC money; also PASMO interoperable." },
28
+ { "code": "ZENGIN", "label": "Zengin System (全銀システム)", "kind": "payment_rail", "notes": "Interbank transfer rail; furikomi descriptors." },
29
+ { "code": "NOMURA", "label": "Nomura Securities (野村證券)", "kind": "broker", "notes": "Largest full-service broker." },
30
+ { "code": "DAIWA", "label": "Daiwa Securities (大和証券)", "kind": "broker" },
31
+ { "code": "SBI-SEC", "label": "SBI Securities (SBI証券)", "kind": "broker", "notes": "Largest online broker." },
32
+ { "code": "RAKUTEN-SEC", "label": "Rakuten Securities (楽天証券)", "kind": "broker", "notes": "Online; NISA-popular." },
33
+ { "code": "MONEX", "label": "Monex Securities (マネックス証券)", "kind": "broker" },
34
+ { "code": "MATSUI", "label": "Matsui Securities (松井証券)", "kind": "broker" },
35
+ { "code": "KABUCOM", "label": "au Kabucom Securities (auカブコム証券)", "kind": "broker", "notes": "MUFG + KDDI." },
36
+ { "code": "BITFLYER", "label": "bitFlyer", "kind": "crypto_exchange", "notes": "FSA-licensed; largest by BTC volume." },
37
+ { "code": "COINCHECK", "label": "Coincheck", "kind": "crypto_exchange", "notes": "Monex group." },
38
+ { "code": "GMOCOIN", "label": "GMO Coin (GMOコイン)", "kind": "crypto_exchange" },
39
+ { "code": "BITBANK", "label": "bitbank", "kind": "crypto_exchange" },
40
+ { "code": "SBIVC", "label": "SBI VC Trade", "kind": "crypto_exchange", "notes": "SBI group." },
41
+ { "code": "NIPPONLIFE", "label": "Nippon Life (日本生命)", "kind": "insurer", "notes": "Life; largest mutual." },
42
+ { "code": "DAIICHILIFE", "label": "Dai-ichi Life (第一生命)", "kind": "insurer", "notes": "Life; listed." },
43
+ { "code": "MEIJIYASUDA", "label": "Meiji Yasuda Life (明治安田生命)", "kind": "insurer" },
44
+ { "code": "SUMITOMOLIFE", "label": "Sumitomo Life (住友生命)", "kind": "insurer" },
45
+ { "code": "TOKIO-MARINE-JP", "label": "Tokio Marine & Nichido (東京海上日動)", "kind": "insurer", "notes": "Non-life leader; parent of Tokio Marine Thailand." },
46
+ { "code": "SOMPO", "label": "Sompo Japan (損保ジャパン)", "kind": "insurer", "notes": "Non-life." },
47
+ { "code": "NTA", "label": "National Tax Agency (国税庁)", "kind": "gov", "notes": "Income tax; nenmatsu-chosei year-end adjustment." },
48
+ { "code": "NENKIN", "label": "Japan Pension Service (日本年金機構)", "kind": "gov", "notes": "National and employee pension contributions." },
49
+ { "code": "DOCOMO", "label": "NTT Docomo", "kind": "telco" },
50
+ { "code": "KDDI", "label": "au (KDDI)", "kind": "telco" },
51
+ { "code": "SOFTBANK", "label": "SoftBank", "kind": "telco" },
52
+ { "code": "RAKUTEN-MOBILE", "label": "Rakuten Mobile (楽天モバイル)", "kind": "telco" },
53
+ { "code": "TEPCO", "label": "Tokyo Electric Power (東京電力)", "kind": "utility", "notes": "Kanto electricity." },
54
+ { "code": "KEPCO-JP", "label": "Kansai Electric Power (関西電力)", "kind": "utility", "notes": "Kansai electricity." },
55
+ { "code": "CHUBU", "label": "Chubu Electric Power (中部電力)", "kind": "utility" },
56
+ { "code": "TOKYOGAS", "label": "Tokyo Gas (東京ガス)", "kind": "utility" },
57
+ { "code": "OSAKAGAS", "label": "Osaka Gas (大阪ガス)", "kind": "utility" }
58
+ ]
59
+ }