@stemtrooper/learningcode 0.3.0 → 0.3.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.
Files changed (4) hide show
  1. package/LICENSE +1 -29
  2. package/NOTICE +42 -0
  3. package/README.md +197 -130
  4. package/package.json +3 -2
package/LICENSE CHANGED
@@ -1,34 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 TLC (The Learning Curve) / stemtrooper
4
-
5
- learningcode is a distribution wrapper. It does not contain source copied from
6
- Pi; it depends on @earendil-works/pi-coding-agent at runtime.
7
-
8
- That dependency is MIT licensed:
9
-
10
- MIT License
11
- Copyright (c) Mario Zechner (and contributors)
12
-
13
- Permission is hereby granted, free of charge, to any person obtaining a copy
14
- of this software and associated documentation files (the "Software"), to deal
15
- in the Software without restriction, including without limitation the rights
16
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
- copies of the Software, and to permit persons to whom the Software is
18
- furnished to do so, subject to the following conditions:
19
-
20
- The above copyright notice and this permission notice shall be included in all
21
- copies or substantial portions of the Software.
22
-
23
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
- SOFTWARE.
30
-
31
- The MIT licence terms below govern learningcode itself.
3
+ Copyright (c) 2026 TLC (The Learning Curve)
32
4
 
33
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
34
6
  of this software and associated documentation files (the "Software"), to deal
package/NOTICE ADDED
@@ -0,0 +1,42 @@
1
+ learningcode
2
+ Copyright (c) 2026 TLC (The Learning Curve)
3
+
4
+ This product includes software developed by third parties.
5
+
6
+ --------------------------------------------------------------------------------
7
+ Pi — https://github.com/earendil-works/pi
8
+ MIT License
9
+ Copyright (c) Mario Zechner (and contributors)
10
+
11
+ learningcode is a distribution wrapper and contains no source copied from Pi. It
12
+ depends on @earendil-works/pi-coding-agent at runtime, and on
13
+ @earendil-works/pi-tui. Both are MIT licensed:
14
+
15
+ Permission is hereby granted, free of charge, to any person obtaining a copy
16
+ of this software and associated documentation files (the "Software"), to deal
17
+ in the Software without restriction, including without limitation the rights
18
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
+ copies of the Software, and to permit persons to whom the Software is
20
+ furnished to do so, subject to the following conditions:
21
+
22
+ The above copyright notice and this permission notice shall be included in all
23
+ copies or substantial portions of the Software.
24
+
25
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
+ SOFTWARE.
32
+
33
+ Pi's own NOTICE credits Ratatui (MIT, Florian Dehau and Ratatui Developers).
34
+
35
+ --------------------------------------------------------------------------------
36
+ Trademarks
37
+
38
+ "The Learning Curve", TLC and Spark are trademarks of The Learning Curve.
39
+
40
+ learningcode is not affiliated with, endorsed by, or connected to Pi, OpenCode,
41
+ Anomaly, or any model provider reachable through this client. Model names
42
+ belonging to their respective owners are used only to identify what is available.
package/README.md CHANGED
@@ -1,55 +1,140 @@
1
1
  # learningcode
2
2
 
3
- A terminal coding agent for TLC students, wired to [Spark](../spark) — the
4
- inference gateway that holds per-student tokens, timetable policy, seat limits
5
- and weekly quota.
3
+ A terminal coding agent for **The Learning Curve** students, running on TLC's own
4
+ inference through **TLC-Spark**.
6
5
 
