@sempods/apps 0.0.0-stage → 0.7.0-dev
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/CHANGELOG.md +205 -0
- package/LICENSE +19 -0
- package/README.md +50 -2
- package/bin/sempods-apps.mjs +36 -0
- package/instructions/app-workflow.md +210 -0
- package/instructions/publish.md +148 -0
- package/instructions/setup.md +112 -0
- package/package.json +59 -3
- package/scripts/build-site.mjs +181 -0
- package/scripts/check.mjs +260 -0
- package/scripts/configure-site.mjs +118 -0
- package/scripts/create.mjs +83 -0
- package/scripts/dev.mjs +19 -0
- package/scripts/lib/apps.mjs +164 -0
- package/scripts/lib/files.mjs +57 -0
- package/scripts/lib/generate.mjs +175 -0
- package/scripts/lib/html.mjs +3 -0
- package/scripts/lib/json.mjs +42 -0
- package/scripts/lib/merge.mjs +159 -0
- package/scripts/lib/overview.mjs +105 -0
- package/scripts/lib/paths.mjs +33 -0
- package/scripts/lib/pnpm.mjs +30 -0
- package/scripts/lib/sdk.mjs +45 -0
- package/scripts/lib/shared.mjs +221 -0
- package/scripts/migrate.mjs +550 -0
- package/scripts/new-app.mjs +166 -0
- package/scripts/regenerate.mjs +41 -0
- package/scripts/sdk-update.mjs +220 -0
- package/scripts/update.mjs +152 -0
- package/shared/files/0221b70340152ba3cc615342254603b29b89c4d7d944d7b3b3e647873bdcefa0 +11 -0
- package/shared/files/1c29eed0a0297c742ca5814de9081ff8efce3b2da5d9e1bdf90a403873da4aa9 +61 -0
- package/shared/files/31ede0d1a035d8531100ebfd751510c772ab0871309a0b9752a77fb96187eb53 +25 -0
- package/shared/files/393b09ecd18889d9e1fdf2a6df12d1f6c193fc7fcd89ba808ad94df521bad8db +41 -0
- package/shared/files/4660ca1887261ae658c7f587190e2b71ac91d15b1b6c4cf04dec823fdd0da654 +22 -0
- package/shared/files/528d7544990228d6d66fa62423775338fe1716326fc68371fb2665aee86e39b0 +6 -0
- package/shared/files/676e6bf33b44044fb4c62c9fe5441729bd47f2d5077ff904e57a4a1b658859ac +38 -0
- package/shared/files/8b7567319e18694aeca8722107281a760e3100239c6d0f548acb71e1806fa172 +28 -0
- package/shared/files/9945f9bd573e5af8aad2e65cc8b4284fbb1d7e8b96c4efdd42eeb49132fb4327 +4 -0
- package/shared/files/b911698dc3cf3227d34d0ad6727f1c4408791203c9665de99ab959331a1fb07d +1 -0
- package/shared/files/c2a4b026a87f6c8e7473e7fc456c6020b63c7e675087f6b58013ed5163c2f6ee +23 -0
- package/shared/files/d3ca3a13c6524a2ee9382977ddc0539790813225f366306024a58c957a4716ee +11 -0
- package/shared/files/e13474647ebaf26d042d76f4917203d209a2b14c0d2af8d12139ea328530823e +78 -0
- package/shared/files/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +0 -0
- package/shared/files/f04e547b89bb933c39de2f781978b93ea8b586ac9dee50312612e2f5c40391b1 +5 -0
- package/shared/files/f2fb601d5ebc4ca72274ac9d3fcf7b7a96e27958bb92cd065a9165b501ee94d7 +57 -0
- package/shared/files/ff9f774d9732fdc7d704ef37ddc40ef507a1bab7ee3c1db5b1a6a8f26e6e4b37 +35 -0
- package/shared/snapshot.json +25 -0
- package/skeleton/app/.oxlintrc.json +14 -0
- package/skeleton/app/NOTES.md +19 -0
- package/skeleton/app/index.html +16 -0
- package/skeleton/app/package.json +28 -0
- package/skeleton/app/public/favicon.svg +1 -0
- package/skeleton/app/public/icon-192.png +0 -0
- package/skeleton/app/public/icon-512.png +0 -0
- package/skeleton/app/src/App.tsx +73 -0
- package/skeleton/app/src/NewVersionNotice.tsx +63 -0
- package/skeleton/app/src/index.css +37 -0
- package/skeleton/app/src/main.tsx +18 -0
- package/skeleton/app/src/pwa.ts +18 -0
- package/skeleton/app/src/start.test.ts +15 -0
- package/skeleton/app/src/start.ts +9 -0
- package/skeleton/app/tsconfig.app.json +27 -0
- package/skeleton/app/tsconfig.json +8 -0
- package/skeleton/app/tsconfig.node.json +23 -0
- package/skeleton/app/tsconfig.test.json +10 -0
- package/skeleton/app/vite.config.ts +13 -0
- package/skills/app-workflow/SKILL.md +22 -0
- package/skills/update/SKILL.md +69 -0
- 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,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
|
+
}
|