geotechcli 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,209 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { createInterface } from 'node:readline/promises';
4
+ import { stdin as input, stdout as output } from 'node:process';
5
+ import { banner, heading, renderChart, renderMultiChart, renderXYPlot, warn, } from '../ui/terminal.js';
6
+ import { buildAtterbergChart, buildMohrCircleChart, loadVisualizationSource, } from '../util/viz.js';
7
+ function summarizeDomain(values) {
8
+ if (values.length === 0) {
9
+ return 'No samples';
10
+ }
11
+ const min = Math.min(...values);
12
+ const max = Math.max(...values);
13
+ return `${min.toFixed(2)} to ${max.toFixed(2)} (${values.length} samples)`;
14
+ }
15
+ function renderVisualization(chart, height) {
16
+ heading(chart.title);
17
+ if (chart.kind === 'xy') {
18
+ console.log(chalk.gray(` X-axis: ${chart.xLabel}${chart.xScale === 'log10' ? ' (log scale)' : ''}`));
19
+ console.log(chalk.gray(` Y-axis: ${chart.yLabel}`));
20
+ if (chart.note) {
21
+ console.log(chalk.gray(` ${chart.note}`));
22
+ }
23
+ renderXYPlot(chart.xySeries ?? [], {
24
+ height,
25
+ title: chart.title,
26
+ xLabel: chart.xLabel,
27
+ yLabel: chart.yLabel,
28
+ xScale: chart.xScale,
29
+ xDomain: chart.xDomain,
30
+ yDomain: chart.yDomain,
31
+ invertY: chart.invertY,
32
+ });
33
+ return;
34
+ }
35
+ const xValues = chart.xValues ?? [];
36
+ const series = chart.series ?? [];
37
+ const labels = chart.labels ?? [];
38
+ console.log(chalk.gray(` X-axis: ${chart.xLabel} | Domain: ${summarizeDomain(xValues)}`));
39
+ console.log(chalk.gray(` Y-axis: ${chart.yLabel}`));
40
+ if (chart.note) {
41
+ console.log(chalk.gray(` ${chart.note}`));
42
+ }
43
+ if (series.length > 1) {
44
+ renderMultiChart(series, labels, {
45
+ height,
46
+ title: `${chart.title} (${chart.xLabel})`,
47
+ });
48
+ }
49
+ else if (series[0]) {
50
+ renderChart(series[0], {
51
+ height,
52
+ label: `${labels[0] ?? chart.yLabel} (${chart.xLabel})`,
53
+ });
54
+ }
55
+ }
56
+ function printChartCatalog(charts) {
57
+ console.log('');
58
+ console.log(chalk.cyan(' Available charts:'));
59
+ charts.forEach((chart, index) => {
60
+ console.log(chalk.gray(` ${String(index + 1).padStart(2, ' ')}. `) + chalk.white(chart.id) + chalk.gray(` - ${chart.title}`));
61
+ });
62
+ console.log('');
63
+ }
64
+ async function browseChartsInteractively(charts, height) {
65
+ const rl = createInterface({ input, output });
66
+ try {
67
+ while (true) {
68
+ printChartCatalog(charts);
69
+ const answer = (await rl.question(' Select chart number, "a" for all, or "q" to quit: ')).trim().toLowerCase();
70
+ if (answer === 'q') {
71
+ console.log('');
72
+ break;
73
+ }
74
+ if (answer === 'a') {
75
+ for (const chart of charts) {
76
+ renderVisualization(chart, height);
77
+ }
78
+ continue;
79
+ }
80
+ const selectedIndex = Number(answer);
81
+ if (!Number.isInteger(selectedIndex) || selectedIndex < 1 || selectedIndex > charts.length) {
82
+ warn(`Invalid selection "${answer}".`);
83
+ continue;
84
+ }
85
+ renderVisualization(charts[selectedIndex - 1], height);
86
+ }
87
+ }
88
+ finally {
89
+ rl.close();
90
+ }
91
+ }
92
+ function loadPresetSource(preset, opts) {
93
+ switch (preset) {
94
+ case 'mohr':
95
+ case 'mohr-circle':
96
+ return {
97
+ sourceType: 'preset',
98
+ sourceName: 'mohr-circle',
99
+ charts: [
100
+ buildMohrCircleChart({
101
+ sigma1: Number(opts.sigma1),
102
+ sigma3: Number(opts.sigma3),
103
+ cohesion: opts.cohesion !== undefined ? Number(opts.cohesion) : undefined,
104
+ frictionAngle: opts.phi !== undefined ? Number(opts.phi) : undefined,
105
+ }),
106
+ ],
107
+ };
108
+ case 'atterberg':
109
+ case 'plasticity':
110
+ return {
111
+ sourceType: 'preset',
112
+ sourceName: 'atterberg',
113
+ charts: [
114
+ buildAtterbergChart({
115
+ liquidLimit: Number(opts.ll),
116
+ plasticityIndex: opts.pi !== undefined ? Number(opts.pi) : undefined,
117
+ plasticLimit: opts.pl !== undefined ? Number(opts.pl) : undefined,
118
+ }),
119
+ ],
120
+ };
121
+ default:
122
+ throw new Error(`Unsupported preset "${preset}". Use mohr-circle or atterberg.`);
123
+ }
124
+ }
125
+ export function registerVizCommand(program) {
126
+ const cmd = new Command('viz')
127
+ .description('Interactive terminal visualization for saved data, engineering presets, and geotechnical chart templates')
128
+ .argument('[file]', 'Visualization source file (.json, .csv, .xlsx)')
129
+ .option('--chart <id>', 'Render a specific chart id directly')
130
+ .option('--list', 'List available charts without rendering')
131
+ .option('--all', 'Render all detected charts')
132
+ .option('--sheet <name>', 'Workbook sheet name for .xlsx inputs')
133
+ .option('--x <column>', 'Override the X-axis column for tabular inputs')
134
+ .option('--y <columns>', 'Comma-separated Y columns for tabular inputs')
135
+ .option('--height <rows>', 'Chart height in terminal rows', (value) => parseInt(value, 10), 12)
136
+ .option('--template <name>', 'File template: compaction | gradation | cpt')
137
+ .option('--preset <name>', 'Preset chart: mohr-circle | atterberg')
138
+ .option('--sigma1 <kPa>', 'Major principal stress for Mohr circle preset', (value) => parseFloat(value))
139
+ .option('--sigma3 <kPa>', 'Minor principal stress for Mohr circle preset', (value) => parseFloat(value))
140
+ .option('--cohesion <kPa>', 'Cohesion intercept for Mohr-Coulomb envelope', (value) => parseFloat(value))
141
+ .option('--phi <deg>', 'Friction angle for Mohr-Coulomb envelope', (value) => parseFloat(value))
142
+ .option('--ll <percent>', 'Liquid limit for Atterberg plasticity chart', (value) => parseFloat(value))
143
+ .option('--pl <percent>', 'Plastic limit for Atterberg plasticity chart', (value) => parseFloat(value))
144
+ .option('--pi <percent>', 'Plasticity index for Atterberg plasticity chart', (value) => parseFloat(value))
145
+ .addHelpText('after', `
146
+ Examples:
147
+ geotech viz samples/visualization/geotech-viz-showcase.csv
148
+ geotech viz samples/visualization/geotech-viz-showcase.xlsx --sheet settlement_profile
149
+ geotech viz samples/visualization/geotech-viz-compaction.csv --template compaction
150
+ geotech viz samples/visualization/geotech-viz-gradation.csv --template gradation
151
+ geotech viz output/liquefaction.json --list
152
+ geotech viz --preset mohr-circle --sigma1 250 --sigma3 90 --cohesion 15 --phi 28
153
+ geotech viz --preset atterberg --ll 55 --pl 25
154
+ `)
155
+ .action(async (filePath, opts) => {
156
+ if (opts.preset && filePath) {
157
+ throw new Error('Use either a <file> input or --preset, not both at the same time.');
158
+ }
159
+ if (!opts.preset && !filePath) {
160
+ throw new Error('Provide a visualization file or use --preset for a built-in engineering chart.');
161
+ }
162
+ const yColumns = typeof opts.y === 'string'
163
+ ? opts.y.split(',').map((value) => value.trim()).filter((value) => value.length > 0)
164
+ : undefined;
165
+ const source = opts.preset
166
+ ? loadPresetSource(String(opts.preset).toLowerCase(), opts)
167
+ : await loadVisualizationSource(filePath, {
168
+ sheetName: opts.sheet,
169
+ xColumn: opts.x,
170
+ yColumns,
171
+ template: opts.template,
172
+ });
173
+ if (source.charts.length === 0) {
174
+ if (opts.template) {
175
+ throw new Error(`No chartable data found in ${filePath} for template "${opts.template}".`);
176
+ }
177
+ throw new Error(`No chartable data found in ${filePath}. Save JSON output from a supported command, or provide numeric CSV/XLSX columns.`);
178
+ }
179
+ banner();
180
+ console.log(chalk.gray(` Source: ${opts.preset ? `preset:${opts.preset}` : filePath} (${source.sourceType.toUpperCase()})`));
181
+ console.log(chalk.gray(` Charts detected: ${source.charts.length}`));
182
+ if (opts.list) {
183
+ printChartCatalog(source.charts);
184
+ return;
185
+ }
186
+ if (typeof opts.chart === 'string') {
187
+ const match = source.charts.find((chart) => chart.id === opts.chart);
188
+ if (!match) {
189
+ throw new Error(`Chart "${opts.chart}" not found. Run "geotech viz ${filePath ?? `--preset ${opts.preset}`} --list" to inspect available chart ids.`);
190
+ }
191
+ renderVisualization(match, opts.height);
192
+ return;
193
+ }
194
+ if (opts.all || source.charts.length === 1 || !input.isTTY) {
195
+ if (!input.isTTY && source.charts.length > 1 && !opts.all) {
196
+ warn('Interactive mode is unavailable in this shell. Rendering the first chart only.');
197
+ renderVisualization(source.charts[0], opts.height);
198
+ return;
199
+ }
200
+ for (const chart of source.charts) {
201
+ renderVisualization(chart, opts.height);
202
+ }
203
+ return;
204
+ }
205
+ await browseChartsInteractively(source.charts, opts.height);
206
+ });
207
+ program.addCommand(cmd);
208
+ }
209
+ //# sourceMappingURL=viz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viz.js","sourceRoot":"","sources":["../../src/commands/viz.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ import { registerSlopeCommand } from './commands/slope.js';
15
15
  import { registerRetainingCommand } from './commands/retaining.js';
