@50heads/cli 2026.925.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ # Changelog
2
+
3
+ Changes to `@50heads/cli`, the `50heads` command. It has its own calendar versions, separate from `@50heads/mcp`.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions are calendar versions, `YYYY.MDD.N`: the year, the month and two-digit day, then the release number for that day (`2026.924.1` is the first release on 24 September 2026). Breaking changes are called out in the notes.
6
+
7
+ Add what changed under Unreleased as you go, written for the people using it. The release workflow moves it under the new version and uses it for the GitHub Release.
8
+
9
+ ## [Unreleased]
10
+
11
+ ## [2026.925.1] - 2026-09-25
12
+
13
+ ### Added
14
+
15
+ - First public release: `ask` (from flags, a JSON file, JSON Lines or CSV on stdin, with `--wait`), `estimate`, `wait`, `results`, `answers`, `list`, `cancel`, `balance`, `templates`, `schema`, `login`, `logout` and `status`.
16
+ - `--json` on every command, and exit codes scripts can branch on.
17
+ - Asks are keyed by a hash of the question, so re-running a script never asks or charges twice. `--new` asks again on purpose.
18
+ - One sign-in for the CLI and `npx @50heads/mcp`.
19
+
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 50heads
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # 50heads CLI
2
+
3
+ Ask verified real people from a script, a Makefile or CI, wait for the answers and read the split. 20 credits an answer at Tier 1, priced in your account's currency; fifty answers take about ten minutes.
4
+
5
+ ```sh
6
+ npx -y @50heads/cli --help
7
+ # or
8
+ npm install -g @50heads/cli
9
+ 50heads --help
10
+ ```
11
+
12
+ Needs Node 20 or later.
13
+
14
+ ## Sign in
15
+
16
+ For CI and scripts, make an API key in the portal (Developers, API keys) with a daily spend cap, and set it:
17
+
18
+ ```sh
19
+ export FIFTYHEADS_API_KEY=fh_live_…
20
+ ```
21
+
22
+ On your own machine you can sign in once in the browser instead:
23
+
24
+ ```sh
25
+ 50heads login # kept in the macOS Keychain, the Secret Service, or ~/.config/50heads (mode 600)
26
+ 50heads status
27
+ 50heads logout
28
+ ```
29
+
30
+ The same sign-in works for `npx @50heads/mcp`. The API key wins when both are there.
31
+
32
+ ## Ask
33
+
34
+ ```sh
35
+ # Price and time first. Never spends.
36
+ 50heads estimate --text "Which name sounds friendlier?" --option Pip --option Moss
37
+ # 50 answers, about 10 minutes, $12.70. 20 credits an answer.
38
+
39
+ # Ask and wait for the answers.
40
+ 50heads ask --text "Which name sounds friendlier?" --option Pip --option Moss --wait
41
+
42
+ # Two images: an A or B question.
43
+ 50heads ask --text "Which cover would you pick up?" \
44
+ --image https://example.com/a.png --image https://example.com/b.png --n 100
45
+
46
+ # From a file: the question draft that POST /v2/questions takes (50heads schema prints its JSON Schema).
47
+ 50heads ask --file question.json --json
48
+ ```
49
+
50
+ `question.json`:
51
+
52
+ ```json
53
+ {
54
+ "type": "single_choice",
55
+ "text": "Which name sounds friendlier?",
56
+ "language": "en",
57
+ "options": [{ "label": "Pip" }, { "label": "Moss" }],
58
+ "n": 50,
59
+ "tier": 1,
60
+ "targeting": { "countries": ["GB", "IE"], "tags": [] }
61
+ }
62
+ ```
63
+
64
+ Wrap it as `{"draft": {…}, "then": [{"text": "Why did you pick {winner}?"}]}` to add follow-ups.
65
+
66
+ ### Many at once
67
+
68
+ ```sh
69
+ 50heads ask --csv asks.csv --json > asked.jsonl
70
+ cat asks.jsonl | 50heads ask - --json
71
+ ```
72
+
73
+ CSV columns (a header row, any order): `text` (required), `type`, `options` (`A|B|C`) or `option1` to `option8`, `images` (`|`, in option order), `context`, `language`, `n`, `tier`, `rush`, `neither`, `countries` (`|`), `tags` (`|`), `stimulus_image`, `stimulus_text`. Every row is checked before anything is asked; a row that fails is reported and the rest go ahead (exit 8).
74
+
75
+ ### Never twice by accident
76
+
77
+ Every ask carries an idempotency key made from a hash of the question. Running the same command or file again, or retrying after a dropped connection, returns the same question within 24 hours and never charges twice. To ask the same question again on purpose, pass `--new` (or `--salt something` for a whole file). `--key` sets the key yourself.
78
+
79
+ ## Read
80
+
81
+ ```sh
82
+ 50heads wait q_123 --timeout 900 # waits on the server, prints the result
83
+ 50heads results q_123 # the result so far
84
+ 50heads answers q_123 --option 0 --limit 100
85
+ 50heads answers q_123 --q price --all --json # one answer per line
86
+ 50heads list --status live
87
+ 50heads cancel q_123 # stops it; unanswered heads are refunded
88
+ 50heads balance
89
+ 50heads templates
90
+ ```
91
+
92
+ `answers` filters by `--option` (0 is the first), `--tier`, `--country`, `--age-band` and `--q` (a word in written answers). Country and age filters show nothing when fewer than 5 answers match. Answers never identify a head.
93
+
94
+ ## Output and exit codes
95
+
96
+ Human-readable by default. With `--json`, each result is one JSON object on stdout (JSON Lines for many), progress stays on stderr (`--quiet` turns it off), and errors are JSON on stderr: `{"error": {"code", "message", "exit"}}`.
97
+
98
+ | Exit | Meaning |
99
+ | --- | --- |
100
+ | 0 | Done |
101
+ | 1 | Something went wrong |
102
+ | 2 | The command line is wrong |
103
+ | 3 | Not signed in, or the key is not allowed to do that |
104
+ | 4 | Not enough credits, or over the key's daily cap |
105
+ | 5 | The question needs fixing (estimate prints the fixes) |
106
+ | 6 | No question with that id |
107
+ | 7 | 50heads is unavailable or rate limited; try again |
108
+ | 8 | Some asks in a bulk run failed; the rest were asked |
109
+ | 124 | `wait` ran out of time and the question is still live |
110
+
111
+ ## In CI
112
+
113
+ ```yaml
114
+ - run: npx -y @50heads/cli ask --file .50heads/headline.json --wait --timeout 1200 --json > result.json
115
+ env:
116
+ FIFTYHEADS_API_KEY: ${{ secrets.FIFTYHEADS_API_KEY }}
117
+ ```
118
+
119
+ The key's daily cap is the limit on what a runaway job can spend.
120
+
121
+ ## Environment
122
+
123
+ | Variable | Meaning |
124
+ | --- | --- |
125
+ | `FIFTYHEADS_API_KEY` | API key for CI and scripts |
126
+ | `FIFTYHEADS_API_URL` | API base, default `https://api.50heads.com` |
127
+ | `FIFTYHEADS_AUTH_URL` | Sign-in server for `login` |
128
+ | `FIFTYHEADS_CREDENTIALS_STORE=file` | Keep the sign-in in a file, not the keychain |
129
+ | `FIFTYHEADS_NO_BROWSER=1` | `login` prints the link without opening a browser |
130
+
131
+ ## Versions
132
+
133
+ Calendar versions, `YYYY.MDD.N`, released from the monorepo by `.github/workflows/release-cli.yml`. See `CHANGELOG.md`.
134
+
135
+ ## Development
136
+
137
+ ```sh
138
+ pnpm --filter @50heads/cli test
139
+ pnpm --filter @50heads/cli build && node packages/cli/dist/cli.js --help
140
+ ```
141
+
142
+ The sign-in and credential store are in `packages/login`, shared with `@50heads/mcp`. Commands are in `src/run.ts`; `run()` takes its I/O as an argument, so the tests drive it in-process against the fake API from `@50heads/mcp/testing`.