@ishlabs/cli 0.17.7 → 0.18.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 (62) hide show
  1. package/README.md +54 -54
  2. package/dist/commands/ask.d.ts +4 -4
  3. package/dist/commands/ask.js +66 -66
  4. package/dist/commands/chat.js +10 -10
  5. package/dist/commands/config.js +1 -1
  6. package/dist/commands/docs.js +1 -1
  7. package/dist/commands/iteration.js +57 -57
  8. package/dist/commands/mcp.d.ts +23 -0
  9. package/dist/commands/mcp.js +676 -0
  10. package/dist/commands/person.d.ts +5 -0
  11. package/dist/commands/{profile.js → person.js} +197 -162
  12. package/dist/commands/source.d.ts +6 -2
  13. package/dist/commands/source.js +35 -30
  14. package/dist/commands/study-analyze.d.ts +1 -1
  15. package/dist/commands/study-analyze.js +3 -3
  16. package/dist/commands/study-participant.d.ts +8 -0
  17. package/dist/commands/{study-tester.js → study-participant.js} +50 -50
  18. package/dist/commands/study-run.d.ts +6 -6
  19. package/dist/commands/study-run.js +295 -271
  20. package/dist/commands/study.js +89 -66
  21. package/dist/commands/workspace.js +13 -13
  22. package/dist/connect.js +5 -5
  23. package/dist/index.js +6 -4
  24. package/dist/lib/accessibility-profile.d.ts +1 -1
  25. package/dist/lib/accessibility-profile.js +1 -1
  26. package/dist/lib/alias-hydrate.js +4 -4
  27. package/dist/lib/alias-store.d.ts +5 -5
  28. package/dist/lib/alias-store.js +8 -8
  29. package/dist/lib/api-client.d.ts +1 -1
  30. package/dist/lib/api-client.js +1 -1
  31. package/dist/lib/billing.d.ts +11 -11
  32. package/dist/lib/billing.js +16 -16
  33. package/dist/lib/chat-endpoint-templates.js +1 -1
  34. package/dist/lib/command-helpers.d.ts +18 -18
  35. package/dist/lib/command-helpers.js +49 -37
  36. package/dist/lib/docs.js +560 -386
  37. package/dist/lib/enums.d.ts +2 -2
  38. package/dist/lib/enums.js +2 -2
  39. package/dist/lib/local-sim/browser.d.ts +1 -1
  40. package/dist/lib/local-sim/browser.js +1 -1
  41. package/dist/lib/local-sim/debug-report.d.ts +2 -2
  42. package/dist/lib/local-sim/debug-report.js +3 -3
  43. package/dist/lib/local-sim/loop.d.ts +5 -5
  44. package/dist/lib/local-sim/loop.js +38 -38
  45. package/dist/lib/local-sim/types.d.ts +12 -12
  46. package/dist/lib/mcp-clients.d.ts +51 -0
  47. package/dist/lib/mcp-clients.js +175 -0
  48. package/dist/lib/modality.d.ts +10 -10
  49. package/dist/lib/modality.js +46 -46
  50. package/dist/lib/output.d.ts +13 -12
  51. package/dist/lib/output.js +244 -184
  52. package/dist/lib/profile-sources.d.ts +64 -16
  53. package/dist/lib/profile-sources.js +91 -30
  54. package/dist/lib/skill-content.js +215 -168
  55. package/dist/lib/study-events.d.ts +3 -3
  56. package/dist/lib/study-events.js +1 -1
  57. package/dist/lib/study-inputs.d.ts +11 -1
  58. package/dist/lib/study-inputs.js +68 -17
  59. package/dist/lib/types.d.ts +105 -34
  60. package/package.json +1 -1
  61. package/dist/commands/profile.d.ts +0 -5
  62. package/dist/commands/study-tester.d.ts +0 -8
