@freeappstore/cli 0.1.0 → 0.1.2
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/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 +11 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +25 -14
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts +8 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +14 -3
- package/dist/commands/login.js.map +1 -1
- package/dist/index.js +27 -2
- package/dist/index.js.map +1 -1
- 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/dist/tui/App.d.ts +2 -0
- package/dist/tui/App.d.ts.map +1 -0
- package/dist/tui/App.js +51 -0
- package/dist/tui/App.js.map +1 -0
- package/dist/tui/screens/Doctor.d.ts +6 -0
- package/dist/tui/screens/Doctor.d.ts.map +1 -0
- package/dist/tui/screens/Doctor.js +27 -0
- package/dist/tui/screens/Doctor.js.map +1 -0
- package/dist/tui/screens/Menu.d.ts +8 -0
- package/dist/tui/screens/Menu.d.ts.map +1 -0
- package/dist/tui/screens/Menu.js +11 -0
- package/dist/tui/screens/Menu.js.map +1 -0
- package/dist/tui/screens/Welcome.d.ts +6 -0
- package/dist/tui/screens/Welcome.d.ts.map +1 -0
- package/dist/tui/screens/Welcome.js +10 -0
- package/dist/tui/screens/Welcome.js.map +1 -0
- package/dist/tui/start.d.ts +6 -0
- package/dist/tui/start.d.ts.map +1 -0
- package/dist/tui/start.js +12 -0
- package/dist/tui/start.js.map +1 -0
- package/package.json +8 -2
|
@@ -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"}
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Scaffolds a new app from a template. Exported so the wizard can call it
|
|
4
|
+
* inline. Returns the absolute path to the new directory.
|
|
5
|
+
*/
|
|
6
|
+
export declare function runInit(opts: {
|
|
7
|
+
appId: string;
|
|
8
|
+
template?: 'standalone' | 'connected';
|
|
9
|
+
}): Promise<{
|
|
10
|
+
path: string;
|
|
11
|
+
substitutionCount: number;
|
|
12
|
+
}>;
|
|
2
13
|
export declare const initCommand: Command;
|
|
3
14
|
//# sourceMappingURL=init.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsCpC,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsCpC;;;GAGG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC;CACvC,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,CAAC,CAkCvD;AAED,eAAO,MAAM,WAAW,SAYpB,CAAC"}
|
package/dist/commands/init.js
CHANGED
|
@@ -30,36 +30,47 @@ const TEXT_EXTENSIONS = new Set([
|
|
|
30
30
|
'.svg',
|
|
31
31
|
]);
|
|
32
32
|
const SKIP_DIRS = new Set(['.git', 'node_modules', 'dist', '.next', '.cache']);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
assertValidAppId(appId);
|
|
39
|
-
const template = opts.template;
|
|
33
|
+
/**
|
|
34
|
+
* Scaffolds a new app from a template. Exported so the wizard can call it
|
|
35
|
+
* inline. Returns the absolute path to the new directory.
|
|
36
|
+
*/
|
|
37
|
+
export async function runInit(opts) {
|
|
38
|
+
assertValidAppId(opts.appId);
|
|
39
|
+
const template = opts.template ?? 'standalone';
|
|
40
40
|
if (!(template in TEMPLATES)) {
|
|
41
|
-
throw new Error(`Unknown template "${
|
|
41
|
+
throw new Error(`Unknown template "${template}". Choose: standalone, connected.`);
|
|
42
42
|
}
|
|
43
|
-
const target = resolve(process.cwd(), appId);
|
|
43
|
+
const target = resolve(process.cwd(), opts.appId);
|
|
44
44
|
if (await exists(target)) {
|
|
45
|
-
throw new Error(`Directory "${appId}" already exists.`);
|
|
45
|
+
throw new Error(`Directory "${opts.appId}" already exists.`);
|
|
46
46
|
}
|
|
47
47
|
const repo = TEMPLATES[template];
|
|
48
|
-
process.stdout.write(`Cloning ${repo} → ${appId}/\n`);
|
|
48
|
+
process.stdout.write(`Cloning ${repo} → ${opts.appId}/\n`);
|
|
49
49
|
await run('git', ['clone', '--depth=1', `https://github.com/${repo}.git`, target]);
|
|
50
50
|
await rm(join(target, '.git'), { recursive: true, force: true });
|
|
51
51
|
// Replace APPNAME placeholder throughout. The template documents this
|
|
52
52
|
// step in its README, but a CLI scaffold should never punt that on the
|
|
53
53
|
// user — the result has to be runnable as-is.
|
|
54
|
-
const
|
|
54
|
+
const substitutionCount = await substituteAppName(target, opts.appId);
|
|
55
55
|
await run('git', ['init', '-q', '-b', 'main'], target);
|
|
56
56
|
// Stage and commit the template so the new repo has a real first commit.
|
|
57
57
|
// Without this, `git push` after fas publish fails with "src refspec
|
|
58
58
|
// main does not match any" because main points at nothing.
|
|
59
59
|
await run('git', ['add', '-A'], target);
|
|
60
60
|
await run('git', ['commit', '-q', '-m', `Initial commit from ${template} template`], target);
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
return { path: target, substitutionCount };
|
|
62
|
+
}
|
|
63
|
+
export const initCommand = new Command('init')
|
|
64
|
+
.description('Scaffold a new free app from a template.')
|
|
65
|
+
.argument('<app-id>', 'Short app id (lowercase, single word). e.g. "calendar"')
|
|
66
|
+
.option('-t, --template <name>', 'Template: standalone | connected', 'standalone')
|
|
67
|
+
.action(async (appId, opts) => {
|
|
68
|
+
const result = await runInit({
|
|
69
|
+
appId,
|
|
70
|
+
template: opts.template,
|
|
71
|
+
});
|
|
72
|
+
process.stdout.write(`\n✓ Scaffolded ${appId}/ from ${opts.template} template.\n`);
|
|
73
|
+
process.stdout.write(` Replaced APPNAME → ${appId} in ${result.substitutionCount} file(s).\n`);
|
|
63
74
|
process.stdout.write(` Next: cd ${appId} && pnpm install && pnpm dev\n`);
|
|
64
75
|
});
|
|
65
76
|
async function substituteAppName(dir, appId) {
|
|
@@ -1 +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,MAAM,SAAS,GAAG;IAChB,UAAU,EAAE,yCAAyC;IACrD,SAAS,EAAE,wCAAwC;CAC3C,CAAC;AAIX,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,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/login.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
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
|
+
}>;
|
|
2
10
|
export declare const loginCommand: Command;
|
|
3
11
|
//# sourceMappingURL=login.d.ts.map
|
|
@@ -1 +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,eAAO,MAAM,YAAY,
|
|
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"}
|
package/dist/commands/login.js
CHANGED
|
@@ -6,9 +6,12 @@ import { startDeviceFlow } from '../lib/github.js';
|
|
|
6
6
|
// Device-flow client_ids are not secret — the user_code/device_code is
|
|
7
7
|
// what authenticates the session. Override at runtime via FAS_GITHUB_CLIENT_ID.
|
|
8
8
|
const DEFAULT_CLIENT_ID = process.env['FAS_GITHUB_CLIENT_ID'] ?? 'Ov23liuUpYPXc1ikEFm2';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Runs the full login flow: GitHub device-authorization, then exchanges the
|
|
11
|
+
* GitHub access token for a fas session token. Persists both to the config
|
|
12
|
+
* file. Exported so other commands (e.g. `fas start`) can call it inline.
|
|
13
|
+
*/
|
|
14
|
+
export async function runLogin() {
|
|
12
15
|
if (!DEFAULT_CLIENT_ID) {
|
|
13
16
|
throw new Error('GitHub client_id is not configured. The platform admin must register a GitHub OAuth App ' +
|
|
14
17
|
'and set FAS_GITHUB_CLIENT_ID, or bake it into the published CLI build.');
|
|
@@ -35,5 +38,13 @@ export const loginCommand = new Command('login')
|
|
|
35
38
|
session: { token: sessionToken, obtainedAt: Date.now() },
|
|
36
39
|
});
|
|
37
40
|
process.stdout.write(`\n✓ Signed in as @${login}\n`);
|
|
41
|
+
return { login };
|
|
42
|
+
}
|
|
43
|
+
export const loginCommand = new Command('login')
|
|
44
|
+
.description('Sign in with GitHub.')
|
|
45
|
+
// Discard runLogin's return value so commander gets the void-returning
|
|
46
|
+
// signature it expects.
|
|
47
|
+
.action(async () => {
|
|
48
|
+
await runLogin();
|
|
38
49
|
});
|
|
39
50
|
//# sourceMappingURL=login.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,+DAA+D;AAC/D,wFAAwF;AACxF,uEAAuE;AACvE,gFAAgF;AAChF,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,IAAI,sBAAsB,CAAC;AAExF
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,+DAA+D;AAC/D,wFAAwF;AACxF,uEAAuE;AACvE,gFAAgF;AAChF,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,IAAI,sBAAsB,CAAC;AAExF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,0FAA0F;YACxF,wEAAwE,CAC3E,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,iBAAiB,CAAC,CAAC;IACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,eAAe,oBAAoB,IAAI,CAAC,QAAQ,MAAM,CAAC,CAAC;IAC5F,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAEvD,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IACjD,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAElC,wEAAwE;IACxE,uEAAuE;IACvE,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,mBAAmB,EAAE;QACpE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;KACnD,CAAC,CAAC;IACH,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,yBAAyB,WAAW,CAAC,MAAM,MAAM,MAAM,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC/F,CAAC;IACD,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,MAAM,WAAW,CAAC,IAAI,EAAE,CAA6B,CAAC;IAEhF,MAAM,WAAW,CAAC;QAChB,GAAG,MAAM;QACT,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE;QACtD,OAAO,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE;KACzD,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,KAAK,IAAI,CAAC,CAAC;IACrD,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,sBAAsB,CAAC;IACpC,uEAAuE;IACvE,wBAAwB;KACvB,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,QAAQ,EAAE,CAAC;AACnB,CAAC,CAAC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,23 +1,48 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
3
6
|
import { loginCommand } from './commands/login.js';
|
|
4
7
|
import { logoutCommand } from './commands/logout.js';
|
|
5
8
|
import { initCommand } from './commands/init.js';
|
|
6
9
|
import { publishCommand } from './commands/publish.js';
|
|
7
10
|
import { logsCommand } from './commands/logs.js';
|
|
8
11
|
import { whoamiCommand } from './commands/whoami.js';
|
|
12
|
+
import { doctorCommand } from './commands/doctor.js';
|
|
13
|
+
// Read version from the package's own package.json so `fas --version` always
|
|
14
|
+
// matches the installed package. dist/index.js sits one level under the
|
|
15
|
+
// package root (where package.json lives).
|
|
16
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const pkg = JSON.parse(readFileSync(join(here, '..', 'package.json'), 'utf8'));
|
|
9
18
|
const program = new Command();
|
|
10
19
|
program
|
|
11
20
|
.name('fas')
|
|
12
21
|
.description('FreeAppStore CLI — sign in, scaffold, and publish free apps.')
|
|
13
|
-
.version(
|
|
22
|
+
.version(pkg.version);
|
|
14
23
|
program.addCommand(loginCommand);
|
|
15
24
|
program.addCommand(logoutCommand);
|
|
16
25
|
program.addCommand(whoamiCommand);
|
|
17
26
|
program.addCommand(initCommand);
|
|
18
27
|
program.addCommand(publishCommand);
|
|
19
28
|
program.addCommand(logsCommand);
|
|
20
|
-
program.
|
|
29
|
+
program.addCommand(doctorCommand);
|
|
30
|
+
// `fas` with no subcommand → launch the TUI when stdout is a TTY.
|
|
31
|
+
// Subcommands keep their normal one-shot behavior, scriptable for CI / agents.
|
|
32
|
+
async function main() {
|
|
33
|
+
if (process.argv.length === 2) {
|
|
34
|
+
if (!process.stdout.isTTY) {
|
|
35
|
+
// Piped output (CI, redirects). Show help instead of TUI.
|
|
36
|
+
program.outputHelp();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const { startTui } = await import('./tui/start.js');
|
|
40
|
+
await startTui();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
await program.parseAsync();
|
|
44
|
+
}
|
|
45
|
+
main().catch((err) => {
|
|
21
46
|
const msg = err instanceof Error ? err.message : String(err);
|
|
22
47
|
process.stderr.write(`fas: ${msg}\n`);
|
|
23
48
|
process.exit(1);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,KAAK,CAAC;KACX,WAAW,CAAC,8DAA8D,CAAC;KAC3E,OAAO,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,6EAA6E;AAC7E,wEAAwE;AACxE,2CAA2C;AAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAE5E,CAAC;AAEF,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,KAAK,CAAC;KACX,WAAW,CAAC,8DAA8D,CAAC;KAC3E,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAExB,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAElC,kEAAkE;AAClE,+EAA+E;AAC/E,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC1B,0DAA0D;YAC1D,OAAO,CAAC,UAAU,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QACD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACpD,MAAM,QAAQ,EAAE,CAAC;QACjB,OAAO;IACT,CAAC;IACD,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;AAC7B,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const bold: (s: string) => string;
|
|
2
|
+
export declare const dim: (s: string) => string;
|
|
3
|
+
export declare const cyan: (s: string) => string;
|
|
4
|
+
export declare const green: (s: string) => string;
|
|
5
|
+
export declare const yellow: (s: string) => string;
|
|
6
|
+
export declare const red: (s: string) => string;
|
|
7
|
+
export declare function header(s: string): string;
|
|
8
|
+
export declare function step(n: number, total: number, label: string): string;
|
|
9
|
+
//# sourceMappingURL=style.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../src/lib/style.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,IAAI,MAHX,MAAM,KAAG,MAGoB,CAAC;AACpC,eAAO,MAAM,GAAG,MAJV,MAAM,KAAG,MAImB,CAAC;AACnC,eAAO,MAAM,IAAI,MALX,MAAM,KAAG,MAKqB,CAAC;AACrC,eAAO,MAAM,KAAK,MANZ,MAAM,KAAG,MAMsB,CAAC;AACtC,eAAO,MAAM,MAAM,MAPb,MAAM,KAAG,MAOuB,CAAC;AACvC,eAAO,MAAM,GAAG,MARV,MAAM,KAAG,MAQoB,CAAC;AAEpC,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAGxC;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Tiny ANSI styling without pulling chalk. Auto-disables when stdout
|
|
2
|
+
// isn't a TTY (CI logs, redirected output) so plain text is captured.
|
|
3
|
+
const isTTY = Boolean(process.stdout.isTTY) && process.env['NO_COLOR'] !== '1';
|
|
4
|
+
const wrap = (open, close) => (s) => isTTY ? `\x1b[${open}m${s}\x1b[${close}m` : s;
|
|
5
|
+
export const bold = wrap('1', '22');
|
|
6
|
+
export const dim = wrap('2', '22');
|
|
7
|
+
export const cyan = wrap('36', '39');
|
|
8
|
+
export const green = wrap('32', '39');
|
|
9
|
+
export const yellow = wrap('33', '39');
|
|
10
|
+
export const red = wrap('31', '39');
|
|
11
|
+
export function header(s) {
|
|
12
|
+
const line = '─'.repeat(Math.min(s.length + 4, 60));
|
|
13
|
+
return `\n${cyan(line)}\n${cyan(' ')}${bold(s)}\n${cyan(line)}\n`;
|
|
14
|
+
}
|
|
15
|
+
export function step(n, total, label) {
|
|
16
|
+
return cyan(`[${n}/${total}]`) + ' ' + bold(label);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=style.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.js","sourceRoot":"","sources":["../../src/lib/style.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sEAAsE;AAEtE,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC;AAE/E,MAAM,IAAI,GACR,CAAC,IAAY,EAAE,KAAa,EAAE,EAAE,CAChC,CAAC,CAAS,EAAU,EAAE,CACpB,KAAK,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAElD,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACnC,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACrC,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACtC,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACvC,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAEpC,MAAM,UAAU,MAAM,CAAC,CAAS;IAC9B,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,CAAS,EAAE,KAAa,EAAE,KAAa;IAC1D,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type CheckStatus = 'pass' | 'fail' | 'warn';
|
|
2
|
+
export interface CheckResult {
|
|
3
|
+
name: string;
|
|
4
|
+
status: CheckStatus;
|
|
5
|
+
detail: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Runs every local + remote health check, in parallel where it's safe to.
|
|
9
|
+
* Returns the full result list. The CLI's `fas doctor` and the TUI's
|
|
10
|
+
* Doctor screen both render this same data.
|
|
11
|
+
*/
|
|
12
|
+
export declare function runDoctor(): Promise<CheckResult[]>;
|
|
13
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/one-shot/doctor.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEnD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAUxD"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { readConfig } from '../lib/config.js';
|
|
6
|
+
/**
|
|
7
|
+
* Runs every local + remote health check, in parallel where it's safe to.
|
|
8
|
+
* Returns the full result list. The CLI's `fas doctor` and the TUI's
|
|
9
|
+
* Doctor screen both render this same data.
|
|
10
|
+
*/
|
|
11
|
+
export async function runDoctor() {
|
|
12
|
+
const checks = await Promise.all([
|
|
13
|
+
checkNodeVersion(),
|
|
14
|
+
checkBinary('git'),
|
|
15
|
+
checkBinary('pnpm'),
|
|
16
|
+
checkConfigFile(),
|
|
17
|
+
checkSignedIn(),
|
|
18
|
+
checkApiReachable(),
|
|
19
|
+
]);
|
|
20
|
+
return checks;
|
|
21
|
+
}
|
|
22
|
+
async function checkNodeVersion() {
|
|
23
|
+
const v = process.versions.node;
|
|
24
|
+
const major = Number(v.split('.')[0]);
|
|
25
|
+
if (Number.isNaN(major)) {
|
|
26
|
+
return { name: 'Node version', status: 'warn', detail: `Could not parse: ${v}` };
|
|
27
|
+
}
|
|
28
|
+
if (major < 22) {
|
|
29
|
+
return {
|
|
30
|
+
name: 'Node version',
|
|
31
|
+
status: 'fail',
|
|
32
|
+
detail: `${v} (need ≥ 22 to run the templates)`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return { name: 'Node version', status: 'pass', detail: v };
|
|
36
|
+
}
|
|
37
|
+
async function checkBinary(name) {
|
|
38
|
+
const found = await which(name);
|
|
39
|
+
return found
|
|
40
|
+
? { name: `${name} installed`, status: 'pass', detail: found }
|
|
41
|
+
: { name: `${name} installed`, status: 'fail', detail: `${name} not on PATH` };
|
|
42
|
+
}
|
|
43
|
+
async function checkConfigFile() {
|
|
44
|
+
const path = join(homedir(), '.fas', 'config.json');
|
|
45
|
+
try {
|
|
46
|
+
const raw = await readFile(path, 'utf8');
|
|
47
|
+
JSON.parse(raw);
|
|
48
|
+
return { name: 'Config file', status: 'pass', detail: path };
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
const code = err.code;
|
|
52
|
+
if (code === 'ENOENT') {
|
|
53
|
+
return { name: 'Config file', status: 'warn', detail: 'No config yet — run `fas login`.' };
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
name: 'Config file',
|
|
57
|
+
status: 'fail',
|
|
58
|
+
detail: `${path}: ${err instanceof Error ? err.message : String(err)}`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async function checkSignedIn() {
|
|
63
|
+
try {
|
|
64
|
+
const config = await readConfig();
|
|
65
|
+
if (!config.session?.token) {
|
|
66
|
+
return { name: 'Signed in', status: 'warn', detail: 'Not signed in. Run `fas login`.' };
|
|
67
|
+
}
|
|
68
|
+
if (!config.github?.login) {
|
|
69
|
+
return {
|
|
70
|
+
name: 'Signed in',
|
|
71
|
+
status: 'warn',
|
|
72
|
+
detail: 'Session present but missing GitHub login — run `fas login` again.',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return { name: 'Signed in', status: 'pass', detail: `@${config.github.login}` };
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
return {
|
|
79
|
+
name: 'Signed in',
|
|
80
|
+
status: 'fail',
|
|
81
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function checkApiReachable() {
|
|
86
|
+
try {
|
|
87
|
+
const config = await readConfig();
|
|
88
|
+
const started = Date.now();
|
|
89
|
+
const res = await fetch(`${config.apiBase}/health`, {
|
|
90
|
+
signal: AbortSignal.timeout(5000),
|
|
91
|
+
});
|
|
92
|
+
const ms = Date.now() - started;
|
|
93
|
+
if (res.ok) {
|
|
94
|
+
return { name: 'API reachable', status: 'pass', detail: `${config.apiBase} (${ms}ms)` };
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
name: 'API reachable',
|
|
98
|
+
status: 'fail',
|
|
99
|
+
detail: `HTTP ${res.status} from ${config.apiBase}`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
104
|
+
return { name: 'API reachable', status: 'fail', detail: msg };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function which(cmd) {
|
|
108
|
+
return new Promise((resolveFn) => {
|
|
109
|
+
const child = spawn('which', [cmd], { stdio: ['ignore', 'pipe', 'ignore'] });
|
|
110
|
+
let buf = '';
|
|
111
|
+
child.stdout.on('data', (chunk) => (buf += chunk.toString()));
|
|
112
|
+
child.on('close', (code) => resolveFn(code === 0 ? buf.trim() : null));
|
|
113
|
+
child.on('error', () => resolveFn(null));
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/one-shot/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.test.d.ts","sourceRoot":"","sources":["../../src/one-shot/doctor.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import { runDoctor } from './doctor.js';
|
|
3
|
+
beforeEach(() => {
|
|
4
|
+
// Provide a fast, deterministic /health response unless a test overrides.
|
|
5
|
+
globalThis.fetch = vi.fn().mockResolvedValue(new Response(JSON.stringify({ ok: true }), { status: 200 }));
|
|
6
|
+
});
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
delete globalThis['fetch'];
|
|
9
|
+
vi.restoreAllMocks();
|
|
10
|
+
});
|
|
11
|
+
describe('runDoctor', () => {
|
|
12
|
+
it('runs all 6 expected checks and returns them in stable order', async () => {
|
|
13
|
+
const results = await runDoctor();
|
|
14
|
+
const names = results.map((r) => r.name);
|
|
15
|
+
expect(names).toEqual([
|
|
16
|
+
'Node version',
|
|
17
|
+
'git installed',
|
|
18
|
+
'pnpm installed',
|
|
19
|
+
'Config file',
|
|
20
|
+
'Signed in',
|
|
21
|
+
'API reachable',
|
|
22
|
+
]);
|
|
23
|
+
});
|
|
24
|
+
it('flags Node < 22 as fail', async () => {
|
|
25
|
+
const original = process.versions;
|
|
26
|
+
Object.defineProperty(process, 'versions', {
|
|
27
|
+
value: { ...original, node: '20.0.0' },
|
|
28
|
+
configurable: true,
|
|
29
|
+
});
|
|
30
|
+
try {
|
|
31
|
+
const results = await runDoctor();
|
|
32
|
+
const node = results.find((r) => r.name === 'Node version');
|
|
33
|
+
expect(node?.status).toBe('fail');
|
|
34
|
+
expect(node?.detail).toContain('20.0.0');
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
Object.defineProperty(process, 'versions', { value: original, configurable: true });
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
it('marks API reachable as fail on 5xx', async () => {
|
|
41
|
+
globalThis.fetch = vi.fn().mockResolvedValue(new Response('boom', { status: 503 }));
|
|
42
|
+
const results = await runDoctor();
|
|
43
|
+
const api = results.find((r) => r.name === 'API reachable');
|
|
44
|
+
expect(api?.status).toBe('fail');
|
|
45
|
+
expect(api?.detail).toContain('503');
|
|
46
|
+
});
|
|
47
|
+
it('marks API reachable as fail on network error', async () => {
|
|
48
|
+
globalThis.fetch = vi.fn().mockRejectedValue(new Error('getaddrinfo ENOTFOUND'));
|
|
49
|
+
const results = await runDoctor();
|
|
50
|
+
const api = results.find((r) => r.name === 'API reachable');
|
|
51
|
+
expect(api?.status).toBe('fail');
|
|
52
|
+
expect(api?.detail).toContain('ENOTFOUND');
|
|
53
|
+
});
|
|
54
|
+
it('all check results have a non-empty name and detail', async () => {
|
|
55
|
+
const results = await runDoctor();
|
|
56
|
+
for (const r of results) {
|
|
57
|
+
expect(r.name.length).toBeGreaterThan(0);
|
|
58
|
+
expect(r.detail.length).toBeGreaterThan(0);
|
|
59
|
+
expect(['pass', 'warn', 'fail']).toContain(r.status);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=doctor.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.test.js","sourceRoot":"","sources":["../../src/one-shot/doctor.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":"AAcA,wBAAgB,GAAG,IAAI,KAAK,CAAC,YAAY,CAwCxC"}
|
package/dist/tui/App.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, useApp, useInput } from 'ink';
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { Doctor } from './screens/Doctor.js';
|
|
5
|
+
import { Menu } from './screens/Menu.js';
|
|
6
|
+
import { Welcome } from './screens/Welcome.js';
|
|
7
|
+
import { readConfig } from '../lib/config.js';
|
|
8
|
+
export function App() {
|
|
9
|
+
const { exit } = useApp();
|
|
10
|
+
const [screen, setScreen] = useState('welcome');
|
|
11
|
+
const [session, setSession] = useState({ loaded: false, login: null });
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
void (async () => {
|
|
14
|
+
const config = await readConfig();
|
|
15
|
+
const login = config.github?.login ?? null;
|
|
16
|
+
setSession({ loaded: true, login });
|
|
17
|
+
setScreen(login ? 'menu' : 'welcome');
|
|
18
|
+
})();
|
|
19
|
+
}, []);
|
|
20
|
+
// Global keys: q to quit, except while typing into an input.
|
|
21
|
+
useInput((input, key) => {
|
|
22
|
+
if (input === 'q' && !key.shift)
|
|
23
|
+
exit();
|
|
24
|
+
});
|
|
25
|
+
if (!session.loaded) {
|
|
26
|
+
return (_jsx(Box, { children: _jsx(Text, { children: "Loading\u2026" }) }));
|
|
27
|
+
}
|
|
28
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Header, { login: session.login }), _jsxs(Box, { marginY: 1, children: [screen === 'welcome' && _jsx(Welcome, { onContinue: () => setScreen('menu') }), screen === 'menu' && (_jsx(Menu, { login: session.login, onSelect: (choice) => handleMenu(choice, setScreen, exit) })), screen === 'doctor' && _jsx(Doctor, { onBack: () => setScreen('menu') })] }), _jsx(Footer, { screen: screen })] }));
|
|
29
|
+
}
|
|
30
|
+
function handleMenu(choice, setScreen, exit) {
|
|
31
|
+
switch (choice) {
|
|
32
|
+
case 'doctor':
|
|
33
|
+
setScreen('doctor');
|
|
34
|
+
break;
|
|
35
|
+
case 'quit':
|
|
36
|
+
exit();
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function Header({ login }) {
|
|
41
|
+
return (_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "cyan", children: "fas" }), _jsx(Text, { color: "gray", children: " \u00B7 FreeAppStore CLI" }), login && (_jsxs(_Fragment, { children: [_jsx(Text, { color: "gray", children: " \u00B7 " }), _jsxs(Text, { color: "green", children: ["@", login] })] }))] }));
|
|
42
|
+
}
|
|
43
|
+
function Footer({ screen }) {
|
|
44
|
+
const hint = screen === 'menu'
|
|
45
|
+
? '↑↓ to navigate · Enter to select · q to quit'
|
|
46
|
+
: screen === 'doctor'
|
|
47
|
+
? 'Esc/b to back · q to quit'
|
|
48
|
+
: 'Enter to continue · q to quit';
|
|
49
|
+
return (_jsx(Box, { children: _jsx(Text, { color: "gray", dimColor: true, children: hint }) }));
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=App.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.js","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Doctor.d.ts","sourceRoot":"","sources":["../../../src/tui/screens/Doctor.tsx"],"names":[],"mappings":"AAKA,UAAU,KAAK;IACb,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,wBAAgB,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC,YAAY,CAoC5D"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, useInput } from 'ink';
|
|
3
|
+
import Spinner from 'ink-spinner';
|
|
4
|
+
import { useEffect, useState } from 'react';
|
|
5
|
+
import { runDoctor } from '../../one-shot/doctor.js';
|
|
6
|
+
export function Doctor({ onBack }) {
|
|
7
|
+
const [results, setResults] = useState(null);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
void (async () => {
|
|
10
|
+
setResults(await runDoctor());
|
|
11
|
+
})();
|
|
12
|
+
}, []);
|
|
13
|
+
useInput((input, key) => {
|
|
14
|
+
if (key.escape || input === 'b')
|
|
15
|
+
onBack();
|
|
16
|
+
});
|
|
17
|
+
if (!results) {
|
|
18
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { children: " Running checks\u2026" })] }));
|
|
19
|
+
}
|
|
20
|
+
return (_jsxs(Box, { flexDirection: "column", children: [results.map((r) => (_jsx(ResultRow, { result: r }, r.name))), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: "Press Esc or b to go back." }) })] }));
|
|
21
|
+
}
|
|
22
|
+
function ResultRow({ result }) {
|
|
23
|
+
const color = result.status === 'pass' ? 'green' : result.status === 'warn' ? 'yellow' : 'red';
|
|
24
|
+
const icon = result.status === 'pass' ? '✓' : result.status === 'warn' ? '!' : '✗';
|
|
25
|
+
return (_jsxs(Box, { children: [_jsxs(Text, { color: color, children: [icon, ' '] }), _jsx(Text, { children: result.name.padEnd(20) }), _jsx(Text, { color: "gray", dimColor: true, children: result.detail })] }));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=Doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Doctor.js","sourceRoot":"","sources":["../../../src/tui/screens/Doctor.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,OAAO,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAoB,MAAM,0BAA0B,CAAC;AAMvE,MAAM,UAAU,MAAM,CAAC,EAAE,MAAM,EAAS;IACtC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAuB,IAAI,CAAC,CAAC;IAEnE,SAAS,CAAC,GAAG,EAAE;QACb,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,UAAU,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC;QAChC,CAAC,CAAC,EAAE,CAAC;IACP,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACtB,IAAI,GAAG,CAAC,MAAM,IAAI,KAAK,KAAK,GAAG;YAAE,MAAM,EAAE,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CACL,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAChB,KAAC,OAAO,IAAC,IAAI,EAAC,MAAM,GAAG,GAClB,EACP,KAAC,IAAI,wCAAwB,IACzB,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACxB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAClB,KAAC,SAAS,IAAc,MAAM,EAAE,CAAC,IAAjB,CAAC,CAAC,IAAI,CAAe,CACtC,CAAC,EACF,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,EAAC,QAAQ,iDAEpB,GACH,IACF,CACP,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,EAAE,MAAM,EAA2B;IACpD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/F,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IACnF,OAAO,CACL,MAAC,GAAG,eACF,MAAC,IAAI,IAAC,KAAK,EAAE,KAAK,aACf,IAAI,EACJ,IAAI,IACA,EACP,KAAC,IAAI,cAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAQ,EACrC,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,EAAC,QAAQ,kBACxB,MAAM,CAAC,MAAM,GACT,IACH,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Menu.d.ts","sourceRoot":"","sources":["../../../src/tui/screens/Menu.tsx"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;AAO3C,UAAU,KAAK;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;CACxC;AAED,wBAAgB,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC,YAAY,CAgBnE"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import SelectInput from 'ink-select-input';
|
|
4
|
+
export function Menu({ login, onSelect }) {
|
|
5
|
+
const items = [
|
|
6
|
+
{ label: 'Doctor — run health checks', value: 'doctor' },
|
|
7
|
+
{ label: 'Quit', value: 'quit' },
|
|
8
|
+
];
|
|
9
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: [login ? `Signed in as @${login}.` : 'Not signed in.', " What would you like to do?"] }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: items, onSelect: (item) => onSelect(item.value) }) })] }));
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=Menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Menu.js","sourceRoot":"","sources":["../../../src/tui/screens/Menu.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,WAAW,MAAM,kBAAkB,CAAC;AAc3C,MAAM,UAAU,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAS;IAC7C,MAAM,KAAK,GAAW;QACpB,EAAE,KAAK,EAAE,4BAA4B,EAAE,KAAK,EAAE,QAAQ,EAAE;QACxD,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;KACjC,CAAC;IAEF,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,MAAC,IAAI,eACF,KAAK,CAAC,CAAC,CAAC,iBAAiB,KAAK,GAAG,CAAC,CAAC,CAAC,gBAAgB,mCAChD,EACP,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,WAAW,IAAa,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAI,GAC/E,IACF,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Welcome.d.ts","sourceRoot":"","sources":["../../../src/tui/screens/Welcome.tsx"],"names":[],"mappings":"AAEA,UAAU,KAAK;IACb,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,wBAAgB,OAAO,CAAC,EAAE,UAAU,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC,YAAY,CAsBjE"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, useInput } from 'ink';
|
|
3
|
+
export function Welcome({ onContinue }) {
|
|
4
|
+
useInput((_, key) => {
|
|
5
|
+
if (key.return)
|
|
6
|
+
onContinue();
|
|
7
|
+
});
|
|
8
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: "Welcome to FreeAppStore." }), _jsxs(Text, { color: "gray", children: ["You're not signed in yet. To publish a free app, run", ' ', _jsx(Text, { bold: true, color: "cyan", children: "fas login" }), ' ', "in another terminal first."] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: "Press Enter to continue to the menu." }) })] }));
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=Welcome.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Welcome.js","sourceRoot":"","sources":["../../../src/tui/screens/Welcome.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAM1C,MAAM,UAAU,OAAO,CAAC,EAAE,UAAU,EAAS;IAC3C,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QAClB,IAAI,GAAG,CAAC,MAAM;YAAE,UAAU,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,KAAC,IAAI,2CAAgC,EACrC,MAAC,IAAI,IAAC,KAAK,EAAC,MAAM,qEACqC,GAAG,EACxD,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,MAAM,0BAEhB,EAAC,GAAG,kCAEN,EACP,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,EAAC,QAAQ,2DAEpB,GACH,IACF,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/tui/start.tsx"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAG9C"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { render } from 'ink';
|
|
3
|
+
import { App } from './App.js';
|
|
4
|
+
/**
|
|
5
|
+
* Entry point for `fas` (no args) → renders the interactive TUI.
|
|
6
|
+
* Awaits until the user quits (Ctrl-C, q, or via the menu).
|
|
7
|
+
*/
|
|
8
|
+
export async function startTui() {
|
|
9
|
+
const instance = render(_jsx(App, {}));
|
|
10
|
+
await instance.waitUntilExit();
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/tui/start.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAC,GAAG,KAAG,CAAC,CAAC;IACjC,MAAM,QAAQ,CAAC,aAAa,EAAE,CAAC;AACjC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@freeappstore/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "fas — CLI for publishing free apps to freeappstore.online",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -37,11 +37,17 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"commander": "^12.1.0",
|
|
40
|
-
"
|
|
40
|
+
"ink": "^7.0.2",
|
|
41
|
+
"ink-select-input": "^6.2.0",
|
|
42
|
+
"ink-spinner": "^5.0.0",
|
|
43
|
+
"ink-text-input": "^6.0.0",
|
|
44
|
+
"prompts": "^2.4.2",
|
|
45
|
+
"react": "^19.2.5"
|
|
41
46
|
},
|
|
42
47
|
"devDependencies": {
|
|
43
48
|
"@types/node": "^22.0.0",
|
|
44
49
|
"@types/prompts": "^2.4.9",
|
|
50
|
+
"@types/react": "^19.2.14",
|
|
45
51
|
"typescript": "^5.7.0"
|
|
46
52
|
}
|
|
47
53
|
}
|