@hallaxius/forge 0.1.3 → 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.
Files changed (45) hide show
  1. package/README.md +160 -158
  2. package/bin/forge.js +2 -2
  3. package/dist/cli.js +12764 -13800
  4. package/package.json +75 -75
  5. package/src/cli.ts +80 -78
  6. package/src/commands/account.ts +80 -0
  7. package/src/commands/alias.ts +66 -66
  8. package/src/commands/branch.ts +46 -46
  9. package/src/commands/ci.ts +28 -28
  10. package/src/commands/clone.ts +100 -100
  11. package/src/commands/commit.ts +88 -88
  12. package/src/commands/config.ts +47 -48
  13. package/src/commands/diff.ts +26 -26
  14. package/src/commands/fetch.ts +20 -20
  15. package/src/commands/help.ts +58 -58
  16. package/src/commands/init.ts +32 -33
  17. package/src/commands/issue.ts +63 -63
  18. package/src/commands/log.ts +29 -29
  19. package/src/commands/merge.ts +37 -37
  20. package/src/commands/pr.ts +65 -65
  21. package/src/commands/push.ts +35 -35
  22. package/src/commands/release.ts +26 -26
  23. package/src/commands/remote.ts +107 -107
  24. package/src/commands/reset.ts +30 -30
  25. package/src/commands/setup.ts +93 -94
  26. package/src/commands/stash.ts +44 -44
  27. package/src/commands/status.ts +74 -74
  28. package/src/commands/sync.ts +20 -20
  29. package/src/commands/tag.ts +41 -41
  30. package/src/commands/undo.ts +27 -27
  31. package/src/commands/version.ts +12 -12
  32. package/src/constants/colors.ts +7 -7
  33. package/src/constants/commit-types.ts +24 -24
  34. package/src/constants/messages.ts +13 -23
  35. package/src/lib/auth.ts +172 -172
  36. package/src/lib/config.ts +108 -108
  37. package/src/lib/git.ts +543 -543
  38. package/src/lib/github.ts +202 -160
  39. package/src/lib/logger.ts +18 -31
  40. package/src/lib/ui.ts +122 -156
  41. package/src/lib/validators.ts +16 -16
  42. package/src/templates/commit-types.json +9 -9
  43. package/src/utils/files.ts +21 -21
  44. package/src/utils/strings.ts +19 -19
  45. package/src/version.const.ts +1 -1
