@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.
- package/LICENSE +22 -0
- package/README.md +67 -2
- package/archetypes/shared/a11y.ts +38 -0
- package/archetypes/shared/hooks/pre-commit +22 -0
- package/archetypes/shared/hooks/pre-push +4 -0
- package/archetypes/shared/i18n.ts +25 -0
- package/archetypes/shared/install-hooks.ts +63 -0
- package/archetypes/shared/playwright.ts +54 -0
- package/archetypes/shared/preset.ts +81 -0
- package/archetypes/shared/storage.ts +167 -0
- package/archetypes/shared/tsconfig.json +27 -0
- package/check/validation-report.v1.schema.json +116 -0
- package/dist/a11y.mjs +30 -0
- package/dist/check/rules/accessible.mjs +18 -0
- package/dist/check/rules/app-content-guide.mjs +69 -0
- package/dist/check/rules/dependency-licence.mjs +82 -0
- package/dist/check/rules/entry-fitness-matches.mjs +22 -0
- package/dist/check/rules/entry-links-resolve.mjs +44 -0
- package/dist/check/rules/explainer-readable-without-js.mjs +66 -0
- package/dist/check/rules/links-resolve.mjs +10 -0
- package/dist/check/rules/lockfile-matches.mjs +57 -0
- package/dist/check/rules/no-request-before-click.mjs +17 -0
- package/dist/check/rules/no-tracking.mjs +17 -0
- package/dist/check/rules/own-data-only.mjs +66 -0
- package/dist/check/rules/pages-reachable.mjs +25 -0
- package/dist/check/rules/usable-at-360px.mjs +19 -0
- package/dist/check-cv4I6CCH.mjs +28 -0
- package/dist/cli.mjs +3118 -0
- package/dist/i18n.mjs +11 -0
- package/dist/lint.mjs +528 -0
- package/dist/plan-DWKayEnY.mjs +75 -0
- package/dist/playwright.mjs +47 -0
- package/dist/preset.mjs +60 -0
- package/dist/skills/lernapps-app/SKILL.md +49 -0
- package/dist/skills/lernapps-cli/SKILL.md +156 -0
- package/dist/skills/lernapps-cli/references/platform-rules.md +258 -0
- package/dist/skills/lernapps-commit/SKILL.md +39 -0
- package/dist/skills/lernapps-content-growth/SKILL.md +33 -0
- package/dist/skills/lernapps-content-questions/SKILL.md +133 -0
- package/dist/skills/lernapps-content-questions/references/question-types.md +69 -0
- package/dist/skills/lernapps-content-research/SKILL.md +50 -0
- package/dist/skills/lernapps-content-research/references/sources.md +16 -0
- package/dist/skills/lernapps-exercise-patterns/SKILL.md +74 -0
- package/dist/skills/lernapps-exercise-patterns/references/biology-geography.md +13 -0
- package/dist/skills/lernapps-exercise-patterns/references/chemistry.md +16 -0
- package/dist/skills/lernapps-exercise-patterns/references/computer-science.md +13 -0
- package/dist/skills/lernapps-exercise-patterns/references/figures.md +10 -0
- package/dist/skills/lernapps-exercise-patterns/references/history.md +13 -0
- package/dist/skills/lernapps-exercise-patterns/references/mathematics.md +19 -0
- package/dist/skills/lernapps-exercise-patterns/references/page-structures.md +8 -0
- package/dist/skills/lernapps-exercise-patterns/references/physics.md +18 -0
- package/dist/skills/lernapps-exercise-patterns/references/success.md +28 -0
- package/dist/skills/lernapps-explainer/SKILL.md +33 -0
- package/dist/skills/lernapps-explainer/references/blocks.md +83 -0
- package/dist/skills/lernapps-explainer/references/components.md +66 -0
- package/dist/skills/lernapps-explainer/references/exercises.md +115 -0
- package/dist/skills/lernapps-explainer/references/rules.md +285 -0
- package/dist/skills/lernapps-explainer/references/runtime.md +79 -0
- package/dist/skills/lernapps-explainer/references/structure.md +24 -0
- package/dist/skills/lernapps-explainer-design/SKILL.md +57 -0
- package/dist/skills/lernapps-explainer-design/references/rules.md +75 -0
- package/dist/skills/lernapps-explainer-self-assessment/SKILL.md +93 -0
- package/dist/skills/lernapps-github/SKILL.md +102 -0
- package/dist/skills/lernapps-interactive/SKILL.md +141 -0
- package/dist/skills/lernapps-interactive/references/frame.md +30 -0
- package/dist/skills/lernapps-interactive-design/SKILL.md +58 -0
- package/dist/skills/lernapps-listing/SKILL.md +44 -0
- package/dist/skills/lernapps-listing/references/keeping-updated.md +33 -0
- package/dist/skills/lernapps-quiz/SKILL.md +100 -0
- package/dist/skills/lernapps-quiz-design/SKILL.md +48 -0
- package/dist/status-CXoQBgfU.mjs +76 -0
- package/dist/storage.mjs +113 -0
- package/generator/app/.agents/skills/app-content/SKILL.md +63 -0
- package/generator/app/.github/ISSUE_TEMPLATE/inhaltsfehler.yml +25 -0
- package/generator/app/.github/workflows/pages.yml +61 -0
- package/generator/app/LICENSE +21 -0
- package/generator/app/renovate.json +4 -0
- package/generator/architecture.ts +212 -0
- package/generator/create.ts +462 -0
- package/generator/init.ts +186 -0
- package/generator/update.ts +429 -0
- package/guidance/AGENTS.md +26 -0
- package/guidance/increment-template.md +194 -0
- package/guidance/plan-front-matter.v1.schema.json +36 -0
- package/guidance/plan-template.md +233 -0
- package/guidance/subagent-brief.md +25 -0
- package/guidance/workflow-rules.md +109 -0
- package/package.json +135 -4
- package/review/verdict.v1.schema.json +134 -0
- package/skills/archetypes/lernapps-explainer/SKILL.md +33 -0
- package/skills/archetypes/lernapps-explainer/references/blocks.md +83 -0
- package/skills/archetypes/lernapps-explainer/references/components.md +66 -0
- package/skills/archetypes/lernapps-explainer/references/exercises.md +115 -0
- package/skills/archetypes/lernapps-explainer/references/rules.md +285 -0
- package/skills/archetypes/lernapps-explainer/references/runtime.md +79 -0
- package/skills/archetypes/lernapps-explainer/references/structure.md +24 -0
- package/skills/archetypes/lernapps-explainer-design/SKILL.md +57 -0
- package/skills/archetypes/lernapps-explainer-design/references/rules.md +75 -0
- package/skills/archetypes/lernapps-explainer-self-assessment/SKILL.md +93 -0
- package/skills/archetypes/lernapps-interactive/SKILL.md +141 -0
- package/skills/archetypes/lernapps-interactive/references/frame.md +30 -0
- package/skills/archetypes/lernapps-interactive-design/SKILL.md +58 -0
- package/skills/archetypes/lernapps-quiz/SKILL.md +100 -0
- package/skills/archetypes/lernapps-quiz-design/SKILL.md +48 -0
- package/skills/content/lernapps-content-questions/SKILL.md +133 -0
- package/skills/content/lernapps-content-questions/references/question-types.md +69 -0
- package/skills/content/lernapps-content-research/SKILL.md +50 -0
- package/skills/content/lernapps-content-research/references/sources.md +16 -0
- package/skills/content/lernapps-exercise-patterns/SKILL.md +74 -0
- package/skills/content/lernapps-exercise-patterns/references/biology-geography.md +13 -0
- package/skills/content/lernapps-exercise-patterns/references/chemistry.md +16 -0
- package/skills/content/lernapps-exercise-patterns/references/computer-science.md +13 -0
- package/skills/content/lernapps-exercise-patterns/references/figures.md +10 -0
- package/skills/content/lernapps-exercise-patterns/references/history.md +13 -0
- package/skills/content/lernapps-exercise-patterns/references/mathematics.md +19 -0
- package/skills/content/lernapps-exercise-patterns/references/page-structures.md +8 -0
- package/skills/content/lernapps-exercise-patterns/references/physics.md +18 -0
- package/skills/content/lernapps-exercise-patterns/references/success.md +28 -0
- package/skills/process/lernapps-app/SKILL.md +49 -0
- package/skills/process/lernapps-commit/SKILL.md +39 -0
- package/skills/process/lernapps-content-growth/SKILL.md +33 -0
- package/skills/process/lernapps-github/SKILL.md +102 -0
- package/skills/process/lernapps-listing/SKILL.md +44 -0
- package/skills/process/lernapps-listing/references/keeping-updated.md +33 -0
- package/skills/tooling/lernapps-cli/SKILL.md +156 -0
- package/skills/tooling/lernapps-cli/references/platform-rules.md +258 -0
package/dist/preset.mjs
ADDED
|
@@ -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.
|