@lernapps/tooling 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -39,7 +39,7 @@ lernapps.net's own websites, and the update policy for dependencies.
39
39
  - **The CLI `lernapps`:** `init` starts an app's plan in an empty folder and syncs the skills of the packages into the agent directories, `skills --archetype` adds those of the chosen archetype, `create` writes a new app for an archetype once the creator confirmed the plan, `check`
40
40
  checks an app the same way in its git hooks and in CI, `update` moves an app to the runtime and tooling versions of the latest
41
41
  tooling and replaces the app's `lernapps-*` skills with that tooling's (and an older app's single plan into
42
- `.vibe/plans/`), `changes` tells what a change can affect, so that hooks and CI run only that, `screenshots` writes an image of every page and every figure of a built explainer or quiz, to show a creator what a learner sees (`npx lernapps screenshots --help`). `npx --yes @lernapps/tooling --help` before an app exists, `npx lernapps --help` in one.
42
+ `.vibe/plans/`), `changes` tells what a change can affect, so that hooks and CI run only that, `screenshots` writes an image of every page and every figure of a built explainer or quiz, to show a creator what a learner sees (`npx --no -- lernapps screenshots --help`). `npx --yes @lernapps/tooling --help` before an app exists, `npx --no -- lernapps --help` in one.
43
43
  - **The actions in [`actions/`](actions/):** the app check, app publish and app preview actions of every app, and the site
44
44
  actions with which lernapps.net's own websites are checked, published and previewed. Each says what it does in its
45
45
  `action.yml`. The reusable workflow [`changes.yml`](.github/workflows/changes.yml) gives other workflows the
package/dist/cli.mjs CHANGED
@@ -632,7 +632,7 @@ the app cannot be created, 2 on a usage error.
632
632
 
633
633
  The package @lernapps/tooling comes from the npm registry. Before an app exists, run a command with
634
634
  npx --yes @lernapps/tooling <command> ...
635
- In an app, it is a development dependency: npx lernapps <command> ...
635
+ In an app, it is a development dependency: npx --no -- lernapps <command> ...
636
636
  `;
637
637
  /** The options of `lernapps check`, as node:util parseArgs takes them. */
638
638
  const CHECK_OPTIONS = {
@@ -1430,7 +1430,7 @@ const CREATE_OPTIONS = {
1430
1430
  const CREATE_USAGE = `Usage: lernapps create --archetype <name> [<dir>] [--plan <file>] [--templates <repo>] [--tooling <spec>]
1431
1431
 
1432
1432
  Writes a new app from the archetype's template into <dir> (default: the current folder), which must be empty
1433
- except for .git, the first version's plan .vibe/plans/01-<short name>.md and the skills that npx skills add
1433
+ except for .git, the first version's plan .vibe/plans/01-<short name>.md and the skills that
1434
1434
  lernapps init synced (.agents/skills/, .claude/skills/, skills-lock.json, and the package.json, package-lock.json and
1435
1435
  node_modules init wrote). The template is the folder <name>/ of the installed package @lernapps/app-templates, the
1436
1436
  version @lernapps/tooling depends on; the app depends on the runtime of the same version.
@@ -1441,7 +1441,7 @@ It needs the plan of the first version, confirmed by the creator: started from t
1441
1441
  tooling is moved to .vibe/plans/01-first-version.md. Without a plan, it writes nothing and says what to do.
1442
1442
 
1443
1443
  Run it in the folder lernapps init prepared, from the tooling init installed:
1444
- npx lernapps create --archetype <name> [<dir>]
1444
+ npx --no -- lernapps create --archetype <name> [<dir>]
1445
1445
  It needs git, and the npm registry for the npm install that follows. The app then depends on the version of
1446
1446
  @lernapps/tooling that created it, and its workflows use the actions of that version's tag.
1447
1447
 
