speqs 0.4.0 → 0.5.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.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Output formatting utilities.
3
+ * Supports both human-readable and JSON output modes.
4
+ */
5
+ export declare function output(data: unknown, json: boolean): void;
6
+ export declare function outputList(rows: unknown[], json: boolean): void;
7
+ export declare function outputError(err: unknown, json: boolean): void;
8
+ export declare function printTable(headers: string[], rows: string[][]): void;
9
+ export declare function printKeyValue(obj: Record<string, unknown>, indent?: string): void;
10
+ export declare function formatWorkspaceList(workspaces: Record<string, unknown>[], json: boolean): void;
11
+ export declare function formatWorkspaceDetail(workspace: Record<string, unknown>, json: boolean): void;
12
+ export declare function formatStudyList(studies: Record<string, unknown>[], json: boolean): void;
13
+ export declare function formatStudyDetail(study: Record<string, unknown>, json: boolean): void;
14
+ export declare function formatStudyResults(study: Record<string, unknown>, json: boolean): void;
15
+ export declare function formatIterationList(iterations: Record<string, unknown>[], json: boolean): void;
16
+ export declare function formatTesterDetail(tester: Record<string, unknown>, json: boolean): void;
17
+ export declare function formatTesterProfileList(profiles: unknown, json: boolean, limit?: number): void;
18
+ export declare function formatSimulationPoll(results: Record<string, unknown>[], json: boolean): void;
19
+ export declare function formatConfigList(configs: Record<string, unknown>[], json: boolean): void;
@@ -0,0 +1,454 @@
1
+ /**
2
+ * Output formatting utilities.
3
+ * Supports both human-readable and JSON output modes.
4
+ */
5
+ import { ApiError } from "./api-client.js";
6
+ // --- JSON mode: always full data ---
7
+ export function output(data, json) {
8
+ if (json) {
9
+ console.log(JSON.stringify(data, null, 2));
10
+ return;
11
+ }
12
+ if (data === null || data === undefined)
13
+ return;
14
+ if (Array.isArray(data)) {
15
+ outputList(data, json);
16
+ return;
17
+ }
18
+ if (typeof data === "object") {
19
+ printKeyValue(data);
20
+ return;
21
+ }
22
+ console.log(String(data));
23
+ }
24
+ export function outputList(rows, json) {
25
+ if (json) {
26
+ console.log(JSON.stringify(rows, null, 2));
27
+ return;
28
+ }
29
+ if (rows.length === 0) {
30
+ console.log("No results.");
31
+ return;
32
+ }
33
+ // Generic list: show name + key fields
34
+ for (const row of rows) {
35
+ if (typeof row === "object" && row !== null) {
36
+ const obj = row;
37
+ const parts = [];
38
+ if (obj.name)
39
+ parts.push(String(obj.name));
40
+ if (obj.status)
41
+ parts.push(`[${obj.status}]`);
42
+ if (obj.modality)
43
+ parts.push(String(obj.modality));
44
+ console.log(" " + parts.join(" "));
45
+ }
46
+ else {
47
+ console.log(" " + String(row));
48
+ }
49
+ }
50
+ }
51
+ export function outputError(err, json) {
52
+ if (err instanceof ApiError) {
53
+ if (json) {
54
+ console.error(JSON.stringify({
55
+ error: err.message,
56
+ error_code: err.error_code,
57
+ status: err.status,
58
+ retryable: err.retryable,
59
+ }));
60
+ }
61
+ else {
62
+ if (err.status === 402) {
63
+ console.error("Error: Insufficient credits. Purchase more at https://app.speqs.io");
64
+ }
65
+ else {
66
+ console.error(`Error: ${err.message}`);
67
+ }
68
+ }
69
+ }
70
+ else if (err instanceof Error) {
71
+ if (json) {
72
+ console.error(JSON.stringify({ error: err.message, error_code: "client_error", retryable: false }));
73
+ }
74
+ else {
75
+ console.error(`Error: ${err.message}`);
76
+ }
77
+ }
78
+ else {
79
+ if (json) {
80
+ console.error(JSON.stringify({ error: String(err), error_code: "unknown_error", retryable: false }));
81
+ }
82
+ else {
83
+ console.error(`Error: ${err}`);
84
+ }
85
+ }
86
+ }
87
+ // --- Entity-specific formatters (human mode) ---
88
+ export function printTable(headers, rows) {
89
+ const colWidths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] || "").length)));
90
+ console.log(" " + headers.map((h, i) => h.padEnd(colWidths[i])).join(" "));
91
+ for (const row of rows) {
92
+ console.log(" " + row.map((cell, i) => (cell || "").padEnd(colWidths[i])).join(" "));
93
+ }
94
+ }
95
+ export function printKeyValue(obj, indent = " ") {
96
+ const entries = Object.entries(obj).filter(([, v]) => v !== null && v !== undefined);
97
+ if (entries.length === 0)
98
+ return;
99
+ const maxKeyLen = Math.max(...entries.map(([k]) => k.length));
100
+ for (const [key, value] of entries) {
101
+ const label = formatLabel(key);
102
+ const displayValue = typeof value === "object" && value !== null
103
+ ? JSON.stringify(value)
104
+ : String(value);
105
+ console.log(`${indent}${label.padEnd(maxKeyLen + 2)}${displayValue}`);
106
+ }
107
+ }
108
+ function formatLabel(key) {
109
+ return key
110
+ .replace(/_/g, " ")
111
+ .replace(/\b\w/g, (c) => c.toUpperCase());
112
+ }
113
+ // --- Workspace formatting ---
114
+ export function formatWorkspaceList(workspaces, json) {
115
+ if (json) {
116
+ console.log(JSON.stringify(workspaces, null, 2));
117
+ return;
118
+ }
119
+ if (workspaces.length === 0) {
120
+ console.log("No workspaces.");
121
+ return;
122
+ }
123
+ printTable(["ID", "NAME", "CREATED"], workspaces.map((w) => [
124
+ String(w.id || ""),
125
+ String(w.name || ""),
126
+ formatDate(w.created_at),
127
+ ]));
128
+ }
129
+ export function formatWorkspaceDetail(workspace, json) {
130
+ if (json) {
131
+ console.log(JSON.stringify(workspace, null, 2));
132
+ return;
133
+ }
134
+ const display = {
135
+ Name: workspace.name,
136
+ Description: workspace.description || "-",
137
+ "Base URL": workspace.base_url || "-",
138
+ Created: formatDate(workspace.created_at),
139
+ };
140
+ printKeyValue(display);
141
+ }
142
+ // --- Study formatting ---
143
+ export function formatStudyList(studies, json) {
144
+ if (json) {
145
+ console.log(JSON.stringify(studies, null, 2));
146
+ return;
147
+ }
148
+ if (studies.length === 0) {
149
+ console.log("No studies.");
150
+ return;
151
+ }
152
+ printTable(["ID", "NAME", "MODALITY", "STATUS", "TESTERS"], studies.map((s) => [
153
+ String(s.id || ""),
154
+ String(s.name || ""),
155
+ String(s.modality || "-"),
156
+ String(s.status || "draft"),
157
+ String(s.tester_count ?? "0"),
158
+ ]));
159
+ }
160
+ export function formatStudyDetail(study, json) {
161
+ if (json) {
162
+ console.log(JSON.stringify(study, null, 2));
163
+ return;
164
+ }
165
+ // Header
166
+ console.log(String(study.name || "Untitled"));
167
+ if (study.description)
168
+ console.log(String(study.description));
169
+ console.log(`${study.modality || "-"} · ${study.status || "draft"} · ${formatDate(study.created_at)}`);
170
+ // Assignments
171
+ const assignments = Array.isArray(study.assignments) ? study.assignments : [];
172
+ if (assignments.length > 0) {
173
+ console.log("\nAssignments:");
174
+ for (let i = 0; i < assignments.length; i++) {
175
+ const a = assignments[i];
176
+ console.log(` ${i + 1}. ${a.name || "Untitled"}`);
177
+ if (a.instructions) {
178
+ console.log(` ${truncate(String(a.instructions), 80)}`);
179
+ }
180
+ }
181
+ }
182
+ // Interview Questions
183
+ const questions = Array.isArray(study.interview_questions) ? study.interview_questions : [];
184
+ if (questions.length > 0) {
185
+ console.log("\nInterview Questions:");
186
+ for (let i = 0; i < questions.length; i++) {
187
+ const q = questions[i];
188
+ const typeStr = formatQuestionType(q);
189
+ console.log(` ${i + 1}. ${q.question || "Untitled"} ${typeStr}`);
190
+ }
191
+ }
192
+ // Testers summary
193
+ const allTesters = collectTesters(study);
194
+ if (allTesters.length > 0) {
195
+ console.log(`\nTesters (${allTesters.length}):`);
196
+ printTable(["ID", "NAME", "ITERATION", "STATUS", "INTERACTIONS"], allTesters.map((t) => [
197
+ t.id,
198
+ t.name,
199
+ t.iterationLabel,
200
+ t.status,
201
+ String(t.interactionCount),
202
+ ]));
203
+ }
204
+ }
205
+ export function formatStudyResults(study, json) {
206
+ if (json) {
207
+ console.log(JSON.stringify(study, null, 2));
208
+ return;
209
+ }
210
+ const allTesters = collectTesters(study);
211
+ const totalInteractions = allTesters.reduce((sum, t) => sum + t.interactionCount, 0);
212
+ // Header
213
+ console.log(`${study.name || "Untitled"} — Results`);
214
+ console.log(`${allTesters.length} tester${allTesters.length !== 1 ? "s" : ""} · ${totalInteractions} total interactions`);
215
+ // Sentiment summary
216
+ const totalSentiment = {};
217
+ for (const t of allTesters) {
218
+ for (const [label, count] of Object.entries(t.sentimentCounts)) {
219
+ totalSentiment[label] = (totalSentiment[label] || 0) + count;
220
+ }
221
+ }
222
+ const sentimentParts = Object.entries(totalSentiment).map(([label, count]) => `${count} ${label.toLowerCase()}`);
223
+ console.log(`\nSentiment: ${sentimentParts.length > 0 ? sentimentParts.join(", ") : "none"}`);
224
+ // Interview Answers grouped by question
225
+ const questions = Array.isArray(study.interview_questions) ? study.interview_questions : [];
226
+ if (questions.length > 0) {
227
+ console.log("\nInterview Answers:");
228
+ for (const q of questions) {
229
+ const qObj = q;
230
+ const typeStr = formatQuestionType(qObj);
231
+ console.log(`\n "${qObj.question}" ${typeStr}`);
232
+ for (const t of allTesters) {
233
+ const answer = t.interviewAnswers.find((a) => a.questionId === qObj.id);
234
+ if (answer) {
235
+ const answerStr = typeof answer.answer === "string"
236
+ ? `"${truncate(answer.answer, 70)}"`
237
+ : String(answer.answer);
238
+ console.log(` ${t.name} (${t.iterationLabel}): ${answerStr}`);
239
+ }
240
+ }
241
+ }
242
+ }
243
+ // Testers table
244
+ if (allTesters.length > 0) {
245
+ console.log("\nTesters:");
246
+ printTable(["ID", "NAME", "ITERATION", "STATUS", "INTERACTIONS", "SENTIMENT"], allTesters.map((t) => {
247
+ const parts = Object.entries(t.sentimentCounts).map(([label, count]) => `${count} ${label.toLowerCase()}`);
248
+ return [
249
+ t.id,
250
+ t.name,
251
+ t.iterationLabel,
252
+ t.status,
253
+ String(t.interactionCount),
254
+ parts.length > 0 ? parts.join(", ") : "-",
255
+ ];
256
+ }));
257
+ console.log("\nRun `speqs tester get <id> --json` for full interaction details.");
258
+ }
259
+ }
260
+ function collectTesters(study) {
261
+ const iterations = Array.isArray(study.iterations) ? study.iterations : [];
262
+ const testers = [];
263
+ for (const iter of iterations) {
264
+ const it = iter;
265
+ const iterLabel = String(it.label || it.name || "-");
266
+ const iterTesters = Array.isArray(it.testers) ? it.testers : [];
267
+ for (const tester of iterTesters) {
268
+ const t = tester;
269
+ const profile = t.tester_profile;
270
+ const interactions = Array.isArray(t.interactions) ? t.interactions : [];
271
+ const sentimentCounts = {};
272
+ for (const interaction of interactions) {
273
+ const ix = interaction;
274
+ const sentiment = ix.sentiment;
275
+ if (sentiment?.label) {
276
+ const label = String(sentiment.label);
277
+ sentimentCounts[label] = (sentimentCounts[label] || 0) + 1;
278
+ }
279
+ }
280
+ const answers = Array.isArray(t.interview_answers) ? t.interview_answers : [];
281
+ testers.push({
282
+ id: String(t.id || ""),
283
+ name: String(profile?.name || t.instance_name || "Unknown"),
284
+ iterationLabel: iterLabel,
285
+ status: String(t.status || "-"),
286
+ interactionCount: interactions.length,
287
+ sentimentCounts,
288
+ interviewAnswers: answers.map((a) => ({
289
+ questionId: String(a.question_id || ""),
290
+ answer: a.answer,
291
+ })),
292
+ });
293
+ }
294
+ }
295
+ return testers;
296
+ }
297
+ function formatQuestionType(q) {
298
+ if (!q.type)
299
+ return "";
300
+ if (q.type === "slider" && q.min !== undefined && q.max !== undefined) {
301
+ return `[${q.type} ${q.min}-${q.max}]`;
302
+ }
303
+ return `[${q.type}]`;
304
+ }
305
+ function truncate(str, maxLen) {
306
+ if (str.length <= maxLen)
307
+ return str;
308
+ return str.slice(0, maxLen - 3) + "...";
309
+ }
310
+ // --- Iteration formatting ---
311
+ export function formatIterationList(iterations, json) {
312
+ if (json) {
313
+ console.log(JSON.stringify(iterations, null, 2));
314
+ return;
315
+ }
316
+ if (iterations.length === 0) {
317
+ console.log("No iterations.");
318
+ return;
319
+ }
320
+ printTable(["ID", "LABEL", "NAME", "TESTERS", "CREATED"], iterations.map((it) => {
321
+ const testers = Array.isArray(it.testers) ? it.testers.length : 0;
322
+ return [
323
+ String(it.id || ""),
324
+ String(it.label || "-"),
325
+ String(it.name || ""),
326
+ String(testers),
327
+ formatDate(it.created_at),
328
+ ];
329
+ }));
330
+ }
331
+ // --- Tester formatting ---
332
+ export function formatTesterDetail(tester, json) {
333
+ if (json) {
334
+ console.log(JSON.stringify(tester, null, 2));
335
+ return;
336
+ }
337
+ const profile = tester.tester_profile;
338
+ const profileName = profile?.name ? String(profile.name) : "Unknown";
339
+ const interactions = Array.isArray(tester.interactions) ? tester.interactions : [];
340
+ // Count sentiments
341
+ const sentimentCounts = {};
342
+ for (const interaction of interactions) {
343
+ const it = interaction;
344
+ const sentiment = it.sentiment;
345
+ if (sentiment?.label) {
346
+ const label = String(sentiment.label);
347
+ sentimentCounts[label] = (sentimentCounts[label] || 0) + 1;
348
+ }
349
+ }
350
+ const sentimentParts = Object.entries(sentimentCounts).map(([label, count]) => `${count} ${label.toLowerCase()}`);
351
+ const display = {
352
+ Profile: profileName,
353
+ Status: tester.status || "-",
354
+ Platform: tester.platform || "-",
355
+ Language: tester.language || "-",
356
+ Interactions: `${interactions.length} interactions`,
357
+ ...(sentimentParts.length > 0 && {
358
+ Sentiment: sentimentParts.join(", "),
359
+ }),
360
+ };
361
+ printKeyValue(display);
362
+ }
363
+ // --- Tester Profile formatting ---
364
+ export function formatTesterProfileList(profiles, json, limit) {
365
+ if (json) {
366
+ console.log(JSON.stringify(profiles, null, 2));
367
+ return;
368
+ }
369
+ // The API may return { items: [...], total, limit, offset } or a flat array
370
+ const wrapper = profiles;
371
+ const fullList = Array.isArray(profiles) ? profiles
372
+ : Array.isArray(wrapper?.items) ? wrapper.items
373
+ : Array.isArray(wrapper?.profiles) ? wrapper.profiles
374
+ : null;
375
+ if (!Array.isArray(fullList) || fullList.length === 0) {
376
+ console.log("No tester profiles.");
377
+ return;
378
+ }
379
+ // Client-side limit (server may not enforce it)
380
+ const list = limit ? fullList.slice(0, limit) : fullList;
381
+ printTable(["ID", "NAME", "OCCUPATION", "COUNTRY", "GENDER", "AGE"], list.map((p) => [
382
+ String(p.id || ""),
383
+ String(p.name || ""),
384
+ String(p.occupation || "-"),
385
+ String(p.country || "-"),
386
+ String(p.gender || "-"),
387
+ formatAge(p.date_of_birth),
388
+ ]));
389
+ if (fullList.length > list.length) {
390
+ console.log(`\n Showing ${list.length} of ${fullList.length} profiles. Use --limit and --offset for more.`);
391
+ }
392
+ }
393
+ // --- Simulation poll formatting ---
394
+ export function formatSimulationPoll(results, json) {
395
+ if (json) {
396
+ console.log(JSON.stringify({ results }, null, 2));
397
+ return;
398
+ }
399
+ if (results.length === 0) {
400
+ console.log("No simulations found.");
401
+ return;
402
+ }
403
+ printTable(["ID", "TESTER", "STATUS", "INTERACTIONS"], results.map((r) => [
404
+ String(r.id || r.tester_id || ""),
405
+ String(r.tester_name || "Unknown"),
406
+ String(r.status || "UNKNOWN"),
407
+ String(r.interaction_count ?? "0"),
408
+ ]));
409
+ }
410
+ // --- Config formatting ---
411
+ export function formatConfigList(configs, json) {
412
+ if (json) {
413
+ console.log(JSON.stringify(configs, null, 2));
414
+ return;
415
+ }
416
+ if (configs.length === 0) {
417
+ console.log("No simulation configs.");
418
+ return;
419
+ }
420
+ printTable(["ID", "NAME", "SOURCE", "CREATED"], configs.map((c) => [
421
+ String(c.id || ""),
422
+ String(c.name || ""),
423
+ String(c.source_type || "manual"),
424
+ formatDate(c.created_at),
425
+ ]));
426
+ }
427
+ // --- Helpers ---
428
+ function formatAge(dob) {
429
+ if (!dob)
430
+ return "-";
431
+ try {
432
+ const birth = new Date(String(dob));
433
+ const now = new Date();
434
+ let age = now.getFullYear() - birth.getFullYear();
435
+ const monthDiff = now.getMonth() - birth.getMonth();
436
+ if (monthDiff < 0 || (monthDiff === 0 && now.getDate() < birth.getDate()))
437
+ age--;
438
+ return String(age);
439
+ }
440
+ catch {
441
+ return "-";
442
+ }
443
+ }
444
+ function formatDate(value) {
445
+ if (!value)
446
+ return "-";
447
+ const str = String(value);
448
+ try {
449
+ return new Date(str).toLocaleDateString("en-CA"); // YYYY-MM-DD
450
+ }
451
+ catch {
452
+ return str.slice(0, 10);
453
+ }
454
+ }
@@ -0,0 +1,202 @@
1
+ /**
2
+ * TypeScript interfaces for Speqs API entities.
3
+ */
4
+ export interface Product {
5
+ id: string;
6
+ name: string;
7
+ description?: string;
8
+ color?: string;
9
+ base_url?: string;
10
+ product_type?: string;
11
+ created_at: string;
12
+ updated_at: string;
13
+ }
14
+ export interface ProductCreateInput {
15
+ name: string;
16
+ description?: string;
17
+ color?: string;
18
+ base_url?: string;
19
+ }
20
+ export interface ProductUpdateInput {
21
+ name?: string;
22
+ description?: string;
23
+ color?: string;
24
+ base_url?: string;
25
+ }
26
+ export interface Assignment {
27
+ id?: string;
28
+ name: string;
29
+ instructions: string;
30
+ }
31
+ export interface InterviewQuestion {
32
+ id?: string;
33
+ question: string;
34
+ type?: string;
35
+ timing?: string;
36
+ min?: number;
37
+ max?: number;
38
+ step?: number;
39
+ labels?: string[];
40
+ options?: string[];
41
+ }
42
+ export interface Study {
43
+ id: string;
44
+ product_id: string;
45
+ name: string;
46
+ description?: string;
47
+ modality?: string;
48
+ content_type?: string;
49
+ status?: string;
50
+ start_frame_id?: string;
51
+ source_study_id?: string;
52
+ assignments?: Assignment[];
53
+ interview_questions?: InterviewQuestion[];
54
+ frames?: unknown[];
55
+ iterations?: Iteration[];
56
+ created_at: string;
57
+ updated_at: string;
58
+ created_by?: string;
59
+ }
60
+ export interface StudyCreateInput {
61
+ product_id: string;
62
+ name: string;
63
+ description?: string;
64
+ modality?: string;
65
+ content_type?: string;
66
+ assignments?: Assignment[];
67
+ interview_questions?: InterviewQuestion[];
68
+ start_frame_id?: string;
69
+ }
70
+ export interface StudyUpdateInput {
71
+ name?: string;
72
+ description?: string;
73
+ status?: string;
74
+ modality?: string;
75
+ content_type?: string;
76
+ assignments?: Assignment[];
77
+ interview_questions?: InterviewQuestion[];
78
+ start_frame_id?: string;
79
+ }
80
+ export interface StudyGenerateInput {
81
+ problem_description: string;
82
+ target_url?: string;
83
+ }
84
+ export interface Iteration {
85
+ id: string;
86
+ study_id: string;
87
+ name?: string;
88
+ description?: string;
89
+ label?: string;
90
+ details?: Record<string, unknown>;
91
+ testers?: Tester[];
92
+ created_at: string;
93
+ updated_at: string;
94
+ }
95
+ export interface IterationCreateInput {
96
+ name: string;
97
+ description?: string;
98
+ details?: Record<string, unknown>;
99
+ }
100
+ export interface IterationUpdateInput {
101
+ name?: string;
102
+ description?: string;
103
+ details?: Record<string, unknown>;
104
+ label?: string;
105
+ }
106
+ export interface TesterProfile {
107
+ id: string;
108
+ name: string;
109
+ [key: string]: unknown;
110
+ }
111
+ export interface Tester {
112
+ id: string;
113
+ iteration_id: string;
114
+ tester_profile_id: string;
115
+ instance_name?: string;
116
+ instance_number?: number;
117
+ status: string;
118
+ language?: string;
119
+ platform?: string;
120
+ tester_type?: string;
121
+ viewport_width?: number;
122
+ viewport_height?: number;
123
+ created_at: string;
124
+ }
125
+ export interface TesterCreateInput {
126
+ tester_profile_id: string;
127
+ instance_name?: string;
128
+ status?: string;
129
+ language?: string;
130
+ platform?: string;
131
+ tester_type?: string;
132
+ }
133
+ export interface SimulationStartInput {
134
+ product_id: string;
135
+ study_id: string;
136
+ tester_id: string;
137
+ config_id?: string;
138
+ platform?: string;
139
+ url?: string;
140
+ screen_format?: string;
141
+ max_interactions?: number;
142
+ language?: string;
143
+ locale?: string;
144
+ config_overrides?: Record<string, unknown>;
145
+ }
146
+ export interface SimulationStartResponse {
147
+ tester_id: string;
148
+ study_id: string;
149
+ job_id: string | null;
150
+ message: string;
151
+ }
152
+ export interface SimulationBatchItem {
153
+ study_id: string;
154
+ tester_id: string;
155
+ config_id?: string;
156
+ language?: string;
157
+ locale?: string;
158
+ config_overrides?: Record<string, unknown>;
159
+ }
160
+ export interface SimulationBatchStartInput {
161
+ product_id: string;
162
+ simulations: SimulationBatchItem[];
163
+ url?: string;
164
+ screen_format?: string;
165
+ platform?: string;
166
+ max_interactions?: number;
167
+ }
168
+ export interface SimulationBatchStartResponse {
169
+ results: SimulationStartResponse[];
170
+ }
171
+ export interface MediaSimulationStartInput {
172
+ product_id: string;
173
+ study_id: string;
174
+ tester_id: string;
175
+ config_id?: string;
176
+ max_interactions?: number;
177
+ language?: string;
178
+ config_overrides?: Record<string, unknown>;
179
+ }
180
+ export interface SimulationStatus {
181
+ job_id: string;
182
+ status: string | null;
183
+ create_time?: string;
184
+ completion_time?: string;
185
+ error?: string;
186
+ }
187
+ export interface SimulationCancelResponse {
188
+ job_id: string;
189
+ success: boolean;
190
+ message: string;
191
+ }
192
+ export interface SimulationConfig {
193
+ id: string;
194
+ name: string;
195
+ model_settings?: Record<string, unknown>;
196
+ simulation_settings?: Record<string, unknown>;
197
+ prompts?: Record<string, unknown>;
198
+ outputs?: Record<string, unknown>;
199
+ source_type?: string;
200
+ created_at: string;
201
+ updated_at: string;
202
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * TypeScript interfaces for Speqs API entities.
3
+ */
4
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "speqs",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "The command-line interface for Speqs",
5
5
  "type": "module",
6
6
  "bin": {