@equt/clis 0.1.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 (46) hide show
  1. package/README.md +3 -0
  2. package/dist/bookkeeping/client.d.ts +13 -0
  3. package/dist/bookkeeping/client.d.ts.map +1 -0
  4. package/dist/bookkeeping/client.js +41 -0
  5. package/dist/bookkeeping/client.js.map +1 -0
  6. package/dist/bookkeeping/commands/accounts.d.ts +3 -0
  7. package/dist/bookkeeping/commands/accounts.d.ts.map +1 -0
  8. package/dist/bookkeeping/commands/accounts.js +28 -0
  9. package/dist/bookkeeping/commands/accounts.js.map +1 -0
  10. package/dist/bookkeeping/commands/currencies.d.ts +3 -0
  11. package/dist/bookkeeping/commands/currencies.d.ts.map +1 -0
  12. package/dist/bookkeeping/commands/currencies.js +27 -0
  13. package/dist/bookkeeping/commands/currencies.js.map +1 -0
  14. package/dist/bookkeeping/commands/journal-inspect.d.ts +3 -0
  15. package/dist/bookkeeping/commands/journal-inspect.d.ts.map +1 -0
  16. package/dist/bookkeeping/commands/journal-inspect.js +164 -0
  17. package/dist/bookkeeping/commands/journal-inspect.js.map +1 -0
  18. package/dist/bookkeeping/commands/journals.d.ts +3 -0
  19. package/dist/bookkeeping/commands/journals.d.ts.map +1 -0
  20. package/dist/bookkeeping/commands/journals.js +43 -0
  21. package/dist/bookkeeping/commands/journals.js.map +1 -0
  22. package/dist/bookkeeping/commands/line-add.d.ts +3 -0
  23. package/dist/bookkeeping/commands/line-add.d.ts.map +1 -0
  24. package/dist/bookkeeping/commands/line-add.js +76 -0
  25. package/dist/bookkeeping/commands/line-add.js.map +1 -0
  26. package/dist/bookkeeping/commands/unit-price.d.ts +3 -0
  27. package/dist/bookkeeping/commands/unit-price.d.ts.map +1 -0
  28. package/dist/bookkeeping/commands/unit-price.js +59 -0
  29. package/dist/bookkeeping/commands/unit-price.js.map +1 -0
  30. package/dist/bookkeeping/index.d.ts +3 -0
  31. package/dist/bookkeeping/index.d.ts.map +1 -0
  32. package/dist/bookkeeping/index.js +33 -0
  33. package/dist/bookkeeping/index.js.map +1 -0
  34. package/dist/bookkeeping/output.d.ts +5 -0
  35. package/dist/bookkeeping/output.d.ts.map +1 -0
  36. package/dist/bookkeeping/output.js +22 -0
  37. package/dist/bookkeeping/output.js.map +1 -0
  38. package/dist/bookkeeping/props.d.ts +12 -0
  39. package/dist/bookkeeping/props.d.ts.map +1 -0
  40. package/dist/bookkeeping/props.js +49 -0
  41. package/dist/bookkeeping/props.js.map +1 -0
  42. package/dist/shared/index.d.ts +9 -0
  43. package/dist/shared/index.d.ts.map +1 -0
  44. package/dist/shared/index.js +12 -0
  45. package/dist/shared/index.js.map +1 -0
  46. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ ## CLIs for My Dear Agents