7
- Students run one command:
6
+ `learningcode` is a purpose-built client for the TLC-Spark token plan. It is not a
7
+ general-purpose AI coding tool: the model, the quota and the seat limits all belong
8
+ to TLC, and every token you spend comes out of your course allocation.
9
+
10
+ ---
11
+
12
+ ## You will need a TLC-Spark token
13
+
14
+ `learningcode` cannot reach a model on its own. It connects to the TLC-Spark
15
+ gateway, which checks who you are and whether you are allowed to use it right now.
16
+
17
+ **Ask your teacher for a Spark API token.** In the Spark bench, go to
18
+ **Issue / rotate token**. The token is shown **once** and cannot be retrieved
19
+ afterwards, so copy it immediately. It looks like `spark_live_…`.
20
+
21
+ Without a token, `learningcode` will not start a conversation. That is by design:
22
+ there is no shared school key and no fallback to somebody else's account.
23
+
24
+ ---
25
+
26
+ ## Requirements
27
+
28
+ | | |
29
+ |---|---|
30
+ | **Node.js** | **22.19.0 or newer** (24.x LTS recommended) |
31
+ | **Disk** | about 120 MB |
32
+ | **Network** | must reach `spark.learning.com.my` |
33
+ | **Token** | your personal `spark_live_…` from the Spark bench |
34
+ | **Terminal** | 51+ columns for the banner; 99+ for the large one |
35
+
36
+ Node 22.19 is the floor because the underlying agent runtime requires it. If you
37
+ install Node and `npm i` only *warns*, check `node --version` — an older Node
38
+ produces a confusing error later rather than at install time.
39
+
40
+ ---
41
+
42
+ ## Install
43
+
44
+ ### Windows (PowerShell)
45
+
46
+ ```powershell
47
+ node --version
48
+ npm install -g @stemtrooper/learningcode
49
+ learningcode --version
50
+ ```
51
+
52
+ If PowerShell refuses to run the command because script execution is disabled:
53
+
54
+ ```powershell
55
+ Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
56
+ ```
57
+
58
+ ### macOS / Linux
8
59
 
9
60
  ```bash
10
- npm i -g @stemtrooper/learningcode
11
- learningcode
61
+ node --version
62
+ npm install -g @stemtrooper/learningcode
63
+ learningcode --version
12
64
  ```
13
65
 
14
- On first run it asks for the personal `spark_live_` token from the Spark bench,
15
- caches it with `0600`, writes the TLC-Spark provider config, and hands off to
16
- Pi with the model pinned.
66
+ ### Termux (Android)
67
+
68
+ No root and no `proot-distro` needed.
17
69
 
70
+ ```bash
71
+ pkg install nodejs-lts npm
72
+ node --version
73
+ npm install -g @stemtrooper/learningcode
74
+ learningcode --version
18
75
  ```
19
- baseURL https://spark.learning.com.my/v1
20
- model TLC-Spark
76
+
77
+ Install `npm` explicitly: Termux stopped bundling it with Node at 25.3.0.
78
+ Prefer `nodejs-lts` (24.x) over `nodejs` (26.x).
79
+
80
+ ---
81
+
82
+ ## First run
83
+
84
+ ```bash
85
+ cd ~/your-project
86
+ learningcode
21
87
  ```
22
88
 
23
- ## What students get
89
+ It asks for your Spark token, stores it with owner-only permissions in
90
+ `~/.learningcode/agent/spark-token`, and writes its configuration. The token is
91
+ only ever read from your own machine.
24
92
 
25
- Pi's four built-in tools — `read`, `bash`, `edit`, `write` — against
26
- Qwen3.8-27B. Two extra commands, because Spark is not a plain OpenAI endpoint:
93
+ You now have an agent that can read files, run shell commands, and edit code in
94
+ the directory you started it from. **It runs those commands on your machine, as
95
+ you.** Nothing runs on a microcontroller, and Spark never executes anything on
96
+ your behalf.
27
97
 
28
- | Command | Why it exists |
29
- |---|---|
30
- | `/quota` | Tokens used against today's limit, and whether AI is enabled for your account |
31
- | `/seats` | Live seat queue, so a student can see why a turn is waiting |
98
+ ---
99
+
100
+ ## Using it
101
+
102
+ Type a request in plain language.
103
+
104
+ ```
105
+ write a function that reads notes.txt and returns the average resistance
106
+ why does my ESP32 reset when I power the servo
107
+ explain this error: "Brown detector failed"
108
+ ```
32
109
 
33
- `session_start` also warns once if you cross 80% of your daily quota or if a
34
- teacher has switched AI off for your account.
110
+ Useful commands, typed inside the session:
35
111
 
36
- ## Why not just ship Pi?
112
+ | Command | What it does |
113
+ |---|---|
114
+ | `/help` | list everything available |
115
+ | `/quota` | your token spend today |
116
+ | `/seats` | how many seats are free |
117
+ | `/model` | switch model |
118
+ | `/hotkeys` | keyboard shortcuts |
37
119
 
38
- Because Spark's limits are the design constraint, not the model:
120
+ `/quota` and `/seats` talk to Spark directly. They are the two commands a stock
121
+ AI coding tool does not have, because those endpoints are not part of any public
122
+ API.
39
123
 
40
- - **32K max context, 16K default.** Agent sessions burn this fast. `learningcode`
41
- starts Pi with `--no-skills`, since skills are pure prompt-token spend.
42
- - **One active generation per student.** Subagents and parallel tool calls would
43
- only earn `429`s. Pi is serial by default and this wrapper does not turn that off.
44
- - **250K tokens per week.** Frugality is the product, so the budget is visible
45
- instead of mysterious.
124
+ One-off, non-interactive:
46
125
 