@@ -1,10 +1,14 @@
1
1
  /**
2
- * ish source — Upload and inspect audience-generation sources.
2
+ * ish source — Upload and inspect participant attachments used as generation inputs.
3
3
  *
4
- * Sources (transcripts, audio, images, PDFs) are inputs to `ish profile
4
+ * Attachments (transcripts, audio, images, PDFs) are inputs to `ish person
5
5
  * generate`. For one-shot generation, `profile generate --source <path>`
6
6
  * auto-uploads. Use these commands to upload once and reuse across multiple
7
7
  * generation runs, or to inspect processing status.
8
+ *
9
+ * The public CLI command name `source` is preserved for compatibility with
10
+ * existing scripts and agents; internally we call the unified
11
+ * /people/attachments/* endpoint family (see ADR-0034).
8
12
  */
9
13
  import type { Command } from "commander";
10
14
  export declare function registerSourceCommands(program: Command): void;
@@ -1,42 +1,47 @@
1
1
  /**
2
- * ish source — Upload and inspect audience-generation sources.
2
+ * ish source — Upload and inspect participant attachments used as generation inputs.
3
3
  *
4
- * Sources (transcripts, audio, images, PDFs) are inputs to `ish profile
4
+ * Attachments (transcripts, audio, images, PDFs) are inputs to `ish person
5
5
  * generate`. For one-shot generation, `profile generate --source <path>`
6
6
  * auto-uploads. Use these commands to upload once and reuse across multiple
7
7
  * generation runs, or to inspect processing status.
8
+ *
9
+ * The public CLI command name `source` is preserved for compatibility with
10
+ * existing scripts and agents; internally we call the unified
11
+ * /people/attachments/* endpoint family (see ADR-0034).
8
12
  */
9
13
  import { withClient, resolveWorkspace } from "../lib/command-helpers.js";
10
14
  import { resolveId, tagAlias, ALIAS_PREFIX } from "../lib/alias-store.js";
11
15
  import { normalizeEnumValue } from "../lib/enums.js";
12
- import { formatAudienceSource, output } from "../lib/output.js";
13
- import { inferSourceKind, uploadAndProcessSource, } from "../lib/profile-sources.js";
16
+ import { formatAttachment, output } from "../lib/output.js";
17
+ import { inferAttachmentKind, uploadAndProcessAttachment, } from "../lib/profile-sources.js";
14
18
  const VALID_KINDS = ["text_file", "audio", "image"];