package/package.json CHANGED
@@ -1,75 +1,75 @@
1
- {
2
- "name": "@hallaxius/forge",
3
- "version": "0.1.3",
4
- "description": "A modern Git CLI with professional UX",
5
- "author": "hallaxius",
6
- "license": "MIT",
7
- "type": "module",
8
- "bin": {
9
- "fg": "./dist/cli.js"
10
- },
11
- "main": "./dist/cli.js",
12
- "types": "./dist/cli.d.ts",
13
- "scripts": {
14
- "dev": "bun --watch src/cli.ts",
15
- "build:version": "bun scripts/gen-version.mjs",
16
- "build": "bun run build:version && bun build src/cli.ts --outdir dist --target node --external inquirer",
17
- "start": "bun bin/forge.js",
18
- "test": "bun test",
19
- "lint": "biome check",
20
- "format": "biome format --write",
21
- "lint:fix": "biome check --write --unsafe",
22
- "prepublishOnly": "bun run build && bun test",
23
- "prepack": "bun run build",
24
- "patch": "npm version patch && npm publish",
25
- "minor": "npm version minor && npm publish",
26
- "major": "npm version major && npm publish"
27
- },
28
- "dependencies": {
29
- "@octokit/rest": "^21.1.0",
30
- "boxen": "^7.1.0",
31
- "chalk": "^5.3.0",
32
- "commander": "^12.0.0",
33
- "conf": "^12.0.0",
34
- "diff": "^7.0.0",
35
- "figures": "^5.0.0",
36
- "inquirer": "^14.0.2",
37
- "isomorphic-git": "^1.38.0",
38
- "ora": "^8.0.0"
39
- },
40
- "devDependencies": {
41
- "@biomejs/biome": "2.5.1",
42
- "typescript": "^5.3.0"
43
- },
44
- "files": [
45
- "bin",
46
- "dist",
47
- "src"
48
- ],
49
- "engines": {
50
- "node": ">=18.0.0",
51
- "bun": ">=1.0.0"
52
- },
53
- "repository": {
54
- "type": "git",
55
- "url": "git+https://github.com/hallaxius/forge.git"
56
- },
57
- "bugs": {
58
- "url": "https://github.com/hallaxius/forge/issues"
59
- },
60
- "publishConfig": {
61
- "access": "public"
62
- },
63
- "homepage": "https://github.com/hallaxius/forge#readme",
64
- "keywords": [
65
- "git",
66
- "cli",
67
- "forge",
68
- "git-cli",
69
- "developer-tools",
70
- "productivity",
71
- "bun",
72
- "command-line",
73
- "github-api"
74
- ]
75
- }
1
+ {
2
+ "name": "@hallaxius/forge",
3
+ "version": "0.1.4",
4
+ "description": "A modern Git CLI with professional UX",
5
+ "author": "hallaxius",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "bin": {
9
+ "fg": "./dist/cli.js"
10
+ },
11
+ "main": "./dist/cli.js",
12
+ "types": "./dist/cli.d.ts",
13
+ "scripts": {
14
+ "dev": "bun --watch src/cli.ts",
15
+ "build:version": "bun scripts/gen-version.mjs",
16
+ "build": "bun run build:version && bun build src/cli.ts --outdir dist --target node --external inquirer",
17
+ "start": "bun bin/forge.js",
18
+ "test": "bun test",
19
+ "lint": "biome check",
20
+ "format": "biome format --write",
21
+ "lint:fix": "biome check --write --unsafe",
22
+ "prepublishOnly": "bun run build && bun test",
23
+ "prepack": "bun run build",
24
+ "patch": "npm version patch && npm publish",
25
+ "minor": "npm version minor && npm publish",
26
+ "major": "npm version major && npm publish",
27
+ "publish": "npm publish"
28
+ },
29
+ "dependencies": {
30
+ "@octokit/rest": "^21.1.0",
31
+ "chalk": "^5.3.0",
32
+ "commander": "^12.0.0",
33
+ "conf": "^12.0.0",
34
+ "diff": "^7.0.0",
35
+ "figures": "^5.0.0",
36
+ "inquirer": "^14.0.2",
37
+ "isomorphic-git": "^1.38.0",
38
+ "ora": "^8.0.0"
39
+ },
40
+ "devDependencies": {
41
+ "@biomejs/biome": "2.5.1",
42
+ "typescript": "^5.3.0"
43
+ },
44
+ "files": [
45
+ "bin",
46
+ "dist",
47
+ "src"
48
+ ],
49
+ "engines": {
50
+ "node": ">=18.0.0",
51
+ "bun": ">=1.0.0"
52
+ },
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "git+https://github.com/hallaxius/forge.git"
56
+ },
57
+ "bugs": {
58
+ "url": "https://github.com/hallaxius/forge/issues"
59
+ },
60
+ "publishConfig": {
61
+ "access": "public"
62
+ },
63
+ "homepage": "https://github.com/hallaxius/forge#readme",
64
+ "keywords": [
65
+ "git",
66
+ "cli",
67
+ "forge",
68
+ "git-cli",
69
+ "developer-tools",
70
+ "productivity",
71
+ "bun",
72
+ "command-line",
73
+ "github-api"
74
+ ]
75
+ }
package/src/cli.ts CHANGED
@@ -1,78 +1,80 @@
1
- import { readFileSync } from "node:fs";
2
- import { dirname, resolve } from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- import { Command } from "commander";
5
-
6
- const __filename = fileURLToPath(import.meta.url);
7
- const __dirname = dirname(__filename);
8
-
9
- const pkg = JSON.parse(
10
- readFileSync(resolve(__dirname, "../package.json"), "utf-8"),
11
- );
12
-
13
- const program = new Command();
14
-
15
- program
16
- .name("fg")
17
- .description("Modern Git CLI for professional workflows")
18
- .version(pkg.version);
19
-
20
- import registerAlias from "./commands/alias.js";
21
-
22
- import registerBranch from "./commands/branch.js";
23
- import registerCi from "./commands/ci.js";
24
- import registerClone from "./commands/clone.js";
25
- import registerCommit from "./commands/commit.js";
26
- import registerConfig from "./commands/config.js";
27
- import registerDiff from "./commands/diff.js";
28
- import registerFetch from "./commands/fetch.js";
29
- import registerHelp from "./commands/help.js";
30
- import registerInit from "./commands/init.js";
31
- import registerIssue from "./commands/issue.js";
32
- import registerLog from "./commands/log.js";
33
- import registerMerge from "./commands/merge.js";
34
- import registerPr from "./commands/pr.js";
35
- import registerPush from "./commands/push.js";
36
- import registerRelease from "./commands/release.js";
37
- import registerRemote from "./commands/remote.js";
38
- import registerReset from "./commands/reset.js";
39
- import registerSetup from "./commands/setup.js";
40
- import registerStash from "./commands/stash.js";
41
- import registerStatus from "./commands/status.js";
42
- import registerSync from "./commands/sync.js";
43
- import registerTag from "./commands/tag.js";
44
- import registerUndo from "./commands/undo.js";
45
- import registerVersion from "./commands/version.js";
46
-
47
- registerSetup(program);
48
- registerCommit(program);
49
- registerPush(program);
50
- registerStatus(program);
51
- registerSync(program);
52
- registerFetch(program);
53
- registerBranch(program);
54
- registerLog(program);
55
- registerDiff(program);
56
- registerStash(program);
57
- registerTag(program);
58
- registerAlias(program);
59
- registerConfig(program);
60
- registerUndo(program);
61
- registerReset(program);
62
- registerHelp(program);
63
- registerVersion(program);
64
- registerClone(program);
65
- registerInit(program);
66
- registerRemote(program);
67
-
68
- registerCi(program);
69
- registerIssue(program);
70
- registerMerge(program);
71
- registerPr(program);
72
- registerRelease(program);
73
-
74
- if (process.argv.length <= 2) {
75
- program.outputHelp();
76
- } else {
77
- program.parse(process.argv);
78
- }
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { Command } from "commander";
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+
9
+ const pkg = JSON.parse(
10
+ readFileSync(resolve(__dirname, "../package.json"), "utf-8"),
11
+ );
12
+
13
+ const program = new Command();
14
+
15
+ program
16
+ .name("fg")
17
+ .description("Modern Git CLI for professional workflows")
18
+ .version(pkg.version);
19
+
20
+ import registerAccount from "./commands/account.js";
21
+ import registerAlias from "./commands/alias.js";
22
+
23
+ import registerBranch from "./commands/branch.js";
24
+ import registerCi from "./commands/ci.js";
25
+ import registerClone from "./commands/clone.js";
26
+ import registerCommit from "./commands/commit.js";
27
+ import registerConfig from "./commands/config.js";
28
+ import registerDiff from "./commands/diff.js";
29
+ import registerFetch from "./commands/fetch.js";
30
+ import registerHelp from "./commands/help.js";
31
+ import registerInit from "./commands/init.js";
32
+ import registerIssue from "./commands/issue.js";
33
+ import registerLog from "./commands/log.js";
34
+ import registerMerge from "./commands/merge.js";
35
+ import registerPr from "./commands/pr.js";
36
+ import registerPush from "./commands/push.js";
37
+ import registerRelease from "./commands/release.js";
38
+ import registerRemote from "./commands/remote.js";
39
+ import registerReset from "./commands/reset.js";
40
+ import registerSetup from "./commands/setup.js";
41
+ import registerStash from "./commands/stash.js";
42
+ import registerStatus from "./commands/status.js";
43
+ import registerSync from "./commands/sync.js";
44
+ import registerTag from "./commands/tag.js";
45
+ import registerUndo from "./commands/undo.js";
46
+ import registerVersion from "./commands/version.js";
47
+
48
+ registerSetup(program);
49
+ registerAccount(program);
50
+ registerCommit(program);
51
+ registerPush(program);
52
+ registerStatus(program);
53
+ registerSync(program);
54
+ registerFetch(program);
55
+ registerBranch(program);
56
+ registerLog(program);
57
+ registerDiff(program);
58
+ registerStash(program);
59
+ registerTag(program);
60
+ registerAlias(program);
61
+ registerConfig(program);
62
+ registerUndo(program);
63
+ registerReset(program);
64
+ registerHelp(program);
65
+ registerVersion(program);
66
+ registerClone(program);
67
+ registerInit(program);
68
+ registerRemote(program);
69
+
70
+ registerCi(program);
71
+ registerIssue(program);
72
+ registerMerge(program);
73
+ registerPr(program);
74
+ registerRelease(program);
75
+
76
+ if (process.argv.length <= 2) {
77
+ program.outputHelp();
78
+ } else {
79
+ program.parse(process.argv);
80
+ }
@@ -0,0 +1,80 @@
1
+ import chalk from "chalk";
2
+ import type { Command } from "commander";
3
+ import { ConfigManager } from "../lib/config.js";
4
+ import { getAccountInfo } from "../lib/github.js";
5
+ import { error, newline, text } from "../lib/logger.js";
6
+ import { withSpinner } from "../lib/ui.js";
7
+
8
+ export default function register(program: Command): void {
9
+ program
10
+ .command("account")
11
+ .description("Display account information")
12
+ .action(async () => {
13
+ try {
14
+ const config = new ConfigManager();
15
+ const cfg = config.getAll();
16
+ const userName = cfg.user.name || "(not set)";
17
+ const userEmail = cfg.user.email || "(not set)";
18
+ const hasToken = !!cfg.github.encryptedToken;
19
+ const security = cfg.auth.hasMasterPassword
20
+ ? "Master password protected"
21
+ : "Machine key";
22
+
23
+ const parts: string[] = [];
24
+
25
+ parts.push(chalk.bold("Local Config"));
26
+ parts.push(` Name: ${userName}`);
27
+ parts.push(` Email: ${userEmail}`);
28
+ parts.push(
29
+ ` Token: ${hasToken ? "Configured (encrypted)" : "Not configured"}`,
30
+ );
31
+ parts.push(` Security: ${security}`);
32
+
33
+ if (hasToken) {
34
+ newline();
35
+ text("Fetching GitHub account info...");
36
+ newline();
37
+
38
+ const account = await withSpinner("Fetching account data...", () =>
39
+ getAccountInfo(),
40
+ );
41
+
42
+ parts.push("");
43
+ parts.push(chalk.bold("GitHub Profile"));
44
+ parts.push(` Username: ${account.login}`);
45
+ if (account.name) parts.push(` Name: ${account.name}`);
46
+ if (account.email) parts.push(` Email: ${account.email}`);
47
+ if (account.company) parts.push(` Company: ${account.company}`);
48
+ if (account.location) parts.push(` Location: ${account.location}`);
49
+ if (account.bio) parts.push(` Bio: ${account.bio}`);
50
+ if (account.blog) parts.push(` Blog: ${account.blog}`);
51
+ if (account.twitter) parts.push(` Twitter: @${account.twitter}`);
52
+ parts.push(` Profile: ${account.profileUrl}`);
53
+ parts.push("");
54
+ parts.push(chalk.bold("Statistics"));
55
+ parts.push(` Repos: ${account.publicRepos}`);
56
+ parts.push(` Gists: ${account.publicGists}`);
57
+ parts.push(` Followers: ${account.followers}`);
58
+ parts.push(` Following: ${account.following}`);
59
+ if (account.plan) parts.push(` Plan: ${account.plan}`);
60
+ parts.push(
61
+ ` Created: ${new Date(account.createdAt).toLocaleDateString()}`,
62
+ );
63
+
64
+ text(parts.join("\n"));
65
+ } else {
66
+ text(parts.join("\n"));
67
+ newline();
68
+ text(
69
+ "No GitHub token configured. Run 'fg setup' to connect your GitHub account.",
70
+ );
71
+ }
72
+
73
+ text("Account information displayed.");
74
+ } catch (err) {
75
+ error(
76
+ `Failed to load account: ${err instanceof Error ? err.message : String(err)}`,
77
+ );
78
+ }
79
+ });
80
+ }
@@ -1,66 +1,66 @@
1
- import { homedir } from "node:os";
2
- import { join } from "node:path";
3
- import type { Command } from "commander";
4
- import Conf from "conf";
5
- import { error, info, success } from "../lib/logger.js";
6
- import { createTable } from "../lib/ui.js";
7
-
8
- const aliasConfig = new Conf({
9
- configName: "forge-aliases",
10
- cwd: join(homedir(), ".forge"),
11
- });
12
-
13
- export default function register(program: Command): void {
14
- const alias = program.command("alias").description("Manage aliases");
15
-
16
- alias
17
- .command("add <name> <command>")
18
- .description("Create an alias")
19
- .action(async (name, command) => {
20
- try {
21
- aliasConfig.set(name, command);
22
- success(`Alias '${name}' created.`);
23
- } catch (err) {
24
- error(
25
- `Failed to create alias: ${err instanceof Error ? err.message : String(err)}`,
26
- );
27
- }
28
- });
29
-
30
- alias
31
- .command("list")
32
- .description("List all aliases")
33
- .action(async () => {
34
- try {
35
- const store = aliasConfig.store as Record<string, string>;
36
- const entries = Object.entries(store);
37
-
38
- if (entries.length === 0) {
39
- info("No aliases configured.");
40
- return;
41
- }
42
-
43
- const rows = entries.map(([name, cmd]) => [name, cmd]);
44
- info("Aliases:");
45
- console.log(createTable(["Name", "Command"], rows));
46
- } catch (err) {
47
- error(
48
- `Failed to list aliases: ${err instanceof Error ? err.message : String(err)}`,
49
- );
50
- }
51
- });
52
-
53
- alias
54
- .command("remove <name>")
55
- .description("Delete an alias")
56
- .action(async (name) => {
57
- try {
58
- aliasConfig.delete(name);
59
- success(`Alias '${name}' removed.`);
60
- } catch (err) {
61
- error(
62
- `Failed to remove alias: ${err instanceof Error ? err.message : String(err)}`,
63
- );
64
- }
65
- });
66
- }
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ import type { Command } from "commander";
4
+ import Conf from "conf";
5
+ import { error, text } from "../lib/logger.js";
6
+ import { createTable } from "../lib/ui.js";
7
+
8
+ const aliasConfig = new Conf({
9
+ configName: "forge-aliases",
10
+ cwd: join(homedir(), ".forge"),
11
+ });
12
+
13
+ export default function register(program: Command): void {
14
+ const alias = program.command("alias").description("Manage aliases");
15
+
16
+ alias
17
+ .command("add <name> <command>")
18
+ .description("Create an alias")
19
+ .action(async (name, command) => {
20
+ try {
21
+ aliasConfig.set(name, command);
22
+ text(`Alias '${name}' created.`);
23
+ } catch (err) {
24
+ error(
25
+ `Failed to create alias: ${err instanceof Error ? err.message : String(err)}`,
26
+ );
27
+ }
28
+ });
29
+
30
+ alias
31
+ .command("list")
32
+ .description("List all aliases")
33
+ .action(async () => {
34
+ try {
35
+ const store = aliasConfig.store as Record<string, string>;
36
+ const entries = Object.entries(store);
37
+
38
+ if (entries.length === 0) {
39
+ text("No aliases configured.");
40
+ return;
41
+ }
42
+
43
+ const rows = entries.map(([name, cmd]) => [name, cmd]);
44
+ text("Aliases:");
45
+ text(createTable(["Name", "Command"], rows));
46
+ } catch (err) {
47
+ error(
48
+ `Failed to list aliases: ${err instanceof Error ? err.message : String(err)}`,
49
+ );
50
+ }
51
+ });
52
+
53
+ alias
54
+ .command("remove <name>")
55
+ .description("Delete an alias")
56
+ .action(async (name) => {
57
+ try {
58
+ aliasConfig.delete(name);
59
+ text(`Alias '${name}' removed.`);
60
+ } catch (err) {
61
+ error(
62
+ `Failed to remove alias: ${err instanceof Error ? err.message : String(err)}`,
63
+ );
64
+ }
65
+ });
66
+ }
@@ -1,46 +1,46 @@
1
- import type { Command } from "commander";
2
- import * as git from "../lib/git.js";
3
- import { error, info, success } from "../lib/logger.js";
4
- import { createTable } from "../lib/ui.js";
5
-
6
- export default function register(program: Command): void {
7
- program
8
- .command("branch")
9
- .description("Manage branches")
10
- .option("-n, --new <name>", "Create new branch")
11
- .option("-d, --delete <name>", "Delete branch")
12
- .option("-s, --switch <name>", "Switch to branch")
13
- .action(async (options) => {
14
- try {
15
- if (options.new) {
16
- await git.createBranch(options.new);
17
- success(`Branch '${options.new}' created.`);
18
- return;
19
- }
20
-
21
- if (options.delete) {
22
- await git.deleteBranch(options.delete);
23
- success(`Branch '${options.delete}' deleted.`);
24
- return;
25
- }
26
-
27
- if (options.switch) {
28
- await git.switchBranch(options.switch);
29
- success(`Switched to '${options.switch}'.`);
30
- return;
31
- }
32
-
33
- const branches = await git.getBranches();
34
- const rows = branches.all.map((b) => [
35
- b === branches.current ? "*" : " ",
36
- b,
37
- ]);
38
- info("Branches:");
39
- console.log(createTable(["", "Name"], rows));
40
- } catch (err) {
41
- error(
42
- `Branch operation failed: ${err instanceof Error ? err.message : String(err)}`,
43
- );
44
- }
45
- });
46
- }
1
+ import type { Command } from "commander";
2
+ import * as git from "../lib/git.js";
3
+ import { error, text } from "../lib/logger.js";
4
+ import { createTable } from "../lib/ui.js";
5
+
6
+ export default function register(program: Command): void {
7
+ program
8
+ .command("branch")
9
+ .description("Manage branches")
10
+ .option("-n, --new <name>", "Create new branch")
11
+ .option("-d, --delete <name>", "Delete branch")
12
+ .option("-s, --switch <name>", "Switch to branch")
13
+ .action(async (options) => {
14
+ try {
15
+ if (options.new) {
16
+ await git.createBranch(options.new);
17
+ text(`Branch '${options.new}' created.`);
18
+ return;
19
+ }
20
+
21
+ if (options.delete) {
22
+ await git.deleteBranch(options.delete);
23
+ text(`Branch '${options.delete}' deleted.`);
24
+ return;
25
+ }
26
+
27
+ if (options.switch) {
28
+ await git.switchBranch(options.switch);
29
+ text(`Switched to '${options.switch}'.`);
30
+ return;
31
+ }
32
+
33
+ const branches = await git.getBranches();
34
+ const rows = branches.all.map((b) => [
35
+ b === branches.current ? "*" : " ",
36
+ b,
37
+ ]);
38
+ text("Branches:");
39
+ text(createTable(["", "Name"], rows));
40
+ } catch (err) {
41
+ error(
42
+ `Branch operation failed: ${err instanceof Error ? err.message : String(err)}`,
43
+ );
44
+ }
45
+ });
46
+ }