@walterra/pi-charts 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/extensions/vega-chart/index.ts +44 -11
- package/package.json +3 -2
|
@@ -102,6 +102,23 @@ Reference: https://vega.github.io/vega-lite/docs/`,
|
|
|
102
102
|
return { content: [{ type: 'text', text: 'Cancelled' }], details: {} };
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
const getErrorMessage = (err: unknown): string => {
|
|
106
|
+
if (err instanceof Error) return err.message;
|
|
107
|
+
if (typeof err === 'string') return err;
|
|
108
|
+
if (err && typeof err === 'object' && 'message' in err) {
|
|
109
|
+
return String((err as { message?: unknown }).message);
|
|
110
|
+
}
|
|
111
|
+
return 'Unknown error';
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const getErrorStderr = (err: unknown): string | undefined => {
|
|
115
|
+
if (err && typeof err === 'object' && 'stderr' in err) {
|
|
116
|
+
const stderr = (err as { stderr?: unknown }).stderr;
|
|
117
|
+
return typeof stderr === 'string' ? stderr : undefined;
|
|
118
|
+
}
|
|
119
|
+
return undefined;
|
|
120
|
+
};
|
|
121
|
+
|
|
105
122
|
try {
|
|
106
123
|
// Check Python and dependencies, auto-install if needed using uv
|
|
107
124
|
const ensureDependencies = (): { success: boolean; error?: string } => {
|
|
@@ -159,30 +176,44 @@ Reference: https://vega.github.io/vega-lite/docs/`,
|
|
|
159
176
|
try {
|
|
160
177
|
execSync(checkCmd, { encoding: 'utf-8', stdio: 'pipe' });
|
|
161
178
|
return { success: true };
|
|
162
|
-
} catch (err:
|
|
179
|
+
} catch (err: unknown) {
|
|
180
|
+
const errorMsg = getErrorMessage(err);
|
|
163
181
|
return {
|
|
164
182
|
success: false,
|
|
165
|
-
error: `Failed to setup Python environment with uv.\nPlease run manually: uv run --with altair --with pandas --with vl-convert-python python3\n\nError: ${
|
|
183
|
+
error: `Failed to setup Python environment with uv.\nPlease run manually: uv run --with altair --with pandas --with vl-convert-python python3\n\nError: ${errorMsg}`,
|
|
166
184
|
};
|
|
167
185
|
}
|
|
168
186
|
};
|
|
169
187
|
|
|
170
188
|
const deps = ensureDependencies();
|
|
171
189
|
if (!deps.success) {
|
|
190
|
+
const errorText = deps.error ?? 'Dependencies not installed';
|
|
172
191
|
return {
|
|
173
|
-
content: [{ type: 'text', text:
|
|
192
|
+
content: [{ type: 'text', text: errorText }],
|
|
174
193
|
details: { error: 'Dependencies not installed' },
|
|
175
194
|
isError: true,
|
|
176
195
|
};
|
|
177
196
|
}
|
|
178
197
|
|
|
179
198
|
// Parse and validate the spec
|
|
180
|
-
|
|
199
|
+
type VegaSpec = {
|
|
200
|
+
$schema?: string;
|
|
201
|
+
width?: number;
|
|
202
|
+
height?: number;
|
|
203
|
+
data?: { values?: unknown[] };
|
|
204
|
+
[key: string]: unknown;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
let vegaSpec: VegaSpec;
|
|
181
208
|
try {
|
|
182
|
-
|
|
209
|
+
const parsed = JSON.parse(spec);
|
|
210
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
211
|
+
throw new Error('Spec must be a JSON object');
|
|
212
|
+
}
|
|
213
|
+
vegaSpec = parsed as VegaSpec;
|
|
183
214
|
} catch (e) {
|
|
184
215
|
return {
|
|
185
|
-
content: [{ type: 'text', text: `Invalid JSON in spec: ${e}` }],
|
|
216
|
+
content: [{ type: 'text', text: `Invalid JSON in spec: ${getErrorMessage(e)}` }],
|
|
186
217
|
details: { error: 'Invalid JSON' },
|
|
187
218
|
isError: true,
|
|
188
219
|
};
|
|
@@ -260,9 +291,9 @@ print('OK')
|
|
|
260
291
|
mkdirSync(dirname(save_path), { recursive: true });
|
|
261
292
|
copyFileSync(tmpPng, save_path);
|
|
262
293
|
savedPath = save_path;
|
|
263
|
-
} catch (saveErr:
|
|
294
|
+
} catch (saveErr: unknown) {
|
|
264
295
|
// Don't fail the whole operation, just note the error
|
|
265
|
-
console.error(`Failed to save to ${save_path}: ${saveErr
|
|
296
|
+
console.error(`Failed to save to ${save_path}: ${getErrorMessage(saveErr)}`);
|
|
266
297
|
}
|
|
267
298
|
}
|
|
268
299
|
|
|
@@ -279,7 +310,9 @@ print('OK')
|
|
|
279
310
|
|
|
280
311
|
const dataPoints = tsv_data
|
|
281
312
|
? tsv_data.trim().split('\n').length - 1
|
|
282
|
-
: vegaSpec.data?.values
|
|
313
|
+
: Array.isArray(vegaSpec.data?.values)
|
|
314
|
+
? vegaSpec.data?.values.length
|
|
315
|
+
: 0;
|
|
283
316
|
|
|
284
317
|
const textMsg = savedPath
|
|
285
318
|
? `Rendered Vega-Lite chart (${dataPoints} data points) - saved to ${savedPath}`
|
|
@@ -292,9 +325,9 @@ print('OK')
|
|
|
292
325
|
],
|
|
293
326
|
details: { dataPoints, width: vegaSpec.width, height: vegaSpec.height, savedPath },
|
|
294
327
|
};
|
|
295
|
-
} catch (error:
|
|
328
|
+
} catch (error: unknown) {
|
|
296
329
|
// Try to extract Python error details
|
|
297
|
-
const errorMsg = error
|
|
330
|
+
const errorMsg = getErrorStderr(error) ?? getErrorMessage(error);
|
|
298
331
|
return {
|
|
299
332
|
content: [{ type: 'text', text: `Error rendering chart: ${errorMsg}` }],
|
|
300
333
|
details: { error: errorMsg },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walterra/pi-charts",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Vega-Lite chart extension for pi coding agent - render data visualizations as inline images",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"pi": {
|
|
11
11
|
"extensions": [
|
|
12
12
|
"./extensions/vega-chart/index.ts"
|
|
13
|
-
]
|
|
13
|
+
],
|
|
14
|
+
"video": "https://www.rafelsberger.at/assets/pi-charts-sm-0003.mp4"
|
|
14
15
|
},
|
|
15
16
|
"repository": {
|
|
16
17
|
"type": "git",
|