@lernapps/tooling 0.0.0-stage → 0.1.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.
Files changed (126) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +67 -2
  3. package/archetypes/shared/a11y.ts +38 -0
  4. package/archetypes/shared/hooks/pre-commit +22 -0
  5. package/archetypes/shared/hooks/pre-push +4 -0
  6. package/archetypes/shared/i18n.ts +25 -0
  7. package/archetypes/shared/install-hooks.ts +63 -0
  8. package/archetypes/shared/playwright.ts +54 -0
  9. package/archetypes/shared/preset.ts +81 -0
  10. package/archetypes/shared/storage.ts +167 -0
  11. package/archetypes/shared/tsconfig.json +27 -0
  12. package/check/validation-report.v1.schema.json +116 -0
  13. package/dist/a11y.mjs +30 -0
  14. package/dist/check/rules/accessible.mjs +18 -0
  15. package/dist/check/rules/app-content-guide.mjs +69 -0
  16. package/dist/check/rules/dependency-licence.mjs +82 -0
  17. package/dist/check/rules/entry-fitness-matches.mjs +22 -0
  18. package/dist/check/rules/entry-links-resolve.mjs +44 -0
  19. package/dist/check/rules/explainer-readable-without-js.mjs +66 -0
  20. package/dist/check/rules/links-resolve.mjs +10 -0
  21. package/dist/check/rules/lockfile-matches.mjs +57 -0
  22. package/dist/check/rules/no-request-before-click.mjs +17 -0
  23. package/dist/check/rules/no-tracking.mjs +17 -0
  24. package/dist/check/rules/own-data-only.mjs +66 -0
  25. package/dist/check/rules/pages-reachable.mjs +25 -0
  26. package/dist/check/rules/usable-at-360px.mjs +19 -0
  27. package/dist/check-cv4I6CCH.mjs +28 -0
  28. package/dist/cli.mjs +3118 -0
  29. package/dist/i18n.mjs +11 -0
  30. package/dist/lint.mjs +528 -0
  31. package/dist/plan-DWKayEnY.mjs +75 -0
  32. package/dist/playwright.mjs +47 -0
  33. package/dist/preset.mjs +60 -0
  34. package/dist/skills/lernapps-app/SKILL.md +49 -0
  35. package/dist/skills/lernapps-cli/SKILL.md +156 -0
  36. package/dist/skills/lernapps-cli/references/platform-rules.md +258 -0
  37. package/dist/skills/lernapps-commit/SKILL.md +39 -0
  38. package/dist/skills/lernapps-content-growth/SKILL.md +33 -0
  39. package/dist/skills/lernapps-content-questions/SKILL.md +133 -0
  40. package/dist/skills/lernapps-content-questions/references/question-types.md +69 -0
  41. package/dist/skills/lernapps-content-research/SKILL.md +50 -0
  42. package/dist/skills/lernapps-content-research/references/sources.md +16 -0
  43. package/dist/skills/lernapps-exercise-patterns/SKILL.md +74 -0
  44. package/dist/skills/lernapps-exercise-patterns/references/biology-geography.md +13 -0
  45. package/dist/skills/lernapps-exercise-patterns/references/chemistry.md +16 -0
  46. package/dist/skills/lernapps-exercise-patterns/references/computer-science.md +13 -0
  47. package/dist/skills/lernapps-exercise-patterns/references/figures.md +10 -0
  48. package/dist/skills/lernapps-exercise-patterns/references/history.md +13 -0
  49. package/dist/skills/lernapps-exercise-patterns/references/mathematics.md +19 -0
  50. package/dist/skills/lernapps-exercise-patterns/references/page-structures.md +8 -0
  51. package/dist/skills/lernapps-exercise-patterns/references/physics.md +18 -0
  52. package/dist/skills/lernapps-exercise-patterns/references/success.md +28 -0
  53. package/dist/skills/lernapps-explainer/SKILL.md +33 -0
  54. package/dist/skills/lernapps-explainer/references/blocks.md +83 -0
  55. package/dist/skills/lernapps-explainer/references/components.md +66 -0
  56. package/dist/skills/lernapps-explainer/references/exercises.md +115 -0
  57. package/dist/skills/lernapps-explainer/references/rules.md +285 -0
  58. package/dist/skills/lernapps-explainer/references/runtime.md +79 -0
  59. package/dist/skills/lernapps-explainer/references/structure.md +24 -0
  60. package/dist/skills/lernapps-explainer-design/SKILL.md +57 -0
  61. package/dist/skills/lernapps-explainer-design/references/rules.md +75 -0
  62. package/dist/skills/lernapps-explainer-self-assessment/SKILL.md +93 -0
  63. package/dist/skills/lernapps-github/SKILL.md +102 -0
  64. package/dist/skills/lernapps-interactive/SKILL.md +141 -0
  65. package/dist/skills/lernapps-interactive/references/frame.md +30 -0
  66. package/dist/skills/lernapps-interactive-design/SKILL.md +58 -0
  67. package/dist/skills/lernapps-listing/SKILL.md +44 -0
  68. package/dist/skills/lernapps-listing/references/keeping-updated.md +33 -0
  69. package/dist/skills/lernapps-quiz/SKILL.md +100 -0
  70. package/dist/skills/lernapps-quiz-design/SKILL.md +48 -0
  71. package/dist/status-CXoQBgfU.mjs +76 -0
  72. package/dist/storage.mjs +113 -0
  73. package/generator/app/.agents/skills/app-content/SKILL.md +63 -0
  74. package/generator/app/.github/ISSUE_TEMPLATE/inhaltsfehler.yml +25 -0
  75. package/generator/app/.github/workflows/pages.yml +61 -0
  76. package/generator/app/LICENSE +21 -0
  77. package/generator/app/renovate.json +4 -0
  78. package/generator/architecture.ts +212 -0
  79. package/generator/create.ts +462 -0
  80. package/generator/init.ts +186 -0
  81. package/generator/update.ts +429 -0
  82. package/guidance/AGENTS.md +26 -0
  83. package/guidance/increment-template.md +194 -0
  84. package/guidance/plan-front-matter.v1.schema.json +36 -0
  85. package/guidance/plan-template.md +233 -0
  86. package/guidance/subagent-brief.md +25 -0
  87. package/guidance/workflow-rules.md +109 -0
  88. package/package.json +135 -4
  89. package/review/verdict.v1.schema.json +134 -0
  90. package/skills/archetypes/lernapps-explainer/SKILL.md +33 -0
  91. package/skills/archetypes/lernapps-explainer/references/blocks.md +83 -0
  92. package/skills/archetypes/lernapps-explainer/references/components.md +66 -0
  93. package/skills/archetypes/lernapps-explainer/references/exercises.md +115 -0
  94. package/skills/archetypes/lernapps-explainer/references/rules.md +285 -0
  95. package/skills/archetypes/lernapps-explainer/references/runtime.md +79 -0
  96. package/skills/archetypes/lernapps-explainer/references/structure.md +24 -0
  97. package/skills/archetypes/lernapps-explainer-design/SKILL.md +57 -0
  98. package/skills/archetypes/lernapps-explainer-design/references/rules.md +75 -0
  99. package/skills/archetypes/lernapps-explainer-self-assessment/SKILL.md +93 -0
  100. package/skills/archetypes/lernapps-interactive/SKILL.md +141 -0
  101. package/skills/archetypes/lernapps-interactive/references/frame.md +30 -0
  102. package/skills/archetypes/lernapps-interactive-design/SKILL.md +58 -0
  103. package/skills/archetypes/lernapps-quiz/SKILL.md +100 -0
  104. package/skills/archetypes/lernapps-quiz-design/SKILL.md +48 -0
  105. package/skills/content/lernapps-content-questions/SKILL.md +133 -0
  106. package/skills/content/lernapps-content-questions/references/question-types.md +69 -0
  107. package/skills/content/lernapps-content-research/SKILL.md +50 -0
  108. package/skills/content/lernapps-content-research/references/sources.md +16 -0
  109. package/skills/content/lernapps-exercise-patterns/SKILL.md +74 -0
  110. package/skills/content/lernapps-exercise-patterns/references/biology-geography.md +13 -0
  111. package/skills/content/lernapps-exercise-patterns/references/chemistry.md +16 -0
  112. package/skills/content/lernapps-exercise-patterns/references/computer-science.md +13 -0
  113. package/skills/content/lernapps-exercise-patterns/references/figures.md +10 -0
  114. package/skills/content/lernapps-exercise-patterns/references/history.md +13 -0
  115. package/skills/content/lernapps-exercise-patterns/references/mathematics.md +19 -0
  116. package/skills/content/lernapps-exercise-patterns/references/page-structures.md +8 -0
  117. package/skills/content/lernapps-exercise-patterns/references/physics.md +18 -0
  118. package/skills/content/lernapps-exercise-patterns/references/success.md +28 -0
  119. package/skills/process/lernapps-app/SKILL.md +49 -0
  120. package/skills/process/lernapps-commit/SKILL.md +39 -0
  121. package/skills/process/lernapps-content-growth/SKILL.md +33 -0
  122. package/skills/process/lernapps-github/SKILL.md +102 -0
  123. package/skills/process/lernapps-listing/SKILL.md +44 -0
  124. package/skills/process/lernapps-listing/references/keeping-updated.md +33 -0
  125. package/skills/tooling/lernapps-cli/SKILL.md +156 -0
  126. package/skills/tooling/lernapps-cli/references/platform-rules.md +258 -0
