@chalksurf/cli 0.1.0 → 0.2.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/docs/agents.md ADDED
@@ -0,0 +1,203 @@
1
+ # Agent And Codex Guide
2
+
3
+ Use this flow when ChalkSurf is driven by Codex, CI, or another orchestration layer.
4
+
5
+ ## Authentication Strategy
6
+
7
+ Agents must always use an explicit profile. The profile name must follow the
8
+ `ENV-AGENT_TYPE` convention, such as `prod-codex`, `staging-codex`, `dev-claude`,
9
+ or `prod-claude`.
10
+
11
+ ```bash
12
+ chalksurf --profile prod-codex auth status --json
13
+ ```
14
+
15
+ Do not rely on the default profile in agent-driven runs. The default profile is
16
+ for the human operator's terminal workflow and may point at a different
17
+ environment, user token, or selected organization.
18
+
19
+ Create or refresh an agent profile explicitly:
20
+
21
+ ```bash
22
+ printf '%s' "$CHALKSURF_TOKEN" | chalksurf auth login \
23
+ --profile prod-codex \
24
+ --base-url https://chalksurf-api.fly.dev \
25
+ --with-token
26
+ ```
27
+
28
+ Use `CHALKSURF_TOKEN` only as the source for login or as a short-lived override.
29
+ Prefer storing the token in the explicit agent profile for repeated Codex/CI runs.
30
+
31
+ ## Command Contract
32
+
33
+ For agent-driven imports, always use:
34
+
35
+ - `--manifest -` or a generated manifest file
36
+ - `--wait` when the next step depends on completed imports
37
+ - `--json` so the response stays machine-readable
38
+
39
+ Recommended invocation shape:
40
+
41
+ ```bash
42
+ chalksurf --profile prod-codex sheet import --manifest - --wait --json
43
+ ```
44
+
45
+ In `--json` mode:
46
+
47
+ - stdout contains a stable JSON envelope
48
+ - known failures still produce JSON on stdout
49
+ - stderr is reserved for unexpected runtime failures
50
+
51
+ Wait-style failures still include a populated `result` payload, so agents can inspect partial outcomes on exit code `6` or `7`.
52
+
53
+ ## Manifest Design
54
+
55
+ Prefer manifests over large positional argument lists.
56
+
57
+ Why:
58
+
59
+ - multi-source imports stay explicit
60
+ - each logical source can carry a stable `sourceId`
61
+ - sheet imports can group multiple source files into one resulting sheet
62
+ - sheet imports carry `targetFolderPath`, `title`, and `translateTo` at the sheet level
63
+ - agents can correlate import results back to the discovered source set
64
+
65
+ Use `sourceId` whenever a browsing step or upstream scraper already has a stable identifier:
66
+
67
+ ```json
68
+ {
69
+ "organizationId": "org_123",
70
+ "wait": true,
71
+ "sheets": [
72
+ {
73
+ "targetFolderPath": "OKTV/2014",
74
+ "title": "OKTV 2014 Round 1",
75
+ "translateTo": ["english"],
76
+ "sources": [
77
+ {
78
+ "sourceId": "oktv-2014-round-1-part-a",
79
+ "kind": "url",
80
+ "url": "https://example.com/oktv-2014-round-1-part-a.pdf"
81
+ },
82
+ {
83
+ "sourceId": "oktv-2014-round-1-part-b",
84
+ "kind": "url",
85
+ "url": "https://example.com/oktv-2014-round-1-part-b.pdf"
86
+ }
87
+ ]
88
+ }
89
+ ]
90
+ }
91
+ ```
92
+
93
+ For sheet imports, `targetFolderPath` is the destination of the resulting sheet. Use `null` for the root folder. Source-level `relativePath` is only a filename or source-label override and should not be used as a destination path.
94
+
95
+ Further reference:
96
+
97
+ - [Manifest reference](./manifest.md)
98
+ - [Sheet import schema](../schemas/sheet-import-manifest.schema.json)
99
+ - [Exercise import schema](../schemas/exercise-import-manifest.schema.json)
100
+ - [Exercise solution import schema](../schemas/exercise-solution-import-manifest.schema.json)
101
+
102
+ ## JSON Result Shape
103
+
104
+ Import commands normalize results around:
105
+
106
+ - `request`
107
+ - `sources`
108
+ - `jobs`
109
+ - `summary`
110
+
111
+ Each resolved source includes stable correlation fields:
112
+
113
+ - `sourceIndex`
114
+ - `sourceInputIndex`
115
+ - `sourceId`
116
+
117
+ Each job includes:
118
+
119
+ - `jobId`
120
+ - `sourceIndexes`
121
+ - `sourceIds`
122
+ - `status`
123
+
124
+ `summary` includes:
125
+
126
+ - source and job counts
127
+ - per-status counts
128
+ - `timedOut`
129
+
130
+ ## Recommended Control Flow
131
+
132
+ 1. Discover candidate URLs or local files.
133
+ 2. Filter them to the target scope.
134
+ 3. Build a manifest with stable `sourceId` values.
135
+ 4. Pipe the manifest into the CLI with `--wait --json`.
136
+ 5. Inspect `ok`, `result.summary`, and `result.jobs`.
137
+ 6. Retry only the failed or timed-out source set.
138
+
139
+ For example:
140
+
141
+ ```bash
142
+ cat import.json | chalksurf --profile prod-codex sheet import --manifest - --wait --json
143
+ ```
144
+
145
+ On success, the envelope looks like:
146
+
147
+ ```json
148
+ {
149
+ "schemaVersion": "v1",
150
+ "command": "sheet import",
151
+ "ok": true,
152
+ "result": {
153
+ "request": {},
154
+ "sources": [],
155
+ "jobs": [],
156
+ "summary": {
157
+ "timedOut": false
158
+ }
159
+ },
160
+ "warnings": []
161
+ }
162
+ ```
163
+
164
+ On timeout or job failure, `ok` becomes `false`, `error.code` is stable, and `result` still contains the normalized import data needed for retries.
165
+
166
+ ## Codex Workflow Example
167
+
168
+ Target task:
169
+
170
+ Import all OKTV exercise sheets between 2010 and 2020 from an archive page, and translate the non-English sheets to English.
171
+
172
+ Recommended workflow:
173
+
174
+ 1. Codex browses the archive page and collects the relevant links.
175
+ 2. Codex filters the links to years `2010` through `2020`.
176
+ 3. Codex builds a sheet-import manifest with one `sheets[]` entry per resulting sheet.
177
+ 4. Codex groups multiple source files inside one `sources[]` array when they belong to the same resulting sheet.
178
+ 5. Codex sets `translateTo: ["english"]` on the sheet entries that should produce an English translation.
179
+ 6. Codex runs `chalksurf --profile prod-codex sheet import --manifest - --wait --json`.
180
+ 7. Codex inspects `result.summary.failed`, `result.summary.timedOut`, and `jobs` to decide whether to retry or report failures.
181
+
182
+ Minimal shell shape:
183
+
184
+ ```bash
185
+ cat import.json | chalksurf --profile prod-codex sheet import --manifest - --wait --json
186
+ ```
187
+
188
+ The discovery step belongs outside the ChalkSurf CLI. The CLI contract starts at a concrete manifest and ends at structured import results.
189
+
190
+ ## Failure Handling
191
+
192
+ Use the exit code and JSON `error.code` together:
193
+
194
+ - `2` / `usage_error`: the manifest or command input is invalid
195
+ - `3` / `not_authenticated`: missing or invalid token
196
+ - `4` / `source_resolution_failed`: local file, directory, or URL preparation failed
197
+ - `5` / `api_error`: the ChalkSurf API rejected the request
198
+ - `6` / `wait_timed_out`: jobs did not finish in time
199
+ - `7` / `job_failed`: one or more jobs finished with failure
200
+
201
+ Reference:
202
+
203
+ - [Exit codes and JSON errors](./exit-codes.md)
@@ -0,0 +1,13 @@
1
+ {
2
+ "organizationId": "org_123",
3
+ "exerciseSheetId": "00000000-0000-4000-8000-000000000111",
4
+ "wait": true,
5
+ "sources": [
6
+ {
7
+ "sourceId": "problem-1",
8
+ "kind": "local",
9
+ "path": "./imports/problem-1.pdf",
10
+ "relativePath": "Problem Set/problem-1.pdf"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "organizationId": "org_123",
3
+ "exerciseId": "00000000-0000-4000-8000-000000000222",
4
+ "wait": true,
5
+ "sources": [
6
+ {
7
+ "sourceId": "problem-1-solution",
8
+ "kind": "local",
9
+ "path": "./imports/problem-1-solution.pdf",
10
+ "relativePath": "Solutions/problem-1.pdf"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "organizationId": "org_123",
3
+ "wait": true,
4
+ "sheets": [
5
+ {
6
+ "targetFolderPath": "OKTV/2014",
7
+ "title": "OKTV 2014 Round 1",
8
+ "translateTo": ["english"],
9
+ "sources": [
10
+ {
11
+ "sourceId": "oktv-2014-round-1-part-a",
12
+ "kind": "url",
13
+ "url": "https://example.com/oktv-2014-round-1-part-a.pdf"
14
+ },
15
+ {
16
+ "sourceId": "oktv-2014-round-1-part-b",
17
+ "kind": "url",
18
+ "url": "https://example.com/oktv-2014-round-1-part-b.pdf"
19
+ }
20
+ ]
21
+ },
22
+ {
23
+ "targetFolderPath": null,
24
+ "sources": [
25
+ {
26
+ "sourceId": "practice-sheet",
27
+ "kind": "local",
28
+ "path": "./practice-sheet.pdf"
29
+ }
30
+ ]
31
+ }
32
+ ]
33
+ }
@@ -0,0 +1,57 @@
1
+ # Exit Codes And JSON Errors
2
+
3
+ The CLI uses stable exit codes so automation can branch without parsing human text.
4
+
5
+ ## Exit Codes
6
+
7
+ | Exit code | Error code | Meaning |
8
+ | --- | --- | --- |
9
+ | `0` | n/a | Success |
10
+ | `1` | `unexpected_error` | Unhandled runtime failure |
11
+ | `2` | `usage_error` | Invalid arguments, invalid manifest, or missing required config such as `--base-url` |
12
+ | `3` | `not_authenticated` | Missing token or rejected CLI token |
13
+ | `4` | `source_resolution_failed` | Local file, directory, URL, or relative path resolution failed |
14
+ | `5` | `api_error` | The ChalkSurf API returned a non-auth failure |
15
+ | `6` | `wait_timed_out` | Waiting ended before all jobs reached a terminal state |
16
+ | `7` | `job_failed` | One or more jobs completed with failure |
17
+
18
+ These same codes are mirrored in `error.exitCode` and `error.code` inside the JSON envelope.
19
+
20
+ ## JSON Envelope
21
+
22
+ In `--json` mode, stdout contains a stable envelope:
23
+
24
+ ```json
25
+ {
26
+ "schemaVersion": "v1",
27
+ "command": "sheet import",
28
+ "ok": true,
29
+ "result": {},
30
+ "warnings": []
31
+ }
32
+ ```
33
+
34
+ Known failures also return JSON on stdout:
35
+
36
+ ```json
37
+ {
38
+ "schemaVersion": "v1",
39
+ "command": "sheet import",
40
+ "ok": false,
41
+ "result": {},
42
+ "error": {
43
+ "code": "source_resolution_failed",
44
+ "message": "Local source \"/tmp/imports/missing.pdf\" does not exist.",
45
+ "exitCode": 4,
46
+ "retryable": false
47
+ },
48
+ "warnings": []
49
+ }
50
+ ```
51
+
52
+ ## Contract Notes
53
+
54
+ - `warnings` contains informational messages that would otherwise be printed for humans.
55
+ - In `--json` mode, stderr is reserved for unexpected runtime failures only.
56
+ - Wait-style commands and imports keep their `result` payload even when `ok` is `false`.
57
+ - Import commands normalize their `result` payloads around `request`, `sources`, `jobs`, and `summary`.
@@ -0,0 +1,129 @@
1
+ # Manifest Reference
2
+
3
+ ChalkSurf uses JSON manifests for batch and agent-driven imports.
4
+
5
+ One manifest file is passed to exactly one command:
6
+
7
+ - `chalksurf sheet import --manifest <path|->`
8
+ - `chalksurf exercise import --manifest <path|->`
9
+ - `chalksurf exercise import-solution --manifest <path|->`
10
+
11
+ Use `--manifest -` to pipe JSON on stdin.
12
+
13
+ ## Common Fields
14
+
15
+ Every manifest is a JSON object with these shared metadata fields:
16
+
17
+ | Field | Type | Required | Notes |
18
+ | --- | --- | --- | --- |
19
+ | `organizationId` | string | no | Overrides the default organization for this invocation. |
20
+ | `wait` | boolean | no | Behaves like `--wait`. The CLI also accepts `--wait`, which wins if set. |
21
+
22
+ Every source object supports these common fields. For `sheet import`, sources appear inside `sheets[].sources[]`. For the exercise import commands, they appear in top-level `sources[]`.
23
+
24
+ | Field | Type | Required | Notes |
25
+ | --- | --- | --- | --- |
26
+ | `sourceId` | string | no | Optional stable identifier for correlating source inputs to results. Must be unique within the manifest. |
27
+ | `kind` | `local` \| `directory` \| `url` | yes | Selects the source shape. |
28
+
29
+ ### Source Kinds
30
+
31
+ `local`
32
+
33
+ | Field | Type | Required | Notes |
34
+ | --- | --- | --- | --- |
35
+ | `path` | string | yes | Local file path relative to `cwd` unless already absolute. |
36
+ | `relativePath` | string | no | Stored path shown to ChalkSurf. Defaults to the basename of `path`. |
37
+
38
+ `directory`
39
+
40
+ | Field | Type | Required | Notes |
41
+ | --- | --- | --- | --- |
42
+ | `path` | string | yes | Directory to expand recursively. |
43
+ | `relativeRoot` | string | no | Base directory used to compute stored relative paths. Defaults to `path`. |
44
+
45
+ `url`
46
+
47
+ | Field | Type | Required | Notes |
48
+ | --- | --- | --- | --- |
49
+ | `url` | string | yes | HTTP(S) URL to download before import. |
50
+ | `relativePath` | string | no | Stored path shown to ChalkSurf. Defaults to the filename derived from the URL. |
51
+
52
+ ## Command-Specific Fields
53
+
54
+ ### Sheet Import
55
+
56
+ Top-level fields:
57
+
58
+ | Field | Type | Required | Notes |
59
+ | --- | --- | --- | --- |
60
+ | `sheets` | array | yes | One or more sheets to import. Each sheet may contain one or more source files. |
61
+
62
+ Sheet fields:
63
+
64
+ | Field | Type | Required | Notes |
65
+ | --- | --- | --- | --- |
66
+ | `targetFolderPath` | string \| null | yes | Destination folder for the resulting sheet. Use `null` for the root folder. |
67
+ | `sources` | array | yes | One or more source files that belong to this sheet, in import order. |
68
+ | `title` | string | no | Overrides the imported sheet title. |
69
+ | `translateTo` | string[] | no | Target translation languages. Must be unique and non-empty when present. |
70
+
71
+ Sheet import metadata is sheet-level, not source-level. Do not put `title` or `translateTo` on individual sources inside `sheets[].sources[]`.
72
+
73
+ Source-level `relativePath` is only a source label or filename override. It does not choose the destination folder for grouped sheet imports; `targetFolderPath` is the only destination field.
74
+
75
+ Canonical example:
76
+
77
+ - [docs/examples/sheet-import-manifest.json](./examples/sheet-import-manifest.json)
78
+ - [schemas/sheet-import-manifest.schema.json](../schemas/sheet-import-manifest.schema.json)
79
+
80
+ ### Exercise Import
81
+
82
+ Top-level fields:
83
+
84
+ | Field | Type | Required | Notes |
85
+ | --- | --- | --- | --- |
86
+ | `sources` | array | yes | One or more import sources. |
87
+ | `exerciseSheetId` | string | no | Default target sheet for the imported exercises. Can still be overridden by `--sheet-id`. |
88
+
89
+ Per-source fields:
90
+
91
+ - Only the common source fields are allowed.
92
+ - `title` and `translateTo` are rejected for this command.
93
+
94
+ Canonical example:
95
+
96
+ - [docs/examples/exercise-import-manifest.json](./examples/exercise-import-manifest.json)
97
+ - [schemas/exercise-import-manifest.schema.json](../schemas/exercise-import-manifest.schema.json)
98
+
99
+ ### Exercise Solution Import
100
+
101
+ Top-level fields:
102
+
103
+ | Field | Type | Required | Notes |
104
+ | --- | --- | --- | --- |
105
+ | `sources` | array | yes | One or more import sources. |
106
+ | `exerciseId` | string | no | Default target exercise for the imported solution files. The command still requires an exercise id overall, either here or positionally. |
107
+
108
+ Per-source fields:
109
+
110
+ - Only the common source fields are allowed.
111
+ - `title` and `translateTo` are rejected for this command.
112
+
113
+ Canonical example:
114
+
115
+ - [docs/examples/exercise-solution-import-manifest.json](./examples/exercise-solution-import-manifest.json)
116
+ - [schemas/exercise-solution-import-manifest.schema.json](../schemas/exercise-solution-import-manifest.schema.json)
117
+
118
+ ## Validation Notes
119
+
120
+ The CLI validates more than the JSON schema can express on its own:
121
+
122
+ - `sourceId` values must be unique within one manifest.
123
+ - Sheet import `translateTo` values must be unique within one sheet.
124
+ - `relativePath` cannot be empty or contain `..`.
125
+ - Sheet import `targetFolderPath` must be `null` or a normalized folder path without `.` or `..` segments.
126
+ - `directory` imports must resolve to at least one file.
127
+ - URL imports must use `http` or `https`.
128
+
129
+ Treat the schema files as a reference format and the CLI as the final validator.
package/docs/manual.md ADDED
@@ -0,0 +1,169 @@
1
+ # Manual Operator Guide
2
+
3
+ Use this flow when a person is driving the CLI directly from a terminal.
4
+
5
+ ## Authentication
6
+
7
+ Interactive login stores the token and base URL in a named profile:
8
+
9
+ ```bash
10
+ chalksurf auth login --profile prod-cztamas --base-url https://chalksurf-api.fly.dev
11
+ ```
12
+
13
+ The same command also works with piped stdin:
14
+
15
+ ```bash
16
+ printf '%s' "$CHALKSURF_TOKEN" | chalksurf auth login \
17
+ --profile prod-cztamas \
18
+ --base-url https://chalksurf-api.fly.dev \
19
+ --with-token
20
+ ```
21
+
22
+ Set the profile you want to use by default in your terminal workflow:
23
+
24
+ ```bash
25
+ chalksurf profile use prod-cztamas
26
+ ```
27
+
28
+ Check what the CLI will use for the current session:
29
+
30
+ ```bash
31
+ chalksurf auth status
32
+ ```
33
+
34
+ Config resolution rules:
35
+
36
+ - `--profile` overrides `CHALKSURF_PROFILE`, which overrides the stored default profile.
37
+ - `--base-url` overrides `CHALKSURF_BASE_URL`, which overrides the active profile.
38
+ - `CHALKSURF_TOKEN` overrides the active profile token.
39
+ - `--organization` overrides manifest `organizationId`, which overrides `CHALKSURF_ORGANIZATION_ID`, which overrides the active profile.
40
+
41
+ ## Organization Selection
42
+
43
+ List organizations visible to the current token:
44
+
45
+ ```bash
46
+ chalksurf org list
47
+ ```
48
+
49
+ Store a default organization for future commands:
50
+
51
+ ```bash
52
+ chalksurf org use org_123
53
+ ```
54
+
55
+ Store a default organization in a different profile without changing your default profile:
56
+
57
+ ```bash
58
+ chalksurf --profile prod-codex org use org_456
59
+ ```
60
+
61
+ Override it for one command:
62
+
63
+ ```bash
64
+ chalksurf sheet import ./fixtures/algebra.pdf --organization org_456
65
+ ```
66
+
67
+ ## Common Import Flows
68
+
69
+ Import one sheet and wait for the background job to finish:
70
+
71
+ ```bash
72
+ chalksurf sheet import ./fixtures/algebra.pdf --wait
73
+ ```
74
+
75
+ Import one sheet, override its title, and request an English translation during import:
76
+
77
+ ```bash
78
+ chalksurf sheet import ./fixtures/algebra.pdf \
79
+ --title "OKTV 2014 Round 1" \
80
+ --translate-to english \
81
+ --wait
82
+ ```
83
+
84
+ Import one sheet assembled from multiple source files:
85
+
86
+ ```bash
87
+ chalksurf sheet import ./fixtures/round-1-a.pdf ./fixtures/round-1-b.pdf \
88
+ --single-sheet \
89
+ --target-folder "OKTV/2014" \
90
+ --wait
91
+ ```
92
+
93
+ Import exercises into an existing sheet:
94
+
95
+ ```bash
96
+ chalksurf exercise import ./fixtures/problem-set.pdf \
97
+ --sheet-id 00000000-0000-4000-8000-000000000001 \
98
+ --wait
99
+ ```
100
+
101
+ Import a solution into an existing exercise:
102
+
103
+ ```bash
104
+ chalksurf exercise import-solution \
105
+ 00000000-0000-4000-8000-000000000001 \
106
+ ./fixtures/solution.pdf \
107
+ --wait
108
+ ```
109
+
110
+ Import from a remote URL:
111
+
112
+ ```bash
113
+ chalksurf sheet import https://example.com/trig.docx \
114
+ --single-sheet \
115
+ --target-folder Imported \
116
+ --wait
117
+ ```
118
+
119
+ Use a manifest for multi-source imports or when each resulting sheet needs explicit metadata:
120
+
121
+ ```bash
122
+ chalksurf sheet import --manifest ./import.json --wait
123
+ ```
124
+
125
+ Sheet import manifests use top-level `sheets[]`. Each sheet has one destination `targetFolderPath`, optional `title` and `translateTo`, and one or more ordered `sources[]`.
126
+
127
+ ## Working With Jobs
128
+
129
+ Read one job:
130
+
131
+ ```bash
132
+ chalksurf job get job_123
133
+ ```
134
+
135
+ Wait on one or more jobs later:
136
+
137
+ ```bash
138
+ chalksurf job wait job_123 job_124
139
+ ```
140
+
141
+ `--wait` on an import command means the requested import work is complete before the command exits. For sheet imports, that includes requested translations.
142
+
143
+ ## Troubleshooting
144
+
145
+ Missing auth:
146
+
147
+ ```bash
148
+ chalksurf auth status
149
+ ```
150
+
151
+ Use profiles when switching between local, staging, production, humans, and agents:
152
+
153
+ ```bash
154
+ chalksurf auth login --profile staging-cztamas --base-url https://chalksurf-api-staging.fly.dev
155
+ chalksurf auth login --profile prod-cztamas --base-url https://chalksurf-api.fly.dev
156
+ chalksurf profile use prod-cztamas
157
+ ```
158
+
159
+ Use JSON mode when you need exact machine-readable output:
160
+
161
+ ```bash
162
+ chalksurf job wait job_123 --json
163
+ ```
164
+
165
+ Further reference:
166
+
167
+ - [Agent and Codex guide](./agents.md)
168
+ - [Manifest reference](./manifest.md)
169
+ - [Exit codes and JSON errors](./exit-codes.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chalksurf/cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "engines": {
@@ -8,7 +8,9 @@
8
8
  },
9
9
  "files": [
10
10
  "dist",
11
- "README.md"
11
+ "README.md",
12
+ "docs",
13
+ "schemas"
12
14
  ],
13
15
  "bin": {
14
16
  "chalksurf": "dist/bin/chalksurf.js"
@@ -26,12 +28,14 @@
26
28
  "build": "tsc --project ./tsconfig.build.json",
27
29
  "lint": "eslint .",
28
30
  "type-check": "tsc --noEmit --project ./tsconfig.json",
29
- "test": "vitest --config ./vitest.config.ts --run",
31
+ "test": "vitest --config ./vitest.config.ts --run --maxWorkers=1",
32
+ "test:watch": "vitest --config ./vitest.config.ts --watch --maxWorkers=1",
30
33
  "smoke-pack": "node --import tsx ./scripts/smoke-pack.ts"
31
34
  },
32
35
  "dependencies": {
33
36
  "p-limit": "^6.2.0",
34
- "yargs": "^17.7.2"
37
+ "yargs": "^17.7.2",
38
+ "zod": "^4.1.12"
35
39
  },
36
40
  "devDependencies": {
37
41
  "@types/node": "^24.10.1",