@@ -1691,7 +1691,7 @@ function create(args) {
1691
1691
  if (positionals.length > 1) throw new UsageError(`one <dir> at most, not ${positionals.join(" ")}`);
1692
1692
  const dir = resolve(positionals[0] ?? ".");
1693
1693
  const found = contents(dir);
1694
- if (found.length > 0) throw new CreateError(`${dir} is not empty (${found.slice(0, 5).join(", ")}${found.length > 5 ? ", ..." : ""}): create the app in an empty folder; only .git, the first version's plan .vibe/plans/01-<short name>.md and the skills that npx skills add lernapps/tooling installed may be there`);
1694
+ if (found.length > 0) throw new CreateError(`${dir} is not empty (${found.slice(0, 5).join(", ")}${found.length > 5 ? ", ..." : ""}): create the app in an empty folder; only .git, the first version's plan .vibe/plans/01-<short name>.md and what lernapps init wrote (its skills, package.json, package-lock.json and node_modules) may be there`);
1695
1695
  const plan = confirmedPlan(dir, archetype, values.plan);
1696
1696
  const architecture = ARCHITECTURE_ARCHETYPES.includes(archetype);
1697
1697
  if (!existsSync(join(templates.root, archetype, "package.json"))) throw new CreateError(`${templates.root} has no template ${archetype}/ (version ${templates.version})`);
@@ -1765,6 +1765,7 @@ const INIT_USAGE = `Usage: lernapps init <short name> [--addon <package>]
1765
1765
 
1766
1766
  Starts an app in the current folder, which must be empty except for .git. It needs git, Node and the npm registry; nothing
1767
1767
  else. In order:
1768
+ git repository on the branch work, which the plan names (unless the folder is one already; no commit)
1768
1769
  package.json names the folder, depends on @lernapps/tooling (this version) and the add-on
1769
1770
  npm install installs them
1770
1771
  .vibe/plans/01-<short name>.md
@@ -1802,6 +1803,26 @@ const SKILLS_BIN = () => {
1802
1803
  const bin = readJson(manifest)["bin"];
1803
1804
  return join(dirname(manifest), bin?.["skills"] ?? "bin/cli.mjs");
1804
1805
  };
1806
+ /** The branch the plan works on (rule 8 of the plan template). */
1807
+ const WORK_BRANCH = "work";
1808
+ /**
1809
+ * Makes the folder a git repository on the branch `work`, which the plan names, unless it is one already: `create` and
1810
+ * the hooks need it, and the plan's first rule is to work there. Returns what it did, for the output; no commit.
1811
+ */
1812
+ function ensureRepository(dir) {
1813
+ if (existsSync(join(dir, ".git"))) return void 0;
1814
+ const result = spawnSync("git", [
1815
+ "init",
1816
+ "--quiet",
1817
+ `--initial-branch=${WORK_BRANCH}`
1818
+ ], {
1819
+ cwd: dir,
1820
+ encoding: "utf8"
1821
+ });
1822
+ if (result.error) throw new CreateError(`git cannot run: ${result.error.message}. Install git, then run init again`);
1823
+ if (result.status !== 0) throw new CreateError(`git init failed: ${`${result.stdout}${result.stderr}`.trim()}`);
1824
+ return `a git repository on the branch ${WORK_BRANCH}`;
1825
+ }
1805
1826
  /** The names of the skills of the archetypes, with the archetype each belongs to (lernapps-<archetype>[-…]). */
1806
1827
  function archetypeSkills() {
1807
1828
  const dir = fromPackage("skills", "archetypes");
@@ -1858,6 +1879,7 @@ function init(args) {
1858
1879
  const present = readdirSync(dir).filter((entry) => entry !== ".git");
1859
1880
  if (present.length > 0) throw new CreateError(`${dir} is not empty (${present.slice(0, 5).join(", ")}${present.length > 5 ? ", ..." : ""}): start in a new, empty folder`);
1860
1881
  const addon = values.addon;
1882
+ const repository = ensureRepository(dir);
1861
1883
  writeJson(join(dir, "package.json"), {
1862
1884
  name: slug(dir),
1863
1885
  version: "0.0.0",
@@ -1883,7 +1905,7 @@ function init(args) {
1883
1905
  mkdirSync(dirname(target), { recursive: true });
1884
1906
  writeFileSync(target, readFileSync(template));
1885
1907
  syncSkills(dir, archetypeSkills().map((skill) => skill.name));
1886
- process.stdout.write(`lernapps init: ${relative$1(dir, target)} from ${relativeTemplate(template, dir)}; the skills of the packages are installed\nNext: read ${relative$1(dir, target)} completely and follow it\n`);
1908
+ process.stdout.write(`lernapps init: ${relative$1(dir, target)} from ${relativeTemplate(template, dir)}; the skills of the packages are installed${repository ? `; ${repository}` : ""}\nNext: read ${relative$1(dir, target)} completely and follow it\n`);
1887
1909
  return 0;
1888
1910
  }
1889
1911
  const relative$1 = (from, to) => to.startsWith(from) ? to.slice(from.length + 1) : to;
@@ -1939,8 +1961,8 @@ moves the app within its version ranges; this moves the ranges, and what npm doe
1939
1961
 
1940
1962
  Run it from the latest tooling, in the app's folder, e.g. to pick up a fixed runtime:
1941
1963
  ${LATEST}
1942
- Run as the app's own tooling (npx lernapps update), it knows only the versions the app already has.
1943
- Then run npx lernapps check, and commit package.json, package-lock.json, .github/workflows/ and what else it names.
1964
+ Run as the app's own tooling (npx --no -- lernapps update), it knows only the versions the app already has.
1965
+ Then run npx --no -- lernapps check, and commit package.json, package-lock.json, .github/workflows/ and what else it names.
1944
1966
 
1945
1967
  Exit codes: 0 when the app is updated (or was up to date), 1 when it cannot be or only partly (the message says
1946
1968
  what was not moved and why), 2 on a usage error.
@@ -2238,7 +2260,7 @@ function update(args) {
2238
2260
  2
2239
2261
  ] });
2240
2262
  if (install.error || install.status !== 0) throw new UpdateError(`npm install ${specs.join(" ")} failed${install.error ? `: ${install.error.message}` : ` (exit ${install.status})`}; its output is above. Fix the cause, then run lernapps update again`);
2241
- if (installHooks([]) !== 0) throw new UpdateError("lernapps hooks failed (see above); run npx lernapps hooks again");
2263
+ if (installHooks([]) !== 0) throw new UpdateError("lernapps hooks failed (see above); run npx --no -- lernapps hooks again");
2242
2264
  }
2243
2265
  const changed = moveActions(`v${version}`);
2244
2266
  if (changed.length > 0) lines.push(`the actions of lernapps/tooling in ${changed.join(", ")}: v${version}`);
@@ -2264,7 +2286,7 @@ function update(args) {
2264
2286
  if (skills.some((line) => line.includes(".gitignore"))) files.push(".gitignore");
2265
2287
  if (architecture.lines.length > 0) files.push(`${ARCHITECTURE}/`);
2266
2288
  if (plan.some((line) => line.startsWith("plan: moved"))) files.push(".vibe/ (git add -A .vibe, to keep the move)");
2267
- process.stdout.write(`Next: npx lernapps check, then commit ${files.slice(0, -1).join(", ")} and ${files.at(-1) ?? ""}\n`);
2289
+ process.stdout.write(`Next: npx --no -- lernapps check, then commit ${files.slice(0, -1).join(", ")} and ${files.at(-1) ?? ""}\n`);
2268
2290
  return 0;
2269
2291
  }
2270
2292
  // src/screenshots.ts
@@ -2431,6 +2453,7 @@ async function screenshots(args) {
2431
2453
  force: true
2432
2454
  });
2433
2455
  mkdirSync(out, { recursive: true });
2456
+ writeFileSync(join(out, ".gitignore"), "*\n");
2434
2457
  const shots = [];
2435
2458
  for (const [index, page] of pages.entries()) {
2436
2459
  const images = [];
@@ -2644,7 +2667,7 @@ function runEndToEndTests(browser) {
2644
2667
  return {
2645
2668
  ...failure,
2646
2669
  found: `end-to-end tests failed (their output is above): ${runtime.length === 1 ? "a generic test" : "generic tests"} of the template's runtime ${RUNTIME}, not of this app: ${shown.join(", ")}${more}`,
2647
- fix: `If the content validates (the build passed), this is a bug in the template: tell the creator and open an issue at ${RUNTIME_ISSUES} with this validation report (or ask the creator to). Never change the tests or the configuration to get around it. Once it is fixed, lernapps update moves the app to the fixed runtime: npx --yes github:lernapps/tooling#main update`
2670
+ fix: `If the content validates (the build passed), this is a bug in the template: tell the creator and open an issue at ${RUNTIME_ISSUES} with this validation report (or ask the creator to). Never change the tests or the configuration to get around it. Once it is fixed, lernapps update moves the app to the fixed runtime: npx --yes @lernapps/tooling@latest update`
2648
2671
  };
