tuimon 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/AI.md +191 -0
  2. package/README.md +223 -87
  3. package/dist/browser.d.ts.map +1 -1
  4. package/dist/browser.js +3 -0
  5. package/dist/browser.js.map +1 -1
  6. package/dist/cli.js +171 -3
  7. package/dist/cli.js.map +1 -1
  8. package/dist/config.d.ts +17 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +106 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/fkeybar.d.ts.map +1 -1
  13. package/dist/fkeybar.js +13 -0
  14. package/dist/fkeybar.js.map +1 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +148 -18
  17. package/dist/index.js.map +1 -1
  18. package/dist/layout/generator-css.d.ts +3 -0
  19. package/dist/layout/generator-css.d.ts.map +1 -0
  20. package/dist/layout/generator-css.js +202 -0
  21. package/dist/layout/generator-css.js.map +1 -0
  22. package/dist/layout/generator-js.d.ts +3 -0
  23. package/dist/layout/generator-js.d.ts.map +1 -0
  24. package/dist/layout/generator-js.js +353 -0
  25. package/dist/layout/generator-js.js.map +1 -0
  26. package/dist/layout/generator.d.ts +4 -0
  27. package/dist/layout/generator.d.ts.map +1 -0
  28. package/dist/layout/generator.js +124 -0
  29. package/dist/layout/generator.js.map +1 -0
  30. package/dist/layout/theme.d.ts +4 -0
  31. package/dist/layout/theme.d.ts.map +1 -0
  32. package/dist/layout/theme.js +28 -0
  33. package/dist/layout/theme.js.map +1 -0
  34. package/dist/layout/types.d.ts +68 -0
  35. package/dist/layout/types.d.ts.map +1 -0
  36. package/dist/layout/types.js +3 -0
  37. package/dist/layout/types.js.map +1 -0
  38. package/dist/quick/auto-layout.d.ts +5 -0
  39. package/dist/quick/auto-layout.d.ts.map +1 -0
  40. package/dist/quick/auto-layout.js +262 -0
  41. package/dist/quick/auto-layout.js.map +1 -0
  42. package/dist/quick/db/detect.d.ts +16 -0
  43. package/dist/quick/db/detect.d.ts.map +1 -0
  44. package/dist/quick/db/detect.js +131 -0
  45. package/dist/quick/db/detect.js.map +1 -0
  46. package/dist/quick/db/mongo.d.ts +10 -0
  47. package/dist/quick/db/mongo.d.ts.map +1 -0
  48. package/dist/quick/db/mongo.js +81 -0
  49. package/dist/quick/db/mongo.js.map +1 -0
  50. package/dist/quick/db/mysql.d.ts +8 -0
  51. package/dist/quick/db/mysql.d.ts.map +1 -0
  52. package/dist/quick/db/mysql.js +43 -0
  53. package/dist/quick/db/mysql.js.map +1 -0
  54. package/dist/quick/db/postgres.d.ts +8 -0
  55. package/dist/quick/db/postgres.d.ts.map +1 -0
  56. package/dist/quick/db/postgres.js +47 -0
  57. package/dist/quick/db/postgres.js.map +1 -0
  58. package/dist/quick/db/sqlite.d.ts +8 -0
  59. package/dist/quick/db/sqlite.d.ts.map +1 -0
  60. package/dist/quick/db/sqlite.js +43 -0
  61. package/dist/quick/db/sqlite.js.map +1 -0
  62. package/dist/quick/db-mode.d.ts +13 -0
  63. package/dist/quick/db-mode.d.ts.map +1 -0
  64. package/dist/quick/db-mode.js +159 -0
  65. package/dist/quick/db-mode.js.map +1 -0
  66. package/dist/quick/detect.d.ts +4 -0
  67. package/dist/quick/detect.d.ts.map +1 -0
  68. package/dist/quick/detect.js +76 -0
  69. package/dist/quick/detect.js.map +1 -0
  70. package/dist/quick/file-mode.d.ts +5 -0
  71. package/dist/quick/file-mode.d.ts.map +1 -0
  72. package/dist/quick/file-mode.js +158 -0
  73. package/dist/quick/file-mode.js.map +1 -0
  74. package/dist/quick/parsers/csv.d.ts +3 -0
  75. package/dist/quick/parsers/csv.d.ts.map +1 -0
  76. package/dist/quick/parsers/csv.js +145 -0
  77. package/dist/quick/parsers/csv.js.map +1 -0
  78. package/dist/quick/parsers/detect-meta.d.ts +7 -0
  79. package/dist/quick/parsers/detect-meta.d.ts.map +1 -0
  80. package/dist/quick/parsers/detect-meta.js +35 -0
  81. package/dist/quick/parsers/detect-meta.js.map +1 -0
  82. package/dist/quick/parsers/json.d.ts +3 -0
  83. package/dist/quick/parsers/json.d.ts.map +1 -0
  84. package/dist/quick/parsers/json.js +74 -0
  85. package/dist/quick/parsers/json.js.map +1 -0
  86. package/dist/quick/parsers/log.d.ts +3 -0
  87. package/dist/quick/parsers/log.d.ts.map +1 -0
  88. package/dist/quick/parsers/log.js +185 -0
  89. package/dist/quick/parsers/log.js.map +1 -0
  90. package/dist/quick/parsers/modsec.d.ts +3 -0
  91. package/dist/quick/parsers/modsec.d.ts.map +1 -0
  92. package/dist/quick/parsers/modsec.js +338 -0
  93. package/dist/quick/parsers/modsec.js.map +1 -0
  94. package/dist/quick/types.d.ts +90 -0
  95. package/dist/quick/types.d.ts.map +1 -0
  96. package/dist/quick/types.js +3 -0
  97. package/dist/quick/types.js.map +1 -0
  98. package/dist/quick/watch-mode.d.ts +3 -0
  99. package/dist/quick/watch-mode.d.ts.map +1 -0
  100. package/dist/quick/watch-mode.js +156 -0
  101. package/dist/quick/watch-mode.js.map +1 -0
  102. package/dist/server.js +2 -2
  103. package/dist/server.js.map +1 -1
  104. package/dist/types.d.ts +8 -1
  105. package/dist/types.d.ts.map +1 -1
  106. package/examples/demo.ts +134 -0
  107. package/examples/generate-access-log.ts +42 -0
  108. package/examples/screenshot-test.ts +105 -0
  109. package/examples/screenshot.png +0 -0
  110. package/frame-log.txt +830 -0
  111. package/package.json +10 -5
