@sempods/apps 0.0.0-stage → 0.7.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +205 -0
  2. package/LICENSE +19 -0
  3. package/README.md +50 -2
  4. package/bin/sempods-apps.mjs +36 -0
  5. package/instructions/app-workflow.md +210 -0
  6. package/instructions/publish.md +148 -0
  7. package/instructions/setup.md +112 -0
  8. package/package.json +59 -3
  9. package/scripts/build-site.mjs +181 -0
  10. package/scripts/check.mjs +260 -0
  11. package/scripts/configure-site.mjs +118 -0
  12. package/scripts/create.mjs +83 -0
  13. package/scripts/dev.mjs +19 -0
  14. package/scripts/lib/apps.mjs +164 -0
  15. package/scripts/lib/files.mjs +57 -0
  16. package/scripts/lib/generate.mjs +175 -0
  17. package/scripts/lib/html.mjs +3 -0
  18. package/scripts/lib/json.mjs +42 -0
  19. package/scripts/lib/merge.mjs +159 -0
  20. package/scripts/lib/overview.mjs +105 -0
  21. package/scripts/lib/paths.mjs +33 -0
  22. package/scripts/lib/pnpm.mjs +30 -0
  23. package/scripts/lib/sdk.mjs +45 -0
  24. package/scripts/lib/shared.mjs +221 -0
  25. package/scripts/migrate.mjs +550 -0
  26. package/scripts/new-app.mjs +166 -0
  27. package/scripts/regenerate.mjs +41 -0
  28. package/scripts/sdk-update.mjs +220 -0
  29. package/scripts/update.mjs +152 -0
  30. package/shared/files/0221b70340152ba3cc615342254603b29b89c4d7d944d7b3b3e647873bdcefa0 +11 -0
  31. package/shared/files/1c29eed0a0297c742ca5814de9081ff8efce3b2da5d9e1bdf90a403873da4aa9 +61 -0
  32. package/shared/files/31ede0d1a035d8531100ebfd751510c772ab0871309a0b9752a77fb96187eb53 +25 -0
  33. package/shared/files/393b09ecd18889d9e1fdf2a6df12d1f6c193fc7fcd89ba808ad94df521bad8db +41 -0
  34. package/shared/files/4660ca1887261ae658c7f587190e2b71ac91d15b1b6c4cf04dec823fdd0da654 +22 -0
  35. package/shared/files/528d7544990228d6d66fa62423775338fe1716326fc68371fb2665aee86e39b0 +6 -0
  36. package/shared/files/676e6bf33b44044fb4c62c9fe5441729bd47f2d5077ff904e57a4a1b658859ac +38 -0
  37. package/shared/files/8b7567319e18694aeca8722107281a760e3100239c6d0f548acb71e1806fa172 +28 -0
  38. package/shared/files/9945f9bd573e5af8aad2e65cc8b4284fbb1d7e8b96c4efdd42eeb49132fb4327 +4 -0
  39. package/shared/files/b911698dc3cf3227d34d0ad6727f1c4408791203c9665de99ab959331a1fb07d +1 -0
  40. package/shared/files/c2a4b026a87f6c8e7473e7fc456c6020b63c7e675087f6b58013ed5163c2f6ee +23 -0
  41. package/shared/files/d3ca3a13c6524a2ee9382977ddc0539790813225f366306024a58c957a4716ee +11 -0
  42. package/shared/files/e13474647ebaf26d042d76f4917203d209a2b14c0d2af8d12139ea328530823e +78 -0
  43. package/shared/files/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +0 -0
  44. package/shared/files/f2fb601d5ebc4ca72274ac9d3fcf7b7a96e27958bb92cd065a9165b501ee94d7 +57 -0
  45. package/shared/files/f9e2544290ee8418484e47194444ee58c2ea675682871ae8a8727d1edb17978e +5 -0
  46. package/shared/files/ff9f774d9732fdc7d704ef37ddc40ef507a1bab7ee3c1db5b1a6a8f26e6e4b37 +35 -0
  47. package/shared/snapshot.json +25 -0
  48. package/skeleton/app/.oxlintrc.json +14 -0
  49. package/skeleton/app/NOTES.md +19 -0
  50. package/skeleton/app/index.html +16 -0
  51. package/skeleton/app/package.json +28 -0
  52. package/skeleton/app/public/favicon.svg +1 -0
  53. package/skeleton/app/public/icon-192.png +0 -0
  54. package/skeleton/app/public/icon-512.png +0 -0
  55. package/skeleton/app/src/App.tsx +73 -0
  56. package/skeleton/app/src/NewVersionNotice.tsx +63 -0
  57. package/skeleton/app/src/index.css +37 -0
  58. package/skeleton/app/src/main.tsx +18 -0
  59. package/skeleton/app/src/pwa.ts +18 -0
  60. package/skeleton/app/src/start.test.ts +15 -0
  61. package/skeleton/app/src/start.ts +9 -0
  62. package/skeleton/app/tsconfig.app.json +27 -0
  63. package/skeleton/app/tsconfig.json +8 -0
  64. package/skeleton/app/tsconfig.node.json +23 -0
  65. package/skeleton/app/tsconfig.test.json +10 -0
  66. package/skeleton/app/vite.config.ts +13 -0
  67. package/skills/app-workflow/SKILL.md +22 -0
  68. package/skills/update/SKILL.md +69 -0
  69. package/update-policy.json +35 -0