2649
2672
  }
2650
2673
  /** Serves a bundle (or opens a URL), visits its pages and measures its fitness. */
@@ -27,11 +27,13 @@ license: MIT
27
27
 
28
28
  ## What each archetype can do
29
29
 
30
+ The READMEs are files of the package `@lernapps/app-templates`, which `init` installed: read them from the folder, in full.
31
+
30
32
  | Archetype | Learners … | Can and cannot (README of its template) |
31
33
  |---|---|---|
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> |
34
+ | `quiz` | answer questions with options and feedback | `node_modules/@lernapps/app-templates/quiz/README.md` |
35
+ | `explainer` | read pages that explain, each with exercises | `node_modules/@lernapps/app-templates/explainer/README.md` |
36
+ | `interactive` | act in one app page, by turns or in real time | `node_modules/@lernapps/app-templates/interactive/README.md` |
35
37
 
36
38
  ## Choose the archetype
37
39
 
@@ -14,7 +14,7 @@ license: MIT
14
14
  ## Create
15
15
 
16
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>`.
17
+ `npx --no -- lernapps create --archetype <archetype>`.
18
18
  2. No git repo yet: `git init --initial-branch=work`. Then `npm install` (dependencies, git hooks), and commit
19
19
  everything on `work`.
20
20
  3. Needs git, Node ≥ 22.18, registry.npmjs.org. Blocked → ask the creator to allow it, run again. Never write the
@@ -29,20 +29,20 @@ license: MIT
29
29
 
30
30
  ## Check
31
31
 
32
- - `npx lernapps check`: format, lint, types, unit tests, build, checks of the built app, end-to-end tests. The hooks
32
+ - `npx --no -- lernapps check`: format, lint, types, unit tests, build, checks of the built app, end-to-end tests. The hooks
33
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`.
34
+ - Report: `node_modules/.cache/lernapps/validation-report.yaml`. Options: `npx --no -- lernapps check --help`.
35
35
 
