@freegamestore/cli 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/LICENSE +21 -0
- package/README.md +84 -0
- package/dist/commands/check.d.ts +14 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +65 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +34 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +22 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +137 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +9 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +96 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/list.test.d.ts +2 -0
- package/dist/commands/list.test.d.ts.map +1 -0
- package/dist/commands/list.test.js +25 -0
- package/dist/commands/list.test.js.map +1 -0
- package/dist/commands/login.d.ts +11 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +50 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +3 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +12 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/logs.d.ts +3 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +33 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/publish.d.ts +42 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +372 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/publish.test.d.ts +2 -0
- package/dist/commands/publish.test.d.ts.map +1 -0
- package/dist/commands/publish.test.js +166 -0
- package/dist/commands/publish.test.js.map +1 -0
- package/dist/commands/screencheck.d.ts +36 -0
- package/dist/commands/screencheck.d.ts.map +1 -0
- package/dist/commands/screencheck.js +428 -0
- package/dist/commands/screencheck.js.map +1 -0
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +13 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/app-id.d.ts +3 -0
- package/dist/lib/app-id.d.ts.map +1 -0
- package/dist/lib/app-id.js +16 -0
- package/dist/lib/app-id.js.map +1 -0
- package/dist/lib/app-id.test.d.ts +2 -0
- package/dist/lib/app-id.test.d.ts.map +1 -0
- package/dist/lib/app-id.test.js +45 -0
- package/dist/lib/app-id.test.js.map +1 -0
- package/dist/lib/apps.d.ts +36 -0
- package/dist/lib/apps.d.ts.map +1 -0
- package/dist/lib/apps.js +21 -0
- package/dist/lib/apps.js.map +1 -0
- package/dist/lib/apps.test.d.ts +2 -0
- package/dist/lib/apps.test.d.ts.map +1 -0
- package/dist/lib/apps.test.js +42 -0
- package/dist/lib/apps.test.js.map +1 -0
- package/dist/lib/config.d.ts +26 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +33 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/config.test.d.ts +2 -0
- package/dist/lib/config.test.d.ts.map +1 -0
- package/dist/lib/config.test.js +22 -0
- package/dist/lib/config.test.js.map +1 -0
- package/dist/lib/github.d.ts +11 -0
- package/dist/lib/github.d.ts.map +1 -0
- package/dist/lib/github.js +62 -0
- package/dist/lib/github.js.map +1 -0
- package/dist/lib/history.d.ts +29 -0
- package/dist/lib/history.d.ts.map +1 -0
- package/dist/lib/history.js +77 -0
- package/dist/lib/history.js.map +1 -0
- package/dist/lib/history.test.d.ts +2 -0
- package/dist/lib/history.test.d.ts.map +1 -0
- package/dist/lib/history.test.js +30 -0
- package/dist/lib/history.test.js.map +1 -0
- package/dist/lib/open.d.ts +6 -0
- package/dist/lib/open.d.ts.map +1 -0
- package/dist/lib/open.js +31 -0
- package/dist/lib/open.js.map +1 -0
- package/dist/lib/style.d.ts +9 -0
- package/dist/lib/style.d.ts.map +1 -0
- package/dist/lib/style.js +18 -0
- package/dist/lib/style.js.map +1 -0
- package/dist/one-shot/doctor.d.ts +13 -0
- package/dist/one-shot/doctor.d.ts.map +1 -0
- package/dist/one-shot/doctor.js +116 -0
- package/dist/one-shot/doctor.js.map +1 -0
- package/dist/one-shot/doctor.test.d.ts +2 -0
- package/dist/one-shot/doctor.test.d.ts.map +1 -0
- package/dist/one-shot/doctor.test.js +63 -0
- package/dist/one-shot/doctor.test.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FreeAppStore
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# @freegamestore/cli
|
|
2
|
+
|
|
3
|
+
The `gas` CLI for [FreeGameStore](https://freegamestore.online) creators. Same surface as [`fas`](https://www.npmjs.com/package/@freeappstore/cli) but games-first: every command targets the games store with no extra flags.
|
|
4
|
+
|
|
5
|
+
Identity is shared with `fas` — `gas login` uses the same `~/.fas/config.json`. If you already have `fas` installed and signed in, `gas` works immediately.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm i -g @freegamestore/cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requires Node 22+.
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
gas login # GitHub device-flow auth (shared with fas)
|
|
19
|
+
gas init asteroids # scaffold from template-game-canvas
|
|
20
|
+
cd asteroids
|
|
21
|
+
pnpm install && pnpm dev
|
|
22
|
+
gas check # compliance checks
|
|
23
|
+
gas publish # provisions repo + hosting + DNS at <id>.freegamestore.online
|
|
24
|
+
git push upstream main # auto-deploys via CI
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Live in 30 seconds at `https://asteroids.freegamestore.online`.
|
|
28
|
+
|
|
29
|
+
## Commands
|
|
30
|
+
|
|
31
|
+
| Command | What it does |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `gas login` | Sign in with GitHub via the device-authorization flow. Token cached at `~/.fas/config.json` (`0600`). |
|
|
34
|
+
| `gas logout` | Clear the cached session. |
|
|
35
|
+
| `gas whoami` | Print the currently signed-in GitHub login. |
|
|
36
|
+
| `gas doctor` | Health check — Node, git, pnpm, config, signed-in state, API reachability. |
|
|
37
|
+
| `gas init <game-id> [--template canvas\|grid\|3d]` | Scaffold a new game. Default is `canvas` (2D arcade). `grid` for puzzles (Sudoku, Minesweeper). `3d` for Three.js / Babylon. |
|
|
38
|
+
| `gas check [--dir <path>]` | Run compliance checks. Exits non-zero on hard failures. |
|
|
39
|
+
| `gas publish` | Provisions repo + Cloudflare Pages project + DNS + storefront entry under the games store. Auto-runs `gas check` first. |
|
|
40
|
+
| `gas list` (alias `gas ls`) | List all apps and games you've published (across both stores — fas and gas share the same backend). |
|
|
41
|
+
| `gas logs <id>` | Tail the live deployment logs for a game's Cloudflare Pages project. |
|
|
42
|
+
|
|
43
|
+
## `gas publish` flags
|
|
44
|
+
|
|
45
|
+
Same as `fas publish` minus `--store` (always `games`):
|
|
46
|
+
|
|
47
|
+
| Flag | Purpose |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `--name <id>` | Game id (lowercase, used as subdomain). |
|
|
50
|
+
| `--category <name>` | Storefront category. Case-insensitive. |
|
|
51
|
+
| `--type standalone\|connected` | Standalone (localStorage only) or Connected. |
|
|
52
|
+
| `--oneliner <text>` | One-line description shown on the storefront. |
|
|
53
|
+
| `--demo <url>` | Optional demo URL. |
|
|
54
|
+
| `--yes` | Non-interactive: missing required fields abort. |
|
|
55
|
+
| `--issue` | Skip auto-provision; open the GitHub Issue submission form instead. |
|
|
56
|
+
| `--skip-checks` | Skip `gas check` before publish (not recommended). |
|
|
57
|
+
|
|
58
|
+
## Brand and UI rules (enforced)
|
|
59
|
+
|
|
60
|
+
Every game on the platform shares the same visual language. `gas check` enforces:
|
|
61
|
+
|
|
62
|
+
- No template placeholders (every `APPNAME` substituted)
|
|
63
|
+
- No tracking SDKs
|
|
64
|
+
- Brand fonts present (Manrope + Fraunces) — DOM/HTML text only; pixel fonts inside a game canvas are fine
|
|
65
|
+
- No brand overrides (no redefining `--accent`, `--paper`, `--ink`, etc. outside the canonical theme file)
|
|
66
|
+
- PWA manifest valid
|
|
67
|
+
- Main bundle under 300 KB gzipped
|
|
68
|
+
|
|
69
|
+
Full rules: <https://freegamestore.online/contribute>
|
|
70
|
+
|
|
71
|
+
## Relationship to `fas`
|
|
72
|
+
|
|
73
|
+
| | fas | gas |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| Targets | FreeAppStore (`*.freeappstore.online`) | FreeGameStore (`*.freegamestore.online`) |
|
|
76
|
+
| Org | freeappstore-online | freegamestore-online |
|
|
77
|
+
| Templates | standalone, connected | canvas, grid, 3d |
|
|
78
|
+
| Identity | `~/.fas/config.json` | same file |
|
|
79
|
+
|
|
80
|
+
You can install both side-by-side. `fas list` and `gas list` show the same combined list (filterable by store badge).
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
MIT.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { type CheckResult } from '@freeappstore/compliance';
|
|
3
|
+
export interface CheckSummary {
|
|
4
|
+
failed: number;
|
|
5
|
+
warned: number;
|
|
6
|
+
passed: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Print compliance results in the standard format. Reused by `fas check`
|
|
10
|
+
* and by `fas publish`'s pre-flight gate so output stays identical.
|
|
11
|
+
*/
|
|
12
|
+
export declare function renderCheckResults(results: CheckResult[]): CheckSummary;
|
|
13
|
+
export declare const checkCommand: Command;
|
|
14
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAsBvE,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,YAAY,CA6BvE;AAED,eAAO,MAAM,YAAY,SAOrB,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { runChecks } from '@freeappstore/compliance';
|
|
3
|
+
const isTTY = Boolean(process.stdout.isTTY) && process.env['NO_COLOR'] !== '1';
|
|
4
|
+
const c = (open) => (s) => (isTTY ? `\x1b[${open}m${s}\x1b[39m` : s);
|
|
5
|
+
const green = c('32');
|
|
6
|
+
const yellow = c('33');
|
|
7
|
+
const red = c('31');
|
|
8
|
+
const dim = (s) => (isTTY ? `\x1b[2m${s}\x1b[22m` : s);
|
|
9
|
+
const bold = (s) => (isTTY ? `\x1b[1m${s}\x1b[22m` : s);
|
|
10
|
+
const ICON = {
|
|
11
|
+
pass: '✓',
|
|
12
|
+
warn: '!',
|
|
13
|
+
fail: '✗',
|
|
14
|
+
};
|
|
15
|
+
const COLOR = {
|
|
16
|
+
pass: green,
|
|
17
|
+
warn: yellow,
|
|
18
|
+
fail: red,
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Print compliance results in the standard format. Reused by `fas check`
|
|
22
|
+
* and by `fas publish`'s pre-flight gate so output stays identical.
|
|
23
|
+
*/
|
|
24
|
+
export function renderCheckResults(results) {
|
|
25
|
+
let failed = 0;
|
|
26
|
+
let warned = 0;
|
|
27
|
+
let passed = 0;
|
|
28
|
+
for (const r of results) {
|
|
29
|
+
const icon = COLOR[r.status](ICON[r.status]);
|
|
30
|
+
process.stdout.write(`${icon} ${bold(r.name.padEnd(28))} ${dim(r.detail)}\n`);
|
|
31
|
+
if (r.suggestions && r.suggestions.length > 0 && r.status !== 'pass') {
|
|
32
|
+
for (const s of r.suggestions) {
|
|
33
|
+
process.stdout.write(` ${dim('→')} ${dim(s)}\n`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (r.status === 'fail')
|
|
37
|
+
failed++;
|
|
38
|
+
else if (r.status === 'warn')
|
|
39
|
+
warned++;
|
|
40
|
+
else
|
|
41
|
+
passed++;
|
|
42
|
+
}
|
|
43
|
+
process.stdout.write('\n');
|
|
44
|
+
if (failed > 0) {
|
|
45
|
+
process.stdout.write(red(`✗ ${failed} failed`));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
process.stdout.write(green(`✓ all hard checks passed`));
|
|
49
|
+
}
|
|
50
|
+
if (warned > 0) {
|
|
51
|
+
process.stdout.write(yellow(`, ${warned} warning${warned === 1 ? '' : 's'}`));
|
|
52
|
+
}
|
|
53
|
+
process.stdout.write('\n');
|
|
54
|
+
return { failed, warned, passed };
|
|
55
|
+
}
|
|
56
|
+
export const checkCommand = new Command('check')
|
|
57
|
+
.description('Run FreeAppStore compliance checks against the current directory.')
|
|
58
|
+
.option('--dir <path>', 'Directory to check', process.cwd())
|
|
59
|
+
.action(async (opts) => {
|
|
60
|
+
const results = await runChecks(opts.dir);
|
|
61
|
+
const { failed } = renderCheckResults(results);
|
|
62
|
+
if (failed > 0)
|
|
63
|
+
process.exit(1);
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBpC,eAAO,MAAM,aAAa,SAWtB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { runDoctor } from '../one-shot/doctor.js';
|
|
3
|
+
const ICON = {
|
|
4
|
+
pass: '✓',
|
|
5
|
+
warn: '!',
|
|
6
|
+
fail: '✗',
|
|
7
|
+
};
|
|
8
|
+
// ANSI color codes — same approach as lib/style.ts but inlined for simplicity
|
|
9
|
+
const isTTY = Boolean(process.stdout.isTTY) && process.env['NO_COLOR'] !== '1';
|
|
10
|
+
const c = (open) => (s) => (isTTY ? `\x1b[${open}m${s}\x1b[39m` : s);
|
|
11
|
+
const green = c('32');
|
|
12
|
+
const yellow = c('33');
|
|
13
|
+
const red = c('31');
|
|
14
|
+
const dim = (s) => (isTTY ? `\x1b[2m${s}\x1b[22m` : s);
|
|
15
|
+
const COLOR = {
|
|
16
|
+
pass: green,
|
|
17
|
+
warn: yellow,
|
|
18
|
+
fail: red,
|
|
19
|
+
};
|
|
20
|
+
export const doctorCommand = new Command('doctor')
|
|
21
|
+
.description('Run local health checks (signed-in, API reachable, tools, etc.).')
|
|
22
|
+
.action(async () => {
|
|
23
|
+
const results = await runDoctor();
|
|
24
|
+
let failed = 0;
|
|
25
|
+
for (const r of results) {
|
|
26
|
+
const icon = COLOR[r.status](ICON[r.status]);
|
|
27
|
+
process.stdout.write(`${icon} ${r.name.padEnd(20)} ${dim(r.detail)}\n`);
|
|
28
|
+
if (r.status === 'fail')
|
|
29
|
+
failed++;
|
|
30
|
+
}
|
|
31
|
+
if (failed > 0)
|
|
32
|
+
process.exit(1);
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAoB,MAAM,uBAAuB,CAAC;AAEpE,MAAM,IAAI,GAA0C;IAClD,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;CACV,CAAC;AAEF,8EAA8E;AAC9E,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC;AAC/E,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrF,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;AACtB,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;AACvB,MAAM,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE/D,MAAM,KAAK,GAAyD;IAClE,IAAI,EAAE,KAAK;IACX,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,GAAG;CACV,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,kEAAkE,CAAC;KAC/E,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,OAAO,GAAG,MAAM,SAAS,EAAE,CAAC;IAClC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzE,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;YAAE,MAAM,EAAE,CAAC;IACpC,CAAC;IACD,IAAI,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
declare const TEMPLATES: {
|
|
3
|
+
readonly canvas: "freegamestore-online/template-game-canvas";
|
|
4
|
+
readonly grid: "freegamestore-online/template-game-grid";
|
|
5
|
+
readonly '3d': "freegamestore-online/template-game-3d";
|
|
6
|
+
};
|
|
7
|
+
type TemplateName = keyof typeof TEMPLATES;
|
|
8
|
+
export declare const ALL_TEMPLATES: TemplateName[];
|
|
9
|
+
/**
|
|
10
|
+
* Scaffolds a new app from a template. Exported so the wizard can call it
|
|
11
|
+
* inline. Returns the absolute path to the new directory.
|
|
12
|
+
*/
|
|
13
|
+
export declare function runInit(opts: {
|
|
14
|
+
appId: string;
|
|
15
|
+
template?: TemplateName;
|
|
16
|
+
}): Promise<{
|
|
17
|
+
path: string;
|
|
18
|
+
substitutionCount: number;
|
|
19
|
+
}>;
|
|
20
|
+
export declare const initCommand: Command;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,QAAA,MAAM,SAAS;;;;CAIL,CAAC;AAEX,KAAK,YAAY,GAAG,MAAM,OAAO,SAAS,CAAC;AAE3C,eAAO,MAAM,aAAa,EAA6B,YAAY,EAAE,CAAC;AA2BtE;;;GAGG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,CAAC,CAkCvD;AAED,eAAO,MAAM,WAAW,SA0BpB,CAAC"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { rm, access, readdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { join, resolve, extname } from 'node:path';
|
|
5
|
+
import { assertValidAppId } from '../lib/app-id.js';
|
|
6
|
+
// fgs only knows about game templates. Apps belong to fas; if a creator
|
|
7
|
+
// runs `fgs init --template standalone` they should be sent to fas.
|
|
8
|
+
const TEMPLATES = {
|
|
9
|
+
canvas: 'freegamestore-online/template-game-canvas',
|
|
10
|
+
grid: 'freegamestore-online/template-game-grid',
|
|
11
|
+
'3d': 'freegamestore-online/template-game-3d',
|
|
12
|
+
};
|
|
13
|
+
export const ALL_TEMPLATES = Object.keys(TEMPLATES);
|
|
14
|
+
// File extensions we'll text-substitute through. Anything else (images,
|
|
15
|
+
// fonts, etc.) is left as-is. Conservative — better to miss a substitution
|
|
16
|
+
// than to corrupt a binary.
|
|
17
|
+
const TEXT_EXTENSIONS = new Set([
|
|
18
|
+
'.md',
|
|
19
|
+
'.txt',
|
|
20
|
+
'.json',
|
|
21
|
+
'.ts',
|
|
22
|
+
'.tsx',
|
|
23
|
+
'.js',
|
|
24
|
+
'.jsx',
|
|
25
|
+
'.mjs',
|
|
26
|
+
'.cjs',
|
|
27
|
+
'.html',
|
|
28
|
+
'.htm',
|
|
29
|
+
'.css',
|
|
30
|
+
'.scss',
|
|
31
|
+
'.yaml',
|
|
32
|
+
'.yml',
|
|
33
|
+
'.toml',
|
|
34
|
+
'.svg',
|
|
35
|
+
]);
|
|
36
|
+
const SKIP_DIRS = new Set(['.git', 'node_modules', 'dist', '.next', '.cache']);
|
|
37
|
+
/**
|
|
38
|
+
* Scaffolds a new app from a template. Exported so the wizard can call it
|
|
39
|
+
* inline. Returns the absolute path to the new directory.
|
|
40
|
+
*/
|
|
41
|
+
export async function runInit(opts) {
|
|
42
|
+
assertValidAppId(opts.appId);
|
|
43
|
+
const template = opts.template ?? 'canvas';
|
|
44
|
+
if (!(template in TEMPLATES)) {
|
|
45
|
+
throw new Error(`Unknown template "${template}". Choose: ${ALL_TEMPLATES.join(', ')}.`);
|
|
46
|
+
}
|
|
47
|
+
const target = resolve(process.cwd(), opts.appId);
|
|
48
|
+
if (await exists(target)) {
|
|
49
|
+
throw new Error(`Directory "${opts.appId}" already exists.`);
|
|
50
|
+
}
|
|
51
|
+
const repo = TEMPLATES[template];
|
|
52
|
+
process.stdout.write(`Cloning ${repo} → ${opts.appId}/\n`);
|
|
53
|
+
await run('git', ['clone', '--depth=1', `https://github.com/${repo}.git`, target]);
|
|
54
|
+
await rm(join(target, '.git'), { recursive: true, force: true });
|
|
55
|
+
// Replace APPNAME placeholder throughout. The template documents this
|
|
56
|
+
// step in its README, but a CLI scaffold should never punt that on the
|
|
57
|
+
// user — the result has to be runnable as-is.
|
|
58
|
+
const substitutionCount = await substituteAppName(target, opts.appId);
|
|
59
|
+
await run('git', ['init', '-q', '-b', 'main'], target);
|
|
60
|
+
// Stage and commit the template so the new repo has a real first commit.
|
|
61
|
+
// Without this, `git push` after fas publish fails with "src refspec
|
|
62
|
+
// main does not match any" because main points at nothing.
|
|
63
|
+
await run('git', ['add', '-A'], target);
|
|
64
|
+
await run('git', ['commit', '-q', '-m', `Initial commit from ${template} template`], target);
|
|
65
|
+
return { path: target, substitutionCount };
|
|
66
|
+
}
|
|
67
|
+
export const initCommand = new Command('init')
|
|
68
|
+
.description('Scaffold a new free game from a template.')
|
|
69
|
+
.argument('<game-id>', 'Short id (lowercase, single word). e.g. "asteroids"')
|
|
70
|
+
.option('-t, --template <name>', `Template: ${ALL_TEMPLATES.join(' | ')} (default: canvas — 2D games)`, 'canvas')
|
|
71
|
+
.action(async (appId, opts) => {
|
|
72
|
+
if (!(opts.template in TEMPLATES)) {
|
|
73
|
+
process.stderr.write(`Unknown template "${opts.template}". Choose: ${ALL_TEMPLATES.join(', ')}.\n`);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
const result = await runInit({
|
|
77
|
+
appId,
|
|
78
|
+
template: opts.template,
|
|
79
|
+
});
|
|
80
|
+
process.stdout.write(`\n✓ Scaffolded ${appId}/ from ${opts.template} template.\n`);
|
|
81
|
+
process.stdout.write(` Replaced APPNAME → ${appId} in ${result.substitutionCount} file(s).\n\n`);
|
|
82
|
+
process.stdout.write('Next steps:\n');
|
|
83
|
+
process.stdout.write(` cd ${appId}\n`);
|
|
84
|
+
process.stdout.write(' pnpm install # one-time setup\n');
|
|
85
|
+
process.stdout.write(' pnpm dev # local dev server\n');
|
|
86
|
+
process.stdout.write(' fgs check # compliance — run before publishing\n');
|
|
87
|
+
process.stdout.write(' fgs publish # provisions repo + hosting + DNS\n\n');
|
|
88
|
+
process.stdout.write('Docs: https://freegamestore.online/contribute.html\n');
|
|
89
|
+
});
|
|
90
|
+
async function substituteAppName(dir, appId) {
|
|
91
|
+
let count = 0;
|
|
92
|
+
for await (const file of walk(dir)) {
|
|
93
|
+
if (!TEXT_EXTENSIONS.has(extname(file).toLowerCase()))
|
|
94
|
+
continue;
|
|
95
|
+
const content = await readFile(file, 'utf8');
|
|
96
|
+
if (!content.includes('APPNAME'))
|
|
97
|
+
continue;
|
|
98
|
+
await writeFile(file, content.split('APPNAME').join(appId));
|
|
99
|
+
count++;
|
|
100
|
+
}
|
|
101
|
+
return count;
|
|
102
|
+
}
|
|
103
|
+
async function* walk(dir) {
|
|
104
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
105
|
+
for (const entry of entries) {
|
|
106
|
+
if (entry.isDirectory()) {
|
|
107
|
+
if (SKIP_DIRS.has(entry.name))
|
|
108
|
+
continue;
|
|
109
|
+
yield* walk(join(dir, entry.name));
|
|
110
|
+
}
|
|
111
|
+
else if (entry.isFile()) {
|
|
112
|
+
yield join(dir, entry.name);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function exists(path) {
|
|
117
|
+
try {
|
|
118
|
+
await access(path);
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function run(cmd, args, cwd) {
|
|
126
|
+
return new Promise((resolveFn, rejectFn) => {
|
|
127
|
+
const child = spawn(cmd, args, { stdio: 'inherit', cwd });
|
|
128
|
+
child.on('exit', (code) => {
|
|
129
|
+
if (code === 0)
|
|
130
|
+
resolveFn();
|
|
131
|
+
else
|
|
132
|
+
rejectFn(new Error(`${cmd} exited with code ${code}`));
|
|
133
|
+
});
|
|
134
|
+
child.on('error', rejectFn);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,wEAAwE;AACxE,oEAAoE;AACpE,MAAM,SAAS,GAAG;IAChB,MAAM,EAAE,2CAA2C;IACnD,IAAI,EAAE,yCAAyC;IAC/C,IAAI,EAAE,uCAAuC;CACrC,CAAC;AAIX,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAmB,CAAC;AAEtE,wEAAwE;AACxE,2EAA2E;AAC3E,4BAA4B;AAC5B,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,KAAK;IACL,MAAM;IACN,OAAO;IACP,KAAK;IACL,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;CACP,CAAC,CAAC;AAEH,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAE/E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAG7B;IACC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC;IAC3C,IAAI,CAAC,CAAC,QAAQ,IAAI,SAAS,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,cAAc,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1F,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,MAAM,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,cAAc,IAAI,CAAC,KAAK,mBAAmB,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,IAAI,MAAM,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC;IAC3D,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,sBAAsB,IAAI,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnF,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAEjE,sEAAsE;IACtE,uEAAuE;IACvE,8CAA8C;IAC9C,MAAM,iBAAiB,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACtE,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IAEvD,yEAAyE;IACzE,qEAAqE;IACrE,2DAA2D;IAC3D,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,GAAG,CACP,KAAK,EACL,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,uBAAuB,QAAQ,WAAW,CAAC,EAClE,MAAM,CACP,CAAC;IAEF,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,2CAA2C,CAAC;KACxD,QAAQ,CAAC,WAAW,EAAE,qDAAqD,CAAC;KAC5E,MAAM,CACL,uBAAuB,EACvB,aAAa,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,+BAA+B,EACrE,QAAQ,CACT;KACA,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,IAA0B,EAAE,EAAE;IAC1D,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,SAAS,CAAC,EAAE,CAAC;QAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,IAAI,CAAC,QAAQ,cAAc,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC;QAC3B,KAAK;QACL,QAAQ,EAAE,IAAI,CAAC,QAAwB;KACxC,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,KAAK,UAAU,IAAI,CAAC,QAAQ,cAAc,CAAC,CAAC;IACnF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,KAAK,OAAO,MAAM,CAAC,iBAAiB,eAAe,CAAC,CAAC;IAClG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC;IACxC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAC5D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC9D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAChF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC/E,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;AAC/E,CAAC,CAAC,CAAC;AAEL,KAAK,UAAU,iBAAiB,CAAC,GAAW,EAAE,KAAa;IACzD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YAAE,SAAS;QAChE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,SAAS;QAC3C,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5D,KAAK,EAAE,CAAC;IACV,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,GAAW;IAC9B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,SAAS;YACxC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACrC,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAY;IAChC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,GAAG,CAAC,GAAW,EAAE,IAAc,EAAE,GAAY;IACpD,OAAO,IAAI,OAAO,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE;QACzC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;QAC1D,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,IAAI,KAAK,CAAC;gBAAE,SAAS,EAAE,CAAC;;gBACvB,QAAQ,CAAC,IAAI,KAAK,CAAC,GAAG,GAAG,qBAAqB,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export declare const listCommand: Command;
|
|
3
|
+
/**
|
|
4
|
+
* Convert "https://github.com/owner/name[.git]" → "owner/name".
|
|
5
|
+
* Allows dots in the repo name (e.g. nodejs/node.js); strips a
|
|
6
|
+
* trailing `.git` suffix and any trailing slash.
|
|
7
|
+
*/
|
|
8
|
+
export declare function repoSlug(url: string): string;
|
|
9
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsBpC,eAAO,MAAM,WAAW,SA0EpB,CAAC;AAsBL;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG5C"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { readConfig } from '../lib/config.js';
|
|
3
|
+
import { fetchAppHistory, formatRelative } from '../lib/history.js';
|
|
4
|
+
const isTTY = Boolean(process.stdout.isTTY) && process.env['NO_COLOR'] !== '1';
|
|
5
|
+
const dim = (s) => (isTTY ? `\x1b[2m${s}\x1b[22m` : s);
|
|
6
|
+
const bold = (s) => (isTTY ? `\x1b[1m${s}\x1b[22m` : s);
|
|
7
|
+
export const listCommand = new Command('list')
|
|
8
|
+
.alias('ls')
|
|
9
|
+
.description('List apps and games you have published.')
|
|
10
|
+
.option('--json', 'Output JSON instead of a table (includes per-app commit history).')
|
|
11
|
+
.option('-v, --verbose', 'Show recent commits per app. Fetches the last 3 commits from each app repo via the GitHub API.')
|
|
12
|
+
.action(async (opts) => {
|
|
13
|
+
const config = await readConfig();
|
|
14
|
+
if (!config.session?.token) {
|
|
15
|
+
process.stdout.write('\n⚠ Not signed in. Run: fas login\n');
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
const res = await fetch(`${config.apiBase}/v1/apps/mine`, {
|
|
19
|
+
headers: { Authorization: `Bearer ${config.session.token}` },
|
|
20
|
+
});
|
|
21
|
+
if (res.status === 401) {
|
|
22
|
+
process.stdout.write('\n⚠ Session expired. Run: fas login\n');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
if (!res.ok) {
|
|
26
|
+
const body = await res.text();
|
|
27
|
+
process.stdout.write(`\n✗ Failed to fetch apps (${res.status}): ${body}\n`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
const { apps } = (await res.json());
|
|
31
|
+
// Fetch commit history in parallel — small set (a creator's own apps),
|
|
32
|
+
// capped at 3 commits each, gracefully degrades on rate-limit (the
|
|
33
|
+
// app prints fine without history). GH_TOKEN env var lifts the
|
|
34
|
+
// 60/hr anonymous limit if the user runs into it.
|
|
35
|
+
const histories = apps.length > 0
|
|
36
|
+
? await Promise.all(apps.map((a) => fetchAppHistory(repoSlug(a.repoUrl))))
|
|
37
|
+
: [];
|
|
38
|
+
if (opts.json) {
|
|
39
|
+
const enriched = apps.map((a, i) => ({ ...a, history: histories[i] }));
|
|
40
|
+
process.stdout.write(JSON.stringify(enriched, null, 2) + '\n');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (apps.length === 0) {
|
|
44
|
+
process.stdout.write('\nNo apps yet. Run `fas init` to start one.\n');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
process.stdout.write('\n');
|
|
48
|
+
for (let i = 0; i < apps.length; i++) {
|
|
49
|
+
const a = apps[i];
|
|
50
|
+
const h = histories[i];
|
|
51
|
+
printApp(a, h, opts.verbose ?? false);
|
|
52
|
+
}
|
|
53
|
+
const gameCount = apps.filter((a) => a.store === 'games').length;
|
|
54
|
+
const appCount = apps.length - gameCount;
|
|
55
|
+
const summary = gameCount === 0
|
|
56
|
+
? `${appCount} app${appCount === 1 ? '' : 's'}`
|
|
57
|
+
: appCount === 0
|
|
58
|
+
? `${gameCount} game${gameCount === 1 ? '' : 's'}`
|
|
59
|
+
: `${appCount} app${appCount === 1 ? '' : 's'}, ${gameCount} game${gameCount === 1 ? '' : 's'}`;
|
|
60
|
+
process.stdout.write(dim(`${summary}\n`));
|
|
61
|
+
// Surface rate-limit failure as a hint, not an error — output above
|
|
62
|
+
// is still useful, just lacks recency info.
|
|
63
|
+
if (histories.some((h) => h.error === 'rate-limited')) {
|
|
64
|
+
process.stdout.write(dim('Some commit history was rate-limited. Set GH_TOKEN to a GitHub PAT to lift the 60/hr anonymous limit.\n'));
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
function printApp(a, h, verbose) {
|
|
68
|
+
const storeBadge = a.store === 'games' ? dim('[game] ') : dim('[app] ');
|
|
69
|
+
process.stdout.write(`${storeBadge}${bold(a.id.padEnd(20))} ${dim(a.category ?? '—')}\n`);
|
|
70
|
+
if (a.oneliner)
|
|
71
|
+
process.stdout.write(` ${a.oneliner}\n`);
|
|
72
|
+
if (h.lastUpdated) {
|
|
73
|
+
process.stdout.write(` ${dim('updated:')} ${formatRelative(h.lastUpdated)}\n`);
|
|
74
|
+
}
|
|
75
|
+
process.stdout.write(` ${dim('live:')} ${a.appUrl}\n`);
|
|
76
|
+
process.stdout.write(` ${dim('repo:')} ${a.repoUrl}\n`);
|
|
77
|
+
if (verbose && h.commits && h.commits.length > 0) {
|
|
78
|
+
process.stdout.write(` ${dim('recent:')}\n`);
|
|
79
|
+
for (const c of h.commits) {
|
|
80
|
+
const short = c.sha.slice(0, 7);
|
|
81
|
+
const msg = c.message.split('\n')[0].slice(0, 80);
|
|
82
|
+
process.stdout.write(` ${dim(short)} ${msg}\n`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
process.stdout.write('\n');
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Convert "https://github.com/owner/name[.git]" → "owner/name".
|
|
89
|
+
* Allows dots in the repo name (e.g. nodejs/node.js); strips a
|
|
90
|
+
* trailing `.git` suffix and any trailing slash.
|
|
91
|
+
*/
|
|
92
|
+
export function repoSlug(url) {
|
|
93
|
+
const m = /github\.com[:/]([\w.-]+)\/([\w.-]+?)(?:\.git)?\/?$/.exec(url);
|
|
94
|
+
return m ? `${m[1]}/${m[2]}` : '';
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.test.d.ts","sourceRoot":"","sources":["../../src/commands/list.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { repoSlug } from './list.js';
|
|
3
|
+
describe('repoSlug', () => {
|
|
4
|
+
it('parses owner/name from a github HTTPS URL', () => {
|
|
5
|
+
expect(repoSlug('https://github.com/foo/bar')).toBe('foo/bar');
|
|
6
|
+
});
|
|
7
|
+
it('strips a trailing .git', () => {
|
|
8
|
+
expect(repoSlug('https://github.com/foo/bar.git')).toBe('foo/bar');
|
|
9
|
+
});
|
|
10
|
+
it('strips a trailing slash', () => {
|
|
11
|
+
expect(repoSlug('https://github.com/foo/bar/')).toBe('foo/bar');
|
|
12
|
+
});
|
|
13
|
+
it('keeps dots in the repo name (regression: previously stopped at the dot)', () => {
|
|
14
|
+
expect(repoSlug('https://github.com/nodejs/node.js')).toBe('nodejs/node.js');
|
|
15
|
+
expect(repoSlug('https://github.com/nodejs/node.js.git')).toBe('nodejs/node.js');
|
|
16
|
+
});
|
|
17
|
+
it('parses SSH-style URLs too', () => {
|
|
18
|
+
expect(repoSlug('git@github.com:foo/bar.git')).toBe('foo/bar');
|
|
19
|
+
});
|
|
20
|
+
it('returns empty string for non-github URLs', () => {
|
|
21
|
+
expect(repoSlug('https://gitlab.com/foo/bar')).toBe('');
|
|
22
|
+
expect(repoSlug('')).toBe('');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=list.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.test.js","sourceRoot":"","sources":["../../src/commands/list.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,QAAQ,CAAC,gCAAgC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,CAAC,QAAQ,CAAC,6BAA6B,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACjF,MAAM,CAAC,QAAQ,CAAC,mCAAmC,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC7E,MAAM,CAAC,QAAQ,CAAC,uCAAuC,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxD,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Runs the full login flow: GitHub device-authorization, then exchanges the
|
|
4
|
+
* GitHub access token for a fas session token. Persists both to the config
|
|
5
|
+
* file. Exported so other commands (e.g. `fas start`) can call it inline.
|
|
6
|
+
*/
|
|
7
|
+
export declare function runLogin(): Promise<{
|
|
8
|
+
login: string;
|
|
9
|
+
}>;
|
|
10
|
+
export declare const loginCommand: Command;
|
|
11
|
+
//# sourceMappingURL=login.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC;;;;GAIG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAkC3D;AAED,eAAO,MAAM,YAAY,SAMrB,CAAC"}
|