@jskit-ai/create-app 0.1.133 → 0.1.136

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/create-app",
3
- "version": "0.1.133",
3
+ "version": "0.1.136",
4
4
  "description": "Scaffold JSKIT app shells.",
5
5
  "type": "module",
6
6
  "files": [
@@ -20,7 +20,7 @@
20
20
  "./client": "./src/client/index.js"
21
21
  },
22
22
  "dependencies": {
23
- "@jskit-ai/jskit-cli": "0.2.136"
23
+ "@jskit-ai/jskit-cli": "0.2.139"
24
24
  },
25
25
  "engines": {
26
26
  "node": "^22.12.0 || ^24.0.0 || ^26.0.0"
@@ -16,7 +16,6 @@ const DEFAULT_INITIAL_BUNDLES = "none";
16
16
  const DEFAULT_PLAYWRIGHT_VERSION = "1.61.1";
17
17
  const INITIAL_BUNDLE_PRESETS = new Set(["none", "auth"]);
18
18
  const TENANCY_MODES = new Set(["none", "personal", "workspaces"]);
19
- const EXACT_SEMVER_PATTERN = /^\d+\.\d+\.\d+$/u;
20
19
  const ALLOWED_EXISTING_TARGET_ENTRIES = new Set([".git"]);
21
20
  const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
22
21
  const TEMPLATES_ROOT = path.join(PACKAGE_ROOT, "templates");
@@ -57,12 +56,12 @@ function normalizeTenancyMode(value, { showUsage = true } = {}) {
57
56
 
58
57
  function normalizePlaywrightVersion(value, { showUsage = true } = {}) {
59
58
  const normalized = String(value || "").trim();
60
- if (EXACT_SEMVER_PATTERN.test(normalized)) {
59
+ if (normalized === DEFAULT_PLAYWRIGHT_VERSION) {
61
60
  return normalized;
62
61
  }
63
62
 
64
63
  throw createCliError(
65
- `Invalid --playwright-version value "${value}". Expected an exact x.y.z version.`,
64
+ `Invalid --playwright-version value "${value}". JSKIT requires ${DEFAULT_PLAYWRIGHT_VERSION}.`,
66
65
  { showUsage }
67
66
  );
68
67
  }
@@ -262,7 +261,7 @@ function printUsage(stream = process.stderr) {
262
261
  stream.write(" --title <text> App title used for template replacements\n");
263
262
  stream.write(" --target <path> Target directory (default: ./<app-name>)\n");
264
263
  stream.write(" --initial-bundles <preset> Optional initial setup preset: none | auth (default: none)\n");
265
- stream.write(` --playwright-version <x.y.z> Exact Playwright test version (default: ${DEFAULT_PLAYWRIGHT_VERSION})\n`);
264
+ stream.write(` --playwright-version <version> Supported Playwright test version (${DEFAULT_PLAYWRIGHT_VERSION})\n`);
266
265
  stream.write(" --tenancy-mode <mode> Optional config seed: none | personal | workspaces\n");
267
266
  stream.write(" --force Allow writing into a non-empty target directory\n");
268
267
  stream.write(" --dry-run Print planned writes without changing the filesystem\n");
@@ -7,6 +7,5 @@ Keep this stage minimal:
7
7
  - Decide the app name and tenancy mode.
8
8
  - Promote the directory into a real scaffold with `npx @jskit-ai/create-app <app-name> --target . --force --tenancy-mode <mode>`.
9
9
  - Run `npm install`.
10
- - If local JSKIT checkout links are used, run `npm run devlinks` immediately afterward.
11
10
 
12
11
  After the real scaffold exists, follow the generated app `AGENTS.md` and JSKIT agent docs. Do not continue from this seed file as a workflow source of truth.
@@ -48,7 +48,13 @@
48
48
  "value": "0.x"
49
49
  }
50
50
  },
51
- "devDependencies": {},
51
+ "devDependencies": {
52
+ "@playwright/test": {
53
+ "hadPrevious": true,
54
+ "previousValue": "__PLAYWRIGHT_VERSION__",
55
+ "value": "__PLAYWRIGHT_VERSION__"
56
+ }
57
+ },
52
58
  "scripts": {}
53
59
  },
54
60
  "text": {
@@ -12,7 +12,6 @@
12
12
  "server:all": "node ./bin/server.js",
13
13
  "server:home": "SERVER_SURFACE=home node ./bin/server.js",
14
14
  "start": "node ./bin/server.js",
15
- "devlinks": "jskit app link-local-packages",
16
15
  "dev": "vite",
17
16
  "dev:all": "vite",
18
17
  "dev:home": "VITE_SURFACE=home vite",
@@ -0,0 +1,4 @@
1
+ import { defineConfig } from "@playwright/test";
2
+ import { createJskitPlaywrightConfig } from "@jskit-ai/jskit-cli/test/playwright";
3
+
4
+ export default defineConfig(createJskitPlaywrightConfig());
@@ -1,57 +1,4 @@
1
1
  import { expect, test } from "@playwright/test";
2
+ import { runGeneratedAppSmoke } from "@jskit-ai/jskit-cli/test/playwright";
2
3
 
3
- const BASE_URL = String(process.env.PLAYWRIGHT_BASE_URL || "http://127.0.0.1:5173").replace(/\/+$/u, "");
4
- const SMOKE_PATH = String(process.env.JSKIT_PLAYWRIGHT_SMOKE_PATH || "/home");
5
-
6
- const viewports = [
7
- { name: "compact", width: 390, height: 844 },
8
- { name: "medium", width: 768, height: 1024 },
9
- { name: "expanded", width: 1280, height: 900 }
10
- ];
11
-
12
- async function expectNoHorizontalOverflow(page) {
13
- const metrics = await page.evaluate(() => ({
14
- clientWidth: document.documentElement.clientWidth,
15
- scrollWidth: document.documentElement.scrollWidth
16
- }));
17
-
18
- expect(metrics.scrollWidth).toBeLessThanOrEqual(metrics.clientWidth + 1);
19
- }
20
-
21
- async function expectGeneratedScreenContract(page) {
22
- const screen = page.locator(".generated-ui-screen").first();
23
-
24
- await expect(screen).toBeVisible();
25
- await expect(screen).toHaveClass(/generated-ui-screen--app/u);
26
- await expect(screen.locator("h1").first()).toBeVisible();
27
- }
28
-
29
- async function expectVisibleTapTargets(page) {
30
- const targetHeights = await page.locator("a[href], button, [role='button'], .v-btn, .v-list-item").evaluateAll(
31
- (elements) => elements
32
- .filter((element) => {
33
- const rect = element.getBoundingClientRect();
34
- const style = window.getComputedStyle(element);
35
- return style.display !== "none" && style.visibility !== "hidden" && rect.width > 0 && rect.height > 0;
36
- })
37
- .map((element) => element.getBoundingClientRect().height)
38
- );
39
-
40
- for (const height of targetHeights) {
41
- expect(height).toBeGreaterThanOrEqual(48);
42
- }
43
- }
44
-
45
- test.describe("generated base app responsive smoke", () => {
46
- for (const viewport of viewports) {
47
- test(`${viewport.name} home route renders without horizontal overflow`, async ({ page }) => {
48
- await page.setViewportSize({ width: viewport.width, height: viewport.height });
49
- await page.goto(`${BASE_URL}${SMOKE_PATH}`);
50
- await expect(page.locator("body")).toBeVisible();
51
- await expect(page.getByText("Ready")).toBeVisible();
52
- await expectGeneratedScreenContract(page);
53
- await expectVisibleTapTargets(page);
54
- await expectNoHorizontalOverflow(page);
55
- });
56
- }
57
- });
4
+ runGeneratedAppSmoke({ test, expect, expectedText: "Ready" });
@@ -9,7 +9,6 @@ const __dirname = path.dirname(__filename);
9
9
  const APP_ROOT = path.resolve(__dirname, "../..");
10
10
 
11
11
  const EXPECTED_MANAGED_SCRIPTS = Object.freeze({
12
- devlinks: "jskit app link-local-packages",
13
12
  verify: "jskit app verify && npm run --if-present verify:app",
14
13
  release: "jskit app release",
15
14
  "jskit:update": "jskit app update-packages"
@@ -12,7 +12,6 @@
12
12
  "server:all": "node ./bin/server.js",
13
13
  "server:home": "SERVER_SURFACE=home node ./bin/server.js",
14
14
  "start": "node ./bin/server.js",
15
- "devlinks": "jskit app link-local-packages",
16
15
  "dev": "vite",
17
16
  "dev:all": "vite",
18
17
  "dev:home": "VITE_SURFACE=home vite",
@@ -0,0 +1,4 @@
1
+ import { defineConfig } from "@playwright/test";
2
+ import { createJskitPlaywrightConfig } from "@jskit-ai/jskit-cli/test/playwright";
3
+
4
+ export default defineConfig(createJskitPlaywrightConfig());
@@ -1,57 +1,4 @@
1
1
  import { expect, test } from "@playwright/test";
2
+ import { runGeneratedAppSmoke } from "@jskit-ai/jskit-cli/test/playwright";
2
3
 
3
- const BASE_URL = String(process.env.PLAYWRIGHT_BASE_URL || "http://127.0.0.1:5173").replace(/\/+$/u, "");
4
- const SMOKE_PATH = String(process.env.JSKIT_PLAYWRIGHT_SMOKE_PATH || "/home");
5
-
6
- const viewports = [
7
- { name: "compact", width: 390, height: 844 },
8
- { name: "medium", width: 768, height: 1024 },
9
- { name: "expanded", width: 1280, height: 900 }
10
- ];
11
-
12
- async function expectNoHorizontalOverflow(page) {
13
- const metrics = await page.evaluate(() => ({
14
- clientWidth: document.documentElement.clientWidth,
15
- scrollWidth: document.documentElement.scrollWidth
16
- }));
17
-
18
- expect(metrics.scrollWidth).toBeLessThanOrEqual(metrics.clientWidth + 1);
19
- }
20
-
21
- async function expectGeneratedScreenContract(page) {
22
- const screen = page.locator(".generated-ui-screen").first();
23
-
24
- await expect(screen).toBeVisible();
25
- await expect(screen).toHaveClass(/generated-ui-screen--app/u);
26
- await expect(screen.locator("h1").first()).toBeVisible();
27
- }
28
-
29
- async function expectVisibleTapTargets(page) {
30
- const targetHeights = await page.locator("a[href], button, [role='button'], .v-btn, .v-list-item").evaluateAll(
31
- (elements) => elements
32
- .filter((element) => {
33
- const rect = element.getBoundingClientRect();
34
- const style = window.getComputedStyle(element);
35
- return style.display !== "none" && style.visibility !== "hidden" && rect.width > 0 && rect.height > 0;
36
- })
37
- .map((element) => element.getBoundingClientRect().height)
38
- );
39
-
40
- for (const height of targetHeights) {
41
- expect(height).toBeGreaterThanOrEqual(48);
42
- }
43
- }
44
-
45
- test.describe("generated base app responsive smoke", () => {
46
- for (const viewport of viewports) {
47
- test(`${viewport.name} home route renders without horizontal overflow`, async ({ page }) => {
48
- await page.setViewportSize({ width: viewport.width, height: viewport.height });
49
- await page.goto(`${BASE_URL}${SMOKE_PATH}`);
50
- await expect(page.locator("body")).toBeVisible();
51
- await expect(page.getByText("Home base")).toBeVisible();
52
- await expectGeneratedScreenContract(page);
53
- await expectVisibleTapTargets(page);
54
- await expectNoHorizontalOverflow(page);
55
- });
56
- }
57
- });
4
+ runGeneratedAppSmoke({ test, expect, expectedText: "Home base" });
@@ -9,7 +9,6 @@ const __dirname = path.dirname(__filename);
9
9
  const APP_ROOT = path.resolve(__dirname, "../..");
10
10
 
11
11
  const EXPECTED_MANAGED_SCRIPTS = Object.freeze({
12
- devlinks: "jskit app link-local-packages",
13
12
  verify: "jskit app verify && npm run --if-present verify:app",
14
13
  release: "jskit app release",
15
14
  "jskit:update": "jskit app update-packages"