36
36
  ## Look at the app
37
37
 
38
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
39
  a submission they declare something about.
40
40
 
41
- - Explainer or quiz: build (`npx vp build`), then `npx lernapps screenshots`. It writes one image of every page, one of
41
+ - Explainer or quiz: build (`npx vp build`), then `npx --no -- lernapps screenshots`. It writes one image of every page, one of
42
42
  every figure, and an `index.html` that shows them in order to `screenshots/` (not part of the app: do not commit it).
43
43
  Show the images, or the `index.html` where you can show HTML. Check every figure in its own image
44
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`.
45
+ Options: `npx --no -- lernapps screenshots --help`. The folder ignores itself in git, so a later check never sees it.
46
46
  - Interactive app: `screenshots` does not support it. Open the built app with the Playwright the tooling installs
47
47
  (`import { chromium } from "playwright"`), at 390 px width, and take `page.screenshot({ fullPage: true })` of each
48
48
  state the creator should see, from a short script outside the app.
@@ -15,7 +15,7 @@ Each slice is one Code task and ends in one commit:
15
15
  3. Exercise: a pattern of the guide, varied. A new pattern goes into the guide in the same slice, with example and
16
16
  data file.
17
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.
18
+ 5. Check: `npx --no -- lernapps check` passes.
19
19
  6. Commit, guide changes included.
20
20
 
21
21
  - A new chapter or round: its slices in the order of the guide's procedure.
@@ -15,8 +15,8 @@ license: MIT
15
15
 
16
16
  - Orientation for grade and order, not a condition. None found → say so once; go on.
17
17
  - Only the Land's official document (Kerncurriculum, Lehrplan, Bildungsplan, Rahmenlehrplan) from the ministry or
18
- state institute. No publisher, schoolbook or portal. No Land known → KMK-Bildungsstandards.
19
- - Download and read it yourself.
18
+ state institute. No publisher, schoolbook or portal. No Land known → KMK-Bildungsstandards. The KMK has none for the subject or level (e.g. Informatik in Sekundarstufe II) → cite no unit, write "not checked" and follow the creator's material.
19
+ - Download and read it yourself. A document you cannot read here (a PDF and no tool to read it) → mark it "not checked"; never cite it from its title alone.
20
20
  - Cite it under "Notes": title, issuer, year, address; page and unit (Inhaltsfeld, Lernbereich, Kompetenz).
21
21
  - The creator's material differs → follow the material; say so in one sentence.
22
22
 
@@ -33,6 +33,7 @@ license: MIT
33
33
 
34
34
  - Per competency one article or video (serlo.org, a channel the creator trusts, Wikipedia).
35
35
  - Read [references/sources.md](references/sources.md) before you choose, cite or rely on a source.
36
+ - A text source (Wikipedia, a schoolbook site): take facts, never sentences. Copying a sentence needs the licence the page states; if you cannot read it, do not copy.
36
37
 
37
38
  ## 4. The creator's material and privacy
38
39
 
@@ -15,7 +15,7 @@ license: MIT
15
15
 
16
16
  ## Can and cannot
17
17
 
18
- - The README of the template says it: <https://raw.githubusercontent.com/lernapps/app-templates/main/explainer/README.md>.
18
+ - The README of the template says it: `node_modules/@lernapps/app-templates/explainer/README.md` (in the folder `init` made).
19
19
  Read it before this skill's mapping, if you have not yet.
20
20
 
21
21
  ## Map the content
@@ -15,7 +15,7 @@ license: MIT
15
15
 
16
16
  ## Can and cannot
17
17
 
18
- - The README of the template says it: <https://raw.githubusercontent.com/lernapps/app-templates/main/interactive/README.md>.
18
+ - The README of the template says it: `node_modules/@lernapps/app-templates/interactive/README.md` (in the folder `init` made).
19
19
  Read it before this skill's mapping, if you have not yet.
20
20
 
21
21
  ## Parts
@@ -15,7 +15,7 @@ license: MIT
15
15
 
16
16
  ## Can and cannot
17
17
 
18
- - The README of the template says it: <https://raw.githubusercontent.com/lernapps/app-templates/main/quiz/README.md>.
18
+ - The README of the template says it: `node_modules/@lernapps/app-templates/quiz/README.md` (in the folder `init` made).
19
19
  Read it before this skill's mapping, if you have not yet.
20
20
 
21
21
  ## Map the content
@@ -42,7 +42,7 @@ export const CREATE_OPTIONS = {
42
42
  export const CREATE_USAGE = `Usage: lernapps create --archetype <name> [<dir>] [--plan <file>] [--templates <repo>] [--tooling <spec>]
