create-octane-xplat 0.7.3 → 0.10.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.
Files changed (30) hide show
  1. package/README.md +28 -8
  2. package/index.mjs +112 -14
  3. package/package.json +15 -8
  4. package/scaffold.mjs +531 -0
  5. package/template/.agents/skills/xplat/SKILL.md +109 -40
  6. package/template/.agents/skills/xplat/references/components.md +149 -96
  7. package/template/.agents/skills/xplat/references/navigation.md +81 -31
  8. package/template/.agents/skills/xplat/references/platform.md +74 -35
  9. package/template/.agents/skills/xplat/references/styling.md +80 -27
  10. package/template/AGENTS.md +1 -1
  11. package/template/package.json +11 -9
  12. package/template/pnpm-workspace.yaml +66 -33
  13. package/template/src/App.tsrx +17 -8
  14. package/template/src/process.d.ts +7 -0
  15. package/template/src/style.css +24 -6
  16. package/template/tsconfig.json +1 -1
  17. package/template/vite.config.native.mts +3 -2
  18. package/template/vite.config.ts +5 -3
  19. package/template/App_Resources/iOS/src/OctaneShaders.metal +0 -128
  20. package/template/App_Resources/iOS/src/ShaderEffectRegistration.swift +0 -31
  21. package/template/patches/@nativescript-community__octane@0.2.1.patch +0 -16
  22. package/template/patches/@nativescript-community__vite-octane@0.2.1.patch +0 -41
  23. package/template/patches/@nativescript__core@9.1.2.patch +0 -794
  24. package/template/patches/@nativescript__core@9.1.3-next.2.patch +0 -428
  25. package/template/patches/@nativescript__vite@8.0.11.patch +0 -569
  26. package/template/patches/@nativescript__vite@8.0.13.patch +0 -233
  27. package/template/patches/@tsrx__typescript-plugin@0.4.11.patch +0 -11
  28. package/template/patches/css@3.0.0.patch +0 -52
  29. package/template/patches/octane@0.6.3.patch +0 -1149
  30. /package/template/src/{index.ts → main.ts} +0 -0
package/README.md CHANGED
@@ -3,20 +3,34 @@
3
3
  > Get a TypeScript app running, then build its first useful flow with your
4
4
  > coding agent.
5
5
 