47
- Stock Pi does not know `/v1/me/quota` or `/v1/queue` exist. That gap is the whole
48
- reason this wrapper exists.
126
+ ```bash
127
+ learningcode -p "explain main.py"
128
+ learningcode -c # continue your last session
129
+ learningcode --mode json # machine-readable output
130
+ ```
49
131
 
50
- ## Banner
132
+ ---
51
133
 
52
- The LEARNINGCODE block banner replaces Pi's header at startup:
134
+ ## What it looks like
135
+
136
+ The TLC brand theme and banner ship with the package, so there is nothing to
137
+ configure.
53
138
 
54
139
  ```
55
140
  ██╗ ███████╗ █████╗ ██████╗ ███╗ ██╗██╗███╗ ██╗ ██████╗ ██████╗ ██████╗ ██████╗ ███████╗
@@ -58,139 +143,121 @@ The LEARNINGCODE block banner replaces Pi's header at startup:
58
143
  ██║ ██╔══╝ ██╔══██║██╔══██╗██║╚██╗██║██║██║╚██╗██║██║ ██║██║ ██║ ██║██║ ██║██╔══╝
59
144
  ███████╗███████╗██║ ██║██║ ██║██║ ╚████║██║██║ ╚████║╚██████╔╝╚██████╗╚██████╔╝██████╔╝███████╗
60
145
  ╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
61
- ═════════════════════════════════════════════════════════════════════════════════════════════════
62
146
  The Learning Curve · Sarawak
63
- /help commands · /quota today's spend · /hotkeys keys
64
147
  ```
65
148
 
66
- The figlet "ANSI Shadow" face, 97 columns wide, kept verbatim because the
67
- double-line box characters only align if every row keeps its exact offset.
149
+ On a narrower terminal it steps down to a condensed banner, then to the wordmark,
150
+ rather than drawing art that would be clipped.
68
151
 
69
- It steps down through three tiers, because a phone will never have 97 columns and
70
- clipping box characters looks like a rendering bug rather than a design:
152
+ A footer shows your remaining quota whenever you are connected to Spark:
71
153
 
72
- | Terminal width | Shows |
73
- |---|---|
74
- | 99 or more | the figlet face above |
75
- | 51 to 98 | a condensed 4 row face, 47 columns |
76
- | under 51 | the wordmark |
154
+ ```
155
+ █████░░░░░ 50% 125k / 250k today
156
+ ```
77
157
 
78
- The condensed tier still spells LEARNINGCODE:
158
+ ---
79
159
 
80
- \\n █ ███ █ ███ █ █ ███ █ █ ███ ███ ███ ███ ███
81
- █ █ █ █ █ █ ███ █ ███ █ █ █ █ █ █ █
82
- █ ███ ███ ███ █ █ █ █ █ █ █ █ █ █ █ █ ███
83
- ███ ███ █ █ █ █ █ █ ███ █ █ ███ ███ ███ ███ ███
84
- \\n
85
- Colour comes from the active theme, so it stays legible in light and dark.
160
+ ## Troubleshooting
86
161
 
87
- It installs via `ctx.ui.setHeader`, the supported way to brand a fork.
162
+ **`Node 22.19.0 or newer is required`**
163
+ Upgrade Node, then reinstall: `npm i -g @stemtrooper/learningcode`.
88
164
 
89
- ## Other providers
165
+ **`No Spark API token configured`**
166
+ You do not have a token yet, or it is not cached. Run `learningcode --login` to
167
+ enter a new one. If you never had one, ask your teacher.
90
168
 
91
- Any `--model` other than `tlc-spark/...` skips the Spark token and the Spark
92
- health check, so you can work while Spark is down:
169
+ **`Token rejected (401)`**
170
+ The token is wrong, or it was rotated and the old one no longer works.
171
+ `learningcode --login`.
93
172
 
94
- ```bash
95
- export OPENCODE_API_KEY=...
96
- learningcode --model opencode-go/glm-5.3-flash
97
- ```
173
+ **`AI off — ask your teacher` / `AI disabled for your account`**
174
+ Spark has AI switched off for your account — usually a timetable window or a
175
+ policy setting. This is not something you can fix.
98
176
 
