auramaxx 0.1.2 → 0.1.4

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 = []) {
@@ -1383,7 +1506,7 @@ async function main() {
1383
1506
  }
1384
1507
  }
1385
1508
 
1386
- maybePrintUpdateNotice();
1509
+ await maybeHandleUpdateNotice();
1387
1510
  maybeAutoInstallAuraAlias();
1388
1511
  maybeAutoInstallSkills();
1389
1512
  maybeAutoInstallMcp();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auramaxx",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "AuraJS CLI for creating, playing, and publishing JavaScript-first games.",
5
5
  "keywords": [
6
6
  "aurajs",
@@ -26,6 +26,8 @@
26
26
  "src/lib/startBannerQuotes.ts",
27
27
  "src/server/cli/commands/onboard.ts",
28
28
  "src/server/cli/commands/create.ts",
29
+ "src/server/cli/commands/fork.ts",
30
+ "src/server/cli/commands/make.ts",
29
31
  "src/server/cli/commands/play.ts",
30
32
  "src/server/cli/commands/publish.ts",
31
33
  "src/server/cli/lib/published-game-integrity.ts",
@@ -0,0 +1,81 @@
1
+ import { execFileSync } from 'child_process';
2
+ import { rmSync } from 'fs';
3
+ import { pathToFileURL } from 'url';
4
+
5
+ import { printBanner, printSection, paint, ANSI } from '../lib/theme';
6
+ import {
7
+ buildPublishedGameLaunchEnv,
8
+ installVerifiedGamePackage,
9
+ parseArgs,
10
+ resolveGameBin,
11
+ resolvePackageName,
12
+ } from './play';
13
+
14
+ export interface ForkCommandPlan {
15
+ help: boolean;
16
+ name: string | null;
17
+ gameArgs: string[];
18
+ gameBin: string | null;
19
+ packageName: string | null;
20
+ forwardedArgs: string[];
21
+ }
22
+
23
+ export function buildForkPlan(argv: string[]): ForkCommandPlan {
24
+ const parsed = parseArgs(argv);
25
+ return {
26
+ ...parsed,
27
+ gameBin: parsed.name ? resolveGameBin(parsed.name) : null,
28
+ packageName: parsed.name ? resolvePackageName(parsed.name) : null,
29
+ forwardedArgs: ['fork', ...parsed.gameArgs],
30
+ };
31
+ }
32
+
33
+ export async function main(argv: string[] = process.argv.slice(2)) {
34
+ const plan = buildForkPlan(argv);
35
+
36
+ if (plan.help || !plan.name) {
37
+ printBanner('FORK');
38
+ console.log(` ${paint('Usage:', ANSI.bold)} auramaxx fork <game> [destination|wrapper fork options]`);
39
+ console.log('');
40
+ console.log(` ${paint('Examples:', ANSI.dim)}`);
41
+ console.log(' auramaxx fork aurasu');
42
+ console.log(' auramaxx fork aurasu ./aurasu-local');
43
+ console.log(' auramaxx fork @auraindustry/chess-dev-cli@1.2.3 --dest ./chess-local');
44
+ console.log('');
45
+ console.log(` ${paint('Runs:', ANSI.dim)} verified signed temporary install -> local game wrapper fork`);
46
+ console.log('');
47
+ if (!plan.name && !plan.help) {
48
+ console.error(' Missing game name.');
49
+ process.exit(1);
50
+ }
51
+ return;
52
+ }
53
+
54
+ printBanner(plan.name.toUpperCase());
55
+ printSection(plan.name, 'Forking editable package into local project...');
56
+
57
+ let install: Awaited<ReturnType<typeof installVerifiedGamePackage>> | null = null;
58
+ try {
59
+ install = await installVerifiedGamePackage(plan);
60
+ const env = buildPublishedGameLaunchEnv(process.env);
61
+ execFileSync(process.execPath, [install.binAbsolutePath, ...plan.forwardedArgs], {
62
+ stdio: 'inherit',
63
+ cwd: install.packageRoot,
64
+ env,
65
+ });
66
+ } finally {
67
+ if (install?.installRoot) {
68
+ rmSync(install.installRoot, { recursive: true, force: true });
69
+ }
70
+ }
71
+ }
72
+
73
+ if (import.meta.url === pathToFileURL(process.argv[1]).href) {
74
+ main().catch((err) => {
75
+ console.error(err instanceof Error ? err.message : String(err));
76
+ const status = (err as { status?: number; exitCode?: number })?.status
77
+ ?? (err as { status?: number; exitCode?: number })?.exitCode
78
+ ?? 1;
79
+ process.exit(Number.isInteger(status) ? status : 1);
80
+ });
81
+ }
@@ -0,0 +1,90 @@
1
+ import { execFileSync } from 'child_process';
2
+ import { existsSync } from 'fs';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { printBanner, paint, ANSI } from '../lib/theme';
6
+
7
+ const COMMAND_DIR = path.dirname(fileURLToPath(import.meta.url));
8
+ const LOCAL_AURAJS_CLI = path.resolve(
9
+ COMMAND_DIR,
10
+ '../../../../../packages/aurascript/src/cli/src/cli.mjs',
11
+ );
12
+
13
+ function parseArgs(argv: string[]) {
14
+ for (const arg of argv) {
15
+ if (arg === '--help' || arg === '-h') {
16
+ return { help: true, passthrough: [] as string[] };
17
+ }
18
+ }
19
+ return {
20
+ help: false,
21
+ passthrough: [...argv],
22
+ };
23
+ }
24
+
25
+ function resolveInvocationCwd(): string {
26
+ const forwardedCwd = process.env.AURA_INVOKE_CWD;
27
+ if (forwardedCwd && path.isAbsolute(forwardedCwd)) {
28
+ return forwardedCwd;
29
+ }
30
+
31
+ const shellPwd = process.env.PWD;
32
+ if (shellPwd && path.isAbsolute(shellPwd)) {
33
+ return shellPwd;
34
+ }
35
+ return process.cwd();
36
+ }
37
+
38
+ async function main() {
39
+ const parsed = parseArgs(process.argv.slice(2));
40
+
41
+ if (parsed.help) {
42
+ printBanner('MAKE');
43
+ console.log(` ${paint('Usage:', ANSI.bold)} auramaxx make [kind] [name] [--role <custom|enemy|pickup|player|world>]`);
44
+ console.log('');
45
+ console.log(' Public wrapper around AuraJS project file generation.');
46
+ console.log(' Run it from inside an AuraJS game project.');
47
+ console.log(` ${paint('Examples:', ANSI.dim)}`);
48
+ console.log(' auramaxx make');
49
+ console.log(' auramaxx make scene Scene1');
50
+ console.log(' auramaxx make ui-screen PauseMenu');
51
+ console.log(' auramaxx make prefab EnemyShip --role enemy');
52
+ console.log(' auramaxx make list');
53
+ console.log('');
54
+ console.log(' When no arguments are passed in a TTY, AuraJS opens an interactive make flow.');
55
+ console.log('');
56
+ return;
57
+ }
58
+
59
+ const invocationCwd = resolveInvocationCwd();
60
+ const auraArgs = ['make', ...parsed.passthrough];
61
+
62
+ try {
63
+ if (existsSync(LOCAL_AURAJS_CLI)) {
64
+ execFileSync(process.execPath, [LOCAL_AURAJS_CLI, ...auraArgs], {
65
+ cwd: invocationCwd,
66
+ stdio: 'inherit',
67
+ env: process.env,
68
+ });
69
+ } else {
70
+ execFileSync(
71
+ 'npm',
72
+ ['exec', '--yes', '--package', '@auraindustry/aurajs', '--', 'aura', ...auraArgs],
73
+ {
74
+ cwd: invocationCwd,
75
+ stdio: 'inherit',
76
+ env: process.env,
77
+ },
78
+ );
79
+ }
80
+ } catch (error: unknown) {
81
+ const status = (error as { status?: number }).status;
82
+ if (status) process.exit(status);
83
+ throw error;
84
+ }
85
+ }
86
+
87
+ main().catch((err) => {
88
+ console.error(err instanceof Error ? err.message : String(err));
89
+ process.exit(1);
90
+ });
@@ -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,
@@ -114,6 +115,27 @@ function resolveAuramaxxCommand(): string {
114
115
  return process.platform === 'win32' ? 'auramaxx.cmd' : 'auramaxx';
115
116
  }
116
117
 
118
+ function resolveInstalledGlobalAuramaxxVersion(): string | null {
119
+ try {
120
+ const root = execFileSync(resolveNpmCommand(), ['root', '-g'], {
121
+ stdio: ['ignore', 'pipe', 'pipe'],
122
+ encoding: 'utf8',
123
+ timeout: 30000,
124
+ }).trim();
125
+ if (!root) {
126
+ return null;
127
+ }
128
+ const packageJsonPath = join(root, 'auramaxx', 'package.json');
129
+ if (!existsSync(packageJsonPath)) {
130
+ return null;
131
+ }
132
+ const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { version?: unknown };
133
+ return typeof pkg.version === 'string' && pkg.version.trim().length > 0 ? pkg.version.trim() : null;
134
+ } catch {
135
+ return null;
136
+ }
137
+ }
138
+
117
139
  function normalizeRelativePath(pathLike: string): string {
118
140
  return String(pathLike || '')
119
141
  .trim()
@@ -212,12 +234,26 @@ async function promptUpgradeAuramaxx(expectedAurajsVersion: string): Promise<boo
212
234
 
213
235
  function installLatestAuramaxx(): void {
214
236
  console.log('');
215
- console.log(` ${paint('Installing latest AuraMaxx...', ANSI.bold)}`);
237
+ console.log(` ${paint('Reinstalling latest AuraMaxx...', ANSI.bold)}`);
216
238
  console.log('');
239
+ try {
240
+ execFileSync(resolveNpmCommand(), ['uninstall', '-g', 'auramaxx'], {
241
+ stdio: 'inherit',
242
+ timeout: 120000,
243
+ });
244
+ } catch {
245
+ // Ignore missing-package uninstall failures and continue with a clean install.
246
+ }
217
247
  execFileSync(resolveNpmCommand(), ['install', '-g', 'auramaxx@latest', '--foreground-scripts'], {
218
248
  stdio: 'inherit',
219
- timeout: 120000,
249
+ timeout: 180000,
220
250
  });
251
+
252
+ const installedVersion = resolveInstalledGlobalAuramaxxVersion();
253
+ if (installedVersion) {
254
+ console.log('');
255
+ console.log(` ${paint(`Installed AuraMaxx ${installedVersion}`, ANSI.dim)}`);
256
+ }
221
257
  }
222
258
 
223
259
  function relaunchWithUpdatedAuramaxx(argv: string[]): never {
@@ -330,6 +366,12 @@ function describeForwardedCommand(command: string): string {
330
366
 
331
367
  export async function main(argv: string[] = process.argv.slice(2)) {
332
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
+ }
333
375
 
334
376
  if (plan.help || !plan.name) {
335
377
  printBanner('PLAY');
@@ -400,7 +442,7 @@ if (import.meta.url === pathToFileURL(process.argv[1]).href) {
400
442
  ? updateError.message
401
443
  : String(updateError),
402
444
  );
403
- console.error(' Manual fallback: npm install -g auramaxx@latest');
445
+ console.error(' Manual fallback: npm uninstall -g auramaxx && npm install -g auramaxx@latest');
404
446
  process.exit(1);
405
447
  }
406
448
  })().catch((promptError) => {
@@ -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) {