6
- xplat's target direction spans web, iOS, Android, macOS, and Windows. This
7
- starter configures **web, iOS, and Android**. macOS is a separate experiment;
8
- Windows has a separate experimental scaffold with runtime verification pending. See
6
+ Xplat's target direction spans web, iOS, Android, macOS, Windows, and Linux.
7
+ This starter configures **web, iOS, and Android**. macOS, Windows, and Linux
8
+ are separate experiments — an AppKit host, a WinUI 3 scaffold with runtime
9
+ verification pending, and a WebKitGTK webview host. See
9
10
  [target support](https://octane-xplat.goddardai.org/spec#choose-your-targets).
10
11
  The framework is `0.x` and its API surface is still changing.
11
12
 
12
- With Node.js and pnpm installed:
13
+ With Node.js and pnpm 11.24.0 installed:
13
14
 
14
15
  ```sh
15
16
  pnpm create octane-xplat my-app
16
17
  ```
17
18
 
19
+ The creator asks which platforms to target — web, iOS, and Android are all
20
+ pre-selected. Pass `--targets` to skip the prompt:
21
+
22
+ ```sh
23
+ pnpm create octane-xplat my-app --targets web # web only
24
+ pnpm create octane-xplat my-app --targets web,android # web + Android
25
+ ```
26
+
27
+ Platforms skipped here can be enabled later with `pnpm xplat add <platform>`
28
+ inside the app. (Non-interactive runs without `--targets` scaffold all
29
+ three.)
30
+
18
31
  The creator copies the template, installs dependencies with pnpm, and starts
19
- the web dev server. Open the printed URL and open `my-app` in your agent.
32
+ the web dev server when the web target is included. Open the printed URL and
33
+ open `my-app` in your agent.
20
34
  Ask it to read `AGENTS.md` and `.agents/skills/xplat/SKILL.md`, then build a
21
35
  packing checklist with add, pack, and remove actions using in-memory state.
22
36
  Check the result before asking for the next feature: add “Passport” and
@@ -25,6 +39,10 @@ clear the list in this in-memory version. The
25
39
  [first-flow guide](https://octane-xplat.goddardai.org/toolchain#build-and-check-your-first-flow)
26
40
  includes the full prompt and failure checks.
27
41
 
42
+ The generated app pins pnpm 11.24.0. Its `pnpm-workspace.yaml` loads
43
+ `@octane-xplat/patches` as a `configDependencies` package, making the
44
+ framework patches available during the first install.
45
+
28
46
  Leave the server running while you edit. After stopping it, restart from the
29
47
  app directory:
30
48
 
@@ -33,18 +51,20 @@ cd my-app
33
51
  pnpm dev # web
34
52
  ```
35
53
 
36
- From that directory, these commands run other targets or check the app:
54
+ From that directory, these commands run other targets or check the app — the
55
+ `dev:*`/`build:*` entries exist only for platforms chosen at create time
56
+ (`pnpm xplat add` adds the rest later):
37
57
 
38
58
  ```sh
39
59
  pnpm dev:ios # needs macOS, Xcode, and NativeScript setup
40
60
  pnpm dev:android # needs Android SDK, compatible JDK, and NativeScript setup
41
61
  pnpm lint
42
- pnpm typecheck # web + native tsconfigs
62
+ pnpm typecheck # every enabled tsconfig
43
63
  pnpm build # web production bundle
44
64
  ```
45
65
 
46
66
  [Get a working app and iterate](https://octane-xplat.goddardai.org/toolchain)
47
67
  provides prerequisites, live-update boundaries, and version guidance. The
48
- starter's xplat skill is included; NativeScript's official skills are optional
68
+ starter's Xplat skill is included; NativeScript's official skills are optional
49
69
  and installed separately. Ask your agent to report checks and targets actually
50
70
  run. [llms.txt](https://octane-xplat.goddardai.org/llms.txt) indexes the docs.
package/index.mjs CHANGED
@@ -1,31 +1,129 @@
1
1
  #!/usr/bin/env node
2
- import { existsSync, readdirSync, cpSync, renameSync } from 'node:fs'
3
- import { dirname, join, resolve } from 'node:path'
4
- import { fileURLToPath } from 'node:url'
2
+ import { existsSync, readdirSync } from 'node:fs'
3
+ import { resolve } from 'node:path'
5
4
  import { spawnSync } from 'node:child_process'
5
+ import {
6
+ composeTargets,
7
+ defaultTargets,
8
+ resolveTargets,
9
+ selectableTargets,
10
+ targets,
11
+ } from './scaffold.mjs'
6
12
 
7
- const dir = resolve(process.argv[2] ?? 'octane-xplat-app')
13
+ const argv = process.argv.slice(2)
14
+ const noInstall = argv.includes('--no-install')
15
+ const targetsIndex = argv.findIndex((arg) => arg === '--targets' || arg.startsWith('--targets='))
16
+ const targetsValueIndex =
17
+ targetsIndex !== -1 && argv[targetsIndex] === '--targets' ? targetsIndex + 1 : -1
18
+
19
+ const targetsArg =
20
+ targetsIndex === -1
21
+ ? undefined
22
+ : targetsValueIndex !== -1
23
+ ? argv[targetsValueIndex]
24
+ : argv[targetsIndex].slice('--targets='.length)
25
+
26
+ if (targetsIndex !== -1 && (targetsArg === undefined || targetsArg.startsWith('-'))) {
27
+ console.error(`✗ --targets needs a comma list: ${selectableTargets.join(', ')}`)
28
+ process.exit(1)
29
+ }
30
+
31
+ const positional = argv.filter((arg, i) => !arg.startsWith('-') && i !== targetsValueIndex)
32
+ const dir = resolve(positional[0] ?? 'octane-xplat-app')
8
33
 
9
34
  if (existsSync(dir) && readdirSync(dir).length > 0) {
10
35
  console.error(`✗ ${dir} exists and is not empty`)
11
36
  process.exit(1)
12
37
  }
13
38
 
14
- const template = join(dirname(fileURLToPath(import.meta.url)), 'template')
15
- cpSync(template, dir, { recursive: true })
16
- // npm packs .gitignore as a renamed file or drops it — ship it undotted.
17
- try {
18
- renameSync(join(dir, 'gitignore'), join(dir, '.gitignore'))
19
- } catch {}
39
+ const parseTargets = (value) => {
40
+ const ids = value
41
+ .split(',')
42
+ .map((s) => s.trim())
43
+ .filter(Boolean)
44
+
45
+ if (ids.length === 0) {
46
+ throw new Error(`--targets needs a comma list: ${selectableTargets.join(', ')}`)
47
+ }
48
+
49
+ for (const id of ids) {
50
+ if (!selectableTargets.includes(id)) {
51
+ throw new Error(
52
+ `unknown target "${id}" — expected a comma list of: ${selectableTargets.join(', ')}`,
53
+ )
54
+ }
55
+ }
56
+
57
+ return resolveTargets(ids)
58
+ }
59
+
60
+ let ids
61
+ if (targetsArg !== undefined) {
62
+ try {
63
+ ids = parseTargets(targetsArg)
64
+ } catch (error) {
65
+ console.error(`✗ ${error.message}`)
66
+ process.exit(1)
67
+ }
68
+ } else if (process.stdout.isTTY) {
69
+ // Lazy: the extracted tarball has no installed deps — only the interactive
70
+ // path needs @clack/prompts (verify-consumer runs the bin dep-free).
71
+ const p = await import('@clack/prompts')
72
+ p.intro('create-octane-xplat')
73
+ const picked = await p.multiselect({
74
+ message: 'Target platforms',
75
+ options: selectableTargets.map((id) => ({
76
+ value: id,
77
+ label: targets[id].label,
78
+ hint: targets[id].note,
79
+ })),
80
+ initialValues: [...defaultTargets],
81
+ required: true,
82
+ })
20
83
 
21
- console.log(`\n✓ scaffolded ${dir}`)
84
+ if (p.isCancel(picked)) {
85
+ p.cancel('Cancelled')
86
+ process.exit(0)
87
+ }
88
+
89
+ ids = picked
90
+ } else {
91
+ ids = defaultTargets
92
+ }
93
+
94
+ composeTargets(ids, dir)
95
+
96
+ console.log(
97
+ `\n✓ scaffolded ${dir} (${[...new Set(resolveTargets(ids))].filter((id) => !targets[id].hidden).join(', ')})`,
98
+ )
99
+
100
+ if (noInstall) {
101
+ console.log('\nSkipped install (--no-install). To run manually:')
102
+ printNextSteps(dir, ids)
103
+ process.exit(0)
104
+ }
22
105
 
23
106
  const install = spawnSync('pnpm', ['install'], { cwd: dir, stdio: 'inherit' })
24
107
  if (install.status !== 0) {
25
108
  console.log(`\nInstall didn't finish (pnpm missing?). To run manually:`)
26
- console.log(` cd ${dir}\n pnpm install\n pnpm dev`)
109
+ printNextSteps(dir, ids)
27
110
  process.exit(install.status ?? 1)
28
111
  }
29
112
 
30
- console.log('\n✓ installed — starting dev server (Ctrl+C to stop)\n')
31
- spawnSync('pnpm', ['dev'], { cwd: dir, stdio: 'inherit' })
113
+ if (ids.includes('web')) {
114
+ console.log('\n✓ installed — starting dev server (Ctrl+C to stop)\n')
115
+ spawnSync('pnpm', ['dev'], { cwd: dir, stdio: 'inherit' })
116
+ } else {
117
+ console.log('\n✓ installed. To run:')
118
+ printNextSteps(dir, ids)
119
+ }
120
+
121
+ function printNextSteps(dir, ids) {
122
+ console.log(` cd ${dir}\n pnpm install`)
123
+ if (ids.includes('web')) {
124
+ console.log(' pnpm dev')
125
+ } else {
126
+ // No web entry — `xplat dev` discovers whichever native targets exist.
127
+ console.log(' pnpm xplat dev')
128
+ }
129
+ }
package/package.json CHANGED
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "name": "create-octane-xplat",
3
- "version": "0.7.3",
3
+ "version": "0.10.0",
4
4
  "description": "Scaffold a minimal @octane-xplat/ui app — one Octane codebase for web + iOS + Android",
5
5
  "keywords": [
6
- "octane",
7
- "xplat",
8
- "cross-platform",
9
6
  "create",
7
+ "cross-platform",
8
+ "init",
9
+ "octane",
10
+ "project-generator",
10
11
  "scaffolding",
11
12
  "starter-template",
12
- "project-generator",
13
- "init"
13
+ "xplat"
14
14
  ],
15
- "license": "MIT",
16
15
  "homepage": "https://github.com/octane-xplat/octane-xplat/tree/main/packages/create",
16
+ "license": "MIT",
17
17
  "repository": {
18
18
  "type": "git",
19
- "url": "git+https://github.com/octane-xplat/octane-xplat.git",
19
+ "url": "https://github.com/octane-xplat/octane-xplat",
20
20
  "directory": "packages/create"
21
21
  },
22
22
  "bin": {
@@ -24,10 +24,17 @@
24
24
  },
25
25
  "files": [
26
26
  "index.mjs",
27
+ "scaffold.mjs",
27
28
  "template"
28
29
  ],
29
30
  "type": "module",
31
+ "exports": {
32
+ "./scaffold": "./scaffold.mjs"
33
+ },
30
34
  "publishConfig": {
31
35
  "access": "public"
36
+ },
37
+ "dependencies": {
38
+ "@clack/prompts": "1.8.1"
32
39
  }
33
40
  }