99
- **OpenCode Zen is excluded.** Zen and Go share one `OPENCODE_API_KEY`, so leaving
100
- that variable in place authenticates both and exposes Zen's 111 pay-per-use models
101
- alongside the 29 a Go subscription covers, at up to $20/M output. learningcode
102
- moves the key into Pi's `auth.json` under `opencode-go` alone, which leaves Zen
103
- credential-less so it never registers. Set `LEARNINGCODE_ALLOW_ZEN=1` to opt in.
177
+ **`You already have a generation running`**
178
+ Spark allows one active generation per student. Stop the running one first.
104
179
 
105
- ## Theme
180
+ **`Every seat is taken` / queue position**
181
+ All seats are busy. `learningcode` prints your position; try again shortly.
106
182
 
107
- Two TLC themes ship with the package and are seeded into
108
- `~/.learningcode/agent/themes/` on first run:
183
+ **The banner looks like plain text**
184
+ Your terminal is narrower than 51 columns. Widen it.
109
185
 
110
- | Theme | Accent | Sampled from |
111
- |---|---|---|
112
- | `tlc-dark` | `#29c8f2` | `TLC_BLACKBGND.png` |
113
- | `tlc-light` | `#0dacd6` | `TLC_WHITEBGND.png` |
186
+ ---
114
187
 
115
- The values are read out of the logo pixels, not eyeballed. The logo ships two
116
- cyans because the darker one has to hold contrast on a white field, which maps
117
- exactly onto Pi's light/dark split.
188
+ ## Configuration
118
189
 
119
- A seeded theme is **never overwritten**, so an edit survives upgrades. Override
120
- the default with `--theme`, or `LEARNINGCODE_THEME=tlc-light`. To try Pi's own:
190
+ Everything lives in `~/.learningcode/agent/`. Nothing is uploaded anywhere except
191
+ to Spark, and no telemetry is sent.
192
+
193
+ | Variable | Purpose |
194
+ |---|---|
195
+ | `LEARNINGCODE_DIR` | config location (default `~/.learningcode/agent`) |
196
+ | `LEARNINGCODE_SPARK_BASE_URL` | point at a different Spark deployment |
197
+ | `LEARNINGCODE_TOKEN` | supply a token without using the cached file |
198
+ | `LEARNINGCODE_THEME` | `tlc-dark` (default), `tlc-light`, or any Pi theme |
199
+ | `LEARNINGCODE_PI_FLAGS` | extra flags passed to the agent on every launch |
121
200
 
122
201
  ```bash
123
- learningcode --theme dark
202
+ learningcode --show-config # show resolved paths and settings
203
+ learningcode --login # enter a new token
204
+ learningcode --list-models # every reachable model
205
+ learningcode --theme dark # use the upstream theme instead of TLC's
124
206
  ```
125
207
 
126
- 28 of Pi's 56 colour tokens are re-tinted: the accent, borders, greys, markdown,
127
- syntax highlighting, diff colours, selected backgrounds, and the thinking-level
128
- ramp. Semantic colours (red, green, yellow) are left alone, because those mean
129
- error, success and warning rather than anything about the brand. The thinking ramp
130
- runs grey to cyan and keeps red at the top, where it still means "this is getting
131
- expensive".
132
-
133
- The banner does **not** follow the theme. It uses the brand cyan directly, the way
134
- Pi's own logo does, because a wordmark that changes colour with whatever theme is
135
- active stops being a wordmark. It picks the right one of the two cyans from the
136
- terminal's colour mode.
208
+ **Your edits are kept.** If you change the theme or the model configuration,
209
+ upgrading `learningcode` will not overwrite your copy.
137
210
 
138
- ## Footer
211
+ ---
139
212
 
140
- While connected to Spark, a footer shows today's token spend:
213
+ ## For educators
141
214
 
142
- ```
143
- █████░░░░░ 50% 125k / 250k today
144
- ```
215
+ <details>
216
+ <summary>Running a local Spark, and other model providers</summary>
145
217
 
146
- Spark's quota endpoint is not part of the OpenAI API, so no stock harness shows
147
- this. It polls at most every two minutes, since Spark allows one active
148
- generation per student and a per-turn refresh would add latency to the thing the
149
- student is waiting on. When AI is switched off for an account the footer says so
150
- instead of showing a bar.
218
+ **Local bench.** `learningcode --base-url http://localhost:3000/v1` points the
219
+ client at a Spark running on your own machine, for demos without spending course
220
+ quota.
151
221
 
