@ishlabs/cli 0.8.1 → 0.8.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.
Files changed (70) hide show
  1. package/README.md +323 -21
  2. package/dist/auth.d.ts +17 -1
  3. package/dist/auth.js +62 -9
  4. package/dist/commands/ask.d.ts +5 -0
  5. package/dist/commands/ask.js +722 -0
  6. package/dist/commands/config.js +25 -1
  7. package/dist/commands/docs.d.ts +17 -0
  8. package/dist/commands/docs.js +147 -0
  9. package/dist/commands/init.d.ts +16 -0
  10. package/dist/commands/init.js +182 -0
  11. package/dist/commands/iteration.d.ts +5 -1
  12. package/dist/commands/iteration.js +243 -31
  13. package/dist/commands/profile.d.ts +5 -0
  14. package/dist/commands/profile.js +313 -0
  15. package/dist/commands/source.d.ts +10 -0
  16. package/dist/commands/source.js +78 -0
  17. package/dist/commands/study-run.d.ts +11 -0
  18. package/dist/commands/study-run.js +552 -0
  19. package/dist/commands/study-tester.d.ts +8 -0
  20. package/dist/commands/study-tester.js +149 -0
  21. package/dist/commands/study.js +145 -70
  22. package/dist/commands/workspace.js +193 -7
  23. package/dist/config.d.ts +3 -1
  24. package/dist/config.js +10 -10
  25. package/dist/connect.d.ts +4 -1
  26. package/dist/connect.js +127 -94
  27. package/dist/index.js +82 -34
  28. package/dist/lib/alias-store.d.ts +3 -0
  29. package/dist/lib/alias-store.js +9 -7
  30. package/dist/lib/api-client.d.ts +9 -6
  31. package/dist/lib/api-client.js +87 -26
  32. package/dist/lib/ask-questions.d.ts +9 -0
  33. package/dist/lib/ask-questions.js +35 -0
  34. package/dist/lib/ask-variants.d.ts +48 -0
  35. package/dist/lib/ask-variants.js +236 -0
  36. package/dist/lib/auth.d.ts +1 -1
  37. package/dist/lib/auth.js +24 -8
  38. package/dist/lib/colors.d.ts +30 -0
  39. package/dist/lib/colors.js +48 -0
  40. package/dist/lib/command-helpers.d.ts +74 -0
  41. package/dist/lib/command-helpers.js +232 -6
  42. package/dist/lib/docs.d.ts +32 -0
  43. package/dist/lib/docs.js +930 -0
  44. package/dist/lib/local-sim/browser.d.ts +0 -1
  45. package/dist/lib/local-sim/browser.js +0 -2
  46. package/dist/lib/local-sim/install.d.ts +4 -7
  47. package/dist/lib/local-sim/install.js +6 -21
  48. package/dist/lib/output.d.ts +25 -3
  49. package/dist/lib/output.js +465 -20
  50. package/dist/lib/paths.d.ts +14 -0
  51. package/dist/lib/paths.js +36 -0
  52. package/dist/lib/profile-sources.d.ts +55 -0
  53. package/dist/lib/profile-sources.js +157 -0
  54. package/dist/lib/site-access.d.ts +80 -0
  55. package/dist/lib/site-access.js +188 -0
  56. package/dist/lib/skill-content.d.ts +31 -0
  57. package/dist/lib/skill-content.js +462 -0
  58. package/dist/lib/study-inputs.d.ts +20 -0
  59. package/dist/lib/study-inputs.js +72 -0
  60. package/dist/lib/types.d.ts +207 -9
  61. package/dist/lib/types.js +7 -0
  62. package/dist/lib/upload.js +2 -2
  63. package/dist/upgrade.js +11 -1
  64. package/package.json +1 -1
  65. package/dist/commands/simulation.d.ts +0 -10
  66. package/dist/commands/simulation.js +0 -647
  67. package/dist/commands/tester-profile.d.ts +0 -5
  68. package/dist/commands/tester-profile.js +0 -109
  69. package/dist/commands/tester.d.ts +0 -5
  70. package/dist/commands/tester.js +0 -73
