@wilm-ai/wilma-cli 1.6.2 → 2.0.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/LICENSE +21 -0
- package/README.md +57 -67
- package/dist/access.d.ts +12 -0
- package/dist/access.js +33 -0
- package/dist/agent-data.d.ts +496 -0
- package/dist/agent-data.js +578 -0
- package/dist/cli-args.d.ts +33 -0
- package/dist/cli-args.js +256 -0
- package/dist/cli-help.d.ts +2 -0
- package/dist/cli-help.js +141 -0
- package/dist/cli-output.d.ts +6 -0
- package/dist/cli-output.js +184 -0
- package/dist/config.js +63 -24
- package/dist/credentials.d.ts +69 -0
- package/dist/credentials.js +195 -0
- package/dist/downloads.d.ts +23 -0
- package/dist/downloads.js +105 -0
- package/dist/index.js +692 -1657
- package/dist/login-server.d.ts +52 -0
- package/dist/login-server.js +595 -0
- package/dist/mcp-tools.d.ts +23 -0
- package/dist/mcp-tools.js +235 -0
- package/dist/mcp.d.ts +1 -0
- package/dist/mcp.js +153 -0
- package/dist/output-json.d.ts +1 -0
- package/dist/output-json.js +26 -0
- package/dist/session-store.d.ts +7 -0
- package/dist/session-store.js +61 -0
- package/dist/tenant-search.d.ts +11 -0
- package/dist/tenant-search.js +127 -0
- package/dist/totp.d.ts +6 -0
- package/dist/totp.js +49 -0
- package/package.json +24 -8
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Wilm.ai
|
|
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
CHANGED
|
@@ -3,101 +3,90 @@
|
|
|
3
3
|
Command line interface for Wilma (Finnish school system), built for parents and AI agents.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
|
+
Needs Node.js 20.18.1 or newer.
|
|
6
7
|
```bash
|
|
7
8
|
npm i -g @wilm-ai/wilma-cli
|
|
8
9
|
# or
|
|
9
10
|
pnpm add -g @wilm-ai/wilma-cli
|
|
10
11
|
```
|
|
11
12
|
|
|
12
|
-
##
|
|
13
|
+
## Log in
|
|
13
14
|
```bash
|
|
14
|
-
wilma
|
|
15
|
-
# or
|
|
16
|
-
wilmai
|
|
15
|
+
wilma login
|
|
17
16
|
```
|
|
17
|
+
Opens a one-time login page in your browser: pick your school's Wilma and log in. The login is saved to `~/.config/wilmai/config.json`.
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
### Daily briefing
|
|
22
|
-
```bash
|
|
23
|
-
wilma summary [--days 7] [--student <id|name>] [--all-students] [--json]
|
|
24
|
-
```
|
|
25
|
-
Combines today's and tomorrow's schedule, upcoming exams, recent homework, news, and messages into one view. Designed for AI agents to surface what matters.
|
|
19
|
+
Without a browser: `wilma login --tenant <url|city> --username <name>` with the password in `WILMA_PASSWORD` or piped via `--password-stdin`. Or set `WILMA_TENANT`, `WILMA_USERNAME`, `WILMA_PASSWORD` (and `WILMA_TOTP_SECRET`) and skip the saved login.
|
|
26
20
|
|
|
27
|
-
|
|
21
|
+
## Use it
|
|
28
22
|
```bash
|
|
29
|
-
wilma
|
|
23
|
+
wilma summary # the daily briefing for every child — start here
|
|
24
|
+
wilma schedule tomorrow # today | tomorrow | week | next-week | 2026-10-07 | thu
|
|
25
|
+
wilma exams # upcoming exams, with topics and start times
|
|
26
|
+
wilma homework
|
|
27
|
+
wilma notes --days 7 # lesson notes: absences and teachers' feedback
|
|
28
|
+
wilma notes summary # those counted by kind for the school year
|
|
29
|
+
wilma messages # newest first; [new] and reply counts
|
|
30
|
+
wilma messages 27164611 # one message with its whole thread
|
|
31
|
+
wilma news # dated bulletins plus pinned ones; --older for the rest
|
|
32
|
+
wilma news 73291 # one bulletin with its links
|
|
33
|
+
wilma news 73291 download 1 # a file linked from it
|
|
34
|
+
wilma grades # recent exam grades
|
|
35
|
+
wilma gradebook # course and report-card grades
|
|
36
|
+
wilma printouts # PDFs such as report cards; `wilma printouts <id>` saves one
|
|
37
|
+
wilma students
|
|
38
|
+
wilma help <command> # usage, examples and the JSON shape
|
|
30
39
|
```
|
|
31
40
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
wilma schedule list --weekday thu --student "Stella" --json
|
|
41
|
+
- **Every child by default.** `--student <number|name>` narrows to one (a number, the full name, or the start of a first or last name — never a loose match).
|
|
42
|
+
- **JSON for programs, text for people.** Output is JSON when another program reads it (agents, pipes) and text in a terminal; `--json` or `--text` forces either. The JSON is the same as the MCP tools' — `{ students: [{ student, … }] }` — compact, with times in Finnish time and their offset (`2026-10-02T13:37:00+03:00`).
|
|
43
|
+
- **Dates** are `YYYY-MM-DD`, `today`, `yesterday` or `tomorrow`.
|
|
44
|
+
- **One login, not one per command.** Commands continue the last Wilma session (saved next to the login, readable only by you) and log in again only when Wilma has ended it. Each login would otherwise log you out of Wilma in your browser and, with two-step verification, need a new code. `WILMAI_NO_SESSION_CACHE=1` turns this off.
|
|
45
|
+
- **For daily runs:** `wilma summary --since yesterday` returns only what is new: bulletins, messages, homework and lesson notes from that day on, plus anything unread.
|
|
46
|
+
- **Errors** are JSON too: `{ "status": "error", "code": "unknown_student", "message": "…" }`, with exit code 2 for usage errors, 3 when not logged in, and 1 otherwise. Codes include `invalid_argument`, `unknown_command`, `not_logged_in`, `unknown_student`, `ambiguous_student`, `not_found`, `login_failed`, `mfa_required`, `network` and `wilma_error`.
|
|
39
47
|
|
|
40
|
-
|
|
41
|
-
wilma schedule list --when tomorrow --student "Stella" --json
|
|
42
|
-
```
|
|
48
|
+
The 1.x spellings still work: `kids list`, `tenants`, `attendance list`, `<command> list`, `messages read <id>`, `news read <id>`, `news resource download <id> <resource>`, `printouts download <id>` and `--all-students`.
|
|
43
49
|
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
wilma homework list [--limit 10] [--student <id|name>] [--all-students] [--json]
|
|
47
|
-
```
|
|
50
|
+
Running `wilma` without arguments in a terminal opens an interactive menu.
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
## Use with AI assistants (MCP)
|
|
50
53
|
```bash
|
|
51
|
-
wilma
|
|
54
|
+
wilma mcp
|
|
52
55
|
```
|
|
56
|
+
Starts a stdio MCP server with read-only Wilma tools (`wilma_summary`, `wilma_schedule`, `wilma_read_news`, …) that return the same data as the commands. Add it to any MCP client as `npx -y @wilm-ai/wilma-cli@2 mcp`. Setup guides for Claude, ChatGPT, Grok Bot and OpenClaw: https://wilm.ai
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
wilma grades list [--limit 20] [--student <id|name>] [--all-students] [--json]
|
|
57
|
-
```
|
|
58
|
+
## Bulletin attachments
|
|
59
|
+
`wilma news <id>` lists every link in a bulletin (`resources`). Any resource can be downloaded with `wilma news <id> download <resource> [--output <directory>]` (the resource id also accepts a bare number, e.g. `1` for `resource-1`). Wilma-hosted files download through the session; external links are fetched without your Wilma login, and only from public websites. The result's `status` says what happened: `downloaded` (use the returned `path`) or `not_a_file` when the link answered with a web page (for example a sharing link that needs signing in — open it in a browser instead). `--output` defaults to the current directory; existing files are never overwritten.
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
## Several Wilmas
|
|
62
|
+
Children at schools on different Wilmas need one login per Wilma. Run `wilma login` again (or press "Add another Wilma" on the login page); commands then cover every child, and each child carries the `wilma` it belongs to.
|
|
60
63
|
```bash
|
|
61
|
-
wilma
|
|
62
|
-
wilma
|
|
63
|
-
wilma news resource download <news-id> <resource-id> [--student <id|name>] [--output <directory>] [--json]
|
|
64
|
-
wilma messages list [--folder inbox] [--limit 20] [--student <id|name>] [--all-students] [--json]
|
|
65
|
-
wilma messages read <id> [--student <id|name>] [--json]
|
|
64
|
+
wilma accounts # saved logins, numbered
|
|
65
|
+
wilma accounts remove <number> # or the Wilma name or username
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
### Attendance / lesson notes
|
|
68
|
+
## Find your Wilma
|
|
71
69
|
```bash
|
|
72
|
-
wilma
|
|
70
|
+
wilma find-school <city or school>
|
|
73
71
|
```
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
### Other
|
|
73
|
+
## Other
|
|
78
74
|
```bash
|
|
79
|
-
wilma kids list [--json]
|
|
80
75
|
wilma update
|
|
81
|
-
wilma config clear
|
|
76
|
+
wilma config clear # deletes every saved login and session
|
|
77
|
+
wilma --version
|
|
82
78
|
```
|
|
83
79
|
|
|
84
80
|
## MFA (Multi-Factor Authentication)
|
|
85
81
|
|
|
86
82
|
If your Wilma account has MFA/TOTP enabled:
|
|
87
83
|
|
|
88
|
-
**
|
|
89
|
-
|
|
90
|
-
**Non-interactive:** Pass the secret directly:
|
|
91
|
-
```bash
|
|
92
|
-
wilma schedule list --totp-secret <base32-key> --json
|
|
93
|
-
wilma schedule list --totp-secret 'otpauth://totp/...' --json
|
|
94
|
-
```
|
|
84
|
+
**Recommended:** run `wilma login`. When Wilma asks for a code, the login page asks for your authenticator's setup key (base32 or `otpauth://` URI) and saves it with the login, so later logins make their own codes. In the interactive menu (`wilma`), choose "Save TOTP secret for automatic login".
|
|
95
85
|
|
|
96
|
-
|
|
86
|
+
**Without a saved login:** set `WILMA_TOTP_SECRET` along with the other `WILMA_*` variables. `--totp-secret <key>` also works, but a key on the command line ends up in shell history and is visible to other programs on the computer.
|
|
97
87
|
|
|
98
88
|
## Config
|
|
99
|
-
|
|
100
|
-
Use `wilma config clear` to remove it. Override with `WILMAI_CONFIG_PATH`.
|
|
89
|
+
Logins are saved in `~/.config/wilmai/config.json` (or `$XDG_CONFIG_HOME/wilmai/config.json`; override with `WILMAI_CONFIG_PATH`) and the current Wilma sessions in `wilmai-sessions.json` next to it, both readable only by you. `wilma config clear` deletes both.
|
|
101
90
|
|
|
102
91
|
## Troubleshooting: TLS errors on a managed laptop
|
|
103
92
|
|
|
@@ -108,26 +97,27 @@ A successful `npm install` is not evidence that TLS is healthy — the npm regis
|
|
|
108
97
|
commonly exempt from inspection.
|
|
109
98
|
|
|
110
99
|
```bash
|
|
111
|
-
NODE_USE_SYSTEM_CA=1 wilma summary
|
|
112
|
-
node --use-system-ca "$(command -v wilma)" summary
|
|
113
|
-
NODE_EXTRA_CA_CERTS=/path/to/root-ca.pem wilma summary
|
|
100
|
+
NODE_USE_SYSTEM_CA=1 wilma summary # Node >=22.19 / >=24.6
|
|
101
|
+
node --use-system-ca "$(command -v wilma)" summary # Node >=22.15
|
|
102
|
+
NODE_EXTRA_CA_CERTS=/path/to/root-ca.pem wilma summary # explicit root
|
|
114
103
|
```
|
|
115
104
|
|
|
116
105
|
Never use `NODE_TLS_REJECT_UNAUTHORIZED=0` — it turns verification off entirely.
|
|
117
106
|
|
|
118
|
-
|
|
119
|
-
`
|
|
107
|
+
In JSON, transport failures have the code `network`, with the underlying `cause` and a
|
|
108
|
+
`hint`, so agents can branch on it:
|
|
120
109
|
|
|
121
110
|
```json
|
|
122
111
|
{
|
|
123
112
|
"status": "error",
|
|
113
|
+
"code": "network",
|
|
124
114
|
"message": "TLS certificate verification failed for https://example.inschool.fi (UNABLE_TO_GET_ISSUER_CERT_LOCALLY)",
|
|
125
|
-
"
|
|
115
|
+
"cause": "UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
|
|
126
116
|
"hint": "..."
|
|
127
117
|
}
|
|
128
118
|
```
|
|
129
119
|
|
|
130
120
|
## Notes
|
|
131
|
-
- Credentials and TOTP secrets are stored with lightweight obfuscation
|
|
132
|
-
-
|
|
133
|
-
-
|
|
121
|
+
- Credentials and TOTP secrets are stored with lightweight obfuscation (not encryption) in a file only your user can read.
|
|
122
|
+
- Bulletin links are fetched only from public websites (never local or private network addresses), without your Wilma login.
|
|
123
|
+
- Commands cover every child; `--student <number|name>` narrows to one.
|
package/dist/access.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { WilmaAccess } from "./agent-data.js";
|
|
2
|
+
import { type ActiveAccount } from "./credentials.js";
|
|
3
|
+
/**
|
|
4
|
+
* Wilma access for the saved (or environment) logins — the same for CLI
|
|
5
|
+
* commands and the local MCP server. Refreshed child lists are written back
|
|
6
|
+
* to the config, changing only that field, so parallel commands and logins
|
|
7
|
+
* aren't overwritten.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createAccess(accounts: ActiveAccount[], opts?: {
|
|
10
|
+
debug?: boolean;
|
|
11
|
+
totpSecret?: string;
|
|
12
|
+
}): WilmaAccess;
|
package/dist/access.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { WilmaAccess } from "./agent-data.js";
|
|
2
|
+
import { loadConfig, saveConfig } from "./config.js";
|
|
3
|
+
import { mfaCallbackFor } from "./credentials.js";
|
|
4
|
+
/**
|
|
5
|
+
* Wilma access for the saved (or environment) logins — the same for CLI
|
|
6
|
+
* commands and the local MCP server. Refreshed child lists are written back
|
|
7
|
+
* to the config, changing only that field, so parallel commands and logins
|
|
8
|
+
* aren't overwritten.
|
|
9
|
+
*/
|
|
10
|
+
export function createAccess(accounts, opts = {}) {
|
|
11
|
+
return new WilmaAccess(accounts.map((account, index) => ({
|
|
12
|
+
profile: { ...account.profile, debug: opts.debug ?? account.profile.debug },
|
|
13
|
+
// A --totp-secret given on the command line belongs to the first (active) login.
|
|
14
|
+
mfa: mfaCallbackFor(index === 0 && opts.totpSecret ? opts.totpSecret : account.totpSecret),
|
|
15
|
+
label: account.stored?.tenantName ?? account.profile.baseUrl,
|
|
16
|
+
knownStudents: account.stored?.students,
|
|
17
|
+
onStudents: async (students) => {
|
|
18
|
+
const stored = account.stored;
|
|
19
|
+
// An empty answer from Wilma keeps the saved list (see knownStudents).
|
|
20
|
+
if (!stored || !students.length)
|
|
21
|
+
return;
|
|
22
|
+
const fresh = students.map((s) => ({ studentNumber: s.studentNumber, name: s.name }));
|
|
23
|
+
if (JSON.stringify(fresh) === JSON.stringify(stored.students ?? []))
|
|
24
|
+
return;
|
|
25
|
+
const latest = await loadConfig();
|
|
26
|
+
const target = latest.profiles.find((p) => p.id === stored.id);
|
|
27
|
+
if (!target)
|
|
28
|
+
return;
|
|
29
|
+
target.students = fresh;
|
|
30
|
+
await saveConfig(latest);
|
|
31
|
+
},
|
|
32
|
+
})));
|
|
33
|
+
}
|