@@ -0,0 +1,60 @@
1
+ import { defineConfig, mergeConfig } from "vite-plus";
2
+ // archetypes/shared/preset.ts
3
+ /** Not code: what tools write, and prose. */
4
+ const notCode = [
5
+ "dist/**",
6
+ "node_modules/**",
7
+ "playwright-report/**",
8
+ "test-results/**",
9
+ "**/*.md"
10
+ ];
11
+ const preset = {
12
+ base: "./",
13
+ fmt: {
14
+ printWidth: 120,
15
+ ignorePatterns: notCode
16
+ },
17
+ lint: {
18
+ ignorePatterns: notCode,
19
+ jsPlugins: ["@lernapps/tooling/lint"],
20
+ options: {
21
+ typeAware: true,
22
+ typeCheck: true
23
+ },
24
+ rules: {
25
+ "lernapps/learner-text-german": "error",
26
+ "lernapps/no-request-before-click": "error",
27
+ "lernapps/storage-through-wrapper": "error",
28
+ "lernapps/suppression-reason": "error",
29
+ "lernapps/vue-component-browser-globals": "error",
30
+ "lernapps/vue-component-imports": "error",
31
+ "lernapps/vue-component-no-html-injection": "error",
32
+ "lernapps/vue-component-no-network": "error",
33
+ "typescript/no-explicit-any": "error"
34
+ }
35
+ },
36
+ test: { include: ["src/**/*.test.ts", "test/**/*.test.ts"] },
37
+ staged: { "*.{ts,tsx,json}": "vp fmt" }
38
+ };
39
+ /** Whether the plugins (nested lists, as Vite takes them) hold one named `name`. */
40
+ const hasPlugin = (plugins, name) => Array.isArray(plugins) ? plugins.some((plugin) => hasPlugin(plugin, name)) : typeof plugins === "object" && plugins !== null && "name" in plugins && plugins.name === name;
41
+ /**
42
+ * The preset, with the app's own settings merged over it. With the interactive runtime's build step among the
43
+ * plugins, a component may also import the app's own files in src/ and the libraries in its dependencies, as that
44
+ * build allows (lint/rules/vue-component-imports.ts).
45
+ */
46
+ const lernapps = (config = {}) => {
47
+ const base = hasPlugin(config.plugins, "lernapps-interactive") ? {
48
+ ...preset,
49
+ lint: {
50
+ ...preset.lint,
51
+ rules: {
52
+ ...preset.lint?.rules,
53
+ "lernapps/vue-component-imports": ["error", { scope: "src" }]
54
+ }
55
+ }
56
+ } : preset;
57
+ return defineConfig(mergeConfig(base, config));
58
+ };
59
+ var preset_default = lernapps();
60
+ export { preset_default as default, lernapps };
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: lernapps-app
3
+ description: Use in Explore, when a creator wants a learning app for lernapps.net, even if they only say "Lern-App", "Übungs-App" or "für meine Klasse". What every app on lernapps.net must be, how to choose an archetype, and where to read what each one can and cannot do.
4
+ license: MIT
5
+ ---
6
+
7
+ # lernapps app
8
+
9
+ ## What an app is
10
+
11
+ - A small learning app for school: static, runs in the browser, no account, no tracking, no ads, free.
12
+ - Accessible (WCAG 2.1 AA) and usable at 360 px. A deviation the idea needs (a time limit, a keyboard) is allowed; the
13
+ catalog entry then says it in `limits`.
14
+ - Other servers (video, map) only after the learner's click. Nothing about a real learner in any text.
15
+ - Published at its creator's own address, usually `https://<owner>.github.io/<repo>/`. Once listed, lernapps.net
16
+ serves a copy at `https://lernapps.net/apps/start/<id>/`, built from the commit the entry names; the creator stays the author.
17
+ - Licence that allows the copy (MIT or Apache 2.0 for code, CC BY 4.0 for content); files referenced relatively.
18
+
19
+ ## Rules
20
+
21
+ - Each rule is a section with a rule block: `id`, `scope`, `severity`. Follow every rule in scope, checked or not.
22
+ - Scope: `listing` every listed app; `tooling` every app built with `@lernapps/tooling`; `archetype:<name>` that
23
+ archetype.
24
+ - Severity: `error` never break; `warning` only with a reason in place; `hint` advice. At the listing, a `tooling`
25
+ rule counts as a warning.
26
+ - Each skill holds the rules of its phase. All rules: <https://lernapps.net/tooling/rules/>.
27
+
28
+ ## What each archetype can do
29
+
30
+ | Archetype | Learners … | Can and cannot (README of its template) |
31
+ |---|---|---|
32
+ | `quiz` | answer questions with options and feedback | <https://raw.githubusercontent.com/lernapps/app-templates/main/quiz/README.md> |
33
+ | `explainer` | read pages that explain, each with exercises | <https://raw.githubusercontent.com/lernapps/app-templates/main/explainer/README.md> |
34
+ | `interactive` | act in one app page, by turns or in real time | <https://raw.githubusercontent.com/lernapps/app-templates/main/interactive/README.md> |
35
+
36
+ ## Choose the archetype
37
+
38
+ - Choose after the interview topics "Goal" and "Learners", from what learners do. Read the patterns of the subject
39
+ first (skill `lernapps-exercise-patterns`): how learners practise points to the archetype.
40
+ - Before you choose, read the README of each archetype in question, in full. Tell the creator in plain words what the
41
+ chosen one can and cannot do, before you ask about content, amount and look.
42
+ - A few background sections on the start page keep an app `interactive`.
43
+ - Explanation pages with one interactive exercise → `explainer` with a component.
44
+
45
+ ## Gotchas
46
+
47
+ - A typing game or a trainer is `interactive`, never `explainer`.
48
+ - What an archetype cannot do is no plan task: tell the creator, choose another archetype or leave it out.
49
+ - The archetype decides what you may write later. Choose it from what learners do, not from what is quickest.
@@ -0,0 +1,156 @@
1
+ ---
2
+ name: lernapps-cli
3
+ description: Use in Code of a lernapps.net app - to create or update the app with the CLI, whenever a check, a git hook or a runtime test fails, and before you change the preset, the configuration or the storage. What `lernapps create`, `update`, `check` and `screenshots` do, how to fix from a message, when to suppress, and what of the preset you never change.
4
+ license: MIT
5
+ ---
6
+
7
+ # lernapps CLI and checks
8
+
9
+ ## Read when
10
+
11
+ - [references/platform-rules.md](references/platform-rules.md): a check names a `listing` rule, and before the
12
+ listing.
13
+
14
+ ## Create
15
+
16
+ 1. Only after the creator's yes to the plan (`explore-before-code`). In the plan's folder:
17
+ `npx lernapps create --archetype <archetype>`.
18
+ 2. No git repo yet: `git init --initial-branch=work`. Then `npm install` (dependencies, git hooks), and commit
19
+ everything on `work`.
20
+ 3. Needs git, Node ≥ 22.18, registry.npmjs.org. Blocked → ask the creator to allow it, run again. Never write the
21
+ app by hand.
22
+ 4. It keeps the plan and the installed skills, and writes the content guide's skeleton.
23
+
24
+ ## Update
25
+
26
+ - `npx --yes @lernapps/tooling@latest update`, then `npm install`: moves the app to this
27
+ tooling's runtime and checks, replaces the `lernapps-*` skills, adds what an older app lacks.
28
+ - `npm update` moves tooling and runtime only within their ranges (`^0.1.0` takes patches); `update` moves the ranges.
29
+
30
+ ## Check
31
+
32
+ - `npx lernapps check`: format, lint, types, unit tests, build, checks of the built app, end-to-end tests. The hooks
33
+ run its parts (`--pre-commit`, `--pre-push`); CI runs it whole.
34
+ - Report: `node_modules/.cache/lernapps/validation-report.yaml`. Options: `npx lernapps check --help`.
35
+
36
+ ## Look at the app
37
+
38
+ A check says the rules hold; only a look says what a learner sees. Show the creator the pages before a push, and before
39
+ a submission they declare something about.
40
+
41
+ - Explainer or quiz: build (`npx vp build`), then `npx lernapps screenshots`. It writes one image of every page, one of
42
+ every figure, and an `index.html` that shows them in order to `screenshots/` (not part of the app: do not commit it).
43
+ Show the images, or the `index.html` where you can show HTML. Check every figure in its own image
44
+ (`…-figure-<n>.png`): a page image is scaled down, its details are not readable. `--desktop` adds 1280 px images.
45
+ Options: `npx lernapps screenshots --help`.
46
+ - Interactive app: `screenshots` does not support it. Open the built app with the Playwright the tooling installs
47
+ (`import { chromium } from "playwright"`), at 390 px width, and take `page.screenshot({ fullPage: true })` of each
48
+ state the creator should see, from a short script outside the app.
49
+
50
+ ## A check fails
51
+
52
+ 1. Read the message: it names the step and links the rule (`https://lernapps.net/tooling/rules/#<id>`).
53
+ 2. Failed commit: one line names the step and `node_modules/.cache/lernapps/pre-commit.log`. Read that log.
54
+ 3. Fix the cause. The rule's text is in the skill of the phase; the link says where.
55
+ 4. Run the check again. Go on only when it passes.
56
+
57
+ - A runtime test (`@lernapps/app-templates`) fails while your content validates: a bug of the template.
58
+ 1. Tell the creator. Open an issue at <https://github.com/lernapps/app-templates/issues> with the validation
59
+ report, or ask the creator to.
60
+ 2. Never change tests, config or `node_modules` to get around it. Go on with the content.
61
+ 3. After the fix: update, check, commit.
62
+ - A link answers HTTP 429: "not checked", a hint that fails nothing. Tell the creator which; go on.
63
+
64
+ ## Rules
65
+
66
+ ### `checks-pass`: Run the checks before you push
67
+
68
+ ```rule
69
+ id: checks-pass
70
+ scope: tooling
71
+ severity: error
72
+ ```
73
+
74
+ - `lernapps check` passes before every push. The hooks run it too; CI runs the same command and keeps its report as
75
+ the artifact `validation-report`.
76
+
77
+ ### `fix-from-message`: Fix failed checks, never bypass them
78
+
79
+ ```rule
80
+ id: fix-from-message
81
+ scope: tooling
82
+ severity: error
83
+ ```
84
+
85
+ - Fix the cause the message names.
86
+ - Never bypass a hook: no `--no-verify`, no acceptance such as `ARC42_CONSISTENT` without a finding shown.
87
+ - Never delete a test to make it pass.
88
+
89
+ ### `suppression-reason`: Suppress only in place, with the reason
90
+
91
+ ```rule
92
+ id: suppression-reason
93
+ scope: tooling
94
+ severity: error
95
+ ```
96
+
97
+ - Lint: only on the line, with the rule named and the reason after `--`:
98
+ `// oxlint-disable-next-line lernapps/no-request-before-click -- the video loads after a click`.
99
+ - Types: only `// @ts-expect-error -- <reason>`; never `@ts-ignore` or `@ts-nocheck`.
100
+ - The review reads every suppression.
101
+
102
+ ### `lockfile-matches`: Commit the lock file with every dependency change
103
+
104
+ ```rule
105
+ id: lockfile-matches
106
+ scope: tooling
107
+ severity: error
108
+ ```
109
+
110
+ - Change dependencies with `npm install`, never in `package.json` alone; commit `package-lock.json` with it.
111
+ - A git pin (`github:…#<commit>`) moves in both files together.
112
+
113
+ ### `keep-the-preset`: Extend the preset, change nothing of it
114
+
115
+ ```rule
116
+ id: keep-the-preset
117
+ scope: [archetype:explainer, archetype:interactive, archetype:quiz]
118
+ severity: error
119
+ ```
120
+
121
+ - `vite.config.ts` is `export default lernapps()`, with only the app's own settings as generated
122
+ (`lernapps({ plugins: [quiz()] })`).
123
+ - `tsconfig.json` extends `@lernapps/tooling/tsconfig.json` as generated.
124
+ - The hooks come from the package (`prepare` in `package.json`); never replace one.
125
+ - Never turn a lint rule off or lower its severity.
126
+
127
+ ### `strict-typescript`: TypeScript only, strict
128
+
129
+ ```rule
130
+ id: strict-typescript
131
+ scope: [archetype:explainer, archetype:interactive, archetype:quiz]
132
+ severity: error
133
+ ```
134
+
135
+ - Every source file is TypeScript; no JavaScript files.
136
+ - Never `any`: use `unknown` and narrow it, or write the type.
137
+ - Type the creator's data; validate it at build time.
138
+
139
+ ### `storage-through-wrapper`: Store only through the preset's storage
140
+
141
+ ```rule
142
+ id: storage-through-wrapper
143
+ scope: [archetype:explainer, archetype:interactive, archetype:quiz]
144
+ severity: error
145
+ ```
146
+
147
+ - Only `createStorage` from `@lernapps/tooling/storage`, named after the app's id in the catalog (own prefix
148
+ `lernapps:<id>:`, rule `own-data-only`; works when storage is blocked).
149
+ - At most 100 kB under the prefix (keys and values, 2 bytes per UTF-16 unit). Beyond, `save` returns false and the
150
+ app keeps working.
151
+ - A setting of the learner that holds for every app or every app of the archetype: `createSettings("<id>",
152
+ "<archetype>")`, saved only where the learner chose it (`"app"`, `"archetype"` or `"all"`); the app's own goes first.
153
+ - Keep the learning state, not growing histories.
154
+ - What only a reload must not lose, such as an answer being written, lasts while the tab is open:
155
+ `createStorage("<id>", { type: "sessionStorage" })` (sessionStorage, same prefix and limit).
156
+ - Never `localStorage`, `sessionStorage`, IndexedDB or cookies directly.
@@ -0,0 +1,258 @@
1
+ # Platform rules
2
+
3
+ - Every app on lernapps.net, however built (this tooling, by hand, another framework, Lovable, bolt.new).
4
+ - Scope `listing`: every listed app, wherever hosted. Severity `error` never break; `hint` advice.
5
+ - Check a built or published app: `npx --yes @lernapps/tooling check <dir|url>` (= `lernapps check`);
6
+ `--entry <file>` checks the catalog entry against it.
7
+ - Published at its own address (e.g. `https://<owner>.github.io/<repo>/`); once listed, lernapps.net serves a copy at
8
+ `https://lernapps.net/apps/start/<id>/`, built from the entry's `commit`.
9
+ - All rules: <https://lernapps.net/tooling/rules/>.
10
+
11
+ ## App
12
+
13
+ ### `no-tracking`: Collect nothing, set no cookies
14
+
15
+ ```rule
16
+ id: no-tracking
17
+ scope: listing
18
+ severity: error
19
+ ```
20
+
21
+ - No cookies, analytics, tracking pixels, server storing data.
22
+ - Stored data stays on the device (`localStorage`, or `sessionStorage` while the tab is open) and serves only the app.
23
+
24
+ ### `own-data-only`: Touch only the app's own data in the browser
25
+
26
+ ```rule
27
+ id: own-data-only
28
+ scope: listing
29
+ severity: error
30
+ ```
31
+
32
+ - Every app on lernapps.net shares one origin with the other apps and the platform.
33
+ - Own data: keys of `localStorage` and `sessionStorage`, IndexedDB databases and caches named `lernapps:<id>:…`,
34
+ `<id>` the app's id in the catalog (`entries/<id>.yaml`).
35
+ - Also every app's: the learner's settings for every app (`lernapps:settings:<key>`, a key without a colon) and for
36
+ every app of the page's archetype (`lernapps:settings:<archetype>:…`, the archetype of
37
+ `<meta name="lernapps-archetype">`); never another archetype's. `settings` is never an app's id.
38
+ - Never read, write or remove other keys; never `clear()`; never `caches.match()` without `cacheName`.
39
+ - Built with this tooling: `createStorage("<id>")` from `@lernapps/tooling/storage`; settings with
40
+ `createSettings("<id>", "<archetype>")`.
41
+ - `lernapps check` puts another app's data into the browser and reports every access to it, before a click.
42
+
43
+ ### `runs-in-browser`: Runs in the browser, without installation
44
+
45
+ ```rule
46
+ id: runs-in-browser
47
+ scope: listing
48
+ severity: error
49
+ ```
50
+
51
+ - Opens and works at its URL in a current browser. No app store, download or extension.
52
+
53
+ ### `app-checkable`: The published app can be opened and checked
54
+
55
+ ```rule
56
+ id: app-checkable
57
+ scope: listing
58
+ severity: error
59
+ ```
60
+
61
+ - Opens at the entry's `url`; a built app from its bundle (`index.html`).
62
+ - Page does not load, build fails, no browser, check stops → only this rule is reported. Fix, check again.
63
+ - Opens in a browser but the check fails → issue at <https://github.com/lernapps/tooling/issues> with the message.
64
+
65
+ ### `no-account`: No account
66
+
67
+ ```rule
68
+ id: no-account
69
+ scope: listing
70
+ severity: error
71
+ ```
72
+
73
+ - Whole app usable without sign-up or login.
74
+
75
+ ### `free-of-charge`: Free of charge
76
+
77
+ ```rule
78
+ id: free-of-charge
79
+ scope: listing
80
+ severity: error
81
+ ```
82
+
83
+ - Every part free: no payment, paid upgrade or ending trial.
84
+
85
+ ### `no-ads`: No ads
86
+
87
+ ```rule
88
+ id: no-ads
89
+ scope: listing
90
+ severity: error
91
+ ```
92
+
93
+ - No advertising, sponsored content or product placement.
94
+
95
+ ### `learners-act`: Learners do something themselves
96
+
97
+ ```rule
98
+ id: learners-act
99
+ scope: listing
100
+ severity: error
101
+ ```
102
+
103
+ - Every page or screen asks learners to try, practise or decide. Reading alone is not enough.
104
+
105
+ ### `no-request-before-click`: No request to another server before a click
106
+
107
+ ```rule
108
+ id: no-request-before-click
109
+ scope: listing
110
+ severity: error
111
+ ```
112
+
113
+ - Bundle fonts, scripts, pictures at build time.
114
+ - Other servers (video, map) only after the learner's click.
115
+ - No other servers' URLs in code; at a click-to-load line suppress the lint message with this reason.
116
+
117
+ ### `accessible`: Accessible to WCAG 2.1 AA
118
+
119
+ ```rule
120
+ id: accessible
121
+ scope: listing
122
+ severity: error
123
+ ```
124
+
125
+ - WCAG 2.1 AA: labels, contrast, keyboard, text alternatives.
126
+ - Deviate only where the idea needs it (typing game against the clock); then say what is missing, in plain German,
127
+ in the entry's `limits`.
128
+ - With `limits`: `lernapps check --entry` reports warnings; without: errors.
129
+
130
+ ### `usable-at-360px`: Usable at 360 px
131
+
132
+ ```rule
133
+ id: usable-at-360px
134
+ scope: listing
135
+ severity: error
136
+ ```
137
+
138
+ - Every page at 360 px width: no horizontal scrolling, every control reachable.
139
+ - Deviate only where the idea needs it (keyboard required), in `limits` as under `accessible`.
140
+
141
+ ### `learner-text-german`: German always, every declared language complete
142
+
143
+ ```rule
144
+ id: learner-text-german
145
+ scope: listing
146
+ severity: error
147
+ ```
148
+
149
+ - Texts for learners, teachers, parents: German, plain (short sentences, active voice, no jargon).
150
+ - More languages only where the archetype supports them (explainer, quiz: `languages`, German first); each declared
151
+ language complete, no other.
152
+ - Texts out of code: in the content (explainer YAML, quiz bank) or message files (`src/messages/de.json`, shown
153
+ with `translator` from `@lernapps/tooling/i18n`).
154
+
155
+ ### `third-party-licence`: Name source and licence of others' content
156
+
157
+ ```rule
158
+ id: third-party-licence
159
+ scope: listing
160
+ severity: error
161
+ ```
162
+
163
+ - Others' content (texts, pictures, quotes) only with a licence that allows it; source and licence next to it.
164
+
165
+ ### `dependency-licence`: Only dependencies with an open licence
166
+
167
+ ```rule
168
+ id: dependency-licence
169
+ scope: listing
170
+ severity: error
171
+ ```
172
+
173
+ - `dependencies` only with these licences, transitively: MIT, MIT-0, ISC, 0BSD, BSD-2-Clause, BSD-3-Clause,
174
+ Apache-2.0, MPL-2.0, BlueOak-1.0.0, Zlib, Unlicense, CC0-1.0, CC-BY-4.0, Python-2.0.
175
+ - Build tools: `devDependencies`.
176
+
177
+ ### `links-resolve`: Every link resolves
178
+
179
+ ```rule
180
+ id: links-resolve
181
+ scope: listing
182
+ severity: error
183
+ ```
184
+
185
+ - Every link and resource points to a page or file the build writes. Relative links inside the app.
186
+
187
+ ### `pages-reachable`: Every page is reachable from the start page
188
+
189
+ ```rule
190
+ id: pages-reachable
191
+ scope: listing
192
+ severity: error
193
+ ```
194
+
195
+ - Every built page linked from the start page or a page it leads to; the listing checks only those.
196
+ - Pages nobody should reach: out of the build. Reached otherwise on purpose: `<meta name="robots" content="noindex">`.
197
+ - `404.html` at the root needs no link.
198
+ - On a URL the checks visit at most 100 pages (hint); check the bundle for all.
199
+
200
+ ### `no-learner-data-in-texts`: Nothing about a particular learner in public texts
201
+
202
+ ```rule
203
+ id: no-learner-data-in-texts
204
+ scope: listing
205
+ severity: error
206
+ ```
207
+
208
+ - No name, class, school, grade, picture or other detail of a real learner in app, entry, README, plan or commit
209
+ message, even if the creator mentions one. Made-up names in exercises.
210
+
211
+ ### `correct-content-support`: Help keep the content correct
212
+
213
+ ```rule
214
+ id: correct-content-support
215
+ scope: listing
216
+ severity: hint
217
+ ```
218
+
219
+ - Computable answers: generate exercises, test answers with a checker.
220
+ - Name a source for facts. Where it fits; never a listing condition.
221
+
222
+ ## Catalog entry
223
+
224
+ - Listed by a pull request to <https://github.com/lernapps/apps>; steps: skill `lernapps-listing`.
225
+
226
+ ### `entry-from-schema`: Fill the entry from the published schema
227
+
228
+ ```rule
229
+ id: entry-from-schema
230
+ scope: listing
231
+ severity: error
232
+ ```
233
+
234
+ - Fetch the entry schema each time; never from memory or another app.
235
+ - Every value from the creator's answers, the plan or the app; never invented.
236
+
237
+ ### `entry-links-resolve`: Every link of the entry resolves
238
+
239
+ ```rule
240
+ id: entry-links-resolve
241
+ scope: listing
242
+ severity: error
243
+ ```
244
+
245
+ - Each topic: path of an existing page, relative to the app's `url`; `<page>#<section>` names an element id there.
246
+ - Check against the deployed app: `lernapps check --entry <file>`.
247
+
248
+ ### `entry-fitness-matches`: Fitness values as measured
249
+
250
+ ```rule
251
+ id: entry-fitness-matches
252
+ scope: listing
253
+ severity: error
254
+ ```
255
+
256
+ - `fitness.storage`, `fitness.thirdParty` from what the app does; `lernapps check --report <file>` measures it.
257
+ - Anything in `localStorage` or `sessionStorage`, also what the app only reads on loading and keeps after an input (an
258
+ assistant chosen for the tutor, an answer being written) → `storage: device`; loads from another server after a click → `thirdParty: on-click`.
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: lernapps-commit
3
+ description: Use in Commit, when you bring the branch of the first version or an increment into main - the history of main stays linear (one squash commit per piece of work, never a merge commit) and every message is a conventional commit with the sections Intent, Key changes, Dependencies and side effects.
4
+ license: MIT
5
+ ---
6
+
7
+ # Commits of a lernapps app
8
+
9
+ ## Linear history
10
+
11
+ Bring a branch into `main` by squash: squash-merge its pull request, or `git switch main`, `git merge --squash <branch>`,
12
+ `git commit`. One piece of work is one commit on `main`; never a merge commit. The commit message of the squash
13
+ describes the whole piece of work, not the last step. When you merge yourself, you squash and write it.
14
+
15
+ ## Content from the plan
16
+
17
+ Do not invent the message: take it from the current plan (`.vibe/plans/<NN>-<short name>.md`). Intent comes from
18
+ "Goal", Key changes from "Key decisions" and the content method, Dependencies and side effects from "Notes". Write it
19
+ in the creator's terms, short.
20
+
21
+ ## Message
22
+
23
+ A conventional commit: `type(scope): summary` (`feat`, `fix`, `docs`, `refactor`, `test`, `chore`), imperative, under 72
24
+ characters. Then this body, in the language of the repo's history. Say why and what behaves differently; never list
25
+ files.
26
+
27
+ ```markdown
28
+ ## Intent
29
+
30
+ What problem does it solve? What was the motivation to introduce this change?
31
+
32
+ ## Key changes
33
+
34
+ The conceptual overview: how does the system behave differently now?
35
+
36
+ ## Dependencies and side effects
37
+
38
+ Only if applicable: effects on other parts of the system.
39
+ ```
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: lernapps-content-growth
3
+ description: Use in Plan of an increment that adds several competencies, chapters, pages, rounds or questions to a published lernapps.net app. How to cut the work into slices, one per competency, and which slices sub-agents can write in parallel without touching each other's files. For every archetype.
4
+ license: MIT
5
+ ---
6
+
7
+ # Content growth
8
+
9
+ ## One slice per competency
10
+
11
+ Each slice is one Code task and ends in one commit:
12
+
13
+ 1. Competency: into the content guide, in its chapter, as "Ich kann …", with its Lehrplan unit where used.
14
+ 2. Content: a page or section (explainer), questions (quiz), in the guide's structure.
15
+ 3. Exercise: a pattern of the guide, varied. A new pattern goes into the guide in the same slice, with example and
16
+ data file.
17
+ 4. Entry topic: the page or section path into the plan's entry draft (`entry-links-resolve`).
18
+ 5. Check: `npx lernapps check` passes.
19
+ 6. Commit, guide changes included.
20
+
21
+ - A new chapter or round: its slices in the order of the guide's procedure.
22
+ - The procedure no longer fits → its fix is part of the slice that shows it (`app-content-matches`).
23
+
24
+ ## Parallel slices
25
+
26
+ - No two agents change the same file.
27
+ - Yours alone: the content guide, the plan, the shared files (explainer `src/app.yaml`, each `chapter.yaml`,
28
+ `src/data/`; quiz `src/quiz.json`).
29
+ - A sub-agent's: one chapter (its pages, its own data file); in a quiz, the question drafts of one round.
30
+ - Each sub-agent works in its own git worktree, branch and browser port. You merge one by one, add the shared parts
31
+ and run the check.
32
+ - In Code, each sub-agent gets the brief `@lernapps/tooling/guidance/subagent-brief.md`, filled in. Write in Plan
33
+ which slices go to sub-agents.