@tutorflow/cli 0.1.2 → 0.3.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 +400 -89
- package/dist/client.d.ts +7 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +53 -19
- package/dist/client.js.map +1 -1
- package/dist/commands/agent.d.ts +3 -0
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +123 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +48 -45
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +34 -45
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/course.d.ts.map +1 -1
- package/dist/commands/course.js +61 -75
- package/dist/commands/course.js.map +1 -1
- package/dist/commands/evaluate.d.ts.map +1 -1
- package/dist/commands/evaluate.js +49 -55
- package/dist/commands/evaluate.js.map +1 -1
- package/dist/commands/module.d.ts +3 -0
- package/dist/commands/module.d.ts.map +1 -0
- package/dist/commands/module.js +108 -0
- package/dist/commands/module.js.map +1 -0
- package/dist/commands/platform.d.ts +3 -0
- package/dist/commands/platform.d.ts.map +1 -0
- package/dist/commands/platform.js +36 -0
- package/dist/commands/platform.js.map +1 -0
- package/dist/commands/slide.d.ts.map +1 -1
- package/dist/commands/slide.js +65 -76
- package/dist/commands/slide.js.map +1 -1
- package/dist/commands/test.d.ts +3 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +119 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/video.d.ts.map +1 -1
- package/dist/commands/video.js +66 -78
- package/dist/commands/video.js.map +1 -1
- package/dist/index.js +24 -2
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +75 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/output.d.ts +15 -2
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/output.js +66 -22
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/runtime.d.ts +39 -0
- package/dist/utils/runtime.d.ts.map +1 -0
- package/dist/utils/runtime.js +105 -0
- package/dist/utils/runtime.js.map +1 -0
- package/package.json +18 -2
package/README.md
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
# @tutorflow/cli
|
|
2
2
|
|
|
3
|
-
TutorFlow CLI for creating AI-powered educational content (slides, videos, courses) and evaluating student responses from the terminal. Wraps the TutorFlow Platform API (`/v1/platform/*`).
|
|
3
|
+
TutorFlow CLI for creating AI-powered educational content (slides, videos, courses) and evaluating student responses from the terminal or from AI agents. Wraps the TutorFlow Platform API (`/v1/platform/*`).
|
|
4
4
|
|
|
5
5
|
- **Binary:** `tutorflow`
|
|
6
|
-
- **
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
6
|
+
- **Package:** [`@tutorflow/cli`](https://www.npmjs.com/package/@tutorflow/cli) (current version in [`package.json`](package.json))
|
|
7
|
+
- **Source:** [tutorflow-io/cli](https://github.com/tutorflow-io/cli) (private)
|
|
8
|
+
- **Node:** `>= 18` for runtime, `>= 20` for development (Vitest 4 requirement)
|
|
9
|
+
- **Agent-friendly:** every command supports `--json` output, env-var auth (`TUTORFLOW_API_KEY`), and proper exit codes — see [Non-interactive / agent usage](#non-interactive--agent-usage)
|
|
9
10
|
|
|
10
11
|
## Installation
|
|
11
12
|
|
|
12
|
-
### A. End users (
|
|
13
|
+
### A. End users (recommended)
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
Install globally with any package manager:
|
|
15
16
|
|
|
16
17
|
```bash
|
|
17
18
|
npm install -g @tutorflow/cli
|
|
@@ -24,122 +25,225 @@ Then anywhere on the system:
|
|
|
24
25
|
```bash
|
|
25
26
|
tutorflow --version
|
|
26
27
|
tutorflow auth login
|
|
28
|
+
tutorflow agent register --name "My Agent Workspace" --slug my-agent-workspace --email me@example.com
|
|
29
|
+
tutorflow --json platform manifest
|
|
27
30
|
tutorflow slide create "My first deck"
|
|
28
31
|
```
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
>
|
|
32
|
-
> ```bash
|
|
33
|
-
> npx @tutorflow/cli slide create "My first deck"
|
|
34
|
-
> ```
|
|
35
|
-
|
|
36
|
-
If you publish to a private registry (e.g. GitHub Packages or a self-hosted Verdaccio), users first authenticate to that registry and scope the `@tutorflow` namespace to it:
|
|
33
|
+
**One-shot use without installing**:
|
|
37
34
|
|
|
38
35
|
```bash
|
|
39
|
-
|
|
40
|
-
npm login --scope=@tutorflow --registry=https://npm.pkg.github.com
|
|
41
|
-
npm install -g @tutorflow/cli
|
|
36
|
+
npx @tutorflow/cli slide create "My first deck"
|
|
42
37
|
```
|
|
43
38
|
|
|
44
|
-
|
|
39
|
+
This is the recommended path for AI agents and CI environments — no install step, always pulls the latest published version.
|
|
45
40
|
|
|
46
|
-
|
|
41
|
+
### B. Local development (this repo)
|
|
47
42
|
|
|
48
43
|
```bash
|
|
44
|
+
git clone https://github.com/tutorflow-io/cli.git
|
|
45
|
+
cd cli
|
|
49
46
|
pnpm install
|
|
50
|
-
pnpm
|
|
51
|
-
pnpm
|
|
47
|
+
pnpm build
|
|
48
|
+
pnpm link # exposes the `tutorflow` binary globally
|
|
52
49
|
```
|
|
53
50
|
|
|
54
51
|
Verify:
|
|
55
52
|
|
|
56
53
|
```bash
|
|
57
|
-
tutorflow --version #
|
|
54
|
+
tutorflow --version # matches package.json
|
|
58
55
|
tutorflow --help
|
|
59
56
|
```
|
|
60
57
|
|
|
61
58
|
To unlink later: `npm unlink -g @tutorflow/cli`.
|
|
62
59
|
|
|
63
|
-
|
|
60
|
+
Run from source without building:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pnpm dev -- <command> [options]
|
|
64
|
+
# e.g. pnpm dev -- slide list --limit 5
|
|
65
|
+
```
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
## Releasing
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
Releases are automated by GitHub Actions on pushes to `master` / `main`.
|
|
70
|
+
Auth uses **npm OIDC Trusted Publishing** — no `NPM_TOKEN` secret in CI.
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
```bash
|
|
73
|
+
git checkout master
|
|
74
|
+
git pull
|
|
71
75
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
npm login --scope=@tutorflow --registry=<your-private-registry>
|
|
76
|
-
```
|
|
76
|
+
npm version patch --no-git-tag-version # 0.3.0 → 0.3.1 (or minor / major)
|
|
77
|
+
git push origin master # Release workflow publishes if that version is not on npm yet
|
|
78
|
+
```
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
The [`Release` workflow](.github/workflows/release.yml):
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
"license": "UNLICENSED"
|
|
86
|
-
}
|
|
87
|
-
```
|
|
82
|
+
1. Reads `package.json` name and version
|
|
83
|
+
2. Skips npm publish if that exact version already exists
|
|
84
|
+
3. Runs `pnpm typecheck` + `pnpm build` + `pnpm test`
|
|
85
|
+
4. Publishes new versions with `npm publish --access public` (auth via OIDC)
|
|
86
|
+
5. Creates a GitHub Release only for `v*.*.*` tag pushes
|
|
88
87
|
|
|
89
|
-
|
|
88
|
+
For full setup (npm org, Trusted Publisher config) see [RELEASING.md](RELEASING.md).
|
|
90
89
|
|
|
91
|
-
###
|
|
90
|
+
### Pre-release / beta
|
|
92
91
|
|
|
93
92
|
```bash
|
|
94
|
-
|
|
93
|
+
npm version prerelease --preid=beta --no-git-tag-version # 0.3.1 → 0.3.2-beta.0
|
|
94
|
+
git push origin master
|
|
95
|
+
```
|
|
95
96
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
# or: npm version minor / major / prerelease --preid=beta
|
|
97
|
+
Pre-release versions publish to a dist-tag derived from the prerelease id
|
|
98
|
+
(`0.3.1-beta.0` publishes with `--tag beta`).
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
## ⚠️ Caveats & gotchas
|
|
101
|
+
|
|
102
|
+
These tripped us up during initial setup. Read before changing release infrastructure.
|
|
103
|
+
|
|
104
|
+
### Versioning
|
|
105
|
+
|
|
106
|
+
- **Don't hardcode the version in `src/index.ts`.** It reads `version` from [`package.json`](package.json) via `resolveJsonModule`. Hardcoding will silently lie to users via `--version` after every `npm version` bump.
|
|
107
|
+
- The `prepublishOnly` script in `package.json` rebuilds `dist/` before publish. Don't skip it.
|
|
108
|
+
|
|
109
|
+
### npm Trusted Publishing (OIDC)
|
|
110
|
+
|
|
111
|
+
- **npm CLI must be 11.5.1+** for OIDC auth. npm also requires a modern Node 22 runtime for trusted publishing, so the workflow uses Node 22.x and invokes `pnpm dlx npm@latest ...` for registry checks and publish. Do not replace that with the runner's bundled npm unless you verify its version supports OIDC trusted publishing.
|
|
112
|
+
- The Trusted Publisher binding at [npmjs.com/package/@tutorflow/cli/access](https://www.npmjs.com/package/@tutorflow/cli/access) hardcodes:
|
|
113
|
+
- GitHub org: `tutorflow-io`
|
|
114
|
+
- Repo: `cli`
|
|
115
|
+
- Workflow filename: `release.yml`
|
|
116
|
+
- Environment: (none)
|
|
117
|
+
|
|
118
|
+
Renaming the repo, moving the workflow file, or adding an `environment:` to the publish job will break OIDC auth until the binding is updated.
|
|
119
|
+
- Local manual publishes still need a token (set `NPM_TOKEN` in `.env` or run `npm login`). Use a Granular Access Token with **"Bypass two-factor authentication (2FA)"** checked, otherwise CI/scripts get `EOTP` errors.
|
|
120
|
+
|
|
121
|
+
### Provenance
|
|
122
|
+
|
|
123
|
+
- `--provenance` is **disabled** in [release.yml](.github/workflows/release.yml). npm only accepts provenance attestations from **public** GitHub repos. Add `--provenance` back to the `npm publish` command when this repo goes public.
|
|
124
|
+
|
|
125
|
+
### Node + tooling
|
|
126
|
+
|
|
127
|
+
- **Vitest 4.x requires Node 20+** (uses `node:util.styleText`). CI tests Node 20 and Node 22, while release publishing runs on Node 22 for npm OIDC. The runtime CLI itself still supports Node 18 (declared in `package.json#engines`).
|
|
128
|
+
|
|
129
|
+
### Tarball hygiene
|
|
130
|
+
|
|
131
|
+
- `tsconfig.json` excludes `**/*.test.ts` so test files don't end up in `dist/` (and therefore not in the published tarball).
|
|
132
|
+
- `package.json#files` is an allowlist (`dist`, `README.md`, `LICENSE`). Anything not listed is excluded.
|
|
133
|
+
- Run `npm pack --dry-run` to inspect the tarball before publish.
|
|
134
|
+
|
|
135
|
+
### Source maps and a private repo
|
|
136
|
+
|
|
137
|
+
The published tarball currently includes `.js.map` and `.d.ts.map` files which embed paths from the build environment. While the source itself isn't shipped, this leaks file structure. If that matters, set `sourceMap: false` and `declarationMap: false` in [tsconfig.json](tsconfig.json) before going public.
|
|
138
|
+
|
|
139
|
+
## Development
|
|
140
|
+
|
|
141
|
+
Run with `tsx` (no build step):
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
pnpm dev -- <command> [options]
|
|
145
|
+
# e.g. pnpm dev -- slide list --limit 5
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Build artifacts land in `dist/` (entry: `dist/index.js`, declared in `package.json#bin`).
|
|
149
|
+
|
|
150
|
+
## Non-interactive / agent usage
|
|
103
151
|
|
|
104
|
-
|
|
105
|
-
npm pack --dry-run
|
|
152
|
+
Every command supports the contract below so AI agents and CI scripts can use the CLI without a TTY.
|
|
106
153
|
|
|
107
|
-
|
|
108
|
-
|
|
154
|
+
### Auth without prompts
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Option 1: env var (preferred for one-shot calls)
|
|
158
|
+
TUTORFLOW_API_KEY=tf_xxx tutorflow --json slide list
|
|
159
|
+
|
|
160
|
+
# Option 2: persist to ~/.tutorflow/config.json once
|
|
161
|
+
tutorflow auth login --api-key tf_xxx
|
|
162
|
+
tutorflow --json slide create "Photosynthesis for 5th graders" -n 12
|
|
109
163
|
```
|
|
110
164
|
|
|
111
|
-
|
|
165
|
+
`TUTORFLOW_API_KEY` always wins over the config file. `tutorflow auth whoami --json` reports `source: "env" | "config"` so an agent can verify which credential is active.
|
|
166
|
+
|
|
167
|
+
### Machine-readable output
|
|
168
|
+
|
|
169
|
+
`--json` (or `TUTORFLOW_JSON=1`) makes every command emit a single JSON line on stdout. Errors emit JSON to stderr.
|
|
112
170
|
|
|
113
171
|
```bash
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
172
|
+
$ tutorflow --json auth whoami
|
|
173
|
+
{"authenticated":true,"apiKeyPreview":"tf_xxxxxxx...","baseUrl":"https://api.tutorflow.io","source":"env"}
|
|
174
|
+
|
|
175
|
+
$ tutorflow --json auth whoami # without auth
|
|
176
|
+
# stdout: (empty)
|
|
177
|
+
# stderr: {"error":{"message":"Not authenticated","code":"EAUTH"}}
|
|
178
|
+
# exit: 1
|
|
117
179
|
```
|
|
118
180
|
|
|
119
|
-
|
|
181
|
+
List commands return raw arrays:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
$ tutorflow --json slide list --limit 3
|
|
185
|
+
[{"id":"...","title":"...","status":"ready","createdAt":"..."},...]
|
|
186
|
+
```
|
|
120
187
|
|
|
121
|
-
|
|
188
|
+
Pipe into `jq` for downstream automation:
|
|
122
189
|
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
- run: npm publish --access public
|
|
126
|
-
working-directory: apps/cli
|
|
127
|
-
env:
|
|
128
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
190
|
+
```bash
|
|
191
|
+
tutorflow --json slide list --status ready | jq -r '.[].id' | xargs -I{} tutorflow --json slide get {}
|
|
129
192
|
```
|
|
130
193
|
|
|
131
|
-
|
|
194
|
+
### Exit codes
|
|
132
195
|
|
|
133
|
-
|
|
196
|
+
| Code | Meaning |
|
|
197
|
+
| ----- | ----------------------------------------------------------------- |
|
|
198
|
+
| `0` | Success |
|
|
199
|
+
| `1` | Generic failure (auth, network, API error, etc.) |
|
|
200
|
+
| `2` | Bad input (invalid flag value, missing required input in non-TTY) |
|
|
201
|
+
| `130` | User cancelled an interactive prompt (Ctrl+C) |
|
|
134
202
|
|
|
135
|
-
|
|
203
|
+
The error JSON includes a stable `code`: `EAUTH`, `EINVAL`, `ENOINTERACTIVE`, `ENETWORK`, `EHTTP_<status>`, `ENOPREVIEW`, `ENOTFOUND`, `ECANCELLED`.
|
|
204
|
+
|
|
205
|
+
### Required-input flags (no prompts)
|
|
206
|
+
|
|
207
|
+
Commands that have required input expose every prompt as a flag:
|
|
136
208
|
|
|
137
209
|
```bash
|
|
138
|
-
|
|
139
|
-
|
|
210
|
+
# self-register a platform workspace and save the returned API key
|
|
211
|
+
tutorflow --json agent register \
|
|
212
|
+
--name "Agent Workspace" \
|
|
213
|
+
--slug agent-workspace \
|
|
214
|
+
--email agent@example.com \
|
|
215
|
+
--agent-identity "codex"
|
|
216
|
+
|
|
217
|
+
# slide / video / course create — accept positional [prompt]
|
|
218
|
+
tutorflow --json slide create "Photosynthesis" -n 12 -l en
|
|
219
|
+
tutorflow --json video create "Newton's laws" -s 6 -r 16:9 -d 90
|
|
220
|
+
tutorflow --json course create "Beginner Python" -l 10 -lang en
|
|
221
|
+
|
|
222
|
+
# evaluate — every input is a flag
|
|
223
|
+
tutorflow --json evaluate \
|
|
224
|
+
--type rubric \
|
|
225
|
+
--question "What is 2+2?" \
|
|
226
|
+
--student-answer "4" \
|
|
227
|
+
--expected-answer "4"
|
|
228
|
+
|
|
229
|
+
# logout (skip confirmation)
|
|
230
|
+
tutorflow auth logout --force
|
|
140
231
|
```
|
|
141
232
|
|
|
142
|
-
|
|
233
|
+
If a required input is missing **and** stdin is not a TTY, the command exits 2 with `ENOINTERACTIVE` and an error message naming the flag(s) to use. It never hangs waiting for input.
|
|
234
|
+
|
|
235
|
+
### Globals
|
|
236
|
+
|
|
237
|
+
| Flag | Env var | Effect |
|
|
238
|
+
| --------------------------------- | -------------------------------- | ----------------------------------------------- |
|
|
239
|
+
| `--json` | `TUTORFLOW_JSON=1` | JSON output to stdout, JSON errors to stderr |
|
|
240
|
+
| `--debug` | `DEBUG=1` or `TUTORFLOW_DEBUG=1` | Print stack traces on errors |
|
|
241
|
+
| `--api-key <k>` (auth login only) | `TUTORFLOW_API_KEY` | API key |
|
|
242
|
+
| (n/a) | `TUTORFLOW_BASE_URL` | Override API base URL (staging, self-hosted) |
|
|
243
|
+
|
|
244
|
+
### MCP server
|
|
245
|
+
|
|
246
|
+
A native MCP server (so agents can call tools directly without shelling out) is on the roadmap. For now, the `--json` shell contract is the recommended integration path.
|
|
143
247
|
|
|
144
248
|
## Authentication
|
|
145
249
|
|
|
@@ -194,6 +298,104 @@ tutorflow config set <key> <value> # update one key
|
|
|
194
298
|
All resource commands require authentication. Without an API key they print:
|
|
195
299
|
`✗ Not authenticated. Run "tutorflow auth login" first.`
|
|
196
300
|
|
|
301
|
+
### `tutorflow agent`
|
|
302
|
+
|
|
303
|
+
Manage the agent-facing TutorFlow Platform account flow.
|
|
304
|
+
|
|
305
|
+
#### `agent register`
|
|
306
|
+
|
|
307
|
+
Public self-service registration. Creates a platform workspace through
|
|
308
|
+
`POST /v1/platform/agent/register`, returns the one-time API key, and saves it
|
|
309
|
+
to `~/.tutorflow/config.json` by default so the next CLI command can run
|
|
310
|
+
without a separate `auth login`.
|
|
311
|
+
|
|
312
|
+
| Option | Type | Default | Description |
|
|
313
|
+
| ------------------------------ | -------- | ------- | -------------------------------------------- |
|
|
314
|
+
| `--name <name>` | `string` | — | Workspace display name |
|
|
315
|
+
| `--slug <slug>` | `string` | — | Unique lowercase slug |
|
|
316
|
+
| `--email <email>` | `string` | none | Contact email for verification and billing |
|
|
317
|
+
| `--agent-identity <identity>` | `string` | none | Optional agent identity string |
|
|
318
|
+
| `--no-save` | boolean | false | Print the API key but do not persist it |
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
tutorflow --json agent register \
|
|
322
|
+
--name "Agent Workspace" \
|
|
323
|
+
--slug agent-workspace \
|
|
324
|
+
--email agent@example.com \
|
|
325
|
+
--agent-identity "codex"
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
#### `agent account`
|
|
329
|
+
|
|
330
|
+
GET `/v1/platform/agent/account`. Shows workspace status, credit balance,
|
|
331
|
+
email verification state, rate limits, and `restrictedActions`.
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
tutorflow --json agent account
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
#### `agent billing status`
|
|
338
|
+
|
|
339
|
+
GET `/v1/platform/agent/billing/status`. Shows payment-method state, credit
|
|
340
|
+
balance, billing mode, email verification state, and `restrictedActions`.
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
tutorflow --json agent billing status
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
#### `agent billing session`
|
|
347
|
+
|
|
348
|
+
POST `/v1/platform/agent/billing/session`. Returns a TutorFlow-hosted checkout
|
|
349
|
+
URL that an agent should forward to a human operator.
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
tutorflow --json agent billing session
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
#### `agent verify-email resend`
|
|
356
|
+
|
|
357
|
+
POST `/v1/platform/agent/verify-email/resend`. Resends the workspace email
|
|
358
|
+
verification message using the active API key.
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
tutorflow --json agent verify-email resend
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### `agent checkout info`
|
|
365
|
+
|
|
366
|
+
GET `/v1/platform/agent/checkout?token=<token>`. Reads workspace info for a
|
|
367
|
+
TutorFlow checkout token returned through the hosted billing-session flow.
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
tutorflow --json agent checkout info --token checkout_123
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
#### `agent checkout create`
|
|
374
|
+
|
|
375
|
+
POST `/v1/platform/agent/checkout`. Creates a Stripe Checkout URL from a
|
|
376
|
+
TutorFlow checkout token and amount. This is normally called by the hosted
|
|
377
|
+
checkout page; CLI support exists for complete automation and testing.
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
tutorflow --json agent checkout create --token checkout_123 --amount-usd 25
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### `tutorflow platform`
|
|
384
|
+
|
|
385
|
+
Inspect public discovery metadata and validate the active Platform API key.
|
|
386
|
+
|
|
387
|
+
| Subcommand | Endpoint | Auth |
|
|
388
|
+
| ---------- | -------- | ---- |
|
|
389
|
+
| `manifest` | `GET /v1/platform/.well-known/agent.json` | none |
|
|
390
|
+
| `pricing` | `GET /v1/platform/pricing-catalog` | none |
|
|
391
|
+
| `health` | `GET /v1/platform/health` | Platform API key |
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
tutorflow --json platform manifest
|
|
395
|
+
tutorflow --json platform pricing
|
|
396
|
+
tutorflow --json platform health
|
|
397
|
+
```
|
|
398
|
+
|
|
197
399
|
### `tutorflow slide`
|
|
198
400
|
|
|
199
401
|
Create and manage slide decks.
|
|
@@ -335,6 +537,98 @@ Opens the course preview URL in the browser.
|
|
|
335
537
|
|
|
336
538
|
---
|
|
337
539
|
|
|
540
|
+
### `tutorflow module`
|
|
541
|
+
|
|
542
|
+
Create and manage standalone lesson modules.
|
|
543
|
+
|
|
544
|
+
#### `module create [prompt]`
|
|
545
|
+
|
|
546
|
+
POST `/v1/platform/modules`. Generates one classroom-compatible standalone
|
|
547
|
+
lesson. `--idempotency-key` is sent as the `Idempotency-Key` header so agents
|
|
548
|
+
can safely retry a create call.
|
|
549
|
+
|
|
550
|
+
| Argument / Option | Type | Default | Description |
|
|
551
|
+
| ------------------------------ | --------------------- | -------- | -------------------------------- |
|
|
552
|
+
| `[prompt]` | `string` (positional) | — | Lesson/module prompt |
|
|
553
|
+
| `--title <title>` | `string` | none | Override generated title |
|
|
554
|
+
| `--description <description>` | `string` | none | Override generated description |
|
|
555
|
+
| `--target <target>` | `string` | none | Target learner audience |
|
|
556
|
+
| `--type <type>` | `string` | `lesson` | Module type |
|
|
557
|
+
| `--locale <locale>` | `string` | `en` | Locale code |
|
|
558
|
+
| `--language <language>` | `string` | `en` | Language code |
|
|
559
|
+
| `--slug <slug>` | `string` | none | Optional slug |
|
|
560
|
+
| `--private` | boolean | false | Set `isPublic: false` |
|
|
561
|
+
| `--no-quiz` | boolean | false | Set `hasQuiz: false` |
|
|
562
|
+
| `--idempotency-key <key>` | `string` | none | Safe retry key |
|
|
563
|
+
|
|
564
|
+
```bash
|
|
565
|
+
tutorflow --json module create "Fractions for 5th grade" \
|
|
566
|
+
--title "Fractions" \
|
|
567
|
+
--target "5th grade" \
|
|
568
|
+
--no-quiz \
|
|
569
|
+
--idempotency-key lesson-001
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
#### `module list`
|
|
573
|
+
|
|
574
|
+
GET `/v1/platform/modules?limit=<n>&offset=<n>[&search=<q>]`.
|
|
575
|
+
|
|
576
|
+
```bash
|
|
577
|
+
tutorflow --json module list --limit 20 --offset 0 --search fractions
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
#### `module get <id>` / `module open <id>`
|
|
581
|
+
|
|
582
|
+
Fetch a module by ID or open its `publicUrl`.
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
### `tutorflow test`
|
|
587
|
+
|
|
588
|
+
Create and manage generated assessments.
|
|
589
|
+
|
|
590
|
+
#### `test create [prompt]`
|
|
591
|
+
|
|
592
|
+
POST `/v1/platform/tests`. Generates a test/assessment. `--idempotency-key` is
|
|
593
|
+
sent as the `Idempotency-Key` header.
|
|
594
|
+
|
|
595
|
+
| Argument / Option | Type | Default | Description |
|
|
596
|
+
| ------------------------- | --------------------- | ---------- | ------------------------------ |
|
|
597
|
+
| `[prompt]` | `string` (positional) | — | Test generation prompt |
|
|
598
|
+
| `--title <title>` | `string` | none | Override generated title |
|
|
599
|
+
| `--description <text>` | `string` | none | Override generated description |
|
|
600
|
+
| `-l, --language <lang>` | `string` | `en` | Language code |
|
|
601
|
+
| `--level <level>` | `string` | none | Difficulty level |
|
|
602
|
+
| `--subject <subject>` | `string` | none | Subject area |
|
|
603
|
+
| `-n, --items <number>` | `string -> int` | none | Target item count |
|
|
604
|
+
| `--time-limit <minutes>` | `string -> int` | none | Time limit in minutes |
|
|
605
|
+
| `--classroom-id <id>` | `string` | none | Classroom ID |
|
|
606
|
+
| `--tier <tier>` | `string` | `standard` | Pricing tier |
|
|
607
|
+
| `--mode <mode>` | `string` | `sync` | `sync` or `async` |
|
|
608
|
+
| `--idempotency-key <key>` | `string` | none | Safe retry key |
|
|
609
|
+
|
|
610
|
+
```bash
|
|
611
|
+
tutorflow --json test create "Algebra quiz" \
|
|
612
|
+
--title "Algebra Basics" \
|
|
613
|
+
--items 8 \
|
|
614
|
+
--time-limit 30 \
|
|
615
|
+
--idempotency-key test-001
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
#### `test list`
|
|
619
|
+
|
|
620
|
+
GET `/v1/platform/tests?limit=<n>&offset=<n>[&status=<s>]`.
|
|
621
|
+
|
|
622
|
+
```bash
|
|
623
|
+
tutorflow --json test list --limit 20 --status READY
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
#### `test get <id>` / `test open <id>` / `test edit-token <id>`
|
|
627
|
+
|
|
628
|
+
Fetch a test, open its preview URL, or generate a fresh edit token.
|
|
629
|
+
|
|
630
|
+
---
|
|
631
|
+
|
|
338
632
|
### `tutorflow evaluate`
|
|
339
633
|
|
|
340
634
|
Evaluates a single student response. Fully interactive; only the type can be passed as a flag.
|
|
@@ -403,33 +697,49 @@ class ApiClient {
|
|
|
403
697
|
## Project layout
|
|
404
698
|
|
|
405
699
|
```
|
|
406
|
-
|
|
407
|
-
├── package.json
|
|
700
|
+
.
|
|
701
|
+
├── package.json # bin: { tutorflow: ./dist/index.js }
|
|
408
702
|
├── tsconfig.json
|
|
703
|
+
├── vitest.config.ts
|
|
704
|
+
├── .github/workflows/
|
|
705
|
+
│ ├── ci.yml # typecheck + build + test on PRs and master
|
|
706
|
+
│ └── release.yml # OIDC publish on master/main pushes when version is new
|
|
707
|
+
├── RELEASING.md # full release procedure + Trusted Publisher setup
|
|
409
708
|
└── src/
|
|
410
|
-
├── index.ts
|
|
411
|
-
├── client.ts
|
|
412
|
-
├──
|
|
709
|
+
├── index.ts # commander entrypoint, registers all commands
|
|
710
|
+
├── client.ts # undici-based ApiClient
|
|
711
|
+
├── client.test.ts
|
|
712
|
+
├── config.ts # ~/.tutorflow/config.json read/write/update/delete
|
|
713
|
+
├── config.test.ts
|
|
714
|
+
├── types.ts # API response interfaces (SlideResource, etc.)
|
|
413
715
|
├── commands/
|
|
414
|
-
│ ├──
|
|
415
|
-
│ ├──
|
|
416
|
-
│ ├──
|
|
417
|
-
│ ├──
|
|
418
|
-
│ ├──
|
|
419
|
-
│
|
|
716
|
+
│ ├── agent.ts # register / account / billing / email verification
|
|
717
|
+
│ ├── auth.ts # login / logout / whoami
|
|
718
|
+
│ ├── config.ts # get / set
|
|
719
|
+
│ ├── course.ts # create / list / open
|
|
720
|
+
│ ├── evaluate.ts # interactive evaluation
|
|
721
|
+
│ ├── module.ts # standalone lesson modules
|
|
722
|
+
│ ├── platform.ts # discovery / pricing / health
|
|
723
|
+
│ ├── slide.ts # create / list / open
|
|
724
|
+
│ ├── test.ts # generated assessments
|
|
725
|
+
│ └── video.ts # create / list / open
|
|
420
726
|
└── utils/
|
|
421
|
-
├── output.ts
|
|
727
|
+
├── output.ts # formatTable, formatJson
|
|
422
728
|
└── spinner.ts
|
|
423
729
|
```
|
|
424
730
|
|
|
425
731
|
## npm scripts
|
|
426
732
|
|
|
427
|
-
| Script
|
|
428
|
-
|
|
|
429
|
-
| `dev`
|
|
430
|
-
| `build`
|
|
431
|
-
| `link`
|
|
432
|
-
| `
|
|
733
|
+
| Script | Command | Purpose |
|
|
734
|
+
| ---------------- | ----------------------- | --------------------------------------- |
|
|
735
|
+
| `dev` | `tsx src/index.ts` | Run from source |
|
|
736
|
+
| `build` | `tsc --outDir dist` | Emit JS + `.d.ts` to `dist/` |
|
|
737
|
+
| `link` | `npm link` | Symlink `tutorflow` globally |
|
|
738
|
+
| `typecheck` | `tsc --noEmit` | Type-check without emitting |
|
|
739
|
+
| `test` | `vitest run` | Run all tests once |
|
|
740
|
+
| `test:watch` | `vitest` | Watch-mode tests |
|
|
741
|
+
| `test:coverage` | `vitest run --coverage` | Generate coverage report |
|
|
742
|
+
| `prepublishOnly` | `rm -rf dist && build` | Auto-runs before `npm publish` |
|
|
433
743
|
|
|
434
744
|
## Stack
|
|
435
745
|
|
|
@@ -438,4 +748,5 @@ apps/cli/
|
|
|
438
748
|
- **HTTP:** [undici](https://github.com/nodejs/undici) `^5.27.0`
|
|
439
749
|
- **Color:** [chalk](https://github.com/chalk/chalk) `^5.3.0`
|
|
440
750
|
- **Browser open:** [open](https://github.com/sindresorhus/open) `^9.0.0`
|
|
751
|
+
- **Tests:** [Vitest](https://vitest.dev) `^4.1.5`
|
|
441
752
|
- **Dev:** TypeScript `^5.0.0`, tsx `^3.0.0`, `@types/node` `^20.0.0`
|
package/dist/client.d.ts
CHANGED
|
@@ -6,7 +6,13 @@ export declare class ApiClient {
|
|
|
6
6
|
private config;
|
|
7
7
|
constructor(config?: IClientConfig);
|
|
8
8
|
static create(): Promise<ApiClient>;
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Like `create` but throws CliError if no API key is resolvable. Use this
|
|
11
|
+
* in any command that talks to the API so we get a single, consistent
|
|
12
|
+
* "not authenticated" path.
|
|
13
|
+
*/
|
|
14
|
+
static createAuthenticated(): Promise<ApiClient>;
|
|
15
|
+
request<T>(method: string, endpoint: string, body?: Record<string, unknown>, headers?: Record<string, string>): Promise<T>;
|
|
10
16
|
setApiKey(apiKey: string): void;
|
|
11
17
|
setBaseUrl(baseUrl: string): void;
|
|
12
18
|
}
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAqBD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,CAAC,EAAE,aAAa;WAIrB,MAAM,IAAI,OAAO,CAAC,SAAS,CAAC;IAIzC;;;;OAIG;WACU,mBAAmB,IAAI,OAAO,CAAC,SAAS,CAAC;IAWhD,OAAO,CAAC,CAAC,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,OAAO,CAAC,CAAC,CAAC;IAwCb,SAAS,CAAC,MAAM,EAAE,MAAM;IAIxB,UAAU,CAAC,OAAO,EAAE,MAAM;CAG3B"}
|