2
+
3
+ [![Publish](https://github.com/equt/clis/actions/workflows/publish.yml/badge.svg)](https://github.com/equt/clis/actions/workflows/publish.yml)
@@ -0,0 +1,13 @@
1
+ import type { PageObjectResponse, QueryDataSourceParameters } from '@notionhq/client/build/src/api-endpoints.js';
2
+ import { Client } from '@notionhq/client';
3
+ export declare const DB: {
4
+ readonly Journals: "2274724d-dd75-80b5-84a2-000b682101b6";
5
+ readonly Lines: "2274724d-dd75-80a3-bdcc-000bacc0fc05";
6
+ readonly Accounts: "2274724d-dd75-80c3-ba5d-000b94e0054f";
7
+ readonly Currencies: "2274724d-dd75-80e0-ac77-000b99fbaf75";
8
+ readonly Exchanges: "2274724d-dd75-808b-b55e-000bd40ff60c";
9
+ readonly Feedback: "2274724d-dd75-80d1-8187-000be688b67f";
10
+ };
11
+ export declare function createClient(): Client;
12
+ export declare function queryAll(client: Client, params: QueryDataSourceParameters, limit?: number): Promise<PageObjectResponse[]>;
13
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/bookkeeping/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,yBAAyB,EAC1B,MAAM,6CAA6C,CAAA;AAEpD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAEzC,eAAO,MAAM,EAAE;;;;;;;CAOL,CAAA;AAEV,wBAAgB,YAAY,IAAI,MAAM,CAOrC;AAED,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,yBAAyB,EACjC,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAyB/B"}
@@ -0,0 +1,41 @@
1
+ import process from 'node:process';
2
+ import { Client } from '@notionhq/client';
3
+ export const DB = {
4
+ Journals: '2274724d-dd75-80b5-84a2-000b682101b6',
5
+ Lines: '2274724d-dd75-80a3-bdcc-000bacc0fc05',
6
+ Accounts: '2274724d-dd75-80c3-ba5d-000b94e0054f',
7
+ Currencies: '2274724d-dd75-80e0-ac77-000b99fbaf75',
8
+ Exchanges: '2274724d-dd75-808b-b55e-000bd40ff60c',
9
+ Feedback: '2274724d-dd75-80d1-8187-000be688b67f',
10
+ };
11
+ export function createClient() {
12
+ const token = process.env.NOTION_TOKEN;
13
+ if (!token) {
14
+ console.error('NOTION_TOKEN environment variable is not set');
15
+ process.exit(1);
16
+ }
17
+ return new Client({ auth: token });
18
+ }
19
+ export async function queryAll(client, params, limit) {
20
+ const results = [];
21
+ let cursor;
22
+ while (true) {
23
+ const response = await client.dataSources.query({
24
+ ...params,
25
+ start_cursor: cursor,
26
+ });
27
+ for (const page of response.results) {
28
+ if (page.object === 'page' && 'properties' in page) {
29
+ results.push(page);
30
+ if (limit !== undefined && results.length >= limit) {
31
+ return results;
32
+ }
33
+ }
34
+ }
35
+ if (!response.has_more || response.next_cursor === null)
36
+ break;
37
+ cursor = response.next_cursor;
38
+ }
39
+ return results;
40
+ }
41
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/bookkeeping/client.ts"],"names":[],"mappings":"AAIA,OAAO,OAAO,MAAM,cAAc,CAAA;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAEzC,MAAM,CAAC,MAAM,EAAE,GAAG;IAChB,QAAQ,EAAE,sCAAsC;IAChD,KAAK,EAAE,sCAAsC;IAC7C,QAAQ,EAAE,sCAAsC;IAChD,UAAU,EAAE,sCAAsC;IAClD,SAAS,EAAE,sCAAsC;IACjD,QAAQ,EAAE,sCAAsC;CACxC,CAAA;AAEV,MAAM,UAAU,YAAY;IAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAA;IACtC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAA;QAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;AACpC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,MAAc,EACd,MAAiC,EACjC,KAAc;IAEd,MAAM,OAAO,GAAyB,EAAE,CAAA;IACxC,IAAI,MAA0B,CAAA;IAE9B,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC;YAC9C,GAAG,MAAM;YACT,YAAY,EAAE,MAAM;SACrB,CAAC,CAAA;QAEF,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACpC,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,YAAY,IAAI,IAAI,EAAE,CAAC;gBACnD,OAAO,CAAC,IAAI,CAAC,IAA0B,CAAC,CAAA;gBACxC,IAAI,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;oBACnD,OAAO,OAAO,CAAA;gBAChB,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAC,WAAW,KAAK,IAAI;YACrD,MAAK;QACP,MAAM,GAAG,QAAQ,CAAC,WAAW,CAAA;IAC/B,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerAccounts(program: Command): void;
3
+ //# sourceMappingURL=accounts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../../src/bookkeeping/commands/accounts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKxC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6BvD"}
@@ -0,0 +1,28 @@
1
+ import { createClient, DB, queryAll } from '../client.js';
2
+ import { renderTable, renderYaml } from '../output.js';
3
+ import { extractRichText, extractTitle } from '../props.js';
4
+ export function registerAccounts(program) {
5
+ const accounts = program
6
+ .command('accounts')
7
+ .description('Manage accounts');
8
+ accounts
9
+ .command('list', { isDefault: true })
10
+ .description('List all accounts')
11
+ .action(async () => {
12
+ const yaml = program.opts().yaml;
13
+ const client = createClient();
14
+ const pages = await queryAll(client, { data_source_id: DB.Accounts });
15
+ const items = pages.map(page => ({
16
+ id: page.id,
17
+ name: extractTitle(page.properties.Name),
18
+ description: extractRichText(page.properties.Description),
19
+ }));
20
+ if (yaml) {
21
+ renderYaml(items);
22
+ }
23
+ else {
24
+ renderTable(['ID', 'Name', 'Description'], items.map(i => [i.id, i.name, i.description]));
25
+ }
26
+ });
27
+ }
28
+ //# sourceMappingURL=accounts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts.js","sourceRoot":"","sources":["../../../src/bookkeeping/commands/accounts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE3D,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,MAAM,QAAQ,GAAG,OAAO;SACrB,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,iBAAiB,CAAC,CAAA;IAEjC,QAAQ;SACL,OAAO,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;SACpC,WAAW,CAAC,mBAAmB,CAAC;SAChC,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAqB,CAAC,IAAI,CAAA;QACnD,MAAM,MAAM,GAAG,YAAY,EAAE,CAAA;QAC7B,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAA;QAErE,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC/B,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YACxC,WAAW,EAAE,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;SAC1D,CAAC,CAAC,CAAA;QAEH,IAAI,IAAI,EAAE,CAAC;YACT,UAAU,CAAC,KAAK,CAAC,CAAA;QACnB,CAAC;aACI,CAAC;YACJ,WAAW,CACT,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,EAC7B,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAC9C,CAAA;QACH,CAAC;IACH,CAAC,CAAC,CAAA;AACN,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerCurrencies(program: Command): void;
3
+ //# sourceMappingURL=currencies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"currencies.d.ts","sourceRoot":"","sources":["../../../src/bookkeeping/commands/currencies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKxC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4BzD"}
@@ -0,0 +1,27 @@
1
+ import { createClient, DB, queryAll } from '../client.js';
2
+ import { renderTable, renderYaml } from '../output.js';
3
+ import { extractTitle } from '../props.js';
4
+ export function registerCurrencies(program) {
5
+ const currencies = program
6
+ .command('currencies')
7
+ .description('Manage currencies');
8
+ currencies
9
+ .command('list', { isDefault: true })
10
+ .description('List all currencies')
11
+ .action(async () => {
12
+ const yaml = program.opts().yaml;
13
+ const client = createClient();
14
+ const pages = await queryAll(client, { data_source_id: DB.Currencies });
15
+ const items = pages.map(page => ({
16
+ id: page.id,
17
+ name: extractTitle(page.properties.Name),
18
+ }));
19
+ if (yaml) {
20
+ renderYaml(items);
21
+ }
22
+ else {
23
+ renderTable(['ID', 'Name'], items.map(i => [i.id, i.name]));
24
+ }
25
+ });
26
+ }
27
+ //# sourceMappingURL=currencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"currencies.js","sourceRoot":"","sources":["../../../src/bookkeeping/commands/currencies.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,MAAM,UAAU,kBAAkB,CAAC,OAAgB;IACjD,MAAM,UAAU,GAAG,OAAO;SACvB,OAAO,CAAC,YAAY,CAAC;SACrB,WAAW,CAAC,mBAAmB,CAAC,CAAA;IAEnC,UAAU;SACP,OAAO,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;SACpC,WAAW,CAAC,qBAAqB,CAAC;SAClC,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAqB,CAAC,IAAI,CAAA;QACnD,MAAM,MAAM,GAAG,YAAY,EAAE,CAAA;QAC7B,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,EAAE,CAAC,UAAU,EAAE,CAAC,CAAA;QAEvE,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC/B,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;SACzC,CAAC,CAAC,CAAA;QAEH,IAAI,IAAI,EAAE,CAAC;YACT,UAAU,CAAC,KAAK,CAAC,CAAA;QACnB,CAAC;aACI,CAAC;YACJ,WAAW,CACT,CAAC,IAAI,EAAE,MAAM,CAAC,EACd,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAC/B,CAAA;QACH,CAAC;IACH,CAAC,CAAC,CAAA;AACN,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerJournalInspect(program: Command): void;
3
+ //# sourceMappingURL=journal-inspect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal-inspect.d.ts","sourceRoot":"","sources":["../../../src/bookkeeping/commands/journal-inspect.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAuCxC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4L7D"}
@@ -0,0 +1,164 @@
1
+ import process from 'node:process';
2
+ import { createClient } from '../client.js';
3
+ import { formatNumber, renderKeyValue, renderTable, renderYaml } from '../output.js';
4
+ import { extractDate, extractFormulaCheckbox, extractNumber, extractRelationIds, extractRichText, extractSelect, extractTitle, } from '../props.js';
5
+ async function fetchPage(client, id) {
6
+ const p = await client.pages.retrieve({ page_id: id });
7
+ return p.object === 'page' && 'properties' in p
8
+ ? p
9
+ : null;
10
+ }
11
+ async function fetchNames(client, ids) {
12
+ const map = new Map();
13
+ await Promise.all(ids.map(async (id) => {
14
+ const p = await fetchPage(client, id);
15
+ if (p)
16
+ map.set(id, extractTitle(p.properties.Name));
17
+ }));
18
+ return map;
19
+ }
20
+ export function registerJournalInspect(program) {
21
+ const journal = program
22
+ .command('journal')
23
+ .description('Journal operations');
24
+ journal
25
+ .command('inspect <journal-id>')
26
+ .description('Show full details for a journal')
27
+ .action(async (journalId) => {
28
+ const yaml = program.opts().yaml;
29
+ const client = createClient();
30
+ // 1. Fetch journal page
31
+ const jPage = await fetchPage(client, journalId);
32
+ if (!jPage) {
33
+ console.error(`Journal not found: ${journalId}`);
34
+ process.exit(1);
35
+ }
36
+ const props = jPage.properties;
37
+ const journalName = extractTitle(props.Name);
38
+ const journalDate = extractDate(props.Date);
39
+ const journalNote = extractRichText(props.Note);
40
+ const journalValid = extractFormulaCheckbox(props.Valid);
41
+ // 2. Get relation IDs inline
42
+ const lineIds = extractRelationIds(props.Transactions);
43
+ const exchangeIds = extractRelationIds(props.Exchanges);
44
+ // 3. Fetch all line and exchange pages in parallel
45
+ const [linePages, exchangePagesList] = await Promise.all([
46
+ Promise.all(lineIds.map(id => fetchPage(client, id))),
47
+ Promise.all(exchangeIds.map(id => fetchPage(client, id))),
48
+ ]);
49
+ const validLinePages = linePages.filter((p) => p !== null);
50
+ const validExchangePages = exchangePagesList.filter((p) => p !== null);
51
+ // 4. Collect all referenced IDs for batch resolution
52
+ const currencyIds = new Set();
53
+ const accountIds = new Set();
54
+ const feedbackIds = new Set();
55
+ for (const lp of validLinePages) {
56
+ extractRelationIds(lp.properties.Currency).forEach(id => currencyIds.add(id));
57
+ extractRelationIds(lp.properties.Account).forEach(id => accountIds.add(id));
58
+ extractRelationIds(lp.properties.Feedbacks).forEach(id => feedbackIds.add(id));
59
+ }
60
+ for (const ep of validExchangePages) {
61
+ extractRelationIds(ep.properties.From).forEach(id => currencyIds.add(id));
62
+ extractRelationIds(ep.properties.To).forEach(id => currencyIds.add(id));
63
+ }
64
+ // 5. Batch fetch currency names, account names, feedback pages
65
+ const feedbackIdList = [...feedbackIds];
66
+ const [currencyNames, accountNames, feedbackPagesList] = await Promise.all([
67
+ fetchNames(client, [...currencyIds]),
68
+ fetchNames(client, [...accountIds]),
69
+ Promise.all(feedbackIdList.map(id => fetchPage(client, id))),
70
+ ]);
71
+ const validFeedbackPages = feedbackPagesList.filter((p) => p !== null);
72
+ // Build line name lookup for feedback resolution
73
+ const lineNameById = new Map();
74
+ for (let i = 0; i < lineIds.length; i++) {
75
+ const lp = validLinePages[i];
76
+ if (lp)
77
+ lineNameById.set(lineIds[i], extractTitle(lp.properties.Name));
78
+ }
79
+ // Build output structures
80
+ const lines = validLinePages.map((lp) => {
81
+ const cIds = extractRelationIds(lp.properties.Currency);
82
+ const aIds = extractRelationIds(lp.properties.Account);
83
+ return {
84
+ name: extractTitle(lp.properties.Name),
85
+ type: extractSelect(lp.properties.Type),
86
+ amount: extractNumber(lp.properties.Amount) ?? 0,
87
+ currency: cIds.length > 0 ? (currencyNames.get(cIds[0]) ?? '') : '',
88
+ accounts: aIds.map(id => accountNames.get(id) ?? id),
89
+ };
90
+ });
91
+ const exchanges = validExchangePages.map((ep) => {
92
+ const fromIds = extractRelationIds(ep.properties.From);
93
+ const toIds = extractRelationIds(ep.properties.To);
94
+ return {
95
+ name: extractTitle(ep.properties.Name),
96
+ from: fromIds.length > 0 ? (currencyNames.get(fromIds[0]) ?? '') : '',
97
+ to: toIds.length > 0 ? (currencyNames.get(toIds[0]) ?? '') : '',
98
+ ratio: extractNumber(ep.properties.Ratio) ?? 0,
99
+ };
100
+ });
101
+ const feedbacks = validFeedbackPages.map((fp) => {
102
+ const lineRelIds = extractRelationIds(fp.properties.Transaction);
103
+ const lineName = lineRelIds.length > 0 ? (lineNameById.get(lineRelIds[0]) ?? '') : '';
104
+ return {
105
+ line: lineName,
106
+ name: extractTitle(fp.properties.Name),
107
+ attitude: extractSelect(fp.properties.Attitude),
108
+ };
109
+ });
110
+ if (yaml) {
111
+ renderYaml({
112
+ journal: {
113
+ name: journalName,
114
+ date: journalDate,
115
+ note: journalNote,
116
+ valid: journalValid,
117
+ },
118
+ lines: lines.map(l => ({
119
+ name: l.name,
120
+ type: l.type,
121
+ amount: l.amount,
122
+ currency: l.currency,
123
+ accounts: l.accounts,
124
+ })),
125
+ exchanges: exchanges.map(e => ({
126
+ name: e.name,
127
+ from: e.from,
128
+ to: e.to,
129
+ ratio: e.ratio,
130
+ })),
131
+ feedbacks: feedbacks.map(f => ({
132
+ line: f.line,
133
+ name: f.name,
134
+ attitude: f.attitude,
135
+ })),
136
+ });
137
+ }
138
+ else {
139
+ process.stdout.write('=== Journal ===\n');
140
+ renderKeyValue([
141
+ ['Name', journalName],
142
+ ['Date', journalDate],
143
+ ['Note', journalNote],
144
+ ['Valid', String(journalValid)],
145
+ ]);
146
+ process.stdout.write('\n');
147
+ process.stdout.write('=== Lines ===\n');
148
+ renderTable(['Name', 'Type', 'Amount', 'Currency', 'Account'], lines.map(l => [
149
+ l.name,
150
+ l.type,
151
+ formatNumber(l.amount),
152
+ l.currency,
153
+ l.accounts.join(', '),
154
+ ]));
155
+ process.stdout.write('\n');
156
+ process.stdout.write('=== Exchanges ===\n');
157
+ renderTable(['Name', 'From', 'To', 'Ratio'], exchanges.map(e => [e.name, e.from, e.to, String(e.ratio)]));
158
+ process.stdout.write('\n');
159
+ process.stdout.write('=== Feedback ===\n');
160
+ renderTable(['Line', 'Feedback', 'Attitude'], feedbacks.map(f => [f.line, f.name, f.attitude]));
161
+ }
162
+ });
163
+ }
164
+ //# sourceMappingURL=journal-inspect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal-inspect.js","sourceRoot":"","sources":["../../../src/bookkeeping/commands/journal-inspect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerJournals(program: Command): void;
3
+ //# sourceMappingURL=journals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journals.d.ts","sourceRoot":"","sources":["../../../src/bookkeeping/commands/journals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKxC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiDvD"}
@@ -0,0 +1,43 @@
1
+ import { createClient, DB, queryAll } from '../client.js';
2
+ import { renderTable, renderYaml } from '../output.js';
3
+ import { extractDate, extractRichText, extractTitle } from '../props.js';
4
+ export function registerJournals(program) {
5
+ const journals = program
6
+ .command('journals')
7
+ .description('Manage journals');
8
+ journals
9
+ .command('list', { isDefault: true })
10
+ .description('List journals sorted by date descending')
11
+ .option('--limit <n>', 'Maximum number of results', '20')
12
+ .option('--invalid-only', 'Show only invalid (unbalanced) journals')
13
+ .action(async (opts) => {
14
+ const yaml = program.opts().yaml;
15
+ const client = createClient();
16
+ const limit = Number.parseInt(opts.limit, 10);
17
+ const pages = await queryAll(client, {
18
+ data_source_id: DB.Journals,
19
+ sorts: [{ property: 'Date', direction: 'descending' }],
20
+ ...(opts.invalidOnly
21
+ ? {
22
+ filter: {
23
+ property: 'Valid',
24
+ formula: { checkbox: { equals: false } },
25
+ },
26
+ }
27
+ : {}),
28
+ }, limit);
29
+ const items = pages.map(page => ({
30
+ id: page.id,
31
+ name: extractTitle(page.properties.Name),
32
+ date: extractDate(page.properties.Date),
33
+ note: extractRichText(page.properties.Note),
34
+ }));
35
+ if (yaml) {
36
+ renderYaml(items.map(({ name, date, note }) => ({ name, date, note })));
37
+ }
38
+ else {
39
+ renderTable(['Name', 'Date', 'Note'], items.map(i => [i.name, i.date, i.note]));
40
+ }
41
+ });
42
+ }
43
+ //# sourceMappingURL=journals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journals.js","sourceRoot":"","sources":["../../../src/bookkeeping/commands/journals.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAExE,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,MAAM,QAAQ,GAAG,OAAO;SACrB,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,iBAAiB,CAAC,CAAA;IAEjC,QAAQ;SACL,OAAO,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;SACpC,WAAW,CAAC,yCAAyC,CAAC;SACtD,MAAM,CAAC,aAAa,EAAE,2BAA2B,EAAE,IAAI,CAAC;SACxD,MAAM,CAAC,gBAAgB,EAAE,yCAAyC,CAAC;SACnE,MAAM,CAAC,KAAK,EAAE,IAA8C,EAAE,EAAE;QAC/D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAqB,CAAC,IAAI,CAAA;QACnD,MAAM,MAAM,GAAG,YAAY,EAAE,CAAA;QAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;QAE7C,MAAM,KAAK,GAAG,MAAM,QAAQ,CAC1B,MAAM,EACN;YACE,cAAc,EAAE,EAAE,CAAC,QAAQ;YAC3B,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;YACtD,GAAG,CAAC,IAAI,CAAC,WAAW;gBAClB,CAAC,CAAC;oBACE,MAAM,EAAE;wBACN,QAAQ,EAAE,OAAO;wBACjB,OAAO,EAAE,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;qBACzC;iBACF;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,EACD,KAAK,CACN,CAAA;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC/B,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YACxC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YACvC,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;SAC5C,CAAC,CAAC,CAAA;QAEH,IAAI,IAAI,EAAE,CAAC;YACT,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QACzE,CAAC;aACI,CAAC;YACJ,WAAW,CACT,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACxB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CACzC,CAAA;QACH,CAAC;IACH,CAAC,CAAC,CAAA;AACN,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerLineAdd(program: Command): void;
3
+ //# sourceMappingURL=line-add.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-add.d.ts","sourceRoot":"","sources":["../../../src/bookkeeping/commands/line-add.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAMxC,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmGtD"}
@@ -0,0 +1,76 @@
1
+ import process from 'node:process';
2
+ import { createClient, DB } from '../client.js';
3
+ import { renderTable, renderYaml } from '../output.js';
4
+ import { extractTitle } from '../props.js';
5
+ export function registerLineAdd(program) {
6
+ const line = program.command('line').description('Line operations');
7
+ line
8
+ .command('add <journal-id> <type> <amount> <currency-id>')
9
+ .description('Add a new line entry to a journal')
10
+ .option('--account-id <id>', 'Notion page ID of the account to link')
11
+ .option('--name <name>', 'Override line name (defaults to journal name)')
12
+ .action(async (journalId, type, amountStr, currencyId, opts) => {
13
+ const yaml = program.opts().yaml;
14
+ // Validate type
15
+ const normalizedType = type.charAt(0).toUpperCase() + type.slice(1).toLowerCase();
16
+ if (normalizedType !== 'Credit' && normalizedType !== 'Debit') {
17
+ console.error(`Invalid type "${type}". Must be "Credit" or "Debit".`);
18
+ process.exit(1);
19
+ }
20
+ // Validate amount
21
+ const amount = Number.parseFloat(amountStr);
22
+ if (!Number.isFinite(amount) || amount <= 0) {
23
+ console.error(`Invalid amount "${amountStr}". Must be a finite positive number.`);
24
+ process.exit(1);
25
+ }
26
+ const client = createClient();
27
+ // Fetch journal to verify existence and get default name
28
+ const journalPage = await client.pages.retrieve({ page_id: journalId });
29
+ if (journalPage.object !== 'page' || !('properties' in journalPage)) {
30
+ console.error(`Journal not found: ${journalId}`);
31
+ process.exit(1);
32
+ }
33
+ const journalName = extractTitle(journalPage.properties.Name);
34
+ const lineName = opts.name ?? journalName;
35
+ // Build properties
36
+ const properties = {
37
+ Name: {
38
+ title: [{ text: { content: lineName } }],
39
+ },
40
+ Type: {
41
+ select: { name: normalizedType },
42
+ },
43
+ Amount: {
44
+ number: amount,
45
+ },
46
+ Currency: {
47
+ relation: [{ id: currencyId }],
48
+ },
49
+ Billing: {
50
+ relation: [{ id: journalId }],
51
+ },
52
+ };
53
+ if (opts.accountId) {
54
+ properties.Account = {
55
+ relation: [{ id: opts.accountId }],
56
+ };
57
+ }
58
+ const created = await client.pages.create({
59
+ parent: { type: 'data_source_id', data_source_id: DB.Lines },
60
+ properties: properties,
61
+ });
62
+ if (yaml) {
63
+ renderYaml({
64
+ id: created.id,
65
+ name: lineName,
66
+ type: normalizedType,
67
+ amount,
68
+ currency_id: currencyId,
69
+ });
70
+ }
71
+ else {
72
+ renderTable(['ID', 'Name', 'Type', 'Amount', 'Currency ID'], [[created.id, lineName, normalizedType, String(amount), currencyId]]);
73
+ }
74
+ });
75
+ }
76
+ //# sourceMappingURL=line-add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-add.js","sourceRoot":"","sources":["../../../src/bookkeeping/commands/line-add.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerUnitPrice(program: Command): void;
3
+ //# sourceMappingURL=unit-price.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unit-price.d.ts","sourceRoot":"","sources":["../../../src/bookkeeping/commands/unit-price.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAWxC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuExD"}
@@ -0,0 +1,59 @@
1
+ import { createClient, DB, queryAll } from '../client.js';
2
+ import { formatNumber, renderTable, renderYaml } from '../output.js';
3
+ import { extractFormulaNumber, extractNumber, extractRelationIds, extractSelect, extractTitle, } from '../props.js';
4
+ export function registerUnitPrice(program) {
5
+ program
6
+ .command('unit-price <query>')
7
+ .description('Search lines by name and show unit price')
8
+ .action(async (query) => {
9
+ const yaml = program.opts().yaml;
10
+ const client = createClient();
11
+ const pages = await queryAll(client, {
12
+ data_source_id: DB.Lines,
13
+ filter: {
14
+ property: 'Name',
15
+ title: { contains: query },
16
+ },
17
+ });
18
+ // Client-side filter: keep only rows with non-zero Unit Price
19
+ const withUnitPrice = pages.filter((page) => {
20
+ const unitPrice = extractFormulaNumber(page.properties['Unit Price']);
21
+ return unitPrice !== null && unitPrice !== 0;
22
+ });
23
+ // Collect all currency IDs for batch resolution
24
+ const currencyIds = new Set();
25
+ for (const page of withUnitPrice) {
26
+ extractRelationIds(page.properties.Currency).forEach(id => currencyIds.add(id));
27
+ }
28
+ // Batch fetch currency names
29
+ const currencyNames = new Map();
30
+ await Promise.all(Array.from(currencyIds, async (id) => {
31
+ const p = await client.pages.retrieve({ page_id: id });
32
+ if (p.object === 'page' && 'properties' in p) {
33
+ const name = extractTitle(p.properties.Name);
34
+ currencyNames.set(id, name);
35
+ }
36
+ }));
37
+ const items = withUnitPrice.map((page) => {
38
+ const cIds = extractRelationIds(page.properties.Currency);
39
+ return {
40
+ name: extractTitle(page.properties.Name),
41
+ type: extractSelect(page.properties.Type),
42
+ currency: cIds.length > 0 ? (currencyNames.get(cIds[0]) ?? '') : '',
43
+ amount: extractNumber(page.properties.Amount) ?? 0,
44
+ };
45
+ });
46
+ if (yaml) {
47
+ renderYaml(items.map(i => ({
48
+ name: i.name,
49
+ type: i.type,
50
+ currency: i.currency,
51
+ amount: i.amount,
52
+ })));
53
+ }
54
+ else {
55
+ renderTable(['Name', 'Type', 'Currency', 'Amount'], items.map(i => [i.name, i.type, i.currency, formatNumber(i.amount)]));
56
+ }
57
+ });
58
+ }
59
+ //# sourceMappingURL=unit-price.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unit-price.js","sourceRoot":"","sources":["../../../src/bookkeeping/commands/unit-price.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bookkeeping/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ import process from 'node:process';
3
+ import { APIResponseError } from '@notionhq/client';
4
+ import { program } from 'commander';
5
+ import { registerAccounts } from './commands/accounts.js';
6
+ import { registerCurrencies } from './commands/currencies.js';
7
+ import { registerJournalInspect } from './commands/journal-inspect.js';
8
+ import { registerJournals } from './commands/journals.js';
9
+ import { registerLineAdd } from './commands/line-add.js';
10
+ import { registerUnitPrice } from './commands/unit-price.js';
11
+ program
12
+ .name('bookkeeping')
13
+ .description('Double-entry bookkeeping CLI backed by Notion')
14
+ .option('--yaml', 'Emit YAML instead of a formatted table');
15
+ registerAccounts(program);
16
+ registerCurrencies(program);
17
+ registerJournals(program);
18
+ registerJournalInspect(program);
19
+ registerLineAdd(program);
20
+ registerUnitPrice(program);
21
+ program.parseAsync(process.argv).catch((err) => {
22
+ if (APIResponseError.isAPIResponseError(err)) {
23
+ console.error(`Notion API error ${err.status}: ${err.message}`);
24
+ }
25
+ else if (err instanceof Error) {
26
+ console.error(err.message);
27
+ }
28
+ else {
29
+ console.error(String(err));
30
+ }
31
+ process.exit(1);
32
+ });
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bookkeeping/index.ts"],"names":[],"mappings":";AACA,OAAO,OAAO,MAAM,cAAc,CAAA;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAE5D,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CAAC,+CAA+C,CAAC;KAC5D,MAAM,CAAC,QAAQ,EAAE,wCAAwC,CAAC,CAAA;AAE7D,gBAAgB,CAAC,OAAO,CAAC,CAAA;AACzB,kBAAkB,CAAC,OAAO,CAAC,CAAA;AAC3B,gBAAgB,CAAC,OAAO,CAAC,CAAA;AACzB,sBAAsB,CAAC,OAAO,CAAC,CAAA;AAC/B,eAAe,CAAC,OAAO,CAAC,CAAA;AACxB,iBAAiB,CAAC,OAAO,CAAC,CAAA;AAE1B,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC7C,IAAI,gBAAgB,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7C,OAAO,CAAC,KAAK,CAAC,oBAAoB,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;IACjE,CAAC;SACI,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC5B,CAAC;SACI,CAAC;QACJ,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;IAC5B,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
@@ -0,0 +1,5 @@
1
+ export declare function renderTable(headers: string[], rows: string[][]): void;
2
+ export declare function renderYaml(data: unknown): void;
3
+ export declare function renderKeyValue(pairs: [string, string][]): void;
4
+ export declare function formatNumber(n: number): string;
5
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/bookkeeping/output.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI,CAMrE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAE9C;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,IAAI,CAI9D;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9C"}
@@ -0,0 +1,22 @@
1
+ import process from 'node:process';
2
+ import Table from 'cli-table3';
3
+ import yaml from 'js-yaml';
4
+ export function renderTable(headers, rows) {
5
+ const table = new Table({ head: headers });
6
+ for (const row of rows) {
7
+ table.push(row);
8
+ }
9
+ process.stdout.write(`${table.toString()}\n`);
10
+ }
11
+ export function renderYaml(data) {
12
+ process.stdout.write(yaml.dump(data, { lineWidth: -1 }));
13
+ }
14
+ export function renderKeyValue(pairs) {
15
+ for (const [key, value] of pairs) {
16
+ process.stdout.write(`${key}: ${value}\n`);
17
+ }
18
+ }
19
+ export function formatNumber(n) {
20
+ return n.toLocaleString('en-US');
21
+ }
22
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/bookkeeping/output.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,cAAc,CAAA;AAClC,OAAO,KAAK,MAAM,YAAY,CAAA;AAC9B,OAAO,IAAI,MAAM,SAAS,CAAA;AAE1B,MAAM,UAAU,WAAW,CAAC,OAAiB,EAAE,IAAgB;IAC7D,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IAC1C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACjB,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;AAC/C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAa;IACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAC1D,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAyB;IACtD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC;QACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,KAAK,KAAK,IAAI,CAAC,CAAA;IAC5C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,OAAO,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;AAClC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { PageObjectResponse } from '@notionhq/client/build/src/api-endpoints.js';
2
+ type PageProp = PageObjectResponse['properties'][string];
3
+ export declare function extractTitle(prop: PageProp | undefined): string;
4
+ export declare function extractRichText(prop: PageProp | undefined): string;
5
+ export declare function extractDate(prop: PageProp | undefined): string;
6
+ export declare function extractNumber(prop: PageProp | undefined): number | null;
7
+ export declare function extractSelect(prop: PageProp | undefined): string;
8
+ export declare function extractRelationIds(prop: PageProp | undefined): string[];
9
+ export declare function extractFormulaCheckbox(prop: PageProp | undefined): boolean;
10
+ export declare function extractFormulaNumber(prop: PageProp | undefined): number | null;
11
+ export {};
12
+ //# sourceMappingURL=props.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../src/bookkeeping/props.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6CAA6C,CAAA;AAErF,KAAK,QAAQ,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AAExD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAK/D;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAKlE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAK9D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAKvE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAKhE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,EAAE,CAKvE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO,CAK1E;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAK9E"}
@@ -0,0 +1,49 @@
1
+ export function extractTitle(prop) {
2
+ if (prop?.type === 'title') {
3
+ return prop.title.map(t => t.plain_text).join('');
4
+ }
5
+ return '';
6
+ }
7
+ export function extractRichText(prop) {
8
+ if (prop?.type === 'rich_text') {
9
+ return prop.rich_text.map(t => t.plain_text).join('');
10
+ }
11
+ return '';
12
+ }
13
+ export function extractDate(prop) {
14
+ if (prop?.type === 'date' && prop.date !== null) {
15
+ return prop.date.start;
16
+ }
17
+ return '';
18
+ }
19
+ export function extractNumber(prop) {
20
+ if (prop?.type === 'number') {
21
+ return prop.number;
22
+ }
23
+ return null;
24
+ }
25
+ export function extractSelect(prop) {
26
+ if (prop?.type === 'select' && prop.select !== null) {
27
+ return prop.select.name;
28
+ }
29
+ return '';
30
+ }
31
+ export function extractRelationIds(prop) {
32
+ if (prop?.type === 'relation') {
33
+ return prop.relation.map(r => r.id);
34
+ }
35
+ return [];
36
+ }
37
+ export function extractFormulaCheckbox(prop) {
38
+ if (prop?.type === 'formula' && prop.formula.type === 'boolean') {
39
+ return prop.formula.boolean ?? false;
40
+ }
41
+ return false;
42
+ }
43
+ export function extractFormulaNumber(prop) {
44
+ if (prop?.type === 'formula' && prop.formula.type === 'number') {
45
+ return prop.formula.number;
46
+ }
47
+ return null;
48
+ }
49
+ //# sourceMappingURL=props.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"props.js","sourceRoot":"","sources":["../../src/bookkeeping/props.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,YAAY,CAAC,IAA0B;IACrD,IAAI,IAAI,EAAE,IAAI,KAAK,OAAO,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACnD,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAA0B;IACxD,IAAI,IAAI,EAAE,IAAI,KAAK,WAAW,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACvD,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAA0B;IACpD,IAAI,IAAI,EAAE,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAA;IACxB,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAA0B;IACtD,IAAI,IAAI,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAA0B;IACtD,IAAI,IAAI,EAAE,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAA;IACzB,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAA0B;IAC3D,IAAI,IAAI,EAAE,IAAI,KAAK,UAAU,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IACrC,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAA0B;IAC/D,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAChE,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,KAAK,CAAA;IACtC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAA0B;IAC7D,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC/D,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAA;IAC5B,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { PropertyItemObjectResponse } from '@notionhq/client';
2
+ type PropertyType = PropertyItemObjectResponse['type'];
3
+ type PropertyOfType<T extends PropertyType> = Extract<PropertyItemObjectResponse, {
4
+ type: T;
5
+ }>;
6
+ export declare function isPropertyOf<T extends PropertyType>(type: T): (column: unknown) => column is PropertyOfType<T>;
7
+ export declare function isPropertyOf<T extends PropertyType>(column: unknown, type: T): column is PropertyOfType<T>;
8
+ export {};
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAA;AAElE,KAAK,YAAY,GAAG,0BAA0B,CAAC,MAAM,CAAC,CAAA;AACtD,KAAK,cAAc,CAAC,CAAC,SAAS,YAAY,IAAI,OAAO,CAAC,0BAA0B,EAAE;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,CAAA;AAE9F,wBAAgB,YAAY,CAAC,CAAC,SAAS,YAAY,EACjD,IAAI,EAAE,CAAC,GACN,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,IAAI,cAAc,CAAC,CAAC,CAAC,CAAA;AACnD,wBAAgB,YAAY,CAAC,CAAC,SAAS,YAAY,EACjD,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,CAAC,GACN,MAAM,IAAI,cAAc,CAAC,CAAC,CAAC,CAAA"}
@@ -0,0 +1,12 @@
1
+ export function isPropertyOf(columnOrType, type) {
2
+ if (type === undefined) {
3
+ const t = columnOrType;
4
+ return (column) => typeof column === 'object'
5
+ && column !== null
6
+ && column.type === t;
7
+ }
8
+ return (typeof columnOrType === 'object'
9
+ && columnOrType !== null
10
+ && columnOrType.type === type);
11
+ }
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAYA,MAAM,UAAU,YAAY,CAC1B,YAAqB,EACrB,IAAQ;IAER,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,YAAiB,CAAA;QAC3B,OAAO,CAAC,MAAe,EAA+B,EAAE,CACtD,OAAO,MAAM,KAAK,QAAQ;eACvB,MAAM,KAAK,IAAI;eACd,MAA4B,CAAC,IAAI,KAAK,CAAC,CAAA;IAC/C,CAAC;IACD,OAAO,CACL,OAAO,YAAY,KAAK,QAAQ;WAC7B,YAAY,KAAK,IAAI;WACpB,YAAkC,CAAC,IAAI,KAAK,IAAI,CACrD,CAAA;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@equt/clis",
3
+ "type": "module",
4
+ "version": "0.1.1",
5
+ "packageManager": "bun@1.3.10",
6
+ "bin": {
7
+ "bookkeeping": "./dist/bookkeeping/index.js"
8
+ },
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "files": [
13
+ "dist/"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "typecheck": "tsc --noEmit",
18
+ "prepare": "simple-git-hooks"
19
+ },
20
+ "dependencies": {
21
+ "@notionhq/client": "^5.13.0",
22
+ "cli-table3": "^0.6.5",
23
+ "commander": "^14.0.0",
24
+ "js-yaml": "^4.1.0"
25
+ },
26
+ "devDependencies": {
27
+ "@antfu/eslint-config": "^7.7.3",
28
+ "@commitlint/cli": "^20.5.0",
29
+ "@commitlint/config-conventional": "^20.5.0",
30
+ "@types/js-yaml": "^4.0.9",
31
+ "@types/node": "^25.5.0",
32
+ "eslint": "^10.0.3",
33
+ "lint-staged": "^16.4.0",
34
+ "simple-git-hooks": "^2.13.1",
35
+ "typescript": "^5.9.3"
36
+ },
37
+ "simple-git-hooks": {
38
+ "commit-msg": "bunx --bun commitlint --edit $1",
39
+ "pre-commit": "bunx --bun lint-staged"
40
+ },
41
+ "commitlint": {
42
+ "extends": [
43
+ "@commitlint/config-conventional"
44
+ ]
45
+ }
46
+ }