16
16
  import { registerSettlementCommands } from './commands/settlement.js';
17
17
  import { registerSeepageCommand } from './commands/seepage.js';
18
+ import { registerVizCommand } from './commands/viz.js';
18
19
  import { registerVisionCommand, registerAIClassifyCommand, registerGBRCommand, registerAgentCommand, registerReportCommand, registerChatCommand, } from './commands/ai.js';
19
20
  const program = new Command();
20
21
  program
@@ -37,6 +38,7 @@ registerRetainingCommand(program);
37
38
  registerSettlementCommands(program);
38
39
  // Seepage
39
40
  registerSeepageCommand(program);
41
+ registerVizCommand(program);
40
42
  // Tunnel engineering
41
43
  registerTunnelCommands(program);
42
44
  // ---------------------------------------------------------------------------
@@ -54,9 +56,10 @@ registerBridgeCommand(program);
54
56
  // System
55
57
  registerConfigCommand(program);
56
58
  registerStatusCommand(program);
57
- // Show banner when invoked with no arguments
59
+ // Show help when invoked with no arguments and exit cleanly.
58
60
  if (process.argv.length <= 2) {
59
- banner();
61
+ program.outputHelp();
62
+ process.exit(0);
60
63
  }
61
64
  // ---------------------------------------------------------------------------