43
43
 
44
44
  Writes a new app from the archetype's template into <dir> (default: the current folder), which must be empty
45
- except for .git, the first version's plan .vibe/plans/01-<short name>.md and the skills that npx skills add
45
+ except for .git, the first version's plan .vibe/plans/01-<short name>.md and the skills that
46
46
  lernapps init synced (.agents/skills/, .claude/skills/, skills-lock.json, and the package.json, package-lock.json and
47
47
  node_modules init wrote). The template is the folder <name>/ of the installed package @lernapps/app-templates, the
48
48
  version @lernapps/tooling depends on; the app depends on the runtime of the same version.
@@ -53,7 +53,7 @@ It needs the plan of the first version, confirmed by the creator: started from t
53
53
  tooling is moved to .vibe/plans/01-first-version.md. Without a plan, it writes nothing and says what to do.
54
54
 
55
55
  Run it in the folder lernapps init prepared, from the tooling init installed:
56
- npx lernapps create --archetype <name> [<dir>]
56
+ npx --no -- lernapps create --archetype <name> [<dir>]
57
57
  It needs git, and the npm registry for the npm install that follows. The app then depends on the version of
58
58
  @lernapps/tooling that created it, and its workflows use the actions of that version's tag.
59
59
 
@@ -384,7 +384,7 @@ export function create(args: string[]): number {
384
384
  const found = contents(dir);
385
385
  if (found.length > 0) {
386
386
  throw new CreateError(
387
- `${dir} is not empty (${found.slice(0, 5).join(", ")}${found.length > 5 ? ", ..." : ""}): create the app in an empty folder; only .git, the first version's plan .vibe/plans/01-<short name>.md and the skills that npx skills add lernapps/tooling installed may be there`,
387
+ `${dir} is not empty (${found.slice(0, 5).join(", ")}${found.length > 5 ? ", ..." : ""}): create the app in an empty folder; only .git, the first version's plan .vibe/plans/01-<short name>.md and what lernapps init wrote (its skills, package.json, package-lock.json and node_modules) may be there`,
388
388
  );
389
389
  }
390
390
  const plan = confirmedPlan(dir, archetype, values.plan);
package/generator/init.ts CHANGED
@@ -24,6 +24,7 @@ export const INIT_USAGE = `Usage: lernapps init <short name> [--addon <package>]
24
24
 
25
25
  Starts an app in the current folder, which must be empty except for .git. It needs git, Node and the npm registry; nothing
26
26
  else. In order:
27
+ git repository on the branch work, which the plan names (unless the folder is one already; no commit)
27
28
  package.json names the folder, depends on @lernapps/tooling (this version) and the add-on
28
29
  npm install installs them
29
30
  .vibe/plans/01-<short name>.md
@@ -61,6 +62,24 @@ const SKILLS_BIN = () => {
61
62
  return join(dirname(manifest), bin?.["skills"] ?? "bin/cli.mjs");
62
63
  };
63
64
 
65
+ /** The branch the plan works on (rule 8 of the plan template). */
66
+ export const WORK_BRANCH = "work";
67
+
68
+ /**
69
+ * Makes the folder a git repository on the branch `work`, which the plan names, unless it is one already: `create` and
70
+ * the hooks need it, and the plan's first rule is to work there. Returns what it did, for the output; no commit.
71
+ */
72
+ export function ensureRepository(dir: string): string | undefined {
73
+ if (existsSync(join(dir, ".git"))) return undefined;
74
+ const result = spawnSync("git", ["init", "--quiet", `--initial-branch=${WORK_BRANCH}`], {
75
+ cwd: dir,
76
+ encoding: "utf8",
77
+ });
78
+ if (result.error) throw new CreateError(`git cannot run: ${result.error.message}. Install git, then run init again`);
79
+ if (result.status !== 0) throw new CreateError(`git init failed: ${`${result.stdout}${result.stderr}`.trim()}`);
80
+ return `a git repository on the branch ${WORK_BRANCH}`;
81
+ }
82
+
64
83
  /** The names of the skills of the archetypes, with the archetype each belongs to (lernapps-<archetype>[-…]). */
65
84
  export function archetypeSkills(): { name: string; archetype: string }[] {
66
85
  const dir = fromPackage("skills", "archetypes");
@@ -129,6 +148,7 @@ export function init(args: string[]): number {
129
148
  );
130
149
  }
131
150
  const addon = values.addon;
151
+ const repository = ensureRepository(dir);
132
152
  writeJson(join(dir, "package.json"), {
133
153
  name: slug(dir),
134
154
  version: "0.0.0",
@@ -157,7 +177,7 @@ export function init(args: string[]): number {
157
177
  archetypeSkills().map((skill) => skill.name),
158
178
  );
159
179
  process.stdout.write(
160
- `lernapps init: ${relative(dir, target)} from ${relativeTemplate(template, dir)}; the skills of the packages are installed\nNext: read ${relative(dir, target)} completely and follow it\n`,
180
+ `lernapps init: ${relative(dir, target)} from ${relativeTemplate(template, dir)}; the skills of the packages are installed${repository ? `; ${repository}` : ""}\nNext: read ${relative(dir, target)} completely and follow it\n`,
161
181
  );
162
182
  return 0;
163
183
  }
@@ -75,8 +75,8 @@ moves the app within its version ranges; this moves the ranges, and what npm doe
75
75
 
76
76
  Run it from the latest tooling, in the app's folder, e.g. to pick up a fixed runtime:
77
77
  ${LATEST}
78
- Run as the app's own tooling (npx lernapps update), it knows only the versions the app already has.
79
- Then run npx lernapps check, and commit package.json, package-lock.json, .github/workflows/ and what else it names.
78
+ Run as the app's own tooling (npx --no -- lernapps update), it knows only the versions the app already has.
79
+ Then run npx --no -- lernapps check, and commit package.json, package-lock.json, .github/workflows/ and what else it names.
80
80
 
81
81
  Exit codes: 0 when the app is updated (or was up to date), 1 when it cannot be or only partly (the message says
82
82
  what was not moved and why), 2 on a usage error.
@@ -395,7 +395,7 @@ export function update(args: string[]): number {
395
395
  }
396
396
  // npm install <spec> runs no prepare script: the hooks of the new tooling, as npm install would install them
397
397
  if (installHooks([]) !== 0)
398
- throw new UpdateError("lernapps hooks failed (see above); run npx lernapps hooks again");
398
+ throw new UpdateError("lernapps hooks failed (see above); run npx --no -- lernapps hooks again");
399
399
  }
400
400
  const changed = moveActions(`v${version}`);
401
401
  if (changed.length > 0) lines.push(`the actions of lernapps/tooling in ${changed.join(", ")}: v${version}`);
@@ -423,7 +423,7 @@ export function update(args: string[]): number {
423
423
  if (architecture.lines.length > 0) files.push(`${ARCHITECTURE}/`);
424
424
  if (plan.some((line) => line.startsWith("plan: moved"))) files.push(".vibe/ (git add -A .vibe, to keep the move)");
425
425
  process.stdout.write(
426
- `Next: npx lernapps check, then commit ${files.slice(0, -1).join(", ")} and ${files.at(-1) ?? ""}\n`,
426
+ `Next: npx --no -- lernapps check, then commit ${files.slice(0, -1).join(", ")} and ${files.at(-1) ?? ""}\n`,
427
427
  );
428
428
  return 0;
429
429
  }
@@ -137,7 +137,7 @@ cannot. Something new goes into the guide in the slice that adds it. -->
137
137
  Parallel slices: send each sub-agent `@lernapps/tooling/guidance/subagent-brief.md`, filled in.
138
138
  - [ ] The content guide describes the app as it is now (`app-content-matches`). `grep -c "FILL IN"
139
139
  .agents/skills/app-content/SKILL.md` prints 0.
140
- - [ ] `npx lernapps check` passes.
140
+ - [ ] `npx --no -- lernapps check` passes.
141
141
  - [ ] Every box of Explore, Plan and Code ticked.
142
142
  - [ ] Set `phase: commit`: change the value line (`grep '^phase:'` prints `phase: commit`).
143
143
  No checkpoint here: set it before you ask or report anything, then start Commit in the same message.
@@ -158,7 +158,7 @@ cannot. Something new goes into the guide in the slice that adds it. -->
158
158
 
159
159
  - [ ] `grep '^phase:'` prints `phase: commit`; else set it.
160
160
  - [ ] An explainer whose pages or exercises changed: load skill `lernapps-explainer-self-assessment`
161
- (missing → `npx lernapps skills --archetype explainer`). Update the
161
+ (missing → `npx --no -- lernapps skills --archetype explainer`). Update the
162
162
  self-assessment as it says (add one, if the app has none and the skill says so). Commit; the hooks check.
163
163
  - [ ] Load skill `lernapps-github`. Push the branch, open the preview pull request, see its checks to green as it
164
164
  says.
@@ -68,7 +68,7 @@ questions. -->
68
68
  - [ ] Choose the archetype as skill `lernapps-app` says, from the kind of practice: read the README of each
69
69
  archetype in question, tell the creator what the chosen one can and cannot do. Write it and its reason under
70
70
  "Key decisions". Set `archetype`.
71
- - [ ] Install the archetype's skills: `npx lernapps skills --archetype <archetype>`. Load skill
71
+ - [ ] Install the archetype's skills: `npx --no -- lernapps skills --archetype <archetype>`. Load skill
72
72
  `lernapps-<archetype>-design`.
73
73
  - [ ] Interview: ask the other topics of "Answers" in order. Skip a topic only when an earlier answer covers it; note
74
74
  which. No answer → ask once more; still none → write your assumption with "(guess)". Done when every topic
@@ -173,7 +173,7 @@ checks and cannot; how a later agent adds a chapter. Becomes the content guide i
173
173
  - [ ] <the tasks written in Plan; after each, commit on `work`; after the first with real content, show the
174
174
  creator a first look (`early-preview`) and go on>
175
175
  - [ ] The content guide matches what was built (`app-content-matches`).
176
- - [ ] `npx lernapps check` passes.
176
+ - [ ] `npx --no -- lernapps check` passes.
177
177
  - [ ] Look at a screenshot of every screen and state (start, each mode, pause, end), desktop and 360 px. Compare
178
178
  each with the confirmed sketches.
179
179
  - [ ] Every box of Explore, Plan and Code ticked.
@@ -195,7 +195,7 @@ checks and cannot; how a later agent adds a chapter. Becomes the content guide i
195
195
  ### Tasks
196
196
 
197
197
  - [ ] `grep '^phase:'` prints `phase: commit`; else set it.
198
- - [ ] An explainer: load skill `lernapps-explainer-self-assessment` (missing → `npx lernapps skills --archetype
198
+ - [ ] An explainer: load skill `lernapps-explainer-self-assessment` (missing → `npx --no -- lernapps skills --archetype
199
199
  explainer`). Add the self-assessment as it says, or
200
200
  write under "Key decisions" why the app has none. Commit; the hooks check.
201
201
  - [ ] Load skill `lernapps-github`. Repo and Pages as it says: ask the repo name and every click only the creator can
@@ -18,7 +18,7 @@ Competencies, one slice each, in this order:
18
18
  Change only: <the files of this chapter or round>. Do not change: the content guide, the plan, <the shared files>.
19
19
  Write what the shared files need into your report instead.
20
20
 
21
- Per slice: content, exercise, `npx lernapps check` green, one commit. Never bypass a hook.
21
+ Per slice: content, exercise, `npx --no -- lernapps check` green, one commit. Never bypass a hook.
22
22
 
23
23
  Report: branch, commits, per competency the ids of its page or questions and exercises, the patterns used, what the
24
24
  shared files need, what you could not verify.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lernapps/tooling",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Shared tooling of the lernapps.net apps and sites: the CLI lernapps, site actions, Renovate preset, guidance for building apps; documentation at https://lernapps.net/tooling/",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -115,7 +115,7 @@
115
115
  },