@@ -23,6 +23,37 @@ export interface ProductUpdateInput {
23
23
  color?: string;
24
24
  base_url?: string;
25
25
  }
26
+ export type SecretScope = "agent" | "project";
27
+ export type SecretVariableType = "secret" | "variable";
28
+ export interface Secret {
29
+ id: string;
30
+ product_id: string;
31
+ key: string;
32
+ description?: string | null;
33
+ scope: SecretScope;
34
+ variable_type: SecretVariableType;
35
+ expires_at?: string | null;
36
+ created_at: string;
37
+ updated_at: string;
38
+ }
39
+ export interface SecretCreateInput {
40
+ key: string;
41
+ value: string;
42
+ description?: string;
43
+ scope: SecretScope;
44
+ variable_type: SecretVariableType;
45
+ expires_at?: string | null;
46
+ }
47
+ export interface SecretUpdateInput {
48
+ value?: string;
49
+ description?: string;
50
+ scope?: SecretScope;
51
+ variable_type?: SecretVariableType;
52
+ expires_at?: string | null;
53
+ }
54
+ export interface SecretBatchCreateInput {
55
+ secrets: SecretCreateInput[];
56
+ }
26
57
  export interface Assignment {
27
58
  id?: string;
28
59
  name: string;
@@ -108,6 +139,49 @@ export interface TesterProfile {
108
139
  name: string;
109
140
  [key: string]: unknown;
110
141
  }
142
+ export type SourceKind = "text_file" | "audio" | "image";
143
+ export type SourceStatus = "pending_upload" | "uploaded" | "transcribing" | "processed" | "failed";
144
+ export interface AudienceSource {
145
+ id: string;
146
+ product_id: string;
147
+ kind: SourceKind;
148
+ status: SourceStatus;
149
+ original_filename: string;
150
+ content_type: string;
151
+ extracted_text_length?: number | null;
152
+ error?: string | null;
153
+ created_at: string;
154
+ }
155
+ export interface InitiateSourceUploadResponse {
156
+ source_id: string;
157
+ signed_url: string;
158
+ upload_token: string;
159
+ }
160
+ export interface ProposeCountResponse {
161
+ proposed_count: number;
162
+ rationale: string;
163
+ }
164
+ export interface GenerateAudienceRequest {
165
+ product_id: string;
166
+ description?: string;
167
+ source_upload_ids?: string[];
168
+ count?: number;
169
+ }
170
+ export interface GeneratedProfile {
171
+ id: string;
172
+ name: string;
173
+ type: "ai" | "human";
174
+ bio?: string | null;
175
+ date_of_birth?: string | null;
176
+ gender?: "male" | "female" | "non-binary" | null;
177
+ country?: string | null;
178
+ city?: string | null;
179
+ occupation?: string | null;
180
+ tech_savviness?: string | null;
181
+ product_id?: string | null;
182
+ custom_field_values?: Record<string, unknown>;
183
+ [key: string]: unknown;
184
+ }
111
185
  export interface Tester {
112
186
  id: string;
113
187
  iteration_id: string;
@@ -139,15 +213,6 @@ export interface SimulationStartResponse {
139
213
  export interface SimulationBatchStartResponse {
140
214
  results: SimulationStartResponse[];
141
215
  }
142
- export interface MediaSimulationStartInput {
143
- product_id: string;
144
- study_id: string;
145
- tester_id: string;
146
- config_id: string;
147
- max_interactions?: number;
148
- language?: string;
149
- config_overrides?: Record<string, unknown>;
150
- }
151
216
  export interface MediaBatchStartResponse {
152
217
  results: SimulationStartResponse[];
153
218
  }
@@ -177,3 +242,136 @@ export interface SimulationConfig {
177
242
  created_at: string;
178
243
  updated_at: string;
179
244
  }
245
+ export type AskVariantKind = "image" | "text" | "audio" | "video" | "document";
246
+ export declare const ASK_VARIANT_KINDS: AskVariantKind[];
247
+ export type AskRoundStatus = "running" | "completed" | "errored";
248
+ export type AskResponseStatus = "pending" | "completed" | "errored";
249
+ export interface AskVariant {
250
+ id: string;
251
+ kind: AskVariantKind;
252
+ label?: string | null;
253
+ /** File path on write, public URL on read for media kinds; literal text for kind="text". */
254
+ content: string;
255
+ }
256
+ export interface AskVariantInput {
257
+ id?: string;
258
+ kind: AskVariantKind;
259
+ label?: string;
260
+ content: string;
261
+ }
262
+ export interface InterviewAnswer {
263
+ question_id: string;
264
+ answer: unknown;
265
+ rationale?: string;
266
+ }
267
+ export interface AskRoundInput {
268
+ prompt: string;
269
+ variants?: AskVariantInput[];
270
+ wants_pick?: boolean;
271
+ wants_ratings?: boolean;
272
+ questions?: InterviewQuestion[];
273
+ }
274
+ export interface AskCreateInput {
275
+ name: string;
276
+ description?: string;
277
+ language?: string;
278
+ tester_profile_ids: string[];
279
+ first_round: AskRoundInput;
280
+ }
281
+ export interface AskUpdateInput {
282
+ name?: string;
283
+ description?: string;
284
+ is_archived?: boolean;
285
+ }
286
+ export interface AddTestersInput {
287
+ tester_profile_ids: string[];
288
+ round_id: string;
289
+ backfill_prior_rounds?: boolean;
290
+ }
291
+ export interface AddRoundQuestionsInput {
292
+ questions: InterviewQuestion[];
293
+ }
294
+ export interface AskAudienceTester {
295
+ id: string;
296
+ ask_id?: string;
297
+ tester_profile_id?: string;
298
+ tester_profile?: Record<string, unknown> | null;
299
+ instance_name?: string;
300
+ status?: string;
301
+ [key: string]: unknown;
302
+ }
303
+ export interface AskResponseModel {
304
+ id: string;
305
+ ask_round_id: string;
306
+ tester_id: string;
307
+ comment?: string | null;
308
+ variant_pick_id?: string | null;
309
+ pick_confidence?: number | null;
310
+ variant_ratings?: Record<string, number> | null;
311
+ question_answers?: InterviewAnswer[] | null;
312
+ status: AskResponseStatus;
313
+ created_at: string;
314
+ }
315
+ export interface AskRoundSummary {
316
+ id?: string;
317
+ comment?: string;
318
+ [key: string]: unknown;
319
+ }
320
+ export interface AskRound {
321
+ id: string;
322
+ ask_id: string;
323
+ order_index: number;
324
+ prompt: string;
325
+ variants: AskVariant[];
326
+ wants_pick: boolean;
327
+ wants_ratings: boolean;
328
+ questions: InterviewQuestion[];
329
+ responses: AskResponseModel[];
330
+ summary?: AskRoundSummary | null;
331
+ status: AskRoundStatus;
332
+ created_at: string;
333
+ completed_at?: string | null;
334
+ }
335
+ export interface Ask {
336
+ id: string;
337
+ product_id: string;
338
+ name: string;
339
+ description?: string | null;
340
+ is_archived: boolean;
341
+ testers: AskAudienceTester[];
342
+ rounds: AskRound[];
343
+ created_at: string;
344
+ updated_at: string;
345
+ created_by?: string | null;
346
+ }
347
+ export interface AskListItem {
348
+ id: string;
349
+ product_id: string;
350
+ name: string;
351
+ description?: string | null;
352
+ is_archived: boolean;
353
+ audience_count: number;
354
+ round_count: number;
355
+ last_round_at?: string | null;
356
+ created_at: string;
357
+ updated_at: string;
358
+ created_by?: string | null;
359
+ }
360
+ export interface AskVariantUploadItemInput {
361
+ content_type: string;
362
+ file_size_bytes?: number;
363
+ }
364
+ export interface AskVariantUploadInput {
365
+ items: AskVariantUploadItemInput[];
366
+ }
367
+ export interface AskVariantUploadResult {
368
+ upload_info: {
369
+ signed_upload_url: string;
370
+ file_path: string;
371
+ expires_in_seconds: number;
372
+ };
373
+ content_url: string;
374
+ }
375
+ export interface AskVariantUploadResponse {
376
+ items: AskVariantUploadResult[];
377
+ }
package/dist/lib/types.js CHANGED
@@ -10,3 +10,10 @@ export const VALID_CONTENT_TYPES = {
10
10
  image: ["product", "photography", "infographic", "artwork", "interface", "social_post", "ad"],
11
11
  document: ["deck", "presentation", "report", "brochure", "guide"],
12
12
  };
13
+ export const ASK_VARIANT_KINDS = [
14
+ "image",
15
+ "text",
16
+ "audio",
17
+ "video",
18
+ "document",
19
+ ];
@@ -109,7 +109,7 @@ export async function uploadStudyContent(client, studyId, filePath, opts) {
109
109
  process.stderr.write(msg); };
110
110
  // Step 1: Request a signed upload URL from the backend
111
111
  log(`Uploading ${name} (${sizeMB} MB)...`);
112
- const uploadResp = await client.post(`/studies/${studyId}/content/upload`, { content_type: mime, file_size_bytes: size });
112
+ const uploadResp = await client.post(`/studies/${studyId}/content/upload`, { content_type: mime, file_size_bytes: size }, { timeout: 60_000 });
113
113
  // Step 2: PUT the raw file bytes to the signed URL
114
114
  const fileBuffer = await readFile(resolved);
115
115
  const putResp = await fetch(uploadResp.upload_info.signed_upload_url, {
@@ -129,7 +129,7 @@ export async function uploadStudyContent(client, studyId, filePath, opts) {
129
129
  await client.put(`/studies/${studyId}/content/upload/complete`, {
130
130
  file_path: uploadResp.upload_info.file_path,
131
131
  is_uploaded: true,
132
- });
132
+ }, { timeout: 60_000 });
133
133
  log(" done.\n");
134
134
  return uploadResp.content_url;
135
135
  }
package/dist/upgrade.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createWriteStream, renameSync, unlinkSync, chmodSync } from "node:fs";
2
- import { join, dirname } from "node:path";
2
+ import { join, dirname, basename } from "node:path";
3
3
  import { pipeline } from "node:stream/promises";
4
4
  import { Readable } from "node:stream";
5
5
  const BASE_URL = "https://ishlabs.io";
@@ -25,6 +25,16 @@ async function getLatestVersion() {
25
25
  return data.version;
26
26
  }
27
27
  export async function upgrade(currentVersion, targetVersion) {
28
+ // Detect npm-linked / npm-installed-globally CLI: process.execPath is `node`, not the ish binary.
29
+ const execBase = basename(process.execPath).toLowerCase();
30
+ const looksLikeNode = execBase === "node" || execBase === "node.exe";
31
+ // Also detect when our script is running under a node_modules directory (npm install -g symlinks here).
32
+ const scriptUrl = import.meta.url;
33
+ const runningFromNodeModules = scriptUrl.includes("/node_modules/");
34
+ if (looksLikeNode || runningFromNodeModules) {
35
+ throw new Error("Cannot self-upgrade an npm-installed CLI (would overwrite the node binary). " +
36
+ "Run `npm install -g @ishlabs/cli@latest` instead.");
37
+ }
28
38
  if (targetVersion && !/^\d+\.\d+\.\d+/.test(targetVersion)) {
29
39
  throw new Error(`Invalid version format: ${targetVersion}`);
30
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ishlabs/cli",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "The command-line interface for Ish",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,10 +0,0 @@
1
- /**
2
- * ish simulation — Run, monitor, and cancel simulations.
3
- *
4
- * Primary command: `ish simulation run` — orchestrates the full flow:
5
- * 1. Creates iteration (if not provided)
6
- * 2. Creates testers from profiles
7
- * 3. Starts simulations (interactive or media, based on study modality)
8
- */
9
- import type { Command } from "commander";
10
- export declare function registerSimulationCommands(program: Command): void;