auramaxx 0.1.3 → 0.1.5

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
@@ -1,5 +1,7 @@
1
1
  # AuraJS
2
2
 
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
+
3
5
  Write JavaScript 2D and 3D games, compile to native.
4
6
  Create, play, and publish from your terminal.
5
7
 
@@ -37,6 +39,8 @@ auramaxx play auracraft
37
39
  npx auracraft play
38
40
  ```
39
41
 
42
+ ![Auracraft demo](https://aurajs.gg/auracraft-demo.gif)
43
+
40
44
  ## Fork a Game
41
45
 
42
46
  ```bash
package/bin/auramaxx.js CHANGED
@@ -49,8 +49,21 @@ const COMMANDS = {
49
49
  play: 'Play an AuraJS game from npm (auramaxx play <game>)',
50
50
  fork: 'Fork a published AuraJS game into a local editable project (auramaxx fork <game>)',
51
51
  create: 'Scaffold a new AuraJS game (2d/3d/multiplayer) via AuraJS CLI',
52
+ dev: 'Run the AuraJS local dev loop in the current project',
53
+ build: 'Build the current AuraJS project',
52
54
  make: 'Generate authored AuraJS project files via AuraJS CLI',
55
+ explain: 'Explain the current AuraJS project surface',
56
+ check: 'Validate the current AuraJS project surface',
53
57
  publish: 'Publish current AuraJS game package to npm with guided prompts',
58
+ 'external-assets': 'Stage self-hosted external asset manifests for the current AuraJS project',
59
+ run: 'Run the current AuraJS project with lower-level launch/session control',
60
+ clean: 'Clean generated AuraJS project output',
61
+ test: 'Run AuraJS project tests',
62
+ conformance: 'Run AuraJS project conformance checks',
63
+ state: 'Run AuraJS project state tools',
64
+ inspect: 'Run AuraJS project inspect tools',
65
+ action: 'Run AuraJS project action tools',
66
+ session: 'Run AuraJS project session tools',
54
67
  // diary: 'Append daily diary entries via authenticated CLI path', // Temporarily disabled at root CLI.
55
68
  // apikey: 'List/validate/set/delete API keys', // Temporarily disabled at root CLI.
56
69
  // quickhack: 'Generate random tutorial secret, run set+inject, and print copyable commands', // Temporarily disabled at root CLI.
@@ -122,7 +135,26 @@ const SHORTCUT_COMMANDS = [];
122
135
  // ];
123
136
 
124
137
  const DEFAULT_ADMIN = ['start', 'status', 'init', 'mcp', 'skill', 'auth'];
125
- const AURAJS_COMMANDS = ['create', 'make', 'play', 'fork', 'publish'];
138
+ const AURAJS_COMMANDS = [
139
+ 'create',
140
+ 'dev',
141
+ 'build',
142
+ 'play',
143
+ 'make',
144
+ 'explain',
145
+ 'check',
146
+ 'publish',
147
+ 'external-assets',
148
+ 'run',
149
+ 'clean',
150
+ 'test',
151
+ 'conformance',
152
+ 'state',
153
+ 'inspect',
154
+ 'action',
155
+ 'session',
156
+ 'fork',
157
+ ];
126
158
  const HIDDEN_HELP_COMMANDS = new Set(['wallet']);
127
159
 
128
160
  const COMMON_EXAMPLES = [
@@ -131,6 +163,8 @@ const COMMON_EXAMPLES = [
131
163
  { cmd: 'aura skill --doctor', note: 'Check skill installation status' },
132
164
  { cmd: 'aura mcp --install', note: 'Install MCP config for supported clients' },
133
165
  { cmd: 'auramaxx make scene Scene1', note: 'Generate a scene in the current AuraJS project' },
166
+ { cmd: 'auramaxx check', note: 'Validate the current AuraJS project from any project subdirectory' },
167
+ { cmd: 'auramaxx external-assets generate --public-base-url https://cdn.example.com/my-game', note: 'Stage self-hosted asset manifests for the current AuraJS project' },
134
168
  { cmd: 'auramaxx fork aurasu ./aurasu-local', note: 'Fork a published AuraJS game into a local editable project' },
135
169
  // { cmd: 'aura diary write --entry "heartbeat ok"', note: 'Append a daily diary entry (auth-aware)' }, // Temporarily disabled at root CLI.
136
170
  // { cmd: 'aura get OURSECRET', note: 'Read a credential' }, // Temporarily disabled at root CLI.
@@ -673,10 +707,18 @@ function getUpdateCachePath() {
673
707
  return path.join(dataDir, `update-check-${key}.json`);
674
708
  }
675
709
 
710
+ function resolveNpmCommand() {
711
+ return process.platform === 'win32' ? 'npm.cmd' : 'npm';
712
+ }
713
+
714
+ function resolveAuramaxxCommand() {
715
+ return process.platform === 'win32' ? 'auramaxx.cmd' : 'auramaxx';
716
+ }
717
+
676
718
  function getGlobalInstalledAuramaxxVersion() {
677
719
  const timeoutMs = Number(process.env.AURA_UPDATE_CHECK_TIMEOUT_MS || '1200');
678
720
  try {
679
- const out = execFileSync('npm', ['list', '-g', 'auramaxx', '--json'], {
721
+ const out = execFileSync(resolveNpmCommand(), ['list', '-g', 'auramaxx', '--json'], {
680
722
  cwd: root,
681
723
  stdio: ['ignore', 'pipe', 'ignore'],
682
724
  timeout: timeoutMs,
@@ -705,7 +747,7 @@ function formatUpdateAvailableLine(current, latest) {
705
747
  return `⚠️ Update available: aura${normalizedCurrent} → aura${normalizedLatest}`;
706
748
  }
707
749
 
708
- function maybePrintUpdateNotice() {
750
+ function resolveUpdateNoticeState() {
709
751
  if (process.env.AURA_NO_UPDATE_CHECK === '1' || process.env.CI === 'true') return;
710
752
 
711
753
  const now = Date.now();
@@ -736,10 +778,9 @@ function maybePrintUpdateNotice() {
736
778
  }
737
779
 
738
780
  if (cachedLatest && compareVersions(cachedLatest, effectiveCurrent || '') > 0) {
739
- console.log(`\n${formatUpdateAvailableLine(effectiveCurrent, cachedLatest)}`);
740
- console.log(' Run: npm i -g auramaxx --foreground-scripts (fallback: npx --yes auramaxx@latest start)\n');
781
+ return { current: effectiveCurrent, latest: cachedLatest };
741
782
  }
742
- return;
783
+ return null;
743
784
  }
744
785
 
745
786
  let latest = process.env.AURA_UPDATE_CHECK_MOCK_LATEST || null;
@@ -747,18 +788,18 @@ function maybePrintUpdateNotice() {
747
788
 
748
789
  if (!latest) {
749
790
  try {
750
- const out = execFileSync('npm', ['view', 'auramaxx', 'version', '--json'], {
791
+ const out = execFileSync(resolveNpmCommand(), ['view', 'auramaxx', 'version', '--json'], {
751
792
  cwd: root,
752
793
  stdio: ['ignore', 'pipe', 'ignore'],
753
794
  timeout: Number(process.env.AURA_UPDATE_CHECK_TIMEOUT_MS || '1200'),
754
795
  }).toString('utf8').trim();
755
796
  latest = JSON.parse(out);
756
797
  } catch {
757
- return;
798
+ return null;
758
799
  }
759
800
  }
760
801
  latest = normalizeVersionString(latest);
761
- if (!latest) return;
802
+ if (!latest) return null;
762
803
 
763
804
  try {
764
805
  fs.mkdirSync(path.dirname(cachePath), { recursive: true });
@@ -766,9 +807,91 @@ function maybePrintUpdateNotice() {
766
807
  } catch {}
767
808
 
768
809
  if (latest && compareVersions(latest, current) > 0) {
769
- console.log(`\n${formatUpdateAvailableLine(current, latest)}`);
770
- console.log(' Run: npm i -g auramaxx --foreground-scripts (fallback: npx --yes auramaxx@latest start)\n');
810
+ return { current, latest };
771
811
  }
812
+
813
+ return null;
814
+ }
815
+
816
+ function reinstallLatestAuramaxx() {
817
+ try {
818
+ execFileSync(resolveNpmCommand(), ['uninstall', '-g', 'auramaxx'], {
819
+ stdio: 'inherit',
820
+ timeout: 120000,
821
+ });
822
+ } catch {
823
+ // Ignore uninstall failures for missing or partially-installed global packages.
824
+ }
825
+
826
+ execFileSync(resolveNpmCommand(), ['install', '-g', 'auramaxx@latest', '--foreground-scripts'], {
827
+ stdio: 'inherit',
828
+ timeout: 180000,
829
+ });
830
+ }
831
+
832
+ function relaunchUpdatedAuramaxx(argv, latestVersion) {
833
+ const installedVersion = normalizeVersionString(getGlobalInstalledAuramaxxVersion()) || 'unknown';
834
+ const useNpxLatest = installedVersion === 'unknown' || compareVersions(latestVersion, installedVersion) > 0;
835
+ const command = useNpxLatest ? 'npx' : resolveAuramaxxCommand();
836
+ const args = useNpxLatest
837
+ ? ['--yes', 'auramaxx@latest', ...argv]
838
+ : argv;
839
+
840
+ execFileSync(command, args, {
841
+ stdio: 'inherit',
842
+ env: {
843
+ ...process.env,
844
+ AURA_NO_UPDATE_CHECK: '1',
845
+ },
846
+ });
847
+ process.exit(0);
848
+ }
849
+
850
+ async function maybeHandleUpdateNotice() {
851
+ const update = resolveUpdateNoticeState();
852
+ if (!update) return;
853
+
854
+ const noticeLine = formatUpdateAvailableLine(update.current, update.latest);
855
+ if (!canPromptForInput()) {
856
+ console.log(`\n${noticeLine}`);
857
+ console.log(' Run: npm uninstall -g auramaxx && npm install -g auramaxx --foreground-scripts (fallback: npx --yes auramaxx@latest start)\n');
858
+ return;
859
+ }
860
+
861
+ console.log(`\n${noticeLine}`);
862
+ const choice = await promptSelect(
863
+ 'Update AuraMaxx now?',
864
+ [
865
+ { value: 'continue', label: 'No, continue', aliases: ['n', 'no', 'continue', '2'] },
866
+ { value: 'update', label: 'Yes, update and relaunch', aliases: ['y', 'yes', 'update', '1'] },
867
+ ],
868
+ 'continue',
869
+ );
870
+
871
+ if (choice !== 'update') {
872
+ console.log('');
873
+ return;
874
+ }
875
+
876
+ console.log('');
877
+ console.log(' Reinstalling latest AuraMaxx...');
878
+ console.log('');
879
+
880
+ try {
881
+ reinstallLatestAuramaxx();
882
+ } catch (error) {
883
+ console.log('');
884
+ console.error(` Failed to update AuraMaxx automatically: ${error?.message || String(error)}`);
885
+ console.error(' Manual fallback: npm uninstall -g auramaxx && npm install -g auramaxx --foreground-scripts');
886
+ console.error(' Fallback: npx --yes auramaxx@latest start');
887
+ console.log('');
888
+ return;
889
+ }
890
+
891
+ console.log('');
892
+ console.log(' [ok] AuraMaxx updated. Relaunching command...');
893
+ console.log('');
894
+ relaunchUpdatedAuramaxx(process.argv.slice(2), update.latest);
772
895
  }
773
896
 
774
897
  function buildRunner(commandName, commandArgs = []) {
@@ -1317,8 +1440,7 @@ async function main() {
1317
1440
 
1318
1441
  const inferredStartFlags = new Set(['--debug', '--terminal', '--headless', '--background', '--daemon', '-d']);
1319
1442
  if (cmd && inferredStartFlags.has(cmd)) {
1320
- const defaultCommand = resolveDefaultCommand();
1321
- if (defaultCommand === 'start') {
1443
+ if (isCommandAvailable('start')) {
1322
1444
  inferredCommand = true;
1323
1445
  args.unshift(cmd);
1324
1446
  cmd = 'start';
@@ -1383,7 +1505,7 @@ async function main() {
1383
1505
  }
1384
1506
  }
1385
1507
 
1386
- maybePrintUpdateNotice();
1508
+ await maybeHandleUpdateNotice();
1387
1509
  maybeAutoInstallAuraAlias();
1388
1510
  maybeAutoInstallSkills();
1389
1511
  maybeAutoInstallMcp();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auramaxx",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "AuraJS CLI for creating, playing, and publishing JavaScript-first games.",
5
5
  "keywords": [
6
6
  "aurajs",
@@ -30,6 +30,7 @@
30
30
  "src/server/cli/commands/make.ts",
31
31
  "src/server/cli/commands/play.ts",
32
32
  "src/server/cli/commands/publish.ts",
33
+ "src/server/cli/lib/aurajs-project.ts",
33
34
  "src/server/cli/lib/published-game-integrity.ts",
34
35
  "src/server/cli/lib/prompt.ts",
35
36
  "src/server/cli/lib/theme.ts"
@@ -6,6 +6,7 @@ import { pathToFileURL } from 'url';
6
6
  import { printBanner, printSection, paint, ANSI, createProgressDisplay, printComplete } from '../lib/theme';
7
7
  import { promptSelect } from '../lib/prompt';
8
8
  import { PublishedGameIntegrityError } from '../lib/published-game-integrity';
9
+ import { resolveAuraJsProjectRoot, resolveInvocationCwd, delegateToAuraJsCommand } from '../lib/aurajs-project';
9
10
  import {
10
11
  assertPublishedGameBinIntegrity,
11
12
  buildPublishedGameLaunchEnv,
@@ -365,6 +366,12 @@ function describeForwardedCommand(command: string): string {
365
366
 
366
367
  export async function main(argv: string[] = process.argv.slice(2)) {
367
368
  const plan = buildPlayPlan(argv);
369
+ const invocationCwd = resolveInvocationCwd();
370
+ const auraJsProjectRoot = resolveAuraJsProjectRoot(invocationCwd);
371
+
372
+ if (!plan.name && auraJsProjectRoot) {
373
+ delegateToAuraJsCommand(['play', ...argv], auraJsProjectRoot);
374
+ }
368
375
 
369
376
  if (plan.help || !plan.name) {
370
377
  printBanner('PLAY');
@@ -1,6 +1,7 @@
1
1
  import { execFileSync } from 'child_process';
2
2
  import { existsSync, readFileSync, writeFileSync } from 'fs';
3
3
  import path from 'path';
4
+ import { fileURLToPath } from 'url';
4
5
  import { printBanner, printSection, printStatus, paint, ANSI } from '../lib/theme';
5
6
  import { promptInput, promptSelect } from '../lib/prompt';
6
7
 
@@ -19,6 +20,11 @@ interface ParsedArgs {
19
20
  const SEMVER_RE = /^v?(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z-.]+)?$/;
20
21
  const SCOPED_PACKAGE_RE = /^@[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*$/;
21
22
  const UNSCOPED_PACKAGE_RE = /^[a-z0-9][a-z0-9._-]*$/;
23
+ const COMMAND_DIR = path.dirname(fileURLToPath(import.meta.url));
24
+ const LOCAL_AURAJS_CLI = path.resolve(
25
+ COMMAND_DIR,
26
+ '../../../../../packages/aurascript/src/cli/src/cli.mjs',
27
+ );
22
28
 
23
29
  function parseArgs(argv: string[]): ParsedArgs {
24
30
  const parsed: ParsedArgs = {
@@ -100,6 +106,52 @@ function resolveInvocationCwd(): string {
100
106
  return process.cwd();
101
107
  }
102
108
 
109
+ function resolveAuraJsProjectRoot(startDir: string): string | null {
110
+ let current = path.resolve(startDir);
111
+
112
+ while (true) {
113
+ const auraConfigPath = path.join(current, 'aura.config.json');
114
+ const packageJsonPath = path.join(current, 'package.json');
115
+ if (existsSync(auraConfigPath) && existsSync(packageJsonPath)) {
116
+ return current;
117
+ }
118
+
119
+ const parent = path.dirname(current);
120
+ if (parent === current) break;
121
+ current = parent;
122
+ }
123
+
124
+ return null;
125
+ }
126
+
127
+ function delegateToAuraJsPublish(rawArgs: string[], projectRoot: string): never {
128
+ const auraArgs = ['publish', ...rawArgs];
129
+
130
+ try {
131
+ if (existsSync(LOCAL_AURAJS_CLI)) {
132
+ execFileSync(process.execPath, [LOCAL_AURAJS_CLI, ...auraArgs], {
133
+ cwd: projectRoot,
134
+ stdio: 'inherit',
135
+ env: process.env,
136
+ });
137
+ } else {
138
+ execFileSync(
139
+ 'npm',
140
+ ['exec', '--yes', '--package', '@auraindustry/aurajs', '--', 'aura', ...auraArgs],
141
+ {
142
+ cwd: projectRoot,
143
+ stdio: 'inherit',
144
+ env: process.env,
145
+ },
146
+ );
147
+ }
148
+ process.exit(0);
149
+ } catch (error: unknown) {
150
+ const status = (error as { status?: number }).status;
151
+ process.exit(status || 1);
152
+ }
153
+ }
154
+
103
155
  function sanitizePackageSlug(value: string): string {
104
156
  const compact = String(value || '')
105
157
  .trim()
@@ -253,8 +305,15 @@ async function resolveVersion(options: {
253
305
  }
254
306
 
255
307
  async function main() {
256
- const parsed = parseArgs(process.argv.slice(2));
257
308
  const invocationCwd = resolveInvocationCwd();
309
+ const rawArgs = process.argv.slice(2);
310
+ const auraJsProjectRoot = resolveAuraJsProjectRoot(invocationCwd);
311
+
312
+ if (auraJsProjectRoot) {
313
+ delegateToAuraJsPublish(rawArgs, auraJsProjectRoot);
314
+ }
315
+
316
+ const parsed = parseArgs(rawArgs);
258
317
  const packageJsonPath = path.join(invocationCwd, 'package.json');
259
318
 
260
319
  if (parsed.help) {
@@ -0,0 +1,84 @@
1
+ import { execFileSync } from 'child_process';
2
+ import { existsSync } from 'fs';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const LIB_DIR = path.dirname(fileURLToPath(import.meta.url));
7
+ export const LOCAL_AURAJS_CLI = path.resolve(
8
+ LIB_DIR,
9
+ '../../../../../packages/aurascript/src/cli/src/cli.mjs',
10
+ );
11
+
12
+ export function resolveInvocationCwd(): string {
13
+ const forwardedCwd = process.env.AURA_INVOKE_CWD;
14
+ if (forwardedCwd && path.isAbsolute(forwardedCwd)) {
15
+ return forwardedCwd;
16
+ }
17
+
18
+ const shellPwd = process.env.PWD;
19
+ if (shellPwd && path.isAbsolute(shellPwd)) {
20
+ return shellPwd;
21
+ }
22
+
23
+ return process.cwd();
24
+ }
25
+
26
+ export function resolveAuraJsProjectRoot(startDir: string): string | null {
27
+ let current = path.resolve(startDir);
28
+
29
+ while (true) {
30
+ const auraConfigPath = path.join(current, 'aura.config.json');
31
+ const packageJsonPath = path.join(current, 'package.json');
32
+ if (existsSync(auraConfigPath) && existsSync(packageJsonPath)) {
33
+ return current;
34
+ }
35
+
36
+ const parent = path.dirname(current);
37
+ if (parent === current) break;
38
+ current = parent;
39
+ }
40
+
41
+ return null;
42
+ }
43
+
44
+ export function requireAuraJsProjectRoot(startDir: string): string {
45
+ const projectRoot = resolveAuraJsProjectRoot(startDir);
46
+ if (projectRoot) {
47
+ return projectRoot;
48
+ }
49
+
50
+ throw new Error('Not an AuraJS project. Run `auramaxx create my-game` first.');
51
+ }
52
+
53
+ export function delegateToAuraJsCommand(auraArgs: string[], cwd: string): never {
54
+ try {
55
+ if (existsSync(LOCAL_AURAJS_CLI)) {
56
+ execFileSync(process.execPath, [LOCAL_AURAJS_CLI, ...auraArgs], {
57
+ cwd,
58
+ stdio: 'inherit',
59
+ env: process.env,
60
+ });
61
+ } else {
62
+ execFileSync(
63
+ 'npm',
64
+ ['exec', '--yes', '--package', '@auraindustry/aurajs', '--', 'aura', ...auraArgs],
65
+ {
66
+ cwd,
67
+ stdio: 'inherit',
68
+ env: process.env,
69
+ },
70
+ );
71
+ }
72
+
73
+ process.exit(0);
74
+ } catch (error: unknown) {
75
+ const status = (error as { status?: number }).status;
76
+ process.exit(status || 1);
77
+ }
78
+ }
79
+
80
+ export function delegateToAuraJsProjectCommand(commandName: string, commandArgs: string[] = []): never {
81
+ const invocationCwd = resolveInvocationCwd();
82
+ const projectRoot = requireAuraJsProjectRoot(invocationCwd);
83
+ delegateToAuraJsCommand([commandName, ...commandArgs], projectRoot);
84
+ }