152
- Off Spark, or with no token, it says so rather than drawing an empty bar that would
153
- read as "you have spent nothing".
222
+ **Other providers.** Any `--model` other than `tlc-spark/…` skips the Spark token
223
+ and health check entirely:
154
224
 
155
- ## Configuration
225
+ ```bash
226
+ export OPENCODE_API_KEY=...
227
+ learningcode --model opencode-go/glm-5.3-flash
228
+ ```
156
229
 
157
- `~/.learningcode/agent/models.json` is created on first run and **never
158
- overwritten** — local edits survive upgrades. The provider is seeded with these
159
- compatibility flags, each of which matches a field Spark either rejects or drops:
230
+ This uses **your own** provider account and **your own** credits, with no Spark
231
+ quota, seat limit or audit trail. `learningcode` deliberately excludes OpenCode
232
+ Zen, which bills per token, so a stale entry cannot silently spend money. It is
233
+ still not something to hand to students.
160
234
 
161
- | Flag | Value | Spark behaviour |
162
- |---|---|---|
163
- | `supportsDeveloperRole` | `false` | message union is `system \| user \| assistant \| tool`; there is no `developer` |
164
- | `maxTokensField` | `"max_tokens"` | `v1.ts` reads `body.max_tokens` only |
165
- | `supportsReasoningEffort` | `false` | not forwarded to the runtime |
166
- | `supportsStore` | `false` | not implemented |
235
+ **Seat awareness.** Spark enforces one active generation per student, so the
236
+ client runs strictly serially with subagents off. Expect a 429 rather than
237
+ parallel fan-out.
167
238
 
168
- Environment variables:
239
+ </details>
169
240
 
170
- | Variable | Purpose |
171
- |---|---|
172
- | `LEARNINGCODE_DIR` | agent directory (default `~/.learningcode/agent`) |
173
- | `LEARNINGCODE_SPARK_BASE_URL` | point at another Spark deployment |
174
- | `LEARNINGCODE_TOKEN` | Spark token, skips the cached file |
175
- | `LEARNINGCODE_PI_FLAGS` | extra flags appended to every launch |
241
+ ---
176
242
 
177
- ```bash
178
- learningcode --show-config # resolved paths, model, token prefix
179
- learningcode --base-url http://localhost:3000/v1 # local bench
180
- learningcode --login # re-enter a rotated token
181
- learningcode -c # continue last session
182
- learningcode -p "explain main.py"
183
- learningcode --mode json # machine-readable event stream
184
- ```
243
+ ## How it works
185
244
 
186
- Anything not listed as a `learningcode` flag is passed straight to Pi.
245
+ `learningcode` is a thin wrapper around [Pi](https://github.com/earendil-works/pi),
246
+ an open-source coding agent by Mario Zechner. It adds the TLC-Spark provider
247
+ configuration, the TLC theme and banner, and the quota and seat commands.
187
248
 
188
- ## Pinning
249
+ The underlying model is **Qwen3.8-27B**, served through TLC-Spark. Every turn is a
250
+ separate request, takes a seat, and spends quota — an agent session that reads ten
251
+ files costs roughly eleven turns. That is why the footer exists.
189
252
 
190
- `@earendil-works/pi-coding-agent` is pinned to an exact version, not a range. Pi
191
- ships breaking changes daily, and a student's install must not change underneath
192
- them mid-term. Bump it deliberately, after testing against a live pod.
253
+ Pi is pinned to an exact version on purpose: the runtime ships breaking changes
254
+ often, and a student's install must not change underneath them mid-term.
193
255
 
194
256
  ## Licence
195
257
 
196
- MIT. Depends on Pi, also MIT. See [LICENSE](LICENSE).
258
+ MIT. `learningcode` is distributed under the MIT licence and depends on Pi, which
259
+ is also MIT. See [LICENSE](LICENSE).
260
+
261
+ Not affiliated with, endorsed by, or connected to Pi, OpenCode, Anomaly, or any of
262
+ the model providers reachable through this client. "The Learning Curve", TLC and
263
+ Spark are trademarks of The Learning Curve.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stemtrooper/learningcode",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "TLC Spark coding agent for students: Pi wired to the Spark OpenAI-compatible endpoint with per-student tokens, quota and seat-queue awareness.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -13,7 +13,8 @@
13
13
  "lib",
14
14
  "extensions",
15
15
  "README.md",
16
- "LICENSE"
16
+ "LICENSE",
17
+ "NOTICE"
17
18
  ],
18
19
  "scripts": {
19
20
  "start": "node ./bin/learningcode.mjs",