62
65
  // Error handling — never leak API keys in stack traces
@@ -70,6 +73,9 @@ catch (err) {
70
73
  if ('exitCode' in err && err.exitCode === 0) {
71
74
  process.exit(0);
72
75
  }
76
+ if ('code' in err && err.code === 'commander.helpDisplayed') {
77
+ process.exit(0);
78
+ }
73
79
  const msg = err.message.replace(/(?:Bearer |sk-|zhipu-|api[_-]?key[=: ]*)[^\s"'\]},]*/gi, '***REDACTED***');
74
80
  console.error(`\n Error: ${msg}\n`);
75
81
  process.exit(1);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,13 @@
1
+ export interface XYPoint {
2
+ x: number;
3
+ y: number;
4
+ }
5
+ export interface XYSeriesSpec {
6
+ label: string;
7
+ points: XYPoint[];
8
+ style?: 'line' | 'scatter';
9
+ symbol?: string;
10
+ }
1
11
  export declare function banner(): void;
2
12
  export declare function heading(text: string): void;
3
13
  export declare function success(text: string): void;
@@ -10,12 +20,22 @@ export declare function renderTable(headers: string[], rows: (string | number)[]
10
20
  export declare function renderChart(data: number[], options?: {
11
21
  height?: number;
12
22
  label?: string;
13
- colors?: readonly string[];
14
23
  }): void;
15
24
  export declare function renderMultiChart(series: number[][], labels: string[], options?: {
16
25
  height?: number;
17
26
  title?: string;
18
27
  }): void;
28
+ export declare function renderXYPlot(series: XYSeriesSpec[], options?: {
29
+ height?: number;
30
+ width?: number;
31
+ title?: string;
32
+ xLabel?: string;
33
+ yLabel?: string;
34
+ xScale?: 'linear' | 'log10';
35
+ xDomain?: [number, number];
36
+ yDomain?: [number, number];
37
+ invertY?: boolean;
38
+ }): void;
19
39
  export declare function renderSteps(steps: string[], verbose: boolean): void;
20
40
  export declare function renderJSON(data: unknown): void;
21
41
  //# sourceMappingURL=terminal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/ui/terminal.ts"],"names":[],"mappings":"AAQA,wBAAgB,MAAM,IAAI,IAAI,CAmB7B;AAGD,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI1C;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvC;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAExC;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvC;AAED,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEtC;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMlE;AAMD,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EAAE,GAC1B,IAAI,CAyCN;AAMD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACxE,IAAI,CAgBN;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EAAE,EAAE,EAClB,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C,IAAI,CA8BN;AAMD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAQnE;AAMD,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAY9C"}
1
+ {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/ui/terminal.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,OAAO;IACtB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAWD,wBAAgB,MAAM,IAAI,IAAI,CAU7B;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI1C;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvC;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAExC;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvC;AAED,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEtC;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMlE;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EAAE,GAAG,IAAI,CA8BhF;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C,IAAI,CAgBN;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EAAE,EAAE,EAClB,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C,IAAI,CA0BN;AAoCD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,YAAY,EAAE,EACtB,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACA,IAAI,CA4GN;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAQnE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAW9C"}
@@ -1,94 +1,70 @@
1
1
  import chalk from 'chalk';
2
2
  import * as asciichart from 'asciichart';
3
3
  import { GEOTECHCLI_VERSION } from '@geotechcli/core';
4
- // ---------------------------------------------------------------------------
5
- // Branded output
6
- // ---------------------------------------------------------------------------
4
+ function stripAnsi(value) {
5
+ return value.replace(/\x1b\[[0-9;]*m/g, '');
6
+ }
7
+ function pad(value, width) {
8
+ const visible = stripAnsi(value).length;
9
+ return `${value}${' '.repeat(Math.max(0, width - visible))}`;
10
+ }
7
11
  export function banner() {
8
- const c = chalk.bold.cyan;
9
- const w = chalk.bold.white;
10
- const g = chalk.gray;
11
12
  console.log('');
12
- console.log(c(' ██████╗ ███████╗ ██████╗ ████████╗███████╗ ██████╗██╗ ██╗ ██████╗██╗ ██╗'));
13
- console.log(c(' ██╔════╝ ██╔════╝██╔═══██╗╚══██╔══╝██╔════╝██╔════╝██║ ██║██╔════╝██║ ██║'));
14
- console.log(w(' ██║ ███╗█████╗ ██║ ██║ ██║ █████╗ ██║ ███████║██║ ██║ ██║'));
15
- console.log(w(' ██║ ██║██╔══╝ ██║ ██║ ██║ ██╔══╝ ██║ ██╔══██║██║ ██║ ██║'));
16
- console.log(c(' ╚██████╔╝███████╗╚██████╔╝ ██║ ███████╗╚██████╗██║ ██║╚██████╗███████╗██║'));
17
- console.log(c(' ╚═════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝╚══════╝╚═╝'));
18
- console.log('');
19
- console.log(g(' v') + chalk.cyan(GEOTECHCLI_VERSION) +
20
- g(' · AI-native geotechnical engineering · ') +
21
- chalk.dim('https://beta.geotechcli.com'));
13
+ console.log(chalk.bold.cyan(' ██████╗ ███████╗ ██████╗ ████████╗███████╗ ██████╗██╗ ██╗ ██████╗██╗ ██╗'));
14
+ console.log(chalk.bold.cyan(' ██╔════╝ ██╔════╝██╔═══██╗╚══██╔══╝██╔════╝██╔════╝██║ ██║██╔════╝██║ ██║'));
15
+ console.log(chalk.bold.white(' ██║ ███╗█████╗ ██║ ██║ ██║ █████╗ ██║ ███████║██║ ██║ ██║'));
16
+ console.log(chalk.bold.white(' ██║ ██║██╔══╝ ██║ ██║ ██║ ██╔══╝ ██║ ██╔══██║██║ ██║ ██║'));
17
+ console.log(chalk.bold.cyan(' ╚██████╔╝███████╗╚██████╔╝ ██║ ███████╗╚██████╗██║ ██║╚██████╗███████╗██║'));
18
+ console.log(chalk.bold.cyan(' ╚═════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝╚══════╝╚═╝'));
19
+ console.log(chalk.gray(` v${GEOTECHCLI_VERSION} | AI-native geotechnical engineering | https://beta.geotechcli.com`));
22
20
  console.log('');
23
21
  }
24
22
  export function heading(text) {
25
23
  console.log('');
26
24
  console.log(chalk.bold.white(` ${text}`));
27
- console.log(chalk.gray(' ' + '─'.repeat(Math.min(text.length + 4, 60))));
25
+ console.log(chalk.gray(` ${'-'.repeat(Math.min(text.length + 4, 60))}`));
28
26
  }
29
27
  export function success(text) {
30
- console.log(chalk.green(' ✓ ') + text);
28
+ console.log(chalk.green(` OK ${text}`));
31
29
  }
32
30
  export function warn(text) {
33
- console.log(chalk.yellow(' ⚠ ') + text);
31
+ console.log(chalk.yellow(` WARN ${text}`));
34
32
  }
35
33
  export function error(text) {
36
- console.log(chalk.red(' ✗ ') + text);
34
+ console.log(chalk.red(` ERR ${text}`));
37
35
  }
38
36
  export function info(text) {
39
- console.log(chalk.blue(' ℹ ') + text);
37
+ console.log(chalk.blue(` INFO ${text}`));
40
38
  }
41
39
  export function dim(text) {
42
40
  console.log(chalk.gray(` ${text}`));
43
41
  }
44
42
  export function keyValue(key, value) {
45
43
  console.log(chalk.gray(' ') +
46
- chalk.white.bold(key.padEnd(28)) +
44
+ chalk.white.bold(pad(key, 28)) +
47
45
  chalk.cyan(String(value)));
48
46
  }
49
- // ---------------------------------------------------------------------------
50
- // Tables
51
- // ---------------------------------------------------------------------------
52
47
  export function renderTable(headers, rows) {
53
- // Calculate column widths (strip ANSI for measurement)
54
- const stripAnsi = (s) => s.replace(/\x1b\[[0-9;]*m/g, '');
55
- const allRows = [headers, ...rows.map((r) => r.map(String))];
56
- const colWidths = headers.map((_, ci) => Math.max(...allRows.map((r) => stripAnsi(String(r[ci] ?? '')).length)) + 2);
57
- const pad = (s, w) => {
58
- const visible = stripAnsi(s).length;
59
- return ' ' + s + ' '.repeat(Math.max(0, w - visible - 1));
60
- };
61
- const colorCell = (s) => {
62
- if (s === 'SEVERE' || s === 'HIGH')
63
- return chalk.red.bold(s);
64
- if (s === 'MODERATE')
65
- return chalk.yellow(s);
66
- if (s === 'LOW')
67
- return chalk.green(s);
68
- return s;
69
- };
70
- const topBorder = chalk.gray(' ┌' + colWidths.map((w) => '─'.repeat(w)).join('┬') + '┐');
71
- const midBorder = chalk.gray(' ├' + colWidths.map((w) => '─'.repeat(w)).join('┼') + '┤');
72
- const botBorder = chalk.gray(' └' + colWidths.map((w) => '─'.repeat(w)).join('┴') + '┘');
73
- const formatRow = (cells, isHeader = false) => {
74
- const formatted = cells.map((c, i) => {
75
- const display = isHeader ? chalk.cyan.bold(c) : colorCell(c);
76
- return pad(display, colWidths[i]);
77
- });
78
- return chalk.gray(' │') + formatted.join(chalk.gray('│')) + chalk.gray('│');
48
+ const stringRows = rows.map((row) => row.map((cell) => String(cell)));
49
+ const allRows = [headers, ...stringRows];
50
+ const colWidths = headers.map((_, columnIndex) => Math.max(...allRows.map((row) => stripAnsi(row[columnIndex] ?? '').length)) + 2);
51
+ const makeBorder = (left, mid, right) => chalk.gray(` ${left}${colWidths.map((width) => '-'.repeat(width + 2)).join(mid)}${right}`);
52
+ const formatCell = (value, columnIndex, isHeader = false) => {
53
+ const display = isHeader ? chalk.cyan.bold(value) : value;
54
+ return ` ${pad(display, colWidths[columnIndex])} `;
79
55
  };
56
+ const formatRow = (cells, isHeader = false) => chalk.gray(' |') +
57
+ cells.map((cell, index) => formatCell(cell, index, isHeader)).join(chalk.gray('|')) +
58
+ chalk.gray('|');
80
59
  console.log('');
81
- console.log(topBorder);
60
+ console.log(makeBorder('+', '+', '+'));
82
61
  console.log(formatRow(headers, true));
83
- console.log(midBorder);
84
- for (const row of rows) {
85
- console.log(formatRow(row.map(String)));
62
+ console.log(makeBorder('+', '+', '+'));
63
+ for (const row of stringRows) {
64
+ console.log(formatRow(row));
86
65
  }
87
- console.log(botBorder);
66
+ console.log(makeBorder('+', '+', '+'));
88
67
  }
89
- // ---------------------------------------------------------------------------
90
- // Charts (ASCII line chart for --plot)
91
- // ---------------------------------------------------------------------------
92
68
  export function renderChart(data, options) {
93
69
  const height = options?.height ?? 12;
94
70
  console.log('');
@@ -123,16 +99,115 @@ export function renderMultiChart(series, labels, options) {
123
99
  format: (x) => x.toFixed(1).padStart(8),
124
100
  });
125
101
  console.log(chart);
126
- // Legend
127
- const legend = labels
128
- .map((l, i) => chalk.hex(i === 0 ? '#00ffff' : i === 1 ? '#ffff00' : i === 2 ? '#ff0000' : '#00ff00')(`■ ${l}`))
129
- .join(' ');
102
+ const legend = labels.map((label, index) => `${index + 1}:${label}`).join(' ');
130
103
  console.log(` ${legend}`);
131
104
  console.log('');
132
105
  }
133
- // ---------------------------------------------------------------------------
134
- // Steps (verbose output)
135
- // ---------------------------------------------------------------------------
106
+ function clamp(value, min, max) {
107
+ return Math.min(Math.max(value, min), max);
108
+ }
109
+ function expandDomain(min, max) {
110
+ if (min === max) {
111
+ const delta = Math.abs(min) > 1 ? Math.abs(min) * 0.1 : 1;
112
+ return [min - delta, max + delta];
113
+ }
114
+ return [min, max];
115
+ }
116
+ function interpolateLine(startCol, startRow, endCol, endRow, symbol, grid) {
117
+ const steps = Math.max(Math.abs(endCol - startCol), Math.abs(endRow - startRow));
118
+ if (steps === 0) {
119
+ grid[startRow][startCol] = symbol;
120
+ return;
121
+ }
122
+ for (let index = 0; index <= steps; index += 1) {
123
+ const t = index / steps;
124
+ const col = Math.round(startCol + (endCol - startCol) * t);
125
+ const row = Math.round(startRow + (endRow - startRow) * t);
126
+ grid[row][col] = symbol;
127
+ }
128
+ }
129
+ export function renderXYPlot(series, options) {
130
+ const height = Math.max(8, options?.height ?? 14);
131
+ const width = Math.max(28, options?.width ?? 60);
132
+ const xScale = options?.xScale ?? 'linear';
133
+ const symbols = ['*', 'o', 'x', '+', '#'];
134
+ const transformedSeries = series
135
+ .map((entry, index) => {
136
+ const points = entry.points
137
+ .filter((point) => Number.isFinite(point.x) && Number.isFinite(point.y))
138
+ .filter((point) => xScale === 'linear' || point.x > 0)
139
+ .map((point) => ({
140
+ x: xScale === 'log10' ? Math.log10(point.x) : point.x,
141
+ y: point.y,
142
+ rawX: point.x,
143
+ rawY: point.y,
144
+ }));
145
+ return {
146
+ ...entry,
147
+ symbol: entry.symbol ?? symbols[index % symbols.length],
148
+ points,
149
+ };
150
+ })
151
+ .filter((entry) => entry.points.length > 0);
152
+ if (transformedSeries.length === 0) {
153
+ warn('No plottable XY data found for this chart.');
154
+ return;
155
+ }
156
+ const allX = transformedSeries.flatMap((entry) => entry.points.map((point) => point.x));
157
+ const allY = transformedSeries.flatMap((entry) => entry.points.map((point) => point.y));
158
+ const rawX = transformedSeries.flatMap((entry) => entry.points.map((point) => point.rawX));
159
+ const transformedDomain = options?.xDomain && xScale === 'log10'
160
+ ? [Math.log10(options.xDomain[0]), Math.log10(options.xDomain[1])]
161
+ : options?.xDomain;
162
+ const [xMin, xMax] = expandDomain(transformedDomain?.[0] ?? Math.min(...allX), transformedDomain?.[1] ?? Math.max(...allX));
163
+ const [yMin, yMax] = expandDomain(options?.yDomain?.[0] ?? Math.min(...allY), options?.yDomain?.[1] ?? Math.max(...allY));
164
+ const grid = Array.from({ length: height }, () => Array.from({ length: width }, () => ' '));
165
+ const xToColumn = (value) => clamp(Math.round(((value - xMin) / (xMax - xMin)) * (width - 1)), 0, width - 1);
166
+ const yToRow = (value) => {
167
+ const normalized = (value - yMin) / (yMax - yMin);
168
+ const row = options?.invertY
169
+ ? Math.round(normalized * (height - 1))
170
+ : Math.round((1 - normalized) * (height - 1));
171
+ return clamp(row, 0, height - 1);
172
+ };
173
+ if (xScale === 'linear' && xMin <= 0 && xMax >= 0) {
174
+ const axisCol = xToColumn(0);
175
+ for (let row = 0; row < height; row += 1) {
176
+ grid[row][axisCol] = '|';
177
+ }
178
+ }
179
+ if (yMin <= 0 && yMax >= 0) {
180
+ const axisRow = yToRow(0);
181
+ for (let col = 0; col < width; col += 1) {
182
+ grid[axisRow][col] = '-';
183
+ }
184
+ }
185
+ if (xScale === 'linear' && xMin <= 0 && xMax >= 0 && yMin <= 0 && yMax >= 0) {
186
+ grid[yToRow(0)][xToColumn(0)] = '+';
187
+ }
188
+ for (const entry of transformedSeries) {
189
+ const symbol = entry.symbol ?? '*';
190
+ for (let index = 0; index < entry.points.length; index += 1) {
191
+ const point = entry.points[index];
192
+ const col = xToColumn(point.x);
193
+ const row = yToRow(point.y);
194
+ grid[row][col] = symbol;
195
+ if (entry.style !== 'scatter' && index > 0) {
196
+ const previous = entry.points[index - 1];
197
+ interpolateLine(xToColumn(previous.x), yToRow(previous.y), col, row, symbol, grid);
198
+ }
199
+ }
200
+ }
201
+ console.log('');
202
+ if (options?.title) {
203
+ console.log(chalk.gray(` ${options.title}`));
204
+ }
205
+ console.log(grid.map((row) => ` ${row.join('')}`).join('\n'));
206
+ console.log(chalk.gray(` x: ${Math.min(...rawX).toFixed(2)} to ${Math.max(...rawX).toFixed(2)}${xScale === 'log10' ? ' (log scale)' : ''}${options?.xLabel ? ` | ${options.xLabel}` : ''}`));
207
+ console.log(chalk.gray(` y: ${yMin.toFixed(2)} to ${yMax.toFixed(2)}${options?.yLabel ? ` | ${options.yLabel}` : ''}`));
208
+ console.log(` ${transformedSeries.map((entry) => `${entry.symbol}=${entry.label}`).join(' ')}`);
209
+ console.log('');
210
+ }
136
211
  export function renderSteps(steps, verbose) {
137
212
  if (!verbose)
138
213
  return;
@@ -142,11 +217,7 @@ export function renderSteps(steps, verbose) {
142
217
  console.log(chalk.gray(` ${step}`));
143
218
  }
144
219
  }
145
- // ---------------------------------------------------------------------------
146
- // JSON output
147
- // ---------------------------------------------------------------------------
148
220
  export function renderJSON(data) {
149
- // Security: strip any apiKey/api_key/token fields before output
150
221
  const sanitized = JSON.parse(JSON.stringify(data, (key, value) => {
151
222
  if (/api.?key|token|secret|password/i.test(key)) {
152
223
  if (typeof value === 'boolean' || typeof value === 'number' || value == null) {