@ishlabs/cli 0.8.4 → 0.9.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.
- package/README.md +2 -2
- package/dist/auth.d.ts +38 -4
- package/dist/auth.js +205 -39
- package/dist/commands/ask.js +28 -2
- package/dist/commands/iteration.js +105 -6
- package/dist/commands/profile.js +25 -12
- package/dist/commands/source.js +24 -2
- package/dist/commands/study.js +14 -6
- package/dist/config.d.ts +4 -0
- package/dist/connect.js +100 -14
- package/dist/index.js +6 -3
- package/dist/lib/auth.js +7 -1
- package/dist/lib/command-helpers.d.ts +37 -0
- package/dist/lib/command-helpers.js +199 -7
- package/dist/lib/docs.js +316 -39
- package/dist/lib/output.d.ts +6 -0
- package/dist/lib/output.js +133 -2
- package/dist/lib/skill-content.js +120 -6
- package/package.json +3 -3
package/dist/lib/docs.js
CHANGED
|
@@ -18,7 +18,7 @@ Workspace (= product)
|
|
|
18
18
|
├── Tester Profiles ────── reusable audience personas (alias: tp-…)
|
|
19
19
|
│ └── Sources ──────── transcripts/audio/images that seed generation
|
|
20
20
|
├── Study ──────────────── persistent research artifact (alias: s-…)
|
|
21
|
-
│ ├── modality ──────── interactive | text | video | audio | image | document
|
|
21
|
+
│ ├── modality ──────── interactive | text | video | audio | image | document | chat
|
|
22
22
|
│ ├── assignments ───── tasks the tester does
|
|
23
23
|
│ ├── questionnaire ─── questions the tester answers
|
|
24
24
|
│ └── Iterations ────── one configured run (URL or content) (alias: i-…)
|
|
@@ -47,7 +47,8 @@ Two top-level run verbs:
|
|
|
47
47
|
and prints active workspace/study/ask. See \`concepts/active-context\`.
|
|
48
48
|
- Running your first study? \`ish docs get-page guides/first-study\`.
|
|
49
49
|
- Comparing study vs ask? \`ish docs get-page concepts/run-verbs\`.
|
|
50
|
-
-
|
|
50
|
+
- **Output modes** (display vs capture vs chain — \`--human\`, \`--get\`,
|
|
51
|
+
\`--json\`)? \`ish docs get-page reference/json-mode\`.
|
|
51
52
|
- Auth gated URL? \`ish docs get-page concepts/site-access\`.
|
|
52
53
|
|
|
53
54
|
## Install the skill into this project
|
|
@@ -74,6 +75,22 @@ A workspace carries:
|
|
|
74
75
|
- Site-access credentials (encrypted at rest) — see \`concepts/site-access\`.
|
|
75
76
|
- Tester profiles + sources visible to every study/ask in the workspace.
|
|
76
77
|
|
|
78
|
+
## Selecting a workspace per command
|
|
79
|
+
|
|
80
|
+
\`--workspace <id>\` works at the **program root** as well as on each
|
|
81
|
+
subcommand — both forms are equivalent, and the subcommand-level flag
|
|
82
|
+
wins on conflict:
|
|
83
|
+
|
|
84
|
+
\`\`\`
|
|
85
|
+
ish --workspace w-6ec study list # program root
|
|
86
|
+
ish study list --workspace w-6ec # subcommand (same effect)
|
|
87
|
+
ish --workspace w-6ec study list --workspace w-other # w-other wins
|
|
88
|
+
\`\`\`
|
|
89
|
+
|
|
90
|
+
Use whichever is most natural for your scripting. Without either, the
|
|
91
|
+
CLI falls back to \`ISH_WORKSPACE\` (env var) and then the
|
|
92
|
+
\`workspace\` saved in \`~/.ish/config.json\`.
|
|
93
|
+
|
|
77
94
|
## Common commands
|
|
78
95
|
|
|
79
96
|
\`\`\`
|
|
@@ -91,8 +108,9 @@ ish workspace site-access status
|
|
|
91
108
|
const CONCEPT_STUDY = `# concept: study
|
|
92
109
|
|
|
93
110
|
A **study** is the persistent research artifact. It defines:
|
|
94
|
-
- \`modality\`: \`interactive\` (the tester drives a real browser)
|
|
95
|
-
\`text | video | audio | image | document\` (media reaction studies)
|
|
111
|
+
- \`modality\`: \`interactive\` (the tester drives a real browser), one of
|
|
112
|
+
\`text | video | audio | image | document\` (media reaction studies),
|
|
113
|
+
or \`chat\` (multi-turn probe against an external chatbot endpoint).
|
|
96
114
|
- \`content_type\` (media studies only): \`email | social_post | ad | …\` —
|
|
97
115
|
controls the framing the tester is given.
|
|
98
116
|
- \`assignments\`: the tasks the tester performs. See \`concepts/assignment\`.
|
|
@@ -148,6 +166,21 @@ Every study response carries two status-shaped fields:
|
|
|
148
166
|
The CLI also surfaces a \`status_inferred\` field + stderr warning when
|
|
149
167
|
it detects raw-vs-derived inconsistencies. See \`reference/json-mode\`.
|
|
150
168
|
|
|
169
|
+
## Deleting a study
|
|
170
|
+
|
|
171
|
+
\`ish study delete <id>\` requires explicit confirmation:
|
|
172
|
+
|
|
173
|
+
- **Interactive (TTY)**: prompts on stderr; type \`y\` to proceed.
|
|
174
|
+
- **Non-interactive** (\`--json\`, piped, or non-TTY stdin): pass
|
|
175
|
+
\`-y\` / \`--yes\` to confirm. Without it, the CLI exits with usage
|
|
176
|
+
code 2 rather than deleting silently.
|
|
177
|
+
|
|
178
|
+
\`\`\`
|
|
179
|
+
ish study delete s-b2c # interactive prompt
|
|
180
|
+
ish study delete s-b2c --yes # skip prompt
|
|
181
|
+
ish study delete s-b2c --json --yes # JSON consumers must be explicit
|
|
182
|
+
\`\`\`
|
|
183
|
+
|
|
151
184
|
## Generate vs create
|
|
152
185
|
|
|
153
186
|
\`ish study generate --problem "..."\` runs an LLM-backed flow that
|
|
@@ -168,9 +201,9 @@ pick was wrong.
|
|
|
168
201
|
const CONCEPT_ITERATION = `# concept: iteration
|
|
169
202
|
|
|
170
203
|
An **iteration** is one configured run of a study. It carries the
|
|
171
|
-
volatile bits — the URL (interactive)
|
|
172
|
-
while the study carries the persistent
|
|
173
|
-
modality).
|
|
204
|
+
volatile bits — the URL (interactive), the media (video/text/etc.), or
|
|
205
|
+
the chatbot endpoint (chat) — while the study carries the persistent
|
|
206
|
+
shape (assignments, questionnaire, modality).
|
|
174
207
|
|
|
175
208
|
- Alias prefix: \`i-\`
|
|
176
209
|
- A study has 1..N iterations. \`ish study run\` defaults to the latest.
|
|
@@ -192,9 +225,19 @@ ish iteration create --study s-b2c --url https://example.com
|
|
|
192
225
|
# Interactive on mobile screen format:
|
|
193
226
|
ish iteration create --url https://example.com --screen-format mobile_portrait
|
|
194
227
|
|
|
228
|
+
# Figma interactive (file_key + start_node_id required):
|
|
229
|
+
ish iteration create --platform figma --url https://figma.com/proto \\
|
|
230
|
+
--screen-format mobile_portrait --file-key abc123 --start-node-id 0:1 \\
|
|
231
|
+
--flow-name "Onboarding A"
|
|
232
|
+
|
|
195
233
|
# Text/email content from a file:
|
|
196
234
|
ish iteration create --content-text @./email.html --title "Newsletter"
|
|
197
235
|
|
|
236
|
+
# Email iteration with sender + featured hero image:
|
|
237
|
+
ish iteration create --content-text @./email.txt --content-html @./email.html \\
|
|
238
|
+
--sender-name "Marketing" --sender-email "marketing@example.com" \\
|
|
239
|
+
--featured-image-url https://cdn.example.com/hero.png
|
|
240
|
+
|
|
198
241
|
# Video (URL or local file):
|
|
199
242
|
ish iteration create --content-url ./video.mp4
|
|
200
243
|
|
|
@@ -204,11 +247,113 @@ ish iteration create --image-urls "./a.png,./b.png"
|
|
|
204
247
|
# Document (PDF):
|
|
205
248
|
ish iteration create --content-url ./report.pdf
|
|
206
249
|
|
|
250
|
+
# Chat — probe a saved chatbot endpoint:
|
|
251
|
+
ish iteration create --chat-endpoint-id ce-... --max-turns 10 --early-termination
|
|
252
|
+
|
|
207
253
|
# Inspect:
|
|
208
254
|
ish iteration list --study s-b2c
|
|
209
255
|
ish iteration get i-d4e
|
|
210
256
|
\`\`\`
|
|
211
257
|
|
|
258
|
+
## Segments and segment labels
|
|
259
|
+
|
|
260
|
+
For media iterations (video, audio, text, image, document), reactions
|
|
261
|
+
can be collected per **segment** instead of over the whole asset. A
|
|
262
|
+
segment is a contiguous slice of the iteration's content — a 30-second
|
|
263
|
+
window of a video, a paragraph range of an email, a section of a PDF.
|
|
264
|
+
Each segment can carry a human-readable **label** ("Intro", "Pricing
|
|
265
|
+
section", "Call to action") that surfaces in the tester UI and in
|
|
266
|
+
results.
|
|
267
|
+
|
|
268
|
+
Segments live inside the iteration's \`segmentation\` field — there is
|
|
269
|
+
no separate segments resource. Three discriminated shapes:
|
|
270
|
+
|
|
271
|
+
- **time_based** (video, audio): boundaries in seconds. Segment 0 runs
|
|
272
|
+
from \`intervals_seconds[0]\` to \`intervals_seconds[1]\`, etc.
|
|
273
|
+
Optional \`labels[]\` names each segment.
|
|
274
|
+
|
|
275
|
+
\`\`\`json
|
|
276
|
+
{
|
|
277
|
+
"type": "time_based",
|
|
278
|
+
"intervals_seconds": [0, 30, 60, 90],
|
|
279
|
+
"labels": ["Hook", "Feature 1", "Feature 2", "CTA"]
|
|
280
|
+
}
|
|
281
|
+
\`\`\`
|
|
282
|
+
|
|
283
|
+
- **section_based** (text, document, image copy): explicit list of
|
|
284
|
+
named sections, either marker-bounded or paragraph-bounded.
|
|
285
|
+
|
|
286
|
+
\`\`\`json
|
|
287
|
+
{
|
|
288
|
+
"type": "section_based",
|
|
289
|
+
"sections": [
|
|
290
|
+
{ "name": "intro", "label": "Intro", "paragraph_start": 0, "paragraph_end": 1 },
|
|
291
|
+
{ "name": "body", "label": "Body", "paragraph_start": 1, "paragraph_end": 4 },
|
|
292
|
+
{ "name": "cta", "label": "Call to action", "paragraph_start": 4, "paragraph_end": 5 }
|
|
293
|
+
]
|
|
294
|
+
}
|
|
295
|
+
\`\`\`
|
|
296
|
+
|
|
297
|
+
- **page_based** (document): pages are auto-derived from the document.
|
|
298
|
+
No additional fields.
|
|
299
|
+
|
|
300
|
+
Pass via \`--segmentation-json '<json>'\` on \`iteration create\`.
|
|
301
|
+
|
|
302
|
+
### Default segmentation for text/image iterations
|
|
303
|
+
|
|
304
|
+
For text- and image-modality iterations created without
|
|
305
|
+
\`--segmentation-json\`, the worker synthesises a single whole-content
|
|
306
|
+
section so a minimal \`ish iteration create --content-text "..."\` runs
|
|
307
|
+
end-to-end. Author your own segmentation when you want section-level
|
|
308
|
+
reactions; otherwise the default just works.
|
|
309
|
+
|
|
310
|
+
### content_config — early termination + selected segments
|
|
311
|
+
|
|
312
|
+
A sibling of \`segmentation\` that controls how the tester progresses
|
|
313
|
+
through segments:
|
|
314
|
+
|
|
315
|
+
- \`early_termination: true\` — stop the session once every selected
|
|
316
|
+
segment has been seen.
|
|
317
|
+
- \`selected_segment_indices: [0, 2]\` — only show these segment
|
|
318
|
+
indices; \`null\` (default) means all segments are active.
|
|
319
|
+
|
|
320
|
+
Pass via \`--content-config-json '<json>'\`.
|
|
321
|
+
|
|
322
|
+
## HTML content (text + media captions)
|
|
323
|
+
|
|
324
|
+
- **Text modality**: pair plain \`--content-text\` with rich
|
|
325
|
+
\`--content-html\` to render emails / articles with formatting. The
|
|
326
|
+
plain text is what testers reason over; the HTML is what they see.
|
|
327
|
+
- **Media captions** (video, audio, image): \`--copy-text\` and
|
|
328
|
+
\`--copy-html\` attach a caption to the media — the social-post
|
|
329
|
+
pattern. Add \`--social-platform\` (instagram/tiktok/facebook/linkedin/x)
|
|
330
|
+
for platform-specific framing, and \`--copy-position before|after\`
|
|
331
|
+
for ordering relative to the media.
|
|
332
|
+
|
|
333
|
+
Captions can carry their own segmentation when you want
|
|
334
|
+
paragraph-by-paragraph reactions to a long caption. Use the
|
|
335
|
+
\`--details-json\` escape hatch to pass a nested
|
|
336
|
+
\`copy_content.segmentation\`.
|
|
337
|
+
|
|
338
|
+
## Chat modality
|
|
339
|
+
|
|
340
|
+
Chat iterations probe an external chatbot endpoint by having a tester
|
|
341
|
+
hold a multi-turn conversation against it. Two ways to wire the
|
|
342
|
+
endpoint:
|
|
343
|
+
|
|
344
|
+
\`\`\`
|
|
345
|
+
# Reference a saved endpoint row (recommended — reproducible):
|
|
346
|
+
ish iteration create --chat-endpoint-id ce-...
|
|
347
|
+
|
|
348
|
+
# Inline endpoint config (one-off):
|
|
349
|
+
ish iteration create --chat-endpoint-json '{"url":"https://...","headers":{...}}'
|
|
350
|
+
\`\`\`
|
|
351
|
+
|
|
352
|
+
Tunables:
|
|
353
|
+
- \`--max-turns N\` — cap the conversation length (default 12, max 50).
|
|
354
|
+
- \`--early-termination\` — let the worker end the session early when
|
|
355
|
+
the tester signals the conversation is over.
|
|
356
|
+
|
|
212
357
|
## No more auto-empty iteration A
|
|
213
358
|
|
|
214
359
|
\`ish study create\` and \`ish study generate\` **do not auto-create
|
|
@@ -229,16 +374,6 @@ then retry.
|
|
|
229
374
|
|
|
230
375
|
Treat this as actionable, not transient — re-running won't change anything.
|
|
231
376
|
|
|
232
|
-
## Default segmentation for text/image iterations
|
|
233
|
-
|
|
234
|
-
For text-modality iterations created with just \`--content-text\` (and
|
|
235
|
-
similarly \`--image-urls\` for image), the worker now synthesises a
|
|
236
|
-
single whole-content section if no \`segmentation\` was supplied. This
|
|
237
|
-
means a minimal \`ish iteration create --study s-XYZ --content-text
|
|
238
|
-
"..."\` actually runs end-to-end without you needing to author a
|
|
239
|
-
SegmentationConfig manually. Author your own segmentation when you
|
|
240
|
-
want section-level reactions; otherwise the default just works.
|
|
241
|
-
|
|
242
377
|
## Related
|
|
243
378
|
|
|
244
379
|
- \`concepts/study\` — the parent artifact.
|
|
@@ -379,7 +514,12 @@ ish ask results a-6ec --json | jq '.rounds[0].aggregates'
|
|
|
379
514
|
|
|
380
515
|
For \`--wants-pick\` / \`--wants-ratings\` rounds, \`ask results --json\`
|
|
381
516
|
includes an \`aggregates\` field per round so you don't have to parse
|
|
382
|
-
prose
|
|
517
|
+
prose. Each individual pick also carries a **\`pick_confidence\`** score
|
|
518
|
+
(0..1) — the model's self-reported confidence in its variant choice.
|
|
519
|
+
Use it to break ties: when two variants are nominally close on count,
|
|
520
|
+
the variant with higher mean \`pick_confidence\` is the more decisive
|
|
521
|
+
choice. \`pick_confidence\` is only present on rounds run with
|
|
522
|
+
\`--wants-pick\`.
|
|
383
523
|
|
|
384
524
|
\`\`\`json
|
|
385
525
|
{
|
|
@@ -517,6 +657,24 @@ ish profile create --file profile.json
|
|
|
517
657
|
Expected JSON: \`{ "name": "...", "type": "ai", "gender": "female",
|
|
518
658
|
"country": "US", "occupation": "...", "bio": "..." }\`
|
|
519
659
|
|
|
660
|
+
## Generation behavior to expect
|
|
661
|
+
|
|
662
|
+
- **Latency**: \`profile generate\` is LLM-backed and typically takes
|
|
663
|
+
10–20s for 1–5 profiles. The CLI emits stderr progress lines
|
|
664
|
+
(\`generating N profiles…\` then \`generated N profiles\`) so you
|
|
665
|
+
know it's not stuck. Suppress with \`--quiet\`.
|
|
666
|
+
- **Brief fidelity**: bios reference domain-specific terms from your
|
|
667
|
+
description verbatim or as close paraphrase. If you mention
|
|
668
|
+
\`F-skatt\`, "manual Excel invoicing", "Stripe payouts", or similar
|
|
669
|
+
tools/jargon, expect those terms (or paraphrases) to appear in
|
|
670
|
+
each generated bio's daily-routine framing — not sanded down to
|
|
671
|
+
generic prose.
|
|
672
|
+
- **DOB diversity**: month-and-day are derived from a deterministic
|
|
673
|
+
per-profile hash so birthdays spread across the year (no more
|
|
674
|
+
every-profile-on-\`06-15\`). Year follows the requested age.
|
|
675
|
+
Re-generating the same name/country/occupation/age yields the
|
|
676
|
+
same DOB.
|
|
677
|
+
|
|
520
678
|
## Related
|
|
521
679
|
|
|
522
680
|
- \`concepts/source\` — the inputs to \`profile generate\`.
|
|
@@ -577,6 +735,24 @@ flags. Two ways to select:
|
|
|
577
735
|
The two modes are **mutually exclusive** — pass either \`--profile\` or
|
|
578
736
|
the filter set, not both.
|
|
579
737
|
|
|
738
|
+
## Empty-pool suggestions
|
|
739
|
+
|
|
740
|
+
When a filter combination matches zero profiles, the error message
|
|
741
|
+
includes the top three populated countries that satisfy your *other*
|
|
742
|
+
filters — so you can pivot to a country with actual coverage without a
|
|
743
|
+
second \`profile list\` round-trip:
|
|
744
|
+
|
|
745
|
+
\`\`\`
|
|
746
|
+
$ ish study run --country XX --min-age 35 --sample 5
|
|
747
|
+
Error: No simulatable AI tester profiles in workspace w-b32 match:
|
|
748
|
+
--country XX --min-age 35.
|
|
749
|
+
Populated countries with these other filters: SE (12), DE (8), NL (3).
|
|
750
|
+
Broaden your filters or run \`ish profile list\` to inspect the pool.
|
|
751
|
+
\`\`\`
|
|
752
|
+
|
|
753
|
+
The suggestion is best-effort — it never replaces the original error,
|
|
754
|
+
just augments it.
|
|
755
|
+
|
|
580
756
|
## Defaults
|
|
581
757
|
|
|
582
758
|
- \`ish study run\` with no audience flags → reuses the iteration's
|
|
@@ -709,6 +885,13 @@ ish study cancel <tester_id> # cancel a running simulation
|
|
|
709
885
|
\`<tester_id>\` accepts a tester alias (\`t-…\`) or a full UUID. The
|
|
710
886
|
study-level \`poll\`/\`wait\` forms also exist (\`--study <id>\` /
|
|
711
887
|
\`--iteration <id>\`) for whole-batch progress.
|
|
888
|
+
|
|
889
|
+
## Related
|
|
890
|
+
|
|
891
|
+
- \`reference/json-mode\` — output modes (display vs capture vs chain).
|
|
892
|
+
Use \`--get tester_aliases\` to capture the run's testers without
|
|
893
|
+
piping through \`jq\`. \`--human\` forces table output even through
|
|
894
|
+
\`tee\`/redirection.
|
|
712
895
|
`;
|
|
713
896
|
const REFERENCE_ALIASES = `# reference: aliases
|
|
714
897
|
|
|
@@ -740,15 +923,84 @@ ish profile generate --source tps-3a4 --count 4
|
|
|
740
923
|
The full UUID is also always accepted. Add \`--verbose\` to JSON output
|
|
741
924
|
to see UUIDs alongside aliases.
|
|
742
925
|
`;
|
|
743
|
-
const REFERENCE_JSON_MODE = `# reference:
|
|
926
|
+
const REFERENCE_JSON_MODE = `# reference: output modes for agents
|
|
927
|
+
|
|
928
|
+
\`ish\` distinguishes **three output modes** so agents don't have to
|
|
929
|
+
post-process CLI output with \`jq\` or \`python\` for routine tasks:
|
|
930
|
+
|
|
931
|
+
1. **Display mode (human)** — readable tables and key/value blocks.
|
|
932
|
+
Default on a TTY. Force it anywhere with \`--human\` (e.g. \`ish
|
|
933
|
+
workspace list --human | tee /tmp/x.txt\` keeps the table layout
|
|
934
|
+
even though stdout is redirected).
|
|
935
|
+
2. **Capture mode (single value)** — \`--get <field>\` extracts the
|
|
936
|
+
value at a dotted path and prints it bare (no JSON quotes, no
|
|
937
|
+
indentation). Use this to feed one CLI's output into another:
|
|
938
|
+
\`ASK=$(ish ask create … --get alias)\` instead of
|
|
939
|
+
\`ASK=$(ish ask create … --json | jq -r .alias)\`.
|
|
940
|
+
3. **Chain mode (full JSON)** — \`--json\` (or auto-enabled when stdout
|
|
941
|
+
is piped). Returns structured payloads for downstream parsing.
|
|
942
|
+
Reach for this only when you actually need multiple fields or a
|
|
943
|
+
nested shape; for one value, \`--get\` is shorter.
|
|
944
|
+
|
|
945
|
+
## Picking the right mode
|
|
946
|
+
|
|
947
|
+
| You want to… | Mode |
|
|
948
|
+
|-------------------------------------------|--------------------------------------------------|
|
|
949
|
+
| Show the user a list of workspaces | bare command (TTY) or \`--human\` if redirecting |
|
|
950
|
+
| Capture an alias for a follow-up command | \`--get alias\` |
|
|
951
|
+
| Inspect a specific nested field | \`--get tester_profile.name\` |
|
|
952
|
+
| Compare 2+ fields, or pipe into jq | \`--json\` (or auto-on when piped) |
|
|
953
|
+
| Force human output through \`tee\` | \`--human\` |
|
|
954
|
+
| Force JSON on a TTY | \`--json\` |
|
|
955
|
+
|
|
956
|
+
\`--get\` and \`--human\` are mutually exclusive — capture and display are
|
|
957
|
+
different intents; pick one. \`--get\` implies \`--json\` internally so the
|
|
958
|
+
renderer always has structured data to extract from; you don't need to
|
|
959
|
+
add \`--json\` yourself.
|
|
960
|
+
|
|
961
|
+
### Worked example: display vs. capture
|
|
962
|
+
|
|
963
|
+
\`\`\`bash
|
|
964
|
+
# Display: bare command on a TTY → human table.
|
|
965
|
+
ish workspace list
|
|
966
|
+
|
|
967
|
+
# Capture: feed one alias into the next command, no jq required.
|
|
968
|
+
ASK=$(ish ask create --new --name demo \\
|
|
969
|
+
--prompt "Which?" --variant text:A --variant text:B \\
|
|
970
|
+
--sample 30 --get alias)
|
|
971
|
+
ish ask wait "$ASK" --timeout 600
|
|
972
|
+
|
|
973
|
+
# Capture across an entire list: one value per line.
|
|
974
|
+
ish workspace list --get alias
|
|
975
|
+
# w-6ec
|
|
976
|
+
# w-d02
|
|
977
|
+
# …
|
|
744
978
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
979
|
+
# Display preserved through tee:
|
|
980
|
+
ish ask results "$ASK" --human | tee /tmp/transcript.txt
|
|
981
|
+
\`\`\`
|
|
748
982
|
|
|
749
983
|
## Flags
|
|
750
984
|
|
|
751
|
-
- \`--
|
|
985
|
+
- \`--human\` — force human-readable output regardless of TTY
|
|
986
|
+
state (overrides the auto-flip-to-JSON when
|
|
987
|
+
stdout is piped). Mutually exclusive with
|
|
988
|
+
\`--get\`.
|
|
989
|
+
- \`--get <field>\` — extract a single field from the JSON response
|
|
990
|
+
and print only its bare value. Supports dotted
|
|
991
|
+
paths (\`tester_profile.name\`). On a paginated
|
|
992
|
+
\`{items: [...]}\` response, the path
|
|
993
|
+
auto-descends into \`items\` so \`--get alias\`
|
|
994
|
+
on a list yields one value per line. Implies
|
|
995
|
+
\`--json\` internally; mutually exclusive with
|
|
996
|
+
\`--human\`. Strings/numbers/bools are printed
|
|
997
|
+
unquoted; \`null\` prints as an empty line;
|
|
998
|
+
arrays print one element per line; objects
|
|
999
|
+
print as compact one-line JSON. Missing field
|
|
1000
|
+
→ exit 2 with a usage error.
|
|
1001
|
+
- \`--json\` — force JSON output even on a TTY. Auto-enabled
|
|
1002
|
+
when stdout is piped (unless \`--human\` is
|
|
1003
|
+
set).
|
|
752
1004
|
- \`--fields a,b,c\` — keep only these fields in JSON output (e.g.
|
|
753
1005
|
\`alias,name,status\`). Filters per item only;
|
|
754
1006
|
list wrappers (\`{items, total, returned,
|
|
@@ -757,7 +1009,9 @@ mode is **auto-enabled when stdout is piped**, so an agent rarely needs
|
|
|
757
1009
|
write paths) the full server payload instead
|
|
758
1010
|
of the compact response.
|
|
759
1011
|
- \`-q, --quiet\` — suppress progress messages on stderr (errors
|
|
760
|
-
still go to stderr).
|
|
1012
|
+
still go to stderr). \`--get\` implies
|
|
1013
|
+
\`--quiet\` so the bare value is the only
|
|
1014
|
+
thing on stdout.
|
|
761
1015
|
|
|
762
1016
|
## Stable shape rules
|
|
763
1017
|
|
|
@@ -854,9 +1108,12 @@ The CLI guarantees these contracts so agents can chain safely:
|
|
|
854
1108
|
in the \`testers[]\` array, and a "Failed testers" subsection in
|
|
855
1109
|
human output. Empty when the tester succeeded.
|
|
856
1110
|
- **\`profile list\` emits a stderr pagination hint** when
|
|
857
|
-
\`has_more=true\` and
|
|
858
|
-
|
|
859
|
-
|
|
1111
|
+
\`has_more=true\` and \`--quiet\` is not set. The hint goes to **stderr
|
|
1112
|
+
in every mode** including \`--json\` and piped stdout — it never
|
|
1113
|
+
pollutes machine-readable stdout but is visible to any agent that
|
|
1114
|
+
reads stderr (which they should, for warnings and progress). Format:
|
|
1115
|
+
"showing N–M of TOTAL; pass --offset M --limit N for more."
|
|
1116
|
+
JSON consumers can also read \`has_more\` directly off the envelope.
|
|
860
1117
|
- **\`ask results --json\` adds an \`aggregates\` field per round.** For
|
|
861
1118
|
rounds with \`wants_pick\`/\`wants_ratings\`, the CLI computes the
|
|
862
1119
|
verdict locally so agents don't have to parse comment prose:
|
|
@@ -938,25 +1195,43 @@ a structured error object on **stdout** and a human message on
|
|
|
938
1195
|
## Examples
|
|
939
1196
|
|
|
940
1197
|
\`\`\`
|
|
941
|
-
|
|
942
|
-
ish
|
|
1198
|
+
# Display (table on TTY, JSON when piped):
|
|
1199
|
+
ish workspace list
|
|
1200
|
+
|
|
1201
|
+
# Display preserved through tee/pipe (force human):
|
|
1202
|
+
ish ask results a-6ec --human | tee /tmp/results.txt
|
|
1203
|
+
|
|
1204
|
+
# Capture a single alias to feed into the next command:
|
|
1205
|
+
WS=$(ish workspace list --get alias | head -1)
|
|
1206
|
+
|
|
1207
|
+
# Inspect a nested field:
|
|
1208
|
+
ish study tester t-a17 --get tester_profile.name
|
|
1209
|
+
|
|
1210
|
+
# Chain (full JSON for jq when you need multiple fields):
|
|
1211
|
+
ish study get s-b2c --fields alias,name,status,iterations --json
|
|
943
1212
|
ish ask results a-6ec --round 1 --json
|
|
944
|
-
ish profile generate --description "..." --count 3 --json | jq '.[].alias'
|
|
945
1213
|
\`\`\`
|
|
946
1214
|
|
|
947
1215
|
## Composing commands
|
|
948
1216
|
|
|
949
|
-
|
|
1217
|
+
\`--get\` removes most of the \`jq\` shims agents reach for. Capture in
|
|
1218
|
+
a script, then display the final result back to the user:
|
|
950
1219
|
|
|
951
1220
|
\`\`\`
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1221
|
+
# Capture — bare values, no jq needed:
|
|
1222
|
+
ITER=$(ish iteration create --url https://example.com --get alias)
|
|
1223
|
+
TESTERS=$(ish study run --iteration "$ITER" --sample 5 --country SE --get tester_aliases)
|
|
955
1224
|
for t in $TESTERS; do
|
|
956
1225
|
ish study wait "$t" --timeout 600
|
|
957
1226
|
done
|
|
958
|
-
|
|
1227
|
+
|
|
1228
|
+
# Display the final results to the user, even though we're in a script:
|
|
1229
|
+
ish study results --human
|
|
959
1230
|
\`\`\`
|
|
1231
|
+
|
|
1232
|
+
When you genuinely need multiple fields in one parse pass, \`--json\` is
|
|
1233
|
+
still the right tool — \`--get\` is for single-value capture, not for
|
|
1234
|
+
reshaping output.
|
|
960
1235
|
`;
|
|
961
1236
|
const GUIDE_FIRST_STUDY = `# guide: your first study, end to end
|
|
962
1237
|
|
|
@@ -1098,7 +1373,9 @@ of scope: \`workspace\`, \`config\`, \`docs\`, \`init\`, \`login\`,
|
|
|
1098
1373
|
## Related
|
|
1099
1374
|
|
|
1100
1375
|
- \`reference/aliases\` — the prefix scheme used by every entity.
|
|
1101
|
-
- \`reference/json-mode\` — output
|
|
1376
|
+
- \`reference/json-mode\` — output modes (display vs capture vs chain),
|
|
1377
|
+
including \`--get workspace.alias\` to capture the active workspace
|
|
1378
|
+
without piping \`ish status --json\` through \`jq\`.
|
|
1102
1379
|
`;
|
|
1103
1380
|
const REFERENCE_BILLING_LIMITS = `# reference: billing tier limits
|
|
1104
1381
|
|
|
@@ -1201,7 +1478,7 @@ const PAGES = [
|
|
|
1201
1478
|
{
|
|
1202
1479
|
slug: "concepts/iteration",
|
|
1203
1480
|
title: "concept: iteration",
|
|
1204
|
-
description: "One configured run of a study (URL or
|
|
1481
|
+
description: "One configured run of a study (URL, media, or chat). Covers segments, segment labels, and HTML content.",
|
|
1205
1482
|
body: CONCEPT_ITERATION,
|
|
1206
1483
|
},
|
|
1207
1484
|
{
|
|
@@ -1272,8 +1549,8 @@ const PAGES = [
|
|
|
1272
1549
|
},
|
|
1273
1550
|
{
|
|
1274
1551
|
slug: "reference/json-mode",
|
|
1275
|
-
title: "reference:
|
|
1276
|
-
description: "
|
|
1552
|
+
title: "reference: output modes for agents (display, capture, chain)",
|
|
1553
|
+
description: "Display vs capture vs chain: --human, --get, --json, --fields, exit codes, pipe behavior.",
|
|
1277
1554
|
body: REFERENCE_JSON_MODE,
|
|
1278
1555
|
},
|
|
1279
1556
|
{
|
package/dist/lib/output.d.ts
CHANGED
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
/** Set by withClient() based on global flags. */
|
|
10
10
|
export declare function setVerbose(v: boolean): void;
|
|
11
11
|
export declare function setFields(fields?: string[]): void;
|
|
12
|
+
/**
|
|
13
|
+
* Pattern Ω capture mode: when set, jsonOutput() returns the bare value at
|
|
14
|
+
* the dotted path instead of the full JSON. Cleared between command runs by
|
|
15
|
+
* each invocation of `applyGlobals()`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function setGetField(field?: string): void;
|
|
12
18
|
/** Per-call output options for stable JSON contracts. */
|
|
13
19
|
export interface OutputOptions {
|
|
14
20
|
/**
|