116
116
  "devDependencies": {
117
117
  "@doctc/arc42": "0.38.0",
118
- "@lernapps/site": "github:lernapps/lernapps.github.io#4c677cc9949b22bcd24b168dfb00098f3ccae624",
118
+ "@lernapps/site": "github:lernapps/lernapps.github.io#96912a0b6691d90a538ac8336ac808152a7a2227",
119
119
  "@types/node": "26.6.5",
120
120
  "ajv": "8.20.0",
121
121
  "vite-plus": "1.4.0"
@@ -15,7 +15,7 @@ license: MIT
15
15
 
16
16
  ## Can and cannot
17
17
 
18
- - The README of the template says it: <https://raw.githubusercontent.com/lernapps/app-templates/main/explainer/README.md>.
18
+ - The README of the template says it: `node_modules/@lernapps/app-templates/explainer/README.md` (in the folder `init` made).
19
19
  Read it before this skill's mapping, if you have not yet.
20
20
 
21
21
  ## Map the content
@@ -15,7 +15,7 @@ license: MIT
15
15
 
16
16
  ## Can and cannot
17
17
 
18
- - The README of the template says it: <https://raw.githubusercontent.com/lernapps/app-templates/main/interactive/README.md>.
18
+ - The README of the template says it: `node_modules/@lernapps/app-templates/interactive/README.md` (in the folder `init` made).
19
19
  Read it before this skill's mapping, if you have not yet.
20
20
 
21
21
  ## Parts
@@ -15,7 +15,7 @@ license: MIT
15
15
 
16
16
  ## Can and cannot
17
17
 
18
- - The README of the template says it: <https://raw.githubusercontent.com/lernapps/app-templates/main/quiz/README.md>.
18
+ - The README of the template says it: `node_modules/@lernapps/app-templates/quiz/README.md` (in the folder `init` made).
19
19
  Read it before this skill's mapping, if you have not yet.
20
20
 
21
21
  ## Map the content
@@ -15,8 +15,8 @@ license: MIT
15
15
 
16
16
  - Orientation for grade and order, not a condition. None found → say so once; go on.
17
17
  - Only the Land's official document (Kerncurriculum, Lehrplan, Bildungsplan, Rahmenlehrplan) from the ministry or
18
- state institute. No publisher, schoolbook or portal. No Land known → KMK-Bildungsstandards.
19
- - Download and read it yourself.
18
+ state institute. No publisher, schoolbook or portal. No Land known → KMK-Bildungsstandards. The KMK has none for the subject or level (e.g. Informatik in Sekundarstufe II) → cite no unit, write "not checked" and follow the creator's material.
19
+ - Download and read it yourself. A document you cannot read here (a PDF and no tool to read it) → mark it "not checked"; never cite it from its title alone.
20
20
  - Cite it under "Notes": title, issuer, year, address; page and unit (Inhaltsfeld, Lernbereich, Kompetenz).
21
21
  - The creator's material differs → follow the material; say so in one sentence.
22
22
 
@@ -33,6 +33,7 @@ license: MIT
33
33
 
34
34
  - Per competency one article or video (serlo.org, a channel the creator trusts, Wikipedia).
35
35
  - Read [references/sources.md](references/sources.md) before you choose, cite or rely on a source.
36
+ - A text source (Wikipedia, a schoolbook site): take facts, never sentences. Copying a sentence needs the licence the page states; if you cannot read it, do not copy.
36
37
 
37
38
  ## 4. The creator's material and privacy
38
39
 
@@ -27,11 +27,13 @@ license: MIT
27
27
 
28
28
  ## What each archetype can do
29
29
 
30
+ The READMEs are files of the package `@lernapps/app-templates`, which `init` installed: read them from the folder, in full.
31
+
30
32
  | Archetype | Learners … | Can and cannot (README of its template) |
31
33
  |---|---|---|
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> |
34
+ | `quiz` | answer questions with options and feedback | `node_modules/@lernapps/app-templates/quiz/README.md` |
35
+ | `explainer` | read pages that explain, each with exercises | `node_modules/@lernapps/app-templates/explainer/README.md` |
36
+ | `interactive` | act in one app page, by turns or in real time | `node_modules/@lernapps/app-templates/interactive/README.md` |
35
37
 
36
38
  ## Choose the archetype
37
39
 
@@ -15,7 +15,7 @@ Each slice is one Code task and ends in one commit:
15
15
  3. Exercise: a pattern of the guide, varied. A new pattern goes into the guide in the same slice, with example and
16
16
  data file.
17
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.
18
+ 5. Check: `npx --no -- lernapps check` passes.
19
19
  6. Commit, guide changes included.
20
20
 
21
21
  - A new chapter or round: its slices in the order of the guide's procedure.
@@ -14,7 +14,7 @@ license: MIT
14
14
  ## Create
15
15
 
16
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>`.
17
+ `npx --no -- lernapps create --archetype <archetype>`.
18
18
  2. No git repo yet: `git init --initial-branch=work`. Then `npm install` (dependencies, git hooks), and commit
19
19
  everything on `work`.
20
20
  3. Needs git, Node ≥ 22.18, registry.npmjs.org. Blocked → ask the creator to allow it, run again. Never write the
@@ -29,20 +29,20 @@ license: MIT
29
29
 
30
30
  ## Check
31
31
 
32
- - `npx lernapps check`: format, lint, types, unit tests, build, checks of the built app, end-to-end tests. The hooks
32
+ - `npx --no -- lernapps check`: format, lint, types, unit tests, build, checks of the built app, end-to-end tests. The hooks
33
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`.
34
+ - Report: `node_modules/.cache/lernapps/validation-report.yaml`. Options: `npx --no -- lernapps check --help`.
35
35
 
36
36
  ## Look at the app
37
37
 
38
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
39
  a submission they declare something about.
40
40
 
41
- - Explainer or quiz: build (`npx vp build`), then `npx lernapps screenshots`. It writes one image of every page, one of
41
+ - Explainer or quiz: build (`npx vp build`), then `npx --no -- lernapps screenshots`. It writes one image of every page, one of
42
42
  every figure, and an `index.html` that shows them in order to `screenshots/` (not part of the app: do not commit it).
43
43
  Show the images, or the `index.html` where you can show HTML. Check every figure in its own image
44
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`.
45
+ Options: `npx --no -- lernapps screenshots --help`. The folder ignores itself in git, so a later check never sees it.
46
46
  - Interactive app: `screenshots` does not support it. Open the built app with the Playwright the tooling installs
47
47
  (`import { chromium } from "playwright"`), at 390 px width, and take `page.screenshot({ fullPage: true })` of each
48
48
  state the creator should see, from a short script outside the app.