@@ -0,0 +1,18 @@
1
+ import { StrictMode } from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import './index.css';
4
+ import App from './App.tsx';
5
+ import { registerAppWorker } from './pwa.ts';
6
+ import { app } from './sempods.generated.ts';
7
+
8
+ // Production builds only: the development server has no service worker.
9
+ const registration =
10
+ import.meta.env.PROD && app.pwa
11
+ ? registerAppWorker(`${app.basePath}sw.js`)
12
+ : Promise.resolve(undefined);
13
+
14
+ createRoot(document.getElementById('root')!).render(
15
+ <StrictMode>
16
+ <App registration={registration} />
17
+ </StrictMode>,
18
+ );
@@ -0,0 +1,18 @@
1
+ // Adapted from the sempods TypeScript SDK v0.2.0 recipe
2
+ // examples/todo/pwa/register.tsx, licensed under Apache-2.0; see
3
+ // the LICENSE and NOTICE of the @sempods/app-sdk package. Changes: this header; the notice
4
+ // component moved to NewVersionNotice.tsx.
5
+ /**
6
+ * Registers the app's service worker. Call it once from the app entry, never on
7
+ * library import. Resolves to undefined where service workers are unavailable
8
+ * (plain HTTP other than loopback, blocked by policy) or registration fails:
9
+ * the app keeps working as an ordinary page.
10
+ */
11
+ export function registerAppWorker(
12
+ url = '/sw.js',
13
+ ): Promise<ServiceWorkerRegistration | undefined> {
14
+ if (!('serviceWorker' in navigator)) return Promise.resolve(undefined);
15
+ // The default scope is the worker's directory: '/' for /sw.js, '/tasks/' for
16
+ // /tasks/sw.js. That scope is also the worker's base path.
17
+ return navigator.serviceWorker.register(url).catch(() => undefined);
18
+ }
@@ -0,0 +1,15 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { app } from './sempods.generated.ts';
3
+ import { startMessage } from './start.ts';
4
+
5
+ describe('startMessage', () => {
6
+ it('speaks the app language', () => {
7
+ expect(startMessage('de')).toMatch(/^Verbunden\./);
8
+ expect(startMessage('en')).toMatch(/^Connected\./);
9
+ });
10
+
11
+ it('has a text for the configured language', () => {
12
+ // The generated configuration imports without a browser.
13
+ expect(startMessage(app.language)).not.toBe('');
14
+ });
15
+ });
@@ -0,0 +1,9 @@
1
+ import type { Language } from '@sempods/app-sdk';
2
+
3
+ // Replace this with your app's own domain logic. Pure functions like this one
4
+ // are tested in src/start.test.ts without a browser or a Pod.
5
+ export function startMessage(language: Language): string {
6
+ return language === 'de'
7
+ ? 'Verbunden. Beschreibe deinem Assistenten, was diese App tun soll.'
8
+ : 'Connected. Tell your assistant what this app should do.';
9
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
+ "target": "es2023",
5
+ "lib": ["ES2023", "DOM"],
6
+ "module": "esnext",
7
+ "types": ["vite/client"],
8
+ "allowArbitraryExtensions": true,
9
+ "skipLibCheck": true,
10
+
11
+ /* Bundler mode */
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "moduleDetection": "force",
16
+ "noEmit": true,
17
+ "jsx": "react-jsx",
18
+
19
+ /* Linting */
20
+ "noUnusedLocals": true,
21
+ "noUnusedParameters": true,
22
+ "erasableSyntaxOnly": true,
23
+ "noFallthroughCasesInSwitch": true
24
+ },
25
+ "include": ["src"],
26
+ "exclude": ["src/**/*.test.ts", "src/**/*.test.tsx"]
27
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" },
6
+ { "path": "./tsconfig.test.json" }
7
+ ]
8
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "es2023",
5
+ "lib": ["ES2023"],
6
+ "types": ["node"],
7
+ "skipLibCheck": true,
8
+
9
+ /* Bundler mode */
10
+ "module": "nodenext",
11
+ "allowImportingTsExtensions": true,
12
+ "verbatimModuleSyntax": true,
13
+ "moduleDetection": "force",
14
+ "noEmit": true,
15
+
16
+ /* Linting */
17
+ "noUnusedLocals": true,
18
+ "noUnusedParameters": true,
19
+ "erasableSyntaxOnly": true,
20
+ "noFallthroughCasesInSwitch": true
21
+ },
22
+ "include": ["vite.config.ts", "vite.sempods.generated.ts"]
23
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.app.json",
3
+ "compilerOptions": {
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.test.tsbuildinfo",
5
+ /* Tests run in Node and may use its APIs, such as node:fs. */
6
+ "types": ["vite/client", "node"]
7
+ },
8
+ "include": ["src/**/*.test.ts", "src/**/*.test.tsx"],
9
+ "exclude": []
10
+ }
@@ -0,0 +1,13 @@
1
+ import react from '@vitejs/plugin-react';
2
+ import { defineConfig } from 'vite';
3
+ import { VitePWA } from 'vite-plugin-pwa';
4
+ import { base, pwa, server } from './vite.sempods.generated.ts';
5
+
6
+ // Base path, development port and PWA settings come from apps.json through the
7
+ // generated file; add your own plugins and options here.
8
+ export default defineConfig({
9
+ base,
10
+ server,
11
+ preview: server,
12
+ plugins: [react(), ...(pwa ? [VitePWA(pwa)] : [])],
13
+ });
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: app-workflow
3
+ description:
4
+ Create or change a sempods app in an owner's apps repository, guide first
5
+ setup and SDK updates, and verify and record the result. For app work, not
6
+ maintenance of the tooling or SDK itself.
7
+ ---
8
+
9
+ # App workflow
10
+
11
+ Read the repository's `AGENTS.md` and owner instructions, then follow the
12
+ [canonical workflow](../../instructions/app-workflow.md). For first setup, use
13
+ the repository's `INIT.md` and the
14
+ [setup procedure](../../instructions/setup.md). Existing apps keep their code
15
+ and decisions in their own folder and `NOTES.md`.
16
+
17
+ The workflow owns commands, pinned SDK references, verification and handoff. It
18
+ works without skill discovery; this entry adds no separate rules.
19
+
20
+ For SDK updates, follow
21
+ [Update the SDK](../../instructions/app-workflow.md#update-the-sdk); for
22
+ tooling updates, the [update skill](../update/SKILL.md).
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: update
3
+ description:
4
+ Update the tooling of a sempods apps repository created from the starter:
5
+ install a newer @sempods/apps, migrate the shared files, review the result
6
+ and open a pull request. Not for SDK-only updates.
7
+ ---
8
+
9
+ # Update the tooling
10
+
11
+ Use this when the owner asks to update the tooling or the starter, or when a
12
+ pull request raises the `@sempods/apps` version in `package.json`. Read the
13
+ repository's `AGENTS.md` and the setup record in its `INIT.md` first. SDK
14
+ updates follow [Update the SDK](../../instructions/app-workflow.md#update-the-sdk)
15
+ instead.
16
+
17
+ 1. **Start clean.** The working tree must have no uncommitted changes, so the
18
+ update is one reviewable diff. Work on a new branch, for example
19
+ `tooling-update-<version>`, or on the branch of the version pull request.
20
+ 2. **Update.** `pnpm run update` installs the newest version and migrates;
21
+ `pnpm run update <version>` a specific one. It first checks that Node and
22
+ pnpm suit that version; if not, it changes nothing and prints a numbered
23
+ order to follow before running it again. On the branch of a version pull request, run
24
+ `pnpm run update <version>` with the version the pull request names, so
25
+ the same check runs before anything is installed. If pnpm refuses to run
26
+ it because the dependencies are out of date, start the installed tooling
27
+ directly:
28
+ `node node_modules/@sempods/apps/bin/sempods-apps.mjs update <version>`.
29
+ 3. **Read the upgrade notes** for every version after the old one, including
30
+ skipped ones, in `node_modules/@sempods/apps/CHANGELOG.md`. They name what
31
+ the migration cannot do alone, such as changes the owner's apps need.
32
+ 4. **Decide the manual cases.** The migration applies only unambiguous
33
+ changes. It lists everything else in `.sempods-migration/migration.json`,
34
+ each with a reason, and leaves those files exactly as they are. Next to
35
+ the list are the old starter's version (`base/`), the new starter's
36
+ version (`starter/`) and, where both are text, a merge suggestion
37
+ (`suggestion/`) whose conflicts are marked. For each case:
38
+ - Compare the repository's file with `base/` to see what the owner changed,
39
+ and `base/` with `starter/` to see what the starter changed.
40
+ - Keep the owner's changes. Keep the owner section of AGENTS.md and the
41
+ setup record of INIT.md exactly as they are, including their marker
42
+ lines.
43
+ - Apply what the starter changed. Where both changed the same lines,
44
+ follow the intent of each; when it is a matter of choice, ask the owner.
45
+ - For a file the starter dropped, a file added on both sides or a
46
+ file/directory collision, explain the case and decide with the owner.
47
+ Keeping the owner's version or declining a starter change is a valid
48
+ decision.
49
+ - Write the decided result to the repository's file; never leave conflict
50
+ markers from a suggestion in it.
51
+ - Record each decision and its reason for the pull request.
52
+ 5. **Finish.** Review the whole list again, the resulting diff and the owner
53
+ section and setup record. Only when every listed case has a deliberate
54
+ decision, run `pnpm run migrate --done`: it confirms those decisions,
55
+ applies anything automatic still left, rewrites the apps' generated
56
+ configuration, installs and advances the baseline in
57
+ `.sempods-baseline.json`. It refuses while a file still contains an
58
+ unresolved suggestion. If it names new manual cases instead, decide them
59
+ and run it again. If a step fails, fix the cause and run the same command
60
+ again; the list and the decisions stay. If pnpm refuses to run it because
61
+ the dependencies are out of date, run
62
+ `node node_modules/@sempods/apps/bin/sempods-apps.mjs migrate --done`.
63
+ Without manual cases, `pnpm run migrate` finishes on its own.
64
+ 6. **Check.** Run `pnpm run check` until it passes.
65
+ 7. **Hand over.** With a GitHub remote, open a pull request "Update the tooling
66
+ to <version>" with the migration report, each manual case and how it was
67
+ decided, and what to try. Tell the owner what changed in plain words and
68
+ what they should try. App code, app notes and the owner's entries in
69
+ `package.json` are never rewritten by the migration.
@@ -0,0 +1,35 @@
1
+ {
2
+ "shared": [
3
+ "AGENTS.md",
4
+ "CLAUDE.md",
5
+ "README.md",
6
+ "INIT.md",
7
+ "docs/start.md",
8
+ ".agents/skills/*/SKILL.md",
9
+ ".claude/skills/*/SKILL.md",
10
+ "pnpm-workspace.yaml",
11
+ ".gitignore",
12
+ ".node-version",
13
+ ".github/dependabot.yml",
14
+ ".github/workflows/check.yml",
15
+ ".github/workflows/codeql.yml",
16
+ ".github/codeql/codeql-config.yml"
17
+ ],
18
+ "sections": {
19
+ "AGENTS.md": [
20
+ ["<!-- BEGIN OWNER INSTRUCTIONS -->", "<!-- END OWNER INSTRUCTIONS -->"]
21
+ ],
22
+ "INIT.md": [
23
+ [
24
+ "<!-- BEGIN INSTANCE SETUP RECORD -->",
25
+ "<!-- END INSTANCE SETUP RECORD -->"
26
+ ]
27
+ ],
28
+ ".github/dependabot.yml": [
29
+ ["# BEGIN OWNER SEMPODS UPDATES", "# END OWNER SEMPODS UPDATES"]
30
+ ]
31
+ },
32
+ "seed": ["apps.json", "apps/.gitkeep"],
33
+ "rootManifest": "package.json",
34
+ "sdk": ["@sempods/app-sdk", "@sempods/client-sdk"]
35
+ }