@@ -0,0 +1,47 @@
1
+ import { createRequire } from 'node:module';
2
+ import { join } from 'node:path';
3
+ import { detectMeta } from '../parsers/detect-meta.js';
4
+ // ─── Table name validation ───────────────────────────────────────────────────
5
+ const TABLE_NAME_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
6
+ function isTableName(query) {
7
+ return !query.includes(' ') && TABLE_NAME_RE.test(query);
8
+ }
9
+ // ─── Query ───────────────────────────────────────────────────────────────────
10
+ export async function queryPostgres(opts) {
11
+ const require = createRequire(join(process.cwd(), 'package.json'));
12
+ const pg = require('pg');
13
+ let sql;
14
+ if (isTableName(opts.query)) {
15
+ if (!TABLE_NAME_RE.test(opts.query)) {
16
+ throw new Error(`Invalid table name: "${opts.query}". Table names must match /^[a-zA-Z_][a-zA-Z0-9_]*$/`);
17
+ }
18
+ sql = `SELECT * FROM ${opts.query} LIMIT ${opts.limit}`;
19
+ }
20
+ else {
21
+ sql = opts.query;
22
+ }
23
+ const client = new pg.Client({
24
+ connectionString: opts.uri,
25
+ statement_timeout: 10000,
26
+ });
27
+ try {
28
+ await client.connect();
29
+ const result = await client.query(sql);
30
+ const columns = result.fields.map((f) => f.name);
31
+ const rows = result.rows;
32
+ const meta = detectMeta(columns, rows);
33
+ return {
34
+ type: 'table',
35
+ columns,
36
+ rows,
37
+ meta: {
38
+ totalRows: rows.length,
39
+ ...meta,
40
+ },
41
+ };
42
+ }
43
+ finally {
44
+ await client.end();
45
+ }
46
+ }
47
+ //# sourceMappingURL=postgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../../src/quick/db/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAUtD,gFAAgF;AAEhF,MAAM,aAAa,GAAG,0BAA0B,CAAA;AAEhD,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAC1D,CAAC;AAED,gFAAgF;AAEhF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAiB;IACnD,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC,CAAA;IAClE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAIrB,CAAA;IAEF,IAAI,GAAW,CAAA;IAEf,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,CAAC,KAAK,sDAAsD,CAAC,CAAA;QAC3G,CAAC;QACD,GAAG,GAAG,iBAAiB,IAAI,CAAC,KAAK,UAAU,IAAI,CAAC,KAAK,EAAE,CAAA;IACzD,CAAC;SAAM,CAAC;QACN,GAAG,GAAG,IAAI,CAAC,KAAK,CAAA;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,EAAE,CAAC,MAAM,CAAC;QAC3B,gBAAgB,EAAE,IAAI,CAAC,GAAG;QAC1B,iBAAiB,EAAE,KAAK;KACzB,CAAC,CAAA;IAEF,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,EAAE,CAAA;QACtB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAEtC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAChD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;QACxB,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QAEtC,OAAO;YACL,IAAI,EAAE,OAAO;YACb,OAAO;YACP,IAAI;YACJ,IAAI,EAAE;gBACJ,SAAS,EAAE,IAAI,CAAC,MAAM;gBACtB,GAAG,IAAI;aACR;SACF,CAAA;IACH,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,GAAG,EAAE,CAAA;IACpB,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { TableData } from '../types.js';
2
+ export interface SqliteQueryOpts {
3
+ filePath: string;
4
+ query: string;
5
+ limit: number;
6
+ }
7
+ export declare function querySqlite(opts: SqliteQueryOpts): Promise<TableData>;
8
+ //# sourceMappingURL=sqlite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../../src/quick/db/sqlite.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAK5C,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAYD,wBAAsB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,CA0C3E"}
@@ -0,0 +1,43 @@
1
+ import { createRequire } from 'node:module';
2
+ import { join } from 'node:path';
3
+ import { detectMeta } from '../parsers/detect-meta.js';
4
+ // ─── Table name validation ───────────────────────────────────────────────────
5
+ const TABLE_NAME_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
6
+ function isTableName(query) {
7
+ return !query.includes(' ') && TABLE_NAME_RE.test(query);
8
+ }
9
+ // ─── Query ───────────────────────────────────────────────────────────────────
10
+ export async function querySqlite(opts) {
11
+ const require = createRequire(join(process.cwd(), 'package.json'));
12
+ const Database = require('better-sqlite3');
13
+ let sql;
14
+ if (isTableName(opts.query)) {
15
+ if (!TABLE_NAME_RE.test(opts.query)) {
16
+ throw new Error(`Invalid table name: "${opts.query}". Table names must match /^[a-zA-Z_][a-zA-Z0-9_]*$/`);
17
+ }
18
+ sql = `SELECT * FROM ${opts.query} LIMIT ${opts.limit}`;
19
+ }
20
+ else {
21
+ sql = opts.query;
22
+ }
23
+ const db = new Database(opts.filePath, { readonly: true });
24
+ try {
25
+ const rows = db.prepare(sql).all();
26
+ // Derive columns from first row, or empty if no rows
27
+ const columns = rows.length > 0 ? Object.keys(rows[0]) : [];
28
+ const meta = detectMeta(columns, rows);
29
+ return {
30
+ type: 'table',
31
+ columns,
32
+ rows,
33
+ meta: {
34
+ totalRows: rows.length,
35
+ ...meta,
36
+ },
37
+ };
38
+ }
39
+ finally {
40
+ db.close();
41
+ }
42
+ }
43
+ //# sourceMappingURL=sqlite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../../src/quick/db/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAUtD,gFAAgF;AAEhF,MAAM,aAAa,GAAG,0BAA0B,CAAA;AAEhD,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAC1D,CAAC;AAED,gFAAgF;AAEhF,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAqB;IACrD,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC,CAAA;IAClE,MAAM,QAAQ,GAAG,OAAO,CAAC,gBAAgB,CAMxC,CAAA;IAED,IAAI,GAAW,CAAA;IAEf,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,CAAC,KAAK,sDAAsD,CAAC,CAAA;QAC3G,CAAC;QACD,GAAG,GAAG,iBAAiB,IAAI,CAAC,KAAK,UAAU,IAAI,CAAC,KAAK,EAAE,CAAA;IACzD,CAAC;SAAM,CAAC;QACN,GAAG,GAAG,IAAI,CAAC,KAAK,CAAA;IAClB,CAAC;IAED,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAE1D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;QAElC,qDAAqD;QACrD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAA4B,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACtF,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QAEtC,OAAO;YACL,IAAI,EAAE,OAAO;YACb,OAAO;YACP,IAAI;YACJ,IAAI,EAAE;gBACJ,SAAS,EAAE,IAAI,CAAC,MAAM;gBACtB,GAAG,IAAI;aACR;SACF,CAAA;IACH,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAA;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,13 @@
1
+ export interface DbModeOptions {
2
+ target: string;
3
+ uri?: string | undefined;
4
+ envVarName?: string | undefined;
5
+ query?: string | undefined;
6
+ sort?: string | undefined;
7
+ limit?: number | undefined;
8
+ watch?: boolean | undefined;
9
+ interval?: number | undefined;
10
+ columns?: string[] | undefined;
11
+ }
12
+ export declare function startDbMode(opts: DbModeOptions): Promise<void>;
13
+ //# sourceMappingURL=db-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-mode.d.ts","sourceRoot":"","sources":["../../src/quick/db-mode.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;CAC/B;AAqDD,wBAAsB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA+GpE"}
@@ -0,0 +1,159 @@
1
+ import { loadConfig } from '../config.js';
2
+ import { detectDbConnection } from './db/detect.js';
3
+ import { autoLayout, dataToWidgetData } from './auto-layout.js';
4
+ import tuimon from '../index.js';
5
+ function isQuery(target) {
6
+ const upper = target.trim().toUpperCase();
7
+ return upper.includes(' ') && /^(SELECT|INSERT|UPDATE|DELETE|WITH|EXPLAIN)\b/.test(upper);
8
+ }
9
+ function filterTableColumns(widgetData, columns) {
10
+ const result = { ...widgetData };
11
+ for (const [key, value] of Object.entries(result)) {
12
+ if (value && typeof value === 'object' && 'columns' in value && 'rows' in value) {
13
+ const table = value;
14
+ const filtered = {
15
+ columns: columns.filter((c) => table.columns.includes(c)),
16
+ rows: table.rows.map((row) => {
17
+ const r = {};
18
+ for (const c of columns) {
19
+ if (c in row)
20
+ r[c] = row[c];
21
+ }
22
+ return r;
23
+ }),
24
+ };
25
+ if (filtered.columns.length > 0)
26
+ result[key] = filtered;
27
+ }
28
+ }
29
+ return result;
30
+ }
31
+ async function executeQuery(type, opts, limit, uri) {
32
+ switch (type) {
33
+ case 'mongodb': {
34
+ const { queryMongo } = await import('./db/mongo.js');
35
+ return queryMongo({
36
+ uri,
37
+ collection: opts.target,
38
+ filter: opts.query,
39
+ sort: opts.sort,
40
+ limit,
41
+ });
42
+ }
43
+ case 'postgres': {
44
+ const { queryPostgres } = await import('./db/postgres.js');
45
+ return queryPostgres({ uri, query: opts.target, limit });
46
+ }
47
+ case 'mysql': {
48
+ const { queryMysql } = await import('./db/mysql.js');
49
+ return queryMysql({ uri, query: opts.target, limit });
50
+ }
51
+ case 'sqlite': {
52
+ const { querySqlite } = await import('./db/sqlite.js');
53
+ return querySqlite({ filePath: uri, query: opts.target, limit });
54
+ }
55
+ }
56
+ }
57
+ export async function startDbMode(opts) {
58
+ const config = loadConfig();
59
+ const limit = opts.limit ?? config.db.defaultLimit;
60
+ const watchInterval = opts.interval ?? config.db.watchInterval;
61
+ // Detect connection
62
+ let connection;
63
+ try {
64
+ connection = detectDbConnection({
65
+ uri: opts.uri,
66
+ envVarName: opts.envVarName,
67
+ configEnvVar: config.db.envVar,
68
+ configUri: config.db.uri,
69
+ });
70
+ }
71
+ catch (err) {
72
+ console.error(`[tuimon] ${err instanceof Error ? err.message : String(err)}`);
73
+ console.error('');
74
+ console.error(' Fix: set your connection string:');
75
+ console.error(' tuimon config db.envVar YOUR_DB_ENV_VAR');
76
+ console.error(' or: tuimon db <table> --uri "your://connection/string"');
77
+ console.error(' or: tuimon db <table> --env YOUR_ENV_VAR');
78
+ process.exit(1);
79
+ }
80
+ const { type, uri } = connection;
81
+ const dbLabel = type.charAt(0).toUpperCase() + type.slice(1);
82
+ const targetLabel = isQuery(opts.target) ? 'Query' : opts.target;
83
+ console.log(`[tuimon] Connecting to ${dbLabel}...`);
84
+ // Execute initial query
85
+ let data;
86
+ try {
87
+ data = await executeQuery(type, opts, limit, uri);
88
+ }
89
+ catch (err) {
90
+ console.error(`[tuimon] Query failed: ${err instanceof Error ? err.message : String(err)}`);
91
+ process.exit(1);
92
+ }
93
+ console.log(`[tuimon] ${data.meta.totalRows} rows from ${targetLabel}`);
94
+ // Build layouts
95
+ const overviewLayout = autoLayout(data, `${dbLabel}: ${targetLabel}`);
96
+ const tableLayout = {
97
+ title: `${dbLabel}: ${targetLabel}`,
98
+ panels: [{ id: '_table_full', label: 'All Data', type: 'table', span: 2 }],
99
+ };
100
+ let dash;
101
+ function getAllData() {
102
+ let d = dataToWidgetData(data);
103
+ d['_table_full'] = { columns: data.columns, rows: data.rows };
104
+ if (opts.columns)
105
+ d = filterTableColumns(d, opts.columns);
106
+ return d;
107
+ }
108
+ async function refresh() {
109
+ try {
110
+ data = await executeQuery(type, opts, limit, uri);
111
+ await dash.render(getAllData());
112
+ }
113
+ catch (err) {
114
+ console.error(`[tuimon] Query error: ${err instanceof Error ? err.message : String(err)}`);
115
+ }
116
+ }
117
+ const pages = {
118
+ overview: {
119
+ html: '',
120
+ default: true,
121
+ label: 'Overview',
122
+ layout: overviewLayout,
123
+ keys: {
124
+ F5: { label: 'Refresh', action: refresh },
125
+ F3: { label: 'Data Table [D]', action: () => { } },
126
+ F10: { label: 'Quit', action: () => process.exit(0) },
127
+ },
128
+ },
129
+ datatable: {
130
+ html: '',
131
+ shortcut: 'd',
132
+ label: 'Data Table',
133
+ layout: tableLayout,
134
+ keys: {
135
+ F5: { label: 'Refresh', action: refresh },
136
+ F10: { label: 'Quit', action: () => process.exit(0) },
137
+ },
138
+ },
139
+ };
140
+ if (opts.watch) {
141
+ dash = await tuimon.start({
142
+ pages: pages,
143
+ refresh: watchInterval,
144
+ data: async () => {
145
+ data = await executeQuery(type, opts, limit, uri);
146
+ return getAllData();
147
+ },
148
+ renderDelay: 0,
149
+ });
150
+ }
151
+ else {
152
+ dash = await tuimon.start({
153
+ pages: pages,
154
+ renderDelay: 0,
155
+ });
156
+ await dash.render(getAllData());
157
+ }
158
+ }
159
+ //# sourceMappingURL=db-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-mode.js","sourceRoot":"","sources":["../../src/quick/db-mode.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,kBAAkB,EAAe,MAAM,gBAAgB,CAAA;AAChE,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAC/D,OAAO,MAAM,MAAM,aAAa,CAAA;AAchC,SAAS,OAAO,CAAC,MAAc;IAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACzC,OAAO,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,+CAA+C,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAC3F,CAAC;AAED,SAAS,kBAAkB,CAAC,UAAmC,EAAE,OAAiB;IAChF,MAAM,MAAM,GAA4B,EAAE,GAAG,UAAU,EAAE,CAAA;IACzD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,SAAS,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;YAChF,MAAM,KAAK,GAAG,KAA+D,CAAA;YAC7E,MAAM,QAAQ,GAAG;gBACf,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACzD,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;oBAC3B,MAAM,CAAC,GAA4B,EAAE,CAAA;oBACrC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;wBAAC,IAAI,CAAC,IAAI,GAAG;4BAAE,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAA;oBAAC,CAAC;oBACxD,OAAO,CAAC,CAAA;gBACV,CAAC,CAAC;aACH,CAAA;YACD,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;gBAAE,MAAM,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAA;QACzD,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAY,EAAE,IAAmB,EAAE,KAAa,EAAE,GAAW;IACvF,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAA;YACpD,OAAO,UAAU,CAAC;gBAChB,GAAG;gBACH,UAAU,EAAE,IAAI,CAAC,MAAM;gBACvB,MAAM,EAAE,IAAI,CAAC,KAAK;gBAClB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK;aACN,CAAC,CAAA;QACJ,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;YAC1D,OAAO,aAAa,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;QAC1D,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAA;YACpD,OAAO,UAAU,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;QACvD,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;YACtD,OAAO,WAAW,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;QAClE,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAmB;IACnD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,EAAE,CAAC,YAAY,CAAA;IAClD,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,EAAE,CAAC,aAAa,CAAA;IAE9D,oBAAoB;IACpB,IAAI,UAAU,CAAA;IACd,IAAI,CAAC;QACH,UAAU,GAAG,kBAAkB,CAAC;YAC9B,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,YAAY,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM;YAC9B,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG;SACzB,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC7E,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACjB,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAA;QACnD,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAA;QAC5D,OAAO,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAA;QAC3E,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAA;QAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,UAAU,CAAA;IAChC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC5D,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAA;IAEhE,OAAO,CAAC,GAAG,CAAC,0BAA0B,OAAO,KAAK,CAAC,CAAA;IAEnD,wBAAwB;IACxB,IAAI,IAAe,CAAA;IACnB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAA;IACnD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,0BAA0B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC3F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,SAAS,cAAc,WAAW,EAAE,CAAC,CAAA;IAEvE,gBAAgB;IAChB,MAAM,cAAc,GAAG,UAAU,CAAC,IAAI,EAAE,GAAG,OAAO,KAAK,WAAW,EAAE,CAAC,CAAA;IACrE,MAAM,WAAW,GAAiB;QAChC,KAAK,EAAE,GAAG,OAAO,KAAK,WAAW,EAAE;QACnC,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,OAA+B,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;KACnG,CAAA;IAED,IAAI,IAAqB,CAAA;IAEzB,SAAS,UAAU;QACjB,IAAI,CAAC,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAA;QAC9B,CAAC,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAA;QAC7D,IAAI,IAAI,CAAC,OAAO;YAAE,CAAC,GAAG,kBAAkB,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;QACzD,OAAO,CAAC,CAAA;IACV,CAAC;IAED,KAAK,UAAU,OAAO;QACpB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAA;YACjD,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAA;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC5F,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAIN;QACH,QAAQ,EAAE;YACR,IAAI,EAAE,EAAE;YACR,OAAO,EAAE,IAAI;YACb,KAAK,EAAE,UAAU;YACjB,MAAM,EAAE,cAAc;YACtB,IAAI,EAAE;gBACJ,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;gBACzC,EAAE,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE;gBACjD,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;aACtD;SACF;QACD,SAAS,EAAE;YACT,IAAI,EAAE,EAAE;YACR,QAAQ,EAAE,GAAG;YACb,KAAK,EAAE,YAAY;YACnB,MAAM,EAAE,WAAW;YACnB,IAAI,EAAE;gBACJ,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;gBACzC,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;aACtD;SACF;KACF,CAAA;IAED,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,IAAI,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;YACxB,KAAK,EAAE,KAAoD;YAC3D,OAAO,EAAE,aAAa;YACtB,IAAI,EAAE,KAAK,IAAI,EAAE;gBACf,IAAI,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAA;gBACjD,OAAO,UAAU,EAAE,CAAA;YACrB,CAAC;YACD,WAAW,EAAE,CAAC;SACf,CAAC,CAAA;IACJ,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;YACxB,KAAK,EAAE,KAAoD;YAC3D,WAAW,EAAE,CAAC;SACf,CAAC,CAAA;QACF,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAA;IACjC,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { InputType } from './types.js';
2
+ export declare function detectInputType(input: string): InputType;
3
+ export declare function detectLogFormat(content: string): 'nginx' | 'modsec' | 'json' | 'plain';
4
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/quick/detect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CA6BxD;AA2BD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAqBtF"}
@@ -0,0 +1,76 @@
1
+ import { readFileSync } from 'node:fs';
2
+ export function detectInputType(input) {
3
+ // URL
4
+ if (input.startsWith('http://') || input.startsWith('https://'))
5
+ return 'url';
6
+ // stdin
7
+ if (input === '-')
8
+ return 'stdin';
9
+ // By file extension
10
+ const ext = input.split('.').pop()?.toLowerCase() ?? '';
11
+ switch (ext) {
12
+ case 'json':
13
+ case 'jsonl':
14
+ return 'json';
15
+ case 'csv':
16
+ case 'tsv':
17
+ return 'csv';
18
+ case 'js':
19
+ case 'ts':
20
+ case 'mjs':
21
+ case 'mts':
22
+ return 'module';
23
+ case 'log':
24
+ case 'txt':
25
+ return 'log';
26
+ default:
27
+ // Try content-based detection
28
+ return detectByContent(input);
29
+ }
30
+ }
31
+ function detectByContent(filePath) {
32
+ try {
33
+ const head = readFileSync(filePath, 'utf-8').slice(0, 4096);
34
+ // ModSecurity audit log
35
+ if (/--[a-f0-9]+-A--/i.test(head))
36
+ return 'log';
37
+ // JSON
38
+ const trimmed = head.trimStart();
39
+ if (trimmed.startsWith('{') || trimmed.startsWith('['))
40
+ return 'json';
41
+ // CSV (has commas/tabs in most lines)
42
+ const lines = head.split('\n').filter((l) => l.trim());
43
+ if (lines.length >= 2) {
44
+ const commas = lines.slice(0, 5).filter((l) => l.includes(',')).length;
45
+ if (commas >= 3)
46
+ return 'csv';
47
+ }
48
+ // Default to log
49
+ return 'log';
50
+ }
51
+ catch {
52
+ return 'log';
53
+ }
54
+ }
55
+ export function detectLogFormat(content) {
56
+ const head = content.slice(0, 4096);
57
+ // ModSecurity audit log sections
58
+ if (/--[a-f0-9]+-A--/i.test(head))
59
+ return 'modsec';
60
+ // Nginx combined log format
61
+ const nginxPattern = /^\S+ \S+ \S+ \[[^\]]+\] "\S+ \S+ [^"]*" \d+ \d+/;
62
+ const lines = head.split('\n').filter((l) => l.trim());
63
+ if (lines.length > 0 && nginxPattern.test(lines[0] ?? ''))
64
+ return 'nginx';
65
+ // JSON lines
66
+ const firstLine = (lines[0] ?? '').trim();
67
+ if (firstLine.startsWith('{') && firstLine.endsWith('}')) {
68
+ try {
69
+ JSON.parse(firstLine);
70
+ return 'json';
71
+ }
72
+ catch { /* not json */ }
73
+ }
74
+ return 'plain';
75
+ }
76
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/quick/detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface FileModeOptions {
2
+ columns?: string[] | undefined;
3
+ }
4
+ export declare function startFileMode(filePath: string, opts?: FileModeOptions): Promise<void>;
5
+ //# sourceMappingURL=file-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-mode.d.ts","sourceRoot":"","sources":["../../src/quick/file-mode.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;CAC/B;AAgFD,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAiF3F"}
@@ -0,0 +1,158 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { watch } from 'chokidar';
3
+ import { detectInputType, detectLogFormat } from './detect.js';
4
+ import { parseJsonFile } from './parsers/json.js';
5
+ import { parseCsvFile } from './parsers/csv.js';
6
+ import { parseLogFile } from './parsers/log.js';
7
+ import { parseModSecFile } from './parsers/modsec.js';
8
+ import { autoLayout, dataToWidgetData } from './auto-layout.js';
9
+ import tuimon from '../index.js';
10
+ function parseFile(filePath) {
11
+ const inputType = detectInputType(filePath);
12
+ switch (inputType) {
13
+ case 'json':
14
+ return parseJsonFile(filePath);
15
+ case 'csv':
16
+ return parseCsvFile(filePath);
17
+ case 'log': {
18
+ // Read once, detect format, then parse (avoids double-read)
19
+ const format = detectLogFormat(readFileSync(filePath, 'utf-8').slice(0, 4096));
20
+ if (format === 'modsec')
21
+ return parseModSecFile(filePath);
22
+ return parseLogFile(filePath);
23
+ }
24
+ default:
25
+ return parseLogFile(filePath);
26
+ }
27
+ }
28
+ function hasTableData(data) {
29
+ return data.type === 'table'
30
+ || (data.type === 'log' && data.format === 'nginx')
31
+ || data.type === 'modsec';
32
+ }
33
+ function getFullTableData(data) {
34
+ if (data.type === 'table') {
35
+ return { _table_full: { columns: data.columns, rows: data.rows } };
36
+ }
37
+ if (data.type === 'log' && data.format === 'nginx') {
38
+ return {
39
+ _table_full: {
40
+ columns: ['Timestamp', 'IP', 'Method', 'Path', 'Status', 'Bytes'],
41
+ rows: data.entries.map((e) => ({
42
+ Timestamp: e.timestamp ?? '', IP: e.ip ?? '', Method: e.method ?? '',
43
+ Path: e.path ?? '', Status: e.status ?? 0, Bytes: e.bytes ?? 0,
44
+ })),
45
+ },
46
+ };
47
+ }
48
+ if (data.type === 'modsec') {
49
+ return {
50
+ _table_full: {
51
+ columns: ['Time', 'IP', 'Method', 'URI', 'Code', 'Rule', 'Severity', 'Message'],
52
+ rows: data.events.map((e) => ({
53
+ Time: e.timestamp, IP: e.clientIp, Method: e.method, URI: e.uri,
54
+ Code: e.httpCode, Rule: e.messages[0]?.id ?? '',
55
+ Severity: e.messages[0]?.severity ?? '', Message: e.messages[0]?.msg ?? '',
56
+ })),
57
+ },
58
+ };
59
+ }
60
+ return {};
61
+ }
62
+ function filterTableColumns(widgetData, columns) {
63
+ const result = { ...widgetData };
64
+ for (const [key, value] of Object.entries(result)) {
65
+ if (value && typeof value === 'object' && 'columns' in value && 'rows' in value) {
66
+ const table = value;
67
+ const filtered = {
68
+ columns: columns.filter((c) => table.columns.includes(c)),
69
+ rows: table.rows.map((row) => {
70
+ const r = {};
71
+ for (const c of columns) {
72
+ if (c in row)
73
+ r[c] = row[c];
74
+ }
75
+ return r;
76
+ }),
77
+ };
78
+ if (filtered.columns.length > 0)
79
+ result[key] = filtered;
80
+ }
81
+ }
82
+ return result;
83
+ }
84
+ function titleFromFilename(filePath) {
85
+ const name = filePath.split('/').pop()?.split('\\').pop() ?? 'Data';
86
+ return name.replace(/\.[^.]+$/, '').replace(/[-_]/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
87
+ }
88
+ export async function startFileMode(filePath, opts) {
89
+ const columns = opts?.columns;
90
+ let data = parseFile(filePath);
91
+ const title = titleFromFilename(filePath);
92
+ const overviewLayout = autoLayout(data, filePath);
93
+ const showTable = hasTableData(data);
94
+ let dash;
95
+ // Always merge overview + table data so both pages can render
96
+ function getAllData() {
97
+ let d = dataToWidgetData(data);
98
+ if (showTable)
99
+ d = { ...d, ...getFullTableData(data) };
100
+ if (columns)
101
+ d = filterTableColumns(d, columns);
102
+ return d;
103
+ }
104
+ function reload() {
105
+ data = parseFile(filePath);
106
+ }
107
+ const pages = {
108
+ overview: {
109
+ html: '',
110
+ default: true,
111
+ label: 'Overview',
112
+ layout: overviewLayout,
113
+ keys: {
114
+ F5: { label: 'Reload', action: async () => { reload(); await dash.render(getAllData()); } },
115
+ F10: { label: 'Quit', action: () => { void watcher.close().then(() => process.exit(0)); } },
116
+ },
117
+ },
118
+ };
119
+ if (showTable) {
120
+ pages['datatable'] = {
121
+ html: '',
122
+ shortcut: 'd',
123
+ label: 'Data Table',
124
+ layout: {
125
+ title: `${title} — Data`,
126
+ panels: [{ id: '_table_full', label: 'All Data', type: 'table', span: 2 }],
127
+ },
128
+ keys: {
129
+ F5: { label: 'Reload', action: async () => { reload(); await dash.render(getAllData()); } },
130
+ F10: { label: 'Quit', action: () => { void watcher.close().then(() => process.exit(0)); } },
131
+ },
132
+ };
133
+ pages['overview'].keys['F3'] = {
134
+ label: 'Data Table [D]',
135
+ action: () => { }, // hint only — D shortcut handles navigation
136
+ };
137
+ }
138
+ dash = await tuimon.start({
139
+ pages: pages,
140
+ renderDelay: 0,
141
+ });
142
+ await dash.render(getAllData());
143
+ const watcher = watch(filePath, {
144
+ ignoreInitial: true,
145
+ awaitWriteFinish: { stabilityThreshold: 200 },
146
+ });
147
+ watcher.on('change', async () => {
148
+ try {
149
+ reload();
150
+ await dash.render(getAllData());
151
+ }
152
+ catch (err) {
153
+ console.error('[tuimon] file reload error:', err);
154
+ }
155
+ });
156
+ process.once('beforeExit', () => { void watcher.close(); });
157
+ }
158
+ //# sourceMappingURL=file-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-mode.js","sourceRoot":"","sources":["../../src/quick/file-mode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { TableData } from '../types.js';
2
+ export declare function parseCsvFile(filePath: string): TableData;
3
+ //# sourceMappingURL=csv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csv.d.ts","sourceRoot":"","sources":["../../../src/quick/parsers/csv.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAQ5C,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CA6DxD"}