15
19
  export function registerSourceCommands(program) {
16
20
  const source = program
17
21
  .command("source")
18
- .description("Upload and inspect audience-generation sources (transcripts, audio, images)")
22
+ .description("Upload and inspect participant attachments used as generation inputs (transcripts, audio, images)")
19
23
  .addHelpText("after", `
20
- A source is an input to \`ish profile generate\` — transcript, audio, image, or PDF. Use
21
- \`source upload\` when you want to reuse the same source across multiple generation runs;
22
- otherwise pass a local path directly to \`profile generate --source\` and it auto-uploads.
24
+ A source — internally a participant attachment — is an input to \`ish person generate\`:
25
+ transcript, audio, image, or PDF. Use \`source upload\` when you want to reuse the
26
+ same attachment across multiple generation runs; otherwise pass a local path directly
27
+ to \`profile generate --source\` and it auto-uploads.
23
28
 
24
29
  Concept pages: ish docs get-page concepts/source
25
30
  ish docs get-page concepts/profile`);
26
31
  source
27
32
  .command("upload")
28
- .description("Upload a file as an audience source and wait for processing")
33
+ .description("Upload a file as a participant attachment and wait for processing")
29
34
  .argument("<file>", "Local file path (transcript, audio, image, PDF, etc.)")
30
35
  .option("--workspace <id>", "Workspace (product) ID; falls back to active workspace")
31
- .option("--kind <kind>", "Source kind: text_file | audio | image (auto-detected if omitted; hyphen/underscore variants accepted)")
32
- .option("--description <text>", "Context note attached to the source (max 500 chars)")
33
- .option("--diarize", "Apply speaker diarization to audio sources (silently ignored for text/image)")
36
+ .option("--kind <kind>", "Attachment kind: text_file | audio | image (auto-detected if omitted; hyphen/underscore variants accepted)")
37
+ .option("--description <text>", "Context note attached to the file (max 500 chars)")
38
+ .option("--diarize", "Accepted for backward compat; audio diarization is the worker default and the flag is ignored.")
34
39
  .option("--no-wait", "Don't poll until terminal status — return after confirm")
35
40
  .option("--timeout <seconds>", "Poll timeout in seconds (default 300)", "300")
36
41
  .addHelpText("after", `
37
42
  Examples:
38
43
  $ ish source upload ./transcript.txt
39
- $ ish source upload ./call.mp3 --diarize --description "Q3 churn interview"
44
+ $ ish source upload ./call.mp3 --description "Q3 churn interview"
40
45
  $ ish source upload ./screenshot.png --kind image --no-wait`)
41
46
  .action(async (file, opts, cmd) => {
42
47
  await withClient(cmd, async (client, globals) => {
@@ -50,10 +55,10 @@ Examples:
50
55
  kind = normalized;
51
56
  }
52
57
  else {
53
- kind = inferSourceKind(file);
58
+ kind = inferAttachmentKind(file);
54
59
  }
55
60
  const timeoutMs = Math.max(1, parseInt(opts.timeout, 10)) * 1000;
56
- const src = await uploadAndProcessSource(client, {
61
+ const attachment = await uploadAndProcessAttachment(client, {
57
62
  productId,
58
63
  filePath: file,
59
64
  kind,
@@ -63,39 +68,39 @@ Examples:
63
68
  timeoutMs,
64
69
  quiet: globals.quiet,
65
70
  });
66
- formatAudienceSource(src, globals.json);
71
+ formatAttachment(attachment, globals.json);
67
72
  });
68
73
  });
69
74
  source
70
75
  .command("get")
71
- .description("Get an audience source's current status")
72
- .argument("<id>", "Source ID or alias")
73
- .addHelpText("after", "\nExamples:\n $ ish source get tps-3a4")
76
+ .description("Get a participant attachment's current status")
77
+ .argument("<id>", "Attachment ID or alias")
78
+ .addHelpText("after", "\nExamples:\n $ ish source get ps-3a4")
74
79
  .action(async (id, _opts, cmd) => {
75
80
  await withClient(cmd, async (client, globals) => {
76
- const src = await client.get(`/tester-profiles/sources/${resolveId(id)}`);
77
- formatAudienceSource(src, globals.json);
81
+ const attachment = await client.get(`/people/attachments/${resolveId(id)}`);
82
+ formatAttachment(attachment, globals.json);
78
83
  });
79
84
  });
80
85
  source
81
86
  .command("delete")
82
- .description("Delete an audience source plus its uploaded file")
83
- .argument("<id>", "Source ID or alias")
87
+ .description("Delete a participant attachment plus its uploaded file")
88
+ .argument("<id>", "Attachment ID or alias")
84
89
  .addHelpText("after", `
85
- Removes both the database row and the underlying uploaded file. Profiles
86
- already generated from this source remain in place they don't reference
87
- the source after generation.
90
+ The backend ref-counts attachment deletes: the file row + storage object are
91
+ removed only when no profile mappings remain. Profiles already generated from
92
+ this attachment keep their seed mapping until they themselves are deleted.
88
93
 
89
94
  Examples:
90
- $ ish source delete tps-3a4`)
95
+ $ ish source delete ps-3a4`)
91
96
  .action(async (id, _opts, cmd) => {
92
97
  await withClient(cmd, async (client, globals) => {
93
98
  const rid = resolveId(id);
94
- await client.del(`/tester-profiles/sources/${rid}`);
99
+ await client.del(`/people/attachments/${rid}`);
95
100
  output({
96
101
  id: rid,
97
- alias: tagAlias(ALIAS_PREFIX.testerProfileSource, rid),
98
- message: "Source deleted",
102
+ alias: tagAlias(ALIAS_PREFIX.personSource, rid),
103
+ message: "Attachment deleted",
99
104
  }, globals.json, { writePath: true });
100
105
  });
101
106
  });
@@ -19,7 +19,7 @@ export interface KeyInsight {
19
19
  title: string;
20
20
  description: string;
21
21
  category: "friction" | "confusion" | "blocker" | "observation" | "positive";
22
- tester_count: number;
22
+ participant_count: number;
23
23
  iteration_labels: string[];
24
24
  is_discarded: boolean;
25
25
  interaction_ids: string[];
@@ -51,12 +51,12 @@ async function pollAnalysisUntilDone(client, opts) {
51
51
  }
52
52
  }
53
53
  function formatKeyInsightsTable(insights) {
54
- printTable(["#", "CATEGORY", "TESTERS", "TITLE"], insights
54
+ printTable(["#", "CATEGORY", "PARTICIPANTS", "TITLE"], insights
55
55
  .filter((i) => !i.is_discarded)
56
56
  .map((i) => [
57
57
  String(i.sequence),
58
58
  i.category,
59
- String(i.tester_count),
59
+ String(i.participant_count),
60
60
  i.title,
61
61
  ]));
62
62
  }
@@ -95,7 +95,7 @@ Examples:
95
95
 
96
96
  Prerequisites (enforced server-side):
97
97
  - Study modality is one of: interactive, video, audio, text, image, document
98
- - At least 5 testers with completed interactions
98
+ - At least 5 participants with completed interactions
99
99
 
100
100
  Read prior runs:
101
101
  $ ish study insights <study-id>`)
@@ -0,0 +1,8 @@
1
+ /**
2
+ * ish study participant — Inspect and manage participants (low-level; usually
3
+ * created via `ish study run`).
4
+ *
5
+ * Default action: `ish study participant <id>` shows participant details and results.
6
+ */
7
+ import type { Command } from "commander";
8
+ export declare function attachStudyParticipantCommands(study: Command): void;
@@ -1,12 +1,12 @@
1
1
  /**
2
- * ish study tester — Inspect and manage testers (low-level; usually
2
+ * ish study participant — Inspect and manage participants (low-level; usually
3
3
  * created via `ish study run`).
4
4
  *
5
- * Default action: `ish study tester <id>` shows tester details and results.
5
+ * Default action: `ish study participant <id>` shows participant details and results.
6
6
  */
7
7
  import { withClient, readJsonFileOrStdin, resolveWorkspace } from "../lib/command-helpers.js";
8
8
  import { resolveId, tagAlias, ALIAS_PREFIX } from "../lib/alias-store.js";
9
- import { formatTesterDetail, buildTesterSummary, output } from "../lib/output.js";
9
+ import { formatParticipantDetail, buildParticipantSummary, output } from "../lib/output.js";
10
10
  /** Pick the latest iteration on a study (highest order_index, falling back to last). */
11
11
  async function latestIterationForStudy(client, studyId) {
12
12
  const study = await client.get(`/studies/${studyId}`);
@@ -18,12 +18,12 @@ async function latestIterationForStudy(client, studyId) {
18
18
  return sorted[0].id;
19
19
  }
20
20
  /**
21
- * Walk a parsed JSON body and resolve any alias-shaped strings (tp-..., i-..., s-...)
21
+ * Walk a parsed JSON body and resolve any alias-shaped strings (p-..., i-..., s-...)
22
22
  * appearing in well-known id fields. Pure client-side: avoids a backend round-trip
23
23
  * when the body uses local aliases that the backend wouldn't recognise.
24
24
  */
25
- const ALIAS_FIELDS = new Set(["tester_profile_id", "iteration_id", "study_id"]);
26
- const ALIAS_RE = /^(tp|i|s)-[0-9a-f]{3,}$/i;
25
+ const ALIAS_FIELDS = new Set(["person_id", "iteration_id", "study_id"]);
26
+ const ALIAS_RE = /^(p|i|s)-[0-9a-f]{3,}$/i;
27
27
  function prewalkAliases(value) {
28
28
  if (Array.isArray(value)) {
29
29
  return value.map(prewalkAliases);
@@ -47,20 +47,20 @@ function prewalkAliases(value) {
47
47
  }
48
48
  return value;
49
49
  }
50
- export function attachStudyTesterCommands(study) {
51
- const tester = study
52
- .command("tester")
53
- .description("Inspect or manage testers (low-level; usually created via `study run`)")
54
- .argument("[id]", "Tester ID — pass directly to view tester details and results")
55
- .option("--workspace <id>", "Workspace ID; accepted for consistency (workspace is inferred from the tester)")
50
+ export function attachStudyParticipantCommands(study) {
51
+ const participant = study
52
+ .command("participant")
53
+ .description("Inspect or manage participants (low-level; usually created via `study run`)")
54
+ .argument("[id]", "Participant ID — pass directly to view participant details and results")
55
+ .option("--workspace <id>", "Workspace ID; accepted for consistency (workspace is inferred from the participant)")
56
56
  .option("--summary", "Lean projection: alias + status + sentiment + comment + error_message. Drops the action timeline / interactions array.")
57
57
  .addHelpText("after", `
58
58
  Examples:
59
- $ ish study tester t-d4e # show tester details
60
- $ ish study tester t-d4e --summary --json # headline only (sentiment + comment)
61
- $ ish study tester create --iteration <id> --profile <id>
62
- $ ish study tester batch-create --iteration <id> --file testers.json
63
- $ ish study tester delete t-d4e
59
+ $ ish study participant pt-d4e # show participant details
60
+ $ ish study participant pt-d4e --summary --json # headline only (sentiment + comment)
61
+ $ ish study participant create --iteration <id> --person <id>
62
+ $ ish study participant batch-create --iteration <id> --file participants.json
63
+ $ ish study participant delete pt-d4e
64
64
 
65
65
  Tips:
66
66
  Use \`--get <path>\` to grab one value (e.g. \`--get sentiment\`),
@@ -72,27 +72,27 @@ Tips:
72
72
  await withClient(cmd, async (client, globals) => {
73
73
  if (opts.workspace)
74
74
  resolveWorkspace(opts.workspace);
75
- const data = await client.get(`/testers/${resolveId(id)}`);
75
+ const data = await client.get(`/participants/${resolveId(id)}`);
76
76
  const result = data;
77
77
  if (result.id)
78
- result.alias = tagAlias(ALIAS_PREFIX.tester, String(result.id));
78
+ result.alias = tagAlias(ALIAS_PREFIX.participant, String(result.id));
79
79
  if (opts.summary) {
80
- output(buildTesterSummary(result), globals.json, { preProjected: true });
80
+ output(buildParticipantSummary(result), globals.json, { preProjected: true });
81
81
  return;
82
82
  }
83
- formatTesterDetail(result, globals.json);
83
+ formatParticipantDetail(result, globals.json);
84
84
  });
85
85
  });
86
- tester
86
+ participant
87
87
  .command("create")
88
- .description("Create a tester (low-level)")
88
+ .description("Create a participant (low-level)")
89
89
  .option("--iteration <id>", "Iteration ID (or use --study to pick the latest iteration on a study)")
90
90
  .option("--study <id>", "Study ID; resolves to the latest iteration on that study (alternative to --iteration)")
91
- .requiredOption("--profile <id>", "Tester profile ID")
91
+ .requiredOption("--person <id>", "Participant profile ID")
92
92
  .option("--language <lang>", "Language code (e.g. en, sv)")
93
93
  .option("--platform <platform>", "Platform (browser, android, figma, code)")
94
- .option("--tester-type <type>", "Tester type (ai, human)", "ai")
95
- .addHelpText("after", "\nExamples:\n $ ish study tester create --iteration <id> --profile <id>\n $ ish study tester create --study s-XXX --profile tp-XXX\n $ ish study tester create --iteration <id> --profile <id> --platform android --json")
94
+ .option("--participant-type <type>", "Participant type (ai, human)", "ai")
95
+ .addHelpText("after", "\nExamples:\n $ ish study participant create --iteration <id> --person <id>\n $ ish study participant create --study s-XXX --person p-XXX\n $ ish study participant create --iteration <id> --person <id> --platform android --json")
96
96
  .action(async (opts, cmd) => {
97
97
  await withClient(cmd, async (client, globals) => {
98
98
  if (!opts.iteration && !opts.study) {
@@ -105,63 +105,63 @@ Tips:
105
105
  ? resolveId(opts.iteration)
106
106
  : await latestIterationForStudy(client, resolveId(opts.study));
107
107
  const body = {
108
- tester_profile_id: resolveId(opts.profile),
109
- tester_type: opts.testerType,
108
+ person_id: resolveId(opts.person),
109
+ participant_type: opts.participantType,
110
110
  ...(opts.language && { language: opts.language }),
111
111
  ...(opts.platform && { platform: opts.platform }),
112
112
  };
113
- const data = await client.post(`/iterations/${iterationId}/testers`, body);
113
+ const data = await client.post(`/iterations/${iterationId}/participants`, body);
114
114
  const result = data;
115
115
  if (result.id)
116
- result.alias = tagAlias(ALIAS_PREFIX.tester, String(result.id));
116
+ result.alias = tagAlias(ALIAS_PREFIX.participant, String(result.id));
117
117
  output(result, globals.json);
118
118
  });
119
119
  });
120
- tester
120
+ participant
121
121
  .command("batch-create")
122
- .description("Create multiple testers (low-level)")
122
+ .description("Create multiple participants (low-level)")
123
123
  .requiredOption("--iteration <id>", "Iteration ID")
124
- .option("--file <path>", "JSON file with testers array (alternative to --profiles)")
125
- .option("--profiles <ids>", "Comma-separated profile IDs/aliases; shortcut for --file with one tester per profile (mutually exclusive with --file)")
126
- .addHelpText("after", "\nExamples:\n $ ish study tester batch-create --iteration <id> --file testers.json\n $ ish study tester batch-create --iteration <id> --profiles tp-eba,tp-289,tp-913\n\n Expected JSON: [{ \"tester_profile_id\": \"<id>\", \"platform\": \"browser\" }, ...]\n Profile-id strings inside --file (tester_profile_id, iteration_id, study_id) are resolved client-side via the local alias store before submitting.")
124
+ .option("--file <path>", "JSON file with participants array (alternative to --persons)")
125
+ .option("--persons <ids>", "Comma-separated profile IDs/aliases; shortcut for --file with one participant per profile (mutually exclusive with --file)")
126
+ .addHelpText("after", "\nExamples:\n $ ish study participant batch-create --iteration <id> --file participants.json\n $ ish study participant batch-create --iteration <id> --persons p-eba,p-289,p-913\n\n Expected JSON: [{ \"person_id\": \"<id>\", \"platform\": \"browser\" }, ...]\n Profile-id strings inside --file (person_id, iteration_id, study_id) are resolved client-side via the local alias store before submitting.")
127
127
  .action(async (opts, cmd) => {
128
128
  await withClient(cmd, async (client, globals) => {
129
- if (!opts.file && !opts.profiles) {
130
- throw new Error("Provide --file <path> or --profiles <ids>.");
129
+ if (!opts.file && !opts.persons) {
130
+ throw new Error("Provide --file <path> or --persons <ids>.");
131
131
  }
132
- if (opts.file && opts.profiles) {
133
- throw new Error("Pass either --file or --profiles, not both.");
132
+ if (opts.file && opts.persons) {
133
+ throw new Error("Pass either --file or --persons, not both.");
134
134
  }
135
135
  const iterationId = resolveId(opts.iteration);
136
136
  let body;
137
- if (opts.profiles) {
138
- const ids = opts.profiles
137
+ if (opts.persons) {
138
+ const ids = opts.persons
139
139
  .split(",")
140
140
  .map((s) => s.trim())
141
141
  .filter(Boolean)
142
142
  .map((s) => resolveId(s));
143
143
  if (ids.length === 0) {
144
- throw new Error("--profiles must contain at least one profile id/alias.");
144
+ throw new Error("--persons must contain at least one profile id/alias.");
145
145
  }
146
- body = { testers: ids.map((pid) => ({ tester_profile_id: pid, tester_type: "ai" })) };
146
+ body = { participants: ids.map((pid) => ({ person_id: pid, participant_type: "ai" })) };
147
147
  }
148
148
  else {
149
149
  const parsed = await readJsonFileOrStdin(opts.file);
150
150
  body = prewalkAliases(parsed);
151
151
  }
152
- const data = await client.post(`/iterations/${iterationId}/testers/batch`, body);
152
+ const data = await client.post(`/iterations/${iterationId}/participants/batch`, body);
153
153
  output(data, globals.json);
154
154
  });
155
155
  });
156
- tester
156
+ participant
157
157
  .command("delete")
158
- .description("Delete a tester")
159
- .argument("<id>", "Tester ID")
160
- .addHelpText("after", "\nExamples:\n $ ish study tester delete <id>")
158
+ .description("Delete a participant")
159
+ .argument("<id>", "Participant ID")
160
+ .addHelpText("after", "\nExamples:\n $ ish study participant delete <id>")
161
161
  .action(async (id, _opts, cmd) => {
162
162
  await withClient(cmd, async (client, globals) => {
163
- await client.del(`/testers/${resolveId(id)}`);
164
- output({ message: "Tester deleted" }, globals.json);
163
+ await client.del(`/participants/${resolveId(id)}`);
164
+ output({ message: "Participant deleted" }, globals.json);
165
165
  });
166
166
  });
167
167
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * ish study run — Run, monitor, and cancel simulations of a study.
3
3
  *
4
- * `ish study run` creates testers for the latest (or specified) iteration
4
+ * `ish study run` creates participants for the latest (or specified) iteration
5
5
  * and dispatches simulations. Iterations are created separately via
6
6
  * `ish iteration create`, which carries the URL/content details.
7
7
  *
@@ -13,7 +13,7 @@ import type { Command } from "commander";
13
13
  * produce a structured envelope (`error_code: "wait_timeout"`, exit 5
14
14
  * transient) distinct from the generic timeout/network/server errors
15
15
  * that the api-client wrapper produces. Carries the in-flight progress
16
- * (testers done / total) so `study wait` always emits final state JSON
16
+ * (participants done / total) so `study wait` always emits final state JSON
17
17
  * even when it bails on the timer.
18
18
  */
19
19
  export declare class WaitTimeoutError extends Error {
@@ -24,7 +24,7 @@ export declare class WaitTimeoutError extends Error {
24
24
  done: number;
25
25
  total: number;
26
26
  pending: number;
27
- rows: TesterStatusRow[];
27
+ rows: ParticipantStatusRow[];
28
28
  };
29
29
  readonly error_code = "wait_timeout";
30
30
  readonly retryable = true;
@@ -35,13 +35,13 @@ export declare class WaitTimeoutError extends Error {
35
35
  done: number;
36
36
  total: number;
37
37
  pending: number;
38
- rows: TesterStatusRow[];
38
+ rows: ParticipantStatusRow[];
39
39
  });
40
40
  }
41
- interface TesterStatusRow {
41
+ interface ParticipantStatusRow {
42
42
  id: string;
43
43
  status: string;
44
- tester_name: string;
44
+ participant_name: string;
45
45
  interaction_count: number;
46
46
  error_message?: string;
47
47
  }