@stemtrooper/learningcode 0.2.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.
@@ -1,4 +1,5 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { foregroundAnsi, rgbColor } from "@earendil-works/pi-tui";
2
3
 
3
4
  /**
4
5
  * LEARNINGCODE startup banner.
@@ -17,10 +18,16 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
17
18
  * hard-coding colours that break on one of them.
18
19
  */
19
20
 
20
- /** Structural types, so this file needs no runtime import from Pi's packages. */
21
+ /**
22
+ * Only the parts of Pi's Theme this file touches, to keep the runtime import
23
+ * down to the two colour helpers it actually needs.
24
+ */
21
25
  type ThemeLike = {
22
26
  fg(token: string, text: string): string;
23
- getColorMode?(): "light" | "dark";
27
+ /** "light" | "dark" - the background the active theme is designed for. */
28
+ appearance?: "light" | "dark";
29
+ /** The terminal's colour capability, e.g. "truecolor". Not light or dark. */
30
+ getColorMode?(): string;
24
31
  };
25
32
  type HeaderComponent = { render(width: number): string[] };
26
33
 
@@ -35,9 +42,16 @@ type HeaderComponent = { render(width: number): string[] };
35
42
  *
36
43
  * Two values because the logo ships two: the darker cyan holds contrast on a
37
44
  * white field, the brighter one on black.
45
+ *
46
+ * Note this must not go through `theme.fg()`. That resolves theme *tokens*, and
47
+ * `Theme.tokenAnsi` throws `Unknown theme color: #29c8f2` for anything that is
48
+ * not one, so a raw hex there crashes the header at render time. `foregroundAnsi`
49
+ * takes a colour value directly, and unlike a hand-rolled escape it still
50
+ * degrades to 256 colour on terminals without truecolour support.
38
51
  */
39
- const CYAN_DARK_BG = "#29c8f2";
40
- const CYAN_LIGHT_BG = "#0dacd6";
52
+ const CYAN_DARK_BG = rgbColor(0x29, 0xc8, 0xf2);
53
+ const CYAN_LIGHT_BG = rgbColor(0x0d, 0xac, 0xd6);
54
+ const RESET = "\x1b[0m";
41
55
 
42
56
  const ART: readonly string[] = [
43
57
  "██╗ ███████╗ █████╗ ██████╗ ███╗ ██╗██╗███╗ ██╗ ██████╗ ██████╗ ██████╗ ██████╗ ███████╗",
@@ -69,11 +83,15 @@ export function createBanner(theme: ThemeLike): HeaderComponent {
69
83
  const art = bannerArt();
70
84
  const artWidth = bannerWidth();
71
85
 
72
- // Fall back to the theme's accent only if a caller cannot report its colour
73
- // mode, which keeps the banner legible rather than dropping colour entirely.
74
- const mode = typeof theme.getColorMode === "function" ? theme.getColorMode() : "dark";
75
- const brand = mode === "light" ? CYAN_LIGHT_BG : CYAN_DARK_BG;
76
- const ink = (text: string) => theme.fg(brand as never, text);
86
+ // Two different things, easy to swap by accident:
87
+ // appearance light or dark, decides which brand cyan is readable
88
+ // getColorMode the terminal's colour capability, decides how to emit it
89
+ // Default to dark so the banner keeps its colour on a host that reports
90
+ // neither, rather than dropping the brand.
91
+ const isLight = theme.appearance === "light";
92
+ const mode = typeof theme.getColorMode === "function" ? theme.getColorMode() : "truecolor";
93
+ const brand = foregroundAnsi(isLight ? CYAN_LIGHT_BG : CYAN_DARK_BG, mode as never);
94
+ const ink = (text: string) => `${brand}${text}${RESET}`;
77
95
 
78
96
  return {
79
97
  render(width: number): string[] {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stemtrooper/learningcode",
3
- "version": "0.2.0",
3
+ "version": "0.2.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",
@@ -17,10 +17,12 @@
17
17
  ],
18
18
  "scripts": {
19
19
  "start": "node ./bin/learningcode.mjs",
20
- "test": "node --test \"test/**/*.test.mjs\""
20
+ "test": "node --test \"test/**/*.test.mjs\"",
21
+ "preview": "node ./scripts/preview.mjs"
21
22
  },
22
23
  "dependencies": {
23
- "@earendil-works/pi-coding-agent": "1.0.4"
24
+ "@earendil-works/pi-coding-agent": "1.0.4",
25
+ "@earendil-works/pi-tui": "1.0.4"
24
26
  },
25
27
  "devDependencies": {
26
28
  "jiti": "2.7.0"